增加动画处理

This commit is contained in:
ival 2021-04-04 00:44:29 +08:00
parent 870852b97a
commit eb429506f5
8 changed files with 183 additions and 51 deletions

View File

@ -0,0 +1,76 @@
import Group from 'zrender/src/container/Group';
class Animate {
constructor(state) {
this.state = {...state}
this.shapeFactory = this.shape? this.shape.shapeFactory: null;
this.timer = null;
this.total = 0;
this.count = 0;
}
run(delay) {
this.total = this.total + delay;
if (this.total > this.state.time) {
clearTimeout(this.timer);
this.timer = setTimeout(this.__animate.bind(this), this.state.delay);
this.count = this.count + 1;
this.total = 0;
}
}
isLoop() {
return this.state.loop;
}
__animate() {
const shape = this.state.shape;
const frameList = this.state.frameList;
const mapView = this.__traverse(shape, {});
if(shape && frameList) {
const size = frameList.length;
const frame = frameList[this.count%size];
Object.keys(frame).forEach(name => {
const view = mapView[name];
const model = frame[name];
if (view && model) {
view.attr({shape: model.shape, style: model.style});
}
})
}
}
__traverse(group, map) {
group.eachChild(el => {
if (el instanceof Group) {
this.__traverse(el, map);
} else {
map[el.name] = el;
}
})
return map;
}
}
class AnimateHandle {
constructor(painter) {
this.animates = [];
}
onframe (delay) {
const animate = this.animates.shift();
if (animate) {
animate.run(delay);
if (animate.isLoop()) {
this.animates.push(animate);
}
}
}
animate(state) {
this.animates.push(new Animate(state));
}
}
export default AnimateHandle

View File

@ -44,6 +44,7 @@ class Element extends AbstractShape {
this.instance.origin = utils.createOrigin(this.instance);
this.instance.transform = utils.createTransform({scale: this.model.scale, position: this.model.position, rotation: this.model.rotation});
this.add(this.instance);
// this.instance.animate('style', true).when(1000, {fill: 'blue'}).when(2000, {fill: 'rellow'}).start();
}
}

View File

