1
0
mirror of https://gitlab.com/JKANetwork/CheckServer.git synced 2026-04-04 01:32:01 +02:00

Start again

This commit is contained in:
2020-10-04 17:14:00 +02:00
parent c0d3912413
commit 091f119048
4382 changed files with 1762543 additions and 9606 deletions

232
vendors/echarts/src/coord/Axis.js vendored Normal file
View File

@@ -0,0 +1,232 @@
define(function (require) {
var numberUtil = require('../util/number');
var linearMap = numberUtil.linearMap;
var zrUtil = require('zrender/core/util');
function fixExtentWithBands(extent, nTick) {
var size = extent[1] - extent[0];
var len = nTick;
var margin = size / len / 2;
extent[0] += margin;
extent[1] -= margin;
}
var normalizedExtent = [0, 1];
/**
* @name module:echarts/coord/CartesianAxis
* @constructor
*/
var Axis = function (dim, scale, extent) {
/**
* Axis dimension. Such as 'x', 'y', 'z', 'angle', 'radius'
* @type {string}
*/
this.dim = dim;
/**
* Axis scale
* @type {module:echarts/coord/scale/*}
*/
this.scale = scale;
/**
* @type {Array.<number>}
* @private
*/
this._extent = extent || [0, 0];
/**
* @type {boolean}
*/
this.inverse = false;
/**
* Usually true when axis has a ordinal scale
* @type {boolean}
*/
this.onBand = false;
};
Axis.prototype = {
constructor: Axis,
/**
* If axis extent contain given coord
* @param {number} coord
* @return {boolean}
*/
contain: function (coord) {
var extent = this._extent;
var min = Math.min(extent[0], extent[1]);
var max = Math.max(extent[0], extent[1]);
return coord >= min && coord <= max;
},
/**
* If axis extent contain given data
* @param {number} data
* @return {boolean}
*/
containData: function (data) {
return this.contain(this.dataToCoord(data));
},
/**
* Get coord extent.
* @return {Array.<number>}
*/
getExtent: function () {
var ret = this._extent.slice();
return ret;
},
/**
* Get precision used for formatting
* @param {Array.<number>} [dataExtent]
* @return {number}
*/
getPixelPrecision: function (dataExtent) {
return numberUtil.getPixelPrecision(
dataExtent || this.scale.getExtent(),
this._extent
);
},
/**
* Set coord extent
* @param {number} start
* @param {number} end
*/
setExtent: function (start, end) {
var extent = this._extent;
extent[0] = start;
extent[1] = end;
},
/**
* Convert data to coord. Data is the rank if it has a ordinal scale
* @param {number} data
* @param {boolean} clamp
* @return {number}
*/
dataToCoord: function (data, clamp) {
var extent = this._extent;
var scale = this.scale;
data = scale.normalize(data);
if (this.onBand && scale.type === 'ordinal') {
extent = extent.slice();
fixExtentWithBands(extent, scale.count());
}
return linearMap(data, normalizedExtent, extent, clamp);
},
/**
* Convert coord to data. Data is the rank if it has a ordinal scale
* @param {number} coord
* @param {boolean} clamp
* @return {number}
*/
coordToData: function (coord, clamp) {
var extent = this._extent;
var scale = this.scale;
if (this.onBand && scale.type === 'ordinal') {
extent = extent.slice();
fixExtentWithBands(extent, scale.count());
}
var t = linearMap(coord, extent, normalizedExtent, clamp);
return this.scale.scale(t);
},
/**
* @return {Array.<number>}
*/
getTicksCoords: function () {
if (this.onBand) {
var bands = this.getBands();
var coords = [];
for (var i = 0; i < bands.length; i++) {
coords.push(bands[i][0]);
}
if (bands[i - 1]) {
coords.push(bands[i - 1][1]);
}
return coords;
}
else {
return zrUtil.map(this.scale.getTicks(), this.dataToCoord, this);
}
},
/**
* Coords of labels are on the ticks or on the middle of bands
* @return {Array.<number>}
*/
getLabelsCoords: function () {
if (this.onBand) {
var bands = this.getBands();
var coords = [];
var band;
for (var i = 0; i < bands.length; i++) {
band = bands[i];
coords.push((band[0] + band[1]) / 2);
}
return coords;
}
else {
return zrUtil.map(this.scale.getTicks(), this.dataToCoord, this);
}
},
/**
* Get bands.
*
* If axis has labels [1, 2, 3, 4]. Bands on the axis are
* |---1---|---2---|---3---|---4---|.
*
* @return {Array}
*/
// FIXME Situation when labels is on ticks
getBands: function () {
var extent = this.getExtent();
var bands = [];
var len = this.scale.count();
var start = extent[0];
var end = extent[1];
var span = end - start;
for (var i = 0; i < len; i++) {
bands.push([
span * i / len + start,
span * (i + 1) / len + start
]);
}
return bands;
},
/**
* Get width of band
* @return {number}
*/
getBandWidth: function () {
var axisExtent = this._extent;
var dataExtent = this.scale.getExtent();
var len = dataExtent[1] - dataExtent[0] + (this.onBand ? 1 : 0);
// Fix #2728, avoid NaN when only one data.
len === 0 && (len = 1);
var size = Math.abs(axisExtent[1] - axisExtent[0]);
return Math.abs(size) / len;
}
};
return Axis;
});

272
vendors/echarts/src/coord/View.js vendored Normal file
View File

@@ -0,0 +1,272 @@
/**
* Simple view coordinate system
* Mapping given x, y to transformd view x, y
*/
define(function (require) {
var vector = require('zrender/core/vector');
var matrix = require('zrender/core/matrix');
var Transformable = require('zrender/mixin/Transformable');
var zrUtil = require('zrender/core/util');
var BoundingRect = require('zrender/core/BoundingRect');
var v2ApplyTransform = vector.applyTransform;
// Dummy transform node
function TransformDummy() {
Transformable.call(this);
}
zrUtil.mixin(TransformDummy, Transformable);
function View(name) {
/**
* @type {string}
*/
this.name = name;
/**
* @type {Object}
*/
this.zoomLimit;
Transformable.call(this);
this._roamTransform = new TransformDummy();
this._viewTransform = new TransformDummy();
this._center;
this._zoom;
}
View.prototype = {
constructor: View,
type: 'view',
/**
* @param {Array.<string>}
* @readOnly
*/
dimensions: ['x', 'y'],
/**
* Set bounding rect
* @param {number} x
* @param {number} y
* @param {number} width
* @param {number} height
*/
// PENDING to getRect
setBoundingRect: function (x, y, width, height) {
this._rect = new BoundingRect(x, y, width, height);
return this._rect;
},
/**
* @return {module:zrender/core/BoundingRect}
*/
// PENDING to getRect
getBoundingRect: function () {
return this._rect;
},
/**
* @param {number} x
* @param {number} y
* @param {number} width
* @param {number} height
*/
setViewRect: function (x, y, width, height) {
width = width;
height = height;
this.transformTo(x, y, width, height);
this._viewRect = new BoundingRect(x, y, width, height);
},
/**
* Transformed to particular position and size
* @param {number} x
* @param {number} y
* @param {number} width
* @param {number} height
*/
transformTo: function (x, y, width, height) {
var rect = this.getBoundingRect();
var viewTransform = this._viewTransform;
viewTransform.transform = rect.calculateTransform(
new BoundingRect(x, y, width, height)
);
viewTransform.decomposeTransform();
this._updateTransform();
},
/**
* Set center of view
* @param {Array.<number>} [centerCoord]
*/
setCenter: function (centerCoord) {
if (!centerCoord) {
return;
}
this._center = centerCoord;
this._updateCenterAndZoom();
},
/**
* @param {number} zoom
*/
setZoom: function (zoom) {
zoom = zoom || 1;
var zoomLimit = this.zoomLimit;
if (zoomLimit) {
if (zoomLimit.max != null) {
zoom = Math.min(zoomLimit.max, zoom);
}
if (zoomLimit.min != null) {
zoom = Math.max(zoomLimit.min, zoom);
}
}
this._zoom = zoom;
this._updateCenterAndZoom();
},
/**
* Get default center without roam
*/
getDefaultCenter: function () {
// Rect before any transform
var rawRect = this.getBoundingRect();
var cx = rawRect.x + rawRect.width / 2;
var cy = rawRect.y + rawRect.height / 2;
return [cx, cy];
},
getCenter: function () {
return this._center || this.getDefaultCenter();
},
getZoom: function () {
return this._zoom || 1;
},
/**
* @return {Array.<number}
*/
getRoamTransform: function () {
return this._roamTransform;
},
_updateCenterAndZoom: function () {
// Must update after view transform updated
var viewTransformMatrix = this._viewTransform.getLocalTransform();
var roamTransform = this._roamTransform;
var defaultCenter = this.getDefaultCenter();
var center = this.getCenter();
var zoom = this.getZoom();
center = vector.applyTransform([], center, viewTransformMatrix);
defaultCenter = vector.applyTransform([], defaultCenter, viewTransformMatrix);
roamTransform.origin = center;
roamTransform.position = [
defaultCenter[0] - center[0],
defaultCenter[1] - center[1]
];
roamTransform.scale = [zoom, zoom];
this._updateTransform();
},
/**
* Update transform from roam and mapLocation
* @private
*/
_updateTransform: function () {
var roamTransform = this._roamTransform;
var viewTransform = this._viewTransform;
viewTransform.parent = roamTransform;
roamTransform.updateTransform();
viewTransform.updateTransform();
viewTransform.transform
&& matrix.copy(this.transform || (this.transform = []), viewTransform.transform);
if (this.transform) {
this.invTransform = this.invTransform || [];
matrix.invert(this.invTransform, this.transform);
}
else {
this.invTransform = null;
}
this.decomposeTransform();
},
/**
* @return {module:zrender/core/BoundingRect}
*/
getViewRect: function () {
return this._viewRect;
},
/**
* Get view rect after roam transform
* @return {module:zrender/core/BoundingRect}
*/
getViewRectAfterRoam: function () {
var rect = this.getBoundingRect().clone();
rect.applyTransform(this.transform);
return rect;
},
/**
* Convert a single (lon, lat) data item to (x, y) point.
* @param {Array.<number>} data
* @return {Array.<number>}
*/
dataToPoint: function (data) {
var transform = this.transform;
return transform
? v2ApplyTransform([], data, transform)
: [data[0], data[1]];
},
/**
* Convert a (x, y) point to (lon, lat) data
* @param {Array.<number>} point
* @return {Array.<number>}
*/
pointToData: function (point) {
var invTransform = this.invTransform;
return invTransform
? v2ApplyTransform([], point, invTransform)
: [point[0], point[1]];
}
/**
* @return {number}
*/
// getScalarScale: function () {
// // Use determinant square root of transform to mutiply scalar
// var m = this.transform;
// var det = Math.sqrt(Math.abs(m[0] * m[3] - m[2] * m[1]));
// return det;
// }
};
zrUtil.mixin(View, Transformable);
return View;
});

130
vendors/echarts/src/coord/axisDefault.js vendored Normal file
View File

@@ -0,0 +1,130 @@
define(function (require) {
var zrUtil = require('zrender/core/util');
var defaultOption = {
show: true,
zlevel: 0, // 一级层叠
z: 0, // 二级层叠
// 反向坐标轴
inverse: false,
// 坐标轴名字,默认为空
name: '',
// 坐标轴名字位置,支持'start' | 'middle' | 'end'
nameLocation: 'end',
// 坐标轴文字样式,默认取全局样式
nameTextStyle: {},
// 文字与轴线距离
nameGap: 15,
// 是否能触发鼠标事件
silent: true,
// 坐标轴线
axisLine: {
// 默认显示属性show控制显示与否
show: true,
onZero: true,
// 属性lineStyle控制线条样式
lineStyle: {
color: '#333',
width: 1,
type: 'solid'
}
},
// 坐标轴小标记
axisTick: {
// 属性show控制显示与否默认显示
show: true,
// 控制小标记是否在grid里
inside: false,
// 属性length控制线长
length: 5,
// 属性lineStyle控制线条样式
lineStyle: {
color: '#333',
width: 1
}
},
// 坐标轴文本标签详见axis.axisLabel
axisLabel: {
show: true,
// 控制文本标签是否在grid里
inside: false,
rotate: 0,
margin: 8,
// formatter: null,
// 其余属性默认使用全局文本样式详见TEXTSTYLE
textStyle: {
color: '#333',
fontSize: 12
}
},
// 分隔线
splitLine: {
// 默认显示属性show控制显示与否
show: true,
// 属性lineStyle详见lineStyle控制线条样式
lineStyle: {
color: ['#ccc'],
width: 1,
type: 'solid'
}
},
// 分隔区域
splitArea: {
// 默认不显示属性show控制显示与否
show: false,
// 属性areaStyle详见areaStyle控制区域样式
areaStyle: {
color: ['rgba(250,250,250,0.3)','rgba(200,200,200,0.3)']
}
}
};
var categoryAxis = zrUtil.merge({
// 类目起始和结束两端空白策略
boundaryGap: true,
// 坐标轴小标记
axisTick: {
interval: 'auto'
},
// 坐标轴文本标签详见axis.axisLabel
axisLabel: {
interval: 'auto'
}
}, defaultOption);
var valueAxis = zrUtil.defaults({
// 数值起始和结束两端空白策略
boundaryGap: [0, 0],
// 最小值, 设置成 'dataMin' 则从数据中计算最小值
// min: null,
// 最大值,设置成 'dataMax' 则从数据中计算最大值
// max: null,
// Readonly prop, specifies start value of the range when using data zoom.
// rangeStart: null
// Readonly prop, specifies end value of the range when using data zoom.
// rangeEnd: null
// 脱离0值比例放大聚焦到最终_min_max区间
// scale: false,
// 分割段数默认为5
splitNumber: 5
// Minimum interval
// minInterval: null
}, defaultOption);
// FIXME
var timeAxis = zrUtil.defaults({
scale: true,
min: 'dataMin',
max: 'dataMax'
}, valueAxis);
var logAxis = zrUtil.defaults({}, valueAxis);
logAxis.scale = true;
return {
categoryAxis: categoryAxis,
valueAxis: valueAxis,
timeAxis: timeAxis,
logAxis: logAxis
};
});

222
vendors/echarts/src/coord/axisHelper.js vendored Normal file
View File

