import Node from "./Node"; import NodeEvent from "./NodeEvent"; export default class Canvas { public context : CanvasRenderingContext2D; public canvas : HTMLCanvasElement; public width : number; public height : number; public rootNode = new Node("Root"); public nodes: [Node,number][] = []; public pool : DrawPool = new DrawPool(); public constructor() { this.canvas = document.createElement("canvas"); this.context = this.canvas.getContext("2d") as CanvasRenderingContext2D; this.installMouseManager(); this.installKeyboardManager(); } public init() { this.canvas.style.imageRendering = "pixelated"; window.document.body.appendChild(this.canvas); this.recalculateSize(); window.addEventListener("resize",() => this.recalculateSize()); this.pool.trigger = () => this.drawContext(); } public installMouseManager() { this.canvas.addEventListener("mousedown",(event) => { let mouseEvent = new NodeEvent(); mouseEvent.x = event.offsetX; mouseEvent.y = event.offsetY; mouseEvent.type = "mouse:down"; this.rootNode.emit("mouse", mouseEvent); }); this.canvas.addEventListener("mousemove",(event) => { let mouseEvent = new NodeEvent(); mouseEvent.x = event.offsetX; mouseEvent.y = event.offsetY; mouseEvent.data = { deltaX: event.movementX, deltaY: event.movementY }; mouseEvent.type = "mouse:move"; this.rootNode.emit("mouse", mouseEvent); }); this.canvas.addEventListener("mouseup",(event) => { let mouseEvent = new NodeEvent(); mouseEvent.x = event.offsetX; mouseEvent.y = event.offsetY; mouseEvent.type = "mouse:up"; this.rootNode.emit("mouse", mouseEvent); }); this.canvas.addEventListener("click",(event) => { let mouseEvent = new NodeEvent(); mouseEvent.x = event.offsetX; mouseEvent.y = event.offsetY; mouseEvent.type = "mouse:click"; this.rootNode.emit("mouse", mouseEvent); }); this.canvas.addEventListener("wheel",(event) => { let mouseEvent = new NodeEvent(); mouseEvent.x = event.offsetX; mouseEvent.y = event.offsetY; mouseEvent.data = { xModulus: event.deltaX == 0 ? 0 : event.deltaX < 0 ? -1 : +1, yModulus: event.deltaY == 0 ? 0 : event.deltaY < 0 ? -1 : +1, xScroll: event.deltaX, yScroll: event.deltaY }; mouseEvent.type = "mouse:wheel"; this.rootNode.emit("mouse", mouseEvent); }); } public installKeyboardManager() { } public recalculateSize() { let { width, height } = document.body.getClientRects()[0]; this.canvas.setAttribute("width", width + "px"); this.canvas.setAttribute("height", height + "px"); this.canvas.style.width = width + "px"; this.canvas.style.height = height + "px"; this.width = width; this.height = height this.pool.notify(); } public addNode(node:Node, priority : number= 0) { this.nodes.push([node,priority]); node.on('draw',() => { this.pool.notify(); }); this.pool.notify(); } public drawContext() { this.rootNode.width = this.width; this.rootNode.height = this.height; this.rootNode.ChildNodes = this.nodes.sort(([,n], [,k]) => n - k).map(e => e[0]); this.context.clearRect(0, 0, this.width, this.height); this.rootNode.context.resize(this.rootNode.width, this.rootNode.height); this.rootNode.draw().writeTo( this.context, 0, 0, this.rootNode.width, this.rootNode.height, 0, 0, this.rootNode.width, this.rootNode.height ); } }; class DrawPool { public busy : boolean = true; public trigger : Function; public inf : number = -1; public addPool(e:Function) { if(!this.busy) { this.notify() }else this.trigger = e; } public notify() { this.busy = true; this.inf = requestAnimationFrame(() => { if(this.trigger) { this.trigger(); } this.busy = false; }); } }