mirror of
https://github.com/GEEKiDoS/polaris-touch.git
synced 2026-09-22 22:47:58 +03:00
use pointer api
This commit is contained in:
+38
-84
@@ -1,6 +1,6 @@
|
||||
import "./style.css"
|
||||
|
||||
import { TouchManager } from "./touch-manager";
|
||||
import { TouchManager, type Finger } from "./touch-manager";
|
||||
import { SpiceConnection } from "./spice-connection";
|
||||
import { listenHold } from "./listen-hold";
|
||||
|
||||
@@ -108,7 +108,7 @@ const lanes = Array.from(document.querySelectorAll<HTMLDivElement>(".lane>div"))
|
||||
const faderPositions = Array.from(document.querySelectorAll<HTMLDivElement>(".fader .position"));
|
||||
|
||||
const laneState = new Array(12).fill(false);
|
||||
const faderTouches: Array<Touch | null> = [null, null];
|
||||
const faderTouches: Array<Finger | null> = [null, null];
|
||||
const lastFaderPositions: Array<number | null> = [null, null];
|
||||
const faderDirs = [0, 0];
|
||||
const faderAnalogs = [0.51, 0.51];
|
||||
@@ -165,102 +165,60 @@ function updateFaderAnalog() {
|
||||
}
|
||||
}
|
||||
|
||||
let laneTouches: number[][] = new Array(12).fill([]);
|
||||
function updateLaneState() {
|
||||
for (let i = 0; i < 12; i++) {
|
||||
laneState[i] = !!laneTouches[i].length;
|
||||
}
|
||||
}
|
||||
window.touchMgr.onTouchStart = (finger) => {
|
||||
const x = finger.x / document.body.clientWidth;
|
||||
const y = finger.y / document.body.clientHeight;
|
||||
|
||||
function removeTouches(touches: Touch[]): boolean {
|
||||
// remove ended touches
|
||||
let changed = false;
|
||||
|
||||
// remove changed touches
|
||||
for (let i = 0; i < 12; i++) {
|
||||
const oldLen = laneTouches[i].length;
|
||||
laneTouches[i] =
|
||||
laneTouches[i].filter(v => touches.findIndex(t => t.identifier == v) == -1);
|
||||
|
||||
if (oldLen != laneTouches[i].length) {
|
||||
changed = true;
|
||||
}
|
||||
if (y > 0.35) {
|
||||
return;
|
||||
}
|
||||
|
||||
return changed
|
||||
}
|
||||
// find new touch for binding to fader
|
||||
if (faderTouches[1] && finger.x < faderTouches[1].x) {
|
||||
faderTouches[0] = finger;
|
||||
} else if (x < 0.5 && !faderTouches[0]) {
|
||||
faderTouches[0] = finger;
|
||||
}
|
||||
|
||||
window.touchMgr.onTouchStart = (touches) => {
|
||||
const touchArr = Array.from(touches);
|
||||
|
||||
for (const touch of touchArr) {
|
||||
const x = touch.clientX / document.body.clientWidth;
|
||||
const y = touch.clientY / document.body.clientHeight;
|
||||
|
||||
if (y > 0.5) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// find new touch for binding to fader
|
||||
if (faderTouches[1] && touch.clientX < faderTouches[1].clientX) {
|
||||
faderTouches[0] = touch;
|
||||
} else if (x < 0.5 && !faderTouches[0]) {
|
||||
faderTouches[0] = touch;
|
||||
}
|
||||
|
||||
if (faderTouches[0] && touch.clientX > faderTouches[0].clientX) {
|
||||
faderTouches[1] = touch;
|
||||
} else if (x > 0.5 && !faderTouches[1]) {
|
||||
faderTouches[1] = touch;
|
||||
}
|
||||
if (faderTouches[0] && finger.x > faderTouches[0].x) {
|
||||
faderTouches[1] = finger;
|
||||
} else if (x > 0.5 && !faderTouches[1]) {
|
||||
faderTouches[1] = finger;
|
||||
}
|
||||
};
|
||||
|
||||
window.touchMgr.onTouchChange = (touches, noSend) => {
|
||||
const touchArr = Array.from(touches);
|
||||
let changed = removeTouches(touchArr);
|
||||
window.touchMgr.onTouchChange = (fingers) => {
|
||||
laneState.fill(false);
|
||||
|
||||
for (const touch of touchArr) {
|
||||
const x = touch.clientX / document.body.clientWidth;
|
||||
const y = touch.clientY / document.body.clientHeight;
|
||||
for (const finger of fingers) {
|
||||
const x = finger.x / document.body.clientWidth;
|
||||
const y = finger.y / document.body.clientHeight;
|
||||
|
||||
// update touch bounded to fader
|
||||
if (touch.identifier == faderTouches[0]?.identifier) {
|
||||
faderTouches[0] = touch;
|
||||
if (finger.id == faderTouches[0]?.id) {
|
||||
faderTouches[0] = finger;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (touch.identifier == faderTouches[1]?.identifier) {
|
||||
faderTouches[1] = touch;
|
||||
if (finger.id == faderTouches[1]?.id) {
|
||||
faderTouches[1] = finger;
|
||||
continue;
|
||||
}
|
||||
|
||||
// lane area touches
|
||||
if (y < 0.5) {
|
||||
if (y < 0.35) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const column = Math.max(0, Math.min(Math.floor(x * 12), 11));
|
||||
laneTouches[column].push(touch.identifier);
|
||||
changed = true;
|
||||
}
|
||||
|
||||
if (changed) {
|
||||
updateLaneState();
|
||||
if (!noSend) sendButtonState(laneState);
|
||||
laneState[column] = true;
|
||||
}
|
||||
|
||||
sendButtonState(laneState);
|
||||
frames++;
|
||||
};
|
||||
|
||||
window.touchMgr.onTouchEnd = (touches) => {
|
||||
const touchArr = Array.from(touches);
|
||||
const changed = removeTouches(touchArr);
|
||||
if (changed) {
|
||||
updateLaneState();
|
||||
sendButtonState(laneState);
|
||||
}
|
||||
|
||||
window.touchMgr.onTouchEnd = (finger) => {
|
||||
// remove fader touches
|
||||
for (let i = 0; i < 2; i++) {
|
||||
const faderTouch = faderTouches[i];
|
||||
@@ -268,19 +226,15 @@ window.touchMgr.onTouchEnd = (touches) => {
|
||||
continue
|
||||
}
|
||||
|
||||
for (const touch of touchArr) {
|
||||
if (faderTouch.identifier !== touch.identifier) {
|
||||
continue
|
||||
}
|
||||
|
||||
faderTouches[i] = null;
|
||||
lastFaderPositions[i] = null;
|
||||
faderDirs[i] = 0;
|
||||
break;
|
||||
if (faderTouch.id !== finger.id) {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
frames++;
|
||||
faderTouches[i] = null;
|
||||
lastFaderPositions[i] = null;
|
||||
faderDirs[i] = 0;
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
const update = () => {
|
||||
@@ -303,7 +257,7 @@ const update = () => {
|
||||
continue;
|
||||
}
|
||||
|
||||
const x = faderTouch.clientX - (i * areaWidth);
|
||||
const x = faderTouch.x - (i * areaWidth);
|
||||
const lastX = lastFaderPositions[i];
|
||||
if (lastX !== null) {
|
||||
const delta = x - lastX;
|
||||
|
||||
+2
-2
@@ -16,7 +16,7 @@ body {
|
||||
|
||||
.fader {
|
||||
display: flex;
|
||||
height: 50vh;
|
||||
height: 35vh;
|
||||
}
|
||||
|
||||
.fader>div {
|
||||
@@ -57,7 +57,7 @@ body {
|
||||
.lane {
|
||||
display: flex;
|
||||
background-color: #000;
|
||||
height: 50vh;
|
||||
height: 65vh;
|
||||
}
|
||||
|
||||
.lane>div {
|
||||
|
||||
+49
-90
@@ -1,119 +1,78 @@
|
||||
export type TouchEventCallback = (touches: ArrayLike<Touch>, noSend?: boolean) => void;
|
||||
export class TouchManager {
|
||||
onTouchEnd: TouchEventCallback | undefined = undefined;
|
||||
onTouchChange: TouchEventCallback | undefined = undefined;
|
||||
onTouchStart: TouchEventCallback | undefined = undefined;
|
||||
export interface Finger {
|
||||
id: number | string;
|
||||
x: number;
|
||||
y: number;
|
||||
}
|
||||
|
||||
touchStartTimes: Map<number | string, number> = new Map();
|
||||
export class TouchManager {
|
||||
onTouchStart: ((touch: Finger) => void) | undefined = undefined;
|
||||
onTouchChange: ((touches: Finger[]) => void) | undefined = undefined;
|
||||
onTouchEnd: ((touches: Finger) => void) | undefined = undefined;
|
||||
|
||||
touches: Map<number | string, Finger> = new Map();
|
||||
|
||||
constructor() {
|
||||
document.addEventListener("touchmove", (e) => {
|
||||
if (this.onTouchChange) {
|
||||
this.onTouchChange(e.changedTouches);
|
||||
}
|
||||
e.preventDefault();
|
||||
});
|
||||
|
||||
document.addEventListener("touchstart", (e) => {
|
||||
for (const touch of e.changedTouches) {
|
||||
this.touchStartTimes.set(touch.identifier, Date.now());
|
||||
}
|
||||
document.addEventListener("pointerdown", (e) => {
|
||||
const finger = {
|
||||
id: e.pointerId,
|
||||
x: e.clientX,
|
||||
y: e.clientY,
|
||||
};
|
||||
|
||||
if (this.onTouchStart) {
|
||||
this.onTouchStart(e.changedTouches);
|
||||
this.onTouchStart(finger);
|
||||
}
|
||||
|
||||
this.touches.set(e.pointerId, finger);
|
||||
const touches = Array.from(this.touches.values());
|
||||
|
||||
if (this.onTouchChange) {
|
||||
this.onTouchChange(e.changedTouches);
|
||||
this.onTouchChange(touches);
|
||||
}
|
||||
|
||||
e.preventDefault();
|
||||
});
|
||||
|
||||
document.addEventListener("touchend", (e) => {
|
||||
this.touchEnd(e.changedTouches);
|
||||
e.preventDefault();
|
||||
});
|
||||
|
||||
document.addEventListener("touchcancel", (e) => {
|
||||
this.touchEnd(e.changedTouches);
|
||||
e.preventDefault();
|
||||
});
|
||||
|
||||
document.addEventListener("mousedown", (e) => {
|
||||
const fakeTouch = {
|
||||
clientX: e.clientX,
|
||||
clientY: e.clientY,
|
||||
identifier: 'MOUSE' as any,
|
||||
} as Touch;
|
||||
|
||||
this.touchStartTimes.set(fakeTouch.identifier, Date.now());
|
||||
if (this.onTouchStart) {
|
||||
this.onTouchStart([fakeTouch]);
|
||||
}
|
||||
|
||||
if (this.onTouchChange) {
|
||||
this.onTouchChange([fakeTouch]);
|
||||
}
|
||||
});
|
||||
|
||||
document.addEventListener("mousemove", (e) => {
|
||||
if (!this.touchStartTimes.has('MOUSE')) {
|
||||
document.addEventListener("pointermove", (e) => {
|
||||
if (!this.touches.has(e.pointerId)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const fakeTouch = {
|
||||
clientX: e.clientX,
|
||||
clientY: e.clientY,
|
||||
identifier: 'MOUSE' as any,
|
||||
} as Touch;
|
||||
this.touches.set(e.pointerId, {
|
||||
id: e.pointerId,
|
||||
x: e.clientX,
|
||||
y: e.clientY,
|
||||
});
|
||||
|
||||
const touches = Array.from(this.touches.values());
|
||||
|
||||
if (this.onTouchChange) {
|
||||
this.onTouchChange([fakeTouch]);
|
||||
this.onTouchChange(touches);
|
||||
}
|
||||
|
||||
e.preventDefault();
|
||||
});
|
||||
|
||||
document.addEventListener("mouseup", (e) => {
|
||||
const fakeTouch = {
|
||||
clientX: e.clientX,
|
||||
clientY: e.clientY,
|
||||
identifier: 'MOUSE' as any,
|
||||
} as Touch;
|
||||
|
||||
this.touchEnd([fakeTouch]);
|
||||
document.addEventListener("pointerup", (e) => {
|
||||
this.touchEnd({
|
||||
id: e.pointerId,
|
||||
x: e.clientX,
|
||||
y: e.clientY,
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
touchEnd(changedTouches: TouchList | Touch[]) {
|
||||
touchEnd(finger: Finger) {
|
||||
this.touches.delete(finger.id);
|
||||
|
||||
const touches = Array.from(this.touches.values());
|
||||
|
||||
if (this.onTouchChange) {
|
||||
this.onTouchChange(changedTouches, true);
|
||||
this.onTouchChange(touches);
|
||||
}
|
||||
|
||||
const instaRelease = [];
|
||||
|
||||
for (const touch of changedTouches) {
|
||||
const startTime = this.touchStartTimes.get(touch.identifier);
|
||||
if (startTime == undefined) {
|
||||
throw new Error("?");
|
||||
}
|
||||
|
||||
const duration = Date.now() - startTime;
|
||||
this.touchStartTimes.delete(touch.identifier);
|
||||
|
||||
// delay touch end event if it releases too fast
|
||||
if (duration > 16) {
|
||||
instaRelease.push(touch);
|
||||
continue;
|
||||
}
|
||||
|
||||
setTimeout(() => {
|
||||
if (this.onTouchEnd) {
|
||||
this.onTouchEnd([touch]);
|
||||
}
|
||||
}, 16 - duration);
|
||||
}
|
||||
|
||||
if (this.onTouchEnd && instaRelease.length) {
|
||||
this.onTouchEnd(instaRelease);
|
||||
if (this.onTouchEnd) {
|
||||
this.onTouchEnd(finger);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user