@@ -0,0 +1,222 @@
define(function (require) {
var OrdinalScale = require('../scale/Ordinal');
var IntervalScale = require('../scale/Interval');
require('../scale/Time');
require('../scale/Log');
var Scale = require('../scale/Scale');
var numberUtil = require('../util/number');
var zrUtil = require('zrender/core/util');
var textContain = require('zrender/contain/text');
var axisHelper = {};
/**
* Get axis scale extent before niced.
*/
axisHelper.getScaleExtent = function (axis, model) {
var scale = axis.scale;
var originalExtent = scale.getExtent();
var span = originalExtent[1] - originalExtent[0];
if (scale.type === 'ordinal') {
// If series has no data, scale extent may be wrong
if (!isFinite(span)) {
return [0, 0];
}
else {
return originalExtent;
}
}
var min = model.getMin ? model.getMin() : model.get('min');
var max = model.getMax ? model.getMax() : model.get('max');
var crossZero = model.getNeedCrossZero
? model.getNeedCrossZero() : !model.get('scale');
var boundaryGap = model.get('boundaryGap');
if (!zrUtil.isArray(boundaryGap)) {
boundaryGap = [boundaryGap || 0, boundaryGap || 0];
}
boundaryGap[0] = numberUtil.parsePercent(boundaryGap[0], 1);
boundaryGap[1] = numberUtil.parsePercent(boundaryGap[1], 1);
var fixMin = true;
var fixMax = true;
// Add boundary gap
if (min == null) {
min = originalExtent[0] - boundaryGap[0] * span;
fixMin = false;
}
if (max == null) {
max = originalExtent[1] + boundaryGap[1] * span;
fixMax = false;
}
if (min === 'dataMin') {
min = originalExtent[0];
}
if (max === 'dataMax') {
max = originalExtent[1];
}
// Evaluate if axis needs cross zero
if (crossZero) {
// Axis is over zero and min is not set
if (min > 0 && max > 0 && !fixMin) {
min = 0;
}
// Axis is under zero and max is not set
if (min < 0 && max < 0 && !fixMax) {
max = 0;
}
}
return [min, max];
};
axisHelper.niceScaleExtent = function (axis, model) {
var scale = axis.scale;
var extent = axisHelper.getScaleExtent(axis, model);
var fixMin = (model.getMin ? model.getMin() : model.get('min')) != null;
var fixMax = (model.getMax ? model.getMax() : model.get('max')) != null;
var splitNumber = model.get('splitNumber');
scale.setExtent(extent[0], extent[1]);
scale.niceExtent(splitNumber, fixMin, fixMax);
// Use minInterval to constraint the calculated interval.
// If calculated interval is less than minInterval. increase the interval quantity until
// it is larger than minInterval.
// For example:
// minInterval is 1, calculated interval is 0.2, so increase it to be 1. In this way we can get
// an integer axis.
var minInterval = model.get('minInterval');
if (isFinite(minInterval) && !fixMin && !fixMax && scale.type === 'interval') {
var interval = scale.getInterval();
var intervalScale = Math.max(Math.abs(interval), minInterval) / interval;
// while (interval < minInterval) {
// var quantity = numberUtil.quantity(interval);
// interval = quantity * 10;
// scaleQuantity *= 10;
// }
extent = scale.getExtent();
scale.setExtent(intervalScale * extent[0], extent[1] * intervalScale);
scale.niceExtent(splitNumber);
}
// If some one specified the min, max. And the default calculated interval
// is not good enough. He can specify the interval. It is often appeared
// in angle axis with angle 0 - 360. Interval calculated in interval scale is hard
// to be 60.
// FIXME
var interval = model.get('interval');
if (interval != null) {
scale.setInterval && scale.setInterval(interval);
}
};
/**
* @param {module:echarts/model/Model} model
* @param {string} [axisType] Default retrieve from model.type
* @return {module:echarts/scale/*}
*/
axisHelper.createScaleByModel = function(model, axisType) {
axisType = axisType || model.get('type');
if (axisType) {
switch (axisType) {
// Buildin scale
case 'category':
return new OrdinalScale(
model.getCategories(), [Infinity, -Infinity]
);
case 'value':
return new IntervalScale();
// Extended scale, like time and log
default:
return (Scale.getClass(axisType) || IntervalScale).create(model);
}
}
};
/**
* Check if the axis corss 0
*/
axisHelper.ifAxisCrossZero = function (axis) {
var dataExtent = axis.scale.getExtent();
var min = dataExtent[0];
var max = dataExtent[1];
return !((min > 0 && max > 0) || (min < 0 && max < 0));
};
/**
* @param {Array.<number>} tickCoords In axis self coordinate.
* @param {Array.<string>} labels
* @param {string} font
* @param {boolean} isAxisHorizontal
* @return {number}
*/
axisHelper.getAxisLabelInterval = function (tickCoords, labels, font, isAxisHorizontal) {
// FIXME
// 不同角的axis和label不只是horizontal和vertical.
var textSpaceTakenRect;
var autoLabelInterval = 0;
var accumulatedLabelInterval = 0;
var step = 1;
if (labels.length > 40) {
// Simple optimization for large amount of labels
step = Math.round(labels.length / 40);
}
for (var i = 0; i < tickCoords.length; i += step) {
var tickCoord = tickCoords[i];
var rect = textContain.getBoundingRect(
labels[i], font, 'center', 'top'
);
rect[isAxisHorizontal ? 'x' : 'y'] += tickCoord;
rect[isAxisHorizontal ? 'width' : 'height'] *= 1.5;
if (!textSpaceTakenRect) {
textSpaceTakenRect = rect.clone();
}
// There is no space for current label;
else if (textSpaceTakenRect.intersect(rect)) {
accumulatedLabelInterval++;
autoLabelInterval = Math.max(autoLabelInterval, accumulatedLabelInterval);
}
else {
textSpaceTakenRect.union(rect);
// Reset
accumulatedLabelInterval = 0;
}
}
if (autoLabelInterval === 0 && step > 1) {
return step;
}
return autoLabelInterval * step;
};
/**
* @param {Object} axis
* @param {Function} labelFormatter
* @return {Array.<string>}
*/
axisHelper.getFormattedLabels = function (axis, labelFormatter) {
var scale = axis.scale;
var labels = scale.getTicksLabels();
var ticks = scale.getTicks();
if (typeof labelFormatter === 'string') {
labelFormatter = (function (tpl) {
return function (val) {
return tpl.replace('{value}', val);
};
})(labelFormatter);
return zrUtil.map(labels, labelFormatter);
}
else if (typeof labelFormatter === 'function') {
return zrUtil.map(ticks, function (tick, idx) {
return labelFormatter(
axis.type === 'category' ? scale.getLabel(tick) : tick,
idx
);
}, this);
}
else {
return labels;
}
};
return axisHelper;
});

View File

@@ -0,0 +1,39 @@
define(function (require) {
var zrUtil = require('zrender/core/util');
var axisHelper = require('./axisHelper');
function getName(obj) {
if (zrUtil.isObject(obj) && obj.value != null) {
return obj.value;
}
else {
return obj;
}
}
/**
* Get categories
*/
function getCategories() {
return this.get('type') === 'category'
&& zrUtil.map(this.get('data'), getName);
}
/**
* Format labels
* @return {Array.<string>}
*/
function getFormattedLabels() {
return axisHelper.getFormattedLabels(
this.axis,
this.get('axisLabel.formatter')
);
}
return {
getFormattedLabels: getFormattedLabels,
getCategories: getCategories
};
});

View File

@@ -0,0 +1,58 @@
define(function (require) {
var axisDefault = require('./axisDefault');
var zrUtil = require('zrender/core/util');
var ComponentModel = require('../model/Component');
var layout = require('../util/layout');
// FIXME axisType is fixed ?
var AXIS_TYPES = ['value', 'category', 'time', 'log'];
/**
* Generate sub axis model class
* @param {string} axisName 'x' 'y' 'radius' 'angle' 'parallel'
* @param {module:echarts/model/Component} BaseAxisModelClass
* @param {Function} axisTypeDefaulter
* @param {Object} [extraDefaultOption]
*/
return function (axisName, BaseAxisModelClass, axisTypeDefaulter, extraDefaultOption) {
zrUtil.each(AXIS_TYPES, function (axisType) {
BaseAxisModelClass.extend({
type: axisName + 'Axis.' + axisType,
mergeDefaultAndTheme: function (option, ecModel) {
var layoutMode = this.layoutMode;
var inputPositionParams = layoutMode
? layout.getLayoutParams(option) : {};
var themeModel = ecModel.getTheme();
zrUtil.merge(option, themeModel.get(axisType + 'Axis'));
zrUtil.merge(option, this.getDefaultOption());
option.type = axisTypeDefaulter(axisName, option);
if (layoutMode) {
layout.mergeLayoutParam(option, inputPositionParams, layoutMode);
}
},
defaultOption: zrUtil.mergeAll(
[
{},
axisDefault[axisType + 'Axis'],
extraDefaultOption
],
true
)
});
});
ComponentModel.registerSubTypeDefaulter(
axisName + 'Axis',
zrUtil.curry(axisTypeDefaulter, axisName)
);
};
});

View File

@@ -0,0 +1,117 @@
define(function (require) {
var zrUtil = require('zrender/core/util');
var Axis = require('../Axis');
var axisLabelInterval = require('./axisLabelInterval');
/**
* Extend axis 2d
* @constructor module:echarts/coord/cartesian/Axis2D
* @extends {module:echarts/coord/cartesian/Axis}
* @param {string} dim
* @param {*} scale
* @param {Array.<number>} coordExtent
* @param {string} axisType
* @param {string} position
*/
var Axis2D = function (dim, scale, coordExtent, axisType, position) {
Axis.call(this, dim, scale, coordExtent);
/**
* Axis type
* - 'category'
* - 'value'
* - 'time'
* - 'log'
* @type {string}
*/
this.type = axisType || 'value';
/**
* Axis position
* - 'top'
* - 'bottom'
* - 'left'
* - 'right'
*/
this.position = position || 'bottom';
};
Axis2D.prototype = {
constructor: Axis2D,
/**
* Index of axis, can be used as key
*/
index: 0,
/**
* If axis is on the zero position of the other axis
* @type {boolean}
*/
onZero: false,
/**
* Axis model
* @param {module:echarts/coord/cartesian/AxisModel}
*/
model: null,
isHorizontal: function () {
var position = this.position;
return position === 'top' || position === 'bottom';
},
getGlobalExtent: function () {
var ret = this.getExtent();
ret[0] = this.toGlobalCoord(ret[0]);
ret[1] = this.toGlobalCoord(ret[1]);
return ret;
},
/**
* @return {number}
*/
getLabelInterval: function () {
var labelInterval = this._labelInterval;
if (!labelInterval) {
labelInterval = this._labelInterval = axisLabelInterval(this);
}
return labelInterval;
},
/**
* If label is ignored.
* Automatically used when axis is category and label can not be all shown
* @param {number} idx
* @return {boolean}
*/
isLabelIgnored: function (idx) {
if (this.type === 'category') {
var labelInterval = this.getLabelInterval();
return ((typeof labelInterval === 'function')
&& !labelInterval(idx, this.scale.getLabel(idx)))
|| idx % (labelInterval + 1);
}
},
/**
* Transform global coord to local coord,
* i.e. var localCoord = axis.toLocalCoord(80);
* designate by module:echarts/coord/cartesian/Grid.
* @type {Function}
*/
toLocalCoord: null,
/**
* Transform global coord to local coord,
* i.e. var globalCoord = axis.toLocalCoord(40);
* designate by module:echarts/coord/cartesian/Grid.
* @type {Function}
*/
toGlobalCoord: null
};
zrUtil.inherits(Axis2D, Axis);
return Axis2D;
});

View File

@@ -0,0 +1,105 @@
define(function(require) {
'use strict';
var ComponentModel = require('../../model/Component');
var zrUtil = require('zrender/core/util');
var axisModelCreator = require('../axisModelCreator');
var AxisModel = ComponentModel.extend({
type: 'cartesian2dAxis',
/**
* @type {module:echarts/coord/cartesian/Axis2D}
*/
axis: null,
/**
* @override
*/
init: function () {
AxisModel.superApply(this, 'init', arguments);
this._resetRange();
},
/**
* @override
*/
mergeOption: function () {
AxisModel.superApply(this, 'mergeOption', arguments);
this._resetRange();
},
/**
* @override
*/
restoreData: function () {
AxisModel.superApply(this, 'restoreData', arguments);
this._resetRange();
},
/**
* @public
* @param {number} rangeStart
* @param {number} rangeEnd
*/
setRange: function (rangeStart, rangeEnd) {
this.option.rangeStart = rangeStart;
this.option.rangeEnd = rangeEnd;
},
/**
* @public
* @return {Array.<number|string|Date>}
*/
getMin: function () {
var option = this.option;
return option.rangeStart != null ? option.rangeStart : option.min;
},
/**
* @public
* @return {Array.<number|string|Date>}
*/
getMax: function () {
var option = this.option;
return option.rangeEnd != null ? option.rangeEnd : option.max;
},
/**
* @public
* @return {boolean}
*/
getNeedCrossZero: function () {
var option = this.option;
return (option.rangeStart != null || option.rangeEnd != null)
? false : !option.scale;
},
/**
* @private
*/
_resetRange: function () {
// rangeStart and rangeEnd is readonly.
this.option.rangeStart = this.option.rangeEnd = null;
}
});
function getAxisType(axisDim, option) {
// Default axis with data is category axis
return option.type || (option.data ? 'category' : 'value');
}
zrUtil.merge(AxisModel.prototype, require('../axisModelCommonMixin'));
var extraOption = {
gridIndex: 0
};
axisModelCreator('x', AxisModel, getAxisType, extraOption);
axisModelCreator('y', AxisModel, getAxisType, extraOption);
return AxisModel;
});

View File

@@ -0,0 +1,114 @@
/**
* Cartesian coordinate system
* @module echarts/coord/Cartesian
*
*/
define(function (require) {
'use strict';
var zrUtil = require('zrender/core/util');
function dimAxisMapper(dim) {
return this._axes[dim];
}
/**
* @alias module:echarts/coord/Cartesian
* @constructor
*/
var Cartesian = function (name) {
this._axes = {};
this._dimList = [];
/**
* @type {string}
*/
this.name = name || '';
};
Cartesian.prototype = {
constructor: Cartesian,
type: 'cartesian',
/**
* Get axis
* @param {number|string} dim
* @return {module:echarts/coord/Cartesian~Axis}
*/
getAxis: function (dim) {
return this._axes[dim];
},
/**
* Get axes list
* @return {Array.<module:echarts/coord/Cartesian~Axis>}
*/
getAxes: function () {
return zrUtil.map(this._dimList, dimAxisMapper, this);
},
/**
* Get axes list by given scale type
*/
getAxesByScale: function (scaleType) {
scaleType = scaleType.toLowerCase();
return zrUtil.filter(
this.getAxes(),
function (axis) {
return axis.scale.type === scaleType;
}
);
},
/**
* Add axis
* @param {module:echarts/coord/Cartesian.Axis}
*/
addAxis: function (axis) {
var dim = axis.dim;
this._axes[dim] = axis;
this._dimList.push(dim);
},
/**
* Convert data to coord in nd space
* @param {Array.<number>|Object.<string, number>} val
* @return {Array.<number>|Object.<string, number>}
*/
dataToCoord: function (val) {
return this._dataCoordConvert(val, 'dataToCoord');
},
/**
* Convert coord in nd space to data
* @param {Array.<number>|Object.<string, number>} val
* @return {Array.<number>|Object.<string, number>}
*/
coordToData: function (val) {
return this._dataCoordConvert(val, 'coordToData');
},
_dataCoordConvert: function (input, method) {
var dimList = this._dimList;
var output = input instanceof Array ? [] : {};
for (var i = 0; i < dimList.length; i++) {
var dim = dimList[i];
var axis = this._axes[dim];
output[dim] = axis[method](input[dim]);
}
return output;
}
};
return Cartesian;
});

