index : btroops | |
Virtual board game-aid for BattleTroops, an infantry combat simulator wargame published by FASA in 1989. |
aboutsummaryrefslogtreecommitdiff |
diff options
Diffstat (limited to 'src/index.js')
-rw-r--r-- | src/index.js | 563 |
1 files changed, 267 insertions, 296 deletions
diff --git a/src/index.js b/src/index.js index 20a0623..9a114d7 100644 --- a/src/index.js +++ b/src/index.js @@ -1,3 +1,5 @@ +import { pan, zoom } from 'svg-pan-zoom'; + function isEven(n) { return n % 2 === 0; } @@ -23,10 +25,10 @@ function calculateAngle(xDiff, yDiff) { function edgePoint(x1, y1, x2, y2, maxX, maxY) { let pointCoords, - xDiff = x2 - x1, - yDiff = y2 - y1, - xIntercept = y => (y - y1) * xDiff / yDiff + x1, - yIntercept = x => (x - x1) * yDiff / xDiff + y1; + xDiff = x2 - x1, + yDiff = y2 - y1, + xIntercept = y => (y - y1) * xDiff / yDiff + x1, + yIntercept = x => (x - x1) * yDiff / xDiff + y1; if (xDiff > 0 && yDiff > 0) { let x = xIntercept(maxY); @@ -50,11 +52,11 @@ function edgePoint(x1, y1, x2, y2, maxX, maxY) { } function evenr_to_axial(x, y) { - return {q: x - (y + (y & 1)) / 2, r: y}; + return { q: x - (y + (y & 1)) / 2, r: y }; } function axial_to_evenr(q, r) { - return {x: q + (r + (r & 1)) / 2, y: r}; + return { x: q + (r + (r & 1)) / 2, y: r }; } function axial_distance(q1, r1, q2, r2) { @@ -63,7 +65,7 @@ function axial_distance(q1, r1, q2, r2) { function offset_distance(x1, y1, x2, y2) { let { q: q1, r: r1 } = evenr_to_axial(x1, y1), - { q: q2, r: r2 } = evenr_to_axial(x2, y2); + { q: q2, r: r2 } = evenr_to_axial(x2, y2); return axial_distance(q1, r1, q2, r2); } @@ -73,7 +75,7 @@ function cube_to_axial(q, r, s) { } function axial_to_cube(q, r) { - return { q: q, r: r, s: -q - r}; + return { q: q, r: r, s: -q - r }; } function cube_round(q, r, s) { @@ -82,8 +84,8 @@ function cube_round(q, r, s) { rS = Math.round(s); let q_diff = Math.abs(rQ - q), - r_diff = Math.abs(rR - r), - s_diff = Math.abs(rS - s); + r_diff = Math.abs(rR - r), + s_diff = Math.abs(rS - s); if (q_diff > r_diff && q_diff > s_diff) { rQ = -rR - rS; @@ -93,15 +95,15 @@ function cube_round(q, r, s) { rS = -rQ - rR; } - return {q: rQ, r: rR, s: rS}; + return { q: rQ, r: rR, s: rS }; } function axial_round(q, r) { let cube = axial_to_cube(q, r), - round = cube_round(cube.q, cube.r, cube.s), - axial = cube_to_axial(round.q, round.r, round.s); + round = cube_round(cube.q, cube.r, cube.s), + axial = cube_to_axial(round.q, round.r, round.s); - return {q: axial.q, r: axial.r}; + return { q: axial.q, r: axial.r }; } function lerp(a, b, t) { @@ -114,14 +116,14 @@ function axial_lerp(q1, r1, q2, r2, t) { function linedraw(x1, y1, x2, y2) { let axial1 = evenr_to_axial(x1, y1), - axial2 = evenr_to_axial(x2, y2), - n = offset_distance(x1, y1, x2, y2), - results = []; + axial2 = evenr_to_axial(x2, y2), + n = offset_distance(x1, y1, x2, y2), + results = []; for (let i = 0; i <= n; i++) { let lerp = axial_lerp(axial1.q, axial1.r, axial2.q, axial2.r, 1.0 / n * i), - round = axial_round(lerp.q, lerp.r), - { x, y } = axial_to_evenr(round.q, round.r); + round = axial_round(lerp.q, lerp.r), + { x, y } = axial_to_evenr(round.q, round.r); results.push([x, y]); } @@ -129,39 +131,68 @@ function linedraw(x1, y1, x2, y2) { return results; } +const PanZoom = new function () { + this.start = function (svg) { + svg.addEventListener('wheel', e => { + e.preventDefault(); + + svg.setAttributeNS(null, 'viewBox', zoom(svg, e)); + }, { passive: false }); + + svg.addEventListener('pointerdown', e => { + e.preventDefault(); + + pan(svg, e); + }, { passive: false }); + } +}; + window.addEventListener('load', () => { const svgns = "http://www.w3.org/2000/svg", - // svg = document.querySelector('svg'), - svg = document.querySelector('object').contentDocument.querySelector('svg'), - hex = svg.querySelector('#point'), - ptGrp = svg.querySelector('#points'), - cntrGrp = svg.querySelector('#counters'), - settingsPanel = document.getElementById('panel'), - recordSheetVisibility = document.querySelector('#content input[type="checkbox"].visible'); + // svg = document.querySelector('svg'), + // hex = svg.querySelector('#point'), + svg = document.querySelector('object').contentDocument.querySelector('svg'), + hex = svg.querySelector('#hex'), + ptGrp = svg.querySelector('#points'), + cntrGrp = svg.querySelector('#counters'), + settingsPanel = document.getElementById('panel'), + recordSheetVisibility = document.querySelector('#content input[type="checkbox"].visible'); + + PanZoom.start(svg); + + let cells = svg.querySelectorAll('g[data-x]'); + + cells.forEach(cell => { + cell.addEventListener('click', e => { + let { dataset: { x }, parentElement: { dataset: { y }}} = cell; + + console.log(`Cell at index { x: ${x}, y: ${y} } clicked.`); + } + )}); const q = s => document.querySelector(s), - qA = s => document.querySelectorAll(s); + qA = s => document.querySelectorAll(s); const { x: VIEWBOX_X, y: VIEWBOX_Y, width: VIEWBOX_WIDTH, height: VIEWBOX_HEIGHT } = svg.viewBox.baseVal; const COLUMN_COUNT = 33, - ROW_COUNT = 51, - // const COLUMN_COUNT = 20, - // ROW_COUNT = 20, - HORZ_POINT_DISTANCE = 1.005, - VERT_POINT_DISTANCE = Math.sqrt(3) * HORZ_POINT_DISTANCE / 2, - ALTERNATING_OFFSET = HORZ_POINT_DISTANCE / 2, - CIRCUMRADIUS = Math.max(...[...new Set(Object.values(hex.points).flatMap(({x, y}) => [x, y]))]), - INRADIUS = CIRCUMRADIUS * Math.sqrt(3) / 2, - [COLUMNS, ROWS] = [COLUMN_COUNT, ROW_COUNT].map(n => [...Array(n).keys()]), - POINTS = ROWS.map(y => COLUMNS.map(x => [x, y])); + ROW_COUNT = 51, + // const COLUMN_COUNT = 20, + // ROW_COUNT = 20, + HORZ_POINT_DISTANCE = 1.005, + VERT_POINT_DISTANCE = Math.sqrt(3) * HORZ_POINT_DISTANCE / 2, + ALTERNATING_OFFSET = HORZ_POINT_DISTANCE / 2, + CIRCUMRADIUS = Math.max(...[...new Set(Object.values(hex.points).flatMap(({ x, y }) => [x, y]))]), + INRADIUS = CIRCUMRADIUS * Math.sqrt(3) / 2, + [COLUMNS, ROWS] = [COLUMN_COUNT, ROW_COUNT].map(n => [...Array(n).keys()]), + POINTS = ROWS.map(y => COLUMNS.map(x => [x, y])); const 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)) - }; + '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)) + }; function positionFiringArc(e) { let activeFiringArc = svg.querySelector('polygon.firing-arc.active'); @@ -170,12 +201,12 @@ window.addEventListener('load', () => { if (activeFiringArc) { let activeFiringArcOutline = svg.querySelector(`#lines polygon[data-troop-number="${activeFiringArc.dataset.troopNumber}"][data-troop-allegiance="${activeFiringArc.dataset.troopAllegiance}"]`); - board = svg.querySelector('#image-maps'), - { width, height } = board.getBBox(), - pt = new DOMPoint(e.clientX, e.clientY), - { x: pointerX, y: pointerY } = pt.matrixTransform(board.getScreenCTM().inverse()), - [maxXpx, maxYpx] = [width, height], - {x: x1px, y: y1px} = activeFiringArc.points[0]; + board = svg.querySelector('#image-maps'), + { width, height } = board.getBBox(), + pt = new DOMPoint(e.clientX, e.clientY), + { x: pointerX, y: pointerY } = pt.matrixTransform(board.getScreenCTM().inverse()), + [maxXpx, maxYpx] = [width, height], + { x: x1px, y: y1px } = activeFiringArc.points[0]; let [x2px, y2px] = [ pointerX / width * maxXpx, @@ -187,7 +218,7 @@ window.addEventListener('load', () => { let angle = calculateAngle(xDiff, yDiff); let arcAngle = FIRING_ARC_SIZE[activeFiringArc.dataset.size]; - let distance = Math.sqrt((x2px - x1px)**2 + (y2px - y1px)**2); + 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); @@ -331,133 +362,133 @@ window.addEventListener('load', () => { const grid = svg.querySelector('#grid'); - const Counter = new function() { + const Counter = new function () { let container = ptGrp, - selectedClass = 'selected', - - dataSelector = function(troopNumber, allegiance) { - return `[data-troop-number="${troopNumber}"][data-troop-allegiance="${allegiance}"]`; - }, - - selector = function(troopNumber, allegiance) { - return `use.counter${dataSelector(troopNumber, allegiance)}`; - }, - - position = function(x, y) { - return `g[data-x="${x}"][data-y="${y}"]`; - }, - - counterPosition = function(x, y) { - return `use.counter[data-x="${x}"][data-x="${y}"]`; - }, - - traceSelector = function(troopNumber, allegiance) { - return `polyline.move-trace${dataSelector(troopNumber, allegiance)}`; - }, - - clickClone = function() { - let { troopNumber, troopAllegiance, x, y } = this.dataset, - [xAttr, yAttr] = this.parentElement.getAttribute('transform').match(/-?\d+\.?\d*/g); - - if (Counter.isSelected(troopNumber, troopAllegiance)) { - let trace = grid.querySelector(traceSelector(troopNumber, troopAllegiance)), - points = trace.getAttribute('points').split(' '); - - if (`${xAttr},${yAttr}` == points.at(0)) { - let counter = Counter.get(troopNumber, troopAllegiance); - counter.setAttributeNS(null, 'x', 0); - counter.setAttributeNS(null, 'y', 0); - counter.dataset.x = x; - counter.dataset.y = y; - container.querySelector(`g[data-x="${x}"][data-y="${y}"]`).appendChild(counter); - - Counter.removeClones(this); - trace.remove(); - } else { - points = points.filter(p => p != `${xAttr},${yAttr}`).join(' '); - - trace.setAttributeNS(null, 'points', points); - } + selectedClass = 'selected', + + dataSelector = function (troopNumber, allegiance) { + return `[data-troop-number="${troopNumber}"][data-troop-allegiance="${allegiance}"]`; + }, + + selector = function (troopNumber, allegiance) { + return `use.counter${dataSelector(troopNumber, allegiance)}`; + }, + + position = function (x, y) { + return `g[data-x="${x}"][data-y="${y}"]`; + }, + + counterPosition = function (x, y) { + return `use.counter[data-x="${x}"][data-x="${y}"]`; + }, + + traceSelector = function (troopNumber, allegiance) { + return `polyline.move-trace${dataSelector(troopNumber, allegiance)}`; + }, + + clickClone = function () { + let { troopNumber, troopAllegiance, x, y } = this.dataset, + [xAttr, yAttr] = this.parentElement.getAttribute('transform').match(/-?\d+\.?\d*/g); + + if (Counter.isSelected(troopNumber, troopAllegiance)) { + let trace = grid.querySelector(traceSelector(troopNumber, troopAllegiance)), + points = trace.getAttribute('points').split(' '); + + if (`${xAttr},${yAttr}` == points.at(0)) { + let counter = Counter.get(troopNumber, troopAllegiance); + counter.setAttributeNS(null, 'x', 0); + counter.setAttributeNS(null, 'y', 0); + counter.dataset.x = x; + counter.dataset.y = y; + container.querySelector(`g[data-x="${x}"][data-y="${y}"]`).appendChild(counter); + + Counter.removeClones(this); + trace.remove(); + } else { + points = points.filter(p => p != `${xAttr},${yAttr}`).join(' '); - this.remove(); + trace.setAttributeNS(null, 'points', points); } - }, - pointerOver = function() { - let { troopNumber, troopAllegiance } = this.dataset; - cp = svg.querySelector(`#clip-path-${troopAllegiance}-${troopNumber}`); + this.remove(); + } + }, - if (cp) { - cp.style.display = 'none'; - } - }, + pointerOver = function () { + let { troopNumber, troopAllegiance } = this.dataset; + cp = svg.querySelector(`#clip-path-${troopAllegiance}-${troopNumber}`); - pointerOut = function() { - let { troopNumber, troopAllegiance } = this.dataset; - cp = svg.querySelector(`#clip-path-${troopAllegiance}-${troopNumber}`); + if (cp) { + cp.style.display = 'none'; + } + }, - if (cp) { - let isVisible = - document - .getElementById('toggle-firing-arc-vis') - .querySelector(`input[data-allegiance="${troopAllegiance}"]`) - .checked; + pointerOut = function () { + let { troopNumber, troopAllegiance } = this.dataset; + cp = svg.querySelector(`#clip-path-${troopAllegiance}-${troopNumber}`); - cp.style.display = isVisible ? 'none' : ''; - } - }, + if (cp) { + let isVisible = + document + .getElementById('toggle-firing-arc-vis') + .querySelector(`input[data-allegiance="${troopAllegiance}"]`) + .checked; - click = function() { - if (this.classList.contains(selectedClass)) { - let { troopNumber, troopAllegiance } = this.dataset, - trace = grid.querySelector(traceSelector(troopNumber, troopAllegiance)); + cp.style.display = isVisible ? 'none' : ''; + } + }, - if (trace) { - let points = trace.getAttribute('points').split(' '), - [xAttr, yAttr] = points.at(-2).split(','), - clone = container.querySelector(`g[transform="translate(${xAttr} ${yAttr})"] ${dataSelector(troopNumber, troopAllegiance)}.clone`); + click = function () { + if (this.classList.contains(selectedClass)) { + let { troopNumber, troopAllegiance } = this.dataset, + trace = grid.querySelector(traceSelector(troopNumber, troopAllegiance)); - points.pop(); + if (trace) { + let points = trace.getAttribute('points').split(' '), + [xAttr, yAttr] = points.at(-2).split(','), + clone = container.querySelector(`g[transform="translate(${xAttr} ${yAttr})"] ${dataSelector(troopNumber, troopAllegiance)}.clone`); - if (points.length >= 2) { - trace.setAttributeNS(null, 'points', points.join(' ')); - } else { - trace.remove(); - } + points.pop(); - this.setAttributeNS(null, 'x', clone.getAttribute('x')); - this.setAttributeNS(null, 'y', clone.getAttribute('y')); - this.dataset.x = clone.dataset.x; - this.dataset.y = clone.dataset.y; + if (points.length >= 2) { + trace.setAttributeNS(null, 'points', points.join(' ')); + } else { + trace.remove(); + } - container.querySelector(`g[data-x="${this.dataset.x}"][data-y="${this.dataset.y}"]`).appendChild(this); + this.setAttributeNS(null, 'x', clone.getAttribute('x')); + this.setAttributeNS(null, 'y', clone.getAttribute('y')); + this.dataset.x = clone.dataset.x; + this.dataset.y = clone.dataset.y; - clone.remove(); - } + container.querySelector(`g[data-x="${this.dataset.x}"][data-y="${this.dataset.y}"]`).appendChild(this); + + clone.remove(); } - }, + } + }, - dblClick = function() { - if (this.classList.contains(selectedClass)) { - let { troopNumber, troopAllegiance } = this.dataset, - trace = grid.querySelector(traceSelector(troopNumber, troopAllegiance)); + dblClick = function () { + if (this.classList.contains(selectedClass)) { + let { troopNumber, troopAllegiance } = this.dataset, + trace = grid.querySelector(traceSelector(troopNumber, troopAllegiance)); - if (!trace) { - Counter.remove(this); - svg.querySelectorAll(`#firing-arcs ${dataSelector(troopNumber, troopAllegiance)}`).forEach(el => el.remove()); - } + if (!trace) { + Counter.remove(this); + svg.querySelectorAll(`#firing-arcs ${dataSelector(troopNumber, troopAllegiance)}`).forEach(el => el.remove()); } - }; + } + }; - this.get = function(troopNumber, allegiance) { + this.get = function (troopNumber, allegiance) { return container.querySelector(`${selector(troopNumber, allegiance)}:not(.clone)`); }; - this.getAt = function(x, y) { + this.getAt = function (x, y) { return container.querySelector(`${counterPosition(x, y)}:not(.clone)`); }; - this.select = function({ dataset: { troopNumber, troopAllegiance }}) { + this.select = function ({ dataset: { troopNumber, troopAllegiance } }) { this.unSelect(); let counter = container.querySelector(`${selector(troopNumber, troopAllegiance)}:not(.clone)`); @@ -467,7 +498,7 @@ window.addEventListener('load', () => { } }; - this.unSelect = function() { + this.unSelect = function () { let selected = container.querySelector(`.${selectedClass}`); if (selected) { @@ -482,35 +513,35 @@ window.addEventListener('load', () => { } }; - this.isSelected = function(troopNumber, allegiance) { + this.isSelected = function (troopNumber, allegiance) { return container.querySelector(`${selector(troopNumber, allegiance)}.${selectedClass}`) !== null; }; - this.place = function({ dataset: { troopNumber, troopAllegiance }}, point) { + this.place = function ({ dataset: { troopNumber, troopAllegiance } }, point) { let counter, points, - counterNodeList = container.querySelectorAll(selector(troopNumber, troopAllegiance)); + counterNodeList = container.querySelectorAll(selector(troopNumber, troopAllegiance)); if (counterNodeList.length > 0) { let counters = Array.from(counterNodeList), - original = counters.find(el => !el.classList.contains('clone')), - trace = grid.querySelector(traceSelector(troopNumber, troopAllegiance)); + original = counters.find(el => !el.classList.contains('clone')), + trace = grid.querySelector(traceSelector(troopNumber, troopAllegiance)); // let ptContainers = counters.map(c => ptGrp.querySelector(position(c.dataset.x, c.dataset.y))); let current = { - x: point.dataset.x, - y: point.dataset.y, - // xAttr: point.getAttribute('x'), - // yAttr: point.getAttribute('y'), - transform: container.querySelector(position(point.dataset.x, point.dataset.y)).getAttribute('transform') - }, - previous = { - x: original.dataset.x, - y: original.dataset.y, - // xAttr: original.getAttribute('x'), - // yAttr: original.getAttribute('y'), - transform: container.querySelector(position(original.dataset.x, original.dataset.y)).getAttribute('transform') - }; + x: point.dataset.x, + y: point.dataset.y, + // xAttr: point.getAttribute('x'), + // yAttr: point.getAttribute('y'), + transform: container.querySelector(position(point.dataset.x, point.dataset.y)).getAttribute('transform') + }, + previous = { + x: original.dataset.x, + y: original.dataset.y, + // xAttr: original.getAttribute('x'), + // yAttr: original.getAttribute('y'), + transform: container.querySelector(position(original.dataset.x, original.dataset.y)).getAttribute('transform') + }; [current.xAttr, current.yAttr] = current.transform.match(/-?\d+\.?\d*/g); [previous.xAttr, previous.yAttr] = previous.transform.match(/-?\d+\.?\d*/g); @@ -549,7 +580,7 @@ window.addEventListener('load', () => { } else { counter = document.createElementNS(svgns, 'use'), - counter.setAttributeNS(null, 'href', `#${troopAllegiance}-${troopNumber}`); + counter.setAttributeNS(null, 'href', `#${troopAllegiance}-${troopNumber}`); counter.classList.add('counter', 'selected'); counter.setAttributeNS(null, 'x', point.getAttribute('x')); counter.setAttributeNS(null, 'y', point.getAttribute('y')); @@ -570,19 +601,19 @@ window.addEventListener('load', () => { // container.appendChild(counter); }; - this.remove = function({ dataset: { troopNumber, troopAllegiance }}) { + this.remove = function ({ dataset: { troopNumber, troopAllegiance } }) { container .querySelectorAll(dataSelector(troopNumber, troopAllegiance)) .forEach(el => el.remove()); }; - this.removeClones = function({ dataset: { troopNumber, troopAllegiance }}) { + this.removeClones = function ({ dataset: { troopNumber, troopAllegiance } }) { container .querySelectorAll(`${selector(troopNumber, troopAllegiance)}.clone`) .forEach(el => el.remove()); }; - this.endMove = function(el) { + this.endMove = function (el) { let { troopNumber, troopAllegiance } = el.dataset; let trace = grid.querySelector(traceSelector(troopNumber, troopAllegiance)); @@ -593,20 +624,20 @@ window.addEventListener('load', () => { Counter.removeClones(el); }; - this.hasProne = function(troopNumber, troopAllegiance) { + this.hasProne = function (troopNumber, troopAllegiance) { let selector = `g#${troopAllegiance}-${troopNumber} use[href="#counter-prone"]`; return !!svg.querySelector(selector); }; }; - const RecordSheet = new function() { - let clipUnclippedFiringArcs = function() { + const RecordSheet = new function () { + let clipUnclippedFiringArcs = function () { let unclipped = svg.querySelectorAll('#firing-arcs polygon:not([clip-path])'); unclipped.forEach(el => { let { troopNumber, troopAllegiance } = el.dataset, - clipPathId = `clip-path-${troopAllegiance}-${troopNumber}`; + clipPathId = `clip-path-${troopAllegiance}-${troopNumber}`; let isVisible = document @@ -622,7 +653,7 @@ window.addEventListener('load', () => { }); }; - this.unSelect = function() { + this.unSelect = function () { let selected = this.getSelected(); if (selected) { @@ -634,13 +665,13 @@ window.addEventListener('load', () => { Counter.unSelect(); }; - this.getSelected = function() { + this.getSelected = function () { return document.querySelector('.soldier-record.selected'); }; - this.select = function(el) { + this.select = function (el) { let { troopNumber, troopAllegiance } = el.dataset, - proneStatus = Counter.hasProne(troopNumber, troopAllegiance); + proneStatus = Counter.hasProne(troopNumber, troopAllegiance); RecordSheet.unSelect(); document.querySelector(`#record-sheet .soldier-record[data-troop-number="${troopNumber}"][data-troop-allegiance="${troopAllegiance}"]`).classList.add('selected'); @@ -650,8 +681,8 @@ window.addEventListener('load', () => { }; }; - const SightLine = new function() { - this.clear = function() { + const SightLine = new function () { + this.clear = function () { let sl = grid.querySelector('line.sight-line'); let target = grid.querySelector(`use[href="#point"].sight-line-target`); @@ -666,18 +697,18 @@ window.addEventListener('load', () => { this.clearHexes(); }; - this.clearHexes = function() { + this.clearHexes = function () { ptGrp.querySelectorAll('use[href="#point"].active').forEach(el => el.classList.remove('active')); }; - this.draw = function(x1, y1, x2, y2) { + this.draw = function (x1, y1, x2, y2) { let source = ptGrp.querySelector(`g[data-x="${x1}"][data-y="${y1}"]`), - target = ptGrp.querySelector(`g[data-x="${x2}"][data-y="${y2}"]`), + target = ptGrp.querySelector(`g[data-x="${x2}"][data-y="${y2}"]`), - [slX1, slY1] = source.getAttribute('transform').match(/-?\d+\.?\d*/g), - [slX2, slY2] = target.getAttribute('transform').match(/-?\d+\.?\d*/g), + [slX1, slY1] = source.getAttribute('transform').match(/-?\d+\.?\d*/g), + [slX2, slY2] = target.getAttribute('transform').match(/-?\d+\.?\d*/g), - sightLine = document.createElementNS(svgns, 'line'); + sightLine = document.createElementNS(svgns, 'line'); sightLine.classList.add('sight-line'); sightLine.classList.add('active'); @@ -692,7 +723,7 @@ window.addEventListener('load', () => { this.drawHexes(...coords); }; - this.drawHexes = function(...coords) { + this.drawHexes = function (...coords) { this.clearHexes() info.querySelector('#hex-count').textContent = offset_distance(...coords); @@ -706,10 +737,29 @@ window.addEventListener('load', () => { }; }; + // POINTS.forEach((row, index) => row.forEach(([x, y]) => { - [].forEach(() => row.forEach(([x, y]) => { - let group = svg.querySelector(`g[data-x="${x}"][data-y="${y}"]`); - let point = group.querySelector(`use[href="#point"]`); + [].forEach((row, index) => row.forEach(([x, y]) => { + var cx = x * INRADIUS * 2 + (isEven(index) ? INRADIUS : 0), + cy = y * 3 / 2 * CIRCUMRADIUS, + point = document.createElementNS(svgns, 'use'), + group = document.createElementNS(svgns, 'g'); + + cx = parseFloat(cx.toFixed(1)); + cy = parseFloat(cy.toFixed(1)); + + point.setAttributeNS(null, 'href', `#point`); + point.setAttributeNS(null, 'x', 0); + point.setAttributeNS(null, 'y', 0); + + point.dataset.x = x; + point.dataset.y = y; + + group.setAttributeNS(null, 'transform', `translate(${cx} ${cy})`); + group.dataset.x = x; + group.dataset.y = y; + + group.appendChild(point); group.addEventListener('pointerout', e => { group.classList.remove('hover'); @@ -717,23 +767,23 @@ window.addEventListener('load', () => { group.addEventListener('click', e => { let cl = e.target.classList, - sl = grid.querySelector('line.sight-line'), - targetIsSomeOtherUnitCounter = cl.contains('counter') && !cl.contains('clone'), - selected = RecordSheet.getSelected(); + sl = grid.querySelector('line.sight-line'), + targetIsSomeOtherUnitCounter = cl.contains('counter') && !cl.contains('clone'), + selected = RecordSheet.getSelected(); // maybe we should start with, "are we clicking on a counter?" if (sl) { - let { troopNumber: sTn, troopAllegiance: sTa} = selected.dataset, - { troopNumber: tTn, troopAllegiance: tTa} = e.target.dataset, - sightLineInLockedPosition = !sl.classList.contains('active'), - targetIsCounterOrCloneOfSelected = cl.contains('counter') && sTn == tTn && sTa == tTa; + let { troopNumber: sTn, troopAllegiance: sTa } = selected.dataset, + { troopNumber: tTn, troopAllegiance: tTa } = e.target.dataset, + sightLineInLockedPosition = !sl.classList.contains('active'), + targetIsCounterOrCloneOfSelected = cl.contains('counter') && sTn == tTn && sTa == tTa; if (sightLineInLockedPosition && targetIsCounterOrCloneOfSelected) { let counterParent = Counter.get(tTn, tTa).parentElement, - [x, y] = counterParent.getAttribute('transform').match(/-?\d+\.?\d*/g), - target = ptGrp.querySelector(`g[transform="translate(${sl.getAttribute('x2')} ${sl.getAttribute('y2')})"]`), - { x: x1, y: y1 } = counterParent.dataset, - { x: x2, y: y2 } = target.dataset; + [x, y] = counterParent.getAttribute('transform').match(/-?\d+\.?\d*/g), + target = ptGrp.querySelector(`g[transform="translate(${sl.getAttribute('x2')} ${sl.getAttribute('y2')})"]`), + { x: x1, y: y1 } = counterParent.dataset, + { x: x2, y: y2 } = target.dataset; sl.setAttributeNS(null, 'x1', x); sl.setAttributeNS(null, 'y1', y); @@ -768,9 +818,9 @@ window.addEventListener('load', () => { SightLine.clear(); } else { let [x, y] = point.parentElement.getAttribute('transform').match(/-?\d+\.?\d*/g), - target = ptGrp.querySelector(`g[transform="translate(${sl.getAttribute('x2')} ${sl.getAttribute('y2')})"]`), - { x: x1, y: y1 } = point.dataset, - { x: x2, y: y2 } = target.dataset; + target = ptGrp.querySelector(`g[transform="translate(${sl.getAttribute('x2')} ${sl.getAttribute('y2')})"]`), + { x: x1, y: y1 } = point.dataset, + { x: x2, y: y2 } = target.dataset; sl.setAttributeNS(null, 'x1', x); sl.setAttributeNS(null, 'y1', y); @@ -806,8 +856,8 @@ window.addEventListener('load', () => { if (selected) { let { troopNumber: tn, troopAllegiance: ta } = selected.dataset, - counter = Counter.get(tn, ta), - sl = svg.querySelector('line.sight-line'); + counter = Counter.get(tn, ta), + sl = svg.querySelector('line.sight-line'); if (counter && (!sl || sl.classList.contains('active'))) { if (counter.dataset.x !== e.target.dataset.x || counter.dataset.y !== e.target.dataset.y) { @@ -833,7 +883,7 @@ window.addEventListener('load', () => { }); // ptGrp.appendChild(document.createTextNode('\n ')); - // ptGrp.appendChild(group); + ptGrp.appendChild(group); })); document.querySelectorAll('.soldier-record').forEach(el => @@ -873,11 +923,11 @@ window.addEventListener('load', () => { })); document.querySelectorAll('.end-turn').forEach(el => - el.addEventListener('click', ({ target: { dataset: { allegiance }}}) => { + el.addEventListener('click', ({ target: { dataset: { allegiance } } }) => { let dataSelector = `[data-troop-allegiance="${allegiance}"]`, - records = Array.from(qA(`.soldier-record${dataSelector}`)), - turnCounter = document.getElementById('turn-count'), - { textContent: count, dataset: { update }} = turnCounter; + records = Array.from(qA(`.soldier-record${dataSelector}`)), + turnCounter = document.getElementById('turn-count'), + { textContent: count, dataset: { update } } = turnCounter; el.setAttribute('disabled', ''); @@ -907,8 +957,8 @@ window.addEventListener('load', () => { let selectedSoldier = document.querySelector('.soldier-record.selected'); if (selectedSoldier) { - let {troopNumber, troopAllegiance} = selectedSoldier.dataset, - counter = Counter.get(troopNumber, troopAllegiance); + let { troopNumber, troopAllegiance } = selectedSoldier.dataset, + counter = Counter.get(troopNumber, troopAllegiance); let existingArcs = svg.querySelectorAll( `#firing-arcs [data-troop-number="${troopNumber}"][data-troop-allegiance="${troopAllegiance}"]` @@ -989,85 +1039,6 @@ window.addEventListener('load', () => { } })); - svg.addEventListener('wheel', e => { - e.preventDefault(); - - const pt = new DOMPoint(e.clientX, e.clientY), - svgP = pt.matrixTransform(svg.getScreenCTM().inverse()); - - let { x, y, width, height } = svg.viewBox.baseVal, - - widthDelta = width * 0.25, - heightDelta = height * 0.25, - - xChange = (svgP.x - x) / width * widthDelta, - yChange = (svgP.y - y) / height * heightDelta, - - widthChange = (1 - ((svgP.x - x) / width)) * widthDelta, - heightChange = (1 - ((svgP.y - y) / height)) * heightDelta, - - newX = parseInt(e.deltaY < 0 ? x + xChange : x - xChange), - newWidth = parseInt(e.deltaY < 0 ? width - xChange - widthChange : width + xChange + widthChange), - - newY = parseInt(e.deltaY < 0 ? y + yChange : y - yChange), - newHeight = parseInt(e.deltaY < 0 ? height - yChange - heightChange : height + yChange + heightChange); - - let vb = `${newX} ${newY} ${newWidth} ${newHeight}` - - // TODO attribute change event? - localStorage.setItem('viewBox', vb); - svg.setAttributeNS(null, 'viewBox', vb); - }, { passive: false }); - - svg.addEventListener('pointerdown', e => { - e.preventDefault(); - - const minPanDistanceThreshold = 5; - - let dist, ctm, - pan = false, - { x, y, width, height } = svg.viewBox.baseVal, - startPt = new DOMPoint(e.clientX, e.clientY), - movePt = new DOMPoint(); - - function pointerMove(e) { - movePt.x = e.clientX; - movePt.y = e.clientY; - - if (!pan) { - dist = Math.sqrt((movePt.x - startPt.x)**2 + (movePt.y - startPt.y)**2); - - if (dist >= minPanDistanceThreshold) { - pan = true; - svg.setPointerCapture(e.pointerId); - startPt.x = e.clientX; - startPt.y = e.clientY; - } - } - - if (pan) { - ctm = svg.getScreenCTM().inverse(); - - const [svgStartPt, svgMovePt] = [startPt, movePt].map(p => p.matrixTransform(ctm)), - moveX = parseInt(svgStartPt.x - svgMovePt.x + x), - moveY = parseInt(svgStartPt.y - svgMovePt.y + y); - - let vb = `${moveX} ${moveY} ${width} ${height}`; - - localStorage.setItem('viewBox', vb); - svg.setAttributeNS(null, 'viewBox', vb); - } - } - - function pointerUp(e) { - svg.removeEventListener('pointermove', pointerMove); - svg.removeEventListener('pointerup', pointerUp); - } - - svg.addEventListener('pointermove', pointerMove); - svg.addEventListener('pointerup', pointerUp); - }, { passive: false }); - recordSheetVisibility.addEventListener('input', e => { let divs = document.querySelectorAll('#content div'); @@ -1086,7 +1057,7 @@ window.addEventListener('load', () => { clipPaths.forEach(cp => cp.style.display = el.checked ? 'none' : ''); })); - document.getElementById('toggle-prone-counter').addEventListener('input', function(e) { + document.getElementById('toggle-prone-counter').addEventListener('input', function (e) { let selected = RecordSheet.getSelected(); if (selected) { @@ -1101,4 +1072,4 @@ window.addEventListener('load', () => { } } }); -});
\ No newline at end of file +}); |