/** * 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 }; });