forked from RDCNWebs/rd.rdlevel.cn
Reviewed-on: RDCNWebs/rd.rdlevel.cn#52 Co-authored-by: kuanpan <kuanpan791@gmail.com> Co-committed-by: kuanpan <kuanpan791@gmail.com>
394 lines
15 KiB
JavaScript
394 lines
15 KiB
JavaScript
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) => `<div>${lines[i] || " "}</div>`);
|
||
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) => `<div>${lines[i] || " "}</div>`);
|
||
number.innerHTML = lineDoms.join("");
|
||
}
|
||
function initCanvas() {
|
||
let objs = [];
|
||
try {
|
||
objs = JSON.parse(`[${textarea.value}]`);
|
||
rdcanvas.innerHTML = "";
|
||
} catch (e) {
|
||
rdcanvas.innerHTML =
|
||
`<div style="color: red; font-weight: bold;">JSON解析错误:${e.message}</div>`;
|
||
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(() => {
|
||
});
|