625 lines
18 KiB
JavaScript
625 lines
18 KiB
JavaScript
/**
|
||
* echarts图表动画基类
|
||
*
|
||
* @desc echarts基于Canvas,纯Javascript图表库,提供直观,生动,可交互,可个性化定制的数据统计图表。
|
||
* @author Kener (@Kener-林峰, kener.linfeng@gmail.com)
|
||
*
|
||
*/
|
||
define(function (require) {
|
||
var zrUtil = require('zrender/tool/util');
|
||
var curveTool = require('zrender/tool/curve');
|
||
|
||
/**
|
||
* 折线型动画
|
||
*
|
||
* @param {ZRender} zr
|
||
* @param {shape} oldShape
|
||
* @param {shape} newShape
|
||
* @param {number} duration
|
||
* @param {tring} easing
|
||
*/
|
||
function pointList(zr, oldShape, newShape, duration, easing) {
|
||
var newPointList = newShape.style.pointList;
|
||
var newPointListLen = newPointList.length;
|
||
var oldPointList;
|
||
|
||
if (!oldShape) { // add
|
||
oldPointList = [];
|
||
if (newShape._orient != 'vertical') {
|
||
var y = newPointList[0][1];
|
||
for (var i = 0; i < newPointListLen; i++) {
|
||
oldPointList[i] = [newPointList[i][0], y];
|
||
}
|
||
}
|
||
else {
|
||
var x = newPointList[0][0];
|
||
for (var i = 0; i < newPointListLen; i++) {
|
||
oldPointList[i] = [x, newPointList[i][1]];
|
||
}
|
||
}
|
||
|
||
if (newShape.type == 'half-smooth-polygon') {
|
||
oldPointList[newPointListLen - 1] = zrUtil.clone(newPointList[newPointListLen - 1]);
|
||
oldPointList[newPointListLen - 2] = zrUtil.clone(newPointList[newPointListLen - 2]);
|
||
}
|
||
oldShape = {style : {pointList : oldPointList}};
|
||
}
|
||
|
||
oldPointList = oldShape.style.pointList;
|
||
var oldPointListLen = oldPointList.length;
|
||
if (oldPointListLen == newPointListLen) {
|
||
newShape.style.pointList = oldPointList;
|
||
}
|
||
else if (oldPointListLen < newPointListLen) {
|
||
// 原来短,新的长,补全
|
||
newShape.style.pointList = oldPointList.concat(newPointList.slice(oldPointListLen));
|
||
}
|
||
else {
|
||
// 原来长,新的短,截断
|
||
newShape.style.pointList = oldPointList.slice(0, newPointListLen);
|
||
}
|
||
|
||
zr.addShape(newShape);
|
||
newShape.__animating = true;
|
||
zr.animate(newShape.id, 'style')
|
||
.when(
|
||
duration,
|
||
{ pointList: newPointList }
|
||
)
|
||
.during(function () {
|
||
// Updating bezier points
|
||
if (newShape.updateControlPoints) {
|
||
newShape.updateControlPoints(newShape.style);
|
||
}
|
||
})
|
||
.done(function() {
|
||
newShape.__animating = false;
|
||
})
|
||
.start(easing);
|
||
}
|
||
|
||
/**
|
||
* 复制样式
|
||
*
|
||
* @inner
|
||
* @param {Object} target 目标对象
|
||
* @param {Object} source 源对象
|
||
* @param {...string} props 复制的属性列表
|
||
*/
|
||
function cloneStyle(target, source) {
|
||
var len = arguments.length;
|
||
for (var i = 2; i < len; i++) {
|
||
var prop = arguments[i];
|
||
target.style[prop] = source.style[prop];
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 方型动画
|
||
*
|
||
* @param {ZRender} zr
|
||
* @param {shape} oldShape
|
||
* @param {shape} newShape
|
||
* @param {number} duration
|
||
* @param {tring} easing
|
||
*/
|
||
function rectangle(zr, oldShape, newShape, duration, easing) {
|
||
var newShapeStyle = newShape.style;
|
||
if (!oldShape) { // add
|
||
oldShape = {
|
||
position : newShape.position,
|
||
style : {
|
||
x : newShapeStyle.x,
|
||
y : newShape._orient == 'vertical'
|
||
? newShapeStyle.y + newShapeStyle.height
|
||
: newShapeStyle.y,
|
||
width: newShape._orient == 'vertical'
|
||
? newShapeStyle.width : 0,
|
||
height: newShape._orient != 'vertical'
|
||
? newShapeStyle.height : 0
|
||
}
|
||
};
|
||
}
|
||
|
||
var newX = newShapeStyle.x;
|
||
var newY = newShapeStyle.y;
|
||
var newWidth = newShapeStyle.width;
|
||
var newHeight = newShapeStyle.height;
|
||
var newPosition = [newShape.position[0], newShape.position[1]];
|
||
cloneStyle(
|
||
newShape, oldShape,
|
||
'x', 'y', 'width', 'height'
|
||
);
|
||
newShape.position = oldShape.position;
|
||
|
||
zr.addShape(newShape);
|
||
if (newPosition[0] != oldShape.position[0] || newPosition[1] != oldShape.position[1]) {
|
||
zr.animate(newShape.id, '')
|
||
.when(
|
||
duration,
|
||
{
|
||
position: newPosition
|
||
}
|
||
)
|
||
.start(easing);
|
||
}
|
||
|
||
newShape.__animating = true;
|
||
zr.animate(newShape.id, 'style')
|
||
.when(
|
||
duration,
|
||
{
|
||
x: newX,
|
||
y: newY,
|
||
width: newWidth,
|
||
height: newHeight
|
||
}
|
||
)
|
||
.done(function() {
|
||
newShape.__animating = false;
|
||
})
|
||
.start(easing);
|
||
}
|
||
|
||
/**
|
||
* 蜡烛动画
|
||
*
|
||
* @param {ZRender} zr
|
||
* @param {shape} oldShape
|
||
* @param {shape} newShape
|
||
* @param {number} duration
|
||
* @param {tring} easing
|
||
*/
|
||
function candle(zr, oldShape, newShape, duration, easing) {
|
||
if (!oldShape) { // add
|
||
var y = newShape.style.y;
|
||
oldShape = {style : {y : [y[0], y[0], y[0], y[0]]}};
|
||
}
|
||
|
||
var newY = newShape.style.y;
|
||
newShape.style.y = oldShape.style.y;
|
||
zr.addShape(newShape);
|
||
newShape.__animating = true;
|
||
zr.animate(newShape.id, 'style')
|
||
.when(
|
||
duration,
|
||
{ y: newY }
|
||
)
|
||
.done(function() {
|
||
newShape.__animating = false;
|
||
})
|
||
.start(easing);
|
||
}
|
||
|
||
/**
|
||
* 环型动画
|
||
*
|
||
* @param {ZRender} zr
|
||
* @param {shape} oldShape
|
||
* @param {shape} newShape
|
||
* @param {number} duration
|
||
* @param {tring} easing
|
||
*/
|
||
function ring(zr, oldShape, newShape, duration, easing) {
|
||
var x = newShape.style.x;
|
||
var y = newShape.style.y;
|
||
var r0 = newShape.style.r0;
|
||
var r = newShape.style.r;
|
||
|
||
newShape.__animating = true;
|
||
|
||
if (newShape._animationAdd != 'r') {
|
||
newShape.style.r0 = 0;
|
||
newShape.style.r = 0;
|
||
newShape.rotation = [Math.PI*2, x, y];
|
||
|
||
zr.addShape(newShape);
|
||
zr.animate(newShape.id, 'style')
|
||
.when(
|
||
duration,
|
||
{
|
||
r0 : r0,
|
||
r : r
|
||
}
|
||
)
|
||
.done(function() {
|
||
newShape.__animating = false;
|
||
})
|
||
.start(easing);
|
||
zr.animate(newShape.id, '')
|
||
.when(
|
||
duration,
|
||
{ rotation : [0, x, y] }
|
||
)
|
||
.start(easing);
|
||
}
|
||
else {
|
||
newShape.style.r0 = newShape.style.r;
|
||
|
||
zr.addShape(newShape);
|
||
zr.animate(newShape.id, 'style')
|
||
.when(
|
||
duration,
|
||
{
|
||
r0 : r0
|
||
}
|
||
)
|
||
.done(function() {
|
||
newShape.__animating = false;
|
||
})
|
||
.start(easing);
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 扇形动画
|
||
*
|
||
* @param {ZRender} zr
|
||
* @param {shape} oldShape
|
||
* @param {shape} newShape
|
||
* @param {number} duration
|
||
* @param {tring} easing
|
||
*/
|
||
function sector(zr, oldShape, newShape, duration, easing) {
|
||
if (!oldShape) { // add
|
||
if (newShape._animationAdd != 'r') {
|
||
oldShape = {
|
||
style : {
|
||
startAngle : newShape.style.startAngle,
|
||
endAngle : newShape.style.startAngle
|
||
}
|
||
};
|
||
}
|
||
else {
|
||
oldShape = {style : {r0 : newShape.style.r}};
|
||
}
|
||
}
|
||
|
||
var startAngle = newShape.style.startAngle;
|
||
var endAngle = newShape.style.endAngle;
|
||
|
||
cloneStyle(
|
||
newShape, oldShape,
|
||
'startAngle', 'endAngle'
|
||
);
|
||
|
||
zr.addShape(newShape);
|
||
newShape.__animating = true;
|
||
zr.animate(newShape.id, 'style')
|
||
.when(
|
||
duration,
|
||
{
|
||
startAngle : startAngle,
|
||
endAngle : endAngle
|
||
}
|
||
)
|
||
.done(function() {
|
||
newShape.__animating = false;
|
||
})
|
||
.start(easing);
|
||
}
|
||
|
||
/**
|
||
* 文本动画
|
||
*
|
||
* @param {ZRender} zr
|
||
* @param {shape} oldShape
|
||
* @param {shape} newShape
|
||
* @param {number} duration
|
||
* @param {tring} easing
|
||
*/
|
||
function text(zr, oldShape, newShape, duration, easing) {
|
||
if (!oldShape) { // add
|
||
oldShape = {
|
||
style : {
|
||
x : newShape.style.textAlign == 'left'
|
||
? newShape.style.x + 100
|
||
: newShape.style.x - 100,
|
||
y : newShape.style.y
|
||
}
|
||
};
|
||
}
|
||
|
||
var x = newShape.style.x;
|
||
var y = newShape.style.y;
|
||
|
||
cloneStyle(
|
||
newShape, oldShape,
|
||
'x', 'y'
|
||
);
|
||
|
||
zr.addShape(newShape);
|
||
newShape.__animating = true;
|
||
zr.animate(newShape.id, 'style')
|
||
.when(
|
||
duration,
|
||
{
|
||
x : x,
|
||
y : y
|
||
}
|
||
)
|
||
.done(function() {
|
||
newShape.__animating = false;
|
||
})
|
||
.start(easing);
|
||
}
|
||
|
||
/**
|
||
* 多边形动画
|
||
*
|
||
* @param {ZRender} zr
|
||
* @param {shape} oldShape
|
||
* @param {shape} newShape
|
||
* @param {number} duration
|
||
* @param {tring} easing
|
||
*/
|
||
function polygon(zr, oldShape, newShape, duration, easing) {
|
||
var rect = require('zrender/shape/Polygon').prototype.getRect(newShape.style);
|
||
var x = rect.x + rect.width / 2;
|
||
var y = rect.y + rect.height / 2;
|
||
|
||
newShape.scale = [0.1, 0.1, x, y];
|
||
zr.addShape(newShape);
|
||
newShape.__animating = true;
|
||
zr.animate(newShape.id, '')
|
||
.when(
|
||
duration,
|
||
{
|
||
scale : [1, 1, x, y]
|
||
}
|
||
)
|
||
.done(function() {
|
||
newShape.__animating = false;
|
||
})
|
||
.start(easing);
|
||
}
|
||
|
||
/**
|
||
* 和弦动画
|
||
*
|
||
* @param {ZRender} zr
|
||
* @param {shape} oldShape
|
||
* @param {shape} newShape
|
||
* @param {number} duration
|
||
* @param {tring} easing
|
||
*/
|
||
function ribbon(zr, oldShape, newShape, duration, easing) {
|
||
if (!oldShape) { // add
|
||
oldShape = {
|
||
style : {
|
||
source0 : 0,
|
||
source1 : newShape.style.source1 > 0 ? 360 : -360,
|
||
target0 : 0,
|
||
target1 : newShape.style.target1 > 0 ? 360 : -360
|
||
}
|
||
};
|
||
}
|
||
|
||
var source0 = newShape.style.source0;
|
||
var source1 = newShape.style.source1;
|
||
var target0 = newShape.style.target0;
|
||
var target1 = newShape.style.target1;
|
||
|
||
if (oldShape.style) {
|
||
cloneStyle(
|
||
newShape, oldShape,
|
||
'source0', 'source1', 'target0', 'target1'
|
||
);
|
||
}
|
||
|
||
zr.addShape(newShape);
|
||
newShape.__animating = true;
|
||
zr.animate(newShape.id, 'style')
|
||
.when(
|
||
duration,
|
||
{
|
||
source0 : source0,
|
||
source1 : source1,
|
||
target0 : target0,
|
||
target1 : target1
|
||
}
|
||
)
|
||
.done(function() {
|
||
newShape.__animating = false;
|
||
})
|
||
.start(easing);
|
||
}
|
||
|
||
/**
|
||
* gaugePointer动画
|
||
*
|
||
* @param {ZRender} zr
|
||
* @param {shape} oldShape
|
||
* @param {shape} newShape
|
||
* @param {number} duration
|
||
* @param {tring} easing
|
||
*/
|
||
function gaugePointer(zr, oldShape, newShape, duration, easing) {
|
||
if (!oldShape) { // add
|
||
oldShape = {
|
||
style : {
|
||
angle : newShape.style.startAngle
|
||
}
|
||
};
|
||
}
|
||
|
||
var angle = newShape.style.angle;
|
||
newShape.style.angle = oldShape.style.angle;
|
||
zr.addShape(newShape);
|
||
newShape.__animating = true;
|
||
zr.animate(newShape.id, 'style')
|
||
.when(
|
||
duration,
|
||
{
|
||
angle : angle
|
||
}
|
||
)
|
||
.done(function() {
|
||
newShape.__animating = false;
|
||
})
|
||
.start(easing);
|
||
}
|
||
|
||
/**
|
||
* icon动画
|
||
*
|
||
* @param {ZRender} zr
|
||
* @param {shape} oldShape
|
||
* @param {shape} newShape
|
||
* @param {number} duration
|
||
* @param {tring} easing
|
||
*/
|
||
function icon(zr, oldShape, newShape, duration, easing, delay) {
|
||
// 避免markPoint特效取值在动画帧上
|
||
newShape.style._x = newShape.style.x;
|
||
newShape.style._y = newShape.style.y;
|
||
newShape.style._width = newShape.style.width;
|
||
newShape.style._height = newShape.style.height;
|
||
|
||
if (!oldShape) { // add
|
||
var x = newShape._x || 0;
|
||
var y = newShape._y || 0;
|
||
newShape.scale = [0.01, 0.01, x, y];
|
||
zr.addShape(newShape);
|
||
newShape.__animating = true;
|
||
zr.animate(newShape.id, '')
|
||
.delay(delay)
|
||
.when(
|
||
duration,
|
||
{scale : [1, 1, x, y]}
|
||
)
|
||
.done(function() {
|
||
newShape.__animating = false;
|
||
})
|
||
.start(easing || 'QuinticOut');
|
||
}
|
||
else { // mod
|
||
rectangle(zr, oldShape, newShape, duration, easing);
|
||
}
|
||
}
|
||
|
||
/**
|
||
* line动画
|
||
*
|
||
* @param {ZRender} zr
|
||
* @param {shape} oldShape
|
||
* @param {shape} newShape
|
||
* @param {number} duration
|
||
* @param {tring} easing
|
||
*/
|
||
function line(zr, oldShape, newShape, duration, easing) {
|
||
if (!oldShape) {
|
||
oldShape = {
|
||
style : {
|
||
xStart : newShape.style.xStart,
|
||
yStart : newShape.style.yStart,
|
||
xEnd : newShape.style.xStart,
|
||
yEnd : newShape.style.yStart
|
||
}
|
||
};
|
||
}
|
||
|
||
var xStart = newShape.style.xStart;
|
||
var xEnd = newShape.style.xEnd;
|
||
var yStart = newShape.style.yStart;
|
||
var yEnd = newShape.style.yEnd;
|
||
|
||
cloneStyle(
|
||
newShape, oldShape,
|
||
'xStart', 'xEnd', 'yStart', 'yEnd'
|
||
);
|
||
|
||
zr.addShape(newShape);
|
||
newShape.__animating = true;
|
||
zr.animate(newShape.id, 'style')
|
||
.when(
|
||
duration,
|
||
{
|
||
xStart: xStart,
|
||
xEnd: xEnd,
|
||
yStart: yStart,
|
||
yEnd: yEnd
|
||
}
|
||
)
|
||
.done(function() {
|
||
newShape.__animating = false;
|
||
})
|
||
.start(easing);
|
||
}
|
||
|
||
/**
|
||
* markline动画
|
||
*
|
||
* @param {ZRender} zr
|
||
* @param {shape} oldShape
|
||
* @param {shape} newShape
|
||
* @param {number} duration
|
||
* @param {tring} easing
|
||
*/
|
||
function markline(zr, oldShape, newShape, duration, easing) {
|
||
easing = easing || 'QuinticOut';
|
||
newShape.__animating = true;
|
||
zr.addShape(newShape);
|
||
var newShapeStyle = newShape.style;
|
||
|
||
var animationDone = function () {
|
||
newShape.__animating = false;
|
||
};
|
||
var x0 = newShapeStyle.xStart;
|
||
var y0 = newShapeStyle.yStart;
|
||
var x2 = newShapeStyle.xEnd;
|
||
var y2 = newShapeStyle.yEnd;
|
||
if (newShapeStyle.curveness > 0) {
|
||
newShape.updatePoints(newShapeStyle);
|
||
var obj = { p: 0 };
|
||
var x1 = newShapeStyle.cpX1;
|
||
var y1 = newShapeStyle.cpY1;
|
||
var newXArr = [];
|
||
var newYArr = [];
|
||
var subdivide = curveTool.quadraticSubdivide;
|
||
zr.animation.animate(obj)
|
||
.when(duration, { p: 1 })
|
||
.during(function () {
|
||
// Calculate subdivided curve
|
||
subdivide(x0, x1, x2, obj.p, newXArr);
|
||
subdivide(y0, y1, y2, obj.p, newYArr);
|
||
newShapeStyle.cpX1 = newXArr[1];
|
||
newShapeStyle.cpY1 = newYArr[1];
|
||
newShapeStyle.xEnd = newXArr[2];
|
||
newShapeStyle.yEnd = newYArr[2];
|
||
zr.modShape(newShape);
|
||
})
|
||
.done(animationDone)
|
||
.start(easing);
|
||
}
|
||
else {
|
||
zr.animate(newShape.id, 'style')
|
||
.when(0, {
|
||
xEnd: x0,
|
||
yEnd: y0
|
||
})
|
||
.when(duration, {
|
||
xEnd: x2,
|
||
yEnd: y2
|
||
})
|
||
.done(animationDone)
|
||
.start(easing);
|
||
}
|
||
}
|
||
|
||
return {
|
||
pointList : pointList,
|
||
rectangle : rectangle,
|
||
candle : candle,
|
||
ring : ring,
|
||
sector : sector,
|
||
text : text,
|
||
polygon : polygon,
|
||
ribbon : ribbon,
|
||
gaugePointer : gaugePointer,
|
||
icon : icon,
|
||
line : line,
|
||
markline : markline
|
||
};
|
||
});
|