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