View File

@@ -0,0 +1,112 @@
define(function(require) {
'use strict';
var zrUtil = require('zrender/core/util');
var Cartesian = require('./Cartesian');
function Cartesian2D(name) {
Cartesian.call(this, name);
}
Cartesian2D.prototype = {
constructor: Cartesian2D,
type: 'cartesian2d',
/**
* @type {Array.<string>}
* @readOnly
*/
dimensions: ['x', 'y'],
/**
* Base axis will be used on stacking.
*
* @return {module:echarts/coord/cartesian/Axis2D}
*/
getBaseAxis: function () {
return this.getAxesByScale('ordinal')[0]
|| this.getAxesByScale('time')[0]
|| this.getAxis('x');
},
/**
* If contain point
* @param {Array.<number>} point
* @return {boolean}
*/
containPoint: function (point) {
var axisX = this.getAxis('x');
var axisY = this.getAxis('y');
return axisX.contain(axisX.toLocalCoord(point[0]))
&& axisY.contain(axisY.toLocalCoord(point[1]));
},
/**
* If contain data
* @param {Array.<number>} data
* @return {boolean}
*/
containData: function (data) {
return this.getAxis('x').containData(data[0])
&& this.getAxis('y').containData(data[1]);
},
/**
* Convert series data to an array of points
* @param {module:echarts/data/List} data
* @param {boolean} stack
* @return {Array}
* Return array of points. For example:
* `[[10, 10], [20, 20], [30, 30]]`
*/
dataToPoints: function (data, stack) {
return data.mapArray(['x', 'y'], function (x, y) {
return this.dataToPoint([x, y]);
}, stack, this);
},
/**
* @param {Array.<number>} data
* @param {boolean} [clamp=false]
* @return {Array.<number>}
*/
dataToPoint: function (data, clamp) {
var xAxis = this.getAxis('x');
var yAxis = this.getAxis('y');
return [
xAxis.toGlobalCoord(xAxis.dataToCoord(data[0], clamp)),
yAxis.toGlobalCoord(yAxis.dataToCoord(data[1], clamp))
];
},
/**
* @param {Array.<number>} point
* @param {boolean} [clamp=false]
* @return {Array.<number>}
*/
pointToData: function (point, clamp) {
var xAxis = this.getAxis('x');
var yAxis = this.getAxis('y');
return [
xAxis.coordToData(xAxis.toLocalCoord(point[0]), clamp),
yAxis.coordToData(yAxis.toLocalCoord(point[1]), clamp)
];
},
/**
* Get other axis
* @param {module:echarts/coord/cartesian/Axis2D} axis
*/
getOtherAxis: function (axis) {
return this.getAxis(axis.dim === 'x' ? 'y' : 'x');
}
};
zrUtil.inherits(Cartesian2D, Cartesian);
return Cartesian2D;
});

View File

@@ -0,0 +1,419 @@
/**
* Grid is a region which contains at most 4 cartesian systems
*
* TODO Default cartesian
*/
define(function(require, factory) {
var layout = require('../../util/layout');
var axisHelper = require('../../coord/axisHelper');
var zrUtil = require('zrender/core/util');
var Cartesian2D = require('./Cartesian2D');
var Axis2D = require('./Axis2D');
var each = zrUtil.each;
var ifAxisCrossZero = axisHelper.ifAxisCrossZero;
var niceScaleExtent = axisHelper.niceScaleExtent;
// 依赖 GridModel, AxisModel 做预处理
require('./GridModel');
/**
* Check if the axis is used in the specified grid
* @inner
*/
function isAxisUsedInTheGrid(axisModel, gridModel, ecModel) {
return ecModel.getComponent('grid', axisModel.get('gridIndex')) === gridModel;
}
function getLabelUnionRect(axis) {
var axisModel = axis.model;
var labels = axisModel.getFormattedLabels();
var rect;
var step = 1;
var labelCount = labels.length;
if (labelCount > 40) {
// Simple optimization for large amount of labels
step = Math.ceil(labelCount / 40);
}
for (var i = 0; i < labelCount; i += step) {
if (!axis.isLabelIgnored(i)) {
var singleRect = axisModel.getTextRect(labels[i]);
// FIXME consider label rotate
rect ? rect.union(singleRect) : (rect = singleRect);
}
}
return rect;
}
function Grid(gridModel, ecModel, api) {
/**
* @type {Object.<string, module:echarts/coord/cartesian/Cartesian2D>}
* @private
*/
this._coordsMap = {};
/**
* @type {Array.<module:echarts/coord/cartesian/Cartesian>}
* @private
*/
this._coordsList = [];
/**
* @type {Object.<string, module:echarts/coord/cartesian/Axis2D>}
* @private
*/
this._axesMap = {};
/**
* @type {Array.<module:echarts/coord/cartesian/Axis2D>}
* @private
*/
this._axesList = [];
this._initCartesian(gridModel, ecModel, api);
this._model = gridModel;
}
var gridProto = Grid.prototype;
gridProto.type = 'grid';
gridProto.getRect = function () {
return this._rect;
};
gridProto.update = function (ecModel, api) {
var axesMap = this._axesMap;
this._updateScale(ecModel, this._model);
function ifAxisCanNotOnZero(otherAxisDim) {
var axes = axesMap[otherAxisDim];
for (var idx in axes) {
var axis = axes[idx];
if (axis && (axis.type === 'category' || !ifAxisCrossZero(axis))) {
return true;
}
}
return false;
}
each(axesMap.x, function (xAxis) {
niceScaleExtent(xAxis, xAxis.model);
});
each(axesMap.y, function (yAxis) {
niceScaleExtent(yAxis, yAxis.model);
});
// Fix configuration
each(axesMap.x, function (xAxis) {
// onZero can not be enabled in these two situations
// 1. When any other axis is a category axis
// 2. When any other axis not across 0 point
if (ifAxisCanNotOnZero('y')) {
xAxis.onZero = false;
}
});
each(axesMap.y, function (yAxis) {
if (ifAxisCanNotOnZero('x')) {
yAxis.onZero = false;
}
});
// Resize again if containLabel is enabled
// FIXME It may cause getting wrong grid size in data processing stage
this.resize(this._model, api);
};
/**
* Resize the grid
* @param {module:echarts/coord/cartesian/GridModel} gridModel
* @param {module:echarts/ExtensionAPI} api
*/
gridProto.resize = function (gridModel, api) {
var gridRect = layout.getLayoutRect(
gridModel.getBoxLayoutParams(), {
width: api.getWidth(),
height: api.getHeight()
});
this._rect = gridRect;
var axesList = this._axesList;
adjustAxes();
// Minus label size
if (gridModel.get('containLabel')) {
each(axesList, function (axis) {
if (!axis.model.get('axisLabel.inside')) {
var labelUnionRect = getLabelUnionRect(axis);
if (labelUnionRect) {
var dim = axis.isHorizontal() ? 'height' : 'width';
var margin = axis.model.get('axisLabel.margin');
gridRect[dim] -= labelUnionRect[dim] + margin;
if (axis.position === 'top') {
gridRect.y += labelUnionRect.height + margin;
}
else if (axis.position === 'left') {
gridRect.x += labelUnionRect.width + margin;
}
}
}
});
adjustAxes();
}
function adjustAxes() {
each(axesList, function (axis) {
var isHorizontal = axis.isHorizontal();
var extent = isHorizontal ? [0, gridRect.width] : [0, gridRect.height];
var idx = axis.inverse ? 1 : 0;
axis.setExtent(extent[idx], extent[1 - idx]);
updateAxisTransfrom(axis, isHorizontal ? gridRect.x : gridRect.y);
});
}
};
/**
* @param {string} axisType
* @param {ndumber} [axisIndex]
*/
gridProto.getAxis = function (axisType, axisIndex) {
var axesMapOnDim = this._axesMap[axisType];
if (axesMapOnDim != null) {
if (axisIndex == null) {
// Find first axis
for (var name in axesMapOnDim) {
return axesMapOnDim[name];
}
}
return axesMapOnDim[axisIndex];
}
};
gridProto.getCartesian = function (xAxisIndex, yAxisIndex) {
var key = 'x' + xAxisIndex + 'y' + yAxisIndex;
return this._coordsMap[key];
};
/**
* Initialize cartesian coordinate systems
* @private
*/
gridProto._initCartesian = function (gridModel, ecModel, api) {
var axisPositionUsed = {
left: false,
right: false,
top: false,
bottom: false
};
var axesMap = {
x: {},
y: {}
};
var axesCount = {
x: 0,
y: 0
};
/// Create axis
ecModel.eachComponent('xAxis', createAxisCreator('x'), this);
ecModel.eachComponent('yAxis', createAxisCreator('y'), this);
if (!axesCount.x || !axesCount.y) {
// Roll back when there no either x or y axis
this._axesMap = {};
this._axesList = [];
return;
}
this._axesMap = axesMap;
/// Create cartesian2d
each(axesMap.x, function (xAxis, xAxisIndex) {
each(axesMap.y, function (yAxis, yAxisIndex) {
var key = 'x' + xAxisIndex + 'y' + yAxisIndex;
var cartesian = new Cartesian2D(key);
cartesian.grid = this;
this._coordsMap[key] = cartesian;
this._coordsList.push(cartesian);
cartesian.addAxis(xAxis);
cartesian.addAxis(yAxis);
}, this);
}, this);
function createAxisCreator(axisType) {
return function (axisModel, idx) {
if (!isAxisUsedInTheGrid(axisModel, gridModel, ecModel)) {
return;
}
var axisPosition = axisModel.get('position');
if (axisType === 'x') {
// Fix position
if (axisPosition !== 'top' && axisPosition !== 'bottom') {
// Default bottom of X
axisPosition = 'bottom';
}
if (axisPositionUsed[axisPosition]) {
axisPosition = axisPosition === 'top' ? 'bottom' : 'top';
}
}
else {
// Fix position
if (axisPosition !== 'left' && axisPosition !== 'right') {
// Default left of Y
axisPosition = 'left';
}
if (axisPositionUsed[axisPosition]) {
axisPosition = axisPosition === 'left' ? 'right' : 'left';
}
}
axisPositionUsed[axisPosition] = true;
var axis = new Axis2D(
axisType, axisHelper.createScaleByModel(axisModel),
[0, 0],
axisModel.get('type'),
axisPosition
);
var isCategory = axis.type === 'category';
axis.onBand = isCategory && axisModel.get('boundaryGap');
axis.inverse = axisModel.get('inverse');
axis.onZero = axisModel.get('axisLine.onZero');
// Inject axis into axisModel
axisModel.axis = axis;
// Inject axisModel into axis
axis.model = axisModel;
// Index of axis, can be used as key
axis.index = idx;
this._axesList.push(axis);
axesMap[axisType][idx] = axis;
axesCount[axisType]++;
};
}
};
/**
* Update cartesian properties from series
* @param {module:echarts/model/Option} option
* @private
*/
gridProto._updateScale = function (ecModel, gridModel) {
// Reset scale
zrUtil.each(this._axesList, function (axis) {
axis.scale.setExtent(Infinity, -Infinity);
});
ecModel.eachSeries(function (seriesModel) {
if (seriesModel.get('coordinateSystem') === 'cartesian2d') {
var xAxisIndex = seriesModel.get('xAxisIndex');
var yAxisIndex = seriesModel.get('yAxisIndex');
var xAxisModel = ecModel.getComponent('xAxis', xAxisIndex);
var yAxisModel = ecModel.getComponent('yAxis', yAxisIndex);
if (!isAxisUsedInTheGrid(xAxisModel, gridModel, ecModel)
|| !isAxisUsedInTheGrid(yAxisModel, gridModel, ecModel)
) {
return;
}
var cartesian = this.getCartesian(xAxisIndex, yAxisIndex);
var data = seriesModel.getData();
var xAxis = cartesian.getAxis('x');
var yAxis = cartesian.getAxis('y');
if (data.type === 'list') {
unionExtent(data, xAxis, seriesModel);
unionExtent(data, yAxis, seriesModel);
}
}
}, this);
function unionExtent(data, axis, seriesModel) {
each(seriesModel.coordDimToDataDim(axis.dim), function (dim) {
axis.scale.unionExtent(data.getDataExtent(
dim, axis.scale.type !== 'ordinal'
));
});
}
};
/**
* @inner
*/
function updateAxisTransfrom(axis, coordBase) {
var axisExtent = axis.getExtent();
var axisExtentSum = axisExtent[0] + axisExtent[1];
// Fast transform
axis.toGlobalCoord = axis.dim === 'x'
? function (coord) {
return coord + coordBase;
}
: function (coord) {
return axisExtentSum - coord + coordBase;
};
axis.toLocalCoord = axis.dim === 'x'
? function (coord) {
return coord - coordBase;
}
: function (coord) {
return axisExtentSum - coord + coordBase;
};
}
Grid.create = function (ecModel, api) {
var grids = [];
ecModel.eachComponent('grid', function (gridModel, idx) {
var grid = new Grid(gridModel, ecModel, api);
grid.name = 'grid_' + idx;
grid.resize(gridModel, api);
gridModel.coordinateSystem = grid;
grids.push(grid);
});
// Inject the coordinateSystems into seriesModel
ecModel.eachSeries(function (seriesModel) {
if (seriesModel.get('coordinateSystem') !== 'cartesian2d') {
return;
}
var xAxisIndex = seriesModel.get('xAxisIndex');
// TODO Validate
var xAxisModel = ecModel.getComponent('xAxis', xAxisIndex);
var grid = grids[xAxisModel.get('gridIndex')];
seriesModel.coordinateSystem = grid.getCartesian(
xAxisIndex, seriesModel.get('yAxisIndex')
);
});
return grids;
};
// For deciding which dimensions to use when creating list data
Grid.dimensions = Cartesian2D.prototype.dimensions;
require('../../CoordinateSystem').register('cartesian2d', Grid);
return Grid;
});

