@@ 204,13 204,18 @@
<button class="action" id="action-swap">
<span class="name">Swap</span>
<span class="icon"></span>
- <span class="shortcut">S</span>
+ <span class="shortcut">Alt-S</span>
</button>
<button class="action" id="action-minorLines">
<span class="name">Minor lines</span>
<span class="icon"></span>
<span class="shortcut">M</span>
</button>
+ <button class="action" id="action-snap">
+ <span class="name">Snap</span>
+ <span class="icon"></span>
+ <span class="shortcut">S</span>
+ </button>
</nav>
<canvas id="transform-canvas"></canvas>
<canvas id="grid-canvas"></canvas>
@@ 6,12 6,15 @@ let can, ctx, gridCan, gridCtx;
let state = {
ihat: [1, 0],
jhat: [0, 1],
+ ihatUnsnapped: null,
+ jhatUnsnapped: null,
points: [[1, 1]],
scale: 120,
theme: "light",
selected: null,
curTransition: null,
minorLines: true,
+ snap: false,
rendering: {
dirty: true,
gridDirty: true,
@@ 356,6 359,8 @@ function dragStart(loc) {
selected = id;
}
state.selected = selected; // if nothing selected this will null-ify it
+ state.ihatUnsnapped = state.ihat;
+ state.jhatUnsnapped = state.jhat;
stateUpdated();
return selected !== null;
}
@@ 369,8 374,16 @@ function dragContinue(delta) {
state.points[idx][0] += move[0];
state.points[idx][1] += move[1];
} else {
- state[state.selected][0] += delta[0] / state.scale;
- state[state.selected][1] += delta[1] / state.scale;
+ if (state.snap) {
+ state[state.selected + "Unsnapped"][0] += delta[0] / state.scale;
+ state[state.selected + "Unsnapped"][1] += delta[1] / state.scale;
+ const snapScale = state.minorLines ? 2 : 1;
+ state.ihat = state.ihatUnsnapped.map(x => Math.round(x * snapScale) / snapScale);
+ state.jhat = state.jhatUnsnapped.map(x => Math.round(x * snapScale) / snapScale);
+ } else {
+ state[state.selected][0] += delta[0] / state.scale;
+ state[state.selected][1] += delta[1] / state.scale;
+ }
}
stateUpdated();
}
@@ 378,6 391,8 @@ function dragContinue(delta) {
function dragEnd() {
state.selected = null;
+ state.ihatUnsnapped = null;
+ state.jhatUnsnapped = null;
stateUpdated();
}
@@ 410,13 425,19 @@ const ACTIONS = [
name: "swap",
actionType: "move",
action: () => ({ ihat: state.jhat, jhat: state.ihat }),
- keys: ["KeyS"]
+ keys: ["alt", "KeyS"]
},
{
name: "minorLines",
actionType: "toggle",
stateBool: "minorLines",
keys: ["KeyM"]
+ },
+ {
+ name: "snap",
+ actionType: "toggle",
+ stateBool: "snap",
+ keys: ["KeyS"]
}
];
@@ 524,7 545,21 @@ document.addEventListener("DOMContentLoaded", () => {
const btn = document.getElementById("action-" + action.name);
action.keys.forEach(key => {
document.body.addEventListener("keydown", e => {
- if (!e.ctrlKey && !e.altKey && !e.metaKey && (state.curTransition === null) && (e.code === key)) execAction(id, e.shiftKey);
+ const mainKey = action.keys[action.keys.length - 1];
+ if (e.code !== mainKey) return;
+
+ // if we require a control key, make sure it's pressed
+ if (!e.ctrlKey && action.keys.includes("ctrl")) return;
+ if (!e.altKey && action.keys.includes("alt")) return;
+ if (!e.metaKey && action.keys.includes("meta")) return;
+
+ // if a control key is pressed but we don't expect it, ignore
+ if (e.ctrlKey && !action.keys.includes("ctrl")) return;
+ if (e.altKey && !action.keys.includes("alt")) return;
+ if (e.metaKey && !action.keys.includes("meta")) return;
+
+ if (state.curTransition !== null) return;
+ execAction(id, e.shiftKey);
});
});
if (btn) {