@ -60,13 +60,13 @@ function update2List(source, model, action, name='') {
return updateModel;
}
class ShapeFactory extends Eventful {
constructor(map) {
super();
this.$map = map;
this.$painter = map.getPainter();
this.$controller = map.getController();
this.$zr = map.getZr();
this.border = new graphic.Rect(shapeStyleBuilder());
@ -100,8 +100,9 @@ class ShapeFactory extends Eventful {
parseTemplates(list=[]) {
list.forEach(el => {
this.mapTemplate[el.type] = templateParser.parser(el);
this.mapTemplate[el.type] = templateParser.parse(el);
})
console.log(this.mapTemplate);
}
parse(source={}, take=None) {

View File

@ -3,8 +3,8 @@ class TemplateParser {
constructor() {
}
parser(template) {
const model = {
parse(template) {
return {
type: template.type,
name: template.name,
isActive: template.isActive,
@ -13,7 +13,6 @@ class TemplateParser {
mapState: this.parseState(template.stateList),
mapEvent: this.parseEvent(template.eventList),
}
return model;
}
parseShape(list=[], map={}) {

View File

@ -43,25 +43,32 @@ class JMap {
const optionHandler = this.setOption.bind(this);
this.draw = opts.draw;
// 实例化zr
this.$zr = zrender.init(opts.dom, { renderer, devicePixelRatio, width, height, ...utils.deepClone(opts.config||{})});
this.$zr.dom.setAttribute('tabIndex', -1);
this.$zr.dom.style.cursor = 'auto';
// 实例化缩放偏移缩放参数
this.$option = new Option({ scaleRate: 1, offsetX: 0, offsetY: 0, ...utils.deepClone(opts.option||{})}, (dataZoom) => { this.$controller.trigger(events.DataZoom, dataZoom); }); // 缩放
// 实例化绘图模块
this.$painter = new Painter(this);
this.$painter.updateZrSize({width: this.$zr.getWidth(), height: this.$zr.getHeight()});
this.$painter.updateTransform(this.$option);
// 实例化事件分发模块
this.$controller = new Controller(this);
this.$controller.enable();
this.$controller.on(this.events.__Pan, optionHandler);
this.$controller.on(this.events.__Zoom, optionHandler);
this.$eventEmitter = new Eventful(this);
// 名声周期发射器
this.$eventEmitter = new Eventful({});
// 数据容器工厂
this.$shapeFactory = new ShapeFactory(this);
// 状态处理器
this.$stateHandle = new StateHandle(this);
this.disable = function() {
@ -71,6 +78,10 @@ class JMap {
}
setMap(templates=[], source={}, eventOpts={}) {
// 清楚数据
this.$shapeFactory.clear();
this.$painter.clear();
// 绑定事件
this.$controller.enable(eventOpts);
@ -135,8 +146,6 @@ class JMap {
}
repaint(source={}) {
this.$shapeFactory.clear();
this.$painter.clear();
this.$shapeFactory.parse(source, shape => {
if (shape) {
this.$painter.add(shape);
@ -193,7 +202,7 @@ class JMap {
}
update(list=[]) {
this.$painter.update(this.$stateHandle.update(list));
this.$painter.update(this.$stateHandle.update(this.$shapeFactory, list));
this.$eventEmitter.trigger(events.StateUpdate, list);
return this;
}
@ -274,6 +283,9 @@ class JMap {
case events.DataLoaded:
this.$eventEmitter.on(events.DataLoaded, cb, context);
break;
case events.ViewLoaded:
this.$eventEmitter.on(events.ViewLoaded, cb, context);
break;
case events.StateLoaded:
this.$eventEmitter.on(events.StateLoaded, cb, context);
break;
@ -286,15 +298,16 @@ class JMap {
case events.OptionUpdate:
this.$eventEmitter.on(events.OptionUpdate, cb, context);
break;
case events.Reflect:
this.$controller.on(events.Reflect, _.throttle(cb, 200), context);
break;
case events.Selected:
this.$controller.on(events.Selected, cb, context);
break;
case events.ContextMenu:
this.$controller.on(events.ContextMenu, cb, context);
break;
case events.Reflect:
this.$controller.on(events.Reflect, _.throttle(cb, 200), context);
break;
case events.DataZoom:
this.$controller.on(events.DataZoom, cb, context);
break;
@ -318,6 +331,9 @@ class JMap {
case events.DataLoaded:
this.$eventEmitter.off(events.DataLoaded, cb, context);
break;
case events.ViewLoaded:
this.$eventEmitter.off(events.ViewLoaded, cb, context);
break;
case events.StateLoaded:
this.$eventEmitter.off(events.StateLoaded, cb, context);
break;
@ -330,15 +346,16 @@ class JMap {
case events.OptionUpdate:
this.$eventEmitter.off(events.OptionUpdate, cb, context);
break;
case events.Reflect:
this.$controller.off(events.Reflect, _.throttle(cb, 200));
break;
case events.Selected:
this.$controller.off(events.Selected, cb);
break;
case events.ContextMenu:
this.$controller.off(events.ContextMenu, cb);
break;
case events.Reflect:
this.$controller.off(events.Reflect, _.throttle(cb, 200));
break;
case events.DataZoom:
this.$controller.off(events.DataZoom, cb);
break;

View File

@ -2,28 +2,41 @@ import * as graphic from './core/graphic';
import shapeLayer from './constant/shapeLayer';
import Group from 'zrender/src/container/Group';
import TransformHandle from './transformHandle';
import AnimateHandle from './animateHandle';
class Painter extends Group {
constructor(map) {
super({name: `__Container__` });
// 添加父级图层
const zr = map.getZr();
zr.add(this);
// 初始图层
this.initLevels(map);
// 视图控制器
this.$transformHandle = new TransformHandle(this);
// 动画处理器
this.$animateHandle = new AnimateHandle(this);
// 重新动画函数,加入钩子
this.onframe(zr);
}
onframe(zr) {
const onframe = zr.animation.onframe;
const animateHandle = this.$animateHandle;
zr.animation.onframe = (...args) => {
onframe.apply(zr.animation, args);
animateHandle.onframe(...args);
}
}
initLevels(map) {
// 初始化图层对象
this.mapShapeLayer = {};
// 获取顶层图层
this.$zr = map.getZr();
// 添加父级图层
this.$zr.add(this);
// 创建select图层
this.mapShapeLayer[shapeLayer.Selecting] = new Group({ name: shapeLayer.Selecting });
@ -58,10 +71,10 @@ class Painter extends Group {
}
}
update(shape) {
if (shape) {
//
}
update(stateList=[]) {
stateList.forEach(state => {
this.$animateHandle.animate(state);
})
}
updateTransform(opt) {
@ -100,6 +113,7 @@ class Painter extends Group {
destroy() {
this.clear();
this.mapShapeLayer = {};
this.mapAnimate = {};
}
}

View File

@ -5,8 +5,24 @@ export default class StateHandle {
}
parse(shapeFactory, state) {
console.log(shapeFactory, state);
return state;
const mapTemplate = shapeFactory.getMapTemplate();
const template = mapTemplate[state.type];
const templateState = template.mapState[state.status];
return {
...state,
...templateState,
shape: shapeFactory.getShapeByCode(state.code),
frameList: templateState.frameList.map(frame => {
return Object.fromEntries(frame.map(el => {
const mapState = template.mapShape[el.name];
return [el.name, {
...el,
...mapState[el.status]
}]
}));
})
}
}
update(shapeFactory, states=[]) {
@ -17,7 +33,7 @@ export default class StateHandle {
// this.updateState(this.parse(shapeFactory, state)), // 处理自身
// this.updateState(this.parse(shapeFactory, state)) // 处理依赖
];
}, []);
}, []).sort((a,b) => a.weight - b.weight);
}
updateState(state={}) {

View File

@ -93,7 +93,10 @@ export default {
});
Vue.prototype.$iscs = this.$iscs;
this.$iscs.on('viewLoaded', this.onUpdate, this);
this.$iscs.on('contextmenu', this.onContextMenu, this);
this.$iscs.on('selected', this.onSelected, this);
this.$iscs.on('keyboard', this.onKeyboard, this);
this.$iscs.setMap([
{
type: 'Device',
@ -104,7 +107,10 @@ export default {
{ name: 'a',
type: 'Rect',
shape: {},
style: {},
style: {
fill: 'red',
stroke: 'black'
},
stateList: [
{ status: 'st1', shape: {}, style:{ fill: 'yellow', stroke: 'black'} },
{ status: 'st2', shape: {}, style:{ fill: 'blue', stroke: 'black'} }
@ -113,7 +119,10 @@ export default {
{ name: 'b',
type: 'Circle',
shape: {},
style: {},
style: {
fill: 'red',
stroke: 'black'
},
stateList: [
{ status: 'st1', shape: {}, style:{ fill: 'yellow', stroke: 'black'} },
{ status: 'st2', shape: {}, style:{ fill: 'blue', stroke: 'black'} }
@ -121,8 +130,8 @@ export default {
},
],
stateList: [
{ status: 's1', frameList: [[{name: 'a', status: 'st1'}, {name: 'b', status: 'st1'}], [{name: 'a', status: 'st2'}, {name: 'b', status: 'st2'}]], weight: 2, needDefault: false, loop: true },
{ status: 's2', frameList: [[{name: 'a', status: 'st2'}, {name: 'b', status: 'st1'}], [{name: 'a', status: 'st1'}, {name: 'b', status: 'st2'}]], weight: 2, needDefault: false, lopp: false }
{ status: 's1', frameList: [[{name: 'a', status: 'st1'}, {name: 'b', status: 'st1'}], [{name: 'a', status: 'st2'}, {name: 'b', status: 'st2'}]], weight: 2, loop: true, delay: 2000, time: 200, needDefault: false },
{ status: 's2', frameList: [[{name: 'a', status: 'st2'}, {name: 'b', status: 'st1'}], [{name: 'a', status: 'st1'}, {name: 'b', status: 'st2'}]], weight: 1, loop: true, delay: 5000, time: 500, needDefault: true }
]
}
], {
@ -268,7 +277,7 @@ export default {
scale: [0.5, 0.5],
position: [100, 100],
rotation: Math.PI/2,
composeCode: '1000',
// composeCode: '1000',
},
{
code: '101',
@ -277,17 +286,17 @@ export default {
scale: [1, 1],
position: [200, 0],
rotation: 0,
composeCode: '1000'
// composeCode: '1000'
},
{
code: '1000',
type: 'Device',
scale: [1, 1],
position: [0, 0],
rotation: 0,
elementCodes: ['100', '101'],
composeCode: ''
}
// {
// code: '1000',
// type: 'Device',
// scale: [1, 1],
// position: [0, 0],
// rotation: 0,
// elementCodes: ['100', '101'],
// composeCode: ''
// }
]
}, {
panEnable: true,
@ -299,18 +308,17 @@ export default {
reflect: true
});
this.$iscs.update([
{ status: 's1', frameList: [[{name: 'a', status: 'st1'}, {name: 'b', status: 'st1'}], [{name: 'a', status: 'st2'}, {name: 'b', status: 'st2'}]], weight: 2, needDefault: false, loop: true },
{ status: 's2', frameList: [[{name: 'a', status: 'st2'}, {name: 'b', status: 'st1'}], [{name: 'a', status: 'st1'}, {name: 'b', status: 'st2'}]], weight: 2, needDefault: false, lopp: false }
]);
this.$iscs.on('contextmenu', this.onContextMenu, this);
this.$iscs.on('selected', this.onSelected, this);
this.$iscs.on('keyboard', this.onKeyboard, this);
window.document.oncontextmenu = function () {
return false;
};
},
onUpdate(e) {
this.$iscs.update([
{ status: 's1', code: '100', type: 'Device' },
{ status: 's2', code: '101', type: 'Device' }
]);
},
//
onKeyboard(hook) {
console.log(hook);