View File

@@ -0,0 +1,40 @@
// Grid 是在有直角坐标系的时候必须要存在的
// 所以这里也要被 Cartesian2D 依赖
define(function(require) {
'use strict';
require('./AxisModel');
var ComponentModel = require('../../model/Component');
return ComponentModel.extend({
type: 'grid',
dependencies: ['xAxis', 'yAxis'],
layoutMode: 'box',
/**
* @type {module:echarts/coord/cartesian/Grid}
*/
coordinateSystem: null,
defaultOption: {
show: false,
zlevel: 0,
z: 0,
left: '10%',
top: 60,
right: '10%',
bottom: 60,
// If grid size contain label
containLabel: false,
// width: {totalWidth} - left - right,
// height: {totalHeight} - top - bottom,
backgroundColor: 'rgba(0,0,0,0)',
borderWidth: 1,
borderColor: '#ccc'
}
});
});

View File

@@ -0,0 +1,26 @@
/**
* Helper function for axisLabelInterval calculation
*/
define(function(require) {
'use strict';
var zrUtil = require('zrender/core/util');
var axisHelper = require('../axisHelper');
return function (axis) {
var axisModel = axis.model;
var labelModel = axisModel.getModel('axisLabel');
var labelInterval = labelModel.get('interval');
if (!(axis.type === 'category' && labelInterval === 'auto')) {
return labelInterval === 'auto' ? 0 : labelInterval;
}
return axisHelper.getAxisLabelInterval(
zrUtil.map(axis.scale.getTicks(), axis.dataToCoord, axis),
axisModel.getFormattedLabels(),
labelModel.getModel('textStyle').getFont(),
axis.isHorizontal()
);
};
});

230
vendors/echarts/src/coord/geo/Geo.js vendored Normal file
View File

@@ -0,0 +1,230 @@
define(function (require) {
var parseGeoJson = require('./parseGeoJson');
var zrUtil = require('zrender/core/util');
var BoundingRect = require('zrender/core/BoundingRect');
var View = require('../View');
// Geo fix functions
var geoFixFuncs = [
require('./fix/nanhai'),
require('./fix/textCoord'),
require('./fix/geoCoord')
];
/**
* [Geo description]
* @param {string} name Geo name
* @param {string} map Map type
* @param {Object} geoJson
* @param {Object} [specialAreas]
* Specify the positioned areas by left, top, width, height
* @param {Object.<string, string>} [nameMap]
* Specify name alias
*/
function Geo(name, map, geoJson, specialAreas, nameMap) {
View.call(this, name);
/**
* Map type
* @type {string}
*/
this.map = map;
this._nameCoordMap = {};
this.loadGeoJson(geoJson, specialAreas, nameMap);
}
Geo.prototype = {
constructor: Geo,
type: 'geo',
/**
* @param {Array.<string>}
* @readOnly
*/
dimensions: ['lng', 'lat'],
/**
* If contain given lng,lat coord
* @param {Array.<number>}
* @readOnly
*/
containCoord: function (coord) {
var regions = this.regions;
for (var i = 0; i < regions.length; i++) {
if (regions[i].contain(coord)) {
return true;
}
}
return false;
},
/**
* @param {Object} geoJson
* @param {Object} [specialAreas]
* Specify the positioned areas by left, top, width, height
* @param {Object.<string, string>} [nameMap]
* Specify name alias
*/
loadGeoJson: function (geoJson, specialAreas, nameMap) {
// https://jsperf.com/try-catch-performance-overhead
try {
this.regions = geoJson ? parseGeoJson(geoJson) : [];
}
catch (e) {
throw 'Invalid geoJson format\n' + e;
}
specialAreas = specialAreas || {};
nameMap = nameMap || {};
var regions = this.regions;
var regionsMap = {};
for (var i = 0; i < regions.length; i++) {
var regionName = regions[i].name;
// Try use the alias in nameMap
regionName = nameMap[regionName] || regionName;
regions[i].name = regionName;
regionsMap[regionName] = regions[i];
// Add geoJson
this.addGeoCoord(regionName, regions[i].center);
// Some area like Alaska in USA map needs to be tansformed
// to look better
var specialArea = specialAreas[regionName];
if (specialArea) {
regions[i].transformTo(
specialArea.left, specialArea.top, specialArea.width, specialArea.height
);
}
}
this._regionsMap = regionsMap;
this._rect = null;
zrUtil.each(geoFixFuncs, function (fixFunc) {
fixFunc(this);
}, this);
},
// Overwrite
transformTo: function (x, y, width, height) {
var rect = this.getBoundingRect();
rect = rect.clone();
// Longitute is inverted
rect.y = -rect.y - rect.height;
var viewTransform = this._viewTransform;
viewTransform.transform = rect.calculateTransform(
new BoundingRect(x, y, width, height)
);
viewTransform.decomposeTransform();
var scale = viewTransform.scale;
scale[1] = -scale[1];
viewTransform.updateTransform();
this._updateTransform();
},
/**
* @param {string} name
* @return {module:echarts/coord/geo/Region}
*/
getRegion: function (name) {
return this._regionsMap[name];
},
getRegionByCoord: function (coord) {
var regions = this.regions;
for (var i = 0; i < regions.length; i++) {
if (regions[i].contain(coord)) {
return regions[i];
}
}
},
/**
* Add geoCoord for indexing by name
* @param {string} name
* @param {Array.<number>} geoCoord
*/
addGeoCoord: function (name, geoCoord) {
this._nameCoordMap[name] = geoCoord;
},
/**
* Get geoCoord by name
* @param {string} name
* @return {Array.<number>}
*/
getGeoCoord: function (name) {
return this._nameCoordMap[name];
},
// Overwrite
getBoundingRect: function () {
if (this._rect) {
return this._rect;
}
var rect;
var regions = this.regions;
for (var i = 0; i < regions.length; i++) {
var regionRect = regions[i].getBoundingRect();
rect = rect || regionRect.clone();
rect.union(regionRect);
}
// FIXME Always return new ?
return (this._rect = rect || new BoundingRect(0, 0, 0, 0));
},
/**
* Convert series data to a list of points
* @param {module:echarts/data/List} data
* @param {boolean} stack
* @return {Array}
* Return list of points. For example:
* `[[10, 10], [20, 20], [30, 30]]`
*/
dataToPoints: function (data) {
var item = [];
return data.mapArray(['lng', 'lat'], function (lon, lat) {
item[0] = lon;
item[1] = lat;
return this.dataToPoint(item);
}, this);
},
// Overwrite
/**
* @param {string|Array.<number>} data
* @return {Array.<number>}
*/
dataToPoint: function (data) {
if (typeof data === 'string') {
// Map area name to geoCoord
data = this.getGeoCoord(data);
}
if (data) {
return View.prototype.dataToPoint.call(this, data);
}
}
};
zrUtil.mixin(Geo, View);
return Geo;
});

View File

@@ -0,0 +1,148 @@
define(function (require) {
'use strict';
var modelUtil = require('../../util/model');
var ComponentModel = require('../../model/Component');
var Model = require('../../model/Model');
var zrUtil = require('zrender/core/util');
var selectableMixin = require('../../component/helper/selectableMixin');
var geoCreator = require('./geoCreator');
var GeoModel = ComponentModel.extend({
type: 'geo',
/**
* @type {module:echarts/coord/geo/Geo}
*/
coordinateSystem: null,
init: function (option) {
ComponentModel.prototype.init.apply(this, arguments);
// Default label emphasis `position` and `show`
modelUtil.defaultEmphasis(
option.label, ['position', 'show', 'textStyle', 'distance', 'formatter']
);
},
optionUpdated: function () {
var option = this.option;
var self = this;
option.regions = geoCreator.getFilledRegions(option.regions, option.map);
this._optionModelMap = zrUtil.reduce(option.regions || [], function (obj, regionOpt) {
if (regionOpt.name) {
obj[regionOpt.name] = new Model(regionOpt, self);
}
return obj;
}, {});
this.updateSelectedMap(option.regions);
},
defaultOption: {
zlevel: 0,
z: 0,
show: true,
left: 'center',
top: 'center',
// 自适应
// width:,
// height:,
// right
// bottom
// Map type
map: '',
// Default on center of map
center: null,
zoom: 1,
scaleLimit: null,
// selectedMode: false
label: {
normal: {
show: false,
textStyle: {
color: '#000'
}
},
emphasis: {
show: true,
textStyle: {
color: 'rgb(100,0,0)'
}
}
},
itemStyle: {
normal: {
// color: 各异,
borderWidth: 0.5,
borderColor: '#444',
color: '#eee'
},
emphasis: { // 也是选中样式
color: 'rgba(255,215,0,0.8)'
}
},
regions: []
},
/**
* Get model of region
* @param {string} name
* @return {module:echarts/model/Model}
*/
getRegionModel: function (name) {
return this._optionModelMap[name];
},
/**
* Format label
* @param {string} name Region name
* @param {string} [status='normal'] 'normal' or 'emphasis'
* @return {string}
*/
getFormattedLabel: function (name, status) {
var formatter = this.get('label.' + status + '.formatter');
var params = {
name: name
};
if (typeof formatter === 'function') {
params.status = status;
return formatter(params);
}
else if (typeof formatter === 'string') {
return formatter.replace('{a}', params.seriesName);
}
},
setZoom: function (zoom) {
this.option.zoom = zoom;
},
setCenter: function (center) {
this.option.center = center;
}
});
zrUtil.mixin(GeoModel, selectableMixin);
return GeoModel;
});

127
vendors/echarts/src/coord/geo/Region.js vendored Normal file
View File

@@ -0,0 +1,127 @@
/**
* @module echarts/coord/geo/Region
*/
define(function (require) {
var polygonContain = require('zrender/contain/polygon');
var BoundingRect = require('zrender/core/BoundingRect');
var bbox = require('zrender/core/bbox');
var vec2 = require('zrender/core/vector');
/**
* @param {string} name
* @param {Array} contours
* @param {Array.<number>} cp
*/
function Region(name, contours, cp) {
/**
* @type {string}
* @readOnly
*/
this.name = name;
/**
* @type {Array.<Array>}
* @readOnly
*/
this.contours = contours;
if (!cp) {
var rect = this.getBoundingRect();
cp = [
rect.x + rect.width / 2,
rect.y + rect.height / 2
];
}
else {
cp = [cp[0], cp[1]];
}
/**
* @type {Array.<number>}
*/
this.center = cp;
}
Region.prototype = {
constructor: Region,
/**
* @return {module:zrender/core/BoundingRect}
*/
getBoundingRect: function () {
var rect = this._rect;
if (rect) {
return rect;
}
var MAX_NUMBER = Number.MAX_VALUE;
var min = [MAX_NUMBER, MAX_NUMBER];
var max = [-MAX_NUMBER, -MAX_NUMBER];
var min2 = [];
var max2 = [];
var contours = this.contours;
for (var i = 0; i < contours.length; i++) {
bbox.fromPoints(contours[i], min2, max2);
vec2.min(min, min, min2);
vec2.max(max, max, max2);
}
// No data
if (i === 0) {
min[0] = min[1] = max[0] = max[1] = 0;
}
return (this._rect = new BoundingRect(
min[0], min[1], max[0] - min[0], max[1] - min[1]
));
},
/**
* @param {<Array.<number>} coord
* @return {boolean}
*/
contain: function (coord) {
var rect = this.getBoundingRect();
var contours = this.contours;
if (rect.contain(coord[0], coord[1])) {
for (var i = 0, len = contours.length; i < len; i++) {
if (polygonContain.contain(contours[i], coord[0], coord[1])) {
return true;
}
}
}
return false;
},
transformTo: function (x, y, width, height) {
var rect = this.getBoundingRect();
var aspect = rect.width / rect.height;
if (!width) {
width = aspect * height;
}
else if (!height) {
height = width / aspect ;
}
var target = new BoundingRect(x, y, width, height);
var transform = rect.calculateTransform(target);
var contours = this.contours;
for (var i = 0; i < contours.length; i++) {
for (var p = 0; p < contours[i].length; p++) {
vec2.applyTransform(contours[i][p], contours[i][p], transform);
}
}
rect = this._rect;
rect.copy(target);
// Update center
this.center = [
rect.x + rect.width / 2,
rect.y + rect.height / 2
];
}
};
return Region;
});

View File

@@ -0,0 +1,20 @@
define(function (require) {
var zrUtil = require('zrender/core/util');
var geoCoordMap = {
'Russia': [100, 60],
'United States of America': [-99, 38]
};
return function (geo) {
zrUtil.each(geo.regions, function (region) {
var geoCoord = geoCoordMap[region.name];
if (geoCoord) {
var cp = region.center;
cp[0] = geoCoord[0];
cp[1] = geoCoord[1];
}
});
};
});

View File

@@ -0,0 +1,40 @@
// Fix for 南海诸岛
define(function (require) {
var Region = require('../Region');
var geoCoord = [126, 25];
var points = [
[[0,3.5],[7,11.2],[15,11.9],[30,7],[42,0.7],[52,0.7],
[56,7.7],[59,0.7],[64,0.7],[64,0],[5,0],[0,3.5]],
[[13,16.1],[19,14.7],[16,21.7],[11,23.1],[13,16.1]],
[[12,32.2],[14,38.5],[15,38.5],[13,32.2],[12,32.2]],
[[16,47.6],[12,53.2],[13,53.2],[18,47.6],[16,47.6]],
[[6,64.4],[8,70],[9,70],[8,64.4],[6,64.4]],
[[23,82.6],[29,79.8],[30,79.8],[25,82.6],[23,82.6]],
[[37,70.7],[43,62.3],[44,62.3],[39,70.7],[37,70.7]],
[[48,51.1],[51,45.5],[53,45.5],[50,51.1],[48,51.1]],
[[51,35],[51,28.7],[53,28.7],[53,35],[51,35]],
[[52,22.4],[55,17.5],[56,17.5],[53,22.4],[52,22.4]],
[[58,12.6],[62,7],[63,7],[60,12.6],[58,12.6]],
[[0,3.5],[0,93.1],[64,93.1],[64,0],[63,0],[63,92.4],
[1,92.4],[1,3.5],[0,3.5]]
];
for (var i = 0; i < points.length; i++) {
for (var k = 0; k < points[i].length; k++) {
points[i][k][0] /= 10.5;
points[i][k][1] /= -10.5 / 0.75;
points[i][k][0] += geoCoord[0];
points[i][k][1] += geoCoord[1];
}
}
return function (geo) {
if (geo.map === 'china') {
geo.regions.push(new Region(
'南海诸岛', points, geoCoord
));
}
};
});

