WIP: line draw, localstorage settings
This commit is contained in:
parent
45cfef270f
commit
798658a826
@ -150,8 +150,8 @@
|
|||||||
</defs>
|
</defs>
|
||||||
|
|
||||||
<rect id="background" x="-1" y="-1" width="2287" height="3087" />
|
<rect id="background" x="-1" y="-1" width="2287" height="3087" />
|
||||||
<image id="map2" class="map-scans" href="scans/map2.jpg" width="2284" height="1518" x="2" y="2" />
|
<!-- <image id="map2" class="map-scans" href="scans/map2.jpg" width="2284" height="1518" x="2" y="2" />
|
||||||
<image id="map3" class="map-scans" href="scans/map3.jpg" width="2284" height="1518" x="4" y="1564" />
|
<image id="map3" class="map-scans" href="scans/map3.jpg" width="2284" height="1518" x="4" y="1564" /> -->
|
||||||
<g id="firing-arcs"></g>
|
<g id="firing-arcs"></g>
|
||||||
<rect id="map" x="-1" y="-1" width="2287" height="3087" />
|
<rect id="map" x="-1" y="-1" width="2287" height="3087" />
|
||||||
<g id="points"></g>
|
<g id="points"></g>
|
||||||
@ -159,6 +159,7 @@
|
|||||||
</svg>
|
</svg>
|
||||||
|
|
||||||
<div id="content">
|
<div id="content">
|
||||||
|
<input type="checkbox" class="visible" checked />
|
||||||
<div>
|
<div>
|
||||||
Set firing arc:
|
Set firing arc:
|
||||||
<button type="button" class="set-firing-arc" data-size="small">
|
<button type="button" class="set-firing-arc" data-size="small">
|
||||||
|
202
index.js
202
index.js
@ -63,14 +63,17 @@ const svgns = "http://www.w3.org/2000/svg",
|
|||||||
svg = document.querySelector('svg'),
|
svg = document.querySelector('svg'),
|
||||||
map = document.querySelector('rect#map'),
|
map = document.querySelector('rect#map'),
|
||||||
hex = document.getElementById('point'),
|
hex = document.getElementById('point'),
|
||||||
pointsGroup = document.getElementById('points'),
|
ptGrp = document.getElementById('points'),
|
||||||
settingsPanel = document.getElementById('panel');
|
settingsPanel = document.getElementById('panel'),
|
||||||
|
recordSheetVisibility = document.querySelector('#content input[type="checkbox"].visible');
|
||||||
|
|
||||||
const { x: VIEWBOX_X, y: VIEWBOX_Y, width: VIEWBOX_WIDTH, height: VIEWBOX_HEIGHT } =
|
const { x: VIEWBOX_X, y: VIEWBOX_Y, width: VIEWBOX_WIDTH, height: VIEWBOX_HEIGHT } =
|
||||||
svg.viewBox.baseVal;
|
svg.viewBox.baseVal;
|
||||||
|
|
||||||
const COLUMN_COUNT = 33,
|
// const COLUMN_COUNT = 33,
|
||||||
ROW_COUNT = 51,
|
// ROW_COUNT = 51,
|
||||||
|
const COLUMN_COUNT = 20,
|
||||||
|
ROW_COUNT = 20,
|
||||||
HORZ_POINT_DISTANCE = 1.005,
|
HORZ_POINT_DISTANCE = 1.005,
|
||||||
VERT_POINT_DISTANCE = Math.sqrt(3) * HORZ_POINT_DISTANCE / 2,
|
VERT_POINT_DISTANCE = Math.sqrt(3) * HORZ_POINT_DISTANCE / 2,
|
||||||
ALTERNATING_OFFSET = HORZ_POINT_DISTANCE / 2,
|
ALTERNATING_OFFSET = HORZ_POINT_DISTANCE / 2,
|
||||||
@ -85,9 +88,21 @@ const FIRING_ARC_SIZE = {
|
|||||||
'large': Math.atan((21 * HORZ_POINT_DISTANCE) / (6 * VERT_POINT_DISTANCE))
|
'large': Math.atan((21 * HORZ_POINT_DISTANCE) / (6 * VERT_POINT_DISTANCE))
|
||||||
}
|
}
|
||||||
|
|
||||||
Object.values(settingsPanel.querySelectorAll('fieldset')).forEach(fieldset => {
|
let prevVb = localStorage.getItem('viewBox');
|
||||||
|
let recVis = localStorage.getItem('recordsVisibility');
|
||||||
|
|
||||||
|
if (prevVb) {
|
||||||
|
svg.setAttributeNS(null, 'viewBox', prevVb);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (recVis == 'false') {
|
||||||
|
recordSheetVisibility.checked = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Object.values(settingsPanel.querySelectorAll('fieldset')).forEach(fieldset => {
|
||||||
|
[].forEach(fieldset => {
|
||||||
const target = document.getElementById(fieldset.name);
|
const target = document.getElementById(fieldset.name);
|
||||||
const transform = window.getComputedStyle(target).transform.match(/-?\d+\.?\d*/g);
|
const transform = getComputedStyle(target).transform.match(/-?\d+\.?\d*/g);
|
||||||
const inputs = fieldset.querySelectorAll('input');
|
const inputs = fieldset.querySelectorAll('input');
|
||||||
|
|
||||||
if (transform) {
|
if (transform) {
|
||||||
@ -131,9 +146,12 @@ POINTS.forEach((row, index) => row.forEach(([x, y]) => {
|
|||||||
cy = y * 3 / 2 * CIRCUMRADIUS,
|
cy = y * 3 / 2 * CIRCUMRADIUS,
|
||||||
point = document.createElementNS(svgns, 'use');
|
point = document.createElementNS(svgns, 'use');
|
||||||
|
|
||||||
|
cx = parseFloat(cx.toFixed(1));
|
||||||
|
cy = parseFloat(cy.toFixed(1));
|
||||||
|
|
||||||
point.setAttributeNS(null, 'href', `#point`);
|
point.setAttributeNS(null, 'href', `#point`);
|
||||||
point.setAttributeNS(null, 'x', `${parseFloat(cx.toFixed(1))}`);
|
point.setAttributeNS(null, 'x', cx);
|
||||||
point.setAttributeNS(null, 'y', `${parseFloat(cy.toFixed(1))}`);
|
point.setAttributeNS(null, 'y', cy);
|
||||||
point.dataset.x = x;
|
point.dataset.x = x;
|
||||||
point.dataset.y = y;
|
point.dataset.y = y;
|
||||||
|
|
||||||
@ -146,21 +164,20 @@ POINTS.forEach((row, index) => row.forEach(([x, y]) => {
|
|||||||
{troopNumber, troopAllegiance} = selectedSoldier.dataset,
|
{troopNumber, troopAllegiance} = selectedSoldier.dataset,
|
||||||
selector = troopSelector(troopNumber, troopAllegiance);
|
selector = troopSelector(troopNumber, troopAllegiance);
|
||||||
|
|
||||||
let matrix = window.getComputedStyle(pointsGroup).transform.match(/-?\d+\.?\d*/g),
|
let transProp = getComputedStyle(ptGrp).transform.match(/-?\d+\.?\d*/g),
|
||||||
svgMatrix = new DOMMatrix(matrix || ''),
|
mtx = new DOMMatrix(transProp || ''),
|
||||||
pt = new DOMPoint(point.x.baseVal.value, point.y.baseVal.value),
|
pt = new DOMPoint(point.x.baseVal.value, point.y.baseVal.value),
|
||||||
svgP = pt.matrixTransform(svgMatrix);
|
svgP = pt.matrixTransform(mtx);
|
||||||
|
|
||||||
counter.setAttributeNS(null, 'cx', `${parseFloat(svgP.x.toFixed(1))}`);
|
counter.setAttributeNS(null, 'cx', svgP.x);
|
||||||
counter.setAttributeNS(null, 'cy', `${parseFloat(svgP.y.toFixed(1))}`);
|
counter.setAttributeNS(null, 'cy', svgP.y);
|
||||||
counter.setAttributeNS(null, 'r', '0.25in');
|
counter.setAttributeNS(null, 'r', '0.25in');
|
||||||
counter.dataset.troopNumber = troopNumber;
|
counter.dataset.troopNumber = troopNumber;
|
||||||
counter.dataset.troopAllegiance = troopAllegiance;
|
counter.dataset.troopAllegiance = troopAllegiance;
|
||||||
counter.classList.add('counter');
|
counter.classList.add('counter');
|
||||||
|
|
||||||
text.setAttributeNS(null, 'text-anchor', 'middle');
|
text.setAttributeNS(null, 'x', svgP.x);
|
||||||
text.setAttributeNS(null, 'x', `${svgP.x}`);
|
text.setAttributeNS(null, 'y', svgP.y);
|
||||||
text.setAttributeNS(null, 'y', `${svgP.y}`);
|
|
||||||
text.dataset.troopNumber = troopNumber;
|
text.dataset.troopNumber = troopNumber;
|
||||||
text.dataset.troopAllegiance = troopAllegiance;
|
text.dataset.troopAllegiance = troopAllegiance;
|
||||||
text.textContent = troopNumber;
|
text.textContent = troopNumber;
|
||||||
@ -233,9 +250,146 @@ POINTS.forEach((row, index) => row.forEach(([x, y]) => {
|
|||||||
|
|
||||||
point.addEventListener('mouseout', e => e.target.removeAttribute('class'));
|
point.addEventListener('mouseout', e => e.target.removeAttribute('class'));
|
||||||
|
|
||||||
pointsGroup.appendChild(point);
|
ptGrp.appendChild(point);
|
||||||
|
|
||||||
|
text = document.createElementNS(svgns, 'text'),
|
||||||
|
|
||||||
|
text.setAttributeNS(null, 'x', cx);
|
||||||
|
text.setAttributeNS(null, 'y', cy);
|
||||||
|
text.textContent = `${point.dataset.x},${point.dataset.y}`;
|
||||||
|
|
||||||
|
ptGrp.appendChild(text);
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
(function debug() {
|
||||||
|
function drawLine(x1, y1, x2, y2) {
|
||||||
|
let start = ptGrp.querySelector(`[data-x="${x1}"][data-y="${y1}"]`);
|
||||||
|
let end = ptGrp.querySelector(`[data-x="${x2}"][data-y="${y2}"]`);
|
||||||
|
let [startX, startY] = [start.x.baseVal.value, start.y.baseVal.value];
|
||||||
|
let [endX, endY] = [end.x.baseVal.value, end.y.baseVal.value];
|
||||||
|
|
||||||
|
let startP = new DOMPoint(startX, startY);
|
||||||
|
let endP = new DOMPoint(endX, endY);
|
||||||
|
|
||||||
|
let tStart = startP.matrixTransform(mtx);
|
||||||
|
let tEnd = endP.matrixTransform(mtx);
|
||||||
|
|
||||||
|
let line = document.createElementNS(svgns, 'line');
|
||||||
|
line.setAttributeNS(null, 'x1', tStart.x);
|
||||||
|
line.setAttributeNS(null, 'y1', tStart.y);
|
||||||
|
line.setAttributeNS(null, 'x2', tEnd.x);
|
||||||
|
line.setAttributeNS(null, 'y2', tEnd.y);
|
||||||
|
line.classList.add('debug');
|
||||||
|
|
||||||
|
line.setAttributeNS(null, 'stroke', 'green');
|
||||||
|
line.setAttributeNS(null, 'stroke-width', 10);
|
||||||
|
svg.appendChild(line);
|
||||||
|
|
||||||
|
return line;
|
||||||
|
}
|
||||||
|
|
||||||
|
let transProp = getComputedStyle(ptGrp).transform.match(/-?\d+\.?\d*/g),
|
||||||
|
mtx = new DOMMatrix(transProp || ''),
|
||||||
|
circR = (new DOMPoint(0, 3 * CIRCUMRADIUS / 2)).matrixTransform(mtx).y * 2 / 3;
|
||||||
|
|
||||||
|
// let l1 = drawLine(1, 1, 1, 2);
|
||||||
|
|
||||||
|
drawLine(0, 0, 5, 4);
|
||||||
|
// drawLine(1, 1, 1, 3);
|
||||||
|
|
||||||
|
// let pt = l1.getPointAtLength(circR);
|
||||||
|
|
||||||
|
// let c = document.createElementNS(svgns, 'circle');
|
||||||
|
// c.setAttributeNS(null, 'cx', pt.x);
|
||||||
|
// c.setAttributeNS(null, 'cy', pt.y);
|
||||||
|
// c.setAttributeNS(null, 'r', 20);
|
||||||
|
// c.setAttributeNS(null, 'fill', 'red');
|
||||||
|
// c.setAttributeNS(null, 'opacity', '0.2');
|
||||||
|
// svg.appendChild(c);
|
||||||
|
})();
|
||||||
|
|
||||||
|
function evenr_to_axial(x, 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};
|
||||||
|
}
|
||||||
|
|
||||||
|
function axial_distance(q1, r1, q2, r2) {
|
||||||
|
return (Math.abs(q1 - q2) + Math.abs(q1 + r1 - q2 - r2) + Math.abs(r1 - r2)) / 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
return axial_distance(q1, r1, q2, r2);
|
||||||
|
}
|
||||||
|
|
||||||
|
function cube_to_axial(q, r, s) {
|
||||||
|
return { q: q, r: r };
|
||||||
|
}
|
||||||
|
|
||||||
|
function axial_to_cube(q, r) {
|
||||||
|
return { q: q, r: r, s: -q - r};
|
||||||
|
}
|
||||||
|
|
||||||
|
function cube_round(q, r, s) {
|
||||||
|
rQ = Math.round(q);
|
||||||
|
rR = Math.round(r);
|
||||||
|
rS = Math.round(s);
|
||||||
|
|
||||||
|
let q_diff = Math.abs(rQ - q),
|
||||||
|
r_diff = Math.abs(rR - r),
|
||||||
|
s_diff = Math.abs(rS - s);
|
||||||
|
|
||||||
|
if (q_diff > r_diff && q_diff > s_diff) {
|
||||||
|
rQ = -rR - rS;
|
||||||
|
} else if (r_diff > s_diff) {
|
||||||
|
rR = -rQ - rS;
|
||||||
|
} else {
|
||||||
|
rS = -rQ - rR;
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
return {q: axial.q, r: axial.r};
|
||||||
|
}
|
||||||
|
|
||||||
|
function lerp(a, b, t) {
|
||||||
|
return a + (b - a) * t;
|
||||||
|
}
|
||||||
|
|
||||||
|
function axial_lerp(q1, r1, q2, r2, t) {
|
||||||
|
return { q: lerp(q1, q2, t), r: lerp(r1, 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 = [];
|
||||||
|
|
||||||
|
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)
|
||||||
|
|
||||||
|
console.log(x, y);
|
||||||
|
|
||||||
|
results.push([x, y]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return results;
|
||||||
|
}
|
||||||
|
|
||||||
map.addEventListener('mousemove', e => {
|
map.addEventListener('mousemove', e => {
|
||||||
let boundingRect = e.target.getBoundingClientRect();
|
let boundingRect = e.target.getBoundingClientRect();
|
||||||
let pointerX = e.clientX - boundingRect.left;
|
let pointerX = e.clientX - boundingRect.left;
|
||||||
@ -462,7 +616,10 @@ svg.addEventListener('wheel', e => {
|
|||||||
// newX = newX < VIEWBOX_X ? VIEWBOX_X : newX;
|
// newX = newX < VIEWBOX_X ? VIEWBOX_X : newX;
|
||||||
// newY = newY < VIEWBOX_Y ? VIEWBOX_Y : newY;
|
// newY = newY < VIEWBOX_Y ? VIEWBOX_Y : newY;
|
||||||
|
|
||||||
svg.setAttributeNS(null, 'viewBox', `${newX} ${newY} ${newWidth} ${newHeight}`);
|
let vb = `${newX} ${newY} ${newWidth} ${newHeight}`
|
||||||
|
|
||||||
|
localStorage.setItem('viewBox', vb);
|
||||||
|
svg.setAttributeNS(null, 'viewBox', vb);
|
||||||
});
|
});
|
||||||
|
|
||||||
svg.addEventListener('pointerdown', e => {
|
svg.addEventListener('pointerdown', e => {
|
||||||
@ -493,7 +650,10 @@ svg.addEventListener('pointerdown', e => {
|
|||||||
moveX = parseInt(svgStartPt.x - svgMovePt.x + x),
|
moveX = parseInt(svgStartPt.x - svgMovePt.x + x),
|
||||||
moveY = parseInt(svgStartPt.y - svgMovePt.y + y);
|
moveY = parseInt(svgStartPt.y - svgMovePt.y + y);
|
||||||
|
|
||||||
svg.setAttributeNS(null, 'viewBox', `${moveX} ${moveY} ${width} ${height}`);
|
let vb = `${moveX} ${moveY} ${width} ${height}`;
|
||||||
|
|
||||||
|
localStorage.setItem('viewBox', vb);
|
||||||
|
svg.setAttributeNS(null, 'viewBox', vb);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -505,4 +665,8 @@ svg.addEventListener('pointerdown', e => {
|
|||||||
|
|
||||||
svg.addEventListener('pointermove', pointerMove);
|
svg.addEventListener('pointermove', pointerMove);
|
||||||
svg.addEventListener('pointerup', pointerUp);
|
svg.addEventListener('pointerup', pointerUp);
|
||||||
|
});
|
||||||
|
|
||||||
|
recordSheetVisibility.addEventListener('input', e => {
|
||||||
|
localStorage.setItem('recordsVisibility', recordSheetVisibility.checked);
|
||||||
});
|
});
|
38
style.css
38
style.css
@ -8,14 +8,21 @@ body {
|
|||||||
svg {
|
svg {
|
||||||
background-color: darkgray;
|
background-color: darkgray;
|
||||||
flex-basis: 100%;
|
flex-basis: 100%;
|
||||||
/* transform: rotate(-90deg);
|
|
||||||
transform-origin: center; */
|
|
||||||
/* max-height: 50vh; */
|
/* max-height: 50vh; */
|
||||||
/* max-height: 100vw; */
|
/* max-height: 100vw; */
|
||||||
}
|
}
|
||||||
|
|
||||||
svg text {
|
svg text {
|
||||||
user-select: none;
|
user-select: none;
|
||||||
|
font-size: 4px;
|
||||||
|
fill: white;
|
||||||
|
stroke: black;
|
||||||
|
stroke-width: 0.2px;
|
||||||
|
font-weight: bold;
|
||||||
|
transform: translateY(6px);
|
||||||
|
font-family: monospace;
|
||||||
|
text-anchor: middle;
|
||||||
|
/* display: none; */
|
||||||
}
|
}
|
||||||
|
|
||||||
div#content {
|
div#content {
|
||||||
@ -27,6 +34,7 @@ div#content {
|
|||||||
max-height: 100vh;
|
max-height: 100vh;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
/* padding: 2px; */
|
/* padding: 2px; */
|
||||||
|
position: relative;
|
||||||
}
|
}
|
||||||
|
|
||||||
#content > div:first-of-type {
|
#content > div:first-of-type {
|
||||||
@ -34,6 +42,23 @@ div#content {
|
|||||||
border-bottom: 1px solid gray;
|
border-bottom: 1px solid gray;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#content > div {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
#content input[type="checkbox"].visible {
|
||||||
|
position: absolute;
|
||||||
|
right: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#content:has(input[type="checkbox"].visible:checked) > div {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
#content:has(input[type="checkbox"].visible:checked) div#record-sheet {
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
|
||||||
#record-sheet {
|
#record-sheet {
|
||||||
/* max-height: 100%; */
|
/* max-height: 100%; */
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
@ -73,13 +98,14 @@ div#content {
|
|||||||
}
|
}
|
||||||
|
|
||||||
svg > defs > #point {
|
svg > defs > #point {
|
||||||
fill: transparent;
|
fill: teal;
|
||||||
|
fill-opacity: 0.5;
|
||||||
stroke: black;
|
stroke: black;
|
||||||
stroke-width: 0.5px;
|
stroke-width: 0.5px;
|
||||||
}
|
}
|
||||||
|
|
||||||
use[href="#point"] {
|
use[href="#point"] {
|
||||||
opacity: 0;
|
opacity: 0.2;
|
||||||
}
|
}
|
||||||
|
|
||||||
use[href="#point"].active {
|
use[href="#point"].active {
|
||||||
@ -90,10 +116,6 @@ g#points {
|
|||||||
transform: translate(19px, 31px) scale(4);
|
transform: translate(19px, 31px) scale(4);
|
||||||
}
|
}
|
||||||
|
|
||||||
g#test {
|
|
||||||
transform: scale(2);
|
|
||||||
}
|
|
||||||
|
|
||||||
#background {
|
#background {
|
||||||
fill: #bacae3;
|
fill: #bacae3;
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user