提交 37b25730 编写于 作者: D deqingli

refactor(sankey): update the method of drawing sankey diagram and add test

上级 1b907924
......@@ -73,34 +73,34 @@ var SankeyShape = graphic.extendShape({
},
buildPath: function (ctx, shape) {
var halfExtent = shape.extent / 2;
var extent = shape.extent;
var orient = shape.orient;
if (orient === 'vertical') {
ctx.moveTo(shape.x1 - halfExtent, shape.y1);
ctx.moveTo(shape.x1, shape.y1);
ctx.bezierCurveTo(
shape.cpx1 - halfExtent, shape.cpy1,
shape.cpx2 - halfExtent, shape.cpy2,
shape.x2 - halfExtent, shape.y2
shape.cpx1, shape.cpy1,
shape.cpx2, shape.cpy2,
shape.x2, shape.y2
);
ctx.lineTo(shape.x2 + halfExtent, shape.y2);
ctx.lineTo(shape.x2 + extent, shape.y2);
ctx.bezierCurveTo(
shape.cpx2 + halfExtent, shape.cpy2,
shape.cpx1 + halfExtent, shape.cpy1,
shape.x1 + halfExtent, shape.y1
shape.cpx2 + extent, shape.cpy2,
shape.cpx1 + extent, shape.cpy1,
shape.x1 + extent, shape.y1
);
}
else {
ctx.moveTo(shape.x1, shape.y1 - halfExtent);
ctx.moveTo(shape.x1, shape.y1);
ctx.bezierCurveTo(
shape.cpx1, shape.cpy1 - halfExtent,
shape.cpx2, shape.cpy2 - halfExtent,
shape.x2, shape.y2 - halfExtent
shape.cpx1, shape.cpy1,
shape.cpx2, shape.cpy2,
shape.x2, shape.y2
);
ctx.lineTo(shape.x2, shape.y2 + halfExtent);
ctx.lineTo(shape.x2, shape.y2 + extent);
ctx.bezierCurveTo(
shape.cpx2, shape.cpy2 + halfExtent,
shape.cpx1, shape.cpy1 + halfExtent,
shape.x1, shape.y1 + halfExtent
shape.cpx2, shape.cpy2 + extent,
shape.cpx1, shape.cpy1 + extent,
shape.x1, shape.y1 + extent
);
}
ctx.closePath();
......@@ -159,29 +159,37 @@ export default echarts.extendChartView({
var dragX2 = node2Model.get('localX');
var dragY2 = node2Model.get('localY');
var edgeLayout = edge.getLayout();
var x1;
var y1;
var x2;
var y2;
var cpx1;
var cpy1;
var cpx2;
var cpy2;
curve.shape.extent = Math.max(1, edgeLayout.dy);
curve.shape.orient = orient;
if (orient === 'vertical') {
var x1 = (dragX1 != null ? dragX1 * width : n1Layout.x) + edgeLayout.sy + edgeLayout.dy / 2;
var y1 = (dragY1 != null ? dragY1 * height : n1Layout.y) + n1Layout.dy;
var x2 = (dragX2 != null ? dragX2 * width : n2Layout.x) + edgeLayout.ty + edgeLayout.dy / 2;
var y2 = dragY2 != null ? dragY2 * height : n2Layout.y;
var cpx1 = x1;
var cpy1 = y1 * (1 - curvature) + y2 * curvature;
var cpx2 = x2;
var cpy2 = y1 * curvature + y2 * (1 - curvature);
x1 = (dragX1 != null ? dragX1 * width : n1Layout.x) + edgeLayout.sy;
y1 = (dragY1 != null ? dragY1 * height : n1Layout.y) + n1Layout.dy;
x2 = (dragX2 != null ? dragX2 * width : n2Layout.x) + edgeLayout.ty;
y2 = dragY2 != null ? dragY2 * height : n2Layout.y;
cpx1 = x1;
cpy1 = y1 * (1 - curvature) + y2 * curvature;
cpx2 = x2;
cpy2 = y1 * curvature + y2 * (1 - curvature);
}
else {
var x1 = (dragX1 != null ? dragX1 * width : n1Layout.x) + n1Layout.dx;
var y1 = (dragY1 != null ? dragY1 * height : n1Layout.y) + edgeLayout.sy + edgeLayout.dy / 2;
var x2 = dragX2 != null ? dragX2 * width : n2Layout.x;
var y2 = (dragY2 != null ? dragY2 * height : n2Layout.y) + edgeLayout.ty + edgeLayout.dy / 2;
var cpx1 = x1 * (1 - curvature) + x2 * curvature;
var cpy1 = y1;
var cpx2 = x1 * curvature + x2 * (1 - curvature);
var cpy2 = y2;
x1 = (dragX1 != null ? dragX1 * width : n1Layout.x) + n1Layout.dx;
y1 = (dragY1 != null ? dragY1 * height : n1Layout.y) + edgeLayout.sy;
x2 = dragX2 != null ? dragX2 * width : n2Layout.x;
y2 = (dragY2 != null ? dragY2 * height : n2Layout.y) + edgeLayout.ty;
cpx1 = x1 * (1 - curvature) + x2 * curvature;
cpy1 = y1;
cpx2 = x1 * curvature + x2 * (1 - curvature);
cpy2 = y2;
}
curve.setShape({
......
......@@ -23,6 +23,7 @@
*/
import * as layout from '../../util/layout';
import nest from '../../util/nest';
import * as zrUtil from 'zrender/src/core/util';
import { __DEV__ } from '../../config';
......@@ -227,38 +228,15 @@ function scaleNodeBreadths(nodes, kx, orient) {
* @param {number} iterations the number of iterations for the algorithm
*/
function computeNodeDepths(nodes, edges, height, width, nodeGap, iterations, orient) {
var i = -1;
var valuesByKey = {};
while (++i < nodes.length) {
if (orient === 'vertical') {
var keyValue = nodes[i].getLayout().y;
}
else {
var keyValue = nodes[i].getLayout().x;
}
var values = valuesByKey[keyValue];
if (values) {
values.push(nodes[i]);
}
else {
valuesByKey[keyValue] = [nodes[i]];
}
}
var tempArray = [];
zrUtil.each(valuesByKey, function (value, key) {
tempArray.push({
key: key, values: value
var nodesByBreadth = nest()
.key(getKeyFunction(orient))
.sortKeys(function (a, b) {
return a - b;
})
.entries(nodes)
.map(function (d) {
return d.values;
});
});
tempArray.sort(function (a, b) {
return a.key - b.key;
});
var nodesByBreadth = tempArray.map(function (d) {
return d.values;
});
initializeNodeDepth(nodes, nodesByBreadth, edges, height, width, nodeGap, orient);
resolveCollisions(nodesByBreadth, nodeGap, height, width, orient);
......@@ -274,6 +252,17 @@ function computeNodeDepths(nodes, edges, height, width, nodeGap, iterations, ori
}
}
function getKeyFunction(orient) {
if (orient === 'vertical') {
return function (d) {
return d.getLayout().y;
};
}
return function (d) {
return d.getLayout().x;
};
}
/**
* Compute the original y-position for each node
*
......
......@@ -28,7 +28,7 @@ import {getDimensionTypeByAxis} from '../../data/helper/dimensionHelper';
import List from '../../data/List';
import * as zrUtil from 'zrender/src/core/util';
import {encodeHTML} from '../../util/format';
import nest from '../../util/array/nest';
import nest from '../../util/nest';
var DATA_NAME_INDEX = 2;
......@@ -48,6 +48,7 @@ var ThemeRiverSeries = SeriesModel.extend({
* @override
*/
init: function (option) {
// eslint-disable-next-line
ThemeRiverSeries.superApply(this, 'init', arguments);
// Put this function here is for the sake of consistency of code style.
......
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
import * as zrUtil from 'zrender/src/core/util';
/**
* nest helper used to group by the array.
* can specified the keys and sort the keys.
*/
export default function nest() {
var keysFunction = [];
var sortKeysFunction = [];
/**
* map an Array into the mapObject.
* @param {Array} array
* @param {number} depth
*/
function map(array, depth) {
if (depth >= keysFunction.length) {
return array;
}
var i = -1;
var n = array.length;
var keyFunction = keysFunction[depth++];
var mapObject = {};
var valuesByKey = {};
while (++i < n) {
var keyValue = keyFunction(array[i]);
var values = valuesByKey[keyValue];
if (values) {
values.push(array[i]);
}
else {
valuesByKey[keyValue] = [array[i]];
}
}
zrUtil.each(valuesByKey, function (value, key) {
mapObject[key] = map(value, depth);
});
return mapObject;
}
/**
* transform the Map Object to multidimensional Array
* @param {Object} map
* @param {number} depth
*/
function entriesMap(mapObject, depth) {
if (depth >= keysFunction.length) {
return mapObject;
}
var array = [];
var sortKeyFunction = sortKeysFunction[depth++];
zrUtil.each(mapObject, function (value, key) {
array.push({
key: key, values: entriesMap(value, depth)
});
});
if (sortKeyFunction) {
return array.sort(function (a, b) {
return sortKeyFunction(a.key, b.key);
});
}
return array;
}
return {
/**
* specified the key to groupby the arrays.
* users can specified one more keys.
* @param {Function} d
*/
key: function (d) {
keysFunction.push(d);
return this;
},
/**
* specified the comparator to sort the keys
* @param {Function} order
*/
sortKeys: function (order) {
sortKeysFunction[keysFunction.length - 1] = order;
return this;
},
/**
* the array to be grouped by.
* @param {Array} array
*/
entries: function (array) {
return entriesMap(map(array, 0), 0);
}
};
}
\ No newline at end of file
<!--
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. The ASF licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied. See the License for the
specific language governing permissions and limitations
under the License.
-->
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1" />
<script src="lib/esl.js"></script>
<script src="lib/config.js"></script>
<script src="lib/jquery.min.js"></script>
</head>
<body>
<style>
html, body, #main {
width: 100%;
height: 100%;
/*border: 1px solid #000;*/
}
</style>
<div id="main"><div>
<script>
require(['echarts'], function (echarts) {
var chart = echarts.init(document.getElementById('main'), null, {});
window.onresize = function () {
chart.resize();
};
// var data = {
// nodes: [
// {name: 'Brazil'},
// {name: 'Canada'},
// {name: 'Mexico'},
// {name: 'USA'},
// {name: 'Portugal'},
// {name: 'France'},
// {name: 'Spain'},
// {name: 'England'},
// {name: 'Angola'},
// {name: 'Senegal'},
// {name: 'Morocco'},
// {name: 'South Africa'},
// {name: 'Mali'},
// {name: 'China'},
// {name: 'India'},
// {name: 'Japan'}
// ],
// links: [
// {source: 'Brazil', target: 'Portugal', value: 5},
// {source: 'Brazil', target: 'France', value: 1},
// {source: 'Brazil', target: 'Spain', value: 1},
// {source: 'Brazil', target: 'England', value: 1},
// {source: 'Canada', target: 'Portugal', value: 1},
// {source: 'Canada', target: 'France', value: 5},
// {source: 'Canada', target: 'England', value: 1},
// {source: 'Mexico', target: 'Portugal', value: 1},
// {source: 'Mexico', target: 'France', value: 1},
// {source: 'Mexico', target: 'Spain', value: 5},
// {source: 'Mexico', target: 'England', value: 1},
// {source: 'USA', target: 'Portugal', value: 1},
// {source: 'USA', target: 'France', value: 1},
// {source: 'USA', target: 'Spain', value: 1},
// {source: 'USA', target: 'England', value: 5},
// {source: 'Portugal', target: 'Angola', value: 2},
// {source: 'Portugal', target: 'Senegal', value: 1},
// {source:'Portugal', target: 'Morocco', value: 1},
// {source: 'Portugal', target: 'South Africa', value: 3},
// {source: 'France', target: 'Angola', value: 1},
// {source: 'France', target: 'Senegal', value: 3},
// {source: 'France', target: 'Mali', value: 3},
// {source: 'France', target: 'Morocco', value: 3},
// {source: 'France', target: 'South Africa', value: 1},
// {source: 'Spain', target: 'Senegal', value: 1},
// {source: 'Spain', target: 'Morocco', value: 3},
// {source: 'Spain', target: 'South Africa', value: 1},
// {source: 'England', target: 'Angola', value: 1},
// {source: 'England', target: 'Senegal', value: 1},
// {source: 'England', target: 'Morocco', value: 2},
// {source: 'England', target: 'South Africa', value: 7},
// {source: 'South Africa', target: 'China', value: 5},
// {source: 'South Africa', target: 'India', value: 1},
// {source: 'South Africa', target: 'Japan', value: 3},
// {source: 'Angola', target: 'China', value: 5},
// {source: 'Angola', target: 'India', value: 1},
// {source: 'Angola', target: 'Japan', value: 3},
// {source: 'Senegal', target: 'China', value: 5},
// {source: 'Senegal', target: 'India', value: 1},
// {source: 'Senegal', target: 'Japan', value: 3},
// {source: 'Mali', target: 'China', value: 5},
// {source: 'Mali', target: 'India', value: 1},
// {source: 'Mali', target: 'Japan', value: 3},
// {source: 'Morocco', target: 'China', value: 5},
// {source: 'Morocco', target: 'India', value: 1},
// {source: 'Morocco', target: 'Japan', value: 3}
// ]
// };
var testData = {
nodes: [
{
name: 'a'
},
{
name: 'b'
},
{
name: 'a1'
},
{
name: 'b1'
},
{
name: 'c'
},
{
name: 'e'
}
],
links: [
{
source: 'a',
target: 'a1',
value: 5
},
{
source: 'e',
target: 'b',
value: 3
},
{
source: 'a',
target: 'b1',
value: 3
},
{
source: 'b1',
target: 'a1',
value: 1
},
{
source: 'b1',
target: 'c',
value: 2
},
{
source: 'b',
target: 'c',
value: 1
}
]
};
chart.setOption({
color: ['#67001f', '#b2182b', '#d6604d', '#f4a582', '#fddbc7', '#d1e5f0', '#92c5de', '#4393c3', '#2166ac', '#053061'],
tooltip: {
trigger: 'item',
triggerOn: 'mousemove'
},
animation: false,
series: [
{
type: 'sankey',
layout:'none',
bottom: '10%',
// focusNodeAdjacency: 'allEdges',
data: testData.nodes,
links: testData.links,
orient: 'horizontal',
label: {
position: 'left'
},
// Used to test when the data is null whether it is work well.
// data: [],
// links: [],
lineStyle: {
normal: {
color: 'source',
curveness: 0.5
}
}
}
]
});
});
</script>
</body>
</html>
\ No newline at end of file
......@@ -184,8 +184,6 @@ under the License.
data: testData.nodes,
links: testData.links,
orient: 'vertical',
// orient: 'horizontal',
label: {
position: 'left'
},
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册