View File

@@ -0,0 +1,25 @@
define(function (require) {
var zrUtil = require('zrender/core/util');
var coordsOffsetMap = {
'南海诸岛' : [32, 80],
// 全国
'广东': [0, -10],
'香港': [10, 5],
'澳门': [-10, 10],
//'北京': [-10, 0],
'天津': [5, 5]
};
return function (geo) {
zrUtil.each(geo.regions, function (region) {
var coordFix = coordsOffsetMap[region.name];
if (coordFix) {
var cp = region.center;
cp[0] += coordFix[0] / 10.5;
cp[1] += -coordFix[1] / (10.5 / 0.75);
}
});
};
});

View File

@@ -0,0 +1,217 @@
define(function (require) {
var Geo = require('./Geo');
var layout = require('../../util/layout');
var zrUtil = require('zrender/core/util');
var mapDataStores = {};
/**
* Resize method bound to the geo
* @param {module:echarts/coord/geo/GeoModel|module:echarts/chart/map/MapModel} geoModel
* @param {module:echarts/ExtensionAPI} api
*/
function resizeGeo (geoModel, api) {
var rect = this.getBoundingRect();
var boxLayoutOption = geoModel.getBoxLayoutParams();
// 0.75 rate
boxLayoutOption.aspect = rect.width / rect.height * 0.75;
var viewRect = layout.getLayoutRect(boxLayoutOption, {
width: api.getWidth(),
height: api.getHeight()
});
this.setViewRect(viewRect.x, viewRect.y, viewRect.width, viewRect.height);
this.setCenter(geoModel.get('center'));
this.setZoom(geoModel.get('zoom'));
}
/**
* @param {module:echarts/coord/Geo} geo
* @param {module:echarts/model/Model} model
* @inner
*/
function setGeoCoords(geo, model) {
zrUtil.each(model.get('geoCoord'), function (geoCoord, name) {
geo.addGeoCoord(name, geoCoord);
});
}
function mapNotExistsError(name) {
console.error('Map ' + name + ' not exists');
}
var geoCreator = {
// For deciding which dimensions to use when creating list data
dimensions: Geo.prototype.dimensions,
create: function (ecModel, api) {
var geoList = [];
// FIXME Create each time may be slow
ecModel.eachComponent('geo', function (geoModel, idx) {
var name = geoModel.get('map');
var mapData = mapDataStores[name];
if (!mapData) {
mapNotExistsError(name);
}
var geo = new Geo(
name + idx, name,
mapData && mapData.geoJson, mapData && mapData.specialAreas,
geoModel.get('nameMap')
);
geo.zoomLimit = geoModel.get('scaleLimit');
geoList.push(geo);
setGeoCoords(geo, geoModel);
geoModel.coordinateSystem = geo;
geo.model = geoModel;
// Inject resize method
geo.resize = resizeGeo;
geo.resize(geoModel, api);
});
ecModel.eachSeries(function (seriesModel) {
var coordSys = seriesModel.get('coordinateSystem');
if (coordSys === 'geo') {
var geoIndex = seriesModel.get('geoIndex') || 0;
seriesModel.coordinateSystem = geoList[geoIndex];
}
});
// If has map series
var mapModelGroupBySeries = {};
ecModel.eachSeriesByType('map', function (seriesModel) {
var mapType = seriesModel.get('map');
mapModelGroupBySeries[mapType] = mapModelGroupBySeries[mapType] || [];
mapModelGroupBySeries[mapType].push(seriesModel);
});
zrUtil.each(mapModelGroupBySeries, function (mapSeries, mapType) {
var mapData = mapDataStores[mapType];
if (!mapData) {
mapNotExistsError(name);
}
var nameMapList = zrUtil.map(mapSeries, function (singleMapSeries) {
return singleMapSeries.get('nameMap');
});
var geo = new Geo(
mapType, mapType,
mapData && mapData.geoJson, mapData && mapData.specialAreas,
zrUtil.mergeAll(nameMapList)
);
geo.zoomLimit = zrUtil.retrieve.apply(null, zrUtil.map(mapSeries, function (singleMapSeries) {
return singleMapSeries.get('scaleLimit');
}));
geoList.push(geo);
// Inject resize method
geo.resize = resizeGeo;
geo.resize(mapSeries[0], api);
zrUtil.each(mapSeries, function (singleMapSeries) {
singleMapSeries.coordinateSystem = geo;
setGeoCoords(geo, singleMapSeries);
});
});
return geoList;
},
/**
* @param {string} mapName
* @param {Object|string} geoJson
* @param {Object} [specialAreas]
*
* @example
* $.get('USA.json', function (geoJson) {
* echarts.registerMap('USA', geoJson);
* // Or
* echarts.registerMap('USA', {
* geoJson: geoJson,
* specialAreas: {}
* })
* });
*/
registerMap: function (mapName, geoJson, specialAreas) {
if (geoJson.geoJson && !geoJson.features) {
specialAreas = geoJson.specialAreas;
geoJson = geoJson.geoJson;
}
if (typeof geoJson === 'string') {
geoJson = (typeof JSON !== 'undefined' && JSON.parse)
? JSON.parse(geoJson) : (new Function('return (' + geoJson + ');'))();
}
mapDataStores[mapName] = {
geoJson: geoJson,
specialAreas: specialAreas
};
},
/**
* @param {string} mapName
* @return {Object}
*/
getMap: function (mapName) {
return mapDataStores[mapName];
},
/**
* Fill given regions array
* @param {Array.<Object>} originRegionArr
* @param {string} mapName
* @return {Array}
*/
getFilledRegions: function (originRegionArr, mapName) {
// Not use the original
var regionsArr = (originRegionArr || []).slice();
var map = geoCreator.getMap(mapName);
var geoJson = map && map.geoJson;
var dataNameMap = {};
var features = geoJson.features;
for (var i = 0; i < regionsArr.length; i++) {
dataNameMap[regionsArr[i].name] = regionsArr[i];
}
for (var i = 0; i < features.length; i++) {
var name = features[i].properties.name;
if (!dataNameMap[name]) {
regionsArr.push({
name: name
});
}
}
return regionsArr;
}
};
// Inject methods into echarts
var echarts = require('../../echarts');
echarts.registerMap = geoCreator.registerMap;
echarts.getMap = geoCreator.getMap;
// TODO
echarts.loadMap = function () {};
echarts.registerCoordinateSystem('geo', geoCreator);
return geoCreator;
});

View File

@@ -0,0 +1,114 @@
/**
* Parse and decode geo json
* @module echarts/coord/geo/parseGeoJson
*/
define(function (require) {
var zrUtil = require('zrender/core/util');
var Region = require('./Region');
function decode(json) {
if (!json.UTF8Encoding) {
return json;
}
var features = json.features;
for (var f = 0; f < features.length; f++) {
var feature = features[f];
var geometry = feature.geometry;
var coordinates = geometry.coordinates;
var encodeOffsets = geometry.encodeOffsets;
for (var c = 0; c < coordinates.length; c++) {
var coordinate = coordinates[c];
if (geometry.type === 'Polygon') {
coordinates[c] = decodePolygon(
coordinate,
encodeOffsets[c]
);
}
else if (geometry.type === 'MultiPolygon') {
for (var c2 = 0; c2 < coordinate.length; c2++) {
var polygon = coordinate[c2];
coordinate[c2] = decodePolygon(
polygon,
encodeOffsets[c][c2]
);
}
}
}
}
// Has been decoded
json.UTF8Encoding = false;
return json;
}
function decodePolygon(coordinate, encodeOffsets) {
var result = [];
var prevX = encodeOffsets[0];
var prevY = encodeOffsets[1];
for (var i = 0; i < coordinate.length; i += 2) {
var x = coordinate.charCodeAt(i) - 64;
var y = coordinate.charCodeAt(i + 1) - 64;
// ZigZag decoding
x = (x >> 1) ^ (-(x & 1));
y = (y >> 1) ^ (-(y & 1));
// Delta deocding
x += prevX;
y += prevY;
prevX = x;
prevY = y;
// Dequantize
result.push([x / 1024, y / 1024]);
}
return result;
}
/**
* @inner
*/
function flattern2D(array) {
var ret = [];
for (var i = 0; i < array.length; i++) {
for (var k = 0; k < array[i].length; k++) {
ret.push(array[i][k]);
}
}
return ret;
}
/**
* @alias module:echarts/coord/geo/parseGeoJson
* @param {Object} geoJson
* @return {module:zrender/container/Group}
*/
return function (geoJson) {
decode(geoJson);
return zrUtil.map(zrUtil.filter(geoJson.features, function (featureObj) {
// Output of mapshaper may have geometry null
return featureObj.geometry && featureObj.properties;
}), function (featureObj) {
var properties = featureObj.properties;
var geometry = featureObj.geometry;
var coordinates = geometry.coordinates;
if (geometry.type === 'MultiPolygon') {
coordinates = flattern2D(coordinates);
}
return new Region(
properties.name,
coordinates,
properties.cp
);
});
};
});

View File

@@ -0,0 +1,120 @@
define(function(require) {
var ComponentModel = require('../../model/Component');
var zrUtil = require('zrender/core/util');
var makeStyleMapper = require('../../model/mixin/makeStyleMapper');
var axisModelCreator = require('../axisModelCreator');
var numberUtil = require('../../util/number');
var AxisModel = ComponentModel.extend({
type: 'baseParallelAxis',
/**
* @type {module:echarts/coord/parallel/Axis}
*/
axis: null,
/**
* @type {Array.<Array.<number>}
* @readOnly
*/
activeIntervals: [],
/**
* @return {Object}
*/
getAreaSelectStyle: function () {
return makeStyleMapper(
[
['fill', 'color'],
['lineWidth', 'borderWidth'],
['stroke', 'borderColor'],
['width', 'width'],
['opacity', 'opacity']
]
).call(this.getModel('areaSelectStyle'));
},
/**
* The code of this feature is put on AxisModel but not ParallelAxis,
* because axisModel can be alive after echarts updating but instance of
* ParallelAxis having been disposed. this._activeInterval should be kept
* when action dispatched (i.e. legend click).
*
* @param {Array.<Array<number>>} intervals interval.length === 0
* means set all active.
* @public
*/
setActiveIntervals: function (intervals) {
var activeIntervals = this.activeIntervals = zrUtil.clone(intervals);
// Normalize
if (activeIntervals) {
for (var i = activeIntervals.length - 1; i >= 0; i--) {
numberUtil.asc(activeIntervals[i]);
}
}
},
/**
* @param {number|string} [value] When attempting to detect 'no activeIntervals set',
* value can not be input.
* @return {string} 'normal': no activeIntervals set,
* 'active',
* 'inactive'.
* @public
*/
getActiveState: function (value) {
var activeIntervals = this.activeIntervals;
if (!activeIntervals.length) {
return 'normal';
}
if (value == null) {
return 'inactive';
}
for (var i = 0, len = activeIntervals.length; i < len; i++) {
if (activeIntervals[i][0] <= value && value <= activeIntervals[i][1]) {
return 'active';
}
}
return 'inactive';
}
});
var defaultOption = {
type: 'value',
/**
* @type {Array.<number>}
*/
dim: null, // 0, 1, 2, ...
parallelIndex: null,
areaSelectStyle: {
width: 20,
borderWidth: 1,
borderColor: 'rgba(160,197,232)',
color: 'rgba(160,197,232)',
opacity: 0.3
},
z: 10
};
zrUtil.merge(AxisModel.prototype, require('../axisModelCommonMixin'));
function getAxisType(axisName, option) {
return option.type || (option.data ? 'category' : 'value');
}
axisModelCreator('parallel', AxisModel, getAxisType, defaultOption);
return AxisModel;
});

View File

