diff --git a/src/iscs_new/animateHandle.js b/src/iscs_new/animateHandle.js new file mode 100644 index 000000000..28d8a6c1b --- /dev/null +++ b/src/iscs_new/animateHandle.js @@ -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 \ No newline at end of file diff --git a/src/iscs_new/factory/element.js b/src/iscs_new/factory/element.js index 982942e59..2ce6112bf 100644 --- a/src/iscs_new/factory/element.js +++ b/src/iscs_new/factory/element.js @@ -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(); } } diff --git a/src/iscs_new/factory/index.js b/src/iscs_new/factory/index.js index b03708db1..34dc0f52e 100644 --- a/src/iscs_new/factory/index.js +++ b/src/iscs_new/factory/index.js @@ -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) { diff --git a/src/iscs_new/factory/templateParser.js b/src/iscs_new/factory/templateParser.js index eb8c3381a..93dd0b04c 100644 --- a/src/iscs_new/factory/templateParser.js +++ b/src/iscs_new/factory/templateParser.js @@ -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={}) { diff --git a/src/iscs_new/map.js b/src/iscs_new/map.js index 99eeaeb3c..62a6d70ff 100644 --- a/src/iscs_new/map.js +++ b/src/iscs_new/map.js @@ -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; diff --git a/src/iscs_new/painter.js b/src/iscs_new/painter.js index e414e40fc..99920cf9d 100644 --- a/src/iscs_new/painter.js +++ b/src/iscs_new/painter.js @@ -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 = {}; } } diff --git a/src/iscs_new/stateHandle.js b/src/iscs_new/stateHandle.js index d4efff54f..c8e001383 100644 --- a/src/iscs_new/stateHandle.js +++ b/src/iscs_new/stateHandle.js @@ -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={}) { diff --git a/src/views/test/index.vue b/src/views/test/index.vue index 41fcd077b..d08f9ef1d 100644 --- a/src/views/test/index.vue +++ b/src/views/test/index.vue @@ -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);