WIP: 3-state css?

This commit is contained in:
Catalin Mititiuc 2024-03-23 13:48:10 -07:00
parent 17e6864d69
commit 51f2656ad9
3 changed files with 179 additions and 80 deletions

View File

@ -5,7 +5,7 @@
<link rel="stylesheet" href="style.css">
</head>
<body>
<svg viewbox="-100 -100 3450 2400" xmlns="http://www.w3.org/2000/svg" stroke-width="20">
<svg viewbox="-100 -100 3450 2400" xmlns="http://www.w3.org/2000/svg">
<defs>
<pattern id="inch-mark" x="0" y="0" width="2in" height="2in" patternUnits="userSpaceOnUse">
<rect x="0" y="0" width="1in" height="2in" fill="black" />
@ -21,18 +21,19 @@
<!-- <circle id="point" cx="0" cy="0" r="0.07in" /> -->
<circle id="point" cx="0" cy="0" r="0.5in" />
<polygon id="hex" fill="url('#gradient')" points="0,121.32 184.152,15.544 368.312,121.32 368.312,332.864 184.152,438.64 0,332.864 "/>
<polygon id="hex" points="0,121.32 184.152,15.544 368.312,121.32 368.312,332.864 184.152,438.64 0,332.864 "/>
<text id="asterisk" x="-0.06in" y="0.22in">*</text>
</defs>
<line x1="0" y1="-0.25in" x2="34in" y2="-0.25in" stroke="url(#inch-mark)" />
<line x1="-0.25in" y1="0" x2="-0.25in" y2="23in" stroke="url(#vert)" />
<line class="ruler" x1="0" y1="-0.25in" x2="34in" y2="-0.25in" stroke="url(#inch-mark)" />
<line class="ruler" 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>
<div>
Set firing arc:
<button type="button" class="set-firing-arc" data-size="small">
<img src="firing_arc_small.png" height="12" /> 2 MP
@ -43,6 +44,7 @@
<button type="button" class="set-firing-arc" data-size="large">
<img src="firing_arc_large.png" height="12" /> 6 MP
</button>
</div>
<div id="record-sheet">
<div>
@ -53,19 +55,60 @@
17th Kestral Mechanized Infantry -->
</p>
<div class="soldier-record" data-troop-number="1" data-troop-allegiance="davion">
Troop Number: 1<br>
Primary Weapon Type: Rifle, Damage: 4L, Short: 1-27, Long: 28-75<br>
HG: 4
<!-- <p class="damage">
<span>
<label>
<input type="checkbox" /> Bruise
</label>
<label>
<input type="checkbox" /> Lethal
</label>
</span>
<span>
<label>
<input type="checkbox" />
Bruise
</label>
<label>
<input type="checkbox" />
Lethal
</label>
</span>
</p> -->
<p class="damage">
<span>
<!-- <label>
</label>
<label>
</label>
<label>
</label> -->
<input type="radio" name="d1">
<!-- <label>label1</label> -->
<input type="radio" name="d1">
<!-- <label>label2</label> -->
<input type="radio" name="d1" checked>
<!-- <label>label3</label> -->
</span>
</p>
<p><span>Troop Number</span> 1</p>
<p><span>Primary Weapon Type</span> Rifle</p>
<ul>
<li><span>Damage</span> 4L</li>
<li><span>Short</span> 1-27</li>
<li><span>Long</span> 28-75</li>
</ul>
<p><span>Hand Grenades</span> 4</p>
</div>
<div class="soldier-record" data-troop-number="2" data-troop-allegiance="davion">
Troop Number: 2<br>
Primary Weapon Type: SMG, Damage: 3L, Short: 1-15, Long: 16-25<br>
HG: 4
Hand Grenades: 4
</div>
<div class="soldier-record" data-troop-number="3" data-troop-allegiance="davion">
Troop Number: 3<br>
Primary Weapon Type: Blazer, Damage: 4L, Short: 1-17, Long: 18-105<br>
HG: 4
Hand Grenades: 4
</div>
</div>
<div>

View File

@ -10,6 +10,21 @@ function radToDeg(radians) {
return radians * 180 / Math.PI;
}
function calculateAngle(xDiff, yDiff) {
yDiff = -yDiff;
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;
}
return angle;
}
function edgePoint(x1, y1, x2, y2, maxX, maxY) {
let pointCoords,
xDiff = x2 - x1,
@ -100,11 +115,31 @@ POINTS.forEach((row, index) => row.forEach(([x, y]) => {
`.counter[data-troop-number="${selectedSoldier.dataset.troopNumber}"][data-troop-allegiance="${selectedSoldier.dataset.troopAllegiance}"]`
).forEach(el => el.remove());
counter.addEventListener('click', e => {
document.querySelectorAll(
`.counter[data-troop-number="${selectedSoldier.dataset.troopNumber}"][data-troop-allegiance="${selectedSoldier.dataset.troopAllegiance}"]`
).forEach(el => el.remove());
document.querySelectorAll(
`.firing-arc[data-troop-number="${selectedSoldier.dataset.troopNumber}"][data-troop-allegiance="${selectedSoldier.dataset.troopAllegiance}"]`
).forEach(el => el.remove());
});
svg.appendChild(counter);
svg.appendChild(text);
}
});
point.addEventListener('mouseover', e => {
let selectedSoldier = document.querySelector('.soldier-record.selected');
if (selectedSoldier) {
e.target.classList.add('active');
}
});
point.addEventListener('mouseout', e => e.target.removeAttribute('class'));
svg.appendChild(point);
}));
@ -129,16 +164,8 @@ map.addEventListener('mousemove', e => {
];
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;
}
let yDiff = y2px - y1px;
let angle = calculateAngle(xDiff, yDiff);
console.log('angle:', `${toFixed(radToDeg(angle))}\u00B0`, `${angle}rad`);
@ -167,9 +194,6 @@ map.addEventListener('mousemove', e => {
let points;
xDiff = x2px - x1px;
yDiff = y2px - y1px;
if (oppositeEdgeConditions.some(e => e)) {
let cornerPoints;
@ -186,7 +210,6 @@ map.addEventListener('mousemove', e => {
cornerPoints = [[0, 0], [maxXpx, 0]];
}
// points = `${newX1},${newY1} ${x1px},${y1px} ${newX2},${newY2} ${cornerPoints[0]} ${cornerPoints[1]}`;
} else if (xDiff < 0 && yDiff > 0) {
if ((newY1 == 0 && newY2 == maxYpx) || (newY1 == maxYpx && newY2 == 0)) {
cornerPoints = [[0, maxYpx], [0, 0]];
@ -194,7 +217,6 @@ map.addEventListener('mousemove', e => {
cornerPoints = [[maxXpx, maxYpx], [0, maxYpx]];
}
// points = `${newX1},${newY1} ${x1px},${y1px} ${newX2},${newY2} ${cornerPoints[0]} ${cornerPoints[1]}`;
} else {
if ((newY1 == 0 && newY2 == maxYpx) || (newY1 == maxYpx && newY2 == 0)) {
cornerPoints = [[0, maxYpx], [0, 0]];
@ -202,40 +224,12 @@ map.addEventListener('mousemove', e => {
cornerPoints = [[0, 0], [maxXpx, 0]];
}
// points = `${newX1},${newY1} ${x1px},${y1px} ${newX2},${newY2} ${cornerPoints[0]} ${cornerPoints[1]}`;
}
points = `${x1px},${y1px} ${newX1},${newY1} ${cornerPoints[1]} ${cornerPoints[0]} ${newX2},${newY2}`;
} else if (orthogonalEdgeConditions.some(e => e)) {
let cornerPoint;
let cornerPoints = [];
// console.log('x1px', x1px, 'y1px', y1px, 'x2px', x2px, 'y2px', y2px);
console.log('xDiff', xDiff, 'yDiff', yDiff);
if (newX1 == 0 || newX1 == maxXpx) {
cornerPoint = [newX1, newY2];
} else {
cornerPoint = [newX2, newY1];
}
if (newX1 == 0 || newX1 == maxXpx) {
console.log(newX1, newY1, 'nearest corner point', newX1, yDiff > 0 ? maxYpx : 0);
} else {
console.log(newX1, newY1, 'nearest corner point', xDiff > 0 ? maxXpx : 0, newY1);
}
if (newX2 == 0 || newX2 == maxXpx) {
console.log(newX2, newY2, 'nearest corner point', newX2, yDiff > 0 ? maxYpx : 0);
} else {
console.log(newX2, newY2, 'nearest corner point', xDiff > 0 ? maxXpx : 0, newY2);
}
let cp1, cp2;
console.log('x1px, y1px', x1px, y1px);
console.log('newX1, newY1', newX1, newY1);
console.log('newX2, newY2', newX2, newY2);
if (newX1 == 0 || newX1 == maxXpx) {
cp1 = [newX1, yDiff > 0 ? maxYpx : 0];
} else {
@ -248,8 +242,6 @@ map.addEventListener('mousemove', e => {
cp2 = [xDiff > 0 ? maxXpx : 0, newY2];
}
console.log('cp1', cp1, 'cp2', cp2);
if (cp1[0] == cp2[0] && cp1[1] == cp2[1]) {
cornerPoints.push(cp1);
} else {
@ -258,13 +250,8 @@ map.addEventListener('mousemove', e => {
cornerPoints.push(cp2);
}
console.log(`${cornerPoints.join(' ')}`);
// points = `${newX1},${newY1} ${x1px},${y1px} ${newX2},${newY2}`;
points = `${x1px},${y1px} ${newX1},${newY1} ${cornerPoints.join(' ')} ${newX2},${newY2}`;
console.log('points', points);
} else {
points = `${newX1},${newY1} ${x1px},${y1px} ${newX2},${newY2}`;
points = `${x1px},${y1px} ${newX1},${newY1} ${newX2},${newY2}`;
}
@ -274,13 +261,15 @@ map.addEventListener('mousemove', e => {
document.querySelectorAll('.soldier-record').forEach(el =>
el.addEventListener('click', e => {
if (e.target.classList.contains('selected')) {
e.target.classList.remove('selected');
if (e.target.tagName !== 'INPUT' && e.target.tagName !== 'LABEL') {
if (el.classList.contains('selected')) {
el.classList.remove('selected');
} else {
document.querySelectorAll('.soldier-record.selected').forEach(el =>
el.classList.remove('selected')
);
e.target.classList.add('selected');
el.classList.add('selected');
}
}
})
);
@ -306,7 +295,7 @@ document.querySelectorAll('.set-firing-arc').forEach(el => el.addEventListener('
let firingArcPlacementListener = e => {
document.querySelectorAll('.firing-arc.active').forEach(el => el.classList.remove('active'));
document.querySelector('circle#point').style.pointerEvents = 'auto';
document.querySelector('circle#point').style.display = '';
map.removeEventListener('click', firingArcPlacementListener);
};
@ -323,7 +312,7 @@ document.querySelectorAll('.set-firing-arc').forEach(el => el.addEventListener('
arcLayer.prepend(firingArc);
document.querySelector('circle#point').style.pointerEvents = 'none';
document.querySelector('circle#point').style.display = 'none';
}
}
}));

View File

@ -8,6 +8,16 @@ body {
circle#point {
fill: transparent;
stroke: black;
stroke-width: 2px;
}
use[href="#point"] {
opacity: 0;
}
use[href="#point"].active {
opacity: 1;
}
circle.counter[data-troop-allegiance="liao"] {
@ -25,6 +35,8 @@ text.counter {
fill: white;
stroke-width: 2px;
font-family: sans-serif;
cursor: default;
pointer-events: none;
}
rect#map {
@ -46,6 +58,61 @@ line.firing-arc {
opacity: 0.1;
}
line.ruler {
stroke-width: 0.25in;
}
.soldier-record span {
font-size: smaller;
font-family: monospace;
margin-right: 1em;
}
.soldier-record ul {
margin: 0;
padding: 0;
}
.soldier-record ul li {
display: inline;
margin-left: 1em;
}
.soldier-record p {
margin: 0;
}
.soldier-record p.damage span {
display: inline-block;
}
.soldier-record p.damage span input {
display: block;
}
input {
border: none;
outline: 2px solid deeppink;
}
input:first-of-type {
outline: none;
}
input:checked {
border: none;
outline: 2px solid deeppink;
}
input:has(+ input:checked) {
border: none;
outline: 2px solid deeppink;
}
input[type="radio"]:checked + input {
outline: none;
}
image#img1 {
transform: scale(3.41) rotate(-0.15deg);
/* opacity: 0.33; */
@ -84,7 +151,7 @@ image#img2 {
padding: 0 2px;
}
#record-sheet > div div {
#record-sheet > div > div {
border: 1px solid black;
margin: 2px 0;
padding: 2px;