@@ -0,0 +1,300 @@
/**
* Parallel Coordinates
* <https://en.wikipedia.org/wiki/Parallel_coordinates>
*/
define(function(require) {
var layout = require('../../util/layout');
var axisHelper = require('../../coord/axisHelper');
var zrUtil = require('zrender/core/util');
var ParallelAxis = require('./ParallelAxis');
var matrix = require('zrender/core/matrix');
var vector = require('zrender/core/vector');
var each = zrUtil.each;
var PI = Math.PI;
function Parallel(parallelModel, ecModel, api) {
/**
* key: dimension
* @type {Object.<string, module:echarts/coord/parallel/Axis>}
* @private
*/
this._axesMap = {};
/**
* key: dimension
* value: {position: [], rotation, }
* @type {Object.<string, Object>}
* @private
*/
this._axesLayout = {};
/**
* Always follow axis order.
* @type {Array.<string>}
* @readOnly
*/
this.dimensions = parallelModel.dimensions;
/**
* @type {module:zrender/core/BoundingRect}
*/
this._rect;
/**
* @type {module:echarts/coord/parallel/ParallelModel}
*/
this._model = parallelModel;
this._init(parallelModel, ecModel, api);
}
Parallel.prototype = {
type: 'parallel',
constructor: Parallel,
/**
* Initialize cartesian coordinate systems
* @private
*/
_init: function (parallelModel, ecModel, api) {
var dimensions = parallelModel.dimensions;
var parallelAxisIndex = parallelModel.parallelAxisIndex;
each(dimensions, function (dim, idx) {
var axisIndex = parallelAxisIndex[idx];
var axisModel = ecModel.getComponent('parallelAxis', axisIndex);
var axis = this._axesMap[dim] = new ParallelAxis(
dim,
axisHelper.createScaleByModel(axisModel),
[0, 0],
axisModel.get('type'),
axisIndex
);
var isCategory = axis.type === 'category';
axis.onBand = isCategory && axisModel.get('boundaryGap');
axis.inverse = axisModel.get('inverse');
// Inject axis into axisModel
axisModel.axis = axis;
// Inject axisModel into axis
axis.model = axisModel;
}, this);
},
/**
* Update axis scale after data processed
* @param {module:echarts/model/Global} ecModel
* @param {module:echarts/ExtensionAPI} api
*/
update: function (ecModel, api) {
this._updateAxesFromSeries(this._model, ecModel);
},
/**
* Update properties from series
* @private
*/
_updateAxesFromSeries: function (parallelModel, ecModel) {
ecModel.eachSeries(function (seriesModel) {
if (!parallelModel.contains(seriesModel, ecModel)) {
return;
}
var data = seriesModel.getData();
each(this.dimensions, function (dim) {
var axis = this._axesMap[dim];
axis.scale.unionExtent(data.getDataExtent(dim));
axisHelper.niceScaleExtent(axis, axis.model);
}, this);
}, this);
},
/**
* Resize the parallel coordinate system.
* @param {module:echarts/coord/parallel/ParallelModel} parallelModel
* @param {module:echarts/ExtensionAPI} api
*/
resize: function (parallelModel, api) {
this._rect = layout.getLayoutRect(
parallelModel.getBoxLayoutParams(),
{
width: api.getWidth(),
height: api.getHeight()
}
);
this._layoutAxes(parallelModel);
},
/**
* @return {module:zrender/core/BoundingRect}
*/
getRect: function () {
return this._rect;
},
/**
* @private
*/
_layoutAxes: function (parallelModel) {
var rect = this._rect;
var layout = parallelModel.get('layout');
var axes = this._axesMap;
var dimensions = this.dimensions;
var size = [rect.width, rect.height];
var sizeIdx = layout === 'horizontal' ? 0 : 1;
var layoutLength = size[sizeIdx];
var axisLength = size[1 - sizeIdx];
var axisExtent = [0, axisLength];
each(axes, function (axis) {
var idx = axis.inverse ? 1 : 0;
axis.setExtent(axisExtent[idx], axisExtent[1 - idx]);
});
each(dimensions, function (dim, idx) {
var pos = layoutLength * idx / (dimensions.length - 1);
var positionTable = {
horizontal: {
x: pos,
y: axisLength
},
vertical: {
x: 0,
y: pos
}
};
var rotationTable = {
horizontal: PI / 2,
vertical: 0
};
var position = [
positionTable[layout].x + rect.x,
positionTable[layout].y + rect.y
];
var rotation = rotationTable[layout];
var transform = matrix.create();
matrix.rotate(transform, transform, rotation);
matrix.translate(transform, transform, position);
// TODO
// tick等排布信息。
// TODO
// 根据axis order 更新 dimensions顺序。
this._axesLayout[dim] = {
position: position,
rotation: rotation,
transform: transform,
tickDirection: 1,
labelDirection: 1
};
}, this);
},
/**
* Get axis by dim.
* @param {string} dim
* @return {module:echarts/coord/parallel/ParallelAxis} [description]
*/
getAxis: function (dim) {
return this._axesMap[dim];
},
/**
* Convert a dim value of a single item of series data to Point.
* @param {*} value
* @param {string} dim
* @return {Array}
*/
dataToPoint: function (value, dim) {
return this.axisCoordToPoint(
this._axesMap[dim].dataToCoord(value),
dim
);
},
/**
* @param {module:echarts/data/List} data
* @param {Functio} cb param: {string} activeState 'active' or 'inactive' or 'normal'
* {number} dataIndex
* @param {Object} context
*/
eachActiveState: function (data, callback, context) {
var dimensions = this.dimensions;
var axesMap = this._axesMap;
var hasActiveSet = false;
for (var j = 0, lenj = dimensions.length; j < lenj; j++) {
if (axesMap[dimensions[j]].model.getActiveState() !== 'normal') {
hasActiveSet = true;
}
}
for (var i = 0, len = data.count(); i < len; i++) {
var values = data.getValues(dimensions, i);
var activeState;
if (!hasActiveSet) {
activeState = 'normal';
}
else {
activeState = 'active';
for (var j = 0, lenj = dimensions.length; j < lenj; j++) {
var dimName = dimensions[j];
var state = axesMap[dimName].model.getActiveState(values[j], j);
if (state === 'inactive') {
activeState = 'inactive';
break;
}
}
}
callback.call(context, activeState, i);
}
},
/**
* Convert coords of each axis to Point.
* Return point. For example: [10, 20]
* @param {Array.<number>} coords
* @param {string} dim
* @return {Array.<number>}
*/
axisCoordToPoint: function (coord, dim) {
var axisLayout = this._axesLayout[dim];
var point = [coord, 0];
vector.applyTransform(point, point, axisLayout.transform);
return point;
},
/**
* Get axis layout.
*/
getAxisLayout: function (dim) {
return zrUtil.clone(this._axesLayout[dim]);
}
};
return Parallel;
});

View File

@@ -0,0 +1,50 @@
define(function (require) {
var zrUtil = require('zrender/core/util');
var Axis = require('../Axis');
/**
* @constructor module:echarts/coord/parallel/ParallelAxis
* @extends {module:echarts/coord/Axis}
* @param {string} dim
* @param {*} scale
* @param {Array.<number>} coordExtent
* @param {string} axisType
*/
var ParallelAxis = function (dim, scale, coordExtent, axisType, axisIndex) {
Axis.call(this, dim, scale, coordExtent);
/**
* Axis type
* - 'category'
* - 'value'
* - 'time'
* - 'log'
* @type {string}
*/
this.type = axisType || 'value';
/**
* @type {number}
* @readOnly
*/
this.axisIndex = axisIndex;
};
ParallelAxis.prototype = {
constructor: ParallelAxis,
/**
* Axis model
* @param {module:echarts/coord/parallel/AxisModel}
*/
model: null
};
zrUtil.inherits(ParallelAxis, Axis);
return ParallelAxis;
});

View File

@@ -0,0 +1,100 @@
define(function(require) {
var zrUtil = require('zrender/core/util');
var Component = require('../../model/Component');
require('./AxisModel');
Component.extend({
type: 'parallel',
dependencies: ['parallelAxis'],
/**
* @type {module:echarts/coord/parallel/Parallel}
*/
coordinateSystem: null,
/**
* Each item like: 'dim0', 'dim1', 'dim2', ...
* @type {Array.<string>}
* @readOnly
*/
dimensions: null,
/**
* Coresponding to dimensions.
* @type {Array.<number>}
* @readOnly
*/
parallelAxisIndex: null,
defaultOption: {
zlevel: 0, // 一级层叠
z: 0, // 二级层叠
left: 80,
top: 60,
right: 80,
bottom: 60,
// width: {totalWidth} - left - right,
// height: {totalHeight} - top - bottom,
layout: 'horizontal', // 'horizontal' or 'vertical'
parallelAxisDefault: null
},
/**
* @override
*/
init: function () {
Component.prototype.init.apply(this, arguments);
this.mergeOption({});
},
/**
* @override
*/
mergeOption: function (newOption) {
var thisOption = this.option;
newOption && zrUtil.merge(thisOption, newOption, true);
this._initDimensions();
},
/**
* Whether series or axis is in this coordinate system.
* @param {module:echarts/model/Series|module:echarts/coord/parallel/AxisModel} model
* @param {module:echarts/model/Global} ecModel
*/
contains: function (model, ecModel) {
var parallelIndex = model.get('parallelIndex');
return parallelIndex != null
&& ecModel.getComponent('parallel', parallelIndex) === this;
},
/**
* @private
*/
_initDimensions: function () {
var dimensions = this.dimensions = [];
var parallelAxisIndex = this.parallelAxisIndex = [];
var axisModels = zrUtil.filter(this.dependentModels.parallelAxis, function (axisModel) {
// Can not use this.contains here, because
// initialization has not been completed yet.
return axisModel.get('parallelIndex') === this.componentIndex;
});
zrUtil.each(axisModels, function (axisModel) {
dimensions.push('dim' + axisModel.get('dim'));
parallelAxisIndex.push(axisModel.componentIndex);
});
}
});
});

View File

@@ -0,0 +1,36 @@
/**
* Parallel coordinate system creater.
*/
define(function(require) {
var Parallel = require('./Parallel');
function create(ecModel, api) {
var coordSysList = [];
ecModel.eachComponent('parallel', function (parallelModel, idx) {
var coordSys = new Parallel(parallelModel, ecModel, api);
coordSys.name = 'parallel_' + idx;
coordSys.resize(parallelModel, api);
parallelModel.coordinateSystem = coordSys;
coordSys.model = parallelModel;
coordSysList.push(coordSys);
});
// Inject the coordinateSystems into seriesModel
ecModel.eachSeries(function (seriesModel) {
if (seriesModel.get('coordinateSystem') === 'parallel') {
var parallelIndex = seriesModel.get('parallelIndex');
seriesModel.coordinateSystem = coordSysList[parallelIndex];
}
});
return coordSysList;
}
require('../../CoordinateSystem').register('parallel', {create: create});
});

View File

@@ -0,0 +1,54 @@
define(function (require) {
var zrUtil = require('zrender/core/util');
var modelUtil = require('../../util/model');
return function (option) {
createParallelIfNeeded(option);
mergeAxisOptionFromParallel(option);
};
/**
* Create a parallel coordinate if not exists.
* @inner
*/
function createParallelIfNeeded(option) {
if (option.parallel) {
return;
}
var hasParallelSeries = false;
zrUtil.each(option.series, function (seriesOpt) {
if (seriesOpt && seriesOpt.type === 'parallel') {
hasParallelSeries = true;
}
});
if (hasParallelSeries) {
option.parallel = [{}];
}
}
/**
* Merge aixs definition from parallel option (if exists) to axis option.
* @inner
*/
function mergeAxisOptionFromParallel(option) {
var axes = modelUtil.normalizeToArray(option.parallelAxis);
zrUtil.each(axes, function (axisOption) {
if (!zrUtil.isObject(axisOption)) {
return;
}
var parallelIndex = axisOption.parallelIndex || 0;
var parallelOption = modelUtil.normalizeToArray(option.parallel)[parallelIndex];
if (parallelOption && parallelOption.parallelAxisDefault) {
zrUtil.merge(axisOption, parallelOption.parallelAxisDefault, false);
}
});
}
});

View File

@@ -0,0 +1,36 @@
define(function(require) {
'use strict';
var zrUtil = require('zrender/core/util');
var Axis = require('../Axis');
function AngleAxis(scale, angleExtent) {
angleExtent = angleExtent || [0, 360];
Axis.call(this, 'angle', scale, angleExtent);
/**
* Axis type
* - 'category'
* - 'value'
* - 'time'
* - 'log'
* @type {string}
*/
this.type = 'category';
}
AngleAxis.prototype = {
constructor: AngleAxis,
dataToAngle: Axis.prototype.dataToCoord,
angleToData: Axis.prototype.coordToData
};
zrUtil.inherits(AngleAxis, Axis);
return AngleAxis;
});

View File

@@ -0,0 +1,48 @@
define(function(require) {
'use strict';
var zrUtil = require('zrender/core/util');
var ComponentModel = require('../../model/Component');
var axisModelCreator = require('../axisModelCreator');
var PolarAxisModel = ComponentModel.extend({
type: 'polarAxis',
/**
* @type {module:echarts/coord/polar/AngleAxis|module:echarts/coord/polar/RadiusAxis}
*/
axis: null
});
zrUtil.merge(PolarAxisModel.prototype, require('../axisModelCommonMixin'));
var polarAxisDefaultExtendedOption = {
angle: {
polarIndex: 0,
startAngle: 90,
clockwise: true,
splitNumber: 12,
axisLabel: {
rotate: false
}
},
radius: {
polarIndex: 0,
splitNumber: 5
}
};
function getAxisType(axisDim, option) {
// Default axis with data is category axis
return option.type || (option.data ? 'category' : 'value');
}
axisModelCreator('angle', PolarAxisModel, getAxisType, polarAxisDefaultExtendedOption.angle);
axisModelCreator('radius', PolarAxisModel, getAxisType, polarAxisDefaultExtendedOption.radius);
});

229
vendors/echarts/src/coord/polar/Polar.js vendored Normal file
View File

@@ -0,0 +1,229 @@
/**
* @module echarts/coord/polar/Polar
*/
define(function(require) {
'use strict';
var RadiusAxis = require('./RadiusAxis');
var AngleAxis = require('./AngleAxis');
/**
* @alias {module:echarts/coord/polar/Polar}
* @constructor
* @param {string} name
*/
var Polar = function (name) {
/**
* @type {string}
*/
this.name = name || '';
/**
* x of polar center
* @type {number}
*/
this.cx = 0;
/**
* y of polar center
* @type {number}
*/
this.cy = 0;
/**
* @type {module:echarts/coord/polar/RadiusAxis}
* @private
*/
this._radiusAxis = new RadiusAxis();
/**
* @type {module:echarts/coord/polar/AngleAxis}
* @private
*/
this._angleAxis = new AngleAxis();
};
Polar.prototype = {
constructor: Polar,
type: 'polar',
/**
* @param {Array.<string>}
* @readOnly
*/
dimensions: ['radius', 'angle'],
/**
* If contain coord
* @param {Array.<number>} point
* @return {boolean}
*/
containPoint: function (point) {
var coord = this.pointToCoord(point);
return this._radiusAxis.contain(coord[0])
&& this._angleAxis.contain(coord[1]);
},
/**
* If contain data
* @param {Array.<number>} data
* @return {boolean}
*/
containData: function (data) {
return this._radiusAxis.containData(data[0])
&& this._angleAxis.containData(data[1]);
},
/**
* @param {string} axisType
* @return {module:echarts/coord/polar/AngleAxis|module:echarts/coord/polar/RadiusAxis}
*/
getAxis: function (axisType) {
return this['_' + axisType + 'Axis'];
},
/**
* Get axes by type of scale
* @param {string} scaleType
* @return {module:echarts/coord/polar/AngleAxis|module:echarts/coord/polar/RadiusAxis}
*/
getAxesByScale: function (scaleType) {
var axes = [];
var angleAxis = this._angleAxis;
var radiusAxis = this._radiusAxis;
angleAxis.scale.type === scaleType && axes.push(angleAxis);
radiusAxis.scale.type === scaleType && axes.push(radiusAxis);
return axes;
},
/**
* @return {module:echarts/coord/polar/AngleAxis}
*/
getAngleAxis: function () {
return this._angleAxis;
},
/**
* @return {module:echarts/coord/polar/RadiusAxis}
*/
getRadiusAxis: function () {
return this._radiusAxis;
},
/**
* @param {module:echarts/coord/polar/Axis}
* @return {module:echarts/coord/polar/Axis}
*/
getOtherAxis: function (axis) {
var angleAxis = this._angleAxis;
return axis === angleAxis ? this._radiusAxis : angleAxis;
},
/**
* Base axis will be used on stacking.
*
* @return {module:echarts/coord/polar/Axis}
*/
getBaseAxis: function () {
return this.getAxesByScale('ordinal')[0]
|| this.getAxesByScale('time')[0]
|| this.getAngleAxis();
},
/**
* Convert series data to a list of (x, y) points
* @param {module:echarts/data/List} data
* @return {Array}
* Return list of coordinates. For example:
* `[[10, 10], [20, 20], [30, 30]]`
*/
dataToPoints: function (data) {
return data.mapArray(this.dimensions, function (radius, angle) {
return this.dataToPoint([radius, angle]);
}, this);
},
/**
* Convert a single data item to (x, y) point.
* Parameter data is an array which the first element is radius and the second is angle
* @param {Array.<number>} data
* @param {boolean} [clamp=false]
* @return {Array.<number>}
*/
dataToPoint: function (data, clamp) {
return this.coordToPoint([
this._radiusAxis.dataToRadius(data[0], clamp),
this._angleAxis.dataToAngle(data[1], clamp)
]);
},
/**
* Convert a (x, y) point to data
* @param {Array.<number>} point
* @param {boolean} [clamp=false]
* @return {Array.<number>}
*/
pointToData: function (point, clamp) {
var coord = this.pointToCoord(point);
return [
this._radiusAxis.radiusToData(coord[0], clamp),
this._angleAxis.angleToData(coord[1], clamp)
];
},
/**
* Convert a (x, y) point to (radius, angle) coord
* @param {Array.<number>} point
* @return {Array.<number>}
*/
pointToCoord: function (point) {
var dx = point[0] - this.cx;
var dy = point[1] - this.cy;
var angleAxis = this.getAngleAxis();
var extent = angleAxis.getExtent();
var minAngle = Math.min(extent[0], extent[1]);
var maxAngle = Math.max(extent[0], extent[1]);
// Fix fixed extent in polarCreator
// FIXME
angleAxis.inverse
? (minAngle = maxAngle - 360)
: (maxAngle = minAngle + 360);
var radius = Math.sqrt(dx * dx + dy * dy);
dx /= radius;
dy /= radius;
var radian = Math.atan2(-dy, dx) / Math.PI * 180;
// move to angleExtent
var dir = radian < minAngle ? 1 : -1;
while (radian < minAngle || radian > maxAngle) {
radian += dir * 360;
}
return [radius, radian];
},
/**
* Convert a (radius, angle) coord to (x, y) point
* @param {Array.<number>} coord
* @return {Array.<number>}
*/
coordToPoint: function (coord) {
var radius = coord[0];
var radian = coord[1] / 180 * Math.PI;
var x = Math.cos(radian) * radius + this.cx;
// Inverse the y
var y = -Math.sin(radian) * radius + this.cy;
return [x, y];
}
};
return Polar;
});

