WIP: line draw, localstorage settings

This commit is contained in:
Catalin Mititiuc 2024-03-30 19:58:55 -07:00
parent 45cfef270f
commit 798658a826
3 changed files with 216 additions and 29 deletions

View File

@ -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
View File

@ -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);
} }
} }
@ -506,3 +666,7 @@ 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);
});

View File

@ -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;
} }