/** * @fileOverview The entry of chart's animation * @author sima.zhang */ const Util = require('../util'); const Animate = require('./animate'); const MatrixUtil = Util.MatrixUtil; const { mat3 } = MatrixUtil; // 获取图组内所有的shapes function getShapes(container, viewId) { let shapes = []; if (container.get('animate') === false) { return []; } const children = container.get('children'); Util.each(children, child => { if (child.isGroup) { shapes = shapes.concat(getShapes(child, viewId)); } else if (child.isShape && child._id) { let id = child._id; id = id.split('-')[0]; if (id === viewId) { shapes.push(child); } } }); return shapes; } function cache(shapes) { const rst = {}; Util.each(shapes, shape => { if (!shape._id || shape.isClip) return; const id = shape._id; rst[id] = { _id: id, type: shape.get('type'), attrs: Util.cloneDeep(shape.attr()), // 原始属性 name: shape.name, index: shape.get('index'), animateCfg: shape.get('animateCfg'), coord: shape.get('coord') }; }); return rst; } function getAnimate(geomType, coord, animationType, animationName) { let result; if (animationName) { result = Animate.Action[animationType][animationName]; } else { result = Animate.getAnimation(geomType, coord, animationType); } return result; } function getAnimateCfg(geomType, animationType, animateCfg) { const defaultCfg = Animate.getAnimateCfg(geomType, animationType); if (animateCfg && animateCfg[animationType]) { return Util.deepMix({}, defaultCfg, animateCfg[animationType]); } return defaultCfg; } function addAnimate(cache, shapes, canvas, isUpdate) { let animate; let animateCfg; let canvasDrawn = false; if (isUpdate) { // Step: leave -> update -> enter const updateShapes = []; // 存储的是 shapes const newShapes = []; // 存储的是 shapes Util.each(shapes, shape => { const result = cache[shape._id]; if (!result) { newShapes.push(shape); } else { shape.setSilent('cacheShape', result); updateShapes.push(shape); delete cache[shape._id]; } }); Util.each(cache, deletedShape => { const { name, coord, _id, attrs, index, type } = deletedShape; animateCfg = getAnimateCfg(name, 'leave', deletedShape.animateCfg); animate = getAnimate(name, coord, 'leave', animateCfg.animation); if (Util.isFunction(animate)) { const tempShape = canvas.addShape(type, { attrs, index }); tempShape._id = _id; tempShape.name = name; if (coord && name !== 'label') { const tempShapeMatrix = tempShape.getMatrix(); const finalMatrix = mat3.multiply([], tempShapeMatrix, coord.matrix); tempShape.setMatrix(finalMatrix); } canvasDrawn = true; animate(tempShape, animateCfg, coord); } }); Util.each(updateShapes, updateShape => { const name = updateShape.name; const coord = updateShape.get('coord'); const cacheAttrs = updateShape.get('cacheShape').attrs; // 判断如果属性相同的话就不进行变换 if (!Util.isEqual(cacheAttrs, updateShape.attr())) { animateCfg = getAnimateCfg(name, 'update', updateShape.get('animateCfg')); animate = getAnimate(name, coord, 'update', animateCfg.animation); if (Util.isFunction(animate)) { animate(updateShape, animateCfg, coord); } else { const endState = Util.cloneDeep(updateShape.attr()); updateShape.attr(cacheAttrs); updateShape.animate(endState, animateCfg.duration, animateCfg.easing, () => { updateShape.setSilent('cacheShape', null); }); } canvasDrawn = true; } }); Util.each(newShapes, newShape => { const name = newShape.name; const coord = newShape.get('coord'); animateCfg = getAnimateCfg(name, 'enter', newShape.get('animateCfg')); animate = getAnimate(name, coord, 'enter', animateCfg.animation); if (Util.isFunction(animate)) { animate(newShape, animateCfg, coord); canvasDrawn = true; } }); } else { Util.each(shapes, shape => { const name = shape.name; const coord = shape.get('coord'); animateCfg = getAnimateCfg(name, 'appear', shape.get('animateCfg')); animate = getAnimate(name, coord, 'appear', animateCfg.animation); if (Util.isFunction(animate)) { animate(shape, animateCfg, coord); canvasDrawn = true; } }); } return canvasDrawn; } module.exports = { execAnimation(view, isUpdate) { const viewContainer = view.get('middlePlot'); const axisContainer = view.get('backPlot'); const viewId = view.get('_id'); const canvas = view.get('canvas'); const caches = canvas.get(viewId + 'caches') || []; if (caches.length === 0) { isUpdate = false; } const shapes = getShapes(viewContainer, viewId); const axisShapes = getShapes(axisContainer, viewId); const cacheShapes = shapes.concat(axisShapes); canvas.setSilent(viewId + 'caches', cache(cacheShapes)); let drawn; if (isUpdate) { drawn = addAnimate(caches, cacheShapes, canvas, isUpdate); } else { drawn = addAnimate(caches, shapes, canvas, isUpdate); } if (!drawn) { canvas.draw(); } } };