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", { alpha: false, desynchronized: true }); block.width = width * scale * 14; block.height = height * scale * 14; if (!data) { return; } const jsonData = JSON.parse(`[${JSON.parse(data)}]`); 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) => { 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; } evtId = currentEvtId; lastActive = active; ctx.clearRect(0, 0, block.width, block.height); 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) { return; } frameId = requestAnimationFrame(() => { block.render(x, y, active); frameId = null; }); } const getMousePos = (e) => ({ x: e.clientX - cachedRect.left, y: e.clientY - cachedRect.top }); block.addEventListener("mousemove", (e) => { const { x, y } = getMousePos(e); console.log(x, y); throttledRender(x, y, mdown); }, { passive: true }); block.addEventListener("mousedown", (e) => { const { x, y } = getMousePos(e); mdown = true; block.render(x, y, mdown); }); block.addEventListener("mouseup", (e) => { const { x, y } = getMousePos(e); mdown = false; block.render(x, y, mdown); }); 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(-1, -1, mdown); }); } window.$docsify.plugins = [].concat(window.$docsify.plugins, function (hook) { hook.doneEach(function () { rend(); }); });