UNPKG

cvs

Version:

A basic canvas framework for 2d drawing.

130 lines (126 loc) 3.27 kB
import Element from './element' import { animFrame, cancelAnim, arrSort2, forArr, remove, getItem, error, createCtx } from './utils/utils' import { loadTexture } from './utils/resource' let id = 0 class Layer { constructor (opt) { this.id = id++ this.children = [] // 根据 zIndex 升序排列的子元素 this.stop = null // 定时器 this.initAnimateTime = 0 // 动画初始时间 this.pauseTime = 0 // 暂定总时间 this.finishedAinmCount = 0 // 已完成动画的元素个数 this.isPause = false // 动画是否被暂停 Object.assign(this, { zIndex: 0, handleEvent: true }, opt) this.init() } async preload (obj) { const tasks = [], res = {} for (let key in obj) { tasks.push( loadTexture(key, obj[key]).then(r => { res[key] = r }) ) } await Promise.all(tasks) return res } init () { this.width = this.container.clientWidth this.height = this.container.clientHeight this.ctx = createCtx(this.width, this.height) this.ctx.canvas.style.cssText = `position: absolute; top: 0px; left: 0px;z-index:${ this.zIndex }` this.container.appendChild(this.ctx.canvas) } element (id) { return getItem(this.children, id) } // 触发子元素的事件监听 emitEvent (children, e) { forArr( children, child => { child.emit && child.emit(e) if (child.children && child.children.length > 0) { // 组合内的元素位置相对于组合计算 e.x -= child.attr('x') e.y -= child.attr('y') this.emitEvent(child.children, e) } }, true ) } // 分发事件 dispatchEvent (evtArgs) { let e = evtArgs.originalEvent const { left, top } = e.target.getBoundingClientRect() const { clientX, clientY } = e.changedTouches ? e.changedTouches[0] : e // zIndex 大的元素先触发监听事件,父元素优先于子元素触发 this.emitEvent( this.children, Object.assign(evtArgs, { x: Math.round((clientX | 0) - left), y: Math.round((clientY | 0) - top) }) ) } append (...elements) { elements.forEach(child => { if (!(child instanceof Element)) { error('Function add only accept the instance of Element.') } child._layer = this child._ctx = this.ctx child._timeline = this.timeline.fork() this.children.push(child) arrSort2(this.children, 'zIndex') }) return this } remove (...elements) { if (elements.length) { elements.forEach(child => { remove(this.children, child) }) } else this.children = [] } draw () { this.children.forEach(child => { if (child.attr('visible')) { child.render.call(child, this.ctx) } }) } clear () { this.ctx.clearRect(0, 0, this.width, this.height) } animate () { var that = this animFrame(function loopUnit () { that.stop = animFrame(loopUnit) that.clear() forArr(that.children, child => { if (child.animatable) child.animate() }) that.draw() }) } cancelAnimate () { if (this.stop) cancelAnim(this.stop) } } export default Layer