View File

@@ -0,0 +1,46 @@
define(function (require) {
'use strict';
require('./AxisModel');
require('../../echarts').extendComponentModel({
type: 'polar',
dependencies: ['polarAxis', 'angleAxis'],
/**
* @type {module:echarts/coord/polar/Polar}
*/
coordinateSystem: null,
/**
* @param {string} axisType
* @return {module:echarts/coord/polar/AxisModel}
*/
findAxisModel: function (axisType) {
var angleAxisModel;
var ecModel = this.ecModel;
ecModel.eachComponent(axisType, function (axisModel) {
if (ecModel.getComponent(
'polar', axisModel.getShallow('polarIndex')
) === this) {
angleAxisModel = axisModel;
}
}, this);
return angleAxisModel;
},
defaultOption: {
zlevel: 0,
z: 0,
center: ['50%', '50%'],
radius: '80%'
}
});
});

View File

@@ -0,0 +1,34 @@
define(function (require) {
'use strict';
var zrUtil = require('zrender/core/util');
var Axis = require('../Axis');
function RadiusAxis(scale, radiusExtent) {
Axis.call(this, 'radius', scale, radiusExtent);
/**
* Axis type
* - 'category'
* - 'value'
* - 'time'
* - 'log'
* @type {string}
*/
this.type = 'category';
}
RadiusAxis.prototype = {
constructor: RadiusAxis,
dataToRadius: Axis.prototype.dataToCoord,
radiusToData: Axis.prototype.coordToData
};
zrUtil.inherits(RadiusAxis, Axis);
return RadiusAxis;
});

View File

@@ -0,0 +1,131 @@
// TODO Axis scale
define(function (require) {
var Polar = require('./Polar');
var numberUtil = require('../../util/number');
var axisHelper = require('../../coord/axisHelper');
var niceScaleExtent = axisHelper.niceScaleExtent;
// 依赖 PolarModel 做预处理
require('./PolarModel');
/**
* Resize method bound to the polar
* @param {module:echarts/coord/polar/PolarModel} polarModel
* @param {module:echarts/ExtensionAPI} api
*/
function resizePolar(polarModel, api) {
var center = polarModel.get('center');
var radius = polarModel.get('radius');
var width = api.getWidth();
var height = api.getHeight();
var parsePercent = numberUtil.parsePercent;
this.cx = parsePercent(center[0], width);
this.cy = parsePercent(center[1], height);
var radiusAxis = this.getRadiusAxis();
var size = Math.min(width, height) / 2;
// var idx = radiusAxis.inverse ? 1 : 0;
radiusAxis.setExtent(0, parsePercent(radius, size));
}
/**
* Update polar
*/
function updatePolarScale(ecModel, api) {
var polar = this;
var angleAxis = polar.getAngleAxis();
var radiusAxis = polar.getRadiusAxis();
// Reset scale
angleAxis.scale.setExtent(Infinity, -Infinity);
radiusAxis.scale.setExtent(Infinity, -Infinity);
ecModel.eachSeries(function (seriesModel) {
if (seriesModel.coordinateSystem === polar) {
var data = seriesModel.getData();
radiusAxis.scale.unionExtent(
data.getDataExtent('radius', radiusAxis.type !== 'category')
);
angleAxis.scale.unionExtent(
data.getDataExtent('angle', angleAxis.type !== 'category')
);
}
});
niceScaleExtent(angleAxis, angleAxis.model);
niceScaleExtent(radiusAxis, radiusAxis.model);
// Fix extent of category angle axis
if (angleAxis.type === 'category' && !angleAxis.onBand) {
var extent = angleAxis.getExtent();
var diff = 360 / angleAxis.scale.count();
angleAxis.inverse ? (extent[1] += diff) : (extent[1] -= diff);
angleAxis.setExtent(extent[0], extent[1]);
}
}
/**
* Set common axis properties
* @param {module:echarts/coord/polar/AngleAxis|module:echarts/coord/polar/RadiusAxis}
* @param {module:echarts/coord/polar/AxisModel}
* @inner
*/
function setAxis(axis, axisModel) {
axis.type = axisModel.get('type');
axis.scale = axisHelper.createScaleByModel(axisModel);
axis.onBand = axisModel.get('boundaryGap') && axis.type === 'category';
// FIXME Radius axis not support inverse axis
if (axisModel.mainType === 'angleAxis') {
var startAngle = axisModel.get('startAngle');
axis.inverse = axisModel.get('inverse') ^ axisModel.get('clockwise');
axis.setExtent(startAngle, startAngle + (axis.inverse ? -360 : 360));
}
// Inject axis instance
axisModel.axis = axis;
axis.model = axisModel;
}
var polarCreator = {
dimensions: Polar.prototype.dimensions,
create: function (ecModel, api) {
var polarList = [];
ecModel.eachComponent('polar', function (polarModel, idx) {
var polar = new Polar(idx);
// Inject resize and update method
polar.resize = resizePolar;
polar.update = updatePolarScale;
var radiusAxis = polar.getRadiusAxis();
var angleAxis = polar.getAngleAxis();
var radiusAxisModel = polarModel.findAxisModel('radiusAxis');
var angleAxisModel = polarModel.findAxisModel('angleAxis');
setAxis(radiusAxis, radiusAxisModel);
setAxis(angleAxis, angleAxisModel);
polar.resize(polarModel, api);
polarList.push(polar);
polarModel.coordinateSystem = polar;
});
// Inject coordinateSystem to series
ecModel.eachSeries(function (seriesModel) {
if (seriesModel.get('coordinateSystem') === 'polar') {
seriesModel.coordinateSystem = polarList[seriesModel.get('polarIndex')];
}
});
return polarList;
}
};
require('../../CoordinateSystem').register('polar', polarCreator);
});

View File

@@ -0,0 +1,35 @@
define(function (require) {
var zrUtil = require('zrender/core/util');
var Axis = require('../Axis');
function IndicatorAxis(dim, scale, radiusExtent) {
Axis.call(this, dim, scale, radiusExtent);
/**
* Axis type
* - 'category'
* - 'value'
* - 'time'
* - 'log'
* @type {string}
*/
this.type = 'value';
this.angle = 0;
/**
* Indicator name
* @type {string}
*/
this.name = '';
/**
* @type {module:echarts/model/Model}
*/
this.model;
}
zrUtil.inherits(IndicatorAxis, Axis);
return IndicatorAxis;
});

234
vendors/echarts/src/coord/radar/Radar.js vendored Normal file
View File

@@ -0,0 +1,234 @@
// TODO clockwise
define(function (require) {
var zrUtil = require('zrender/core/util');
var IndicatorAxis = require('./IndicatorAxis');
var IntervalScale = require('../../scale/Interval');
var numberUtil = require('../../util/number');
var axisHelper = require('../axisHelper');
function Radar(radarModel, ecModel, api) {
this._model = radarModel;
/**
* Radar dimensions
* @type {Array.<string>}
*/
this.dimensions = [];
this._indicatorAxes = zrUtil.map(radarModel.getIndicatorModels(), function (indicatorModel, idx) {
var dim = 'indicator_' + idx;
var indicatorAxis = new IndicatorAxis(dim, new IntervalScale());
indicatorAxis.name = indicatorModel.get('name');
// Inject model and axis
indicatorAxis.model = indicatorModel;
indicatorModel.axis = indicatorAxis;
this.dimensions.push(dim);
return indicatorAxis;
}, this);
this.resize(radarModel, api);
/**
* @type {number}
* @readOnly
*/
this.cx;
/**
* @type {number}
* @readOnly
*/
this.cy;
/**
* @type {number}
* @readOnly
*/
this.r;
/**
* @type {number}
* @readOnly
*/
this.startAngle;
}
Radar.prototype.getIndicatorAxes = function () {
return this._indicatorAxes;
};
Radar.prototype.dataToPoint = function (value, indicatorIndex) {
var indicatorAxis = this._indicatorAxes[indicatorIndex];
return this.coordToPoint(indicatorAxis.dataToCoord(value), indicatorIndex);
};
Radar.prototype.coordToPoint = function (coord, indicatorIndex) {
var indicatorAxis = this._indicatorAxes[indicatorIndex];
var angle = indicatorAxis.angle;
var x = this.cx + coord * Math.cos(angle);
var y = this.cy - coord * Math.sin(angle);
return [x, y];
};
Radar.prototype.pointToData = function (pt) {
var dx = pt[0] - this.cx;
var dy = pt[1] - this.cy;
var radius = Math.sqrt(dx * dx + dy * dy);
dx /= radius;
dy /= radius;
var radian = Math.atan2(-dy, dx);
// Find the closest angle
// FIXME index can calculated directly
var minRadianDiff = Infinity;
var closestAxis;
var closestAxisIdx = -1;
for (var i = 0; i < this._indicatorAxes.length; i++) {
var indicatorAxis = this._indicatorAxes[i];
var diff = Math.abs(radian - indicatorAxis.angle);
if (diff < minRadianDiff) {
closestAxis = indicatorAxis;
closestAxisIdx = i;
minRadianDiff = diff;
}
}
return [closestAxisIdx, +(closestAxis && closestAxis.coodToData(radius))];
};
Radar.prototype.resize = function (radarModel, api) {
var center = radarModel.get('center');
var viewWidth = api.getWidth();
var viewHeight = api.getHeight();
var viewSize = Math.min(viewWidth, viewHeight) / 2;
this.cx = numberUtil.parsePercent(center[0], viewWidth);
this.cy = numberUtil.parsePercent(center[1], viewHeight);
this.startAngle = radarModel.get('startAngle') * Math.PI / 180;
this.r = numberUtil.parsePercent(radarModel.get('radius'), viewSize);
zrUtil.each(this._indicatorAxes, function (indicatorAxis, idx) {
indicatorAxis.setExtent(0, this.r);
var angle = (this.startAngle + idx * Math.PI * 2 / this._indicatorAxes.length);
// Normalize to [-PI, PI]
angle = Math.atan2(Math.sin(angle), Math.cos(angle));
indicatorAxis.angle = angle;
}, this);
};
Radar.prototype.update = function (ecModel, api) {
var indicatorAxes = this._indicatorAxes;
var radarModel = this._model;
zrUtil.each(indicatorAxes, function (indicatorAxis) {
indicatorAxis.scale.setExtent(Infinity, -Infinity);
});
ecModel.eachSeriesByType('radar', function (radarSeries, idx) {
if (radarSeries.get('coordinateSystem') !== 'radar'
|| ecModel.getComponent('radar', radarSeries.get('radarIndex')) !== radarModel
) {
return;
}
var data = radarSeries.getData();
zrUtil.each(indicatorAxes, function (indicatorAxis) {
indicatorAxis.scale.unionExtent(data.getDataExtent(indicatorAxis.dim));
});
}, this);
var splitNumber = radarModel.get('splitNumber');
function increaseInterval(interval) {
var exp10 = Math.pow(10, Math.floor(Math.log(interval) / Math.LN10));
// Increase interval
var f = interval / exp10;
if (f === 2) {
f = 5;
}
else { // f is 2 or 5
f *= 2;
}
return f * exp10;
}
// Force all the axis fixing the maxSplitNumber.
zrUtil.each(indicatorAxes, function (indicatorAxis, idx) {
var rawExtent = axisHelper.getScaleExtent(indicatorAxis, indicatorAxis.model);
axisHelper.niceScaleExtent(indicatorAxis, indicatorAxis.model);
var axisModel = indicatorAxis.model;
var scale = indicatorAxis.scale;
var fixedMin = axisModel.get('min');
var fixedMax = axisModel.get('max');
var interval = scale.getInterval();
if (fixedMin != null && fixedMax != null) {
// User set min, max, divide to get new interval
// FIXME precision
scale.setInterval(
(fixedMax - fixedMin) / splitNumber
);
}
else if (fixedMin != null) {
var max;
// User set min, expand extent on the other side
do {
max = fixedMin + interval * splitNumber;
scale.setExtent(+fixedMin, max);
// Interval must been set after extent
// FIXME
scale.setInterval(interval);
interval = increaseInterval(interval);
} while (max < rawExtent[1] && isFinite(max) && isFinite(rawExtent[1]));
}
else if (fixedMax != null) {
var min;
// User set min, expand extent on the other side
do {
min = fixedMax - interval * splitNumber;
scale.setExtent(min, +fixedMax);
scale.setInterval(interval);
interval = increaseInterval(interval);
} while (min > rawExtent[0] && isFinite(min) && isFinite(rawExtent[0]));
}
else {
var nicedSplitNumber = scale.getTicks().length - 1;
if (nicedSplitNumber > splitNumber) {
interval = increaseInterval(interval);
}
// PENDING
var center = Math.round((rawExtent[0] + rawExtent[1]) / 2 / interval) * interval;
var halfSplitNumber = Math.round(splitNumber / 2);
scale.setExtent(
numberUtil.round(center - halfSplitNumber * interval),
numberUtil.round(center + (splitNumber - halfSplitNumber) * interval)
);
scale.setInterval(interval);
}
});
};
/**
* Radar dimensions is based on the data
* @type {Array}
*/
Radar.dimensions = [];
Radar.create = function (ecModel, api) {
var radarList = [];
ecModel.eachComponent('radar', function (radarModel) {
var radar = new Radar(radarModel, ecModel, api);
radarList.push(radar);
radarModel.coordinateSystem = radar;
});
ecModel.eachSeriesByType('radar', function (radarSeries) {
if (radarSeries.get('coordinateSystem') === 'radar') {
// Inject coordinate system
radarSeries.coordinateSystem = radarList[radarSeries.get('radarIndex') || 0];
}
});
return radarList;
};
require('../../CoordinateSystem').register('radar', Radar);
return Radar;
});

