aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--layout.js29
-rw-r--r--main.js56
-rw-r--r--pattern.js64
3 files changed, 72 insertions, 77 deletions
diff --git a/layout.js b/layout.js
index e4eab79..297d7bc 100644
--- a/layout.js
+++ b/layout.js
@@ -3,7 +3,7 @@ const panel = document.querySelector('aside.layout');
const svg = document.getElementById('diagram');
const arrows = Array.from(svg.querySelectorAll('.arrow'));
-const preset = panel.querySelector('.control--preset');
+const preset = panel.querySelector('.control--preset select');
const controls = Array.from(panel.querySelectorAll('.control--axis'));
const steps = Array.from(panel.querySelectorAll('.control--axis > input'));
const dirs = Array.from(panel.querySelectorAll('.control--axis .dir input'));
@@ -28,6 +28,13 @@ const completeState = ([a, b, c]) => {
return [a, b, c, -a, -b, -c];
};
+const PRESETS = {
+ 'wicki-hayden': [ 7, 2, null ],
+ 'janko': [ 1, 2, null ],
+ 'harmonic': [ 7, 4, null ],
+ 'gerhard': [ 4, 3, null ],
+};
+
const updateValues = () => {
const full = completeState(state);
@@ -40,6 +47,10 @@ const updateValues = () => {
dirs[i].disabled = val == 0;
}
});
+
+ const presetName = Object.keys(PRESETS).find(k => completeState(PRESETS[k]).join(',') === full.join(','));
+ preset.value = presetName ?? 'custom';
+
updateFocus();
};
@@ -95,7 +106,6 @@ steps.forEach((input, i) => {
select(i);
state[i] = +input.value;
if (dirs[i].checked) state[i] = -state[i];
- preset.value = 'custom';
updateValues();
};
});
@@ -104,22 +114,17 @@ dirs.forEach((input, i) => {
input.onchange = () => {
select(i);
state[i] = state[i] * -1;
- preset.value = 'custom';
updateValues();
};
});
preset.onchange = () => {
- switch (preset.value) {
- case 'custom': return;
- case 'wicki-hayden': state = [ 7, 2, null ]; break;
- case 'janko': state = [ 1, 2, null ]; break;
- case 'harmonic': state = [ 7, 4, null ]; break;
- case 'gerhard': state = [ 4, 3, null ]; break;
+ const nextState = PRESETS[preset.value];
+ if (nextState) {
+ state = nextState.slice();
+ last = state.findIndex(s => s != null);
+ updateValues();
}
-
- last = state.findIndex(s => s != null);
- updateValues();
};
preset.value = 'wicki-hayden';
preset.onchange();
diff --git a/main.js b/main.js
index 4aa2009..9bf6823 100644
--- a/main.js
+++ b/main.js
@@ -57,25 +57,25 @@ document.body.onkeydown = (e) => {
let lastCanvasSize = 0;
-const updateBackground = (canvasSize) => {
- bg.strokeStyle = '#b9bdc1';
- bg.strokeWidth = 1.5;
+const updateForeground = (canvasSize) => {
+ fg.strokeStyle = '#b9bdc1';
+ fg.strokeWidth = 1.5;
- bg.canvas.width = bg.canvas.width;
- bg.translate(canvasSize/2, canvasSize/2);
+ fg.canvas.width = fg.canvas.width;
+ fg.translate(canvasSize/2, canvasSize/2);
const rad = Math.ceil(canvasSize / size / 3);
for (let q = -rad; q <= rad; q++) {
const rMin = Math.max(-rad, -q-rad);
const rMax = Math.min(rad, rad-q);
for (let r = rMin; r <= rMax; r++) {
- bg.save();
- bg.translate(...hex2px([q, r]));
+ fg.save();
+ fg.translate(...hex2px([q, r]));
- hexagon(bg);
- bg.stroke();
+ hexagon(fg);
+ fg.stroke();
- bg.restore();
+ fg.restore();
}
}
};
@@ -91,21 +91,21 @@ const draw = () => {
fg.canvas.width = fg.canvas.height = canvasSize;
lastCanvasSize = canvasSize;
- updateBackground(canvasSize);
+ updateForeground(canvasSize);
}
- fg.canvas.width = fg.canvas.width;
+ bg.canvas.width = bg.canvas.width;
layout.update();
- fg.translate(canvasSize/2, canvasSize/2);
+ bg.translate(canvasSize/2, canvasSize/2);
- fg.font = `${size*0.5}px sans-serif`;
- fg.textAlign = 'center';
+ bg.font = `${size*0.5}px sans-serif`;
+ bg.textAlign = 'center';
+ bg.textBaseline = 'middle';
- fg.strokeStyle = '#ff0000';
- fg.strokeWidth = 5;
-
+ bg.strokeStyle = '#ff0000';
+ bg.strokeWidth = 5;
const rot = layout.getRot();
const [qq, rr] = layout.getSteps();
@@ -118,29 +118,29 @@ const draw = () => {
const rMin = Math.max(-rad, -q-rad);
const rMax = Math.min(rad, rad-q);
for (let r = rMin; r <= rMax; r++) {
- fg.save();
- fg.translate(...hex2px([q, r]));
+ bg.save();
+ bg.translate(...hex2px([q, r]));
const note = q*qq + r*rr;
let step = note % length;
step = (step + length) % length;
if (steps.includes(note)) {
- fg.fillStyle = '#eeeeee';
- hexagon(fg);
- fg.fill();
+ bg.fillStyle = '#eeeeee';
+ hexagon(bg);
+ bg.fill();
}
- fg.rotate(-rot);
- fg.fillStyle = '#303336';
- fg.fillText(step, 0, size/3);
+ bg.rotate(-rot);
+ bg.fillStyle = '#303336';
+ bg.fillText(step, 0, 0);
- fg.restore();
+ bg.restore();
}
}
// const mouse = px2hex(rotate(mousePos, rot));
- // fg.arc(...hex2px(mouse), 10, 0, 2*Math.PI);
+ // bg.arc(...hex2px(mouse), 10, 0, 2*Math.PI);
document.body.style.setProperty('--global-rot', `${rot}rad`);
requestAnimationFrame(draw);
diff --git a/pattern.js b/pattern.js
index 731139f..6b15fac 100644
--- a/pattern.js
+++ b/pattern.js
@@ -1,12 +1,25 @@
const panel = document.querySelector('aside.pattern');
-const preset = panel.querySelector('.control--preset');
+const preset = panel.querySelector('.control--preset select');
const patternLength = document.getElementById('pattern-len');
const steps = panel.querySelector('.steps');
let length = 12;
let pattern = [0, 2, 4, 5, 7, 9, 11];
+const PRESETS = {
+ 'major-7': [0, 2, 4, 5, 7, 9, 11],
+ 'minor-7': [0, 2, 3, 5, 7, 8, 10],
+ 'minor-harm-7': [0, 2, 3, 5, 7, 8, 11],
+ 'minor-mel-7': [0, 2, 3, 5, 7, 9, 11],
+ 'minor-hung-7': [0, 2, 3, 6, 7, 8, 11],
+ 'penta': [0, 2, 4, 7, 9],
+ 'major-3': [0, 4, 7],
+ 'major-3+': [0, 4, 8],
+ 'minor-3': [0, 3, 7],
+ 'minor-3-': [0, 3, 6],
+};
+
const update = () => {
while (steps.childElementCount > length) {
steps.lastElementChild.remove();
@@ -21,6 +34,13 @@ const update = () => {
Array.from(steps.children).forEach((toggle, i) => {
toggle.checked = pattern.includes(i);
});
+
+ updatePreset();
+};
+
+const updatePreset = () => {
+ const presetName = Object.keys(PRESETS).find(k => PRESETS[k].join(',') === pattern.join(','));
+ preset.value = presetName ?? 'custom';
};
patternLength.onchange = () => {
@@ -34,48 +54,18 @@ steps.onchange = () => {
Array.from(steps.children).forEach((toggle, i) => {
if (toggle.checked) pattern.push(i);
});
+ updatePreset();
};
preset.onchange = (e) => {
- const value = e.target.value;
- switch (value) {
- case 'custom': return;
- case 'major-7':
- pattern = [0, 2, 4, 5, 7, 9, 11];
- break;
- case 'minor-7':
- pattern = [0, 2, 3, 5, 7, 8, 10];
- break;
- case 'minor-harm-7':
- pattern = [0, 2, 3, 5, 7, 8, 11];
- break;
- case 'minor-mel-7':
- pattern = [0, 2, 3, 5, 7, 9, 11];
- break;
- case 'minor-hung-7':
- pattern = [0, 2, 3, 6, 7, 8, 11];
- break;
- case 'penta':
- pattern = [0, 2, 4, 7, 9];
- break;
- case 'major-3':
- pattern = [0, 4, 7];
- break;
- case 'major-3+':
- pattern = [0, 4, 8];
- break;
- case 'minor-3':
- pattern = [0, 3, 7];
- break;
- case 'minor-3-':
- pattern = [0, 3, 6];
- break;
+ const nextPattern = PRESETS[preset.value];
+ if (nextPattern) {
+ pattern = nextPattern.slice();
+ update();
}
- update();
- preset.value = value;
};
preset.value = 'major-7';
-preset.onchange({ target: preset });
+preset.onchange();
export const getLength = () => length;
export const getSteps = () => pattern;