From d9c5d2fcc10f60cb86d76d6a8a996e162abcb48b Mon Sep 17 00:00:00 2001 From: zakwu <123537200@qq.com> Date: Thu, 11 Jun 2020 19:40:59 +0800 Subject: [PATCH] fix(tree): code rebuild follow the review suggest --- src/chart/graph/GraphSeries.js | 5 +- src/chart/graph/circularLayoutHelper.js | 10 +- src/chart/graph/forceLayout.js | 8 +- src/chart/graph/simpleLayoutHelper.js | 17 +- src/chart/helper/createGraphFromNodeEdge.js | 6 +- src/chart/helper/multipleGraphEdgeHelper.js | 230 ++++++++++---------- src/data/Graph.js | 6 +- test/graph-mulitple-edges.html | 107 ++++++--- 8 files changed, 234 insertions(+), 155 deletions(-) diff --git a/src/chart/graph/GraphSeries.js b/src/chart/graph/GraphSeries.js index 13682126d..beaaaa058 100644 --- a/src/chart/graph/GraphSeries.js +++ b/src/chart/graph/GraphSeries.js @@ -25,6 +25,7 @@ import Model from '../../model/Model'; import {encodeHTML} from '../../util/format'; import createGraphFromNodeEdge from '../helper/createGraphFromNodeEdge'; import LegendVisualProvider from '../../visual/LegendVisualProvider'; +import {initCurvenessList} from '../helper/multipleGraphEdgeHelper'; var GraphSeries = echarts.extendSeriesModel({ @@ -66,6 +67,8 @@ var GraphSeries = echarts.extendSeriesModel({ var self = this; if (nodes && edges) { + // auto curveness + initCurvenessList(edges, this); return createGraphFromNodeEdge(nodes, edges, this, true, beforeLink).data; } @@ -289,4 +292,4 @@ var GraphSeries = echarts.extendSeriesModel({ } }); -export default GraphSeries; \ No newline at end of file +export default GraphSeries; diff --git a/src/chart/graph/circularLayoutHelper.js b/src/chart/graph/circularLayoutHelper.js index 3552c626d..93f888ad8 100644 --- a/src/chart/graph/circularLayoutHelper.js +++ b/src/chart/graph/circularLayoutHelper.js @@ -19,6 +19,8 @@ import * as vec2 from 'zrender/src/core/vector'; import {getSymbolSize, getNodeGlobalScale} from './graphHelper'; +import * as zrUtil from 'zrender/src/core/util'; +import {getCurvenessForEdge} from '../helper/multipleGraphEdgeHelper'; var PI = Math.PI; @@ -73,8 +75,12 @@ export function circularLayout(seriesModel, basedOn) { _layoutNodesBasedOn[basedOn](seriesModel, coordSys, graph, nodeData, r, cx, cy, count); - graph.eachEdge(function (edge) { - var curveness = edge.getModel().get('lineStyle.curveness') || 0; + graph.eachEdge(function (edge, index) { + var curveness = zrUtil.retrieve3( + getCurvenessForEdge(edge, seriesModel, index), + edge.getModel().get('lineStyle.curveness'), + 0 + ); var p1 = vec2.clone(edge.node1.getLayout()); var p2 = vec2.clone(edge.node2.getLayout()); var cp1; diff --git a/src/chart/graph/forceLayout.js b/src/chart/graph/forceLayout.js index e61555ac1..a0b6da02c 100644 --- a/src/chart/graph/forceLayout.js +++ b/src/chart/graph/forceLayout.js @@ -23,6 +23,7 @@ import {circularLayout} from './circularLayoutHelper'; import {linearMap} from '../../util/number'; import * as vec2 from 'zrender/src/core/vector'; import * as zrUtil from 'zrender/src/core/util'; +import {getCurvenessForEdge} from '../helper/multipleGraphEdgeHelper'; export default function (ecModel) { ecModel.eachSeriesByType('graph', function (graphSeries) { @@ -84,11 +85,16 @@ export default function (ecModel) { d = (edgeLength[0] + edgeLength[1]) / 2; } var edgeModel = edge.getModel(); + var curveness = zrUtil.retrieve3( + -getCurvenessForEdge(edge, graphSeries, idx, true), + edge.getModel().get('lineStyle.curveness'), + 0 + ); return { n1: nodes[edge.node1.dataIndex], n2: nodes[edge.node2.dataIndex], d: d, - curveness: edgeModel.get('lineStyle.curveness') || 0, + curveness: curveness, ignoreForceLayout: edgeModel.get('ignoreForceLayout') }; }); diff --git a/src/chart/graph/simpleLayoutHelper.js b/src/chart/graph/simpleLayoutHelper.js index 83d026c61..022989a5f 100644 --- a/src/chart/graph/simpleLayoutHelper.js +++ b/src/chart/graph/simpleLayoutHelper.js @@ -18,6 +18,9 @@ */ import * as vec2 from 'zrender/src/core/vector'; +import * as zrUtil from 'zrender/src/core/util'; +import {getCurvenessForEdge} from '../helper/multipleGraphEdgeHelper'; + export function simpleLayout(seriesModel) { var coordSys = seriesModel.coordinateSystem; @@ -31,12 +34,16 @@ export function simpleLayout(seriesModel) { node.setLayout([+model.get('x'), +model.get('y')]); }); - simpleLayoutEdge(graph); + simpleLayoutEdge(graph, seriesModel); } -export function simpleLayoutEdge(graph) { - graph.eachEdge(function (edge) { - var curveness = edge.getModel().get('lineStyle.curveness') || 0; +export function simpleLayoutEdge(graph, seriesModel) { + graph.eachEdge(function (edge, index) { + var curveness = zrUtil.retrieve3( + edge.getModel().get('lineStyle.curveness') || null, + -getCurvenessForEdge(edge, seriesModel, index, true), + 0 + ); var p1 = vec2.clone(edge.node1.getLayout()); var p2 = vec2.clone(edge.node2.getLayout()); var points = [p1, p2]; @@ -48,4 +55,4 @@ export function simpleLayoutEdge(graph) { } edge.setLayout(points); }); -} \ No newline at end of file +} diff --git a/src/chart/helper/createGraphFromNodeEdge.js b/src/chart/helper/createGraphFromNodeEdge.js index b5ccccd89..8f875f352 100644 --- a/src/chart/helper/createGraphFromNodeEdge.js +++ b/src/chart/helper/createGraphFromNodeEdge.js @@ -24,7 +24,6 @@ import linkList from '../../data/helper/linkList'; import createDimensions from '../../data/helper/createDimensions'; import CoordinateSystem from '../../CoordinateSystem'; import createListFromArray from './createListFromArray'; -import {calculateMutilEdges, setCurvenessForLink} from './multipleGraphEdgeHelper'; export default function (nodes, edges, seriesModel, directed, beforeLink) { // ??? TODO @@ -41,16 +40,13 @@ export default function (nodes, edges, seriesModel, directed, beforeLink) { var validEdges = []; var linkCount = 0; - // auto curveness - calculateMutilEdges(edges, seriesModel, graph); for (var i = 0; i < edges.length; i++) { var link = edges[i]; var source = link.source; var target = link.target; - setCurvenessForLink(link, seriesModel, i, graph); // addEdge may fail when source or target not exists - if (graph.addEdge(source, target, linkCount)) { + if (graph.addEdge(source, target, linkCount, seriesModel)) { validEdges.push(link); linkNameList.push(zrUtil.retrieve(link.id, source + ' > ' + target)); linkCount++; diff --git a/src/chart/helper/multipleGraphEdgeHelper.js b/src/chart/helper/multipleGraphEdgeHelper.js index 7176a232e..ee3ba0f52 100644 --- a/src/chart/helper/multipleGraphEdgeHelper.js +++ b/src/chart/helper/multipleGraphEdgeHelper.js @@ -17,122 +17,117 @@ * under the License. */ -var linkMap = {}; -var curvenessList = []; - +var KEY_DELIMITER = '-->'; /** * params handler - * @param seriesModel + * @param {module:echarts/model/SeriesModel} seriesModel * @returns {*} */ var getAutoCurvenessParams = function (seriesModel) { - var autoCurveness = seriesModel.getModel('autoCurveness'); - - if (!autoCurveness || !autoCurveness.option) { - return null; - } - - return autoCurveness.option; + return seriesModel.get('autoCurveness') || null; }; /** * Generate a list of edge curvatures, 20 is the default - * @param seriesModel - * @param addLength append length + * @param {module:echarts/model/SeriesModel} seriesModel + * @param {number} appendLength * @return 20 => [0, -0.2, 0.2, -0.4, 0.4, -0.6, 0.6, -0.8, 0.8, -1, 1, -1.2, 1.2, -1.4, 1.4, -1.6, 1.6, -1.8, 1.8, -2] */ -var createCurveness = function (seriesModel, addLength) { - var autoCurvenssParmas = getAutoCurvenessParams(seriesModel); +var createCurveness = function (seriesModel, appendLength) { + var autoCurvenessParmas = getAutoCurvenessParams(seriesModel); var length = 20; + var curvenessList = []; // handler the function set - if (typeof autoCurvenssParmas === 'number') { - length = autoCurvenssParmas; + if (typeof autoCurvenessParmas === 'number') { + length = autoCurvenessParmas; } - else if (typeof autoCurvenssParmas === 'function') { - curvenessList = autoCurvenssParmas(); + else if (Object.prototype.toString.call(autoCurvenessParmas) === '[object Array]') { + seriesModel._curvenessList = autoCurvenessParmas; return; } - // addLength - if (addLength) { - length = addLength; - } - - // if already calculated return - if (length < curvenessList.length) { - return; + // append length + if (appendLength > length) { + length = appendLength; } - // 保证长度为偶数 + // make sure the length is even var len = length % 2 ? length + 2 : length + 3; curvenessList = []; for (var i = 0; i < len; i++) { curvenessList.push((i % 2 ? i + 1 : i) / 10 * (i % 2 ? -1 : 1)); } + seriesModel._curvenessList = curvenessList; }; /** * Create different cache key data in the positive and negative directions, in order to set the curvature later - * @param link - * @param seriesModel - * @returns {string} + * @param {number|string|module:echarts/data/Graph.Node} n1 + * @param {number|string|module:echarts/data/Graph.Node} n2 + * @param {module:echarts/model/SeriesModel} seriesModel + * @returns {string} key */ -var getKeyOfLinks = function (link, seriesModel) { - return [seriesModel.uid, link.source, link.target].join('>'); +var getKeyOfEdges = function (n1, n2, seriesModel) { + var source = [n1.id, n1.dataIndex].join('.'); + var target = [n2.id, n2.dataIndex].join('.'); + return [seriesModel.uid, source, target].join(KEY_DELIMITER); }; /** * get opposite key - * 获取反向的key - * @param key + * @param {string} key * @returns {string} */ var getOppositeKey = function (key) { - var keys = key.split('>'); - - return [keys[0], keys[2], keys[1]].join('>'); + var keys = key.split(KEY_DELIMITER); + return [keys[0], keys[2], keys[1]].join(KEY_DELIMITER); }; /** - * set linkMap with key - * @param link - * @param seriesModel - * @param index + * set edgeMap with key + * @param {number|string|module:echarts/data/Graph.Node} n1 + * @param {number|string|module:echarts/data/Graph.Node} n2 + * @param {module:echarts/model/SeriesModel} seriesModel + * @param {number} index */ -var setLinkToMap = function (link, seriesModel, index) { - var key = getKeyOfLinks(link, seriesModel); - var hasOppositeLinks = linkMap[getOppositeKey(key)]; +var setEdgeToMap = function (n1, n2, seriesModel, index) { + var key = getKeyOfEdges(n1, n2, seriesModel); + var edgeMap = seriesModel._edgeMap; + var oppositeEdges = edgeMap[getOppositeKey(key)]; // set direction - if (hasOppositeLinks && linkMap[key] && !linkMap[key].isForward) { - linkMap[getOppositeKey(key)].isForward = true; + if (edgeMap[key] && !oppositeEdges) { + edgeMap[key].isForward = true; + } + else if (oppositeEdges && edgeMap[key]) { + oppositeEdges.isForward = true; + edgeMap[key].isForward = false; } - linkMap[key] = linkMap[key] || []; - linkMap[key].push(index); + edgeMap[key] = edgeMap[key] || []; + edgeMap[key].push(index); }; /** - * get linkMap with key - * @param link - * @param seriesModel - * @param index + * get edgeMap with key + * @param edge + * @param {module:echarts/model/SeriesModel} seriesModel */ -var getLinkFromMap = function (link, seriesModel) { - var key = getKeyOfLinks(link, seriesModel); - return linkMap[key]; +var getEdgeFromMap = function (edge, seriesModel) { + var key = getKeyOfEdges(edge.node1, edge.node2, seriesModel); + return seriesModel._edgeMap[key]; }; /** * calculate all cases total length - * @param link + * @param edge * @param seriesModel * @returns {number} */ -var getTotalLengthBetweenNodes = function (link, seriesModel) { - var len = getLinkMapLengthWithKey([seriesModel.uid, link.source, link.target].join('>')); - var lenV = getLinkMapLengthWithKey([seriesModel.uid, link.target, link.source].join('>')); +var getTotalLengthBetweenNodes = function (edge, seriesModel) { + var len = getEdgeMapLengthWithKey(getKeyOfEdges(edge.node1, edge.node2, seriesModel), seriesModel); + var lenV = getEdgeMapLengthWithKey(getKeyOfEdges(edge.node2, edge.node1, seriesModel), seriesModel); return len + lenV; }; @@ -141,81 +136,96 @@ var getTotalLengthBetweenNodes = function (link, seriesModel) { * * @param key */ -var getLinkMapLengthWithKey = function (key) { - return linkMap[key] ? linkMap[key].length : 0; +var getEdgeMapLengthWithKey = function (key, seriesModel) { + var edgeMap = seriesModel._edgeMap; + return edgeMap[key] ? edgeMap[key].length : 0; }; /** * Count the number of edges between the same two points, used to obtain the curvature table and the parity of the edge + * @see /graph/GraphSeries.js@getInitialData * @param edges - * @param seriesModel - * @param graph + * @param {module:echarts/model/SeriesModel} seriesModel */ -export function calculateMutilEdges(edges, seriesModel, graph) { +export function initCurvenessList(edges, seriesModel) { if (!getAutoCurvenessParams(seriesModel)) { return; } // Hang on this object 4 dispose - curvenessList = graph.curvenessList || []; - linkMap = graph.linkMap = graph.linkMap || {}; - - - for (var i = 0; i < edges.length; i++) { - var link = edges[i]; - var source = link.source; - var target = link.target; - if (!source || !target) { - continue; - } - setLinkToMap(link, seriesModel, i); - } - - // calc the array of curvenessList + seriesModel._curvenessList = seriesModel._curvenessList || []; + // calc the array of curveness List createCurveness(seriesModel); } /** - * Set curvature for link - * @param link - * @param seriesModel + * create the edgeMap after addEdges + * @see chart/helper/createGraphFromNodeEdge.js#L52 + * @param {number|string|module:echarts/data/Graph.Node} n1 + * @param {number|string|module:echarts/data/Graph.Node} n2 + * @param {module:echarts/model/SeriesModel} seriesModel + * @param {number} dataIndex + */ +export function createEdgeMapForCurveness(n1, n2, seriesModel, dataIndex) { + seriesModel._edgeMap = seriesModel._edgeMap || {}; + setEdgeToMap(n1, n2, seriesModel, dataIndex); +} + +/** + * get curvature for edge + * @param edge + * @param {module:echarts/model/SeriesModel} seriesModel * @param index */ -export function setCurvenessForLink(link, seriesModel, index) { - if (!getAutoCurvenessParams(seriesModel)) { - return; +export function getCurvenessForEdge(edge, seriesModel, index, needReverse) { + const autoCurvenessParams = getAutoCurvenessParams(seriesModel); + const isArrayParam = Object.prototype.toString.call(autoCurvenessParams) === '[object Array]'; + if (!autoCurvenessParams) { + return null; } - var linkArray = getLinkFromMap(link, seriesModel); - if (!linkArray) { - return; + var edgeArray = getEdgeFromMap(edge, seriesModel); + if (!edgeArray) { + return null; } - var linkIndex = linkArray.findIndex(function (it) { - return it === index; - }); - var totalLen = getTotalLengthBetweenNodes(link, seriesModel); - // if totalLen bigger than curvenessList, recreate curvenessList - if (totalLen > curvenessList.length) { - createCurveness(seriesModel, totalLen); + var edgeIndex = -1; + for (var i = 0; i < edgeArray.length; i++) { + if (edgeArray[i] === index) { + edgeIndex = i; + break; + } } - - link.lineStyle = link.lineStyle || {}; - // if is opposite link, must set curvenss to opposite number - var curKey = getKeyOfLinks(link, seriesModel); - if (!linkArray.isForward) { - // the opposite link show outside + // if totalLen is Longer createCurveness + var totalLen = getTotalLengthBetweenNodes(edge, seriesModel); + createCurveness(seriesModel, totalLen); + + edge.lineStyle = edge.lineStyle || {}; + // if is opposite edge, must set curvenss to opposite number + var curKey = getKeyOfEdges(edge.node1, edge.node2, seriesModel); + var curvenessList = seriesModel._curvenessList; + // if pass array no need parity + var parityCorrection = isArrayParam ? 0 : totalLen % 2 ? 0 : 1; + + if (!edgeArray.isForward) { + // the opposite edge show outside var oppositeKey = getOppositeKey(curKey); - var len = getLinkMapLengthWithKey(oppositeKey); - var layout = seriesModel.getModel('layout').option; - // Because the curvature algorithm of each layout is different, the reverse needs to be adapted here - if (layout === 'none' || layout === 'force') { - link.lineStyle.curveness = -1 * curvenessList[linkIndex + len + (totalLen % 2 ? 0 : 1)]; + var len = getEdgeMapLengthWithKey(oppositeKey, seriesModel); + var resValue = curvenessList[edgeIndex + len + parityCorrection]; + // isNeedReverse, simple, force type need reverse the curveness in the junction of the forword and the opposite + if (needReverse) { + // set as array may make the parity by add 1 + if (isArrayParam) { + return (len + parityCorrection + 1) % 2 ? resValue : -resValue; + } + else { + return (len + parityCorrection) % 2 ? resValue : -resValue; + } } - else if (layout === 'circular') { - link.lineStyle.curveness = curvenessList[linkIndex + len + (totalLen % 2 ? 0 : 1)]; + else { + return curvenessList[edgeIndex + len + parityCorrection]; } } else { - link.lineStyle.curveness = curvenessList[linkIndex + (totalLen % 2 ? 0 : 1)]; + return curvenessList[edgeIndex]; } } diff --git a/src/data/Graph.js b/src/data/Graph.js index 236089f81..a9f986198 100644 --- a/src/data/Graph.js +++ b/src/data/Graph.js @@ -20,6 +20,7 @@ import {__DEV__} from '../config'; import * as zrUtil from 'zrender/src/core/util'; import {enableClassCheck} from '../util/clazz'; +import {createEdgeMapForCurveness} from '../chart/helper/multipleGraphEdgeHelper'; // id may be function name of Object, add a prefix to avoid this problem. function generateNodeKey(id) { @@ -137,9 +138,10 @@ graphProto.getNodeById = function (id) { * @param {number|string|module:echarts/data/Graph.Node} n1 * @param {number|string|module:echarts/data/Graph.Node} n2 * @param {number} [dataIndex=-1] + * @param {module:echarts/model/SeriesModel} seriesModel * @return {module:echarts/data/Graph.Edge} */ -graphProto.addEdge = function (n1, n2, dataIndex) { +graphProto.addEdge = function (n1, n2, dataIndex, seriesModel) { var nodesMap = this._nodesMap; var edgesMap = this._edgesMap; @@ -177,6 +179,8 @@ graphProto.addEdge = function (n1, n2, dataIndex) { this.edges.push(edge); edgesMap[key] = edge; + createEdgeMapForCurveness(n1, n2, seriesModel, dataIndex); + return edge; }; diff --git a/test/graph-mulitple-edges.html b/test/graph-mulitple-edges.html index 4e7d6c504..e5fa604bc 100644 --- a/test/graph-mulitple-edges.html +++ b/test/graph-mulitple-edges.html @@ -34,6 +34,7 @@ under the License. }
+
@@ -41,37 +42,74 @@ under the License.
+ +