View File

@@ -0,0 +1,124 @@
define(function (require) {
var axisDefault = require('../axisDefault');
var valueAxisDefault = axisDefault.valueAxis;
var Model = require('../../model/Model');
var zrUtil = require('zrender/core/util');
var axisModelCommonMixin = require('../axisModelCommonMixin');
function defaultsShow(opt, show) {
return zrUtil.defaults({
show: show
}, opt);
}
var RadarModel = require('../../echarts').extendComponentModel({
type: 'radar',
optionUpdated: function () {
var boundaryGap = this.get('boundaryGap');
var splitNumber = this.get('splitNumber');
var scale = this.get('scale');
var axisLine = this.get('axisLine');
var axisTick = this.get('axisTick');
var axisLabel = this.get('axisLabel');
var nameTextStyle = this.get('name.textStyle');
var showName = this.get('name.show');
var nameFormatter = this.get('name.formatter');
var nameGap = this.get('nameGap');
var indicatorModels = zrUtil.map(this.get('indicator') || [], function (indicatorOpt) {
// PENDING
if (indicatorOpt.max != null && indicatorOpt.max > 0) {
indicatorOpt.min = 0;
}
else if (indicatorOpt.min != null && indicatorOpt.min < 0) {
indicatorOpt.max = 0;
}
// Use same configuration
indicatorOpt = zrUtil.merge(zrUtil.clone(indicatorOpt), {
boundaryGap: boundaryGap,
splitNumber: splitNumber,
scale: scale,
axisLine: axisLine,
axisTick: axisTick,
axisLabel: axisLabel,
// Competitable with 2 and use text
name: indicatorOpt.text,
nameLocation: 'end',
nameGap: nameGap,
// min: 0,
nameTextStyle: nameTextStyle
}, false);
if (!showName) {
indicatorOpt.name = '';
}
if (typeof nameFormatter === 'string') {
indicatorOpt.name = nameFormatter.replace('{value}', indicatorOpt.name);
}
else if (typeof nameFormatter === 'function') {
indicatorOpt.name = nameFormatter(
indicatorOpt.name, indicatorOpt
);
}
return zrUtil.extend(
new Model(indicatorOpt, null, this.ecModel),
axisModelCommonMixin
);
}, this);
this.getIndicatorModels = function () {
return indicatorModels;
};
},
defaultOption: {
zlevel: 0,
z: 0,
center: ['50%', '50%'],
radius: '75%',
startAngle: 90,
name: {
show: true
// formatter: null
// textStyle: {}
},
boundaryGap: [0, 0],
splitNumber: 5,
nameGap: 15,
scale: false,
// Polygon or circle
shape: 'polygon',
axisLine: zrUtil.merge(
{
lineStyle: {
color: '#bbb'
}
},
valueAxisDefault.axisLine
),
axisLabel: defaultsShow(valueAxisDefault.axisLabel, false),
axisTick: defaultsShow(valueAxisDefault.axisTick, false),
splitLine: defaultsShow(valueAxisDefault.splitLine, true),
splitArea: defaultsShow(valueAxisDefault.splitArea, true),
// {text, min, max}
indicator: []
}
});
return RadarModel;
});

View File

@@ -0,0 +1,78 @@
define(function (require) {
var ComponentModel = require('../../model/Component');
var axisModelCreator = require('../axisModelCreator');
var zrUtil = require('zrender/core/util');
var AxisModel = ComponentModel.extend({
type: 'singleAxis',
layoutMode: 'box',
/**
* @type {module:echarts/coord/single/SingleAxis}
*/
axis: null,
/**
* @type {module:echarts/coord/single/Single}
*/
coordinateSystem: null
});
var defaultOption = {
left: '5%',
top: '5%',
right: '5%',
bottom: '5%',
type: 'value',
position: 'bottom',
orient: 'horizontal',
// singleIndex: 0,
axisLine: {
show: true,
lineStyle: {
width: 2,
type: 'solid'
}
},
axisTick: {
show: true,
length: 6,
lineStyle: {
width: 2
}
},
axisLabel: {
show: true,
interval: 'auto'
},
splitLine: {
show: true,
lineStyle: {
type: 'dashed',
opacity: 0.2
}
}
};
function getAxisType(axisName, option) {
return option.type || (option.data ? 'category' : 'value');
}
zrUtil.merge(AxisModel.prototype, require('../axisModelCommonMixin'));
axisModelCreator('single', AxisModel, getAxisType, defaultOption);
return AxisModel;
});

View File

@@ -0,0 +1,266 @@
/**
* Single coordinates system.
*/
define(function (require) {
var SingleAxis = require('./SingleAxis');
var axisHelper = require('../axisHelper');
var layout = require('../../util/layout');
/**
* Create a single coordinates system.
*
* @param {module:echarts/coord/single/AxisModel} axisModel
* @param {module:echarts/model/Global} ecModel
* @param {module:echarts/ExtensionAPI} api
*/
function Single(axisModel, ecModel, api) {
/**
* @type {string}
* @readOnly
*/
this.dimension = 'oneDim';
/**
* Add it just for draw tooltip.
*
* @type {Array.<string>}
* @readOnly
*/
this.dimensions = ['oneDim'];
/**
* @private
* @type {module:echarts/coord/single/SingleAxis}.
*/
this._axis = null;
/**
* @private
* @type {module:zrender/core/BoundingRect}
*/
this._rect;
this._init(axisModel, ecModel, api);
/**
* @type {module:echarts/coord/single/AxisModel}
*/
this._model = axisModel;
}
Single.prototype = {
type: 'single',
constructor: Single,
/**
* Initialize single coordinate system.
*
* @param {module:echarts/coord/single/AxisModel} axisModel
* @param {module:echarts/model/Global} ecModel
* @param {module:echarts/ExtensionAPI} api
* @private
*/
_init: function (axisModel, ecModel, api) {
var dim = this.dimension;
var axis = new SingleAxis(
dim,
axisHelper.createScaleByModel(axisModel),
[0, 0],
axisModel.get('type'),
axisModel.get('position')
);
var isCategory = axis.type === 'category';
axis.onBand = isCategory && axisModel.get('boundaryGap');
axis.inverse = axisModel.get('inverse');
axis.orient = axisModel.get('orient');
axisModel.axis = axis;
axis.model = axisModel;
this._axis = axis;
},
/**
* Update axis scale after data processed
* @param {module:echarts/model/Global} ecModel
* @param {module:echarts/ExtensionAPI} api
*/
update: function (ecModel, api) {
this._updateAxisFromSeries(ecModel);
},
/**
* Update the axis extent from series.
*
* @param {module:echarts/model/Global} ecModel
* @private
*/
_updateAxisFromSeries: function (ecModel) {
ecModel.eachSeries(function (seriesModel) {
var data = seriesModel.getData();
var dim = this.dimension;
this._axis.scale.unionExtent(
data.getDataExtent(seriesModel.coordDimToDataDim(dim))
);
axisHelper.niceScaleExtent(this._axis, this._axis.model);
}, this);
},
/**
* Resize the single coordinate system.
*
* @param {module:echarts/coord/single/AxisModel} axisModel
* @param {module:echarts/ExtensionAPI} api
*/
resize: function (axisModel, api) {
this._rect = layout.getLayoutRect(
{
left: axisModel.get('left'),
top: axisModel.get('top'),
right: axisModel.get('right'),
bottom: axisModel.get('bottom'),
width: axisModel.get('width'),
height: axisModel.get('height')
},
{
width: api.getWidth(),
height: api.getHeight()
}
);
this._adjustAxis();
},
/**
* @return {module:zrender/core/BoundingRect}
*/
getRect: function () {
return this._rect;
},
/**
* @private
*/
_adjustAxis: function () {
var rect = this._rect;
var axis = this._axis;
var isHorizontal = axis.isHorizontal();
var extent = isHorizontal ? [0, rect.width] : [0, rect.height];
var idx = axis.reverse ? 1 : 0;
axis.setExtent(extent[idx], extent[1 - idx]);
this._updateAxisTransform(axis, isHorizontal ? rect.x : rect.y);
},
/**
* @param {module:echarts/coord/single/SingleAxis} axis
* @param {number} coordBase
*/
_updateAxisTransform: function (axis, coordBase) {
var axisExtent = axis.getExtent();
var extentSum = axisExtent[0] + axisExtent[1];
var isHorizontal = axis.isHorizontal();
axis.toGlobalCoord = isHorizontal ?
function (coord) {
return coord + coordBase;
} :
function (coord) {
return extentSum - coord + coordBase;
};
axis.toLocalCoord = isHorizontal ?
function (coord) {
return coord - coordBase;
} :
function (coord) {
return extentSum - coord + coordBase;
};
},
/**
* Get axis.
*
* @return {module:echarts/coord/single/SingleAxis}
*/
getAxis: function () {
return this._axis;
},
/**
* Get axis, add it just for draw tooltip.
*
* @return {[type]} [description]
*/
getBaseAxis: function () {
return this._axis;
},
/**
* If contain point.
*
* @param {Array.<number>} point
* @return {boolean}
*/
containPoint: function (point) {
var rect = this.getRect();
var axis = this.getAxis();
var orient = axis.orient;
if (orient === 'horizontal') {
return axis.contain(axis.toLocalCoord(point[0]))
&& (point[1] >= rect.y && point[1] <= (rect.y + rect.height));
}
else {
return axis.contain(axis.toLocalCoord(point[1]))
&& (point[0] >= rect.y && point[0] <= (rect.y + rect.height));
}
},
/**
* @param {Array.<number>} point
*/
pointToData: function (point) {
var axis = this.getAxis();
var orient = axis.orient;
if (orient === 'horizontal') {
return [
axis.coordToData(axis.toLocalCoord(point[0])),
point[1]
];
}
else {
return [
axis.coordToData(axis.toLocalCoord(point[1])),
point[0]
];
}
},
/**
* Convert the series data to concrete point.
*
* @param {*} value
* @return {number}
*/
dataToPoint: function (point) {
var axis = this.getAxis();
return [axis.toGlobalCoord(axis.dataToCoord(point[0])), point[1]];
}
};
return Single;
});

View File

@@ -0,0 +1,121 @@
define(function (require) {
var zrUtil = require('zrender/core/util');
var Axis = require('../Axis');
var axisHelper = require('../axisHelper');
/**
* @constructor module:echarts/coord/single/SingleAxis
* @extends {module:echarts/coord/Axis}
* @param {string} dim
* @param {*} scale
* @param {Array.<number>} coordExtent
* @param {string} axisType
* @param {string} position
*/
var SingleAxis = function (dim, scale, coordExtent, axisType, position) {
Axis.call(this, dim, scale, coordExtent);
/**
* Axis type
* - 'category'
* - 'value'
* - 'time'
* - 'log'
* @type {string}
*/
this.type = axisType || 'value';
/**
* Axis position
* - 'top'
* - 'bottom'
* - 'left'
* - 'right'
* @type {string}
*/
this.position = position || 'bottom';
/**
* Axis orient
* - 'horizontal'
* - 'vertical'
* @type {[type]}
*/
this.orient = null;
/**
* @type {number}
*/
this._labelInterval = null;
};
SingleAxis.prototype = {
constructor: SingleAxis,
/**
* Axis model
* @type {module:echarts/coord/single/AxisModel}
*/
model: null,
/**
* Judge the orient of the axis.
* @return {boolean}
*/
isHorizontal: function () {
var position = this.position;
return position === 'top' || position === 'bottom';
},
/**
* Get interval of the axis label.
* @return {number}
*/
getLabelInterval: function () {
var labelInterval = this._labelInterval;
if (!labelInterval) {
var axisModel = this.model;
var labelModel = axisModel.getModel('axisLabel');
var interval = labelModel.get('interval');
if (!(this.type === 'category' && interval === 'auto')) {
labelInterval = this._labelInterval = interval === 'auto' ? 0 : interval;
return labelInterval;
}
labelInterval = this._labelInterval =
axisHelper.getAxisLabelInterval(
zrUtil.map(this.scale.getTicks(), this.dataToCoord, this),
axisModel.getFormattedLabels(),
labelModel.getModel('textStyle').getFont(),
this.isHorizontal()
);
}
return labelInterval;
},
/**
* Convert the local coord(processed by dataToCoord())
* to global coord(concrete pixel coord).
* designated by module:echarts/coord/single/Single.
* @type {Function}
*/
toGlobalCoord: null,
/**
* Convert the global coord to local coord.
* designated by module:echarts/coord/single/Single.
* @type {Function}
*/
toLocalCoord: null
};
zrUtil.inherits(SingleAxis, Axis);
return SingleAxis;
});

View File

@@ -0,0 +1,41 @@
/**
* Single coordinate system creator.
*/
define(function (require) {
var Single = require('./Single');
/**
* Create single coordinate system and inject it into seriesModel.
*
* @param {module:echarts/model/Global} ecModel
* @param {module:echarts/ExtensionAPI} api
* @return {Array.<module:echarts/coord/single/Single>}
*/
function create(ecModel, api) {
var singles = [];
ecModel.eachComponent('singleAxis', function(axisModel, idx) {
var single = new Single(axisModel, ecModel, api);
single.name = 'single_' + idx;
single.resize(axisModel, api);
axisModel.coordinateSystem = single;
singles.push(single);
});
ecModel.eachSeries(function (seriesModel) {
if (seriesModel.get('coordinateSystem') === 'single') {
var singleAxisIndex = seriesModel.get('singleAxisIndex');
var axisModel = ecModel.getComponent('singleAxis', singleAxisIndex);
seriesModel.coordinateSystem = axisModel.coordinateSystem;
}
});
return singles;
}
require('../../CoordinateSystem').register('single', {create: create});
});