chord.js 50 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256
  1. define('echarts/chart/chord', [
  2. 'require',
  3. './base',
  4. 'zrender/shape/Text',
  5. 'zrender/shape/Line',
  6. 'zrender/shape/Sector',
  7. '../util/shape/Ribbon',
  8. '../util/shape/Icon',
  9. 'zrender/shape/BezierCurve',
  10. '../config',
  11. '../util/ecData',
  12. 'zrender/tool/util',
  13. 'zrender/tool/vector',
  14. '../data/Graph',
  15. '../layout/Chord',
  16. '../chart'
  17. ], function (require) {
  18. 'use strict';
  19. var ChartBase = require('./base');
  20. var TextShape = require('zrender/shape/Text');
  21. var LineShape = require('zrender/shape/Line');
  22. var SectorShape = require('zrender/shape/Sector');
  23. var RibbonShape = require('../util/shape/Ribbon');
  24. var IconShape = require('../util/shape/Icon');
  25. var BezierCurveShape = require('zrender/shape/BezierCurve');
  26. var ecConfig = require('../config');
  27. ecConfig.chord = {
  28. zlevel: 0,
  29. z: 2,
  30. clickable: true,
  31. radius: [
  32. '65%',
  33. '75%'
  34. ],
  35. center: [
  36. '50%',
  37. '50%'
  38. ],
  39. padding: 2,
  40. sort: 'none',
  41. sortSub: 'none',
  42. startAngle: 90,
  43. clockWise: true,
  44. ribbonType: true,
  45. minRadius: 10,
  46. maxRadius: 20,
  47. symbol: 'circle',
  48. showScale: false,
  49. showScaleText: false,
  50. itemStyle: {
  51. normal: {
  52. borderWidth: 0,
  53. borderColor: '#000',
  54. label: {
  55. show: true,
  56. rotate: false,
  57. distance: 5
  58. },
  59. chordStyle: {
  60. width: 1,
  61. color: 'black',
  62. borderWidth: 1,
  63. borderColor: '#999',
  64. opacity: 0.5
  65. }
  66. },
  67. emphasis: {
  68. borderWidth: 0,
  69. borderColor: '#000',
  70. chordStyle: {
  71. width: 1,
  72. color: 'black',
  73. borderWidth: 1,
  74. borderColor: '#999'
  75. }
  76. }
  77. }
  78. };
  79. var ecData = require('../util/ecData');
  80. var zrUtil = require('zrender/tool/util');
  81. var vec2 = require('zrender/tool/vector');
  82. var Graph = require('../data/Graph');
  83. var ChordLayout = require('../layout/Chord');
  84. function Chord(ecTheme, messageCenter, zr, option, myChart) {
  85. ChartBase.call(this, ecTheme, messageCenter, zr, option, myChart);
  86. this.scaleLineLength = 4;
  87. this.scaleUnitAngle = 4;
  88. this.refresh(option);
  89. }
  90. Chord.prototype = {
  91. type: ecConfig.CHART_TYPE_CHORD,
  92. _init: function () {
  93. var series = this.series;
  94. this.selectedMap = {};
  95. var chordSeriesMap = {};
  96. var chordSeriesGroups = {};
  97. for (var i = 0, l = series.length; i < l; i++) {
  98. if (series[i].type === this.type) {
  99. var _isSelected = this.isSelected(series[i].name);
  100. this.selectedMap[series[i].name] = _isSelected;
  101. if (_isSelected) {
  102. this.buildMark(i);
  103. }
  104. this.reformOption(series[i]);
  105. chordSeriesMap[series[i].name] = series[i];
  106. }
  107. }
  108. for (var i = 0, l = series.length; i < l; i++) {
  109. if (series[i].type === this.type) {
  110. if (series[i].insertToSerie) {
  111. var referenceSerie = chordSeriesMap[series[i].insertToSerie];
  112. series[i]._referenceSerie = referenceSerie;
  113. } else {
  114. chordSeriesGroups[series[i].name] = [series[i]];
  115. }
  116. }
  117. }
  118. for (var i = 0, l = series.length; i < l; i++) {
  119. if (series[i].type === this.type) {
  120. if (series[i].insertToSerie) {
  121. var mainSerie = series[i]._referenceSerie;
  122. while (mainSerie && mainSerie._referenceSerie) {
  123. mainSerie = mainSerie._referenceSerie;
  124. }
  125. if (chordSeriesGroups[mainSerie.name] && this.selectedMap[series[i].name]) {
  126. chordSeriesGroups[mainSerie.name].push(series[i]);
  127. }
  128. }
  129. }
  130. }
  131. for (var name in chordSeriesGroups) {
  132. this._buildChords(chordSeriesGroups[name]);
  133. }
  134. this.addShapeList();
  135. },
  136. _getNodeCategory: function (serie, group) {
  137. return serie.categories && serie.categories[group.category || 0];
  138. },
  139. _getNodeQueryTarget: function (serie, group) {
  140. var category = this._getNodeCategory(serie, group);
  141. return [
  142. group,
  143. category,
  144. serie
  145. ];
  146. },
  147. _getEdgeQueryTarget: function (serie, edge, type) {
  148. type = type || 'normal';
  149. return [
  150. edge.itemStyle && edge.itemStyle[type],
  151. serie.itemStyle[type].chordStyle
  152. ];
  153. },
  154. _buildChords: function (series) {
  155. var graphs = [];
  156. var mainSerie = series[0];
  157. var nodeFilter = function (n) {
  158. return n.layout.size > 0;
  159. };
  160. var createEdgeFilter = function (graph) {
  161. return function (e) {
  162. return graph.getEdge(e.node2, e.node1);
  163. };
  164. };
  165. for (var i = 0; i < series.length; i++) {
  166. var serie = series[i];
  167. if (this.selectedMap[serie.name]) {
  168. var graph;
  169. if (serie.data && serie.matrix) {
  170. graph = this._getSerieGraphFromDataMatrix(serie, mainSerie);
  171. } else if (serie.nodes && serie.links) {
  172. graph = this._getSerieGraphFromNodeLinks(serie, mainSerie);
  173. }
  174. graph.filterNode(nodeFilter, this);
  175. if (serie.ribbonType) {
  176. graph.filterEdge(createEdgeFilter(graph));
  177. }
  178. graphs.push(graph);
  179. graph.__serie = serie;
  180. }
  181. }
  182. if (!graphs.length) {
  183. return;
  184. }
  185. var mainGraph = graphs[0];
  186. if (!mainSerie.ribbonType) {
  187. var minRadius = mainSerie.minRadius;
  188. var maxRadius = mainSerie.maxRadius;
  189. var min = Infinity, max = -Infinity;
  190. mainGraph.eachNode(function (node) {
  191. max = Math.max(node.layout.size, max);
  192. min = Math.min(node.layout.size, min);
  193. });
  194. var multiplier = (maxRadius - minRadius) / (max - min);
  195. mainGraph.eachNode(function (node) {
  196. var queryTarget = this._getNodeQueryTarget(mainSerie, node);
  197. var symbolSize = this.query(queryTarget, 'symbolSize');
  198. if (max === min) {
  199. node.layout.size = symbolSize || min;
  200. } else {
  201. node.layout.size = symbolSize || (node.layout.size - min) * multiplier + minRadius;
  202. }
  203. }, this);
  204. }
  205. var layout = new ChordLayout();
  206. layout.clockWise = mainSerie.clockWise;
  207. layout.startAngle = mainSerie.startAngle * Math.PI / 180;
  208. if (!layout.clockWise) {
  209. layout.startAngle = -layout.startAngle;
  210. }
  211. layout.padding = mainSerie.padding * Math.PI / 180;
  212. layout.sort = mainSerie.sort;
  213. layout.sortSub = mainSerie.sortSub;
  214. layout.directed = mainSerie.ribbonType;
  215. layout.run(graphs);
  216. var showLabel = this.query(mainSerie, 'itemStyle.normal.label.show');
  217. if (mainSerie.ribbonType) {
  218. this._buildSectors(mainSerie, 0, mainGraph, mainSerie, graphs);
  219. if (showLabel) {
  220. this._buildLabels(mainSerie, 0, mainGraph, mainSerie, graphs);
  221. }
  222. for (var i = 0, j = 0; i < series.length; i++) {
  223. if (this.selectedMap[series[i].name]) {
  224. this._buildRibbons(series, i, graphs[j++], mainSerie);
  225. }
  226. }
  227. if (mainSerie.showScale) {
  228. this._buildScales(mainSerie, 0, mainGraph);
  229. }
  230. } else {
  231. this._buildNodeIcons(mainSerie, 0, mainGraph, mainSerie, graphs);
  232. if (showLabel) {
  233. this._buildLabels(mainSerie, 0, mainGraph, mainSerie, graphs);
  234. }
  235. for (var i = 0, j = 0; i < series.length; i++) {
  236. if (this.selectedMap[series[i].name]) {
  237. this._buildEdgeCurves(series, i, graphs[j++], mainSerie, mainGraph);
  238. }
  239. }
  240. }
  241. this._initHoverHandler(series, graphs);
  242. },
  243. _getSerieGraphFromDataMatrix: function (serie, mainSerie) {
  244. var nodesData = [];
  245. var count = 0;
  246. var matrix = [];
  247. for (var i = 0; i < serie.matrix.length; i++) {
  248. matrix[i] = serie.matrix[i].slice();
  249. }
  250. var data = serie.data || serie.nodes;
  251. for (var i = 0; i < data.length; i++) {
  252. var node = {};
  253. var group = data[i];
  254. group.rawIndex = i;
  255. for (var key in group) {
  256. if (key === 'name') {
  257. node['id'] = group['name'];
  258. } else {
  259. node[key] = group[key];
  260. }
  261. }
  262. var category = this._getNodeCategory(mainSerie, group);
  263. var name = category ? category.name : group.name;
  264. this.selectedMap[name] = this.isSelected(name);
  265. if (this.selectedMap[name]) {
  266. nodesData.push(node);
  267. count++;
  268. } else {
  269. matrix.splice(count, 1);
  270. for (var j = 0; j < matrix.length; j++) {
  271. matrix[j].splice(count, 1);
  272. }
  273. }
  274. }
  275. var graph = Graph.fromMatrix(nodesData, matrix, true);
  276. graph.eachNode(function (n, idx) {
  277. n.layout = { size: n.data.outValue };
  278. n.rawIndex = n.data.rawIndex;
  279. });
  280. graph.eachEdge(function (e) {
  281. e.layout = { weight: e.data.weight };
  282. });
  283. return graph;
  284. },
  285. _getSerieGraphFromNodeLinks: function (serie, mainSerie) {
  286. var graph = new Graph(true);
  287. var nodes = serie.data || serie.nodes;
  288. for (var i = 0, len = nodes.length; i < len; i++) {
  289. var n = nodes[i];
  290. if (!n || n.ignore) {
  291. continue;
  292. }
  293. var category = this._getNodeCategory(mainSerie, n);
  294. var name = category ? category.name : n.name;
  295. this.selectedMap[name] = this.isSelected(name);
  296. if (this.selectedMap[name]) {
  297. var node = graph.addNode(n.name, n);
  298. node.rawIndex = i;
  299. }
  300. }
  301. for (var i = 0, len = serie.links.length; i < len; i++) {
  302. var e = serie.links[i];
  303. var n1 = e.source;
  304. var n2 = e.target;
  305. if (typeof n1 === 'number') {
  306. n1 = nodes[n1];
  307. if (n1) {
  308. n1 = n1.name;
  309. }
  310. }
  311. if (typeof n2 === 'number') {
  312. n2 = nodes[n2];
  313. if (n2) {
  314. n2 = n2.name;
  315. }
  316. }
  317. var edge = graph.addEdge(n1, n2, e);
  318. if (edge) {
  319. edge.rawIndex = i;
  320. }
  321. }
  322. graph.eachNode(function (n) {
  323. var value = n.data.value;
  324. if (value == null) {
  325. value = 0;
  326. if (mainSerie.ribbonType) {
  327. for (var i = 0; i < n.outEdges.length; i++) {
  328. value += n.outEdges[i].data.weight || 0;
  329. }
  330. } else {
  331. for (var i = 0; i < n.edges.length; i++) {
  332. value += n.edges[i].data.weight || 0;
  333. }
  334. }
  335. }
  336. n.layout = { size: value };
  337. });
  338. graph.eachEdge(function (e) {
  339. e.layout = { weight: e.data.weight == null ? 1 : e.data.weight };
  340. });
  341. return graph;
  342. },
  343. _initHoverHandler: function (series, graphs) {
  344. var mainSerie = series[0];
  345. var mainGraph = graphs[0];
  346. var self = this;
  347. mainGraph.eachNode(function (node) {
  348. node.shape.onmouseover = function () {
  349. mainGraph.eachNode(function (n) {
  350. n.shape.style.opacity = 0.1;
  351. if (n.labelShape) {
  352. n.labelShape.style.opacity = 0.1;
  353. n.labelShape.modSelf();
  354. }
  355. n.shape.modSelf();
  356. });
  357. for (var i = 0; i < graphs.length; i++) {
  358. for (var j = 0; j < graphs[i].edges.length; j++) {
  359. var e = graphs[i].edges[j];
  360. var queryTarget = self._getEdgeQueryTarget(graphs[i].__serie, e.data);
  361. e.shape.style.opacity = self.deepQuery(queryTarget, 'opacity') * 0.1;
  362. e.shape.modSelf();
  363. }
  364. }
  365. node.shape.style.opacity = 1;
  366. if (node.labelShape) {
  367. node.labelShape.style.opacity = 1;
  368. }
  369. for (var i = 0; i < graphs.length; i++) {
  370. var n = graphs[i].getNodeById(node.id);
  371. if (n) {
  372. for (var j = 0; j < n.outEdges.length; j++) {
  373. var e = n.outEdges[j];
  374. var queryTarget = self._getEdgeQueryTarget(graphs[i].__serie, e.data);
  375. e.shape.style.opacity = self.deepQuery(queryTarget, 'opacity');
  376. var other = graphs[0].getNodeById(e.node2.id);
  377. if (other) {
  378. if (other.shape) {
  379. other.shape.style.opacity = 1;
  380. }
  381. if (other.labelShape) {
  382. other.labelShape.style.opacity = 1;
  383. }
  384. }
  385. }
  386. }
  387. }
  388. self.zr.refreshNextFrame();
  389. };
  390. node.shape.onmouseout = function () {
  391. mainGraph.eachNode(function (n) {
  392. n.shape.style.opacity = 1;
  393. if (n.labelShape) {
  394. n.labelShape.style.opacity = 1;
  395. n.labelShape.modSelf();
  396. }
  397. n.shape.modSelf();
  398. });
  399. for (var i = 0; i < graphs.length; i++) {
  400. for (var j = 0; j < graphs[i].edges.length; j++) {
  401. var e = graphs[i].edges[j];
  402. var queryTarget = [
  403. e.data,
  404. mainSerie
  405. ];
  406. e.shape.style.opacity = self.deepQuery(queryTarget, 'itemStyle.normal.chordStyle.opacity');
  407. e.shape.modSelf();
  408. }
  409. }
  410. self.zr.refreshNextFrame();
  411. };
  412. });
  413. },
  414. _buildSectors: function (serie, serieIdx, graph, mainSerie) {
  415. var center = this.parseCenter(this.zr, mainSerie.center);
  416. var radius = this.parseRadius(this.zr, mainSerie.radius);
  417. var clockWise = mainSerie.clockWise;
  418. var sign = clockWise ? 1 : -1;
  419. graph.eachNode(function (node) {
  420. var category = this._getNodeCategory(mainSerie, node.data);
  421. var color = category ? this.getColor(category.name) : this.getColor(node.id);
  422. var startAngle = node.layout.startAngle / Math.PI * 180 * sign;
  423. var endAngle = node.layout.endAngle / Math.PI * 180 * sign;
  424. var sector = new SectorShape({
  425. zlevel: this.getZlevelBase(),
  426. z: this.getZBase(),
  427. style: {
  428. x: center[0],
  429. y: center[1],
  430. r0: radius[0],
  431. r: radius[1],
  432. startAngle: startAngle,
  433. endAngle: endAngle,
  434. brushType: 'fill',
  435. opacity: 1,
  436. color: color,
  437. clockWise: clockWise
  438. },
  439. clickable: mainSerie.clickable,
  440. highlightStyle: { brushType: 'fill' }
  441. });
  442. sector.style.lineWidth = this.deepQuery([
  443. node.data,
  444. mainSerie
  445. ], 'itemStyle.normal.borderWidth');
  446. sector.highlightStyle.lineWidth = this.deepQuery([
  447. node.data,
  448. mainSerie
  449. ], 'itemStyle.emphasis.borderWidth');
  450. sector.style.strokeColor = this.deepQuery([
  451. node.data,
  452. mainSerie
  453. ], 'itemStyle.normal.borderColor');
  454. sector.highlightStyle.strokeColor = this.deepQuery([
  455. node.data,
  456. mainSerie
  457. ], 'itemStyle.emphasis.borderColor');
  458. if (sector.style.lineWidth > 0) {
  459. sector.style.brushType = 'both';
  460. }
  461. if (sector.highlightStyle.lineWidth > 0) {
  462. sector.highlightStyle.brushType = 'both';
  463. }
  464. ecData.pack(sector, serie, serieIdx, node.data, node.rawIndex, node.id, node.category);
  465. this.shapeList.push(sector);
  466. node.shape = sector;
  467. }, this);
  468. },
  469. _buildNodeIcons: function (serie, serieIdx, graph, mainSerie) {
  470. var center = this.parseCenter(this.zr, mainSerie.center);
  471. var radius = this.parseRadius(this.zr, mainSerie.radius);
  472. var r = radius[1];
  473. graph.eachNode(function (node) {
  474. var startAngle = node.layout.startAngle;
  475. var endAngle = node.layout.endAngle;
  476. var angle = (startAngle + endAngle) / 2;
  477. var x = r * Math.cos(angle);
  478. var y = r * Math.sin(angle);
  479. var queryTarget = this._getNodeQueryTarget(mainSerie, node.data);
  480. var category = this._getNodeCategory(mainSerie, node.data);
  481. var color = this.deepQuery(queryTarget, 'itemStyle.normal.color');
  482. if (!color) {
  483. color = category ? this.getColor(category.name) : this.getColor(node.id);
  484. }
  485. var iconShape = new IconShape({
  486. zlevel: this.getZlevelBase(),
  487. z: this.getZBase() + 1,
  488. style: {
  489. x: -node.layout.size,
  490. y: -node.layout.size,
  491. width: node.layout.size * 2,
  492. height: node.layout.size * 2,
  493. iconType: this.deepQuery(queryTarget, 'symbol'),
  494. color: color,
  495. brushType: 'both',
  496. lineWidth: this.deepQuery(queryTarget, 'itemStyle.normal.borderWidth'),
  497. strokeColor: this.deepQuery(queryTarget, 'itemStyle.normal.borderColor')
  498. },
  499. highlightStyle: {
  500. color: this.deepQuery(queryTarget, 'itemStyle.emphasis.color'),
  501. lineWidth: this.deepQuery(queryTarget, 'itemStyle.emphasis.borderWidth'),
  502. strokeColor: this.deepQuery(queryTarget, 'itemStyle.emphasis.borderColor')
  503. },
  504. clickable: mainSerie.clickable,
  505. position: [
  506. x + center[0],
  507. y + center[1]
  508. ]
  509. });
  510. ecData.pack(iconShape, serie, serieIdx, node.data, node.rawIndex, node.id, node.category);
  511. this.shapeList.push(iconShape);
  512. node.shape = iconShape;
  513. }, this);
  514. },
  515. _buildLabels: function (serie, serieIdx, graph, mainSerie) {
  516. var labelColor = this.query(mainSerie, 'itemStyle.normal.label.color');
  517. var rotateLabel = this.query(mainSerie, 'itemStyle.normal.label.rotate');
  518. var labelDistance = this.query(mainSerie, 'itemStyle.normal.label.distance');
  519. var center = this.parseCenter(this.zr, mainSerie.center);
  520. var radius = this.parseRadius(this.zr, mainSerie.radius);
  521. var clockWise = mainSerie.clockWise;
  522. var sign = clockWise ? 1 : -1;
  523. graph.eachNode(function (node) {
  524. var startAngle = node.layout.startAngle / Math.PI * 180 * sign;
  525. var endAngle = node.layout.endAngle / Math.PI * 180 * sign;
  526. var angle = (startAngle * -sign + endAngle * -sign) / 2;
  527. angle %= 360;
  528. if (angle < 0) {
  529. angle += 360;
  530. }
  531. var isRightSide = angle <= 90 || angle >= 270;
  532. angle = angle * Math.PI / 180;
  533. var v = [
  534. Math.cos(angle),
  535. -Math.sin(angle)
  536. ];
  537. var distance = 0;
  538. if (mainSerie.ribbonType) {
  539. distance = mainSerie.showScaleText ? 35 + labelDistance : labelDistance;
  540. } else {
  541. distance = labelDistance + node.layout.size;
  542. }
  543. var start = vec2.scale([], v, radius[1] + distance);
  544. vec2.add(start, start, center);
  545. var labelShape = {
  546. zlevel: this.getZlevelBase(),
  547. z: this.getZBase() + 1,
  548. hoverable: false,
  549. style: {
  550. text: node.data.label == null ? node.id : node.data.label,
  551. textAlign: isRightSide ? 'left' : 'right',
  552. color: labelColor || '#000000'
  553. }
  554. };
  555. if (rotateLabel) {
  556. labelShape.rotation = isRightSide ? angle : Math.PI + angle;
  557. if (isRightSide) {
  558. labelShape.style.x = radius[1] + distance;
  559. } else {
  560. labelShape.style.x = -radius[1] - distance;
  561. }
  562. labelShape.style.y = 0;
  563. labelShape.position = center.slice();
  564. } else {
  565. labelShape.style.x = start[0];
  566. labelShape.style.y = start[1];
  567. }
  568. labelShape.style.textColor = this.deepQuery([
  569. node.data,
  570. mainSerie
  571. ], 'itemStyle.normal.label.textStyle.color') || '#fff';
  572. labelShape.style.textFont = this.getFont(this.deepQuery([
  573. node.data,
  574. mainSerie
  575. ], 'itemStyle.normal.label.textStyle'));
  576. labelShape = new TextShape(labelShape);
  577. this.shapeList.push(labelShape);
  578. node.labelShape = labelShape;
  579. }, this);
  580. },
  581. _buildRibbons: function (series, serieIdx, graph, mainSerie) {
  582. var serie = series[serieIdx];
  583. var center = this.parseCenter(this.zr, mainSerie.center);
  584. var radius = this.parseRadius(this.zr, mainSerie.radius);
  585. graph.eachEdge(function (edge, idx) {
  586. var color;
  587. var other = graph.getEdge(edge.node2, edge.node1);
  588. if (!other || edge.shape) {
  589. return;
  590. }
  591. if (other.shape) {
  592. edge.shape = other.shape;
  593. return;
  594. }
  595. var s0 = edge.layout.startAngle / Math.PI * 180;
  596. var s1 = edge.layout.endAngle / Math.PI * 180;
  597. var t0 = other.layout.startAngle / Math.PI * 180;
  598. var t1 = other.layout.endAngle / Math.PI * 180;
  599. if (series.length === 1) {
  600. if (edge.layout.weight <= other.layout.weight) {
  601. color = this.getColor(edge.node1.id);
  602. } else {
  603. color = this.getColor(edge.node2.id);
  604. }
  605. } else {
  606. color = this.getColor(serie.name);
  607. }
  608. var queryTarget = this._getEdgeQueryTarget(serie, edge.data);
  609. var queryTargetEmphasis = this._getEdgeQueryTarget(serie, edge.data, 'emphasis');
  610. var ribbon = new RibbonShape({
  611. zlevel: this.getZlevelBase(),
  612. z: this.getZBase(),
  613. style: {
  614. x: center[0],
  615. y: center[1],
  616. r: radius[0],
  617. source0: s0,
  618. source1: s1,
  619. target0: t0,
  620. target1: t1,
  621. brushType: 'both',
  622. opacity: this.deepQuery(queryTarget, 'opacity'),
  623. color: color,
  624. lineWidth: this.deepQuery(queryTarget, 'borderWidth'),
  625. strokeColor: this.deepQuery(queryTarget, 'borderColor'),
  626. clockWise: mainSerie.clockWise
  627. },
  628. clickable: mainSerie.clickable,
  629. highlightStyle: {
  630. brushType: 'both',
  631. opacity: this.deepQuery(queryTargetEmphasis, 'opacity'),
  632. lineWidth: this.deepQuery(queryTargetEmphasis, 'borderWidth'),
  633. strokeColor: this.deepQuery(queryTargetEmphasis, 'borderColor')
  634. }
  635. });
  636. var node1, node2;
  637. if (edge.layout.weight <= other.layout.weight) {
  638. node1 = other.node1;
  639. node2 = other.node2;
  640. } else {
  641. node1 = edge.node1;
  642. node2 = edge.node2;
  643. }
  644. ecData.pack(ribbon, serie, serieIdx, edge.data, edge.rawIndex == null ? idx : edge.rawIndex, edge.data.name || node1.id + '-' + node2.id, node1.id, node2.id);
  645. this.shapeList.push(ribbon);
  646. edge.shape = ribbon;
  647. }, this);
  648. },
  649. _buildEdgeCurves: function (series, serieIdx, graph, mainSerie, mainGraph) {
  650. var serie = series[serieIdx];
  651. var center = this.parseCenter(this.zr, mainSerie.center);
  652. graph.eachEdge(function (e, idx) {
  653. var node1 = mainGraph.getNodeById(e.node1.id);
  654. var node2 = mainGraph.getNodeById(e.node2.id);
  655. var shape1 = node1.shape;
  656. var shape2 = node2.shape;
  657. var queryTarget = this._getEdgeQueryTarget(serie, e.data);
  658. var queryTargetEmphasis = this._getEdgeQueryTarget(serie, e.data, 'emphasis');
  659. var curveShape = new BezierCurveShape({
  660. zlevel: this.getZlevelBase(),
  661. z: this.getZBase(),
  662. style: {
  663. xStart: shape1.position[0],
  664. yStart: shape1.position[1],
  665. xEnd: shape2.position[0],
  666. yEnd: shape2.position[1],
  667. cpX1: center[0],
  668. cpY1: center[1],
  669. lineWidth: this.deepQuery(queryTarget, 'width'),
  670. strokeColor: this.deepQuery(queryTarget, 'color'),
  671. opacity: this.deepQuery(queryTarget, 'opacity')
  672. },
  673. highlightStyle: {
  674. lineWidth: this.deepQuery(queryTargetEmphasis, 'width'),
  675. strokeColor: this.deepQuery(queryTargetEmphasis, 'color'),
  676. opacity: this.deepQuery(queryTargetEmphasis, 'opacity')
  677. }
  678. });
  679. ecData.pack(curveShape, serie, serieIdx, e.data, e.rawIndex == null ? idx : e.rawIndex, e.data.name || e.node1.id + '-' + e.node2.id, e.node1.id, e.node2.id);
  680. this.shapeList.push(curveShape);
  681. e.shape = curveShape;
  682. }, this);
  683. },
  684. _buildScales: function (serie, serieIdx, graph) {
  685. var clockWise = serie.clockWise;
  686. var center = this.parseCenter(this.zr, serie.center);
  687. var radius = this.parseRadius(this.zr, serie.radius);
  688. var sign = clockWise ? 1 : -1;
  689. var sumValue = 0;
  690. var maxValue = -Infinity;
  691. var unitPostfix;
  692. var unitScale;
  693. if (serie.showScaleText) {
  694. graph.eachNode(function (node) {
  695. var val = node.data.value;
  696. if (val > maxValue) {
  697. maxValue = val;
  698. }
  699. sumValue += val;
  700. });
  701. if (maxValue > 10000000000) {
  702. unitPostfix = 'b';
  703. unitScale = 1e-9;
  704. } else if (maxValue > 10000000) {
  705. unitPostfix = 'm';
  706. unitScale = 0.000001;
  707. } else if (maxValue > 10000) {
  708. unitPostfix = 'k';
  709. unitScale = 0.001;
  710. } else {
  711. unitPostfix = '';
  712. unitScale = 1;
  713. }
  714. }
  715. var unitValue = sumValue / (360 - serie.padding);
  716. graph.eachNode(function (node) {
  717. var startAngle = node.layout.startAngle / Math.PI * 180;
  718. var endAngle = node.layout.endAngle / Math.PI * 180;
  719. var scaleAngle = startAngle;
  720. while (true) {
  721. if (clockWise && scaleAngle > endAngle || !clockWise && scaleAngle < endAngle) {
  722. break;
  723. }
  724. var theta = scaleAngle / 180 * Math.PI;
  725. var v = [
  726. Math.cos(theta),
  727. Math.sin(theta)
  728. ];
  729. var start = vec2.scale([], v, radius[1] + 1);
  730. vec2.add(start, start, center);
  731. var end = vec2.scale([], v, radius[1] + this.scaleLineLength);
  732. vec2.add(end, end, center);
  733. var scaleShape = new LineShape({
  734. zlevel: this.getZlevelBase(),
  735. z: this.getZBase() - 1,
  736. hoverable: false,
  737. style: {
  738. xStart: start[0],
  739. yStart: start[1],
  740. xEnd: end[0],
  741. yEnd: end[1],
  742. lineCap: 'round',
  743. brushType: 'stroke',
  744. strokeColor: '#666',
  745. lineWidth: 1
  746. }
  747. });
  748. this.shapeList.push(scaleShape);
  749. scaleAngle += sign * this.scaleUnitAngle;
  750. }
  751. if (!serie.showScaleText) {
  752. return;
  753. }
  754. var scaleTextAngle = startAngle;
  755. var step = unitValue * 5 * this.scaleUnitAngle;
  756. var scaleValue = 0;
  757. while (true) {
  758. if (clockWise && scaleTextAngle > endAngle || !clockWise && scaleTextAngle < endAngle) {
  759. break;
  760. }
  761. var theta = scaleTextAngle;
  762. theta = theta % 360;
  763. if (theta < 0) {
  764. theta += 360;
  765. }
  766. var isRightSide = theta <= 90 || theta >= 270;
  767. var textShape = new TextShape({
  768. zlevel: this.getZlevelBase(),
  769. z: this.getZBase() - 1,
  770. hoverable: false,
  771. style: {
  772. x: isRightSide ? radius[1] + this.scaleLineLength + 4 : -radius[1] - this.scaleLineLength - 4,
  773. y: 0,
  774. text: Math.round(scaleValue * 10) / 10 + unitPostfix,
  775. textAlign: isRightSide ? 'left' : 'right'
  776. },
  777. position: center.slice(),
  778. rotation: isRightSide ? [
  779. -theta / 180 * Math.PI,
  780. 0,
  781. 0
  782. ] : [
  783. -(theta + 180) / 180 * Math.PI,
  784. 0,
  785. 0
  786. ]
  787. });
  788. this.shapeList.push(textShape);
  789. scaleValue += step * unitScale;
  790. scaleTextAngle += sign * this.scaleUnitAngle * 5;
  791. }
  792. }, this);
  793. },
  794. refresh: function (newOption) {
  795. if (newOption) {
  796. this.option = newOption;
  797. this.series = newOption.series;
  798. }
  799. this.legend = this.component.legend;
  800. if (this.legend) {
  801. this.getColor = function (param) {
  802. return this.legend.getColor(param);
  803. };
  804. this.isSelected = function (param) {
  805. return this.legend.isSelected(param);
  806. };
  807. } else {
  808. var colorMap = {};
  809. var count = 0;
  810. this.getColor = function (key) {
  811. if (colorMap[key]) {
  812. return colorMap[key];
  813. }
  814. if (!colorMap[key]) {
  815. colorMap[key] = this.zr.getColor(count++);
  816. }
  817. return colorMap[key];
  818. };
  819. this.isSelected = function () {
  820. return true;
  821. };
  822. }
  823. this.backupShapeList();
  824. this._init();
  825. },
  826. reformOption: function (opt) {
  827. var _merge = zrUtil.merge;
  828. opt = _merge(_merge(opt || {}, this.ecTheme.chord), ecConfig.chord);
  829. opt.itemStyle.normal.label.textStyle = this.getTextStyle(opt.itemStyle.normal.label.textStyle);
  830. this.z = opt.z;
  831. this.zlevel = opt.zlevel;
  832. }
  833. };
  834. zrUtil.inherits(Chord, ChartBase);
  835. require('../chart').define('chord', Chord);
  836. return Chord;
  837. });define('echarts/util/shape/Ribbon', [
  838. 'require',
  839. 'zrender/shape/Base',
  840. 'zrender/shape/util/PathProxy',
  841. 'zrender/tool/util',
  842. 'zrender/tool/area'
  843. ], function (require) {
  844. var Base = require('zrender/shape/Base');
  845. var PathProxy = require('zrender/shape/util/PathProxy');
  846. var zrUtil = require('zrender/tool/util');
  847. var area = require('zrender/tool/area');
  848. function RibbonShape(options) {
  849. Base.call(this, options);
  850. this._pathProxy = new PathProxy();
  851. }
  852. RibbonShape.prototype = {
  853. type: 'ribbon',
  854. buildPath: function (ctx, style) {
  855. var clockWise = style.clockWise || false;
  856. var path = this._pathProxy;
  857. path.begin(ctx);
  858. var cx = style.x;
  859. var cy = style.y;
  860. var r = style.r;
  861. var s0 = style.source0 / 180 * Math.PI;
  862. var s1 = style.source1 / 180 * Math.PI;
  863. var t0 = style.target0 / 180 * Math.PI;
  864. var t1 = style.target1 / 180 * Math.PI;
  865. var sx0 = cx + Math.cos(s0) * r;
  866. var sy0 = cy + Math.sin(s0) * r;
  867. var sx1 = cx + Math.cos(s1) * r;
  868. var sy1 = cy + Math.sin(s1) * r;
  869. var tx0 = cx + Math.cos(t0) * r;
  870. var ty0 = cy + Math.sin(t0) * r;
  871. var tx1 = cx + Math.cos(t1) * r;
  872. var ty1 = cy + Math.sin(t1) * r;
  873. path.moveTo(sx0, sy0);
  874. path.arc(cx, cy, style.r, s0, s1, !clockWise);
  875. path.bezierCurveTo((cx - sx1) * 0.7 + sx1, (cy - sy1) * 0.7 + sy1, (cx - tx0) * 0.7 + tx0, (cy - ty0) * 0.7 + ty0, tx0, ty0);
  876. if (style.source0 === style.target0 && style.source1 === style.target1) {
  877. return;
  878. }
  879. path.arc(cx, cy, style.r, t0, t1, !clockWise);
  880. path.bezierCurveTo((cx - tx1) * 0.7 + tx1, (cy - ty1) * 0.7 + ty1, (cx - sx0) * 0.7 + sx0, (cy - sy0) * 0.7 + sy0, sx0, sy0);
  881. },
  882. getRect: function (style) {
  883. if (style.__rect) {
  884. return style.__rect;
  885. }
  886. if (!this._pathProxy.isEmpty()) {
  887. this.buildPath(null, style);
  888. }
  889. return this._pathProxy.fastBoundingRect();
  890. },
  891. isCover: function (x, y) {
  892. var rect = this.getRect(this.style);
  893. if (x >= rect.x && x <= rect.x + rect.width && y >= rect.y && y <= rect.y + rect.height) {
  894. return area.isInsidePath(this._pathProxy.pathCommands, 0, 'fill', x, y);
  895. }
  896. }
  897. };
  898. zrUtil.inherits(RibbonShape, Base);
  899. return RibbonShape;
  900. });define('echarts/data/Graph', [
  901. 'require',
  902. 'zrender/tool/util'
  903. ], function (require) {
  904. var util = require('zrender/tool/util');
  905. 'use strict';
  906. var Graph = function (directed) {
  907. this._directed = directed || false;
  908. this.nodes = [];
  909. this.edges = [];
  910. this._nodesMap = {};
  911. this._edgesMap = {};
  912. };
  913. Graph.prototype.isDirected = function () {
  914. return this._directed;
  915. };
  916. Graph.prototype.addNode = function (id, data) {
  917. if (this._nodesMap[id]) {
  918. return this._nodesMap[id];
  919. }
  920. var node = new Graph.Node(id, data);
  921. this.nodes.push(node);
  922. this._nodesMap[id] = node;
  923. return node;
  924. };
  925. Graph.prototype.getNodeById = function (id) {
  926. return this._nodesMap[id];
  927. };
  928. Graph.prototype.addEdge = function (n1, n2, data) {
  929. if (typeof n1 == 'string') {
  930. n1 = this._nodesMap[n1];
  931. }
  932. if (typeof n2 == 'string') {
  933. n2 = this._nodesMap[n2];
  934. }
  935. if (!n1 || !n2) {
  936. return;
  937. }
  938. var key = n1.id + '-' + n2.id;
  939. if (this._edgesMap[key]) {
  940. return this._edgesMap[key];
  941. }
  942. var edge = new Graph.Edge(n1, n2, data);
  943. if (this._directed) {
  944. n1.outEdges.push(edge);
  945. n2.inEdges.push(edge);
  946. }
  947. n1.edges.push(edge);
  948. if (n1 !== n2) {
  949. n2.edges.push(edge);
  950. }
  951. this.edges.push(edge);
  952. this._edgesMap[key] = edge;
  953. return edge;
  954. };
  955. Graph.prototype.removeEdge = function (edge) {
  956. var n1 = edge.node1;
  957. var n2 = edge.node2;
  958. var key = n1.id + '-' + n2.id;
  959. if (this._directed) {
  960. n1.outEdges.splice(util.indexOf(n1.outEdges, edge), 1);
  961. n2.inEdges.splice(util.indexOf(n2.inEdges, edge), 1);
  962. }
  963. n1.edges.splice(util.indexOf(n1.edges, edge), 1);
  964. if (n1 !== n2) {
  965. n2.edges.splice(util.indexOf(n2.edges, edge), 1);
  966. }
  967. delete this._edgesMap[key];
  968. this.edges.splice(util.indexOf(this.edges, edge), 1);
  969. };
  970. Graph.prototype.getEdge = function (n1, n2) {
  971. if (typeof n1 !== 'string') {
  972. n1 = n1.id;
  973. }
  974. if (typeof n2 !== 'string') {
  975. n2 = n2.id;
  976. }
  977. if (this._directed) {
  978. return this._edgesMap[n1 + '-' + n2];
  979. } else {
  980. return this._edgesMap[n1 + '-' + n2] || this._edgesMap[n2 + '-' + n1];
  981. }
  982. };
  983. Graph.prototype.removeNode = function (node) {
  984. if (typeof node === 'string') {
  985. node = this._nodesMap[node];
  986. if (!node) {
  987. return;
  988. }
  989. }
  990. delete this._nodesMap[node.id];
  991. this.nodes.splice(util.indexOf(this.nodes, node), 1);
  992. for (var i = 0; i < this.edges.length;) {
  993. var edge = this.edges[i];
  994. if (edge.node1 === node || edge.node2 === node) {
  995. this.removeEdge(edge);
  996. } else {
  997. i++;
  998. }
  999. }
  1000. };
  1001. Graph.prototype.filterNode = function (cb, context) {
  1002. var len = this.nodes.length;
  1003. for (var i = 0; i < len;) {
  1004. if (cb.call(context, this.nodes[i], i)) {
  1005. i++;
  1006. } else {
  1007. this.removeNode(this.nodes[i]);
  1008. len--;
  1009. }
  1010. }
  1011. };
  1012. Graph.prototype.filterEdge = function (cb, context) {
  1013. var len = this.edges.length;
  1014. for (var i = 0; i < len;) {
  1015. if (cb.call(context, this.edges[i], i)) {
  1016. i++;
  1017. } else {
  1018. this.removeEdge(this.edges[i]);
  1019. len--;
  1020. }
  1021. }
  1022. };
  1023. Graph.prototype.eachNode = function (cb, context) {
  1024. var len = this.nodes.length;
  1025. for (var i = 0; i < len; i++) {
  1026. if (this.nodes[i]) {
  1027. cb.call(context, this.nodes[i], i);
  1028. }
  1029. }
  1030. };
  1031. Graph.prototype.eachEdge = function (cb, context) {
  1032. var len = this.edges.length;
  1033. for (var i = 0; i < len; i++) {
  1034. if (this.edges[i]) {
  1035. cb.call(context, this.edges[i], i);
  1036. }
  1037. }
  1038. };
  1039. Graph.prototype.clear = function () {
  1040. this.nodes.length = 0;
  1041. this.edges.length = 0;
  1042. this._nodesMap = {};
  1043. this._edgesMap = {};
  1044. };
  1045. Graph.prototype.breadthFirstTraverse = function (cb, startNode, direction, context) {
  1046. if (typeof startNode === 'string') {
  1047. startNode = this._nodesMap[startNode];
  1048. }
  1049. if (!startNode) {
  1050. return;
  1051. }
  1052. var edgeType = 'edges';
  1053. if (direction === 'out') {
  1054. edgeType = 'outEdges';
  1055. } else if (direction === 'in') {
  1056. edgeType = 'inEdges';
  1057. }
  1058. for (var i = 0; i < this.nodes.length; i++) {
  1059. this.nodes[i].__visited = false;
  1060. }
  1061. if (cb.call(context, startNode, null)) {
  1062. return;
  1063. }
  1064. var queue = [startNode];
  1065. while (queue.length) {
  1066. var currentNode = queue.shift();
  1067. var edges = currentNode[edgeType];
  1068. for (var i = 0; i < edges.length; i++) {
  1069. var e = edges[i];
  1070. var otherNode = e.node1 === currentNode ? e.node2 : e.node1;
  1071. if (!otherNode.__visited) {
  1072. if (cb.call(otherNode, otherNode, currentNode)) {
  1073. return;
  1074. }
  1075. queue.push(otherNode);
  1076. otherNode.__visited = true;
  1077. }
  1078. }
  1079. }
  1080. };
  1081. Graph.prototype.clone = function () {
  1082. var graph = new Graph(this._directed);
  1083. for (var i = 0; i < this.nodes.length; i++) {
  1084. graph.addNode(this.nodes[i].id, this.nodes[i].data);
  1085. }
  1086. for (var i = 0; i < this.edges.length; i++) {
  1087. var e = this.edges[i];
  1088. graph.addEdge(e.node1.id, e.node2.id, e.data);
  1089. }
  1090. return graph;
  1091. };
  1092. var Node = function (id, data) {
  1093. this.id = id;
  1094. this.data = data || null;
  1095. this.inEdges = [];
  1096. this.outEdges = [];
  1097. this.edges = [];
  1098. };
  1099. Node.prototype.degree = function () {
  1100. return this.edges.length;
  1101. };
  1102. Node.prototype.inDegree = function () {
  1103. return this.inEdges.length;
  1104. };
  1105. Node.prototype.outDegree = function () {
  1106. return this.outEdges.length;
  1107. };
  1108. var Edge = function (node1, node2, data) {
  1109. this.node1 = node1;
  1110. this.node2 = node2;
  1111. this.data = data || null;
  1112. };
  1113. Graph.Node = Node;
  1114. Graph.Edge = Edge;
  1115. Graph.fromMatrix = function (nodesData, matrix, directed) {
  1116. if (!matrix || !matrix.length || matrix[0].length !== matrix.length || nodesData.length !== matrix.length) {
  1117. return;
  1118. }
  1119. var size = matrix.length;
  1120. var graph = new Graph(directed);
  1121. for (var i = 0; i < size; i++) {
  1122. var node = graph.addNode(nodesData[i].id, nodesData[i]);
  1123. node.data.value = 0;
  1124. if (directed) {
  1125. node.data.outValue = node.data.inValue = 0;
  1126. }
  1127. }
  1128. for (var i = 0; i < size; i++) {
  1129. for (var j = 0; j < size; j++) {
  1130. var item = matrix[i][j];
  1131. if (directed) {
  1132. graph.nodes[i].data.outValue += item;
  1133. graph.nodes[j].data.inValue += item;
  1134. }
  1135. graph.nodes[i].data.value += item;
  1136. graph.nodes[j].data.value += item;
  1137. }
  1138. }
  1139. for (var i = 0; i < size; i++) {
  1140. for (var j = i; j < size; j++) {
  1141. var item = matrix[i][j];
  1142. if (item === 0) {
  1143. continue;
  1144. }
  1145. var n1 = graph.nodes[i];
  1146. var n2 = graph.nodes[j];
  1147. var edge = graph.addEdge(n1, n2, {});
  1148. edge.data.weight = item;
  1149. if (i !== j) {
  1150. if (directed && matrix[j][i]) {
  1151. var inEdge = graph.addEdge(n2, n1, {});
  1152. inEdge.data.weight = matrix[j][i];
  1153. }
  1154. }
  1155. }
  1156. }
  1157. return graph;
  1158. };
  1159. return Graph;
  1160. });define('echarts/layout/Chord', ['require'], function (require) {
  1161. var ChordLayout = function (opts) {
  1162. opts = opts || {};
  1163. this.sort = opts.sort || null;
  1164. this.sortSub = opts.sortSub || null;
  1165. this.padding = 0.05;
  1166. this.startAngle = opts.startAngle || 0;
  1167. this.clockWise = opts.clockWise == null ? false : opts.clockWise;
  1168. this.center = opts.center || [
  1169. 0,
  1170. 0
  1171. ];
  1172. this.directed = true;
  1173. };
  1174. ChordLayout.prototype.run = function (graphs) {
  1175. if (!(graphs instanceof Array)) {
  1176. graphs = [graphs];
  1177. }
  1178. var gl = graphs.length;
  1179. if (!gl) {
  1180. return;
  1181. }
  1182. var graph0 = graphs[0];
  1183. var nl = graph0.nodes.length;
  1184. var groups = [];
  1185. var sumSize = 0;
  1186. for (var i = 0; i < nl; i++) {
  1187. var g0node = graph0.nodes[i];
  1188. var group = {
  1189. size: 0,
  1190. subGroups: [],
  1191. node: g0node
  1192. };
  1193. groups.push(group);
  1194. var sumWeight = 0;
  1195. for (var k = 0; k < graphs.length; k++) {
  1196. var graph = graphs[k];
  1197. var node = graph.getNodeById(g0node.id);
  1198. if (!node) {
  1199. continue;
  1200. }
  1201. group.size += node.layout.size;
  1202. var edges = this.directed ? node.outEdges : node.edges;
  1203. for (var j = 0; j < edges.length; j++) {
  1204. var e = edges[j];
  1205. var w = e.layout.weight;
  1206. group.subGroups.push({
  1207. weight: w,
  1208. edge: e,
  1209. graph: graph
  1210. });
  1211. sumWeight += w;
  1212. }
  1213. }
  1214. sumSize += group.size;
  1215. var multiplier = group.size / sumWeight;
  1216. for (var j = 0; j < group.subGroups.length; j++) {
  1217. group.subGroups[j].weight *= multiplier;
  1218. }
  1219. if (this.sortSub === 'ascending') {
  1220. group.subGroups.sort(compareSubGroups);
  1221. } else if (this.sort === 'descending') {
  1222. group.subGroups.sort(compareSubGroups);
  1223. group.subGroups.reverse();
  1224. }
  1225. }
  1226. if (this.sort === 'ascending') {
  1227. groups.sort(compareGroups);
  1228. } else if (this.sort === 'descending') {
  1229. groups.sort(compareGroups);
  1230. groups.reverse();
  1231. }
  1232. var multiplier = (Math.PI * 2 - this.padding * nl) / sumSize;
  1233. var angle = this.startAngle;
  1234. var sign = this.clockWise ? 1 : -1;
  1235. for (var i = 0; i < nl; i++) {
  1236. var group = groups[i];
  1237. group.node.layout.startAngle = angle;
  1238. group.node.layout.endAngle = angle + sign * group.size * multiplier;
  1239. group.node.layout.subGroups = [];
  1240. for (var j = 0; j < group.subGroups.length; j++) {
  1241. var subGroup = group.subGroups[j];
  1242. subGroup.edge.layout.startAngle = angle;
  1243. angle += sign * subGroup.weight * multiplier;
  1244. subGroup.edge.layout.endAngle = angle;
  1245. }
  1246. angle = group.node.layout.endAngle + sign * this.padding;
  1247. }
  1248. };
  1249. var compareSubGroups = function (a, b) {
  1250. return a.weight - b.weight;
  1251. };
  1252. var compareGroups = function (a, b) {
  1253. return a.size - b.size;
  1254. };
  1255. return ChordLayout;
  1256. });