提交 64cc4a94 编写于 作者: L lang

Have a try

上级
define(function (require) {
var zrUtil = require('zrender/core/util');
function Chart(echarts, chartOption) {
}
Chart.prototype = {
type: '',
init: function () {},
render: function () {},
dispose: function () {}
};
var chartClassStore = {};
Chart.extend = function (proto) {
var Super = this;
var ExtendedChart = function (echarts, chartOption) {
Super.call(this, echarts, chartOption);
};
for (var name in proto) {
ExtendedChart.prototype[name] = proto[name];
}
ExtendedChart.extend = Super.extend;
zrUtil.inherits(ExtendedChart, Super);
if (proto.type) {
if (chartClassStore[proto.type]) {
// Error exists
}
chartClassStore[proto.type] = ExtendedChart;
}
return ExtendedChart;
};
/**
* Create a chart by a given option
*/
Chart.create = function (option) {
var chartType = option.type;
var ExtendedChart = chartClassStore[chartType];
if (! ExtendedChart) {
// Error
}
return new ExtendedChart(option);
};
return Chart;
});
\ No newline at end of file
define(function (require) {
var Chart = require('../Chart');
require('./BarSeries');
var Bar = Chart.extend({
type: 'bar',
init: function () {
},
render: function () {
}
});
return Bar;
});
\ No newline at end of file
define(function(require) {
'use strict';
var Series = require('../../data/Series');
var List = require('../../data/List');
var BarSeries = Series.extend({
type: 'bar',
getInitialData: function (option) {
return List.fromArray(option.data);
}
});
return BarSeries;
});
\ No newline at end of file
define(function (require) {
var stateSyncHelper = require('../../processor/legendFilterStateSyncHelper')('pieDataItemFilter');
var PieDataFilter = require('../../processor/Processor').extend({
type: 'pieDataItemFilter',
getInitialState: function (option) {
var allData = option.get('legend.data') || [];
return {
all: allData,
legend: allData.slice()
};
},
syncState: function (globalState) {
stateSyncHelper(this.state, globalState);
},
process: function (option, processorCenter) {
option.eachSeries(function (series) {
if (series.type === 'pie') {
series.getData().filter(function (dataItem) {
return this.state.indexOf(dataItem.name) >= 0;
}, this);
}
}, this);
}
});
return PieDataFilter;
});
\ No newline at end of file
define(function (require) {
require('./PieSeries');
var DataItemFilter = require('./DataItemFilter');
var Pie = require('../Chart').extend({
type: 'pie',
init: function (echarts) {
var dataItemFilter = new DataItemFilter();
this._dataItemFilter = dataItemFilter;
echarts.addProcessor(dataItemFilter);
},
render: function () {
},
dispose: function (echarts) {
echarts.removeProcessor()
}
});
return Pie;
});
\ No newline at end of file
define(function(require) {
'use strict';
var Series = require('../../data/Series');
var List = require('../../data/List');
var PieSeries = Series.extend({
type: 'pie',
getInitialData: function (option) {
return List.fromArray(option.data);
}
});
return PieSeries;
});
\ No newline at end of file
define(function (require) {
var zrUtil = require('zrender/core/util');
var Component = function () {
};
Component.prototype = {
constructor: Component,
init: function () {},
render: function () {},
dispose: function () {}
};
var componentClassStore = {};
var componentTypeList = [];
Component.extend = function (proto) {
var Super = this;
var ExtendedComponent = function (echarts, chartOption) {
Super.call(this, echarts, chartOption);
};
for (var name in proto) {
ExtendedComponent.prototype[name] = proto[name];
}
ExtendedComponent.extend = Super.extend;
zrUtil.inherits(ExtendedComponent, Super);
if (proto.type) {
if (componentClassStore[proto.type]) {
// Error exists
return;
}
componentClassStore[proto.type] = ExtendedComponent;
componentTypeList.push(proto.type);
}
return ExtendedComponent;
};
Component.eachAvailableComponent = function (cb, context) {
zrUtil.each(componentTypeList, cb, context);
};
Component.create = function (type, option) {
var Component = componentClassStore[type];
if (! Component) {
// Error
}
return new Component();
}
return Component;
});
\ No newline at end of file
define(function (require) {
return require('../Component').extend({
type: 'dataZoom',
init: function (echarts) {
},
render: function (option) {
},
});
});
\ No newline at end of file
define(function (require) {
var zrUtil = require('zrender/core/util');
return require('../Component').extend({
type: 'legend',
init: function () {
},
render: function (option, processorState) {
}
});
});
\ No newline at end of file
{
}
\ No newline at end of file
/**
* Cartesian coordinate system
* @module echarts/coord/Cartesian
*
*/
define(function (require) {
'use strict';
var linearMap = require('../core/number').linearMap;
var util = require('zrender/tool/util');
/**
* @name module:echarts/coord/Cartesian.Axis
* @constructor
*/
var Axis = function (name, scale, coordExtent) {
/**
* Axis name. Such as 'x', 'y', 'z'
* @type {string}
*/
this.name = name;
/**
* Axis scale
* @type {module:echarts/coord/scale/*}
*/
this.scale = scale;
this._coordExtent = coordExtent;
};
Axis.prototype = {
constructor: Axis,
/**
* Reverse axis direction
*/
reverse: function () {
this._coordExtent = this._coordExtent.reverse();
},
/**
* Get coord extent
* @return {Array.<number>}
*/
getCoordExtent: function () {
return this._coordExtent;
},
/**
* Set coord extent
* @param {number} min
* @param {number} max
*/
setCoordExtent: function (min, max) {
var extent = this._coordExtent;
extent[0] = min;
extent[1] = max;
},
/**
* Map a data to coord. Data is the rank if it has a ordinal scale
* @param {number} data
* @return {number}
*/
dataToCoord: function (data) {
data = this.scale.normalize(data);
return linearMap(data, [0, 1], this._coordExtent);
},
/**
* Map a coord to data. Data is the rank if it has a ordinal scale
* @param {number} coord
* @return {number}
*/
coordToData: function (coord) {
var t = linearMap(coord, this._coordExtent, [0, 1]);
return this.scale.scale(t);
},
/**
* @return {ticks}
*/
getTicksCoords: function () {
var ticks = this.scale.getTicks();
return util.map(ticks, function (data) {
return this.dataToCoord(data);
}, this);
},
/**
* Get coords of bands.
* If axis has ticks [1, 2, 3, 4]. Bands on the axis are
* |---1---|---2---|---3---|---4---|. And band coords is an array of coords
* where `|` is. It is useful when axis has an ordinal scale.
*
* @param {boolean} [margin=false]
* If margin is true. Coord extent is start at the position of first tick and end
* at the position of last tick.
* @return {Array.<number>}
*/
getBandsCoords: function (margin) {
var coordExtent = this._coordExtent;
var extent = this.scale.getExtent();
var coords = [];
var len = extent[1] - extent[0] + 1;
var startCoord = coordExtent[0];
var endCoord = coordExtent[1];
var size = endCoord - startCoord;
if (margin) {
var marginSize = size / (len * 2 - 2);
startCoord -= marginSize;
size += marginSize * 2;
}
for (var i = 0; i <= len; i++) {
coords.push(size * i / len + startCoord);
}
return coords;
},
/**
* Get width of band
* @param {boolean} margin
* @return {number}
*/
getBandWidth: function (margin) {
var coordExtent = this._coordExtent;
var extent = this.scale.getExtent();
var len = extent[1] - extent[0] + 1;
var size = coordExtent[1] - coordExtent[0];
if (margin) {
size += size / (len - 1);
}
return Math.abs(size) / len;
}
};
function keyAxisMapper(key) {
return this._axis[key];
}
/**
* @alias module:echarts/coord/Cartesian
* @constructor
*/
var Cartesian = function (name) {
this._axis = {};
this._axisKeyList = [];
/**
* @type {string}
*/
this.name = name || '';
/**
* Series using this cartesian coordinate system
* @type {Array.<Object>}
*/
this.series = [];
};
Cartesian.prototype = {
constructor: Cartesian,
/**
* Get axis
* @param {number|string} key
* @return {module:echarts/coord/Cartesian~Axis}
*/
getAxis: function (key) {
return this._axis[key];
},
/**
* Get axes list
* @return {Array.<module:echarts/coord/Cartesian~Axis>}
*/
getAxes: function () {
return util.map(this._axisKeyList, keyAxisMapper, this);
},
/**
* Get axes list by given scale type
*/
getAxesByScale: function (scaleType) {
scaleType = scaleType.toLowerCase();
return util.filter(
this.getAxes(),
function (axis) {
return axis.scale.type === scaleType;
}
);
},
/**
* Create a basic axis
* @param {number|string} key
* @return {module:echarts/coord/Cartesian.Axis}
*/
createAxis: function (key, scale, coordExtent) {
var axis = new Axis(key, scale, coordExtent);
this.addAxis(axis);
return axis;
},
/**
* Add axis
* @param {module:echarts/coord/Cartesian.Axis}
*/
addAxis: function (axis) {
var key = axis.name;
this._axis[key] = axis;
this._axisKeyList.push(key);
},
/**
* Convert data to coord in nd space
* @param {Array.<number>|Object.<string, number>} val
* @param {boolean} clamp
* @return {Array.<number>|Object.<string, number>}
*/
dataToCoord: function (val, clamp) {
return this._dataCoordConvert(val, 'dataToCoord', clamp);
},
/**
* Convert coord in nd space to data
* @param {Array.<number>|Object.<string, number>} val
* @param {boolean} clamp
* @return {Array.<number>|Object.<string, number>}
*/
coordToData: function (val, clamp) {
return this._dataCoordConversion(val, 'coordToData', clamp);
},
_dataCoordConvert: function (input, method, clamp) {
var axisKeyList = this._axisKeyList;
var output = input instanceof Array ? [] : {};
for (var i = 0; i < axisKeyList.length; i++) {
var key = axisKeyList[i];
var axis = this._axis[axis];
output[key] = axis[method](input[key], clamp);
}
return output;
}
};
Cartesian.Axis = Axis;
return Cartesian;
});
\ No newline at end of file
define(function(require) {
'use strict';
});
\ No newline at end of file
/**
* K-Dimension Tree
*
* @module echarts/data/KDTree
* @author Yi Shen(https://github.com/pissang)
*/
define(function (require) {
var quickSelect = require('./quickSelect');
function Node(axis, data) {
this.left = null;
this.right = null;
this.axis = axis;
this.data = data;
}
/**
* @constructor
* @alias module:echarts/data/KDTree
* @param {Array} points List of points.
* each point needs an array property to repesent the actual data
* @param {Number} [dimension]
* Point dimension.
* Default will use the first point's length as dimensiont
*/
var KDTree = function (points, dimension) {
if (!points.length) {
return;
}
if (!dimension) {
dimension = points[0].array.length;
}
this.dimension = dimension;
this.root = this._buildTree(points, 0, points.length - 1, 0);
// Use one stack to avoid allocation
// each time searching the nearest point
this._stack = [];
// Again avoid allocating a new array
// each time searching nearest N points
this._nearstNList = [];
};
/**
* Resursively build the tree
*/
KDTree.prototype._buildTree = function (points, left, right, axis) {
if (right < left) {
return null;
}
var medianIndex = Math.floor((left + right) / 2);
medianIndex = quickSelect(
points, left, right, medianIndex,
function (a, b) {
return a.array[axis] - b.array[axis];
}
);
var median = points[medianIndex];
var node = new Node(axis, median);
axis = (axis + 1) % this.dimension;
if (right > left) {
node.left = this._buildTree(points, left, medianIndex - 1, axis);
node.right = this._buildTree(points, medianIndex + 1, right, axis);
}
return node;
};
/**
* Find nearest point
* @param {Array} target Target point
* @param {Function} squaredDistance Squared distance function
* @return {Array} Nearest point
*/
KDTree.prototype.nearest = function (target, squaredDistance) {
var curr = this.root;
var stack = this._stack;
var idx = 0;
var minDist = Infinity;
var nearestNode = null;
if (curr.data !== target) {
minDist = squaredDistance(curr.data, target);
nearestNode = curr;
}
if (target.array[curr.axis] < curr.data.array[curr.axis]) {
// Left first
curr.right && (stack[idx++] = curr.right);
curr.left && (stack[idx++] = curr.left);
}
else {
// Right first
curr.left && (stack[idx++] = curr.left);
curr.right && (stack[idx++] = curr.right);
}
while (idx--) {
curr = stack[idx];
var currDist = target.array[curr.axis] - curr.data.array[curr.axis];
var isLeft = currDist < 0;
var needsCheckOtherSide = false;
currDist = currDist * currDist;
// Intersecting right hyperplane with minDist hypersphere
if (currDist < minDist) {
currDist = squaredDistance(curr.data, target);
if (currDist < minDist && curr.data !== target) {
minDist = currDist;
nearestNode = curr;
}
needsCheckOtherSide = true;
}
if (isLeft) {
if (needsCheckOtherSide) {
curr.right && (stack[idx++] = curr.right);
}
// Search in the left area
curr.left && (stack[idx++] = curr.left);
}
else {
if (needsCheckOtherSide) {
curr.left && (stack[idx++] = curr.left);
}
// Search the right area
curr.right && (stack[idx++] = curr.right);
}
}
return nearestNode.data;
};
KDTree.prototype._addNearest = function (found, dist, node) {
var nearestNList = this._nearstNList;
// Insert to the right position
// Sort from small to large
for (var i = found - 1; i > 0; i--) {
if (dist >= nearestNList[i - 1].dist) {
break;
}
else {
nearestNList[i].dist = nearestNList[i - 1].dist;
nearestNList[i].node = nearestNList[i - 1].node;
}
}
nearestNList[i].dist = dist;
nearestNList[i].node = node;
};
/**
* Find nearest N points
* @param {Array} target Target point
* @param {number} N
* @param {Function} squaredDistance Squared distance function
* @param {Array} [output] Output nearest N points
*/
KDTree.prototype.nearestN = function (target, N, squaredDistance, output) {
if (N <= 0) {
output.length = 0;
return output;
}
var curr = this.root;
var stack = this._stack;
var idx = 0;
var nearestNList = this._nearstNList;
for (var i = 0; i < N; i++) {
// Allocate
if (!nearestNList[i]) {
nearestNList[i] = {};
}
nearestNList[i].dist = 0;
nearestNList[i].node = null;
}
var currDist = squaredDistance(curr.data, target);
var found = 0;
if (curr.data !== target) {
found++;
this._addNearest(found, currDist, curr);
}
if (target.array[curr.axis] < curr.data.array[curr.axis]) {
// Left first
curr.right && (stack[idx++] = curr.right);
curr.left && (stack[idx++] = curr.left);
}
else {
// Right first
curr.left && (stack[idx++] = curr.left);
curr.right && (stack[idx++] = curr.right);
}
while (idx--) {
curr = stack[idx];
var currDist = target.array[curr.axis] - curr.data.array[curr.axis];
var isLeft = currDist < 0;
var needsCheckOtherSide = false;
currDist = currDist * currDist;
// Intersecting right hyperplane with minDist hypersphere
if (found < N || currDist < nearestNList[found - 1].dist) {
currDist = squaredDistance(curr.data, target);
if (
(found < N || currDist < nearestNList[found - 1].dist)
&& curr.data !== target
) {
if (found < N) {
found++;
}
this._addNearest(found, currDist, curr);
}
needsCheckOtherSide = true;
}
if (isLeft) {
if (needsCheckOtherSide) {
curr.right && (stack[idx++] = curr.right);
}
// Search in the left area
curr.left && (stack[idx++] = curr.left);
}
else {
if (needsCheckOtherSide) {
curr.left && (stack[idx++] = curr.left);
}
// Search the right area
curr.right && (stack[idx++] = curr.right);
}
}
// Copy to output
for (var i = 0; i < found; i++) {
output[i] = nearestNList[i].node.data;
}
output.length = found;
return output;
};
return KDTree;
});
\ No newline at end of file
/**
* 数值处理模块
* @module echarts/core/number
*/
define(function (require) {
/**
* Linear mapping a value from domain to range
* @memberOf module:echarts/core/number
* @param {number} val
* @param {Array.<number>} domain Domain extent
* @param {Array.<number>} range Range extent
* @param {boolean} clamp
* @return {number}
*/
function linearMap (val, domain, range, clamp) {
var sub = domain[1] - domain[0];
if (sub === 0) {
return val;
}
var t = (val - domain[0]) / sub;
if (clamp) {
t = Math.min(Math.max(t, 0), 1);
}
return t * (range[1] - range[0]) + range[0];
};
return {
linearMap: linearMap
}
});
\ No newline at end of file
/**
* Quick select n-th element in an array.
*
* Note: it will change the elements placement in array.
*
* @module echarts/data/quickSelect
* @author Yi Shen(https://github.com/pissang)
*/
define(function (require) {
function defaultCompareFunc(a, b) {
return a - b;
}
function swapElement(list, idx0, idx1) {
var tmp = list[idx0];
list[idx0] = list[idx1];
list[idx1] = tmp;
}
function select(list, left, right, nth, compareFunc) {
var pivotIdx = left;
while (right > left) {
pivotIdx = Math.round((right + left) / 2);
var pivotValue = list[pivotIdx];
// Swap pivot to the end
swapElement(list, pivotIdx, right);
pivotIdx = left;
for (var i = left; i <= right - 1; i++) {
if (compareFunc(pivotValue, list[i]) >= 0) {
swapElement(list, i, pivotIdx);
pivotIdx++;
}
}
swapElement(list, right, pivotIdx);
if (pivotIdx === nth) {
return pivotIdx;
}
else if (pivotIdx < nth) {
left = pivotIdx + 1;
}
else {
right = pivotIdx - 1;
}
}
// Left == right
return left;
}
/**
* @alias module:echarts/data/quickSelect
* @param {Array} list
* @param {number} [left]
* @param {number} [right]
* @param {number} nth
* @param {Function} [compareFunc]
* @example
* var quickSelect = require('echarts/data/quickSelect');
* var list = [5, 2, 1, 4, 3]
* quickSelect(list, 3);
* quickSelect(list, 0, 3, 1, function (a, b) {return a - b});
*
* @return {number}
*/
function quickSelect(list, left, right, nth, compareFunc) {
if (arguments.length <= 3) {
nth = left;
if (arguments.length == 2) {
compareFunc = defaultCompareFunc;
}
else {
compareFunc = right;
}
left = 0;
right = list.length - 1;
}
return select(list, left, right, nth, compareFunc);
}
return quickSelect;
});
\ No newline at end of file
/**
* Graph data structure
*
* @module echarts/data/Graph
* @author Yi Shen(https://www.github.com/pissang)
*/
define(function(require) {
var util = require('zrender/tool/util');
'use strict';
/**
* @alias module:echarts/data/Graph
* @constructor
* @param {boolean} directed
*/
var Graph = function(directed) {
/**
* 是否是有向图
* @type {boolean}
* @private
*/
this._directed = directed || false;
/**
* @type {Array}
*/
this.nodes = [];
this.edges = [];
this._nodesMap = {};
this._edgesMap = {};
};
/**
* 是否是有向图
* @return {boolean}
*/
Graph.prototype.isDirected = function () {
return this._directed;
};
/**
* 添加一个新的节点
* @param {string} id 节点名称
* @param {*} [data] 存储的数据
*/
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;
};
/**
* 获取节点
* @param {string} id
* @return {module:echarts/data/Graph~Node}
*/
Graph.prototype.getNodeById = function (id) {
return this._nodesMap[id];
};
/**
* 添加边
* @param {string|module:echarts/data/Graph~Node} n1
* @param {string|module:echarts/data/Graph~Node} n2
* @param {*} data
* @return {module:echarts/data/Graph~Edge}
*/
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;
};
/**
* 移除边
* @param {module:echarts/data/Graph~Edge} 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);
};
/**
* 获取边
* @param {module:echarts/data/Graph~Node|string} n1
* @param {module:echarts/data/Graph~Node|string} n2
* @return {module:echarts/data/Graph~Edge}
*/
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];
}
};
/**
* 移除节点(及其邻接边)
* @param {module:echarts/data/Graph~Node|string} node
*/
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++;
}
}
};
/**
* 遍历并且过滤指定的节点
* @param {Function} cb
* @param {*} [context]
*/
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--;
}
}
};
/**
* 遍历并且过滤指定的边
* @param {Function} cb
* @param {*} [context]
*/
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--;
}
}
};
/**
* 线性遍历所有节点
* @param {Function} cb
* @param {*} [context]
*/
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);
}
}
};
/**
* 线性遍历所有边
* @param {Function} cb
* @param {*} [context]
*/
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 = {};
};
/**
* 广度优先遍历
* @param {Function} cb
* @param {module:echarts/data/Graph~Node} startNode 遍历起始节点
* @param {string} [direction=none] none, in, out 指定遍历边
* @param {*} [context] 回调函数调用context
*/
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)) {
// Stop traversing
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;
};
/**
* 图节点
* @alias module:echarts/data/Graph~Node
* @param {string} id
* @param {*} [data]
*/
var Node = function(id, data) {
/**
* 节点名称
* @type {string}
*/
this.id = id;
/**
* 节点存储的数据
* @type {*}
*/
this.data = data || null;
/**
* 入边,只在有向图上有效
* @type {Array.<module:echarts/data/Graph~Edge>}
*/
this.inEdges = [];
/**
* 出边,只在有向图上有效
* @type {Array.<module:echarts/data/Graph~Edge>}
*/
this.outEdges = [];
/**
* 邻接边
* @type {Array.<module:echarts/data/Graph~Edge>}
*/
this.edges = [];
};
/**
* 度
* @return {number}
*/
Node.prototype.degree = function () {
return this.edges.length;
};
/**
* 入度,只在有向图上有效
* @return {number}
*/
Node.prototype.inDegree = function () {
return this.inEdges.length;
};
/**
* 出度,只在有向图上有效
* @return {number}
*/
Node.prototype.outDegree = function () {
return this.outEdges.length;
};
/**
* 获取数据项
* @return {number}
*/
Node.prototype.getValue = function () {
return this.data.value;
};
/**
* 图边
* @alias module:echarts/data/Graph~Edge
* @param {module:echarts/data/Graph~Node} node1
* @param {module:echarts/data/Graph~Node} node2
* @param {extra} data
*/
var Edge = function(node1, node2, data) {
/**
* 节点1,如果是有向图则为源节点
* @type {module:echarts/data/Graph~Node}
*/
this.node1 = node1;
/**
* 节点2,如果是有向图则为目标节点
* @type {module:echarts/data/Graph~Node}
*/
this.node2 = node2;
/**
* 边存储的数据
* @type {*}
*/
this.data = data || null;
};
Graph.Node = Node;
Graph.Edge = Edge;
/**
* 从邻接矩阵生成
* ```
* TARGET
* -1--2--3--4--5-
* 1| x x x x x
* 2| x x x x x
* 3| x x x x x SOURCE
* 4| x x x x x
* 5| x x x x x
* ```
* 节点的行列总和会被写到`node.data.value`
* 对于有向图会计算每一行的和写到`node.data.outValue`,
* 计算每一列的和写到`node.data.inValue`。
* 边的权重会被然后写到`edge.data.weight`。
*
* @method module:echarts/data/Graph.fromMatrix
* @param {Array.<Object>} nodesData 节点信息,必须有`id`属性, 会保存到`node.data`中
* @param {Array} matrix 邻接矩阵
* @param {boolean} directed 是否是有向图
* @return {module:echarts/data/Graph}
*/
Graph.fromMatrix = function(nodesData, matrix, directed) {
if (
!matrix || !matrix.length
|| (matrix[0].length !== matrix.length)
|| (nodesData.length !== matrix.length)
) {
// Not a valid data
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]);
// TODO
// node.data已经有value的情况
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;
});
\ No newline at end of file
define(function(require) {
'use strict';
var zrUtil = require('zrender/core/util');
function createArrayIterWithDepth(maxDepth, properties, cb, context, iterType) {
// Simple optimization to avoid read the undefined value in properties array
var nestedProperties = properties.length > 0;
return function eachAxis(array, depth) {
if (depth === maxDepth) {
return zrUtil[iterType](array, cb, context);
}
else {
if (array) {
var property = properties[i];
for (var i = 0; i < array.length; i++) {
var item = array[i];
// Access property of each item
if (nestedProperties && property && item) {
item = item[property];
}
array[i] = eachAxis(item, depth);
}
}
}
}
}
function List() {
this.elements = this.elements || [];
// Depth and properties is useful in nested Array.
// For example in eventRiver, data structure is a nested 2d array as following
// [{evolution: []}, {evolution: []}]
// In this situation. depth should be 2 and properties should be ['evolution']
this.depth = 1;
this.properties = [];
}
List.prototype = {
constructor: List,
each: function (cb, context) {
context = context || this;
if (this.depth > 1) {
createArrayIterWithDepth(
this.depth, this.properties, cb, context, 'each'
)(this.elements, 0);
}
else {
zrUtil.each(this.elements, cb, context);
}
},
/**
* In-place filter
*/
filter: function (cb, context) {
context = context || this;
if (this.depth > 1) {
createArrayIterWithDepth(
this.depth, this.properties, cb, context, 'filter'
)(this.elements, 0);
}
else {
this.elements = zrUtil.filter(this.elements, cb, context);
}
},
/**
* In-place map
*/
map: function (cb, context) {
context = context || this;
if (this.depth > 1) {
createArrayIterWithDepth(
this.depth, this.properties, cb, context, 'map'
)(this.elements, 0);
}
else {
this.elements = zrUtil.map(this.elements, cb, context);
}
},
/*
PENDING
flatten: function () {
},
group: function () {
},
*/
/**
* Get x of single data item by a given data index.
* can be overwritten
* @param {number} idx
* @return {number}
*/
getX: function (idx) {
},
/**
* Get y of single data item by a given data index.
* can be overwritten
* @param {number} idx
* @return {number}
*/
getY: function (idx) {
},
/**
* Get z of single data item by a given data index.
* can be overwritten
* @param {number} idx
* @return {number}
*/
getZ: function (idx) {
},
/**
* Get value of single data item by a given data index.
* can be overwritten
* @param {number} idx
* @return {number}
*/
getValue: function (idx) {
},
clone: function () {
// Clone with depth
}
};
List.fromArray = function (data) {
var list = new List();
// Normalize data
// 2D Array
list.elements = zrUtil.map(data, function (dataItem) {
if (dataItem !== Object(dataItem)) {
return {
value: dataItem
};
}
return dataItem;
});
return list;
}
return List;
});
\ No newline at end of file
/**
* Tree data structure
*
* @module echarts/data/Tree
* @author Yi Shen(https://www.github.com/pissang)
*/
define(function(require) {
var zrUtil = require('zrender/tool/util');
/**
* @constructor module:echarts/data/Tree~TreeNode
* @param {string} id Node ID
* @param {Object} [data]
*/
function TreeNode(id, data) {
/**
* @type {string}
*/
this.id = id;
/**
* 节点的深度
* @type {number}
*/
this.depth = 0;
/**
* 以当前节点为根节点的子树的高度
* @type {number}
*/
this.height = 0;
/**
* 子节点列表
* @type {Array.<module:echarts/data/Tree~TreeNode>}
*/
this.children = [];
/**
* @type {module:echarts/data/Tree~TreeNode}
*/
this.parent = null;
/**
* 存储的用户数据
* @type {Object}
*/
this.data = data || null;
}
/**
* 添加子节点
* @param {module:echarts/data/Tree~TreeNode} child
*/
TreeNode.prototype.add = function (child) {
var children = this.children;
if (child.parent === this) {
return;
}
children.push(child);
child.parent = this;
};
/**
* 移除子节点
* @param {module:echarts/data/Tree~TreeNode} child
*/
TreeNode.prototype.remove = function (child) {
var children = this.children;
var idx = zrUtil.indexOf(children, child);
if (idx >= 0) {
children.splice(idx, 1);
child.parent = null;
}
};
/**
* 遍历当前节点及其所有子节点
* @param {Function} cb
* @param {Object} [context]
*/
TreeNode.prototype.eachNode = function (cb, context) {
cb.call(context, this);
for (var i = 0; i < this.children.length; i++) {
this.children[i].eachNode(cb, context);
}
};
/**
* 更新当前树及所有子树的高度和深度
* @param {number} depth
*/
TreeNode.prototype.updateDepthAndHeight = function (depth) {
var height = 0;
this.depth = depth;
for (var i = 0; i < this.children.length; i++) {
var child = this.children[i];
child.updateDepthAndHeight(depth + 1);
if (child.height > height) {
height = child.height;
}
}
this.height = height + 1;
};
/**
* @param {string} id
* @return module:echarts/data/Tree~TreeNode
*/
TreeNode.prototype.getNodeById = function (id) {
if (this.id === id) {
return this;
}
for (var i = 0; i < this.children.length; i++) {
var res = this.children[i].getNodeById(id);
if (res) {
return res;
}
}
};
/**
* @constructor
* @alias module:echarts/data/Tree
* @param {string} id
*/
function Tree(id) {
/**
* @type {module:echarts/data/Tree~TreeNode}
*/
this.root = new TreeNode(id);
}
/**
* 遍历树的所有子节点
* @param {Function} cb
* @param {Object} [context]
*/
Tree.prototype.eachNode = function(cb, context) {
this.root.eachNode(cb, context);
};
/**
* 生成子树
* @param {string} id 子树根节点 id
* @return {module:echarts/data/Tree}
*/
Tree.prototype.getSubTree = function(id) {
var root = this.getNodeById(id);
if (root) {
var tree = new Tree(root.id);
tree.root = root;
return tree;
}
};
/**
* @param {string} id
* @return module:echarts/data/Tree~TreeNode
*/
Tree.prototype.getNodeById = function (id) {
return this.root.getNodeById(id);
};
/**
* 从 option 里的 data 数据构建树
* @param {string} id
* @param {Array.<Object>} data
* @return module:echarts/data/Tree
*/
Tree.fromOptionData = function (id, data) {
var tree = new Tree(id);
var rootNode = tree.root;
// Root node
rootNode.data = {
name: id,
children: data
};
function buildHierarchy(dataNode, parentNode) {
var node = new TreeNode(dataNode.name, dataNode);
parentNode.add(node);
// 遍历添加子节点
var children = dataNode.children;
if (children) {
for (var i = 0; i < children.length; i++) {
buildHierarchy(children[i], node);
}
}
}
for (var i = 0; i < data.length; i++) {
buildHierarchy(data[i], rootNode);
}
tree.root.updateDepthAndHeight(0);
return tree;
};
return Tree;
});
\ No newline at end of file
define(function (require) {
var config = require('./config');
var OptionModel = require('./model/Option');
var Model = require('./model/Model');
var zrUtil = require('zrender/core/util');
var Chart = require('./chart/Chart');
var Component = require('./component/Component');
var zrender = require('zrender');
var startupProcessorClasses = [];
/**
* @module echarts~ECharts
*/
var ECharts = function (dom, theme) {
this.zr = zrender.init(dom);
theme = zrUtil.clone(theme || {});
zrUtil.merge(theme, config);
this._theme = theme;
this._chartsList = [];
this._chartsMap = {};
this._componentsList = [];
this._componentsMap = {};
this._originalOption = null;
};
ECharts.prototype = {
setOption: function (rawOption, merge) {
rawOption = zrUtil.clone(rawOption);
zrUtil.merge(rawOption, this._theme);
var option = new OptionModel(rawOption);
// Add series index
option.eachSeries(function (series, seriesIndex) {
series.seriesIndex = seriesIndex;
});
// Pending
// optionModel as parent ?
var globalState = new Model({}, option);
// Create processors
this._processors = zrUtil.map(startupProcessorClasses, function (Processor) {
var processor = new Processor();
processor.init(option, globalState);
});
this._originalOption = option;
this.updateImmediate();
},
addProcessor: function (processor, oneForEachType) {
var processors = this._processors;
if (zrUtil.indexOf(processors, processor) >= 0) {
return;
};
if (oneForEachType) {
if (zrUtil.filter(processors, function (exist) {
return exist.type === processor.type;
}).length) {
return;
}
}
processors.push(processor);
},
update: function () {
},
updateImmediate: function () {
// TODO Performance
var option = this._originalOption.clone();
this._processOption(option);
this._prepareComponents(option);
this._prepareCharts(option);
this._dispatchOption(option);
},
_prepareCharts: function (option) {
var chartUsedMap = {};
zrUtil.each(option.get('series'), function (series, idx) {
var id = series.type + '_' + (series.name || idx);
chartUsedMap[id] = true;
var chart = this._chartsMap[id];
if (! chart) {
chart = Chart.create(series);
if (chart) {
chart.init();
this._chartsMap[series.type] = chart;
this._chartsList.push(chart);
}
else {
// Error
}
}
chart.__id__ = id;
}, this);
for (var i = 0; i < this._chartsList.length;) {
var chart = this._chartsList[i];
if (! chartUsedMap[chart.__id__]) {
chart.dispose();
this._chartsList.splice(i, 1);
delete this._chartsMap[chart.__id__];
}
else {
i++;
}
};
},
_prepareComponents: function (option) {
Component.eachAvailableComponent(function (componentType) {
var componentsMap = this._componentsMap;
var componentsList = this._componentsList;
var componentOption = option.get(componentType);
var component = componentsMap[componentType];
if (componentOption) {
if (! component) {
// Create and add component
component = Component.create(componentType, componentOption);
componentsMap[componentType] = component;
componentsList.push(component);
}
}
else {
if (component) {
// Remove and dispose component
component.dispose();
delete componentsMap[componentType];
componentsList.splice(zrUtil.indexOf(componentsList, component));
}
}
}, this);
},
_processOption: function (option) {
zrUtil.each(this._processors, function (processor) {
processor.process(option);
});
},
_dispatchOption: function (option) {
// Render all components
zrUtil.each(this._components, function (component) {
component.render(option);
});
// Render all charts
zrUtil.each(this._charts, function (chart) {
chart.render(option);
});
},
dispose: function () {
zrUtil.each(this._components, function (component) {
component.dispose();
});
zrUtil.each(this._charts, function (chart) {
chart.dispose();
});
this.zr.dispose();
}
};
/**
* @module echarts
*/
var echarts = {
init: function (dom, theme) {
return new ECharts(dom, theme);
},
registerStartupProcessor: function (processorFactory) {}
};
echarts.registerProcessor(require('./processor/SeriesFilter'));
return echarts;
});
\ No newline at end of file
/**
* Chord layout
* @module echarts/layout/Chord
* @author pissang(http://github.com/pissang)
*/
define(function (require) {
var ChordLayout = function (opts) {
opts = opts || {};
/**
* 是否排序组(即图的节点), 可以是`ascending`, `descending`, 或者为空不排序
* @type {string}
*/
this.sort = opts.sort || null;
/**
* 是否排序子组(即图中每个节点的邻接边), 可以是`ascending`, `descending`, 或者为空不排序
* @type {string}
*/
this.sortSub = opts.sortSub || null;
this.padding = 0.05;
this.startAngle = opts.startAngle || 0;
this.clockWise = opts.clockWise == null ? false : opts.clockWise;
this.center = opts.center || [0, 0];
this.directed = true;
};
/**
* 对指定的一个或多个 Graph 运行 chord 布局
* 可以有多个 Graph, 后面几个 Graph 的节点是第一个 Graph 的节点的子集(ID一一对应)
*
* 布局结果保存在第一个 Graph 的每个节点的 layout.startAngle 和 layout.endAngle.
* 以及每个图的边的 layout.startAngle 和 layout.endAngle
*
* @param {Array.<module:echarts/data/Graph>|module:echarts/data/Graph} graphs
*/
ChordLayout.prototype.run = function (graphs) {
if (!(graphs instanceof Array)) {
graphs = [graphs];
}
var gl = graphs.length;
if (!gl) {
return;
}
var graph0 = graphs[0];
var nl = graph0.nodes.length;
var groups = [];
var sumSize = 0;
// 使用第一个 graph 的节点
for (var i = 0; i < nl; i++) {
var g0node = graph0.nodes[i];
var group = {
size: 0,
subGroups: [],
node: g0node
};
groups.push(group);
var sumWeight = 0;
// 合并所有 Graph 的 边
for (var k = 0; k < graphs.length; k++) {
var graph = graphs[k];
var node = graph.getNodeById(g0node.id);
// 节点可能没有值被过滤掉了
if (!node) {
continue;
}
group.size += node.layout.size;
// PENDING
var edges = this.directed ? node.outEdges : node.edges;
for (var j = 0; j < edges.length; j++) {
var e = edges[j];
var w = e.layout.weight;
group.subGroups.push({
weight: w,
edge: e,
graph: graph
});
sumWeight += w;
}
}
sumSize += group.size;
// Sum sub group weights to group size
var multiplier = group.size / sumWeight;
for (var j = 0; j < group.subGroups.length; j++) {
group.subGroups[j].weight *= multiplier;
}
if (this.sortSub === 'ascending') {
group.subGroups.sort(compareSubGroups);
}
else if (this.sort === 'descending') {
group.subGroups.sort(compareSubGroups);
group.subGroups.reverse();
}
}
if (this.sort === 'ascending') {
groups.sort(compareGroups);
}
else if (this.sort === 'descending') {
groups.sort(compareGroups);
groups.reverse();
}
var multiplier = (Math.PI * 2 - this.padding * nl) / sumSize;
var angle = this.startAngle;
var sign = this.clockWise ? 1 : -1;
// Calculate angles
for (var i = 0; i < nl; i++) {
var group = groups[i];
group.node.layout.startAngle = angle;
group.node.layout.endAngle = angle + sign * group.size * multiplier;
group.node.layout.subGroups = [];
for (var j = 0; j < group.subGroups.length; j++) {
var subGroup = group.subGroups[j];
subGroup.edge.layout.startAngle = angle;
angle += sign * subGroup.weight * multiplier;
subGroup.edge.layout.endAngle = angle;
}
angle = group.node.layout.endAngle + sign * this.padding;
}
};
var compareSubGroups = function (a, b) {
return a.weight - b.weight;
};
var compareGroups = function (a, b) {
return a.size - b.size;
};
return ChordLayout;
});
\ No newline at end of file
/**
* Edge bundling laytout
*
* Use MINGLE algorithm
* Multilevel agglomerative edge bundling for visualizing large graphs
*
* @module echarts/layout/EdgeBundling
*/
define(function (require) {
var KDTree = require('../data/KDTree');
var vec2 = require('zrender/tool/vector');
var v2Create = vec2.create;
var v2DistSquare = vec2.distSquare;
var v2Dist = vec2.dist;
var v2Copy = vec2.copy;
var v2Clone = vec2.clone;
function squaredDistance(a, b) {
a = a.array;
b = b.array;
var x = b[0] - a[0];
var y = b[1] - a[1];
var z = b[2] - a[2];
var w = b[3] - a[3];
return x * x + y * y + z * z + w * w;
}
function CoarsenedEdge(group) {
this.points = [
group.mp0, group.mp1
];
this.group = group;
}
function Edge(edge) {
var points = edge.points;
// Sort on y
if (
points[0][1] < points[1][1]
// If coarsened edge is flipped, the final composition of meet point
// will be unordered
|| edge instanceof CoarsenedEdge
) {
this.array = [points[0][0], points[0][1], points[1][0], points[1][1]];
this._startPoint = points[0];
this._endPoint = points[1];
}
else {
this.array = [points[1][0], points[1][1], points[0][0], points[0][1]];
this._startPoint = points[1];
this._endPoint = points[0];
}
this.ink = v2Dist(points[0], points[1]);
this.edge = edge;
this.group = null;
}
Edge.prototype.getStartPoint = function () {
return this._startPoint;
};
Edge.prototype.getEndPoint = function () {
return this._endPoint;
};
function BundledEdgeGroup() {
this.edgeList = [];
this.mp0 = v2Create();
this.mp1 = v2Create();
this.ink = 0;
}
BundledEdgeGroup.prototype.addEdge = function (edge) {
edge.group = this;
this.edgeList.push(edge);
};
BundledEdgeGroup.prototype.removeEdge = function (edge) {
edge.group = null;
this.edgeList.splice(this.edgeList.indexOf(edge), 1);
};
/**
* @constructor
* @alias module:echarts/layout/EdgeBundling
*/
function EdgeBundling() {
this.maxNearestEdge = 6;
this.maxTurningAngle = Math.PI / 4;
this.maxIteration = 20;
}
EdgeBundling.prototype = {
constructor: EdgeBundling,
run: function (rawEdges) {
var res = this._iterate(rawEdges);
var nIterate = 0;
while (nIterate++ < this.maxIteration) {
var coarsenedEdges = [];
for (var i = 0; i < res.groups.length; i++) {
coarsenedEdges.push(new CoarsenedEdge(res.groups[i]));
}
var newRes = this._iterate(coarsenedEdges);
if (newRes.savedInk <= 0) {
break;
} else {
res = newRes;
}
}
// Get new edges
var newEdges = [];
function pointApproxEqual(p0, p1) {
// Use Float32Array may affect the precision
return v2DistSquare(p0, p1) < 1e-10;
}
// Clone all points to make sure all points in edge will not reference to the same array
// And clean the duplicate points
function cleanEdgePoints(edgePoints, rawEdgePoints) {
var res = [];
var off = 0;
for (var i = 0; i < edgePoints.length; i++) {
if (! (off > 0 && pointApproxEqual(edgePoints[i], res[off - 1]))) {
res[off++] = v2Clone(edgePoints[i]);
}
}
// Edge has been reversed
if (rawEdgePoints[0] && !pointApproxEqual(res[0], rawEdgePoints[0])) {
res = res.reverse();
}
return res;
}
var buildNewEdges = function (groups, fromEdgePoints) {
var newEdgePoints;
for (var i = 0; i < groups.length; i++) {
var group = groups[i];
if (
group.edgeList[0]
&& (group.edgeList[0].edge instanceof CoarsenedEdge)
) {
var newGroups = [];
for (var j = 0; j < group.edgeList.length; j++) {
newGroups.push(group.edgeList[j].edge.group);
}
if (! fromEdgePoints) {
newEdgePoints = [];
} else {
newEdgePoints = fromEdgePoints.slice();
}
newEdgePoints.unshift(group.mp0);
newEdgePoints.push(group.mp1);
buildNewEdges(newGroups, newEdgePoints);
} else {
// console.log(group.edgeList.length);
for (var j = 0; j < group.edgeList.length; j++) {
var edge = group.edgeList[j];
if (! fromEdgePoints) {
newEdgePoints = [];
} else {
newEdgePoints = fromEdgePoints.slice();
}
newEdgePoints.unshift(group.mp0);
newEdgePoints.push(group.mp1);
newEdgePoints.unshift(edge.getStartPoint());
newEdgePoints.push(edge.getEndPoint());
newEdges.push({
points: cleanEdgePoints(newEdgePoints, edge.edge.points),
rawEdge: edge.edge
});
}
}
}
};
buildNewEdges(res.groups);
return newEdges;
},
_iterate: function (rawEdges) {
var edges = [];
var groups = [];
var totalSavedInk = 0;
for (var i = 0; i < rawEdges.length; i++) {
var edge = new Edge(rawEdges[i]);
edges.push(edge);
}
var tree = new KDTree(edges, 4);
var nearests = [];
var _mp0 = v2Create();
var _mp1 = v2Create();
var _newGroupInk = 0;
var mp0 = v2Create();
var mp1 = v2Create();
var newGroupInk = 0;
for (var i = 0; i < edges.length; i++) {
var edge = edges[i];
if (edge.group) {
// Edge have been groupped
continue;
}
tree.nearestN(
edge, this.maxNearestEdge,
squaredDistance, nearests
);
var maxSavedInk = 0;
var mostSavingInkEdge = null;
var lastCheckedGroup = null;
for (var j = 0; j < nearests.length; j++) {
var nearest = nearests[j];
var savedInk = 0;
if (nearest.group) {
if (nearest.group !== lastCheckedGroup) {
lastCheckedGroup = nearest.group;
_newGroupInk = this._calculateGroupEdgeInk(
nearest.group, edge, _mp0, _mp1
);
savedInk = nearest.group.ink + edge.ink - _newGroupInk;
}
}
else {
_newGroupInk = this._calculateEdgeEdgeInk(
edge, nearest, _mp0, _mp1
);
savedInk = nearest.ink + edge.ink - _newGroupInk;
}
if (savedInk > maxSavedInk) {
maxSavedInk = savedInk;
mostSavingInkEdge = nearest;
v2Copy(mp1, _mp1);
v2Copy(mp0, _mp0);
newGroupInk = _newGroupInk;
}
}
if (mostSavingInkEdge) {
totalSavedInk += maxSavedInk;
var group;
if (! mostSavingInkEdge.group) {
group = new BundledEdgeGroup();
groups.push(group);
group.addEdge(mostSavingInkEdge);
}
group = mostSavingInkEdge.group;
// Use the meet point and group ink calculated before
v2Copy(group.mp0, mp0);
v2Copy(group.mp1, mp1);
group.ink = newGroupInk;
mostSavingInkEdge.group.addEdge(edge);
}
else {
var group = new BundledEdgeGroup();
groups.push(group);
v2Copy(group.mp0, edge.getStartPoint());
v2Copy(group.mp1, edge.getEndPoint());
group.ink = edge.ink;
group.addEdge(edge);
}
}
return {
groups: groups,
edges: edges,
savedInk: totalSavedInk
};
},
_calculateEdgeEdgeInk: (function () {
var startPointSet = [];
var endPointSet = [];
return function (e0, e1, mp0, mp1) {
startPointSet[0] = e0.getStartPoint();
startPointSet[1] = e1.getStartPoint();
endPointSet[0] = e0.getEndPoint();
endPointSet[1] = e1.getEndPoint();
this._calculateMeetPoints(
startPointSet, endPointSet, mp0, mp1
);
var ink = v2Dist(startPointSet[0], mp0)
+ v2Dist(mp0, mp1)
+ v2Dist(mp1, endPointSet[0])
+ v2Dist(startPointSet[1], mp0)
+ v2Dist(mp1, endPointSet[1]);
return ink;
};
})(),
_calculateGroupEdgeInk: function (group, edgeTryAdd, mp0, mp1) {
var startPointSet = [];
var endPointSet = [];
for (var i = 0; i < group.edgeList.length; i++) {
var edge = group.edgeList[i];
startPointSet.push(edge.getStartPoint());
endPointSet.push(edge.getEndPoint());
}
startPointSet.push(edgeTryAdd.getStartPoint());
endPointSet.push(edgeTryAdd.getEndPoint());
this._calculateMeetPoints(
startPointSet, endPointSet, mp0, mp1
);
var ink = v2Dist(mp0, mp1);
for (var i = 0; i < startPointSet.length; i++) {
ink += v2Dist(startPointSet[i], mp0)
+ v2Dist(endPointSet[i], mp1);
}
return ink;
},
/**
* Calculating the meet points
* @method
* @param {Array} startPointSet Start points set of bundled edges
* @param {Array} endPointSet End points set of bundled edges
* @param {Array.<number>} mp0 Output meet point 0
* @param {Array.<number>} mp1 Output meet point 1
*/
_calculateMeetPoints: (function () {
var cp0 = v2Create();
var cp1 = v2Create();
return function (startPointSet, endPointSet, mp0, mp1) {
vec2.set(cp0, 0, 0);
vec2.set(cp1, 0, 0);
var len = startPointSet.length;
// Calculate the centroid of start points set
for (var i = 0; i < len; i++) {
vec2.add(cp0, cp0, startPointSet[i]);
}
vec2.scale(cp0, cp0, 1 / len);
// Calculate the centroid of end points set
len = endPointSet.length;
for (var i = 0; i < len; i++) {
vec2.add(cp1, cp1, endPointSet[i]);
}
vec2.scale(cp1, cp1, 1 / len);
this._limitTurningAngle(
startPointSet, cp0, cp1, mp0
);
this._limitTurningAngle(
endPointSet, cp1, cp0, mp1
);
};
})(),
_limitTurningAngle: (function () {
var v10 = v2Create();
var vTmp = v2Create();
var project = v2Create();
var tmpOut = v2Create();
return function (pointSet, p0, p1, out) {
// Limit the max turning angle
var maxTurningAngleCos = Math.cos(this.maxTurningAngle);
var maxTurningAngleTan = Math.tan(this.maxTurningAngle);
vec2.sub(v10, p0, p1);
vec2.normalize(v10, v10);
// Simply copy the centroid point if no need to turn the angle
vec2.copy(out, p0);
var maxMovement = 0;
for (var i = 0; i < pointSet.length; i++) {
var p = pointSet[i];
vec2.sub(vTmp, p, p0);
var len = vec2.len(vTmp);
vec2.scale(vTmp, vTmp, 1 / len);
var turningAngleCos = vec2.dot(vTmp, v10);
// Turning angle is to large
if (turningAngleCos < maxTurningAngleCos) {
// Calculat p's project point on vector p1-p0
// and distance to the vector
vec2.scaleAndAdd(
project, p0, v10, len * turningAngleCos
);
var distance = v2Dist(project, p);
// Use the max turning angle to calculate the new meet point
var d = distance / maxTurningAngleTan;
vec2.scaleAndAdd(tmpOut, project, v10, -d);
var movement = v2DistSquare(tmpOut, p0);
if (movement > maxMovement) {
maxMovement = movement;
vec2.copy(out, tmpOut);
}
}
}
};
})()
};
return EdgeBundling;
});
\ No newline at end of file
/**
* 力导向布局
* @module echarts/layout/Force
* @author pissang(http://github.com/pissang)
*/
define(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 getToken() {
// return Math.round((new Date()).getTime() / 100) % 10000000;
// }
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.0,
gravity: this.gravity || 1.0,
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) { // IE10-11 will throw security error when using blog url
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) {
// Sync back
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;
});
\ No newline at end of file
/**
* Tree layout
* @module echarts/layout/Tree
* @author pissang(http://github.com/pissang)
*/
define(function (require) {
var vec2 = require('zrender/tool/vector');
function TreeLayout(opts) {
opts = opts || {};
this.nodePadding = opts.nodePadding || 30;
this.layerPadding = opts.layerPadding || 100;
this._layerOffsets = [];
this._layers = [];
}
TreeLayout.prototype.run = function (tree) {
this._layerOffsets.length = 0;
for (var i = 0; i < tree.root.height + 1; i++) {
this._layerOffsets[i] = 0;
this._layers[i] = [];
}
this._updateNodeXPosition(tree.root);
var root = tree.root;
this._updateNodeYPosition(root, 0, root.layout.height);
};
TreeLayout.prototype._updateNodeXPosition = function (node) {
var minX = Infinity;
var maxX = -Infinity;
node.layout.position = node.layout.position || vec2.create();
for (var i = 0; i < node.children.length; i++) {
var child = node.children[i];
this._updateNodeXPosition(child);
var x = child.layout.position[0];
if (x < minX) {
minX = x;
}
if (x > maxX) {
maxX = x;
}
}
if (node.children.length > 0) {
node.layout.position[0] = (minX + maxX) / 2;
} else {
node.layout.position[0] = 0;
}
var off = this._layerOffsets[node.depth] || 0;
if (off > node.layout.position[0]) {
var shift = off - node.layout.position[0];
this._shiftSubtree(node, shift);
for (var i = node.depth + 1; i < node.height + node.depth; i++) {
this._layerOffsets[i] += shift;
}
}
this._layerOffsets[node.depth] = node.layout.position[0] + node.layout.width + this.nodePadding;
this._layers[node.depth].push(node);
};
TreeLayout.prototype._shiftSubtree = function (root, offset) {
root.layout.position[0] += offset;
for (var i = 0; i < root.children.length; i++) {
this._shiftSubtree(root.children[i], offset);
}
};
TreeLayout.prototype._updateNodeYPosition = function (node, y, prevLayerHeight) {
node.layout.position[1] = y;
var layerHeight = 0;
for (var i = 0; i < node.children.length; i++) {
layerHeight = Math.max(node.children[i].layout.height, layerHeight);
}
var layerPadding = this.layerPadding;
if (typeof(layerPadding) === 'function') {
layerPadding = layerPadding(node.depth);
}
for (var i = 0; i < node.children.length; i++) {
this._updateNodeYPosition(node.children[i], y + layerPadding + prevLayerHeight, layerHeight);
}
};
return TreeLayout;
});
\ No newline at end of file
/**
* TreeMap layout
* @module echarts/layout/TreeMap
* @author loutongbing(loutongbing@126.com)
*/
define(function (require) {
function TreeMapLayout(opts) {
/**
* areas 每个子矩形面积
* x 父矩形横坐标
* y 父矩形横坐标
* width 父矩形宽
* height 父矩形高
*/
var row = {
x: opts.x,
y: opts.y,
width: opts.width,
height: opts.height
};
this.x = opts.x;
this.y = opts.y;
this.width = opts.width;
this.height = opts.height;
}
TreeMapLayout.prototype.run = function (areas) {
var out = [];
this._squarify(areas, {
x: this.x,
y: this.y,
width: this.width,
height: this.height
}, out);
return out;
};
TreeMapLayout.prototype._squarify = function (areas, row, out) {
var layoutDirection = 'VERTICAL';
var width = row.width;
var height = row.height;
if (row.width < row.height) {
layoutDirection = 'HORIZONTAL';
width = row.height;
height = row.width;
}
// 把考虑方向与位置的因素剥离出来,只考虑怎么排列,运行完毕之后再修正
var shapeArr = this._getShapeListInAbstractRow(
areas, width, height
);
// 首先换算出虚拟的x、y坐标
for (var i = 0; i < shapeArr.length; i++) {
shapeArr[i].x = 0;
shapeArr[i].y = 0;
for (var j = 0; j < i; j++) {
shapeArr[i].y += shapeArr[j].height;
}
}
var nextRow = {};
// 根据虚拟的shapeArr计算真实的小矩形
if (layoutDirection == 'VERTICAL') {
for (var k = 0; k < shapeArr.length; k++) {
out.push(
{
x: shapeArr[k].x + row.x,
y: shapeArr[k].y + row.y,
width: shapeArr[k].width,
height: shapeArr[k].height
}
);
}
nextRow = {
x: shapeArr[0].width + row.x,
y: row.y,
width: row.width - shapeArr[0].width,
height: row.height
};
}
else {
for (var l = 0; l < shapeArr.length; l++) {
out.push(
{
x: shapeArr[l].y + row.x,
y: shapeArr[l].x + row.y,
width: shapeArr[l].height,
height: shapeArr[l].width
}
);
}
nextRow = {
x: row.x,
y: row.y + shapeArr[0].width, // 注意是虚拟形状下的width
width: row.width,
height: row.height - shapeArr[0].width // 注意是虚拟形状下的width
};
}
// 下一步的矩形数组要剔除已经填充过的矩形
var nextAreaArr = areas.slice(shapeArr.length);
if (nextAreaArr.length === 0) {
return;
}
else {
this._squarify(
nextAreaArr,
nextRow,
out
);
}
};
TreeMapLayout.prototype._getShapeListInAbstractRow = function (
areas,
width,
height
) {
// 如果只剩下一个了,直接返回
if (areas.length === 1) {
return [
{
width: width,
height: height
}
];
}
// 填充进入的个数,从填充一个开始到填充所有小矩形,
// 纵横比最优时break并保留结果
for (var count = 1; count < areas.length; count++) {
var shapeArr0 = this._placeFixedNumberRectangles(
areas.slice(0, count),
width,
height
);
var shapeArr1 = this._placeFixedNumberRectangles(
areas.slice(0, count + 1),
width,
height
);
if (this._isFirstBetter(shapeArr0, shapeArr1)) {
return shapeArr0;
}
}
};
// 确定数量进行填充
TreeMapLayout.prototype._placeFixedNumberRectangles = function (
areaSubArr,
width,
height
) {
var count = areaSubArr.length;
// 声明返回值-每个矩形的形状(长宽)之数组
// 例如:
/*[
{
width: 11
height: 12
},
{
width: 11
height: 22
}
]*/
var shapeArr = [];
// 求出面积总和
var sum = 0;
for (var i = 0; i < areaSubArr.length; i++) {
sum += areaSubArr[i];
}
var cellWidth = sum / height;
for (var j = 0; j < count; j++) {
var cellHeight = height * areaSubArr[j] / sum;
shapeArr.push(
{
width: cellWidth,
height: cellHeight
}
);
}
return shapeArr;
};
// 相邻的两种填充方式放进去,比较是不是前一个的纵横比较小
TreeMapLayout.prototype._isFirstBetter = function (
shapeArr0,
shapeArr1
) {
var ratio0 = shapeArr0[0].height / shapeArr0[0].width;
ratio0 = (ratio0 > 1) ? 1 / ratio0 : ratio0;
var ratio1 = shapeArr1[0].height / shapeArr1[0].width;
ratio1 = (ratio1 > 1) ? 1 / ratio1 : ratio1;
if (Math.abs(ratio0 - 1) <= Math.abs(ratio1 - 1)) {
return true;
}
return false;
};
return TreeMapLayout;
});
\ No newline at end of file
此差异已折叠。
/**
* @file 主要功能
* @author clmtulip(车丽美, clmtulip@gmail.com) liyong(liyong1239@163.com)
*/
define(function (require) {
function ZeroArray(option) {
this.defaultOption = {type: 'RECT'};
this._init(option);
}
ZeroArray.prototype = {
RECT: '_calculateRect',
_init: function (option) {
this._initOption(option);
this._initCanvas();
},
_initOption: function (option) {
for (k in option) {
this.defaultOption[k] = option[k];
}
},
_initCanvas: function () {
var canvas = document.createElement("canvas");
canvas.width = 1;
canvas.height = 1;
var ratio = Math.sqrt(canvas.getContext("2d").getImageData(0, 0, 1, 1).data.length >> 2);
canvas.width = this.defaultOption.width;
canvas.height = this.defaultOption.height;
if (canvas.getContext) {
var ctx = canvas.getContext('2d');
}
this.canvas = canvas;
this.ctx = ctx;
this.ratio = ratio;
},
/**执行计算, 并返回
*
* @param callback
* 返回 {initarr, area, maxHit, maxWit} 给callback
*/
calculate: function (callback, callbackObj) {
var calType = this.defaultOption.type,
calmethod = this[calType];
this[calmethod].call(this, callback, callbackObj);
},
/**
* callback 函数的 正确执行
* @param result 计算后的结果,{initarr, area, maxHit, maxWit}
* @param callback 计算成功之后的回调函数
* @param callbackObj 回调函数的执行作用域
* @private
*/
_calculateReturn: function (result, callback, callbackObj) {
callback.call(callbackObj, result);
},
_calculateRect: function (callback, callbackObj) {
var result = {},
width = this.defaultOption.width >> 5 << 5,
height = this.defaultOption.height;
// 初始化数组
result.initarr = this._rectZeroArray(width * height);
// 总面积
result.area = width * height;
// 最大高度
result.maxHit = height;
// 最大宽度
result.maxWit = width;
// 边界
result.imgboard = this._rectBoard(width, height);
this._calculateReturn(result, callback, callbackObj);
},
_rectBoard: function (width, height) {
var row = [];
for (var i = 0; i < height; i++) {
row.push({
y: i,
start: 0,
end: width
})
}
var cloumn = [];
for (var i = 0; i < width; i++) {
cloumn.push({
x: i,
start: 0,
end: height
})
}
return {row: row, cloumn: cloumn};
},
_rectZeroArray: function (num) {
var a = [],
n = num,
i = -1;
while (++i < n) a[i] = 0;
return a;
}
};
return ZeroArray;
});
\ No newline at end of file
/**
* eventRiver 布局算法
* @module echarts/layout/eventRiver
* @author clmtulip (车丽美, clmtulip@gmail.com)
*/
define(function(require) {
function eventRiverLayout(series, intervalX, area) {
var space = 4;
var scale = intervalX;
function importanceSort(a, b) {
var x = a.importance;
var y = b.importance;
return ((x > y) ? -1 : ((x < y) ? 1 : 0));
}
/**
* 查询数组中元素的index
*/
function indexOf(array, value) {
if (array.indexOf) {
return array.indexOf(value);
}
for (var i = 0, len = array.length; i < len; i++) {
if (array[i] === value) {
return i;
}
}
return -1;
}
// step 0. calculate event importance and sort descending
for (var i = 0; i < series.length; i++) {
for (var j = 0; j < series[i].data.length; j++) {
if (series[i].data[j].weight == null) {
series[i].data[j].weight = 1;
}
var importance = 0;
for (var k = 0; k < series[i].data[j].evolution.length; k++) {
importance += series[i].data[j].evolution[k].valueScale;
}
series[i].data[j].importance = importance * series[i].data[j].weight;
}
series[i].data.sort(importanceSort);
}
// step 1. 计算每个group的重要值importance,并按递减顺序排序
for (var i = 0; i < series.length; i++) {
if (series[i].weight == null) {
series[i].weight = 1;
}
var importance = 0;
for (var j = 0; j < series[i].data.length; j++) {
importance += series[i].data[j].weight;
}
series[i].importance = importance * series[i].weight;
}
// 根据importance对groups进行递减排序
series.sort(importanceSort);
// step 3. set bubble positions in group order, then in event order
// 找到包含所有事件的时间段,即最小和最大时间点
var minTime = Number.MAX_VALUE;
var maxTime = 0;
for (var i = 0; i < series.length; i++) {
for (var j = 0; j < series[i].data.length; j++) {
for (var k = 0; k < series[i].data[j].evolution.length; k++) {
var time = series[i].data[j].evolution[k].timeScale;
minTime = Math.min(minTime, time);
maxTime = Math.max(maxTime, time);
}
}
}
//console.log('minTime: ' + minTime);
//console.log('maxTime: ' + maxTime);
// 时间范围 即 x轴显示的起始范围
minTime = ~~minTime;
maxTime = ~~maxTime;
// 气泡之间的间隙
var flagForOffset = (function () {
var length = maxTime - minTime + 1 + (~~intervalX);
if (length <= 0){
return [0];
}
var result = [];
while (length--){
result.push(0);
}
return result;
})();
var flagForPos = flagForOffset.slice(0);
var bubbleData = [];
var totalMaxy = 0;
var totalOffset = 0;
for (var i = 0; i < series.length; i++) {
for (var j = 0; j < series[i].data.length; j++) {
var e = series[i].data[j];
e.time = [];
e.value = [];
var tmp;
var maxy = 0;
for (var k = 0; k < series[i].data[j].evolution.length; k++) {
tmp = series[i].data[j].evolution[k];
e.time.push(tmp.timeScale);
e.value.push(tmp.valueScale);
maxy = Math.max(maxy, tmp.valueScale);
}
// 边界计算
bubbleBound(e, intervalX, minTime);
// 得到可以放置的位置
e.y = findLocation(flagForPos, e, function (e, index){return e.ypx[index];});
// 得到偏移量
e._offset = findLocation(flagForOffset, e, function (){ return space;});
totalMaxy = Math.max(totalMaxy, e.y + maxy);
totalOffset = Math.max(totalOffset, e._offset);
bubbleData.push(e);
}
}
// 映射到显示区域内
scaleY(bubbleData, area, totalMaxy, totalOffset);
}
/**
* 映射到显示区域内
*/
function scaleY(bubbleData, area, maxY, offset) {
var height = area.height;
var offsetScale = offset / height > 0.5 ? 0.5 : 1;
var yBase = area.y;
var yScale = (area.height - offset) / maxY;
for (var i = 0, length = bubbleData.length; i < length; i++){
var e = bubbleData[i];
e.y = yBase + yScale * e.y + e._offset * offsetScale;
delete e.time;
delete e.value;
delete e.xpx;
delete e.ypx;
delete e._offset;
// 修改值域范围
var evolutionList = e.evolution;
for (var k = 0, klen = evolutionList.length; k < klen; k++) {
evolutionList[k].valueScale *= yScale;
}
}
}
/**
* 得到两点式的方程函数 y = k*x + b
* @param {number} x0 起点横坐标
* @param {number} y0 起点纵坐标
* @param {number} x1 终点横坐标
* @param {number} y1 终点纵坐标
* @returns {Function} 输入为横坐标 返回纵坐标s
*/
function line(x0, y0, x1, y1){
// 横坐标相同,应该抛出错误
if (x0 === x1) {
throw new Error('x0 is equal with x1!!!');
}
// 纵坐标相同
if (y0 === y1) {
return function () {
return y0;
}
}
var k = (y0 - y1) / (x0 - x1);
var b = (y1 * x0 - y0 * x1) / (x0 - x1);
return function (x) {
return k * x + b;
}
}
/**
* 计算当前气泡的值经过的边界
* @param {object} e 气泡的值
* @param {array} e.time 时间范围
* @param {array} e.value 值域范围
* @param {number} intervalX 气泡尾巴长度
*/
function bubbleBound(e, intervalX, minX){
var space = ~~intervalX;
var length = e.time.length;
e.xpx = [];
e.ypx = [];
var i = 0;
var x0 = 0;
var x1 = 0;
var y0 = 0;
var y1 = 0;
var newline;
for(; i < length; i++){
x0 = ~~e.time[i];
y0 = e.value[i] / 2;
if (i === length - 1) {
// i = length - 1 ~ += intervalX
x1 = x0 + space;
y1 = 0;
} else {
x1 = ~~(e.time[i + 1]);
y1 = e.value[i + 1] / 2;
}
// to line
newline = line(x0, y0, x1, y1);
//
for (var x = x0; x < x1; x++){
e.xpx.push(x - minX);
e.ypx.push(newline(x));
}
}
e.xpx.push(x1 - minX);
e.ypx.push(y1);
}
function findLocation(flags, e, yvalue){
var pos = 0;
var length = e.xpx.length;
var i = 0;
var y;
for(; i < length; i++){
y = yvalue(e, i);
pos = Math.max(pos, y + flags[e.xpx[i]]);
}
// reset flags
for(i = 0; i < length; i++){
y = yvalue(e, i);
flags[e.xpx[i]] = pos + y;
}
return pos;
}
return eventRiverLayout;
});
此差异已折叠。
此差异已折叠。
define(function (require) {
var zrUtil = require('zrender/core/util');
var Model = require('./Model');
var SeriesModel = require('./SeriesModel');
var OptionModel = Model.extend({
constructor: OptionModel,
init: function (option) {
this._series = zrUtil.map(option.series, function (seriesOption) {
return SeriesModel.create(seriesOption);
});
},
getSeries: function (seriesIndex) {
return this._series[seriesIndex];
},
eachSeries: function (cb, context) {
}
});
return OptionModel;
});
\ No newline at end of file
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册