From 05c34174398b8023582241f059e6733292d10b7e Mon Sep 17 00:00:00 2001 From: OLDREDSTONE Date: Wed, 31 Dec 2025 22:11:33 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BC=98=E5=8C=96=E6=B8=B2=E6=9F=93=E6=B5=81?= =?UTF-8?q?=E7=A8=8B=EF=BC=88=E8=99=BD=E7=84=B6=E8=BF=98=E6=98=AF=E5=BE=88?= =?UTF-8?q?=E5=8D=A1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- script/rdview2.js | 121 ++++++++++++++++++++++++++++++++++------------ 1 file changed, 90 insertions(+), 31 deletions(-) diff --git a/script/rdview2.js b/script/rdview2.js index b8ac205..a3f2c52 100644 --- a/script/rdview2.js +++ b/script/rdview2.js @@ -2,11 +2,16 @@ import { Extensions, IconStyle } from "/script/Extensions.js"; function rend() { const codeBlocks = document.querySelectorAll("canvas.rdview2-canvas"); codeBlocks.forEach((block) => { + // 清理旧的实例 + if (block.cleanup) { + block.cleanup(); + } + const width = block.getAttribute("data-width") || 8; const height = block.getAttribute("data-height") || 4; const scale = block.getAttribute("data-scale") || 2; const data = block.getAttribute("data"); - const ctx = block.getContext("2d"); + const ctx = block.getContext("2d", { alpha: false, desynchronized: true }); block.width = width * scale * 14; block.height = height * scale * 14; if (!data) { @@ -14,34 +19,68 @@ function rend() { } const jsonData = JSON.parse(`[${JSON.parse(data)}]`); - let lastX = -1, lastY = -1, lastActive = false; + let lastActive = false; + let evtId = 0; let frameId = null; + let cachedRect = null; + let mdown = false; + + const eventPositions = jsonData.map(evt => ({ + evt, + x: ((evt.beat ?? 1) - 1) * scale * 14, + y: (evt.y ?? 0) * scale * 14 + })); const style = new IconStyle(); + style.Scale = scale; + + const updateRect = () => { + cachedRect = block.getBoundingClientRect(); + }; + updateRect(); + + let rectTimeout; + const debouncedUpdateRect = () => { + clearTimeout(rectTimeout); + rectTimeout = setTimeout(updateRect, 100); + }; + + const observer = new ResizeObserver(debouncedUpdateRect); + observer.observe(block); + + window.addEventListener("resize", debouncedUpdateRect, { passive: true }); + window.addEventListener("scroll", debouncedUpdateRect, { passive: true }); block.render = (x, y, active) => { - if (x === lastX && y === lastY && active === lastActive) { + const point = { x, y }; + let currentEvtId = null; + for (let i = 0; i < eventPositions.length; i++) { + const { evt } = eventPositions[i]; + if (evt.area?.contains(point)) { + currentEvtId = i; + break; + } + } + + if (currentEvtId === evtId && active === lastActive) { return; } - lastX = x; - lastY = y; + evtId = currentEvtId; lastActive = active; ctx.clearRect(0, 0, block.width, block.height); - for (const evt of jsonData) { - style.Scale = scale; - style.Hover = evt.area?.contains({x, y}) ?? false; - style.Active = evt.area?.contains({x, y}) ? active : false; - evt.area = Extensions.DrawEventIcon(ctx, evt, { - x: ((evt.beat ?? 1) - 1) * scale * 14, - y: (evt.y ?? 0) * scale * 14, - }, style); + + for (const { evt, x: posX, y: posY } of eventPositions) { + const isHovered = evt.area?.contains(point) ?? false; + style.Hover = isHovered; + style.Active = isHovered ? active : false; + evt.area = Extensions.DrawEventIcon(ctx, evt, { x: posX, y: posY }, style); } } const throttledRender = (x, y, active) => { if (frameId !== null) { - cancelAnimationFrame(frameId); + return; } frameId = requestAnimationFrame(() => { block.render(x, y, active); @@ -49,31 +88,51 @@ function rend() { }); } + const getMousePos = (e) => ({ + x: e.clientX - cachedRect.left, + y: e.clientY - cachedRect.top + }); + block.addEventListener("mousemove", (e) => { - const rect = block.getBoundingClientRect(); - const x = e.clientX - rect.left; - const y = e.clientY - rect.top; - throttledRender(x, y, false); - }); + const { x, y } = getMousePos(e); + console.log(x, y); + throttledRender(x, y, mdown); + }, { passive: true }); + block.addEventListener("mousedown", (e) => { - const rect = block.getBoundingClientRect(); - const x = e.clientX - rect.left; - const y = e.clientY - rect.top; - block.render(x, y, true); + const { x, y } = getMousePos(e); + mdown = true; + block.render(x, y, mdown); }); + block.addEventListener("mouseup", (e) => { - const rect = block.getBoundingClientRect(); - const x = e.clientX - rect.left; - const y = e.clientY - rect.top; - block.render(x, y, false); + const { x, y } = getMousePos(e); + mdown = false; + block.render(x, y, mdown); }); - block.addEventListener("mouseleave", (e) => { + + block.addEventListener("mouseleave", () => { + if (frameId !== null) { + cancelAnimationFrame(frameId); + frameId = null; + } + mdown = false; + evtId = null; + lastActive = false; + block.render(-1, -1, mdown); + }, { passive: true }); + + block.cleanup = () => { + observer.disconnect(); + window.removeEventListener("resize", debouncedUpdateRect); + window.removeEventListener("scroll", debouncedUpdateRect); + clearTimeout(rectTimeout); if (frameId !== null) { cancelAnimationFrame(frameId); } - block.render(0, 0, false); - }); - block.render(0, 0, false); + }; + + block.render(-1, -1, mdown); }); }