plugins/report/public/echarts2/doc/echarts/chart/force.js in admin-sys-1.0.2 vs plugins/report/public/echarts2/doc/echarts/chart/force.js in admin-sys-1.1.0
- old
+ new
@@ -1,1697 +1,1697 @@
-define('echarts/chart/force', [
- 'require',
- './base',
- '../data/Graph',
- '../layout/Force',
- 'zrender/shape/Line',
- 'zrender/shape/BezierCurve',
- 'zrender/shape/Image',
- '../util/shape/Icon',
- '../config',
- '../util/ecData',
- 'zrender/tool/util',
- 'zrender/config',
- 'zrender/tool/vector',
- '../chart'
-], function (require) {
- 'use strict';
- var ChartBase = require('./base');
- var Graph = require('../data/Graph');
- var ForceLayout = require('../layout/Force');
- var LineShape = require('zrender/shape/Line');
- var BezierCurveShape = require('zrender/shape/BezierCurve');
- var ImageShape = require('zrender/shape/Image');
- var IconShape = require('../util/shape/Icon');
- var ecConfig = require('../config');
- ecConfig.force = {
- zlevel: 1,
- z: 2,
- center: [
- '50%',
- '50%'
- ],
- size: '100%',
- preventOverlap: false,
- coolDown: 0.99,
- minRadius: 10,
- maxRadius: 20,
- ratioScaling: false,
- large: false,
- useWorker: false,
- steps: 1,
- scaling: 1,
- gravity: 1,
- symbol: 'circle',
- symbolSize: 0,
- linkSymbol: null,
- linkSymbolSize: [
- 10,
- 15
- ],
- draggable: true,
- clickable: true,
- roam: false,
- itemStyle: {
- normal: {
- label: {
- show: false,
- position: 'inside'
- },
- nodeStyle: {
- brushType: 'both',
- borderColor: '#5182ab',
- borderWidth: 1
- },
- linkStyle: {
- color: '#5182ab',
- width: 1,
- type: 'line'
- }
- },
- emphasis: {
- label: { show: false },
- nodeStyle: {},
- linkStyle: { opacity: 0 }
- }
- }
- };
- var ecData = require('../util/ecData');
- var zrUtil = require('zrender/tool/util');
- var zrConfig = require('zrender/config');
- var vec2 = require('zrender/tool/vector');
- function Force(ecTheme, messageCenter, zr, option, myChart) {
- var self = this;
- ChartBase.call(this, ecTheme, messageCenter, zr, option, myChart);
- this.__nodePositionMap = {};
- this._graph = new Graph(true);
- this._layout = new ForceLayout();
- this._layout.onupdate = function () {
- self._step();
- };
- this._steps = 1;
- this.ondragstart = function () {
- ondragstart.apply(self, arguments);
- };
- this.ondragend = function () {
- ondragend.apply(self, arguments);
- };
- this.ondrop = function () {
- };
- this.shapeHandler.ondragstart = function () {
- self.isDragstart = true;
- };
- this.onmousemove = function () {
- onmousemove.apply(self, arguments);
- };
- this.refresh(option);
- }
- Force.prototype = {
- constructor: Force,
- type: ecConfig.CHART_TYPE_FORCE,
- _init: function () {
- this.selectedMap = {};
- var legend = this.component.legend;
- var series = this.series;
- var serieName;
- this.clear();
- for (var i = 0, l = series.length; i < l; i++) {
- var serie = series[i];
- if (serie.type === ecConfig.CHART_TYPE_FORCE) {
- series[i] = this.reformOption(series[i]);
- serieName = series[i].name || '';
- this.selectedMap[serieName] = legend ? legend.isSelected(serieName) : true;
- if (!this.selectedMap[serieName]) {
- continue;
- }
- this.buildMark(i);
- this._initSerie(serie, i);
- break;
- }
- }
- this.animationEffect();
- },
- _getNodeCategory: function (serie, node) {
- return serie.categories && serie.categories[node.category || 0];
- },
- _getNodeQueryTarget: function (serie, node, type) {
- type = type || 'normal';
- var category = this._getNodeCategory(serie, node) || {};
- return [
- node.itemStyle && node.itemStyle[type],
- category && category.itemStyle && category.itemStyle[type],
- serie.itemStyle[type].nodeStyle
- ];
- },
- _getEdgeQueryTarget: function (serie, edge, type) {
- type = type || 'normal';
- return [
- edge.itemStyle && edge.itemStyle[type],
- serie.itemStyle[type].linkStyle
- ];
- },
- _initSerie: function (serie, serieIdx) {
- this._temperature = 1;
- if (serie.matrix) {
- this._graph = this._getSerieGraphFromDataMatrix(serie);
- } else if (serie.links) {
- this._graph = this._getSerieGraphFromNodeLinks(serie);
- }
- this._buildLinkShapes(serie, serieIdx);
- this._buildNodeShapes(serie, serieIdx);
- var panable = serie.roam === true || serie.roam === 'move';
- var zoomable = serie.roam === true || serie.roam === 'scale';
- this.zr.modLayer(this.getZlevelBase(), {
- panable: panable,
- zoomable: zoomable
- });
- if (this.query('markPoint.effect.show') || this.query('markLine.effect.show')) {
- this.zr.modLayer(ecConfig.EFFECT_ZLEVEL, {
- panable: panable,
- zoomable: zoomable
- });
- }
- this._initLayout(serie);
- this._step();
- },
- _getSerieGraphFromDataMatrix: function (serie) {
- var nodesData = [];
- var count = 0;
- var matrix = [];
- for (var i = 0; i < serie.matrix.length; i++) {
- matrix[i] = serie.matrix[i].slice();
- }
- var data = serie.data || serie.nodes;
- for (var i = 0; i < data.length; i++) {
- var node = {};
- var group = data[i];
- for (var key in group) {
- if (key === 'name') {
- node['id'] = group['name'];
- } else {
- node[key] = group[key];
- }
- }
- var category = this._getNodeCategory(serie, group);
- var name = category ? category.name : group.name;
- this.selectedMap[name] = this.isSelected(name);
- if (this.selectedMap[name]) {
- nodesData.push(node);
- count++;
- } else {
- matrix.splice(count, 1);
- for (var j = 0; j < matrix.length; j++) {
- matrix[j].splice(count, 1);
- }
- }
- }
- var graph = Graph.fromMatrix(nodesData, matrix, true);
- graph.eachNode(function (n, idx) {
- n.layout = {
- size: n.data.value,
- mass: 0
- };
- n.rawIndex = idx;
- });
- graph.eachEdge(function (e) {
- e.layout = { weight: e.data.weight };
- });
- return graph;
- },
- _getSerieGraphFromNodeLinks: function (serie) {
- var graph = new Graph(true);
- var nodes = serie.data || serie.nodes;
- for (var i = 0, len = nodes.length; i < len; i++) {
- var n = nodes[i];
- if (!n || n.ignore) {
- continue;
- }
- var category = this._getNodeCategory(serie, n);
- var name = category ? category.name : n.name;
- this.selectedMap[name] = this.isSelected(name);
- if (this.selectedMap[name]) {
- var node = graph.addNode(n.name, n);
- node.rawIndex = i;
- }
- }
- for (var i = 0, len = serie.links.length; i < len; i++) {
- var e = serie.links[i];
- var n1 = e.source;
- var n2 = e.target;
- if (typeof n1 === 'number') {
- n1 = nodes[n1];
- if (n1) {
- n1 = n1.name;
- }
- }
- if (typeof n2 === 'number') {
- n2 = nodes[n2];
- if (n2) {
- n2 = n2.name;
- }
- }
- var edge = graph.addEdge(n1, n2, e);
- if (edge) {
- edge.rawIndex = i;
- }
- }
- graph.eachNode(function (n) {
- var value = n.data.value;
- if (value == null) {
- value = 0;
- for (var i = 0; i < n.edges.length; i++) {
- value += n.edges[i].data.weight || 0;
- }
- }
- n.layout = {
- size: value,
- mass: 0
- };
- });
- graph.eachEdge(function (e) {
- e.layout = { weight: e.data.weight == null ? 1 : e.data.weight };
- });
- return graph;
- },
- _initLayout: function (serie) {
- var graph = this._graph;
- var len = graph.nodes.length;
- var minRadius = this.query(serie, 'minRadius');
- var maxRadius = this.query(serie, 'maxRadius');
- this._steps = serie.steps || 1;
- var layout = this._layout;
- layout.center = this.parseCenter(this.zr, serie.center);
- layout.width = this.parsePercent(serie.size, this.zr.getWidth());
- layout.height = this.parsePercent(serie.size, this.zr.getHeight());
- layout.large = serie.large;
- layout.scaling = serie.scaling;
- layout.ratioScaling = serie.ratioScaling;
- layout.gravity = serie.gravity;
- layout.temperature = 1;
- layout.coolDown = serie.coolDown;
- layout.preventNodeEdgeOverlap = serie.preventOverlap;
- layout.preventNodeOverlap = serie.preventOverlap;
- var min = Infinity;
- var max = -Infinity;
- for (var i = 0; i < len; i++) {
- var gNode = graph.nodes[i];
- max = Math.max(gNode.layout.size, max);
- min = Math.min(gNode.layout.size, min);
- }
- var divider = max - min;
- for (var i = 0; i < len; i++) {
- var gNode = graph.nodes[i];
- if (divider > 0) {
- gNode.layout.size = (gNode.layout.size - min) * (maxRadius - minRadius) / divider + minRadius;
- gNode.layout.mass = gNode.layout.size / maxRadius;
- } else {
- gNode.layout.size = (maxRadius - minRadius) / 2;
- gNode.layout.mass = 0.5;
- }
- }
- for (var i = 0; i < len; i++) {
- var gNode = graph.nodes[i];
- if (typeof this.__nodePositionMap[gNode.id] !== 'undefined') {
- gNode.layout.position = vec2.create();
- vec2.copy(gNode.layout.position, this.__nodePositionMap[gNode.id]);
- } else if (typeof gNode.data.initial !== 'undefined') {
- gNode.layout.position = vec2.create();
- vec2.copy(gNode.layout.position, gNode.data.initial);
- } else {
- var center = this._layout.center;
- var size = Math.min(this._layout.width, this._layout.height);
- gNode.layout.position = _randomInSquare(center[0], center[1], size * 0.8);
- }
- var style = gNode.shape.style;
- var radius = gNode.layout.size;
- style.width = style.width || radius * 2;
- style.height = style.height || radius * 2;
- style.x = -style.width / 2;
- style.y = -style.height / 2;
- vec2.copy(gNode.shape.position, gNode.layout.position);
- }
- len = graph.edges.length;
- max = -Infinity;
- for (var i = 0; i < len; i++) {
- var e = graph.edges[i];
- if (e.layout.weight > max) {
- max = e.layout.weight;
- }
- }
- for (var i = 0; i < len; i++) {
- var e = graph.edges[i];
- e.layout.weight /= max;
- }
- this._layout.init(graph, serie.useWorker);
- },
- _buildNodeShapes: function (serie, serieIdx) {
- var graph = this._graph;
- var categories = this.query(serie, 'categories');
- graph.eachNode(function (node) {
- var category = this._getNodeCategory(serie, node.data);
- var queryTarget = [
- node.data,
- category,
- serie
- ];
- var styleQueryTarget = this._getNodeQueryTarget(serie, node.data);
- var emphasisStyleQueryTarget = this._getNodeQueryTarget(serie, node.data, 'emphasis');
- var shape = new IconShape({
- style: {
- x: 0,
- y: 0,
- color: this.deepQuery(styleQueryTarget, 'color'),
- brushType: 'both',
- strokeColor: this.deepQuery(styleQueryTarget, 'strokeColor') || this.deepQuery(styleQueryTarget, 'borderColor'),
- lineWidth: this.deepQuery(styleQueryTarget, 'lineWidth') || this.deepQuery(styleQueryTarget, 'borderWidth')
- },
- highlightStyle: {
- color: this.deepQuery(emphasisStyleQueryTarget, 'color'),
- strokeColor: this.deepQuery(emphasisStyleQueryTarget, 'strokeColor') || this.deepQuery(emphasisStyleQueryTarget, 'borderColor'),
- lineWidth: this.deepQuery(emphasisStyleQueryTarget, 'lineWidth') || this.deepQuery(emphasisStyleQueryTarget, 'borderWidth')
- },
- clickable: serie.clickable,
- zlevel: this.getZlevelBase(),
- z: this.getZBase()
- });
- if (!shape.style.color) {
- shape.style.color = category ? this.getColor(category.name) : this.getColor(node.id);
- }
- shape.style.iconType = this.deepQuery(queryTarget, 'symbol');
- var symbolSize = this.deepQuery(queryTarget, 'symbolSize') || 0;
- if (typeof symbolSize === 'number') {
- symbolSize = [
- symbolSize,
- symbolSize
- ];
- }
- shape.style.width = symbolSize[0] * 2;
- shape.style.height = symbolSize[1] * 2;
- if (shape.style.iconType.match('image')) {
- shape.style.image = shape.style.iconType.replace(new RegExp('^image:\\/\\/'), '');
- shape = new ImageShape({
- style: shape.style,
- highlightStyle: shape.highlightStyle,
- clickable: shape.clickable,
- zlevel: this.getZlevelBase(),
- z: this.getZBase()
- });
- }
- if (this.deepQuery(queryTarget, 'itemStyle.normal.label.show')) {
- shape.style.text = node.data.label == null ? node.id : node.data.label;
- shape.style.textPosition = this.deepQuery(queryTarget, 'itemStyle.normal.label.position');
- shape.style.textColor = this.deepQuery(queryTarget, 'itemStyle.normal.label.textStyle.color');
- shape.style.textFont = this.getFont(this.deepQuery(queryTarget, 'itemStyle.normal.label.textStyle') || {});
- }
- if (this.deepQuery(queryTarget, 'itemStyle.emphasis.label.show')) {
- shape.highlightStyle.textPosition = this.deepQuery(queryTarget, 'itemStyle.emphasis.label.position');
- shape.highlightStyle.textColor = this.deepQuery(queryTarget, 'itemStyle.emphasis.label.textStyle.color');
- shape.highlightStyle.textFont = this.getFont(this.deepQuery(queryTarget, 'itemStyle.emphasis.label.textStyle') || {});
- }
- if (this.deepQuery(queryTarget, 'draggable')) {
- this.setCalculable(shape);
- shape.dragEnableTime = 0;
- shape.draggable = true;
- shape.ondragstart = this.shapeHandler.ondragstart;
- shape.ondragover = null;
- }
- var categoryName = '';
- if (typeof node.category !== 'undefined') {
- var category = categories[node.category];
- categoryName = category && category.name || '';
- }
- ecData.pack(shape, serie, serieIdx, node.data, node.rawIndex, node.data.name || '', node.category);
- this.shapeList.push(shape);
- this.zr.addShape(shape);
- node.shape = shape;
- }, this);
- },
- _buildLinkShapes: function (serie, serieIdx) {
- var graph = this._graph;
- var len = graph.edges.length;
- for (var i = 0; i < len; i++) {
- var gEdge = graph.edges[i];
- var link = gEdge.data;
- var source = gEdge.node1;
- var target = gEdge.node2;
- var otherEdge = graph.getEdge(target, source);
- var queryTarget = this._getEdgeQueryTarget(serie, link);
- var linkType = this.deepQuery(queryTarget, 'type');
- if (serie.linkSymbol && serie.linkSymbol !== 'none') {
- linkType = 'line';
- }
- var LinkShapeCtor = linkType === 'line' ? LineShape : BezierCurveShape;
- var linkShape = new LinkShapeCtor({
- style: {
- xStart: 0,
- yStart: 0,
- xEnd: 0,
- yEnd: 0
- },
- clickable: this.query(serie, 'clickable'),
- highlightStyle: {},
- zlevel: this.getZlevelBase(),
- z: this.getZBase()
- });
- if (otherEdge && otherEdge.shape) {
- linkShape.style.offset = 4;
- otherEdge.shape.style.offset = 4;
- }
- zrUtil.merge(linkShape.style, this.query(serie, 'itemStyle.normal.linkStyle'), true);
- zrUtil.merge(linkShape.highlightStyle, this.query(serie, 'itemStyle.emphasis.linkStyle'), true);
- if (typeof link.itemStyle !== 'undefined') {
- if (link.itemStyle.normal) {
- zrUtil.merge(linkShape.style, link.itemStyle.normal, true);
- }
- if (link.itemStyle.emphasis) {
- zrUtil.merge(linkShape.highlightStyle, link.itemStyle.emphasis, true);
- }
- }
- linkShape.style.lineWidth = linkShape.style.lineWidth || linkShape.style.width;
- linkShape.style.strokeColor = linkShape.style.strokeColor || linkShape.style.color;
- linkShape.highlightStyle.lineWidth = linkShape.highlightStyle.lineWidth || linkShape.highlightStyle.width;
- linkShape.highlightStyle.strokeColor = linkShape.highlightStyle.strokeColor || linkShape.highlightStyle.color;
- ecData.pack(linkShape, serie, serieIdx, gEdge.data, gEdge.rawIndex == null ? i : gEdge.rawIndex, gEdge.data.name || source.id + ' - ' + target.id, source.id, target.id);
- this.shapeList.push(linkShape);
- this.zr.addShape(linkShape);
- gEdge.shape = linkShape;
- if (serie.linkSymbol && serie.linkSymbol !== 'none') {
- var symbolShape = new IconShape({
- style: {
- x: -5,
- y: 0,
- width: serie.linkSymbolSize[0],
- height: serie.linkSymbolSize[1],
- iconType: serie.linkSymbol,
- brushType: 'fill',
- color: linkShape.style.strokeColor
- },
- highlightStyle: { brushType: 'fill' },
- position: [
- 0,
- 0
- ],
- rotation: 0,
- zlevel: this.getZlevelBase(),
- z: this.getZBase()
- });
- linkShape._symbolShape = symbolShape;
- this.shapeList.push(symbolShape);
- this.zr.addShape(symbolShape);
- }
- }
- },
- _updateLinkShapes: function () {
- var v = vec2.create();
- var n = vec2.create();
- var p1 = vec2.create();
- var p2 = vec2.create();
- var edges = this._graph.edges;
- for (var i = 0, len = edges.length; i < len; i++) {
- var edge = edges[i];
- var sourceShape = edge.node1.shape;
- var targetShape = edge.node2.shape;
- vec2.copy(p1, sourceShape.position);
- vec2.copy(p2, targetShape.position);
- var edgeShapeStyle = edge.shape.style;
- vec2.sub(v, p1, p2);
- vec2.normalize(v, v);
- if (edgeShapeStyle.offset) {
- n[0] = v[1];
- n[1] = -v[0];
- vec2.scaleAndAdd(p1, p1, n, edgeShapeStyle.offset);
- vec2.scaleAndAdd(p2, p2, n, edgeShapeStyle.offset);
- } else if (edge.shape.type === 'bezier-curve') {
- edgeShapeStyle.cpX1 = (p1[0] + p2[0]) / 2 - (p2[1] - p1[1]) / 4;
- edgeShapeStyle.cpY1 = (p1[1] + p2[1]) / 2 - (p1[0] - p2[0]) / 4;
- }
- edgeShapeStyle.xStart = p1[0];
- edgeShapeStyle.yStart = p1[1];
- edgeShapeStyle.xEnd = p2[0];
- edgeShapeStyle.yEnd = p2[1];
- edge.shape.modSelf();
- if (edge.shape._symbolShape) {
- var symbolShape = edge.shape._symbolShape;
- vec2.copy(symbolShape.position, p2);
- vec2.scaleAndAdd(symbolShape.position, symbolShape.position, v, targetShape.style.width / 2 + 2);
- var angle = Math.atan2(v[1], v[0]);
- symbolShape.rotation = Math.PI / 2 - angle;
- symbolShape.modSelf();
- }
- }
- },
- _syncNodePositions: function () {
- var graph = this._graph;
- for (var i = 0; i < graph.nodes.length; i++) {
- var gNode = graph.nodes[i];
- var position = gNode.layout.position;
- var node = gNode.data;
- var shape = gNode.shape;
- var fixX = shape.fixed || node.fixX;
- var fixY = shape.fixed || node.fixY;
- if (fixX === true) {
- fixX = 1;
- } else if (isNaN(fixX)) {
- fixX = 0;
- }
- if (fixY === true) {
- fixY = 1;
- } else if (isNaN(fixY)) {
- fixY = 0;
- }
- shape.position[0] += (position[0] - shape.position[0]) * (1 - fixX);
- shape.position[1] += (position[1] - shape.position[1]) * (1 - fixY);
- vec2.copy(position, shape.position);
- var nodeName = node.name;
- if (nodeName) {
- var gPos = this.__nodePositionMap[nodeName];
- if (!gPos) {
- gPos = this.__nodePositionMap[nodeName] = vec2.create();
- }
- vec2.copy(gPos, position);
- }
- shape.modSelf();
- }
- },
- _step: function (e) {
- this._syncNodePositions();
- this._updateLinkShapes();
- this.zr.refreshNextFrame();
- if (this._layout.temperature > 0.01) {
- this._layout.step(this._steps);
- } else {
- this.messageCenter.dispatch(ecConfig.EVENT.FORCE_LAYOUT_END, {}, {}, this.myChart);
- }
- },
- refresh: function (newOption) {
- if (newOption) {
- this.option = newOption;
- this.series = this.option.series;
- }
- this.legend = this.component.legend;
- if (this.legend) {
- this.getColor = function (param) {
- return this.legend.getColor(param);
- };
- this.isSelected = function (param) {
- return this.legend.isSelected(param);
- };
- } else {
- var colorMap = {};
- var count = 0;
- this.getColor = function (key) {
- if (colorMap[key]) {
- return colorMap[key];
- }
- if (!colorMap[key]) {
- colorMap[key] = this.zr.getColor(count++);
- }
- return colorMap[key];
- };
- this.isSelected = function () {
- return true;
- };
- }
- this._init();
- },
- dispose: function () {
- this.clear();
- this.shapeList = null;
- this.effectList = null;
- this._layout.dispose();
- this._layout = null;
- this.__nodePositionMap = {};
- },
- getPosition: function () {
- var position = [];
- this._graph.eachNode(function (n) {
- if (n.layout) {
- position.push({
- name: n.data.name,
- position: Array.prototype.slice.call(n.layout.position)
- });
- }
- });
- return position;
- }
- };
- function ondragstart(param) {
- if (!this.isDragstart || !param.target) {
- return;
- }
- var shape = param.target;
- shape.fixed = true;
- this.isDragstart = false;
- this.zr.on(zrConfig.EVENT.MOUSEMOVE, this.onmousemove);
- }
- function onmousemove() {
- this._layout.temperature = 0.8;
- this._step();
- }
- function ondragend(param, status) {
- if (!this.isDragend || !param.target) {
- return;
- }
- var shape = param.target;
- shape.fixed = false;
- status.dragIn = true;
- status.needRefresh = false;
- this.isDragend = false;
- this.zr.un(zrConfig.EVENT.MOUSEMOVE, this.onmousemove);
- }
- function _randomInSquare(x, y, size) {
- var v = vec2.create();
- v[0] = (Math.random() - 0.5) * size + x;
- v[1] = (Math.random() - 0.5) * size + y;
- return v;
- }
- zrUtil.inherits(Force, ChartBase);
- require('../chart').define('force', Force);
- return Force;
-});define('echarts/data/Graph', [
- 'require',
- 'zrender/tool/util'
-], function (require) {
- var util = require('zrender/tool/util');
- 'use strict';
- var Graph = function (directed) {
- this._directed = directed || false;
- this.nodes = [];
- this.edges = [];
- this._nodesMap = {};
- this._edgesMap = {};
- };
- Graph.prototype.isDirected = function () {
- return this._directed;
- };
- Graph.prototype.addNode = function (id, data) {
- if (this._nodesMap[id]) {
- return this._nodesMap[id];
- }
- var node = new Graph.Node(id, data);
- this.nodes.push(node);
- this._nodesMap[id] = node;
- return node;
- };
- Graph.prototype.getNodeById = function (id) {
- return this._nodesMap[id];
- };
- Graph.prototype.addEdge = function (n1, n2, data) {
- if (typeof n1 == 'string') {
- n1 = this._nodesMap[n1];
- }
- if (typeof n2 == 'string') {
- n2 = this._nodesMap[n2];
- }
- if (!n1 || !n2) {
- return;
- }
- var key = n1.id + '-' + n2.id;
- if (this._edgesMap[key]) {
- return this._edgesMap[key];
- }
- var edge = new Graph.Edge(n1, n2, data);
- if (this._directed) {
- n1.outEdges.push(edge);
- n2.inEdges.push(edge);
- }
- n1.edges.push(edge);
- if (n1 !== n2) {
- n2.edges.push(edge);
- }
- this.edges.push(edge);
- this._edgesMap[key] = edge;
- return edge;
- };
- Graph.prototype.removeEdge = function (edge) {
- var n1 = edge.node1;
- var n2 = edge.node2;
- var key = n1.id + '-' + n2.id;
- if (this._directed) {
- n1.outEdges.splice(util.indexOf(n1.outEdges, edge), 1);
- n2.inEdges.splice(util.indexOf(n2.inEdges, edge), 1);
- }
- n1.edges.splice(util.indexOf(n1.edges, edge), 1);
- if (n1 !== n2) {
- n2.edges.splice(util.indexOf(n2.edges, edge), 1);
- }
- delete this._edgesMap[key];
- this.edges.splice(util.indexOf(this.edges, edge), 1);
- };
- Graph.prototype.getEdge = function (n1, n2) {
- if (typeof n1 !== 'string') {
- n1 = n1.id;
- }
- if (typeof n2 !== 'string') {
- n2 = n2.id;
- }
- if (this._directed) {
- return this._edgesMap[n1 + '-' + n2];
- } else {
- return this._edgesMap[n1 + '-' + n2] || this._edgesMap[n2 + '-' + n1];
- }
- };
- Graph.prototype.removeNode = function (node) {
- if (typeof node === 'string') {
- node = this._nodesMap[node];
- if (!node) {
- return;
- }
- }
- delete this._nodesMap[node.id];
- this.nodes.splice(util.indexOf(this.nodes, node), 1);
- for (var i = 0; i < this.edges.length;) {
- var edge = this.edges[i];
- if (edge.node1 === node || edge.node2 === node) {
- this.removeEdge(edge);
- } else {
- i++;
- }
- }
- };
- Graph.prototype.filterNode = function (cb, context) {
- var len = this.nodes.length;
- for (var i = 0; i < len;) {
- if (cb.call(context, this.nodes[i], i)) {
- i++;
- } else {
- this.removeNode(this.nodes[i]);
- len--;
- }
- }
- };
- Graph.prototype.filterEdge = function (cb, context) {
- var len = this.edges.length;
- for (var i = 0; i < len;) {
- if (cb.call(context, this.edges[i], i)) {
- i++;
- } else {
- this.removeEdge(this.edges[i]);
- len--;
- }
- }
- };
- Graph.prototype.eachNode = function (cb, context) {
- var len = this.nodes.length;
- for (var i = 0; i < len; i++) {
- if (this.nodes[i]) {
- cb.call(context, this.nodes[i], i);
- }
- }
- };
- Graph.prototype.eachEdge = function (cb, context) {
- var len = this.edges.length;
- for (var i = 0; i < len; i++) {
- if (this.edges[i]) {
- cb.call(context, this.edges[i], i);
- }
- }
- };
- Graph.prototype.clear = function () {
- this.nodes.length = 0;
- this.edges.length = 0;
- this._nodesMap = {};
- this._edgesMap = {};
- };
- Graph.prototype.breadthFirstTraverse = function (cb, startNode, direction, context) {
- if (typeof startNode === 'string') {
- startNode = this._nodesMap[startNode];
- }
- if (!startNode) {
- return;
- }
- var edgeType = 'edges';
- if (direction === 'out') {
- edgeType = 'outEdges';
- } else if (direction === 'in') {
- edgeType = 'inEdges';
- }
- for (var i = 0; i < this.nodes.length; i++) {
- this.nodes[i].__visited = false;
- }
- if (cb.call(context, startNode, null)) {
- return;
- }
- var queue = [startNode];
- while (queue.length) {
- var currentNode = queue.shift();
- var edges = currentNode[edgeType];
- for (var i = 0; i < edges.length; i++) {
- var e = edges[i];
- var otherNode = e.node1 === currentNode ? e.node2 : e.node1;
- if (!otherNode.__visited) {
- if (cb.call(otherNode, otherNode, currentNode)) {
- return;
- }
- queue.push(otherNode);
- otherNode.__visited = true;
- }
- }
- }
- };
- Graph.prototype.clone = function () {
- var graph = new Graph(this._directed);
- for (var i = 0; i < this.nodes.length; i++) {
- graph.addNode(this.nodes[i].id, this.nodes[i].data);
- }
- for (var i = 0; i < this.edges.length; i++) {
- var e = this.edges[i];
- graph.addEdge(e.node1.id, e.node2.id, e.data);
- }
- return graph;
- };
- var Node = function (id, data) {
- this.id = id;
- this.data = data || null;
- this.inEdges = [];
- this.outEdges = [];
- this.edges = [];
- };
- Node.prototype.degree = function () {
- return this.edges.length;
- };
- Node.prototype.inDegree = function () {
- return this.inEdges.length;
- };
- Node.prototype.outDegree = function () {
- return this.outEdges.length;
- };
- var Edge = function (node1, node2, data) {
- this.node1 = node1;
- this.node2 = node2;
- this.data = data || null;
- };
- Graph.Node = Node;
- Graph.Edge = Edge;
- Graph.fromMatrix = function (nodesData, matrix, directed) {
- if (!matrix || !matrix.length || matrix[0].length !== matrix.length || nodesData.length !== matrix.length) {
- return;
- }
- var size = matrix.length;
- var graph = new Graph(directed);
- for (var i = 0; i < size; i++) {
- var node = graph.addNode(nodesData[i].id, nodesData[i]);
- node.data.value = 0;
- if (directed) {
- node.data.outValue = node.data.inValue = 0;
- }
- }
- for (var i = 0; i < size; i++) {
- for (var j = 0; j < size; j++) {
- var item = matrix[i][j];
- if (directed) {
- graph.nodes[i].data.outValue += item;
- graph.nodes[j].data.inValue += item;
- }
- graph.nodes[i].data.value += item;
- graph.nodes[j].data.value += item;
- }
- }
- for (var i = 0; i < size; i++) {
- for (var j = i; j < size; j++) {
- var item = matrix[i][j];
- if (item === 0) {
- continue;
- }
- var n1 = graph.nodes[i];
- var n2 = graph.nodes[j];
- var edge = graph.addEdge(n1, n2, {});
- edge.data.weight = item;
- if (i !== j) {
- if (directed && matrix[j][i]) {
- var inEdge = graph.addEdge(n2, n1, {});
- inEdge.data.weight = matrix[j][i];
- }
- }
- }
- }
- return graph;
- };
- return Graph;
-});define('echarts/layout/Force', [
- 'require',
- './forceLayoutWorker',
- 'zrender/tool/vector'
-], function (require) {
- var ForceLayoutWorker = require('./forceLayoutWorker');
- var vec2 = require('zrender/tool/vector');
- var requestAnimationFrame = window.requestAnimationFrame || window.msRequestAnimationFrame || window.mozRequestAnimationFrame || window.webkitRequestAnimationFrame || function (func) {
- setTimeout(func, 16);
- };
- var ArrayCtor = typeof Float32Array == 'undefined' ? Array : Float32Array;
- var workerUrl;
- function createWorkerUrl() {
- if (typeof Worker !== 'undefined' && typeof Blob !== 'undefined') {
- try {
- var blob = new Blob([ForceLayoutWorker.getWorkerCode()]);
- workerUrl = window.URL.createObjectURL(blob);
- } catch (e) {
- workerUrl = '';
- }
- }
- return workerUrl;
- }
- var ForceLayout = function (opts) {
- if (typeof workerUrl === 'undefined') {
- createWorkerUrl();
- }
- opts = opts || {};
- this.width = opts.width || 500;
- this.height = opts.height || 500;
- this.center = opts.center || [
- this.width / 2,
- this.height / 2
- ];
- this.ratioScaling = opts.ratioScaling || false;
- this.scaling = opts.scaling || 1;
- this.gravity = typeof opts.gravity !== 'undefined' ? opts.gravity : 1;
- this.large = opts.large || false;
- this.preventNodeOverlap = opts.preventNodeOverlap || false;
- this.preventNodeEdgeOverlap = opts.preventNodeEdgeOverlap || false;
- this.maxSpeedIncrease = opts.maxSpeedIncrease || 1;
- this.onupdate = opts.onupdate || function () {
- };
- this.temperature = opts.temperature || 1;
- this.coolDown = opts.coolDown || 0.99;
- this._layout = null;
- this._layoutWorker = null;
- var self = this;
- var _$onupdate = this._$onupdate;
- this._$onupdate = function (e) {
- _$onupdate.call(self, e);
- };
- };
- ForceLayout.prototype.updateConfig = function () {
- var width = this.width;
- var height = this.height;
- var size = Math.min(width, height);
- var config = {
- center: this.center,
- width: this.ratioScaling ? width : size,
- height: this.ratioScaling ? height : size,
- scaling: this.scaling || 1,
- gravity: this.gravity || 1,
- barnesHutOptimize: this.large,
- preventNodeOverlap: this.preventNodeOverlap,
- preventNodeEdgeOverlap: this.preventNodeEdgeOverlap,
- maxSpeedIncrease: this.maxSpeedIncrease
- };
- if (this._layoutWorker) {
- this._layoutWorker.postMessage({
- cmd: 'updateConfig',
- config: config
- });
- } else {
- for (var name in config) {
- this._layout[name] = config[name];
- }
- }
- };
- ForceLayout.prototype.init = function (graph, useWorker) {
- if (this._layoutWorker) {
- this._layoutWorker.terminate();
- this._layoutWorker = null;
- }
- if (workerUrl && useWorker) {
- try {
- if (!this._layoutWorker) {
- this._layoutWorker = new Worker(workerUrl);
- this._layoutWorker.onmessage = this._$onupdate;
- }
- this._layout = null;
- } catch (e) {
- this._layoutWorker = null;
- if (!this._layout) {
- this._layout = new ForceLayoutWorker();
- }
- }
- } else {
- if (!this._layout) {
- this._layout = new ForceLayoutWorker();
- }
- }
- this.temperature = 1;
- this.graph = graph;
- var len = graph.nodes.length;
- var positionArr = new ArrayCtor(len * 2);
- var massArr = new ArrayCtor(len);
- var sizeArr = new ArrayCtor(len);
- for (var i = 0; i < len; i++) {
- var n = graph.nodes[i];
- positionArr[i * 2] = n.layout.position[0];
- positionArr[i * 2 + 1] = n.layout.position[1];
- massArr[i] = typeof n.layout.mass === 'undefined' ? 1 : n.layout.mass;
- sizeArr[i] = typeof n.layout.size === 'undefined' ? 1 : n.layout.size;
- n.layout.__index = i;
- }
- len = graph.edges.length;
- var edgeArr = new ArrayCtor(len * 2);
- var edgeWeightArr = new ArrayCtor(len);
- for (var i = 0; i < len; i++) {
- var edge = graph.edges[i];
- edgeArr[i * 2] = edge.node1.layout.__index;
- edgeArr[i * 2 + 1] = edge.node2.layout.__index;
- edgeWeightArr[i] = edge.layout.weight || 1;
- }
- if (this._layoutWorker) {
- this._layoutWorker.postMessage({
- cmd: 'init',
- nodesPosition: positionArr,
- nodesMass: massArr,
- nodesSize: sizeArr,
- edges: edgeArr,
- edgesWeight: edgeWeightArr
- });
- } else {
- this._layout.initNodes(positionArr, massArr, sizeArr);
- this._layout.initEdges(edgeArr, edgeWeightArr);
- }
- this.updateConfig();
- };
- ForceLayout.prototype.step = function (steps) {
- var nodes = this.graph.nodes;
- if (this._layoutWorker) {
- var positionArr = new ArrayCtor(nodes.length * 2);
- for (var i = 0; i < nodes.length; i++) {
- var n = nodes[i];
- positionArr[i * 2] = n.layout.position[0];
- positionArr[i * 2 + 1] = n.layout.position[1];
- }
- this._layoutWorker.postMessage(positionArr.buffer, [positionArr.buffer]);
- this._layoutWorker.postMessage({
- cmd: 'update',
- steps: steps,
- temperature: this.temperature,
- coolDown: this.coolDown
- });
- for (var i = 0; i < steps; i++) {
- this.temperature *= this.coolDown;
- }
- } else {
- requestAnimationFrame(this._$onupdate);
- for (var i = 0; i < nodes.length; i++) {
- var n = nodes[i];
- vec2.copy(this._layout.nodes[i].position, n.layout.position);
- }
- for (var i = 0; i < steps; i++) {
- this._layout.temperature = this.temperature;
- this._layout.update();
- this.temperature *= this.coolDown;
- }
- }
- };
- ForceLayout.prototype._$onupdate = function (e) {
- if (this._layoutWorker) {
- var positionArr = new Float32Array(e.data);
- for (var i = 0; i < this.graph.nodes.length; i++) {
- var n = this.graph.nodes[i];
- n.layout.position[0] = positionArr[i * 2];
- n.layout.position[1] = positionArr[i * 2 + 1];
- }
- this.onupdate && this.onupdate();
- } else if (this._layout) {
- for (var i = 0; i < this.graph.nodes.length; i++) {
- var n = this.graph.nodes[i];
- vec2.copy(n.layout.position, this._layout.nodes[i].position);
- }
- this.onupdate && this.onupdate();
- }
- };
- ForceLayout.prototype.dispose = function () {
- if (this._layoutWorker) {
- this._layoutWorker.terminate();
- }
- this._layoutWorker = null;
- this._layout = null;
- };
- return ForceLayout;
-});define('echarts/layout/forceLayoutWorker', [
- 'require',
- 'zrender/tool/vector'
-], function __echartsForceLayoutWorker(require) {
- 'use strict';
- var vec2;
- var inWorker = typeof window === 'undefined' && typeof require === 'undefined';
- if (inWorker) {
- vec2 = {
- create: function (x, y) {
- var out = new Float32Array(2);
- out[0] = x || 0;
- out[1] = y || 0;
- return out;
- },
- dist: function (a, b) {
- var x = b[0] - a[0];
- var y = b[1] - a[1];
- return Math.sqrt(x * x + y * y);
- },
- len: function (a) {
- var x = a[0];
- var y = a[1];
- return Math.sqrt(x * x + y * y);
- },
- scaleAndAdd: function (out, a, b, scale) {
- out[0] = a[0] + b[0] * scale;
- out[1] = a[1] + b[1] * scale;
- return out;
- },
- scale: function (out, a, b) {
- out[0] = a[0] * b;
- out[1] = a[1] * b;
- return out;
- },
- add: function (out, a, b) {
- out[0] = a[0] + b[0];
- out[1] = a[1] + b[1];
- return out;
- },
- sub: function (out, a, b) {
- out[0] = a[0] - b[0];
- out[1] = a[1] - b[1];
- return out;
- },
- dot: function (v1, v2) {
- return v1[0] * v2[0] + v1[1] * v2[1];
- },
- normalize: function (out, a) {
- var x = a[0];
- var y = a[1];
- var len = x * x + y * y;
- if (len > 0) {
- len = 1 / Math.sqrt(len);
- out[0] = a[0] * len;
- out[1] = a[1] * len;
- }
- return out;
- },
- negate: function (out, a) {
- out[0] = -a[0];
- out[1] = -a[1];
- return out;
- },
- copy: function (out, a) {
- out[0] = a[0];
- out[1] = a[1];
- return out;
- },
- set: function (out, x, y) {
- out[0] = x;
- out[1] = y;
- return out;
- }
- };
- } else {
- vec2 = require('zrender/tool/vector');
- }
- var ArrayCtor = typeof Float32Array == 'undefined' ? Array : Float32Array;
- function Region() {
- this.subRegions = [];
- this.nSubRegions = 0;
- this.node = null;
- this.mass = 0;
- this.centerOfMass = null;
- this.bbox = new ArrayCtor(4);
- this.size = 0;
- }
- Region.prototype.beforeUpdate = function () {
- for (var i = 0; i < this.nSubRegions; i++) {
- this.subRegions[i].beforeUpdate();
- }
- this.mass = 0;
- if (this.centerOfMass) {
- this.centerOfMass[0] = 0;
- this.centerOfMass[1] = 0;
- }
- this.nSubRegions = 0;
- this.node = null;
- };
- Region.prototype.afterUpdate = function () {
- this.subRegions.length = this.nSubRegions;
- for (var i = 0; i < this.nSubRegions; i++) {
- this.subRegions[i].afterUpdate();
- }
- };
- Region.prototype.addNode = function (node) {
- if (this.nSubRegions === 0) {
- if (this.node == null) {
- this.node = node;
- return;
- } else {
- this._addNodeToSubRegion(this.node);
- this.node = null;
- }
- }
- this._addNodeToSubRegion(node);
- this._updateCenterOfMass(node);
- };
- Region.prototype.findSubRegion = function (x, y) {
- for (var i = 0; i < this.nSubRegions; i++) {
- var region = this.subRegions[i];
- if (region.contain(x, y)) {
- return region;
- }
- }
- };
- Region.prototype.contain = function (x, y) {
- return this.bbox[0] <= x && this.bbox[2] >= x && this.bbox[1] <= y && this.bbox[3] >= y;
- };
- Region.prototype.setBBox = function (minX, minY, maxX, maxY) {
- this.bbox[0] = minX;
- this.bbox[1] = minY;
- this.bbox[2] = maxX;
- this.bbox[3] = maxY;
- this.size = (maxX - minX + maxY - minY) / 2;
- };
- Region.prototype._newSubRegion = function () {
- var subRegion = this.subRegions[this.nSubRegions];
- if (!subRegion) {
- subRegion = new Region();
- this.subRegions[this.nSubRegions] = subRegion;
- }
- this.nSubRegions++;
- return subRegion;
- };
- Region.prototype._addNodeToSubRegion = function (node) {
- var subRegion = this.findSubRegion(node.position[0], node.position[1]);
- var bbox = this.bbox;
- if (!subRegion) {
- var cx = (bbox[0] + bbox[2]) / 2;
- var cy = (bbox[1] + bbox[3]) / 2;
- var w = (bbox[2] - bbox[0]) / 2;
- var h = (bbox[3] - bbox[1]) / 2;
- var xi = node.position[0] >= cx ? 1 : 0;
- var yi = node.position[1] >= cy ? 1 : 0;
- var subRegion = this._newSubRegion();
- subRegion.setBBox(xi * w + bbox[0], yi * h + bbox[1], (xi + 1) * w + bbox[0], (yi + 1) * h + bbox[1]);
- }
- subRegion.addNode(node);
- };
- Region.prototype._updateCenterOfMass = function (node) {
- if (this.centerOfMass == null) {
- this.centerOfMass = vec2.create();
- }
- var x = this.centerOfMass[0] * this.mass;
- var y = this.centerOfMass[1] * this.mass;
- x += node.position[0] * node.mass;
- y += node.position[1] * node.mass;
- this.mass += node.mass;
- this.centerOfMass[0] = x / this.mass;
- this.centerOfMass[1] = y / this.mass;
- };
- function GraphNode() {
- this.position = vec2.create();
- this.force = vec2.create();
- this.forcePrev = vec2.create();
- this.speed = vec2.create();
- this.speedPrev = vec2.create();
- this.mass = 1;
- this.inDegree = 0;
- this.outDegree = 0;
- }
- function GraphEdge(node1, node2) {
- this.node1 = node1;
- this.node2 = node2;
- this.weight = 1;
- }
- function ForceLayout() {
- this.barnesHutOptimize = false;
- this.barnesHutTheta = 1.5;
- this.repulsionByDegree = false;
- this.preventNodeOverlap = false;
- this.preventNodeEdgeOverlap = false;
- this.strongGravity = true;
- this.gravity = 1;
- this.scaling = 1;
- this.edgeWeightInfluence = 1;
- this.center = [
- 0,
- 0
- ];
- this.width = 500;
- this.height = 500;
- this.maxSpeedIncrease = 1;
- this.nodes = [];
- this.edges = [];
- this.bbox = new ArrayCtor(4);
- this._rootRegion = new Region();
- this._rootRegion.centerOfMass = vec2.create();
- this._massArr = null;
- this._k = 0;
- }
- ForceLayout.prototype.nodeToNodeRepulsionFactor = function (mass, d, k) {
- return k * k * mass / d;
- };
- ForceLayout.prototype.edgeToNodeRepulsionFactor = function (mass, d, k) {
- return k * mass / d;
- };
- ForceLayout.prototype.attractionFactor = function (w, d, k) {
- return w * d / k;
- };
- ForceLayout.prototype.initNodes = function (positionArr, massArr, sizeArr) {
- this.temperature = 1;
- var nNodes = positionArr.length / 2;
- this.nodes.length = 0;
- var haveSize = typeof sizeArr !== 'undefined';
- for (var i = 0; i < nNodes; i++) {
- var node = new GraphNode();
- node.position[0] = positionArr[i * 2];
- node.position[1] = positionArr[i * 2 + 1];
- node.mass = massArr[i];
- if (haveSize) {
- node.size = sizeArr[i];
- }
- this.nodes.push(node);
- }
- this._massArr = massArr;
- if (haveSize) {
- this._sizeArr = sizeArr;
- }
- };
- ForceLayout.prototype.initEdges = function (edgeArr, edgeWeightArr) {
- var nEdges = edgeArr.length / 2;
- this.edges.length = 0;
- var edgeHaveWeight = typeof edgeWeightArr !== 'undefined';
- for (var i = 0; i < nEdges; i++) {
- var sIdx = edgeArr[i * 2];
- var tIdx = edgeArr[i * 2 + 1];
- var sNode = this.nodes[sIdx];
- var tNode = this.nodes[tIdx];
- if (!sNode || !tNode) {
- continue;
- }
- sNode.outDegree++;
- tNode.inDegree++;
- var edge = new GraphEdge(sNode, tNode);
- if (edgeHaveWeight) {
- edge.weight = edgeWeightArr[i];
- }
- this.edges.push(edge);
- }
- };
- ForceLayout.prototype.update = function () {
- var nNodes = this.nodes.length;
- this.updateBBox();
- this._k = 0.4 * this.scaling * Math.sqrt(this.width * this.height / nNodes);
- if (this.barnesHutOptimize) {
- this._rootRegion.setBBox(this.bbox[0], this.bbox[1], this.bbox[2], this.bbox[3]);
- this._rootRegion.beforeUpdate();
- for (var i = 0; i < nNodes; i++) {
- this._rootRegion.addNode(this.nodes[i]);
- }
- this._rootRegion.afterUpdate();
- } else {
- var mass = 0;
- var centerOfMass = this._rootRegion.centerOfMass;
- vec2.set(centerOfMass, 0, 0);
- for (var i = 0; i < nNodes; i++) {
- var node = this.nodes[i];
- mass += node.mass;
- vec2.scaleAndAdd(centerOfMass, centerOfMass, node.position, node.mass);
- }
- if (mass > 0) {
- vec2.scale(centerOfMass, centerOfMass, 1 / mass);
- }
- }
- this.updateForce();
- this.updatePosition();
- };
- ForceLayout.prototype.updateForce = function () {
- var nNodes = this.nodes.length;
- for (var i = 0; i < nNodes; i++) {
- var node = this.nodes[i];
- vec2.copy(node.forcePrev, node.force);
- vec2.copy(node.speedPrev, node.speed);
- vec2.set(node.force, 0, 0);
- }
- this.updateNodeNodeForce();
- if (this.gravity > 0) {
- this.updateGravityForce();
- }
- this.updateEdgeForce();
- if (this.preventNodeEdgeOverlap) {
- this.updateNodeEdgeForce();
- }
- };
- ForceLayout.prototype.updatePosition = function () {
- var nNodes = this.nodes.length;
- var v = vec2.create();
- for (var i = 0; i < nNodes; i++) {
- var node = this.nodes[i];
- var speed = node.speed;
- vec2.scale(node.force, node.force, 1 / 30);
- var df = vec2.len(node.force) + 0.1;
- var scale = Math.min(df, 500) / df;
- vec2.scale(node.force, node.force, scale);
- vec2.add(speed, speed, node.force);
- vec2.scale(speed, speed, this.temperature);
- vec2.sub(v, speed, node.speedPrev);
- var swing = vec2.len(v);
- if (swing > 0) {
- vec2.scale(v, v, 1 / swing);
- var base = vec2.len(node.speedPrev);
- if (base > 0) {
- swing = Math.min(swing / base, this.maxSpeedIncrease) * base;
- vec2.scaleAndAdd(speed, node.speedPrev, v, swing);
- }
- }
- var ds = vec2.len(speed);
- var scale = Math.min(ds, 100) / (ds + 0.1);
- vec2.scale(speed, speed, scale);
- vec2.add(node.position, node.position, speed);
- }
- };
- ForceLayout.prototype.updateNodeNodeForce = function () {
- var nNodes = this.nodes.length;
- for (var i = 0; i < nNodes; i++) {
- var na = this.nodes[i];
- if (this.barnesHutOptimize) {
- this.applyRegionToNodeRepulsion(this._rootRegion, na);
- } else {
- for (var j = i + 1; j < nNodes; j++) {
- var nb = this.nodes[j];
- this.applyNodeToNodeRepulsion(na, nb, false);
- }
- }
- }
- };
- ForceLayout.prototype.updateGravityForce = function () {
- for (var i = 0; i < this.nodes.length; i++) {
- this.applyNodeGravity(this.nodes[i]);
- }
- };
- ForceLayout.prototype.updateEdgeForce = function () {
- for (var i = 0; i < this.edges.length; i++) {
- this.applyEdgeAttraction(this.edges[i]);
- }
- };
- ForceLayout.prototype.updateNodeEdgeForce = function () {
- for (var i = 0; i < this.nodes.length; i++) {
- for (var j = 0; j < this.edges.length; j++) {
- this.applyEdgeToNodeRepulsion(this.edges[j], this.nodes[i]);
- }
- }
- };
- ForceLayout.prototype.applyRegionToNodeRepulsion = function () {
- var v = vec2.create();
- return function applyRegionToNodeRepulsion(region, node) {
- if (region.node) {
- this.applyNodeToNodeRepulsion(region.node, node, true);
- } else {
- if (region.mass === 0 && node.mass === 0) {
- return;
- }
- vec2.sub(v, node.position, region.centerOfMass);
- var d2 = v[0] * v[0] + v[1] * v[1];
- if (d2 > this.barnesHutTheta * region.size * region.size) {
- var factor = this._k * this._k * (node.mass + region.mass) / (d2 + 1);
- vec2.scaleAndAdd(node.force, node.force, v, factor * 2);
- } else {
- for (var i = 0; i < region.nSubRegions; i++) {
- this.applyRegionToNodeRepulsion(region.subRegions[i], node);
- }
- }
- }
- };
- }();
- ForceLayout.prototype.applyNodeToNodeRepulsion = function () {
- var v = vec2.create();
- return function applyNodeToNodeRepulsion(na, nb, oneWay) {
- if (na === nb) {
- return;
- }
- if (na.mass === 0 && nb.mass === 0) {
- return;
- }
- vec2.sub(v, na.position, nb.position);
- var d2 = v[0] * v[0] + v[1] * v[1];
- if (d2 === 0) {
- return;
- }
- var factor;
- var mass = na.mass + nb.mass;
- var d = Math.sqrt(d2);
- vec2.scale(v, v, 1 / d);
- if (this.preventNodeOverlap) {
- d = d - na.size - nb.size;
- if (d > 0) {
- factor = this.nodeToNodeRepulsionFactor(mass, d, this._k);
- } else if (d <= 0) {
- factor = this._k * this._k * 10 * mass;
- }
- } else {
- factor = this.nodeToNodeRepulsionFactor(mass, d, this._k);
- }
- if (!oneWay) {
- vec2.scaleAndAdd(na.force, na.force, v, factor * 2);
- }
- vec2.scaleAndAdd(nb.force, nb.force, v, -factor * 2);
- };
- }();
- ForceLayout.prototype.applyEdgeAttraction = function () {
- var v = vec2.create();
- return function applyEdgeAttraction(edge) {
- var na = edge.node1;
- var nb = edge.node2;
- vec2.sub(v, na.position, nb.position);
- var d = vec2.len(v);
- var w;
- if (this.edgeWeightInfluence === 0) {
- w = 1;
- } else if (this.edgeWeightInfluence == 1) {
- w = edge.weight;
- } else {
- w = Math.pow(edge.weight, this.edgeWeightInfluence);
- }
- var factor;
- if (this.preventOverlap) {
- d = d - na.size - nb.size;
- if (d <= 0) {
- return;
- }
- }
- var factor = this.attractionFactor(w, d, this._k);
- vec2.scaleAndAdd(na.force, na.force, v, -factor);
- vec2.scaleAndAdd(nb.force, nb.force, v, factor);
- };
- }();
- ForceLayout.prototype.applyNodeGravity = function () {
- var v = vec2.create();
- return function (node) {
- vec2.sub(v, this.center, node.position);
- if (this.width > this.height) {
- v[1] *= this.width / this.height;
- } else {
- v[0] *= this.height / this.width;
- }
- var d = vec2.len(v) / 100;
- if (this.strongGravity) {
- vec2.scaleAndAdd(node.force, node.force, v, d * this.gravity * node.mass);
- } else {
- vec2.scaleAndAdd(node.force, node.force, v, this.gravity * node.mass / (d + 1));
- }
- };
- }();
- ForceLayout.prototype.applyEdgeToNodeRepulsion = function () {
- var v12 = vec2.create();
- var v13 = vec2.create();
- var p = vec2.create();
- return function (e, n3) {
- var n1 = e.node1;
- var n2 = e.node2;
- if (n1 === n3 || n2 === n3) {
- return;
- }
- vec2.sub(v12, n2.position, n1.position);
- vec2.sub(v13, n3.position, n1.position);
- var len12 = vec2.len(v12);
- vec2.scale(v12, v12, 1 / len12);
- var len = vec2.dot(v12, v13);
- if (len < 0 || len > len12) {
- return;
- }
- vec2.scaleAndAdd(p, n1.position, v12, len);
- var dist = vec2.dist(p, n3.position) - n3.size;
- var factor = this.edgeToNodeRepulsionFactor(n3.mass, Math.max(dist, 0.1), 100);
- vec2.sub(v12, n3.position, p);
- vec2.normalize(v12, v12);
- vec2.scaleAndAdd(n3.force, n3.force, v12, factor);
- vec2.scaleAndAdd(n1.force, n1.force, v12, -factor);
- vec2.scaleAndAdd(n2.force, n2.force, v12, -factor);
- };
- }();
- ForceLayout.prototype.updateBBox = function () {
- var minX = Infinity;
- var minY = Infinity;
- var maxX = -Infinity;
- var maxY = -Infinity;
- for (var i = 0; i < this.nodes.length; i++) {
- var pos = this.nodes[i].position;
- minX = Math.min(minX, pos[0]);
- minY = Math.min(minY, pos[1]);
- maxX = Math.max(maxX, pos[0]);
- maxY = Math.max(maxY, pos[1]);
- }
- this.bbox[0] = minX;
- this.bbox[1] = minY;
- this.bbox[2] = maxX;
- this.bbox[3] = maxY;
- };
- ForceLayout.getWorkerCode = function () {
- var str = __echartsForceLayoutWorker.toString();
- return str.slice(str.indexOf('{') + 1, str.lastIndexOf('return'));
- };
- if (inWorker) {
- var forceLayout = null;
- self.onmessage = function (e) {
- if (e.data instanceof ArrayBuffer) {
- if (!forceLayout)
- return;
- var positionArr = new Float32Array(e.data);
- var nNodes = positionArr.length / 2;
- for (var i = 0; i < nNodes; i++) {
- var node = forceLayout.nodes[i];
- node.position[0] = positionArr[i * 2];
- node.position[1] = positionArr[i * 2 + 1];
- }
- return;
- }
- switch (e.data.cmd) {
- case 'init':
- if (!forceLayout) {
- forceLayout = new ForceLayout();
- }
- forceLayout.initNodes(e.data.nodesPosition, e.data.nodesMass, e.data.nodesSize);
- forceLayout.initEdges(e.data.edges, e.data.edgesWeight);
- break;
- case 'updateConfig':
- if (forceLayout) {
- for (var name in e.data.config) {
- forceLayout[name] = e.data.config[name];
- }
- }
- break;
- case 'update':
- var steps = e.data.steps;
- if (forceLayout) {
- var nNodes = forceLayout.nodes.length;
- var positionArr = new Float32Array(nNodes * 2);
- forceLayout.temperature = e.data.temperature;
- for (var i = 0; i < steps; i++) {
- forceLayout.update();
- forceLayout.temperature *= e.data.coolDown;
- }
- for (var i = 0; i < nNodes; i++) {
- var node = forceLayout.nodes[i];
- positionArr[i * 2] = node.position[0];
- positionArr[i * 2 + 1] = node.position[1];
- }
- self.postMessage(positionArr.buffer, [positionArr.buffer]);
- } else {
- var emptyArr = new Float32Array();
- self.postMessage(emptyArr.buffer, [emptyArr.buffer]);
- }
- break;
- }
- };
- }
- return ForceLayout;
+define('echarts/chart/force', [
+ 'require',
+ './base',
+ '../data/Graph',
+ '../layout/Force',
+ 'zrender/shape/Line',
+ 'zrender/shape/BezierCurve',
+ 'zrender/shape/Image',
+ '../util/shape/Icon',
+ '../config',
+ '../util/ecData',
+ 'zrender/tool/util',
+ 'zrender/config',
+ 'zrender/tool/vector',
+ '../chart'
+], function (require) {
+ 'use strict';
+ var ChartBase = require('./base');
+ var Graph = require('../data/Graph');
+ var ForceLayout = require('../layout/Force');
+ var LineShape = require('zrender/shape/Line');
+ var BezierCurveShape = require('zrender/shape/BezierCurve');
+ var ImageShape = require('zrender/shape/Image');
+ var IconShape = require('../util/shape/Icon');
+ var ecConfig = require('../config');
+ ecConfig.force = {
+ zlevel: 1,
+ z: 2,
+ center: [
+ '50%',
+ '50%'
+ ],
+ size: '100%',
+ preventOverlap: false,
+ coolDown: 0.99,
+ minRadius: 10,
+ maxRadius: 20,
+ ratioScaling: false,
+ large: false,
+ useWorker: false,
+ steps: 1,
+ scaling: 1,
+ gravity: 1,
+ symbol: 'circle',
+ symbolSize: 0,
+ linkSymbol: null,
+ linkSymbolSize: [
+ 10,
+ 15
+ ],
+ draggable: true,
+ clickable: true,
+ roam: false,
+ itemStyle: {
+ normal: {
+ label: {
+ show: false,
+ position: 'inside'
+ },
+ nodeStyle: {
+ brushType: 'both',
+ borderColor: '#5182ab',
+ borderWidth: 1
+ },
+ linkStyle: {
+ color: '#5182ab',
+ width: 1,
+ type: 'line'
+ }
+ },
+ emphasis: {
+ label: { show: false },
+ nodeStyle: {},
+ linkStyle: { opacity: 0 }
+ }
+ }
+ };
+ var ecData = require('../util/ecData');
+ var zrUtil = require('zrender/tool/util');
+ var zrConfig = require('zrender/config');
+ var vec2 = require('zrender/tool/vector');
+ function Force(ecTheme, messageCenter, zr, option, myChart) {
+ var self = this;
+ ChartBase.call(this, ecTheme, messageCenter, zr, option, myChart);
+ this.__nodePositionMap = {};
+ this._graph = new Graph(true);
+ this._layout = new ForceLayout();
+ this._layout.onupdate = function () {
+ self._step();
+ };
+ this._steps = 1;
+ this.ondragstart = function () {
+ ondragstart.apply(self, arguments);
+ };
+ this.ondragend = function () {
+ ondragend.apply(self, arguments);
+ };
+ this.ondrop = function () {
+ };
+ this.shapeHandler.ondragstart = function () {
+ self.isDragstart = true;
+ };
+ this.onmousemove = function () {
+ onmousemove.apply(self, arguments);
+ };
+ this.refresh(option);
+ }
+ Force.prototype = {
+ constructor: Force,
+ type: ecConfig.CHART_TYPE_FORCE,
+ _init: function () {
+ this.selectedMap = {};
+ var legend = this.component.legend;
+ var series = this.series;
+ var serieName;
+ this.clear();
+ for (var i = 0, l = series.length; i < l; i++) {
+ var serie = series[i];
+ if (serie.type === ecConfig.CHART_TYPE_FORCE) {
+ series[i] = this.reformOption(series[i]);
+ serieName = series[i].name || '';
+ this.selectedMap[serieName] = legend ? legend.isSelected(serieName) : true;
+ if (!this.selectedMap[serieName]) {
+ continue;
+ }
+ this.buildMark(i);
+ this._initSerie(serie, i);
+ break;
+ }
+ }
+ this.animationEffect();
+ },
+ _getNodeCategory: function (serie, node) {
+ return serie.categories && serie.categories[node.category || 0];
+ },
+ _getNodeQueryTarget: function (serie, node, type) {
+ type = type || 'normal';
+ var category = this._getNodeCategory(serie, node) || {};
+ return [
+ node.itemStyle && node.itemStyle[type],
+ category && category.itemStyle && category.itemStyle[type],
+ serie.itemStyle[type].nodeStyle
+ ];
+ },
+ _getEdgeQueryTarget: function (serie, edge, type) {
+ type = type || 'normal';
+ return [
+ edge.itemStyle && edge.itemStyle[type],
+ serie.itemStyle[type].linkStyle
+ ];
+ },
+ _initSerie: function (serie, serieIdx) {
+ this._temperature = 1;
+ if (serie.matrix) {
+ this._graph = this._getSerieGraphFromDataMatrix(serie);
+ } else if (serie.links) {
+ this._graph = this._getSerieGraphFromNodeLinks(serie);
+ }
+ this._buildLinkShapes(serie, serieIdx);
+ this._buildNodeShapes(serie, serieIdx);
+ var panable = serie.roam === true || serie.roam === 'move';
+ var zoomable = serie.roam === true || serie.roam === 'scale';
+ this.zr.modLayer(this.getZlevelBase(), {
+ panable: panable,
+ zoomable: zoomable
+ });
+ if (this.query('markPoint.effect.show') || this.query('markLine.effect.show')) {
+ this.zr.modLayer(ecConfig.EFFECT_ZLEVEL, {
+ panable: panable,
+ zoomable: zoomable
+ });
+ }
+ this._initLayout(serie);
+ this._step();
+ },
+ _getSerieGraphFromDataMatrix: function (serie) {
+ var nodesData = [];
+ var count = 0;
+ var matrix = [];
+ for (var i = 0; i < serie.matrix.length; i++) {
+ matrix[i] = serie.matrix[i].slice();
+ }
+ var data = serie.data || serie.nodes;
+ for (var i = 0; i < data.length; i++) {
+ var node = {};
+ var group = data[i];
+ for (var key in group) {
+ if (key === 'name') {
+ node['id'] = group['name'];
+ } else {
+ node[key] = group[key];
+ }
+ }
+ var category = this._getNodeCategory(serie, group);
+ var name = category ? category.name : group.name;
+ this.selectedMap[name] = this.isSelected(name);
+ if (this.selectedMap[name]) {
+ nodesData.push(node);
+ count++;
+ } else {
+ matrix.splice(count, 1);
+ for (var j = 0; j < matrix.length; j++) {
+ matrix[j].splice(count, 1);
+ }
+ }
+ }
+ var graph = Graph.fromMatrix(nodesData, matrix, true);
+ graph.eachNode(function (n, idx) {
+ n.layout = {
+ size: n.data.value,
+ mass: 0
+ };
+ n.rawIndex = idx;
+ });
+ graph.eachEdge(function (e) {
+ e.layout = { weight: e.data.weight };
+ });
+ return graph;
+ },
+ _getSerieGraphFromNodeLinks: function (serie) {
+ var graph = new Graph(true);
+ var nodes = serie.data || serie.nodes;
+ for (var i = 0, len = nodes.length; i < len; i++) {
+ var n = nodes[i];
+ if (!n || n.ignore) {
+ continue;
+ }
+ var category = this._getNodeCategory(serie, n);
+ var name = category ? category.name : n.name;
+ this.selectedMap[name] = this.isSelected(name);
+ if (this.selectedMap[name]) {
+ var node = graph.addNode(n.name, n);
+ node.rawIndex = i;
+ }
+ }
+ for (var i = 0, len = serie.links.length; i < len; i++) {
+ var e = serie.links[i];
+ var n1 = e.source;
+ var n2 = e.target;
+ if (typeof n1 === 'number') {
+ n1 = nodes[n1];
+ if (n1) {
+ n1 = n1.name;
+ }
+ }
+ if (typeof n2 === 'number') {
+ n2 = nodes[n2];
+ if (n2) {
+ n2 = n2.name;
+ }
+ }
+ var edge = graph.addEdge(n1, n2, e);
+ if (edge) {
+ edge.rawIndex = i;
+ }
+ }
+ graph.eachNode(function (n) {
+ var value = n.data.value;
+ if (value == null) {
+ value = 0;
+ for (var i = 0; i < n.edges.length; i++) {
+ value += n.edges[i].data.weight || 0;
+ }
+ }
+ n.layout = {
+ size: value,
+ mass: 0
+ };
+ });
+ graph.eachEdge(function (e) {
+ e.layout = { weight: e.data.weight == null ? 1 : e.data.weight };
+ });
+ return graph;
+ },
+ _initLayout: function (serie) {
+ var graph = this._graph;
+ var len = graph.nodes.length;
+ var minRadius = this.query(serie, 'minRadius');
+ var maxRadius = this.query(serie, 'maxRadius');
+ this._steps = serie.steps || 1;
+ var layout = this._layout;
+ layout.center = this.parseCenter(this.zr, serie.center);
+ layout.width = this.parsePercent(serie.size, this.zr.getWidth());
+ layout.height = this.parsePercent(serie.size, this.zr.getHeight());
+ layout.large = serie.large;
+ layout.scaling = serie.scaling;
+ layout.ratioScaling = serie.ratioScaling;
+ layout.gravity = serie.gravity;
+ layout.temperature = 1;
+ layout.coolDown = serie.coolDown;
+ layout.preventNodeEdgeOverlap = serie.preventOverlap;
+ layout.preventNodeOverlap = serie.preventOverlap;
+ var min = Infinity;
+ var max = -Infinity;
+ for (var i = 0; i < len; i++) {
+ var gNode = graph.nodes[i];
+ max = Math.max(gNode.layout.size, max);
+ min = Math.min(gNode.layout.size, min);
+ }
+ var divider = max - min;
+ for (var i = 0; i < len; i++) {
+ var gNode = graph.nodes[i];
+ if (divider > 0) {
+ gNode.layout.size = (gNode.layout.size - min) * (maxRadius - minRadius) / divider + minRadius;
+ gNode.layout.mass = gNode.layout.size / maxRadius;
+ } else {
+ gNode.layout.size = (maxRadius - minRadius) / 2;
+ gNode.layout.mass = 0.5;
+ }
+ }
+ for (var i = 0; i < len; i++) {
+ var gNode = graph.nodes[i];
+ if (typeof this.__nodePositionMap[gNode.id] !== 'undefined') {
+ gNode.layout.position = vec2.create();
+ vec2.copy(gNode.layout.position, this.__nodePositionMap[gNode.id]);
+ } else if (typeof gNode.data.initial !== 'undefined') {
+ gNode.layout.position = vec2.create();
+ vec2.copy(gNode.layout.position, gNode.data.initial);
+ } else {
+ var center = this._layout.center;
+ var size = Math.min(this._layout.width, this._layout.height);
+ gNode.layout.position = _randomInSquare(center[0], center[1], size * 0.8);
+ }
+ var style = gNode.shape.style;
+ var radius = gNode.layout.size;
+ style.width = style.width || radius * 2;
+ style.height = style.height || radius * 2;
+ style.x = -style.width / 2;
+ style.y = -style.height / 2;
+ vec2.copy(gNode.shape.position, gNode.layout.position);
+ }
+ len = graph.edges.length;
+ max = -Infinity;
+ for (var i = 0; i < len; i++) {
+ var e = graph.edges[i];
+ if (e.layout.weight > max) {
+ max = e.layout.weight;
+ }
+ }
+ for (var i = 0; i < len; i++) {
+ var e = graph.edges[i];
+ e.layout.weight /= max;
+ }
+ this._layout.init(graph, serie.useWorker);
+ },
+ _buildNodeShapes: function (serie, serieIdx) {
+ var graph = this._graph;
+ var categories = this.query(serie, 'categories');
+ graph.eachNode(function (node) {
+ var category = this._getNodeCategory(serie, node.data);
+ var queryTarget = [
+ node.data,
+ category,
+ serie
+ ];
+ var styleQueryTarget = this._getNodeQueryTarget(serie, node.data);
+ var emphasisStyleQueryTarget = this._getNodeQueryTarget(serie, node.data, 'emphasis');
+ var shape = new IconShape({
+ style: {
+ x: 0,
+ y: 0,
+ color: this.deepQuery(styleQueryTarget, 'color'),
+ brushType: 'both',
+ strokeColor: this.deepQuery(styleQueryTarget, 'strokeColor') || this.deepQuery(styleQueryTarget, 'borderColor'),
+ lineWidth: this.deepQuery(styleQueryTarget, 'lineWidth') || this.deepQuery(styleQueryTarget, 'borderWidth')
+ },
+ highlightStyle: {
+ color: this.deepQuery(emphasisStyleQueryTarget, 'color'),
+ strokeColor: this.deepQuery(emphasisStyleQueryTarget, 'strokeColor') || this.deepQuery(emphasisStyleQueryTarget, 'borderColor'),
+ lineWidth: this.deepQuery(emphasisStyleQueryTarget, 'lineWidth') || this.deepQuery(emphasisStyleQueryTarget, 'borderWidth')
+ },
+ clickable: serie.clickable,
+ zlevel: this.getZlevelBase(),
+ z: this.getZBase()
+ });
+ if (!shape.style.color) {
+ shape.style.color = category ? this.getColor(category.name) : this.getColor(node.id);
+ }
+ shape.style.iconType = this.deepQuery(queryTarget, 'symbol');
+ var symbolSize = this.deepQuery(queryTarget, 'symbolSize') || 0;
+ if (typeof symbolSize === 'number') {
+ symbolSize = [
+ symbolSize,
+ symbolSize
+ ];
+ }
+ shape.style.width = symbolSize[0] * 2;
+ shape.style.height = symbolSize[1] * 2;
+ if (shape.style.iconType.match('image')) {
+ shape.style.image = shape.style.iconType.replace(new RegExp('^image:\\/\\/'), '');
+ shape = new ImageShape({
+ style: shape.style,
+ highlightStyle: shape.highlightStyle,
+ clickable: shape.clickable,
+ zlevel: this.getZlevelBase(),
+ z: this.getZBase()
+ });
+ }
+ if (this.deepQuery(queryTarget, 'itemStyle.normal.label.show')) {
+ shape.style.text = node.data.label == null ? node.id : node.data.label;
+ shape.style.textPosition = this.deepQuery(queryTarget, 'itemStyle.normal.label.position');
+ shape.style.textColor = this.deepQuery(queryTarget, 'itemStyle.normal.label.textStyle.color');
+ shape.style.textFont = this.getFont(this.deepQuery(queryTarget, 'itemStyle.normal.label.textStyle') || {});
+ }
+ if (this.deepQuery(queryTarget, 'itemStyle.emphasis.label.show')) {
+ shape.highlightStyle.textPosition = this.deepQuery(queryTarget, 'itemStyle.emphasis.label.position');
+ shape.highlightStyle.textColor = this.deepQuery(queryTarget, 'itemStyle.emphasis.label.textStyle.color');
+ shape.highlightStyle.textFont = this.getFont(this.deepQuery(queryTarget, 'itemStyle.emphasis.label.textStyle') || {});
+ }
+ if (this.deepQuery(queryTarget, 'draggable')) {
+ this.setCalculable(shape);
+ shape.dragEnableTime = 0;
+ shape.draggable = true;
+ shape.ondragstart = this.shapeHandler.ondragstart;
+ shape.ondragover = null;
+ }
+ var categoryName = '';
+ if (typeof node.category !== 'undefined') {
+ var category = categories[node.category];
+ categoryName = category && category.name || '';
+ }
+ ecData.pack(shape, serie, serieIdx, node.data, node.rawIndex, node.data.name || '', node.category);
+ this.shapeList.push(shape);
+ this.zr.addShape(shape);
+ node.shape = shape;
+ }, this);
+ },
+ _buildLinkShapes: function (serie, serieIdx) {
+ var graph = this._graph;
+ var len = graph.edges.length;
+ for (var i = 0; i < len; i++) {
+ var gEdge = graph.edges[i];
+ var link = gEdge.data;
+ var source = gEdge.node1;
+ var target = gEdge.node2;
+ var otherEdge = graph.getEdge(target, source);
+ var queryTarget = this._getEdgeQueryTarget(serie, link);
+ var linkType = this.deepQuery(queryTarget, 'type');
+ if (serie.linkSymbol && serie.linkSymbol !== 'none') {
+ linkType = 'line';
+ }
+ var LinkShapeCtor = linkType === 'line' ? LineShape : BezierCurveShape;
+ var linkShape = new LinkShapeCtor({
+ style: {
+ xStart: 0,
+ yStart: 0,
+ xEnd: 0,
+ yEnd: 0
+ },
+ clickable: this.query(serie, 'clickable'),
+ highlightStyle: {},
+ zlevel: this.getZlevelBase(),
+ z: this.getZBase()
+ });
+ if (otherEdge && otherEdge.shape) {
+ linkShape.style.offset = 4;
+ otherEdge.shape.style.offset = 4;
+ }
+ zrUtil.merge(linkShape.style, this.query(serie, 'itemStyle.normal.linkStyle'), true);
+ zrUtil.merge(linkShape.highlightStyle, this.query(serie, 'itemStyle.emphasis.linkStyle'), true);
+ if (typeof link.itemStyle !== 'undefined') {
+ if (link.itemStyle.normal) {
+ zrUtil.merge(linkShape.style, link.itemStyle.normal, true);
+ }
+ if (link.itemStyle.emphasis) {
+ zrUtil.merge(linkShape.highlightStyle, link.itemStyle.emphasis, true);
+ }
+ }
+ linkShape.style.lineWidth = linkShape.style.lineWidth || linkShape.style.width;
+ linkShape.style.strokeColor = linkShape.style.strokeColor || linkShape.style.color;
+ linkShape.highlightStyle.lineWidth = linkShape.highlightStyle.lineWidth || linkShape.highlightStyle.width;
+ linkShape.highlightStyle.strokeColor = linkShape.highlightStyle.strokeColor || linkShape.highlightStyle.color;
+ ecData.pack(linkShape, serie, serieIdx, gEdge.data, gEdge.rawIndex == null ? i : gEdge.rawIndex, gEdge.data.name || source.id + ' - ' + target.id, source.id, target.id);
+ this.shapeList.push(linkShape);
+ this.zr.addShape(linkShape);
+ gEdge.shape = linkShape;
+ if (serie.linkSymbol && serie.linkSymbol !== 'none') {
+ var symbolShape = new IconShape({
+ style: {
+ x: -5,
+ y: 0,
+ width: serie.linkSymbolSize[0],
+ height: serie.linkSymbolSize[1],
+ iconType: serie.linkSymbol,
+ brushType: 'fill',
+ color: linkShape.style.strokeColor
+ },
+ highlightStyle: { brushType: 'fill' },
+ position: [
+ 0,
+ 0
+ ],
+ rotation: 0,
+ zlevel: this.getZlevelBase(),
+ z: this.getZBase()
+ });
+ linkShape._symbolShape = symbolShape;
+ this.shapeList.push(symbolShape);
+ this.zr.addShape(symbolShape);
+ }
+ }
+ },
+ _updateLinkShapes: function () {
+ var v = vec2.create();
+ var n = vec2.create();
+ var p1 = vec2.create();
+ var p2 = vec2.create();
+ var edges = this._graph.edges;
+ for (var i = 0, len = edges.length; i < len; i++) {
+ var edge = edges[i];
+ var sourceShape = edge.node1.shape;
+ var targetShape = edge.node2.shape;
+ vec2.copy(p1, sourceShape.position);
+ vec2.copy(p2, targetShape.position);
+ var edgeShapeStyle = edge.shape.style;
+ vec2.sub(v, p1, p2);
+ vec2.normalize(v, v);
+ if (edgeShapeStyle.offset) {
+ n[0] = v[1];
+ n[1] = -v[0];
+ vec2.scaleAndAdd(p1, p1, n, edgeShapeStyle.offset);
+ vec2.scaleAndAdd(p2, p2, n, edgeShapeStyle.offset);
+ } else if (edge.shape.type === 'bezier-curve') {
+ edgeShapeStyle.cpX1 = (p1[0] + p2[0]) / 2 - (p2[1] - p1[1]) / 4;
+ edgeShapeStyle.cpY1 = (p1[1] + p2[1]) / 2 - (p1[0] - p2[0]) / 4;
+ }
+ edgeShapeStyle.xStart = p1[0];
+ edgeShapeStyle.yStart = p1[1];
+ edgeShapeStyle.xEnd = p2[0];
+ edgeShapeStyle.yEnd = p2[1];
+ edge.shape.modSelf();
+ if (edge.shape._symbolShape) {
+ var symbolShape = edge.shape._symbolShape;
+ vec2.copy(symbolShape.position, p2);
+ vec2.scaleAndAdd(symbolShape.position, symbolShape.position, v, targetShape.style.width / 2 + 2);
+ var angle = Math.atan2(v[1], v[0]);
+ symbolShape.rotation = Math.PI / 2 - angle;
+ symbolShape.modSelf();
+ }
+ }
+ },
+ _syncNodePositions: function () {
+ var graph = this._graph;
+ for (var i = 0; i < graph.nodes.length; i++) {
+ var gNode = graph.nodes[i];
+ var position = gNode.layout.position;
+ var node = gNode.data;
+ var shape = gNode.shape;
+ var fixX = shape.fixed || node.fixX;
+ var fixY = shape.fixed || node.fixY;
+ if (fixX === true) {
+ fixX = 1;
+ } else if (isNaN(fixX)) {
+ fixX = 0;
+ }
+ if (fixY === true) {
+ fixY = 1;
+ } else if (isNaN(fixY)) {
+ fixY = 0;
+ }
+ shape.position[0] += (position[0] - shape.position[0]) * (1 - fixX);
+ shape.position[1] += (position[1] - shape.position[1]) * (1 - fixY);
+ vec2.copy(position, shape.position);
+ var nodeName = node.name;
+ if (nodeName) {
+ var gPos = this.__nodePositionMap[nodeName];
+ if (!gPos) {
+ gPos = this.__nodePositionMap[nodeName] = vec2.create();
+ }
+ vec2.copy(gPos, position);
+ }
+ shape.modSelf();
+ }
+ },
+ _step: function (e) {
+ this._syncNodePositions();
+ this._updateLinkShapes();
+ this.zr.refreshNextFrame();
+ if (this._layout.temperature > 0.01) {
+ this._layout.step(this._steps);
+ } else {
+ this.messageCenter.dispatch(ecConfig.EVENT.FORCE_LAYOUT_END, {}, {}, this.myChart);
+ }
+ },
+ refresh: function (newOption) {
+ if (newOption) {
+ this.option = newOption;
+ this.series = this.option.series;
+ }
+ this.legend = this.component.legend;
+ if (this.legend) {
+ this.getColor = function (param) {
+ return this.legend.getColor(param);
+ };
+ this.isSelected = function (param) {
+ return this.legend.isSelected(param);
+ };
+ } else {
+ var colorMap = {};
+ var count = 0;
+ this.getColor = function (key) {
+ if (colorMap[key]) {
+ return colorMap[key];
+ }
+ if (!colorMap[key]) {
+ colorMap[key] = this.zr.getColor(count++);
+ }
+ return colorMap[key];
+ };
+ this.isSelected = function () {
+ return true;
+ };
+ }
+ this._init();
+ },
+ dispose: function () {
+ this.clear();
+ this.shapeList = null;
+ this.effectList = null;
+ this._layout.dispose();
+ this._layout = null;
+ this.__nodePositionMap = {};
+ },
+ getPosition: function () {
+ var position = [];
+ this._graph.eachNode(function (n) {
+ if (n.layout) {
+ position.push({
+ name: n.data.name,
+ position: Array.prototype.slice.call(n.layout.position)
+ });
+ }
+ });
+ return position;
+ }
+ };
+ function ondragstart(param) {
+ if (!this.isDragstart || !param.target) {
+ return;
+ }
+ var shape = param.target;
+ shape.fixed = true;
+ this.isDragstart = false;
+ this.zr.on(zrConfig.EVENT.MOUSEMOVE, this.onmousemove);
+ }
+ function onmousemove() {
+ this._layout.temperature = 0.8;
+ this._step();
+ }
+ function ondragend(param, status) {
+ if (!this.isDragend || !param.target) {
+ return;
+ }
+ var shape = param.target;
+ shape.fixed = false;
+ status.dragIn = true;
+ status.needRefresh = false;
+ this.isDragend = false;
+ this.zr.un(zrConfig.EVENT.MOUSEMOVE, this.onmousemove);
+ }
+ function _randomInSquare(x, y, size) {
+ var v = vec2.create();
+ v[0] = (Math.random() - 0.5) * size + x;
+ v[1] = (Math.random() - 0.5) * size + y;
+ return v;
+ }
+ zrUtil.inherits(Force, ChartBase);
+ require('../chart').define('force', Force);
+ return Force;
+});define('echarts/data/Graph', [
+ 'require',
+ 'zrender/tool/util'
+], function (require) {
+ var util = require('zrender/tool/util');
+ 'use strict';
+ var Graph = function (directed) {
+ this._directed = directed || false;
+ this.nodes = [];
+ this.edges = [];
+ this._nodesMap = {};
+ this._edgesMap = {};
+ };
+ Graph.prototype.isDirected = function () {
+ return this._directed;
+ };
+ Graph.prototype.addNode = function (id, data) {
+ if (this._nodesMap[id]) {
+ return this._nodesMap[id];
+ }
+ var node = new Graph.Node(id, data);
+ this.nodes.push(node);
+ this._nodesMap[id] = node;
+ return node;
+ };
+ Graph.prototype.getNodeById = function (id) {
+ return this._nodesMap[id];
+ };
+ Graph.prototype.addEdge = function (n1, n2, data) {
+ if (typeof n1 == 'string') {
+ n1 = this._nodesMap[n1];
+ }
+ if (typeof n2 == 'string') {
+ n2 = this._nodesMap[n2];
+ }
+ if (!n1 || !n2) {
+ return;
+ }
+ var key = n1.id + '-' + n2.id;
+ if (this._edgesMap[key]) {
+ return this._edgesMap[key];
+ }
+ var edge = new Graph.Edge(n1, n2, data);
+ if (this._directed) {
+ n1.outEdges.push(edge);
+ n2.inEdges.push(edge);
+ }
+ n1.edges.push(edge);
+ if (n1 !== n2) {
+ n2.edges.push(edge);
+ }
+ this.edges.push(edge);
+ this._edgesMap[key] = edge;
+ return edge;
+ };
+ Graph.prototype.removeEdge = function (edge) {
+ var n1 = edge.node1;
+ var n2 = edge.node2;
+ var key = n1.id + '-' + n2.id;
+ if (this._directed) {
+ n1.outEdges.splice(util.indexOf(n1.outEdges, edge), 1);
+ n2.inEdges.splice(util.indexOf(n2.inEdges, edge), 1);
+ }
+ n1.edges.splice(util.indexOf(n1.edges, edge), 1);
+ if (n1 !== n2) {
+ n2.edges.splice(util.indexOf(n2.edges, edge), 1);
+ }
+ delete this._edgesMap[key];
+ this.edges.splice(util.indexOf(this.edges, edge), 1);
+ };
+ Graph.prototype.getEdge = function (n1, n2) {
+ if (typeof n1 !== 'string') {
+ n1 = n1.id;
+ }
+ if (typeof n2 !== 'string') {
+ n2 = n2.id;
+ }
+ if (this._directed) {
+ return this._edgesMap[n1 + '-' + n2];
+ } else {
+ return this._edgesMap[n1 + '-' + n2] || this._edgesMap[n2 + '-' + n1];
+ }
+ };
+ Graph.prototype.removeNode = function (node) {
+ if (typeof node === 'string') {
+ node = this._nodesMap[node];
+ if (!node) {
+ return;
+ }
+ }
+ delete this._nodesMap[node.id];
+ this.nodes.splice(util.indexOf(this.nodes, node), 1);
+ for (var i = 0; i < this.edges.length;) {
+ var edge = this.edges[i];
+ if (edge.node1 === node || edge.node2 === node) {
+ this.removeEdge(edge);
+ } else {
+ i++;
+ }
+ }
+ };
+ Graph.prototype.filterNode = function (cb, context) {
+ var len = this.nodes.length;
+ for (var i = 0; i < len;) {
+ if (cb.call(context, this.nodes[i], i)) {
+ i++;
+ } else {
+ this.removeNode(this.nodes[i]);
+ len--;
+ }
+ }
+ };
+ Graph.prototype.filterEdge = function (cb, context) {
+ var len = this.edges.length;
+ for (var i = 0; i < len;) {
+ if (cb.call(context, this.edges[i], i)) {
+ i++;
+ } else {
+ this.removeEdge(this.edges[i]);
+ len--;
+ }
+ }
+ };
+ Graph.prototype.eachNode = function (cb, context) {
+ var len = this.nodes.length;
+ for (var i = 0; i < len; i++) {
+ if (this.nodes[i]) {
+ cb.call(context, this.nodes[i], i);
+ }
+ }
+ };
+ Graph.prototype.eachEdge = function (cb, context) {
+ var len = this.edges.length;
+ for (var i = 0; i < len; i++) {
+ if (this.edges[i]) {
+ cb.call(context, this.edges[i], i);
+ }
+ }
+ };
+ Graph.prototype.clear = function () {
+ this.nodes.length = 0;
+ this.edges.length = 0;
+ this._nodesMap = {};
+ this._edgesMap = {};
+ };
+ Graph.prototype.breadthFirstTraverse = function (cb, startNode, direction, context) {
+ if (typeof startNode === 'string') {
+ startNode = this._nodesMap[startNode];
+ }
+ if (!startNode) {
+ return;
+ }
+ var edgeType = 'edges';
+ if (direction === 'out') {
+ edgeType = 'outEdges';
+ } else if (direction === 'in') {
+ edgeType = 'inEdges';
+ }
+ for (var i = 0; i < this.nodes.length; i++) {
+ this.nodes[i].__visited = false;
+ }
+ if (cb.call(context, startNode, null)) {
+ return;
+ }
+ var queue = [startNode];
+ while (queue.length) {
+ var currentNode = queue.shift();
+ var edges = currentNode[edgeType];
+ for (var i = 0; i < edges.length; i++) {
+ var e = edges[i];
+ var otherNode = e.node1 === currentNode ? e.node2 : e.node1;
+ if (!otherNode.__visited) {
+ if (cb.call(otherNode, otherNode, currentNode)) {
+ return;
+ }
+ queue.push(otherNode);
+ otherNode.__visited = true;
+ }
+ }
+ }
+ };
+ Graph.prototype.clone = function () {
+ var graph = new Graph(this._directed);
+ for (var i = 0; i < this.nodes.length; i++) {
+ graph.addNode(this.nodes[i].id, this.nodes[i].data);
+ }
+ for (var i = 0; i < this.edges.length; i++) {
+ var e = this.edges[i];
+ graph.addEdge(e.node1.id, e.node2.id, e.data);
+ }
+ return graph;
+ };
+ var Node = function (id, data) {
+ this.id = id;
+ this.data = data || null;
+ this.inEdges = [];
+ this.outEdges = [];
+ this.edges = [];
+ };
+ Node.prototype.degree = function () {
+ return this.edges.length;
+ };
+ Node.prototype.inDegree = function () {
+ return this.inEdges.length;
+ };
+ Node.prototype.outDegree = function () {
+ return this.outEdges.length;
+ };
+ var Edge = function (node1, node2, data) {
+ this.node1 = node1;
+ this.node2 = node2;
+ this.data = data || null;
+ };
+ Graph.Node = Node;
+ Graph.Edge = Edge;
+ Graph.fromMatrix = function (nodesData, matrix, directed) {
+ if (!matrix || !matrix.length || matrix[0].length !== matrix.length || nodesData.length !== matrix.length) {
+ return;
+ }
+ var size = matrix.length;
+ var graph = new Graph(directed);
+ for (var i = 0; i < size; i++) {
+ var node = graph.addNode(nodesData[i].id, nodesData[i]);
+ node.data.value = 0;
+ if (directed) {
+ node.data.outValue = node.data.inValue = 0;
+ }
+ }
+ for (var i = 0; i < size; i++) {
+ for (var j = 0; j < size; j++) {
+ var item = matrix[i][j];
+ if (directed) {
+ graph.nodes[i].data.outValue += item;
+ graph.nodes[j].data.inValue += item;
+ }
+ graph.nodes[i].data.value += item;
+ graph.nodes[j].data.value += item;
+ }
+ }
+ for (var i = 0; i < size; i++) {
+ for (var j = i; j < size; j++) {
+ var item = matrix[i][j];
+ if (item === 0) {
+ continue;
+ }
+ var n1 = graph.nodes[i];
+ var n2 = graph.nodes[j];
+ var edge = graph.addEdge(n1, n2, {});
+ edge.data.weight = item;
+ if (i !== j) {
+ if (directed && matrix[j][i]) {
+ var inEdge = graph.addEdge(n2, n1, {});
+ inEdge.data.weight = matrix[j][i];
+ }
+ }
+ }
+ }
+ return graph;
+ };
+ return Graph;
+});define('echarts/layout/Force', [
+ 'require',
+ './forceLayoutWorker',
+ 'zrender/tool/vector'
+], function (require) {
+ var ForceLayoutWorker = require('./forceLayoutWorker');
+ var vec2 = require('zrender/tool/vector');
+ var requestAnimationFrame = window.requestAnimationFrame || window.msRequestAnimationFrame || window.mozRequestAnimationFrame || window.webkitRequestAnimationFrame || function (func) {
+ setTimeout(func, 16);
+ };
+ var ArrayCtor = typeof Float32Array == 'undefined' ? Array : Float32Array;
+ var workerUrl;
+ function createWorkerUrl() {
+ if (typeof Worker !== 'undefined' && typeof Blob !== 'undefined') {
+ try {
+ var blob = new Blob([ForceLayoutWorker.getWorkerCode()]);
+ workerUrl = window.URL.createObjectURL(blob);
+ } catch (e) {
+ workerUrl = '';
+ }
+ }
+ return workerUrl;
+ }
+ var ForceLayout = function (opts) {
+ if (typeof workerUrl === 'undefined') {
+ createWorkerUrl();
+ }
+ opts = opts || {};
+ this.width = opts.width || 500;
+ this.height = opts.height || 500;
+ this.center = opts.center || [
+ this.width / 2,
+ this.height / 2
+ ];
+ this.ratioScaling = opts.ratioScaling || false;
+ this.scaling = opts.scaling || 1;
+ this.gravity = typeof opts.gravity !== 'undefined' ? opts.gravity : 1;
+ this.large = opts.large || false;
+ this.preventNodeOverlap = opts.preventNodeOverlap || false;
+ this.preventNodeEdgeOverlap = opts.preventNodeEdgeOverlap || false;
+ this.maxSpeedIncrease = opts.maxSpeedIncrease || 1;
+ this.onupdate = opts.onupdate || function () {
+ };
+ this.temperature = opts.temperature || 1;
+ this.coolDown = opts.coolDown || 0.99;
+ this._layout = null;
+ this._layoutWorker = null;
+ var self = this;
+ var _$onupdate = this._$onupdate;
+ this._$onupdate = function (e) {
+ _$onupdate.call(self, e);
+ };
+ };
+ ForceLayout.prototype.updateConfig = function () {
+ var width = this.width;
+ var height = this.height;
+ var size = Math.min(width, height);
+ var config = {
+ center: this.center,
+ width: this.ratioScaling ? width : size,
+ height: this.ratioScaling ? height : size,
+ scaling: this.scaling || 1,
+ gravity: this.gravity || 1,
+ barnesHutOptimize: this.large,
+ preventNodeOverlap: this.preventNodeOverlap,
+ preventNodeEdgeOverlap: this.preventNodeEdgeOverlap,
+ maxSpeedIncrease: this.maxSpeedIncrease
+ };
+ if (this._layoutWorker) {
+ this._layoutWorker.postMessage({
+ cmd: 'updateConfig',
+ config: config
+ });
+ } else {
+ for (var name in config) {
+ this._layout[name] = config[name];
+ }
+ }
+ };
+ ForceLayout.prototype.init = function (graph, useWorker) {
+ if (this._layoutWorker) {
+ this._layoutWorker.terminate();
+ this._layoutWorker = null;
+ }
+ if (workerUrl && useWorker) {
+ try {
+ if (!this._layoutWorker) {
+ this._layoutWorker = new Worker(workerUrl);
+ this._layoutWorker.onmessage = this._$onupdate;
+ }
+ this._layout = null;
+ } catch (e) {
+ this._layoutWorker = null;
+ if (!this._layout) {
+ this._layout = new ForceLayoutWorker();
+ }
+ }
+ } else {
+ if (!this._layout) {
+ this._layout = new ForceLayoutWorker();
+ }
+ }
+ this.temperature = 1;
+ this.graph = graph;
+ var len = graph.nodes.length;
+ var positionArr = new ArrayCtor(len * 2);
+ var massArr = new ArrayCtor(len);
+ var sizeArr = new ArrayCtor(len);
+ for (var i = 0; i < len; i++) {
+ var n = graph.nodes[i];
+ positionArr[i * 2] = n.layout.position[0];
+ positionArr[i * 2 + 1] = n.layout.position[1];
+ massArr[i] = typeof n.layout.mass === 'undefined' ? 1 : n.layout.mass;
+ sizeArr[i] = typeof n.layout.size === 'undefined' ? 1 : n.layout.size;
+ n.layout.__index = i;
+ }
+ len = graph.edges.length;
+ var edgeArr = new ArrayCtor(len * 2);
+ var edgeWeightArr = new ArrayCtor(len);
+ for (var i = 0; i < len; i++) {
+ var edge = graph.edges[i];
+ edgeArr[i * 2] = edge.node1.layout.__index;
+ edgeArr[i * 2 + 1] = edge.node2.layout.__index;
+ edgeWeightArr[i] = edge.layout.weight || 1;
+ }
+ if (this._layoutWorker) {
+ this._layoutWorker.postMessage({
+ cmd: 'init',
+ nodesPosition: positionArr,
+ nodesMass: massArr,
+ nodesSize: sizeArr,
+ edges: edgeArr,
+ edgesWeight: edgeWeightArr
+ });
+ } else {
+ this._layout.initNodes(positionArr, massArr, sizeArr);
+ this._layout.initEdges(edgeArr, edgeWeightArr);
+ }
+ this.updateConfig();
+ };
+ ForceLayout.prototype.step = function (steps) {
+ var nodes = this.graph.nodes;
+ if (this._layoutWorker) {
+ var positionArr = new ArrayCtor(nodes.length * 2);
+ for (var i = 0; i < nodes.length; i++) {
+ var n = nodes[i];
+ positionArr[i * 2] = n.layout.position[0];
+ positionArr[i * 2 + 1] = n.layout.position[1];
+ }
+ this._layoutWorker.postMessage(positionArr.buffer, [positionArr.buffer]);
+ this._layoutWorker.postMessage({
+ cmd: 'update',
+ steps: steps,
+ temperature: this.temperature,
+ coolDown: this.coolDown
+ });
+ for (var i = 0; i < steps; i++) {
+ this.temperature *= this.coolDown;
+ }
+ } else {
+ requestAnimationFrame(this._$onupdate);
+ for (var i = 0; i < nodes.length; i++) {
+ var n = nodes[i];
+ vec2.copy(this._layout.nodes[i].position, n.layout.position);
+ }
+ for (var i = 0; i < steps; i++) {
+ this._layout.temperature = this.temperature;
+ this._layout.update();
+ this.temperature *= this.coolDown;
+ }
+ }
+ };
+ ForceLayout.prototype._$onupdate = function (e) {
+ if (this._layoutWorker) {
+ var positionArr = new Float32Array(e.data);
+ for (var i = 0; i < this.graph.nodes.length; i++) {
+ var n = this.graph.nodes[i];
+ n.layout.position[0] = positionArr[i * 2];
+ n.layout.position[1] = positionArr[i * 2 + 1];
+ }
+ this.onupdate && this.onupdate();
+ } else if (this._layout) {
+ for (var i = 0; i < this.graph.nodes.length; i++) {
+ var n = this.graph.nodes[i];
+ vec2.copy(n.layout.position, this._layout.nodes[i].position);
+ }
+ this.onupdate && this.onupdate();
+ }
+ };
+ ForceLayout.prototype.dispose = function () {
+ if (this._layoutWorker) {
+ this._layoutWorker.terminate();
+ }
+ this._layoutWorker = null;
+ this._layout = null;
+ };
+ return ForceLayout;
+});define('echarts/layout/forceLayoutWorker', [
+ 'require',
+ 'zrender/tool/vector'
+], function __echartsForceLayoutWorker(require) {
+ 'use strict';
+ var vec2;
+ var inWorker = typeof window === 'undefined' && typeof require === 'undefined';
+ if (inWorker) {
+ vec2 = {
+ create: function (x, y) {
+ var out = new Float32Array(2);
+ out[0] = x || 0;
+ out[1] = y || 0;
+ return out;
+ },
+ dist: function (a, b) {
+ var x = b[0] - a[0];
+ var y = b[1] - a[1];
+ return Math.sqrt(x * x + y * y);
+ },
+ len: function (a) {
+ var x = a[0];
+ var y = a[1];
+ return Math.sqrt(x * x + y * y);
+ },
+ scaleAndAdd: function (out, a, b, scale) {
+ out[0] = a[0] + b[0] * scale;
+ out[1] = a[1] + b[1] * scale;
+ return out;
+ },
+ scale: function (out, a, b) {
+ out[0] = a[0] * b;
+ out[1] = a[1] * b;
+ return out;
+ },
+ add: function (out, a, b) {
+ out[0] = a[0] + b[0];
+ out[1] = a[1] + b[1];
+ return out;
+ },
+ sub: function (out, a, b) {
+ out[0] = a[0] - b[0];
+ out[1] = a[1] - b[1];
+ return out;
+ },
+ dot: function (v1, v2) {
+ return v1[0] * v2[0] + v1[1] * v2[1];
+ },
+ normalize: function (out, a) {
+ var x = a[0];
+ var y = a[1];
+ var len = x * x + y * y;
+ if (len > 0) {
+ len = 1 / Math.sqrt(len);
+ out[0] = a[0] * len;
+ out[1] = a[1] * len;
+ }
+ return out;
+ },
+ negate: function (out, a) {
+ out[0] = -a[0];
+ out[1] = -a[1];
+ return out;
+ },
+ copy: function (out, a) {
+ out[0] = a[0];
+ out[1] = a[1];
+ return out;
+ },
+ set: function (out, x, y) {
+ out[0] = x;
+ out[1] = y;
+ return out;
+ }
+ };
+ } else {
+ vec2 = require('zrender/tool/vector');
+ }
+ var ArrayCtor = typeof Float32Array == 'undefined' ? Array : Float32Array;
+ function Region() {
+ this.subRegions = [];
+ this.nSubRegions = 0;
+ this.node = null;
+ this.mass = 0;
+ this.centerOfMass = null;
+ this.bbox = new ArrayCtor(4);
+ this.size = 0;
+ }
+ Region.prototype.beforeUpdate = function () {
+ for (var i = 0; i < this.nSubRegions; i++) {
+ this.subRegions[i].beforeUpdate();
+ }
+ this.mass = 0;
+ if (this.centerOfMass) {
+ this.centerOfMass[0] = 0;
+ this.centerOfMass[1] = 0;
+ }
+ this.nSubRegions = 0;
+ this.node = null;
+ };
+ Region.prototype.afterUpdate = function () {
+ this.subRegions.length = this.nSubRegions;
+ for (var i = 0; i < this.nSubRegions; i++) {
+ this.subRegions[i].afterUpdate();
+ }
+ };
+ Region.prototype.addNode = function (node) {
+ if (this.nSubRegions === 0) {
+ if (this.node == null) {
+ this.node = node;
+ return;
+ } else {
+ this._addNodeToSubRegion(this.node);
+ this.node = null;
+ }
+ }
+ this._addNodeToSubRegion(node);
+ this._updateCenterOfMass(node);
+ };
+ Region.prototype.findSubRegion = function (x, y) {
+ for (var i = 0; i < this.nSubRegions; i++) {
+ var region = this.subRegions[i];
+ if (region.contain(x, y)) {
+ return region;
+ }
+ }
+ };
+ Region.prototype.contain = function (x, y) {
+ return this.bbox[0] <= x && this.bbox[2] >= x && this.bbox[1] <= y && this.bbox[3] >= y;
+ };
+ Region.prototype.setBBox = function (minX, minY, maxX, maxY) {
+ this.bbox[0] = minX;
+ this.bbox[1] = minY;
+ this.bbox[2] = maxX;
+ this.bbox[3] = maxY;
+ this.size = (maxX - minX + maxY - minY) / 2;
+ };
+ Region.prototype._newSubRegion = function () {
+ var subRegion = this.subRegions[this.nSubRegions];
+ if (!subRegion) {
+ subRegion = new Region();
+ this.subRegions[this.nSubRegions] = subRegion;
+ }
+ this.nSubRegions++;
+ return subRegion;
+ };
+ Region.prototype._addNodeToSubRegion = function (node) {
+ var subRegion = this.findSubRegion(node.position[0], node.position[1]);
+ var bbox = this.bbox;
+ if (!subRegion) {
+ var cx = (bbox[0] + bbox[2]) / 2;
+ var cy = (bbox[1] + bbox[3]) / 2;
+ var w = (bbox[2] - bbox[0]) / 2;
+ var h = (bbox[3] - bbox[1]) / 2;
+ var xi = node.position[0] >= cx ? 1 : 0;
+ var yi = node.position[1] >= cy ? 1 : 0;
+ var subRegion = this._newSubRegion();
+ subRegion.setBBox(xi * w + bbox[0], yi * h + bbox[1], (xi + 1) * w + bbox[0], (yi + 1) * h + bbox[1]);
+ }
+ subRegion.addNode(node);
+ };
+ Region.prototype._updateCenterOfMass = function (node) {
+ if (this.centerOfMass == null) {
+ this.centerOfMass = vec2.create();
+ }
+ var x = this.centerOfMass[0] * this.mass;
+ var y = this.centerOfMass[1] * this.mass;
+ x += node.position[0] * node.mass;
+ y += node.position[1] * node.mass;
+ this.mass += node.mass;
+ this.centerOfMass[0] = x / this.mass;
+ this.centerOfMass[1] = y / this.mass;
+ };
+ function GraphNode() {
+ this.position = vec2.create();
+ this.force = vec2.create();
+ this.forcePrev = vec2.create();
+ this.speed = vec2.create();
+ this.speedPrev = vec2.create();
+ this.mass = 1;
+ this.inDegree = 0;
+ this.outDegree = 0;
+ }
+ function GraphEdge(node1, node2) {
+ this.node1 = node1;
+ this.node2 = node2;
+ this.weight = 1;
+ }
+ function ForceLayout() {
+ this.barnesHutOptimize = false;
+ this.barnesHutTheta = 1.5;
+ this.repulsionByDegree = false;
+ this.preventNodeOverlap = false;
+ this.preventNodeEdgeOverlap = false;
+ this.strongGravity = true;
+ this.gravity = 1;
+ this.scaling = 1;
+ this.edgeWeightInfluence = 1;
+ this.center = [
+ 0,
+ 0
+ ];
+ this.width = 500;
+ this.height = 500;
+ this.maxSpeedIncrease = 1;
+ this.nodes = [];
+ this.edges = [];
+ this.bbox = new ArrayCtor(4);
+ this._rootRegion = new Region();
+ this._rootRegion.centerOfMass = vec2.create();
+ this._massArr = null;
+ this._k = 0;
+ }
+ ForceLayout.prototype.nodeToNodeRepulsionFactor = function (mass, d, k) {
+ return k * k * mass / d;
+ };
+ ForceLayout.prototype.edgeToNodeRepulsionFactor = function (mass, d, k) {
+ return k * mass / d;
+ };
+ ForceLayout.prototype.attractionFactor = function (w, d, k) {
+ return w * d / k;
+ };
+ ForceLayout.prototype.initNodes = function (positionArr, massArr, sizeArr) {
+ this.temperature = 1;
+ var nNodes = positionArr.length / 2;
+ this.nodes.length = 0;
+ var haveSize = typeof sizeArr !== 'undefined';
+ for (var i = 0; i < nNodes; i++) {
+ var node = new GraphNode();
+ node.position[0] = positionArr[i * 2];
+ node.position[1] = positionArr[i * 2 + 1];
+ node.mass = massArr[i];
+ if (haveSize) {
+ node.size = sizeArr[i];
+ }
+ this.nodes.push(node);
+ }
+ this._massArr = massArr;
+ if (haveSize) {
+ this._sizeArr = sizeArr;
+ }
+ };
+ ForceLayout.prototype.initEdges = function (edgeArr, edgeWeightArr) {
+ var nEdges = edgeArr.length / 2;
+ this.edges.length = 0;
+ var edgeHaveWeight = typeof edgeWeightArr !== 'undefined';
+ for (var i = 0; i < nEdges; i++) {
+ var sIdx = edgeArr[i * 2];
+ var tIdx = edgeArr[i * 2 + 1];
+ var sNode = this.nodes[sIdx];
+ var tNode = this.nodes[tIdx];
+ if (!sNode || !tNode) {
+ continue;
+ }
+ sNode.outDegree++;
+ tNode.inDegree++;
+ var edge = new GraphEdge(sNode, tNode);
+ if (edgeHaveWeight) {
+ edge.weight = edgeWeightArr[i];
+ }
+ this.edges.push(edge);
+ }
+ };
+ ForceLayout.prototype.update = function () {
+ var nNodes = this.nodes.length;
+ this.updateBBox();
+ this._k = 0.4 * this.scaling * Math.sqrt(this.width * this.height / nNodes);
+ if (this.barnesHutOptimize) {
+ this._rootRegion.setBBox(this.bbox[0], this.bbox[1], this.bbox[2], this.bbox[3]);
+ this._rootRegion.beforeUpdate();
+ for (var i = 0; i < nNodes; i++) {
+ this._rootRegion.addNode(this.nodes[i]);
+ }
+ this._rootRegion.afterUpdate();
+ } else {
+ var mass = 0;
+ var centerOfMass = this._rootRegion.centerOfMass;
+ vec2.set(centerOfMass, 0, 0);
+ for (var i = 0; i < nNodes; i++) {
+ var node = this.nodes[i];
+ mass += node.mass;
+ vec2.scaleAndAdd(centerOfMass, centerOfMass, node.position, node.mass);
+ }
+ if (mass > 0) {
+ vec2.scale(centerOfMass, centerOfMass, 1 / mass);
+ }
+ }
+ this.updateForce();
+ this.updatePosition();
+ };
+ ForceLayout.prototype.updateForce = function () {
+ var nNodes = this.nodes.length;
+ for (var i = 0; i < nNodes; i++) {
+ var node = this.nodes[i];
+ vec2.copy(node.forcePrev, node.force);
+ vec2.copy(node.speedPrev, node.speed);
+ vec2.set(node.force, 0, 0);
+ }
+ this.updateNodeNodeForce();
+ if (this.gravity > 0) {
+ this.updateGravityForce();
+ }
+ this.updateEdgeForce();
+ if (this.preventNodeEdgeOverlap) {
+ this.updateNodeEdgeForce();
+ }
+ };
+ ForceLayout.prototype.updatePosition = function () {
+ var nNodes = this.nodes.length;
+ var v = vec2.create();
+ for (var i = 0; i < nNodes; i++) {
+ var node = this.nodes[i];
+ var speed = node.speed;
+ vec2.scale(node.force, node.force, 1 / 30);
+ var df = vec2.len(node.force) + 0.1;
+ var scale = Math.min(df, 500) / df;
+ vec2.scale(node.force, node.force, scale);
+ vec2.add(speed, speed, node.force);
+ vec2.scale(speed, speed, this.temperature);
+ vec2.sub(v, speed, node.speedPrev);
+ var swing = vec2.len(v);
+ if (swing > 0) {
+ vec2.scale(v, v, 1 / swing);
+ var base = vec2.len(node.speedPrev);
+ if (base > 0) {
+ swing = Math.min(swing / base, this.maxSpeedIncrease) * base;
+ vec2.scaleAndAdd(speed, node.speedPrev, v, swing);
+ }
+ }
+ var ds = vec2.len(speed);
+ var scale = Math.min(ds, 100) / (ds + 0.1);
+ vec2.scale(speed, speed, scale);
+ vec2.add(node.position, node.position, speed);
+ }
+ };
+ ForceLayout.prototype.updateNodeNodeForce = function () {
+ var nNodes = this.nodes.length;
+ for (var i = 0; i < nNodes; i++) {
+ var na = this.nodes[i];
+ if (this.barnesHutOptimize) {
+ this.applyRegionToNodeRepulsion(this._rootRegion, na);
+ } else {
+ for (var j = i + 1; j < nNodes; j++) {
+ var nb = this.nodes[j];
+ this.applyNodeToNodeRepulsion(na, nb, false);
+ }
+ }
+ }
+ };
+ ForceLayout.prototype.updateGravityForce = function () {
+ for (var i = 0; i < this.nodes.length; i++) {
+ this.applyNodeGravity(this.nodes[i]);
+ }
+ };
+ ForceLayout.prototype.updateEdgeForce = function () {
+ for (var i = 0; i < this.edges.length; i++) {
+ this.applyEdgeAttraction(this.edges[i]);
+ }
+ };
+ ForceLayout.prototype.updateNodeEdgeForce = function () {
+ for (var i = 0; i < this.nodes.length; i++) {
+ for (var j = 0; j < this.edges.length; j++) {
+ this.applyEdgeToNodeRepulsion(this.edges[j], this.nodes[i]);
+ }
+ }
+ };
+ ForceLayout.prototype.applyRegionToNodeRepulsion = function () {
+ var v = vec2.create();
+ return function applyRegionToNodeRepulsion(region, node) {
+ if (region.node) {
+ this.applyNodeToNodeRepulsion(region.node, node, true);
+ } else {
+ if (region.mass === 0 && node.mass === 0) {
+ return;
+ }
+ vec2.sub(v, node.position, region.centerOfMass);
+ var d2 = v[0] * v[0] + v[1] * v[1];
+ if (d2 > this.barnesHutTheta * region.size * region.size) {
+ var factor = this._k * this._k * (node.mass + region.mass) / (d2 + 1);
+ vec2.scaleAndAdd(node.force, node.force, v, factor * 2);
+ } else {
+ for (var i = 0; i < region.nSubRegions; i++) {
+ this.applyRegionToNodeRepulsion(region.subRegions[i], node);
+ }
+ }
+ }
+ };
+ }();
+ ForceLayout.prototype.applyNodeToNodeRepulsion = function () {
+ var v = vec2.create();
+ return function applyNodeToNodeRepulsion(na, nb, oneWay) {
+ if (na === nb) {
+ return;
+ }
+ if (na.mass === 0 && nb.mass === 0) {
+ return;
+ }
+ vec2.sub(v, na.position, nb.position);
+ var d2 = v[0] * v[0] + v[1] * v[1];
+ if (d2 === 0) {
+ return;
+ }
+ var factor;
+ var mass = na.mass + nb.mass;
+ var d = Math.sqrt(d2);
+ vec2.scale(v, v, 1 / d);
+ if (this.preventNodeOverlap) {
+ d = d - na.size - nb.size;
+ if (d > 0) {
+ factor = this.nodeToNodeRepulsionFactor(mass, d, this._k);
+ } else if (d <= 0) {
+ factor = this._k * this._k * 10 * mass;
+ }
+ } else {
+ factor = this.nodeToNodeRepulsionFactor(mass, d, this._k);
+ }
+ if (!oneWay) {
+ vec2.scaleAndAdd(na.force, na.force, v, factor * 2);
+ }
+ vec2.scaleAndAdd(nb.force, nb.force, v, -factor * 2);
+ };
+ }();
+ ForceLayout.prototype.applyEdgeAttraction = function () {
+ var v = vec2.create();
+ return function applyEdgeAttraction(edge) {
+ var na = edge.node1;
+ var nb = edge.node2;
+ vec2.sub(v, na.position, nb.position);
+ var d = vec2.len(v);
+ var w;
+ if (this.edgeWeightInfluence === 0) {
+ w = 1;
+ } else if (this.edgeWeightInfluence == 1) {
+ w = edge.weight;
+ } else {
+ w = Math.pow(edge.weight, this.edgeWeightInfluence);
+ }
+ var factor;
+ if (this.preventOverlap) {
+ d = d - na.size - nb.size;
+ if (d <= 0) {
+ return;
+ }
+ }
+ var factor = this.attractionFactor(w, d, this._k);
+ vec2.scaleAndAdd(na.force, na.force, v, -factor);
+ vec2.scaleAndAdd(nb.force, nb.force, v, factor);
+ };
+ }();
+ ForceLayout.prototype.applyNodeGravity = function () {
+ var v = vec2.create();
+ return function (node) {
+ vec2.sub(v, this.center, node.position);
+ if (this.width > this.height) {
+ v[1] *= this.width / this.height;
+ } else {
+ v[0] *= this.height / this.width;
+ }
+ var d = vec2.len(v) / 100;
+ if (this.strongGravity) {
+ vec2.scaleAndAdd(node.force, node.force, v, d * this.gravity * node.mass);
+ } else {
+ vec2.scaleAndAdd(node.force, node.force, v, this.gravity * node.mass / (d + 1));
+ }
+ };
+ }();
+ ForceLayout.prototype.applyEdgeToNodeRepulsion = function () {
+ var v12 = vec2.create();
+ var v13 = vec2.create();
+ var p = vec2.create();
+ return function (e, n3) {
+ var n1 = e.node1;
+ var n2 = e.node2;
+ if (n1 === n3 || n2 === n3) {
+ return;
+ }
+ vec2.sub(v12, n2.position, n1.position);
+ vec2.sub(v13, n3.position, n1.position);
+ var len12 = vec2.len(v12);
+ vec2.scale(v12, v12, 1 / len12);
+ var len = vec2.dot(v12, v13);
+ if (len < 0 || len > len12) {
+ return;
+ }
+ vec2.scaleAndAdd(p, n1.position, v12, len);
+ var dist = vec2.dist(p, n3.position) - n3.size;
+ var factor = this.edgeToNodeRepulsionFactor(n3.mass, Math.max(dist, 0.1), 100);
+ vec2.sub(v12, n3.position, p);
+ vec2.normalize(v12, v12);
+ vec2.scaleAndAdd(n3.force, n3.force, v12, factor);
+ vec2.scaleAndAdd(n1.force, n1.force, v12, -factor);
+ vec2.scaleAndAdd(n2.force, n2.force, v12, -factor);
+ };
+ }();
+ ForceLayout.prototype.updateBBox = function () {
+ var minX = Infinity;
+ var minY = Infinity;
+ var maxX = -Infinity;
+ var maxY = -Infinity;
+ for (var i = 0; i < this.nodes.length; i++) {
+ var pos = this.nodes[i].position;
+ minX = Math.min(minX, pos[0]);
+ minY = Math.min(minY, pos[1]);
+ maxX = Math.max(maxX, pos[0]);
+ maxY = Math.max(maxY, pos[1]);
+ }
+ this.bbox[0] = minX;
+ this.bbox[1] = minY;
+ this.bbox[2] = maxX;
+ this.bbox[3] = maxY;
+ };
+ ForceLayout.getWorkerCode = function () {
+ var str = __echartsForceLayoutWorker.toString();
+ return str.slice(str.indexOf('{') + 1, str.lastIndexOf('return'));
+ };
+ if (inWorker) {
+ var forceLayout = null;
+ self.onmessage = function (e) {
+ if (e.data instanceof ArrayBuffer) {
+ if (!forceLayout)
+ return;
+ var positionArr = new Float32Array(e.data);
+ var nNodes = positionArr.length / 2;
+ for (var i = 0; i < nNodes; i++) {
+ var node = forceLayout.nodes[i];
+ node.position[0] = positionArr[i * 2];
+ node.position[1] = positionArr[i * 2 + 1];
+ }
+ return;
+ }
+ switch (e.data.cmd) {
+ case 'init':
+ if (!forceLayout) {
+ forceLayout = new ForceLayout();
+ }
+ forceLayout.initNodes(e.data.nodesPosition, e.data.nodesMass, e.data.nodesSize);
+ forceLayout.initEdges(e.data.edges, e.data.edgesWeight);
+ break;
+ case 'updateConfig':
+ if (forceLayout) {
+ for (var name in e.data.config) {
+ forceLayout[name] = e.data.config[name];
+ }
+ }
+ break;
+ case 'update':
+ var steps = e.data.steps;
+ if (forceLayout) {
+ var nNodes = forceLayout.nodes.length;
+ var positionArr = new Float32Array(nNodes * 2);
+ forceLayout.temperature = e.data.temperature;
+ for (var i = 0; i < steps; i++) {
+ forceLayout.update();
+ forceLayout.temperature *= e.data.coolDown;
+ }
+ for (var i = 0; i < nNodes; i++) {
+ var node = forceLayout.nodes[i];
+ positionArr[i * 2] = node.position[0];
+ positionArr[i * 2 + 1] = node.position[1];
+ }
+ self.postMessage(positionArr.buffer, [positionArr.buffer]);
+ } else {
+ var emptyArr = new Float32Array();
+ self.postMessage(emptyArr.buffer, [emptyArr.buffer]);
+ }
+ break;
+ }
+ };
+ }
+ return ForceLayout;
});
\ No newline at end of file