Füge Unterstützung für Auswahlepochen hinzu, um die Auswahl bei Änderungen zu verwalten
This commit is contained in:
29
js/app.js
29
js/app.js
@@ -4,6 +4,7 @@ document.addEventListener('DOMContentLoaded', function(){
|
|||||||
let selecting = false;
|
let selecting = false;
|
||||||
let selectionDone = false;
|
let selectionDone = false;
|
||||||
let selectionTimer = null;
|
let selectionTimer = null;
|
||||||
|
let selectionEpoch = 0;
|
||||||
|
|
||||||
function createFinger(t){
|
function createFinger(t){
|
||||||
const id = (t.identifier !== undefined && t.identifier !== null) ? String(t.identifier) : ('m'+Date.now());
|
const id = (t.identifier !== undefined && t.identifier !== null) ? String(t.identifier) : ('m'+Date.now());
|
||||||
@@ -57,15 +58,16 @@ document.addEventListener('DOMContentLoaded', function(){
|
|||||||
|
|
||||||
function startSelectionIfNeeded(){
|
function startSelectionIfNeeded(){
|
||||||
if(selecting || selectionDone) return;
|
if(selecting || selectionDone) return;
|
||||||
if(touches.size < 1) return; // require at least 1 finger
|
if(touches.size < 1) return;
|
||||||
selecting = true;
|
selecting = true;
|
||||||
|
const epoch = selectionEpoch;
|
||||||
|
|
||||||
const {items} = computeOrderedItems();
|
const {items} = computeOrderedItems();
|
||||||
const els = items.map(i=>i.el);
|
const els = items.map(i=>i.el);
|
||||||
const n = els.length;
|
const n = els.length;
|
||||||
|
|
||||||
// If only one finger, immediately mark it as winner (short visual)
|
|
||||||
if(n === 1){
|
if(n === 1){
|
||||||
|
if(epoch !== selectionEpoch) return;
|
||||||
const el = els[0];
|
const el = els[0];
|
||||||
el.classList.add('winner','pulse');
|
el.classList.add('winner','pulse');
|
||||||
selecting = false;
|
selecting = false;
|
||||||
@@ -73,7 +75,7 @@ document.addEventListener('DOMContentLoaded', function(){
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const rotations = Math.floor(Math.random()*3)+3; // 3-5 rotations
|
const rotations = Math.floor(Math.random()*3)+3;
|
||||||
const winnerIndex = Math.floor(Math.random()*n);
|
const winnerIndex = Math.floor(Math.random()*n);
|
||||||
const totalSteps = rotations * n + winnerIndex;
|
const totalSteps = rotations * n + winnerIndex;
|
||||||
|
|
||||||
@@ -81,10 +83,11 @@ document.addEventListener('DOMContentLoaded', function(){
|
|||||||
let current = 0;
|
let current = 0;
|
||||||
for(let step=0; step<=totalSteps; step++){
|
for(let step=0; step<=totalSteps; step++){
|
||||||
const t = step/totalSteps;
|
const t = step/totalSteps;
|
||||||
const delay = 40 + Math.pow(t,2)*520; // ease-out timing
|
const delay = 40 + Math.pow(t,2)*520;
|
||||||
cumulative += delay;
|
cumulative += delay;
|
||||||
const idx = current % n;
|
const idx = current % n;
|
||||||
setTimeout(()=>{
|
setTimeout(()=>{
|
||||||
|
if(epoch !== selectionEpoch) return;
|
||||||
els.forEach((el,i)=>{
|
els.forEach((el,i)=>{
|
||||||
if(i===idx) el.classList.add('highlight'); else el.classList.remove('highlight');
|
if(i===idx) el.classList.add('highlight'); else el.classList.remove('highlight');
|
||||||
});
|
});
|
||||||
@@ -93,6 +96,7 @@ document.addEventListener('DOMContentLoaded', function(){
|
|||||||
}
|
}
|
||||||
|
|
||||||
setTimeout(()=>{
|
setTimeout(()=>{
|
||||||
|
if(epoch !== selectionEpoch) return;
|
||||||
els.forEach((el,i)=>{
|
els.forEach((el,i)=>{
|
||||||
if(i===winnerIndex){ el.classList.remove('highlight'); el.classList.add('winner','pulse'); }
|
if(i===winnerIndex){ el.classList.remove('highlight'); el.classList.add('winner','pulse'); }
|
||||||
else { el.classList.remove('highlight'); el.classList.add('lost'); }
|
else { el.classList.remove('highlight'); el.classList.add('lost'); }
|
||||||
@@ -103,6 +107,7 @@ document.addEventListener('DOMContentLoaded', function(){
|
|||||||
}
|
}
|
||||||
|
|
||||||
function cancelSelection(){
|
function cancelSelection(){
|
||||||
|
selectionEpoch++;
|
||||||
clearTimeout(selectionTimer);
|
clearTimeout(selectionTimer);
|
||||||
selectionTimer = null;
|
selectionTimer = null;
|
||||||
selecting = false;
|
selecting = false;
|
||||||
@@ -113,6 +118,7 @@ document.addEventListener('DOMContentLoaded', function(){
|
|||||||
function resetWhenAllUp(){
|
function resetWhenAllUp(){
|
||||||
if(touches.size===0){
|
if(touches.size===0){
|
||||||
setTimeout(()=>{
|
setTimeout(()=>{
|
||||||
|
if(touches.size > 0) return;
|
||||||
selecting=false; selectionDone=false;
|
selecting=false; selectionDone=false;
|
||||||
const nodes = Array.from(stage.querySelectorAll('.finger'));
|
const nodes = Array.from(stage.querySelectorAll('.finger'));
|
||||||
nodes.forEach(node=>node.remove());
|
nodes.forEach(node=>node.remove());
|
||||||
@@ -126,10 +132,8 @@ document.addEventListener('DOMContentLoaded', function(){
|
|||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
const changed = Array.from(e.changedTouches || []);
|
const changed = Array.from(e.changedTouches || []);
|
||||||
changed.forEach(t=>createFinger(t));
|
changed.forEach(t=>createFinger(t));
|
||||||
if(!selectionDone){
|
cancelSelection();
|
||||||
clearTimeout(selectionTimer);
|
selectionTimer = setTimeout(startSelectionIfNeeded, 700);
|
||||||
selectionTimer = setTimeout(startSelectionIfNeeded, 700);
|
|
||||||
}
|
|
||||||
}, {passive:false});
|
}, {passive:false});
|
||||||
stage.addEventListener('touchmove', function(e){
|
stage.addEventListener('touchmove', function(e){
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
@@ -147,8 +151,13 @@ document.addEventListener('DOMContentLoaded', function(){
|
|||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
const changed = Array.from(e.changedTouches || []);
|
const changed = Array.from(e.changedTouches || []);
|
||||||
changed.forEach(t=>removeFingerById(t.identifier));
|
changed.forEach(t=>removeFingerById(t.identifier));
|
||||||
if(!selectionDone) cancelSelection();
|
cancelSelection();
|
||||||
if(touches.size===0) resetWhenAllUp();
|
if(touches.size > 0){
|
||||||
|
selectionTimer = setTimeout(startSelectionIfNeeded, 700);
|
||||||
|
}
|
||||||
|
// touches.size===0: cancelSelection hat State bereits bereinigt,
|
||||||
|
// DOM-Elemente durch removeFingerById entfernt.
|
||||||
|
// iOS feuert neue touchstart-Events für noch liegende Finger selbst.
|
||||||
}, {passive:false});
|
}, {passive:false});
|
||||||
|
|
||||||
// Support mouse for desktop testing
|
// Support mouse for desktop testing
|
||||||
|
|||||||
Reference in New Issue
Block a user