123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977 |
- /**
- * echarts图表类:力导向图
- *
- * @author pissang (https://github.com/pissang/)
- *
- */
- define(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,
- // 在 500+ 顶点的图上建议设置 large 为 true, 会使用 Barnes-Hut simulation
- // 同时开启 useWorker 并且把 steps 值调大
- // 关于Barnes-Hut simulation: http://en.wikipedia.org/wiki/Barnes–Hut_simulation
- large: false,
- // 是否在浏览器支持 worker 的时候使用 web worker
- useWorker: false,
- // 每一帧 force 迭代的次数,仅在启用webworker的情况下有用
- steps: 1,
- // 布局缩放因子,并不完全精确, 效果跟布局大小类似
- scaling: 1.0,
- // 向心力因子,越大向心力越大( 所有顶点会往 center 的位置收拢 )
- gravity: 1,
- symbol: 'circle',
- // symbolSize 为 0 的话使用映射到minRadius-maxRadius后的值
- symbolSize: 0,
- linkSymbol: null,
- linkSymbolSize: [10, 15],
- draggable: true,
- clickable: true,
- roam: false,
- // 分类里如果有样式会覆盖节点默认样式
- // categories: [{
- // itemStyle
- // symbol
- // symbolSize
- // name
- // }],
- itemStyle: {
- normal: {
- // color: 各异,
- label: {
- show: false,
- position: 'inside'
- // textStyle: null // 默认使用全局文本样式,详见TEXTSTYLE
- },
- nodeStyle: {
- brushType : 'both',
- borderColor : '#5182ab',
- borderWidth: 1
- },
- linkStyle: {
- color: '#5182ab',
- width: 1,
- type: 'line'
- }
- },
- emphasis: {
- // color: 各异,
- label: {
- show: false
- // textStyle: null // 默认使用全局文本样式,详见TEXTSTYLE
- },
- nodeStyle: {},
- linkStyle: {
- opacity: 0
- }
- }
- }
- // nodes: [{
- // name: 'xxx',
- // value: 1,
- // itemStyle: {},
- // initial: [0, 0],
- // fixX: false,
- // fixY: false,
- // ignore: false,
- // symbol: 'circle',
- // symbolSize: 0
- // }]
- // links: [{
- // source: 1,
- // target: 2,
- // weight: 1,
- // itemStyle: {}
- // }, {
- // source: 'xxx',
- // target: 'ooo'
- // }]
- };
-
- var ecData = require('../util/ecData');
- var zrUtil = require('zrender/tool/util');
- var zrConfig = require('zrender/config');
- var vec2 = require('zrender/tool/vector');
- /**
- * 构造函数
- * @param {Object} messageCenter echart消息中心
- * @param {ZRender} zr zrender实例
- * @param {Object} series 数据
- * @param {Object} component 组件
- */
- 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);
-
- // TODO 多个 force
- 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
- node.itemStyle && node.itemStyle[type],
- // Category
- category && category.itemStyle && category.itemStyle[type],
- // Serie
- 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;
- // matrix 表示边
- if (serie.matrix) {
- this._graph = this._getSerieGraphFromDataMatrix(serie);
- }
- // links 表示边
- 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';
- // Enable pan and zooom
- 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 = [];
- // 复制一份新的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) {
- // name改为id
- if (key === 'name') {
- node['id'] = group['name'];
- }
- else {
- node[key] = group[key];
- }
- }
- // legends 选择优先级 category -> group
- 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 {
- // 过滤legend未选中的数据
- matrix.splice(count, 1);
- for (var j = 0; j < matrix.length; j++) {
- matrix[j].splice(count, 1);
- }
- }
- }
- var graph = Graph.fromMatrix(nodesData, matrix, true);
- // Prepare layout parameters
- 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;
- }
- // legends 选择优先级 category -> group
- 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 是 null 或者 undefined
- value = 0;
- // 默认使用所有边值的和作为节点的大小, 不修改 data 里的数值
- 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 为1
- 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;
- // 将值映射到minRadius-maxRadius的范围上
- 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 initPos;
- 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];
- }
- // 强制设定节点大小,否则默认映射到 minRadius 到 maxRadius 后的值
- 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) || '';
- }
- // !!Pack data before addShape
- ecData.pack(
- shape,
- serie,
- serieIdx,
- // data
- node.data,
- // data index
- node.rawIndex,
- // name
- node.data.name || '',
- // category
- // special
- 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');
- // TODO 暂时只有线段支持箭头
- 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
- serie,
- // serie index
- serieIdx,
- // link data
- gEdge.data,
- // link data index
- gEdge.rawIndex == null ? i : gEdge.rawIndex,
- // source name - target name
- gEdge.data.name || (source.id + ' - ' + target.id),
- // link source id
- // special
- source.id,
- // link target id
- // special2
- target.id
- );
- this.shapeList.push(linkShape);
- this.zr.addShape(linkShape);
- gEdge.shape = linkShape;
- // Arrow shape
- 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',
- // Use same style with link shape
- 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 = {}赋值啊!!
- status.dragIn = true;
- //你自己refresh的话把他设为false,设true就会重新调refresh接口
- 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;
- });
|