You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

150 lines
4.7 KiB
JavaScript

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);