Last active
January 27, 2022 11:58
-
-
Save nexpr/fa17e15012c82206df78117cbc1daede to your computer and use it in GitHub Desktop.
PointerEvent method DEMO see http://var.blog.jp/archives/85911896.html
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!DOCTYPE html> | |
<meta charset="utf-8" /> | |
<style> | |
.flex-container { | |
display: flex; | |
flex-flow: row wrap; | |
gap: 20px; | |
} | |
.box { | |
width: 320px; | |
height: 320px; | |
border: 2px solid #aaa; | |
touch-action: none; | |
} | |
button { | |
background: #eee; | |
border: 1px solid #aaa; | |
border-radius: 3px; | |
padding: 2px 4px; | |
} | |
[data-blocking-ms="10"] button[data-blocking-ms="10"], | |
[data-blocking-ms="50"] button[data-blocking-ms="50"], | |
[data-blocking-ms="100"] button[data-blocking-ms="100"], | |
[data-blocking-ms="500"] button[data-blocking-ms="500"], | |
[data-blocking-ms="1000"] button[data-blocking-ms="1000"], | |
[data-interval-ms="10"] button[data-interval-ms="10"], | |
[data-interval-ms="50"] button[data-interval-ms="50"], | |
[data-interval-ms="100"] button[data-interval-ms="100"], | |
[data-interval-ms="500"] button[data-interval-ms="500"], | |
[data-interval-ms="1000"] button[data-interval-ms="1000"] { | |
background: #333; | |
color: white; | |
} | |
</style> | |
<script type="module"> | |
{ // draw | |
const outputs = Array.from(document.querySelectorAll("canvas"), cvs => { | |
cvs.width = 320 | |
cvs.height = 320 | |
const ctx = cvs.getContext("2d") | |
const clear = () => ctx.clearRect(0, 0, cvs.width, cvs.height) | |
const draw = (path, color) => { | |
if (path.length === 0) return | |
ctx.strokeStyle = color | |
ctx.beginPath() | |
ctx.moveTo(path[0][0], path[0][1]) | |
for (const [x, y] of path.slice(1)) { | |
ctx.lineTo(x, y) | |
} | |
ctx.stroke() | |
} | |
return { clear, draw } | |
}) | |
const events = { | |
mouse: [], | |
coalesced: [], | |
} | |
const clean = (events, before) => { | |
while (events.length && events[0].timeStamp < before) events.shift() | |
} | |
input.addEventListener("mousemove", event => { | |
events.mouse.push(event) | |
scheduleRedraw() | |
}) | |
input.addEventListener("pointermove", event => { | |
events.coalesced.push(...event.getCoalescedEvents()) | |
scheduleRedraw() | |
}) | |
let redraw_scheduled = false | |
const scheduleRedraw = () => { | |
if (!redraw_scheduled) { | |
redraw_scheduled = true | |
setTimeout(() => { | |
redraw() | |
redraw_scheduled = false | |
}, 1) | |
} | |
} | |
const redraw = () => { | |
// clean | |
const now = performance.now() | |
const keep = 3000 | |
for (const event of Object.values(events)) { | |
clean(event, now - keep) | |
} | |
const path_mouse = events.mouse.map(event => [event.offsetX, event.offsetY]) | |
const path_coalesced = events.coalesced.map(event => [event.offsetX, event.offsetY]) | |
outputs[0].clear() | |
outputs[0].draw(path_mouse, "red") | |
outputs[1].clear() | |
outputs[1].draw(path_coalesced, "blue") | |
outputs[2].clear() | |
outputs[2].draw(path_mouse, "red") | |
outputs[2].draw(path_coalesced, "blue") | |
} | |
} | |
{ // timer | |
setInterval(() => { | |
const date = new Date() | |
now.textContent = new Date().toLocaleString("ja-JP", { hour: "2-digit", minute: "2-digit", second: "2-digit", fractionalSecondDigits: 3 }) | |
}, 100) | |
} | |
{ // heavy processing | |
let blocking_ms = 100 | |
let interval_ms = 100 | |
const schedule = () => | |
setTimeout(() => { | |
const now = Date.now() | |
while (Date.now() < now + blocking_ms) { } | |
schedule() | |
}, interval_ms) | |
schedule() | |
window.addEventListener("click", (event) => { | |
const button = event.target.closest("button") | |
if (button.dataset.blockingMs) { | |
blocking_ms = +button.dataset.blockingMs | |
button.closest("div[data-blocking-ms]").dataset.blockingMs = button.dataset.blockingMs | |
} | |
if (button.dataset.intervalMs) { | |
interval_ms = +button.dataset.intervalMs | |
button.closest("div[data-interval-ms]").dataset.intervalMs = button.dataset.intervalMs | |
} | |
}) | |
} | |
</script> | |
<div> | |
<span>timer:</span> | |
<span id="now"></span> | |
</div> | |
<div data-blocking-ms="100"> | |
<span>blocking_ms:</span> | |
<button data-blocking-ms="10">10ms</button> | |
<button data-blocking-ms="50">50ms</button> | |
<button data-blocking-ms="100">100ms</button> | |
<button data-blocking-ms="500">500ms</button> | |
<button data-blocking-ms="1000">1s</button> | |
</div> | |
<div data-interval-ms="100"> | |
<span>interval_ms:</span> | |
<button data-interval-ms="10">10ms</button> | |
<button data-interval-ms="50">50ms</button> | |
<button data-interval-ms="100">100ms</button> | |
<button data-interval-ms="500">500ms</button> | |
<button data-interval-ms="1000">1s</button> | |
</div> | |
<div class="flex-container"> | |
<div> | |
<p>このエリアでマウスを動かす</p> | |
<div id="input" class="box"></div> | |
</div> | |
<div> | |
<p>mouseevent</p> | |
<canvas id="output1" class="box"></canvas> | |
</div> | |
<div> | |
<p>getCoalescedEvents</p> | |
<canvas id="output2" class="box"></canvas> | |
</div> | |
<div> | |
<p>両方</p> | |
<canvas id="output3" class="box"></canvas> | |
</div> | |
</div> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!DOCTYPE html> | |
<meta charset="utf-8" /> | |
<style> | |
.container { | |
display: flex; | |
gap: 10px; | |
} | |
#canvas { | |
width: 800px; | |
height: 800px; | |
border: 2px solid #aaa; | |
cursor: none; | |
touch-action: none; | |
} | |
#detail { | |
border: 1px solid #aaa; | |
} | |
.red { | |
background: #fcc; | |
} | |
.blue { | |
background: #ccf; | |
} | |
span { | |
display: inline-block; | |
width: 100px; | |
} | |
</style> | |
<script type="module"> | |
canvas.width = 80 | |
canvas.height = 80 | |
const ctx = canvas.getContext("2d") | |
const clear = () => ctx.clearRect(0, 0, canvas.width, canvas.height) | |
const dot = (x, y, color) => { | |
ctx.fillStyle = color | |
ctx.fillRect(x, y, 1, 1) | |
} | |
const draw = (path, color) => { | |
if (path.length === 0) return | |
ctx.strokeStyle = color | |
ctx.beginPath() | |
ctx.moveTo(path[0][0], path[0][1]) | |
for (const [x, y] of path.slice(1)) { | |
ctx.lineTo(x, y) | |
} | |
ctx.stroke() | |
} | |
const events = { | |
coalesced: [], | |
predicted: [], | |
} | |
canvas.addEventListener("pointermove", event => { | |
const now = performance.now() | |
const coalesced = event.getCoalescedEvents().map(event => [event.offsetX / 10, event.offsetY / 10, event.timeStamp]) | |
const predicted = event.getPredictedEvents().map(event => [event.offsetX / 10, event.offsetY / 10, event.timeStamp]) | |
clear() | |
draw(coalesced, "blue") | |
draw(predicted, "red") | |
const current = coalesced.at(-1) | |
dot(current[0], current[1], "black") | |
detail.innerHTML = | |
`<div><span>x</span><span>y</span><span>ts(${~~now})</span></div>` + | |
coalesced.map(item => `<div class="blue">${item.map(v => `<span>${~~v}</span>`).join("")}</div>`).join("") + | |
predicted.map(item => `<div class="red">${item.map(v => `<span>${~~v}</span>`).join("")}</div>`).join("") | |
}) | |
</script> | |
<div class="container"> | |
<canvas id="canvas"></canvas> | |
<div id="detail"></div> | |
</div> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment