index : btroops | |
Virtual board game-aid for BattleTroops, an infantry combat simulator wargame published by FASA in 1989. |
aboutsummaryrefslogtreecommitdiff |
diff options
author | Catalin Mititiuc <Catalin.Mititiuc@gmail.com> | 2024-03-22 15:07:52 -0700 |
---|---|---|
committer | Catalin Mititiuc <Catalin.Mititiuc@gmail.com> | 2024-03-22 15:07:52 -0700 |
commit | afadb8022dcaca2310e88e3e56079cea575e8c48 (patch) | |
tree | 58f60b227487daed336387fe09cf5e62a8d97850 | |
parent | b24460efc3f07ba89cd4239ca498dbbb4e32effa (diff) |
Some cleanup
-rw-r--r-- | index.html | 1 | ||||
-rw-r--r-- | index.js | 277 | ||||
-rw-r--r-- | style.css | 4 |
3 files changed, 114 insertions, 168 deletions
@@ -29,6 +29,7 @@ <line x1="-0.25in" y1="0" x2="-0.25in" y2="23in" stroke="url(#vert)" /> <!-- <image id="img1" href="map1.png" height="6.428in" width="9.971in" /> --> <image id="img2" href="scans/map1.jpg" width="2284" height="1518" /> + <g id="firing-arcs"></g> <rect id="map" x="0" y="0" width="34in" height="23in" /> </svg> @@ -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; - -let getPointCoords = (x, y) => { - let point = document.querySelector(`[data-x="${x}"][data-y="${y}"]`); - - 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])); +function isEven(n) { + return n % 2 === 0; +} -let xOffset = 0.25, - yOffset = 0.45; - calcY = Math.sqrt(3) * pointDistanceInInches / 2, - alternatingOffset = pointDistanceInInches / 2; +function toFixed(n) { + return Number.parseFloat(n).toFixed(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,6 +58,76 @@ function edgePoint(x1, y1, x2, y2, maxX, maxY) { return pointCoords; } +let getPointCoords = (x, y) => { + let point = document.querySelector(`[data-x="${x}"][data-y="${y}"]`); + + 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'); + +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])); + +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)) + } + +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`); + point.setAttributeNS(null, 'x', `${cx}in`); + point.setAttributeNS(null, 'y', `${cy}in`); + point.dataset.x = x; + point.dataset.y = y; + + point.addEventListener('click', e => { + let selectedSoldier = document.querySelector('.soldier-record.selected'); + + if (selectedSoldier) { + let counter = document.createElementNS(svgns, 'circle'); + let text = document.createElementNS(svgns, 'text'); + + counter.setAttributeNS(null, 'cx', `${cx}in`); + counter.setAttributeNS(null, 'cy', `${cy}in`); + counter.setAttributeNS(null, 'r', '0.25in'); + counter.dataset.troopNumber = selectedSoldier.dataset.troopNumber; + counter.dataset.troopAllegiance = selectedSoldier.dataset.troopAllegiance; + counter.classList.add('counter'); + + text.setAttributeNS(null, 'text-anchor', 'middle'); + text.setAttributeNS(null, 'x', `${cx}in`); + text.setAttributeNS(null, 'y', `${cy + 0.25}in`); + text.dataset.troopNumber = selectedSoldier.dataset.troopNumber; + text.dataset.troopAllegiance = selectedSoldier.dataset.troopAllegiance; + text.textContent = `${selectedSoldier.dataset.troopNumber}`; + text.classList.add('counter'); + + document.querySelectorAll( + `.counter[data-troop-number="${selectedSoldier.dataset.troopNumber}"][data-troop-allegiance="${selectedSoldier.dataset.troopAllegiance}"]` + ).forEach(el => el.remove()); + + svg.appendChild(counter); + svg.appendChild(text); + } + }); + + svg.appendChild(point); +})); + rect.addEventListener('mousemove', e => { var rect = e.target.getBoundingClientRect(); var x = e.clientX - rect.left; @@ -89,122 +138,57 @@ rect.addEventListener('mousemove', e => { // 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('polyline.firing-arc.active'); + let p = document.querySelector('polygon.firing-arc.active'); // TODO: handle horizontal and vertical lines 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)); + let xDiff = x2px - x1px; + let yDiff = -(y2px - y1px); + let angle = Math.abs(Math.atan(yDiff / xDiff)); - if (width < 0 && height > 0) { - // angle = 180 - angle; + if (xDiff < 0 && yDiff > 0) { angle = Math.PI - angle; - } else if (width < 0 && height < 0) { - // angle = 180 + angle; + } else if (xDiff < 0 && yDiff < 0) { angle = Math.PI + angle; - } else if (width > 0 && height < 0) { - // angle = 360 - angle; + } else if (xDiff > 0 && yDiff < 0) { angle = 2 * Math.PI - angle; } console.log('angle:', `${toFixed(radToDeg(angle))}\u00B0`, `${angle}rad`); - let arcAngle = firingArcSize[p.dataset.size]; + 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 = y2px + yDelta; - let newX1 = x2px + xDelta; - - let newY2 = y2px - yDelta; - let newX2 = x2px - xDelta; + 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}`); - 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; - } - } 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); + let [newX, newY] = edgePoint(x1, y1, x2, y2, maxX, maxY); 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`); } }); @@ -239,6 +223,8 @@ document.querySelectorAll('.set-firing-arc').forEach(el => el.addEventListener(' `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'); @@ -251,72 +237,31 @@ document.querySelectorAll('.set-firing-arc').forEach(el => el.addEventListener(' aim.setAttributeNS(null, 'y2', counter.cy.baseVal.valueAsString); // aim.style.transformOrigin = `${counter.cx.baseVal.valueAsString} ${counter.cy.baseVal.valueAsString}`; - svg.appendChild(aim); + // svg.appendChild(aim); + arcLayer.prepend(aim); aim.addEventListener('click', e => { - e.target.classList.remove('active'); + // 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, '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}`); - svg.appendChild(firingArc); + arcLayer.prepend(firingArc); + // 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, - point = document.createElementNS(svgns, 'use'); - - point.setAttributeNS(null, 'href', `#point`); - point.setAttributeNS(null, 'x', `${cx}in`); - point.setAttributeNS(null, 'y', `${cy}in`); - point.dataset.x = x; - point.dataset.y = y; - - point.addEventListener('click', e => { - let selectedSoldier = document.querySelector('.soldier-record.selected'); - - if (selectedSoldier) { - let counter = document.createElementNS(svgns, 'circle'); - let text = document.createElementNS(svgns, 'text'); - - counter.setAttributeNS(null, 'cx', `${cx}in`); - counter.setAttributeNS(null, 'cy', `${cy}in`); - counter.setAttributeNS(null, 'r', '0.25in'); - counter.dataset.troopNumber = selectedSoldier.dataset.troopNumber; - counter.dataset.troopAllegiance = selectedSoldier.dataset.troopAllegiance; - counter.classList.add('counter'); - - text.setAttributeNS(null, 'text-anchor', 'middle'); - text.setAttributeNS(null, 'x', `${cx}in`); - text.setAttributeNS(null, 'y', `${cy + 0.25}in`); - text.dataset.troopNumber = selectedSoldier.dataset.troopNumber; - text.dataset.troopAllegiance = selectedSoldier.dataset.troopAllegiance; - text.textContent = `${selectedSoldier.dataset.troopNumber}`; - text.classList.add('counter'); - - document.querySelectorAll( - `.counter[data-troop-number="${selectedSoldier.dataset.troopNumber}"][data-troop-allegiance="${selectedSoldier.dataset.troopAllegiance}"]` - ).forEach(el => el.remove()); - - svg.appendChild(counter); - svg.appendChild(text); - } - }); - - svg.appendChild(point); -})); - 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 @@ -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 { |