Skip to content

Commit 883d52d

Browse files
authored
optimize primary mouse events, add free drag (#133)
1 parent 91f344f commit 883d52d

File tree

2 files changed

+73
-30
lines changed

2 files changed

+73
-30
lines changed

docs/static/hexmaps.css

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,19 +8,23 @@ html, body {
88
}
99

1010
.brushcursor {
11-
cursor:url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='40' height='48' viewport='0 0 100 100' style='fill:black;font-size:24px;'><text y='50%'>🖌</text></svg>") 0 16,auto;
11+
cursor: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='40' height='48' viewport='0 0 100 100' style='fill:black;font-size:24px;'><text y='50%'>🖌</text></svg>") 0 16,auto;
1212
}
1313

1414
.fillcursor {
15-
cursor:url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='40' height='48' viewport='0 0 100 100' style='fill:black;font-size:24px;'><text y='50%'>🪣</text></svg>") 16 0,auto;
15+
cursor: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='40' height='48' viewport='0 0 100 100' style='fill:black;font-size:24px;'><text y='50%'>🪣</text></svg>") 16 0,auto;
1616
}
1717

1818
.eyedroppercursor {
19-
cursor:url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='40' height='48' viewport='0 0 100 100' style='fill:black;font-size:24px;'><text y='50%'>💧</text></svg>") 20 0,auto;
19+
cursor: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='40' height='48' viewport='0 0 100 100' style='fill:black;font-size:24px;'><text y='50%'>💧</text></svg>") 20 0,auto;
2020
}
2121

2222
.erasercursor {
23-
cursor:url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='40' height='48' viewport='0 0 100 100' style='fill:black;font-size:24px;'><text y='50%'>🧻</text></svg>") 0 0,auto;
23+
cursor: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='40' height='48' viewport='0 0 100 100' style='fill:black;font-size:24px;'><text y='50%'>🧻</text></svg>") 0 0,auto;
24+
}
25+
26+
.movecursor {
27+
cursor: move;
2428
}
2529

2630
.btn {

docs/static/hexmaps.js

Lines changed: 65 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -59,12 +59,13 @@ const GLOBAL_STATE = {
5959
holdingKeyZ: false,
6060
holdingMeta: false,
6161
},
62-
selectedElements: [],
6362
canvasColor: "#c4b9a5",
6463

65-
// brushing metadata/status
64+
// active actions
65+
freeDragging: false,
6666
brushingActive: false,
6767
usingSecondary: false,
68+
selectedElements: [],
6869

6970
layers: {
7071
BASE: {
@@ -175,7 +176,7 @@ document.addEventListener("keyup", e => {
175176

176177
// when window loses focus, reset - otherwise, Cmd+Tab to change windows
177178
// will continue having holdingMeta after coming back
178-
document.addEventListener("blur", () => {
179+
document.addEventListener("blur", e => {
179180
GLOBAL_STATE.keyState.holdingKeyZ = false;
180181
GLOBAL_STATE.keyState.holdingMeta = false;
181182
});
@@ -262,11 +263,50 @@ document.getElementById("saveBtn").addEventListener("click", (e) => {
262263
});
263264

264265
// SVG events listeners
266+
// mousedown is the big one that coordinates most of the page
267+
SVG.addEventListener("mousedown", (e) => {
268+
e.preventDefault();
269+
console.log(e);
270+
if (GLOBAL_STATE.keyState.holdingKeyZ) {
271+
const zoomFactor = .5 * (e.button == 2 ? 1 : -1);
272+
zoom(zoomFactor, e.clientX, e.clientY);
273+
return;
274+
} else if (e.buttons < 3) { // single left/right click
275+
GLOBAL_STATE.brushingActive = true;
276+
// a right mouse down means paint with secondary colors
277+
GLOBAL_STATE.usingSecondary = (e.button == 2);
278+
const hexAtMouse = document.elementsFromPoint(e.clientX, e.clientY).find(el => el.classList.contains("hex"));
279+
if (hexAtMouse) {
280+
handleHexInteraction(hexAtMouse.getAttribute("c"), hexAtMouse.getAttribute("r"), e.clientX, e.clientY, true);
281+
}
282+
} else if (e.buttons == 4) {
283+
GLOBAL_STATE.freeDragging = true;
284+
SVG.addEventListener("mousemove", freeDragScroll);
285+
switchToCursor("move");
286+
}
287+
});
288+
SVG.addEventListener("mouseover", (e) => {
289+
console.log(e);
290+
if (GLOBAL_STATE.brushingActive) {
291+
const hexAtMouse = document.elementsFromPoint(e.clientX, e.clientY).find(el => el.classList.contains("hex"));
292+
console.log(hexAtMouse);
293+
if (hexAtMouse) {
294+
handleHexInteraction(hexAtMouse.getAttribute("c"), hexAtMouse.getAttribute("r"), e.x, e.y, false);
295+
}
296+
}
297+
});
265298
SVG.addEventListener("mouseup", () => {
299+
if (GLOBAL_STATE.layers.BOUNDARY.lastBoundaryPoint) {
300+
SVG.removeEventListener("mousemove", drawBoundary);
301+
}
302+
if (GLOBAL_STATE.freeDragging) {
303+
SVG.removeEventListener("mousemove", freeDragScroll);
304+
switchToCursor(GLOBAL_STATE.currentTool);
305+
}
266306
GLOBAL_STATE.brushingActive = false;
267307
GLOBAL_STATE.layers.PATH.activePath = null;
308+
GLOBAL_STATE.freeDragging = false;
268309
GLOBAL_STATE.layers.BOUNDARY.lastBoundaryPoint = null;
269-
SVG.removeEventListener("mousemove", drawBoundary);
270310
});
271311

272312
SVG.addEventListener("contextmenu", e => e.preventDefault());
@@ -281,6 +321,7 @@ SVG.addEventListener("wheel", e => {
281321
}
282322
});
283323

324+
284325
/*********************************
285326
* INTERACTING WITH GLOBAL STATE *
286327
*********************************/
@@ -345,12 +386,17 @@ function switchToLayer(layer) {
345386
setSecondaryColor(GLOBAL_STATE.layers[GLOBAL_STATE.currentLayer].secondaryColor);
346387
}
347388

389+
function switchToCursor(name) {
390+
Object.keys(Tools).forEach(t => SVG.classList.remove(`${t.toLowerCase()}cursor`));
391+
SVG.classList.remove("movecursor");
392+
SVG.classList.add(`${name.toLowerCase()}cursor`);
393+
}
394+
348395
function switchToTool(tool) {
349396
if (!LAYER_TOOL_COMPATIBILITY[GLOBAL_STATE.currentLayer].includes(tool)) {
350397
return;
351398
}
352-
Object.keys(Tools).forEach(t => SVG.classList.remove(`${t.toLowerCase()}cursor`));
353-
SVG.classList.add(`${tool.toLowerCase()}cursor`);
399+
switchToCursor(tool);
354400
TOOL_PICKER_BUTTONS.forEach(b => {
355401
if (b.dataset.tool == tool) {
356402
b.classList.add("selected")
@@ -375,6 +421,10 @@ function switchToTool(tool) {
375421
/*************
376422
* SVG UTILS *
377423
*************/
424+
function freeDragScroll(e) {
425+
scroll(e.movementX, e.movementY);
426+
}
427+
378428
function scroll(xdiff, ydiff) {
379429
const viewBox = SVG.getAttribute("viewBox") || `0 0 ${window.innerWidth} ${window.innerHeight}`;
380430
const [x, y, width, height] = viewBox.split(" ").map(Number);
@@ -409,7 +459,9 @@ function hexIndexToPixel(c, r) {
409459
return {x, y};
410460
}
411461

412-
function getHexNeighbors(c, r) {
462+
function getHexNeighbors(_c, _r) {
463+
const c = parseInt(_c);
464+
const r = parseInt(_r);
413465
if (GLOBAL_STATE.useVerticalAxes) {
414466
const offset = (r % 2 == 0) ? -1 : 1;
415467
return [
@@ -463,6 +515,7 @@ function floodFill(startC, startR, fn) {
463515
while (queue.length > 0) {
464516
const [c, r] = queue.shift();
465517
getHexNeighbors(c, r).forEach(n => {
518+
console.log(n);
466519
const stringedCoords = `${n[0]},${n[1]}`;
467520
if (visited.includes(stringedCoords)) return;
468521
const nhexentry = GLOBAL_STATE.hexes[stringedCoords];
@@ -477,6 +530,8 @@ function floodFill(startC, startR, fn) {
477530
}
478531

479532
function eraseHex(c, r) {
533+
hexObject.setAttribute("c", c);
534+
hexObject.setAttribute("r", r);
480535
GLOBAL_STATE.layers.OBJECT.objectsOnHexes[`${c},${r}`].textContent = "";
481536
GLOBAL_STATE.hexes[`${c},${r}`].hex.setAttribute("fill", GLOBAL_STATE.canvasColor);
482537
}
@@ -658,6 +713,7 @@ function placeTextAtPoint(pt) {
658713
}
659714

660715
function handleHexInteraction(c, r, mouseX, mouseY, isClick) {
716+
console.log(c, r, mouseX, mouseY, isClick);
661717
const hexEntry = GLOBAL_STATE.hexes[`${c},${r}`];
662718
const {hex, x, y} = hexEntry;
663719
if (GLOBAL_STATE.currentLayer == Layers.BASE) {
@@ -730,27 +786,10 @@ function drawHex(c, r) {
730786
hex.setAttribute("fill", GLOBAL_STATE.canvasColor);
731787
hex.setAttribute("stroke", "black");
732788
hex.setAttribute("stroke-width", "5px");
789+
hex.setAttribute("c", c);
790+
hex.setAttribute("r", r);
733791
hex.classList.add("hex");
734792

735-
hex.addEventListener("mousedown", (e) => {
736-
e.preventDefault();
737-
738-
if (GLOBAL_STATE.keyState.holdingKeyZ) {
739-
const zoomFactor = .5 * (e.button == 2 ? 1 : -1);
740-
zoom(zoomFactor, e.clientX, e.clientY);
741-
return;
742-
}
743-
GLOBAL_STATE.brushingActive = true;
744-
// a right mouse down means paint with secondary colors
745-
GLOBAL_STATE.usingSecondary = (e.button == 2);
746-
handleHexInteraction(c, r, e.x, e.y, true);
747-
});
748-
hex.addEventListener("mouseover", (e) => {
749-
if (GLOBAL_STATE.brushingActive) {
750-
handleHexInteraction(c, r, e.x, e.y, false);
751-
}
752-
});
753-
754793
const hexObject = document.createElementNS("http://www.w3.org/2000/svg", "text");
755794
hexObject.setAttribute("x", x);
756795
hexObject.setAttribute("y", y);

0 commit comments

Comments
 (0)