Compare commits
5 Commits
abf26a0a59
...
5625e0c83a
Author | SHA1 | Date | |
---|---|---|---|
5625e0c83a | |||
7e63c07cda | |||
eefea94149 | |||
a1ecc7ec1a | |||
6433b30ed1 |
|
@ -1,5 +1,5 @@
|
||||||
import { CoupleRole, DancerIdentity, Rotation, normalizeRotation } from "./danceCommon.js";
|
import { CoupleRole, DancerIdentity, Rotation, normalizeRotation } from "./danceCommon.js";
|
||||||
import { DancerSetPosition, DancersSetPositions, Hand, OffsetEquals, OffsetMinus, OffsetPlus, OffsetTimes, offsetZero } from "./rendererConstants.js";
|
import { DancerSetPosition, DancersSetPositions, Hand, OffsetEquals, OffsetMinus, OffsetPlus, OffsetTimes, offsetZero, setHeight } from "./rendererConstants.js";
|
||||||
import { Offset, leftShoulder, rightShoulder, degreesToRadians, radiansToDegrees } from "./rendererConstants.js";
|
import { Offset, leftShoulder, rightShoulder, degreesToRadians, radiansToDegrees } from "./rendererConstants.js";
|
||||||
|
|
||||||
export enum AnimationKind {
|
export enum AnimationKind {
|
||||||
|
@ -359,6 +359,7 @@ export class Animation {
|
||||||
private readonly segments : Map<DancerIdentity, AnimationSegment[]>;
|
private readonly segments : Map<DancerIdentity, AnimationSegment[]>;
|
||||||
public readonly progression : Offset;
|
public readonly progression : Offset;
|
||||||
public readonly numBeats : number;
|
public readonly numBeats : number;
|
||||||
|
public readonly progressionError : string | undefined;
|
||||||
|
|
||||||
constructor(segments: Map<DancerIdentity, AnimationSegment[]>) {
|
constructor(segments: Map<DancerIdentity, AnimationSegment[]>) {
|
||||||
this.segments = segments;
|
this.segments = segments;
|
||||||
|
@ -373,19 +374,22 @@ export class Animation {
|
||||||
a.at(0)!.startPosition.position)]));
|
a.at(0)!.startPosition.position)]));
|
||||||
this.progression = progressions.get(DancerIdentity.OnesLark)!;
|
this.progression = progressions.get(DancerIdentity.OnesLark)!;
|
||||||
if (this.progression.x !== 0) {
|
if (this.progression.x !== 0) {
|
||||||
throw "Progressing to different line is unsupported.";
|
this.progressionError = "Progressing to different line is unsupported.";
|
||||||
}
|
}
|
||||||
if (this.progression.y === 0) {
|
if (this.progression.y === 0) {
|
||||||
throw "Dance does not progress.";
|
this.progressionError = "Dance does not progress.";
|
||||||
}
|
}
|
||||||
if (!OffsetEquals(progressions.get(DancerIdentity.OnesLark)!, progressions.get(DancerIdentity.OnesRobin)!)) {
|
if (!OffsetEquals(progressions.get(DancerIdentity.OnesLark)!, progressions.get(DancerIdentity.OnesRobin)!)) {
|
||||||
throw "Ones are not progressing the same as each other.";
|
this.progressionError = "Ones are not progressing the same as each other.";
|
||||||
}
|
}
|
||||||
if (!OffsetEquals(progressions.get(DancerIdentity.TwosLark)!, progressions.get(DancerIdentity.TwosRobin)!)) {
|
if (!OffsetEquals(progressions.get(DancerIdentity.TwosLark)!, progressions.get(DancerIdentity.TwosRobin)!)) {
|
||||||
throw "Twos are not progressing the same as each other.";
|
this.progressionError = "Twos are not progressing the same as each other.";
|
||||||
}
|
}
|
||||||
if (!OffsetEquals(progressions.get(DancerIdentity.OnesLark)!, OffsetMinus(offsetZero, progressions.get(DancerIdentity.TwosLark)!))) {
|
if (!OffsetEquals(progressions.get(DancerIdentity.OnesLark)!, OffsetMinus(offsetZero, progressions.get(DancerIdentity.TwosLark)!))) {
|
||||||
throw "Ones and Twos are not progressing opposite each other.";
|
this.progressionError = "Ones and Twos are not progressing opposite each other.";
|
||||||
|
}
|
||||||
|
if (this.progression.y % setHeight / 2 !== 0) {
|
||||||
|
this.progressionError = "Progression is not an integer number of places.";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -46,6 +46,8 @@ export class CoupleRole {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export type StartFormation = "improper" | "Becket" | "Becket ccw" | "Sawtooth Becket";
|
||||||
|
|
||||||
export enum Rotation {
|
export enum Rotation {
|
||||||
Up = 180,
|
Up = 180,
|
||||||
Down = 0,
|
Down = 0,
|
||||||
|
|
|
@ -1,10 +1,11 @@
|
||||||
|
import { StartFormation } from "./danceCommon.js";
|
||||||
import { LibFigureDance } from "./libfigureMapper.js";
|
import { LibFigureDance } from "./libfigureMapper.js";
|
||||||
|
|
||||||
export interface ContraDBDance {
|
export interface ContraDBDance {
|
||||||
id: number,
|
id: number,
|
||||||
title: string,
|
title: string,
|
||||||
choreographer_name: string,
|
choreographer_name: string,
|
||||||
start_type: "improper" | "Becket" | "Becket ccw" | "Sawtooth Becket",
|
start_type: StartFormation,
|
||||||
preamble: string,
|
preamble: string,
|
||||||
figures: LibFigureDance,
|
figures: LibFigureDance,
|
||||||
notes: string,
|
notes: string,
|
||||||
|
|
|
@ -44,9 +44,6 @@ const handsFourImproper: Map<common.DancerIdentity, SemanticPosition> = new Map<
|
||||||
}],
|
}],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
// Two Hearts in Time by Isaac Banner. Selected arbitrarily.
|
|
||||||
const exampleDance: LibFigureDance = [{ "parameter_values": [true, 8], "move": "petronella" }, { "parameter_values": [true, 8], "move": "petronella" }, { "parameter_values": ["neighbors", "balance", 16], "move": "swing" }, { "parameter_values": ["ladles", true, 540, 8], "move": "allemande" }, { "parameter_values": ["partners", "none", 8], "move": "swing" }, { "parameter_values": ["gentlespoons", 360, 6], "move": "mad robin" }, { "parameter_values": [true, 270, 6], "move": "circle" }, { "parameter_values": ["partners", 4], "move": "California twirl", "progression": 1 }];
|
|
||||||
|
|
||||||
function balanceCircleInAndOut(move: Move, startPos: SemanticPosition, balanceBeats?: number): [LowLevelMove, LowLevelMove] {
|
function balanceCircleInAndOut(move: Move, startPos: SemanticPosition, balanceBeats?: number): [LowLevelMove, LowLevelMove] {
|
||||||
if (startPos.kind !== PositionKind.Circle) {
|
if (startPos.kind !== PositionKind.Circle) {
|
||||||
throw "Balance circle must start in a circle, but starting at " + startPos;
|
throw "Balance circle must start in a circle, but starting at " + startPos;
|
||||||
|
@ -520,7 +517,7 @@ function moveAsLowLevelMoves(move: Move, startingPos: Map<DancerIdentity, Semant
|
||||||
//throw "Unknown move: " + move.move + ": " + JSON.stringify(move);
|
//throw "Unknown move: " + move.move + ": " + JSON.stringify(move);
|
||||||
for (const [id, startPos] of startingPos.entries()) {
|
for (const [id, startPos] of startingPos.entries()) {
|
||||||
res.set(id, [{
|
res.set(id, [{
|
||||||
remarks: "UNKNOWN MOVE: standing still",
|
interpreterError: "UNKNOWN MOVE: standing still",
|
||||||
move,
|
move,
|
||||||
startBeat: 0,
|
startBeat: 0,
|
||||||
beats: move.beats,
|
beats: move.beats,
|
||||||
|
@ -546,8 +543,6 @@ function danceAsLowLevelMoves(moves: Move[], startingPos: Map<DancerIdentity, Se
|
||||||
}
|
}
|
||||||
|
|
||||||
const progression = animateFromLowLevelMoves(res).progression;
|
const progression = animateFromLowLevelMoves(res).progression;
|
||||||
if (progression.x !== 0) throw "Progressing to different line is unsupported.";
|
|
||||||
if (progression.y % setHeight / 2 !== 0) throw "Progression is not an integer number of places.";
|
|
||||||
const progressionInSets = progression.y / setDistance;
|
const progressionInSets = progression.y / setDistance;
|
||||||
|
|
||||||
// fixup end positions to match start of next move
|
// fixup end positions to match start of next move
|
||||||
|
@ -568,18 +563,68 @@ function danceAsLowLevelMoves(moves: Move[], startingPos: Map<DancerIdentity, Se
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function StartingPosForFormation(formation: common.StartFormation): Map<DancerIdentity, SemanticPosition> {
|
||||||
|
switch (formation) {
|
||||||
|
case "improper":
|
||||||
|
return handsFourImproper;
|
||||||
|
case "Becket":
|
||||||
|
return new Map<DancerIdentity, SemanticPosition>([...handsFourImproper.entries()].map(
|
||||||
|
el => {
|
||||||
|
const [id, pos] = el;
|
||||||
|
if (pos.kind !== PositionKind.Circle) throw "Unreachable; improper starts in a circle.";
|
||||||
|
return ([id, {...pos, which: pos.which.circleLeft(1)}])
|
||||||
|
}
|
||||||
|
));
|
||||||
|
case "Becket ccw":
|
||||||
|
return new Map<DancerIdentity, SemanticPosition>([...handsFourImproper.entries()].map(
|
||||||
|
el => {
|
||||||
|
const [id, pos] = el;
|
||||||
|
if (pos.kind !== PositionKind.Circle) throw "Unreachable; improper starts in a circle.";
|
||||||
|
return ([id, {...pos, which: pos.which.circleRight(1)}])
|
||||||
|
}
|
||||||
|
));
|
||||||
|
case "Sawtooth Becket":
|
||||||
|
// Dancers start becket, then slide one person to the right. https://contradb.com/dances/848
|
||||||
|
// TODO Not sure this is right.
|
||||||
|
return new Map<common.DancerIdentity, SemanticPosition>([
|
||||||
|
[DancerIdentity.OnesLark, {
|
||||||
|
kind: PositionKind.Circle,
|
||||||
|
which: CirclePosition.BottomLeft,
|
||||||
|
facing: Facing.CenterOfCircle,
|
||||||
|
hands: handsInCircle,
|
||||||
|
}],
|
||||||
|
[DancerIdentity.OnesRobin, {
|
||||||
|
kind: PositionKind.Circle,
|
||||||
|
which: CirclePosition.TopLeft,
|
||||||
|
facing: Facing.CenterOfCircle,
|
||||||
|
hands: handsInCircle,
|
||||||
|
}],
|
||||||
|
[DancerIdentity.TwosLark, {
|
||||||
|
kind: PositionKind.Circle,
|
||||||
|
which: CirclePosition.BottomRight,
|
||||||
|
facing: Facing.CenterOfCircle,
|
||||||
|
hands: handsInCircle,
|
||||||
|
}],
|
||||||
|
[DancerIdentity.TwosRobin, {
|
||||||
|
kind: PositionKind.Circle,
|
||||||
|
which: CirclePosition.TopRight,
|
||||||
|
facing: Facing.CenterOfCircle,
|
||||||
|
hands: handsInCircle,
|
||||||
|
setOffset: 1,
|
||||||
|
}],
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export let mappedDance: Move[];
|
export let mappedDance: Move[];
|
||||||
|
|
||||||
export let interpretedDance: Map<DancerIdentity, LowLevelMove[]>;
|
export let interpretedDance: Map<DancerIdentity, LowLevelMove[]>;
|
||||||
export let interpretedAnimation: animation.Animation;
|
export let interpretedAnimation: animation.Animation;
|
||||||
|
|
||||||
export function loadDance(dance: LibFigureDance): animation.Animation {
|
export function loadDance(dance: LibFigureDance, formation: common.StartFormation): animation.Animation {
|
||||||
mappedDance = dance.map(nameLibFigureParameters);
|
mappedDance = dance.map(nameLibFigureParameters);
|
||||||
interpretedDance = danceAsLowLevelMoves(mappedDance, handsFourImproper);
|
interpretedDance = danceAsLowLevelMoves(mappedDance, StartingPosForFormation(formation));
|
||||||
interpretedAnimation = animateFromLowLevelMoves(interpretedDance);
|
interpretedAnimation = animateFromLowLevelMoves(interpretedDance);
|
||||||
|
|
||||||
return interpretedAnimation;
|
return interpretedAnimation;
|
||||||
}
|
}
|
||||||
|
|
||||||
loadDance(exampleDance);
|
|
|
@ -84,6 +84,7 @@ export type SemanticAnimation = {
|
||||||
export interface LowLevelMove {
|
export interface LowLevelMove {
|
||||||
// for debugging messages
|
// for debugging messages
|
||||||
remarks?: string,
|
remarks?: string,
|
||||||
|
interpreterError?: string,
|
||||||
// move is here for reference/debugging, shouldn't actually get used.
|
// move is here for reference/debugging, shouldn't actually get used.
|
||||||
move: Move,
|
move: Move,
|
||||||
// for debugging, if move has been broken into multiple low-level moves, where does this one start
|
// for debugging, if move has been broken into multiple low-level moves, where does this one start
|
||||||
|
|
133
www/js/main.ts
133
www/js/main.ts
|
@ -1,4 +1,5 @@
|
||||||
import * as animation from "./animation.js";
|
import * as animation from "./animation.js";
|
||||||
|
import * as danceLibrary from "./danceLibrary.js";
|
||||||
import * as interpreter from "./interpreter.js";
|
import * as interpreter from "./interpreter.js";
|
||||||
import * as renderer from "./renderer.js";
|
import * as renderer from "./renderer.js";
|
||||||
import { DancerIdentity } from "./danceCommon.js";
|
import { DancerIdentity } from "./danceCommon.js";
|
||||||
|
@ -56,9 +57,6 @@ const r = new renderer.Renderer(canvas, ctx);
|
||||||
r.extraLines = 3;
|
r.extraLines = 3;
|
||||||
r.extraSets = 3;
|
r.extraSets = 3;
|
||||||
r.clear();
|
r.clear();
|
||||||
r.animation = interpreter.interpretedAnimation;
|
|
||||||
beatSlider.max = r.animation.numBeats.toString();
|
|
||||||
r.drawSetsWithTrails(0);
|
|
||||||
|
|
||||||
const bpmSelector = document.createElement('input');
|
const bpmSelector = document.createElement('input');
|
||||||
bpmSelector.type = 'number';
|
bpmSelector.type = 'number';
|
||||||
|
@ -88,8 +86,10 @@ autoProgressLabel.innerText = 'Loop playback';
|
||||||
const playButton = document.createElement('button');
|
const playButton = document.createElement('button');
|
||||||
playButton.innerText = "Play";
|
playButton.innerText = "Play";
|
||||||
|
|
||||||
|
const danceTitle = document.createElement('h1');
|
||||||
const movesList = document.createElement('ul');
|
const movesList = document.createElement('ul');
|
||||||
|
|
||||||
|
wrapperDiv.appendChild(danceTitle);
|
||||||
wrapperDiv.appendChild(movesList);
|
wrapperDiv.appendChild(movesList);
|
||||||
wrapperDiv.appendChild(document.createElement('br'));
|
wrapperDiv.appendChild(document.createElement('br'));
|
||||||
wrapperDiv.appendChild(bpmSelector);
|
wrapperDiv.appendChild(bpmSelector);
|
||||||
|
@ -159,10 +159,7 @@ bpmSelector.addEventListener('change', (ev) => {
|
||||||
restartAnimation(false);
|
restartAnimation(false);
|
||||||
});
|
});
|
||||||
|
|
||||||
// Two Hearts in Time by Isaac Banner. Selected arbitrarily.
|
// Copied from my (Daniel Perelman's) dialect settings on contradb.
|
||||||
const exampleDance: LibFigureDance = [{ "parameter_values": [true, 8], "move": "petronella" }, { "parameter_values": [true, 8], "move": "petronella" }, { "parameter_values": ["neighbors", "balance", 16], "move": "swing" }, { "parameter_values": ["ladles", true, 540, 8], "move": "allemande" }, { "parameter_values": ["partners", "none", 8], "move": "swing" }, { "parameter_values": ["gentlespoons", 360, 6], "move": "mad robin" }, { "parameter_values": [true, 270, 6], "move": "circle" }, { "parameter_values": ["partners", 4], "move": "California twirl", "progression": 1 }];
|
|
||||||
|
|
||||||
// Copied from my dialect settings on contradb.
|
|
||||||
const dialect = {
|
const dialect = {
|
||||||
"moves": {
|
"moves": {
|
||||||
"gyre": "%S shoulder round"
|
"gyre": "%S shoulder round"
|
||||||
|
@ -180,19 +177,30 @@ const dialect = {
|
||||||
"text_in_dialect": true
|
"text_in_dialect": true
|
||||||
};
|
};
|
||||||
|
|
||||||
let dance: LibFigureDance;
|
let dance: danceLibrary.ContraDBDance;
|
||||||
function buildMovesList() {
|
function buildMovesList() {
|
||||||
removeAllChildNodes(movesList);
|
removeAllChildNodes(movesList);
|
||||||
|
|
||||||
|
const formation = document.createElement('li');
|
||||||
|
formation.innerText = 'Starting formation: ' + dance.start_type;
|
||||||
|
formation.className = 'formation';
|
||||||
|
movesList.appendChild(formation);
|
||||||
|
|
||||||
let currentBeat: number = 0;
|
let currentBeat: number = 0;
|
||||||
let lastItem: HTMLLIElement | undefined;
|
let lastItem: HTMLLIElement | undefined;
|
||||||
for (const figure of dance) {
|
for (const figure of dance.figures) {
|
||||||
const startBeat = currentBeat;
|
const startBeat = currentBeat;
|
||||||
currentBeat += figureBeats(figure);
|
currentBeat += figureBeats(figure);
|
||||||
const moveItem = document.createElement('li');
|
const moveItem = document.createElement('li');
|
||||||
|
let figureHtml: string;
|
||||||
|
try {
|
||||||
|
figureHtml = figureToHtml(figure, dialect);
|
||||||
|
} catch (e) {
|
||||||
|
figureHtml = "libfigureError: " + e;
|
||||||
|
}
|
||||||
moveItem.innerHTML = "[" + labelForBeats(Math.floor(startBeat / 16) * 16) + " "
|
moveItem.innerHTML = "[" + labelForBeats(Math.floor(startBeat / 16) * 16) + " "
|
||||||
+ "(" + startBeat + "-" + currentBeat + ")] "
|
+ "(" + startBeat + "-" + currentBeat + ")] "
|
||||||
+ figureToHtml(figure, dialect);
|
+ figureHtml;
|
||||||
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);
|
||||||
|
@ -208,6 +216,22 @@ function buildMovesList() {
|
||||||
if (lastItem) {
|
if (lastItem) {
|
||||||
lastItem.classList.add('moveForBeat_' + currentBeat);
|
lastItem.classList.add('moveForBeat_' + currentBeat);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (r.animation.progressionError) {
|
||||||
|
const error = document.createElement('li');
|
||||||
|
error.classList.add('error');
|
||||||
|
error.classList.add('progressionError');
|
||||||
|
error.innerText = 'Dance progression does not work; dance was probably interpreted wrong: ' + r.animation.progressionError;
|
||||||
|
movesList.appendChild(error);
|
||||||
|
}
|
||||||
|
const interpreterError = [...interpreter.interpretedDance.values()].flatMap(moves => moves.filter(m => m.interpreterError !== undefined).map(m => m.interpreterError)).at(0);
|
||||||
|
if (interpreterError) {
|
||||||
|
const error = document.createElement('li');
|
||||||
|
error.classList.add('error');
|
||||||
|
error.classList.add('interpreterError');
|
||||||
|
error.innerText = 'Interpreter failed on some move, see debug information below for more information: ' + interpreterError;
|
||||||
|
movesList.appendChild(error);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function setBeat(beat: number) {
|
function setBeat(beat: number) {
|
||||||
|
@ -263,8 +287,66 @@ function playAnimation(bpm: number, start: number, end: number) {
|
||||||
anim();
|
anim();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Default dance is Two Hearts in Time by Isaac Banner. Selected arbitrarily.
|
||||||
|
const defaultDanceTitle = "Two Hearts in Time";
|
||||||
|
|
||||||
|
wrapperDiv.appendChild(document.createElement('br'));
|
||||||
|
const danceList = document.createElement('select');
|
||||||
|
for (const [idx, dance] of danceLibrary.dances.entries()) {
|
||||||
|
const opt = document.createElement('option');
|
||||||
|
opt.value = idx.toString();
|
||||||
|
opt.innerText = dance.title + " by " + dance.choreographer_name;
|
||||||
|
if (dance.title === defaultDanceTitle) {
|
||||||
|
opt.selected = true;
|
||||||
|
}
|
||||||
|
danceList.appendChild(opt);
|
||||||
|
}
|
||||||
|
danceList.addEventListener('input', () => {
|
||||||
|
danceJsonArea.value = JSON.stringify(danceLibrary.dances[danceList.value], undefined, 2);
|
||||||
|
})
|
||||||
|
wrapperDiv.appendChild(danceList);
|
||||||
|
|
||||||
|
const verifyButton = document.createElement('button');
|
||||||
|
verifyButton.innerText = 'Test loading every dance';
|
||||||
|
verifyButton.addEventListener('click', () => {
|
||||||
|
danceList.childNodes.forEach((opt: HTMLOptionElement) => {
|
||||||
|
if (opt.innerText.startsWith('[')) return; // already processed
|
||||||
|
|
||||||
|
const dance = danceLibrary.dances[parseInt(opt.value)];
|
||||||
|
let interpreterError: string | undefined = undefined;
|
||||||
|
let progressionError: string | undefined = undefined;
|
||||||
|
let libfigureError: string | undefined = undefined;
|
||||||
|
try {
|
||||||
|
for (const figure of dance.figures) {
|
||||||
|
figureToHtml(figure, dialect);
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
libfigureError = 'libfigure ex: ' + e;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
progressionError = interpreter.loadDance(dance.figures, dance.start_type).progressionError;
|
||||||
|
const moveError = [...interpreter.interpretedDance.values()].flatMap(moves => moves.filter(m => m.interpreterError !== undefined).map(m => m.interpreterError)).at(0);
|
||||||
|
if (moveError) {
|
||||||
|
interpreterError = "interpreter move error: " + moveError;
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
interpreterError = "interpreter exception: " + e;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!interpreterError && !progressionError && !libfigureError) {
|
||||||
|
opt.innerText = "[OK] " + opt.innerText;
|
||||||
|
} else {
|
||||||
|
const errors = (libfigureError ? "[" + libfigureError + "] " : "")
|
||||||
|
+ (interpreterError ? "[" + interpreterError + "] " : "")
|
||||||
|
+ (progressionError ? "[" + progressionError + "] " : "");
|
||||||
|
opt.innerText = errors + opt.innerText;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
wrapperDiv.appendChild(verifyButton);
|
||||||
|
|
||||||
const danceJsonArea = document.createElement('textarea');
|
const danceJsonArea = document.createElement('textarea');
|
||||||
danceJsonArea.value = JSON.stringify(exampleDance, undefined, 2);
|
danceJsonArea.value = JSON.stringify(danceLibrary.dances.find(d => d.title === defaultDanceTitle), undefined, 2);
|
||||||
danceJsonArea.rows = 15;
|
danceJsonArea.rows = 15;
|
||||||
danceJsonArea.cols = 30;
|
danceJsonArea.cols = 30;
|
||||||
const loadDanceButton = document.createElement('button');
|
const loadDanceButton = document.createElement('button');
|
||||||
|
@ -275,8 +357,33 @@ wrapperDiv.appendChild(loadDanceButton);
|
||||||
|
|
||||||
const table = document.createElement('table');
|
const table = document.createElement('table');
|
||||||
function loadDance() {
|
function loadDance() {
|
||||||
dance = JSON.parse(danceJsonArea.value);
|
const loadedDance : LibFigureDance | danceLibrary.ContraDBDance = JSON.parse(danceJsonArea.value);
|
||||||
r.animation = interpreter.loadDance(dance);
|
removeAllChildNodes(danceTitle);
|
||||||
|
if (loadedDance instanceof Array) {
|
||||||
|
dance = {
|
||||||
|
figures: loadedDance,
|
||||||
|
id: 0,
|
||||||
|
title: "",
|
||||||
|
choreographer_name: "",
|
||||||
|
start_type: "improper",
|
||||||
|
preamble: "",
|
||||||
|
notes: "",
|
||||||
|
hook: "",
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
dance = loadedDance;
|
||||||
|
|
||||||
|
const title = document.createElement('a');
|
||||||
|
title.href = 'https://contradb.com/dances/' + dance.id;
|
||||||
|
title.innerText = dance.title;
|
||||||
|
|
||||||
|
const author = document.createElement('span');
|
||||||
|
author.innerText = ' by ' + dance.choreographer_name;
|
||||||
|
|
||||||
|
danceTitle.appendChild(title);
|
||||||
|
danceTitle.appendChild(author);
|
||||||
|
}
|
||||||
|
r.animation = interpreter.loadDance(dance.figures, dance.start_type);
|
||||||
if (cancelAnim !== undefined) {
|
if (cancelAnim !== undefined) {
|
||||||
cancelAnimationFrame(cancelAnim);
|
cancelAnimationFrame(cancelAnim);
|
||||||
playButton.innerText = 'Play';
|
playButton.innerText = 'Play';
|
||||||
|
|
Loading…
Reference in New Issue
Block a user