class DpadWidget extends BaseWidget { $el; #posX = 0; #posY = 0; #pressed = false; #_onTouchStart; #_onTouchEnd; #_onMouseDown; #_onMouseUp; constructor(data, renderer) { super(data, renderer); this.makeLayout({ type: 'canvas', name: 'el' }); if (!this.data.color) this.data.color = colToInt(window.getComputedStyle(document.body).getPropertyValue('--prim')); if ("ontouchstart" in document.documentElement) { this.#_onTouchStart = this.#onTouchStart.bind(this); this.#_onTouchEnd = this.#onTouchEnd.bind(this); this.$el.addEventListener("touchstart", this.#_onTouchStart); document.addEventListener("touchend", this.#_onTouchEnd); } else { this.#_onMouseDown = this.#onMouseDown.bind(this); this.#_onMouseUp = this.#onMouseUp.bind(this); this.$el.addEventListener("mousedown", this.#_onMouseDown); document.addEventListener("mouseup", this.#_onMouseUp); } this.$el.parentNode.addEventListener('resize', () => { this.#redraw(); }) this.update(data); this.disable(this.$el, data.disable); waitFrame().then(() => { this.#redraw(false); }); } close() { if ("ontouchstart" in document.documentElement) { this.$el.removeEventListener("touchstart", this.#_onTouchStart); document.removeEventListener("touchend", this.#_onTouchEnd); } else { this.$el.removeEventListener("mousedown", this.#_onMouseDown); document.removeEventListener("mouseup", this.#_onMouseUp); } } #redraw(send = true) { const cv = this.$el; let size = cv.parentNode.clientWidth; if (!size) return; cv.style.width = size + 'px'; cv.style.height = size + 'px'; size *= window.devicePixelRatio; const center = size / 2; cv.width = size; cv.height = size; cv.style.cursor = 'pointer'; let x = 0; let y = 0; if (this.#pressed) { x = Math.round((this.#posX - center) / center * 255); y = -Math.round((this.#posY - center) / center * 255); if (Math.abs(x) < 50 && Math.abs(y) < 50) { x = 0; y = 0; } else { if (Math.abs(x) > Math.abs(y)) { x = Math.sign(x); y = 0; } else { x = 0; y = Math.sign(y); } } } const cx = cv.getContext("2d"); cx.clearRect(0, 0, size, size); cx.beginPath(); cx.arc(center, center, size * 0.44, 0, 2 * Math.PI, false); cx.lineWidth = size * 0.02; cx.strokeStyle = intToCol(this.#pressed ? adjustColor(this.data.color, 1.3) : this.data.color); cx.stroke(); cx.lineWidth = size * 0.045; const rr = size * 0.36; const cw = size * 0.1; const ch = rr - cw; const sh = [[1, 0], [-1, 0], [0, 1], [0, -1]]; for (let i = 0; i < 4; i++) { cx.beginPath(); cx.strokeStyle = intToCol((x == sh[i][0] && y == -sh[i][1]) ? adjustColor(this.data.color, 1.3) : this.data.color); cx.moveTo(center + ch * sh[i][0] - cw * sh[i][1], center + ch * sh[i][1] - cw * sh[i][0]); cx.lineTo(center + rr * sh[i][0], center + rr * sh[i][1]); cx.lineTo(center + ch * sh[i][0] + cw * sh[i][1], center + ch * sh[i][1] + cw * sh[i][0]); cx.stroke(); } if (send) this.set((x + 255) << 16) | (y + 255); } #onTouchStart(event) { if (this.data.disable) return; event.preventDefault(); this.#pressed = true; const ratio = window.devicePixelRatio; this.#posX = (event.targetTouches[0].pageX - this.$el.offsetLeft) * ratio; this.#posY = (event.targetTouches[0].pageY - this.$el.offsetTop) * ratio; this.#redraw(); } #onMouseDown(event) { if (this.data.disable) return; this.#pressed = true; const ratio = window.devicePixelRatio; this.#posX = (event.pageX - this.$el.offsetLeft) * ratio; this.#posY = (event.pageY - this.$el.offsetTop) * ratio; this.#redraw(); } #onTouchEnd() { if (this.#pressed) { this.#pressed = false; this.#redraw(); } } #onMouseUp() { if (this.#pressed) { this.#pressed = false; this.#redraw(); } } } Renderer.register('dpad', DpadWidget);