More functional refactor
This commit is contained in:
parent
e7f7bf1f31
commit
7f0c19becd
@ -46,7 +46,7 @@ window.addEventListener('load', () => {
|
||||
const svgns = "http://www.w3.org/2000/svg",
|
||||
recordSheetVisibility = document.querySelector('#content input[type="checkbox"].visible');
|
||||
|
||||
new PanZoom(svg);
|
||||
PanZoom(svg);
|
||||
|
||||
const distanceOutput = document.getElementById('status');
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
import FiringArc from './firingArc.js';
|
||||
import SightLine from './sightLine.js';
|
||||
import Counter from './counter.js';
|
||||
import firingArc from './game/firingArc.js';
|
||||
import SightLine from './game/sightLine.js';
|
||||
import Counter from './game/counter.js';
|
||||
|
||||
const svgns = "http://www.w3.org/2000/svg";
|
||||
|
||||
@ -10,7 +10,7 @@ export default class Game {
|
||||
|
||||
constructor(svg) {
|
||||
this.svg = svg;
|
||||
this.firingArc = new FiringArc(svg);
|
||||
this.firingArc = new firingArc(svg);
|
||||
this.sightLine = new SightLine(svg);
|
||||
this.counter = new Counter(svg);
|
||||
|
||||
|
@ -1,11 +1,25 @@
|
||||
const HORZ_POINT_DISTANCE = 1.005,
|
||||
VERT_POINT_DISTANCE = Math.sqrt(3) * HORZ_POINT_DISTANCE / 2,
|
||||
// https://www.redblobgames.com/grids/hexagons/
|
||||
|
||||
FIRING_ARC_SIZE = {
|
||||
'small': Math.atan(HORZ_POINT_DISTANCE / (6 * VERT_POINT_DISTANCE)),
|
||||
'medium': Math.atan((HORZ_POINT_DISTANCE / 2) / VERT_POINT_DISTANCE),
|
||||
'large': Math.atan((21 * HORZ_POINT_DISTANCE) / (6 * VERT_POINT_DISTANCE))
|
||||
};
|
||||
// Horizontal distance between hex centers is sqrt(3) * size. The vertical
|
||||
// distance is 3 / 2 * size. When we calculate horzDist / vertDist, the size
|
||||
// cancels out, leaving us with a unitless ratio of sqrt(3) / (3 / 2), or
|
||||
// 2 * sqrt(3) / 3.
|
||||
|
||||
const svgns = "http://www.w3.org/2000/svg",
|
||||
horzToVertDistRatio = 2 * Math.sqrt(3) / 3,
|
||||
|
||||
arcSize = {
|
||||
'small': Math.atan(horzToVertDistRatio / 6),
|
||||
'medium': Math.atan(horzToVertDistRatio / 2),
|
||||
'large': Math.atan(7 * horzToVertDistRatio / 2)
|
||||
},
|
||||
|
||||
firingArcVisibility = {
|
||||
davion: false,
|
||||
liao: false
|
||||
};
|
||||
|
||||
let svg;
|
||||
|
||||
function calculateAngle(xDiff, yDiff) {
|
||||
yDiff = -yDiff;
|
||||
@ -73,7 +87,7 @@ function position(e) {
|
||||
let yDiff = y2px - y1px;
|
||||
let angle = calculateAngle(xDiff, yDiff);
|
||||
|
||||
let arcAngle = FIRING_ARC_SIZE[activeFiringArc.dataset.size];
|
||||
let arcAngle = arcSize[activeFiringArc.dataset.size];
|
||||
let distance = Math.sqrt((x2px - x1px) ** 2 + (y2px - y1px) ** 2);
|
||||
let yDelta = distance * Math.cos(angle) * Math.tan(arcAngle);
|
||||
let xDelta = distance * Math.sin(angle) * Math.tan(arcAngle);
|
||||
@ -164,30 +178,30 @@ function position(e) {
|
||||
}
|
||||
}
|
||||
|
||||
export default class FiringArc {
|
||||
#firingArcVisibility = {
|
||||
davion: false,
|
||||
liao: false
|
||||
};
|
||||
function setDataAttrs({ dataset: { allegiance, number }}, el) {
|
||||
el.dataset.allegiance = allegiance;
|
||||
el.dataset.number = number;
|
||||
}
|
||||
|
||||
constructor(svg) {
|
||||
this.svg = svg;
|
||||
}
|
||||
function getClipPathId({ dataset: { allegiance, number }}) {
|
||||
return `clip-path-${allegiance}-${number}`;
|
||||
}
|
||||
|
||||
set(size, { dataset: { allegiance, number }}, { x, y }) {
|
||||
const svgns = "http://www.w3.org/2000/svg";
|
||||
function getUnclipped() {
|
||||
return svg.querySelectorAll('#firing-arcs polygon:not([clip-path])');
|
||||
};
|
||||
|
||||
let existingArcs = this.svg.querySelectorAll(
|
||||
`#firing-arcs [data-number="${number}"][data-allegiance="${allegiance}"]`
|
||||
);
|
||||
export default function (el) {
|
||||
svg = el;
|
||||
|
||||
existingArcs.forEach(el => el.remove());
|
||||
this.set = function (size, counter, { x, y }) {
|
||||
this.get(counter).forEach(fa => fa.remove());
|
||||
|
||||
let arcLayer = this.svg.querySelector('#shapes');
|
||||
let outlineLayer = this.svg.querySelector('#lines');
|
||||
let arcContainer = this.svg.querySelector('#firing-arcs');
|
||||
let arcLayer = svg.querySelector('#shapes');
|
||||
let outlineLayer = svg.querySelector('#lines');
|
||||
let arcContainer = svg.querySelector('#firing-arcs');
|
||||
|
||||
let grid = this.svg.querySelector('.board');
|
||||
let grid = svg.querySelector('.board');
|
||||
const transform = getComputedStyle(grid).transform.match(/-?\d+\.?\d*/g);
|
||||
const pt = new DOMPoint(x, y);
|
||||
const mtx = new DOMMatrix(transform);
|
||||
@ -197,14 +211,12 @@ export default class FiringArc {
|
||||
let firingArc = document.createElementNS(svgns, 'polygon');
|
||||
let firingArcOutline = document.createElementNS(svgns, 'polygon');
|
||||
|
||||
firingArc.classList.add('firing-arc', 'active');
|
||||
firingArc.dataset.number = number;
|
||||
firingArc.dataset.allegiance = allegiance;
|
||||
setDataAttrs(counter, firingArc);
|
||||
firingArc.dataset.size = size;
|
||||
firingArc.classList.add('firing-arc', 'active');
|
||||
firingArc.setAttributeNS(null, 'points', `${pivotPoint} ${pivotPoint} ${pivotPoint}`);
|
||||
|
||||
firingArcOutline.dataset.number = number;
|
||||
firingArcOutline.dataset.allegiance = allegiance;
|
||||
setDataAttrs(counter, firingArcOutline);
|
||||
firingArcOutline.setAttributeNS(null, 'points', `${pivotPoint} ${pivotPoint} ${pivotPoint}`);
|
||||
|
||||
let clipShape = document.createElementNS(svgns, 'circle');
|
||||
@ -213,9 +225,8 @@ export default class FiringArc {
|
||||
clipShape.setAttributeNS(null, 'r', 100);
|
||||
|
||||
let clipPath = document.createElementNS(svgns, 'clipPath');
|
||||
clipPath.setAttributeNS(null, 'id', `clip-path-${allegiance}-${number}`);
|
||||
clipPath.dataset.number = number;
|
||||
clipPath.dataset.allegiance = allegiance;
|
||||
setDataAttrs(counter, clipPath);
|
||||
clipPath.setAttributeNS(null, 'id', getClipPathId(counter));
|
||||
clipPath.appendChild(clipShape);
|
||||
|
||||
arcContainer.appendChild(clipPath);
|
||||
@ -223,9 +234,9 @@ export default class FiringArc {
|
||||
outlineLayer.appendChild(firingArcOutline);
|
||||
|
||||
let firingArcPlacementListener = e => {
|
||||
this.svg.querySelectorAll('.firing-arc.active').forEach(el => el.classList.remove('active'));
|
||||
svg.querySelectorAll('.firing-arc.active').forEach(el => el.classList.remove('active'));
|
||||
grid.removeAttribute('style');
|
||||
this.svg.removeEventListener('mousemove', position);
|
||||
svg.removeEventListener('mousemove', position);
|
||||
firingArc.removeEventListener('click', firingArcPlacementListener);
|
||||
firingArc.removeEventListener('contextmenu', cancelFiringArcPlacement);
|
||||
};
|
||||
@ -236,65 +247,58 @@ export default class FiringArc {
|
||||
firingArc.removeEventListener('click', firingArcPlacementListener);
|
||||
firingArc.removeEventListener('contextmenu', cancelFiringArcPlacement);
|
||||
|
||||
let existingArcs = this.svg.querySelectorAll(
|
||||
`#firing-arcs [data-number="${number}"][data-allegiance="${allegiance}"]`
|
||||
);
|
||||
|
||||
existingArcs.forEach(el => el.remove());
|
||||
this.get(counter).forEach(fa => fa.remove());
|
||||
|
||||
grid.removeAttribute('style');
|
||||
this.svg.removeEventListener('mousemove', position);
|
||||
svg.removeEventListener('mousemove', position);
|
||||
};
|
||||
|
||||
grid.style.pointerEvents = 'none';
|
||||
this.svg.addEventListener('mousemove', position);
|
||||
svg.addEventListener('mousemove', position);
|
||||
firingArc.addEventListener('click', firingArcPlacementListener);
|
||||
firingArc.addEventListener('contextmenu', cancelFiringArcPlacement);
|
||||
}
|
||||
};
|
||||
|
||||
clear(allegiance) {
|
||||
this.clear = function (allegiance) {
|
||||
const selector = `#firing-arcs [data-allegiance="${allegiance}"]`;
|
||||
this.svg.querySelectorAll(selector).forEach(el => el.remove());
|
||||
}
|
||||
svg.querySelectorAll(selector).forEach(el => el.remove());
|
||||
};
|
||||
|
||||
get({ dataset: { allegiance, number }}) {
|
||||
return this.svg.querySelectorAll(`#firing-arcs polygon[data-number="${number}"][data-allegiance="${allegiance}"]`);
|
||||
}
|
||||
this.get = function ({ dataset: { allegiance, number }}) {
|
||||
return svg.querySelectorAll(`#firing-arcs polygon[data-number="${number}"][data-allegiance="${allegiance}"]`);
|
||||
};
|
||||
|
||||
getUnclipped() {
|
||||
return this.svg.querySelectorAll('#firing-arcs polygon:not([clip-path])');
|
||||
}
|
||||
|
||||
toggleVisibility(allegiance) {
|
||||
const vis = this.#firingArcVisibility[allegiance],
|
||||
clipPaths = this.svg.querySelectorAll(`clipPath[data-allegiance="${allegiance}"]`);
|
||||
this.toggleVisibility = function (allegiance) {
|
||||
const vis = firingArcVisibility[allegiance],
|
||||
clipPaths = svg.querySelectorAll(`clipPath[data-allegiance="${allegiance}"]`);
|
||||
|
||||
clipPaths.forEach(cp => cp.style.display = !vis ? 'none' : '');
|
||||
this.#firingArcVisibility[allegiance] = !vis;
|
||||
}
|
||||
firingArcVisibility[allegiance] = !vis;
|
||||
};
|
||||
|
||||
toggleCounterVisibility({ dataset: { number, allegiance }}, vis) {
|
||||
const cp = this.svg.querySelector(`#clip-path-${allegiance}-${number}`),
|
||||
this.toggleCounterVisibility = function ({ dataset: { number, allegiance }}, vis) {
|
||||
const cp = svg.querySelector(`#clip-path-${allegiance}-${number}`),
|
||||
display = vis ? 'none' : '';
|
||||
|
||||
if (cp) {
|
||||
cp.style.display = this.#firingArcVisibility[allegiance] ? 'none' : display;
|
||||
}
|
||||
cp.style.display = firingArcVisibility[allegiance] ? 'none' : display;
|
||||
}
|
||||
};
|
||||
|
||||
clipAll() {
|
||||
let unclipped = this.getUnclipped();
|
||||
this.clipAll = function () {
|
||||
console.log('clipall')
|
||||
let unclipped = getUnclipped();
|
||||
|
||||
unclipped.forEach(el => {
|
||||
const { number, allegiance } = el.dataset,
|
||||
clipPathId = `clip-path-${allegiance}-${number}`,
|
||||
isVisible = this.#firingArcVisibility[allegiance];
|
||||
isVisible = firingArcVisibility[allegiance];
|
||||
|
||||
if (isVisible) {
|
||||
this.svg.querySelector(`#${clipPathId}`).style.display = 'none';
|
||||
svg.querySelector(`#${clipPathId}`).style.display = 'none';
|
||||
}
|
||||
|
||||
el.setAttributeNS(null, 'clip-path', `url(#${clipPathId})`);
|
||||
});
|
||||
}
|
||||
};
|
||||
}
|
@ -1,36 +1,33 @@
|
||||
import { pan, zoom } from 'pan-zoom';
|
||||
|
||||
export default class PanZoom {
|
||||
#storageKey = 'pan-zoom';
|
||||
#zoomFactor = 0.25;
|
||||
const storageKey = 'pan-zoom',
|
||||
zoomFactor = 0.25;
|
||||
|
||||
constructor(svg) {
|
||||
this.#restorePanZoomVal(svg);
|
||||
this.#addEventListeners(svg);
|
||||
this.#observePanZoomChanges(svg);
|
||||
}
|
||||
|
||||
#storePanZoomVal(transformMatrix) {
|
||||
localStorage.setItem(this.#storageKey, transformMatrix);
|
||||
}
|
||||
|
||||
#observePanZoomChanges(svg) {
|
||||
const observer =
|
||||
new MutationObserver(() => this.#storePanZoomVal(svg.style.transform));
|
||||
|
||||
observer.observe(svg, { attributeFilter: ['style'] });
|
||||
}
|
||||
|
||||
#restorePanZoomVal(svg) {
|
||||
const storedPanZoomVal = localStorage.getItem(this.#storageKey);
|
||||
function restorePanZoomVal(svg) {
|
||||
const storedPanZoomVal = localStorage.getItem(storageKey);
|
||||
|
||||
if (storedPanZoomVal) {
|
||||
svg.style.transform = storedPanZoomVal;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#addEventListeners(svg) {
|
||||
svg.addEventListener('wheel', e => zoom(svg, e, this.#zoomFactor), { passive: false });
|
||||
function addEventListeners(svg) {
|
||||
svg.addEventListener('wheel', e => zoom(svg, e, zoomFactor), { passive: false });
|
||||
svg.addEventListener('pointerdown', e => pan(svg, e), { passive: false });
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
function storePanZoomVal(transformMatrix) {
|
||||
localStorage.setItem(storageKey, transformMatrix);
|
||||
}
|
||||
|
||||
function observePanZoomChanges(svg) {
|
||||
const observer = new MutationObserver(() => storePanZoomVal(svg.style.transform));
|
||||
|
||||
observer.observe(svg, { attributeFilter: ['style'] });
|
||||
}
|
||||
|
||||
export default function (svg) {
|
||||
restorePanZoomVal(svg);
|
||||
addEventListeners(svg);
|
||||
observePanZoomChanges(svg);
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user