mirror of
https://gitlab.com/JKANetwork/CheckServer.git
synced 2026-03-28 13:22:01 +01:00
Start again
This commit is contained in:
7
vendors/echarts/src/component/angleAxis.js
vendored
Normal file
7
vendors/echarts/src/component/angleAxis.js
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
define(function(require) {
|
||||
'use strict';
|
||||
|
||||
require('../coord/polar/polarCreator');
|
||||
|
||||
require('./axis/AngleAxisView');
|
||||
});
|
||||
8
vendors/echarts/src/component/axis.js
vendored
Normal file
8
vendors/echarts/src/component/axis.js
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
// TODO boundaryGap
|
||||
define(function(require) {
|
||||
'use strict';
|
||||
|
||||
require('../coord/cartesian/AxisModel');
|
||||
|
||||
require('./axis/AxisView');
|
||||
});
|
||||
224
vendors/echarts/src/component/axis/AngleAxisView.js
vendored
Normal file
224
vendors/echarts/src/component/axis/AngleAxisView.js
vendored
Normal file
@@ -0,0 +1,224 @@
|
||||
define(function (require) {
|
||||
'use strict';
|
||||
|
||||
var zrUtil = require('zrender/core/util');
|
||||
var graphic = require('../../util/graphic');
|
||||
var Model = require('../../model/Model');
|
||||
|
||||
var elementList = ['axisLine', 'axisLabel', 'axisTick', 'splitLine', 'splitArea'];
|
||||
|
||||
function getAxisLineShape(polar, r0, r, angle) {
|
||||
var start = polar.coordToPoint([r0, angle]);
|
||||
var end = polar.coordToPoint([r, angle]);
|
||||
|
||||
return {
|
||||
x1: start[0],
|
||||
y1: start[1],
|
||||
x2: end[0],
|
||||
y2: end[1]
|
||||
};
|
||||
}
|
||||
require('../../echarts').extendComponentView({
|
||||
|
||||
type: 'angleAxis',
|
||||
|
||||
render: function (angleAxisModel, ecModel) {
|
||||
this.group.removeAll();
|
||||
if (!angleAxisModel.get('show')) {
|
||||
return;
|
||||
}
|
||||
|
||||
var polarModel = ecModel.getComponent('polar', angleAxisModel.get('polarIndex'));
|
||||
var angleAxis = angleAxisModel.axis;
|
||||
var polar = polarModel.coordinateSystem;
|
||||
var radiusExtent = polar.getRadiusAxis().getExtent();
|
||||
var ticksAngles = angleAxis.getTicksCoords();
|
||||
|
||||
if (angleAxis.type !== 'category') {
|
||||
// Remove the last tick which will overlap the first tick
|
||||
ticksAngles.pop();
|
||||
}
|
||||
|
||||
zrUtil.each(elementList, function (name) {
|
||||
if (angleAxisModel.get(name +'.show')) {
|
||||
this['_' + name](angleAxisModel, polar, ticksAngles, radiusExtent);
|
||||
}
|
||||
}, this);
|
||||
},
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
_axisLine: function (angleAxisModel, polar, ticksAngles, radiusExtent) {
|
||||
var lineStyleModel = angleAxisModel.getModel('axisLine.lineStyle');
|
||||
|
||||
var circle = new graphic.Circle({
|
||||
shape: {
|
||||
cx: polar.cx,
|
||||
cy: polar.cy,
|
||||
r: radiusExtent[1]
|
||||
},
|
||||
style: lineStyleModel.getLineStyle(),
|
||||
z2: 1,
|
||||
silent: true
|
||||
});
|
||||
circle.style.fill = null;
|
||||
|
||||
this.group.add(circle);
|
||||
},
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
_axisTick: function (angleAxisModel, polar, ticksAngles, radiusExtent) {
|
||||
var tickModel = angleAxisModel.getModel('axisTick');
|
||||
|
||||
var tickLen = (tickModel.get('inside') ? -1 : 1) * tickModel.get('length');
|
||||
|
||||
var lines = zrUtil.map(ticksAngles, function (tickAngle) {
|
||||
return new graphic.Line({
|
||||
shape: getAxisLineShape(polar, radiusExtent[1], radiusExtent[1] + tickLen, tickAngle)
|
||||
});
|
||||
});
|
||||
this.group.add(graphic.mergePath(
|
||||
lines, {
|
||||
style: tickModel.getModel('lineStyle').getLineStyle()
|
||||
}
|
||||
));
|
||||
},
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
_axisLabel: function (angleAxisModel, polar, ticksAngles, radiusExtent) {
|
||||
var axis = angleAxisModel.axis;
|
||||
|
||||
var categoryData = angleAxisModel.get('data');
|
||||
|
||||
var labelModel = angleAxisModel.getModel('axisLabel');
|
||||
var axisTextStyleModel = labelModel.getModel('textStyle');
|
||||
|
||||
var labels = angleAxisModel.getFormattedLabels();
|
||||
|
||||
var labelMargin = labelModel.get('margin');
|
||||
var labelsAngles = axis.getLabelsCoords();
|
||||
|
||||
// Use length of ticksAngles because it may remove the last tick to avoid overlapping
|
||||
for (var i = 0; i < ticksAngles.length; i++) {
|
||||
var r = radiusExtent[1];
|
||||
var p = polar.coordToPoint([r + labelMargin, labelsAngles[i]]);
|
||||
var cx = polar.cx;
|
||||
var cy = polar.cy;
|
||||
|
||||
var labelTextAlign = Math.abs(p[0] - cx) / r < 0.3
|
||||
? 'center' : (p[0] > cx ? 'left' : 'right');
|
||||
var labelTextBaseline = Math.abs(p[1] - cy) / r < 0.3
|
||||
? 'middle' : (p[1] > cy ? 'top' : 'bottom');
|
||||
|
||||
var textStyleModel = axisTextStyleModel;
|
||||
if (categoryData && categoryData[i] && categoryData[i].textStyle) {
|
||||
textStyleModel = new Model(
|
||||
categoryData[i].textStyle, axisTextStyleModel
|
||||
);
|
||||
}
|
||||
this.group.add(new graphic.Text({
|
||||
style: {
|
||||
x: p[0],
|
||||
y: p[1],
|
||||
fill: textStyleModel.getTextColor(),
|
||||
text: labels[i],
|
||||
textAlign: labelTextAlign,
|
||||
textVerticalAlign: labelTextBaseline,
|
||||
textFont: textStyleModel.getFont()
|
||||
},
|
||||
silent: true
|
||||
}));
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
_splitLine: function (angleAxisModel, polar, ticksAngles, radiusExtent) {
|
||||
var splitLineModel = angleAxisModel.getModel('splitLine');
|
||||
var lineStyleModel = splitLineModel.getModel('lineStyle');
|
||||
var lineColors = lineStyleModel.get('color');
|
||||
var lineCount = 0;
|
||||
|
||||
lineColors = lineColors instanceof Array ? lineColors : [lineColors];
|
||||
|
||||
var splitLines = [];
|
||||
|
||||
for (var i = 0; i < ticksAngles.length; i++) {
|
||||
var colorIndex = (lineCount++) % lineColors.length;
|
||||
splitLines[colorIndex] = splitLines[colorIndex] || [];
|
||||
splitLines[colorIndex].push(new graphic.Line({
|
||||
shape: getAxisLineShape(polar, radiusExtent[0], radiusExtent[1], ticksAngles[i])
|
||||
}));
|
||||
}
|
||||
|
||||
// Simple optimization
|
||||
// Batching the lines if color are the same
|
||||
for (var i = 0; i < splitLines.length; i++) {
|
||||
this.group.add(graphic.mergePath(splitLines[i], {
|
||||
style: zrUtil.defaults({
|
||||
stroke: lineColors[i % lineColors.length]
|
||||
}, lineStyleModel.getLineStyle()),
|
||||
silent: true,
|
||||
z: angleAxisModel.get('z')
|
||||
}));
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
_splitArea: function (angleAxisModel, polar, ticksAngles, radiusExtent) {
|
||||
|
||||
var splitAreaModel = angleAxisModel.getModel('splitArea');
|
||||
var areaStyleModel = splitAreaModel.getModel('areaStyle');
|
||||
var areaColors = areaStyleModel.get('color');
|
||||
var lineCount = 0;
|
||||
|
||||
areaColors = areaColors instanceof Array ? areaColors : [areaColors];
|
||||
|
||||
var splitAreas = [];
|
||||
|
||||
var RADIAN = Math.PI / 180;
|
||||
var prevAngle = -ticksAngles[0] * RADIAN;
|
||||
var r0 = Math.min(radiusExtent[0], radiusExtent[1]);
|
||||
var r1 = Math.max(radiusExtent[0], radiusExtent[1]);
|
||||
|
||||
var clockwise = angleAxisModel.get('clockwise');
|
||||
|
||||
for (var i = 1; i < ticksAngles.length; i++) {
|
||||
var colorIndex = (lineCount++) % areaColors.length;
|
||||
splitAreas[colorIndex] = splitAreas[colorIndex] || [];
|
||||
splitAreas[colorIndex].push(new graphic.Sector({
|
||||
shape: {
|
||||
cx: polar.cx,
|
||||
cy: polar.cy,
|
||||
r0: r0,
|
||||
r: r1,
|
||||
startAngle: prevAngle,
|
||||
endAngle: -ticksAngles[i] * RADIAN,
|
||||
clockwise: clockwise
|
||||
},
|
||||
silent: true
|
||||
}));
|
||||
prevAngle = -ticksAngles[i] * RADIAN;
|
||||
}
|
||||
|
||||
// Simple optimization
|
||||
// Batching the lines if color are the same
|
||||
for (var i = 0; i < splitAreas.length; i++) {
|
||||
this.group.add(graphic.mergePath(splitAreas[i], {
|
||||
style: zrUtil.defaults({
|
||||
fill: areaColors[i % areaColors.length]
|
||||
}, areaStyleModel.getAreaStyle()),
|
||||
silent: true
|
||||
}));
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
463
vendors/echarts/src/component/axis/AxisBuilder.js
vendored
Normal file
463
vendors/echarts/src/component/axis/AxisBuilder.js
vendored
Normal file
@@ -0,0 +1,463 @@
|
||||
define(function (require) {
|
||||
|
||||
var zrUtil = require('zrender/core/util');
|
||||
var graphic = require('../../util/graphic');
|
||||
var Model = require('../../model/Model');
|
||||
var numberUtil = require('../../util/number');
|
||||
var remRadian = numberUtil.remRadian;
|
||||
var isRadianAroundZero = numberUtil.isRadianAroundZero;
|
||||
|
||||
var PI = Math.PI;
|
||||
|
||||
function makeAxisEventDataBase(axisModel) {
|
||||
var eventData = {
|
||||
componentType: axisModel.mainType
|
||||
};
|
||||
eventData[axisModel.mainType + 'Index'] = axisModel.componentIndex;
|
||||
return eventData;
|
||||
}
|
||||
|
||||
/**
|
||||
* A final axis is translated and rotated from a "standard axis".
|
||||
* So opt.position and opt.rotation is required.
|
||||
*
|
||||
* A standard axis is and axis from [0, 0] to [0, axisExtent[1]],
|
||||
* for example: (0, 0) ------------> (0, 50)
|
||||
*
|
||||
* nameDirection or tickDirection or labelDirection is 1 means tick
|
||||
* or label is below the standard axis, whereas is -1 means above
|
||||
* the standard axis. labelOffset means offset between label and axis,
|
||||
* which is useful when 'onZero', where axisLabel is in the grid and
|
||||
* label in outside grid.
|
||||
*
|
||||
* Tips: like always,
|
||||
* positive rotation represents anticlockwise, and negative rotation
|
||||
* represents clockwise.
|
||||
* The direction of position coordinate is the same as the direction
|
||||
* of screen coordinate.
|
||||
*
|
||||
* Do not need to consider axis 'inverse', which is auto processed by
|
||||
* axis extent.
|
||||
*
|
||||
* @param {module:zrender/container/Group} group
|
||||
* @param {Object} axisModel
|
||||
* @param {Object} opt Standard axis parameters.
|
||||
* @param {Array.<number>} opt.position [x, y]
|
||||
* @param {number} opt.rotation by radian
|
||||
* @param {number} [opt.nameDirection=1] 1 or -1 Used when nameLocation is 'middle'.
|
||||
* @param {number} [opt.tickDirection=1] 1 or -1
|
||||
* @param {number} [opt.labelDirection=1] 1 or -1
|
||||
* @param {number} [opt.labelOffset=0] Usefull when onZero.
|
||||
* @param {string} [opt.axisName] default get from axisModel.
|
||||
* @param {number} [opt.labelRotation] by degree, default get from axisModel.
|
||||
* @param {number} [opt.labelInterval] Default label interval when label
|
||||
* interval from model is null or 'auto'.
|
||||
* @param {number} [opt.strokeContainThreshold] Default label interval when label
|
||||
* @param {number} [opt.axisLineSilent=true] If axis line is silent
|
||||
*/
|
||||
var AxisBuilder = function (axisModel, opt) {
|
||||
|
||||
/**
|
||||
* @readOnly
|
||||
*/
|
||||
this.opt = opt;
|
||||
|
||||
/**
|
||||
* @readOnly
|
||||
*/
|
||||
this.axisModel = axisModel;
|
||||
|
||||
// Default value
|
||||
zrUtil.defaults(
|
||||
opt,
|
||||
{
|
||||
labelOffset: 0,
|
||||
nameDirection: 1,
|
||||
tickDirection: 1,
|
||||
labelDirection: 1,
|
||||
silent: true
|
||||
}
|
||||
);
|
||||
|
||||
/**
|
||||
* @readOnly
|
||||
*/
|
||||
this.group = new graphic.Group({
|
||||
position: opt.position.slice(),
|
||||
rotation: opt.rotation
|
||||
});
|
||||
};
|
||||
|
||||
AxisBuilder.prototype = {
|
||||
|
||||
constructor: AxisBuilder,
|
||||
|
||||
hasBuilder: function (name) {
|
||||
return !!builders[name];
|
||||
},
|
||||
|
||||
add: function (name) {
|
||||
builders[name].call(this);
|
||||
},
|
||||
|
||||
getGroup: function () {
|
||||
return this.group;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
var builders = {
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
axisLine: function () {
|
||||
var opt = this.opt;
|
||||
var axisModel = this.axisModel;
|
||||
|
||||
if (!axisModel.get('axisLine.show')) {
|
||||
return;
|
||||
}
|
||||
|
||||
var extent = this.axisModel.axis.getExtent();
|
||||
|
||||
this.group.add(new graphic.Line({
|
||||
shape: {
|
||||
x1: extent[0],
|
||||
y1: 0,
|
||||
x2: extent[1],
|
||||
y2: 0
|
||||
},
|
||||
style: zrUtil.extend(
|
||||
{lineCap: 'round'},
|
||||
axisModel.getModel('axisLine.lineStyle').getLineStyle()
|
||||
),
|
||||
strokeContainThreshold: opt.strokeContainThreshold,
|
||||
silent: !!opt.axisLineSilent,
|
||||
z2: 1
|
||||
}));
|
||||
},
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
axisTick: function () {
|
||||
var axisModel = this.axisModel;
|
||||
|
||||
if (!axisModel.get('axisTick.show')) {
|
||||
return;
|
||||
}
|
||||
|
||||
var axis = axisModel.axis;
|
||||
var tickModel = axisModel.getModel('axisTick');
|
||||
var opt = this.opt;
|
||||
|
||||
var lineStyleModel = tickModel.getModel('lineStyle');
|
||||
var tickLen = tickModel.get('length');
|
||||
var tickInterval = getInterval(tickModel, opt.labelInterval);
|
||||
var ticksCoords = axis.getTicksCoords();
|
||||
var tickLines = [];
|
||||
|
||||
for (var i = 0; i < ticksCoords.length; i++) {
|
||||
// Only ordinal scale support tick interval
|
||||
if (ifIgnoreOnTick(axis, i, tickInterval)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
var tickCoord = ticksCoords[i];
|
||||
|
||||
// Tick line
|
||||
tickLines.push(new graphic.Line(graphic.subPixelOptimizeLine({
|
||||
shape: {
|
||||
x1: tickCoord,
|
||||
y1: 0,
|
||||
x2: tickCoord,
|
||||
y2: opt.tickDirection * tickLen
|
||||
},
|
||||
style: {
|
||||
lineWidth: lineStyleModel.get('width')
|
||||
},
|
||||
silent: true
|
||||
})));
|
||||
}
|
||||
|
||||
this.group.add(graphic.mergePath(tickLines, {
|
||||
style: lineStyleModel.getLineStyle(),
|
||||
z2: 2,
|
||||
silent: true
|
||||
}));
|
||||
},
|
||||
|
||||
/**
|
||||
* @param {module:echarts/coord/cartesian/AxisModel} axisModel
|
||||
* @param {module:echarts/coord/cartesian/GridModel} gridModel
|
||||
* @private
|
||||
*/
|
||||
axisLabel: function () {
|
||||
var axisModel = this.axisModel;
|
||||
|
||||
if (!axisModel.get('axisLabel.show')) {
|
||||
return;
|
||||
}
|
||||
|
||||
var opt = this.opt;
|
||||
var axis = axisModel.axis;
|
||||
var labelModel = axisModel.getModel('axisLabel');
|
||||
var textStyleModel = labelModel.getModel('textStyle');
|
||||
var labelMargin = labelModel.get('margin');
|
||||
var ticks = axis.scale.getTicks();
|
||||
var labels = axisModel.getFormattedLabels();
|
||||
|
||||
// Special label rotate.
|
||||
var labelRotation = opt.labelRotation;
|
||||
if (labelRotation == null) {
|
||||
labelRotation = labelModel.get('rotate') || 0;
|
||||
}
|
||||
// To radian.
|
||||
labelRotation = labelRotation * PI / 180;
|
||||
|
||||
var labelLayout = innerTextLayout(opt, labelRotation, opt.labelDirection);
|
||||
var categoryData = axisModel.get('data');
|
||||
|
||||
var textEls = [];
|
||||
var isSilent = axisModel.get('silent');
|
||||
for (var i = 0; i < ticks.length; i++) {
|
||||
if (ifIgnoreOnTick(axis, i, opt.labelInterval)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
var itemTextStyleModel = textStyleModel;
|
||||
if (categoryData && categoryData[i] && categoryData[i].textStyle) {
|
||||
itemTextStyleModel = new Model(
|
||||
categoryData[i].textStyle, textStyleModel, axisModel.ecModel
|
||||
);
|
||||
}
|
||||
var textColor = itemTextStyleModel.getTextColor();
|
||||
|
||||
var tickCoord = axis.dataToCoord(ticks[i]);
|
||||
var pos = [
|
||||
tickCoord,
|
||||
opt.labelOffset + opt.labelDirection * labelMargin
|
||||
];
|
||||
var labelBeforeFormat = axis.scale.getLabel(ticks[i]);
|
||||
|
||||
var textEl = new graphic.Text({
|
||||
style: {
|
||||
text: labels[i],
|
||||
textAlign: itemTextStyleModel.get('align', true) || labelLayout.textAlign,
|
||||
textVerticalAlign: itemTextStyleModel.get('baseline', true) || labelLayout.verticalAlign,
|
||||
textFont: itemTextStyleModel.getFont(),
|
||||
fill: typeof textColor === 'function' ? textColor(labelBeforeFormat) : textColor
|
||||
},
|
||||
position: pos,
|
||||
rotation: labelLayout.rotation,
|
||||
silent: isSilent,
|
||||
z2: 10
|
||||
});
|
||||
// Pack data for mouse event
|
||||
textEl.eventData = makeAxisEventDataBase(axisModel);
|
||||
textEl.eventData.targetType = 'axisLabel';
|
||||
textEl.eventData.value = labelBeforeFormat;
|
||||
|
||||
textEls.push(textEl);
|
||||
this.group.add(textEl);
|
||||
}
|
||||
|
||||
function isTwoLabelOverlapped(current, next) {
|
||||
var firstRect = current && current.getBoundingRect().clone();
|
||||
var nextRect = next && next.getBoundingRect().clone();
|
||||
if (firstRect && nextRect) {
|
||||
firstRect.applyTransform(current.getLocalTransform());
|
||||
nextRect.applyTransform(next.getLocalTransform());
|
||||
return firstRect.intersect(nextRect);
|
||||
}
|
||||
}
|
||||
if (axis.type !== 'category') {
|
||||
// If min or max are user set, we need to check
|
||||
// If the tick on min(max) are overlap on their neighbour tick
|
||||
// If they are overlapped, we need to hide the min(max) tick label
|
||||
if (axisModel.getMin ? axisModel.getMin() : axisModel.get('min')) {
|
||||
var firstLabel = textEls[0];
|
||||
var nextLabel = textEls[1];
|
||||
if (isTwoLabelOverlapped(firstLabel, nextLabel)) {
|
||||
firstLabel.ignore = true;
|
||||
}
|
||||
}
|
||||
if (axisModel.getMax ? axisModel.getMax() : axisModel.get('max')) {
|
||||
var lastLabel = textEls[textEls.length - 1];
|
||||
var prevLabel = textEls[textEls.length - 2];
|
||||
if (isTwoLabelOverlapped(prevLabel, lastLabel)) {
|
||||
lastLabel.ignore = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
axisName: function () {
|
||||
var opt = this.opt;
|
||||
var axisModel = this.axisModel;
|
||||
|
||||
var name = this.opt.axisName;
|
||||
// If name is '', do not get name from axisMode.
|
||||
if (name == null) {
|
||||
name = axisModel.get('name');
|
||||
}
|
||||
|
||||
if (!name) {
|
||||
return;
|
||||
}
|
||||
|
||||
var nameLocation = axisModel.get('nameLocation');
|
||||
var nameDirection = opt.nameDirection;
|
||||
var textStyleModel = axisModel.getModel('nameTextStyle');
|
||||
var gap = axisModel.get('nameGap') || 0;
|
||||
|
||||
var extent = this.axisModel.axis.getExtent();
|
||||
var gapSignal = extent[0] > extent[1] ? -1 : 1;
|
||||
var pos = [
|
||||
nameLocation === 'start'
|
||||
? extent[0] - gapSignal * gap
|
||||
: nameLocation === 'end'
|
||||
? extent[1] + gapSignal * gap
|
||||
: (extent[0] + extent[1]) / 2, // 'middle'
|
||||
// Reuse labelOffset.
|
||||
nameLocation === 'middle' ? opt.labelOffset + nameDirection * gap : 0
|
||||
];
|
||||
|
||||
var labelLayout;
|
||||
|
||||
if (nameLocation === 'middle') {
|
||||
labelLayout = innerTextLayout(opt, opt.rotation, nameDirection);
|
||||
}
|
||||
else {
|
||||
labelLayout = endTextLayout(opt, nameLocation, extent);
|
||||
}
|
||||
|
||||
var textEl = new graphic.Text({
|
||||
style: {
|
||||
text: name,
|
||||
textFont: textStyleModel.getFont(),
|
||||
fill: textStyleModel.getTextColor()
|
||||
|| axisModel.get('axisLine.lineStyle.color'),
|
||||
textAlign: labelLayout.textAlign,
|
||||
textVerticalAlign: labelLayout.verticalAlign
|
||||
},
|
||||
position: pos,
|
||||
rotation: labelLayout.rotation,
|
||||
silent: axisModel.get('silent'),
|
||||
z2: 1
|
||||
});
|
||||
|
||||
textEl.eventData = makeAxisEventDataBase(axisModel);
|
||||
textEl.eventData.targetType = 'axisName';
|
||||
textEl.eventData.name = name;
|
||||
|
||||
this.group.add(textEl);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* @inner
|
||||
*/
|
||||
function innerTextLayout(opt, textRotation, direction) {
|
||||
var rotationDiff = remRadian(textRotation - opt.rotation);
|
||||
var textAlign;
|
||||
var verticalAlign;
|
||||
|
||||
if (isRadianAroundZero(rotationDiff)) { // Label is parallel with axis line.
|
||||
verticalAlign = direction > 0 ? 'top' : 'bottom';
|
||||
textAlign = 'center';
|
||||
}
|
||||
else if (isRadianAroundZero(rotationDiff - PI)) { // Label is inverse parallel with axis line.
|
||||
verticalAlign = direction > 0 ? 'bottom' : 'top';
|
||||
textAlign = 'center';
|
||||
}
|
||||
else {
|
||||
verticalAlign = 'middle';
|
||||
|
||||
if (rotationDiff > 0 && rotationDiff < PI) {
|
||||
textAlign = direction > 0 ? 'right' : 'left';
|
||||
}
|
||||
else {
|
||||
textAlign = direction > 0 ? 'left' : 'right';
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
rotation: rotationDiff,
|
||||
textAlign: textAlign,
|
||||
verticalAlign: verticalAlign
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @inner
|
||||
*/
|
||||
function endTextLayout(opt, textPosition, extent) {
|
||||
var rotationDiff = remRadian(-opt.rotation);
|
||||
var textAlign;
|
||||
var verticalAlign;
|
||||
var inverse = extent[0] > extent[1];
|
||||
var onLeft = (textPosition === 'start' && !inverse)
|
||||
|| (textPosition !== 'start' && inverse);
|
||||
|
||||
if (isRadianAroundZero(rotationDiff - PI / 2)) {
|
||||
verticalAlign = onLeft ? 'bottom' : 'top';
|
||||
textAlign = 'center';
|
||||
}
|
||||
else if (isRadianAroundZero(rotationDiff - PI * 1.5)) {
|
||||
verticalAlign = onLeft ? 'top' : 'bottom';
|
||||
textAlign = 'center';
|
||||
}
|
||||
else {
|
||||
verticalAlign = 'middle';
|
||||
if (rotationDiff < PI * 1.5 && rotationDiff > PI / 2) {
|
||||
textAlign = onLeft ? 'left' : 'right';
|
||||
}
|
||||
else {
|
||||
textAlign = onLeft ? 'right' : 'left';
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
rotation: rotationDiff,
|
||||
textAlign: textAlign,
|
||||
verticalAlign: verticalAlign
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @static
|
||||
*/
|
||||
var ifIgnoreOnTick = AxisBuilder.ifIgnoreOnTick = function (axis, i, interval) {
|
||||
var rawTick;
|
||||
var scale = axis.scale;
|
||||
return scale.type === 'ordinal'
|
||||
&& (
|
||||
typeof interval === 'function'
|
||||
? (
|
||||
rawTick = scale.getTicks()[i],
|
||||
!interval(rawTick, scale.getLabel(rawTick))
|
||||
)
|
||||
: i % (interval + 1)
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* @static
|
||||
*/
|
||||
var getInterval = AxisBuilder.getInterval = function (model, labelInterval) {
|
||||
var interval = model.get('interval');
|
||||
if (interval == null || interval == 'auto') {
|
||||
interval = labelInterval;
|
||||
}
|
||||
return interval;
|
||||
};
|
||||
|
||||
return AxisBuilder;
|
||||
|
||||
});
|
||||
274
vendors/echarts/src/component/axis/AxisView.js
vendored
Normal file
274
vendors/echarts/src/component/axis/AxisView.js
vendored
Normal file
@@ -0,0 +1,274 @@
|
||||
define(function (require) {
|
||||
|
||||
var zrUtil = require('zrender/core/util');
|
||||
var graphic = require('../../util/graphic');
|
||||
var AxisBuilder = require('./AxisBuilder');
|
||||
var ifIgnoreOnTick = AxisBuilder.ifIgnoreOnTick;
|
||||
var getInterval = AxisBuilder.getInterval;
|
||||
|
||||
var axisBuilderAttrs = [
|
||||
'axisLine', 'axisLabel', 'axisTick', 'axisName'
|
||||
];
|
||||
var selfBuilderAttrs = [
|
||||
'splitLine', 'splitArea'
|
||||
];
|
||||
|
||||
var AxisView = require('../../echarts').extendComponentView({
|
||||
|
||||
type: 'axis',
|
||||
|
||||
render: function (axisModel, ecModel) {
|
||||
|
||||
this.group.removeAll();
|
||||
|
||||
if (!axisModel.get('show')) {
|
||||
return;
|
||||
}
|
||||
|
||||
var gridModel = ecModel.getComponent('grid', axisModel.get('gridIndex'));
|
||||
|
||||
var layout = layoutAxis(gridModel, axisModel);
|
||||
|
||||
var axisBuilder = new AxisBuilder(axisModel, layout);
|
||||
|
||||
zrUtil.each(axisBuilderAttrs, axisBuilder.add, axisBuilder);
|
||||
|
||||
this.group.add(axisBuilder.getGroup());
|
||||
|
||||
zrUtil.each(selfBuilderAttrs, function (name) {
|
||||
if (axisModel.get(name +'.show')) {
|
||||
this['_' + name](axisModel, gridModel, layout.labelInterval);
|
||||
}
|
||||
}, this);
|
||||
},
|
||||
|
||||
/**
|
||||
* @param {module:echarts/coord/cartesian/AxisModel} axisModel
|
||||
* @param {module:echarts/coord/cartesian/GridModel} gridModel
|
||||
* @param {number|Function} labelInterval
|
||||
* @private
|
||||
*/
|
||||
_splitLine: function (axisModel, gridModel, labelInterval) {
|
||||
var axis = axisModel.axis;
|
||||
|
||||
var splitLineModel = axisModel.getModel('splitLine');
|
||||
var lineStyleModel = splitLineModel.getModel('lineStyle');
|
||||
var lineWidth = lineStyleModel.get('width');
|
||||
var lineColors = lineStyleModel.get('color');
|
||||
|
||||
var lineInterval = getInterval(splitLineModel, labelInterval);
|
||||
|
||||
lineColors = zrUtil.isArray(lineColors) ? lineColors : [lineColors];
|
||||
|
||||
var gridRect = gridModel.coordinateSystem.getRect();
|
||||
var isHorizontal = axis.isHorizontal();
|
||||
|
||||
var splitLines = [];
|
||||
var lineCount = 0;
|
||||
|
||||
var ticksCoords = axis.getTicksCoords();
|
||||
|
||||
var p1 = [];
|
||||
var p2 = [];
|
||||
for (var i = 0; i < ticksCoords.length; i++) {
|
||||
if (ifIgnoreOnTick(axis, i, lineInterval)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
var tickCoord = axis.toGlobalCoord(ticksCoords[i]);
|
||||
|
||||
if (isHorizontal) {
|
||||
p1[0] = tickCoord;
|
||||
p1[1] = gridRect.y;
|
||||
p2[0] = tickCoord;
|
||||
p2[1] = gridRect.y + gridRect.height;
|
||||
}
|
||||
else {
|
||||
p1[0] = gridRect.x;
|
||||
p1[1] = tickCoord;
|
||||
p2[0] = gridRect.x + gridRect.width;
|
||||
p2[1] = tickCoord;
|
||||
}
|
||||
|
||||
var colorIndex = (lineCount++) % lineColors.length;
|
||||
splitLines[colorIndex] = splitLines[colorIndex] || [];
|
||||
splitLines[colorIndex].push(new graphic.Line(graphic.subPixelOptimizeLine({
|
||||
shape: {
|
||||
x1: p1[0],
|
||||
y1: p1[1],
|
||||
x2: p2[0],
|
||||
y2: p2[1]
|
||||
},
|
||||
style: {
|
||||
lineWidth: lineWidth
|
||||
},
|
||||
silent: true
|
||||
})));
|
||||
}
|
||||
|
||||
// Simple optimization
|
||||
// Batching the lines if color are the same
|
||||
var lineStyle = lineStyleModel.getLineStyle();
|
||||
for (var i = 0; i < splitLines.length; i++) {
|
||||
this.group.add(graphic.mergePath(splitLines[i], {
|
||||
style: zrUtil.defaults({
|
||||
stroke: lineColors[i % lineColors.length]
|
||||
}, lineStyle),
|
||||
silent: true
|
||||
}));
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* @param {module:echarts/coord/cartesian/AxisModel} axisModel
|
||||
* @param {module:echarts/coord/cartesian/GridModel} gridModel
|
||||
* @param {number|Function} labelInterval
|
||||
* @private
|
||||
*/
|
||||
_splitArea: function (axisModel, gridModel, labelInterval) {
|
||||
var axis = axisModel.axis;
|
||||
|
||||
var splitAreaModel = axisModel.getModel('splitArea');
|
||||
var areaStyleModel = splitAreaModel.getModel('areaStyle');
|
||||
var areaColors = areaStyleModel.get('color');
|
||||
|
||||
var gridRect = gridModel.coordinateSystem.getRect();
|
||||
var ticksCoords = axis.getTicksCoords();
|
||||
|
||||
var prevX = axis.toGlobalCoord(ticksCoords[0]);
|
||||
var prevY = axis.toGlobalCoord(ticksCoords[0]);
|
||||
|
||||
var splitAreaRects = [];
|
||||
var count = 0;
|
||||
|
||||
var areaInterval = getInterval(splitAreaModel, labelInterval);
|
||||
|
||||
areaColors = zrUtil.isArray(areaColors) ? areaColors : [areaColors];
|
||||
|
||||
for (var i = 1; i < ticksCoords.length; i++) {
|
||||
if (ifIgnoreOnTick(axis, i, areaInterval)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
var tickCoord = axis.toGlobalCoord(ticksCoords[i]);
|
||||
|
||||
var x;
|
||||
var y;
|
||||
var width;
|
||||
var height;
|
||||
if (axis.isHorizontal()) {
|
||||
x = prevX;
|
||||
y = gridRect.y;
|
||||
width = tickCoord - x;
|
||||
height = gridRect.height;
|
||||
}
|
||||
else {
|
||||
x = gridRect.x;
|
||||
y = prevY;
|
||||
width = gridRect.width;
|
||||
height = tickCoord - y;
|
||||
}
|
||||
|
||||
var colorIndex = (count++) % areaColors.length;
|
||||
splitAreaRects[colorIndex] = splitAreaRects[colorIndex] || [];
|
||||
splitAreaRects[colorIndex].push(new graphic.Rect({
|
||||
shape: {
|
||||
x: x,
|
||||
y: y,
|
||||
width: width,
|
||||
height: height
|
||||
},
|
||||
silent: true
|
||||
}));
|
||||
|
||||
prevX = x + width;
|
||||
prevY = y + height;
|
||||
}
|
||||
|
||||
// Simple optimization
|
||||
// Batching the rects if color are the same
|
||||
var areaStyle = areaStyleModel.getAreaStyle();
|
||||
for (var i = 0; i < splitAreaRects.length; i++) {
|
||||
this.group.add(graphic.mergePath(splitAreaRects[i], {
|
||||
style: zrUtil.defaults({
|
||||
fill: areaColors[i % areaColors.length]
|
||||
}, areaStyle),
|
||||
silent: true
|
||||
}));
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
AxisView.extend({
|
||||
type: 'xAxis'
|
||||
});
|
||||
AxisView.extend({
|
||||
type: 'yAxis'
|
||||
});
|
||||
|
||||
/**
|
||||
* @inner
|
||||
*/
|
||||
function layoutAxis(gridModel, axisModel) {
|
||||
var grid = gridModel.coordinateSystem;
|
||||
var axis = axisModel.axis;
|
||||
var layout = {};
|
||||
|
||||
var rawAxisPosition = axis.position;
|
||||
var axisPosition = axis.onZero ? 'onZero' : rawAxisPosition;
|
||||
var axisDim = axis.dim;
|
||||
|
||||
// [left, right, top, bottom]
|
||||
var rect = grid.getRect();
|
||||
var rectBound = [rect.x, rect.x + rect.width, rect.y, rect.y + rect.height];
|
||||
|
||||
var posMap = {
|
||||
x: {top: rectBound[2], bottom: rectBound[3]},
|
||||
y: {left: rectBound[0], right: rectBound[1]}
|
||||
};
|
||||
posMap.x.onZero = Math.max(Math.min(getZero('y'), posMap.x.bottom), posMap.x.top);
|
||||
posMap.y.onZero = Math.max(Math.min(getZero('x'), posMap.y.right), posMap.y.left);
|
||||
|
||||
function getZero(dim, val) {
|
||||
var theAxis = grid.getAxis(dim);
|
||||
return theAxis.toGlobalCoord(theAxis.dataToCoord(0));
|
||||
}
|
||||
|
||||
// Axis position
|
||||
layout.position = [
|
||||
axisDim === 'y' ? posMap.y[axisPosition] : rectBound[0],
|
||||
axisDim === 'x' ? posMap.x[axisPosition] : rectBound[3]
|
||||
];
|
||||
|
||||
// Axis rotation
|
||||
var r = {x: 0, y: 1};
|
||||
layout.rotation = Math.PI / 2 * r[axisDim];
|
||||
|
||||
// Tick and label direction, x y is axisDim
|
||||
var dirMap = {top: -1, bottom: 1, left: -1, right: 1};
|
||||
|
||||
layout.labelDirection = layout.tickDirection = layout.nameDirection = dirMap[rawAxisPosition];
|
||||
if (axis.onZero) {
|
||||
layout.labelOffset = posMap[axisDim][rawAxisPosition] - posMap[axisDim].onZero;
|
||||
}
|
||||
|
||||
if (axisModel.getModel('axisTick').get('inside')) {
|
||||
layout.tickDirection = -layout.tickDirection;
|
||||
}
|
||||
if (axisModel.getModel('axisLabel').get('inside')) {
|
||||
layout.labelDirection = -layout.labelDirection;
|
||||
}
|
||||
|
||||
// Special label rotation
|
||||
var labelRotation = axisModel.getModel('axisLabel').get('rotate');
|
||||
layout.labelRotation = axisPosition === 'top' ? -labelRotation : labelRotation;
|
||||
|
||||
// label interval when auto mode.
|
||||
layout.labelInterval = axis.getLabelInterval();
|
||||
|
||||
// Over splitLine and splitArea
|
||||
layout.z2 = 1;
|
||||
|
||||
return layout;
|
||||
}
|
||||
});
|
||||
137
vendors/echarts/src/component/axis/ParallelAxisView.js
vendored
Normal file
137
vendors/echarts/src/component/axis/ParallelAxisView.js
vendored
Normal file
@@ -0,0 +1,137 @@
|
||||
define(function (require) {
|
||||
|
||||
var zrUtil = require('zrender/core/util');
|
||||
var AxisBuilder = require('./AxisBuilder');
|
||||
var SelectController = require('../helper/SelectController');
|
||||
|
||||
var elementList = ['axisLine', 'axisLabel', 'axisTick', 'axisName'];
|
||||
|
||||
var AxisView = require('../../echarts').extendComponentView({
|
||||
|
||||
type: 'parallelAxis',
|
||||
|
||||
/**
|
||||
* @type {module:echarts/component/helper/SelectController}
|
||||
*/
|
||||
_selectController: null,
|
||||
|
||||
/**
|
||||
* @override
|
||||
*/
|
||||
render: function (axisModel, ecModel, api, payload) {
|
||||
if (fromAxisAreaSelect(axisModel, ecModel, payload)) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.axisModel = axisModel;
|
||||
this.api = api;
|
||||
|
||||
this.group.removeAll();
|
||||
|
||||
if (!axisModel.get('show')) {
|
||||
return;
|
||||
}
|
||||
|
||||
var coordSys = ecModel.getComponent(
|
||||
'parallel', axisModel.get('parallelIndex')
|
||||
).coordinateSystem;
|
||||
|
||||
var areaSelectStyle = axisModel.getAreaSelectStyle();
|
||||
var areaWidth = areaSelectStyle.width;
|
||||
|
||||
var axisLayout = coordSys.getAxisLayout(axisModel.axis.dim);
|
||||
var builderOpt = zrUtil.extend(
|
||||
{
|
||||
strokeContainThreshold: areaWidth,
|
||||
// lineWidth === 0 or no value.
|
||||
axisLineSilent: !(areaWidth > 0) // jshint ignore:line
|
||||
},
|
||||
axisLayout
|
||||
);
|
||||
|
||||
var axisBuilder = new AxisBuilder(axisModel, builderOpt);
|
||||
|
||||
zrUtil.each(elementList, axisBuilder.add, axisBuilder);
|
||||
|
||||
var axisGroup = axisBuilder.getGroup();
|
||||
|
||||
this.group.add(axisGroup);
|
||||
|
||||
this._buildSelectController(
|
||||
axisGroup, areaSelectStyle, axisModel, api
|
||||
);
|
||||
},
|
||||
|
||||
_buildSelectController: function (axisGroup, areaSelectStyle, axisModel, api) {
|
||||
|
||||
var axis = axisModel.axis;
|
||||
var selectController = this._selectController;
|
||||
|
||||
if (!selectController) {
|
||||
selectController = this._selectController = new SelectController(
|
||||
'line',
|
||||
api.getZr(),
|
||||
areaSelectStyle
|
||||
);
|
||||
|
||||
selectController.on('selected', zrUtil.bind(this._onSelected, this));
|
||||
}
|
||||
|
||||
selectController.enable(axisGroup);
|
||||
|
||||
// After filtering, axis may change, select area needs to be update.
|
||||
var ranges = zrUtil.map(axisModel.activeIntervals, function (interval) {
|
||||
return [
|
||||
axis.dataToCoord(interval[0], true),
|
||||
axis.dataToCoord(interval[1], true)
|
||||
];
|
||||
});
|
||||
selectController.update(ranges);
|
||||
},
|
||||
|
||||
_onSelected: function (ranges) {
|
||||
// Do not cache these object, because the mey be changed.
|
||||
var axisModel = this.axisModel;
|
||||
var axis = axisModel.axis;
|
||||
|
||||
var intervals = zrUtil.map(ranges, function (range) {
|
||||
return [
|
||||
axis.coordToData(range[0], true),
|
||||
axis.coordToData(range[1], true)
|
||||
];
|
||||
});
|
||||
this.api.dispatchAction({
|
||||
type: 'axisAreaSelect',
|
||||
parallelAxisId: axisModel.id,
|
||||
intervals: intervals
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* @override
|
||||
*/
|
||||
remove: function () {
|
||||
this._selectController && this._selectController.disable();
|
||||
},
|
||||
|
||||
/**
|
||||
* @override
|
||||
*/
|
||||
dispose: function () {
|
||||
if (this._selectController) {
|
||||
this._selectController.dispose();
|
||||
this._selectController = null;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
function fromAxisAreaSelect(axisModel, ecModel, payload) {
|
||||
return payload
|
||||
&& payload.type === 'axisAreaSelect'
|
||||
&& ecModel.findComponents(
|
||||
{mainType: 'parallelAxis', query: payload}
|
||||
)[0] === axisModel;
|
||||
}
|
||||
|
||||
return AxisView;
|
||||
});
|
||||
144
vendors/echarts/src/component/axis/RadiusAxisView.js
vendored
Normal file
144
vendors/echarts/src/component/axis/RadiusAxisView.js
vendored
Normal file
@@ -0,0 +1,144 @@
|
||||
define(function (require) {
|
||||
|
||||
'use strict';
|
||||
|
||||
var zrUtil = require('zrender/core/util');
|
||||
var graphic = require('../../util/graphic');
|
||||
var AxisBuilder = require('./AxisBuilder');
|
||||
|
||||
var axisBuilderAttrs = [
|
||||
'axisLine', 'axisLabel', 'axisTick', 'axisName'
|
||||
];
|
||||
var selfBuilderAttrs = [
|
||||
'splitLine', 'splitArea'
|
||||
];
|
||||
|
||||
require('../../echarts').extendComponentView({
|
||||
|
||||
type: 'radiusAxis',
|
||||
|
||||
render: function (radiusAxisModel, ecModel) {
|
||||
this.group.removeAll();
|
||||
if (!radiusAxisModel.get('show')) {
|
||||
return;
|
||||
}
|
||||
var polarModel = ecModel.getComponent('polar', radiusAxisModel.get('polarIndex'));
|
||||
var angleAxis = polarModel.coordinateSystem.getAngleAxis();
|
||||
var radiusAxis = radiusAxisModel.axis;
|
||||
var polar = polarModel.coordinateSystem;
|
||||
var ticksCoords = radiusAxis.getTicksCoords();
|
||||
var axisAngle = angleAxis.getExtent()[0];
|
||||
var radiusExtent = radiusAxis.getExtent();
|
||||
|
||||
var layout = layoutAxis(polar, radiusAxisModel, axisAngle);
|
||||
var axisBuilder = new AxisBuilder(radiusAxisModel, layout);
|
||||
zrUtil.each(axisBuilderAttrs, axisBuilder.add, axisBuilder);
|
||||
this.group.add(axisBuilder.getGroup());
|
||||
|
||||
zrUtil.each(selfBuilderAttrs, function (name) {
|
||||
if (radiusAxisModel.get(name +'.show')) {
|
||||
this['_' + name](radiusAxisModel, polar, axisAngle, radiusExtent, ticksCoords);
|
||||
}
|
||||
}, this);
|
||||
},
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
_splitLine: function (radiusAxisModel, polar, axisAngle, radiusExtent, ticksCoords) {
|
||||
var splitLineModel = radiusAxisModel.getModel('splitLine');
|
||||
var lineStyleModel = splitLineModel.getModel('lineStyle');
|
||||
var lineColors = lineStyleModel.get('color');
|
||||
var lineCount = 0;
|
||||
|
||||
lineColors = lineColors instanceof Array ? lineColors : [lineColors];
|
||||
|
||||
var splitLines = [];
|
||||
|
||||
for (var i = 0; i < ticksCoords.length; i++) {
|
||||
var colorIndex = (lineCount++) % lineColors.length;
|
||||
splitLines[colorIndex] = splitLines[colorIndex] || [];
|
||||
splitLines[colorIndex].push(new graphic.Circle({
|
||||
shape: {
|
||||
cx: polar.cx,
|
||||
cy: polar.cy,
|
||||
r: ticksCoords[i]
|
||||
},
|
||||
silent: true
|
||||
}));
|
||||
}
|
||||
|
||||
// Simple optimization
|
||||
// Batching the lines if color are the same
|
||||
for (var i = 0; i < splitLines.length; i++) {
|
||||
this.group.add(graphic.mergePath(splitLines[i], {
|
||||
style: zrUtil.defaults({
|
||||
stroke: lineColors[i % lineColors.length],
|
||||
fill: null
|
||||
}, lineStyleModel.getLineStyle()),
|
||||
silent: true
|
||||
}));
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
_splitArea: function (radiusAxisModel, polar, axisAngle, radiusExtent, ticksCoords) {
|
||||
|
||||
var splitAreaModel = radiusAxisModel.getModel('splitArea');
|
||||
var areaStyleModel = splitAreaModel.getModel('areaStyle');
|
||||
var areaColors = areaStyleModel.get('color');
|
||||
var lineCount = 0;
|
||||
|
||||
areaColors = areaColors instanceof Array ? areaColors : [areaColors];
|
||||
|
||||
var splitAreas = [];
|
||||
|
||||
var prevRadius = ticksCoords[0];
|
||||
for (var i = 1; i < ticksCoords.length; i++) {
|
||||
var colorIndex = (lineCount++) % areaColors.length;
|
||||
splitAreas[colorIndex] = splitAreas[colorIndex] || [];
|
||||
splitAreas[colorIndex].push(new graphic.Sector({
|
||||
shape: {
|
||||
cx: polar.cx,
|
||||
cy: polar.cy,
|
||||
r0: prevRadius,
|
||||
r: ticksCoords[i],
|
||||
startAngle: 0,
|
||||
endAngle: Math.PI * 2
|
||||
},
|
||||
silent: true
|
||||
}));
|
||||
prevRadius = ticksCoords[i];
|
||||
}
|
||||
|
||||
// Simple optimization
|
||||
// Batching the lines if color are the same
|
||||
for (var i = 0; i < splitAreas.length; i++) {
|
||||
this.group.add(graphic.mergePath(splitAreas[i], {
|
||||
style: zrUtil.defaults({
|
||||
fill: areaColors[i % areaColors.length]
|
||||
}, areaStyleModel.getAreaStyle()),
|
||||
silent: true
|
||||
}));
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* @inner
|
||||
*/
|
||||
function layoutAxis(polar, radiusAxisModel, axisAngle) {
|
||||
return {
|
||||
position: [polar.cx, polar.cy],
|
||||
rotation: axisAngle / 180 * Math.PI,
|
||||
labelDirection: -1,
|
||||
tickDirection: -1,
|
||||
nameDirection: 1,
|
||||
labelRotation: radiusAxisModel.getModel('axisLabel').get('rotate'),
|
||||
// Over splitLine and splitArea
|
||||
z2: 1
|
||||
};
|
||||
}
|
||||
});
|
||||
161
vendors/echarts/src/component/axis/SingleAxisView.js
vendored
Normal file
161
vendors/echarts/src/component/axis/SingleAxisView.js
vendored
Normal file
@@ -0,0 +1,161 @@
|
||||
define(function (require) {
|
||||
|
||||
var AxisBuilder = require('./AxisBuilder');
|
||||
var zrUtil = require('zrender/core/util');
|
||||
var graphic = require('../../util/graphic');
|
||||
var getInterval = AxisBuilder.getInterval;
|
||||
var ifIgnoreOnTick = AxisBuilder.ifIgnoreOnTick;
|
||||
|
||||
var axisBuilderAttrs = [
|
||||
'axisLine', 'axisLabel', 'axisTick', 'axisName'
|
||||
];
|
||||
|
||||
var selfBuilderAttr = 'splitLine';
|
||||
|
||||
var AxisView = require('../../echarts').extendComponentView({
|
||||
|
||||
type: 'singleAxis',
|
||||
|
||||
render: function (axisModel, ecModel) {
|
||||
|
||||
var group = this.group;
|
||||
|
||||
group.removeAll();
|
||||
|
||||
var layout = axisLayout(axisModel);
|
||||
|
||||
var axisBuilder = new AxisBuilder(axisModel, layout);
|
||||
|
||||
zrUtil.each(axisBuilderAttrs, axisBuilder.add, axisBuilder);
|
||||
|
||||
group.add(axisBuilder.getGroup());
|
||||
|
||||
if (axisModel.get(selfBuilderAttr + '.show')) {
|
||||
this['_' + selfBuilderAttr](axisModel, layout.labelInterval);
|
||||
}
|
||||
},
|
||||
|
||||
_splitLine: function(axisModel, labelInterval) {
|
||||
var axis = axisModel.axis;
|
||||
var splitLineModel = axisModel.getModel('splitLine');
|
||||
var lineStyleModel = splitLineModel.getModel('lineStyle');
|
||||
var lineWidth = lineStyleModel.get('width');
|
||||
var lineColors = lineStyleModel.get('color');
|
||||
var lineInterval = getInterval(splitLineModel, labelInterval);
|
||||
|
||||
lineColors = lineColors instanceof Array ? lineColors : [lineColors];
|
||||
|
||||
var gridRect = axisModel.coordinateSystem.getRect();
|
||||
var isHorizontal = axis.isHorizontal();
|
||||
|
||||
var splitLines = [];
|
||||
var lineCount = 0;
|
||||
|
||||
var ticksCoords = axis.getTicksCoords();
|
||||
|
||||
var p1 = [];
|
||||
var p2 = [];
|
||||
|
||||
for (var i = 0; i < ticksCoords.length; ++i) {
|
||||
if (ifIgnoreOnTick(axis, i, lineInterval)) {
|
||||
continue;
|
||||
}
|
||||
var tickCoord = axis.toGlobalCoord(ticksCoords[i]);
|
||||
if (isHorizontal) {
|
||||
p1[0] = tickCoord;
|
||||
p1[1] = gridRect.y;
|
||||
p2[0] = tickCoord;
|
||||
p2[1] = gridRect.y + gridRect.height;
|
||||
}
|
||||
else {
|
||||
p1[0] = gridRect.x;
|
||||
p1[1] = tickCoord;
|
||||
p2[0] = gridRect.x + gridRect.width;
|
||||
p2[1] = tickCoord;
|
||||
}
|
||||
var colorIndex = (lineCount++) % lineColors.length;
|
||||
splitLines[colorIndex] = splitLines[colorIndex] || [];
|
||||
splitLines[colorIndex].push(new graphic.Line(
|
||||
graphic.subPixelOptimizeLine({
|
||||
shape: {
|
||||
x1: p1[0],
|
||||
y1: p1[1],
|
||||
x2: p2[0],
|
||||
y2: p2[1]
|
||||
},
|
||||
style: {
|
||||
lineWidth: lineWidth
|
||||
},
|
||||
silent: true
|
||||
})));
|
||||
}
|
||||
|
||||
for (var i = 0; i < splitLines.length; ++i) {
|
||||
this.group.add(graphic.mergePath(splitLines[i], {
|
||||
style: {
|
||||
stroke: lineColors[i % lineColors.length],
|
||||
lineDash: lineStyleModel.getLineDash(),
|
||||
lineWidth: lineWidth
|
||||
},
|
||||
silent: true
|
||||
}));
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
function axisLayout(axisModel) {
|
||||
|
||||
var single = axisModel.coordinateSystem;
|
||||
var axis = axisModel.axis;
|
||||
var layout = {};
|
||||
|
||||
var axisPosition = axis.position;
|
||||
var orient = axis.orient;
|
||||
|
||||
var rect = single.getRect();
|
||||
var rectBound = [rect.x, rect.x + rect.width, rect.y, rect.y + rect.height];
|
||||
|
||||
var positionMap = {
|
||||
horizontal: {top: rectBound[2], bottom: rectBound[3]},
|
||||
vertical: {left: rectBound[0], right: rectBound[1]}
|
||||
};
|
||||
|
||||
layout.position = [
|
||||
orient === 'vertical'
|
||||
? positionMap.vertical[axisPosition]
|
||||
: rectBound[0],
|
||||
orient === 'horizontal'
|
||||
? positionMap.horizontal[axisPosition]
|
||||
: rectBound[3]
|
||||
];
|
||||
|
||||
var r = {horizontal: 0, vertical: 1};
|
||||
layout.rotation = Math.PI / 2 * r[orient];
|
||||
|
||||
var directionMap = {top: -1, bottom: 1, right: 1, left: -1};
|
||||
|
||||
layout.labelDirection = layout.tickDirection
|
||||
= layout.nameDirection
|
||||
= directionMap[axisPosition];
|
||||
|
||||
if (axisModel.getModel('axisTick').get('inside')) {
|
||||
layout.tickDirection = -layout.tickDirection;
|
||||
}
|
||||
|
||||
if (axisModel.getModel('axisLabel').get('inside')) {
|
||||
layout.labelDirection = -layout.labelDirection;
|
||||
}
|
||||
|
||||
var labelRotation = axisModel.getModel('axisLabel').get('rotate');
|
||||
layout.labelRotation = axisPosition === 'top' ? -labelRotation : labelRotation;
|
||||
|
||||
layout.labelInterval = axis.getLabelInterval();
|
||||
|
||||
layout.z2 = 1;
|
||||
|
||||
return layout;
|
||||
}
|
||||
|
||||
return AxisView;
|
||||
|
||||
});
|
||||
25
vendors/echarts/src/component/axis/parallelAxisAction.js
vendored
Normal file
25
vendors/echarts/src/component/axis/parallelAxisAction.js
vendored
Normal file
@@ -0,0 +1,25 @@
|
||||
define(function (require) {
|
||||
|
||||
var echarts = require('../../echarts');
|
||||
|
||||
var actionInfo = {
|
||||
type: 'axisAreaSelect',
|
||||
event: 'axisAreaSelected',
|
||||
update: 'updateVisual'
|
||||
};
|
||||
|
||||
/**
|
||||
* @payload
|
||||
* @property {string} parallelAxisId
|
||||
* @property {Array.<Array.<number>>} intervals
|
||||
*/
|
||||
echarts.registerAction(actionInfo, function (payload, ecModel) {
|
||||
ecModel.eachComponent(
|
||||
{mainType: 'parallelAxis', query: payload},
|
||||
function (parallelAxisModel) {
|
||||
parallelAxisModel.axis.model.setActiveIntervals(payload.intervals);
|
||||
}
|
||||
);
|
||||
|
||||
});
|
||||
});
|
||||
20
vendors/echarts/src/component/dataZoom.js
vendored
Normal file
20
vendors/echarts/src/component/dataZoom.js
vendored
Normal file
@@ -0,0 +1,20 @@
|
||||
/**
|
||||
* DataZoom component entry
|
||||
*/
|
||||
define(function (require) {
|
||||
|
||||
require('./dataZoom/typeDefaulter');
|
||||
|
||||
require('./dataZoom/DataZoomModel');
|
||||
require('./dataZoom/DataZoomView');
|
||||
|
||||
require('./dataZoom/SliderZoomModel');
|
||||
require('./dataZoom/SliderZoomView');
|
||||
|
||||
require('./dataZoom/InsideZoomModel');
|
||||
require('./dataZoom/InsideZoomView');
|
||||
|
||||
require('./dataZoom/dataZoomProcessor');
|
||||
require('./dataZoom/dataZoomAction');
|
||||
|
||||
});
|
||||
357
vendors/echarts/src/component/dataZoom/AxisProxy.js
vendored
Normal file
357
vendors/echarts/src/component/dataZoom/AxisProxy.js
vendored
Normal file
@@ -0,0 +1,357 @@
|
||||
/**
|
||||
* @file Axis operator
|
||||
*/
|
||||
define(function(require) {
|
||||
|
||||
var zrUtil = require('zrender/core/util');
|
||||
var numberUtil = require('../../util/number');
|
||||
var each = zrUtil.each;
|
||||
var asc = numberUtil.asc;
|
||||
|
||||
/**
|
||||
* Operate single axis.
|
||||
* One axis can only operated by one axis operator.
|
||||
* Different dataZoomModels may be defined to operate the same axis.
|
||||
* (i.e. 'inside' data zoom and 'slider' data zoom components)
|
||||
* So dataZoomModels share one axisProxy in that case.
|
||||
*
|
||||
* @class
|
||||
*/
|
||||
var AxisProxy = function (dimName, axisIndex, dataZoomModel, ecModel) {
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {string}
|
||||
*/
|
||||
this._dimName = dimName;
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
this._axisIndex = axisIndex;
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {Array.<number>}
|
||||
*/
|
||||
this._valueWindow;
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {Array.<number>}
|
||||
*/
|
||||
this._percentWindow;
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {Array.<number>}
|
||||
*/
|
||||
this._dataExtent;
|
||||
|
||||
/**
|
||||
* @readOnly
|
||||
* @type {module: echarts/model/Global}
|
||||
*/
|
||||
this.ecModel = ecModel;
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {module: echarts/component/dataZoom/DataZoomModel}
|
||||
*/
|
||||
this._dataZoomModel = dataZoomModel;
|
||||
};
|
||||
|
||||
AxisProxy.prototype = {
|
||||
|
||||
constructor: AxisProxy,
|
||||
|
||||
/**
|
||||
* Whether the axisProxy is hosted by dataZoomModel.
|
||||
*
|
||||
* @public
|
||||
* @param {module: echarts/component/dataZoom/DataZoomModel} dataZoomModel
|
||||
* @return {boolean}
|
||||
*/
|
||||
hostedBy: function (dataZoomModel) {
|
||||
return this._dataZoomModel === dataZoomModel;
|
||||
},
|
||||
|
||||
/**
|
||||
* @return {Array.<number>}
|
||||
*/
|
||||
getDataExtent: function () {
|
||||
return this._dataExtent.slice();
|
||||
},
|
||||
|
||||
/**
|
||||
* @return {Array.<number>}
|
||||
*/
|
||||
getDataValueWindow: function () {
|
||||
return this._valueWindow.slice();
|
||||
},
|
||||
|
||||
/**
|
||||
* @return {Array.<number>}
|
||||
*/
|
||||
getDataPercentWindow: function () {
|
||||
return this._percentWindow.slice();
|
||||
},
|
||||
|
||||
/**
|
||||
* @public
|
||||
* @param {number} axisIndex
|
||||
* @return {Array} seriesModels
|
||||
*/
|
||||
getTargetSeriesModels: function () {
|
||||
var seriesModels = [];
|
||||
|
||||
this.ecModel.eachSeries(function (seriesModel) {
|
||||
if (this._axisIndex === seriesModel.get(this._dimName + 'AxisIndex')) {
|
||||
seriesModels.push(seriesModel);
|
||||
}
|
||||
}, this);
|
||||
|
||||
return seriesModels;
|
||||
},
|
||||
|
||||
getAxisModel: function () {
|
||||
return this.ecModel.getComponent(this._dimName + 'Axis', this._axisIndex);
|
||||
},
|
||||
|
||||
getOtherAxisModel: function () {
|
||||
var axisDim = this._dimName;
|
||||
var ecModel = this.ecModel;
|
||||
var axisModel = this.getAxisModel();
|
||||
var isCartesian = axisDim === 'x' || axisDim === 'y';
|
||||
var otherAxisDim;
|
||||
var coordSysIndexName;
|
||||
if (isCartesian) {
|
||||
coordSysIndexName = 'gridIndex';
|
||||
otherAxisDim = axisDim === 'x' ? 'y' : 'x';
|
||||
}
|
||||
else {
|
||||
coordSysIndexName = 'polarIndex';
|
||||
otherAxisDim = axisDim === 'angle' ? 'radius' : 'angle';
|
||||
}
|
||||
var foundOtherAxisModel;
|
||||
ecModel.eachComponent(otherAxisDim + 'Axis', function (otherAxisModel) {
|
||||
if ((otherAxisModel.get(coordSysIndexName) || 0)
|
||||
=== (axisModel.get(coordSysIndexName) || 0)
|
||||
) {
|
||||
foundOtherAxisModel = otherAxisModel;
|
||||
}
|
||||
});
|
||||
return foundOtherAxisModel;
|
||||
},
|
||||
|
||||
/**
|
||||
* Notice: reset should not be called before series.restoreData() called,
|
||||
* so it is recommanded to be called in "process stage" but not "model init
|
||||
* stage".
|
||||
*
|
||||
* @param {module: echarts/component/dataZoom/DataZoomModel} dataZoomModel
|
||||
*/
|
||||
reset: function (dataZoomModel) {
|
||||
if (dataZoomModel !== this._dataZoomModel) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Culculate data window and data extent, and record them.
|
||||
var dataExtent = this._dataExtent = calculateDataExtent(
|
||||
this._dimName, this.getTargetSeriesModels()
|
||||
);
|
||||
var dataWindow = calculateDataWindow(
|
||||
dataZoomModel.option, dataExtent, this
|
||||
);
|
||||
this._valueWindow = dataWindow.valueWindow;
|
||||
this._percentWindow = dataWindow.percentWindow;
|
||||
|
||||
// Update axis setting then.
|
||||
setAxisModel(this);
|
||||
},
|
||||
|
||||
/**
|
||||
* @param {module: echarts/component/dataZoom/DataZoomModel} dataZoomModel
|
||||
*/
|
||||
restore: function (dataZoomModel) {
|
||||
if (dataZoomModel !== this._dataZoomModel) {
|
||||
return;
|
||||
}
|
||||
|
||||
this._valueWindow = this._percentWindow = null;
|
||||
setAxisModel(this, true);
|
||||
},
|
||||
|
||||
/**
|
||||
* @param {module: echarts/component/dataZoom/DataZoomModel} dataZoomModel
|
||||
*/
|
||||
filterData: function (dataZoomModel) {
|
||||
if (dataZoomModel !== this._dataZoomModel) {
|
||||
return;
|
||||
}
|
||||
|
||||
var axisDim = this._dimName;
|
||||
var seriesModels = this.getTargetSeriesModels();
|
||||
var filterMode = dataZoomModel.get('filterMode');
|
||||
var valueWindow = this._valueWindow;
|
||||
|
||||
// FIXME
|
||||
// Toolbox may has dataZoom injected. And if there are stacked bar chart
|
||||
// with NaN data, NaN will be filtered and stack will be wrong.
|
||||
// So we need to force the mode to be set empty.
|
||||
// In fect, it is not a big deal that do not support filterMode-'filter'
|
||||
// when using toolbox#dataZoom, utill tooltip#dataZoom support "single axis
|
||||
// selection" some day, which might need "adapt to data extent on the
|
||||
// otherAxis", which is disabled by filterMode-'empty'.
|
||||
var otherAxisModel = this.getOtherAxisModel();
|
||||
if (dataZoomModel.get('$fromToolbox')
|
||||
&& otherAxisModel
|
||||
&& otherAxisModel.get('type') === 'category'
|
||||
) {
|
||||
filterMode = 'empty';
|
||||
}
|
||||
|
||||
// Process series data
|
||||
each(seriesModels, function (seriesModel) {
|
||||
var seriesData = seriesModel.getData();
|
||||
|
||||
seriesData && each(seriesModel.coordDimToDataDim(axisDim), function (dim) {
|
||||
if (filterMode === 'empty') {
|
||||
seriesModel.setData(
|
||||
seriesData.map(dim, function (value) {
|
||||
return !isInWindow(value) ? NaN : value;
|
||||
})
|
||||
);
|
||||
}
|
||||
else {
|
||||
seriesData.filterSelf(dim, isInWindow);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
function isInWindow(value) {
|
||||
return value >= valueWindow[0] && value <= valueWindow[1];
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
function calculateDataExtent(axisDim, seriesModels) {
|
||||
var dataExtent = [Infinity, -Infinity];
|
||||
|
||||
each(seriesModels, function (seriesModel) {
|
||||
var seriesData = seriesModel.getData();
|
||||
if (seriesData) {
|
||||
each(seriesModel.coordDimToDataDim(axisDim), function (dim) {
|
||||
var seriesExtent = seriesData.getDataExtent(dim);
|
||||
seriesExtent[0] < dataExtent[0] && (dataExtent[0] = seriesExtent[0]);
|
||||
seriesExtent[1] > dataExtent[1] && (dataExtent[1] = seriesExtent[1]);
|
||||
});
|
||||
}
|
||||
}, this);
|
||||
|
||||
return dataExtent;
|
||||
}
|
||||
|
||||
function calculateDataWindow(opt, dataExtent, axisProxy) {
|
||||
var axisModel = axisProxy.getAxisModel();
|
||||
var scale = axisModel.axis.scale;
|
||||
var percentExtent = [0, 100];
|
||||
var percentWindow = [
|
||||
opt.start,
|
||||
opt.end
|
||||
];
|
||||
var valueWindow = [];
|
||||
|
||||
// In percent range is used and axis min/max/scale is set,
|
||||
// window should be based on min/max/0, but should not be
|
||||
// based on the extent of filtered data.
|
||||
dataExtent = dataExtent.slice();
|
||||
fixExtendByAxis(dataExtent, axisModel, scale);
|
||||
|
||||
each(['startValue', 'endValue'], function (prop) {
|
||||
valueWindow.push(
|
||||
opt[prop] != null
|
||||
? scale.parse(opt[prop])
|
||||
: null
|
||||
);
|
||||
});
|
||||
|
||||
// Normalize bound.
|
||||
each([0, 1], function (idx) {
|
||||
var boundValue = valueWindow[idx];
|
||||
var boundPercent = percentWindow[idx];
|
||||
|
||||
// start/end has higher priority over startValue/endValue,
|
||||
// because start/end can be consistent among different type
|
||||
// of axis but startValue/endValue not.
|
||||
|
||||
if (boundPercent != null || boundValue == null) {
|
||||
if (boundPercent == null) {
|
||||
boundPercent = percentExtent[idx];
|
||||
}
|
||||
// Use scale.parse to math round for category or time axis.
|
||||
boundValue = scale.parse(numberUtil.linearMap(
|
||||
boundPercent, percentExtent, dataExtent, true
|
||||
));
|
||||
}
|
||||
else { // boundPercent == null && boundValue != null
|
||||
boundPercent = numberUtil.linearMap(
|
||||
boundValue, dataExtent, percentExtent, true
|
||||
);
|
||||
}
|
||||
// valueWindow[idx] = round(boundValue);
|
||||
// percentWindow[idx] = round(boundPercent);
|
||||
valueWindow[idx] = boundValue;
|
||||
percentWindow[idx] = boundPercent;
|
||||
});
|
||||
|
||||
return {
|
||||
valueWindow: asc(valueWindow),
|
||||
percentWindow: asc(percentWindow)
|
||||
};
|
||||
}
|
||||
|
||||
function fixExtendByAxis(dataExtent, axisModel, scale) {
|
||||
each(['min', 'max'], function (minMax, index) {
|
||||
var axisMax = axisModel.get(minMax, true);
|
||||
// Consider 'dataMin', 'dataMax'
|
||||
if (axisMax != null && (axisMax + '').toLowerCase() !== 'data' + minMax) {
|
||||
dataExtent[index] = scale.parse(axisMax);
|
||||
}
|
||||
});
|
||||
|
||||
if (!axisModel.get('scale', true)) {
|
||||
dataExtent[0] > 0 && (dataExtent[0] = 0);
|
||||
dataExtent[1] < 0 && (dataExtent[1] = 0);
|
||||
}
|
||||
|
||||
return dataExtent;
|
||||
}
|
||||
|
||||
function setAxisModel(axisProxy, isRestore) {
|
||||
var axisModel = axisProxy.getAxisModel();
|
||||
|
||||
var percentWindow = axisProxy._percentWindow;
|
||||
var valueWindow = axisProxy._valueWindow;
|
||||
|
||||
if (!percentWindow) {
|
||||
return;
|
||||
}
|
||||
|
||||
var isFull = isRestore || (percentWindow[0] === 0 && percentWindow[1] === 100);
|
||||
// [0, 500]: arbitrary value, guess axis extent.
|
||||
var precision = !isRestore && numberUtil.getPixelPrecision(valueWindow, [0, 500]);
|
||||
// toFixed() digits argument must be between 0 and 20
|
||||
var invalidPrecision = !isRestore && !(precision < 20 && precision >= 0);
|
||||
|
||||
var useOrigin = isRestore || isFull || invalidPrecision;
|
||||
|
||||
axisModel.setRange && axisModel.setRange(
|
||||
useOrigin ? null : +valueWindow[0].toFixed(precision),
|
||||
useOrigin ? null : +valueWindow[1].toFixed(precision)
|
||||
);
|
||||
}
|
||||
|
||||
return AxisProxy;
|
||||
|
||||
});
|
||||
432
vendors/echarts/src/component/dataZoom/DataZoomModel.js
vendored
Normal file
432
vendors/echarts/src/component/dataZoom/DataZoomModel.js
vendored
Normal file
@@ -0,0 +1,432 @@
|
||||
/**
|
||||
* @file Data zoom model
|
||||
*/
|
||||
define(function(require) {
|
||||
|
||||
var zrUtil = require('zrender/core/util');
|
||||
var env = require('zrender/core/env');
|
||||
var echarts = require('../../echarts');
|
||||
var modelUtil = require('../../util/model');
|
||||
var AxisProxy = require('./AxisProxy');
|
||||
var each = zrUtil.each;
|
||||
var eachAxisDim = modelUtil.eachAxisDim;
|
||||
|
||||
var DataZoomModel = echarts.extendComponentModel({
|
||||
|
||||
type: 'dataZoom',
|
||||
|
||||
dependencies: [
|
||||
'xAxis', 'yAxis', 'zAxis', 'radiusAxis', 'angleAxis', 'series'
|
||||
],
|
||||
|
||||
/**
|
||||
* @protected
|
||||
*/
|
||||
defaultOption: {
|
||||
zlevel: 0,
|
||||
z: 4, // Higher than normal component (z: 2).
|
||||
orient: null, // Default auto by axisIndex. Possible value: 'horizontal', 'vertical'.
|
||||
xAxisIndex: null, // Default all horizontal category axis.
|
||||
yAxisIndex: null, // Default all vertical category axis.
|
||||
angleAxisIndex: null,
|
||||
radiusAxisIndex: null,
|
||||
filterMode: 'filter', // Possible values: 'filter' or 'empty'.
|
||||
// 'filter': data items which are out of window will be removed.
|
||||
// This option is applicable when filtering outliers.
|
||||
// 'empty': data items which are out of window will be set to empty.
|
||||
// This option is applicable when user should not neglect
|
||||
// that there are some data items out of window.
|
||||
// Taking line chart as an example, line will be broken in
|
||||
// the filtered points when filterModel is set to 'empty', but
|
||||
// be connected when set to 'filter'.
|
||||
|
||||
throttle: 100, // Dispatch action by the fixed rate, avoid frequency.
|
||||
// default 100. Do not throttle when use null/undefined.
|
||||
start: 0, // Start percent. 0 ~ 100
|
||||
end: 100, // End percent. 0 ~ 100
|
||||
startValue: null, // Start value. If startValue specified, start is ignored.
|
||||
endValue: null // End value. If endValue specified, end is ignored.
|
||||
},
|
||||
|
||||
/**
|
||||
* @override
|
||||
*/
|
||||
init: function (option, parentModel, ecModel) {
|
||||
|
||||
/**
|
||||
* key like x_0, y_1
|
||||
* @private
|
||||
* @type {Object}
|
||||
*/
|
||||
this._dataIntervalByAxis = {};
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
this._dataInfo = {};
|
||||
|
||||
/**
|
||||
* key like x_0, y_1
|
||||
* @private
|
||||
*/
|
||||
this._axisProxies = {};
|
||||
|
||||
/**
|
||||
* @readOnly
|
||||
*/
|
||||
this.textStyleModel;
|
||||
|
||||
var rawOption = retrieveRaw(option);
|
||||
|
||||
this.mergeDefaultAndTheme(option, ecModel);
|
||||
|
||||
this.doInit(rawOption);
|
||||
},
|
||||
|
||||
/**
|
||||
* @override
|
||||
*/
|
||||
mergeOption: function (newOption) {
|
||||
var rawOption = retrieveRaw(newOption);
|
||||
|
||||
//FIX #2591
|
||||
zrUtil.merge(this.option, newOption, true);
|
||||
|
||||
this.doInit(rawOption);
|
||||
},
|
||||
|
||||
/**
|
||||
* @protected
|
||||
*/
|
||||
doInit: function (rawOption) {
|
||||
var thisOption = this.option;
|
||||
|
||||
// Disable realtime view update if canvas is not supported.
|
||||
if (!env.canvasSupported) {
|
||||
thisOption.realtime = false;
|
||||
}
|
||||
|
||||
processRangeProp('start', 'startValue', rawOption, thisOption);
|
||||
processRangeProp('end', 'endValue', rawOption, thisOption);
|
||||
|
||||
this.textStyleModel = this.getModel('textStyle');
|
||||
|
||||
this._resetTarget();
|
||||
|
||||
this._giveAxisProxies();
|
||||
},
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
_giveAxisProxies: function () {
|
||||
var axisProxies = this._axisProxies;
|
||||
|
||||
this.eachTargetAxis(function (dimNames, axisIndex, dataZoomModel, ecModel) {
|
||||
var axisModel = this.dependentModels[dimNames.axis][axisIndex];
|
||||
|
||||
// If exists, share axisProxy with other dataZoomModels.
|
||||
var axisProxy = axisModel.__dzAxisProxy || (
|
||||
// Use the first dataZoomModel as the main model of axisProxy.
|
||||
axisModel.__dzAxisProxy = new AxisProxy(
|
||||
dimNames.name, axisIndex, this, ecModel
|
||||
)
|
||||
);
|
||||
// FIXME
|
||||
// dispose __dzAxisProxy
|
||||
|
||||
axisProxies[dimNames.name + '_' + axisIndex] = axisProxy;
|
||||
}, this);
|
||||
},
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
_resetTarget: function () {
|
||||
var thisOption = this.option;
|
||||
|
||||
var autoMode = this._judgeAutoMode();
|
||||
|
||||
eachAxisDim(function (dimNames) {
|
||||
var axisIndexName = dimNames.axisIndex;
|
||||
thisOption[axisIndexName] = modelUtil.normalizeToArray(
|
||||
thisOption[axisIndexName]
|
||||
);
|
||||
}, this);
|
||||
|
||||
if (autoMode === 'axisIndex') {
|
||||
this._autoSetAxisIndex();
|
||||
}
|
||||
else if (autoMode === 'orient') {
|
||||
this._autoSetOrient();
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
_judgeAutoMode: function () {
|
||||
// Auto set only works for setOption at the first time.
|
||||
// The following is user's reponsibility. So using merged
|
||||
// option is OK.
|
||||
var thisOption = this.option;
|
||||
|
||||
var hasIndexSpecified = false;
|
||||
eachAxisDim(function (dimNames) {
|
||||
// When user set axisIndex as a empty array, we think that user specify axisIndex
|
||||
// but do not want use auto mode. Because empty array may be encountered when
|
||||
// some error occured.
|
||||
if (thisOption[dimNames.axisIndex] != null) {
|
||||
hasIndexSpecified = true;
|
||||
}
|
||||
}, this);
|
||||
|
||||
var orient = thisOption.orient;
|
||||
|
||||
if (orient == null && hasIndexSpecified) {
|
||||
return 'orient';
|
||||
}
|
||||
else if (!hasIndexSpecified) {
|
||||
if (orient == null) {
|
||||
thisOption.orient = 'horizontal';
|
||||
}
|
||||
return 'axisIndex';
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
_autoSetAxisIndex: function () {
|
||||
var autoAxisIndex = true;
|
||||
var orient = this.get('orient', true);
|
||||
var thisOption = this.option;
|
||||
|
||||
if (autoAxisIndex) {
|
||||
// Find axis that parallel to dataZoom as default.
|
||||
var dimNames = orient === 'vertical'
|
||||
? {dim: 'y', axisIndex: 'yAxisIndex', axis: 'yAxis'}
|
||||
: {dim: 'x', axisIndex: 'xAxisIndex', axis: 'xAxis'};
|
||||
|
||||
if (this.dependentModels[dimNames.axis].length) {
|
||||
thisOption[dimNames.axisIndex] = [0];
|
||||
autoAxisIndex = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (autoAxisIndex) {
|
||||
// Find the first category axis as default. (consider polar)
|
||||
eachAxisDim(function (dimNames) {
|
||||
if (!autoAxisIndex) {
|
||||
return;
|
||||
}
|
||||
var axisIndices = [];
|
||||
var axisModels = this.dependentModels[dimNames.axis];
|
||||
if (axisModels.length && !axisIndices.length) {
|
||||
for (var i = 0, len = axisModels.length; i < len; i++) {
|
||||
if (axisModels[i].get('type') === 'category') {
|
||||
axisIndices.push(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
thisOption[dimNames.axisIndex] = axisIndices;
|
||||
if (axisIndices.length) {
|
||||
autoAxisIndex = false;
|
||||
}
|
||||
}, this);
|
||||
}
|
||||
|
||||
if (autoAxisIndex) {
|
||||
// FIXME
|
||||
// 这里是兼容ec2的写法(没指定xAxisIndex和yAxisIndex时把scatter和双数值轴折柱纳入dataZoom控制),
|
||||
// 但是实际是否需要Grid.js#getScaleByOption来判断(考虑time,log等axis type)?
|
||||
|
||||
// If both dataZoom.xAxisIndex and dataZoom.yAxisIndex is not specified,
|
||||
// dataZoom component auto adopts series that reference to
|
||||
// both xAxis and yAxis which type is 'value'.
|
||||
this.ecModel.eachSeries(function (seriesModel) {
|
||||
if (this._isSeriesHasAllAxesTypeOf(seriesModel, 'value')) {
|
||||
eachAxisDim(function (dimNames) {
|
||||
var axisIndices = thisOption[dimNames.axisIndex];
|
||||
var axisIndex = seriesModel.get(dimNames.axisIndex);
|
||||
if (zrUtil.indexOf(axisIndices, axisIndex) < 0) {
|
||||
axisIndices.push(axisIndex);
|
||||
}
|
||||
});
|
||||
}
|
||||
}, this);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
_autoSetOrient: function () {
|
||||
var dim;
|
||||
|
||||
// Find the first axis
|
||||
this.eachTargetAxis(function (dimNames) {
|
||||
!dim && (dim = dimNames.name);
|
||||
}, this);
|
||||
|
||||
this.option.orient = dim === 'y' ? 'vertical' : 'horizontal';
|
||||
},
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
_isSeriesHasAllAxesTypeOf: function (seriesModel, axisType) {
|
||||
// FIXME
|
||||
// 需要series的xAxisIndex和yAxisIndex都首先自动设置上。
|
||||
// 例如series.type === scatter时。
|
||||
|
||||
var is = true;
|
||||
eachAxisDim(function (dimNames) {
|
||||
var seriesAxisIndex = seriesModel.get(dimNames.axisIndex);
|
||||
var axisModel = this.dependentModels[dimNames.axis][seriesAxisIndex];
|
||||
|
||||
if (!axisModel || axisModel.get('type') !== axisType) {
|
||||
is = false;
|
||||
}
|
||||
}, this);
|
||||
return is;
|
||||
},
|
||||
|
||||
/**
|
||||
* @public
|
||||
*/
|
||||
getFirstTargetAxisModel: function () {
|
||||
var firstAxisModel;
|
||||
eachAxisDim(function (dimNames) {
|
||||
if (firstAxisModel == null) {
|
||||
var indices = this.get(dimNames.axisIndex);
|
||||
if (indices.length) {
|
||||
firstAxisModel = this.dependentModels[dimNames.axis][indices[0]];
|
||||
}
|
||||
}
|
||||
}, this);
|
||||
|
||||
return firstAxisModel;
|
||||
},
|
||||
|
||||
/**
|
||||
* @public
|
||||
* @param {Function} callback param: axisModel, dimNames, axisIndex, dataZoomModel, ecModel
|
||||
*/
|
||||
eachTargetAxis: function (callback, context) {
|
||||
var ecModel = this.ecModel;
|
||||
eachAxisDim(function (dimNames) {
|
||||
each(
|
||||
this.get(dimNames.axisIndex),
|
||||
function (axisIndex) {
|
||||
callback.call(context, dimNames, axisIndex, this, ecModel);
|
||||
},
|
||||
this
|
||||
);
|
||||
}, this);
|
||||
},
|
||||
|
||||
getAxisProxy: function (dimName, axisIndex) {
|
||||
return this._axisProxies[dimName + '_' + axisIndex];
|
||||
},
|
||||
|
||||
/**
|
||||
* If not specified, set to undefined.
|
||||
*
|
||||
* @public
|
||||
* @param {Object} opt
|
||||
* @param {number} [opt.start]
|
||||
* @param {number} [opt.end]
|
||||
* @param {number} [opt.startValue]
|
||||
* @param {number} [opt.endValue]
|
||||
*/
|
||||
setRawRange: function (opt) {
|
||||
each(['start', 'end', 'startValue', 'endValue'], function (name) {
|
||||
// If any of those prop is null/undefined, we should alos set
|
||||
// them, because only one pair between start/end and
|
||||
// startValue/endValue can work.
|
||||
this.option[name] = opt[name];
|
||||
}, this);
|
||||
},
|
||||
|
||||
/**
|
||||
* @public
|
||||
* @return {Array.<number>} [startPercent, endPercent]
|
||||
*/
|
||||
getPercentRange: function () {
|
||||
var axisProxy = this.findRepresentativeAxisProxy();
|
||||
if (axisProxy) {
|
||||
return axisProxy.getDataPercentWindow();
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* @public
|
||||
* For example, chart.getModel().getComponent('dataZoom').getValueRange('y', 0);
|
||||
*
|
||||
* @param {string} [axisDimName]
|
||||
* @param {number} [axisIndex]
|
||||
* @return {Array.<number>} [startValue, endValue]
|
||||
*/
|
||||
getValueRange: function (axisDimName, axisIndex) {
|
||||
if (axisDimName == null && axisIndex == null) {
|
||||
var axisProxy = this.findRepresentativeAxisProxy();
|
||||
if (axisProxy) {
|
||||
return axisProxy.getDataValueWindow();
|
||||
}
|
||||
}
|
||||
else {
|
||||
return this.getAxisProxy(axisDimName, axisIndex).getDataValueWindow();
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* @public
|
||||
* @return {module:echarts/component/dataZoom/AxisProxy}
|
||||
*/
|
||||
findRepresentativeAxisProxy: function () {
|
||||
// Find the first hosted axisProxy
|
||||
var axisProxies = this._axisProxies;
|
||||
for (var key in axisProxies) {
|
||||
if (axisProxies.hasOwnProperty(key) && axisProxies[key].hostedBy(this)) {
|
||||
return axisProxies[key];
|
||||
}
|
||||
}
|
||||
|
||||
// If no hosted axis find not hosted axisProxy.
|
||||
// Consider this case: dataZoomModel1 and dataZoomModel2 control the same axis,
|
||||
// and the option.start or option.end settings are different. The percentRange
|
||||
// should follow axisProxy.
|
||||
// (We encounter this problem in toolbox data zoom.)
|
||||
for (var key in axisProxies) {
|
||||
if (axisProxies.hasOwnProperty(key) && !axisProxies[key].hostedBy(this)) {
|
||||
return axisProxies[key];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
function retrieveRaw(option) {
|
||||
var ret = {};
|
||||
each(
|
||||
['start', 'end', 'startValue', 'endValue'],
|
||||
function (name) {
|
||||
ret[name] = option[name];
|
||||
}
|
||||
);
|
||||
return ret;
|
||||
}
|
||||
|
||||
function processRangeProp(percentProp, valueProp, rawOption, thisOption) {
|
||||
// start/end has higher priority over startValue/endValue,
|
||||
// but we should make chart.setOption({endValue: 1000}) effective,
|
||||
// rather than chart.setOption({endValue: 1000, end: null}).
|
||||
if (rawOption[valueProp] != null && rawOption[percentProp] == null) {
|
||||
thisOption[percentProp] = null;
|
||||
}
|
||||
// Otherwise do nothing and use the merge result.
|
||||
}
|
||||
|
||||
return DataZoomModel;
|
||||
});
|
||||
84
vendors/echarts/src/component/dataZoom/DataZoomView.js
vendored
Normal file
84
vendors/echarts/src/component/dataZoom/DataZoomView.js
vendored
Normal file
@@ -0,0 +1,84 @@
|
||||
define(function (require) {
|
||||
|
||||
var ComponentView = require('../../view/Component');
|
||||
|
||||
return ComponentView.extend({
|
||||
|
||||
type: 'dataZoom',
|
||||
|
||||
render: function (dataZoomModel, ecModel, api, payload) {
|
||||
this.dataZoomModel = dataZoomModel;
|
||||
this.ecModel = ecModel;
|
||||
this.api = api;
|
||||
},
|
||||
|
||||
/**
|
||||
* Find the first target coordinate system.
|
||||
*
|
||||
* @protected
|
||||
* @return {Object} {
|
||||
* cartesians: [
|
||||
* {model: coord0, axisModels: [axis1, axis3], coordIndex: 1},
|
||||
* {model: coord1, axisModels: [axis0, axis2], coordIndex: 0},
|
||||
* ...
|
||||
* ], // cartesians must not be null/undefined.
|
||||
* polars: [
|
||||
* {model: coord0, axisModels: [axis4], coordIndex: 0},
|
||||
* ...
|
||||
* ], // polars must not be null/undefined.
|
||||
* axisModels: [axis0, axis1, axis2, axis3, axis4]
|
||||
* // axisModels must not be null/undefined.
|
||||
* }
|
||||
*/
|
||||
getTargetInfo: function () {
|
||||
var dataZoomModel = this.dataZoomModel;
|
||||
var ecModel = this.ecModel;
|
||||
var cartesians = [];
|
||||
var polars = [];
|
||||
var axisModels = [];
|
||||
|
||||
dataZoomModel.eachTargetAxis(function (dimNames, axisIndex) {
|
||||
var axisModel = ecModel.getComponent(dimNames.axis, axisIndex);
|
||||
if (axisModel) {
|
||||
axisModels.push(axisModel);
|
||||
|
||||
var gridIndex = axisModel.get('gridIndex');
|
||||
var polarIndex = axisModel.get('polarIndex');
|
||||
|
||||
if (gridIndex != null) {
|
||||
var coordModel = ecModel.getComponent('grid', gridIndex);
|
||||
save(coordModel, axisModel, cartesians, gridIndex);
|
||||
}
|
||||
else if (polarIndex != null) {
|
||||
var coordModel = ecModel.getComponent('polar', polarIndex);
|
||||
save(coordModel, axisModel, polars, polarIndex);
|
||||
}
|
||||
}
|
||||
}, this);
|
||||
|
||||
function save(coordModel, axisModel, store, coordIndex) {
|
||||
var item;
|
||||
for (var i = 0; i < store.length; i++) {
|
||||
if (store[i].model === coordModel) {
|
||||
item = store[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!item) {
|
||||
store.push(item = {
|
||||
model: coordModel, axisModels: [], coordIndex: coordIndex
|
||||
});
|
||||
}
|
||||
item.axisModels.push(axisModel);
|
||||
}
|
||||
|
||||
return {
|
||||
cartesians: cartesians,
|
||||
polars: polars,
|
||||
axisModels: axisModels
|
||||
};
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
17
vendors/echarts/src/component/dataZoom/InsideZoomModel.js
vendored
Normal file
17
vendors/echarts/src/component/dataZoom/InsideZoomModel.js
vendored
Normal file
@@ -0,0 +1,17 @@
|
||||
/**
|
||||
* @file Data zoom model
|
||||
*/
|
||||
define(function(require) {
|
||||
|
||||
return require('./DataZoomModel').extend({
|
||||
|
||||
type: 'dataZoom.inside',
|
||||
|
||||
/**
|
||||
* @protected
|
||||
*/
|
||||
defaultOption: {
|
||||
zoomLock: false // Whether disable zoom but only pan.
|
||||
}
|
||||
});
|
||||
});
|
||||
194
vendors/echarts/src/component/dataZoom/InsideZoomView.js
vendored
Normal file
194
vendors/echarts/src/component/dataZoom/InsideZoomView.js
vendored
Normal file
@@ -0,0 +1,194 @@
|
||||
define(function (require) {
|
||||
|
||||
var DataZoomView = require('./DataZoomView');
|
||||
var zrUtil = require('zrender/core/util');
|
||||
var sliderMove = require('../helper/sliderMove');
|
||||
var roams = require('./roams');
|
||||
var bind = zrUtil.bind;
|
||||
|
||||
var InsideZoomView = DataZoomView.extend({
|
||||
|
||||
type: 'dataZoom.inside',
|
||||
|
||||
/**
|
||||
* @override
|
||||
*/
|
||||
init: function (ecModel, api) {
|
||||
/**
|
||||
* 'throttle' is used in this.dispatchAction, so we save range
|
||||
* to avoid missing some 'pan' info.
|
||||
* @private
|
||||
* @type {Array.<number>}
|
||||
*/
|
||||
this._range;
|
||||
},
|
||||
|
||||
/**
|
||||
* @override
|
||||
*/
|
||||
render: function (dataZoomModel, ecModel, api, payload) {
|
||||
InsideZoomView.superApply(this, 'render', arguments);
|
||||
|
||||
// Notice: origin this._range should be maintained, and should not be re-fetched
|
||||
// from dataZoomModel when payload.type is 'dataZoom', otherwise 'pan' or 'zoom'
|
||||
// info will be missed because of 'throttle' of this.dispatchAction.
|
||||
if (roams.shouldRecordRange(payload, dataZoomModel.id)) {
|
||||
this._range = dataZoomModel.getPercentRange();
|
||||
}
|
||||
|
||||
// Reset controllers.
|
||||
var coordInfoList = this.getTargetInfo().cartesians;
|
||||
var allCoordIds = zrUtil.map(coordInfoList, function (coordInfo) {
|
||||
return roams.generateCoordId(coordInfo.model);
|
||||
});
|
||||
zrUtil.each(coordInfoList, function (coordInfo) {
|
||||
var coordModel = coordInfo.model;
|
||||
roams.register(
|
||||
api,
|
||||
{
|
||||
coordId: roams.generateCoordId(coordModel),
|
||||
allCoordIds: allCoordIds,
|
||||
coordinateSystem: coordModel.coordinateSystem,
|
||||
dataZoomId: dataZoomModel.id,
|
||||
throttleRage: dataZoomModel.get('throttle', true),
|
||||
panGetRange: bind(this._onPan, this, coordInfo),
|
||||
zoomGetRange: bind(this._onZoom, this, coordInfo)
|
||||
}
|
||||
);
|
||||
}, this);
|
||||
|
||||
// TODO
|
||||
// polar支持
|
||||
},
|
||||
|
||||
/**
|
||||
* @override
|
||||
*/
|
||||
remove: function () {
|
||||
roams.unregister(this.api, this.dataZoomModel.id);
|
||||
InsideZoomView.superApply(this, 'remove', arguments);
|
||||
this._range = null;
|
||||
},
|
||||
|
||||
/**
|
||||
* @override
|
||||
*/
|
||||
dispose: function () {
|
||||
roams.unregister(this.api, this.dataZoomModel.id);
|
||||
InsideZoomView.superApply(this, 'dispose', arguments);
|
||||
this._range = null;
|
||||
},
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
_onPan: function (coordInfo, controller, dx, dy) {
|
||||
return (
|
||||
this._range = panCartesian(
|
||||
[dx, dy], this._range, controller, coordInfo
|
||||
)
|
||||
);
|
||||
},
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
_onZoom: function (coordInfo, controller, scale, mouseX, mouseY) {
|
||||
var dataZoomModel = this.dataZoomModel;
|
||||
|
||||
if (dataZoomModel.option.zoomLock) {
|
||||
return this._range;
|
||||
}
|
||||
|
||||
return (
|
||||
this._range = scaleCartesian(
|
||||
1 / scale, [mouseX, mouseY], this._range,
|
||||
controller, coordInfo, dataZoomModel
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
function panCartesian(pixelDeltas, range, controller, coordInfo) {
|
||||
range = range.slice();
|
||||
|
||||
// Calculate transform by the first axis.
|
||||
var axisModel = coordInfo.axisModels[0];
|
||||
if (!axisModel) {
|
||||
return;
|
||||
}
|
||||
|
||||
var directionInfo = getDirectionInfo(pixelDeltas, axisModel, controller);
|
||||
|
||||
var percentDelta = directionInfo.signal
|
||||
* (range[1] - range[0])
|
||||
* directionInfo.pixel / directionInfo.pixelLength;
|
||||
|
||||
sliderMove(
|
||||
percentDelta,
|
||||
range,
|
||||
[0, 100],
|
||||
'rigid'
|
||||
);
|
||||
|
||||
return range;
|
||||
}
|
||||
|
||||
function scaleCartesian(scale, mousePoint, range, controller, coordInfo, dataZoomModel) {
|
||||
range = range.slice();
|
||||
|
||||
// Calculate transform by the first axis.
|
||||
var axisModel = coordInfo.axisModels[0];
|
||||
if (!axisModel) {
|
||||
return;
|
||||
}
|
||||
|
||||
var directionInfo = getDirectionInfo(mousePoint, axisModel, controller);
|
||||
|
||||
var mouse = directionInfo.pixel - directionInfo.pixelStart;
|
||||
var percentPoint = mouse / directionInfo.pixelLength * (range[1] - range[0]) + range[0];
|
||||
|
||||
scale = Math.max(scale, 0);
|
||||
range[0] = (range[0] - percentPoint) * scale + percentPoint;
|
||||
range[1] = (range[1] - percentPoint) * scale + percentPoint;
|
||||
|
||||
return fixRange(range);
|
||||
}
|
||||
|
||||
function getDirectionInfo(xy, axisModel, controller) {
|
||||
var axis = axisModel.axis;
|
||||
var rect = controller.rectProvider();
|
||||
var ret = {};
|
||||
|
||||
if (axis.dim === 'x') {
|
||||
ret.pixel = xy[0];
|
||||
ret.pixelLength = rect.width;
|
||||
ret.pixelStart = rect.x;
|
||||
ret.signal = axis.inverse ? 1 : -1;
|
||||
}
|
||||
else { // axis.dim === 'y'
|
||||
ret.pixel = xy[1];
|
||||
ret.pixelLength = rect.height;
|
||||
ret.pixelStart = rect.y;
|
||||
ret.signal = axis.inverse ? -1 : 1;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
function fixRange(range) {
|
||||
// Clamp, using !(<= or >=) to handle NaN.
|
||||
// jshint ignore:start
|
||||
var bound = [0, 100];
|
||||
!(range[0] <= bound[1]) && (range[0] = bound[1]);
|
||||
!(range[1] <= bound[1]) && (range[1] = bound[1]);
|
||||
!(range[0] >= bound[0]) && (range[0] = bound[0]);
|
||||
!(range[1] >= bound[0]) && (range[1] = bound[0]);
|
||||
// jshint ignore:end
|
||||
|
||||
return range;
|
||||
}
|
||||
|
||||
return InsideZoomView;
|
||||
});
|
||||
14
vendors/echarts/src/component/dataZoom/SelectZoomModel.js
vendored
Normal file
14
vendors/echarts/src/component/dataZoom/SelectZoomModel.js
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
/**
|
||||
* @file Data zoom model
|
||||
*/
|
||||
define(function(require) {
|
||||
|
||||
var DataZoomModel = require('./DataZoomModel');
|
||||
|
||||
return DataZoomModel.extend({
|
||||
|
||||
type: 'dataZoom.select'
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
9
vendors/echarts/src/component/dataZoom/SelectZoomView.js
vendored
Normal file
9
vendors/echarts/src/component/dataZoom/SelectZoomView.js
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
define(function (require) {
|
||||
|
||||
return require('./DataZoomView').extend({
|
||||
|
||||
type: 'dataZoom.select'
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
57
vendors/echarts/src/component/dataZoom/SliderZoomModel.js
vendored
Normal file
57
vendors/echarts/src/component/dataZoom/SliderZoomModel.js
vendored
Normal file
@@ -0,0 +1,57 @@
|
||||
/**
|
||||
* @file Data zoom model
|
||||
*/
|
||||
define(function(require) {
|
||||
|
||||
var DataZoomModel = require('./DataZoomModel');
|
||||
|
||||
var SliderZoomModel = DataZoomModel.extend({
|
||||
|
||||
type: 'dataZoom.slider',
|
||||
|
||||
layoutMode: 'box',
|
||||
|
||||
/**
|
||||
* @protected
|
||||
*/
|
||||
defaultOption: {
|
||||
show: true,
|
||||
|
||||
// ph => placeholder. Using placehoder here because
|
||||
// deault value can only be drived in view stage.
|
||||
right: 'ph', // Default align to grid rect.
|
||||
top: 'ph', // Default align to grid rect.
|
||||
width: 'ph', // Default align to grid rect.
|
||||
height: 'ph', // Default align to grid rect.
|
||||
left: null, // Default align to grid rect.
|
||||
bottom: null, // Default align to grid rect.
|
||||
|
||||
backgroundColor: 'rgba(47,69,84,0)', // Background of slider zoom component.
|
||||
dataBackgroundColor: '#ddd', // Background of data shadow.
|
||||
fillerColor: 'rgba(47,69,84,0.15)', // Color of selected area.
|
||||
handleColor: 'rgba(148,164,165,0.95)', // Color of handle.
|
||||
handleSize: 10,
|
||||
|
||||
labelPrecision: null,
|
||||
labelFormatter: null,
|
||||
showDetail: true,
|
||||
showDataShadow: 'auto', // Default auto decision.
|
||||
realtime: true,
|
||||
zoomLock: false, // Whether disable zoom.
|
||||
textStyle: {
|
||||
color: '#333'
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* @override
|
||||
*/
|
||||
mergeOption: function (option) {
|
||||
SliderZoomModel.superApply(this, 'mergeOption', arguments);
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
return SliderZoomModel;
|
||||
|
||||
});
|
||||
700
vendors/echarts/src/component/dataZoom/SliderZoomView.js
vendored
Normal file
700
vendors/echarts/src/component/dataZoom/SliderZoomView.js
vendored
Normal file
@@ -0,0 +1,700 @@
|
||||
define(function (require) {
|
||||
|
||||
var zrUtil = require('zrender/core/util');
|
||||
var graphic = require('../../util/graphic');
|
||||
var throttle = require('../../util/throttle');
|
||||
var DataZoomView = require('./DataZoomView');
|
||||
var Rect = graphic.Rect;
|
||||
var numberUtil = require('../../util/number');
|
||||
var linearMap = numberUtil.linearMap;
|
||||
var layout = require('../../util/layout');
|
||||
var sliderMove = require('../helper/sliderMove');
|
||||
var asc = numberUtil.asc;
|
||||
var bind = zrUtil.bind;
|
||||
var mathRound = Math.round;
|
||||
var mathMax = Math.max;
|
||||
var each = zrUtil.each;
|
||||
|
||||
// Constants
|
||||
var DEFAULT_LOCATION_EDGE_GAP = 7;
|
||||
var DEFAULT_FRAME_BORDER_WIDTH = 1;
|
||||
var DEFAULT_FILLER_SIZE = 30;
|
||||
var HORIZONTAL = 'horizontal';
|
||||
var VERTICAL = 'vertical';
|
||||
var LABEL_GAP = 5;
|
||||
var SHOW_DATA_SHADOW_SERIES_TYPE = ['line', 'bar', 'candlestick', 'scatter'];
|
||||
|
||||
var SliderZoomView = DataZoomView.extend({
|
||||
|
||||
type: 'dataZoom.slider',
|
||||
|
||||
init: function (ecModel, api) {
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {Object}
|
||||
*/
|
||||
this._displayables = {};
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {string}
|
||||
*/
|
||||
this._orient;
|
||||
|
||||
/**
|
||||
* [0, 100]
|
||||
* @private
|
||||
*/
|
||||
this._range;
|
||||
|
||||
/**
|
||||
* [coord of the first handle, coord of the second handle]
|
||||
* @private
|
||||
*/
|
||||
this._handleEnds;
|
||||
|
||||
/**
|
||||
* [length, thick]
|
||||
* @private
|
||||
* @type {Array.<number>}
|
||||
*/
|
||||
this._size;
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {number}
|
||||
*/
|
||||
this._halfHandleSize;
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
this._location;
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
this._dragging;
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
this._dataShadowInfo;
|
||||
|
||||
this.api = api;
|
||||
},
|
||||
|
||||
/**
|
||||
* @override
|
||||
*/
|
||||
render: function (dataZoomModel, ecModel, api, payload) {
|
||||
SliderZoomView.superApply(this, 'render', arguments);
|
||||
|
||||
throttle.createOrUpdate(
|
||||
this,
|
||||
'_dispatchZoomAction',
|
||||
this.dataZoomModel.get('throttle'),
|
||||
'fixRate'
|
||||
);
|
||||
|
||||
this._orient = dataZoomModel.get('orient');
|
||||
this._halfHandleSize = mathRound(dataZoomModel.get('handleSize') / 2);
|
||||
|
||||
if (this.dataZoomModel.get('show') === false) {
|
||||
this.group.removeAll();
|
||||
return;
|
||||
}
|
||||
|
||||
// Notice: this._resetInterval() should not be executed when payload.type
|
||||
// is 'dataZoom', origin this._range should be maintained, otherwise 'pan'
|
||||
// or 'zoom' info will be missed because of 'throttle' of this.dispatchAction,
|
||||
if (!payload || payload.type !== 'dataZoom' || payload.from !== this.uid) {
|
||||
this._buildView();
|
||||
}
|
||||
|
||||
this._updateView();
|
||||
},
|
||||
|
||||
/**
|
||||
* @override
|
||||
*/
|
||||
remove: function () {
|
||||
SliderZoomView.superApply(this, 'remove', arguments);
|
||||
throttle.clear(this, '_dispatchZoomAction');
|
||||
},
|
||||
|
||||
/**
|
||||
* @override
|
||||
*/
|
||||
dispose: function () {
|
||||
SliderZoomView.superApply(this, 'dispose', arguments);
|
||||
throttle.clear(this, '_dispatchZoomAction');
|
||||
},
|
||||
|
||||
_buildView: function () {
|
||||
var thisGroup = this.group;
|
||||
|
||||
thisGroup.removeAll();
|
||||
|
||||
this._resetLocation();
|
||||
this._resetInterval();
|
||||
|
||||
var barGroup = this._displayables.barGroup = new graphic.Group();
|
||||
|
||||
this._renderBackground();
|
||||
this._renderDataShadow();
|
||||
this._renderHandle();
|
||||
|
||||
thisGroup.add(barGroup);
|
||||
|
||||
this._positionGroup();
|
||||
},
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
_resetLocation: function () {
|
||||
var dataZoomModel = this.dataZoomModel;
|
||||
var api = this.api;
|
||||
|
||||
// If some of x/y/width/height are not specified,
|
||||
// auto-adapt according to target grid.
|
||||
var coordRect = this._findCoordRect();
|
||||
var ecSize = {width: api.getWidth(), height: api.getHeight()};
|
||||
// Default align by coordinate system rect.
|
||||
var positionInfo = this._orient === HORIZONTAL
|
||||
? {
|
||||
// Why using 'right', because right should be used in vertical,
|
||||
// and it is better to be consistent for dealing with position param merge.
|
||||
right: ecSize.width - coordRect.x - coordRect.width,
|
||||
top: (ecSize.height - DEFAULT_FILLER_SIZE - DEFAULT_LOCATION_EDGE_GAP),
|
||||
width: coordRect.width,
|
||||
height: DEFAULT_FILLER_SIZE
|
||||
}
|
||||
: { // vertical
|
||||
right: DEFAULT_LOCATION_EDGE_GAP,
|
||||
top: coordRect.y,
|
||||
width: DEFAULT_FILLER_SIZE,
|
||||
height: coordRect.height
|
||||
};
|
||||
|
||||
// Do not write back to option and replace value 'ph', because
|
||||
// the 'ph' value should be recalculated when resize.
|
||||
var layoutParams = layout.getLayoutParams(dataZoomModel.option);
|
||||
|
||||
// Replace the placeholder value.
|
||||
zrUtil.each(['right', 'top', 'width', 'height'], function (name) {
|
||||
if (layoutParams[name] === 'ph') {
|
||||
layoutParams[name] = positionInfo[name];
|
||||
}
|
||||
});
|
||||
|
||||
var layoutRect = layout.getLayoutRect(
|
||||
layoutParams,
|
||||
ecSize,
|
||||
dataZoomModel.padding
|
||||
);
|
||||
|
||||
this._location = {x: layoutRect.x, y: layoutRect.y};
|
||||
this._size = [layoutRect.width, layoutRect.height];
|
||||
this._orient === VERTICAL && this._size.reverse();
|
||||
},
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
_positionGroup: function () {
|
||||
var thisGroup = this.group;
|
||||
var location = this._location;
|
||||
var orient = this._orient;
|
||||
|
||||
// Just use the first axis to determine mapping.
|
||||
var targetAxisModel = this.dataZoomModel.getFirstTargetAxisModel();
|
||||
var inverse = targetAxisModel && targetAxisModel.get('inverse');
|
||||
|
||||
var barGroup = this._displayables.barGroup;
|
||||
var otherAxisInverse = (this._dataShadowInfo || {}).otherAxisInverse;
|
||||
|
||||
// Transform barGroup.
|
||||
barGroup.attr(
|
||||
(orient === HORIZONTAL && !inverse)
|
||||
? {scale: otherAxisInverse ? [1, 1] : [1, -1]}
|
||||
: (orient === HORIZONTAL && inverse)
|
||||
? {scale: otherAxisInverse ? [-1, 1] : [-1, -1]}
|
||||
: (orient === VERTICAL && !inverse)
|
||||
? {scale: otherAxisInverse ? [1, -1] : [1, 1], rotation: Math.PI / 2}
|
||||
// Dont use Math.PI, considering shadow direction.
|
||||
: {scale: otherAxisInverse ? [-1, -1] : [-1, 1], rotation: Math.PI / 2}
|
||||
);
|
||||
|
||||
// Position barGroup
|
||||
var rect = thisGroup.getBoundingRect([barGroup]);
|
||||
thisGroup.position[0] = location.x - rect.x;
|
||||
thisGroup.position[1] = location.y - rect.y;
|
||||
},
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
_getViewExtent: function () {
|
||||
// View total length.
|
||||
var halfHandleSize = this._halfHandleSize;
|
||||
var totalLength = mathMax(this._size[0], halfHandleSize * 4);
|
||||
var extent = [halfHandleSize, totalLength - halfHandleSize];
|
||||
|
||||
return extent;
|
||||
},
|
||||
|
||||
_renderBackground : function () {
|
||||
var dataZoomModel = this.dataZoomModel;
|
||||
var size = this._size;
|
||||
|
||||
this._displayables.barGroup.add(new Rect({
|
||||
silent: true,
|
||||
shape: {
|
||||
x: 0, y: 0, width: size[0], height: size[1]
|
||||
},
|
||||
style: {
|
||||
fill: dataZoomModel.get('backgroundColor')
|
||||
}
|
||||
}));
|
||||
},
|
||||
|
||||
_renderDataShadow: function () {
|
||||
var info = this._dataShadowInfo = this._prepareDataShadowInfo();
|
||||
|
||||
if (!info) {
|
||||
return;
|
||||
}
|
||||
|
||||
var size = this._size;
|
||||
var seriesModel = info.series;
|
||||
var data = seriesModel.getRawData();
|
||||
var otherDim = seriesModel.getShadowDim
|
||||
? seriesModel.getShadowDim() // @see candlestick
|
||||
: info.otherDim;
|
||||
|
||||
var otherDataExtent = data.getDataExtent(otherDim);
|
||||
// Nice extent.
|
||||
var otherOffset = (otherDataExtent[1] - otherDataExtent[0]) * 0.3;
|
||||
otherDataExtent = [
|
||||
otherDataExtent[0] - otherOffset,
|
||||
otherDataExtent[1] + otherOffset
|
||||
];
|
||||
var otherShadowExtent = [0, size[1]];
|
||||
|
||||
var thisShadowExtent = [0, size[0]];
|
||||
|
||||
var points = [[size[0], 0], [0, 0]];
|
||||
var step = thisShadowExtent[1] / (data.count() - 1);
|
||||
var thisCoord = 0;
|
||||
|
||||
// Optimize for large data shadow
|
||||
var stride = Math.round(data.count() / size[0]);
|
||||
data.each([otherDim], function (value, index) {
|
||||
if (stride > 0 && (index % stride)) {
|
||||
thisCoord += step;
|
||||
return;
|
||||
}
|
||||
// FIXME
|
||||
// 应该使用统计的空判断?还是在list里进行空判断?
|
||||
var otherCoord = (value == null || isNaN(value) || value === '')
|
||||
? null
|
||||
: linearMap(value, otherDataExtent, otherShadowExtent, true);
|
||||
otherCoord != null && points.push([thisCoord, otherCoord]);
|
||||
|
||||
thisCoord += step;
|
||||
});
|
||||
|
||||
this._displayables.barGroup.add(new graphic.Polyline({
|
||||
shape: {points: points},
|
||||
style: {fill: this.dataZoomModel.get('dataBackgroundColor'), lineWidth: 0},
|
||||
silent: true,
|
||||
z2: -20
|
||||
}));
|
||||
},
|
||||
|
||||
_prepareDataShadowInfo: function () {
|
||||
var dataZoomModel = this.dataZoomModel;
|
||||
var showDataShadow = dataZoomModel.get('showDataShadow');
|
||||
|
||||
if (showDataShadow === false) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Find a representative series.
|
||||
var result;
|
||||
var ecModel = this.ecModel;
|
||||
|
||||
dataZoomModel.eachTargetAxis(function (dimNames, axisIndex) {
|
||||
var seriesModels = dataZoomModel
|
||||
.getAxisProxy(dimNames.name, axisIndex)
|
||||
.getTargetSeriesModels();
|
||||
|
||||
zrUtil.each(seriesModels, function (seriesModel) {
|
||||
if (result) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (showDataShadow !== true && zrUtil.indexOf(
|
||||
SHOW_DATA_SHADOW_SERIES_TYPE, seriesModel.get('type')
|
||||
) < 0
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
var otherDim = getOtherDim(dimNames.name);
|
||||
|
||||
var thisAxis = ecModel.getComponent(dimNames.axis, axisIndex).axis;
|
||||
|
||||
result = {
|
||||
thisAxis: thisAxis,
|
||||
series: seriesModel,
|
||||
thisDim: dimNames.name,
|
||||
otherDim: otherDim,
|
||||
otherAxisInverse: seriesModel
|
||||
.coordinateSystem.getOtherAxis(thisAxis).inverse
|
||||
};
|
||||
|
||||
}, this);
|
||||
|
||||
}, this);
|
||||
|
||||
return result;
|
||||
},
|
||||
|
||||
_renderHandle: function () {
|
||||
var displaybles = this._displayables;
|
||||
var handles = displaybles.handles = [];
|
||||
var handleLabels = displaybles.handleLabels = [];
|
||||
var barGroup = this._displayables.barGroup;
|
||||
var size = this._size;
|
||||
|
||||
barGroup.add(displaybles.filler = new Rect({
|
||||
draggable: true,
|
||||
cursor: 'move',
|
||||
drift: bind(this._onDragMove, this, 'all'),
|
||||
ondragend: bind(this._onDragEnd, this),
|
||||
onmouseover: bind(this._showDataInfo, this, true),
|
||||
onmouseout: bind(this._showDataInfo, this, false),
|
||||
style: {
|
||||
fill: this.dataZoomModel.get('fillerColor'),
|
||||
// text: ':::',
|
||||
textPosition : 'inside'
|
||||
}
|
||||
}));
|
||||
|
||||
// Frame border.
|
||||
barGroup.add(new Rect(graphic.subPixelOptimizeRect({
|
||||
silent: true,
|
||||
shape: {
|
||||
x: 0,
|
||||
y: 0,
|
||||
width: size[0],
|
||||
height: size[1]
|
||||
},
|
||||
style: {
|
||||
stroke: this.dataZoomModel.get('dataBackgroundColor'),
|
||||
lineWidth: DEFAULT_FRAME_BORDER_WIDTH,
|
||||
fill: 'rgba(0,0,0,0)'
|
||||
}
|
||||
})));
|
||||
|
||||
each([0, 1], function (handleIndex) {
|
||||
|
||||
barGroup.add(handles[handleIndex] = new Rect({
|
||||
style: {
|
||||
fill: this.dataZoomModel.get('handleColor')
|
||||
},
|
||||
cursor: 'move',
|
||||
draggable: true,
|
||||
drift: bind(this._onDragMove, this, handleIndex),
|
||||
ondragend: bind(this._onDragEnd, this),
|
||||
onmouseover: bind(this._showDataInfo, this, true),
|
||||
onmouseout: bind(this._showDataInfo, this, false)
|
||||
}));
|
||||
|
||||
var textStyleModel = this.dataZoomModel.textStyleModel;
|
||||
|
||||
this.group.add(
|
||||
handleLabels[handleIndex] = new graphic.Text({
|
||||
silent: true,
|
||||
invisible: true,
|
||||
style: {
|
||||
x: 0, y: 0, text: '',
|
||||
textVerticalAlign: 'middle',
|
||||
textAlign: 'center',
|
||||
fill: textStyleModel.getTextColor(),
|
||||
textFont: textStyleModel.getFont()
|
||||
}
|
||||
}));
|
||||
|
||||
}, this);
|
||||
},
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
_resetInterval: function () {
|
||||
var range = this._range = this.dataZoomModel.getPercentRange();
|
||||
var viewExtent = this._getViewExtent();
|
||||
|
||||
this._handleEnds = [
|
||||
linearMap(range[0], [0, 100], viewExtent, true),
|
||||
linearMap(range[1], [0, 100], viewExtent, true)
|
||||
];
|
||||
},
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @param {(number|string)} handleIndex 0 or 1 or 'all'
|
||||
* @param {number} dx
|
||||
* @param {number} dy
|
||||
*/
|
||||
_updateInterval: function (handleIndex, delta) {
|
||||
var handleEnds = this._handleEnds;
|
||||
var viewExtend = this._getViewExtent();
|
||||
|
||||
sliderMove(
|
||||
delta,
|
||||
handleEnds,
|
||||
viewExtend,
|
||||
(handleIndex === 'all' || this.dataZoomModel.get('zoomLock'))
|
||||
? 'rigid' : 'cross',
|
||||
handleIndex
|
||||
);
|
||||
|
||||
this._range = asc([
|
||||
linearMap(handleEnds[0], viewExtend, [0, 100], true),
|
||||
linearMap(handleEnds[1], viewExtend, [0, 100], true)
|
||||
]);
|
||||
},
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
_updateView: function () {
|
||||
var displaybles = this._displayables;
|
||||
var handleEnds = this._handleEnds;
|
||||
var handleInterval = asc(handleEnds.slice());
|
||||
var size = this._size;
|
||||
var halfHandleSize = this._halfHandleSize;
|
||||
|
||||
each([0, 1], function (handleIndex) {
|
||||
|
||||
// Handles
|
||||
var handle = displaybles.handles[handleIndex];
|
||||
handle.setShape({
|
||||
x: handleEnds[handleIndex] - halfHandleSize,
|
||||
y: -1,
|
||||
width: halfHandleSize * 2,
|
||||
height: size[1] + 2,
|
||||
r: 1
|
||||
});
|
||||
|
||||
}, this);
|
||||
|
||||
// Filler
|
||||
displaybles.filler.setShape({
|
||||
x: handleInterval[0],
|
||||
y: 0,
|
||||
width: handleInterval[1] - handleInterval[0],
|
||||
height: this._size[1]
|
||||
});
|
||||
|
||||
this._updateDataInfo();
|
||||
},
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
_updateDataInfo: function () {
|
||||
var dataZoomModel = this.dataZoomModel;
|
||||
var displaybles = this._displayables;
|
||||
var handleLabels = displaybles.handleLabels;
|
||||
var orient = this._orient;
|
||||
var labelTexts = ['', ''];
|
||||
|
||||
// FIXME
|
||||
// date型,支持formatter,autoformatter(ec2 date.getAutoFormatter)
|
||||
if (dataZoomModel.get('showDetail')) {
|
||||
var dataInterval;
|
||||
var axis;
|
||||
dataZoomModel.eachTargetAxis(function (dimNames, axisIndex) {
|
||||
// Using dataInterval of the first axis.
|
||||
if (!dataInterval) {
|
||||
dataInterval = dataZoomModel
|
||||
.getAxisProxy(dimNames.name, axisIndex)
|
||||
.getDataValueWindow();
|
||||
axis = this.ecModel.getComponent(dimNames.axis, axisIndex).axis;
|
||||
}
|
||||
}, this);
|
||||
|
||||
if (dataInterval) {
|
||||
labelTexts = [
|
||||
this._formatLabel(dataInterval[0], axis),
|
||||
this._formatLabel(dataInterval[1], axis)
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
var orderedHandleEnds = asc(this._handleEnds.slice());
|
||||
|
||||
setLabel.call(this, 0);
|
||||
setLabel.call(this, 1);
|
||||
|
||||
function setLabel(handleIndex) {
|
||||
// Label
|
||||
// Text should not transform by barGroup.
|
||||
var barTransform = graphic.getTransform(
|
||||
displaybles.handles[handleIndex], this.group
|
||||
);
|
||||
var direction = graphic.transformDirection(
|
||||
handleIndex === 0 ? 'right' : 'left', barTransform
|
||||
);
|
||||
var offset = this._halfHandleSize + LABEL_GAP;
|
||||
var textPoint = graphic.applyTransform(
|
||||
[
|
||||
orderedHandleEnds[handleIndex] + (handleIndex === 0 ? -offset : offset),
|
||||
this._size[1] / 2
|
||||
],
|
||||
barTransform
|
||||
);
|
||||
handleLabels[handleIndex].setStyle({
|
||||
x: textPoint[0],
|
||||
y: textPoint[1],
|
||||
textVerticalAlign: orient === HORIZONTAL ? 'middle' : direction,
|
||||
textAlign: orient === HORIZONTAL ? direction : 'center',
|
||||
text: labelTexts[handleIndex]
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
_formatLabel: function (value, axis) {
|
||||
var dataZoomModel = this.dataZoomModel;
|
||||
var labelFormatter = dataZoomModel.get('labelFormatter');
|
||||
if (zrUtil.isFunction(labelFormatter)) {
|
||||
return labelFormatter(value);
|
||||
}
|
||||
|
||||
var labelPrecision = dataZoomModel.get('labelPrecision');
|
||||
if (labelPrecision == null || labelPrecision === 'auto') {
|
||||
labelPrecision = axis.getPixelPrecision();
|
||||
}
|
||||
|
||||
value = (value == null && isNaN(value))
|
||||
? ''
|
||||
// FIXME Glue code
|
||||
: (axis.type === 'category' || axis.type === 'time')
|
||||
? axis.scale.getLabel(Math.round(value))
|
||||
// param of toFixed should less then 20.
|
||||
: value.toFixed(Math.min(labelPrecision, 20));
|
||||
|
||||
if (zrUtil.isString(labelFormatter)) {
|
||||
value = labelFormatter.replace('{value}', value);
|
||||
}
|
||||
|
||||
return value;
|
||||
},
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @param {boolean} showOrHide true: show, false: hide
|
||||
*/
|
||||
_showDataInfo: function (showOrHide) {
|
||||
// Always show when drgging.
|
||||
showOrHide = this._dragging || showOrHide;
|
||||
|
||||
var handleLabels = this._displayables.handleLabels;
|
||||
handleLabels[0].attr('invisible', !showOrHide);
|
||||
handleLabels[1].attr('invisible', !showOrHide);
|
||||
},
|
||||
|
||||
_onDragMove: function (handleIndex, dx, dy) {
|
||||
this._dragging = true;
|
||||
|
||||
// Transform dx, dy to bar coordination.
|
||||
var vertex = this._applyBarTransform([dx, dy], true);
|
||||
|
||||
this._updateInterval(handleIndex, vertex[0]);
|
||||
this._updateView();
|
||||
|
||||
if (this.dataZoomModel.get('realtime')) {
|
||||
this._dispatchZoomAction();
|
||||
}
|
||||
},
|
||||
|
||||
_onDragEnd: function () {
|
||||
this._dragging = false;
|
||||
this._showDataInfo(false);
|
||||
this._dispatchZoomAction();
|
||||
},
|
||||
|
||||
/**
|
||||
* This action will be throttled.
|
||||
* @private
|
||||
*/
|
||||
_dispatchZoomAction: function () {
|
||||
var range = this._range;
|
||||
|
||||
this.api.dispatchAction({
|
||||
type: 'dataZoom',
|
||||
from: this.uid,
|
||||
dataZoomId: this.dataZoomModel.id,
|
||||
start: range[0],
|
||||
end: range[1]
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
_applyBarTransform: function (vertex, inverse) {
|
||||
var barTransform = this._displayables.barGroup.getLocalTransform();
|
||||
return graphic.applyTransform(vertex, barTransform, inverse);
|
||||
},
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
_findCoordRect: function () {
|
||||
// Find the grid coresponding to the first axis referred by dataZoom.
|
||||
var targetInfo = this.getTargetInfo();
|
||||
|
||||
// FIXME
|
||||
// 判断是catesian还是polar
|
||||
var rect;
|
||||
if (targetInfo.cartesians.length) {
|
||||
rect = targetInfo.cartesians[0].model.coordinateSystem.getRect();
|
||||
}
|
||||
else { // Polar
|
||||
// FIXME
|
||||
// 暂时随便写的
|
||||
var width = this.api.getWidth();
|
||||
var height = this.api.getHeight();
|
||||
rect = {
|
||||
x: width * 0.2,
|
||||
y: height * 0.2,
|
||||
width: width * 0.6,
|
||||
height: height * 0.6
|
||||
};
|
||||
}
|
||||
|
||||
return rect;
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
function getOtherDim(thisDim) {
|
||||
// FIXME
|
||||
// 这个逻辑和getOtherAxis里一致,但是写在这里是否不好
|
||||
return thisDim === 'x' ? 'y' : 'x';
|
||||
}
|
||||
|
||||
return SliderZoomView;
|
||||
|
||||
});
|
||||
43
vendors/echarts/src/component/dataZoom/dataZoomAction.js
vendored
Normal file
43
vendors/echarts/src/component/dataZoom/dataZoomAction.js
vendored
Normal file
@@ -0,0 +1,43 @@
|
||||
/**
|
||||
* @file Data zoom action
|
||||
*/
|
||||
define(function(require) {
|
||||
|
||||
var zrUtil = require('zrender/core/util');
|
||||
var modelUtil = require('../../util/model');
|
||||
var echarts = require('../../echarts');
|
||||
|
||||
|
||||
echarts.registerAction('dataZoom', function (payload, ecModel) {
|
||||
|
||||
var linkedNodesFinder = modelUtil.createLinkedNodesFinder(
|
||||
zrUtil.bind(ecModel.eachComponent, ecModel, 'dataZoom'),
|
||||
modelUtil.eachAxisDim,
|
||||
function (model, dimNames) {
|
||||
return model.get(dimNames.axisIndex);
|
||||
}
|
||||
);
|
||||
|
||||
var effectedModels = [];
|
||||
|
||||
ecModel.eachComponent(
|
||||
{mainType: 'dataZoom', query: payload},
|
||||
function (model, index) {
|
||||
effectedModels.push.apply(
|
||||
effectedModels, linkedNodesFinder(model).nodes
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
zrUtil.each(effectedModels, function (dataZoomModel, index) {
|
||||
dataZoomModel.setRawRange({
|
||||
start: payload.start,
|
||||
end: payload.end,
|
||||
startValue: payload.startValue,
|
||||
endValue: payload.endValue
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
57
vendors/echarts/src/component/dataZoom/dataZoomProcessor.js
vendored
Normal file
57
vendors/echarts/src/component/dataZoom/dataZoomProcessor.js
vendored
Normal file
@@ -0,0 +1,57 @@
|
||||
/**
|
||||
* @file Data zoom processor
|
||||
*/
|
||||
define(function (require) {
|
||||
|
||||
var echarts = require('../../echarts');
|
||||
|
||||
echarts.registerProcessor('filter', function (ecModel, api) {
|
||||
|
||||
ecModel.eachComponent('dataZoom', function (dataZoomModel) {
|
||||
// We calculate window and reset axis here but not in model
|
||||
// init stage and not after action dispatch handler, because
|
||||
// reset should be called after seriesData.restoreData.
|
||||
dataZoomModel.eachTargetAxis(resetSingleAxis);
|
||||
|
||||
// Caution: data zoom filtering is order sensitive when using
|
||||
// percent range and no min/max/scale set on axis.
|
||||
// For example, we have dataZoom definition:
|
||||
// [
|
||||
// {xAxisIndex: 0, start: 30, end: 70},
|
||||
// {yAxisIndex: 0, start: 20, end: 80}
|
||||
// ]
|
||||
// In this case, [20, 80] of y-dataZoom should be based on data
|
||||
// that have filtered by x-dataZoom using range of [30, 70],
|
||||
// but should not be based on full raw data. Thus sliding
|
||||
// x-dataZoom will change both ranges of xAxis and yAxis,
|
||||
// while sliding y-dataZoom will only change the range of yAxis.
|
||||
// So we should filter x-axis after reset x-axis immediately,
|
||||
// and then reset y-axis and filter y-axis.
|
||||
dataZoomModel.eachTargetAxis(filterSingleAxis);
|
||||
});
|
||||
|
||||
ecModel.eachComponent('dataZoom', function (dataZoomModel) {
|
||||
// Fullfill all of the range props so that user
|
||||
// is able to get them from chart.getOption().
|
||||
var axisProxy = dataZoomModel.findRepresentativeAxisProxy();
|
||||
var percentRange = axisProxy.getDataPercentWindow();
|
||||
var valueRange = axisProxy.getDataValueWindow();
|
||||
|
||||
dataZoomModel.setRawRange({
|
||||
start: percentRange[0],
|
||||
end: percentRange[1],
|
||||
startValue: valueRange[0],
|
||||
endValue: valueRange[1]
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
function resetSingleAxis(dimNames, axisIndex, dataZoomModel) {
|
||||
dataZoomModel.getAxisProxy(dimNames.name, axisIndex).reset(dataZoomModel);
|
||||
}
|
||||
|
||||
function filterSingleAxis(dimNames, axisIndex, dataZoomModel) {
|
||||
dataZoomModel.getAxisProxy(dimNames.name, axisIndex).filterData(dataZoomModel);
|
||||
}
|
||||
|
||||
});
|
||||
109
vendors/echarts/src/component/dataZoom/history.js
vendored
Normal file
109
vendors/echarts/src/component/dataZoom/history.js
vendored
Normal file
@@ -0,0 +1,109 @@
|
||||
/**
|
||||
* @file History manager.
|
||||
*/
|
||||
define(function(require) {
|
||||
|
||||
var zrUtil = require('zrender/core/util');
|
||||
var each = zrUtil.each;
|
||||
|
||||
var ATTR = '\0_ec_hist_store';
|
||||
|
||||
var history = {
|
||||
|
||||
/**
|
||||
* @public
|
||||
* @param {module:echarts/model/Global} ecModel
|
||||
* @param {Object} newSnapshot {dataZoomId, batch: [payloadInfo, ...]}
|
||||
*/
|
||||
push: function (ecModel, newSnapshot) {
|
||||
var store = giveStore(ecModel);
|
||||
|
||||
// If previous dataZoom can not be found,
|
||||
// complete an range with current range.
|
||||
each(newSnapshot, function (batchItem, dataZoomId) {
|
||||
var i = store.length - 1;
|
||||
for (; i >= 0; i--) {
|
||||
var snapshot = store[i];
|
||||
if (snapshot[dataZoomId]) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (i < 0) {
|
||||
// No origin range set, create one by current range.
|
||||
var dataZoomModel = ecModel.queryComponents(
|
||||
{mainType: 'dataZoom', subType: 'select', id: dataZoomId}
|
||||
)[0];
|
||||
if (dataZoomModel) {
|
||||
var percentRange = dataZoomModel.getPercentRange();
|
||||
store[0][dataZoomId] = {
|
||||
dataZoomId: dataZoomId,
|
||||
start: percentRange[0],
|
||||
end: percentRange[1]
|
||||
};
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
store.push(newSnapshot);
|
||||
},
|
||||
|
||||
/**
|
||||
* @public
|
||||
* @param {module:echarts/model/Global} ecModel
|
||||
* @return {Object} snapshot
|
||||
*/
|
||||
pop: function (ecModel) {
|
||||
var store = giveStore(ecModel);
|
||||
var head = store[store.length - 1];
|
||||
store.length > 1 && store.pop();
|
||||
|
||||
// Find top for all dataZoom.
|
||||
var snapshot = {};
|
||||
each(head, function (batchItem, dataZoomId) {
|
||||
for (var i = store.length - 1; i >= 0; i--) {
|
||||
var batchItem = store[i][dataZoomId];
|
||||
if (batchItem) {
|
||||
snapshot[dataZoomId] = batchItem;
|
||||
break;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return snapshot;
|
||||
},
|
||||
|
||||
/**
|
||||
* @public
|
||||
*/
|
||||
clear: function (ecModel) {
|
||||
ecModel[ATTR] = null;
|
||||
},
|
||||
|
||||
/**
|
||||
* @public
|
||||
* @param {module:echarts/model/Global} ecModel
|
||||
* @return {number} records. always >= 1.
|
||||
*/
|
||||
count: function (ecModel) {
|
||||
return giveStore(ecModel).length;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* [{key: dataZoomId, value: {dataZoomId, range}}, ...]
|
||||
* History length of each dataZoom may be different.
|
||||
* this._history[0] is used to store origin range.
|
||||
* @type {Array.<Object>}
|
||||
*/
|
||||
function giveStore(ecModel) {
|
||||
var store = ecModel[ATTR];
|
||||
if (!store) {
|
||||
store = ecModel[ATTR] = [{}];
|
||||
}
|
||||
return store;
|
||||
}
|
||||
|
||||
return history;
|
||||
|
||||
});
|
||||
192
vendors/echarts/src/component/dataZoom/roams.js
vendored
Normal file
192
vendors/echarts/src/component/dataZoom/roams.js
vendored
Normal file
@@ -0,0 +1,192 @@
|
||||
/**
|
||||
* @file Roam controller manager.
|
||||
*/
|
||||
define(function(require) {
|
||||
|
||||
// Only create one roam controller for each coordinate system.
|
||||
// one roam controller might be refered by two inside data zoom
|
||||
// components (for example, one for x and one for y). When user
|
||||
// pan or zoom, only dispatch one action for those data zoom
|
||||
// components.
|
||||
|
||||
var zrUtil = require('zrender/core/util');
|
||||
var RoamController = require('../../component/helper/RoamController');
|
||||
var throttle = require('../../util/throttle');
|
||||
var curry = zrUtil.curry;
|
||||
|
||||
var ATTR = '\0_ec_dataZoom_roams';
|
||||
|
||||
var roams = {
|
||||
|
||||
/**
|
||||
* @public
|
||||
* @param {module:echarts/ExtensionAPI} api
|
||||
* @param {Object} dataZoomInfo
|
||||
* @param {string} dataZoomInfo.coordId
|
||||
* @param {Object} dataZoomInfo.coordinateSystem
|
||||
* @param {Array.<string>} dataZoomInfo.allCoordIds
|
||||
* @param {string} dataZoomInfo.dataZoomId
|
||||
* @param {number} dataZoomInfo.throttleRate
|
||||
* @param {Function} dataZoomInfo.panGetRange
|
||||
* @param {Function} dataZoomInfo.zoomGetRange
|
||||
*/
|
||||
register: function (api, dataZoomInfo) {
|
||||
var store = giveStore(api);
|
||||
var theDataZoomId = dataZoomInfo.dataZoomId;
|
||||
var theCoordId = dataZoomInfo.coordId;
|
||||
|
||||
// Do clean when a dataZoom changes its target coordnate system.
|
||||
zrUtil.each(store, function (record, coordId) {
|
||||
var dataZoomInfos = record.dataZoomInfos;
|
||||
if (dataZoomInfos[theDataZoomId]
|
||||
&& zrUtil.indexOf(dataZoomInfo.allCoordIds, theCoordId) < 0
|
||||
) {
|
||||
delete dataZoomInfos[theDataZoomId];
|
||||
record.count--;
|
||||
}
|
||||
});
|
||||
|
||||
cleanStore(store);
|
||||
|
||||
var record = store[theCoordId];
|
||||
|
||||
// Create if needed.
|
||||
if (!record) {
|
||||
record = store[theCoordId] = {
|
||||
coordId: theCoordId,
|
||||
dataZoomInfos: {},
|
||||
count: 0
|
||||
};
|
||||
record.controller = createController(api, dataZoomInfo, record);
|
||||
record.dispatchAction = zrUtil.curry(dispatchAction, api);
|
||||
}
|
||||
|
||||
// Consider resize, area should be always updated.
|
||||
var rect = dataZoomInfo.coordinateSystem.getRect().clone();
|
||||
record.controller.rectProvider = function () {
|
||||
return rect;
|
||||
};
|
||||
|
||||
// Update throttle.
|
||||
throttle.createOrUpdate(
|
||||
record,
|
||||
'dispatchAction',
|
||||
dataZoomInfo.throttleRate,
|
||||
'fixRate'
|
||||
);
|
||||
|
||||
// Update reference of dataZoom.
|
||||
!(record.dataZoomInfos[theDataZoomId]) && record.count++;
|
||||
record.dataZoomInfos[theDataZoomId] = dataZoomInfo;
|
||||
},
|
||||
|
||||
/**
|
||||
* @public
|
||||
* @param {module:echarts/ExtensionAPI} api
|
||||
* @param {string} dataZoomId
|
||||
*/
|
||||
unregister: function (api, dataZoomId) {
|
||||
var store = giveStore(api);
|
||||
|
||||
zrUtil.each(store, function (record) {
|
||||
var dataZoomInfos = record.dataZoomInfos;
|
||||
if (dataZoomInfos[dataZoomId]) {
|
||||
delete dataZoomInfos[dataZoomId];
|
||||
record.count--;
|
||||
}
|
||||
});
|
||||
|
||||
cleanStore(store);
|
||||
},
|
||||
|
||||
/**
|
||||
* @public
|
||||
*/
|
||||
shouldRecordRange: function (payload, dataZoomId) {
|
||||
if (payload && payload.type === 'dataZoom' && payload.batch) {
|
||||
for (var i = 0, len = payload.batch.length; i < len; i++) {
|
||||
if (payload.batch[i].dataZoomId === dataZoomId) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
},
|
||||
|
||||
/**
|
||||
* @public
|
||||
*/
|
||||
generateCoordId: function (coordModel) {
|
||||
return coordModel.type + '\0_' + coordModel.id;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Key: coordId, value: {dataZoomInfos: [], count, controller}
|
||||
* @type {Array.<Object>}
|
||||
*/
|
||||
function giveStore(api) {
|
||||
// Mount store on zrender instance, so that we do not
|
||||
// need to worry about dispose.
|
||||
var zr = api.getZr();
|
||||
return zr[ATTR] || (zr[ATTR] = {});
|
||||
}
|
||||
|
||||
function createController(api, dataZoomInfo, newRecord) {
|
||||
var controller = new RoamController(api.getZr());
|
||||
controller.enable();
|
||||
controller.on('pan', curry(onPan, newRecord));
|
||||
controller.on('zoom', curry(onZoom, newRecord));
|
||||
|
||||
return controller;
|
||||
}
|
||||
|
||||
function cleanStore(store) {
|
||||
zrUtil.each(store, function (record, coordId) {
|
||||
if (!record.count) {
|
||||
record.controller.off('pan').off('zoom');
|
||||
delete store[coordId];
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function onPan(record, dx, dy) {
|
||||
wrapAndDispatch(record, function (info) {
|
||||
return info.panGetRange(record.controller, dx, dy);
|
||||
});
|
||||
}
|
||||
|
||||
function onZoom(record, scale, mouseX, mouseY) {
|
||||
wrapAndDispatch(record, function (info) {
|
||||
return info.zoomGetRange(record.controller, scale, mouseX, mouseY);
|
||||
});
|
||||
}
|
||||
|
||||
function wrapAndDispatch(record, getRange) {
|
||||
var batch = [];
|
||||
|
||||
zrUtil.each(record.dataZoomInfos, function (info) {
|
||||
var range = getRange(info);
|
||||
range && batch.push({
|
||||
dataZoomId: info.dataZoomId,
|
||||
start: range[0],
|
||||
end: range[1]
|
||||
});
|
||||
});
|
||||
|
||||
record.dispatchAction(batch);
|
||||
}
|
||||
|
||||
/**
|
||||
* This action will be throttled.
|
||||
*/
|
||||
function dispatchAction(api, batch) {
|
||||
api.dispatchAction({
|
||||
type: 'dataZoom',
|
||||
batch: batch
|
||||
});
|
||||
}
|
||||
|
||||
return roams;
|
||||
|
||||
});
|
||||
8
vendors/echarts/src/component/dataZoom/typeDefaulter.js
vendored
Normal file
8
vendors/echarts/src/component/dataZoom/typeDefaulter.js
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
define(function (require) {
|
||||
|
||||
require('../../model/Component').registerSubTypeDefaulter('dataZoom', function (option) {
|
||||
// Default 'slider' when no type specified.
|
||||
return 'slider';
|
||||
});
|
||||
|
||||
});
|
||||
17
vendors/echarts/src/component/dataZoomInside.js
vendored
Normal file
17
vendors/echarts/src/component/dataZoomInside.js
vendored
Normal file
@@ -0,0 +1,17 @@
|
||||
/**
|
||||
* DataZoom component entry
|
||||
*/
|
||||
define(function (require) {
|
||||
|
||||
require('./dataZoom/typeDefaulter');
|
||||
|
||||
require('./dataZoom/DataZoomModel');
|
||||
require('./dataZoom/DataZoomView');
|
||||
|
||||
require('./dataZoom/InsideZoomModel');
|
||||
require('./dataZoom/InsideZoomView');
|
||||
|
||||
require('./dataZoom/dataZoomProcessor');
|
||||
require('./dataZoom/dataZoomAction');
|
||||
|
||||
});
|
||||
17
vendors/echarts/src/component/dataZoomSelect.js
vendored
Normal file
17
vendors/echarts/src/component/dataZoomSelect.js
vendored
Normal file
@@ -0,0 +1,17 @@
|
||||
/**
|
||||
* DataZoom component entry
|
||||
*/
|
||||
define(function (require) {
|
||||
|
||||
require('./dataZoom/typeDefaulter');
|
||||
|
||||
require('./dataZoom/DataZoomModel');
|
||||
require('./dataZoom/DataZoomView');
|
||||
|
||||
require('./dataZoom/SelectZoomModel');
|
||||
require('./dataZoom/SelectZoomView');
|
||||
|
||||
require('./dataZoom/dataZoomProcessor');
|
||||
require('./dataZoom/dataZoomAction');
|
||||
|
||||
});
|
||||
49
vendors/echarts/src/component/geo.js
vendored
Normal file
49
vendors/echarts/src/component/geo.js
vendored
Normal file
@@ -0,0 +1,49 @@
|
||||
define(function (require) {
|
||||
|
||||
require('../coord/geo/GeoModel');
|
||||
|
||||
require('../coord/geo/geoCreator');
|
||||
|
||||
require('./geo/GeoView');
|
||||
|
||||
require('../action/geoRoam');
|
||||
|
||||
var echarts = require('../echarts');
|
||||
var zrUtil = require('zrender/core/util');
|
||||
|
||||
function makeAction(method, actionInfo) {
|
||||
actionInfo.update = 'updateView';
|
||||
echarts.registerAction(actionInfo, function (payload, ecModel) {
|
||||
var selected = {};
|
||||
|
||||
ecModel.eachComponent(
|
||||
{ mainType: 'geo', query: payload},
|
||||
function (geoModel) {
|
||||
geoModel[method](payload.name);
|
||||
var geo = geoModel.coordinateSystem;
|
||||
zrUtil.each(geo.regions, function (region) {
|
||||
selected[region.name] = geoModel.isSelected(region.name) || false;
|
||||
});
|
||||
}
|
||||
);
|
||||
|
||||
return {
|
||||
selected: selected,
|
||||
name: payload.name
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
makeAction('toggleSelected', {
|
||||
type: 'geoToggleSelect',
|
||||
event: 'geoselectchanged'
|
||||
});
|
||||
makeAction('select', {
|
||||
type: 'geoSelect',
|
||||
event: 'geoselected'
|
||||
});
|
||||
makeAction('unSelect', {
|
||||
type: 'geoUnSelect',
|
||||
event: 'geounselected'
|
||||
});
|
||||
});
|
||||
35
vendors/echarts/src/component/geo/GeoView.js
vendored
Normal file
35
vendors/echarts/src/component/geo/GeoView.js
vendored
Normal file
@@ -0,0 +1,35 @@
|
||||
define(function (require) {
|
||||
|
||||
'use strict';
|
||||
|
||||
var MapDraw = require('../helper/MapDraw');
|
||||
|
||||
return require('../../echarts').extendComponentView({
|
||||
|
||||
type: 'geo',
|
||||
|
||||
init: function (ecModel, api) {
|
||||
var mapDraw = new MapDraw(api, true);
|
||||
this._mapDraw = mapDraw;
|
||||
|
||||
this.group.add(mapDraw.group);
|
||||
},
|
||||
|
||||
render: function (geoModel, ecModel, api, payload) {
|
||||
// Not render if it is an toggleSelect action from self
|
||||
if (payload && payload.type === 'geoToggleSelect'
|
||||
&& payload.from === this.uid
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
var mapDraw = this._mapDraw;
|
||||
if (geoModel.get('show')) {
|
||||
mapDraw.draw(geoModel, ecModel, api, this, payload);
|
||||
}
|
||||
else {
|
||||
this._mapDraw.group.removeAll();
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
29
vendors/echarts/src/component/grid.js
vendored
Normal file
29
vendors/echarts/src/component/grid.js
vendored
Normal file
@@ -0,0 +1,29 @@
|
||||
define(function(require) {
|
||||
'use strict';
|
||||
|
||||
var graphic = require('../util/graphic');
|
||||
var zrUtil = require('zrender/core/util');
|
||||
|
||||
require('../coord/cartesian/Grid');
|
||||
|
||||
require('./axis');
|
||||
|
||||
// Grid view
|
||||
require('../echarts').extendComponentView({
|
||||
|
||||
type: 'grid',
|
||||
|
||||
render: function (gridModel, ecModel) {
|
||||
this.group.removeAll();
|
||||
if (gridModel.get('show')) {
|
||||
this.group.add(new graphic.Rect({
|
||||
shape:gridModel.coordinateSystem.getRect(),
|
||||
style: zrUtil.defaults({
|
||||
fill: gridModel.get('backgroundColor')
|
||||
}, gridModel.getItemStyle()),
|
||||
silent: true
|
||||
}));
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
295
vendors/echarts/src/component/helper/MapDraw.js
vendored
Normal file
295
vendors/echarts/src/component/helper/MapDraw.js
vendored
Normal file
@@ -0,0 +1,295 @@
|
||||
/**
|
||||
* @module echarts/component/helper/MapDraw
|
||||
*/
|
||||
define(function (require) {
|
||||
|
||||
var RoamController = require('./RoamController');
|
||||
var graphic = require('../../util/graphic');
|
||||
var zrUtil = require('zrender/core/util');
|
||||
|
||||
function getFixedItemStyle(model, scale) {
|
||||
var itemStyle = model.getItemStyle();
|
||||
var areaColor = model.get('areaColor');
|
||||
if (areaColor) {
|
||||
itemStyle.fill = areaColor;
|
||||
}
|
||||
|
||||
return itemStyle;
|
||||
}
|
||||
|
||||
function updateMapSelectHandler(mapOrGeoModel, group, api, fromView) {
|
||||
group.off('click');
|
||||
mapOrGeoModel.get('selectedMode')
|
||||
&& group.on('click', function (e) {
|
||||
var el = e.target;
|
||||
while (!el.__region) {
|
||||
el = el.parent;
|
||||
}
|
||||
if (!el) {
|
||||
return;
|
||||
}
|
||||
|
||||
var region = el.__region;
|
||||
var action = {
|
||||
type: (mapOrGeoModel.mainType === 'geo' ? 'geo' : 'map') + 'ToggleSelect',
|
||||
name: region.name,
|
||||
from: fromView.uid
|
||||
};
|
||||
action[mapOrGeoModel.mainType + 'Id'] = mapOrGeoModel.id;
|
||||
|
||||
api.dispatchAction(action);
|
||||
|
||||
updateMapSelected(mapOrGeoModel, group);
|
||||
});
|
||||
}
|
||||
|
||||
function updateMapSelected(mapOrGeoModel, group) {
|
||||
// FIXME
|
||||
group.eachChild(function (otherRegionEl) {
|
||||
if (otherRegionEl.__region) {
|
||||
otherRegionEl.trigger(mapOrGeoModel.isSelected(otherRegionEl.__region.name) ? 'emphasis' : 'normal');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @alias module:echarts/component/helper/MapDraw
|
||||
* @param {module:echarts/ExtensionAPI} api
|
||||
* @param {boolean} updateGroup
|
||||
*/
|
||||
function MapDraw(api, updateGroup) {
|
||||
|
||||
var group = new graphic.Group();
|
||||
|
||||
/**
|
||||
* @type {module:echarts/component/helper/RoamController}
|
||||
* @private
|
||||
*/
|
||||
this._controller = new RoamController(
|
||||
api.getZr(), updateGroup ? group : null, null
|
||||
);
|
||||
|
||||
/**
|
||||
* @type {module:zrender/container/Group}
|
||||
* @readOnly
|
||||
*/
|
||||
this.group = group;
|
||||
|
||||
/**
|
||||
* @type {boolean}
|
||||
* @private
|
||||
*/
|
||||
this._updateGroup = updateGroup;
|
||||
}
|
||||
|
||||
MapDraw.prototype = {
|
||||
|
||||
constructor: MapDraw,
|
||||
|
||||
draw: function (mapOrGeoModel, ecModel, api, fromView, payload) {
|
||||
|
||||
// geoModel has no data
|
||||
var data = mapOrGeoModel.getData && mapOrGeoModel.getData();
|
||||
|
||||
var geo = mapOrGeoModel.coordinateSystem;
|
||||
|
||||
var group = this.group;
|
||||
|
||||
var scale = geo.scale;
|
||||
var groupNewProp = {
|
||||
position: geo.position,
|
||||
scale: scale
|
||||
};
|
||||
|
||||
// No animation when first draw or in action
|
||||
if (!group.childAt(0) || payload) {
|
||||
group.attr(groupNewProp);
|
||||
}
|
||||
else {
|
||||
graphic.updateProps(group, groupNewProp, mapOrGeoModel);
|
||||
}
|
||||
|
||||
group.removeAll();
|
||||
|
||||
var itemStyleAccessPath = ['itemStyle', 'normal'];
|
||||
var hoverItemStyleAccessPath = ['itemStyle', 'emphasis'];
|
||||
var labelAccessPath = ['label', 'normal'];
|
||||
var hoverLabelAccessPath = ['label', 'emphasis'];
|
||||
|
||||
zrUtil.each(geo.regions, function (region) {
|
||||
|
||||
var regionGroup = new graphic.Group();
|
||||
var compoundPath = new graphic.CompoundPath({
|
||||
shape: {
|
||||
paths: []
|
||||
}
|
||||
});
|
||||
regionGroup.add(compoundPath);
|
||||
|
||||
var regionModel = mapOrGeoModel.getRegionModel(region.name) || mapOrGeoModel;
|
||||
|
||||
var itemStyleModel = regionModel.getModel(itemStyleAccessPath);
|
||||
var hoverItemStyleModel = regionModel.getModel(hoverItemStyleAccessPath);
|
||||
var itemStyle = getFixedItemStyle(itemStyleModel, scale);
|
||||
var hoverItemStyle = getFixedItemStyle(hoverItemStyleModel, scale);
|
||||
|
||||
var labelModel = regionModel.getModel(labelAccessPath);
|
||||
var hoverLabelModel = regionModel.getModel(hoverLabelAccessPath);
|
||||
|
||||
var dataIdx;
|
||||
// Use the itemStyle in data if has data
|
||||
if (data) {
|
||||
dataIdx = data.indexOfName(region.name);
|
||||
// Only visual color of each item will be used. It can be encoded by dataRange
|
||||
// But visual color of series is used in symbol drawing
|
||||
//
|
||||
// Visual color for each series is for the symbol draw
|
||||
var visualColor = data.getItemVisual(dataIdx, 'color', true);
|
||||
if (visualColor) {
|
||||
itemStyle.fill = visualColor;
|
||||
}
|
||||
}
|
||||
|
||||
var textStyleModel = labelModel.getModel('textStyle');
|
||||
var hoverTextStyleModel = hoverLabelModel.getModel('textStyle');
|
||||
|
||||
zrUtil.each(region.contours, function (contour) {
|
||||
|
||||
var polygon = new graphic.Polygon({
|
||||
shape: {
|
||||
points: contour
|
||||
}
|
||||
});
|
||||
|
||||
compoundPath.shape.paths.push(polygon);
|
||||
});
|
||||
|
||||
compoundPath.setStyle(itemStyle);
|
||||
compoundPath.style.strokeNoScale = true;
|
||||
compoundPath.culling = true;
|
||||
// Label
|
||||
var showLabel = labelModel.get('show');
|
||||
var hoverShowLabel = hoverLabelModel.get('show');
|
||||
|
||||
var isDataNaN = data && isNaN(data.get('value', dataIdx));
|
||||
var itemLayout = data && data.getItemLayout(dataIdx);
|
||||
// In the following cases label will be drawn
|
||||
// 1. In map series and data value is NaN
|
||||
// 2. In geo component
|
||||
// 4. Region has no series legendSymbol, which will be add a showLabel flag in mapSymbolLayout
|
||||
if (
|
||||
(!data || isDataNaN && (showLabel || hoverShowLabel))
|
||||
|| (itemLayout && itemLayout.showLabel)
|
||||
) {
|
||||
var query = data ? dataIdx : region.name;
|
||||
var formattedStr = mapOrGeoModel.getFormattedLabel(query, 'normal');
|
||||
var hoverFormattedStr = mapOrGeoModel.getFormattedLabel(query, 'emphasis');
|
||||
var text = new graphic.Text({
|
||||
style: {
|
||||
text: showLabel ? (formattedStr || region.name) : '',
|
||||
fill: textStyleModel.getTextColor(),
|
||||
textFont: textStyleModel.getFont(),
|
||||
textAlign: 'center',
|
||||
textVerticalAlign: 'middle'
|
||||
},
|
||||
hoverStyle: {
|
||||
text: hoverShowLabel ? (hoverFormattedStr || region.name) : '',
|
||||
fill: hoverTextStyleModel.getTextColor(),
|
||||
textFont: hoverTextStyleModel.getFont()
|
||||
},
|
||||
position: region.center.slice(),
|
||||
scale: [1 / scale[0], 1 / scale[1]],
|
||||
z2: 10,
|
||||
silent: true
|
||||
});
|
||||
|
||||
regionGroup.add(text);
|
||||
}
|
||||
|
||||
// setItemGraphicEl, setHoverStyle after all polygons and labels
|
||||
// are added to the rigionGroup
|
||||
if (data) {
|
||||
data.setItemGraphicEl(dataIdx, regionGroup);
|
||||
}
|
||||
else {
|
||||
var regionModel = mapOrGeoModel.getRegionModel(region.name);
|
||||
// Package custom mouse event for geo component
|
||||
compoundPath.eventData = {
|
||||
componentType: 'geo',
|
||||
geoIndex: mapOrGeoModel.componentIndex,
|
||||
name: region.name,
|
||||
region: (regionModel && regionModel.option) || {}
|
||||
};
|
||||
}
|
||||
|
||||
regionGroup.__region = region;
|
||||
|
||||
graphic.setHoverStyle(regionGroup, hoverItemStyle);
|
||||
|
||||
group.add(regionGroup);
|
||||
});
|
||||
|
||||
this._updateController(mapOrGeoModel, ecModel, api);
|
||||
|
||||
updateMapSelectHandler(mapOrGeoModel, group, api, fromView);
|
||||
|
||||
updateMapSelected(mapOrGeoModel, group);
|
||||
},
|
||||
|
||||
remove: function () {
|
||||
this.group.removeAll();
|
||||
this._controller.dispose();
|
||||
},
|
||||
|
||||
_updateController: function (mapOrGeoModel, ecModel, api) {
|
||||
var geo = mapOrGeoModel.coordinateSystem;
|
||||
var controller = this._controller;
|
||||
controller.zoomLimit = mapOrGeoModel.get('scaleLimit');
|
||||
// Update zoom from model
|
||||
controller.zoom = geo.getZoom();
|
||||
// roamType is will be set default true if it is null
|
||||
controller.enable(mapOrGeoModel.get('roam') || false);
|
||||
var mainType = mapOrGeoModel.mainType;
|
||||
|
||||
function makeActionBase() {
|
||||
var action = {
|
||||
type: 'geoRoam',
|
||||
componentType: mainType
|
||||
};
|
||||
action[mainType + 'Id'] = mapOrGeoModel.id;
|
||||
return action;
|
||||
}
|
||||
controller.off('pan')
|
||||
.on('pan', function (dx, dy) {
|
||||
api.dispatchAction(zrUtil.extend(makeActionBase(), {
|
||||
dx: dx,
|
||||
dy: dy
|
||||
}));
|
||||
});
|
||||
controller.off('zoom')
|
||||
.on('zoom', function (zoom, mouseX, mouseY) {
|
||||
api.dispatchAction(zrUtil.extend(makeActionBase(), {
|
||||
zoom: zoom,
|
||||
originX: mouseX,
|
||||
originY: mouseY
|
||||
}));
|
||||
|
||||
if (this._updateGroup) {
|
||||
var group = this.group;
|
||||
var scale = group.scale;
|
||||
group.traverse(function (el) {
|
||||
if (el.type === 'text') {
|
||||
el.attr('scale', [1 / scale[0], 1 / scale[1]]);
|
||||
}
|
||||
});
|
||||
}
|
||||
}, this);
|
||||
|
||||
controller.rectProvider = function () {
|
||||
return geo.getViewRectAfterRoam();
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
return MapDraw;
|
||||
});
|
||||
221
vendors/echarts/src/component/helper/RoamController.js
vendored
Normal file
221
vendors/echarts/src/component/helper/RoamController.js
vendored
Normal file
@@ -0,0 +1,221 @@
|
||||
/**
|
||||
* @module echarts/component/helper/RoamController
|
||||
*/
|
||||
|
||||
define(function (require) {
|
||||
|
||||
var Eventful = require('zrender/mixin/Eventful');
|
||||
var zrUtil = require('zrender/core/util');
|
||||
var eventTool = require('zrender/core/event');
|
||||
var interactionMutex = require('./interactionMutex');
|
||||
|
||||
function mousedown(e) {
|
||||
if (e.target && e.target.draggable) {
|
||||
return;
|
||||
}
|
||||
|
||||
var x = e.offsetX;
|
||||
var y = e.offsetY;
|
||||
var rect = this.rectProvider && this.rectProvider();
|
||||
if (rect && rect.contain(x, y)) {
|
||||
this._x = x;
|
||||
this._y = y;
|
||||
this._dragging = true;
|
||||
}
|
||||
}
|
||||
|
||||
function mousemove(e) {
|
||||
if (!this._dragging) {
|
||||
return;
|
||||
}
|
||||
|
||||
eventTool.stop(e.event);
|
||||
|
||||
if (e.gestureEvent !== 'pinch') {
|
||||
|
||||
if (interactionMutex.isTaken('globalPan', this._zr)) {
|
||||
return;
|
||||
}
|
||||
|
||||
var x = e.offsetX;
|
||||
var y = e.offsetY;
|
||||
|
||||
var dx = x - this._x;
|
||||
var dy = y - this._y;
|
||||
|
||||
this._x = x;
|
||||
this._y = y;
|
||||
|
||||
var target = this.target;
|
||||
|
||||
if (target) {
|
||||
var pos = target.position;
|
||||
pos[0] += dx;
|
||||
pos[1] += dy;
|
||||
target.dirty();
|
||||
}
|
||||
|
||||
eventTool.stop(e.event);
|
||||
this.trigger('pan', dx, dy);
|
||||
}
|
||||
}
|
||||
|
||||
function mouseup(e) {
|
||||
this._dragging = false;
|
||||
}
|
||||
|
||||
function mousewheel(e) {
|
||||
// Convenience:
|
||||
// Mac and VM Windows on Mac: scroll up: zoom out.
|
||||
// Windows: scroll up: zoom in.
|
||||
var zoomDelta = e.wheelDelta > 0 ? 1.1 : 1 / 1.1;
|
||||
zoom.call(this, e, zoomDelta, e.offsetX, e.offsetY);
|
||||
}
|
||||
|
||||
function pinch(e) {
|
||||
if (interactionMutex.isTaken('globalPan', this._zr)) {
|
||||
return;
|
||||
}
|
||||
|
||||
var zoomDelta = e.pinchScale > 1 ? 1.1 : 1 / 1.1;
|
||||
zoom.call(this, e, zoomDelta, e.pinchX, e.pinchY);
|
||||
}
|
||||
|
||||
function zoom(e, zoomDelta, zoomX, zoomY) {
|
||||
var rect = this.rectProvider && this.rectProvider();
|
||||
|
||||
if (rect && rect.contain(zoomX, zoomY)) {
|
||||
// When mouse is out of roamController rect,
|
||||
// default befavoius should be be disabled, otherwise
|
||||
// page sliding is disabled, contrary to expectation.
|
||||
eventTool.stop(e.event);
|
||||
|
||||
var target = this.target;
|
||||
var zoomLimit = this.zoomLimit;
|
||||
|
||||
if (target) {
|
||||
var pos = target.position;
|
||||
var scale = target.scale;
|
||||
|
||||
var newZoom = this.zoom = this.zoom || 1;
|
||||
newZoom *= zoomDelta;
|
||||
if (zoomLimit) {
|
||||
var zoomMin = zoomLimit.min || 0;
|
||||
var zoomMax = zoomLimit.max || Infinity;
|
||||
newZoom = Math.max(
|
||||
Math.min(zoomMax, newZoom),
|
||||
zoomMin
|
||||
);
|
||||
}
|
||||
var zoomScale = newZoom / this.zoom;
|
||||
this.zoom = newZoom;
|
||||
// Keep the mouse center when scaling
|
||||
pos[0] -= (zoomX - pos[0]) * (zoomScale - 1);
|
||||
pos[1] -= (zoomY - pos[1]) * (zoomScale - 1);
|
||||
scale[0] *= zoomScale;
|
||||
scale[1] *= zoomScale;
|
||||
|
||||
target.dirty();
|
||||
}
|
||||
|
||||
this.trigger('zoom', zoomDelta, zoomX, zoomY);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @alias module:echarts/component/helper/RoamController
|
||||
* @constructor
|
||||
* @mixin {module:zrender/mixin/Eventful}
|
||||
*
|
||||
* @param {module:zrender/zrender~ZRender} zr
|
||||
* @param {module:zrender/Element} target
|
||||
* @param {Function} rectProvider
|
||||
*/
|
||||
function RoamController(zr, target, rectProvider) {
|
||||
|
||||
/**
|
||||
* @type {module:zrender/Element}
|
||||
*/
|
||||
this.target = target;
|
||||
|
||||
/**
|
||||
* @type {Function}
|
||||
*/
|
||||
this.rectProvider = rectProvider;
|
||||
|
||||
/**
|
||||
* { min: 1, max: 2 }
|
||||
* @type {Object}
|
||||
*/
|
||||
this.zoomLimit;
|
||||
|
||||
/**
|
||||
* @type {number}
|
||||
*/
|
||||
this.zoom;
|
||||
/**
|
||||
* @type {module:zrender}
|
||||
*/
|
||||
this._zr = zr;
|
||||
|
||||
// Avoid two roamController bind the same handler
|
||||
var bind = zrUtil.bind;
|
||||
var mousedownHandler = bind(mousedown, this);
|
||||
var mousemoveHandler = bind(mousemove, this);
|
||||
var mouseupHandler = bind(mouseup, this);
|
||||
var mousewheelHandler = bind(mousewheel, this);
|
||||
var pinchHandler = bind(pinch, this);
|
||||
|
||||
Eventful.call(this);
|
||||
|
||||
/**
|
||||
* Notice: only enable needed types. For example, if 'zoom'
|
||||
* is not needed, 'zoom' should not be enabled, otherwise
|
||||
* default mousewheel behaviour (scroll page) will be disabled.
|
||||
*
|
||||
* @param {boolean|string} [controlType=true] Specify the control type,
|
||||
* which can be null/undefined or true/false
|
||||
* or 'pan/move' or 'zoom'/'scale'
|
||||
*/
|
||||
this.enable = function (controlType) {
|
||||
// Disable previous first
|
||||
this.disable();
|
||||
|
||||
if (controlType == null) {
|
||||
controlType = true;
|
||||
}
|
||||
|
||||
if (controlType === true || (controlType === 'move' || controlType === 'pan')) {
|
||||
zr.on('mousedown', mousedownHandler);
|
||||
zr.on('mousemove', mousemoveHandler);
|
||||
zr.on('mouseup', mouseupHandler);
|
||||
}
|
||||
if (controlType === true || (controlType === 'scale' || controlType === 'zoom')) {
|
||||
zr.on('mousewheel', mousewheelHandler);
|
||||
zr.on('pinch', pinchHandler);
|
||||
}
|
||||
};
|
||||
|
||||
this.disable = function () {
|
||||
zr.off('mousedown', mousedownHandler);
|
||||
zr.off('mousemove', mousemoveHandler);
|
||||
zr.off('mouseup', mouseupHandler);
|
||||
zr.off('mousewheel', mousewheelHandler);
|
||||
zr.off('pinch', pinchHandler);
|
||||
};
|
||||
|
||||
this.dispose = this.disable;
|
||||
|
||||
this.isDragging = function () {
|
||||
return this._dragging;
|
||||
};
|
||||
|
||||
this.isPinching = function () {
|
||||
return this._pinching;
|
||||
};
|
||||
}
|
||||
|
||||
zrUtil.mixin(RoamController, Eventful);
|
||||
|
||||
return RoamController;
|
||||
});
|
||||
373
vendors/echarts/src/component/helper/SelectController.js
vendored
Normal file
373
vendors/echarts/src/component/helper/SelectController.js
vendored
Normal file
@@ -0,0 +1,373 @@
|
||||
/**
|
||||
* Box selection tool.
|
||||
*
|
||||
* @module echarts/component/helper/SelectController
|
||||
*/
|
||||
|
||||
define(function (require) {
|
||||
|
||||
var Eventful = require('zrender/mixin/Eventful');
|
||||
var zrUtil = require('zrender/core/util');
|
||||
var graphic = require('../../util/graphic');
|
||||
var bind = zrUtil.bind;
|
||||
var each = zrUtil.each;
|
||||
var mathMin = Math.min;
|
||||
var mathMax = Math.max;
|
||||
var mathPow = Math.pow;
|
||||
|
||||
var COVER_Z = 10000;
|
||||
var UNSELECT_THRESHOLD = 2;
|
||||
var EVENTS = ['mousedown', 'mousemove', 'mouseup'];
|
||||
|
||||
/**
|
||||
* @alias module:echarts/component/helper/SelectController
|
||||
* @constructor
|
||||
* @mixin {module:zrender/mixin/Eventful}
|
||||
*
|
||||
* @param {string} type 'line', 'rect'
|
||||
* @param {module:zrender/zrender~ZRender} zr
|
||||
* @param {Object} [opt]
|
||||
* @param {number} [opt.width]
|
||||
* @param {number} [opt.lineWidth]
|
||||
* @param {string} [opt.stroke]
|
||||
* @param {string} [opt.fill]
|
||||
*/
|
||||
function SelectController(type, zr, opt) {
|
||||
|
||||
Eventful.call(this);
|
||||
|
||||
/**
|
||||
* @type {string}
|
||||
* @readOnly
|
||||
*/
|
||||
this.type = type;
|
||||
|
||||
/**
|
||||
* @type {module:zrender/zrender~ZRender}
|
||||
*/
|
||||
this.zr = zr;
|
||||
|
||||
/**
|
||||
* @type {Object}
|
||||
* @readOnly
|
||||
*/
|
||||
this.opt = zrUtil.clone(opt);
|
||||
|
||||
/**
|
||||
* @type {module:zrender/container/Group}
|
||||
* @readOnly
|
||||
*/
|
||||
this.group = new graphic.Group();
|
||||
|
||||
/**
|
||||
* @type {module:zrender/core/BoundingRect}
|
||||
*/
|
||||
this._containerRect = null;
|
||||
|
||||
/**
|
||||
* @type {Array.<nubmer>}
|
||||
* @private
|
||||
*/
|
||||
this._track = [];
|
||||
|
||||
/**
|
||||
* @type {boolean}
|
||||
*/
|
||||
this._dragging;
|
||||
|
||||
/**
|
||||
* @type {module:zrender/Element}
|
||||
* @private
|
||||
*/
|
||||
this._cover;
|
||||
|
||||
/**
|
||||
* @type {boolean}
|
||||
* @private
|
||||
*/
|
||||
this._disabled = true;
|
||||
|
||||
/**
|
||||
* @type {Object}
|
||||
* @private
|
||||
*/
|
||||
this._handlers = {
|
||||
mousedown: bind(mousedown, this),
|
||||
mousemove: bind(mousemove, this),
|
||||
mouseup: bind(mouseup, this)
|
||||
};
|
||||
|
||||
each(EVENTS, function (eventName) {
|
||||
this.zr.on(eventName, this._handlers[eventName]);
|
||||
}, this);
|
||||
}
|
||||
|
||||
SelectController.prototype = {
|
||||
|
||||
constructor: SelectController,
|
||||
|
||||
/**
|
||||
* @param {module:zrender/mixin/Transformable} container
|
||||
* @param {module:zrender/core/BoundingRect|boolean} [rect] If not specified,
|
||||
* use container.getBoundingRect().
|
||||
* If false, do not use containerRect.
|
||||
*/
|
||||
enable: function (container, rect) {
|
||||
|
||||
this._disabled = false;
|
||||
|
||||
// Remove from old container.
|
||||
removeGroup.call(this);
|
||||
|
||||
// boundingRect will change when dragging, so we have
|
||||
// to keep initial boundingRect.
|
||||
this._containerRect = rect !== false
|
||||
? (rect || container.getBoundingRect()) : null;
|
||||
|
||||
// Add to new container.
|
||||
container.add(this.group);
|
||||
},
|
||||
|
||||
/**
|
||||
* Update cover location.
|
||||
* @param {Array.<number>|Object} ranges If null/undefined, remove cover.
|
||||
*/
|
||||
update: function (ranges) {
|
||||
// TODO
|
||||
// Only support one interval yet.
|
||||
renderCover.call(this, ranges && zrUtil.clone(ranges));
|
||||
},
|
||||
|
||||
disable: function () {
|
||||
this._disabled = true;
|
||||
|
||||
removeGroup.call(this);
|
||||
},
|
||||
|
||||
dispose: function () {
|
||||
this.disable();
|
||||
|
||||
each(EVENTS, function (eventName) {
|
||||
this.zr.off(eventName, this._handlers[eventName]);
|
||||
}, this);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
zrUtil.mixin(SelectController, Eventful);
|
||||
|
||||
function updateZ(group) {
|
||||
group.traverse(function (el) {
|
||||
el.z = COVER_Z;
|
||||
});
|
||||
}
|
||||
|
||||
function isInContainer(x, y) {
|
||||
var localPos = this.group.transformCoordToLocal(x, y);
|
||||
return !this._containerRect
|
||||
|| this._containerRect.contain(localPos[0], localPos[1]);
|
||||
}
|
||||
|
||||
function preventDefault(e) {
|
||||
var rawE = e.event;
|
||||
rawE.preventDefault && rawE.preventDefault();
|
||||
}
|
||||
|
||||
function mousedown(e) {
|
||||
if (this._disabled || (e.target && e.target.draggable)) {
|
||||
return;
|
||||
}
|
||||
|
||||
preventDefault(e);
|
||||
|
||||
var x = e.offsetX;
|
||||
var y = e.offsetY;
|
||||
|
||||
if (isInContainer.call(this, x, y)) {
|
||||
this._dragging = true;
|
||||
this._track = [[x, y]];
|
||||
}
|
||||
}
|
||||
|
||||
function mousemove(e) {
|
||||
if (!this._dragging || this._disabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
preventDefault(e);
|
||||
|
||||
updateViewByCursor.call(this, e);
|
||||
}
|
||||
|
||||
function mouseup(e) {
|
||||
if (!this._dragging || this._disabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
preventDefault(e);
|
||||
|
||||
updateViewByCursor.call(this, e, true);
|
||||
|
||||
this._dragging = false;
|
||||
this._track = [];
|
||||
}
|
||||
|
||||
function updateViewByCursor(e, isEnd) {
|
||||
var x = e.offsetX;
|
||||
var y = e.offsetY;
|
||||
|
||||
if (isInContainer.call(this, x, y)) {
|
||||
this._track.push([x, y]);
|
||||
|
||||
// Create or update cover.
|
||||
var ranges = shouldShowCover.call(this)
|
||||
? coverRenderers[this.type].getRanges.call(this)
|
||||
// Remove cover.
|
||||
: [];
|
||||
|
||||
renderCover.call(this, ranges);
|
||||
|
||||
this.trigger('selected', zrUtil.clone(ranges));
|
||||
|
||||
if (isEnd) {
|
||||
this.trigger('selectEnd', zrUtil.clone(ranges));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function shouldShowCover() {
|
||||
var track = this._track;
|
||||
|
||||
if (!track.length) {
|
||||
return false;
|
||||
}
|
||||
|
||||
var p2 = track[track.length - 1];
|
||||
var p1 = track[0];
|
||||
var dx = p2[0] - p1[0];
|
||||
var dy = p2[1] - p1[1];
|
||||
var dist = mathPow(dx * dx + dy * dy, 0.5);
|
||||
|
||||
return dist > UNSELECT_THRESHOLD;
|
||||
}
|
||||
|
||||
function renderCover(ranges) {
|
||||
var coverRenderer = coverRenderers[this.type];
|
||||
|
||||
if (ranges && ranges.length) {
|
||||
if (!this._cover) {
|
||||
this._cover = coverRenderer.create.call(this);
|
||||
this.group.add(this._cover);
|
||||
}
|
||||
coverRenderer.update.call(this, ranges);
|
||||
}
|
||||
else {
|
||||
this.group.remove(this._cover);
|
||||
this._cover = null;
|
||||
}
|
||||
|
||||
updateZ(this.group);
|
||||
}
|
||||
|
||||
function removeGroup() {
|
||||
// container may 'removeAll' outside.
|
||||
var group = this.group;
|
||||
var container = group.parent;
|
||||
if (container) {
|
||||
container.remove(group);
|
||||
}
|
||||
}
|
||||
|
||||
function createRectCover() {
|
||||
var opt = this.opt;
|
||||
return new graphic.Rect({
|
||||
// FIXME
|
||||
// customize style.
|
||||
style: {
|
||||
stroke: opt.stroke,
|
||||
fill: opt.fill,
|
||||
lineWidth: opt.lineWidth,
|
||||
opacity: opt.opacity
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function getLocalTrack() {
|
||||
return zrUtil.map(this._track, function (point) {
|
||||
return this.group.transformCoordToLocal(point[0], point[1]);
|
||||
}, this);
|
||||
}
|
||||
|
||||
function getLocalTrackEnds() {
|
||||
var localTrack = getLocalTrack.call(this);
|
||||
var tail = localTrack.length - 1;
|
||||
tail < 0 && (tail = 0);
|
||||
return [localTrack[0], localTrack[tail]];
|
||||
}
|
||||
|
||||
/**
|
||||
* key: this.type
|
||||
* @type {Object}
|
||||
*/
|
||||
var coverRenderers = {
|
||||
|
||||
line: {
|
||||
|
||||
create: createRectCover,
|
||||
|
||||
getRanges: function () {
|
||||
var ends = getLocalTrackEnds.call(this);
|
||||
var min = mathMin(ends[0][0], ends[1][0]);
|
||||
var max = mathMax(ends[0][0], ends[1][0]);
|
||||
|
||||
return [[min, max]];
|
||||
},
|
||||
|
||||
update: function (ranges) {
|
||||
var range = ranges[0];
|
||||
var width = this.opt.width;
|
||||
this._cover.setShape({
|
||||
x: range[0],
|
||||
y: -width / 2,
|
||||
width: range[1] - range[0],
|
||||
height: width
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
rect: {
|
||||
|
||||
create: createRectCover,
|
||||
|
||||
getRanges: function () {
|
||||
var ends = getLocalTrackEnds.call(this);
|
||||
|
||||
var min = [
|
||||
mathMin(ends[1][0], ends[0][0]),
|
||||
mathMin(ends[1][1], ends[0][1])
|
||||
];
|
||||
var max = [
|
||||
mathMax(ends[1][0], ends[0][0]),
|
||||
mathMax(ends[1][1], ends[0][1])
|
||||
];
|
||||
|
||||
return [[
|
||||
[min[0], max[0]], // x range
|
||||
[min[1], max[1]] // y range
|
||||
]];
|
||||
},
|
||||
|
||||
update: function (ranges) {
|
||||
var range = ranges[0];
|
||||
this._cover.setShape({
|
||||
x: range[0][0],
|
||||
y: range[1][0],
|
||||
width: range[0][1] - range[0][0],
|
||||
height: range[1][1] - range[1][0]
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
return SelectController;
|
||||
});
|
||||
25
vendors/echarts/src/component/helper/interactionMutex.js
vendored
Normal file
25
vendors/echarts/src/component/helper/interactionMutex.js
vendored
Normal file
@@ -0,0 +1,25 @@
|
||||
define(function (require) {
|
||||
|
||||
var ATTR = '\0_ec_interaction_mutex';
|
||||
|
||||
var interactionMutex = {
|
||||
|
||||
take: function (key, zr) {
|
||||
getStore(zr)[key] = true;
|
||||
},
|
||||
|
||||
release: function (key, zr) {
|
||||
getStore(zr)[key] = false;
|
||||
},
|
||||
|
||||
isTaken: function (key, zr) {
|
||||
return !!getStore(zr)[key];
|
||||
}
|
||||
};
|
||||
|
||||
function getStore(zr) {
|
||||
return zr[ATTR] || (zr[ATTR] = {});
|
||||
}
|
||||
|
||||
return interactionMutex;
|
||||
});
|
||||
65
vendors/echarts/src/component/helper/listComponent.js
vendored
Normal file
65
vendors/echarts/src/component/helper/listComponent.js
vendored
Normal file
@@ -0,0 +1,65 @@
|
||||
define(function (require) {
|
||||
// List layout
|
||||
var layout = require('../../util/layout');
|
||||
var formatUtil = require('../../util/format');
|
||||
var graphic = require('../../util/graphic');
|
||||
|
||||
function positionGroup(group, model, api) {
|
||||
layout.positionGroup(
|
||||
group, model.getBoxLayoutParams(),
|
||||
{
|
||||
width: api.getWidth(),
|
||||
height: api.getHeight()
|
||||
},
|
||||
model.get('padding')
|
||||
);
|
||||
}
|
||||
|
||||
return {
|
||||
/**
|
||||
* Layout list like component.
|
||||
* It will box layout each items in group of component and then position the whole group in the viewport
|
||||
* @param {module:zrender/group/Group} group
|
||||
* @param {module:echarts/model/Component} componentModel
|
||||
* @param {module:echarts/ExtensionAPI}
|
||||
*/
|
||||
layout: function (group, componentModel, api) {
|
||||
var rect = layout.getLayoutRect(componentModel.getBoxLayoutParams(), {
|
||||
width: api.getWidth(),
|
||||
height: api.getHeight()
|
||||
}, componentModel.get('padding'));
|
||||
layout.box(
|
||||
componentModel.get('orient'),
|
||||
group,
|
||||
componentModel.get('itemGap'),
|
||||
rect.width,
|
||||
rect.height
|
||||
);
|
||||
|
||||
positionGroup(group, componentModel, api);
|
||||
},
|
||||
|
||||
addBackground: function (group, componentModel) {
|
||||
var padding = formatUtil.normalizeCssArray(
|
||||
componentModel.get('padding')
|
||||
);
|
||||
var boundingRect = group.getBoundingRect();
|
||||
var style = componentModel.getItemStyle(['color', 'opacity']);
|
||||
style.fill = componentModel.get('backgroundColor');
|
||||
var rect = new graphic.Rect({
|
||||
shape: {
|
||||
x: boundingRect.x - padding[3],
|
||||
y: boundingRect.y - padding[0],
|
||||
width: boundingRect.width + padding[1] + padding[3],
|
||||
height: boundingRect.height + padding[0] + padding[2]
|
||||
},
|
||||
style: style,
|
||||
silent: true,
|
||||
z2: -1
|
||||
});
|
||||
graphic.subPixelOptimizeRect(rect);
|
||||
|
||||
group.add(rect);
|
||||
}
|
||||
};
|
||||
});
|
||||
65
vendors/echarts/src/component/helper/selectableMixin.js
vendored
Normal file
65
vendors/echarts/src/component/helper/selectableMixin.js
vendored
Normal file
@@ -0,0 +1,65 @@
|
||||
/**
|
||||
* Data selectable mixin for chart series.
|
||||
* To eanble data select, option of series must have `selectedMode`.
|
||||
* And each data item will use `selected` to toggle itself selected status
|
||||
*
|
||||
* @module echarts/chart/helper/DataSelectable
|
||||
*/
|
||||
define(function (require) {
|
||||
|
||||
var zrUtil = require('zrender/core/util');
|
||||
|
||||
return {
|
||||
|
||||
updateSelectedMap: function (targetList) {
|
||||
this._selectTargetMap = zrUtil.reduce(targetList || [], function (targetMap, target) {
|
||||
targetMap[target.name] = target;
|
||||
return targetMap;
|
||||
}, {});
|
||||
},
|
||||
/**
|
||||
* @param {string} name
|
||||
*/
|
||||
// PENGING If selectedMode is null ?
|
||||
select: function (name) {
|
||||
var targetMap = this._selectTargetMap;
|
||||
var target = targetMap[name];
|
||||
var selectedMode = this.get('selectedMode');
|
||||
if (selectedMode === 'single') {
|
||||
zrUtil.each(targetMap, function (target) {
|
||||
target.selected = false;
|
||||
});
|
||||
}
|
||||
target && (target.selected = true);
|
||||
},
|
||||
|
||||
/**
|
||||
* @param {string} name
|
||||
*/
|
||||
unSelect: function (name) {
|
||||
var target = this._selectTargetMap[name];
|
||||
// var selectedMode = this.get('selectedMode');
|
||||
// selectedMode !== 'single' && target && (target.selected = false);
|
||||
target && (target.selected = false);
|
||||
},
|
||||
|
||||
/**
|
||||
* @param {string} name
|
||||
*/
|
||||
toggleSelected: function (name) {
|
||||
var target = this._selectTargetMap[name];
|
||||
if (target != null) {
|
||||
this[target.selected ? 'unSelect' : 'select'](name);
|
||||
return target.selected;
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* @param {string} name
|
||||
*/
|
||||
isSelected: function (name) {
|
||||
var target = this._selectTargetMap[name];
|
||||
return target && target.selected;
|
||||
}
|
||||
};
|
||||
});
|
||||
54
vendors/echarts/src/component/helper/sliderMove.js
vendored
Normal file
54
vendors/echarts/src/component/helper/sliderMove.js
vendored
Normal file
@@ -0,0 +1,54 @@
|
||||
define(function (require) {
|
||||
|
||||
/**
|
||||
* Calculate slider move result.
|
||||
*
|
||||
* @param {number} delta Move length.
|
||||
* @param {Array.<number>} handleEnds handleEnds[0] and be bigger then handleEnds[1].
|
||||
* handleEnds will be modified in this method.
|
||||
* @param {Array.<number>} extent handleEnds is restricted by extent.
|
||||
* extent[0] should less or equals than extent[1].
|
||||
* @param {string} mode 'rigid': Math.abs(handleEnds[0] - handleEnds[1]) remain unchanged,
|
||||
* 'cross' handleEnds[0] can be bigger then handleEnds[1],
|
||||
* 'push' handleEnds[0] can not be bigger then handleEnds[1],
|
||||
* when they touch, one push other.
|
||||
* @param {number} handleIndex If mode is 'rigid', handleIndex is not required.
|
||||
* @param {Array.<number>} The input handleEnds.
|
||||
*/
|
||||
return function (delta, handleEnds, extent, mode, handleIndex) {
|
||||
if (!delta) {
|
||||
return handleEnds;
|
||||
}
|
||||
|
||||
if (mode === 'rigid') {
|
||||
delta = getRealDelta(delta, handleEnds, extent);
|
||||
handleEnds[0] += delta;
|
||||
handleEnds[1] += delta;
|
||||
}
|
||||
else {
|
||||
delta = getRealDelta(delta, handleEnds[handleIndex], extent);
|
||||
handleEnds[handleIndex] += delta;
|
||||
|
||||
if (mode === 'push' && handleEnds[0] > handleEnds[1]) {
|
||||
handleEnds[1 - handleIndex] = handleEnds[handleIndex];
|
||||
}
|
||||
}
|
||||
|
||||
return handleEnds;
|
||||
|
||||
function getRealDelta(delta, handleEnds, extent) {
|
||||
var handleMinMax = !handleEnds.length
|
||||
? [handleEnds, handleEnds]
|
||||
: handleEnds.slice();
|
||||
handleEnds[0] > handleEnds[1] && handleMinMax.reverse();
|
||||
|
||||
if (delta < 0 && handleMinMax[0] + delta < extent[0]) {
|
||||
delta = extent[0] - handleMinMax[0];
|
||||
}
|
||||
if (delta > 0 && handleMinMax[1] + delta > extent[1]) {
|
||||
delta = extent[1] - handleMinMax[1];
|
||||
}
|
||||
return delta;
|
||||
}
|
||||
};
|
||||
});
|
||||
13
vendors/echarts/src/component/legend.js
vendored
Normal file
13
vendors/echarts/src/component/legend.js
vendored
Normal file
@@ -0,0 +1,13 @@
|
||||
/**
|
||||
* Legend component entry file8
|
||||
*/
|
||||
define(function (require) {
|
||||
|
||||
require('./legend/LegendModel');
|
||||
require('./legend/legendAction');
|
||||
require('./legend/LegendView');
|
||||
|
||||
var echarts = require('../echarts');
|
||||
// Series Filter
|
||||
echarts.registerProcessor('filter', require('./legend/legendFilter'));
|
||||
});
|
||||
180
vendors/echarts/src/component/legend/LegendModel.js
vendored
Normal file
180
vendors/echarts/src/component/legend/LegendModel.js
vendored
Normal file
@@ -0,0 +1,180 @@
|
||||
define(function(require) {
|
||||
|
||||
'use strict';
|
||||
|
||||
var zrUtil = require('zrender/core/util');
|
||||
var Model = require('../../model/Model');
|
||||
|
||||
var LegendModel = require('../../echarts').extendComponentModel({
|
||||
|
||||
type: 'legend',
|
||||
|
||||
dependencies: ['series'],
|
||||
|
||||
layoutMode: {
|
||||
type: 'box',
|
||||
ignoreSize: true
|
||||
},
|
||||
|
||||
init: function (option, parentModel, ecModel) {
|
||||
this.mergeDefaultAndTheme(option, ecModel);
|
||||
|
||||
option.selected = option.selected || {};
|
||||
|
||||
this._updateData(ecModel);
|
||||
|
||||
var legendData = this._data;
|
||||
// If has any selected in option.selected
|
||||
var selectedMap = this.option.selected;
|
||||
// If selectedMode is single, try to select one
|
||||
if (legendData[0] && this.get('selectedMode') === 'single') {
|
||||
var hasSelected = false;
|
||||
for (var name in selectedMap) {
|
||||
if (selectedMap[name]) {
|
||||
this.select(name);
|
||||
hasSelected = true;
|
||||
}
|
||||
}
|
||||
// Try select the first if selectedMode is single
|
||||
!hasSelected && this.select(legendData[0].get('name'));
|
||||
}
|
||||
},
|
||||
|
||||
mergeOption: function (option) {
|
||||
LegendModel.superCall(this, 'mergeOption', option);
|
||||
|
||||
this._updateData(this.ecModel);
|
||||
},
|
||||
|
||||
_updateData: function (ecModel) {
|
||||
var legendData = zrUtil.map(this.get('data') || [], function (dataItem) {
|
||||
if (typeof dataItem === 'string') {
|
||||
dataItem = {
|
||||
name: dataItem
|
||||
};
|
||||
}
|
||||
return new Model(dataItem, this, this.ecModel);
|
||||
}, this);
|
||||
this._data = legendData;
|
||||
|
||||
var availableNames = zrUtil.map(ecModel.getSeries(), function (series) {
|
||||
return series.name;
|
||||
});
|
||||
ecModel.eachSeries(function (seriesModel) {
|
||||
if (seriesModel.legendDataProvider) {
|
||||
var data = seriesModel.legendDataProvider();
|
||||
availableNames = availableNames.concat(data.mapArray(data.getName));
|
||||
}
|
||||
});
|
||||
/**
|
||||
* @type {Array.<string>}
|
||||
* @private
|
||||
*/
|
||||
this._availableNames = availableNames;
|
||||
},
|
||||
|
||||
/**
|
||||
* @return {Array.<module:echarts/model/Model>}
|
||||
*/
|
||||
getData: function () {
|
||||
return this._data;
|
||||
},
|
||||
|
||||
/**
|
||||
* @param {string} name
|
||||
*/
|
||||
select: function (name) {
|
||||
var selected = this.option.selected;
|
||||
var selectedMode = this.get('selectedMode');
|
||||
if (selectedMode === 'single') {
|
||||
var data = this._data;
|
||||
zrUtil.each(data, function (dataItem) {
|
||||
selected[dataItem.get('name')] = false;
|
||||
});
|
||||
}
|
||||
selected[name] = true;
|
||||
},
|
||||
|
||||
/**
|
||||
* @param {string} name
|
||||
*/
|
||||
unSelect: function (name) {
|
||||
if (this.get('selectedMode') !== 'single') {
|
||||
this.option.selected[name] = false;
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* @param {string} name
|
||||
*/
|
||||
toggleSelected: function (name) {
|
||||
var selected = this.option.selected;
|
||||
// Default is true
|
||||
if (!(name in selected)) {
|
||||
selected[name] = true;
|
||||
}
|
||||
this[selected[name] ? 'unSelect' : 'select'](name);
|
||||
},
|
||||
|
||||
/**
|
||||
* @param {string} name
|
||||
*/
|
||||
isSelected: function (name) {
|
||||
var selected = this.option.selected;
|
||||
return !((name in selected) && !selected[name])
|
||||
&& zrUtil.indexOf(this._availableNames, name) >= 0;
|
||||
},
|
||||
|
||||
defaultOption: {
|
||||
// 一级层叠
|
||||
zlevel: 0,
|
||||
// 二级层叠
|
||||
z: 4,
|
||||
show: true,
|
||||
|
||||
// 布局方式,默认为水平布局,可选为:
|
||||
// 'horizontal' | 'vertical'
|
||||
orient: 'horizontal',
|
||||
|
||||
left: 'center',
|
||||
// right: 'center',
|
||||
|
||||
top: 'top',
|
||||
// bottom: 'top',
|
||||
|
||||
// 水平对齐
|
||||
// 'auto' | 'left' | 'right'
|
||||
// 默认为 'auto', 根据 x 的位置判断是左对齐还是右对齐
|
||||
align: 'auto',
|
||||
|
||||
backgroundColor: 'rgba(0,0,0,0)',
|
||||
// 图例边框颜色
|
||||
borderColor: '#ccc',
|
||||
// 图例边框线宽,单位px,默认为0(无边框)
|
||||
borderWidth: 0,
|
||||
// 图例内边距,单位px,默认各方向内边距为5,
|
||||
// 接受数组分别设定上右下左边距,同css
|
||||
padding: 5,
|
||||
// 各个item之间的间隔,单位px,默认为10,
|
||||
// 横向布局时为水平间隔,纵向布局时为纵向间隔
|
||||
itemGap: 10,
|
||||
// 图例图形宽度
|
||||
itemWidth: 25,
|
||||
// 图例图形高度
|
||||
itemHeight: 14,
|
||||
textStyle: {
|
||||
// 图例文字颜色
|
||||
color: '#333'
|
||||
},
|
||||
// formatter: '',
|
||||
// 选择模式,默认开启图例开关
|
||||
selectedMode: true
|
||||
// 配置默认选中状态,可配合LEGEND.SELECTED事件做动态数据载入
|
||||
// selected: null,
|
||||
// 图例内容(详见legend.data,数组中每一项代表一个item
|
||||
// data: [],
|
||||
}
|
||||
});
|
||||
|
||||
return LegendModel;
|
||||
});
|
||||
230
vendors/echarts/src/component/legend/LegendView.js
vendored
Normal file
230
vendors/echarts/src/component/legend/LegendView.js
vendored
Normal file
@@ -0,0 +1,230 @@
|
||||
define(function (require) {
|
||||
|
||||
var zrUtil = require('zrender/core/util');
|
||||
var symbolCreator = require('../../util/symbol');
|
||||
var graphic = require('../../util/graphic');
|
||||
var listComponentHelper = require('../helper/listComponent');
|
||||
|
||||
var curry = zrUtil.curry;
|
||||
|
||||
var LEGEND_DISABLE_COLOR = '#ccc';
|
||||
|
||||
function dispatchSelectAction(name, api) {
|
||||
api.dispatchAction({
|
||||
type: 'legendToggleSelect',
|
||||
name: name
|
||||
});
|
||||
}
|
||||
|
||||
function dispatchHighlightAction(seriesModel, dataName, api) {
|
||||
seriesModel.get('legendHoverLink') && api.dispatchAction({
|
||||
type: 'highlight',
|
||||
seriesName: seriesModel.name,
|
||||
name: dataName
|
||||
});
|
||||
}
|
||||
|
||||
function dispatchDownplayAction(seriesModel, dataName, api) {
|
||||
seriesModel.get('legendHoverLink') && api.dispatchAction({
|
||||
type: 'downplay',
|
||||
seriesName: seriesModel.name,
|
||||
name: dataName
|
||||
});
|
||||
}
|
||||
|
||||
return require('../../echarts').extendComponentView({
|
||||
|
||||
type: 'legend',
|
||||
|
||||
init: function () {
|
||||
this._symbolTypeStore = {};
|
||||
},
|
||||
|
||||
render: function (legendModel, ecModel, api) {
|
||||
var group = this.group;
|
||||
group.removeAll();
|
||||
|
||||
if (!legendModel.get('show')) {
|
||||
return;
|
||||
}
|
||||
|
||||
var selectMode = legendModel.get('selectedMode');
|
||||
var itemAlign = legendModel.get('align');
|
||||
|
||||
if (itemAlign === 'auto') {
|
||||
itemAlign = (legendModel.get('left') === 'right'
|
||||
&& legendModel.get('orient') === 'vertical')
|
||||
? 'right' : 'left';
|
||||
}
|
||||
|
||||
var legendDrawedMap = {};
|
||||
|
||||
zrUtil.each(legendModel.getData(), function (itemModel) {
|
||||
var name = itemModel.get('name');
|
||||
|
||||
// Use empty string or \n as a newline string
|
||||
if (name === '' || name === '\n') {
|
||||
group.add(new graphic.Group({
|
||||
newline: true
|
||||
}));
|
||||
return;
|
||||
}
|
||||
|
||||
var seriesModel = ecModel.getSeriesByName(name)[0];
|
||||
|
||||
if (legendDrawedMap[name]) {
|
||||
// Series not exists
|
||||
return;
|
||||
}
|
||||
|
||||
// Series legend
|
||||
if (seriesModel) {
|
||||
var data = seriesModel.getData();
|
||||
var color = data.getVisual('color');
|
||||
|
||||
// If color is a callback function
|
||||
if (typeof color === 'function') {
|
||||
// Use the first data
|
||||
color = color(seriesModel.getDataParams(0));
|
||||
}
|
||||
|
||||
// Using rect symbol defaultly
|
||||
var legendSymbolType = data.getVisual('legendSymbol') || 'roundRect';
|
||||
var symbolType = data.getVisual('symbol');
|
||||
|
||||
var itemGroup = this._createItem(
|
||||
name, itemModel, legendModel,
|
||||
legendSymbolType, symbolType,
|
||||
itemAlign, color,
|
||||
selectMode
|
||||
);
|
||||
|
||||
itemGroup.on('click', curry(dispatchSelectAction, name, api))
|
||||
.on('mouseover', curry(dispatchHighlightAction, seriesModel, '', api))
|
||||
.on('mouseout', curry(dispatchDownplayAction, seriesModel, '', api));
|
||||
|
||||
legendDrawedMap[name] = true;
|
||||
}
|
||||
else {
|
||||
// Data legend of pie, funnel
|
||||
ecModel.eachRawSeries(function (seriesModel) {
|
||||
// In case multiple series has same data name
|
||||
if (legendDrawedMap[name]) {
|
||||
return;
|
||||
}
|
||||
if (seriesModel.legendDataProvider) {
|
||||
var data = seriesModel.legendDataProvider();
|
||||
var idx = data.indexOfName(name);
|
||||
if (idx < 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
var color = data.getItemVisual(idx, 'color');
|
||||
|
||||
var legendSymbolType = 'roundRect';
|
||||
|
||||
var itemGroup = this._createItem(
|
||||
name, itemModel, legendModel,
|
||||
legendSymbolType, null,
|
||||
itemAlign, color,
|
||||
selectMode
|
||||
);
|
||||
|
||||
itemGroup.on('click', curry(dispatchSelectAction, name, api))
|
||||
// FIXME Should not specify the series name
|
||||
.on('mouseover', curry(dispatchHighlightAction, seriesModel, name, api))
|
||||
.on('mouseout', curry(dispatchDownplayAction, seriesModel, name, api));
|
||||
|
||||
legendDrawedMap[name] = true;
|
||||
}
|
||||
}, this);
|
||||
}
|
||||
}, this);
|
||||
|
||||
listComponentHelper.layout(group, legendModel, api);
|
||||
// Render background after group is layout
|
||||
// FIXME
|
||||
listComponentHelper.addBackground(group, legendModel);
|
||||
},
|
||||
|
||||
_createItem: function (
|
||||
name, itemModel, legendModel,
|
||||
legendSymbolType, symbolType,
|
||||
itemAlign, color, selectMode
|
||||
) {
|
||||
var itemWidth = legendModel.get('itemWidth');
|
||||
var itemHeight = legendModel.get('itemHeight');
|
||||
|
||||
var isSelected = legendModel.isSelected(name);
|
||||
var itemGroup = new graphic.Group();
|
||||
|
||||
var textStyleModel = itemModel.getModel('textStyle');
|
||||
|
||||
var itemIcon = itemModel.get('icon');
|
||||
|
||||
// Use user given icon first
|
||||
legendSymbolType = itemIcon || legendSymbolType;
|
||||
itemGroup.add(symbolCreator.createSymbol(
|
||||
legendSymbolType, 0, 0, itemWidth, itemHeight, isSelected ? color : LEGEND_DISABLE_COLOR
|
||||
));
|
||||
|
||||
// Compose symbols
|
||||
// PENDING
|
||||
if (!itemIcon && symbolType
|
||||
// At least show one symbol, can't be all none
|
||||
&& ((symbolType !== legendSymbolType) || symbolType == 'none')
|
||||
) {
|
||||
var size = itemHeight * 0.8;
|
||||
if (symbolType === 'none') {
|
||||
symbolType = 'circle';
|
||||
}
|
||||
// Put symbol in the center
|
||||
itemGroup.add(symbolCreator.createSymbol(
|
||||
symbolType, (itemWidth - size) / 2, (itemHeight - size) / 2, size, size,
|
||||
isSelected ? color : LEGEND_DISABLE_COLOR
|
||||
));
|
||||
}
|
||||
|
||||
// Text
|
||||
var textX = itemAlign === 'left' ? itemWidth + 5 : -5;
|
||||
var textAlign = itemAlign;
|
||||
|
||||
var formatter = legendModel.get('formatter');
|
||||
if (typeof formatter === 'string' && formatter) {
|
||||
name = formatter.replace('{name}', name);
|
||||
}
|
||||
else if (typeof formatter === 'function') {
|
||||
name = formatter(name);
|
||||
}
|
||||
|
||||
var text = new graphic.Text({
|
||||
style: {
|
||||
text: name,
|
||||
x: textX,
|
||||
y: itemHeight / 2,
|
||||
fill: isSelected ? textStyleModel.getTextColor() : LEGEND_DISABLE_COLOR,
|
||||
textFont: textStyleModel.getFont(),
|
||||
textAlign: textAlign,
|
||||
textVerticalAlign: 'middle'
|
||||
}
|
||||
});
|
||||
itemGroup.add(text);
|
||||
|
||||
// Add a invisible rect to increase the area of mouse hover
|
||||
itemGroup.add(new graphic.Rect({
|
||||
shape: itemGroup.getBoundingRect(),
|
||||
invisible: true
|
||||
}));
|
||||
|
||||
itemGroup.eachChild(function (child) {
|
||||
child.silent = !selectMode;
|
||||
});
|
||||
|
||||
this.group.add(itemGroup);
|
||||
|
||||
graphic.setHoverStyle(itemGroup);
|
||||
|
||||
return itemGroup;
|
||||
}
|
||||
});
|
||||
});
|
||||
82
vendors/echarts/src/component/legend/legendAction.js
vendored
Normal file
82
vendors/echarts/src/component/legend/legendAction.js
vendored
Normal file
@@ -0,0 +1,82 @@
|
||||
/**
|
||||
* @file Legend action
|
||||
*/
|
||||
define(function(require) {
|
||||
|
||||
var echarts = require('../../echarts');
|
||||
var zrUtil = require('zrender/core/util');
|
||||
|
||||
function legendSelectActionHandler(methodName, payload, ecModel) {
|
||||
var selectedMap = {};
|
||||
var isToggleSelect = methodName === 'toggleSelected';
|
||||
var isSelected;
|
||||
// Update all legend components
|
||||
ecModel.eachComponent('legend', function (legendModel) {
|
||||
if (isToggleSelect && isSelected != null) {
|
||||
// Force other legend has same selected status
|
||||
// Or the first is toggled to true and other are toggled to false
|
||||
// In the case one legend has some item unSelected in option. And if other legend
|
||||
// doesn't has the item, they will assume it is selected.
|
||||
legendModel[isSelected ? 'select' : 'unSelect'](payload.name);
|
||||
}
|
||||
else {
|
||||
legendModel[methodName](payload.name);
|
||||
isSelected = legendModel.isSelected(payload.name);
|
||||
}
|
||||
var legendData = legendModel.getData();
|
||||
zrUtil.each(legendData, function (model) {
|
||||
var name = model.get('name');
|
||||
// Wrap element
|
||||
if (name === '\n' || name === '') {
|
||||
return;
|
||||
}
|
||||
var isItemSelected = legendModel.isSelected(name);
|
||||
if (name in selectedMap) {
|
||||
// Unselected if any legend is unselected
|
||||
selectedMap[name] = selectedMap[name] && isItemSelected;
|
||||
}
|
||||
else {
|
||||
selectedMap[name] = isItemSelected;
|
||||
}
|
||||
});
|
||||
});
|
||||
// Return the event explicitly
|
||||
return {
|
||||
name: payload.name,
|
||||
selected: selectedMap
|
||||
};
|
||||
}
|
||||
/**
|
||||
* @event legendToggleSelect
|
||||
* @type {Object}
|
||||
* @property {string} type 'legendToggleSelect'
|
||||
* @property {string} [from]
|
||||
* @property {string} name Series name or data item name
|
||||
*/
|
||||
echarts.registerAction(
|
||||
'legendToggleSelect', 'legendselectchanged',
|
||||
zrUtil.curry(legendSelectActionHandler, 'toggleSelected')
|
||||
);
|
||||
|
||||
/**
|
||||
* @event legendSelect
|
||||
* @type {Object}
|
||||
* @property {string} type 'legendSelect'
|
||||
* @property {string} name Series name or data item name
|
||||
*/
|
||||
echarts.registerAction(
|
||||
'legendSelect', 'legendselected',
|
||||
zrUtil.curry(legendSelectActionHandler, 'select')
|
||||
);
|
||||
|
||||
/**
|
||||
* @event legendUnSelect
|
||||
* @type {Object}
|
||||
* @property {string} type 'legendUnSelect'
|
||||
* @property {string} name Series name or data item name
|
||||
*/
|
||||
echarts.registerAction(
|
||||
'legendUnSelect', 'legendunselected',
|
||||
zrUtil.curry(legendSelectActionHandler, 'unSelect')
|
||||
);
|
||||
});
|
||||
19
vendors/echarts/src/component/legend/legendFilter.js
vendored
Normal file
19
vendors/echarts/src/component/legend/legendFilter.js
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
define(function () {
|
||||
return function (ecModel) {
|
||||
var legendModels = ecModel.findComponents({
|
||||
mainType: 'legend'
|
||||
});
|
||||
if (legendModels && legendModels.length) {
|
||||
ecModel.filterSeries(function (series) {
|
||||
// If in any legend component the status is not selected.
|
||||
// Because in legend series is assumed selected when it is not in the legend data.
|
||||
for (var i = 0; i < legendModels.length; i++) {
|
||||
if (!legendModels[i].isSelected(series.name)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
});
|
||||
}
|
||||
};
|
||||
});
|
||||
10
vendors/echarts/src/component/markLine.js
vendored
Normal file
10
vendors/echarts/src/component/markLine.js
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
define(function (require) {
|
||||
|
||||
require('./marker/MarkLineModel');
|
||||
require('./marker/MarkLineView');
|
||||
|
||||
require('../echarts').registerPreprocessor(function (opt) {
|
||||
// Make sure markLine component is enabled
|
||||
opt.markLine = opt.markLine || {};
|
||||
});
|
||||
});
|
||||
11
vendors/echarts/src/component/markPoint.js
vendored
Normal file
11
vendors/echarts/src/component/markPoint.js
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
// HINT Markpoint can't be used too much
|
||||
define(function (require) {
|
||||
|
||||
require('./marker/MarkPointModel');
|
||||
require('./marker/MarkPointView');
|
||||
|
||||
require('../echarts').registerPreprocessor(function (opt) {
|
||||
// Make sure markPoint component is enabled
|
||||
opt.markPoint = opt.markPoint || {};
|
||||
});
|
||||
});
|
||||
103
vendors/echarts/src/component/marker/MarkLineModel.js
vendored
Normal file
103
vendors/echarts/src/component/marker/MarkLineModel.js
vendored
Normal file
@@ -0,0 +1,103 @@
|
||||
define(function (require) {
|
||||
|
||||
var modelUtil = require('../../util/model');
|
||||
var zrUtil = require('zrender/core/util');
|
||||
|
||||
function fillLabel(opt) {
|
||||
modelUtil.defaultEmphasis(
|
||||
opt.label,
|
||||
modelUtil.LABEL_OPTIONS
|
||||
);
|
||||
}
|
||||
|
||||
var MarkLineModel = require('../../echarts').extendComponentModel({
|
||||
|
||||
type: 'markLine',
|
||||
|
||||
dependencies: ['series', 'grid', 'polar', 'geo'],
|
||||
/**
|
||||
* @overrite
|
||||
*/
|
||||
init: function (option, parentModel, ecModel, extraOpt) {
|
||||
this.mergeDefaultAndTheme(option, ecModel);
|
||||
this.mergeOption(option, ecModel, extraOpt.createdBySelf, true);
|
||||
},
|
||||
|
||||
mergeOption: function (newOpt, ecModel, createdBySelf, isInit) {
|
||||
if (!createdBySelf) {
|
||||
ecModel.eachSeries(function (seriesModel) {
|
||||
var markLineOpt = seriesModel.get('markLine');
|
||||
var mlModel = seriesModel.markLineModel;
|
||||
if (!markLineOpt || !markLineOpt.data) {
|
||||
seriesModel.markLineModel = null;
|
||||
return;
|
||||
}
|
||||
if (!mlModel) {
|
||||
if (isInit) {
|
||||
// Default label emphasis `position` and `show`
|
||||
fillLabel(markLineOpt);
|
||||
}
|
||||
zrUtil.each(markLineOpt.data, function (item) {
|
||||
if (item instanceof Array) {
|
||||
fillLabel(item[0]);
|
||||
fillLabel(item[1]);
|
||||
}
|
||||
else {
|
||||
fillLabel(item);
|
||||
}
|
||||
});
|
||||
var opt = {
|
||||
mainType: 'markLine',
|
||||
// Use the same series index and name
|
||||
seriesIndex: seriesModel.seriesIndex,
|
||||
name: seriesModel.name,
|
||||
createdBySelf: true
|
||||
};
|
||||
mlModel = new MarkLineModel(
|
||||
markLineOpt, this, ecModel, opt
|
||||
);
|
||||
}
|
||||
else {
|
||||
mlModel.mergeOption(markLineOpt, ecModel, true);
|
||||
}
|
||||
seriesModel.markLineModel = mlModel;
|
||||
}, this);
|
||||
}
|
||||
},
|
||||
|
||||
defaultOption: {
|
||||
zlevel: 0,
|
||||
z: 5,
|
||||
|
||||
symbol: ['circle', 'arrow'],
|
||||
symbolSize: [8, 16],
|
||||
|
||||
//symbolRotate: 0,
|
||||
|
||||
precision: 2,
|
||||
tooltip: {
|
||||
trigger: 'item'
|
||||
},
|
||||
label: {
|
||||
normal: {
|
||||
show: true,
|
||||
position: 'end'
|
||||
},
|
||||
emphasis: {
|
||||
show: true
|
||||
}
|
||||
},
|
||||
lineStyle: {
|
||||
normal: {
|
||||
type: 'dashed'
|
||||
},
|
||||
emphasis: {
|
||||
width: 3
|
||||
}
|
||||
},
|
||||
animationEasing: 'linear'
|
||||
}
|
||||
});
|
||||
|
||||
return MarkLineModel;
|
||||
});
|
||||
407
vendors/echarts/src/component/marker/MarkLineView.js
vendored
Normal file
407
vendors/echarts/src/component/marker/MarkLineView.js
vendored
Normal file
@@ -0,0 +1,407 @@
|
||||
define(function (require) {
|
||||
|
||||
var zrUtil = require('zrender/core/util');
|
||||
var List = require('../../data/List');
|
||||
var formatUtil = require('../../util/format');
|
||||
var modelUtil = require('../../util/model');
|
||||
var numberUtil = require('../../util/number');
|
||||
|
||||
var addCommas = formatUtil.addCommas;
|
||||
var encodeHTML = formatUtil.encodeHTML;
|
||||
|
||||
var markerHelper = require('./markerHelper');
|
||||
|
||||
var LineDraw = require('../../chart/helper/LineDraw');
|
||||
|
||||
var markLineTransform = function (seriesModel, coordSys, mlModel, item) {
|
||||
var data = seriesModel.getData();
|
||||
// Special type markLine like 'min', 'max', 'average'
|
||||
var mlType = item.type;
|
||||
|
||||
if (!zrUtil.isArray(item)
|
||||
&& (
|
||||
mlType === 'min' || mlType === 'max' || mlType === 'average'
|
||||
// In case
|
||||
// data: [{
|
||||
// yAxis: 10
|
||||
// }]
|
||||
|| (item.xAxis != null || item.yAxis != null)
|
||||
)
|
||||
) {
|
||||
var valueAxis;
|
||||
var valueDataDim;
|
||||
var value;
|
||||
|
||||
if (item.yAxis != null || item.xAxis != null) {
|
||||
valueDataDim = item.yAxis != null ? 'y' : 'x';
|
||||
valueAxis = coordSys.getAxis(valueDataDim);
|
||||
|
||||
value = zrUtil.retrieve(item.yAxis, item.xAxis);
|
||||
}
|
||||
else {
|
||||
var axisInfo = markerHelper.getAxisInfo(item, data, coordSys, seriesModel);
|
||||
valueDataDim = axisInfo.valueDataDim;
|
||||
valueAxis = axisInfo.valueAxis;
|
||||
value = markerHelper.numCalculate(data, valueDataDim, mlType);
|
||||
}
|
||||
var valueIndex = valueDataDim === 'x' ? 0 : 1;
|
||||
var baseIndex = 1 - valueIndex;
|
||||
|
||||
var mlFrom = zrUtil.clone(item);
|
||||
var mlTo = {};
|
||||
|
||||
mlFrom.type = null;
|
||||
|
||||
mlFrom.coord = [];
|
||||
mlTo.coord = [];
|
||||
mlFrom.coord[baseIndex] = -Infinity;
|
||||
mlTo.coord[baseIndex] = Infinity;
|
||||
|
||||
var precision = mlModel.get('precision');
|
||||
if (precision >= 0) {
|
||||
value = +value.toFixed(precision);
|
||||
}
|
||||
|
||||
mlFrom.coord[valueIndex] = mlTo.coord[valueIndex] = value;
|
||||
|
||||
item = [mlFrom, mlTo, { // Extra option for tooltip and label
|
||||
type: mlType,
|
||||
valueIndex: item.valueIndex,
|
||||
// Force to use the value of calculated value.
|
||||
value: value
|
||||
}];
|
||||
}
|
||||
|
||||
item = [
|
||||
markerHelper.dataTransform(seriesModel, item[0]),
|
||||
markerHelper.dataTransform(seriesModel, item[1]),
|
||||
zrUtil.extend({}, item[2])
|
||||
];
|
||||
|
||||
// Avoid line data type is extended by from(to) data type
|
||||
item[2].type = item[2].type || '';
|
||||
|
||||
// Merge from option and to option into line option
|
||||
zrUtil.merge(item[2], item[0]);
|
||||
zrUtil.merge(item[2], item[1]);
|
||||
|
||||
return item;
|
||||
};
|
||||
|
||||
function isInifinity(val) {
|
||||
return !isNaN(val) && !isFinite(val);
|
||||
}
|
||||
|
||||
// If a markLine has one dim
|
||||
function ifMarkLineHasOnlyDim(dimIndex, fromCoord, toCoord, coordSys) {
|
||||
var otherDimIndex = 1 - dimIndex;
|
||||
var dimName = coordSys.dimensions[dimIndex];
|
||||
return isInifinity(fromCoord[otherDimIndex]) && isInifinity(toCoord[otherDimIndex])
|
||||
&& fromCoord[dimIndex] === toCoord[dimIndex] && coordSys.getAxis(dimName).containData(fromCoord[dimIndex]);
|
||||
}
|
||||
|
||||
function markLineFilter(coordSys, item) {
|
||||
if (coordSys.type === 'cartesian2d') {
|
||||
var fromCoord = item[0].coord;
|
||||
var toCoord = item[1].coord;
|
||||
// In case
|
||||
// {
|
||||
// markLine: {
|
||||
// data: [{ yAxis: 2 }]
|
||||
// }
|
||||
// }
|
||||
if (
|
||||
fromCoord && toCoord &&
|
||||
(ifMarkLineHasOnlyDim(1, fromCoord, toCoord, coordSys)
|
||||
|| ifMarkLineHasOnlyDim(0, fromCoord, toCoord, coordSys))
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return markerHelper.dataFilter(coordSys, item[0])
|
||||
&& markerHelper.dataFilter(coordSys, item[1]);
|
||||
}
|
||||
|
||||
function updateSingleMarkerEndLayout(
|
||||
data, idx, isFrom, mlType, valueIndex, seriesModel, api
|
||||
) {
|
||||
var coordSys = seriesModel.coordinateSystem;
|
||||
var itemModel = data.getItemModel(idx);
|
||||
|
||||
var point;
|
||||
var xPx = itemModel.get('x');
|
||||
var yPx = itemModel.get('y');
|
||||
if (xPx != null && yPx != null) {
|
||||
point = [
|
||||
numberUtil.parsePercent(xPx, api.getWidth()),
|
||||
numberUtil.parsePercent(yPx, api.getHeight())
|
||||
];
|
||||
}
|
||||
else {
|
||||
// Chart like bar may have there own marker positioning logic
|
||||
if (seriesModel.getMarkerPosition) {
|
||||
// Use the getMarkerPoisition
|
||||
point = seriesModel.getMarkerPosition(
|
||||
data.getValues(data.dimensions, idx)
|
||||
);
|
||||
}
|
||||
else {
|
||||
var dims = coordSys.dimensions;
|
||||
var x = data.get(dims[0], idx);
|
||||
var y = data.get(dims[1], idx);
|
||||
point = coordSys.dataToPoint([x, y]);
|
||||
}
|
||||
// Expand line to the edge of grid if value on one axis is Inifnity
|
||||
// In case
|
||||
// markLine: {
|
||||
// data: [{
|
||||
// yAxis: 2
|
||||
// // or
|
||||
// type: 'average'
|
||||
// }]
|
||||
// }
|
||||
if (coordSys.type === 'cartesian2d') {
|
||||
var xAxis = coordSys.getAxis('x');
|
||||
var yAxis = coordSys.getAxis('y');
|
||||
var dims = coordSys.dimensions;
|
||||
if (isInifinity(data.get(dims[0], idx))) {
|
||||
point[0] = xAxis.toGlobalCoord(xAxis.getExtent()[isFrom ? 0 : 1]);
|
||||
}
|
||||
else if (isInifinity(data.get(dims[1], idx))) {
|
||||
point[1] = yAxis.toGlobalCoord(yAxis.getExtent()[isFrom ? 0 : 1]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
data.setItemLayout(idx, point);
|
||||
}
|
||||
|
||||
var markLineFormatMixin = {
|
||||
formatTooltip: function (dataIndex) {
|
||||
var data = this._data;
|
||||
var value = this.getRawValue(dataIndex);
|
||||
var formattedValue = zrUtil.isArray(value)
|
||||
? zrUtil.map(value, addCommas).join(', ') : addCommas(value);
|
||||
var name = data.getName(dataIndex);
|
||||
return this.name + '<br />'
|
||||
+ ((name ? encodeHTML(name) + ' : ' : '') + formattedValue);
|
||||
},
|
||||
|
||||
getData: function () {
|
||||
return this._data;
|
||||
},
|
||||
|
||||
setData: function (data) {
|
||||
this._data = data;
|
||||
}
|
||||
};
|
||||
|
||||
zrUtil.defaults(markLineFormatMixin, modelUtil.dataFormatMixin);
|
||||
|
||||
require('../../echarts').extendComponentView({
|
||||
|
||||
type: 'markLine',
|
||||
|
||||
init: function () {
|
||||
/**
|
||||
* Markline grouped by series
|
||||
* @private
|
||||
* @type {Object}
|
||||
*/
|
||||
this._markLineMap = {};
|
||||
},
|
||||
|
||||
render: function (markLineModel, ecModel, api) {
|
||||
var lineDrawMap = this._markLineMap;
|
||||
for (var name in lineDrawMap) {
|
||||
lineDrawMap[name].__keep = false;
|
||||
}
|
||||
|
||||
ecModel.eachSeries(function (seriesModel) {
|
||||
var mlModel = seriesModel.markLineModel;
|
||||
mlModel && this._renderSeriesML(seriesModel, mlModel, ecModel, api);
|
||||
}, this);
|
||||
|
||||
for (var name in lineDrawMap) {
|
||||
if (!lineDrawMap[name].__keep) {
|
||||
this.group.remove(lineDrawMap[name].group);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
updateLayout: function (markLineModel, ecModel, api) {
|
||||
ecModel.eachSeries(function (seriesModel) {
|
||||
var mlModel = seriesModel.markLineModel;
|
||||
if (mlModel) {
|
||||
var mlData = mlModel.getData();
|
||||
var fromData = mlModel.__from;
|
||||
var toData = mlModel.__to;
|
||||
// Update visual and layout of from symbol and to symbol
|
||||
fromData.each(function (idx) {
|
||||
var lineModel = mlData.getItemModel(idx);
|
||||
var mlType = lineModel.get('type');
|
||||
var valueIndex = lineModel.get('valueIndex');
|
||||
updateSingleMarkerEndLayout(fromData, idx, true, mlType, valueIndex, seriesModel, api);
|
||||
updateSingleMarkerEndLayout(toData, idx, false, mlType, valueIndex, seriesModel, api);
|
||||
});
|
||||
// Update layout of line
|
||||
mlData.each(function (idx) {
|
||||
mlData.setItemLayout(idx, [
|
||||
fromData.getItemLayout(idx),
|
||||
toData.getItemLayout(idx)
|
||||
]);
|
||||
});
|
||||
|
||||
this._markLineMap[seriesModel.name].updateLayout();
|
||||
}
|
||||
}, this);
|
||||
},
|
||||
|
||||
_renderSeriesML: function (seriesModel, mlModel, ecModel, api) {
|
||||
var coordSys = seriesModel.coordinateSystem;
|
||||
var seriesName = seriesModel.name;
|
||||
var seriesData = seriesModel.getData();
|
||||
|
||||
var lineDrawMap = this._markLineMap;
|
||||
var lineDraw = lineDrawMap[seriesName];
|
||||
if (!lineDraw) {
|
||||
lineDraw = lineDrawMap[seriesName] = new LineDraw();
|
||||
}
|
||||
this.group.add(lineDraw.group);
|
||||
|
||||
var mlData = createList(coordSys, seriesModel, mlModel);
|
||||
|
||||
var fromData = mlData.from;
|
||||
var toData = mlData.to;
|
||||
var lineData = mlData.line;
|
||||
|
||||
mlModel.__from = fromData;
|
||||
mlModel.__to = toData;
|
||||
// Line data for tooltip and formatter
|
||||
zrUtil.extend(mlModel, markLineFormatMixin);
|
||||
mlModel.setData(lineData);
|
||||
|
||||
var symbolType = mlModel.get('symbol');
|
||||
var symbolSize = mlModel.get('symbolSize');
|
||||
if (!zrUtil.isArray(symbolType)) {
|
||||
symbolType = [symbolType, symbolType];
|
||||
}
|
||||
if (typeof symbolSize === 'number') {
|
||||
symbolSize = [symbolSize, symbolSize];
|
||||
}
|
||||
|
||||
// Update visual and layout of from symbol and to symbol
|
||||
mlData.from.each(function (idx) {
|
||||
var lineModel = lineData.getItemModel(idx);
|
||||
var mlType = lineModel.get('type');
|
||||
var valueIndex = lineModel.get('valueIndex');
|
||||
updateDataVisualAndLayout(fromData, idx, true, mlType, valueIndex);
|
||||
updateDataVisualAndLayout(toData, idx, false, mlType, valueIndex);
|
||||
});
|
||||
|
||||
// Update visual and layout of line
|
||||
lineData.each(function (idx) {
|
||||
var lineColor = lineData.getItemModel(idx).get('lineStyle.normal.color');
|
||||
lineData.setItemVisual(idx, {
|
||||
color: lineColor || fromData.getItemVisual(idx, 'color')
|
||||
});
|
||||
lineData.setItemLayout(idx, [
|
||||
fromData.getItemLayout(idx),
|
||||
toData.getItemLayout(idx)
|
||||
]);
|
||||
|
||||
lineData.setItemVisual(idx, {
|
||||
'fromSymbolSize': fromData.getItemVisual(idx, 'symbolSize'),
|
||||
'fromSymbol': fromData.getItemVisual(idx, 'symbol'),
|
||||
'toSymbolSize': toData.getItemVisual(idx, 'symbolSize'),
|
||||
'toSymbol': toData.getItemVisual(idx, 'symbol')
|
||||
});
|
||||
});
|
||||
|
||||
lineDraw.updateData(lineData);
|
||||
|
||||
// Set host model for tooltip
|
||||
// FIXME
|
||||
mlData.line.eachItemGraphicEl(function (el, idx) {
|
||||
el.traverse(function (child) {
|
||||
child.dataModel = mlModel;
|
||||
});
|
||||
});
|
||||
|
||||
function updateDataVisualAndLayout(data, idx, isFrom, mlType, valueIndex) {
|
||||
var itemModel = data.getItemModel(idx);
|
||||
|
||||
updateSingleMarkerEndLayout(
|
||||
data, idx, isFrom, mlType, valueIndex, seriesModel, api
|
||||
);
|
||||
|
||||
data.setItemVisual(idx, {
|
||||
symbolSize: itemModel.get('symbolSize') || symbolSize[isFrom ? 0 : 1],
|
||||
symbol: itemModel.get('symbol', true) || symbolType[isFrom ? 0 : 1],
|
||||
color: itemModel.get('itemStyle.normal.color') || seriesData.getVisual('color')
|
||||
});
|
||||
}
|
||||
|
||||
lineDraw.__keep = true;
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* @inner
|
||||
* @param {module:echarts/coord/*} coordSys
|
||||
* @param {module:echarts/model/Series} seriesModel
|
||||
* @param {module:echarts/model/Model} mpModel
|
||||
*/
|
||||
function createList(coordSys, seriesModel, mlModel) {
|
||||
|
||||
var coordDimsInfos;
|
||||
if (coordSys) {
|
||||
coordDimsInfos = zrUtil.map(coordSys && coordSys.dimensions, function (coordDim) {
|
||||
var info = seriesModel.getData().getDimensionInfo(
|
||||
seriesModel.coordDimToDataDim(coordDim)[0]
|
||||
) || {}; // In map series data don't have lng and lat dimension. Fallback to same with coordSys
|
||||
info.name = coordDim;
|
||||
return info;
|
||||
});
|
||||
}
|
||||
else {
|
||||
coordDimsInfos =[{
|
||||
name: 'value',
|
||||
type: 'float'
|
||||
}];
|
||||
}
|
||||
|
||||
var fromData = new List(coordDimsInfos, mlModel);
|
||||
var toData = new List(coordDimsInfos, mlModel);
|
||||
// No dimensions
|
||||
var lineData = new List([], mlModel);
|
||||
|
||||
var optData = zrUtil.map(mlModel.get('data'), zrUtil.curry(
|
||||
markLineTransform, seriesModel, coordSys, mlModel
|
||||
));
|
||||
if (coordSys) {
|
||||
optData = zrUtil.filter(
|
||||
optData, zrUtil.curry(markLineFilter, coordSys)
|
||||
);
|
||||
}
|
||||
var dimValueGetter = coordSys ? markerHelper.dimValueGetter : function (item) {
|
||||
return item.value;
|
||||
};
|
||||
fromData.initData(
|
||||
zrUtil.map(optData, function (item) { return item[0]; }),
|
||||
null, dimValueGetter
|
||||
);
|
||||
toData.initData(
|
||||
zrUtil.map(optData, function (item) { return item[1]; }),
|
||||
null, dimValueGetter
|
||||
);
|
||||
lineData.initData(
|
||||
zrUtil.map(optData, function (item) { return item[2]; })
|
||||
);
|
||||
return {
|
||||
from: fromData,
|
||||
to: toData,
|
||||
line: lineData
|
||||
};
|
||||
}
|
||||
});
|
||||
87
vendors/echarts/src/component/marker/MarkPointModel.js
vendored
Normal file
87
vendors/echarts/src/component/marker/MarkPointModel.js
vendored
Normal file
@@ -0,0 +1,87 @@
|
||||
define(function (require) {
|
||||
|
||||
var modelUtil = require('../../util/model');
|
||||
var zrUtil = require('zrender/core/util');
|
||||
|
||||
function fillLabel(opt) {
|
||||
modelUtil.defaultEmphasis(
|
||||
opt.label,
|
||||
modelUtil.LABEL_OPTIONS
|
||||
);
|
||||
}
|
||||
var MarkPointModel = require('../../echarts').extendComponentModel({
|
||||
|
||||
type: 'markPoint',
|
||||
|
||||
dependencies: ['series', 'grid', 'polar'],
|
||||
/**
|
||||
* @overrite
|
||||
*/
|
||||
init: function (option, parentModel, ecModel, extraOpt) {
|
||||
this.mergeDefaultAndTheme(option, ecModel);
|
||||
this.mergeOption(option, ecModel, extraOpt.createdBySelf, true);
|
||||
},
|
||||
|
||||
mergeOption: function (newOpt, ecModel, createdBySelf, isInit) {
|
||||
if (!createdBySelf) {
|
||||
ecModel.eachSeries(function (seriesModel) {
|
||||
var markPointOpt = seriesModel.get('markPoint');
|
||||
var mpModel = seriesModel.markPointModel;
|
||||
if (!markPointOpt || !markPointOpt.data) {
|
||||
seriesModel.markPointModel = null;
|
||||
return;
|
||||
}
|
||||
if (!mpModel) {
|
||||
if (isInit) {
|
||||
// Default label emphasis `position` and `show`
|
||||
fillLabel(markPointOpt);
|
||||
}
|
||||
zrUtil.each(markPointOpt.data, fillLabel);
|
||||
var opt = {
|
||||
mainType: 'markPoint',
|
||||
// Use the same series index and name
|
||||
seriesIndex: seriesModel.seriesIndex,
|
||||
name: seriesModel.name,
|
||||
createdBySelf: true
|
||||
};
|
||||
mpModel = new MarkPointModel(
|
||||
markPointOpt, this, ecModel, opt
|
||||
);
|
||||
}
|
||||
else {
|
||||
mpModel.mergeOption(markPointOpt, ecModel, true);
|
||||
}
|
||||
seriesModel.markPointModel = mpModel;
|
||||
}, this);
|
||||
}
|
||||
},
|
||||
|
||||
defaultOption: {
|
||||
zlevel: 0,
|
||||
z: 5,
|
||||
symbol: 'pin',
|
||||
symbolSize: 50,
|
||||
//symbolRotate: 0,
|
||||
//symbolOffset: [0, 0]
|
||||
tooltip: {
|
||||
trigger: 'item'
|
||||
},
|
||||
label: {
|
||||
normal: {
|
||||
show: true,
|
||||
position: 'inside'
|
||||
},
|
||||
emphasis: {
|
||||
show: true
|
||||
}
|
||||
},
|
||||
itemStyle: {
|
||||
normal: {
|
||||
borderWidth: 2
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return MarkPointModel;
|
||||
});
|
||||
200
vendors/echarts/src/component/marker/MarkPointView.js
vendored
Normal file
200
vendors/echarts/src/component/marker/MarkPointView.js
vendored
Normal file
@@ -0,0 +1,200 @@
|
||||
define(function (require) {
|
||||
|
||||
var SymbolDraw = require('../../chart/helper/SymbolDraw');
|
||||
var zrUtil = require('zrender/core/util');
|
||||
var formatUtil = require('../../util/format');
|
||||
var modelUtil = require('../../util/model');
|
||||
var numberUtil = require('../../util/number');
|
||||
|
||||
var addCommas = formatUtil.addCommas;
|
||||
var encodeHTML = formatUtil.encodeHTML;
|
||||
|
||||
var List = require('../../data/List');
|
||||
|
||||
var markerHelper = require('./markerHelper');
|
||||
|
||||
function updateMarkerLayout(mpData, seriesModel, api) {
|
||||
var coordSys = seriesModel.coordinateSystem;
|
||||
mpData.each(function (idx) {
|
||||
var itemModel = mpData.getItemModel(idx);
|
||||
var point;
|
||||
var xPx = itemModel.getShallow('x');
|
||||
var yPx = itemModel.getShallow('y');
|
||||
if (xPx != null && yPx != null) {
|
||||
point = [
|
||||
numberUtil.parsePercent(xPx, api.getWidth()),
|
||||
numberUtil.parsePercent(yPx, api.getHeight())
|
||||
];
|
||||
}
|
||||
// Chart like bar may have there own marker positioning logic
|
||||
else if (seriesModel.getMarkerPosition) {
|
||||
// Use the getMarkerPoisition
|
||||
point = seriesModel.getMarkerPosition(
|
||||
mpData.getValues(mpData.dimensions, idx)
|
||||
);
|
||||
}
|
||||
else if (coordSys) {
|
||||
var x = mpData.get(coordSys.dimensions[0], idx);
|
||||
var y = mpData.get(coordSys.dimensions[1], idx);
|
||||
point = coordSys.dataToPoint([x, y]);
|
||||
}
|
||||
|
||||
mpData.setItemLayout(idx, point);
|
||||
});
|
||||
}
|
||||
|
||||
// FIXME
|
||||
var markPointFormatMixin = {
|
||||
formatTooltip: function (dataIndex) {
|
||||
var data = this.getData();
|
||||
var value = this.getRawValue(dataIndex);
|
||||
var formattedValue = zrUtil.isArray(value)
|
||||
? zrUtil.map(value, addCommas).join(', ') : addCommas(value);
|
||||
var name = data.getName(dataIndex);
|
||||
return this.name + '<br />'
|
||||
+ ((name ? encodeHTML(name) + ' : ' : '') + formattedValue);
|
||||
},
|
||||
|
||||
getData: function () {
|
||||
return this._data;
|
||||
},
|
||||
|
||||
setData: function (data) {
|
||||
this._data = data;
|
||||
}
|
||||
};
|
||||
|
||||
zrUtil.defaults(markPointFormatMixin, modelUtil.dataFormatMixin);
|
||||
|
||||
require('../../echarts').extendComponentView({
|
||||
|
||||
type: 'markPoint',
|
||||
|
||||
init: function () {
|
||||
this._symbolDrawMap = {};
|
||||
},
|
||||
|
||||
render: function (markPointModel, ecModel, api) {
|
||||
var symbolDrawMap = this._symbolDrawMap;
|
||||
for (var name in symbolDrawMap) {
|
||||
symbolDrawMap[name].__keep = false;
|
||||
}
|
||||
|
||||
ecModel.eachSeries(function (seriesModel) {
|
||||
var mpModel = seriesModel.markPointModel;
|
||||
mpModel && this._renderSeriesMP(seriesModel, mpModel, api);
|
||||
}, this);
|
||||
|
||||
for (var name in symbolDrawMap) {
|
||||
if (!symbolDrawMap[name].__keep) {
|
||||
symbolDrawMap[name].remove();
|
||||
this.group.remove(symbolDrawMap[name].group);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
updateLayout: function (markPointModel, ecModel, api) {
|
||||
ecModel.eachSeries(function (seriesModel) {
|
||||
var mpModel = seriesModel.markPointModel;
|
||||
if (mpModel) {
|
||||
updateMarkerLayout(mpModel.getData(), seriesModel, api);
|
||||
this._symbolDrawMap[seriesModel.name].updateLayout(mpModel);
|
||||
}
|
||||
}, this);
|
||||
},
|
||||
|
||||
_renderSeriesMP: function (seriesModel, mpModel, api) {
|
||||
var coordSys = seriesModel.coordinateSystem;
|
||||
var seriesName = seriesModel.name;
|
||||
var seriesData = seriesModel.getData();
|
||||
|
||||
var symbolDrawMap = this._symbolDrawMap;
|
||||
var symbolDraw = symbolDrawMap[seriesName];
|
||||
if (!symbolDraw) {
|
||||
symbolDraw = symbolDrawMap[seriesName] = new SymbolDraw();
|
||||
}
|
||||
|
||||
var mpData = createList(coordSys, seriesModel, mpModel);
|
||||
|
||||
// FIXME
|
||||
zrUtil.mixin(mpModel, markPointFormatMixin);
|
||||
mpModel.setData(mpData);
|
||||
|
||||
updateMarkerLayout(mpModel.getData(), seriesModel, api);
|
||||
|
||||
mpData.each(function (idx) {
|
||||
var itemModel = mpData.getItemModel(idx);
|
||||
var symbolSize = itemModel.getShallow('symbolSize');
|
||||
if (typeof symbolSize === 'function') {
|
||||
// FIXME 这里不兼容 ECharts 2.x,2.x 貌似参数是整个数据?
|
||||
symbolSize = symbolSize(
|
||||
mpModel.getRawValue(idx), mpModel.getDataParams(idx)
|
||||
);
|
||||
}
|
||||
mpData.setItemVisual(idx, {
|
||||
symbolSize: symbolSize,
|
||||
color: itemModel.get('itemStyle.normal.color')
|
||||
|| seriesData.getVisual('color'),
|
||||
symbol: itemModel.getShallow('symbol')
|
||||
});
|
||||
});
|
||||
|
||||
// TODO Text are wrong
|
||||
symbolDraw.updateData(mpData);
|
||||
this.group.add(symbolDraw.group);
|
||||
|
||||
// Set host model for tooltip
|
||||
// FIXME
|
||||
mpData.eachItemGraphicEl(function (el) {
|
||||
el.traverse(function (child) {
|
||||
child.dataModel = mpModel;
|
||||
});
|
||||
});
|
||||
|
||||
symbolDraw.__keep = true;
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* @inner
|
||||
* @param {module:echarts/coord/*} [coordSys]
|
||||
* @param {module:echarts/model/Series} seriesModel
|
||||
* @param {module:echarts/model/Model} mpModel
|
||||
*/
|
||||
function createList(coordSys, seriesModel, mpModel) {
|
||||
var coordDimsInfos;
|
||||
if (coordSys) {
|
||||
coordDimsInfos = zrUtil.map(coordSys && coordSys.dimensions, function (coordDim) {
|
||||
var info = seriesModel.getData().getDimensionInfo(
|
||||
seriesModel.coordDimToDataDim(coordDim)[0]
|
||||
) || {}; // In map series data don't have lng and lat dimension. Fallback to same with coordSys
|
||||
info.name = coordDim;
|
||||
return info;
|
||||
});
|
||||
}
|
||||
else {
|
||||
coordDimsInfos =[{
|
||||
name: 'value',
|
||||
type: 'float'
|
||||
}];
|
||||
}
|
||||
|
||||
var mpData = new List(coordDimsInfos, mpModel);
|
||||
var dataOpt = zrUtil.map(mpModel.get('data'), zrUtil.curry(
|
||||
markerHelper.dataTransform, seriesModel
|
||||
));
|
||||
if (coordSys) {
|
||||
dataOpt = zrUtil.filter(
|
||||
dataOpt, zrUtil.curry(markerHelper.dataFilter, coordSys)
|
||||
);
|
||||
}
|
||||
|
||||
mpData.initData(dataOpt, null,
|
||||
coordSys ? markerHelper.dimValueGetter : function (item) {
|
||||
return item.value;
|
||||
}
|
||||
);
|
||||
return mpData;
|
||||
}
|
||||
|
||||
});
|
||||
174
vendors/echarts/src/component/marker/markerHelper.js
vendored
Normal file
174
vendors/echarts/src/component/marker/markerHelper.js
vendored
Normal file
@@ -0,0 +1,174 @@
|
||||
define(function (require) {
|
||||
|
||||
var zrUtil = require('zrender/core/util');
|
||||
var numberUtil = require('../../util/number');
|
||||
var indexOf = zrUtil.indexOf;
|
||||
|
||||
function getPrecision(data, valueAxisDim, dataIndex) {
|
||||
var precision = -1;
|
||||
do {
|
||||
precision = Math.max(
|
||||
numberUtil.getPrecision(data.get(
|
||||
valueAxisDim, dataIndex
|
||||
)),
|
||||
precision
|
||||
);
|
||||
data = data.stackedOn;
|
||||
} while (data);
|
||||
|
||||
return precision;
|
||||
}
|
||||
|
||||
function markerTypeCalculatorWithExtent(
|
||||
mlType, data, baseDataDim, valueDataDim, baseCoordIndex, valueCoordIndex
|
||||
) {
|
||||
var coordArr = [];
|
||||
var value = numCalculate(data, valueDataDim, mlType);
|
||||
|
||||
var dataIndex = data.indexOfNearest(valueDataDim, value, true);
|
||||
coordArr[baseCoordIndex] = data.get(baseDataDim, dataIndex, true);
|
||||
coordArr[valueCoordIndex] = data.get(valueDataDim, dataIndex, true);
|
||||
|
||||
var precision = getPrecision(data, valueDataDim, dataIndex);
|
||||
if (precision >= 0) {
|
||||
coordArr[valueCoordIndex] = +coordArr[valueCoordIndex].toFixed(precision);
|
||||
}
|
||||
|
||||
return coordArr;
|
||||
}
|
||||
|
||||
var curry = zrUtil.curry;
|
||||
// TODO Specified percent
|
||||
var markerTypeCalculator = {
|
||||
/**
|
||||
* @method
|
||||
* @param {module:echarts/data/List} data
|
||||
* @param {string} baseAxisDim
|
||||
* @param {string} valueAxisDim
|
||||
*/
|
||||
min: curry(markerTypeCalculatorWithExtent, 'min'),
|
||||
/**
|
||||
* @method
|
||||
* @param {module:echarts/data/List} data
|
||||
* @param {string} baseAxisDim
|
||||
* @param {string} valueAxisDim
|
||||
*/
|
||||
max: curry(markerTypeCalculatorWithExtent, 'max'),
|
||||
/**
|
||||
* @method
|
||||
* @param {module:echarts/data/List} data
|
||||
* @param {string} baseAxisDim
|
||||
* @param {string} valueAxisDim
|
||||
*/
|
||||
average: curry(markerTypeCalculatorWithExtent, 'average')
|
||||
};
|
||||
|
||||
/**
|
||||
* Transform markPoint data item to format used in List by do the following
|
||||
* 1. Calculate statistic like `max`, `min`, `average`
|
||||
* 2. Convert `item.xAxis`, `item.yAxis` to `item.coord` array
|
||||
* @param {module:echarts/model/Series} seriesModel
|
||||
* @param {module:echarts/coord/*} [coordSys]
|
||||
* @param {Object} item
|
||||
* @return {Object}
|
||||
*/
|
||||
var dataTransform = function (seriesModel, item) {
|
||||
var data = seriesModel.getData();
|
||||
var coordSys = seriesModel.coordinateSystem;
|
||||
|
||||
// 1. If not specify the position with pixel directly
|
||||
// 2. If `coord` is not a data array. Which uses `xAxis`,
|
||||
// `yAxis` to specify the coord on each dimension
|
||||
|
||||
// parseFloat first because item.x and item.y can be percent string like '20%'
|
||||
if (item && (isNaN(parseFloat(item.x)) || isNaN(parseFloat(item.y)))
|
||||
&& !zrUtil.isArray(item.coord)
|
||||
&& coordSys
|
||||
) {
|
||||
var axisInfo = getAxisInfo(item, data, coordSys, seriesModel);
|
||||
|
||||
// Clone the option
|
||||
// Transform the properties xAxis, yAxis, radiusAxis, angleAxis, geoCoord to value
|
||||
item = zrUtil.clone(item);
|
||||
|
||||
if (item.type
|
||||
&& markerTypeCalculator[item.type]
|
||||
&& axisInfo.baseAxis && axisInfo.valueAxis
|
||||
) {
|
||||
var dims = coordSys.dimensions;
|
||||
var baseCoordIndex = indexOf(dims, axisInfo.baseAxis.dim);
|
||||
var valueCoordIndex = indexOf(dims, axisInfo.valueAxis.dim);
|
||||
|
||||
item.coord = markerTypeCalculator[item.type](
|
||||
data, axisInfo.baseDataDim, axisInfo.valueDataDim,
|
||||
baseCoordIndex, valueCoordIndex
|
||||
);
|
||||
// Force to use the value of calculated value.
|
||||
item.value = item.coord[valueCoordIndex];
|
||||
}
|
||||
else {
|
||||
// FIXME Only has one of xAxis and yAxis.
|
||||
item.coord = [
|
||||
item.xAxis != null ? item.xAxis : item.radiusAxis,
|
||||
item.yAxis != null ? item.yAxis : item.angleAxis
|
||||
];
|
||||
}
|
||||
}
|
||||
return item;
|
||||
};
|
||||
|
||||
var getAxisInfo = function (item, data, coordSys, seriesModel) {
|
||||
var ret = {};
|
||||
|
||||
if (item.valueIndex != null || item.valueDim != null) {
|
||||
ret.valueDataDim = item.valueIndex != null
|
||||
? data.getDimension(item.valueIndex) : item.valueDim;
|
||||
ret.valueAxis = coordSys.getAxis(seriesModel.dataDimToCoordDim(ret.valueDataDim));
|
||||
ret.baseAxis = coordSys.getOtherAxis(ret.valueAxis);
|
||||
ret.baseDataDim = seriesModel.coordDimToDataDim(ret.baseAxis.dim)[0];
|
||||
}
|
||||
else {
|
||||
ret.baseAxis = seriesModel.getBaseAxis();
|
||||
ret.valueAxis = coordSys.getOtherAxis(ret.baseAxis);
|
||||
ret.baseDataDim = seriesModel.coordDimToDataDim(ret.baseAxis.dim)[0];
|
||||
ret.valueDataDim = seriesModel.coordDimToDataDim(ret.valueAxis.dim)[0];
|
||||
}
|
||||
|
||||
return ret;
|
||||
};
|
||||
|
||||
/**
|
||||
* Filter data which is out of coordinateSystem range
|
||||
* [dataFilter description]
|
||||
* @param {module:echarts/coord/*} [coordSys]
|
||||
* @param {Object} item
|
||||
* @return {boolean}
|
||||
*/
|
||||
var dataFilter = function (coordSys, item) {
|
||||
// Alwalys return true if there is no coordSys
|
||||
return (coordSys && coordSys.containData && item.coord && (item.x == null || item.y == null))
|
||||
? coordSys.containData(item.coord) : true;
|
||||
};
|
||||
|
||||
var dimValueGetter = function (item, dimName, dataIndex, dimIndex) {
|
||||
// x, y, radius, angle
|
||||
if (dimIndex < 2) {
|
||||
return item.coord && item.coord[dimIndex];
|
||||
}
|
||||
return item.value;
|
||||
};
|
||||
|
||||
var numCalculate = function (data, valueDataDim, mlType) {
|
||||
return mlType === 'average'
|
||||
? data.getSum(valueDataDim, true) / data.count()
|
||||
: data.getDataExtent(valueDataDim, true)[mlType === 'max' ? 1 : 0];
|
||||
};
|
||||
|
||||
return {
|
||||
dataTransform: dataTransform,
|
||||
dataFilter: dataFilter,
|
||||
dimValueGetter: dimValueGetter,
|
||||
getAxisInfo: getAxisInfo,
|
||||
numCalculate: numCalculate
|
||||
};
|
||||
});
|
||||
18
vendors/echarts/src/component/parallel.js
vendored
Normal file
18
vendors/echarts/src/component/parallel.js
vendored
Normal file
@@ -0,0 +1,18 @@
|
||||
define(function(require) {
|
||||
|
||||
require('../coord/parallel/parallelCreator');
|
||||
require('../coord/parallel/ParallelModel');
|
||||
require('./parallelAxis');
|
||||
|
||||
var echarts = require('../echarts');
|
||||
|
||||
// Parallel view
|
||||
echarts.extendComponentView({
|
||||
type: 'parallel'
|
||||
});
|
||||
|
||||
echarts.registerPreprocessor(
|
||||
require('../coord/parallel/parallelPreprocessor')
|
||||
);
|
||||
|
||||
});
|
||||
7
vendors/echarts/src/component/parallelAxis.js
vendored
Normal file
7
vendors/echarts/src/component/parallelAxis.js
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
define(function(require) {
|
||||
|
||||
require('../coord/parallel/parallelCreator');
|
||||
require('./axis/parallelAxisAction');
|
||||
require('./axis/ParallelAxisView');
|
||||
|
||||
});
|
||||
12
vendors/echarts/src/component/polar.js
vendored
Normal file
12
vendors/echarts/src/component/polar.js
vendored
Normal file
@@ -0,0 +1,12 @@
|
||||
define(function(require) {
|
||||
'use strict';
|
||||
|
||||
require('../coord/polar/polarCreator');
|
||||
require('./angleAxis');
|
||||
require('./radiusAxis');
|
||||
|
||||
// Polar view
|
||||
require('../echarts').extendComponentView({
|
||||
type: 'polar'
|
||||
});
|
||||
});
|
||||
7
vendors/echarts/src/component/radar.js
vendored
Normal file
7
vendors/echarts/src/component/radar.js
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
define(function (require) {
|
||||
|
||||
require('../coord/radar/Radar');
|
||||
require('../coord/radar/RadarModel');
|
||||
|
||||
require('./radar/RadarView');
|
||||
});
|
||||
167
vendors/echarts/src/component/radar/RadarView.js
vendored
Normal file
167
vendors/echarts/src/component/radar/RadarView.js
vendored
Normal file
@@ -0,0 +1,167 @@
|
||||
define(function (require) {
|
||||
|
||||
var AxisBuilder = require('../axis/AxisBuilder');
|
||||
var zrUtil = require('zrender/core/util');
|
||||
var graphic = require('../../util/graphic');
|
||||
|
||||
var axisBuilderAttrs = [
|
||||
'axisLine', 'axisLabel', 'axisTick', 'axisName'
|
||||
];
|
||||
|
||||
return require('../../echarts').extendComponentView({
|
||||
|
||||
type: 'radar',
|
||||
|
||||
render: function (radarModel, ecModel, api) {
|
||||
var group = this.group;
|
||||
group.removeAll();
|
||||
|
||||
this._buildAxes(radarModel);
|
||||
this._buildSplitLineAndArea(radarModel);
|
||||
},
|
||||
|
||||
_buildAxes: function (radarModel) {
|
||||
var radar = radarModel.coordinateSystem;
|
||||
var indicatorAxes = radar.getIndicatorAxes();
|
||||
var axisBuilders = zrUtil.map(indicatorAxes, function (indicatorAxis) {
|
||||
var axisBuilder = new AxisBuilder(indicatorAxis.model, {
|
||||
position: [radar.cx, radar.cy],
|
||||
rotation: indicatorAxis.angle,
|
||||
labelDirection: -1,
|
||||
tickDirection: -1,
|
||||
nameDirection: 1
|
||||
});
|
||||
return axisBuilder;
|
||||
});
|
||||
|
||||
zrUtil.each(axisBuilders, function (axisBuilder) {
|
||||
zrUtil.each(axisBuilderAttrs, axisBuilder.add, axisBuilder);
|
||||
this.group.add(axisBuilder.getGroup());
|
||||
}, this);
|
||||
},
|
||||
|
||||
_buildSplitLineAndArea: function (radarModel) {
|
||||
var radar = radarModel.coordinateSystem;
|
||||
var splitNumber = radarModel.get('splitNumber');
|
||||
var indicatorAxes = radar.getIndicatorAxes();
|
||||
if (!indicatorAxes.length) {
|
||||
return;
|
||||
}
|
||||
var shape = radarModel.get('shape');
|
||||
var splitLineModel = radarModel.getModel('splitLine');
|
||||
var splitAreaModel = radarModel.getModel('splitArea');
|
||||
var lineStyleModel = splitLineModel.getModel('lineStyle');
|
||||
var areaStyleModel = splitAreaModel.getModel('areaStyle');
|
||||
|
||||
var showSplitLine = splitLineModel.get('show');
|
||||
var showSplitArea = splitAreaModel.get('show');
|
||||
var splitLineColors = lineStyleModel.get('color');
|
||||
var splitAreaColors = areaStyleModel.get('color');
|
||||
|
||||
splitLineColors = zrUtil.isArray(splitLineColors) ? splitLineColors : [splitLineColors];
|
||||
splitAreaColors = zrUtil.isArray(splitAreaColors) ? splitAreaColors : [splitAreaColors];
|
||||
|
||||
var splitLines = [];
|
||||
var splitAreas = [];
|
||||
|
||||
function getColorIndex(areaOrLine, areaOrLineColorList, idx) {
|
||||
var colorIndex = idx % areaOrLineColorList.length;
|
||||
areaOrLine[colorIndex] = areaOrLine[colorIndex] || [];
|
||||
return colorIndex;
|
||||
}
|
||||
|
||||
if (shape === 'circle') {
|
||||
var ticksRadius = indicatorAxes[0].getTicksCoords();
|
||||
var cx = radar.cx;
|
||||
var cy = radar.cy;
|
||||
for (var i = 0; i < ticksRadius.length; i++) {
|
||||
if (showSplitLine) {
|
||||
var colorIndex = getColorIndex(splitLines, splitLineColors, i);
|
||||
splitLines[colorIndex].push(new graphic.Circle({
|
||||
shape: {
|
||||
cx: cx,
|
||||
cy: cy,
|
||||
r: ticksRadius[i]
|
||||
}
|
||||
}));
|
||||
}
|
||||
if (showSplitArea && i < ticksRadius.length - 1) {
|
||||
var colorIndex = getColorIndex(splitAreas, splitAreaColors, i);
|
||||
splitAreas[colorIndex].push(new graphic.Ring({
|
||||
shape: {
|
||||
cx: cx,
|
||||
cy: cy,
|
||||
r0: ticksRadius[i],
|
||||
r: ticksRadius[i + 1]
|
||||
}
|
||||
}));
|
||||
}
|
||||
}
|
||||
}
|
||||
// Polyyon
|
||||
else {
|
||||
var axesTicksPoints = zrUtil.map(indicatorAxes, function (indicatorAxis, idx) {
|
||||
var ticksCoords = indicatorAxis.getTicksCoords();
|
||||
return zrUtil.map(ticksCoords, function (tickCoord) {
|
||||
return radar.coordToPoint(tickCoord, idx);
|
||||
});
|
||||
});
|
||||
|
||||
var prevPoints = [];
|
||||
for (var i = 0; i <= splitNumber; i++) {
|
||||
var points = [];
|
||||
for (var j = 0; j < indicatorAxes.length; j++) {
|
||||
points.push(axesTicksPoints[j][i]);
|
||||
}
|
||||
// Close
|
||||
points.push(points[0].slice());
|
||||
if (showSplitLine) {
|
||||
var colorIndex = getColorIndex(splitLines, splitLineColors, i);
|
||||
splitLines[colorIndex].push(new graphic.Polyline({
|
||||
shape: {
|
||||
points: points
|
||||
}
|
||||
}));
|
||||
}
|
||||
if (showSplitArea && prevPoints) {
|
||||
var colorIndex = getColorIndex(splitAreas, splitAreaColors, i - 1);
|
||||
splitAreas[colorIndex].push(new graphic.Polygon({
|
||||
shape: {
|
||||
points: points.concat(prevPoints)
|
||||
}
|
||||
}));
|
||||
}
|
||||
prevPoints = points.slice().reverse();
|
||||
}
|
||||
}
|
||||
|
||||
var lineStyle = lineStyleModel.getLineStyle();
|
||||
var areaStyle = areaStyleModel.getAreaStyle();
|
||||
// Add splitArea before splitLine
|
||||
zrUtil.each(splitAreas, function (splitAreas, idx) {
|
||||
this.group.add(graphic.mergePath(
|
||||
splitAreas, {
|
||||
style: zrUtil.defaults({
|
||||
stroke: 'none',
|
||||
fill: splitAreaColors[idx % splitAreaColors.length]
|
||||
}, areaStyle),
|
||||
silent: true
|
||||
}
|
||||
));
|
||||
}, this);
|
||||
|
||||
zrUtil.each(splitLines, function (splitLines, idx) {
|
||||
this.group.add(graphic.mergePath(
|
||||
splitLines, {
|
||||
style: zrUtil.defaults({
|
||||
fill: 'none',
|
||||
stroke: splitLineColors[idx % splitLineColors.length]
|
||||
}, lineStyle),
|
||||
silent: true
|
||||
}
|
||||
));
|
||||
}, this);
|
||||
|
||||
}
|
||||
});
|
||||
});
|
||||
6
vendors/echarts/src/component/radiusAxis.js
vendored
Normal file
6
vendors/echarts/src/component/radiusAxis.js
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
define(function(require) {
|
||||
|
||||
require('../coord/polar/polarCreator');
|
||||
|
||||
require('./axis/RadiusAxisView');
|
||||
});
|
||||
12
vendors/echarts/src/component/single.js
vendored
Normal file
12
vendors/echarts/src/component/single.js
vendored
Normal file
@@ -0,0 +1,12 @@
|
||||
define(function (require) {
|
||||
|
||||
require('../coord/single/singleCreator');
|
||||
require('./singleAxis');
|
||||
|
||||
var echarts = require('../echarts');
|
||||
|
||||
echarts.extendComponentView({
|
||||
type: 'single'
|
||||
});
|
||||
|
||||
});
|
||||
7
vendors/echarts/src/component/singleAxis.js
vendored
Normal file
7
vendors/echarts/src/component/singleAxis.js
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
define(function (require) {
|
||||
|
||||
require('../coord/single/singleCreator');
|
||||
require('./axis/SingleAxisView');
|
||||
require('../coord/single/AxisModel');
|
||||
|
||||
});
|
||||
15
vendors/echarts/src/component/timeline.js
vendored
Normal file
15
vendors/echarts/src/component/timeline.js
vendored
Normal file
@@ -0,0 +1,15 @@
|
||||
/**
|
||||
* DataZoom component entry
|
||||
*/
|
||||
define(function (require) {
|
||||
|
||||
var echarts = require('../echarts');
|
||||
|
||||
echarts.registerPreprocessor(require('./timeline/preprocessor'));
|
||||
|
||||
require('./timeline/typeDefaulter');
|
||||
require('./timeline/timelineAction');
|
||||
require('./timeline/SliderTimelineModel');
|
||||
require('./timeline/SliderTimelineView');
|
||||
|
||||
});
|
||||
111
vendors/echarts/src/component/timeline/SliderTimelineModel.js
vendored
Normal file
111
vendors/echarts/src/component/timeline/SliderTimelineModel.js
vendored
Normal file
@@ -0,0 +1,111 @@
|
||||
/**
|
||||
* @file Silder timeline model
|
||||
*/
|
||||
define(function(require) {
|
||||
|
||||
var TimelineModel = require('./TimelineModel');
|
||||
var zrUtil = require('zrender/core/util');
|
||||
var modelUtil = require('../../util/model');
|
||||
|
||||
var SliderTimelineModel = TimelineModel.extend({
|
||||
|
||||
type: 'timeline.slider',
|
||||
|
||||
/**
|
||||
* @protected
|
||||
*/
|
||||
defaultOption: {
|
||||
|
||||
backgroundColor: 'rgba(0,0,0,0)', // 时间轴背景颜色
|
||||
borderColor: '#ccc', // 时间轴边框颜色
|
||||
borderWidth: 0, // 时间轴边框线宽,单位px,默认为0(无边框)
|
||||
|
||||
orient: 'horizontal', // 'vertical'
|
||||
inverse: false,
|
||||
|
||||
tooltip: { // boolean or Object
|
||||
trigger: 'item' // data item may also have tootip attr.
|
||||
},
|
||||
|
||||
symbol: 'emptyCircle',
|
||||
symbolSize: 10,
|
||||
|
||||
lineStyle: {
|
||||
show: true,
|
||||
width: 2,
|
||||
color: '#304654'
|
||||
},
|
||||
label: { // 文本标签
|
||||
position: 'auto', // auto left right top bottom
|
||||
// When using number, label position is not
|
||||
// restricted by viewRect.
|
||||
// positive: right/bottom, negative: left/top
|
||||
normal: {
|
||||
show: true,
|
||||
interval: 'auto',
|
||||
rotate: 0,
|
||||
// formatter: null,
|
||||
textStyle: { // 其余属性默认使用全局文本样式,详见TEXTSTYLE
|
||||
color: '#304654'
|
||||
}
|
||||
},
|
||||
emphasis: {
|
||||
show: true,
|
||||
textStyle: { // 其余属性默认使用全局文本样式,详见TEXTSTYLE
|
||||
color: '#c23531'
|
||||
}
|
||||
}
|
||||
},
|
||||
itemStyle: {
|
||||
normal: {
|
||||
color: '#304654',
|
||||
borderWidth: 1
|
||||
},
|
||||
emphasis: {
|
||||
color: '#c23531'
|
||||
}
|
||||
},
|
||||
|
||||
checkpointStyle: {
|
||||
symbol: 'circle',
|
||||
symbolSize: 13,
|
||||
color: '#c23531',
|
||||
borderWidth: 5,
|
||||
borderColor: 'rgba(194,53,49, 0.5)',
|
||||
animation: true,
|
||||
animationDuration: 300,
|
||||
animationEasing: 'quinticInOut'
|
||||
},
|
||||
|
||||
controlStyle: {
|
||||
show: true,
|
||||
showPlayBtn: true,
|
||||
showPrevBtn: true,
|
||||
showNextBtn: true,
|
||||
itemSize: 22,
|
||||
itemGap: 12,
|
||||
position: 'left', // 'left' 'right' 'top' 'bottom'
|
||||
playIcon: 'path://M31.6,53C17.5,53,6,41.5,6,27.4S17.5,1.8,31.6,1.8C45.7,1.8,57.2,13.3,57.2,27.4S45.7,53,31.6,53z M31.6,3.3 C18.4,3.3,7.5,14.1,7.5,27.4c0,13.3,10.8,24.1,24.1,24.1C44.9,51.5,55.7,40.7,55.7,27.4C55.7,14.1,44.9,3.3,31.6,3.3z M24.9,21.3 c0-2.2,1.6-3.1,3.5-2l10.5,6.1c1.899,1.1,1.899,2.9,0,4l-10.5,6.1c-1.9,1.1-3.5,0.2-3.5-2V21.3z', // jshint ignore:line
|
||||
stopIcon: 'path://M30.9,53.2C16.8,53.2,5.3,41.7,5.3,27.6S16.8,2,30.9,2C45,2,56.4,13.5,56.4,27.6S45,53.2,30.9,53.2z M30.9,3.5C17.6,3.5,6.8,14.4,6.8,27.6c0,13.3,10.8,24.1,24.101,24.1C44.2,51.7,55,40.9,55,27.6C54.9,14.4,44.1,3.5,30.9,3.5z M36.9,35.8c0,0.601-0.4,1-0.9,1h-1.3c-0.5,0-0.9-0.399-0.9-1V19.5c0-0.6,0.4-1,0.9-1H36c0.5,0,0.9,0.4,0.9,1V35.8z M27.8,35.8 c0,0.601-0.4,1-0.9,1h-1.3c-0.5,0-0.9-0.399-0.9-1V19.5c0-0.6,0.4-1,0.9-1H27c0.5,0,0.9,0.4,0.9,1L27.8,35.8L27.8,35.8z', // jshint ignore:line
|
||||
nextIcon: 'path://M18.6,50.8l22.5-22.5c0.2-0.2,0.3-0.4,0.3-0.7c0-0.3-0.1-0.5-0.3-0.7L18.7,4.4c-0.1-0.1-0.2-0.3-0.2-0.5 c0-0.4,0.3-0.8,0.8-0.8c0.2,0,0.5,0.1,0.6,0.3l23.5,23.5l0,0c0.2,0.2,0.3,0.4,0.3,0.7c0,0.3-0.1,0.5-0.3,0.7l-0.1,0.1L19.7,52 c-0.1,0.1-0.3,0.2-0.5,0.2c-0.4,0-0.8-0.3-0.8-0.8C18.4,51.2,18.5,51,18.6,50.8z', // jshint ignore:line
|
||||
prevIcon: 'path://M43,52.8L20.4,30.3c-0.2-0.2-0.3-0.4-0.3-0.7c0-0.3,0.1-0.5,0.3-0.7L42.9,6.4c0.1-0.1,0.2-0.3,0.2-0.5 c0-0.4-0.3-0.8-0.8-0.8c-0.2,0-0.5,0.1-0.6,0.3L18.3,28.8l0,0c-0.2,0.2-0.3,0.4-0.3,0.7c0,0.3,0.1,0.5,0.3,0.7l0.1,0.1L41.9,54 c0.1,0.1,0.3,0.2,0.5,0.2c0.4,0,0.8-0.3,0.8-0.8C43.2,53.2,43.1,53,43,52.8z', // jshint ignore:line
|
||||
normal: {
|
||||
color: '#304654',
|
||||
borderColor: '#304654',
|
||||
borderWidth: 1
|
||||
},
|
||||
emphasis: {
|
||||
color: '#c23531',
|
||||
borderColor: '#c23531',
|
||||
borderWidth: 2
|
||||
}
|
||||
},
|
||||
data: []
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
zrUtil.mixin(SliderTimelineModel, modelUtil.dataFormatMixin);
|
||||
|
||||
return SliderTimelineModel;
|
||||
});
|
||||
688
vendors/echarts/src/component/timeline/SliderTimelineView.js
vendored
Normal file
688
vendors/echarts/src/component/timeline/SliderTimelineView.js
vendored
Normal file
@@ -0,0 +1,688 @@
|
||||
/**
|
||||
* @file Silder timeline view
|
||||
*/
|
||||
define(function (require) {
|
||||
|
||||
var zrUtil = require('zrender/core/util');
|
||||
var graphic = require('../../util/graphic');
|
||||
var layout = require('../../util/layout');
|
||||
var TimelineView = require('./TimelineView');
|
||||
var TimelineAxis = require('./TimelineAxis');
|
||||
var symbolUtil = require('../../util/symbol');
|
||||
var axisHelper = require('../../coord/axisHelper');
|
||||
var BoundingRect = require('zrender/core/BoundingRect');
|
||||
var matrix = require('zrender/core/matrix');
|
||||
var numberUtil = require('../../util/number');
|
||||
var formatUtil = require('../../util/format');
|
||||
var encodeHTML = formatUtil.encodeHTML;
|
||||
|
||||
var bind = zrUtil.bind;
|
||||
var each = zrUtil.each;
|
||||
|
||||
var PI = Math.PI;
|
||||
|
||||
return TimelineView.extend({
|
||||
|
||||
type: 'timeline.slider',
|
||||
|
||||
init: function (ecModel, api) {
|
||||
|
||||
this.api = api;
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {module:echarts/component/timeline/TimelineAxis}
|
||||
*/
|
||||
this._axis;
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {module:zrender/core/BoundingRect}
|
||||
*/
|
||||
this._viewRect;
|
||||
|
||||
/**
|
||||
* @type {number}
|
||||
*/
|
||||
this._timer;
|
||||
|
||||
/**
|
||||
* @type {module:zrende/Element}
|
||||
*/
|
||||
this._currentPointer;
|
||||
|
||||
/**
|
||||
* @type {module:zrender/container/Group}
|
||||
*/
|
||||
this._mainGroup;
|
||||
|
||||
/**
|
||||
* @type {module:zrender/container/Group}
|
||||
*/
|
||||
this._labelGroup;
|
||||
},
|
||||
|
||||
/**
|
||||
* @override
|
||||
*/
|
||||
render: function (timelineModel, ecModel, api, payload) {
|
||||
this.model = timelineModel;
|
||||
this.api = api;
|
||||
this.ecModel = ecModel;
|
||||
|
||||
this.group.removeAll();
|
||||
|
||||
if (timelineModel.get('show', true)) {
|
||||
|
||||
var layoutInfo = this._layout(timelineModel, api);
|
||||
var mainGroup = this._createGroup('mainGroup');
|
||||
var labelGroup = this._createGroup('labelGroup');
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {module:echarts/component/timeline/TimelineAxis}
|
||||
*/
|
||||
var axis = this._axis = this._createAxis(layoutInfo, timelineModel);
|
||||
|
||||
timelineModel.formatTooltip = function (dataIndex) {
|
||||
return encodeHTML(axis.scale.getLabel(dataIndex));
|
||||
};
|
||||
|
||||
each(
|
||||
['AxisLine', 'AxisTick', 'Control', 'CurrentPointer'],
|
||||
function (name) {
|
||||
this['_render' + name](layoutInfo, mainGroup, axis, timelineModel);
|
||||
},
|
||||
this
|
||||
);
|
||||
|
||||
this._renderAxisLabel(layoutInfo, labelGroup, axis, timelineModel);
|
||||
|
||||
this._position(layoutInfo, timelineModel);
|
||||
}
|
||||
|
||||
this._doPlayStop();
|
||||
},
|
||||
|
||||
/**
|
||||
* @override
|
||||
*/
|
||||
remove: function () {
|
||||
this._clearTimer();
|
||||
this.group.removeAll();
|
||||
},
|
||||
|
||||
/**
|
||||
* @override
|
||||
*/
|
||||
dispose: function () {
|
||||
this._clearTimer();
|
||||
},
|
||||
|
||||
_layout: function (timelineModel, api) {
|
||||
var labelPosOpt = timelineModel.get('label.normal.position');
|
||||
var orient = timelineModel.get('orient');
|
||||
var viewRect = getViewRect(timelineModel, api);
|
||||
// Auto label offset.
|
||||
if (labelPosOpt == null || labelPosOpt === 'auto') {
|
||||
labelPosOpt = orient === 'horizontal'
|
||||
? ((viewRect.y + viewRect.height / 2) < api.getHeight() / 2 ? '-' : '+')
|
||||
: ((viewRect.x + viewRect.width / 2) < api.getWidth() / 2 ? '+' : '-');
|
||||
}
|
||||
else if (isNaN(labelPosOpt)) {
|
||||
labelPosOpt = ({
|
||||
horizontal: {top: '-', bottom: '+'},
|
||||
vertical: {left: '-', right: '+'}
|
||||
})[orient][labelPosOpt];
|
||||
}
|
||||
|
||||
// FIXME
|
||||
// 暂没有实现用户传入
|
||||
// var labelAlign = timelineModel.get('label.normal.textStyle.align');
|
||||
// var labelBaseline = timelineModel.get('label.normal.textStyle.baseline');
|
||||
var labelAlignMap = {
|
||||
horizontal: 'center',
|
||||
vertical: (labelPosOpt >= 0 || labelPosOpt === '+') ? 'left' : 'right'
|
||||
};
|
||||
|
||||
var labelBaselineMap = {
|
||||
horizontal: (labelPosOpt >= 0 || labelPosOpt === '+') ? 'top' : 'bottom',
|
||||
vertical: 'middle'
|
||||
};
|
||||
var rotationMap = {
|
||||
horizontal: 0,
|
||||
vertical: PI / 2
|
||||
};
|
||||
|
||||
// Position
|
||||
var mainLength = orient === 'vertical' ? viewRect.height : viewRect.width;
|
||||
|
||||
var controlModel = timelineModel.getModel('controlStyle');
|
||||
var showControl = controlModel.get('show');
|
||||
var controlSize = showControl ? controlModel.get('itemSize') : 0;
|
||||
var controlGap = showControl ? controlModel.get('itemGap') : 0;
|
||||
var sizePlusGap = controlSize + controlGap;
|
||||
|
||||
// Special label rotate.
|
||||
var labelRotation = timelineModel.get('label.normal.rotate') || 0;
|
||||
labelRotation = labelRotation * PI / 180; // To radian.
|
||||
|
||||
var playPosition;
|
||||
var prevBtnPosition;
|
||||
var nextBtnPosition;
|
||||
var axisExtent;
|
||||
var controlPosition = controlModel.get('position', true);
|
||||
var showControl = controlModel.get('show', true);
|
||||
var showPlayBtn = showControl && controlModel.get('showPlayBtn', true);
|
||||
var showPrevBtn = showControl && controlModel.get('showPrevBtn', true);
|
||||
var showNextBtn = showControl && controlModel.get('showNextBtn', true);
|
||||
var xLeft = 0;
|
||||
var xRight = mainLength;
|
||||
|
||||
// position[0] means left, position[1] means middle.
|
||||
if (controlPosition === 'left' || controlPosition === 'bottom') {
|
||||
showPlayBtn && (playPosition = [0, 0], xLeft += sizePlusGap);
|
||||
showPrevBtn && (prevBtnPosition = [xLeft, 0], xLeft += sizePlusGap);
|
||||
showNextBtn && (nextBtnPosition = [xRight - controlSize, 0], xRight -= sizePlusGap);
|
||||
}
|
||||
else { // 'top' 'right'
|
||||
showPlayBtn && (playPosition = [xRight - controlSize, 0], xRight -= sizePlusGap);
|
||||
showPrevBtn && (prevBtnPosition = [0, 0], xLeft += sizePlusGap);
|
||||
showNextBtn && (nextBtnPosition = [xRight - controlSize, 0], xRight -= sizePlusGap);
|
||||
}
|
||||
axisExtent = [xLeft, xRight];
|
||||
|
||||
if (timelineModel.get('inverse')) {
|
||||
axisExtent.reverse();
|
||||
}
|
||||
|
||||
return {
|
||||
viewRect: viewRect,
|
||||
mainLength: mainLength,
|
||||
orient: orient,
|
||||
|
||||
rotation: rotationMap[orient],
|
||||
labelRotation: labelRotation,
|
||||
labelPosOpt: labelPosOpt,
|
||||
labelAlign: labelAlignMap[orient],
|
||||
labelBaseline: labelBaselineMap[orient],
|
||||
|
||||
// Based on mainGroup.
|
||||
playPosition: playPosition,
|
||||
prevBtnPosition: prevBtnPosition,
|
||||
nextBtnPosition: nextBtnPosition,
|
||||
axisExtent: axisExtent,
|
||||
|
||||
controlSize: controlSize,
|
||||
controlGap: controlGap
|
||||
};
|
||||
},
|
||||
|
||||
_position: function (layoutInfo, timelineModel) {
|
||||
// Position is be called finally, because bounding rect is needed for
|
||||
// adapt content to fill viewRect (auto adapt offset).
|
||||
|
||||
// Timeline may be not all in the viewRect when 'offset' is specified
|
||||
// as a number, because it is more appropriate that label aligns at
|
||||
// 'offset' but not the other edge defined by viewRect.
|
||||
|
||||
var mainGroup = this._mainGroup;
|
||||
var labelGroup = this._labelGroup;
|
||||
|
||||
var viewRect = layoutInfo.viewRect;
|
||||
if (layoutInfo.orient === 'vertical') {
|
||||
// transfrom to horizontal, inverse rotate by left-top point.
|
||||
var m = matrix.create();
|
||||
var rotateOriginX = viewRect.x;
|
||||
var rotateOriginY = viewRect.y + viewRect.height;
|
||||
matrix.translate(m, m, [-rotateOriginX, -rotateOriginY]);
|
||||
matrix.rotate(m, m, -PI / 2);
|
||||
matrix.translate(m, m, [rotateOriginX, rotateOriginY]);
|
||||
viewRect = viewRect.clone();
|
||||
viewRect.applyTransform(m);
|
||||
}
|
||||
|
||||
var viewBound = getBound(viewRect);
|
||||
var mainBound = getBound(mainGroup.getBoundingRect());
|
||||
var labelBound = getBound(labelGroup.getBoundingRect());
|
||||
|
||||
var mainPosition = mainGroup.position;
|
||||
var labelsPosition = labelGroup.position;
|
||||
|
||||
labelsPosition[0] = mainPosition[0] = viewBound[0][0];
|
||||
|
||||
var labelPosOpt = layoutInfo.labelPosOpt;
|
||||
|
||||
if (isNaN(labelPosOpt)) { // '+' or '-'
|
||||
var mainBoundIdx = labelPosOpt === '+' ? 0 : 1;
|
||||
toBound(mainPosition, mainBound, viewBound, 1, mainBoundIdx);
|
||||
toBound(labelsPosition, labelBound, viewBound, 1, 1 - mainBoundIdx);
|
||||
}
|
||||
else {
|
||||
var mainBoundIdx = labelPosOpt >= 0 ? 0 : 1;
|
||||
toBound(mainPosition, mainBound, viewBound, 1, mainBoundIdx);
|
||||
labelsPosition[1] = mainPosition[1] + labelPosOpt;
|
||||
}
|
||||
|
||||
mainGroup.position = mainPosition;
|
||||
labelGroup.position = labelsPosition;
|
||||
mainGroup.rotation = labelGroup.rotation = layoutInfo.rotation;
|
||||
|
||||
setOrigin(mainGroup);
|
||||
setOrigin(labelGroup);
|
||||
|
||||
function setOrigin(targetGroup) {
|
||||
var pos = targetGroup.position;
|
||||
targetGroup.origin = [
|
||||
viewBound[0][0] - pos[0],
|
||||
viewBound[1][0] - pos[1]
|
||||
];
|
||||
}
|
||||
|
||||
function getBound(rect) {
|
||||
// [[xmin, xmax], [ymin, ymax]]
|
||||
return [
|
||||
[rect.x, rect.x + rect.width],
|
||||
[rect.y, rect.y + rect.height]
|
||||
];
|
||||
}
|
||||
|
||||
function toBound(fromPos, from, to, dimIdx, boundIdx) {
|
||||
fromPos[dimIdx] += to[dimIdx][boundIdx] - from[dimIdx][boundIdx];
|
||||
}
|
||||
},
|
||||
|
||||
_createAxis: function (layoutInfo, timelineModel) {
|
||||
var data = timelineModel.getData();
|
||||
var axisType = timelineModel.get('axisType');
|
||||
|
||||
var scale = axisHelper.createScaleByModel(timelineModel, axisType);
|
||||
var dataExtent = data.getDataExtent('value');
|
||||
scale.setExtent(dataExtent[0], dataExtent[1]);
|
||||
this._customizeScale(scale, data);
|
||||
scale.niceTicks();
|
||||
|
||||
var axis = new TimelineAxis('value', scale, layoutInfo.axisExtent, axisType);
|
||||
axis.model = timelineModel;
|
||||
|
||||
return axis;
|
||||
},
|
||||
|
||||
_customizeScale: function (scale, data) {
|
||||
|
||||
scale.getTicks = function () {
|
||||
return data.mapArray(['value'], function (value) {
|
||||
return value;
|
||||
});
|
||||
};
|
||||
|
||||
scale.getTicksLabels = function () {
|
||||
return zrUtil.map(this.getTicks(), scale.getLabel, scale);
|
||||
};
|
||||
},
|
||||
|
||||
_createGroup: function (name) {
|
||||
var newGroup = this['_' + name] = new graphic.Group();
|
||||
this.group.add(newGroup);
|
||||
return newGroup;
|
||||
},
|
||||
|
||||
_renderAxisLine: function (layoutInfo, group, axis, timelineModel) {
|
||||
var axisExtent = axis.getExtent();
|
||||
|
||||
if (!timelineModel.get('lineStyle.show')) {
|
||||
return;
|
||||
}
|
||||
|
||||
group.add(new graphic.Line({
|
||||
shape: {
|
||||
x1: axisExtent[0], y1: 0,
|
||||
x2: axisExtent[1], y2: 0
|
||||
},
|
||||
style: zrUtil.extend(
|
||||
{lineCap: 'round'},
|
||||
timelineModel.getModel('lineStyle').getLineStyle()
|
||||
),
|
||||
silent: true,
|
||||
z2: 1
|
||||
}));
|
||||
},
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
_renderAxisTick: function (layoutInfo, group, axis, timelineModel) {
|
||||
var data = timelineModel.getData();
|
||||
var ticks = axis.scale.getTicks();
|
||||
|
||||
each(ticks, function (value, dataIndex) {
|
||||
|
||||
var tickCoord = axis.dataToCoord(value);
|
||||
var itemModel = data.getItemModel(dataIndex);
|
||||
var itemStyleModel = itemModel.getModel('itemStyle.normal');
|
||||
var hoverStyleModel = itemModel.getModel('itemStyle.emphasis');
|
||||
var symbolOpt = {
|
||||
position: [tickCoord, 0],
|
||||
onclick: bind(this._changeTimeline, this, dataIndex)
|
||||
};
|
||||
var el = giveSymbol(itemModel, itemStyleModel, group, symbolOpt);
|
||||
graphic.setHoverStyle(el, hoverStyleModel.getItemStyle());
|
||||
|
||||
if (itemModel.get('tooltip')) {
|
||||
el.dataIndex = dataIndex;
|
||||
el.dataModel = timelineModel;
|
||||
}
|
||||
else {
|
||||
el.dataIndex = el.dataModel = null;
|
||||
}
|
||||
|
||||
}, this);
|
||||
},
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
_renderAxisLabel: function (layoutInfo, group, axis, timelineModel) {
|
||||
var labelModel = timelineModel.getModel('label.normal');
|
||||
|
||||
if (!labelModel.get('show')) {
|
||||
return;
|
||||
}
|
||||
|
||||
var data = timelineModel.getData();
|
||||
var ticks = axis.scale.getTicks();
|
||||
var labels = axisHelper.getFormattedLabels(
|
||||
axis, labelModel.get('formatter')
|
||||
);
|
||||
var labelInterval = axis.getLabelInterval();
|
||||
|
||||
each(ticks, function (tick, dataIndex) {
|
||||
if (axis.isLabelIgnored(dataIndex, labelInterval)) {
|
||||
return;
|
||||
}
|
||||
|
||||
var itemModel = data.getItemModel(dataIndex);
|
||||
var itemTextStyleModel = itemModel.getModel('label.normal.textStyle');
|
||||
var hoverTextStyleModel = itemModel.getModel('label.emphasis.textStyle');
|
||||
var tickCoord = axis.dataToCoord(tick);
|
||||
var textEl = new graphic.Text({
|
||||
style: {
|
||||
text: labels[dataIndex],
|
||||
textAlign: layoutInfo.labelAlign,
|
||||
textVerticalAlign: layoutInfo.labelBaseline,
|
||||
textFont: itemTextStyleModel.getFont(),
|
||||
fill: itemTextStyleModel.getTextColor()
|
||||
},
|
||||
position: [tickCoord, 0],
|
||||
rotation: layoutInfo.labelRotation - layoutInfo.rotation,
|
||||
onclick: bind(this._changeTimeline, this, dataIndex),
|
||||
silent: false
|
||||
});
|
||||
|
||||
group.add(textEl);
|
||||
graphic.setHoverStyle(textEl, hoverTextStyleModel.getItemStyle());
|
||||
|
||||
}, this);
|
||||
},
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
_renderControl: function (layoutInfo, group, axis, timelineModel) {
|
||||
var controlSize = layoutInfo.controlSize;
|
||||
var rotation = layoutInfo.rotation;
|
||||
|
||||
var itemStyle = timelineModel.getModel('controlStyle.normal').getItemStyle();
|
||||
var hoverStyle = timelineModel.getModel('controlStyle.emphasis').getItemStyle();
|
||||
var rect = [0, -controlSize / 2, controlSize, controlSize];
|
||||
var playState = timelineModel.getPlayState();
|
||||
var inverse = timelineModel.get('inverse', true);
|
||||
|
||||
makeBtn(
|
||||
layoutInfo.nextBtnPosition,
|
||||
'controlStyle.nextIcon',
|
||||
bind(this._changeTimeline, this, inverse ? '-' : '+')
|
||||
);
|
||||
makeBtn(
|
||||
layoutInfo.prevBtnPosition,
|
||||
'controlStyle.prevIcon',
|
||||
bind(this._changeTimeline, this, inverse ? '+' : '-')
|
||||
);
|
||||
makeBtn(
|
||||
layoutInfo.playPosition,
|
||||
'controlStyle.' + (playState ? 'stopIcon' : 'playIcon'),
|
||||
bind(this._handlePlayClick, this, !playState),
|
||||
true
|
||||
);
|
||||
|
||||
function makeBtn(position, iconPath, onclick, willRotate) {
|
||||
if (!position) {
|
||||
return;
|
||||
}
|
||||
var opt = {
|
||||
position: position,
|
||||
origin: [controlSize / 2, 0],
|
||||
rotation: willRotate ? -rotation : 0,
|
||||
rectHover: true,
|
||||
style: itemStyle,
|
||||
onclick: onclick
|
||||
};
|
||||
var btn = makeIcon(timelineModel, iconPath, rect, opt);
|
||||
group.add(btn);
|
||||
graphic.setHoverStyle(btn, hoverStyle);
|
||||
}
|
||||
},
|
||||
|
||||
_renderCurrentPointer: function (layoutInfo, group, axis, timelineModel) {
|
||||
var data = timelineModel.getData();
|
||||
var currentIndex = timelineModel.getCurrentIndex();
|
||||
var pointerModel = data.getItemModel(currentIndex).getModel('checkpointStyle');
|
||||
var me = this;
|
||||
|
||||
var callback = {
|
||||
onCreate: function (pointer) {
|
||||
pointer.draggable = true;
|
||||
pointer.drift = bind(me._handlePointerDrag, me);
|
||||
pointer.ondragend = bind(me._handlePointerDragend, me);
|
||||
pointerMoveTo(pointer, currentIndex, axis, timelineModel, true);
|
||||
},
|
||||
onUpdate: function (pointer) {
|
||||
pointerMoveTo(pointer, currentIndex, axis, timelineModel);
|
||||
}
|
||||
};
|
||||
|
||||
// Reuse when exists, for animation and drag.
|
||||
this._currentPointer = giveSymbol(
|
||||
pointerModel, pointerModel, this._mainGroup, {}, this._currentPointer, callback
|
||||
);
|
||||
},
|
||||
|
||||
_handlePlayClick: function (nextState) {
|
||||
this._clearTimer();
|
||||
this.api.dispatchAction({
|
||||
type: 'timelinePlayChange',
|
||||
playState: nextState,
|
||||
from: this.uid
|
||||
});
|
||||
},
|
||||
|
||||
_handlePointerDrag: function (dx, dy, e) {
|
||||
this._clearTimer();
|
||||
this._pointerChangeTimeline([e.offsetX, e.offsetY]);
|
||||
},
|
||||
|
||||
_handlePointerDragend: function (e) {
|
||||
this._pointerChangeTimeline([e.offsetX, e.offsetY], true);
|
||||
},
|
||||
|
||||
_pointerChangeTimeline: function (mousePos, trigger) {
|
||||
var toCoord = this._toAxisCoord(mousePos)[0];
|
||||
|
||||
var axis = this._axis;
|
||||
var axisExtent = numberUtil.asc(axis.getExtent().slice());
|
||||
|
||||
toCoord > axisExtent[1] && (toCoord = axisExtent[1]);
|
||||
toCoord < axisExtent[0] && (toCoord = axisExtent[0]);
|
||||
|
||||
this._currentPointer.position[0] = toCoord;
|
||||
this._currentPointer.dirty();
|
||||
|
||||
var targetDataIndex = this._findNearestTick(toCoord);
|
||||
var timelineModel = this.model;
|
||||
|
||||
if (trigger || (
|
||||
targetDataIndex !== timelineModel.getCurrentIndex()
|
||||
&& timelineModel.get('realtime')
|
||||
)) {
|
||||
this._changeTimeline(targetDataIndex);
|
||||
}
|
||||
},
|
||||
|
||||
_doPlayStop: function () {
|
||||
this._clearTimer();
|
||||
|
||||
if (this.model.getPlayState()) {
|
||||
this._timer = setTimeout(
|
||||
bind(handleFrame, this),
|
||||
this.model.get('playInterval')
|
||||
);
|
||||
}
|
||||
|
||||
function handleFrame() {
|
||||
// Do not cache
|
||||
var timelineModel = this.model;
|
||||
this._changeTimeline(
|
||||
timelineModel.getCurrentIndex()
|
||||
+ (timelineModel.get('rewind', true) ? -1 : 1)
|
||||
);
|
||||
}
|
||||
},
|
||||
|
||||
_toAxisCoord: function (vertex) {
|
||||
var trans = this._mainGroup.getLocalTransform();
|
||||
return graphic.applyTransform(vertex, trans, true);
|
||||
},
|
||||
|
||||
_findNearestTick: function (axisCoord) {
|
||||
var data = this.model.getData();
|
||||
var dist = Infinity;
|
||||
var targetDataIndex;
|
||||
var axis = this._axis;
|
||||
|
||||
data.each(['value'], function (value, dataIndex) {
|
||||
var coord = axis.dataToCoord(value);
|
||||
var d = Math.abs(coord - axisCoord);
|
||||
if (d < dist) {
|
||||
dist = d;
|
||||
targetDataIndex = dataIndex;
|
||||
}
|
||||
});
|
||||
|
||||
return targetDataIndex;
|
||||
},
|
||||
|
||||
_clearTimer: function () {
|
||||
if (this._timer) {
|
||||
clearTimeout(this._timer);
|
||||
this._timer = null;
|
||||
}
|
||||
},
|
||||
|
||||
_changeTimeline: function (nextIndex) {
|
||||
var currentIndex = this.model.getCurrentIndex();
|
||||
|
||||
if (nextIndex === '+') {
|
||||
nextIndex = currentIndex + 1;
|
||||
}
|
||||
else if (nextIndex === '-') {
|
||||
nextIndex = currentIndex - 1;
|
||||
}
|
||||
|
||||
this.api.dispatchAction({
|
||||
type: 'timelineChange',
|
||||
currentIndex: nextIndex,
|
||||
from: this.uid
|
||||
});
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
function getViewRect(model, api) {
|
||||
return layout.getLayoutRect(
|
||||
model.getBoxLayoutParams(),
|
||||
{
|
||||
width: api.getWidth(),
|
||||
height: api.getHeight()
|
||||
},
|
||||
model.get('padding')
|
||||
);
|
||||
}
|
||||
|
||||
function makeIcon(timelineModel, objPath, rect, opts) {
|
||||
var icon = graphic.makePath(
|
||||
timelineModel.get(objPath).replace(/^path:\/\//, ''),
|
||||
zrUtil.clone(opts || {}),
|
||||
new BoundingRect(rect[0], rect[1], rect[2], rect[3]),
|
||||
'center'
|
||||
);
|
||||
|
||||
return icon;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create symbol or update symbol
|
||||
*/
|
||||
function giveSymbol(hostModel, itemStyleModel, group, opt, symbol, callback) {
|
||||
var symbolType = hostModel.get('symbol');
|
||||
var color = itemStyleModel.get('color');
|
||||
var symbolSize = hostModel.get('symbolSize');
|
||||
var halfSymbolSize = symbolSize / 2;
|
||||
var itemStyle = itemStyleModel.getItemStyle(['color', 'symbol', 'symbolSize']);
|
||||
|
||||
if (!symbol) {
|
||||
symbol = symbolUtil.createSymbol(
|
||||
symbolType, -halfSymbolSize, -halfSymbolSize, symbolSize, symbolSize, color
|
||||
);
|
||||
group.add(symbol);
|
||||
callback && callback.onCreate(symbol);
|
||||
}
|
||||
else {
|
||||
symbol.setStyle(itemStyle);
|
||||
symbol.setColor(color);
|
||||
group.add(symbol); // Group may be new, also need to add.
|
||||
callback && callback.onUpdate(symbol);
|
||||
}
|
||||
|
||||
opt = zrUtil.merge({
|
||||
rectHover: true,
|
||||
style: itemStyle,
|
||||
z2: 100
|
||||
}, opt, true);
|
||||
|
||||
symbol.attr(opt);
|
||||
|
||||
return symbol;
|
||||
}
|
||||
|
||||
function pointerMoveTo(pointer, dataIndex, axis, timelineModel, noAnimation) {
|
||||
if (pointer.dragging) {
|
||||
return;
|
||||
}
|
||||
|
||||
var pointerModel = timelineModel.getModel('checkpointStyle');
|
||||
var toCoord = axis.dataToCoord(timelineModel.getData().get(['value'], dataIndex));
|
||||
|
||||
if (noAnimation || !pointerModel.get('animation', true)) {
|
||||
pointer.attr({position: [toCoord, 0]});
|
||||
}
|
||||
else {
|
||||
pointer.stopAnimation(true);
|
||||
pointer.animateTo(
|
||||
{position: [toCoord, 0]},
|
||||
pointerModel.get('animationDuration', true),
|
||||
pointerModel.get('animationEasing', true)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
});
|
||||
96
vendors/echarts/src/component/timeline/TimelineAxis.js
vendored
Normal file
96
vendors/echarts/src/component/timeline/TimelineAxis.js
vendored
Normal file
@@ -0,0 +1,96 @@
|
||||
define(function (require) {
|
||||
|
||||
var zrUtil = require('zrender/core/util');
|
||||
var Axis = require('../../coord/Axis');
|
||||
var axisHelper = require('../../coord/axisHelper');
|
||||
|
||||
/**
|
||||
* 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 TimelineAxis = function (dim, scale, coordExtent, axisType) {
|
||||
|
||||
Axis.call(this, dim, scale, coordExtent);
|
||||
|
||||
/**
|
||||
* Axis type
|
||||
* - 'category'
|
||||
* - 'value'
|
||||
* - 'time'
|
||||
* - 'log'
|
||||
* @type {string}
|
||||
*/
|
||||
this.type = axisType || 'value';
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {number}
|
||||
*/
|
||||
this._autoLabelInterval;
|
||||
|
||||
/**
|
||||
* Axis model
|
||||
* @param {module:echarts/component/TimelineModel}
|
||||
*/
|
||||
this.model = null;
|
||||
};
|
||||
|
||||
TimelineAxis.prototype = {
|
||||
|
||||
constructor: TimelineAxis,
|
||||
|
||||
/**
|
||||
* @public
|
||||
* @return {number}
|
||||
*/
|
||||
getLabelInterval: function () {
|
||||
var timelineModel = this.model;
|
||||
var labelModel = timelineModel.getModel('label.normal');
|
||||
var labelInterval = labelModel.get('interval');
|
||||
|
||||
if (labelInterval != null && labelInterval != 'auto') {
|
||||
return labelInterval;
|
||||
}
|
||||
|
||||
var labelInterval = this._autoLabelInterval;
|
||||
|
||||
if (!labelInterval) {
|
||||
labelInterval = this._autoLabelInterval = axisHelper.getAxisLabelInterval(
|
||||
zrUtil.map(this.scale.getTicks(), this.dataToCoord, this),
|
||||
axisHelper.getFormattedLabels(this, labelModel.get('formatter')),
|
||||
labelModel.getModel('textStyle').getFont(),
|
||||
timelineModel.get('orient') === 'horizontal'
|
||||
);
|
||||
}
|
||||
|
||||
return labelInterval;
|
||||
},
|
||||
|
||||
/**
|
||||
* If label is ignored.
|
||||
* Automatically used when axis is category and label can not be all shown
|
||||
* @public
|
||||
* @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);
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
zrUtil.inherits(TimelineAxis, Axis);
|
||||
|
||||
return TimelineAxis;
|
||||
});
|
||||
197
vendors/echarts/src/component/timeline/TimelineModel.js
vendored
Normal file
197
vendors/echarts/src/component/timeline/TimelineModel.js
vendored
Normal file
@@ -0,0 +1,197 @@
|
||||
/**
|
||||
* @file Timeline model
|
||||
*/
|
||||
define(function(require) {
|
||||
|
||||
var ComponentModel = require('../../model/Component');
|
||||
var List = require('../../data/List');
|
||||
var zrUtil = require('zrender/core/util');
|
||||
var modelUtil = require('../../util/model');
|
||||
|
||||
var TimelineModel = ComponentModel.extend({
|
||||
|
||||
type: 'timeline',
|
||||
|
||||
layoutMode: 'box',
|
||||
|
||||
/**
|
||||
* @protected
|
||||
*/
|
||||
defaultOption: {
|
||||
|
||||
zlevel: 0, // 一级层叠
|
||||
z: 4, // 二级层叠
|
||||
show: true,
|
||||
|
||||
axisType: 'time', // 模式是时间类型,支持 value, category
|
||||
|
||||
realtime: true,
|
||||
|
||||
left: '20%',
|
||||
top: null,
|
||||
right: '20%',
|
||||
bottom: 0,
|
||||
width: null,
|
||||
height: 40,
|
||||
padding: 5,
|
||||
|
||||
controlPosition: 'left', // 'left' 'right' 'top' 'bottom' 'none'
|
||||
autoPlay: false,
|
||||
rewind: false, // 反向播放
|
||||
loop: true,
|
||||
playInterval: 2000, // 播放时间间隔,单位ms
|
||||
|
||||
currentIndex: 0,
|
||||
|
||||
itemStyle: {
|
||||
normal: {},
|
||||
emphasis: {}
|
||||
},
|
||||
label: {
|
||||
normal: {
|
||||
textStyle: {
|
||||
color: '#000'
|
||||
}
|
||||
},
|
||||
emphasis: {}
|
||||
},
|
||||
|
||||
data: []
|
||||
},
|
||||
|
||||
/**
|
||||
* @override
|
||||
*/
|
||||
init: function (option, parentModel, ecModel) {
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {module:echarts/data/List}
|
||||
*/
|
||||
this._data;
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {Array.<string>}
|
||||
*/
|
||||
this._names;
|
||||
|
||||
this.mergeDefaultAndTheme(option, ecModel);
|
||||
this._initData();
|
||||
},
|
||||
|
||||
/**
|
||||
* @override
|
||||
*/
|
||||
mergeOption: function (option) {
|
||||
TimelineModel.superApply(this, 'mergeOption', arguments);
|
||||
this._initData();
|
||||
},
|
||||
|
||||
/**
|
||||
* @param {number} [currentIndex]
|
||||
*/
|
||||
setCurrentIndex: function (currentIndex) {
|
||||
if (currentIndex == null) {
|
||||
currentIndex = this.option.currentIndex;
|
||||
}
|
||||
var count = this._data.count();
|
||||
|
||||
if (this.option.loop) {
|
||||
currentIndex = (currentIndex % count + count) % count;
|
||||
}
|
||||
else {
|
||||
currentIndex >= count && (currentIndex = count - 1);
|
||||
currentIndex < 0 && (currentIndex = 0);
|
||||
}
|
||||
|
||||
this.option.currentIndex = currentIndex;
|
||||
},
|
||||
|
||||
/**
|
||||
* @return {number} currentIndex
|
||||
*/
|
||||
getCurrentIndex: function () {
|
||||
return this.option.currentIndex;
|
||||
},
|
||||
|
||||
/**
|
||||
* @return {boolean}
|
||||
*/
|
||||
isIndexMax: function () {
|
||||
return this.getCurrentIndex() >= this._data.count() - 1;
|
||||
},
|
||||
|
||||
/**
|
||||
* @param {boolean} state true: play, false: stop
|
||||
*/
|
||||
setPlayState: function (state) {
|
||||
this.option.autoPlay = !!state;
|
||||
},
|
||||
|
||||
/**
|
||||
* @return {boolean} true: play, false: stop
|
||||
*/
|
||||
getPlayState: function () {
|
||||
return !!this.option.autoPlay;
|
||||
},
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
_initData: function () {
|
||||
var thisOption = this.option;
|
||||
var dataArr = thisOption.data || [];
|
||||
var axisType = thisOption.axisType;
|
||||
var names = this._names = [];
|
||||
|
||||
if (axisType === 'category') {
|
||||
var idxArr = [];
|
||||
zrUtil.each(dataArr, function (item, index) {
|
||||
var value = modelUtil.getDataItemValue(item);
|
||||
var newItem;
|
||||
|
||||
if (zrUtil.isObject(item)) {
|
||||
newItem = zrUtil.clone(item);
|
||||
newItem.value = index;
|
||||
}
|
||||
else {
|
||||
newItem = index;
|
||||
}
|
||||
|
||||
idxArr.push(newItem);
|
||||
|
||||
if (!zrUtil.isString(value) && (value == null || isNaN(value))) {
|
||||
value = '';
|
||||
}
|
||||
|
||||
names.push(value + '');
|
||||
});
|
||||
dataArr = idxArr;
|
||||
}
|
||||
|
||||
var dimType = ({category: 'ordinal', time: 'time'})[axisType] || 'number';
|
||||
|
||||
var data = this._data = new List([{name: 'value', type: dimType}], this);
|
||||
|
||||
data.initData(dataArr, names);
|
||||
},
|
||||
|
||||
getData: function () {
|
||||
return this._data;
|
||||
},
|
||||
|
||||
/**
|
||||
* @public
|
||||
* @return {Array.<string>} categoreis
|
||||
*/
|
||||
getCategories: function () {
|
||||
if (this.get('axisType') === 'category') {
|
||||
return this._names.slice();
|
||||
}
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
return TimelineModel;
|
||||
});
|
||||
15
vendors/echarts/src/component/timeline/TimelineView.js
vendored
Normal file
15
vendors/echarts/src/component/timeline/TimelineView.js
vendored
Normal file
@@ -0,0 +1,15 @@
|
||||
/**
|
||||
* @file Timeline view
|
||||
*/
|
||||
define(function (require) {
|
||||
|
||||
// var zrUtil = require('zrender/core/util');
|
||||
// var graphic = require('../../util/graphic');
|
||||
var ComponentView = require('../../view/Component');
|
||||
|
||||
return ComponentView.extend({
|
||||
|
||||
type: 'timeline'
|
||||
});
|
||||
|
||||
});
|
||||
86
vendors/echarts/src/component/timeline/preprocessor.js
vendored
Normal file
86
vendors/echarts/src/component/timeline/preprocessor.js
vendored
Normal file
@@ -0,0 +1,86 @@
|
||||
/**
|
||||
* @file Timeline preprocessor
|
||||
*/
|
||||
define(function(require) {
|
||||
|
||||
var zrUtil = require('zrender/core/util');
|
||||
|
||||
return function (option) {
|
||||
var timelineOpt = option && option.timeline;
|
||||
|
||||
if (!zrUtil.isArray(timelineOpt)) {
|
||||
timelineOpt = timelineOpt ? [timelineOpt] : [];
|
||||
}
|
||||
|
||||
zrUtil.each(timelineOpt, function (opt) {
|
||||
if (!opt) {
|
||||
return;
|
||||
}
|
||||
|
||||
compatibleEC2(opt);
|
||||
});
|
||||
};
|
||||
|
||||
function compatibleEC2(opt) {
|
||||
var type = opt.type;
|
||||
|
||||
var ec2Types = {'number': 'value', 'time': 'time'};
|
||||
|
||||
// Compatible with ec2
|
||||
if (ec2Types[type]) {
|
||||
opt.axisType = ec2Types[type];
|
||||
delete opt.type;
|
||||
}
|
||||
|
||||
transferItem(opt);
|
||||
|
||||
if (has(opt, 'controlPosition')) {
|
||||
var controlStyle = opt.controlStyle || (opt.controlStyle = {});
|
||||
if (!has(controlStyle, 'position')) {
|
||||
controlStyle.position = opt.controlPosition;
|
||||
}
|
||||
if (controlStyle.position === 'none' && !has(controlStyle, 'show')) {
|
||||
controlStyle.show = false;
|
||||
delete controlStyle.position;
|
||||
}
|
||||
delete opt.controlPosition;
|
||||
}
|
||||
|
||||
zrUtil.each(opt.data || [], function (dataItem) {
|
||||
if (zrUtil.isObject(dataItem) && !zrUtil.isArray(dataItem)) {
|
||||
if (!has(dataItem, 'value') && has(dataItem, 'name')) {
|
||||
// In ec2, using name as value.
|
||||
dataItem.value = dataItem.name;
|
||||
}
|
||||
transferItem(dataItem);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function transferItem(opt) {
|
||||
var itemStyle = opt.itemStyle || (opt.itemStyle = {});
|
||||
|
||||
var itemStyleEmphasis = itemStyle.emphasis || (itemStyle.emphasis = {});
|
||||
|
||||
// Transfer label out
|
||||
var label = opt.label || (opt.label || {});
|
||||
var labelNormal = label.normal || (label.normal = {});
|
||||
var excludeLabelAttr = {normal: 1, emphasis: 1};
|
||||
|
||||
zrUtil.each(label, function (value, name) {
|
||||
if (!excludeLabelAttr[name] && !has(labelNormal, name)) {
|
||||
labelNormal[name] = value;
|
||||
}
|
||||
});
|
||||
|
||||
if (itemStyleEmphasis.label && !has(label, 'emphasis')) {
|
||||
label.emphasis = itemStyleEmphasis.label;
|
||||
delete itemStyleEmphasis.label;
|
||||
}
|
||||
}
|
||||
|
||||
function has(obj, attr) {
|
||||
return obj.hasOwnProperty(attr);
|
||||
}
|
||||
|
||||
});
|
||||
39
vendors/echarts/src/component/timeline/timelineAction.js
vendored
Normal file
39
vendors/echarts/src/component/timeline/timelineAction.js
vendored
Normal file
@@ -0,0 +1,39 @@
|
||||
/**
|
||||
* @file Timeilne action
|
||||
*/
|
||||
define(function(require) {
|
||||
|
||||
var echarts = require('../../echarts');
|
||||
|
||||
echarts.registerAction(
|
||||
|
||||
{type: 'timelineChange', event: 'timelineChanged', update: 'prepareAndUpdate'},
|
||||
|
||||
function (payload, ecModel) {
|
||||
|
||||
var timelineModel = ecModel.getComponent('timeline');
|
||||
if (timelineModel && payload.currentIndex != null) {
|
||||
timelineModel.setCurrentIndex(payload.currentIndex);
|
||||
|
||||
if (!timelineModel.get('loop', true) && timelineModel.isIndexMax()) {
|
||||
timelineModel.setPlayState(false);
|
||||
}
|
||||
}
|
||||
|
||||
ecModel.resetOption('timeline');
|
||||
}
|
||||
);
|
||||
|
||||
echarts.registerAction(
|
||||
|
||||
{type: 'timelinePlayChange', event: 'timelinePlayChanged', update: 'update'},
|
||||
|
||||
function (payload, ecModel) {
|
||||
var timelineModel = ecModel.getComponent('timeline');
|
||||
if (timelineModel && payload.playState != null) {
|
||||
timelineModel.setPlayState(payload.playState);
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
});
|
||||
8
vendors/echarts/src/component/timeline/typeDefaulter.js
vendored
Normal file
8
vendors/echarts/src/component/timeline/typeDefaulter.js
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
define(function (require) {
|
||||
|
||||
require('../../model/Component').registerSubTypeDefaulter('timeline', function () {
|
||||
// Only slider now.
|
||||
return 'slider';
|
||||
});
|
||||
|
||||
});
|
||||
188
vendors/echarts/src/component/title.js
vendored
Normal file
188
vendors/echarts/src/component/title.js
vendored
Normal file
@@ -0,0 +1,188 @@
|
||||
define(function(require) {
|
||||
|
||||
'use strict';
|
||||
|
||||
var echarts = require('../echarts');
|
||||
var graphic = require('../util/graphic');
|
||||
var layout = require('../util/layout');
|
||||
|
||||
// Model
|
||||
echarts.extendComponentModel({
|
||||
|
||||
type: 'title',
|
||||
|
||||
layoutMode: {type: 'box', ignoreSize: true},
|
||||
|
||||
defaultOption: {
|
||||
// 一级层叠
|
||||
zlevel: 0,
|
||||
// 二级层叠
|
||||
z: 6,
|
||||
show: true,
|
||||
|
||||
text: '',
|
||||
// 超链接跳转
|
||||
// link: null,
|
||||
// 仅支持self | blank
|
||||
target: 'blank',
|
||||
subtext: '',
|
||||
|
||||
// 超链接跳转
|
||||
// sublink: null,
|
||||
// 仅支持self | blank
|
||||
subtarget: 'blank',
|
||||
|
||||
// 'center' ¦ 'left' ¦ 'right'
|
||||
// ¦ {number}(x坐标,单位px)
|
||||
left: 0,
|
||||
// 'top' ¦ 'bottom' ¦ 'center'
|
||||
// ¦ {number}(y坐标,单位px)
|
||||
top: 0,
|
||||
|
||||
// 水平对齐
|
||||
// 'auto' | 'left' | 'right'
|
||||
// 默认根据 x 的位置判断是左对齐还是右对齐
|
||||
//textAlign: null
|
||||
|
||||
backgroundColor: 'rgba(0,0,0,0)',
|
||||
|
||||
// 标题边框颜色
|
||||
borderColor: '#ccc',
|
||||
|
||||
// 标题边框线宽,单位px,默认为0(无边框)
|
||||
borderWidth: 0,
|
||||
|
||||
// 标题内边距,单位px,默认各方向内边距为5,
|
||||
// 接受数组分别设定上右下左边距,同css
|
||||
padding: 5,
|
||||
|
||||
// 主副标题纵向间隔,单位px,默认为10,
|
||||
itemGap: 10,
|
||||
textStyle: {
|
||||
fontSize: 18,
|
||||
fontWeight: 'bolder',
|
||||
// 主标题文字颜色
|
||||
color: '#333'
|
||||
},
|
||||
subtextStyle: {
|
||||
// 副标题文字颜色
|
||||
color: '#aaa'
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// View
|
||||
echarts.extendComponentView({
|
||||
|
||||
type: 'title',
|
||||
|
||||
render: function (titleModel, ecModel, api) {
|
||||
this.group.removeAll();
|
||||
|
||||
if (!titleModel.get('show')) {
|
||||
return;
|
||||
}
|
||||
|
||||
var group = this.group;
|
||||
|
||||
var textStyleModel = titleModel.getModel('textStyle');
|
||||
var subtextStyleModel = titleModel.getModel('subtextStyle');
|
||||
|
||||
var textAlign = titleModel.get('textAlign');
|
||||
|
||||
var textEl = new graphic.Text({
|
||||
style: {
|
||||
text: titleModel.get('text'),
|
||||
textFont: textStyleModel.getFont(),
|
||||
fill: textStyleModel.getTextColor(),
|
||||
textBaseline: 'top'
|
||||
},
|
||||
z2: 10
|
||||
});
|
||||
|
||||
var textRect = textEl.getBoundingRect();
|
||||
|
||||
var subText = titleModel.get('subtext');
|
||||
var subTextEl = new graphic.Text({
|
||||
style: {
|
||||
text: subText,
|
||||
textFont: subtextStyleModel.getFont(),
|
||||
fill: subtextStyleModel.getTextColor(),
|
||||
y: textRect.height + titleModel.get('itemGap'),
|
||||
textBaseline: 'top'
|
||||
},
|
||||
z2: 10
|
||||
});
|
||||
|
||||
var link = titleModel.get('link');
|
||||
var sublink = titleModel.get('sublink');
|
||||
|
||||
textEl.silent = !link;
|
||||
subTextEl.silent = !sublink;
|
||||
|
||||
if (link) {
|
||||
textEl.on('click', function () {
|
||||
window.open(link, '_' + titleModel.get('target'));
|
||||
});
|
||||
}
|
||||
if (sublink) {
|
||||
subTextEl.on('click', function () {
|
||||
window.open(sublink, '_' + titleModel.get('subtarget'));
|
||||
});
|
||||
}
|
||||
|
||||
group.add(textEl);
|
||||
subText && group.add(subTextEl);
|
||||
// If no subText, but add subTextEl, there will be an empty line.
|
||||
|
||||
var groupRect = group.getBoundingRect();
|
||||
var layoutOption = titleModel.getBoxLayoutParams();
|
||||
layoutOption.width = groupRect.width;
|
||||
layoutOption.height = groupRect.height;
|
||||
var layoutRect = layout.getLayoutRect(
|
||||
layoutOption, {
|
||||
width: api.getWidth(),
|
||||
height: api.getHeight()
|
||||
}, titleModel.get('padding')
|
||||
);
|
||||
// Adjust text align based on position
|
||||
if (!textAlign) {
|
||||
// Align left if title is on the left. center and right is same
|
||||
textAlign = titleModel.get('left') || titleModel.get('right');
|
||||
if (textAlign === 'middle') {
|
||||
textAlign = 'center';
|
||||
}
|
||||
// Adjust layout by text align
|
||||
if (textAlign === 'right') {
|
||||
layoutRect.x += layoutRect.width;
|
||||
}
|
||||
else if (textAlign === 'center') {
|
||||
layoutRect.x += layoutRect.width / 2;
|
||||
}
|
||||
}
|
||||
group.position = [layoutRect.x, layoutRect.y];
|
||||
textEl.setStyle('textAlign', textAlign);
|
||||
subTextEl.setStyle('textAlign', textAlign);
|
||||
|
||||
// Render background
|
||||
// Get groupRect again because textAlign has been changed
|
||||
groupRect = group.getBoundingRect();
|
||||
var padding = layoutRect.margin;
|
||||
var style = titleModel.getItemStyle(['color', 'opacity']);
|
||||
style.fill = titleModel.get('backgroundColor');
|
||||
var rect = new graphic.Rect({
|
||||
shape: {
|
||||
x: groupRect.x - padding[3],
|
||||
y: groupRect.y - padding[0],
|
||||
width: groupRect.width + padding[1] + padding[3],
|
||||
height: groupRect.height + padding[0] + padding[2]
|
||||
},
|
||||
style: style,
|
||||
silent: true
|
||||
});
|
||||
graphic.subPixelOptimizeRect(rect);
|
||||
|
||||
group.add(rect);
|
||||
}
|
||||
});
|
||||
});
|
||||
11
vendors/echarts/src/component/toolbox.js
vendored
Normal file
11
vendors/echarts/src/component/toolbox.js
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
define(function (require) {
|
||||
|
||||
require('./toolbox/ToolboxModel');
|
||||
require('./toolbox/ToolboxView');
|
||||
|
||||
require('./toolbox/feature/SaveAsImage');
|
||||
require('./toolbox/feature/MagicType');
|
||||
require('./toolbox/feature/DataView');
|
||||
require('./toolbox/feature/DataZoom');
|
||||
require('./toolbox/feature/Restore');
|
||||
});
|
||||
71
vendors/echarts/src/component/toolbox/ToolboxModel.js
vendored
Normal file
71
vendors/echarts/src/component/toolbox/ToolboxModel.js
vendored
Normal file
@@ -0,0 +1,71 @@
|
||||
define(function (require) {
|
||||
|
||||
var featureManager = require('./featureManager');
|
||||
var zrUtil = require('zrender/core/util');
|
||||
|
||||
var ToolboxModel = require('../../echarts').extendComponentModel({
|
||||
|
||||
type: 'toolbox',
|
||||
|
||||
layoutMode: {
|
||||
type: 'box',
|
||||
ignoreSize: true
|
||||
},
|
||||
|
||||
mergeDefaultAndTheme: function (option) {
|
||||
ToolboxModel.superApply(this, 'mergeDefaultAndTheme', arguments);
|
||||
|
||||
zrUtil.each(this.option.feature, function (featureOpt, featureName) {
|
||||
var Feature = featureManager.get(featureName);
|
||||
Feature && zrUtil.merge(featureOpt, Feature.defaultOption);
|
||||
});
|
||||
},
|
||||
|
||||
defaultOption: {
|
||||
|
||||
show: true,
|
||||
|
||||
z: 6,
|
||||
|
||||
zlevel: 0,
|
||||
|
||||
orient: 'horizontal',
|
||||
|
||||
left: 'right',
|
||||
|
||||
top: 'top',
|
||||
|
||||
// right
|
||||
// bottom
|
||||
|
||||
backgroundColor: 'transparent',
|
||||
|
||||
borderColor: '#ccc',
|
||||
|
||||
borderWidth: 0,
|
||||
|
||||
padding: 5,
|
||||
|
||||
itemSize: 15,
|
||||
|
||||
itemGap: 8,
|
||||
|
||||
showTitle: true,
|
||||
|
||||
iconStyle: {
|
||||
normal: {
|
||||
borderColor: '#666',
|
||||
color: 'none'
|
||||
},
|
||||
emphasis: {
|
||||
borderColor: '#3E98C5'
|
||||
}
|
||||
}
|
||||
// textStyle: {},
|
||||
|
||||
// feature
|
||||
}
|
||||
});
|
||||
|
||||
return ToolboxModel;
|
||||
});
|
||||
233
vendors/echarts/src/component/toolbox/ToolboxView.js
vendored
Normal file
233
vendors/echarts/src/component/toolbox/ToolboxView.js
vendored
Normal file
@@ -0,0 +1,233 @@
|
||||
define(function (require) {
|
||||
|
||||
var featureManager = require('./featureManager');
|
||||
var zrUtil = require('zrender/core/util');
|
||||
var graphic = require('../../util/graphic');
|
||||
var Model = require('../../model/Model');
|
||||
var DataDiffer = require('../../data/DataDiffer');
|
||||
var listComponentHelper = require('../helper/listComponent');
|
||||
var textContain = require('zrender/contain/text');
|
||||
|
||||
return require('../../echarts').extendComponentView({
|
||||
|
||||
type: 'toolbox',
|
||||
|
||||
render: function (toolboxModel, ecModel, api) {
|
||||
var group = this.group;
|
||||
group.removeAll();
|
||||
|
||||
if (!toolboxModel.get('show')) {
|
||||
return;
|
||||
}
|
||||
|
||||
var itemSize = +toolboxModel.get('itemSize');
|
||||
var featureOpts = toolboxModel.get('feature') || {};
|
||||
var features = this._features || (this._features = {});
|
||||
|
||||
var featureNames = [];
|
||||
zrUtil.each(featureOpts, function (opt, name) {
|
||||
featureNames.push(name);
|
||||
});
|
||||
|
||||
(new DataDiffer(this._featureNames || [], featureNames))
|
||||
.add(process)
|
||||
.update(process)
|
||||
.remove(zrUtil.curry(process, null))
|
||||
.execute();
|
||||
|
||||
// Keep for diff.
|
||||
this._featureNames = featureNames;
|
||||
|
||||
function process(newIndex, oldIndex) {
|
||||
var featureName = featureNames[newIndex];
|
||||
var oldName = featureNames[oldIndex];
|
||||
var featureOpt = featureOpts[featureName];
|
||||
var featureModel = new Model(featureOpt, toolboxModel, toolboxModel.ecModel);
|
||||
var feature;
|
||||
|
||||
if (featureName && !oldName) { // Create
|
||||
if (isUserFeatureName(featureName)) {
|
||||
feature = {
|
||||
model: featureModel,
|
||||
onclick: featureModel.option.onclick,
|
||||
featureName: featureName
|
||||
};
|
||||
}
|
||||
else {
|
||||
var Feature = featureManager.get(featureName);
|
||||
if (!Feature) {
|
||||
return;
|
||||
}
|
||||
feature = new Feature(featureModel);
|
||||
}
|
||||
features[featureName] = feature;
|
||||
}
|
||||
else {
|
||||
feature = features[oldName];
|
||||
// If feature does not exsit.
|
||||
if (!feature) {
|
||||
return;
|
||||
}
|
||||
feature.model = featureModel;
|
||||
}
|
||||
|
||||
if (!featureName && oldName) {
|
||||
feature.dispose && feature.dispose(ecModel, api);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!featureModel.get('show') || feature.unusable) {
|
||||
feature.remove && feature.remove(ecModel, api);
|
||||
return;
|
||||
}
|
||||
|
||||
createIconPaths(featureModel, feature, featureName);
|
||||
|
||||
featureModel.setIconStatus = function (iconName, status) {
|
||||
var option = this.option;
|
||||
var iconPaths = this.iconPaths;
|
||||
option.iconStatus = option.iconStatus || {};
|
||||
option.iconStatus[iconName] = status;
|
||||
// FIXME
|
||||
iconPaths[iconName] && iconPaths[iconName].trigger(status);
|
||||
};
|
||||
|
||||
if (feature.render) {
|
||||
feature.render(featureModel, ecModel, api);
|
||||
}
|
||||
}
|
||||
|
||||
function createIconPaths(featureModel, feature, featureName) {
|
||||
var iconStyleModel = featureModel.getModel('iconStyle');
|
||||
|
||||
// If one feature has mutiple icon. they are orginaized as
|
||||
// {
|
||||
// icon: {
|
||||
// foo: '',
|
||||
// bar: ''
|
||||
// },
|
||||
// title: {
|
||||
// foo: '',
|
||||
// bar: ''
|
||||
// }
|
||||
// }
|
||||
var icons = feature.getIcons ? feature.getIcons() : featureModel.get('icon');
|
||||
var titles = featureModel.get('title') || {};
|
||||
if (typeof icons === 'string') {
|
||||
var icon = icons;
|
||||
var title = titles;
|
||||
icons = {};
|
||||
titles = {};
|
||||
icons[featureName] = icon;
|
||||
titles[featureName] = title;
|
||||
}
|
||||
var iconPaths = featureModel.iconPaths = {};
|
||||
zrUtil.each(icons, function (icon, iconName) {
|
||||
var normalStyle = iconStyleModel.getModel('normal').getItemStyle();
|
||||
var hoverStyle = iconStyleModel.getModel('emphasis').getItemStyle();
|
||||
|
||||
var style = {
|
||||
x: -itemSize / 2,
|
||||
y: -itemSize / 2,
|
||||
width: itemSize,
|
||||
height: itemSize
|
||||
};
|
||||
var path = icon.indexOf('image://') === 0
|
||||
? (
|
||||
style.image = icon.slice(8),
|
||||
new graphic.Image({style: style})
|
||||
)
|
||||
: graphic.makePath(
|
||||
icon.replace('path://', ''),
|
||||
{
|
||||
style: normalStyle,
|
||||
hoverStyle: hoverStyle,
|
||||
rectHover: true
|
||||
},
|
||||
style,
|
||||
'center'
|
||||
);
|
||||
|
||||
graphic.setHoverStyle(path);
|
||||
|
||||
if (toolboxModel.get('showTitle')) {
|
||||
path.__title = titles[iconName];
|
||||
path.on('mouseover', function () {
|
||||
path.setStyle({
|
||||
text: titles[iconName],
|
||||
textPosition: hoverStyle.textPosition || 'bottom',
|
||||
textFill: hoverStyle.fill || hoverStyle.stroke || '#000',
|
||||
textAlign: hoverStyle.textAlign || 'center'
|
||||
});
|
||||
})
|
||||
.on('mouseout', function () {
|
||||
path.setStyle({
|
||||
textFill: null
|
||||
});
|
||||
});
|
||||
}
|
||||
path.trigger(featureModel.get('iconStatus.' + iconName) || 'normal');
|
||||
|
||||
group.add(path);
|
||||
path.on('click', zrUtil.bind(
|
||||
feature.onclick, feature, ecModel, api, iconName
|
||||
));
|
||||
|
||||
iconPaths[iconName] = path;
|
||||
});
|
||||
}
|
||||
|
||||
listComponentHelper.layout(group, toolboxModel, api);
|
||||
// Render background after group is layout
|
||||
// FIXME
|
||||
listComponentHelper.addBackground(group, toolboxModel);
|
||||
|
||||
// Adjust icon title positions to avoid them out of screen
|
||||
group.eachChild(function (icon) {
|
||||
var titleText = icon.__title;
|
||||
var hoverStyle = icon.hoverStyle;
|
||||
// May be background element
|
||||
if (hoverStyle && titleText) {
|
||||
var rect = textContain.getBoundingRect(
|
||||
titleText, hoverStyle.font
|
||||
);
|
||||
var offsetX = icon.position[0] + group.position[0];
|
||||
var offsetY = icon.position[1] + group.position[1] + itemSize;
|
||||
|
||||
var needPutOnTop = false;
|
||||
if (offsetY + rect.height > api.getHeight()) {
|
||||
hoverStyle.textPosition = 'top';
|
||||
needPutOnTop = true;
|
||||
}
|
||||
var topOffset = needPutOnTop ? (-5 - rect.height) : (itemSize + 8);
|
||||
if (offsetX + rect.width / 2 > api.getWidth()) {
|
||||
hoverStyle.textPosition = ['100%', topOffset];
|
||||
hoverStyle.textAlign = 'right';
|
||||
}
|
||||
else if (offsetX - rect.width / 2 < 0) {
|
||||
hoverStyle.textPosition = [0, topOffset];
|
||||
hoverStyle.textAlign = 'left';
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
remove: function (ecModel, api) {
|
||||
zrUtil.each(this._features, function (feature) {
|
||||
feature.remove && feature.remove(ecModel, api);
|
||||
});
|
||||
this.group.removeAll();
|
||||
},
|
||||
|
||||
dispose: function (ecModel, api) {
|
||||
zrUtil.each(this._features, function (feature) {
|
||||
feature.dispose && feature.dispose(ecModel, api);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
function isUserFeatureName(featureName) {
|
||||
return featureName.indexOf('my') === 0;
|
||||
}
|
||||
|
||||
});
|
||||
478
vendors/echarts/src/component/toolbox/feature/DataView.js
vendored
Normal file
478
vendors/echarts/src/component/toolbox/feature/DataView.js
vendored
Normal file
@@ -0,0 +1,478 @@
|
||||
/**
|
||||
* @module echarts/component/toolbox/feature/DataView
|
||||
*/
|
||||
|
||||
define(function (require) {
|
||||
|
||||
var zrUtil = require('zrender/core/util');
|
||||
var eventTool = require('zrender/core/event');
|
||||
|
||||
|
||||
var BLOCK_SPLITER = new Array(60).join('-');
|
||||
var ITEM_SPLITER = '\t';
|
||||
/**
|
||||
* Group series into two types
|
||||
* 1. on category axis, like line, bar
|
||||
* 2. others, like scatter, pie
|
||||
* @param {module:echarts/model/Global} ecModel
|
||||
* @return {Object}
|
||||
* @inner
|
||||
*/
|
||||
function groupSeries(ecModel) {
|
||||
var seriesGroupByCategoryAxis = {};
|
||||
var otherSeries = [];
|
||||
var meta = [];
|
||||
ecModel.eachRawSeries(function (seriesModel) {
|
||||
var coordSys = seriesModel.coordinateSystem;
|
||||
|
||||
if (coordSys && (coordSys.type === 'cartesian2d' || coordSys.type === 'polar')) {
|
||||
var baseAxis = coordSys.getBaseAxis();
|
||||
if (baseAxis.type === 'category') {
|
||||
var key = baseAxis.dim + '_' + baseAxis.index;
|
||||
if (!seriesGroupByCategoryAxis[key]) {
|
||||
seriesGroupByCategoryAxis[key] = {
|
||||
categoryAxis: baseAxis,
|
||||
valueAxis: coordSys.getOtherAxis(baseAxis),
|
||||
series: []
|
||||
};
|
||||
meta.push({
|
||||
axisDim: baseAxis.dim,
|
||||
axisIndex: baseAxis.index
|
||||
});
|
||||
}
|
||||
seriesGroupByCategoryAxis[key].series.push(seriesModel);
|
||||
}
|
||||
else {
|
||||
otherSeries.push(seriesModel);
|
||||
}
|
||||
}
|
||||
else {
|
||||
otherSeries.push(seriesModel);
|
||||
}
|
||||
});
|
||||
|
||||
return {
|
||||
seriesGroupByCategoryAxis: seriesGroupByCategoryAxis,
|
||||
other: otherSeries,
|
||||
meta: meta
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Assemble content of series on cateogory axis
|
||||
* @param {Array.<module:echarts/model/Series>} series
|
||||
* @return {string}
|
||||
* @inner
|
||||
*/
|
||||
function assembleSeriesWithCategoryAxis(series) {
|
||||
var tables = [];
|
||||
zrUtil.each(series, function (group, key) {
|
||||
var categoryAxis = group.categoryAxis;
|
||||
var valueAxis = group.valueAxis;
|
||||
var valueAxisDim = valueAxis.dim;
|
||||
|
||||
var headers = [' '].concat(zrUtil.map(group.series, function (series) {
|
||||
return series.name;
|
||||
}));
|
||||
var columns = [categoryAxis.model.getCategories()];
|
||||
zrUtil.each(group.series, function (series) {
|
||||
columns.push(series.getRawData().mapArray(valueAxisDim, function (val) {
|
||||
return val;
|
||||
}));
|
||||
});
|
||||
// Assemble table content
|
||||
var lines = [headers.join(ITEM_SPLITER)];
|
||||
for (var i = 0; i < columns[0].length; i++) {
|
||||
var items = [];
|
||||
for (var j = 0; j < columns.length; j++) {
|
||||
items.push(columns[j][i]);
|
||||
}
|
||||
lines.push(items.join(ITEM_SPLITER));
|
||||
}
|
||||
tables.push(lines.join('\n'));
|
||||
});
|
||||
return tables.join('\n\n' + BLOCK_SPLITER + '\n\n');
|
||||
}
|
||||
|
||||
/**
|
||||
* Assemble content of other series
|
||||
* @param {Array.<module:echarts/model/Series>} series
|
||||
* @return {string}
|
||||
* @inner
|
||||
*/
|
||||
function assembleOtherSeries(series) {
|
||||
return zrUtil.map(series, function (series) {
|
||||
var data = series.getRawData();
|
||||
var lines = [series.name];
|
||||
var vals = [];
|
||||
data.each(data.dimensions, function () {
|
||||
var argLen = arguments.length;
|
||||
var dataIndex = arguments[argLen - 1];
|
||||
var name = data.getName(dataIndex);
|
||||
for (var i = 0; i < argLen - 1; i++) {
|
||||
vals[i] = arguments[i];
|
||||
}
|
||||
lines.push((name ? (name + ITEM_SPLITER) : '') + vals.join(ITEM_SPLITER));
|
||||
});
|
||||
return lines.join('\n');
|
||||
}).join('\n\n' + BLOCK_SPLITER + '\n\n');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {module:echarts/model/Global}
|
||||
* @return {string}
|
||||
* @inner
|
||||
*/
|
||||
function getContentFromModel(ecModel) {
|
||||
|
||||
var result = groupSeries(ecModel);
|
||||
|
||||
return {
|
||||
value: zrUtil.filter([
|
||||
assembleSeriesWithCategoryAxis(result.seriesGroupByCategoryAxis),
|
||||
assembleOtherSeries(result.other)
|
||||
], function (str) {
|
||||
return str.replace(/[\n\t\s]/g, '');
|
||||
}).join('\n\n' + BLOCK_SPLITER + '\n\n'),
|
||||
|
||||
meta: result.meta
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
function trim(str) {
|
||||
return str.replace(/^\s\s*/, '').replace(/\s\s*$/, '');
|
||||
}
|
||||
/**
|
||||
* If a block is tsv format
|
||||
*/
|
||||
function isTSVFormat(block) {
|
||||
// Simple method to find out if a block is tsv format
|
||||
var firstLine = block.slice(0, block.indexOf('\n'));
|
||||
if (firstLine.indexOf(ITEM_SPLITER) >= 0) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
var itemSplitRegex = new RegExp('[' + ITEM_SPLITER + ']+', 'g');
|
||||
/**
|
||||
* @param {string} tsv
|
||||
* @return {Array.<Object>}
|
||||
*/
|
||||
function parseTSVContents(tsv) {
|
||||
var tsvLines = tsv.split(/\n+/g);
|
||||
var headers = trim(tsvLines.shift()).split(itemSplitRegex);
|
||||
|
||||
var categories = [];
|
||||
var series = zrUtil.map(headers, function (header) {
|
||||
return {
|
||||
name: header,
|
||||
data: []
|
||||
};
|
||||
});
|
||||
for (var i = 0; i < tsvLines.length; i++) {
|
||||
var items = trim(tsvLines[i]).split(itemSplitRegex);
|
||||
categories.push(items.shift());
|
||||
for (var j = 0; j < items.length; j++) {
|
||||
series[j] && (series[j].data[i] = items[j]);
|
||||
}
|
||||
}
|
||||
return {
|
||||
series: series,
|
||||
categories: categories
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} str
|
||||
* @return {Array.<Object>}
|
||||
* @inner
|
||||
*/
|
||||
function parseListContents(str) {
|
||||
var lines = str.split(/\n+/g);
|
||||
var seriesName = trim(lines.shift());
|
||||
|
||||
var data = [];
|
||||
for (var i = 0; i < lines.length; i++) {
|
||||
var items = trim(lines[i]).split(itemSplitRegex);
|
||||
var name = '';
|
||||
var value;
|
||||
var hasName = false;
|
||||
if (isNaN(items[0])) { // First item is name
|
||||
hasName = true;
|
||||
name = items[0];
|
||||
items = items.slice(1);
|
||||
data[i] = {
|
||||
name: name,
|
||||
value: []
|
||||
};
|
||||
value = data[i].value;
|
||||
}
|
||||
else {
|
||||
value = data[i] = [];
|
||||
}
|
||||
for (var j = 0; j < items.length; j++) {
|
||||
value.push(+items[j]);
|
||||
}
|
||||
if (value.length === 1) {
|
||||
hasName ? (data[i].value = value[0]) : (data[i] = value[0]);
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
name: seriesName,
|
||||
data: data
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} str
|
||||
* @param {Array.<Object>} blockMetaList
|
||||
* @return {Object}
|
||||
* @inner
|
||||
*/
|
||||
function parseContents(str, blockMetaList) {
|
||||
var blocks = str.split(new RegExp('\n*' + BLOCK_SPLITER + '\n*', 'g'));
|
||||
var newOption = {
|
||||
series: []
|
||||
};
|
||||
zrUtil.each(blocks, function (block, idx) {
|
||||
if (isTSVFormat(block)) {
|
||||
var result = parseTSVContents(block);
|
||||
var blockMeta = blockMetaList[idx];
|
||||
var axisKey = blockMeta.axisDim + 'Axis';
|
||||
|
||||
if (blockMeta) {
|
||||
newOption[axisKey] = newOption[axisKey] || [];
|
||||
newOption[axisKey][blockMeta.axisIndex] = {
|
||||
data: result.categories
|
||||
};
|
||||
newOption.series = newOption.series.concat(result.series);
|
||||
}
|
||||
}
|
||||
else {
|
||||
var result = parseListContents(block);
|
||||
newOption.series.push(result);
|
||||
}
|
||||
});
|
||||
return newOption;
|
||||
}
|
||||
|
||||
/**
|
||||
* @alias {module:echarts/component/toolbox/feature/DataView}
|
||||
* @constructor
|
||||
* @param {module:echarts/model/Model} model
|
||||
*/
|
||||
function DataView(model) {
|
||||
|
||||
this._dom = null;
|
||||
|
||||
this.model = model;
|
||||
}
|
||||
|
||||
DataView.defaultOption = {
|
||||
show: true,
|
||||
readOnly: false,
|
||||
optionToContent: null,
|
||||
contentToOption: null,
|
||||
|
||||
icon: 'M17.5,17.3H33 M17.5,17.3H33 M45.4,29.5h-28 M11.5,2v56H51V14.8L38.4,2H11.5z M38.4,2.2v12.7H51 M45.4,41.7h-28',
|
||||
title: '数据视图',
|
||||
lang: ['数据视图', '关闭', '刷新'],
|
||||
backgroundColor: '#fff',
|
||||
textColor: '#000',
|
||||
textareaColor: '#fff',
|
||||
textareaBorderColor: '#333',
|
||||
buttonColor: '#c23531',
|
||||
buttonTextColor: '#fff'
|
||||
};
|
||||
|
||||
DataView.prototype.onclick = function (ecModel, api) {
|
||||
var container = api.getDom();
|
||||
var model = this.model;
|
||||
if (this._dom) {
|
||||
container.removeChild(this._dom);
|
||||
}
|
||||
var root = document.createElement('div');
|
||||
root.style.cssText = 'position:absolute;left:5px;top:5px;bottom:5px;right:5px;';
|
||||
root.style.backgroundColor = model.get('backgroundColor') || '#fff';
|
||||
|
||||
// Create elements
|
||||
var header = document.createElement('h4');
|
||||
var lang = model.get('lang') || [];
|
||||
header.innerHTML = lang[0] || model.get('title');
|
||||
header.style.cssText = 'margin: 10px 20px;';
|
||||
header.style.color = model.get('textColor');
|
||||
|
||||
var viewMain = document.createElement('div');
|
||||
var textarea = document.createElement('textarea');
|
||||
viewMain.style.cssText = 'display:block;width:100%;overflow:hidden;';
|
||||
|
||||
var optionToContent = model.get('optionToContent');
|
||||
var contentToOption = model.get('contentToOption');
|
||||
var result = getContentFromModel(ecModel);
|
||||
if (typeof optionToContent === 'function') {
|
||||
var htmlOrDom = optionToContent(api.getOption());
|
||||
if (typeof htmlOrDom === 'string') {
|
||||
viewMain.innerHTML = htmlOrDom;
|
||||
}
|
||||
else if (zrUtil.isDom(htmlOrDom)) {
|
||||
viewMain.appendChild(htmlOrDom);
|
||||
}
|
||||
}
|
||||
else {
|
||||
// Use default textarea
|
||||
viewMain.appendChild(textarea);
|
||||
textarea.readOnly = model.get('readOnly');
|
||||
textarea.style.cssText = 'width:100%;height:100%;font-family:monospace;font-size:14px;line-height:1.6rem;';
|
||||
textarea.style.color = model.get('textColor');
|
||||
textarea.style.borderColor = model.get('textareaBorderColor');
|
||||
textarea.style.backgroundColor = model.get('textareaColor');
|
||||
textarea.value = result.value;
|
||||
}
|
||||
|
||||
var blockMetaList = result.meta;
|
||||
|
||||
var buttonContainer = document.createElement('div');
|
||||
buttonContainer.style.cssText = 'position:absolute;bottom:0;left:0;right:0;';
|
||||
|
||||
var buttonStyle = 'float:right;margin-right:20px;border:none;'
|
||||
+ 'cursor:pointer;padding:2px 5px;font-size:12px;border-radius:3px';
|
||||
var closeButton = document.createElement('div');
|
||||
var refreshButton = document.createElement('div');
|
||||
|
||||
buttonStyle += ';background-color:' + model.get('buttonColor');
|
||||
buttonStyle += ';color:' + model.get('buttonTextColor');
|
||||
|
||||
var self = this;
|
||||
|
||||
function close() {
|
||||
container.removeChild(root);
|
||||
self._dom = null;
|
||||
}
|
||||
eventTool.addEventListener(closeButton, 'click', close);
|
||||
|
||||
eventTool.addEventListener(refreshButton, 'click', function () {
|
||||
var newOption;
|
||||
try {
|
||||
if (typeof contentToOption === 'function') {
|
||||
newOption = contentToOption(viewMain, api.getOption());
|
||||
}
|
||||
else {
|
||||
newOption = parseContents(textarea.value, blockMetaList);
|
||||
}
|
||||
}
|
||||
catch (e) {
|
||||
close();
|
||||
throw new Error('Data view format error ' + e);
|
||||
}
|
||||
if (newOption) {
|
||||
api.dispatchAction({
|
||||
type: 'changeDataView',
|
||||
newOption: newOption
|
||||
});
|
||||
}
|
||||
|
||||
close();
|
||||
});
|
||||
|
||||
closeButton.innerHTML = lang[1];
|
||||
refreshButton.innerHTML = lang[2];
|
||||
refreshButton.style.cssText = buttonStyle;
|
||||
closeButton.style.cssText = buttonStyle;
|
||||
|
||||
!model.get('readOnly') && buttonContainer.appendChild(refreshButton);
|
||||
buttonContainer.appendChild(closeButton);
|
||||
|
||||
// http://stackoverflow.com/questions/6637341/use-tab-to-indent-in-textarea
|
||||
eventTool.addEventListener(textarea, 'keydown', function (e) {
|
||||
if ((e.keyCode || e.which) === 9) {
|
||||
// get caret position/selection
|
||||
var val = this.value;
|
||||
var start = this.selectionStart;
|
||||
var end = this.selectionEnd;
|
||||
|
||||
// set textarea value to: text before caret + tab + text after caret
|
||||
this.value = val.substring(0, start) + ITEM_SPLITER + val.substring(end);
|
||||
|
||||
// put caret at right position again
|
||||
this.selectionStart = this.selectionEnd = start + 1;
|
||||
|
||||
// prevent the focus lose
|
||||
eventTool.stop(e);
|
||||
}
|
||||
});
|
||||
|
||||
root.appendChild(header);
|
||||
root.appendChild(viewMain);
|
||||
root.appendChild(buttonContainer);
|
||||
|
||||
viewMain.style.height = (container.clientHeight - 80) + 'px';
|
||||
|
||||
container.appendChild(root);
|
||||
this._dom = root;
|
||||
};
|
||||
|
||||
DataView.prototype.remove = function (ecModel, api) {
|
||||
this._dom && api.getDom().removeChild(this._dom);
|
||||
};
|
||||
|
||||
DataView.prototype.dispose = function (ecModel, api) {
|
||||
this.remove(ecModel, api);
|
||||
};
|
||||
|
||||
/**
|
||||
* @inner
|
||||
*/
|
||||
function tryMergeDataOption(newData, originalData) {
|
||||
return zrUtil.map(newData, function (newVal, idx) {
|
||||
var original = originalData && originalData[idx];
|
||||
if (zrUtil.isObject(original) && !zrUtil.isArray(original)) {
|
||||
if (zrUtil.isObject(newVal) && !zrUtil.isArray(newVal)) {
|
||||
newVal = newVal.value;
|
||||
}
|
||||
// Original data has option
|
||||
return zrUtil.defaults({
|
||||
value: newVal
|
||||
}, original);
|
||||
}
|
||||
else {
|
||||
return newVal;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
require('../featureManager').register('dataView', DataView);
|
||||
|
||||
require('../../../echarts').registerAction({
|
||||
type: 'changeDataView',
|
||||
event: 'dataViewChanged',
|
||||
update: 'prepareAndUpdate'
|
||||
}, function (payload, ecModel) {
|
||||
var newSeriesOptList = [];
|
||||
zrUtil.each(payload.newOption.series, function (seriesOpt) {
|
||||
var seriesModel = ecModel.getSeriesByName(seriesOpt.name)[0];
|
||||
if (!seriesModel) {
|
||||
// New created series
|
||||
// Geuss the series type
|
||||
newSeriesOptList.push(zrUtil.extend({
|
||||
// Default is scatter
|
||||
type: 'scatter'
|
||||
}, seriesOpt));
|
||||
}
|
||||
else {
|
||||
var originalData = seriesModel.get('data');
|
||||
newSeriesOptList.push({
|
||||
name: seriesOpt.name,
|
||||
data: tryMergeDataOption(seriesOpt.data, originalData)
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
ecModel.mergeOption(zrUtil.defaults({
|
||||
series: newSeriesOptList
|
||||
}, payload.newOption));
|
||||
});
|
||||
|
||||
return DataView;
|
||||
});
|
||||
343
vendors/echarts/src/component/toolbox/feature/DataZoom.js
vendored
Normal file
343
vendors/echarts/src/component/toolbox/feature/DataZoom.js
vendored
Normal file
@@ -0,0 +1,343 @@
|
||||
define(function(require) {
|
||||
'use strict';
|
||||
|
||||
var zrUtil = require('zrender/core/util');
|
||||
var numberUtil = require('../../../util/number');
|
||||
var SelectController = require('../../helper/SelectController');
|
||||
var BoundingRect = require('zrender/core/BoundingRect');
|
||||
var Group = require('zrender/container/Group');
|
||||
var history = require('../../dataZoom/history');
|
||||
var interactionMutex = require('../../helper/interactionMutex');
|
||||
|
||||
var each = zrUtil.each;
|
||||
var asc = numberUtil.asc;
|
||||
|
||||
// Use dataZoomSelect
|
||||
require('../../dataZoomSelect');
|
||||
|
||||
// Spectial component id start with \0ec\0, see echarts/model/Global.js~hasInnerId
|
||||
var DATA_ZOOM_ID_BASE = '\0_ec_\0toolbox-dataZoom_';
|
||||
|
||||
function DataZoom(model) {
|
||||
this.model = model;
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {module:zrender/container/Group}
|
||||
*/
|
||||
this._controllerGroup;
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {module:echarts/component/helper/SelectController}
|
||||
*/
|
||||
this._controller;
|
||||
|
||||
/**
|
||||
* Is zoom active.
|
||||
* @private
|
||||
* @type {Object}
|
||||
*/
|
||||
this._isZoomActive;
|
||||
}
|
||||
|
||||
DataZoom.defaultOption = {
|
||||
show: true,
|
||||
// Icon group
|
||||
icon: {
|
||||
zoom: 'M0,13.5h26.9 M13.5,26.9V0 M32.1,13.5H58V58H13.5 V32.1',
|
||||
back: 'M22,1.4L9.9,13.5l12.3,12.3 M10.3,13.5H54.9v44.6 H10.3v-26'
|
||||
},
|
||||
title: {
|
||||
zoom: '区域缩放',
|
||||
back: '区域缩放还原'
|
||||
}
|
||||
};
|
||||
|
||||
var proto = DataZoom.prototype;
|
||||
|
||||
proto.render = function (featureModel, ecModel, api) {
|
||||
updateBackBtnStatus(featureModel, ecModel);
|
||||
};
|
||||
|
||||
proto.onclick = function (ecModel, api, type) {
|
||||
var controllerGroup = this._controllerGroup;
|
||||
if (!this._controllerGroup) {
|
||||
controllerGroup = this._controllerGroup = new Group();
|
||||
api.getZr().add(controllerGroup);
|
||||
}
|
||||
|
||||
handlers[type].call(this, controllerGroup, this.model, ecModel, api);
|
||||
};
|
||||
|
||||
proto.remove = function (ecModel, api) {
|
||||
this._disposeController();
|
||||
interactionMutex.release('globalPan', api.getZr());
|
||||
};
|
||||
|
||||
proto.dispose = function (ecModel, api) {
|
||||
var zr = api.getZr();
|
||||
interactionMutex.release('globalPan', zr);
|
||||
this._disposeController();
|
||||
this._controllerGroup && zr.remove(this._controllerGroup);
|
||||
};
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
var handlers = {
|
||||
|
||||
zoom: function (controllerGroup, featureModel, ecModel, api) {
|
||||
var isZoomActive = this._isZoomActive = !this._isZoomActive;
|
||||
var zr = api.getZr();
|
||||
|
||||
interactionMutex[isZoomActive ? 'take' : 'release']('globalPan', zr);
|
||||
|
||||
featureModel.setIconStatus('zoom', isZoomActive ? 'emphasis' : 'normal');
|
||||
|
||||
if (isZoomActive) {
|
||||
zr.setDefaultCursorStyle('crosshair');
|
||||
|
||||
this._createController(
|
||||
controllerGroup, featureModel, ecModel, api
|
||||
);
|
||||
}
|
||||
else {
|
||||
zr.setDefaultCursorStyle('default');
|
||||
this._disposeController();
|
||||
}
|
||||
},
|
||||
|
||||
back: function (controllerGroup, featureModel, ecModel, api) {
|
||||
this._dispatchAction(history.pop(ecModel), api);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
proto._createController = function (
|
||||
controllerGroup, featureModel, ecModel, api
|
||||
) {
|
||||
var controller = this._controller = new SelectController(
|
||||
'rect',
|
||||
api.getZr(),
|
||||
{
|
||||
// FIXME
|
||||
lineWidth: 3,
|
||||
stroke: '#333',
|
||||
fill: 'rgba(0,0,0,0.2)'
|
||||
}
|
||||
);
|
||||
controller.on(
|
||||
'selectEnd',
|
||||
zrUtil.bind(
|
||||
this._onSelected, this, controller,
|
||||
featureModel, ecModel, api
|
||||
)
|
||||
);
|
||||
controller.enable(controllerGroup, false);
|
||||
};
|
||||
|
||||
proto._disposeController = function () {
|
||||
var controller = this._controller;
|
||||
if (controller) {
|
||||
controller.off('selected');
|
||||
controller.dispose();
|
||||
}
|
||||
};
|
||||
|
||||
function prepareCoordInfo(grid, ecModel) {
|
||||
// Default use the first axis.
|
||||
// FIXME
|
||||
var coordInfo = [
|
||||
{axisModel: grid.getAxis('x').model, axisIndex: 0}, // x
|
||||
{axisModel: grid.getAxis('y').model, axisIndex: 0} // y
|
||||
];
|
||||
coordInfo.grid = grid;
|
||||
|
||||
ecModel.eachComponent(
|
||||
{mainType: 'dataZoom', subType: 'select'},
|
||||
function (dzModel, dataZoomIndex) {
|
||||
if (isTheAxis('xAxis', coordInfo[0].axisModel, dzModel, ecModel)) {
|
||||
coordInfo[0].dataZoomModel = dzModel;
|
||||
}
|
||||
if (isTheAxis('yAxis', coordInfo[1].axisModel, dzModel, ecModel)) {
|
||||
coordInfo[1].dataZoomModel = dzModel;
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
return coordInfo;
|
||||
}
|
||||
|
||||
function isTheAxis(axisName, axisModel, dataZoomModel, ecModel) {
|
||||
var axisIndex = dataZoomModel.get(axisName + 'Index');
|
||||
return axisIndex != null
|
||||
&& ecModel.getComponent(axisName, axisIndex) === axisModel;
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
proto._onSelected = function (controller, featureModel, ecModel, api, selRanges) {
|
||||
if (!selRanges.length) {
|
||||
return;
|
||||
}
|
||||
var selRange = selRanges[0];
|
||||
|
||||
controller.update(); // remove cover
|
||||
|
||||
var snapshot = {};
|
||||
|
||||
// FIXME
|
||||
// polar
|
||||
|
||||
ecModel.eachComponent('grid', function (gridModel, gridIndex) {
|
||||
var grid = gridModel.coordinateSystem;
|
||||
var coordInfo = prepareCoordInfo(grid, ecModel);
|
||||
var selDataRange = pointToDataInCartesian(selRange, coordInfo);
|
||||
|
||||
if (selDataRange) {
|
||||
var xBatchItem = scaleCartesianAxis(selDataRange, coordInfo, 0, 'x');
|
||||
var yBatchItem = scaleCartesianAxis(selDataRange, coordInfo, 1, 'y');
|
||||
|
||||
xBatchItem && (snapshot[xBatchItem.dataZoomId] = xBatchItem);
|
||||
yBatchItem && (snapshot[yBatchItem.dataZoomId] = yBatchItem);
|
||||
}
|
||||
}, this);
|
||||
|
||||
history.push(ecModel, snapshot);
|
||||
|
||||
this._dispatchAction(snapshot, api);
|
||||
};
|
||||
|
||||
function pointToDataInCartesian(selRange, coordInfo) {
|
||||
var grid = coordInfo.grid;
|
||||
|
||||
var selRect = new BoundingRect(
|
||||
selRange[0][0],
|
||||
selRange[1][0],
|
||||
selRange[0][1] - selRange[0][0],
|
||||
selRange[1][1] - selRange[1][0]
|
||||
);
|
||||
if (!selRect.intersect(grid.getRect())) {
|
||||
return;
|
||||
}
|
||||
var cartesian = grid.getCartesian(coordInfo[0].axisIndex, coordInfo[1].axisIndex);
|
||||
var dataLeftTop = cartesian.pointToData([selRange[0][0], selRange[1][0]], true);
|
||||
var dataRightBottom = cartesian.pointToData([selRange[0][1], selRange[1][1]], true);
|
||||
|
||||
return [
|
||||
asc([dataLeftTop[0], dataRightBottom[0]]), // x, using asc to handle inverse
|
||||
asc([dataLeftTop[1], dataRightBottom[1]]) // y, using asc to handle inverse
|
||||
];
|
||||
}
|
||||
|
||||
function scaleCartesianAxis(selDataRange, coordInfo, dimIdx, dimName) {
|
||||
var dimCoordInfo = coordInfo[dimIdx];
|
||||
var dataZoomModel = dimCoordInfo.dataZoomModel;
|
||||
|
||||
if (dataZoomModel) {
|
||||
return {
|
||||
dataZoomId: dataZoomModel.id,
|
||||
startValue: selDataRange[dimIdx][0],
|
||||
endValue: selDataRange[dimIdx][1]
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
proto._dispatchAction = function (snapshot, api) {
|
||||
var batch = [];
|
||||
|
||||
each(snapshot, function (batchItem) {
|
||||
batch.push(batchItem);
|
||||
});
|
||||
|
||||
batch.length && api.dispatchAction({
|
||||
type: 'dataZoom',
|
||||
from: this.uid,
|
||||
batch: zrUtil.clone(batch, true)
|
||||
});
|
||||
};
|
||||
|
||||
function updateBackBtnStatus(featureModel, ecModel) {
|
||||
featureModel.setIconStatus(
|
||||
'back',
|
||||
history.count(ecModel) > 1 ? 'emphasis' : 'normal'
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
require('../featureManager').register('dataZoom', DataZoom);
|
||||
|
||||
|
||||
// Create special dataZoom option for select
|
||||
require('../../../echarts').registerPreprocessor(function (option) {
|
||||
if (!option) {
|
||||
return;
|
||||
}
|
||||
|
||||
var dataZoomOpts = option.dataZoom || (option.dataZoom = []);
|
||||
if (!zrUtil.isArray(dataZoomOpts)) {
|
||||
option.dataZoom = dataZoomOpts = [dataZoomOpts];
|
||||
}
|
||||
|
||||
var toolboxOpt = option.toolbox;
|
||||
if (toolboxOpt) {
|
||||
// Assume there is only one toolbox
|
||||
if (zrUtil.isArray(toolboxOpt)) {
|
||||
toolboxOpt = toolboxOpt[0];
|
||||
}
|
||||
|
||||
if (toolboxOpt && toolboxOpt.feature) {
|
||||
var dataZoomOpt = toolboxOpt.feature.dataZoom;
|
||||
addForAxis('xAxis', dataZoomOpt);
|
||||
addForAxis('yAxis', dataZoomOpt);
|
||||
}
|
||||
}
|
||||
|
||||
function addForAxis(axisName, dataZoomOpt) {
|
||||
if (!dataZoomOpt) {
|
||||
return;
|
||||
}
|
||||
|
||||
var axisIndicesName = axisName + 'Index';
|
||||
var givenAxisIndices = dataZoomOpt[axisIndicesName];
|
||||
if (givenAxisIndices != null && !zrUtil.isArray(givenAxisIndices)) {
|
||||
givenAxisIndices = givenAxisIndices === false ? [] : [givenAxisIndices];
|
||||
}
|
||||
|
||||
forEachComponent(axisName, function (axisOpt, axisIndex) {
|
||||
if (givenAxisIndices != null
|
||||
&& zrUtil.indexOf(givenAxisIndices, axisIndex) === -1
|
||||
) {
|
||||
return;
|
||||
}
|
||||
var newOpt = {
|
||||
type: 'select',
|
||||
$fromToolbox: true,
|
||||
// Id for merge mapping.
|
||||
id: DATA_ZOOM_ID_BASE + axisName + axisIndex
|
||||
};
|
||||
// FIXME
|
||||
// Only support one axis now.
|
||||
newOpt[axisIndicesName] = axisIndex;
|
||||
dataZoomOpts.push(newOpt);
|
||||
});
|
||||
}
|
||||
|
||||
function forEachComponent(mainType, cb) {
|
||||
var opts = option[mainType];
|
||||
if (!zrUtil.isArray(opts)) {
|
||||
opts = opts ? [opts] : [];
|
||||
}
|
||||
each(opts, cb);
|
||||
}
|
||||
});
|
||||
|
||||
return DataZoom;
|
||||
});
|
||||
169
vendors/echarts/src/component/toolbox/feature/MagicType.js
vendored
Normal file
169
vendors/echarts/src/component/toolbox/feature/MagicType.js
vendored
Normal file
@@ -0,0 +1,169 @@
|
||||
define(function(require) {
|
||||
'use strict';
|
||||
|
||||
var zrUtil = require('zrender/core/util');
|
||||
|
||||
function MagicType(model) {
|
||||
this.model = model;
|
||||
}
|
||||
|
||||
MagicType.defaultOption = {
|
||||
show: true,
|
||||
type: [],
|
||||
// Icon group
|
||||
icon: {
|
||||
line: 'M4.1,28.9h7.1l9.3-22l7.4,38l9.7-19.7l3,12.8h14.9M4.1,58h51.4',
|
||||
bar: 'M6.7,22.9h10V48h-10V22.9zM24.9,13h10v35h-10V13zM43.2,2h10v46h-10V2zM3.1,58h53.7',
|
||||
stack: 'M8.2,38.4l-8.4,4.1l30.6,15.3L60,42.5l-8.1-4.1l-21.5,11L8.2,38.4z M51.9,30l-8.1,4.2l-13.4,6.9l-13.9-6.9L8.2,30l-8.4,4.2l8.4,4.2l22.2,11l21.5-11l8.1-4.2L51.9,30z M51.9,21.7l-8.1,4.2L35.7,30l-5.3,2.8L24.9,30l-8.4-4.1l-8.3-4.2l-8.4,4.2L8.2,30l8.3,4.2l13.9,6.9l13.4-6.9l8.1-4.2l8.1-4.1L51.9,21.7zM30.4,2.2L-0.2,17.5l8.4,4.1l8.3,4.2l8.4,4.2l5.5,2.7l5.3-2.7l8.1-4.2l8.1-4.2l8.1-4.1L30.4,2.2z', // jshint ignore:line
|
||||
tiled: 'M2.3,2.2h22.8V25H2.3V2.2z M35,2.2h22.8V25H35V2.2zM2.3,35h22.8v22.8H2.3V35z M35,35h22.8v22.8H35V35z'
|
||||
},
|
||||
title: {
|
||||
line: '切换为折线图',
|
||||
bar: '切换为柱状图',
|
||||
stack: '切换为堆叠',
|
||||
tiled: '切换为平铺'
|
||||
},
|
||||
option: {},
|
||||
seriesIndex: {}
|
||||
};
|
||||
|
||||
var proto = MagicType.prototype;
|
||||
|
||||
proto.getIcons = function () {
|
||||
var model = this.model;
|
||||
var availableIcons = model.get('icon');
|
||||
var icons = {};
|
||||
zrUtil.each(model.get('type'), function (type) {
|
||||
if (availableIcons[type]) {
|
||||
icons[type] = availableIcons[type];
|
||||
}
|
||||
});
|
||||
return icons;
|
||||
};
|
||||
|
||||
var seriesOptGenreator = {
|
||||
'line': function (seriesType, seriesId, seriesModel, model) {
|
||||
if (seriesType === 'bar') {
|
||||
return zrUtil.merge({
|
||||
id: seriesId,
|
||||
type: 'line',
|
||||
// Preserve data related option
|
||||
data: seriesModel.get('data'),
|
||||
stack: seriesModel.get('stack'),
|
||||
markPoint: seriesModel.get('markPoint'),
|
||||
markLine: seriesModel.get('markLine')
|
||||
}, model.get('option.line') || {}, true);
|
||||
}
|
||||
},
|
||||
'bar': function (seriesType, seriesId, seriesModel, model) {
|
||||
if (seriesType === 'line') {
|
||||
return zrUtil.merge({
|
||||
id: seriesId,
|
||||
type: 'bar',
|
||||
// Preserve data related option
|
||||
data: seriesModel.get('data'),
|
||||
stack: seriesModel.get('stack'),
|
||||
markPoint: seriesModel.get('markPoint'),
|
||||
markLine: seriesModel.get('markLine')
|
||||
}, model.get('option.bar') || {}, true);
|
||||
}
|
||||
},
|
||||
'stack': function (seriesType, seriesId, seriesModel, model) {
|
||||
if (seriesType === 'line' || seriesType === 'bar') {
|
||||
return zrUtil.merge({
|
||||
id: seriesId,
|
||||
stack: '__ec_magicType_stack__'
|
||||
}, model.get('option.stack') || {}, true);
|
||||
}
|
||||
},
|
||||
'tiled': function (seriesType, seriesId, seriesModel, model) {
|
||||
if (seriesType === 'line' || seriesType === 'bar') {
|
||||
return zrUtil.merge({
|
||||
id: seriesId,
|
||||
stack: ''
|
||||
}, model.get('option.tiled') || {}, true);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
var radioTypes = [
|
||||
['line', 'bar'],
|
||||
['stack', 'tiled']
|
||||
];
|
||||
|
||||
proto.onclick = function (ecModel, api, type) {
|
||||
var model = this.model;
|
||||
var seriesIndex = model.get('seriesIndex.' + type);
|
||||
// Not supported magicType
|
||||
if (!seriesOptGenreator[type]) {
|
||||
return;
|
||||
}
|
||||
var newOption = {
|
||||
series: []
|
||||
};
|
||||
var generateNewSeriesTypes = function (seriesModel) {
|
||||
var seriesType = seriesModel.subType;
|
||||
var seriesId = seriesModel.id;
|
||||
var newSeriesOpt = seriesOptGenreator[type](
|
||||
seriesType, seriesId, seriesModel, model
|
||||
);
|
||||
if (newSeriesOpt) {
|
||||
// PENDING If merge original option?
|
||||
zrUtil.defaults(newSeriesOpt, seriesModel.option);
|
||||
newOption.series.push(newSeriesOpt);
|
||||
}
|
||||
// Modify boundaryGap
|
||||
var coordSys = seriesModel.coordinateSystem;
|
||||
if (coordSys && coordSys.type === 'cartesian2d' && (type === 'line' || type === 'bar')) {
|
||||
var categoryAxis = coordSys.getAxesByScale('ordinal')[0];
|
||||
if (categoryAxis) {
|
||||
var axisDim = categoryAxis.dim;
|
||||
var axisIndex = seriesModel.get(axisDim + 'AxisIndex');
|
||||
var axisKey = axisDim + 'Axis';
|
||||
newOption[axisKey] = newOption[axisKey] || [];
|
||||
for (var i = 0; i <= axisIndex; i++) {
|
||||
newOption[axisKey][axisIndex] = newOption[axisKey][axisIndex] || {};
|
||||
}
|
||||
newOption[axisKey][axisIndex].boundaryGap = type === 'bar' ? true : false;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
zrUtil.each(radioTypes, function (radio) {
|
||||
if (zrUtil.indexOf(radio, type) >= 0) {
|
||||
zrUtil.each(radio, function (item) {
|
||||
model.setIconStatus(item, 'normal');
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
model.setIconStatus(type, 'emphasis');
|
||||
|
||||
ecModel.eachComponent(
|
||||
{
|
||||
mainType: 'series',
|
||||
query: seriesIndex == null ? null : {
|
||||
seriesIndex: seriesIndex
|
||||
}
|
||||
}, generateNewSeriesTypes
|
||||
);
|
||||
api.dispatchAction({
|
||||
type: 'changeMagicType',
|
||||
currentType: type,
|
||||
newOption: newOption
|
||||
});
|
||||
};
|
||||
|
||||
var echarts = require('../../../echarts');
|
||||
echarts.registerAction({
|
||||
type: 'changeMagicType',
|
||||
event: 'magicTypeChanged',
|
||||
update: 'prepareAndUpdate'
|
||||
}, function (payload, ecModel) {
|
||||
ecModel.mergeOption(payload.newOption);
|
||||
});
|
||||
|
||||
require('../featureManager').register('magicType', MagicType);
|
||||
|
||||
return MagicType;
|
||||
});
|
||||
39
vendors/echarts/src/component/toolbox/feature/Restore.js
vendored
Normal file
39
vendors/echarts/src/component/toolbox/feature/Restore.js
vendored
Normal file
@@ -0,0 +1,39 @@
|
||||
define(function(require) {
|
||||
'use strict';
|
||||
|
||||
var history = require('../../dataZoom/history');
|
||||
|
||||
function Restore(model) {
|
||||
this.model = model;
|
||||
}
|
||||
|
||||
Restore.defaultOption = {
|
||||
show: true,
|
||||
icon: 'M3.8,33.4 M47,18.9h9.8V8.7 M56.3,20.1 C52.1,9,40.5,0.6,26.8,2.1C12.6,3.7,1.6,16.2,2.1,30.6 M13,41.1H3.1v10.2 M3.7,39.9c4.2,11.1,15.8,19.5,29.5,18 c14.2-1.6,25.2-14.1,24.7-28.5',
|
||||
title: '还原'
|
||||
};
|
||||
|
||||
var proto = Restore.prototype;
|
||||
|
||||
proto.onclick = function (ecModel, api, type) {
|
||||
history.clear(ecModel);
|
||||
|
||||
api.dispatchAction({
|
||||
type: 'restore',
|
||||
from: this.uid
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
require('../featureManager').register('restore', Restore);
|
||||
|
||||
|
||||
require('../../../echarts').registerAction(
|
||||
{type: 'restore', event: 'restore', update: 'prepareAndUpdate'},
|
||||
function (payload, ecModel) {
|
||||
ecModel.resetOption('recreate');
|
||||
}
|
||||
);
|
||||
|
||||
return Restore;
|
||||
});
|
||||
67
vendors/echarts/src/component/toolbox/feature/SaveAsImage.js
vendored
Normal file
67
vendors/echarts/src/component/toolbox/feature/SaveAsImage.js
vendored
Normal file
@@ -0,0 +1,67 @@
|
||||
define(function (require) {
|
||||
|
||||
var env = require('zrender/core/env');
|
||||
|
||||
function SaveAsImage (model) {
|
||||
this.model = model;
|
||||
}
|
||||
|
||||
SaveAsImage.defaultOption = {
|
||||
show: true,
|
||||
icon: 'M4.7,22.9L29.3,45.5L54.7,23.4M4.6,43.6L4.6,58L53.8,58L53.8,43.6M29.2,45.1L29.2,0',
|
||||
title: '保存为图片',
|
||||
type: 'png',
|
||||
// Default use option.backgroundColor
|
||||
// backgroundColor: '#fff',
|
||||
name: '',
|
||||
excludeComponents: ['toolbox'],
|
||||
pixelRatio: 1,
|
||||
lang: ['右键另存为图片']
|
||||
};
|
||||
|
||||
SaveAsImage.prototype.unusable = !env.canvasSupported;
|
||||
|
||||
var proto = SaveAsImage.prototype;
|
||||
|
||||
proto.onclick = function (ecModel, api) {
|
||||
var model = this.model;
|
||||
var title = model.get('name') || ecModel.get('title.0.text') || 'echarts';
|
||||
var $a = document.createElement('a');
|
||||
var type = model.get('type', true) || 'png';
|
||||
$a.download = title + '.' + type;
|
||||
$a.target = '_blank';
|
||||
var url = api.getConnectedDataURL({
|
||||
type: type,
|
||||
backgroundColor: model.get('backgroundColor', true)
|
||||
|| ecModel.get('backgroundColor') || '#fff',
|
||||
excludeComponents: model.get('excludeComponents'),
|
||||
pixelRatio: model.get('pixelRatio')
|
||||
});
|
||||
$a.href = url;
|
||||
// Chrome and Firefox
|
||||
if (typeof MouseEvent === 'function') {
|
||||
var evt = new MouseEvent('click', {
|
||||
view: window,
|
||||
bubbles: true,
|
||||
cancelable: false
|
||||
});
|
||||
$a.dispatchEvent(evt);
|
||||
}
|
||||
// IE
|
||||
else {
|
||||
var lang = model.get('lang');
|
||||
var html = ''
|
||||
+ '<body style="margin:0;">'
|
||||
+ '<img src="' + url + '" style="max-width:100%;" title="' + ((lang && lang[0]) || '') + '" />'
|
||||
+ '</body>';
|
||||
var tab = window.open();
|
||||
tab.document.write(html);
|
||||
}
|
||||
};
|
||||
|
||||
require('../featureManager').register(
|
||||
'saveAsImage', SaveAsImage
|
||||
);
|
||||
|
||||
return SaveAsImage;
|
||||
});
|
||||
15
vendors/echarts/src/component/toolbox/featureManager.js
vendored
Normal file
15
vendors/echarts/src/component/toolbox/featureManager.js
vendored
Normal file
@@ -0,0 +1,15 @@
|
||||
define(function(require) {
|
||||
'use strict';
|
||||
|
||||
var features = {};
|
||||
|
||||
return {
|
||||
register: function (name, ctor) {
|
||||
features[name] = ctor;
|
||||
},
|
||||
|
||||
get: function (name) {
|
||||
return features[name];
|
||||
}
|
||||
};
|
||||
});
|
||||
36
vendors/echarts/src/component/tooltip.js
vendored
Normal file
36
vendors/echarts/src/component/tooltip.js
vendored
Normal file
@@ -0,0 +1,36 @@
|
||||
// FIXME Better way to pack data in graphic element
|
||||
define(function (require) {
|
||||
|
||||
require('./tooltip/TooltipModel');
|
||||
|
||||
require('./tooltip/TooltipView');
|
||||
|
||||
// Show tip action
|
||||
/**
|
||||
* @action
|
||||
* @property {string} type
|
||||
* @property {number} seriesIndex
|
||||
* @property {number} dataIndex
|
||||
* @property {number} [x]
|
||||
* @property {number} [y]
|
||||
*/
|
||||
require('../echarts').registerAction(
|
||||
{
|
||||
type: 'showTip',
|
||||
event: 'showTip',
|
||||
update: 'none'
|
||||
},
|
||||
// noop
|
||||
function () {}
|
||||
);
|
||||
// Hide tip action
|
||||
require('../echarts').registerAction(
|
||||
{
|
||||
type: 'hideTip',
|
||||
event: 'hideTip',
|
||||
update: 'none'
|
||||
},
|
||||
// noop
|
||||
function () {}
|
||||
);
|
||||
});
|
||||
265
vendors/echarts/src/component/tooltip/TooltipContent.js
vendored
Normal file
265
vendors/echarts/src/component/tooltip/TooltipContent.js
vendored
Normal file
@@ -0,0 +1,265 @@
|
||||
/**
|
||||
* @module echarts/component/tooltip/TooltipContent
|
||||
*/
|
||||
define(function (require) {
|
||||
|
||||
var zrUtil = require('zrender/core/util');
|
||||
var zrColor = require('zrender/tool/color');
|
||||
var eventUtil = require('zrender/core/event');
|
||||
var formatUtil = require('../../util/format');
|
||||
var each = zrUtil.each;
|
||||
var toCamelCase = formatUtil.toCamelCase;
|
||||
var env = require('zrender/core/env');
|
||||
|
||||
var vendors = ['', '-webkit-', '-moz-', '-o-'];
|
||||
|
||||
var gCssText = 'position:absolute;display:block;border-style:solid;white-space:nowrap;z-index:9999999;';
|
||||
|
||||
/**
|
||||
* @param {number} duration
|
||||
* @return {string}
|
||||
* @inner
|
||||
*/
|
||||
function assembleTransition(duration) {
|
||||
var transitionCurve = 'cubic-bezier(0.23, 1, 0.32, 1)';
|
||||
var transitionText = 'left ' + duration + 's ' + transitionCurve + ','
|
||||
+ 'top ' + duration + 's ' + transitionCurve;
|
||||
return zrUtil.map(vendors, function (vendorPrefix) {
|
||||
return vendorPrefix + 'transition:' + transitionText;
|
||||
}).join(';');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Object} textStyle
|
||||
* @return {string}
|
||||
* @inner
|
||||
*/
|
||||
function assembleFont(textStyleModel) {
|
||||
var cssText = [];
|
||||
|
||||
var fontSize = textStyleModel.get('fontSize');
|
||||
var color = textStyleModel.getTextColor();
|
||||
|
||||
color && cssText.push('color:' + color);
|
||||
|
||||
cssText.push('font:' + textStyleModel.getFont());
|
||||
|
||||
fontSize &&
|
||||
cssText.push('line-height:' + Math.round(fontSize * 3 / 2) + 'px');
|
||||
|
||||
each(['decoration', 'align'], function (name) {
|
||||
var val = textStyleModel.get(name);
|
||||
val && cssText.push('text-' + name + ':' + val);
|
||||
});
|
||||
|
||||
return cssText.join(';');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Object} tooltipModel
|
||||
* @return {string}
|
||||
* @inner
|
||||
*/
|
||||
function assembleCssText(tooltipModel) {
|
||||
|
||||
tooltipModel = tooltipModel;
|
||||
|
||||
var cssText = [];
|
||||
|
||||
var transitionDuration = tooltipModel.get('transitionDuration');
|
||||
var backgroundColor = tooltipModel.get('backgroundColor');
|
||||
var textStyleModel = tooltipModel.getModel('textStyle');
|
||||
var padding = tooltipModel.get('padding');
|
||||
|
||||
// Animation transition
|
||||
transitionDuration &&
|
||||
cssText.push(assembleTransition(transitionDuration));
|
||||
|
||||
if (backgroundColor) {
|
||||
if (env.canvasSupported) {
|
||||
cssText.push('background-Color:' + backgroundColor);
|
||||
}
|
||||
else {
|
||||
// for ie
|
||||
cssText.push(
|
||||
'background-Color:#' + zrColor.toHex(backgroundColor)
|
||||
);
|
||||
cssText.push('filter:alpha(opacity=70)');
|
||||
}
|
||||
}
|
||||
|
||||
// Border style
|
||||
each(['width', 'color', 'radius'], function (name) {
|
||||
var borderName = 'border-' + name;
|
||||
var camelCase = toCamelCase(borderName);
|
||||
var val = tooltipModel.get(camelCase);
|
||||
val != null &&
|
||||
cssText.push(borderName + ':' + val + (name === 'color' ? '' : 'px'));
|
||||
});
|
||||
|
||||
// Text style
|
||||
cssText.push(assembleFont(textStyleModel));
|
||||
|
||||
// Padding
|
||||
if (padding != null) {
|
||||
cssText.push('padding:' + formatUtil.normalizeCssArray(padding).join('px ') + 'px');
|
||||
}
|
||||
|
||||
return cssText.join(';') + ';';
|
||||
}
|
||||
|
||||
/**
|
||||
* @alias module:echarts/component/tooltip/TooltipContent
|
||||
* @constructor
|
||||
*/
|
||||
function TooltipContent(container, api) {
|
||||
var el = document.createElement('div');
|
||||
var zr = api.getZr();
|
||||
|
||||
this.el = el;
|
||||
|
||||
this._x = api.getWidth() / 2;
|
||||
this._y = api.getHeight() / 2;
|
||||
|
||||
container.appendChild(el);
|
||||
|
||||
this._container = container;
|
||||
|
||||
this._show = false;
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
this._hideTimeout;
|
||||
|
||||
var self = this;
|
||||
el.onmouseenter = function () {
|
||||
// clear the timeout in hideLater and keep showing tooltip
|
||||
if (self.enterable) {
|
||||
clearTimeout(self._hideTimeout);
|
||||
self._show = true;
|
||||
}
|
||||
self._inContent = true;
|
||||
};
|
||||
el.onmousemove = function (e) {
|
||||
if (!self.enterable) {
|
||||
// Try trigger zrender event to avoid mouse
|
||||
// in and out shape too frequently
|
||||
var handler = zr.handler;
|
||||
eventUtil.normalizeEvent(container, e);
|
||||
handler.dispatch('mousemove', e);
|
||||
}
|
||||
};
|
||||
el.onmouseleave = function () {
|
||||
if (self.enterable) {
|
||||
if (self._show) {
|
||||
self.hideLater(self._hideDelay);
|
||||
}
|
||||
}
|
||||
self._inContent = false;
|
||||
};
|
||||
|
||||
compromiseMobile(el, container);
|
||||
}
|
||||
|
||||
function compromiseMobile(tooltipContentEl, container) {
|
||||
// Prevent default behavior on mobile. For example,
|
||||
// default pinch gesture will cause browser zoom.
|
||||
// We do not preventing event on tooltip contnet el,
|
||||
// because user may need customization in tooltip el.
|
||||
eventUtil.addEventListener(container, 'touchstart', preventDefault);
|
||||
eventUtil.addEventListener(container, 'touchmove', preventDefault);
|
||||
eventUtil.addEventListener(container, 'touchend', preventDefault);
|
||||
|
||||
function preventDefault(e) {
|
||||
if (contains(e.target)) {
|
||||
e.preventDefault();
|
||||
}
|
||||
}
|
||||
|
||||
function contains(targetEl) {
|
||||
while (targetEl && targetEl !== container) {
|
||||
if (targetEl === tooltipContentEl) {
|
||||
return true;
|
||||
}
|
||||
targetEl = targetEl.parentNode;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TooltipContent.prototype = {
|
||||
|
||||
constructor: TooltipContent,
|
||||
|
||||
enterable: true,
|
||||
|
||||
/**
|
||||
* Update when tooltip is rendered
|
||||
*/
|
||||
update: function () {
|
||||
var container = this._container;
|
||||
var stl = container.currentStyle
|
||||
|| document.defaultView.getComputedStyle(container);
|
||||
var domStyle = container.style;
|
||||
if (domStyle.position !== 'absolute' && stl.position !== 'absolute') {
|
||||
domStyle.position = 'relative';
|
||||
}
|
||||
// Hide the tooltip
|
||||
// PENDING
|
||||
// this.hide();
|
||||
},
|
||||
|
||||
show: function (tooltipModel) {
|
||||
clearTimeout(this._hideTimeout);
|
||||
|
||||
this.el.style.cssText = gCssText + assembleCssText(tooltipModel)
|
||||
// http://stackoverflow.com/questions/21125587/css3-transition-not-working-in-chrome-anymore
|
||||
+ ';left:' + this._x + 'px;top:' + this._y + 'px;'
|
||||
+ (tooltipModel.get('extraCssText') || '');
|
||||
|
||||
this._show = true;
|
||||
},
|
||||
|
||||
setContent: function (content) {
|
||||
var el = this.el;
|
||||
el.innerHTML = content;
|
||||
el.style.display = content ? 'block' : 'none';
|
||||
},
|
||||
|
||||
moveTo: function (x, y) {
|
||||
var style = this.el.style;
|
||||
style.left = x + 'px';
|
||||
style.top = y + 'px';
|
||||
|
||||
this._x = x;
|
||||
this._y = y;
|
||||
},
|
||||
|
||||
hide: function () {
|
||||
this.el.style.display = 'none';
|
||||
this._show = false;
|
||||
},
|
||||
|
||||
// showLater: function ()
|
||||
|
||||
hideLater: function (time) {
|
||||
if (this._show && !(this._inContent && this.enterable)) {
|
||||
if (time) {
|
||||
this._hideDelay = time;
|
||||
// Set show false to avoid invoke hideLater mutiple times
|
||||
this._show = false;
|
||||
this._hideTimeout = setTimeout(zrUtil.bind(this.hide, this), time);
|
||||
}
|
||||
else {
|
||||
this.hide();
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
isShow: function () {
|
||||
return this._show;
|
||||
}
|
||||
};
|
||||
|
||||
return TooltipContent;
|
||||
});
|
||||
104
vendors/echarts/src/component/tooltip/TooltipModel.js
vendored
Normal file
104
vendors/echarts/src/component/tooltip/TooltipModel.js
vendored
Normal file
@@ -0,0 +1,104 @@
|
||||
define(function (require) {
|
||||
|
||||
require('../../echarts').extendComponentModel({
|
||||
|
||||
type: 'tooltip',
|
||||
|
||||
defaultOption: {
|
||||
zlevel: 0,
|
||||
|
||||
z: 8,
|
||||
|
||||
show: true,
|
||||
|
||||
// tooltip主体内容
|
||||
showContent: true,
|
||||
|
||||
// 触发类型,默认数据触发,见下图,可选为:'item' ¦ 'axis'
|
||||
trigger: 'item',
|
||||
|
||||
// 触发条件,支持 'click' | 'mousemove'
|
||||
triggerOn: 'mousemove',
|
||||
|
||||
// 是否永远显示 content
|
||||
alwaysShowContent: false,
|
||||
|
||||
// 位置 {Array} | {Function}
|
||||
// position: null
|
||||
|
||||
// 内容格式器:{string}(Template) ¦ {Function}
|
||||
// formatter: null
|
||||
|
||||
showDelay: 0,
|
||||
|
||||
// 隐藏延迟,单位ms
|
||||
hideDelay: 100,
|
||||
|
||||
// 动画变换时间,单位s
|
||||
transitionDuration: 0.4,
|
||||
|
||||
enterable: false,
|
||||
|
||||
// 提示背景颜色,默认为透明度为0.7的黑色
|
||||
backgroundColor: 'rgba(50,50,50,0.7)',
|
||||
|
||||
// 提示边框颜色
|
||||
borderColor: '#333',
|
||||
|
||||
// 提示边框圆角,单位px,默认为4
|
||||
borderRadius: 4,
|
||||
|
||||
// 提示边框线宽,单位px,默认为0(无边框)
|
||||
borderWidth: 0,
|
||||
|
||||
// 提示内边距,单位px,默认各方向内边距为5,
|
||||
// 接受数组分别设定上右下左边距,同css
|
||||
padding: 5,
|
||||
|
||||
// Extra css text
|
||||
extraCssText: '',
|
||||
|
||||
// 坐标轴指示器,坐标轴触发有效
|
||||
axisPointer: {
|
||||
// 默认为直线
|
||||
// 可选为:'line' | 'shadow' | 'cross'
|
||||
type: 'line',
|
||||
|
||||
// type 为 line 的时候有效,指定 tooltip line 所在的轴,可选
|
||||
// 可选 'x' | 'y' | 'angle' | 'radius' | 'auto'
|
||||
// 默认 'auto',会选择类型为 cateogry 的轴,对于双数值轴,笛卡尔坐标系会默认选择 x 轴
|
||||
// 极坐标系会默认选择 angle 轴
|
||||
axis: 'auto',
|
||||
|
||||
animation: true,
|
||||
animationDurationUpdate: 200,
|
||||
animationEasingUpdate: 'exponentialOut',
|
||||
|
||||
// 直线指示器样式设置
|
||||
lineStyle: {
|
||||
color: '#555',
|
||||
width: 1,
|
||||
type: 'solid'
|
||||
},
|
||||
|
||||
crossStyle: {
|
||||
color: '#555',
|
||||
width: 1,
|
||||
type: 'dashed',
|
||||
|
||||
// TODO formatter
|
||||
textStyle: {}
|
||||
},
|
||||
|
||||
// 阴影指示器样式设置
|
||||
shadowStyle: {
|
||||
color: 'rgba(150,150,150,0.3)'
|
||||
}
|
||||
},
|
||||
textStyle: {
|
||||
color: '#fff',
|
||||
fontSize: 14
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
1144
vendors/echarts/src/component/tooltip/TooltipView.js
vendored
Normal file
1144
vendors/echarts/src/component/tooltip/TooltipView.js
vendored
Normal file
File diff suppressed because it is too large
Load Diff
9
vendors/echarts/src/component/visualMap.js
vendored
Normal file
9
vendors/echarts/src/component/visualMap.js
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
/**
|
||||
* visualMap component entry
|
||||
*/
|
||||
define(function (require) {
|
||||
|
||||
require('./visualMapContinuous');
|
||||
require('./visualMapPiecewise');
|
||||
|
||||
});
|
||||
171
vendors/echarts/src/component/visualMap/ContinuousModel.js
vendored
Normal file
171
vendors/echarts/src/component/visualMap/ContinuousModel.js
vendored
Normal file
@@ -0,0 +1,171 @@
|
||||
/**
|
||||
* @file Data zoom model
|
||||
*/
|
||||
define(function(require) {
|
||||
|
||||
var VisualMapModel = require('./VisualMapModel');
|
||||
var zrUtil = require('zrender/core/util');
|
||||
var numberUtil = require('../../util/number');
|
||||
|
||||
// Constant
|
||||
var DEFAULT_BAR_BOUND = [20, 140];
|
||||
|
||||
var ContinuousModel = VisualMapModel.extend({
|
||||
|
||||
type: 'visualMap.continuous',
|
||||
|
||||
/**
|
||||
* @protected
|
||||
*/
|
||||
defaultOption: {
|
||||
align: 'auto', // 'auto', 'left', 'right', 'top', 'bottom'
|
||||
calculable: false, // This prop effect default component type determine,
|
||||
// See echarts/component/visualMap/typeDefaulter.
|
||||
range: null, // selected range. In default case `range` is [min, max]
|
||||
// and can auto change along with modification of min max,
|
||||
// util use specifid a range.
|
||||
realtime: true, // Whether realtime update.
|
||||
itemHeight: null, // The length of the range control edge.
|
||||
itemWidth: null, // The length of the other side.
|
||||
hoverLink: true // Enable hover highlight.
|
||||
},
|
||||
|
||||
/**
|
||||
* @override
|
||||
*/
|
||||
doMergeOption: function (newOption, isInit) {
|
||||
ContinuousModel.superApply(this, 'doMergeOption', arguments);
|
||||
|
||||
this.resetTargetSeries(newOption, isInit);
|
||||
this.resetExtent();
|
||||
|
||||
this.resetVisual(function (mappingOption) {
|
||||
mappingOption.mappingMethod = 'linear';
|
||||
});
|
||||
|
||||
this._resetRange();
|
||||
},
|
||||
|
||||
/**
|
||||
* @protected
|
||||
* @override
|
||||
*/
|
||||
resetItemSize: function () {
|
||||
VisualMapModel.prototype.resetItemSize.apply(this, arguments);
|
||||
|
||||
var itemSize = this.itemSize;
|
||||
|
||||
this._orient === 'horizontal' && itemSize.reverse();
|
||||
|
||||
(itemSize[0] == null || isNaN(itemSize[0])) && (itemSize[0] = DEFAULT_BAR_BOUND[0]);
|
||||
(itemSize[1] == null || isNaN(itemSize[1])) && (itemSize[1] = DEFAULT_BAR_BOUND[1]);
|
||||
},
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
_resetRange: function () {
|
||||
var dataExtent = this.getExtent();
|
||||
var range = this.option.range;
|
||||
|
||||
if (!range || range.auto) {
|
||||
// `range` should always be array (so we dont use other
|
||||
// value like 'auto') for user-friend. (consider getOption).
|
||||
dataExtent.auto = 1;
|
||||
this.option.range = dataExtent;
|
||||
}
|
||||
else if (zrUtil.isArray(range)) {
|
||||
if (range[0] > range[1]) {
|
||||
range.reverse();
|
||||
}
|
||||
range[0] = Math.max(range[0], dataExtent[0]);
|
||||
range[1] = Math.min(range[1], dataExtent[1]);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* @protected
|
||||
* @override
|
||||
*/
|
||||
completeVisualOption: function () {
|
||||
VisualMapModel.prototype.completeVisualOption.apply(this, arguments);
|
||||
|
||||
zrUtil.each(this.stateList, function (state) {
|
||||
var symbolSize = this.option.controller[state].symbolSize;
|
||||
if (symbolSize && symbolSize[0] !== symbolSize[1]) {
|
||||
symbolSize[0] = 0; // For good looking.
|
||||
}
|
||||
}, this);
|
||||
},
|
||||
|
||||
/**
|
||||
* @public
|
||||
* @override
|
||||
*/
|
||||
setSelected: function (selected) {
|
||||
this.option.range = selected.slice();
|
||||
this._resetRange();
|
||||
},
|
||||
|
||||
/**
|
||||
* @public
|
||||
*/
|
||||
getSelected: function () {
|
||||
var dataExtent = this.getExtent();
|
||||
|
||||
var dataInterval = numberUtil.asc(
|
||||
(this.get('range') || []).slice()
|
||||
);
|
||||
|
||||
// Clamp
|
||||
dataInterval[0] > dataExtent[1] && (dataInterval[0] = dataExtent[1]);
|
||||
dataInterval[1] > dataExtent[1] && (dataInterval[1] = dataExtent[1]);
|
||||
dataInterval[0] < dataExtent[0] && (dataInterval[0] = dataExtent[0]);
|
||||
dataInterval[1] < dataExtent[0] && (dataInterval[1] = dataExtent[0]);
|
||||
|
||||
return dataInterval;
|
||||
},
|
||||
|
||||
/**
|
||||
* @public
|
||||
* @override
|
||||
*/
|
||||
getValueState: function (value) {
|
||||
var range = this.option.range;
|
||||
var dataExtent = this.getExtent();
|
||||
|
||||
// When range[0] === dataExtent[0], any value larger than dataExtent[0] maps to 'inRange'.
|
||||
// range[1] is processed likewise.
|
||||
return (
|
||||
(range[0] <= dataExtent[0] || range[0] <= value)
|
||||
&& (range[1] >= dataExtent[1] || value <= range[1])
|
||||
) ? 'inRange' : 'outOfRange';
|
||||
},
|
||||
|
||||
/**
|
||||
* @public
|
||||
* @params {Array.<number>} range target value: range[0] <= value && value <= range[1]
|
||||
* @return {Array.<Object>} [{seriesId, dataIndices: <Array.<number>>}, ...]
|
||||
*/
|
||||
findTargetDataIndices: function (range) {
|
||||
var result = [];
|
||||
|
||||
this.eachTargetSeries(function (seriesModel) {
|
||||
var dataIndices = [];
|
||||
var data = seriesModel.getData();
|
||||
|
||||
data.each(this.getDataDimension(data), function (value, dataIndex) {
|
||||
range[0] <= value && value <= range[1] && dataIndices.push(dataIndex);
|
||||
}, true, this);
|
||||
|
||||
result.push({seriesId: seriesModel.id, dataIndices: dataIndices});
|
||||
}, this);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
return ContinuousModel;
|
||||
|
||||
});
|
||||
718
vendors/echarts/src/component/visualMap/ContinuousView.js
vendored
Normal file
718
vendors/echarts/src/component/visualMap/ContinuousView.js
vendored
Normal file
@@ -0,0 +1,718 @@
|
||||
define(function(require) {
|
||||
|
||||
var VisualMapView = require('./VisualMapView');
|
||||
var graphic = require('../../util/graphic');
|
||||
var zrUtil = require('zrender/core/util');
|
||||
var numberUtil = require('../../util/number');
|
||||
var sliderMove = require('../helper/sliderMove');
|
||||
var LinearGradient = require('zrender/graphic/LinearGradient');
|
||||
var helper = require('./helper');
|
||||
|
||||
var linearMap = numberUtil.linearMap;
|
||||
var convertDataIndicesToBatch = helper.convertDataIndicesToBatch;
|
||||
var each = zrUtil.each;
|
||||
var mathMin = Math.min;
|
||||
var mathMax = Math.max;
|
||||
|
||||
// Arbitrary value
|
||||
var HOVER_LINK_RANGE = 6;
|
||||
var HOVER_LINK_OUT = 6;
|
||||
|
||||
// Notice:
|
||||
// Any "interval" should be by the order of [low, high].
|
||||
// "handle0" (handleIndex === 0) maps to
|
||||
// low data value: this._dataInterval[0] and has low coord.
|
||||
// "handle1" (handleIndex === 1) maps to
|
||||
// high data value: this._dataInterval[1] and has high coord.
|
||||
// The logic of transform is implemented in this._createBarGroup.
|
||||
|
||||
var ContinuousVisualMapView = VisualMapView.extend({
|
||||
|
||||
type: 'visualMap.continuous',
|
||||
|
||||
/**
|
||||
* @override
|
||||
*/
|
||||
init: function () {
|
||||
|
||||
VisualMapView.prototype.init.apply(this, arguments);
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
this._shapes = {};
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
this._dataInterval = [];
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
this._handleEnds = [];
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
this._orient;
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
this._useHandle;
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
this._hoverLinkDataIndices = [];
|
||||
},
|
||||
|
||||
/**
|
||||
* @protected
|
||||
* @override
|
||||
*/
|
||||
doRender: function (visualMapModel, ecModel, api, payload) {
|
||||
if (!payload || payload.type !== 'selectDataRange' || payload.from !== this.uid) {
|
||||
this._buildView();
|
||||
}
|
||||
else {
|
||||
this._updateView();
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
_buildView: function () {
|
||||
this.group.removeAll();
|
||||
|
||||
var visualMapModel = this.visualMapModel;
|
||||
var thisGroup = this.group;
|
||||
|
||||
this._orient = visualMapModel.get('orient');
|
||||
this._useHandle = visualMapModel.get('calculable');
|
||||
|
||||
this._resetInterval();
|
||||
|
||||
this._renderBar(thisGroup);
|
||||
|
||||
var dataRangeText = visualMapModel.get('text');
|
||||
this._renderEndsText(thisGroup, dataRangeText, 0);
|
||||
this._renderEndsText(thisGroup, dataRangeText, 1);
|
||||
|
||||
// Do this for background size calculation.
|
||||
this._updateView(true);
|
||||
|
||||
// After updating view, inner shapes is built completely,
|
||||
// and then background can be rendered.
|
||||
this.renderBackground(thisGroup);
|
||||
|
||||
// Real update view
|
||||
this._updateView();
|
||||
|
||||
this._enableHoverLinkToSeries();
|
||||
this._enableHoverLinkFromSeries();
|
||||
|
||||
this.positionGroup(thisGroup);
|
||||
},
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
_renderEndsText: function (group, dataRangeText, endsIndex) {
|
||||
if (!dataRangeText) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Compatible with ec2, text[0] map to high value, text[1] map low value.
|
||||
var text = dataRangeText[1 - endsIndex];
|
||||
text = text != null ? text + '' : '';
|
||||
|
||||
var visualMapModel = this.visualMapModel;
|
||||
var textGap = visualMapModel.get('textGap');
|
||||
var itemSize = visualMapModel.itemSize;
|
||||
|
||||
var barGroup = this._shapes.barGroup;
|
||||
var position = this._applyTransform(
|
||||
[
|
||||
itemSize[0] / 2,
|
||||
endsIndex === 0 ? -textGap : itemSize[1] + textGap
|
||||
],
|
||||
barGroup
|
||||
);
|
||||
var align = this._applyTransform(
|
||||
endsIndex === 0 ? 'bottom' : 'top',
|
||||
barGroup
|
||||
);
|
||||
var orient = this._orient;
|
||||
var textStyleModel = this.visualMapModel.textStyleModel;
|
||||
|
||||
this.group.add(new graphic.Text({
|
||||
style: {
|
||||
x: position[0],
|
||||
y: position[1],
|
||||
textVerticalAlign: orient === 'horizontal' ? 'middle' : align,
|
||||
textAlign: orient === 'horizontal' ? align : 'center',
|
||||
text: text,
|
||||
textFont: textStyleModel.getFont(),
|
||||
fill: textStyleModel.getTextColor()
|
||||
}
|
||||
}));
|
||||
},
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
_renderBar: function (targetGroup) {
|
||||
var visualMapModel = this.visualMapModel;
|
||||
var shapes = this._shapes;
|
||||
var itemSize = visualMapModel.itemSize;
|
||||
var orient = this._orient;
|
||||
var useHandle = this._useHandle;
|
||||
var itemAlign = helper.getItemAlign(visualMapModel, this.api, itemSize);
|
||||
var barGroup = shapes.barGroup = this._createBarGroup(itemAlign);
|
||||
|
||||
// Bar
|
||||
barGroup.add(shapes.outOfRange = createPolygon());
|
||||
barGroup.add(shapes.inRange = createPolygon(
|
||||
null,
|
||||
zrUtil.bind(this._modifyHandle, this, 'all'),
|
||||
useHandle ? 'move' : null
|
||||
));
|
||||
|
||||
var textRect = visualMapModel.textStyleModel.getTextRect('国');
|
||||
var textSize = Math.max(textRect.width, textRect.height);
|
||||
|
||||
// Handle
|
||||
if (useHandle) {
|
||||
shapes.handleThumbs = [];
|
||||
shapes.handleLabels = [];
|
||||
shapes.handleLabelPoints = [];
|
||||
|
||||
this._createHandle(barGroup, 0, itemSize, textSize, orient, itemAlign);
|
||||
this._createHandle(barGroup, 1, itemSize, textSize, orient, itemAlign);
|
||||
}
|
||||
|
||||
this._createIndicator(barGroup, itemSize, textSize, orient);
|
||||
|
||||
targetGroup.add(barGroup);
|
||||
},
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
_createHandle: function (barGroup, handleIndex, itemSize, textSize, orient) {
|
||||
var modifyHandle = zrUtil.bind(this._modifyHandle, this, handleIndex);
|
||||
var handleThumb = createPolygon(
|
||||
createHandlePoints(handleIndex, textSize),
|
||||
modifyHandle,
|
||||
'move'
|
||||
);
|
||||
handleThumb.position[0] = itemSize[0];
|
||||
barGroup.add(handleThumb);
|
||||
|
||||
// Text is always horizontal layout but should not be effected by
|
||||
// transform (orient/inverse). So label is built separately but not
|
||||
// use zrender/graphic/helper/RectText, and is located based on view
|
||||
// group (according to handleLabelPoint) but not barGroup.
|
||||
var textStyleModel = this.visualMapModel.textStyleModel;
|
||||
var handleLabel = new graphic.Text({
|
||||
draggable: true,
|
||||
drift: modifyHandle,
|
||||
style: {
|
||||
x: 0, y: 0, text: '',
|
||||
textFont: textStyleModel.getFont(),
|
||||
fill: textStyleModel.getTextColor()
|
||||
}
|
||||
});
|
||||
this.group.add(handleLabel);
|
||||
|
||||
var handleLabelPoint = [
|
||||
orient === 'horizontal'
|
||||
? textSize / 2
|
||||
: textSize * 1.5,
|
||||
orient === 'horizontal'
|
||||
? (handleIndex === 0 ? -(textSize * 1.5) : (textSize * 1.5))
|
||||
: (handleIndex === 0 ? -textSize / 2 : textSize / 2)
|
||||
];
|
||||
|
||||
var shapes = this._shapes;
|
||||
shapes.handleThumbs[handleIndex] = handleThumb;
|
||||
shapes.handleLabelPoints[handleIndex] = handleLabelPoint;
|
||||
shapes.handleLabels[handleIndex] = handleLabel;
|
||||
},
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
_createIndicator: function (barGroup, itemSize, textSize, orient) {
|
||||
var indicator = createPolygon([[0, 0]], null, 'move');
|
||||
indicator.position[0] = itemSize[0];
|
||||
indicator.attr({invisible: true, silent: true});
|
||||
barGroup.add(indicator);
|
||||
|
||||
var textStyleModel = this.visualMapModel.textStyleModel;
|
||||
var indicatorLabel = new graphic.Text({
|
||||
silent: true,
|
||||
invisible: true,
|
||||
style: {
|
||||
x: 0, y: 0, text: '',
|
||||
textFont: textStyleModel.getFont(),
|
||||
fill: textStyleModel.getTextColor()
|
||||
}
|
||||
});
|
||||
this.group.add(indicatorLabel);
|
||||
|
||||
var indicatorLabelPoint = [
|
||||
orient === 'horizontal' ? textSize / 2 : HOVER_LINK_OUT + 3,
|
||||
0
|
||||
];
|
||||
|
||||
var shapes = this._shapes;
|
||||
shapes.indicator = indicator;
|
||||
shapes.indicatorLabel = indicatorLabel;
|
||||
shapes.indicatorLabelPoint = indicatorLabelPoint;
|
||||
},
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
_modifyHandle: function (handleIndex, dx, dy) {
|
||||
if (!this._useHandle) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Transform dx, dy to bar coordination.
|
||||
var vertex = this._applyTransform([dx, dy], this._shapes.barGroup, true);
|
||||
this._updateInterval(handleIndex, vertex[1]);
|
||||
|
||||
this.api.dispatchAction({
|
||||
type: 'selectDataRange',
|
||||
from: this.uid,
|
||||
visualMapId: this.visualMapModel.id,
|
||||
selected: this._dataInterval.slice()
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
_resetInterval: function () {
|
||||
var visualMapModel = this.visualMapModel;
|
||||
|
||||
var dataInterval = this._dataInterval = visualMapModel.getSelected();
|
||||
var dataExtent = visualMapModel.getExtent();
|
||||
var sizeExtent = [0, visualMapModel.itemSize[1]];
|
||||
|
||||
this._handleEnds = [
|
||||
linearMap(dataInterval[0], dataExtent, sizeExtent, true),
|
||||
linearMap(dataInterval[1], dataExtent, sizeExtent, true)
|
||||
];
|
||||
},
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @param {(number|string)} handleIndex 0 or 1 or 'all'
|
||||
* @param {number} dx
|
||||
* @param {number} dy
|
||||
*/
|
||||
_updateInterval: function (handleIndex, delta) {
|
||||
delta = delta || 0;
|
||||
var visualMapModel = this.visualMapModel;
|
||||
var handleEnds = this._handleEnds;
|
||||
|
||||
sliderMove(
|
||||
delta,
|
||||
handleEnds,
|
||||
[0, visualMapModel.itemSize[1]],
|
||||
handleIndex === 'all' ? 'rigid' : 'push',
|
||||
handleIndex
|
||||
);
|
||||
var dataExtent = visualMapModel.getExtent();
|
||||
var sizeExtent = [0, visualMapModel.itemSize[1]];
|
||||
// Update data interval.
|
||||
this._dataInterval = [
|
||||
linearMap(handleEnds[0], sizeExtent, dataExtent, true),
|
||||
linearMap(handleEnds[1], sizeExtent, dataExtent, true)
|
||||
];
|
||||
},
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
_updateView: function (forSketch) {
|
||||
var visualMapModel = this.visualMapModel;
|
||||
var dataExtent = visualMapModel.getExtent();
|
||||
var shapes = this._shapes;
|
||||
|
||||
var outOfRangeHandleEnds = [0, visualMapModel.itemSize[1]];
|
||||
var inRangeHandleEnds = forSketch ? outOfRangeHandleEnds : this._handleEnds;
|
||||
|
||||
var visualInRange = this._createBarVisual(
|
||||
this._dataInterval, dataExtent, inRangeHandleEnds, 'inRange'
|
||||
);
|
||||
var visualOutOfRange = this._createBarVisual(
|
||||
dataExtent, dataExtent, outOfRangeHandleEnds, 'outOfRange'
|
||||
);
|
||||
|
||||
shapes.inRange
|
||||
.setStyle({
|
||||
fill: visualInRange.barColor,
|
||||
opacity: visualInRange.opacity
|
||||
})
|
||||
.setShape('points', visualInRange.barPoints);
|
||||
shapes.outOfRange
|
||||
.setStyle({
|
||||
fill: visualOutOfRange.barColor,
|
||||
opacity: visualOutOfRange.opacity
|
||||
})
|
||||
.setShape('points', visualOutOfRange.barPoints);
|
||||
|
||||
this._updateHandle(inRangeHandleEnds, visualInRange);
|
||||
},
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
_createBarVisual: function (dataInterval, dataExtent, handleEnds, forceState) {
|
||||
var opts = {
|
||||
forceState: forceState,
|
||||
convertOpacityToAlpha: true
|
||||
};
|
||||
var colorStops = this._makeColorGradient(dataInterval, opts);
|
||||
|
||||
var symbolSizes = [
|
||||
this.getControllerVisual(dataInterval[0], 'symbolSize', opts),
|
||||
this.getControllerVisual(dataInterval[1], 'symbolSize', opts)
|
||||
];
|
||||
var barPoints = this._createBarPoints(handleEnds, symbolSizes);
|
||||
|
||||
return {
|
||||
barColor: new LinearGradient(0, 0, 1, 1, colorStops),
|
||||
barPoints: barPoints,
|
||||
handlesColor: [
|
||||
colorStops[0].color,
|
||||
colorStops[colorStops.length - 1].color
|
||||
]
|
||||
};
|
||||
},
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
_makeColorGradient: function (dataInterval, opts) {
|
||||
// Considering colorHue, which is not linear, so we have to sample
|
||||
// to calculate gradient color stops, but not only caculate head
|
||||
// and tail.
|
||||
var sampleNumber = 100; // Arbitrary value.
|
||||
var colorStops = [];
|
||||
var step = (dataInterval[1] - dataInterval[0]) / sampleNumber;
|
||||
|
||||
colorStops.push({
|
||||
color: this.getControllerVisual(dataInterval[0], 'color', opts),
|
||||
offset: 0
|
||||
});
|
||||
|
||||
for (var i = 1; i < sampleNumber; i++) {
|
||||
var currValue = dataInterval[0] + step * i;
|
||||
if (currValue > dataInterval[1]) {
|
||||
break;
|
||||
}
|
||||
colorStops.push({
|
||||
color: this.getControllerVisual(currValue, 'color', opts),
|
||||
offset: i / sampleNumber
|
||||
});
|
||||
}
|
||||
|
||||
colorStops.push({
|
||||
color: this.getControllerVisual(dataInterval[1], 'color', opts),
|
||||
offset: 1
|
||||
});
|
||||
|
||||
return colorStops;
|
||||
},
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
_createBarPoints: function (handleEnds, symbolSizes) {
|
||||
var itemSize = this.visualMapModel.itemSize;
|
||||
|
||||
return [
|
||||
[itemSize[0] - symbolSizes[0], handleEnds[0]],
|
||||
[itemSize[0], handleEnds[0]],
|
||||
[itemSize[0], handleEnds[1]],
|
||||
[itemSize[0] - symbolSizes[1], handleEnds[1]]
|
||||
];
|
||||
},
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
_createBarGroup: function (itemAlign) {
|
||||
var orient = this._orient;
|
||||
var inverse = this.visualMapModel.get('inverse');
|
||||
|
||||
return new graphic.Group(
|
||||
(orient === 'horizontal' && !inverse)
|
||||
? {scale: itemAlign === 'bottom' ? [1, 1] : [-1, 1], rotation: Math.PI / 2}
|
||||
: (orient === 'horizontal' && inverse)
|
||||
? {scale: itemAlign === 'bottom' ? [-1, 1] : [1, 1], rotation: -Math.PI / 2}
|
||||
: (orient === 'vertical' && !inverse)
|
||||
? {scale: itemAlign === 'left' ? [1, -1] : [-1, -1]}
|
||||
: {scale: itemAlign === 'left' ? [1, 1] : [-1, 1]}
|
||||
);
|
||||
},
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
_updateHandle: function (handleEnds, visualInRange) {
|
||||
if (!this._useHandle) {
|
||||
return;
|
||||
}
|
||||
|
||||
var shapes = this._shapes;
|
||||
var visualMapModel = this.visualMapModel;
|
||||
var handleThumbs = shapes.handleThumbs;
|
||||
var handleLabels = shapes.handleLabels;
|
||||
|
||||
each([0, 1], function (handleIndex) {
|
||||
var handleThumb = handleThumbs[handleIndex];
|
||||
handleThumb.setStyle('fill', visualInRange.handlesColor[handleIndex]);
|
||||
handleThumb.position[1] = handleEnds[handleIndex];
|
||||
|
||||
// Update handle label position.
|
||||
var textPoint = graphic.applyTransform(
|
||||
shapes.handleLabelPoints[handleIndex],
|
||||
graphic.getTransform(handleThumb, this.group)
|
||||
);
|
||||
handleLabels[handleIndex].setStyle({
|
||||
x: textPoint[0],
|
||||
y: textPoint[1],
|
||||
text: visualMapModel.formatValueText(this._dataInterval[handleIndex]),
|
||||
textVerticalAlign: 'middle',
|
||||
textAlign: this._applyTransform(
|
||||
this._orient === 'horizontal'
|
||||
? (handleIndex === 0 ? 'bottom' : 'top')
|
||||
: 'left',
|
||||
shapes.barGroup
|
||||
)
|
||||
});
|
||||
}, this);
|
||||
},
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
_showIndicator: function (value, isRange) {
|
||||
var visualMapModel = this.visualMapModel;
|
||||
var dataExtent = visualMapModel.getExtent();
|
||||
var itemSize = visualMapModel.itemSize;
|
||||
var sizeExtent = [0, itemSize[1]];
|
||||
var pos = linearMap(value, dataExtent, sizeExtent, true);
|
||||
|
||||
var shapes = this._shapes;
|
||||
var indicator = shapes.indicator;
|
||||
if (!indicator) {
|
||||
return;
|
||||
}
|
||||
|
||||
indicator.position[1] = pos;
|
||||
indicator.attr('invisible', false);
|
||||
indicator.setShape('points', createIndicatorPoints(isRange, pos, itemSize[1]));
|
||||
|
||||
var opts = {convertOpacityToAlpha: true};
|
||||
var color = this.getControllerVisual(value, 'color', opts);
|
||||
indicator.setStyle('fill', color);
|
||||
|
||||
// Update handle label position.
|
||||
var textPoint = graphic.applyTransform(
|
||||
shapes.indicatorLabelPoint,
|
||||
graphic.getTransform(indicator, this.group)
|
||||
);
|
||||
|
||||
var indicatorLabel = shapes.indicatorLabel;
|
||||
indicatorLabel.attr('invisible', false);
|
||||
var align = this._applyTransform('left', shapes.barGroup);
|
||||
var orient = this._orient;
|
||||
indicatorLabel.setStyle({
|
||||
text: (isRange ? '≈' : '') + visualMapModel.formatValueText(value),
|
||||
textVerticalAlign: orient === 'horizontal' ? align : 'middle',
|
||||
textAlign: orient === 'horizontal' ? 'center' : align,
|
||||
x: textPoint[0],
|
||||
y: textPoint[1]
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
_enableHoverLinkToSeries: function () {
|
||||
this._shapes.barGroup
|
||||
.on('mousemove', zrUtil.bind(onMouseOver, this))
|
||||
.on('mouseout', zrUtil.bind(this._clearHoverLinkToSeries, this));
|
||||
|
||||
function onMouseOver(e) {
|
||||
var visualMapModel = this.visualMapModel;
|
||||
var itemSize = visualMapModel.itemSize;
|
||||
|
||||
if (!visualMapModel.option.hoverLink) {
|
||||
return;
|
||||
}
|
||||
|
||||
var pos = this._applyTransform(
|
||||
[e.offsetX, e.offsetY], this._shapes.barGroup, true, true
|
||||
);
|
||||
var hoverRange = [pos[1] - HOVER_LINK_RANGE / 2, pos[1] + HOVER_LINK_RANGE / 2];
|
||||
var sizeExtent = [0, itemSize[1]];
|
||||
var dataExtent = visualMapModel.getExtent();
|
||||
var valueRange = [
|
||||
linearMap(hoverRange[0], sizeExtent, dataExtent, true),
|
||||
linearMap(hoverRange[1], sizeExtent, dataExtent, true)
|
||||
];
|
||||
|
||||
// Do not show indicator when mouse is over handle,
|
||||
// otherwise labels overlap, especially when dragging.
|
||||
if (0 <= pos[0] && pos[0] <= itemSize[0]) {
|
||||
this._showIndicator((valueRange[0] + valueRange[1]) / 2, true);
|
||||
}
|
||||
|
||||
var oldBatch = convertDataIndicesToBatch(this._hoverLinkDataIndices);
|
||||
this._hoverLinkDataIndices = visualMapModel.findTargetDataIndices(valueRange);
|
||||
var newBatch = convertDataIndicesToBatch(this._hoverLinkDataIndices);
|
||||
var resultBatches = helper.removeDuplicateBatch(oldBatch, newBatch);
|
||||
|
||||
this.api.dispatchAction({type: 'downplay', batch: resultBatches[0]});
|
||||
this.api.dispatchAction({type: 'highlight', batch: resultBatches[1]});
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
_enableHoverLinkFromSeries: function () {
|
||||
var zr = this.api.getZr();
|
||||
|
||||
if (this.visualMapModel.option.hoverLink) {
|
||||
zr.on('mouseover', this._hoverLinkFromSeriesMouseOver, this);
|
||||
zr.on('mouseout', this._hideIndicator, this);
|
||||
}
|
||||
else {
|
||||
this._clearHoverLinkFromSeries();
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
_hoverLinkFromSeriesMouseOver: function (e) {
|
||||
var el = e.target;
|
||||
|
||||
if (!el || el.dataIndex == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
var dataModel = el.dataModel || this.ecModel.getSeriesByIndex(el.seriesIndex);
|
||||
var data = dataModel.getData(el.dataType);
|
||||
var dim = data.getDimension(this.visualMapModel.getDataDimension(data));
|
||||
var value = data.get(dim, el.dataIndex, true);
|
||||
|
||||
this._showIndicator(value);
|
||||
},
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
_hideIndicator: function () {
|
||||
var shapes = this._shapes;
|
||||
shapes.indicator && shapes.indicator.attr('invisible', true);
|
||||
shapes.indicatorLabel && shapes.indicatorLabel.attr('invisible', true);
|
||||
},
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
_clearHoverLinkToSeries: function () {
|
||||
this._hideIndicator();
|
||||
|
||||
var indices = this._hoverLinkDataIndices;
|
||||
|
||||
this.api.dispatchAction({
|
||||
type: 'downplay',
|
||||
batch: convertDataIndicesToBatch(indices)
|
||||
});
|
||||
|
||||
indices.length = 0;
|
||||
},
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
_clearHoverLinkFromSeries: function () {
|
||||
this._hideIndicator();
|
||||
|
||||
var zr = this.api.getZr();
|
||||
zr.off('mouseover', this._hoverLinkFromSeriesMouseOver);
|
||||
zr.off('mouseout', this._hideIndicator);
|
||||
},
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
_applyTransform: function (vertex, element, inverse, global) {
|
||||
var transform = graphic.getTransform(element, global ? null : this.group);
|
||||
|
||||
return graphic[
|
||||
zrUtil.isArray(vertex) ? 'applyTransform' : 'transformDirection'
|
||||
](vertex, transform, inverse);
|
||||
},
|
||||
|
||||
/**
|
||||
* @override
|
||||
*/
|
||||
dispose: function () {
|
||||
this._clearHoverLinkFromSeries();
|
||||
this._clearHoverLinkToSeries();
|
||||
},
|
||||
|
||||
/**
|
||||
* @override
|
||||
*/
|
||||
remove: function () {
|
||||
this._clearHoverLinkFromSeries();
|
||||
this._clearHoverLinkToSeries();
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
function createPolygon(points, onDrift, cursor) {
|
||||
return new graphic.Polygon({
|
||||
shape: {points: points},
|
||||
draggable: !!onDrift,
|
||||
cursor: cursor,
|
||||
drift: onDrift
|
||||
});
|
||||
}
|
||||
|
||||
function createHandlePoints(handleIndex, textSize) {
|
||||
return handleIndex === 0
|
||||
? [[0, 0], [textSize, 0], [textSize, -textSize]]
|
||||
: [[0, 0], [textSize, 0], [textSize, textSize]];
|
||||
}
|
||||
|
||||
function createIndicatorPoints(isRange, pos, extentMax) {
|
||||
return isRange
|
||||
? [ // indicate range
|
||||
[0, -mathMin(HOVER_LINK_RANGE, mathMax(pos, 0))],
|
||||
[HOVER_LINK_OUT, 0],
|
||||
[0, mathMin(HOVER_LINK_RANGE, mathMax(extentMax - pos, 0))]
|
||||
]
|
||||
: [ // indicate single value
|
||||
[0, 0], [5, -5], [5, 5]
|
||||
];
|
||||
}
|
||||
|
||||
return ContinuousVisualMapView;
|
||||
});
|
||||
323
vendors/echarts/src/component/visualMap/PiecewiseModel.js
vendored
Normal file
323
vendors/echarts/src/component/visualMap/PiecewiseModel.js
vendored
Normal file
@@ -0,0 +1,323 @@
|
||||
define(function(require) {
|
||||
|
||||
var VisualMapModel = require('./VisualMapModel');
|
||||
var zrUtil = require('zrender/core/util');
|
||||
var VisualMapping = require('../../visual/VisualMapping');
|
||||
|
||||
var PiecewiseModel = VisualMapModel.extend({
|
||||
|
||||
type: 'visualMap.piecewise',
|
||||
|
||||
/**
|
||||
* Order Rule:
|
||||
*
|
||||
* option.categories / option.pieces / option.text / option.selected:
|
||||
* If !option.inverse,
|
||||
* Order when vertical: ['top', ..., 'bottom'].
|
||||
* Order when horizontal: ['left', ..., 'right'].
|
||||
* If option.inverse, the meaning of
|
||||
* the order should be reversed.
|
||||
*
|
||||
* this._pieceList:
|
||||
* The order is always [low, ..., high].
|
||||
*
|
||||
* Mapping from location to low-high:
|
||||
* If !option.inverse
|
||||
* When vertical, top is high.
|
||||
* When horizontal, right is high.
|
||||
* If option.inverse, reverse.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @protected
|
||||
*/
|
||||
defaultOption: {
|
||||
selected: null, // Object. If not specified, means selected.
|
||||
// When pieces and splitNumber: {'0': true, '5': true}
|
||||
// When categories: {'cate1': false, 'cate3': true}
|
||||
// When selected === false, means all unselected.
|
||||
align: 'auto', // 'auto', 'left', 'right'
|
||||
itemWidth: 20, // When put the controller vertically, it is the length of
|
||||
// horizontal side of each item. Otherwise, vertical side.
|
||||
itemHeight: 14, // When put the controller vertically, it is the length of
|
||||
// vertical side of each item. Otherwise, horizontal side.
|
||||
itemSymbol: 'roundRect',
|
||||
pieceList: null, // Each item is Object, with some of those attrs:
|
||||
// {min, max, value, color, colorSaturation, colorAlpha, opacity,
|
||||
// symbol, symbolSize}, which customize the range or visual
|
||||
// coding of the certain piece. Besides, see "Order Rule".
|
||||
categories: null, // category names, like: ['some1', 'some2', 'some3'].
|
||||
// Attr min/max are ignored when categories set. See "Order Rule"
|
||||
splitNumber: 5, // If set to 5, auto split five pieces equally.
|
||||
// If set to 0 and component type not set, component type will be
|
||||
// determined as "continuous". (It is less reasonable but for ec2
|
||||
// compatibility, see echarts/component/visualMap/typeDefaulter)
|
||||
selectedMode: 'multiple', // Can be 'multiple' or 'single'.
|
||||
itemGap: 10, // The gap between two items, in px.
|
||||
hoverLink: true // Enable hover highlight.
|
||||
},
|
||||
|
||||
/**
|
||||
* @override
|
||||
*/
|
||||
doMergeOption: function (newOption, isInit) {
|
||||
PiecewiseModel.superApply(this, 'doMergeOption', arguments);
|
||||
|
||||
/**
|
||||
* The order is always [low, ..., high].
|
||||
* [{text: string, interval: Array.<number>}, ...]
|
||||
* @private
|
||||
* @type {Array.<Object>}
|
||||
*/
|
||||
this._pieceList = [];
|
||||
|
||||
this.resetTargetSeries(newOption, isInit);
|
||||
this.resetExtent();
|
||||
|
||||
/**
|
||||
* 'pieces', 'categories', 'splitNumber'
|
||||
* @type {string}
|
||||
*/
|
||||
var mode = this._mode = this._decideMode();
|
||||
|
||||
resetMethods[this._mode].call(this);
|
||||
|
||||
this._resetSelected(newOption, isInit);
|
||||
|
||||
var categories = this.option.categories;
|
||||
this.resetVisual(function (mappingOption, state) {
|
||||
if (mode === 'categories') {
|
||||
mappingOption.mappingMethod = 'category';
|
||||
mappingOption.categories = zrUtil.clone(categories);
|
||||
}
|
||||
else {
|
||||
mappingOption.mappingMethod = 'piecewise';
|
||||
mappingOption.pieceList = zrUtil.map(this._pieceList, function (piece) {
|
||||
var piece = zrUtil.clone(piece);
|
||||
if (state !== 'inRange') {
|
||||
piece.visual = null;
|
||||
}
|
||||
return piece;
|
||||
});
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
_resetSelected: function (newOption, isInit) {
|
||||
var thisOption = this.option;
|
||||
var pieceList = this._pieceList;
|
||||
|
||||
// Selected do not merge but all override.
|
||||
var selected = (isInit ? thisOption : newOption).selected || {};
|
||||
thisOption.selected = selected;
|
||||
|
||||
// Consider 'not specified' means true.
|
||||
zrUtil.each(pieceList, function (piece, index) {
|
||||
var key = this.getSelectedMapKey(piece);
|
||||
if (!(key in selected)) {
|
||||
selected[key] = true;
|
||||
}
|
||||
}, this);
|
||||
|
||||
if (thisOption.selectedMode === 'single') {
|
||||
// Ensure there is only one selected.
|
||||
var hasSel = false;
|
||||
|
||||
zrUtil.each(pieceList, function (piece, index) {
|
||||
var key = this.getSelectedMapKey(piece);
|
||||
if (selected[key]) {
|
||||
hasSel
|
||||
? (selected[key] = false)
|
||||
: (hasSel = true);
|
||||
}
|
||||
}, this);
|
||||
}
|
||||
// thisOption.selectedMode === 'multiple', default: all selected.
|
||||
},
|
||||
|
||||
/**
|
||||
* @public
|
||||
*/
|
||||
getSelectedMapKey: function (piece) {
|
||||
return this._mode === 'categories'
|
||||
? piece.value + '' : piece.index + '';
|
||||
},
|
||||
|
||||
/**
|
||||
* @public
|
||||
*/
|
||||
getPieceList: function () {
|
||||
return this._pieceList;
|
||||
},
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @return {string}
|
||||
*/
|
||||
_decideMode: function () {
|
||||
var option = this.option;
|
||||
|
||||
return option.pieces && option.pieces.length > 0
|
||||
? 'pieces'
|
||||
: this.option.categories
|
||||
? 'categories'
|
||||
: 'splitNumber';
|
||||
},
|
||||
|
||||
/**
|
||||
* @public
|
||||
* @override
|
||||
*/
|
||||
setSelected: function (selected) {
|
||||
this.option.selected = zrUtil.clone(selected);
|
||||
},
|
||||
|
||||
/**
|
||||
* @public
|
||||
* @override
|
||||
*/
|
||||
getValueState: function (value) {
|
||||
var index = VisualMapping.findPieceIndex(value, this._pieceList);
|
||||
|
||||
return index != null
|
||||
? (this.option.selected[this.getSelectedMapKey(this._pieceList[index])]
|
||||
? 'inRange' : 'outOfRange'
|
||||
)
|
||||
: 'outOfRange';
|
||||
},
|
||||
|
||||
/**
|
||||
* @public
|
||||
* @params {number} pieceIndex piece index in visualMapModel.getPieceList()
|
||||
* @return {Array.<Object>} [{seriesId, dataIndices: <Array.<number>>}, ...]
|
||||
*/
|
||||
findTargetDataIndices: function (pieceIndex) {
|
||||
var result = [];
|
||||
|
||||
this.eachTargetSeries(function (seriesModel) {
|
||||
var dataIndices = [];
|
||||
var data = seriesModel.getData();
|
||||
|
||||
data.each(this.getDataDimension(data), function (value, dataIndex) {
|
||||
// Should always base on model pieceList, because it is order sensitive.
|
||||
var pIdx = VisualMapping.findPieceIndex(value, this._pieceList);
|
||||
pIdx === pieceIndex && dataIndices.push(dataIndex);
|
||||
}, true, this);
|
||||
|
||||
result.push({seriesId: seriesModel.id, dataIndices: dataIndices});
|
||||
}, this);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
/**
|
||||
* Key is this._mode
|
||||
* @type {Object}
|
||||
* @this {module:echarts/component/viusalMap/PiecewiseMode}
|
||||
*/
|
||||
var resetMethods = {
|
||||
|
||||
splitNumber: function () {
|
||||
var thisOption = this.option;
|
||||
var precision = thisOption.precision;
|
||||
var dataExtent = this.getExtent();
|
||||
var splitNumber = thisOption.splitNumber;
|
||||
splitNumber = Math.max(parseInt(splitNumber, 10), 1);
|
||||
thisOption.splitNumber = splitNumber;
|
||||
|
||||
var splitStep = (dataExtent[1] - dataExtent[0]) / splitNumber;
|
||||
// Precision auto-adaption
|
||||
while (+splitStep.toFixed(precision) !== splitStep && precision < 5) {
|
||||
precision++;
|
||||
}
|
||||
thisOption.precision = precision;
|
||||
splitStep = +splitStep.toFixed(precision);
|
||||
|
||||
for (var i = 0, curr = dataExtent[0]; i < splitNumber; i++, curr += splitStep) {
|
||||
var max = i === splitNumber - 1 ? dataExtent[1] : (curr + splitStep);
|
||||
|
||||
this._pieceList.push({
|
||||
text: this.formatValueText([curr, max]),
|
||||
index: i,
|
||||
interval: [curr, max]
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
categories: function () {
|
||||
var thisOption = this.option;
|
||||
zrUtil.each(thisOption.categories, function (cate) {
|
||||
// FIXME category模式也使用pieceList,但在visualMapping中不是使用pieceList。
|
||||
// 是否改一致。
|
||||
this._pieceList.push({
|
||||
text: this.formatValueText(cate, true),
|
||||
value: cate
|
||||
});
|
||||
}, this);
|
||||
|
||||
// See "Order Rule".
|
||||
normalizeReverse(thisOption, this._pieceList);
|
||||
},
|
||||
|
||||
pieces: function () {
|
||||
var thisOption = this.option;
|
||||
zrUtil.each(thisOption.pieces, function (pieceListItem, index) {
|
||||
|
||||
if (!zrUtil.isObject(pieceListItem)) {
|
||||
pieceListItem = {value: pieceListItem};
|
||||
}
|
||||
|
||||
var item = {text: '', index: index};
|
||||
var hasLabel;
|
||||
|
||||
if (pieceListItem.label != null) {
|
||||
item.text = pieceListItem.label;
|
||||
hasLabel = true;
|
||||
}
|
||||
|
||||
if (pieceListItem.hasOwnProperty('value')) {
|
||||
item.value = pieceListItem.value;
|
||||
|
||||
if (!hasLabel) {
|
||||
item.text = this.formatValueText(item.value);
|
||||
}
|
||||
}
|
||||
else {
|
||||
var min = pieceListItem.min;
|
||||
var max = pieceListItem.max;
|
||||
min == null && (min = -Infinity);
|
||||
max == null && (max = Infinity);
|
||||
if (min === max) {
|
||||
// Consider: [{min: 5, max: 5, visual: {...}}, {min: 0, max: 5}],
|
||||
// we use value to lift the priority when min === max
|
||||
item.value = min;
|
||||
}
|
||||
item.interval = [min, max];
|
||||
|
||||
if (!hasLabel) {
|
||||
item.text = this.formatValueText([min, max]);
|
||||
}
|
||||
}
|
||||
|
||||
item.visual = VisualMapping.retrieveVisuals(pieceListItem);
|
||||
|
||||
this._pieceList.push(item);
|
||||
|
||||
}, this);
|
||||
|
||||
// See "Order Rule".
|
||||
normalizeReverse(thisOption, this._pieceList);
|
||||
}
|
||||
};
|
||||
|
||||
function normalizeReverse(thisOption, arr) {
|
||||
var inverse = thisOption.inverse;
|
||||
if (thisOption.orient === 'vertical' ? !inverse : inverse) {
|
||||
arr.reverse();
|
||||
}
|
||||
}
|
||||
|
||||
return PiecewiseModel;
|
||||
});
|
||||
239
vendors/echarts/src/component/visualMap/PiecewiseView.js
vendored
Normal file
239
vendors/echarts/src/component/visualMap/PiecewiseView.js
vendored
Normal file
@@ -0,0 +1,239 @@
|
||||
define(function(require) {
|
||||
|
||||
var VisualMapView = require('./VisualMapView');
|
||||
var zrUtil = require('zrender/core/util');
|
||||
var graphic = require('../../util/graphic');
|
||||
var symbolCreators = require('../../util/symbol');
|
||||
var layout = require('../../util/layout');
|
||||
var helper = require('./helper');
|
||||
|
||||
var PiecewiseVisualMapView = VisualMapView.extend({
|
||||
|
||||
type: 'visualMap.piecewise',
|
||||
|
||||
/**
|
||||
* @protected
|
||||
* @override
|
||||
*/
|
||||
doRender: function () {
|
||||
var thisGroup = this.group;
|
||||
|
||||
thisGroup.removeAll();
|
||||
|
||||
var visualMapModel = this.visualMapModel;
|
||||
var textGap = visualMapModel.get('textGap');
|
||||
var textStyleModel = visualMapModel.textStyleModel;
|
||||
var textFont = textStyleModel.getFont();
|
||||
var textFill = textStyleModel.getTextColor();
|
||||
var itemAlign = this._getItemAlign();
|
||||
var itemSize = visualMapModel.itemSize;
|
||||
|
||||
var viewData = this._getViewData();
|
||||
var showLabel = !viewData.endsText;
|
||||
var showEndsText = !showLabel;
|
||||
|
||||
showEndsText && this._renderEndsText(thisGroup, viewData.endsText[0], itemSize);
|
||||
|
||||
zrUtil.each(viewData.viewPieceList, renderItem, this);
|
||||
|
||||
showEndsText && this._renderEndsText(thisGroup, viewData.endsText[1], itemSize);
|
||||
|
||||
layout.box(
|
||||
visualMapModel.get('orient'), thisGroup, visualMapModel.get('itemGap')
|
||||
);
|
||||
|
||||
this.renderBackground(thisGroup);
|
||||
|
||||
this.positionGroup(thisGroup);
|
||||
|
||||
function renderItem(item) {
|
||||
var piece = item.piece;
|
||||
|
||||
var itemGroup = new graphic.Group();
|
||||
itemGroup.onclick = zrUtil.bind(this._onItemClick, this, piece);
|
||||
|
||||
this._enableHoverLink(itemGroup, item.indexInModelPieceList);
|
||||
|
||||
var representValue = this._getRepresentValue(piece);
|
||||
|
||||
this._createItemSymbol(
|
||||
itemGroup, representValue, [0, 0, itemSize[0], itemSize[1]]
|
||||
);
|
||||
|
||||
if (showLabel) {
|
||||
var visualState = this.visualMapModel.getValueState(representValue);
|
||||
|
||||
itemGroup.add(new graphic.Text({
|
||||
style: {
|
||||
x: itemAlign === 'right' ? -textGap : itemSize[0] + textGap,
|
||||
y: itemSize[1] / 2,
|
||||
text: piece.text,
|
||||
textVerticalAlign: 'middle',
|
||||
textAlign: itemAlign,
|
||||
textFont: textFont,
|
||||
fill: textFill,
|
||||
opacity: visualState === 'outOfRange' ? 0.5 : 1
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
thisGroup.add(itemGroup);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
_enableHoverLink: function (itemGroup, pieceIndex) {
|
||||
itemGroup
|
||||
.on('mouseover', zrUtil.bind(onHoverLink, this, 'highlight'))
|
||||
.on('mouseout', zrUtil.bind(onHoverLink, this, 'downplay'));
|
||||
|
||||
function onHoverLink(method) {
|
||||
var visualMapModel = this.visualMapModel;
|
||||
|
||||
visualMapModel.option.hoverLink && this.api.dispatchAction({
|
||||
type: method,
|
||||
batch: helper.convertDataIndicesToBatch(
|
||||
visualMapModel.findTargetDataIndices(pieceIndex)
|
||||
)
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
_getItemAlign: function () {
|
||||
var visualMapModel = this.visualMapModel;
|
||||
var modelOption = visualMapModel.option;
|
||||
|
||||
if (modelOption.orient === 'vertical') {
|
||||
return helper.getItemAlign(
|
||||
visualMapModel, this.api, visualMapModel.itemSize
|
||||
);
|
||||
}
|
||||
else { // horizontal, most case left unless specifying right.
|
||||
var align = modelOption.align;
|
||||
if (!align || align === 'auto') {
|
||||
align = 'left';
|
||||
}
|
||||
return align;
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
_renderEndsText: function (group, text, itemSize) {
|
||||
if (!text) {
|
||||
return;
|
||||
}
|
||||
|
||||
var itemGroup = new graphic.Group();
|
||||
var textStyleModel = this.visualMapModel.textStyleModel;
|
||||
|
||||
itemGroup.add(new graphic.Text({
|
||||
style: {
|
||||
x: itemSize[0] / 2,
|
||||
y: itemSize[1] / 2,
|
||||
textVerticalAlign: 'middle',
|
||||
textAlign: 'center',
|
||||
text: text,
|
||||
textFont: textStyleModel.getFont(),
|
||||
fill: textStyleModel.getTextColor()
|
||||
}
|
||||
}));
|
||||
|
||||
group.add(itemGroup);
|
||||
},
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @return {Object} {peiceList, endsText} The order is the same as screen pixel order.
|
||||
*/
|
||||
_getViewData: function () {
|
||||
var visualMapModel = this.visualMapModel;
|
||||
|
||||
var viewPieceList = zrUtil.map(visualMapModel.getPieceList(), function (piece, index) {
|
||||
return {piece: piece, indexInModelPieceList: index};
|
||||
});
|
||||
var endsText = visualMapModel.get('text');
|
||||
|
||||
// Consider orient and inverse.
|
||||
var orient = visualMapModel.get('orient');
|
||||
var inverse = visualMapModel.get('inverse');
|
||||
|
||||
// Order of model pieceList is always [low, ..., high]
|
||||
if (orient === 'horizontal' ? inverse : !inverse) {
|
||||
viewPieceList.reverse();
|
||||
}
|
||||
// Origin order of endsText is [high, low]
|
||||
else if (endsText) {
|
||||
endsText = endsText.slice().reverse();
|
||||
}
|
||||
|
||||
return {viewPieceList: viewPieceList, endsText: endsText};
|
||||
},
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
_getRepresentValue: function (piece) {
|
||||
var representValue;
|
||||
if (this.visualMapModel.isCategory()) {
|
||||
representValue = piece.value;
|
||||
}
|
||||
else {
|
||||
if (piece.value != null) {
|
||||
representValue = piece.value;
|
||||
}
|
||||
else {
|
||||
var pieceInterval = piece.interval || [];
|
||||
representValue = (pieceInterval[0] + pieceInterval[1]) / 2;
|
||||
}
|
||||
}
|
||||
return representValue;
|
||||
},
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
_createItemSymbol: function (group, representValue, shapeParam) {
|
||||
group.add(symbolCreators.createSymbol(
|
||||
this.getControllerVisual(representValue, 'symbol'),
|
||||
shapeParam[0], shapeParam[1], shapeParam[2], shapeParam[3],
|
||||
this.getControllerVisual(representValue, 'color')
|
||||
));
|
||||
},
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
_onItemClick: function (piece) {
|
||||
var visualMapModel = this.visualMapModel;
|
||||
var option = visualMapModel.option;
|
||||
var selected = zrUtil.clone(option.selected);
|
||||
var newKey = visualMapModel.getSelectedMapKey(piece);
|
||||
|
||||
if (option.selectedMode === 'single') {
|
||||
selected[newKey] = true;
|
||||
zrUtil.each(selected, function (o, key) {
|
||||
selected[key] = key === newKey;
|
||||
});
|
||||
}
|
||||
else {
|
||||
selected[newKey] = !selected[newKey];
|
||||
}
|
||||
|
||||
this.api.dispatchAction({
|
||||
type: 'selectDataRange',
|
||||
from: this.uid,
|
||||
visualMapId: this.visualMapModel.id,
|
||||
selected: selected
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
return PiecewiseVisualMapView;
|
||||
});
|
||||
539
vendors/echarts/src/component/visualMap/VisualMapModel.js
vendored
Normal file
539
vendors/echarts/src/component/visualMap/VisualMapModel.js
vendored
Normal file
@@ -0,0 +1,539 @@
|
||||
/**
|
||||
* @file Data zoom model
|
||||
*/
|
||||
define(function(require) {
|
||||
|
||||
var zrUtil = require('zrender/core/util');
|
||||
var env = require('zrender/core/env');
|
||||
var echarts = require('../../echarts');
|
||||
var modelUtil = require('../../util/model');
|
||||
var visualDefault = require('../../visual/visualDefault');
|
||||
var VisualMapping = require('../../visual/VisualMapping');
|
||||
var mapVisual = VisualMapping.mapVisual;
|
||||
var eachVisual = VisualMapping.eachVisual;
|
||||
var numberUtil = require('../../util/number');
|
||||
var isArray = zrUtil.isArray;
|
||||
var each = zrUtil.each;
|
||||
var asc = numberUtil.asc;
|
||||
var linearMap = numberUtil.linearMap;
|
||||
|
||||
var VisualMapModel = echarts.extendComponentModel({
|
||||
|
||||
type: 'visualMap',
|
||||
|
||||
dependencies: ['series'],
|
||||
|
||||
/**
|
||||
* [lowerBound, upperBound]
|
||||
*
|
||||
* @readOnly
|
||||
* @type {Array.<number>}
|
||||
*/
|
||||
dataBound: [-Infinity, Infinity],
|
||||
|
||||
/**
|
||||
* @readOnly
|
||||
* @type {Array.<string>}
|
||||
*/
|
||||
stateList: ['inRange', 'outOfRange'],
|
||||
|
||||
/**
|
||||
* @readOnly
|
||||
* @type {string|Object}
|
||||
*/
|
||||
layoutMode: {type: 'box', ignoreSize: true},
|
||||
|
||||
/**
|
||||
* @protected
|
||||
*/
|
||||
defaultOption: {
|
||||
show: true,
|
||||
|
||||
zlevel: 0,
|
||||
z: 4,
|
||||
|
||||
// set min: 0, max: 200, only for campatible with ec2.
|
||||
// In fact min max should not have default value.
|
||||
min: 0, // min value, must specified if pieces is not specified.
|
||||
max: 200, // max value, must specified if pieces is not specified.
|
||||
|
||||
dimension: null,
|
||||
inRange: null, // 'color', 'colorHue', 'colorSaturation', 'colorLightness', 'colorAlpha',
|
||||
// 'symbol', 'symbolSize'
|
||||
outOfRange: null, // 'color', 'colorHue', 'colorSaturation',
|
||||
// 'colorLightness', 'colorAlpha',
|
||||
// 'symbol', 'symbolSize'
|
||||
|
||||
left: 0, // 'center' ¦ 'left' ¦ 'right' ¦ {number} (px)
|
||||
right: null, // The same as left.
|
||||
top: null, // 'top' ¦ 'bottom' ¦ 'center' ¦ {number} (px)
|
||||
bottom: 0, // The same as top.
|
||||
|
||||
itemWidth: null,
|
||||
itemHeight: null,
|
||||
inverse: false,
|
||||
orient: 'vertical', // 'horizontal' ¦ 'vertical'
|
||||
|
||||
seriesIndex: null, // 所控制的series indices,默认所有有value的series.
|
||||
backgroundColor: 'rgba(0,0,0,0)',
|
||||
borderColor: '#ccc', // 值域边框颜色
|
||||
contentColor: '#5793f3',
|
||||
inactiveColor: '#aaa',
|
||||
borderWidth: 0, // 值域边框线宽,单位px,默认为0(无边框)
|
||||
padding: 5, // 值域内边距,单位px,默认各方向内边距为5,
|
||||
// 接受数组分别设定上右下左边距,同css
|
||||
textGap: 10, //
|
||||
precision: 0, // 小数精度,默认为0,无小数点
|
||||
color: ['#bf444c', '#d88273', '#f6efa6'], //颜色(deprecated,兼容ec2,顺序同pieces,不同于inRange/outOfRange)
|
||||
|
||||
formatter: null,
|
||||
text: null, // 文本,如['高', '低'],兼容ec2,text[0]对应高值,text[1]对应低值
|
||||
textStyle: {
|
||||
color: '#333' // 值域文字颜色
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* @protected
|
||||
*/
|
||||
init: function (option, parentModel, ecModel) {
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {Array.<number>}
|
||||
*/
|
||||
this._dataExtent;
|
||||
|
||||
/**
|
||||
* @readOnly
|
||||
*/
|
||||
this.controllerVisuals = {};
|
||||
|
||||
/**
|
||||
* @readOnly
|
||||
*/
|
||||
this.targetVisuals = {};
|
||||
|
||||
/**
|
||||
* @readOnly
|
||||
*/
|
||||
this.textStyleModel;
|
||||
|
||||
/**
|
||||
* [width, height]
|
||||
* @readOnly
|
||||
* @type {Array.<number>}
|
||||
*/
|
||||
this.itemSize;
|
||||
|
||||
this.mergeDefaultAndTheme(option, ecModel);
|
||||
|
||||
this.doMergeOption({}, true);
|
||||
},
|
||||
|
||||
/**
|
||||
* @public
|
||||
*/
|
||||
mergeOption: function (option) {
|
||||
VisualMapModel.superApply(this, 'mergeOption', arguments);
|
||||
this.doMergeOption(option, false);
|
||||
},
|
||||
|
||||
/**
|
||||
* @protected
|
||||
*/
|
||||
doMergeOption: function (newOption, isInit) {
|
||||
var thisOption = this.option;
|
||||
|
||||
!isInit && replaceVisualOption(thisOption, newOption);
|
||||
|
||||
// FIXME
|
||||
// necessary?
|
||||
// Disable realtime view update if canvas is not supported.
|
||||
if (!env.canvasSupported) {
|
||||
thisOption.realtime = false;
|
||||
}
|
||||
|
||||
this.textStyleModel = this.getModel('textStyle');
|
||||
|
||||
this.resetItemSize();
|
||||
|
||||
this.completeVisualOption();
|
||||
},
|
||||
|
||||
/**
|
||||
* @example
|
||||
* this.formatValueText(someVal); // format single numeric value to text.
|
||||
* this.formatValueText(someVal, true); // format single category value to text.
|
||||
* this.formatValueText([min, max]); // format numeric min-max to text.
|
||||
* this.formatValueText([this.dataBound[0], max]); // using data lower bound.
|
||||
* this.formatValueText([min, this.dataBound[1]]); // using data upper bound.
|
||||
*
|
||||
* @param {number|Array.<number>} value Real value, or this.dataBound[0 or 1].
|
||||
* @param {boolean} [isCategory=false] Only available when value is number.
|
||||
* @return {string}
|
||||
* @protected
|
||||
*/
|
||||
formatValueText: function(value, isCategory) {
|
||||
var option = this.option;
|
||||
var precision = option.precision;
|
||||
var dataBound = this.dataBound;
|
||||
var formatter = option.formatter;
|
||||
var isMinMax;
|
||||
var textValue;
|
||||
|
||||
if (zrUtil.isArray(value)) {
|
||||
value = value.slice();
|
||||
isMinMax = true;
|
||||
}
|
||||
|
||||
textValue = isCategory
|
||||
? value
|
||||
: (isMinMax
|
||||
? [toFixed(value[0]), toFixed(value[1])]
|
||||
: toFixed(value)
|
||||
);
|
||||
|
||||
if (zrUtil.isString(formatter)) {
|
||||
return formatter
|
||||
.replace('{value}', isMinMax ? textValue[0] : textValue)
|
||||
.replace('{value2}', isMinMax ? textValue[1] : textValue);
|
||||
}
|
||||
else if (zrUtil.isFunction(formatter)) {
|
||||
return isMinMax
|
||||
? formatter(value[0], value[1])
|
||||
: formatter(value);
|
||||
}
|
||||
|
||||
if (isMinMax) {
|
||||
if (value[0] === dataBound[0]) {
|
||||
return '< ' + textValue[1];
|
||||
}
|
||||
else if (value[1] === dataBound[1]) {
|
||||
return '> ' + textValue[0];
|
||||
}
|
||||
else {
|
||||
return textValue[0] + ' - ' + textValue[1];
|
||||
}
|
||||
}
|
||||
else { // Format single value (includes category case).
|
||||
return textValue;
|
||||
}
|
||||
|
||||
function toFixed(val) {
|
||||
return val === dataBound[0]
|
||||
? 'min'
|
||||
: val === dataBound[1]
|
||||
? 'max'
|
||||
: (+val).toFixed(precision);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* @protected
|
||||
*/
|
||||
resetTargetSeries: function (newOption, isInit) {
|
||||
var thisOption = this.option;
|
||||
var allSeriesIndex = thisOption.seriesIndex == null;
|
||||
thisOption.seriesIndex = allSeriesIndex
|
||||
? [] : modelUtil.normalizeToArray(thisOption.seriesIndex);
|
||||
|
||||
allSeriesIndex && this.ecModel.eachSeries(function (seriesModel, index) {
|
||||
var data = seriesModel.getData();
|
||||
// FIXME
|
||||
// 只考虑了list,还没有考虑map等。
|
||||
|
||||
// FIXME
|
||||
// 这里可能应该这么判断:data.dimensions中有超出其所属coordSystem的量。
|
||||
if (data.type === 'list') {
|
||||
thisOption.seriesIndex.push(index);
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* @protected
|
||||
*/
|
||||
resetExtent: function () {
|
||||
var thisOption = this.option;
|
||||
|
||||
// Can not calculate data extent by data here.
|
||||
// Because series and data may be modified in processing stage.
|
||||
// So we do not support the feature "auto min/max".
|
||||
|
||||
var extent = asc([thisOption.min, thisOption.max]);
|
||||
|
||||
this._dataExtent = extent;
|
||||
},
|
||||
|
||||
/**
|
||||
* @protected
|
||||
*/
|
||||
getDataDimension: function (list) {
|
||||
var optDim = this.option.dimension;
|
||||
return optDim != null
|
||||
? optDim : list.dimensions.length - 1;
|
||||
},
|
||||
|
||||
/**
|
||||
* @public
|
||||
* @override
|
||||
*/
|
||||
getExtent: function () {
|
||||
return this._dataExtent.slice();
|
||||
},
|
||||
|
||||
/**
|
||||
* @protected
|
||||
*/
|
||||
resetVisual: function (fillVisualOption) {
|
||||
var dataExtent = this.getExtent();
|
||||
|
||||
doReset.call(this, 'controller', this.controllerVisuals);
|
||||
doReset.call(this, 'target', this.targetVisuals);
|
||||
|
||||
function doReset(baseAttr, visualMappings) {
|
||||
each(this.stateList, function (state) {
|
||||
|
||||
var mappings = visualMappings[state] || (
|
||||
visualMappings[state] = createMappings()
|
||||
);
|
||||
var visaulOption = this.option[baseAttr][state] || {};
|
||||
|
||||
each(visaulOption, function (visualData, visualType) {
|
||||
if (!VisualMapping.isValidType(visualType)) {
|
||||
return;
|
||||
}
|
||||
var mappingOption = {
|
||||
type: visualType,
|
||||
dataExtent: dataExtent,
|
||||
visual: visualData
|
||||
};
|
||||
fillVisualOption && fillVisualOption.call(this, mappingOption, state);
|
||||
mappings[visualType] = new VisualMapping(mappingOption);
|
||||
|
||||
// Prepare a alpha for opacity, for some case that opacity
|
||||
// is not supported, such as rendering using gradient color.
|
||||
if (baseAttr === 'controller' && visualType === 'opacity') {
|
||||
mappingOption = zrUtil.clone(mappingOption);
|
||||
mappingOption.type = 'colorAlpha';
|
||||
mappings.__hidden.__alphaForOpacity = new VisualMapping(mappingOption);
|
||||
}
|
||||
}, this);
|
||||
}, this);
|
||||
}
|
||||
|
||||
function createMappings() {
|
||||
var Creater = function () {};
|
||||
// Make sure hidden fields will not be visited by
|
||||
// object iteration (with hasOwnProperty checking).
|
||||
Creater.prototype.__hidden = Creater.prototype;
|
||||
var obj = new Creater();
|
||||
return obj;
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* @protected
|
||||
*/
|
||||
completeVisualOption: function () {
|
||||
var thisOption = this.option;
|
||||
var base = {inRange: thisOption.inRange, outOfRange: thisOption.outOfRange};
|
||||
|
||||
var target = thisOption.target || (thisOption.target = {});
|
||||
var controller = thisOption.controller || (thisOption.controller = {});
|
||||
|
||||
zrUtil.merge(target, base); // Do not override
|
||||
zrUtil.merge(controller, base); // Do not override
|
||||
|
||||
var isCategory = this.isCategory();
|
||||
|
||||
completeSingle.call(this, target);
|
||||
completeSingle.call(this, controller);
|
||||
completeInactive.call(this, target, 'inRange', 'outOfRange');
|
||||
completeInactive.call(this, target, 'outOfRange', 'inRange');
|
||||
completeController.call(this, controller);
|
||||
|
||||
function completeSingle(base) {
|
||||
// Compatible with ec2 dataRange.color.
|
||||
// The mapping order of dataRange.color is: [high value, ..., low value]
|
||||
// whereas inRange.color and outOfRange.color is [low value, ..., high value]
|
||||
// Notice: ec2 has no inverse.
|
||||
if (isArray(thisOption.color)
|
||||
// If there has been inRange: {symbol: ...}, adding color is a mistake.
|
||||
// So adding color only when no inRange defined.
|
||||
&& !base.inRange
|
||||
) {
|
||||
base.inRange = {color: thisOption.color.slice().reverse()};
|
||||
}
|
||||
|
||||
// If using shortcut like: {inRange: 'symbol'}, complete default value.
|
||||
each(this.stateList, function (state) {
|
||||
var visualType = base[state];
|
||||
|
||||
if (zrUtil.isString(visualType)) {
|
||||
var defa = visualDefault.get(visualType, 'active', isCategory);
|
||||
if (defa) {
|
||||
base[state] = {};
|
||||
base[state][visualType] = defa;
|
||||
}
|
||||
else {
|
||||
// Mark as not specified.
|
||||
delete base[state];
|
||||
}
|
||||
}
|
||||
}, this);
|
||||
}
|
||||
|
||||
function completeInactive(base, stateExist, stateAbsent) {
|
||||
var optExist = base[stateExist];
|
||||
var optAbsent = base[stateAbsent];
|
||||
|
||||
if (optExist && !optAbsent) {
|
||||
optAbsent = base[stateAbsent] = {};
|
||||
each(optExist, function (visualData, visualType) {
|
||||
if (!VisualMapping.isValidType(visualType)) {
|
||||
return;
|
||||
}
|
||||
|
||||
var defa = visualDefault.get(visualType, 'inactive', isCategory);
|
||||
|
||||
if (defa != null) {
|
||||
optAbsent[visualType] = defa;
|
||||
|
||||
// Compatibable with ec2:
|
||||
// Only inactive color to rgba(0,0,0,0) can not
|
||||
// make label transparent, so use opacity also.
|
||||
if (visualType === 'color'
|
||||
&& !optAbsent.hasOwnProperty('opacity')
|
||||
&& !optAbsent.hasOwnProperty('colorAlpha')
|
||||
) {
|
||||
optAbsent.opacity = [0, 0];
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function completeController(controller) {
|
||||
var symbolExists = (controller.inRange || {}).symbol
|
||||
|| (controller.outOfRange || {}).symbol;
|
||||
var symbolSizeExists = (controller.inRange || {}).symbolSize
|
||||
|| (controller.outOfRange || {}).symbolSize;
|
||||
var inactiveColor = this.get('inactiveColor');
|
||||
|
||||
each(this.stateList, function (state) {
|
||||
|
||||
var itemSize = this.itemSize;
|
||||
var visuals = controller[state];
|
||||
|
||||
// Set inactive color for controller if no other color
|
||||
// attr (like colorAlpha) specified.
|
||||
if (!visuals) {
|
||||
visuals = controller[state] = {
|
||||
color: isCategory ? inactiveColor : [inactiveColor]
|
||||
};
|
||||
}
|
||||
|
||||
// Consistent symbol and symbolSize if not specified.
|
||||
if (visuals.symbol == null) {
|
||||
visuals.symbol = symbolExists
|
||||
&& zrUtil.clone(symbolExists)
|
||||
|| (isCategory ? 'roundRect' : ['roundRect']);
|
||||
}
|
||||
if (visuals.symbolSize == null) {
|
||||
visuals.symbolSize = symbolSizeExists
|
||||
&& zrUtil.clone(symbolSizeExists)
|
||||
|| (isCategory ? itemSize[0] : [itemSize[0], itemSize[0]]);
|
||||
}
|
||||
|
||||
// Filter square and none.
|
||||
visuals.symbol = mapVisual(visuals.symbol, function (symbol) {
|
||||
return (symbol === 'none' || symbol === 'square') ? 'roundRect' : symbol;
|
||||
});
|
||||
|
||||
// Normalize symbolSize
|
||||
var symbolSize = visuals.symbolSize;
|
||||
|
||||
if (symbolSize != null) {
|
||||
var max = -Infinity;
|
||||
// symbolSize can be object when categories defined.
|
||||
eachVisual(symbolSize, function (value) {
|
||||
value > max && (max = value);
|
||||
});
|
||||
visuals.symbolSize = mapVisual(symbolSize, function (value) {
|
||||
return linearMap(value, [0, max], [0, itemSize[0]], true);
|
||||
});
|
||||
}
|
||||
|
||||
}, this);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* @public
|
||||
*/
|
||||
eachTargetSeries: function (callback, context) {
|
||||
zrUtil.each(this.option.seriesIndex, function (seriesIndex) {
|
||||
callback.call(context, this.ecModel.getSeriesByIndex(seriesIndex));
|
||||
}, this);
|
||||
},
|
||||
|
||||
/**
|
||||
* @public
|
||||
*/
|
||||
isCategory: function () {
|
||||
return !!this.option.categories;
|
||||
},
|
||||
|
||||
/**
|
||||
* @protected
|
||||
*/
|
||||
resetItemSize: function () {
|
||||
this.itemSize = [
|
||||
parseFloat(this.get('itemWidth')),
|
||||
parseFloat(this.get('itemHeight'))
|
||||
];
|
||||
},
|
||||
|
||||
/**
|
||||
* @public
|
||||
* @abstract
|
||||
*/
|
||||
setSelected: zrUtil.noop,
|
||||
|
||||
/**
|
||||
* @public
|
||||
* @abstract
|
||||
*/
|
||||
getValueState: zrUtil.noop
|
||||
|
||||
});
|
||||
|
||||
function replaceVisualOption(thisOption, newOption) {
|
||||
// Visual attributes merge is not supported, otherwise it
|
||||
// brings overcomplicated merge logic. See #2853. So if
|
||||
// newOption has anyone of these keys, all of these keys
|
||||
// will be reset. Otherwise, all keys remain.
|
||||
var visualKeys = [
|
||||
'inRange', 'outOfRange', 'target', 'controller', 'color'
|
||||
];
|
||||
var has;
|
||||
zrUtil.each(visualKeys, function (key) {
|
||||
if (newOption.hasOwnProperty(key)) {
|
||||
has = true;
|
||||
}
|
||||
});
|
||||
has && zrUtil.each(visualKeys, function (key) {
|
||||
if (newOption.hasOwnProperty(key)) {
|
||||
thisOption[key] = zrUtil.clone(newOption[key]);
|
||||
}
|
||||
else {
|
||||
delete thisOption[key];
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return VisualMapModel;
|
||||
|
||||
});
|
||||
161
vendors/echarts/src/component/visualMap/VisualMapView.js
vendored
Normal file
161
vendors/echarts/src/component/visualMap/VisualMapView.js
vendored
Normal file
@@ -0,0 +1,161 @@
|
||||
define(function (require) {
|
||||
|
||||
var echarts = require('../../echarts');
|
||||
var zrUtil = require('zrender/core/util');
|
||||
var graphic = require('../../util/graphic');
|
||||
var formatUtil = require('../../util/format');
|
||||
var layout = require('../../util/layout');
|
||||
var VisualMapping = require('../../visual/VisualMapping');
|
||||
|
||||
return echarts.extendComponentView({
|
||||
|
||||
type: 'visualMap',
|
||||
|
||||
/**
|
||||
* @readOnly
|
||||
* @type {Object}
|
||||
*/
|
||||
autoPositionValues: {left: 1, right: 1, top: 1, bottom: 1},
|
||||
|
||||
init: function (ecModel, api) {
|
||||
/**
|
||||
* @readOnly
|
||||
* @type {module:echarts/model/Global}
|
||||
*/
|
||||
this.ecModel = ecModel;
|
||||
|
||||
/**
|
||||
* @readOnly
|
||||
* @type {module:echarts/ExtensionAPI}
|
||||
*/
|
||||
this.api = api;
|
||||
|
||||
/**
|
||||
* @readOnly
|
||||
* @type {module:echarts/component/visualMap/visualMapModel}
|
||||
*/
|
||||
this.visualMapModel;
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {Object}
|
||||
*/
|
||||
this._updatableShapes = {};
|
||||
},
|
||||
|
||||
/**
|
||||
* @protected
|
||||
*/
|
||||
render: function (visualMapModel, ecModel, api, payload) {
|
||||
this.visualMapModel = visualMapModel;
|
||||
|
||||
if (visualMapModel.get('show') === false) {
|
||||
this.group.removeAll();
|
||||
return;
|
||||
}
|
||||
|
||||
this.doRender.apply(this, arguments);
|
||||
},
|
||||
|
||||
/**
|
||||
* @protected
|
||||
*/
|
||||
renderBackground: function (group) {
|
||||
var visualMapModel = this.visualMapModel;
|
||||
var padding = formatUtil.normalizeCssArray(visualMapModel.get('padding') || 0);
|
||||
var rect = group.getBoundingRect();
|
||||
|
||||
group.add(new graphic.Rect({
|
||||
z2: -1, // Lay background rect on the lowest layer.
|
||||
silent: true,
|
||||
shape: {
|
||||
x: rect.x - padding[3],
|
||||
y: rect.y - padding[0],
|
||||
width: rect.width + padding[3] + padding[1],
|
||||
height: rect.height + padding[0] + padding[2]
|
||||
},
|
||||
style: {
|
||||
fill: visualMapModel.get('backgroundColor'),
|
||||
stroke: visualMapModel.get('borderColor'),
|
||||
lineWidth: visualMapModel.get('borderWidth')
|
||||
}
|
||||
}));
|
||||
},
|
||||
|
||||
/**
|
||||
* @protected
|
||||
* @param {number} targetValue
|
||||
* @param {string=} visualCluster Only can be 'color' 'opacity' 'symbol' 'symbolSize'
|
||||
* @param {Object} [opts]
|
||||
* @param {string=} [opts.forceState] Specify state, instead of using getValueState method.
|
||||
* @param {string=} [opts.convertOpacityToAlpha=false] For color gradient in controller widget.
|
||||
* @return {*} Visual value.
|
||||
*/
|
||||
getControllerVisual: function (targetValue, visualCluster, opts) {
|
||||
opts = opts || {};
|
||||
|
||||
var forceState = opts.forceState;
|
||||
var visualMapModel = this.visualMapModel;
|
||||
var visualObj = {};
|
||||
|
||||
// Default values.
|
||||
if (visualCluster === 'symbol') {
|
||||
visualObj.symbol = visualMapModel.get('itemSymbol');
|
||||
}
|
||||
if (visualCluster === 'color') {
|
||||
var defaultColor = visualMapModel.get('contentColor');
|
||||
visualObj.color = defaultColor;
|
||||
}
|
||||
|
||||
function getter(key) {
|
||||
return visualObj[key];
|
||||
}
|
||||
|
||||
function setter(key, value) {
|
||||
visualObj[key] = value;
|
||||
}
|
||||
|
||||
var mappings = visualMapModel.controllerVisuals[
|
||||
forceState || visualMapModel.getValueState(targetValue)
|
||||
];
|
||||
var visualTypes = VisualMapping.prepareVisualTypes(mappings);
|
||||
|
||||
zrUtil.each(visualTypes, function (type) {
|
||||
var visualMapping = mappings[type];
|
||||
if (opts.convertOpacityToAlpha && type === 'opacity') {
|
||||
type = 'colorAlpha';
|
||||
visualMapping = mappings.__alphaForOpacity;
|
||||
}
|
||||
if (VisualMapping.dependsOn(type, visualCluster)) {
|
||||
visualMapping && visualMapping.applyVisual(
|
||||
targetValue, getter, setter
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
return visualObj[visualCluster];
|
||||
},
|
||||
|
||||
/**
|
||||
* @protected
|
||||
*/
|
||||
positionGroup: function (group) {
|
||||
var model = this.visualMapModel;
|
||||
var api = this.api;
|
||||
|
||||
layout.positionGroup(
|
||||
group,
|
||||
model.getBoxLayoutParams(),
|
||||
{width: api.getWidth(), height: api.getHeight()}
|
||||
);
|
||||
},
|
||||
|
||||
/**
|
||||
* @protected
|
||||
* @abstract
|
||||
*/
|
||||
doRender: zrUtil.noop
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
86
vendors/echarts/src/component/visualMap/helper.js
vendored
Normal file
86
vendors/echarts/src/component/visualMap/helper.js
vendored
Normal file
@@ -0,0 +1,86 @@
|
||||
define(function(require) {
|
||||
|
||||
var layout = require('../../util/layout');
|
||||
var zrUtil = require('zrender/core/util');
|
||||
var DataDiffer = require('../../data/DataDiffer');
|
||||
|
||||
var helper = {
|
||||
|
||||
/**
|
||||
* @param {module:echarts/component/visualMap/VisualMapModel} visualMapModel\
|
||||
* @param {module:echarts/ExtensionAPI} api
|
||||
* @param {Array.<number>} itemSize always [short, long]
|
||||
* @return {string} 'left' or 'right' or 'top' or 'bottom'
|
||||
*/
|
||||
getItemAlign: function (visualMapModel, api, itemSize) {
|
||||
var modelOption = visualMapModel.option;
|
||||
var itemAlign = modelOption.align;
|
||||
|
||||
if (itemAlign != null && itemAlign !== 'auto') {
|
||||
return itemAlign;
|
||||
}
|
||||
|
||||
// Auto decision align.
|
||||
var ecSize = {width: api.getWidth(), height: api.getHeight()};
|
||||
var realIndex = modelOption.orient === 'horizontal' ? 1 : 0;
|
||||
|
||||
var paramsSet = [
|
||||
['left', 'right', 'width'],
|
||||
['top', 'bottom', 'height']
|
||||
];
|
||||
var reals = paramsSet[realIndex];
|
||||
var fakeValue = [0, null, 10];
|
||||
|
||||
var layoutInput = {};
|
||||
for (var i = 0; i < 3; i++) {
|
||||
layoutInput[paramsSet[1 - realIndex][i]] = fakeValue[i];
|
||||
layoutInput[reals[i]] = i === 2 ? itemSize[0] : modelOption[reals[i]];
|
||||
}
|
||||
|
||||
var rParam = [['x', 'width', 3], ['y', 'height', 0]][realIndex];
|
||||
var rect = layout.getLayoutRect(layoutInput, ecSize, modelOption.padding);
|
||||
|
||||
return reals[
|
||||
(rect.margin[rParam[2]] || 0) + rect[rParam[0]] + rect[rParam[1]] * 0.5
|
||||
< ecSize[rParam[1]] * 0.5 ? 0 : 1
|
||||
];
|
||||
},
|
||||
|
||||
convertDataIndicesToBatch: function (dataIndicesBySeries) {
|
||||
var batch = [];
|
||||
zrUtil.each(dataIndicesBySeries, function (item) {
|
||||
zrUtil.each(item.dataIndices, function (dataIndex) {
|
||||
batch.push({seriesId: item.seriesId, dataIndex: dataIndex});
|
||||
});
|
||||
});
|
||||
return batch;
|
||||
},
|
||||
|
||||
removeDuplicateBatch: function (batchA, batchB) {
|
||||
var result = [[], []];
|
||||
|
||||
(new DataDiffer(batchA, batchB, getKey, getKey))
|
||||
.add(add)
|
||||
.update(zrUtil.noop)
|
||||
.remove(remove)
|
||||
.execute();
|
||||
|
||||
function getKey(item) {
|
||||
return item.seriesId + '-' + item.dataIndex;
|
||||
}
|
||||
|
||||
function add(index) {
|
||||
result[1].push(batchB[index]);
|
||||
}
|
||||
|
||||
function remove(index) {
|
||||
result[0].push(batchA[index]);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
return helper;
|
||||
});
|
||||
47
vendors/echarts/src/component/visualMap/preprocessor.js
vendored
Normal file
47
vendors/echarts/src/component/visualMap/preprocessor.js
vendored
Normal file
@@ -0,0 +1,47 @@
|
||||
/**
|
||||
* @file VisualMap preprocessor
|
||||
*/
|
||||
define(function(require) {
|
||||
|
||||
var zrUtil = require('zrender/core/util');
|
||||
var each = zrUtil.each;
|
||||
|
||||
return function (option) {
|
||||
var visualMap = option && option.visualMap;
|
||||
|
||||
if (!zrUtil.isArray(visualMap)) {
|
||||
visualMap = visualMap ? [visualMap] : [];
|
||||
}
|
||||
|
||||
each(visualMap, function (opt) {
|
||||
if (!opt) {
|
||||
return;
|
||||
}
|
||||
|
||||
// rename splitList to pieces
|
||||
if (has(opt, 'splitList') && !has(opt, 'pieces')) {
|
||||
opt.pieces = opt.splitList;
|
||||
delete opt.splitList;
|
||||
}
|
||||
|
||||
var pieces = opt.pieces;
|
||||
if (pieces && zrUtil.isArray(pieces)) {
|
||||
each(pieces, function (piece) {
|
||||
if (zrUtil.isObject(piece)) {
|
||||
if (has(piece, 'start') && !has(piece, 'min')) {
|
||||
piece.min = piece.start;
|
||||
}
|
||||
if (has(piece, 'end') && !has(piece, 'max')) {
|
||||
piece.max = piece.end;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
function has(obj, name) {
|
||||
return obj && obj.hasOwnProperty && obj.hasOwnProperty(name);
|
||||
}
|
||||
|
||||
});
|
||||
19
vendors/echarts/src/component/visualMap/typeDefaulter.js
vendored
Normal file
19
vendors/echarts/src/component/visualMap/typeDefaulter.js
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
define(function (require) {
|
||||
|
||||
require('../../model/Component').registerSubTypeDefaulter('visualMap', function (option) {
|
||||
// Compatible with ec2, when splitNumber === 0, continuous visualMap will be used.
|
||||
return (
|
||||
!option.categories
|
||||
&& (
|
||||
!(
|
||||
option.pieces
|
||||
? option.pieces.length > 0
|
||||
: option.splitNumber > 0
|
||||
)
|
||||
|| option.calculable
|
||||
)
|
||||
)
|
||||
? 'continuous' : 'piecewise';
|
||||
});
|
||||
|
||||
});
|
||||
51
vendors/echarts/src/component/visualMap/visualCoding.js
vendored
Normal file
51
vendors/echarts/src/component/visualMap/visualCoding.js
vendored
Normal file
@@ -0,0 +1,51 @@
|
||||
/**
|
||||
* @file Data range visual coding.
|
||||
*/
|
||||
define(function (require) {
|
||||
|
||||
var echarts = require('../../echarts');
|
||||
var VisualMapping = require('../../visual/VisualMapping');
|
||||
var zrUtil = require('zrender/core/util');
|
||||
|
||||
echarts.registerVisualCoding('component', function (ecModel) {
|
||||
ecModel.eachComponent('visualMap', function (visualMapModel) {
|
||||
processSingleVisualMap(visualMapModel, ecModel);
|
||||
});
|
||||
});
|
||||
|
||||
function processSingleVisualMap(visualMapModel, ecModel) {
|
||||
var visualMappings = visualMapModel.targetVisuals;
|
||||
var visualTypesMap = {};
|
||||
zrUtil.each(['inRange', 'outOfRange'], function (state) {
|
||||
var visualTypes = VisualMapping.prepareVisualTypes(visualMappings[state]);
|
||||
visualTypesMap[state] = visualTypes;
|
||||
});
|
||||
|
||||
visualMapModel.eachTargetSeries(function (seriesModel) {
|
||||
var data = seriesModel.getData();
|
||||
var dimension = visualMapModel.getDataDimension(data);
|
||||
var dataIndex;
|
||||
|
||||
function getVisual(key) {
|
||||
return data.getItemVisual(dataIndex, key);
|
||||
}
|
||||
|
||||
function setVisual(key, value) {
|
||||
data.setItemVisual(dataIndex, key, value);
|
||||
}
|
||||
|
||||
data.each([dimension], function (value, index) {
|
||||
// For performance consideration, do not use curry.
|
||||
dataIndex = index;
|
||||
var valueState = visualMapModel.getValueState(value);
|
||||
var mappings = visualMappings[valueState];
|
||||
var visualTypes = visualTypesMap[valueState];
|
||||
for (var i = 0, len = visualTypes.length; i < len; i++) {
|
||||
var type = visualTypes[i];
|
||||
mappings[type] && mappings[type].applyVisual(value, getVisual, setVisual);
|
||||
}
|
||||
}, true);
|
||||
});
|
||||
}
|
||||
|
||||
});
|
||||
23
vendors/echarts/src/component/visualMap/visualMapAction.js
vendored
Normal file
23
vendors/echarts/src/component/visualMap/visualMapAction.js
vendored
Normal file
@@ -0,0 +1,23 @@
|
||||
/**
|
||||
* @file Data range action
|
||||
*/
|
||||
define(function(require) {
|
||||
|
||||
var echarts = require('../../echarts');
|
||||
|
||||
var actionInfo = {
|
||||
type: 'selectDataRange',
|
||||
event: 'dataRangeSelected',
|
||||
// FIXME use updateView appears wrong
|
||||
update: 'update'
|
||||
};
|
||||
|
||||
echarts.registerAction(actionInfo, function (payload, ecModel) {
|
||||
|
||||
ecModel.eachComponent({mainType: 'visualMap', query: payload}, function (model) {
|
||||
model.setSelected(payload.selected);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
16
vendors/echarts/src/component/visualMapContinuous.js
vendored
Normal file
16
vendors/echarts/src/component/visualMapContinuous.js
vendored
Normal file
@@ -0,0 +1,16 @@
|
||||
/**
|
||||
* DataZoom component entry
|
||||
*/
|
||||
define(function (require) {
|
||||
|
||||
require('../echarts').registerPreprocessor(
|
||||
require('./visualMap/preprocessor')
|
||||
);
|
||||
|
||||
require('./visualMap/typeDefaulter');
|
||||
require('./visualMap/visualCoding');
|
||||
require('./visualMap/ContinuousModel');
|
||||
require('./visualMap/ContinuousView');
|
||||
require('./visualMap/visualMapAction');
|
||||
|
||||
});
|
||||
16
vendors/echarts/src/component/visualMapPiecewise.js
vendored
Normal file
16
vendors/echarts/src/component/visualMapPiecewise.js
vendored
Normal file
@@ -0,0 +1,16 @@
|
||||
/**
|
||||
* DataZoom component entry
|
||||
*/
|
||||
define(function (require) {
|
||||
|
||||
require('../echarts').registerPreprocessor(
|
||||
require('./visualMap/preprocessor')
|
||||
);
|
||||
|
||||
require('./visualMap/typeDefaulter');
|
||||
require('./visualMap/visualCoding');
|
||||
require('./visualMap/PiecewiseModel');
|
||||
require('./visualMap/PiecewiseView');
|
||||
require('./visualMap/visualMapAction');
|
||||
|
||||
});
|
||||
Reference in New Issue
Block a user