Compare commits
No commits in common. "16f374d927e68edacc3fcfe8320cb299f4fbe679" and "f1f13bf1fdc9efcef9db8dc2609c004100464a39" have entirely different histories.
16f374d927
...
f1f13bf1fd
|
@ -12,11 +12,6 @@
|
||||||
#canvasDiv {
|
#canvasDiv {
|
||||||
position: relative;
|
position: relative;
|
||||||
margin: 1.4em;
|
margin: 1.4em;
|
||||||
width: 40%;
|
|
||||||
height: 90vh;
|
|
||||||
top: 0;
|
|
||||||
left: 0;
|
|
||||||
float: left;
|
|
||||||
}
|
}
|
||||||
.hallLabel {
|
.hallLabel {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
|
@ -36,13 +31,12 @@
|
||||||
.hallLabel.left {
|
.hallLabel.left {
|
||||||
left: -1.3em;
|
left: -1.3em;
|
||||||
top: 50%;
|
top: 50%;
|
||||||
writing-mode: vertical-lr;
|
writing-mode: sideways-lr;
|
||||||
transform: rotate(180deg);
|
|
||||||
}
|
}
|
||||||
.hallLabel.right {
|
.hallLabel.right {
|
||||||
right: -1.5em;
|
right: -1.5em;
|
||||||
top: 50%;
|
top: 50%;
|
||||||
writing-mode: vertical-lr;
|
writing-mode: sideways-rl;
|
||||||
}
|
}
|
||||||
#debug {
|
#debug {
|
||||||
display: none;
|
display: none;
|
||||||
|
|
132
www/js/main.ts
132
www/js/main.ts
|
@ -7,7 +7,6 @@ import { LibFigureDance, LibFigureMove, Move } from "./libfigureMapper.js";
|
||||||
import { animateLowLevelMove, LowLevelMove } from "./lowLevelMove.js";
|
import { animateLowLevelMove, LowLevelMove } from "./lowLevelMove.js";
|
||||||
import { figureBeats, figureToHtml } from "./libfigure/define-figure.js";
|
import { figureBeats, figureToHtml } from "./libfigure/define-figure.js";
|
||||||
import { labelForBeats } from "./libfigure/dance.js";
|
import { labelForBeats } from "./libfigure/dance.js";
|
||||||
import { setDistance } from "./rendererConstants.js";
|
|
||||||
|
|
||||||
const body = document.querySelector('body')!;
|
const body = document.querySelector('body')!;
|
||||||
|
|
||||||
|
@ -42,52 +41,22 @@ beatDisplay.className = 'beatDisplay';
|
||||||
beatDisplay.innerText = '0.0';
|
beatDisplay.innerText = '0.0';
|
||||||
|
|
||||||
const ctx = canvas.getContext('2d')!;
|
const ctx = canvas.getContext('2d')!;
|
||||||
const r = new renderer.Renderer(canvas, ctx);
|
|
||||||
|
|
||||||
const defaultSetSizeInPx = canvas.offsetHeight / 3;
|
|
||||||
type ResetCanvasSetting = { extraSets?: number; extraLines?: number; setSizeInPx?: number; zoom?: number; };
|
|
||||||
function resetCanvas({ extraSets, extraLines, setSizeInPx, zoom }: ResetCanvasSetting) {
|
|
||||||
ctx.resetTransform();
|
|
||||||
extraLines ??= 0;
|
|
||||||
extraSets ??= 0;
|
|
||||||
// TODO Redo this on resize?
|
// TODO Redo this on resize?
|
||||||
const numSets = (1 + 2 * extraSets);
|
const w = canvas.offsetWidth;
|
||||||
setSizeInPx = zoom ? zoom * defaultSetSizeInPx : (setSizeInPx ?? defaultSetSizeInPx);
|
const h = canvas.offsetHeight;
|
||||||
const w = setSizeInPx * (1 + 2 * extraLines);
|
|
||||||
const h = setSizeInPx * numSets;
|
|
||||||
const s = window.devicePixelRatio;
|
const s = window.devicePixelRatio;
|
||||||
|
|
||||||
canvasDiv.style.width = w + 'px';
|
|
||||||
canvasDiv.style.height = h + 'px';
|
|
||||||
|
|
||||||
canvas.width = w * s;
|
canvas.width = w * s;
|
||||||
canvas.height = h * s;
|
canvas.height = h * s;
|
||||||
|
|
||||||
ctx.translate(canvas.width / 2.0, canvas.height / 2.0);
|
ctx.translate(canvas.width / 2.0, canvas.height / 2.0);
|
||||||
const scale = numSets * setDistance;
|
const scale = 10;
|
||||||
ctx.scale(canvas.height / scale, -canvas.height / scale);
|
ctx.scale(canvas.height / scale, -canvas.height / scale);
|
||||||
r.extraLines = Math.ceil(extraLines) + 1;
|
const r = new renderer.Renderer(canvas, ctx);
|
||||||
r.extraSets = Math.ceil(extraSets) + 1;
|
r.extraLines = 3;
|
||||||
if (r.animation) {
|
r.extraSets = 3;
|
||||||
drawAtCurrentBeat();
|
|
||||||
} else {
|
|
||||||
r.clear();
|
r.clear();
|
||||||
}
|
|
||||||
}
|
|
||||||
let canvasSetting: ResetCanvasSetting = {
|
|
||||||
extraLines: 0.6,
|
|
||||||
extraSets: 0.8,
|
|
||||||
zoom: 1,
|
|
||||||
};
|
|
||||||
function updateCanvasSettings(arg : ResetCanvasSetting) {
|
|
||||||
if (arg.extraLines !== undefined) canvasSetting.extraLines = arg.extraLines;
|
|
||||||
if (arg.extraSets !== undefined) canvasSetting.extraSets = arg.extraSets;
|
|
||||||
if (arg.zoom) canvasSetting.zoom = arg.zoom;
|
|
||||||
|
|
||||||
resetCanvas(canvasSetting);
|
|
||||||
}
|
|
||||||
|
|
||||||
updateCanvasSettings({});
|
|
||||||
|
|
||||||
const bpmSelector = document.createElement('input');
|
const bpmSelector = document.createElement('input');
|
||||||
bpmSelector.type = 'number';
|
bpmSelector.type = 'number';
|
||||||
|
@ -229,36 +198,15 @@ function buildMovesList() {
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
figureHtml = "libfigureError: " + e;
|
figureHtml = "libfigureError: " + e;
|
||||||
}
|
}
|
||||||
const beatsDescription = document.createTextNode(
|
moveItem.innerHTML = "[" + labelForBeats(Math.floor(startBeat / 16) * 16) + " "
|
||||||
"[" + labelForBeats(Math.floor(startBeat / 16) * 16) + " "
|
+ "(" + startBeat + "-" + currentBeat + ")] "
|
||||||
+ "(" + startBeat + "-" + currentBeat + ")] ");
|
+ figureHtml;
|
||||||
const figureDescription = document.createElement('span');
|
|
||||||
figureDescription.innerHTML = figureHtml;
|
|
||||||
|
|
||||||
for (const { label, beat } of [
|
|
||||||
{ label: '<|', beat: startBeat },
|
|
||||||
{ label: '+1', beat: startBeat + 1 },
|
|
||||||
{ label: '½', beat: (startBeat + currentBeat) / 2 },
|
|
||||||
{ label: '-1', beat: currentBeat - 1 },
|
|
||||||
{ label: '|>', beat: currentBeat },
|
|
||||||
]) {
|
|
||||||
const jumpToButton = document.createElement('button');
|
|
||||||
jumpToButton.innerText = label;
|
|
||||||
jumpToButton.addEventListener('click', (ev) => {
|
|
||||||
setBeat(beat);
|
|
||||||
restartAnimation(false);
|
|
||||||
});
|
|
||||||
moveItem.appendChild(jumpToButton);
|
|
||||||
}
|
|
||||||
|
|
||||||
moveItem.appendChild(beatsDescription);
|
|
||||||
moveItem.appendChild(figureDescription);
|
|
||||||
moveItem.classList.add('move');
|
moveItem.classList.add('move');
|
||||||
for (let beat = startBeat; beat < currentBeat; beat++) {
|
for (let beat = startBeat; beat < currentBeat; beat++) {
|
||||||
moveItem.classList.add('moveForBeat_' + beat);
|
moveItem.classList.add('moveForBeat_' + beat);
|
||||||
}
|
}
|
||||||
if (startBeat === 0) moveItem.classList.add('currentMove');
|
if (startBeat === 0) moveItem.classList.add('currentMove');
|
||||||
figureDescription.addEventListener('click', (ev) => {
|
moveItem.addEventListener('click', (ev) => {
|
||||||
setBeat(startBeat);
|
setBeat(startBeat);
|
||||||
restartAnimation(false);
|
restartAnimation(false);
|
||||||
});
|
});
|
||||||
|
@ -339,68 +287,10 @@ function playAnimation(bpm: number, start: number, end: number) {
|
||||||
anim();
|
anim();
|
||||||
}
|
}
|
||||||
|
|
||||||
const displaySettingsDiv = document.createElement('div');
|
|
||||||
displaySettingsDiv.id = 'displaySettings';
|
|
||||||
displaySettingsDiv.style.margin = '1em';
|
|
||||||
|
|
||||||
const zoomSelector = document.createElement('input');
|
|
||||||
zoomSelector.type = 'number';
|
|
||||||
zoomSelector.min = '10';
|
|
||||||
zoomSelector.step = '10';
|
|
||||||
zoomSelector.value = '100';
|
|
||||||
zoomSelector.id = 'zoom';
|
|
||||||
zoomSelector.style.width = '4em';
|
|
||||||
zoomSelector.addEventListener('input', (ev) => {
|
|
||||||
updateCanvasSettings({ zoom: zoomSelector.valueAsNumber / 100 });
|
|
||||||
})
|
|
||||||
const zoomLabel = document.createElement('label');
|
|
||||||
zoomLabel.innerText = '% zoom';
|
|
||||||
zoomLabel.htmlFor = 'zoom';
|
|
||||||
|
|
||||||
displaySettingsDiv.appendChild(zoomSelector);
|
|
||||||
displaySettingsDiv.appendChild(zoomLabel);
|
|
||||||
|
|
||||||
const extraSetsSelector = document.createElement('input');
|
|
||||||
extraSetsSelector.type = 'number';
|
|
||||||
extraSetsSelector.min = '0';
|
|
||||||
extraSetsSelector.step = '0.1';
|
|
||||||
extraSetsSelector.value = canvasSetting.extraSets!.toPrecision(1);
|
|
||||||
extraSetsSelector.id = 'extraSets';
|
|
||||||
extraSetsSelector.style.width = '3em';
|
|
||||||
extraSetsSelector.addEventListener('input', (ev) => {
|
|
||||||
updateCanvasSettings({ extraSets: extraSetsSelector.valueAsNumber });
|
|
||||||
})
|
|
||||||
const extraSetsLabel = document.createElement('label');
|
|
||||||
extraSetsLabel.innerText = '# extra sets: ';
|
|
||||||
extraSetsLabel.htmlFor = 'extraSets';
|
|
||||||
|
|
||||||
displaySettingsDiv.appendChild(document.createElement('br'));
|
|
||||||
displaySettingsDiv.appendChild(extraSetsLabel);
|
|
||||||
displaySettingsDiv.appendChild(extraSetsSelector);
|
|
||||||
|
|
||||||
const extraLinesSelector = document.createElement('input');
|
|
||||||
extraLinesSelector.type = 'number';
|
|
||||||
extraLinesSelector.min = '0';
|
|
||||||
extraLinesSelector.step = '0.1';
|
|
||||||
extraLinesSelector.value = canvasSetting.extraLines!.toPrecision(1);
|
|
||||||
extraLinesSelector.id = 'extraLines';
|
|
||||||
extraLinesSelector.style.width = '3em';
|
|
||||||
extraLinesSelector.addEventListener('input', (ev) => {
|
|
||||||
updateCanvasSettings({ extraLines: extraLinesSelector.valueAsNumber });
|
|
||||||
})
|
|
||||||
const extraLinesLabel = document.createElement('label');
|
|
||||||
extraLinesLabel.innerText = '# extra lines: ';
|
|
||||||
extraLinesLabel.htmlFor = 'extraLines';
|
|
||||||
|
|
||||||
displaySettingsDiv.appendChild(document.createElement('br'));
|
|
||||||
displaySettingsDiv.appendChild(extraLinesLabel);
|
|
||||||
displaySettingsDiv.appendChild(extraLinesSelector);
|
|
||||||
|
|
||||||
wrapperDiv.appendChild(displaySettingsDiv);
|
|
||||||
|
|
||||||
// Default dance is Two Hearts in Time by Isaac Banner. Selected arbitrarily.
|
// Default dance is Two Hearts in Time by Isaac Banner. Selected arbitrarily.
|
||||||
const defaultDanceTitle = "Two Hearts in Time";
|
const defaultDanceTitle = "Two Hearts in Time";
|
||||||
|
|
||||||
|
wrapperDiv.appendChild(document.createElement('br'));
|
||||||
const danceList = document.createElement('select');
|
const danceList = document.createElement('select');
|
||||||
for (const [idx, dance] of danceLibrary.dances.entries()) {
|
for (const [idx, dance] of danceLibrary.dances.entries()) {
|
||||||
const opt = document.createElement('option');
|
const opt = document.createElement('option');
|
||||||
|
|
|
@ -24,8 +24,7 @@ function hueForDancer(identity: DancerIdentity): number {
|
||||||
function colorForDancer(identity: ExtendedDancerIdentity) : string {
|
function colorForDancer(identity: ExtendedDancerIdentity) : string {
|
||||||
const hue = hueForDancer(identity.setIdentity);
|
const hue = hueForDancer(identity.setIdentity);
|
||||||
const sat = 100 - Math.abs(identity.relativeLine * 40);
|
const sat = 100 - Math.abs(identity.relativeLine * 40);
|
||||||
const unclampedLum = 50 + identity.relativeSet * 20;
|
const lum = 50 + identity.relativeSet * 20;
|
||||||
const lum = unclampedLum < 10 ? 10 : unclampedLum > 90 ? 90 : unclampedLum;
|
|
||||||
return `hsl(${hue}, ${sat}%, ${lum}%)`;
|
return `hsl(${hue}, ${sat}%, ${lum}%)`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -41,13 +40,14 @@ function colorForDancerLabel(identity: ExtendedDancerIdentity) : string {
|
||||||
export class Renderer {
|
export class Renderer {
|
||||||
canvas: HTMLCanvasElement;
|
canvas: HTMLCanvasElement;
|
||||||
ctx: CanvasRenderingContext2D;
|
ctx: CanvasRenderingContext2D;
|
||||||
animation?: Animation;
|
animation: Animation;
|
||||||
extraSets?: number;
|
extraSets?: number;
|
||||||
extraLines?: number;
|
extraLines?: number;
|
||||||
|
|
||||||
constructor(canvas: HTMLCanvasElement, ctx: CanvasRenderingContext2D) {
|
constructor(canvas: HTMLCanvasElement, ctx: CanvasRenderingContext2D) {
|
||||||
this.canvas = canvas;
|
this.canvas = canvas;
|
||||||
this.ctx = ctx;
|
this.ctx = ctx;
|
||||||
|
this.animation = exampleAnimations.longLinesForwardAndBack;
|
||||||
}
|
}
|
||||||
|
|
||||||
drawDancerBody(identity: ExtendedDancerIdentity) {
|
drawDancerBody(identity: ExtendedDancerIdentity) {
|
||||||
|
@ -134,14 +134,10 @@ export class Renderer {
|
||||||
}
|
}
|
||||||
|
|
||||||
drawSetsAtBeat(beat: number) {
|
drawSetsAtBeat(beat: number) {
|
||||||
if (!this.animation) throw new Error("Attempted to render before setting animation.");
|
|
||||||
|
|
||||||
this.drawSets(this.animation.positionsAtBeat(beat));
|
this.drawSets(this.animation.positionsAtBeat(beat));
|
||||||
}
|
}
|
||||||
|
|
||||||
drawSetsWithTrails(beat: number, progression?: number) {
|
drawSetsWithTrails(beat: number, progression?: number) {
|
||||||
if (!this.animation) throw new Error("Attempted to render before setting animation.");
|
|
||||||
|
|
||||||
this.clear();
|
this.clear();
|
||||||
const increments = 10;
|
const increments = 10;
|
||||||
const trailLengthInBeats = 1;
|
const trailLengthInBeats = 1;
|
||||||
|
@ -178,8 +174,7 @@ export class Renderer {
|
||||||
|
|
||||||
clear() {
|
clear() {
|
||||||
// TODO Right way to clear?
|
// TODO Right way to clear?
|
||||||
this.ctx.fillStyle = 'white';
|
this.ctx.clearRect(-this.canvas.width, -this.canvas.height, 2*this.canvas.width, 2*this.canvas.height);
|
||||||
this.ctx.fillRect(-this.canvas.width, -this.canvas.height, 2*this.canvas.width, 2*this.canvas.height);
|
|
||||||
|
|
||||||
const extraLines = this.extraLines ?? 0;
|
const extraLines = this.extraLines ?? 0;
|
||||||
const extraSets = this.extraSets ?? 0;
|
const extraSets = this.extraSets ?? 0;
|
||||||
|
@ -188,7 +183,7 @@ export class Renderer {
|
||||||
this.ctx.save();
|
this.ctx.save();
|
||||||
const hue = (relativeLine + relativeSet) % 2 === 0 ? 60 : 170;
|
const hue = (relativeLine + relativeSet) % 2 === 0 ? 60 : 170;
|
||||||
const sat = 100 - Math.abs(relativeLine * 40);
|
const sat = 100 - Math.abs(relativeLine * 40);
|
||||||
const lum = Math.min(98, 90 + Math.abs(relativeSet) * 5);
|
const lum = 90 + Math.abs(relativeSet) * 5;
|
||||||
this.ctx.fillStyle = `hsl(${hue}, ${sat}%, ${lum}%)`;
|
this.ctx.fillStyle = `hsl(${hue}, ${sat}%, ${lum}%)`;
|
||||||
this.ctx.translate(relativeLine * lineDistance,
|
this.ctx.translate(relativeLine * lineDistance,
|
||||||
relativeSet * setDistance);
|
relativeSet * setDistance);
|
||||||
|
|
Loading…
Reference in New Issue
Block a user