You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
444 lines
16 KiB
444 lines
16 KiB
/**
|
|
* echarts图表特效基类
|
|
*
|
|
* @desc echarts基于Canvas,纯Javascript图表库,提供直观,生动,可交互,可个性化定制的数据统计图表。
|
|
* @author Kener (@Kener-林峰, kener.linfeng@gmail.com)
|
|
*
|
|
*/
|
|
define(function (require) {
|
|
var ecData = require('../util/ecData');
|
|
|
|
var CircleShape = require('zrender/shape/Circle');
|
|
var ImageShape = require('zrender/shape/Image');
|
|
var curveTool = require('zrender/tool/curve');
|
|
var IconShape = require('../util/shape/Icon');
|
|
var SymbolShape = require('../util/shape/Symbol');
|
|
var ShapeBundle = require('zrender/shape/ShapeBundle');
|
|
var Polyline = require('zrender/shape/Polyline');
|
|
var vec2 = require('zrender/tool/vector');
|
|
|
|
var canvasSupported = require('zrender/tool/env').canvasSupported;
|
|
|
|
function point(zr, effectList, shape, zlevel) {
|
|
var effect = shape.effect;
|
|
var color = effect.color || shape.style.strokeColor || shape.style.color;
|
|
var shadowColor = effect.shadowColor || color;
|
|
var size = effect.scaleSize;
|
|
var distance = effect.bounceDistance;
|
|
var shadowBlur = typeof effect.shadowBlur != 'undefined'
|
|
? effect.shadowBlur : size;
|
|
|
|
var effectShape;
|
|
if (shape.type !== 'image') {
|
|
effectShape = new IconShape({
|
|
zlevel : zlevel,
|
|
style : {
|
|
brushType : 'stroke',
|
|
iconType : shape.style.iconType != 'droplet'
|
|
? shape.style.iconType
|
|
: 'circle',
|
|
x : shadowBlur + 1, // 线宽
|
|
y : shadowBlur + 1,
|
|
n : shape.style.n,
|
|
width : shape.style._width * size,
|
|
height : shape.style._height * size,
|
|
lineWidth : 1,
|
|
strokeColor : color,
|
|
shadowColor : shadowColor,
|
|
shadowBlur : shadowBlur
|
|
},
|
|
draggable : false,
|
|
hoverable : false
|
|
});
|
|
if (shape.style.iconType == 'pin') {
|
|
effectShape.style.y += effectShape.style.height / 2 * 1.5;
|
|
}
|
|
|
|
if (canvasSupported) { // 提高性能,换成image
|
|
effectShape.style.image = zr.shapeToImage(
|
|
effectShape,
|
|
effectShape.style.width + shadowBlur * 2 + 2,
|
|
effectShape.style.height + shadowBlur * 2 + 2
|
|
).style.image;
|
|
|
|
effectShape = new ImageShape({
|
|
zlevel : effectShape.zlevel,
|
|
style : effectShape.style,
|
|
draggable : false,
|
|
hoverable : false
|
|
});
|
|
}
|
|
}
|
|
else {
|
|
effectShape = new ImageShape({
|
|
zlevel : zlevel,
|
|
style : shape.style,
|
|
draggable : false,
|
|
hoverable : false
|
|
});
|
|
}
|
|
|
|
ecData.clone(shape, effectShape);
|
|
|
|
// 改变坐标,不能移到前面
|
|
effectShape.position = shape.position;
|
|
effectList.push(effectShape);
|
|
zr.addShape(effectShape);
|
|
|
|
var devicePixelRatio = shape.type !== 'image' ? (window.devicePixelRatio || 1) : 1;
|
|
var offset = (effectShape.style.width / devicePixelRatio - shape.style._width) / 2;
|
|
effectShape.style.x = shape.style._x - offset;
|
|
effectShape.style.y = shape.style._y - offset;
|
|
|
|
if (shape.style.iconType == 'pin') {
|
|
effectShape.style.y -= shape.style.height / 2 * 1.5;
|
|
}
|
|
|
|
var duration = (effect.period + Math.random() * 10) * 100;
|
|
|
|
zr.modShape(
|
|
shape.id,
|
|
{ invisible : true}
|
|
);
|
|
|
|
var centerX = effectShape.style.x + (effectShape.style.width) / 2 / devicePixelRatio;
|
|
var centerY = effectShape.style.y + (effectShape.style.height) / 2 / devicePixelRatio;
|
|
|
|
if (effect.type === 'scale') {
|
|
// 放大效果
|
|
zr.modShape(
|
|
effectShape.id,
|
|
{
|
|
scale : [0.1, 0.1, centerX, centerY]
|
|
}
|
|
);
|
|
|
|
zr.animate(effectShape.id, '', effect.loop)
|
|
.when(
|
|
duration,
|
|
{
|
|
scale : [1, 1, centerX, centerY]
|
|
}
|
|
)
|
|
.done(function() {
|
|
shape.effect.show = false;
|
|
zr.delShape(effectShape.id);
|
|
})
|
|
.start();
|
|
}
|
|
else {
|
|
zr.animate(effectShape.id, 'style', effect.loop)
|
|
.when(
|
|
duration,
|
|
{
|
|
y : effectShape.style.y - distance
|
|
}
|
|
)
|
|
.when(
|
|
duration * 2,
|
|
{
|
|
y : effectShape.style.y
|
|
}
|
|
)
|
|
.done(function() {
|
|
shape.effect.show = false;
|
|
zr.delShape(effectShape.id);
|
|
})
|
|
.start();
|
|
}
|
|
|
|
}
|
|
|
|
function largePoint(zr, effectList, shape, zlevel) {
|
|
var effect = shape.effect;
|
|
var color = effect.color || shape.style.strokeColor || shape.style.color;
|
|
var size = effect.scaleSize;
|
|
var shadowColor = effect.shadowColor || color;
|
|
var shadowBlur = typeof effect.shadowBlur != 'undefined'
|
|
? effect.shadowBlur : (size * 2);
|
|
var devicePixelRatio = window.devicePixelRatio || 1;
|
|
var effectShape = new SymbolShape({
|
|
zlevel : zlevel,
|
|
position : shape.position,
|
|
scale : shape.scale,
|
|
style : {
|
|
pointList : shape.style.pointList,
|
|
iconType : shape.style.iconType,
|
|
color : color,
|
|
strokeColor : color,
|
|
shadowColor : shadowColor,
|
|
shadowBlur : shadowBlur * devicePixelRatio,
|
|
random : true,
|
|
brushType: 'fill',
|
|
lineWidth:1,
|
|
size : shape.style.size
|
|
},
|
|
draggable : false,
|
|
hoverable : false
|
|
});
|
|
|
|
effectList.push(effectShape);
|
|
zr.addShape(effectShape);
|
|
zr.modShape(
|
|
shape.id,
|
|
{ invisible : true}
|
|
);
|
|
|
|
var duration = Math.round(effect.period * 100);
|
|
var clip1 = {};
|
|
var clip2 = {};
|
|
for (var i = 0; i < 20; i++) {
|
|
effectShape.style['randomMap' + i] = 0;
|
|
clip1 = {};
|
|
clip1['randomMap' + i] = 100;
|
|
clip2 = {};
|
|
clip2['randomMap' + i] = 0;
|
|
effectShape.style['randomMap' + i] = Math.random() * 100;
|
|
zr.animate(effectShape.id, 'style', true)
|
|
.when(duration, clip1)
|
|
.when(duration * 2, clip2)
|
|
.when(duration * 3, clip1)
|
|
.when(duration * 4, clip1)
|
|
.delay(Math.random() * duration * i)
|
|
//.delay(duration / 15 * (15 - i + 1))
|
|
.start();
|
|
|
|
}
|
|
}
|
|
|
|
function line(zr, effectList, shape, zlevel, isLarge) {
|
|
var effect = shape.effect;
|
|
var shapeStyle = shape.style;
|
|
var color = effect.color || shapeStyle.strokeColor || shapeStyle.color;
|
|
var shadowColor = effect.shadowColor || shapeStyle.strokeColor || color;
|
|
var size = shapeStyle.lineWidth * effect.scaleSize;
|
|
var shadowBlur = typeof effect.shadowBlur != 'undefined'
|
|
? effect.shadowBlur : size;
|
|
|
|
var effectShape = new CircleShape({
|
|
zlevel : zlevel,
|
|
style : {
|
|
x : shadowBlur,
|
|
y : shadowBlur,
|
|
r : size,
|
|
color : color,
|
|
shadowColor : shadowColor,
|
|
shadowBlur : shadowBlur
|
|
},
|
|
hoverable : false
|
|
});
|
|
|
|
var offset = 0;
|
|
if (canvasSupported && ! isLarge) { // 提高性能,换成image
|
|
var zlevel = effectShape.zlevel;
|
|
effectShape = zr.shapeToImage(
|
|
effectShape,
|
|
(size + shadowBlur) * 2,
|
|
(size + shadowBlur) * 2
|
|
);
|
|
effectShape.zlevel = zlevel;
|
|
effectShape.hoverable = false;
|
|
|
|
offset = shadowBlur;
|
|
}
|
|
|
|
if (! isLarge) {
|
|
ecData.clone(shape, effectShape);
|
|
// 改变坐标, 不能移到前面
|
|
effectShape.position = shape.position;
|
|
effectList.push(effectShape);
|
|
zr.addShape(effectShape);
|
|
}
|
|
|
|
var effectDone = function () {
|
|
if (! isLarge) {
|
|
shape.effect.show = false;
|
|
zr.delShape(effectShape.id);
|
|
}
|
|
effectShape.effectAnimator = null;
|
|
};
|
|
|
|
if (shape instanceof Polyline) {
|
|
var distanceList = [0];
|
|
var totalDist = 0;
|
|
var pointList = shapeStyle.pointList;
|
|
var controlPointList = shapeStyle.controlPointList;
|
|
for (var i = 1; i < pointList.length; i++) {
|
|
if (controlPointList) {
|
|
var cp1 = controlPointList[(i - 1) * 2];
|
|
var cp2 = controlPointList[(i - 1) * 2 + 1];
|
|
totalDist += vec2.dist(pointList[i - 1], cp1)
|
|
+ vec2.dist(cp1, cp2)
|
|
+ vec2.dist(cp2, pointList[i]);
|
|
}
|
|
else {
|
|
totalDist += vec2.dist(pointList[i - 1], pointList[i]);
|
|
}
|
|
distanceList.push(totalDist);
|
|
}
|
|
var obj = { p: 0 };
|
|
var animator = zr.animation.animate(obj, { loop: effect.loop });
|
|
|
|
for (var i = 0; i < distanceList.length; i++) {
|
|
animator.when(distanceList[i] * effect.period, { p: i });
|
|
}
|
|
animator.during(function () {
|
|
var i = Math.floor(obj.p);
|
|
var x, y;
|
|
if (i == pointList.length - 1) {
|
|
x = pointList[i][0];
|
|
y = pointList[i][1];
|
|
}
|
|
else {
|
|
var t = obj.p - i;
|
|
var p0 = pointList[i];
|
|
var p1 = pointList[i + 1];
|
|
if (controlPointList) {
|
|
var cp1 = controlPointList[i * 2];
|
|
var cp2 = controlPointList[i * 2 + 1];
|
|
x = curveTool.cubicAt(
|
|
p0[0], cp1[0], cp2[0], p1[0], t
|
|
);
|
|
y = curveTool.cubicAt(
|
|
p0[1], cp1[1], cp2[1], p1[1], t
|
|
);
|
|
}
|
|
else {
|
|
x = (p1[0] - p0[0]) * t + p0[0];
|
|
y = (p1[1] - p0[1]) * t + p0[1];
|
|
}
|
|
}
|
|
effectShape.style.x = x;
|
|
effectShape.style.y = y;
|
|
if (! isLarge) {
|
|
zr.modShape(effectShape);
|
|
}
|
|
})
|
|
.done(effectDone)
|
|
.start();
|
|
|
|
animator.duration = totalDist * effect.period;
|
|
|
|
effectShape.effectAnimator = animator;
|
|
}
|
|
else {
|
|
var x0 = shapeStyle.xStart - offset;
|
|
var y0 = shapeStyle.yStart - offset;
|
|
var x2 = shapeStyle.xEnd - offset;
|
|
var y2 = shapeStyle.yEnd - offset;
|
|
effectShape.style.x = x0;
|
|
effectShape.style.y = y0;
|
|
|
|
var distance = (x2 - x0) * (x2 - x0) + (y2 - y0) * (y2 - y0);
|
|
var duration = Math.round(Math.sqrt(Math.round(
|
|
distance * effect.period * effect.period
|
|
)));
|
|
|
|
if (shape.style.curveness > 0) {
|
|
var x1 = shapeStyle.cpX1 - offset;
|
|
var y1 = shapeStyle.cpY1 - offset;
|
|
effectShape.effectAnimator = zr.animation.animate(effectShape, { loop: effect.loop })
|
|
.when(duration, { p: 1 })
|
|
.during(function (target, t) {
|
|
effectShape.style.x = curveTool.quadraticAt(
|
|
x0, x1, x2, t
|
|
);
|
|
effectShape.style.y = curveTool.quadraticAt(
|
|
y0, y1, y2, t
|
|
);
|
|
if (! isLarge) {
|
|
zr.modShape(effectShape);
|
|
}
|
|
})
|
|
.done(effectDone)
|
|
.start();
|
|
}
|
|
else {
|
|
// 不用 zr.animate,因为在用 ShapeBundle 的时候单个 effectShape 不会
|
|
// 被加到 zrender 中
|
|
effectShape.effectAnimator = zr.animation.animate(effectShape.style, { loop: effect.loop })
|
|
.when(duration, {
|
|
x: x2,
|
|
y: y2
|
|
})
|
|
.during(function () {
|
|
if (! isLarge) {
|
|
zr.modShape(effectShape);
|
|
}
|
|
})
|
|
.done(effectDone)
|
|
.start();
|
|
}
|
|
effectShape.effectAnimator.duration = duration;
|
|
}
|
|
return effectShape;
|
|
}
|
|
|
|
function largeLine(zr, effectList, shape, zlevel) {
|
|
var effectShape = new ShapeBundle({
|
|
style: {
|
|
shapeList: []
|
|
},
|
|
zlevel: zlevel,
|
|
hoverable: false
|
|
});
|
|
var shapeList = shape.style.shapeList;
|
|
var effect = shape.effect;
|
|
effectShape.position = shape.position;
|
|
|
|
var maxDuration = 0;
|
|
var subEffectAnimators = [];
|
|
for (var i = 0; i < shapeList.length; i++) {
|
|
shapeList[i].effect = effect;
|
|
var subEffectShape = line(zr, null, shapeList[i], zlevel, true);
|
|
var subEffectAnimator = subEffectShape.effectAnimator;
|
|
effectShape.style.shapeList.push(subEffectShape);
|
|
if (subEffectAnimator.duration > maxDuration) {
|
|
maxDuration = subEffectAnimator.duration;
|
|
}
|
|
if (i === 0) {
|
|
effectShape.style.color = subEffectShape.style.color;
|
|
effectShape.style.shadowBlur = subEffectShape.style.shadowBlur;
|
|
effectShape.style.shadowColor = subEffectShape.style.shadowColor;
|
|
}
|
|
subEffectAnimators.push(subEffectAnimator);
|
|
}
|
|
effectList.push(effectShape);
|
|
zr.addShape(effectShape);
|
|
|
|
var clearAllAnimators = function () {
|
|
for (var i = 0; i < subEffectAnimators.length; i++) {
|
|
subEffectAnimators[i].stop();
|
|
}
|
|
};
|
|
if (maxDuration) {
|
|
effectShape.__dummy = 0;
|
|
// Proxy animator
|
|
var animator = zr.animate(effectShape.id, '', effect.loop)
|
|
.when(maxDuration, {
|
|
__dummy: 1
|
|
})
|
|
.during(function () {
|
|
zr.modShape(effectShape);
|
|
})
|
|
.done(function () {
|
|
shape.effect.show = false;
|
|
zr.delShape(effectShape.id);
|
|
})
|
|
.start();
|
|
var oldStop = animator.stop;
|
|
|
|
animator.stop = function () {
|
|
clearAllAnimators();
|
|
oldStop.call(this);
|
|
};
|
|
}
|
|
}
|
|
|
|
return {
|
|
point : point,
|
|
largePoint : largePoint,
|
|
line : line,
|
|
largeLine: largeLine
|
|
};
|
|
});
|
|
|