Web Dev Solutions

Catalin Mititiuc

aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCatalin Mititiuc <webdevcat@proton.me>2024-08-08 13:45:24 -0700
committerCatalin Mititiuc <webdevcat@proton.me>2024-08-08 13:45:24 -0700
commit0b27586a7f3c45016cab169661d914154a4d81ef (patch)
treee182e2c39e714737b0ab53b853a1986dfaead89b
parent9d76272f7b57f9d5271b3c5e2c6d0683ff80d019 (diff)
WIP: auto-pan map to selected counter
-rw-r--r--node_modules/pan-zoom/index.js2
-rw-r--r--node_modules/pan-zoom/src/modules/pan.js86
-rw-r--r--src/modules/gameboard.js53
-rw-r--r--src/modules/pan-zoom.js3
4 files changed, 123 insertions, 21 deletions
diff --git a/node_modules/pan-zoom/index.js b/node_modules/pan-zoom/index.js
new file mode 100644
index 0000000..ab80f47
--- /dev/null
+++ b/node_modules/pan-zoom/index.js
@@ -0,0 +1,2 @@
+export { default as pan, manualPan } from './src/modules/pan.js';
+export { default as zoom } from './src/modules/zoom.js';
diff --git a/node_modules/pan-zoom/src/modules/pan.js b/node_modules/pan-zoom/src/modules/pan.js
new file mode 100644
index 0000000..844524d
--- /dev/null
+++ b/node_modules/pan-zoom/src/modules/pan.js
@@ -0,0 +1,86 @@
+import getComputedTransformMatrix from './utils.js';
+
+const minDistanceThreshold = 5;
+
+function distanceBetween({ x: x1, y: y1 }, { x: x2, y: y2 }) {
+ return Math.sqrt((x2 - x1) ** 2 + (y2 - y1) ** 2);
+}
+
+function minDistanceThresholdIsMet(startPt, endPt) {
+ return distanceBetween(startPt, endPt) >= minDistanceThreshold;
+}
+
+function stopEventPropagationToChildren(el, type) {
+ el.addEventListener(type, e => e.stopPropagation(), { capture: true, once: true });
+}
+
+function getTranslateMatrix(startPt, movePt) {
+ const translateMatrix = new DOMMatrix();
+
+ return translateMatrix.translate(movePt.x - startPt.x, movePt.y - startPt.y);
+}
+
+export function manualPan(gb, counter) {
+ const mtx = getComputedTransformMatrix(gb),
+ inverseScreenCTM = gb.getScreenCTM().inverse();
+
+ const counterRect = counter.getBoundingClientRect();
+ const mapRect = document.querySelector('object').getBoundingClientRect();
+
+ let startPt = new DOMPoint(counterRect.x, counterRect.y);
+ let movePt = new DOMPoint(mapRect.width / 2, mapRect.height / 2);
+
+ startPt = startPt.matrixTransform(inverseScreenCTM);
+ movePt = movePt.matrixTransform(inverseScreenCTM);
+
+ gb.style.transition = 'transform 0.5s';
+ gb.style.transform = mtx.multiply(getTranslateMatrix(startPt, movePt));
+ gb.addEventListener('transitionend', () => gb.style.transition = '');
+}
+
+export default function (svg, el, e) {
+ e.preventDefault();
+
+ const mtx = getComputedTransformMatrix(el),
+ inverseScreenCTM = el.getScreenCTM().inverse();
+
+ let startPt = new DOMPoint(e.clientX, e.clientY),
+ movePt = new DOMPoint(),
+ isPanning = false;
+
+ function pointerMove(e) {
+ movePt.x = e.clientX;
+ movePt.y = e.clientY;
+
+ if (!isPanning && minDistanceThresholdIsMet(startPt, movePt)) {
+ isPanning = true;
+ //e.target.setPointerCapture(e.pointerId);
+
+ startPt.x = e.clientX;
+ startPt.y = e.clientY;
+ startPt = startPt.matrixTransform(inverseScreenCTM);
+
+ stopEventPropagationToChildren(el, 'click');
+ }
+
+ if (isPanning) {
+ movePt.x = e.clientX;
+ movePt.y = e.clientY;
+ movePt = movePt.matrixTransform(inverseScreenCTM);
+
+ el.style.transform = mtx.multiply(getTranslateMatrix(startPt, movePt));
+ }
+ }
+
+ svg.addEventListener('pointermove', pointerMove);
+
+ svg.addEventListener(
+ 'pointerup',
+ () => {
+ svg.removeEventListener('pointermove', pointerMove);
+ const t1Rect = t1.getBoundingClientRect();
+ console.log('trooper1 DOM x,y', t1Rect.x, t1Rect.y);
+ },
+ { once: true }
+ );
+}
diff --git a/src/modules/gameboard.js b/src/modules/gameboard.js
index b28f188..e8fe575 100644
--- a/src/modules/gameboard.js
+++ b/src/modules/gameboard.js
@@ -1,15 +1,14 @@
import * as firingArc from './game/firing_arc.js';
import * as sightLine from './game/sight_line.js';
import * as soldier from './game/soldier.js';
-import { Observable } from "./observable";
+import { Observable } from './observable';
+
+
+import { manualPan } from 'pan-zoom';
let svg,
placing = [];
-const top = {
- collection: new Map()
-};
-
const frontmostStore = new Map();
function getCellContents(cell) {
@@ -194,6 +193,11 @@ function select(data) {
if (isSelected || !data) return;
counter.classList.add(soldier.getSelectedClass());
+ const gb = svg.querySelector('.gameboard');
+
+ // TODO check if counter is on board before calling
+ manualPan(gb, counter);
+
firingArc.get(svg, counter).forEach(el => el.removeAttribute('clip-path'));
placing.push(counter);
}
@@ -215,8 +219,8 @@ export function start(el) {
// For when the pointer leaves the window
document.querySelector('object').addEventListener('pointerout', e => {
if (clearHexDialog.open) return;
- console.log('object pointerout');
- console.log('Left map... CLEARING HOVERS');
+ //console.log('object pointerout');
+ //console.log('Left map... CLEARING HOVERS');
svg.querySelectorAll('.hover').forEach(el => el.classList.remove('hover'));
[...frontmost.children].forEach(child => {
@@ -236,7 +240,7 @@ export function start(el) {
// Pointer moves outside the edge of the grid
if (!targetCell) {
- console.log('No target cell... CLEARING HOVERS');
+ //console.log('No target cell... CLEARING HOVERS');
svg.querySelectorAll('.hover').forEach(el => el.classList.remove('hover'));
[...frontmost.children].forEach(child => {
@@ -257,7 +261,7 @@ export function start(el) {
// 's contents that is in frontmost, whose parent cell is not already highlighted
!(targetCell.classList.contains('frontmost') && frontmostStore.get(e.target.closest('.frontmost > *')).classList.contains('hover'))
].every(e => e)) {
- console.log('Target cell missing hover... CLEARING HOVERS AND ADDING TO TARGET CELL');
+ //console.log('Target cell missing hover... CLEARING HOVERS AND ADDING TO TARGET CELL');
svg.querySelectorAll('.hover').forEach(el => el.classList.remove('hover'));
if (placing[0]?.getAttributeNS(null, 'class') === 'mech-template') {
@@ -299,7 +303,7 @@ export function start(el) {
getActiveSightLine(svg) && clearSightLine();
}
- console.log('frontmost contents', frontmost.children);
+ //console.log('frontmost contents', frontmost.children);
});
grid.addEventListener('click', clickHandler);
@@ -378,17 +382,24 @@ export function start(el) {
//cell2.classList.add('hover');
//
- //soldier.place(
- // svg,
- // soldier.createCounter({ dataset: { allegiance: 'attacker', number: 2, squad: 1 }}, 'hsplaser'),
- // getCell(-2, 3, -1, 0)
- //);
- //
- //soldier.place(
- // svg,
- // soldier.createCounter({ dataset: { allegiance: 'attacker', number: 2, squad: 5 }}, 'rifle'),
- // getCell(-3, 3, 0, 0)
- //);
+ const trooper1 = soldier.createCounter({ dataset: { allegiance: 'attacker', number: 1, squad: 1 }}, 'blazer');
+
+
+ soldier.place(svg, trooper1, getCell(-3, 9, -6, 0));
+
+ soldier.place(
+ svg,
+ soldier.createCounter({ dataset: { allegiance: 'defender', number: 1, squad: 1 }}, 'blazer'),
+ getCell(1, -8, 7, 0)
+ );
+
+ const t1Rect = trooper1.getBoundingClientRect();
+
+ setTimeout(() => {
+ const t1Rect = trooper1.getBoundingClientRect();
+ console.log('trooper', trooper1, trooper1.getBoundingClientRect());
+
+ }, 10);
// Add some counters in an unoccupied cell
//const countersCell = getCell(-1, 1, 0, 0);
diff --git a/src/modules/pan-zoom.js b/src/modules/pan-zoom.js
index d13c90f..5e224e8 100644
--- a/src/modules/pan-zoom.js
+++ b/src/modules/pan-zoom.js
@@ -19,6 +19,9 @@ function addEventListeners(svg, el) {
pan(svg, el, e), { passive: false };
}
});
+ svg.addEventListener('pointermove', e => {
+ console.log('clientX,clientY', `${e.clientX},${e.clientY}`);
+ });
}
function storePanZoomVal(transformMatrix) {