From afadb8022dcaca2310e88e3e56079cea575e8c48 Mon Sep 17 00:00:00 2001 From: Catalin Mititiuc Date: Fri, 22 Mar 2024 15:07:52 -0700 Subject: [PATCH] Some cleanup --- index.html | 1 + index.js | 393 +++++++++++++++++++++++------------------------------ style.css | 4 +- 3 files changed, 172 insertions(+), 226 deletions(-) diff --git a/index.html b/index.html index 565adaf..17f5cc4 100644 --- a/index.html +++ b/index.html @@ -29,6 +29,7 @@ + diff --git a/index.js b/index.js index 3df3183..160e61e 100644 --- a/index.js +++ b/index.js @@ -1,42 +1,21 @@ -let isEven = n => n % 2 === 0; -let toFixed = n => Number.parseFloat(n).toFixed(2); -let radToDeg = radians => radians * 180 / Math.PI; +function isEven(n) { + return n % 2 === 0; +} -let getPointCoords = (x, y) => { - let point = document.querySelector(`[data-x="${x}"][data-y="${y}"]`); +function toFixed(n) { + return Number.parseFloat(n).toFixed(2); +} - return [point.x.baseVal.value, point.y.baseVal.value] -}; - -let svgns = "http://www.w3.org/2000/svg", - svg = document.querySelector('svg'), - rect = document.querySelector('rect#map'); - -let columnCount = 33, - rowCount = 25, - pointDistanceInInches = 1.005; - -let columns = [...Array(columnCount).keys()], - rows = [...Array(rowCount).keys()], - points = rows.map(y => columns.map(x => [x, y])); - -let xOffset = 0.25, - yOffset = 0.45; - calcY = Math.sqrt(3) * pointDistanceInInches / 2, - alternatingOffset = pointDistanceInInches / 2; - -let firingArcSize = { - 'small': Math.atan(pointDistanceInInches / (6 * calcY)), - 'medium': Math.atan((pointDistanceInInches / 2) / calcY), - 'large': Math.atan((21 * pointDistanceInInches) / (6 * calcY)) +function radToDeg(radians) { + return radians * 180 / Math.PI; } 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; + xIntercept = y => (y - y1) * xDiff / yDiff + x1, + yIntercept = x => (x - x1) * yDiff / xDiff + y1; if (xDiff > 0 && yDiff > 0) { let yWhenXisMax = yIntercept(maxX); @@ -79,202 +58,34 @@ function edgePoint(x1, y1, x2, y2, maxX, maxY) { return pointCoords; } -rect.addEventListener('mousemove', e => { - var rect = e.target.getBoundingClientRect(); - var x = e.clientX - rect.left; - var y = e.clientY - rect.top; - let [maxX, maxY] = [e.target.width, e.target.height].map(v => v.baseVal.valueInSpecifiedUnits); - let [maxXpx, maxYpx] = [e.target.width, e.target.height].map(v => v.baseVal.value); +let getPointCoords = (x, y) => { + let point = document.querySelector(`[data-x="${x}"][data-y="${y}"]`); - // console.log('x', `${toFixed(x / rect.width * maxX)}"`, 'y', `${toFixed(y / rect.height * maxY)}"`); + return [point.x.baseVal.value, point.y.baseVal.value] +}; - let aim = document.querySelector('line.firing-arc.active'); - let p = document.querySelector('polyline.firing-arc.active'); +let svgns = "http://www.w3.org/2000/svg", + svg = document.querySelector('svg'), + rect = document.querySelector('rect#map'); - // TODO: handle horizontal and vertical lines +const COLUMN_COUNT = 33, + ROW_COUNT = 25, + HORZ_POINT_DISTANCE = 1.005, + VERT_POINT_DISTANCE = Math.sqrt(3) * HORZ_POINT_DISTANCE / 2, + ALTERNATING_OFFSET = HORZ_POINT_DISTANCE / 2, + [X_OFFSET, Y_OFFSET] = [0.25, 0.45], + [COLUMNS, ROWS] = [COLUMN_COUNT, ROW_COUNT].map(n => [...Array(n).keys()]), + POINTS = ROWS.map(y => COLUMNS.map(x => [x, y])); - if (aim && p) { - let xIntercept = y => (y - y1) * (x2 - x1) / (y2 - y1) + x1; - let yIntercept = x => (x - x1) * (y2 - y1) / (x2 - x1) + y1; - let newX, newY; - - let [x1, y1] = [aim.x1, aim.y1].map(v => v.baseVal.valueInSpecifiedUnits); - let [x2, y2] = [x / rect.width * maxX, y / rect.height * maxY]; - - let {x: x1px, y: y1px} = p.points[1]; - let [x2px, y2px] = [x / rect.width * maxXpx, y / rect.height * maxYpx]; - - let width = x2px - x1px; - let height = -(y2px - y1px); - let angle = Math.abs(Math.atan(height / width)); - - if (width < 0 && height > 0) { - // angle = 180 - angle; - angle = Math.PI - angle; - } else if (width < 0 && height < 0) { - // angle = 180 + angle; - angle = Math.PI + angle; - } else if (width > 0 && height < 0) { - // angle = 360 - angle; - angle = 2 * Math.PI - angle; - } - - console.log('angle:', `${toFixed(radToDeg(angle))}\u00B0`, `${angle}rad`); - - let arcAngle = firingArcSize[p.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); - - let newY1 = y2px + yDelta; - let newX1 = x2px + xDelta; - - let newY2 = y2px - yDelta; - let newX2 = x2px - xDelta; - - [newX1, newY1] = edgePoint(x1px, y1px, newX1, newY1, maxXpx, maxYpx); - [newX2, newY2] = edgePoint(x1px, y1px, newX2, newY2, maxXpx, maxYpx); - - // p.setAttributeNS(null, 'points', `${newX},${newY} ${x1px},${y1px} ${newX},${newY}`); - // p.setAttributeNS(null, 'points', `${x2px},${y2px} ${x1px},${y1px} ${x2px},${y2px}`); - p.setAttributeNS(null, 'points', `${newX1},${newY1} ${x1px},${y1px} ${newX2},${newY2}`); - - if (x2 - x1 > 0 && y2 - y1 > 0) { - let yWhenXisMax = yIntercept(maxX); - let xWhenYisMax = xIntercept(maxY); - - if (xWhenYisMax <= maxX) { - newX = xWhenYisMax; - newY = maxY; - } else { - newX = maxX; - newY = yWhenXisMax; +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)) } - } else if (x2 - x1 > 0 && y2 - y1 < 0) { - let yWhenXisMax = yIntercept(maxX); - let xWhenYisZero = xIntercept(0); - if (xWhenYisZero <= maxX) { - newX = xWhenYisZero; - newY = 0; - } else { - newX = maxX; - newY = yWhenXisMax; - } - } else if (x2 - x1 < 0 && y2 - y1 < 0) { - let yWhenXisZero = yIntercept(0); - let xWhenYisZero = xIntercept(0); - - if (yWhenXisZero >= 0) { - newX = 0; - newY = yWhenXisZero; - } else { - newX = xWhenYisZero; - newY = 0; - } - } else { - let yWhenXisZero = yIntercept(0); - let xWhenYisMax = xIntercept(maxY); - - if (yWhenXisZero <= maxY) { - newX = 0; - newY = yWhenXisZero; - } else { - newX = xWhenYisMax; - newY = maxY; - } - } - - distance = Math.sqrt((x2 - x1)**2 + (y2 - y1)**2); - newY = y2 + (distance * Math.cos(angle)) * Math.tan(arcAngle); - newX = x2 + (distance * Math.sin(angle)) * Math.tan(arcAngle); - - aim.setAttributeNS(null, 'x2', `${newX}in`); - aim.setAttributeNS(null, 'y2', `${newY}in`); - - // let width = aim.x2.baseVal.value - aim.x1.baseVal.value; - // let height = -(aim.y2.baseVal.value - aim.y1.baseVal.value); - // let angle = Math.abs(radToDeg(Math.atan(height / width))); - - // if (width < 0 && height > 0) { - // angle = 180 - angle; - // } else if (width < 0 && height < 0) { - // angle = 180 + angle; - // } else if (width > 0 && height < 0) { - // angle = 360 - angle; - // } - - // console.log(`${toFixed(angle)}\u00B0`); - } -}); - -document.querySelectorAll('.soldier-record').forEach(el => - el.addEventListener('click', e => { - if (e.target.classList.contains('selected')) { - e.target.classList.remove('selected'); - } else { - document.querySelectorAll('.soldier-record.selected').forEach(el => - el.classList.remove('selected') - ); - e.target.classList.add('selected'); - } - }) -); - -document.querySelectorAll('.set-firing-arc').forEach(el => el.addEventListener('click', e => { - let selectedSoldier = document.querySelector('.soldier-record.selected'); - - if (selectedSoldier) { - let {troopNumber, troopAllegiance} = selectedSoldier.dataset; - - let existingArcs = document.querySelectorAll( - `.firing-arc[data-troop-number="${troopNumber}"][data-troop-allegiance="${troopAllegiance}"]` - ); - - if (existingArcs.length > 0) { - existingArcs.forEach(el => el.remove()); - } - - let counter = document.querySelector( - `circle.counter[data-troop-number="${troopNumber}"][data-troop-allegiance="${troopAllegiance}"]` - ); - - let aim = document.createElementNS(svgns, 'line'); - - aim.classList.add('firing-arc', 'active'); - aim.dataset.troopNumber = troopNumber; - aim.dataset.troopAllegiance = troopAllegiance; - aim.dataset.size = e.target.dataset.size; - aim.setAttributeNS(null, 'x1', counter.cx.baseVal.valueAsString); - aim.setAttributeNS(null, 'y1', counter.cy.baseVal.valueAsString); - aim.setAttributeNS(null, 'x2', counter.cx.baseVal.valueAsString); - aim.setAttributeNS(null, 'y2', counter.cy.baseVal.valueAsString); - // aim.style.transformOrigin = `${counter.cx.baseVal.valueAsString} ${counter.cy.baseVal.valueAsString}`; - - svg.appendChild(aim); - - aim.addEventListener('click', e => { - e.target.classList.remove('active'); - document.querySelector('circle#point').style.display = ''; - }); - - let pivotPoint = [counter.cx.baseVal.value, counter.cy.baseVal.value]; - let firingArc = document.createElementNS(svgns, 'polyline'); - firingArc.classList.add('firing-arc', 'active'); - firingArc.dataset.troopNumber = troopNumber; - firingArc.dataset.troopAllegiance = troopAllegiance; - firingArc.dataset.size = e.target.dataset.size; - firingArc.setAttributeNS(null, 'points', `${pivotPoint} ${pivotPoint} ${pivotPoint}`); - - svg.appendChild(firingArc); - - document.querySelector('circle#point').style.display = 'none'; - } -})); - -points.forEach((row, index) => row.forEach(([x, y]) => { - var cx = x * pointDistanceInInches + xOffset + (isEven(index) ? alternatingOffset : 0), - cy = y * pointDistanceInInches * calcY + yOffset, +POINTS.forEach((row, index) => row.forEach(([x, y]) => { + var cx = x * HORZ_POINT_DISTANCE + X_OFFSET + (isEven(index) ? ALTERNATING_OFFSET : 0), + cy = y * HORZ_POINT_DISTANCE * VERT_POINT_DISTANCE + Y_OFFSET, point = document.createElementNS(svgns, 'use'); point.setAttributeNS(null, 'href', `#point`); @@ -317,6 +128,140 @@ points.forEach((row, index) => row.forEach(([x, y]) => { svg.appendChild(point); })); +rect.addEventListener('mousemove', e => { + var rect = e.target.getBoundingClientRect(); + var x = e.clientX - rect.left; + var y = e.clientY - rect.top; + let [maxX, maxY] = [e.target.width, e.target.height].map(v => v.baseVal.valueInSpecifiedUnits); + let [maxXpx, maxYpx] = [e.target.width, e.target.height].map(v => v.baseVal.value); + + // console.log('x', `${toFixed(x / rect.width * maxX)}"`, 'y', `${toFixed(y / rect.height * maxY)}"`); + + let aim = document.querySelector('line.firing-arc.active'); + // let p = document.querySelector('polyline.firing-arc.active'); + let p = document.querySelector('polygon.firing-arc.active'); + + // TODO: handle horizontal and vertical lines + + if (aim && p) { + let [x1, y1] = [aim.x1, aim.y1].map(v => v.baseVal.valueInSpecifiedUnits); + let [x2, y2] = [x / rect.width * maxX, y / rect.height * maxY]; + + let {x: x1px, y: y1px} = p.points[1]; + let [x2px, y2px] = [x / rect.width * maxXpx, y / rect.height * maxYpx]; + + let xDiff = x2px - x1px; + let yDiff = -(y2px - y1px); + let angle = Math.abs(Math.atan(yDiff / xDiff)); + + if (xDiff < 0 && yDiff > 0) { + angle = Math.PI - angle; + } else if (xDiff < 0 && yDiff < 0) { + angle = Math.PI + angle; + } else if (xDiff > 0 && yDiff < 0) { + angle = 2 * Math.PI - angle; + } + + console.log('angle:', `${toFixed(radToDeg(angle))}\u00B0`, `${angle}rad`); + + let arcAngle = FIRING_ARC_SIZE[p.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); + + let [newY1, newX1] = [y2px + yDelta, x2px + xDelta]; + let [newY2, newX2] = [y2px - yDelta, x2px - xDelta]; + + [newX1, newY1] = edgePoint(x1px, y1px, newX1, newY1, maxXpx, maxYpx); + [newX2, newY2] = edgePoint(x1px, y1px, newX2, newY2, maxXpx, maxYpx); + + // var sameEdgeConditions = [ + + // ] + + // if (sameEdgeConditions) + + // p.setAttributeNS(null, 'points', `${newX},${newY} ${x1px},${y1px} ${newX},${newY}`); + // p.setAttributeNS(null, 'points', `${x2px},${y2px} ${x1px},${y1px} ${x2px},${y2px}`); + p.setAttributeNS(null, 'points', `${newX1},${newY1} ${x1px},${y1px} ${newX2},${newY2}`); + + let [newX, newY] = edgePoint(x1, y1, x2, y2, maxX, maxY); + + aim.setAttributeNS(null, 'x2', `${newX}in`); + aim.setAttributeNS(null, 'y2', `${newY}in`); + } +}); + +document.querySelectorAll('.soldier-record').forEach(el => + el.addEventListener('click', e => { + if (e.target.classList.contains('selected')) { + e.target.classList.remove('selected'); + } else { + document.querySelectorAll('.soldier-record.selected').forEach(el => + el.classList.remove('selected') + ); + e.target.classList.add('selected'); + } + }) +); + +document.querySelectorAll('.set-firing-arc').forEach(el => el.addEventListener('click', e => { + let selectedSoldier = document.querySelector('.soldier-record.selected'); + + if (selectedSoldier) { + let {troopNumber, troopAllegiance} = selectedSoldier.dataset; + + let existingArcs = document.querySelectorAll( + `.firing-arc[data-troop-number="${troopNumber}"][data-troop-allegiance="${troopAllegiance}"]` + ); + + if (existingArcs.length > 0) { + existingArcs.forEach(el => el.remove()); + } + + let counter = document.querySelector( + `circle.counter[data-troop-number="${troopNumber}"][data-troop-allegiance="${troopAllegiance}"]` + ); + + let arcLayer = document.getElementById('firing-arcs'); + + let aim = document.createElementNS(svgns, 'line'); + + aim.classList.add('firing-arc', 'active'); + aim.dataset.troopNumber = troopNumber; + aim.dataset.troopAllegiance = troopAllegiance; + aim.dataset.size = e.target.dataset.size; + aim.setAttributeNS(null, 'x1', counter.cx.baseVal.valueAsString); + aim.setAttributeNS(null, 'y1', counter.cy.baseVal.valueAsString); + aim.setAttributeNS(null, 'x2', counter.cx.baseVal.valueAsString); + aim.setAttributeNS(null, 'y2', counter.cy.baseVal.valueAsString); + // aim.style.transformOrigin = `${counter.cx.baseVal.valueAsString} ${counter.cy.baseVal.valueAsString}`; + + // svg.appendChild(aim); + arcLayer.prepend(aim); + + aim.addEventListener('click', e => { + // e.target.classList.remove('active'); + document.querySelectorAll('.firing-arc.active').forEach(el => el.classList.remove('active')); + document.querySelector('circle#point').style.display = ''; + }); + + let pivotPoint = [counter.cx.baseVal.value, counter.cy.baseVal.value]; + // let firingArc = document.createElementNS(svgns, 'polyline'); + let firingArc = document.createElementNS(svgns, 'polygon'); + firingArc.classList.add('firing-arc', 'active'); + firingArc.dataset.troopNumber = troopNumber; + firingArc.dataset.troopAllegiance = troopAllegiance; + firingArc.dataset.size = e.target.dataset.size; + firingArc.setAttributeNS(null, 'points', `${pivotPoint} ${pivotPoint} ${pivotPoint}`); + + arcLayer.prepend(firingArc); + // svg.appendChild(firingArc); + + document.querySelector('circle#point').style.display = 'none'; + } +})); + let smlArc = document.createElementNS(svgns, 'polygon'); smlArc.setAttributeNS(null, 'id', 'sml-arc'); let smlArcPoints = `${getPointCoords(1, 24)} ${getPointCoords(1, 21)} ${getPointCoords(2, 21)}`; @@ -343,6 +288,6 @@ svg.appendChild(lrgArc); // arc.style.transformOrigin = `${ox}px ${oy}px`; // arc.style.transform = 'rotate(90deg)'; -var smlArcAngle = radToDeg((Math.atan(pointDistanceInInches / (6 * calcY)) * 2)); -var medArcAngle = radToDeg((Math.atan((3 * pointDistanceInInches) / (6 * calcY)) * 2)); -var lrgArcAngle = radToDeg((Math.atan((21 * pointDistanceInInches) / (6 * calcY)) * 2)); \ No newline at end of file +var smlArcAngle = radToDeg((Math.atan(HORZ_POINT_DISTANCE / (6 * VERT_POINT_DISTANCE)) * 2)); +var medArcAngle = radToDeg((Math.atan((3 * HORZ_POINT_DISTANCE) / (6 * VERT_POINT_DISTANCE)) * 2)); +var lrgArcAngle = radToDeg((Math.atan((21 * HORZ_POINT_DISTANCE) / (6 * VERT_POINT_DISTANCE)) * 2)); \ No newline at end of file diff --git a/style.css b/style.css index 09a75b0..549bd61 100644 --- a/style.css +++ b/style.css @@ -43,8 +43,8 @@ button.set-firing-arc img { } line.firing-arc { - stroke: none; - /* transform: scale(2); */ + stroke: blue; + opacity: 0.1; } polyline.firing-arc {