StructureJS
0.15.2A class based utility library for building modular and scalable web platform applications. Features opt-in classes and utilities which provide a solid foundation and toolset to build your next project.
import DisplayObjectContainer from './DisplayObjectContainer'; import DOMElement from './DOMElement'; import DisplayObject from './DisplayObject'; import Point from '../geom/Point'; class CanvasElement extends DOMElement { public $canvas:JQuery = null; public canvas:HTMLCanvasElement = null; // Notice the capital W and H. That sets the attributes not the styles. constructor(type:any = 'canvas', params:any = {Width: 100, Height: 100}) { super(type, params); } /** * @overridden CanvasElement.create */ public create():void { super.create(); this.$canvas = this.$element; this.canvas = <HTMLCanvasElement>this.element; this.ctx = this.canvas.getContext('2d'); } /** * @overridden CanvasElement.enable */ public enable():void { if (this.isEnabled === true) { return; } // Add mouse event listeners to $canvas element this.$canvas.addEventListener('mousedown', this._onPointerDown, this); this.$canvas.addEventListener('mousemove', this._onPointerMove, this); this.$canvas.addEventListener('mouseup', this._onPointerUp, this); this.$canvas.addEventListener('mouseout', this._onPointerOut, this); // Add touch event listeners to $canvas element this.$canvas.addEventListener('touchstart', this._onPointerDown, this); this.$canvas.addEventListener('touchmove', this._onPointerMove, this); this.$canvas.addEventListener('touchend', this._onPointerUp, this); this.$canvas.addEventListener('touchcancel', this._onPointerOut, this); super.enable(); } /** * @overridden CanvasElement.disable */ public disable():void { if (this.isEnabled === false) { return; } // Remove mouse event listeners on $canvas element this.$canvas.removeEventListener('mousedown', this._onPointerDown, this); this.$canvas.removeEventListener('mousemove', this._onPointerMove, this); this.$canvas.removeEventListener('mouseup', this._onPointerUp, this); this.$canvas.removeEventListener('mouseout', this._onPointerOut, this); // Remove touch event listeners on $canvas element this.$canvas.removeEventListener('touchstart', this._onPointerDown, this); this.$canvas.removeEventListener('touchmove', this._onPointerMove, this); this.$canvas.removeEventListener('touchend', this._onPointerUp, this); this.$canvas.removeEventListener('touchcancel', this._onPointerOut, this); super.disable(); } /** * @overridden DOMElement.addChild */ public addChild(child:DisplayObject):any { //If the child being passed in already has a parent then remove the reference from there. if (child.parent) { child.parent.removeChild(child, false); } this.children.push(child); this.numChildren = this.children.length; child.ctx = this.ctx; child.stage = this; child.parent = this; if (child.isCreated === false) { child.create(); child.isCreated = true; } child.enable(); return this; } /** * @overridden DOMElement.addChildAt */ public addChildAt(child:DisplayObject, index:number):any { //If the child being passed in already has a parent then remove the reference from there. if (child.parent) { child.parent.removeChild(child, false); } this.children.splice(index, 0, child); this.numChildren = this.children.length; child.ctx = this.ctx; child.stage = this; child.parent = this; if (child.isCreated === false) { child.create(); child.isCreated = true; } child.enable(); return this; } /** * @overridden DOMElement.swapChildren */ public swapChildren(child1:DisplayObject, child2:DisplayObject):any { const child1Index = this.children.indexOf(child1); const child2Index = this.children.indexOf(child2); this.addChildAt(child1, child2Index); this.addChildAt(child2, child1Index); return this; } /** * @overridden DOMElement.getChildAt */ public getChildAt(index:number):any { return <any>super.getChildAt(index); } /** * @overridden DOMElement.removeChild */ public removeChild(child:DisplayObject, destroy:boolean = true):any { const index = this.getChildIndex(child); if (index !== -1) { // Removes the child object from the parent. this.children.splice(index, 1); } this.numChildren = this.children.length; if (destroy === true) { child.destroy(); } else { child.disable(); } child.ctx = null; child.stage = null; child.parent = null; return this; } /** * @overridden DOMElement.removeChildAt */ public removeChildAt(index:number, destroy:boolean = true):any { this.removeChild(this.getChildAt(index), destroy); return this; } /** * @overridden DOMElement.removeChildren */ public removeChildren(destroy:boolean = true):any { while (this.children.length > 0) { this.removeChild(this.children.pop(), destroy); } return this; } public renderCanvas():any { this.ctx.clearRect(0, 0, this.width, this.height); for (let i:number = 0; i < this.numChildren; i++) { this.children[i].renderCanvas(); } } public getMousePos(event:MouseEvent|JQueryEventObject):Point { const rect = this.canvas.getBoundingClientRect(); return new Point(event.clientX - rect.left, event.clientY - rect.top); } public getObjectUnderPoint(x:number, y:number):DisplayObject { let foundItem:DisplayObject = null; let sprite:DisplayObject; for (let i = this.numChildren - 1; i >= 0; i--) { sprite = this.children[i]; if (sprite.visible === true && sprite.mouseEnabled === true) { if (this.hitTest(sprite, x, y)) { foundItem = sprite; break; } } } return foundItem; } public getObjectsUnderPoint(x:number, y:number):Array<DisplayObject> { const list:Array<DisplayObject> = []; let sprite:DisplayObject; for (let i = this.numChildren - 1; i >= 0; i--) { sprite = this.children[i]; if (this.hitTest(sprite, x, y)) { list.push(sprite); } } return list; } public hitTest(sprite:DisplayObject, mouseX:number, mouseY:number):boolean { if (mouseX >= sprite.x && mouseX <= sprite.x + sprite.width && mouseY >= sprite.y && mouseY <= sprite.y + sprite.height) { return true; } else { return false; } } protected _onPointerDown(event:MouseEvent|JQueryEventObject):void { this._sendEvent(event); } protected _onPointerUp(event:MouseEvent|JQueryEventObject):void { this._sendEvent(event); } protected _onPointerMove(event:MouseEvent|JQueryEventObject):void { const displayObject:DisplayObject = this._sendEvent(event); if (displayObject != null && displayObject.useHandCursor === true && displayObject.visible === true) { document.body.style.cursor = 'pointer'; } else { document.body.style.cursor = 'default'; } } protected _onPointerOut(event:MouseEvent|JQueryEventObject):void { this._sendEvent(event); } protected _sendEvent(event:MouseEvent|JQueryEventObject):DisplayObject { const mousePos:Point = this.getMousePos(event); let displayObject:DisplayObject = this.getObjectUnderPoint(mousePos.x, mousePos.y); if (displayObject === null) { event.bubbles = true; event.target = <any>this; event.currentTarget = <any>this; this.dispatchEvent(event); } else if (displayObject !== null && displayObject instanceof DisplayObjectContainer && (<DisplayObjectContainer>displayObject).mouseChildren === true) { event.currentTarget = <any>displayObject; displayObject = this._getActualClickedOnChild(<DisplayObjectContainer>displayObject, mousePos.x, mousePos.y); event.bubbles = true; event.target = <any>displayObject; displayObject.dispatchEvent(event); } else { event.bubbles = true; event.target = <any>displayObject; event.currentTarget = <any>this; displayObject.dispatchEvent(event); } return displayObject; } protected _getActualClickedOnChild(displayObject:DisplayObjectContainer, x:number, y:number):any { let item; let newX:number; let newY:number; if (displayObject.numChildren > 0) { for (let i = displayObject.numChildren - 1; i >= 0; i--) { item = displayObject.children[i]; if (item.visible === true) { newX = x - item.parent.x; newY = y - item.parent.y; if (this.hitTest(item, newX, newY)) { return this._getActualClickedOnChild(item, newX, newY); } } } } else { return displayObject; } } } export default CanvasElement;