force.js 64 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697
  1. define('echarts/chart/force', [
  2. 'require',
  3. './base',
  4. '../data/Graph',
  5. '../layout/Force',
  6. 'zrender/shape/Line',
  7. 'zrender/shape/BezierCurve',
  8. 'zrender/shape/Image',
  9. '../util/shape/Icon',
  10. '../config',
  11. '../util/ecData',
  12. 'zrender/tool/util',
  13. 'zrender/config',
  14. 'zrender/tool/vector',
  15. '../chart'
  16. ], function (require) {
  17. 'use strict';
  18. var ChartBase = require('./base');
  19. var Graph = require('../data/Graph');
  20. var ForceLayout = require('../layout/Force');
  21. var LineShape = require('zrender/shape/Line');
  22. var BezierCurveShape = require('zrender/shape/BezierCurve');
  23. var ImageShape = require('zrender/shape/Image');
  24. var IconShape = require('../util/shape/Icon');
  25. var ecConfig = require('../config');
  26. ecConfig.force = {
  27. zlevel: 1,
  28. z: 2,
  29. center: [
  30. '50%',
  31. '50%'
  32. ],
  33. size: '100%',
  34. preventOverlap: false,
  35. coolDown: 0.99,
  36. minRadius: 10,
  37. maxRadius: 20,
  38. ratioScaling: false,
  39. large: false,
  40. useWorker: false,
  41. steps: 1,
  42. scaling: 1,
  43. gravity: 1,
  44. symbol: 'circle',
  45. symbolSize: 0,
  46. linkSymbol: null,
  47. linkSymbolSize: [
  48. 10,
  49. 15
  50. ],
  51. draggable: true,
  52. clickable: true,
  53. roam: false,
  54. itemStyle: {
  55. normal: {
  56. label: {
  57. show: false,
  58. position: 'inside'
  59. },
  60. nodeStyle: {
  61. brushType: 'both',
  62. borderColor: '#5182ab',
  63. borderWidth: 1
  64. },
  65. linkStyle: {
  66. color: '#5182ab',
  67. width: 1,
  68. type: 'line'
  69. }
  70. },
  71. emphasis: {
  72. label: { show: false },
  73. nodeStyle: {},
  74. linkStyle: { opacity: 0 }
  75. }
  76. }
  77. };
  78. var ecData = require('../util/ecData');
  79. var zrUtil = require('zrender/tool/util');
  80. var zrConfig = require('zrender/config');
  81. var vec2 = require('zrender/tool/vector');
  82. function Force(ecTheme, messageCenter, zr, option, myChart) {
  83. var self = this;
  84. ChartBase.call(this, ecTheme, messageCenter, zr, option, myChart);
  85. this.__nodePositionMap = {};
  86. this._graph = new Graph(true);
  87. this._layout = new ForceLayout();
  88. this._layout.onupdate = function () {
  89. self._step();
  90. };
  91. this._steps = 1;
  92. this.ondragstart = function () {
  93. ondragstart.apply(self, arguments);
  94. };
  95. this.ondragend = function () {
  96. ondragend.apply(self, arguments);
  97. };
  98. this.ondrop = function () {
  99. };
  100. this.shapeHandler.ondragstart = function () {
  101. self.isDragstart = true;
  102. };
  103. this.onmousemove = function () {
  104. onmousemove.apply(self, arguments);
  105. };
  106. this.refresh(option);
  107. }
  108. Force.prototype = {
  109. constructor: Force,
  110. type: ecConfig.CHART_TYPE_FORCE,
  111. _init: function () {
  112. this.selectedMap = {};
  113. var legend = this.component.legend;
  114. var series = this.series;
  115. var serieName;
  116. this.clear();
  117. for (var i = 0, l = series.length; i < l; i++) {
  118. var serie = series[i];
  119. if (serie.type === ecConfig.CHART_TYPE_FORCE) {
  120. series[i] = this.reformOption(series[i]);
  121. serieName = series[i].name || '';
  122. this.selectedMap[serieName] = legend ? legend.isSelected(serieName) : true;
  123. if (!this.selectedMap[serieName]) {
  124. continue;
  125. }
  126. this.buildMark(i);
  127. this._initSerie(serie, i);
  128. break;
  129. }
  130. }
  131. this.animationEffect();
  132. },
  133. _getNodeCategory: function (serie, node) {
  134. return serie.categories && serie.categories[node.category || 0];
  135. },
  136. _getNodeQueryTarget: function (serie, node, type) {
  137. type = type || 'normal';
  138. var category = this._getNodeCategory(serie, node) || {};
  139. return [
  140. node.itemStyle && node.itemStyle[type],
  141. category && category.itemStyle && category.itemStyle[type],
  142. serie.itemStyle[type].nodeStyle
  143. ];
  144. },
  145. _getEdgeQueryTarget: function (serie, edge, type) {
  146. type = type || 'normal';
  147. return [
  148. edge.itemStyle && edge.itemStyle[type],
  149. serie.itemStyle[type].linkStyle
  150. ];
  151. },
  152. _initSerie: function (serie, serieIdx) {
  153. this._temperature = 1;
  154. if (serie.matrix) {
  155. this._graph = this._getSerieGraphFromDataMatrix(serie);
  156. } else if (serie.links) {
  157. this._graph = this._getSerieGraphFromNodeLinks(serie);
  158. }
  159. this._buildLinkShapes(serie, serieIdx);
  160. this._buildNodeShapes(serie, serieIdx);
  161. var panable = serie.roam === true || serie.roam === 'move';
  162. var zoomable = serie.roam === true || serie.roam === 'scale';
  163. this.zr.modLayer(this.getZlevelBase(), {
  164. panable: panable,
  165. zoomable: zoomable
  166. });
  167. if (this.query('markPoint.effect.show') || this.query('markLine.effect.show')) {
  168. this.zr.modLayer(ecConfig.EFFECT_ZLEVEL, {
  169. panable: panable,
  170. zoomable: zoomable
  171. });
  172. }
  173. this._initLayout(serie);
  174. this._step();
  175. },
  176. _getSerieGraphFromDataMatrix: function (serie) {
  177. var nodesData = [];
  178. var count = 0;
  179. var matrix = [];
  180. for (var i = 0; i < serie.matrix.length; i++) {
  181. matrix[i] = serie.matrix[i].slice();
  182. }
  183. var data = serie.data || serie.nodes;
  184. for (var i = 0; i < data.length; i++) {
  185. var node = {};
  186. var group = data[i];
  187. for (var key in group) {
  188. if (key === 'name') {
  189. node['id'] = group['name'];
  190. } else {
  191. node[key] = group[key];
  192. }
  193. }
  194. var category = this._getNodeCategory(serie, group);
  195. var name = category ? category.name : group.name;
  196. this.selectedMap[name] = this.isSelected(name);
  197. if (this.selectedMap[name]) {
  198. nodesData.push(node);
  199. count++;
  200. } else {
  201. matrix.splice(count, 1);
  202. for (var j = 0; j < matrix.length; j++) {
  203. matrix[j].splice(count, 1);
  204. }
  205. }
  206. }
  207. var graph = Graph.fromMatrix(nodesData, matrix, true);
  208. graph.eachNode(function (n, idx) {
  209. n.layout = {
  210. size: n.data.value,
  211. mass: 0
  212. };
  213. n.rawIndex = idx;
  214. });
  215. graph.eachEdge(function (e) {
  216. e.layout = { weight: e.data.weight };
  217. });
  218. return graph;
  219. },
  220. _getSerieGraphFromNodeLinks: function (serie) {
  221. var graph = new Graph(true);
  222. var nodes = serie.data || serie.nodes;
  223. for (var i = 0, len = nodes.length; i < len; i++) {
  224. var n = nodes[i];
  225. if (!n || n.ignore) {
  226. continue;
  227. }
  228. var category = this._getNodeCategory(serie, n);
  229. var name = category ? category.name : n.name;
  230. this.selectedMap[name] = this.isSelected(name);
  231. if (this.selectedMap[name]) {
  232. var node = graph.addNode(n.name, n);
  233. node.rawIndex = i;
  234. }
  235. }
  236. for (var i = 0, len = serie.links.length; i < len; i++) {
  237. var e = serie.links[i];
  238. var n1 = e.source;
  239. var n2 = e.target;
  240. if (typeof n1 === 'number') {
  241. n1 = nodes[n1];
  242. if (n1) {
  243. n1 = n1.name;
  244. }
  245. }
  246. if (typeof n2 === 'number') {
  247. n2 = nodes[n2];
  248. if (n2) {
  249. n2 = n2.name;
  250. }
  251. }
  252. var edge = graph.addEdge(n1, n2, e);
  253. if (edge) {
  254. edge.rawIndex = i;
  255. }
  256. }
  257. graph.eachNode(function (n) {
  258. var value = n.data.value;
  259. if (value == null) {
  260. value = 0;
  261. for (var i = 0; i < n.edges.length; i++) {
  262. value += n.edges[i].data.weight || 0;
  263. }
  264. }
  265. n.layout = {
  266. size: value,
  267. mass: 0
  268. };
  269. });
  270. graph.eachEdge(function (e) {
  271. e.layout = { weight: e.data.weight == null ? 1 : e.data.weight };
  272. });
  273. return graph;
  274. },
  275. _initLayout: function (serie) {
  276. var graph = this._graph;
  277. var len = graph.nodes.length;
  278. var minRadius = this.query(serie, 'minRadius');
  279. var maxRadius = this.query(serie, 'maxRadius');
  280. this._steps = serie.steps || 1;
  281. var layout = this._layout;
  282. layout.center = this.parseCenter(this.zr, serie.center);
  283. layout.width = this.parsePercent(serie.size, this.zr.getWidth());
  284. layout.height = this.parsePercent(serie.size, this.zr.getHeight());
  285. layout.large = serie.large;
  286. layout.scaling = serie.scaling;
  287. layout.ratioScaling = serie.ratioScaling;
  288. layout.gravity = serie.gravity;
  289. layout.temperature = 1;
  290. layout.coolDown = serie.coolDown;
  291. layout.preventNodeEdgeOverlap = serie.preventOverlap;
  292. layout.preventNodeOverlap = serie.preventOverlap;
  293. var min = Infinity;
  294. var max = -Infinity;
  295. for (var i = 0; i < len; i++) {
  296. var gNode = graph.nodes[i];
  297. max = Math.max(gNode.layout.size, max);
  298. min = Math.min(gNode.layout.size, min);
  299. }
  300. var divider = max - min;
  301. for (var i = 0; i < len; i++) {
  302. var gNode = graph.nodes[i];
  303. if (divider > 0) {
  304. gNode.layout.size = (gNode.layout.size - min) * (maxRadius - minRadius) / divider + minRadius;
  305. gNode.layout.mass = gNode.layout.size / maxRadius;
  306. } else {
  307. gNode.layout.size = (maxRadius - minRadius) / 2;
  308. gNode.layout.mass = 0.5;
  309. }
  310. }
  311. for (var i = 0; i < len; i++) {
  312. var gNode = graph.nodes[i];
  313. if (typeof this.__nodePositionMap[gNode.id] !== 'undefined') {
  314. gNode.layout.position = vec2.create();
  315. vec2.copy(gNode.layout.position, this.__nodePositionMap[gNode.id]);
  316. } else if (typeof gNode.data.initial !== 'undefined') {
  317. gNode.layout.position = vec2.create();
  318. vec2.copy(gNode.layout.position, gNode.data.initial);
  319. } else {
  320. var center = this._layout.center;
  321. var size = Math.min(this._layout.width, this._layout.height);
  322. gNode.layout.position = _randomInSquare(center[0], center[1], size * 0.8);
  323. }
  324. var style = gNode.shape.style;
  325. var radius = gNode.layout.size;
  326. style.width = style.width || radius * 2;
  327. style.height = style.height || radius * 2;
  328. style.x = -style.width / 2;
  329. style.y = -style.height / 2;
  330. vec2.copy(gNode.shape.position, gNode.layout.position);
  331. }
  332. len = graph.edges.length;
  333. max = -Infinity;
  334. for (var i = 0; i < len; i++) {
  335. var e = graph.edges[i];
  336. if (e.layout.weight > max) {
  337. max = e.layout.weight;
  338. }
  339. }
  340. for (var i = 0; i < len; i++) {
  341. var e = graph.edges[i];
  342. e.layout.weight /= max;
  343. }
  344. this._layout.init(graph, serie.useWorker);
  345. },
  346. _buildNodeShapes: function (serie, serieIdx) {
  347. var graph = this._graph;
  348. var categories = this.query(serie, 'categories');
  349. graph.eachNode(function (node) {
  350. var category = this._getNodeCategory(serie, node.data);
  351. var queryTarget = [
  352. node.data,
  353. category,
  354. serie
  355. ];
  356. var styleQueryTarget = this._getNodeQueryTarget(serie, node.data);
  357. var emphasisStyleQueryTarget = this._getNodeQueryTarget(serie, node.data, 'emphasis');
  358. var shape = new IconShape({
  359. style: {
  360. x: 0,
  361. y: 0,
  362. color: this.deepQuery(styleQueryTarget, 'color'),
  363. brushType: 'both',
  364. strokeColor: this.deepQuery(styleQueryTarget, 'strokeColor') || this.deepQuery(styleQueryTarget, 'borderColor'),
  365. lineWidth: this.deepQuery(styleQueryTarget, 'lineWidth') || this.deepQuery(styleQueryTarget, 'borderWidth')
  366. },
  367. highlightStyle: {
  368. color: this.deepQuery(emphasisStyleQueryTarget, 'color'),
  369. strokeColor: this.deepQuery(emphasisStyleQueryTarget, 'strokeColor') || this.deepQuery(emphasisStyleQueryTarget, 'borderColor'),
  370. lineWidth: this.deepQuery(emphasisStyleQueryTarget, 'lineWidth') || this.deepQuery(emphasisStyleQueryTarget, 'borderWidth')
  371. },
  372. clickable: serie.clickable,
  373. zlevel: this.getZlevelBase(),
  374. z: this.getZBase()
  375. });
  376. if (!shape.style.color) {
  377. shape.style.color = category ? this.getColor(category.name) : this.getColor(node.id);
  378. }
  379. shape.style.iconType = this.deepQuery(queryTarget, 'symbol');
  380. var symbolSize = this.deepQuery(queryTarget, 'symbolSize') || 0;
  381. if (typeof symbolSize === 'number') {
  382. symbolSize = [
  383. symbolSize,
  384. symbolSize
  385. ];
  386. }
  387. shape.style.width = symbolSize[0] * 2;
  388. shape.style.height = symbolSize[1] * 2;
  389. if (shape.style.iconType.match('image')) {
  390. shape.style.image = shape.style.iconType.replace(new RegExp('^image:\\/\\/'), '');
  391. shape = new ImageShape({
  392. style: shape.style,
  393. highlightStyle: shape.highlightStyle,
  394. clickable: shape.clickable,
  395. zlevel: this.getZlevelBase(),
  396. z: this.getZBase()
  397. });
  398. }
  399. if (this.deepQuery(queryTarget, 'itemStyle.normal.label.show')) {
  400. shape.style.text = node.data.label == null ? node.id : node.data.label;
  401. shape.style.textPosition = this.deepQuery(queryTarget, 'itemStyle.normal.label.position');
  402. shape.style.textColor = this.deepQuery(queryTarget, 'itemStyle.normal.label.textStyle.color');
  403. shape.style.textFont = this.getFont(this.deepQuery(queryTarget, 'itemStyle.normal.label.textStyle') || {});
  404. }
  405. if (this.deepQuery(queryTarget, 'itemStyle.emphasis.label.show')) {
  406. shape.highlightStyle.textPosition = this.deepQuery(queryTarget, 'itemStyle.emphasis.label.position');
  407. shape.highlightStyle.textColor = this.deepQuery(queryTarget, 'itemStyle.emphasis.label.textStyle.color');
  408. shape.highlightStyle.textFont = this.getFont(this.deepQuery(queryTarget, 'itemStyle.emphasis.label.textStyle') || {});
  409. }
  410. if (this.deepQuery(queryTarget, 'draggable')) {
  411. this.setCalculable(shape);
  412. shape.dragEnableTime = 0;
  413. shape.draggable = true;
  414. shape.ondragstart = this.shapeHandler.ondragstart;
  415. shape.ondragover = null;
  416. }
  417. var categoryName = '';
  418. if (typeof node.category !== 'undefined') {
  419. var category = categories[node.category];
  420. categoryName = category && category.name || '';
  421. }
  422. ecData.pack(shape, serie, serieIdx, node.data, node.rawIndex, node.data.name || '', node.category);
  423. this.shapeList.push(shape);
  424. this.zr.addShape(shape);
  425. node.shape = shape;
  426. }, this);
  427. },
  428. _buildLinkShapes: function (serie, serieIdx) {
  429. var graph = this._graph;
  430. var len = graph.edges.length;
  431. for (var i = 0; i < len; i++) {
  432. var gEdge = graph.edges[i];
  433. var link = gEdge.data;
  434. var source = gEdge.node1;
  435. var target = gEdge.node2;
  436. var otherEdge = graph.getEdge(target, source);
  437. var queryTarget = this._getEdgeQueryTarget(serie, link);
  438. var linkType = this.deepQuery(queryTarget, 'type');
  439. if (serie.linkSymbol && serie.linkSymbol !== 'none') {
  440. linkType = 'line';
  441. }
  442. var LinkShapeCtor = linkType === 'line' ? LineShape : BezierCurveShape;
  443. var linkShape = new LinkShapeCtor({
  444. style: {
  445. xStart: 0,
  446. yStart: 0,
  447. xEnd: 0,
  448. yEnd: 0
  449. },
  450. clickable: this.query(serie, 'clickable'),
  451. highlightStyle: {},
  452. zlevel: this.getZlevelBase(),
  453. z: this.getZBase()
  454. });
  455. if (otherEdge && otherEdge.shape) {
  456. linkShape.style.offset = 4;
  457. otherEdge.shape.style.offset = 4;
  458. }
  459. zrUtil.merge(linkShape.style, this.query(serie, 'itemStyle.normal.linkStyle'), true);
  460. zrUtil.merge(linkShape.highlightStyle, this.query(serie, 'itemStyle.emphasis.linkStyle'), true);
  461. if (typeof link.itemStyle !== 'undefined') {
  462. if (link.itemStyle.normal) {
  463. zrUtil.merge(linkShape.style, link.itemStyle.normal, true);
  464. }
  465. if (link.itemStyle.emphasis) {
  466. zrUtil.merge(linkShape.highlightStyle, link.itemStyle.emphasis, true);
  467. }
  468. }
  469. linkShape.style.lineWidth = linkShape.style.lineWidth || linkShape.style.width;
  470. linkShape.style.strokeColor = linkShape.style.strokeColor || linkShape.style.color;
  471. linkShape.highlightStyle.lineWidth = linkShape.highlightStyle.lineWidth || linkShape.highlightStyle.width;
  472. linkShape.highlightStyle.strokeColor = linkShape.highlightStyle.strokeColor || linkShape.highlightStyle.color;
  473. ecData.pack(linkShape, serie, serieIdx, gEdge.data, gEdge.rawIndex == null ? i : gEdge.rawIndex, gEdge.data.name || source.id + ' - ' + target.id, source.id, target.id);
  474. this.shapeList.push(linkShape);
  475. this.zr.addShape(linkShape);
  476. gEdge.shape = linkShape;
  477. if (serie.linkSymbol && serie.linkSymbol !== 'none') {
  478. var symbolShape = new IconShape({
  479. style: {
  480. x: -5,
  481. y: 0,
  482. width: serie.linkSymbolSize[0],
  483. height: serie.linkSymbolSize[1],
  484. iconType: serie.linkSymbol,
  485. brushType: 'fill',
  486. color: linkShape.style.strokeColor
  487. },
  488. highlightStyle: { brushType: 'fill' },
  489. position: [
  490. 0,
  491. 0
  492. ],
  493. rotation: 0,
  494. zlevel: this.getZlevelBase(),
  495. z: this.getZBase()
  496. });
  497. linkShape._symbolShape = symbolShape;
  498. this.shapeList.push(symbolShape);
  499. this.zr.addShape(symbolShape);
  500. }
  501. }
  502. },
  503. _updateLinkShapes: function () {
  504. var v = vec2.create();
  505. var n = vec2.create();
  506. var p1 = vec2.create();
  507. var p2 = vec2.create();
  508. var edges = this._graph.edges;
  509. for (var i = 0, len = edges.length; i < len; i++) {
  510. var edge = edges[i];
  511. var sourceShape = edge.node1.shape;
  512. var targetShape = edge.node2.shape;
  513. vec2.copy(p1, sourceShape.position);
  514. vec2.copy(p2, targetShape.position);
  515. var edgeShapeStyle = edge.shape.style;
  516. vec2.sub(v, p1, p2);
  517. vec2.normalize(v, v);
  518. if (edgeShapeStyle.offset) {
  519. n[0] = v[1];
  520. n[1] = -v[0];
  521. vec2.scaleAndAdd(p1, p1, n, edgeShapeStyle.offset);
  522. vec2.scaleAndAdd(p2, p2, n, edgeShapeStyle.offset);
  523. } else if (edge.shape.type === 'bezier-curve') {
  524. edgeShapeStyle.cpX1 = (p1[0] + p2[0]) / 2 - (p2[1] - p1[1]) / 4;
  525. edgeShapeStyle.cpY1 = (p1[1] + p2[1]) / 2 - (p1[0] - p2[0]) / 4;
  526. }
  527. edgeShapeStyle.xStart = p1[0];
  528. edgeShapeStyle.yStart = p1[1];
  529. edgeShapeStyle.xEnd = p2[0];
  530. edgeShapeStyle.yEnd = p2[1];
  531. edge.shape.modSelf();
  532. if (edge.shape._symbolShape) {
  533. var symbolShape = edge.shape._symbolShape;
  534. vec2.copy(symbolShape.position, p2);
  535. vec2.scaleAndAdd(symbolShape.position, symbolShape.position, v, targetShape.style.width / 2 + 2);
  536. var angle = Math.atan2(v[1], v[0]);
  537. symbolShape.rotation = Math.PI / 2 - angle;
  538. symbolShape.modSelf();
  539. }
  540. }
  541. },
  542. _syncNodePositions: function () {
  543. var graph = this._graph;
  544. for (var i = 0; i < graph.nodes.length; i++) {
  545. var gNode = graph.nodes[i];
  546. var position = gNode.layout.position;
  547. var node = gNode.data;
  548. var shape = gNode.shape;
  549. var fixX = shape.fixed || node.fixX;
  550. var fixY = shape.fixed || node.fixY;
  551. if (fixX === true) {
  552. fixX = 1;
  553. } else if (isNaN(fixX)) {
  554. fixX = 0;
  555. }
  556. if (fixY === true) {
  557. fixY = 1;
  558. } else if (isNaN(fixY)) {
  559. fixY = 0;
  560. }
  561. shape.position[0] += (position[0] - shape.position[0]) * (1 - fixX);
  562. shape.position[1] += (position[1] - shape.position[1]) * (1 - fixY);
  563. vec2.copy(position, shape.position);
  564. var nodeName = node.name;
  565. if (nodeName) {
  566. var gPos = this.__nodePositionMap[nodeName];
  567. if (!gPos) {
  568. gPos = this.__nodePositionMap[nodeName] = vec2.create();
  569. }
  570. vec2.copy(gPos, position);
  571. }
  572. shape.modSelf();
  573. }
  574. },
  575. _step: function (e) {
  576. this._syncNodePositions();
  577. this._updateLinkShapes();
  578. this.zr.refreshNextFrame();
  579. if (this._layout.temperature > 0.01) {
  580. this._layout.step(this._steps);
  581. } else {
  582. this.messageCenter.dispatch(ecConfig.EVENT.FORCE_LAYOUT_END, {}, {}, this.myChart);
  583. }
  584. },
  585. refresh: function (newOption) {
  586. if (newOption) {
  587. this.option = newOption;
  588. this.series = this.option.series;
  589. }
  590. this.legend = this.component.legend;
  591. if (this.legend) {
  592. this.getColor = function (param) {
  593. return this.legend.getColor(param);
  594. };
  595. this.isSelected = function (param) {
  596. return this.legend.isSelected(param);
  597. };
  598. } else {
  599. var colorMap = {};
  600. var count = 0;
  601. this.getColor = function (key) {
  602. if (colorMap[key]) {
  603. return colorMap[key];
  604. }
  605. if (!colorMap[key]) {
  606. colorMap[key] = this.zr.getColor(count++);
  607. }
  608. return colorMap[key];
  609. };
  610. this.isSelected = function () {
  611. return true;
  612. };
  613. }
  614. this._init();
  615. },
  616. dispose: function () {
  617. this.clear();
  618. this.shapeList = null;
  619. this.effectList = null;
  620. this._layout.dispose();
  621. this._layout = null;
  622. this.__nodePositionMap = {};
  623. },
  624. getPosition: function () {
  625. var position = [];
  626. this._graph.eachNode(function (n) {
  627. if (n.layout) {
  628. position.push({
  629. name: n.data.name,
  630. position: Array.prototype.slice.call(n.layout.position)
  631. });
  632. }
  633. });
  634. return position;
  635. }
  636. };
  637. function ondragstart(param) {
  638. if (!this.isDragstart || !param.target) {
  639. return;
  640. }
  641. var shape = param.target;
  642. shape.fixed = true;
  643. this.isDragstart = false;
  644. this.zr.on(zrConfig.EVENT.MOUSEMOVE, this.onmousemove);
  645. }
  646. function onmousemove() {
  647. this._layout.temperature = 0.8;
  648. this._step();
  649. }
  650. function ondragend(param, status) {
  651. if (!this.isDragend || !param.target) {
  652. return;
  653. }
  654. var shape = param.target;
  655. shape.fixed = false;
  656. status.dragIn = true;
  657. status.needRefresh = false;
  658. this.isDragend = false;
  659. this.zr.un(zrConfig.EVENT.MOUSEMOVE, this.onmousemove);
  660. }
  661. function _randomInSquare(x, y, size) {
  662. var v = vec2.create();
  663. v[0] = (Math.random() - 0.5) * size + x;
  664. v[1] = (Math.random() - 0.5) * size + y;
  665. return v;
  666. }
  667. zrUtil.inherits(Force, ChartBase);
  668. require('../chart').define('force', Force);
  669. return Force;
  670. });define('echarts/data/Graph', [
  671. 'require',
  672. 'zrender/tool/util'
  673. ], function (require) {
  674. var util = require('zrender/tool/util');
  675. 'use strict';
  676. var Graph = function (directed) {
  677. this._directed = directed || false;
  678. this.nodes = [];
  679. this.edges = [];
  680. this._nodesMap = {};
  681. this._edgesMap = {};
  682. };
  683. Graph.prototype.isDirected = function () {
  684. return this._directed;
  685. };
  686. Graph.prototype.addNode = function (id, data) {
  687. if (this._nodesMap[id]) {
  688. return this._nodesMap[id];
  689. }
  690. var node = new Graph.Node(id, data);
  691. this.nodes.push(node);
  692. this._nodesMap[id] = node;
  693. return node;
  694. };
  695. Graph.prototype.getNodeById = function (id) {
  696. return this._nodesMap[id];
  697. };
  698. Graph.prototype.addEdge = function (n1, n2, data) {
  699. if (typeof n1 == 'string') {
  700. n1 = this._nodesMap[n1];
  701. }
  702. if (typeof n2 == 'string') {
  703. n2 = this._nodesMap[n2];
  704. }
  705. if (!n1 || !n2) {
  706. return;
  707. }
  708. var key = n1.id + '-' + n2.id;
  709. if (this._edgesMap[key]) {
  710. return this._edgesMap[key];
  711. }
  712. var edge = new Graph.Edge(n1, n2, data);
  713. if (this._directed) {
  714. n1.outEdges.push(edge);
  715. n2.inEdges.push(edge);
  716. }
  717. n1.edges.push(edge);
  718. if (n1 !== n2) {
  719. n2.edges.push(edge);
  720. }
  721. this.edges.push(edge);
  722. this._edgesMap[key] = edge;
  723. return edge;
  724. };
  725. Graph.prototype.removeEdge = function (edge) {
  726. var n1 = edge.node1;
  727. var n2 = edge.node2;
  728. var key = n1.id + '-' + n2.id;
  729. if (this._directed) {
  730. n1.outEdges.splice(util.indexOf(n1.outEdges, edge), 1);
  731. n2.inEdges.splice(util.indexOf(n2.inEdges, edge), 1);
  732. }
  733. n1.edges.splice(util.indexOf(n1.edges, edge), 1);
  734. if (n1 !== n2) {
  735. n2.edges.splice(util.indexOf(n2.edges, edge), 1);
  736. }
  737. delete this._edgesMap[key];
  738. this.edges.splice(util.indexOf(this.edges, edge), 1);
  739. };
  740. Graph.prototype.getEdge = function (n1, n2) {
  741. if (typeof n1 !== 'string') {
  742. n1 = n1.id;
  743. }
  744. if (typeof n2 !== 'string') {
  745. n2 = n2.id;
  746. }
  747. if (this._directed) {
  748. return this._edgesMap[n1 + '-' + n2];
  749. } else {
  750. return this._edgesMap[n1 + '-' + n2] || this._edgesMap[n2 + '-' + n1];
  751. }
  752. };
  753. Graph.prototype.removeNode = function (node) {
  754. if (typeof node === 'string') {
  755. node = this._nodesMap[node];
  756. if (!node) {
  757. return;
  758. }
  759. }
  760. delete this._nodesMap[node.id];
  761. this.nodes.splice(util.indexOf(this.nodes, node), 1);
  762. for (var i = 0; i < this.edges.length;) {
  763. var edge = this.edges[i];
  764. if (edge.node1 === node || edge.node2 === node) {
  765. this.removeEdge(edge);
  766. } else {
  767. i++;
  768. }
  769. }
  770. };
  771. Graph.prototype.filterNode = function (cb, context) {
  772. var len = this.nodes.length;
  773. for (var i = 0; i < len;) {
  774. if (cb.call(context, this.nodes[i], i)) {
  775. i++;
  776. } else {
  777. this.removeNode(this.nodes[i]);
  778. len--;
  779. }
  780. }
  781. };
  782. Graph.prototype.filterEdge = function (cb, context) {
  783. var len = this.edges.length;
  784. for (var i = 0; i < len;) {
  785. if (cb.call(context, this.edges[i], i)) {
  786. i++;
  787. } else {
  788. this.removeEdge(this.edges[i]);
  789. len--;
  790. }
  791. }
  792. };
  793. Graph.prototype.eachNode = function (cb, context) {
  794. var len = this.nodes.length;
  795. for (var i = 0; i < len; i++) {
  796. if (this.nodes[i]) {
  797. cb.call(context, this.nodes[i], i);
  798. }
  799. }
  800. };
  801. Graph.prototype.eachEdge = function (cb, context) {
  802. var len = this.edges.length;
  803. for (var i = 0; i < len; i++) {
  804. if (this.edges[i]) {
  805. cb.call(context, this.edges[i], i);
  806. }
  807. }
  808. };
  809. Graph.prototype.clear = function () {
  810. this.nodes.length = 0;
  811. this.edges.length = 0;
  812. this._nodesMap = {};
  813. this._edgesMap = {};
  814. };
  815. Graph.prototype.breadthFirstTraverse = function (cb, startNode, direction, context) {
  816. if (typeof startNode === 'string') {
  817. startNode = this._nodesMap[startNode];
  818. }
  819. if (!startNode) {
  820. return;
  821. }
  822. var edgeType = 'edges';
  823. if (direction === 'out') {
  824. edgeType = 'outEdges';
  825. } else if (direction === 'in') {
  826. edgeType = 'inEdges';
  827. }
  828. for (var i = 0; i < this.nodes.length; i++) {
  829. this.nodes[i].__visited = false;
  830. }
  831. if (cb.call(context, startNode, null)) {
  832. return;
  833. }
  834. var queue = [startNode];
  835. while (queue.length) {
  836. var currentNode = queue.shift();
  837. var edges = currentNode[edgeType];
  838. for (var i = 0; i < edges.length; i++) {
  839. var e = edges[i];
  840. var otherNode = e.node1 === currentNode ? e.node2 : e.node1;
  841. if (!otherNode.__visited) {
  842. if (cb.call(otherNode, otherNode, currentNode)) {
  843. return;
  844. }
  845. queue.push(otherNode);
  846. otherNode.__visited = true;
  847. }
  848. }
  849. }
  850. };
  851. Graph.prototype.clone = function () {
  852. var graph = new Graph(this._directed);
  853. for (var i = 0; i < this.nodes.length; i++) {
  854. graph.addNode(this.nodes[i].id, this.nodes[i].data);
  855. }
  856. for (var i = 0; i < this.edges.length; i++) {
  857. var e = this.edges[i];
  858. graph.addEdge(e.node1.id, e.node2.id, e.data);
  859. }
  860. return graph;
  861. };
  862. var Node = function (id, data) {
  863. this.id = id;
  864. this.data = data || null;
  865. this.inEdges = [];
  866. this.outEdges = [];
  867. this.edges = [];
  868. };
  869. Node.prototype.degree = function () {
  870. return this.edges.length;
  871. };
  872. Node.prototype.inDegree = function () {
  873. return this.inEdges.length;
  874. };
  875. Node.prototype.outDegree = function () {
  876. return this.outEdges.length;
  877. };
  878. var Edge = function (node1, node2, data) {
  879. this.node1 = node1;
  880. this.node2 = node2;
  881. this.data = data || null;
  882. };
  883. Graph.Node = Node;
  884. Graph.Edge = Edge;
  885. Graph.fromMatrix = function (nodesData, matrix, directed) {
  886. if (!matrix || !matrix.length || matrix[0].length !== matrix.length || nodesData.length !== matrix.length) {
  887. return;
  888. }
  889. var size = matrix.length;
  890. var graph = new Graph(directed);
  891. for (var i = 0; i < size; i++) {
  892. var node = graph.addNode(nodesData[i].id, nodesData[i]);
  893. node.data.value = 0;
  894. if (directed) {
  895. node.data.outValue = node.data.inValue = 0;
  896. }
  897. }
  898. for (var i = 0; i < size; i++) {
  899. for (var j = 0; j < size; j++) {
  900. var item = matrix[i][j];
  901. if (directed) {
  902. graph.nodes[i].data.outValue += item;
  903. graph.nodes[j].data.inValue += item;
  904. }
  905. graph.nodes[i].data.value += item;
  906. graph.nodes[j].data.value += item;
  907. }
  908. }
  909. for (var i = 0; i < size; i++) {
  910. for (var j = i; j < size; j++) {
  911. var item = matrix[i][j];
  912. if (item === 0) {
  913. continue;
  914. }
  915. var n1 = graph.nodes[i];
  916. var n2 = graph.nodes[j];
  917. var edge = graph.addEdge(n1, n2, {});
  918. edge.data.weight = item;
  919. if (i !== j) {
  920. if (directed && matrix[j][i]) {
  921. var inEdge = graph.addEdge(n2, n1, {});
  922. inEdge.data.weight = matrix[j][i];
  923. }
  924. }
  925. }
  926. }
  927. return graph;
  928. };
  929. return Graph;
  930. });define('echarts/layout/Force', [
  931. 'require',
  932. './forceLayoutWorker',
  933. 'zrender/tool/vector'
  934. ], function (require) {
  935. var ForceLayoutWorker = require('./forceLayoutWorker');
  936. var vec2 = require('zrender/tool/vector');
  937. var requestAnimationFrame = window.requestAnimationFrame || window.msRequestAnimationFrame || window.mozRequestAnimationFrame || window.webkitRequestAnimationFrame || function (func) {
  938. setTimeout(func, 16);
  939. };
  940. var ArrayCtor = typeof Float32Array == 'undefined' ? Array : Float32Array;
  941. var workerUrl;
  942. function createWorkerUrl() {
  943. if (typeof Worker !== 'undefined' && typeof Blob !== 'undefined') {
  944. try {
  945. var blob = new Blob([ForceLayoutWorker.getWorkerCode()]);
  946. workerUrl = window.URL.createObjectURL(blob);
  947. } catch (e) {
  948. workerUrl = '';
  949. }
  950. }
  951. return workerUrl;
  952. }
  953. var ForceLayout = function (opts) {
  954. if (typeof workerUrl === 'undefined') {
  955. createWorkerUrl();
  956. }
  957. opts = opts || {};
  958. this.width = opts.width || 500;
  959. this.height = opts.height || 500;
  960. this.center = opts.center || [
  961. this.width / 2,
  962. this.height / 2
  963. ];
  964. this.ratioScaling = opts.ratioScaling || false;
  965. this.scaling = opts.scaling || 1;
  966. this.gravity = typeof opts.gravity !== 'undefined' ? opts.gravity : 1;
  967. this.large = opts.large || false;
  968. this.preventNodeOverlap = opts.preventNodeOverlap || false;
  969. this.preventNodeEdgeOverlap = opts.preventNodeEdgeOverlap || false;
  970. this.maxSpeedIncrease = opts.maxSpeedIncrease || 1;
  971. this.onupdate = opts.onupdate || function () {
  972. };
  973. this.temperature = opts.temperature || 1;
  974. this.coolDown = opts.coolDown || 0.99;
  975. this._layout = null;
  976. this._layoutWorker = null;
  977. var self = this;
  978. var _$onupdate = this._$onupdate;
  979. this._$onupdate = function (e) {
  980. _$onupdate.call(self, e);
  981. };
  982. };
  983. ForceLayout.prototype.updateConfig = function () {
  984. var width = this.width;
  985. var height = this.height;
  986. var size = Math.min(width, height);
  987. var config = {
  988. center: this.center,
  989. width: this.ratioScaling ? width : size,
  990. height: this.ratioScaling ? height : size,
  991. scaling: this.scaling || 1,
  992. gravity: this.gravity || 1,
  993. barnesHutOptimize: this.large,
  994. preventNodeOverlap: this.preventNodeOverlap,
  995. preventNodeEdgeOverlap: this.preventNodeEdgeOverlap,
  996. maxSpeedIncrease: this.maxSpeedIncrease
  997. };
  998. if (this._layoutWorker) {
  999. this._layoutWorker.postMessage({
  1000. cmd: 'updateConfig',
  1001. config: config
  1002. });
  1003. } else {
  1004. for (var name in config) {
  1005. this._layout[name] = config[name];
  1006. }
  1007. }
  1008. };
  1009. ForceLayout.prototype.init = function (graph, useWorker) {
  1010. if (this._layoutWorker) {
  1011. this._layoutWorker.terminate();
  1012. this._layoutWorker = null;
  1013. }
  1014. if (workerUrl && useWorker) {
  1015. try {
  1016. if (!this._layoutWorker) {
  1017. this._layoutWorker = new Worker(workerUrl);
  1018. this._layoutWorker.onmessage = this._$onupdate;
  1019. }
  1020. this._layout = null;
  1021. } catch (e) {
  1022. this._layoutWorker = null;
  1023. if (!this._layout) {
  1024. this._layout = new ForceLayoutWorker();
  1025. }
  1026. }
  1027. } else {
  1028. if (!this._layout) {
  1029. this._layout = new ForceLayoutWorker();
  1030. }
  1031. }
  1032. this.temperature = 1;
  1033. this.graph = graph;
  1034. var len = graph.nodes.length;
  1035. var positionArr = new ArrayCtor(len * 2);
  1036. var massArr = new ArrayCtor(len);
  1037. var sizeArr = new ArrayCtor(len);
  1038. for (var i = 0; i < len; i++) {
  1039. var n = graph.nodes[i];
  1040. positionArr[i * 2] = n.layout.position[0];
  1041. positionArr[i * 2 + 1] = n.layout.position[1];
  1042. massArr[i] = typeof n.layout.mass === 'undefined' ? 1 : n.layout.mass;
  1043. sizeArr[i] = typeof n.layout.size === 'undefined' ? 1 : n.layout.size;
  1044. n.layout.__index = i;
  1045. }
  1046. len = graph.edges.length;
  1047. var edgeArr = new ArrayCtor(len * 2);
  1048. var edgeWeightArr = new ArrayCtor(len);
  1049. for (var i = 0; i < len; i++) {
  1050. var edge = graph.edges[i];
  1051. edgeArr[i * 2] = edge.node1.layout.__index;
  1052. edgeArr[i * 2 + 1] = edge.node2.layout.__index;
  1053. edgeWeightArr[i] = edge.layout.weight || 1;
  1054. }
  1055. if (this._layoutWorker) {
  1056. this._layoutWorker.postMessage({
  1057. cmd: 'init',
  1058. nodesPosition: positionArr,
  1059. nodesMass: massArr,
  1060. nodesSize: sizeArr,
  1061. edges: edgeArr,
  1062. edgesWeight: edgeWeightArr
  1063. });
  1064. } else {
  1065. this._layout.initNodes(positionArr, massArr, sizeArr);
  1066. this._layout.initEdges(edgeArr, edgeWeightArr);
  1067. }
  1068. this.updateConfig();
  1069. };
  1070. ForceLayout.prototype.step = function (steps) {
  1071. var nodes = this.graph.nodes;
  1072. if (this._layoutWorker) {
  1073. var positionArr = new ArrayCtor(nodes.length * 2);
  1074. for (var i = 0; i < nodes.length; i++) {
  1075. var n = nodes[i];
  1076. positionArr[i * 2] = n.layout.position[0];
  1077. positionArr[i * 2 + 1] = n.layout.position[1];
  1078. }
  1079. this._layoutWorker.postMessage(positionArr.buffer, [positionArr.buffer]);
  1080. this._layoutWorker.postMessage({
  1081. cmd: 'update',
  1082. steps: steps,
  1083. temperature: this.temperature,
  1084. coolDown: this.coolDown
  1085. });
  1086. for (var i = 0; i < steps; i++) {
  1087. this.temperature *= this.coolDown;
  1088. }
  1089. } else {
  1090. requestAnimationFrame(this._$onupdate);
  1091. for (var i = 0; i < nodes.length; i++) {
  1092. var n = nodes[i];
  1093. vec2.copy(this._layout.nodes[i].position, n.layout.position);
  1094. }
  1095. for (var i = 0; i < steps; i++) {
  1096. this._layout.temperature = this.temperature;
  1097. this._layout.update();
  1098. this.temperature *= this.coolDown;
  1099. }
  1100. }
  1101. };
  1102. ForceLayout.prototype._$onupdate = function (e) {
  1103. if (this._layoutWorker) {
  1104. var positionArr = new Float32Array(e.data);
  1105. for (var i = 0; i < this.graph.nodes.length; i++) {
  1106. var n = this.graph.nodes[i];
  1107. n.layout.position[0] = positionArr[i * 2];
  1108. n.layout.position[1] = positionArr[i * 2 + 1];
  1109. }
  1110. this.onupdate && this.onupdate();
  1111. } else if (this._layout) {
  1112. for (var i = 0; i < this.graph.nodes.length; i++) {
  1113. var n = this.graph.nodes[i];
  1114. vec2.copy(n.layout.position, this._layout.nodes[i].position);
  1115. }
  1116. this.onupdate && this.onupdate();
  1117. }
  1118. };
  1119. ForceLayout.prototype.dispose = function () {
  1120. if (this._layoutWorker) {
  1121. this._layoutWorker.terminate();
  1122. }
  1123. this._layoutWorker = null;
  1124. this._layout = null;
  1125. };
  1126. return ForceLayout;
  1127. });define('echarts/layout/forceLayoutWorker', [
  1128. 'require',
  1129. 'zrender/tool/vector'
  1130. ], function __echartsForceLayoutWorker(require) {
  1131. 'use strict';
  1132. var vec2;
  1133. var inWorker = typeof window === 'undefined' && typeof require === 'undefined';
  1134. if (inWorker) {
  1135. vec2 = {
  1136. create: function (x, y) {
  1137. var out = new Float32Array(2);
  1138. out[0] = x || 0;
  1139. out[1] = y || 0;
  1140. return out;
  1141. },
  1142. dist: function (a, b) {
  1143. var x = b[0] - a[0];
  1144. var y = b[1] - a[1];
  1145. return Math.sqrt(x * x + y * y);
  1146. },
  1147. len: function (a) {
  1148. var x = a[0];
  1149. var y = a[1];
  1150. return Math.sqrt(x * x + y * y);
  1151. },
  1152. scaleAndAdd: function (out, a, b, scale) {
  1153. out[0] = a[0] + b[0] * scale;
  1154. out[1] = a[1] + b[1] * scale;
  1155. return out;
  1156. },
  1157. scale: function (out, a, b) {
  1158. out[0] = a[0] * b;
  1159. out[1] = a[1] * b;
  1160. return out;
  1161. },
  1162. add: function (out, a, b) {
  1163. out[0] = a[0] + b[0];
  1164. out[1] = a[1] + b[1];
  1165. return out;
  1166. },
  1167. sub: function (out, a, b) {
  1168. out[0] = a[0] - b[0];
  1169. out[1] = a[1] - b[1];
  1170. return out;
  1171. },
  1172. dot: function (v1, v2) {
  1173. return v1[0] * v2[0] + v1[1] * v2[1];
  1174. },
  1175. normalize: function (out, a) {
  1176. var x = a[0];
  1177. var y = a[1];
  1178. var len = x * x + y * y;
  1179. if (len > 0) {
  1180. len = 1 / Math.sqrt(len);
  1181. out[0] = a[0] * len;
  1182. out[1] = a[1] * len;
  1183. }
  1184. return out;
  1185. },
  1186. negate: function (out, a) {
  1187. out[0] = -a[0];
  1188. out[1] = -a[1];
  1189. return out;
  1190. },
  1191. copy: function (out, a) {
  1192. out[0] = a[0];
  1193. out[1] = a[1];
  1194. return out;
  1195. },
  1196. set: function (out, x, y) {
  1197. out[0] = x;
  1198. out[1] = y;
  1199. return out;
  1200. }
  1201. };
  1202. } else {
  1203. vec2 = require('zrender/tool/vector');
  1204. }
  1205. var ArrayCtor = typeof Float32Array == 'undefined' ? Array : Float32Array;
  1206. function Region() {
  1207. this.subRegions = [];
  1208. this.nSubRegions = 0;
  1209. this.node = null;
  1210. this.mass = 0;
  1211. this.centerOfMass = null;
  1212. this.bbox = new ArrayCtor(4);
  1213. this.size = 0;
  1214. }
  1215. Region.prototype.beforeUpdate = function () {
  1216. for (var i = 0; i < this.nSubRegions; i++) {
  1217. this.subRegions[i].beforeUpdate();
  1218. }
  1219. this.mass = 0;
  1220. if (this.centerOfMass) {
  1221. this.centerOfMass[0] = 0;
  1222. this.centerOfMass[1] = 0;
  1223. }
  1224. this.nSubRegions = 0;
  1225. this.node = null;
  1226. };
  1227. Region.prototype.afterUpdate = function () {
  1228. this.subRegions.length = this.nSubRegions;
  1229. for (var i = 0; i < this.nSubRegions; i++) {
  1230. this.subRegions[i].afterUpdate();
  1231. }
  1232. };
  1233. Region.prototype.addNode = function (node) {
  1234. if (this.nSubRegions === 0) {
  1235. if (this.node == null) {
  1236. this.node = node;
  1237. return;
  1238. } else {
  1239. this._addNodeToSubRegion(this.node);
  1240. this.node = null;
  1241. }
  1242. }
  1243. this._addNodeToSubRegion(node);
  1244. this._updateCenterOfMass(node);
  1245. };
  1246. Region.prototype.findSubRegion = function (x, y) {
  1247. for (var i = 0; i < this.nSubRegions; i++) {
  1248. var region = this.subRegions[i];
  1249. if (region.contain(x, y)) {
  1250. return region;
  1251. }
  1252. }
  1253. };
  1254. Region.prototype.contain = function (x, y) {
  1255. return this.bbox[0] <= x && this.bbox[2] >= x && this.bbox[1] <= y && this.bbox[3] >= y;
  1256. };
  1257. Region.prototype.setBBox = function (minX, minY, maxX, maxY) {
  1258. this.bbox[0] = minX;
  1259. this.bbox[1] = minY;
  1260. this.bbox[2] = maxX;
  1261. this.bbox[3] = maxY;
  1262. this.size = (maxX - minX + maxY - minY) / 2;
  1263. };
  1264. Region.prototype._newSubRegion = function () {
  1265. var subRegion = this.subRegions[this.nSubRegions];
  1266. if (!subRegion) {
  1267. subRegion = new Region();
  1268. this.subRegions[this.nSubRegions] = subRegion;
  1269. }
  1270. this.nSubRegions++;
  1271. return subRegion;
  1272. };
  1273. Region.prototype._addNodeToSubRegion = function (node) {
  1274. var subRegion = this.findSubRegion(node.position[0], node.position[1]);
  1275. var bbox = this.bbox;
  1276. if (!subRegion) {
  1277. var cx = (bbox[0] + bbox[2]) / 2;
  1278. var cy = (bbox[1] + bbox[3]) / 2;
  1279. var w = (bbox[2] - bbox[0]) / 2;
  1280. var h = (bbox[3] - bbox[1]) / 2;
  1281. var xi = node.position[0] >= cx ? 1 : 0;
  1282. var yi = node.position[1] >= cy ? 1 : 0;
  1283. var subRegion = this._newSubRegion();
  1284. subRegion.setBBox(xi * w + bbox[0], yi * h + bbox[1], (xi + 1) * w + bbox[0], (yi + 1) * h + bbox[1]);
  1285. }
  1286. subRegion.addNode(node);
  1287. };
  1288. Region.prototype._updateCenterOfMass = function (node) {
  1289. if (this.centerOfMass == null) {
  1290. this.centerOfMass = vec2.create();
  1291. }
  1292. var x = this.centerOfMass[0] * this.mass;
  1293. var y = this.centerOfMass[1] * this.mass;
  1294. x += node.position[0] * node.mass;
  1295. y += node.position[1] * node.mass;
  1296. this.mass += node.mass;
  1297. this.centerOfMass[0] = x / this.mass;
  1298. this.centerOfMass[1] = y / this.mass;
  1299. };
  1300. function GraphNode() {
  1301. this.position = vec2.create();
  1302. this.force = vec2.create();
  1303. this.forcePrev = vec2.create();
  1304. this.speed = vec2.create();
  1305. this.speedPrev = vec2.create();
  1306. this.mass = 1;
  1307. this.inDegree = 0;
  1308. this.outDegree = 0;
  1309. }
  1310. function GraphEdge(node1, node2) {
  1311. this.node1 = node1;
  1312. this.node2 = node2;
  1313. this.weight = 1;
  1314. }
  1315. function ForceLayout() {
  1316. this.barnesHutOptimize = false;
  1317. this.barnesHutTheta = 1.5;
  1318. this.repulsionByDegree = false;
  1319. this.preventNodeOverlap = false;
  1320. this.preventNodeEdgeOverlap = false;
  1321. this.strongGravity = true;
  1322. this.gravity = 1;
  1323. this.scaling = 1;
  1324. this.edgeWeightInfluence = 1;
  1325. this.center = [
  1326. 0,
  1327. 0
  1328. ];
  1329. this.width = 500;
  1330. this.height = 500;
  1331. this.maxSpeedIncrease = 1;
  1332. this.nodes = [];
  1333. this.edges = [];
  1334. this.bbox = new ArrayCtor(4);
  1335. this._rootRegion = new Region();
  1336. this._rootRegion.centerOfMass = vec2.create();
  1337. this._massArr = null;
  1338. this._k = 0;
  1339. }
  1340. ForceLayout.prototype.nodeToNodeRepulsionFactor = function (mass, d, k) {
  1341. return k * k * mass / d;
  1342. };
  1343. ForceLayout.prototype.edgeToNodeRepulsionFactor = function (mass, d, k) {
  1344. return k * mass / d;
  1345. };
  1346. ForceLayout.prototype.attractionFactor = function (w, d, k) {
  1347. return w * d / k;
  1348. };
  1349. ForceLayout.prototype.initNodes = function (positionArr, massArr, sizeArr) {
  1350. this.temperature = 1;
  1351. var nNodes = positionArr.length / 2;
  1352. this.nodes.length = 0;
  1353. var haveSize = typeof sizeArr !== 'undefined';
  1354. for (var i = 0; i < nNodes; i++) {
  1355. var node = new GraphNode();
  1356. node.position[0] = positionArr[i * 2];
  1357. node.position[1] = positionArr[i * 2 + 1];
  1358. node.mass = massArr[i];
  1359. if (haveSize) {
  1360. node.size = sizeArr[i];
  1361. }
  1362. this.nodes.push(node);
  1363. }
  1364. this._massArr = massArr;
  1365. if (haveSize) {
  1366. this._sizeArr = sizeArr;
  1367. }
  1368. };
  1369. ForceLayout.prototype.initEdges = function (edgeArr, edgeWeightArr) {
  1370. var nEdges = edgeArr.length / 2;
  1371. this.edges.length = 0;
  1372. var edgeHaveWeight = typeof edgeWeightArr !== 'undefined';
  1373. for (var i = 0; i < nEdges; i++) {
  1374. var sIdx = edgeArr[i * 2];
  1375. var tIdx = edgeArr[i * 2 + 1];
  1376. var sNode = this.nodes[sIdx];
  1377. var tNode = this.nodes[tIdx];
  1378. if (!sNode || !tNode) {
  1379. continue;
  1380. }
  1381. sNode.outDegree++;
  1382. tNode.inDegree++;
  1383. var edge = new GraphEdge(sNode, tNode);
  1384. if (edgeHaveWeight) {
  1385. edge.weight = edgeWeightArr[i];
  1386. }
  1387. this.edges.push(edge);
  1388. }
  1389. };
  1390. ForceLayout.prototype.update = function () {
  1391. var nNodes = this.nodes.length;
  1392. this.updateBBox();
  1393. this._k = 0.4 * this.scaling * Math.sqrt(this.width * this.height / nNodes);
  1394. if (this.barnesHutOptimize) {
  1395. this._rootRegion.setBBox(this.bbox[0], this.bbox[1], this.bbox[2], this.bbox[3]);
  1396. this._rootRegion.beforeUpdate();
  1397. for (var i = 0; i < nNodes; i++) {
  1398. this._rootRegion.addNode(this.nodes[i]);
  1399. }
  1400. this._rootRegion.afterUpdate();
  1401. } else {
  1402. var mass = 0;
  1403. var centerOfMass = this._rootRegion.centerOfMass;
  1404. vec2.set(centerOfMass, 0, 0);
  1405. for (var i = 0; i < nNodes; i++) {
  1406. var node = this.nodes[i];
  1407. mass += node.mass;
  1408. vec2.scaleAndAdd(centerOfMass, centerOfMass, node.position, node.mass);
  1409. }
  1410. if (mass > 0) {
  1411. vec2.scale(centerOfMass, centerOfMass, 1 / mass);
  1412. }
  1413. }
  1414. this.updateForce();
  1415. this.updatePosition();
  1416. };
  1417. ForceLayout.prototype.updateForce = function () {
  1418. var nNodes = this.nodes.length;
  1419. for (var i = 0; i < nNodes; i++) {
  1420. var node = this.nodes[i];
  1421. vec2.copy(node.forcePrev, node.force);
  1422. vec2.copy(node.speedPrev, node.speed);
  1423. vec2.set(node.force, 0, 0);
  1424. }
  1425. this.updateNodeNodeForce();
  1426. if (this.gravity > 0) {
  1427. this.updateGravityForce();
  1428. }
  1429. this.updateEdgeForce();
  1430. if (this.preventNodeEdgeOverlap) {
  1431. this.updateNodeEdgeForce();
  1432. }
  1433. };
  1434. ForceLayout.prototype.updatePosition = function () {
  1435. var nNodes = this.nodes.length;
  1436. var v = vec2.create();
  1437. for (var i = 0; i < nNodes; i++) {
  1438. var node = this.nodes[i];
  1439. var speed = node.speed;
  1440. vec2.scale(node.force, node.force, 1 / 30);
  1441. var df = vec2.len(node.force) + 0.1;
  1442. var scale = Math.min(df, 500) / df;
  1443. vec2.scale(node.force, node.force, scale);
  1444. vec2.add(speed, speed, node.force);
  1445. vec2.scale(speed, speed, this.temperature);
  1446. vec2.sub(v, speed, node.speedPrev);
  1447. var swing = vec2.len(v);
  1448. if (swing > 0) {
  1449. vec2.scale(v, v, 1 / swing);
  1450. var base = vec2.len(node.speedPrev);
  1451. if (base > 0) {
  1452. swing = Math.min(swing / base, this.maxSpeedIncrease) * base;
  1453. vec2.scaleAndAdd(speed, node.speedPrev, v, swing);
  1454. }
  1455. }
  1456. var ds = vec2.len(speed);
  1457. var scale = Math.min(ds, 100) / (ds + 0.1);
  1458. vec2.scale(speed, speed, scale);
  1459. vec2.add(node.position, node.position, speed);
  1460. }
  1461. };
  1462. ForceLayout.prototype.updateNodeNodeForce = function () {
  1463. var nNodes = this.nodes.length;
  1464. for (var i = 0; i < nNodes; i++) {
  1465. var na = this.nodes[i];
  1466. if (this.barnesHutOptimize) {
  1467. this.applyRegionToNodeRepulsion(this._rootRegion, na);
  1468. } else {
  1469. for (var j = i + 1; j < nNodes; j++) {
  1470. var nb = this.nodes[j];
  1471. this.applyNodeToNodeRepulsion(na, nb, false);
  1472. }
  1473. }
  1474. }
  1475. };
  1476. ForceLayout.prototype.updateGravityForce = function () {
  1477. for (var i = 0; i < this.nodes.length; i++) {
  1478. this.applyNodeGravity(this.nodes[i]);
  1479. }
  1480. };
  1481. ForceLayout.prototype.updateEdgeForce = function () {
  1482. for (var i = 0; i < this.edges.length; i++) {
  1483. this.applyEdgeAttraction(this.edges[i]);
  1484. }
  1485. };
  1486. ForceLayout.prototype.updateNodeEdgeForce = function () {
  1487. for (var i = 0; i < this.nodes.length; i++) {
  1488. for (var j = 0; j < this.edges.length; j++) {
  1489. this.applyEdgeToNodeRepulsion(this.edges[j], this.nodes[i]);
  1490. }
  1491. }
  1492. };
  1493. ForceLayout.prototype.applyRegionToNodeRepulsion = function () {
  1494. var v = vec2.create();
  1495. return function applyRegionToNodeRepulsion(region, node) {
  1496. if (region.node) {
  1497. this.applyNodeToNodeRepulsion(region.node, node, true);
  1498. } else {
  1499. if (region.mass === 0 && node.mass === 0) {
  1500. return;
  1501. }
  1502. vec2.sub(v, node.position, region.centerOfMass);
  1503. var d2 = v[0] * v[0] + v[1] * v[1];
  1504. if (d2 > this.barnesHutTheta * region.size * region.size) {
  1505. var factor = this._k * this._k * (node.mass + region.mass) / (d2 + 1);
  1506. vec2.scaleAndAdd(node.force, node.force, v, factor * 2);
  1507. } else {
  1508. for (var i = 0; i < region.nSubRegions; i++) {
  1509. this.applyRegionToNodeRepulsion(region.subRegions[i], node);
  1510. }
  1511. }
  1512. }
  1513. };
  1514. }();
  1515. ForceLayout.prototype.applyNodeToNodeRepulsion = function () {
  1516. var v = vec2.create();
  1517. return function applyNodeToNodeRepulsion(na, nb, oneWay) {
  1518. if (na === nb) {
  1519. return;
  1520. }
  1521. if (na.mass === 0 && nb.mass === 0) {
  1522. return;
  1523. }
  1524. vec2.sub(v, na.position, nb.position);
  1525. var d2 = v[0] * v[0] + v[1] * v[1];
  1526. if (d2 === 0) {
  1527. return;
  1528. }
  1529. var factor;
  1530. var mass = na.mass + nb.mass;
  1531. var d = Math.sqrt(d2);
  1532. vec2.scale(v, v, 1 / d);
  1533. if (this.preventNodeOverlap) {
  1534. d = d - na.size - nb.size;
  1535. if (d > 0) {
  1536. factor = this.nodeToNodeRepulsionFactor(mass, d, this._k);
  1537. } else if (d <= 0) {
  1538. factor = this._k * this._k * 10 * mass;
  1539. }
  1540. } else {
  1541. factor = this.nodeToNodeRepulsionFactor(mass, d, this._k);
  1542. }
  1543. if (!oneWay) {
  1544. vec2.scaleAndAdd(na.force, na.force, v, factor * 2);
  1545. }
  1546. vec2.scaleAndAdd(nb.force, nb.force, v, -factor * 2);
  1547. };
  1548. }();
  1549. ForceLayout.prototype.applyEdgeAttraction = function () {
  1550. var v = vec2.create();
  1551. return function applyEdgeAttraction(edge) {
  1552. var na = edge.node1;
  1553. var nb = edge.node2;
  1554. vec2.sub(v, na.position, nb.position);
  1555. var d = vec2.len(v);
  1556. var w;
  1557. if (this.edgeWeightInfluence === 0) {
  1558. w = 1;
  1559. } else if (this.edgeWeightInfluence == 1) {
  1560. w = edge.weight;
  1561. } else {
  1562. w = Math.pow(edge.weight, this.edgeWeightInfluence);
  1563. }
  1564. var factor;
  1565. if (this.preventOverlap) {
  1566. d = d - na.size - nb.size;
  1567. if (d <= 0) {
  1568. return;
  1569. }
  1570. }
  1571. var factor = this.attractionFactor(w, d, this._k);
  1572. vec2.scaleAndAdd(na.force, na.force, v, -factor);
  1573. vec2.scaleAndAdd(nb.force, nb.force, v, factor);
  1574. };
  1575. }();
  1576. ForceLayout.prototype.applyNodeGravity = function () {
  1577. var v = vec2.create();
  1578. return function (node) {
  1579. vec2.sub(v, this.center, node.position);
  1580. if (this.width > this.height) {
  1581. v[1] *= this.width / this.height;
  1582. } else {
  1583. v[0] *= this.height / this.width;
  1584. }
  1585. var d = vec2.len(v) / 100;
  1586. if (this.strongGravity) {
  1587. vec2.scaleAndAdd(node.force, node.force, v, d * this.gravity * node.mass);
  1588. } else {
  1589. vec2.scaleAndAdd(node.force, node.force, v, this.gravity * node.mass / (d + 1));
  1590. }
  1591. };
  1592. }();
  1593. ForceLayout.prototype.applyEdgeToNodeRepulsion = function () {
  1594. var v12 = vec2.create();
  1595. var v13 = vec2.create();
  1596. var p = vec2.create();
  1597. return function (e, n3) {
  1598. var n1 = e.node1;
  1599. var n2 = e.node2;
  1600. if (n1 === n3 || n2 === n3) {
  1601. return;
  1602. }
  1603. vec2.sub(v12, n2.position, n1.position);
  1604. vec2.sub(v13, n3.position, n1.position);
  1605. var len12 = vec2.len(v12);
  1606. vec2.scale(v12, v12, 1 / len12);
  1607. var len = vec2.dot(v12, v13);
  1608. if (len < 0 || len > len12) {
  1609. return;
  1610. }
  1611. vec2.scaleAndAdd(p, n1.position, v12, len);
  1612. var dist = vec2.dist(p, n3.position) - n3.size;
  1613. var factor = this.edgeToNodeRepulsionFactor(n3.mass, Math.max(dist, 0.1), 100);
  1614. vec2.sub(v12, n3.position, p);
  1615. vec2.normalize(v12, v12);
  1616. vec2.scaleAndAdd(n3.force, n3.force, v12, factor);
  1617. vec2.scaleAndAdd(n1.force, n1.force, v12, -factor);
  1618. vec2.scaleAndAdd(n2.force, n2.force, v12, -factor);
  1619. };
  1620. }();
  1621. ForceLayout.prototype.updateBBox = function () {
  1622. var minX = Infinity;
  1623. var minY = Infinity;
  1624. var maxX = -Infinity;
  1625. var maxY = -Infinity;
  1626. for (var i = 0; i < this.nodes.length; i++) {
  1627. var pos = this.nodes[i].position;
  1628. minX = Math.min(minX, pos[0]);
  1629. minY = Math.min(minY, pos[1]);
  1630. maxX = Math.max(maxX, pos[0]);
  1631. maxY = Math.max(maxY, pos[1]);
  1632. }
  1633. this.bbox[0] = minX;
  1634. this.bbox[1] = minY;
  1635. this.bbox[2] = maxX;
  1636. this.bbox[3] = maxY;
  1637. };
  1638. ForceLayout.getWorkerCode = function () {
  1639. var str = __echartsForceLayoutWorker.toString();
  1640. return str.slice(str.indexOf('{') + 1, str.lastIndexOf('return'));
  1641. };
  1642. if (inWorker) {
  1643. var forceLayout = null;
  1644. self.onmessage = function (e) {
  1645. if (e.data instanceof ArrayBuffer) {
  1646. if (!forceLayout)
  1647. return;
  1648. var positionArr = new Float32Array(e.data);
  1649. var nNodes = positionArr.length / 2;
  1650. for (var i = 0; i < nNodes; i++) {
  1651. var node = forceLayout.nodes[i];
  1652. node.position[0] = positionArr[i * 2];
  1653. node.position[1] = positionArr[i * 2 + 1];
  1654. }
  1655. return;
  1656. }
  1657. switch (e.data.cmd) {
  1658. case 'init':
  1659. if (!forceLayout) {
  1660. forceLayout = new ForceLayout();
  1661. }
  1662. forceLayout.initNodes(e.data.nodesPosition, e.data.nodesMass, e.data.nodesSize);
  1663. forceLayout.initEdges(e.data.edges, e.data.edgesWeight);
  1664. break;
  1665. case 'updateConfig':
  1666. if (forceLayout) {
  1667. for (var name in e.data.config) {
  1668. forceLayout[name] = e.data.config[name];
  1669. }
  1670. }
  1671. break;
  1672. case 'update':
  1673. var steps = e.data.steps;
  1674. if (forceLayout) {
  1675. var nNodes = forceLayout.nodes.length;
  1676. var positionArr = new Float32Array(nNodes * 2);
  1677. forceLayout.temperature = e.data.temperature;
  1678. for (var i = 0; i < steps; i++) {
  1679. forceLayout.update();
  1680. forceLayout.temperature *= e.data.coolDown;
  1681. }
  1682. for (var i = 0; i < nNodes; i++) {
  1683. var node = forceLayout.nodes[i];
  1684. positionArr[i * 2] = node.position[0];
  1685. positionArr[i * 2 + 1] = node.position[1];
  1686. }
  1687. self.postMessage(positionArr.buffer, [positionArr.buffer]);
  1688. } else {
  1689. var emptyArr = new Float32Array();
  1690. self.postMessage(emptyArr.buffer, [emptyArr.buffer]);
  1691. }
  1692. break;
  1693. }
  1694. };
  1695. }
  1696. return ForceLayout;
  1697. });