import { createElementEvent } from "./rdtkview.js"; let curx = 0; let cury = 0; let rowx; let columny; let positions = { "c1": { "x": 66, "name": "第一拍" }, "c2": { "x": 90, "name": "第二拍" }, "c3": { "x": 114, "name": "第三拍" }, "c4": { "x": 138, "name": "第四拍" }, "c5": { "x": 162, "name": "第五拍" }, "c6": { "x": 186, "name": "第六拍" }, "c7": { "x": 251, "name": "第七拍" }, "ccharacter": { "x": 35, "name": "角色" }, "ccenter": { "x": 176, "name": "中心" }, "cheart": { "x": 315, "name": "心" }, "r1": { "y": 162, "name": "四轨时的第四轨" }, "r2": { "y": 141, "name": "三轨时的第三轨" }, "r3": { "y": 120, "name": "二轨时的第一轨/四轨时的第三轨" }, "r4": { "y": 99, "name": "一轨时的第一轨/三轨时的第二轨" }, "r5": { "y": 78, "name": "二轨时的第二轨/四轨时的第二轨" }, "r6": { "y": 57, "name": "三轨时的第一轨" }, "r7": { "y": 36, "name": "四轨时的第一轨" }, }; function themePosition() { let theme_positions = document.getElementById("theme-positions"); if (!theme_positions) return; let perx = theme_positions.querySelector(".per>span.x"); let pery = theme_positions.querySelector(".per>span.y"); let pxx = theme_positions.querySelector(".px>span.x"); let pxy = theme_positions.querySelector(".px>span.y"); let infobox = theme_positions.querySelector(".infobox"); let selectbox = theme_positions.querySelector(".selectbox"); let other = theme_positions.querySelector(".other"); perx.innerText = "100%"; pery.innerText = "100%"; pxx.innerText = "352px"; pxy.innerText = "198px"; infobox.style.right = "calc(10px)"; infobox.style.top = "calc(10px)"; selectbox.style.left = "50%"; selectbox.style.bottom = "50%"; selectbox.style.width = "0"; selectbox.style.height = "0"; other.innerText = ""; theme_positions.addEventListener("mouseenter", function (event) { }); theme_positions.addEventListener("mousemove", function (event) { let x = event.clientX - theme_positions.getBoundingClientRect().left; let y = event.clientY - theme_positions.getBoundingClientRect().top; let width = theme_positions.offsetWidth; let height = theme_positions.offsetHeight; let x_percent = parseFloat(((x / width) * 100).toFixed(2)); let y_percent = parseFloat(((y / height) * 100).toFixed(2)); x = parseFloat((x_percent * 3.52).toFixed(0)); y = parseFloat((y_percent * 1.98).toFixed(0)); rowx = null; columny = null; for (let key in positions) { if ( positions[key].x !== null && Math.abs(x - positions[key].x) < 5 ) { rowx = positions[key].x; } if ( positions[key].y !== null && Math.abs(y - positions[key].y) < 5 ) { columny = positions[key].y; } } if (rowx) { perx.innerText = (rowx / 3.52).toFixed(2) + "%"; perx.classList.add("c"); pxx.innerText = rowx + "px"; pxx.classList.add("c"); } else { perx.innerText = x_percent.toFixed(2) + "%"; perx.classList.remove("c"); pxx.innerText = x + "px"; pxx.classList.remove("c"); } if (columny) { pery.innerText = (100 - columny / 1.98).toFixed(2) + "%"; pery.classList.add("c"); pxy.innerText = 198 - columny + "px"; pxy.classList.add("c"); } else { pery.innerText = (100 - y_percent).toFixed(2) + "%"; pery.classList.remove("c"); pxy.innerText = 198 - y + "px"; pxy.classList.remove("c"); } infobox.style.right = "calc(" + (100 - x_percent) + "% + 10px)"; infobox.style.top = "calc(" + y_percent + "% + 10px)"; selectbox.style.left = rowx ? (rowx / 3.52 - 3.41) + "%" : columny ? "0" : "calc(" + x_percent + "% - 3px"; selectbox.style.bottom = columny ? (100 - columny / 1.98 - 5.305) + "%" : rowx ? "0" : "calc(" + (100 - y_percent) + "% - 3px)"; selectbox.style.width = rowx ? "6.82%" : columny ? "100%" : "6px"; selectbox.style.height = columny ? "10.61%" : rowx ? "100%" : "6px"; let rowname = rowx ? positions[ Object.keys(positions).find((key) => positions[key].x === rowx) ].name : ""; let columnname = columny ? positions[ Object.keys(positions).find((key) => positions[key].y === columny ) ].name : ""; theme_positions.querySelector(".other").innerText = rowname && columnname ? columnname + "上的" + rowname : rowname ? rowname : columnname ? columnname : ""; }); theme_positions.addEventListener("mouseleave", function (event) { perx.innerText = "100%"; pery.innerText = "100%"; pxx.innerText = "352px"; pxy.innerText = "198px"; infobox.style.right = "calc(10px)"; infobox.style.top = "calc(10px)"; selectbox.style.left = "50%"; selectbox.style.bottom = "50%"; selectbox.style.width = "0"; selectbox.style.height = "0"; perx.classList.remove("c"); pery.classList.remove("c"); pxx.classList.remove("c"); pxy.classList.remove("c"); other.innerText = ""; }); } function rdview() { let rdview = document.getElementsByClassName("rdview")[0]; if (!rdview) return; let rdcanvas = rdview.querySelector(".canvas"); let textarea = rdview.querySelector("textarea.area"); let number = rdview.querySelector(".number"); const textareaStyles = window.getComputedStyle(textarea); [ "fontFamily", "fontSize", "fontWeight", "letterSpacing", "lineHeight", "padding", ].forEach((property) => { number.style[property] = textareaStyles[property]; }); const canvas = document.createElement("canvas"); const context = canvas.getContext("2d"); const font = `${textareaStyles.fontSize} ${textareaStyles.fontFamily}`; context.font = font; function calcStringLines(sentence, width) { if (!width) return 0; const words = sentence.split(""); let lineCount = 0; let currentLine = ""; for (let i = 0; i < words.length; i++) { const wordWidth = context.measureText(words[i]).width; const lineWidth = context.measureText(currentLine).width; if (lineWidth + wordWidth > width) { lineCount++; currentLine = words[i]; } else { currentLine += words[i]; } } if (currentLine.trim() !== "") lineCount++; return lineCount; } function calcLines() { const lines = textarea.value.split("\n"); const textareaWidth = textarea.getBoundingClientRect().width; const textareaScrollWidth = textareaWidth - textarea.clientWidth; const parseNumber = (v) => v.endsWith("px") ? parseInt(v.slice(0, -2), 10) : 0; const textareaPaddingLeft = parseNumber(textareaStyles.paddingLeft); const textareaPaddingRight = parseNumber(textareaStyles.paddingRight); const textareaContentWidth = textareaWidth - textareaPaddingLeft - textareaPaddingRight - textareaScrollWidth; const numLines = lines.map((lineString) => calcStringLines(lineString, textareaContentWidth) ); let lineNumbers = []; let i = 1; while (numLines.length > 0) { const numLinesOfSentence = numLines.shift(); lineNumbers.push(i); if (numLinesOfSentence > 1) { Array(numLinesOfSentence - 1) .fill("") .forEach((_) => lineNumbers.push("")); } i++; } return lineNumbers; } function initLineNumbers() { const lines = calcLines(); const lineDoms = Array.from({ length: lines.length, }, (_, i) => `
${lines[i] || " "}
`); number.innerHTML = lineDoms.join(""); } function initCanvas() { const lang = textarea.value.split("\n")[0]; const code = textarea.value.split("\n").slice(1).join("\n"); rdcanvas.innerHTML = RDViewRender(lang, code); } initCanvas(); initLineNumbers(); textarea.addEventListener("input", initLineNumbers); textarea.addEventListener("input", initCanvas); } function rdview2() { let rdview = document.getElementsByClassName("rdview2")[0]; if (!rdview) return; let rdcanvas = rdview.querySelector(".canvas"); let textarea = rdview.querySelector("textarea.area"); let number = rdview.querySelector(".number"); const textareaStyles = window.getComputedStyle(textarea); [ "fontFamily", "fontSize", "fontWeight", "letterSpacing", "lineHeight", "padding", ].forEach((property) => { number.style[property] = textareaStyles[property]; }); const canvas = document.createElement("canvas"); const context = canvas.getContext("2d"); const font = `${textareaStyles.fontSize} ${textareaStyles.fontFamily}`; context.font = font; function calcStringLines(sentence, width) { if (!width) return 0; const words = sentence.split(""); let lineCount = 0; let currentLine = ""; for (let i = 0; i < words.length; i++) { const wordWidth = context.measureText(words[i]).width; const lineWidth = context.measureText(currentLine).width; if (lineWidth + wordWidth > width) { lineCount++; currentLine = words[i]; } else { currentLine += words[i]; } } if (currentLine.trim() !== "") lineCount++; return lineCount; } function calcLines() { const lines = textarea.value.split("\n"); const textareaWidth = textarea.getBoundingClientRect().width; const textareaScrollWidth = textareaWidth - textarea.clientWidth; const parseNumber = (v) => v.endsWith("px") ? parseInt(v.slice(0, -2), 10) : 0; const textareaPaddingLeft = parseNumber(textareaStyles.paddingLeft); const textareaPaddingRight = parseNumber(textareaStyles.paddingRight); const textareaContentWidth = textareaWidth - textareaPaddingLeft - textareaPaddingRight - textareaScrollWidth; const numLines = lines.map((lineString) => calcStringLines(lineString, textareaContentWidth) ); let lineNumbers = []; let i = 1; while (numLines.length > 0) { const numLinesOfSentence = numLines.shift(); lineNumbers.push(i); if (numLinesOfSentence > 1) { Array(numLinesOfSentence - 1) .fill("") .forEach((_) => lineNumbers.push("")); } i++; } return lineNumbers; } function initLineNumbers() { const lines = calcLines(); const lineDoms = Array.from({ length: lines.length, }, (_, i) => `
${lines[i] || " "}
`); number.innerHTML = lineDoms.join(""); } function initCanvas() { let objs = []; try { objs = JSON.parse(`[${textarea.value}]`); rdcanvas.innerHTML = ""; } catch (e) { rdcanvas.innerHTML = `
JSON解析错误:${e.message}
`; return; } const eventStyle = { "scale": 2.0, "showDuration": false }; let maxy = 0; const elemPromises = []; for (let obj of objs) { const style = { ...eventStyle, enabled: obj.active ?? true }; const elem = createElementEvent(obj, style).then((elem) => { elem.eventStyle = style; elem.style.position = "absolute"; elem.style.left = `${ ((((obj.bar ?? 1) - 1) * 8) + (obj.beat ?? 1) - 1) * 14 * eventStyle.scale }px`; elem.style.top = `${ (obj.y ?? obj.row ?? 0) * 14 * eventStyle.scale }px`; if ( ((obj.y ?? obj.row ?? 0) * 14 * eventStyle.scale) + elem.offsetHeight > maxy ) { maxy = ((obj.y ?? obj.row ?? 0) * 14 * eventStyle.scale) + elem.offsetHeight; } elem.addEventListener("mousedown", (event) => { const eStyle = elem.eventStyle; eStyle.active = true; elem.onStateChange(eStyle); }); elem.addEventListener("mouseover", (event) => { const eStyle = elem.eventStyle; eStyle.hover = true; elem.onStateChange(eStyle); }); elem.addEventListener("mouseout", (event) => { const eStyle = elem.eventStyle; eStyle.hover = false; eStyle.active = false; elem.onStateChange(eStyle); }); elem.addEventListener("mouseup", (event) => { const eStyle = elem.eventStyle; eStyle.active = false; elem.onStateChange(eStyle); }); return elem; }); elemPromises.push(elem); } Promise.all(elemPromises).then((elems) => { elems.forEach((elem) => { rdcanvas.appendChild(elem); }); }); rdcanvas.style.position = "relative"; rdcanvas.style.height = `${maxy + 4 * 14 * eventStyle.scale}px`; } initCanvas(); initLineNumbers(); textarea.addEventListener("input", initLineNumbers); textarea.addEventListener("input", initCanvas); } window.$docsify.plugins = [].concat(window.$docsify.plugins, function (hook) { hook.doneEach(function () { themePosition(); rdview(); rdview2(); document.documentElement.scrollTop = document.body.scrollTop = 0; }); }); import("./docsify.min.js").then(() => { });