conductor/src/render.js

129 lines
3.7 KiB
JavaScript

import { Conductor } from "./conductor.js";
export class Renderer {
timeIndicator;
currStaveNumber;
numStaves;
sheetWindow;
canvases = [];
iconCache = [];
iconScale = 0.20;
constructor() {
this.numStaves = 6;
this.currStaveNumber = 1;
this.timeIndicator = document.getElementById("time-indicator");
this.sheetWindow = document.getElementById("music-window");
window.addEventListener("resize", () => {
this.redrawIcons();
});
this.timeIndicator.addEventListener("animationiteration", () => {
this.currStaveNumber++;
if (this.currStaveNumber > this.numStaves) {
this.cleanUpAndRestart();
}
});
for (let i = 1; i <= this.numStaves; i++) {
const staveWrapper = document.createElement("div");
staveWrapper.classList.add("stave-wrapper");
staveWrapper.setAttribute("id", `stave-wrapper-${i}`);
staveWrapper.style.position = "relative";
const staveObject = document.createElement("object");
staveObject.type = "image/svg+xml";
staveObject.data = "assets/svg/stave.svg";
staveObject.className = "stave-svg"; // Fixed className
const canvas = document.createElement("canvas");
canvas.id = `canvas-${i}`;
canvas.className = "event-canvas";
const ctx = canvas.getContext("2d");
this.canvases.push({ canvas, ctx });
staveWrapper.appendChild(staveObject);
staveWrapper.appendChild(canvas);
this.sheetWindow.appendChild(staveWrapper);
// Your exact sizing method + minimal DPR adjustment
requestAnimationFrame(() => {
const dpr = window.devicePixelRatio || 1;
// Keep your offset measurements
const displayWidth = canvas.offsetWidth;
const displayHeight = canvas.offsetHeight;
// Apply to actual canvas buffer
canvas.width = Math.round(displayWidth * dpr);
canvas.height = Math.round(displayHeight * dpr);
// Maintain your display size
canvas.style.width = `${displayWidth}px`;
canvas.style.height = `${displayHeight}px`;
// Scale context to compensate
ctx.scale(dpr , dpr);
});
}
}
async placeIcon(instrument) {
if (this.currStaveNumber > this.numStaves) {
this.currStaveNumber = 1;
this.iconCache.length = 0;
}
const rect = this.timeIndicator.getBoundingClientRect();
const sheetLeft = this.sheetWindow.getBoundingClientRect().left;
const xPosition = rect.left + window.scrollX - sheetLeft;
const canvasEntry = this.canvases[this.currStaveNumber - 1];
const canvas = canvasEntry.canvas;
const ctx = canvasEntry.ctx;
const yPercent = parseFloat(instrument.yPos);
const y = (yPercent / 100) * canvas.height;
const width = instrument.width * this.iconScale;
const height = instrument.height * this.iconScale;
ctx.drawImage(instrument.image, xPosition, y, width, height);
this.iconCache.push({
image: instrument.image,
x: xPosition,
y,
width,
height,
stave: this.currStaveNumber,
});
}
redrawIcons() {
this.canvases.forEach(({ ctx, canvas }) => {
ctx.clearRect(0, 0, canvas.width, canvas.height);
});
this.iconCache.forEach(({ image, x, y, width, height, stave }) => {
const ctx = this.canvases[stave - 1].ctx;
ctx.drawImage(image, x, y, width, height);
});
}
cleanUpAndRestart(reload = false) {
this.iconCache = [];
this.currStaveNumber = 1;
this.canvases.forEach(({ ctx, canvas }) => {
ctx.clearRect(0, 0, canvas.width, canvas.height);
});
Conductor.setTitle();
if (reload) location.reload();
}
}