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 {