Web Dev Solutions

Catalin Mititiuc

aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCatalin Mititiuc <webdevcat@proton.me>2024-08-05 15:29:45 -0700
committerCatalin Mititiuc <webdevcat@proton.me>2024-08-05 15:29:58 -0700
commitf35d716bd38d03285fa511f6794af5d93e88f4dc (patch)
treec9b10a7ff8749a2cdb51a58ba8731e965986e18c
parent34ed6e2a9c0ef9d4354454394c52e412d8c34d51 (diff)
WIP: smoothe squad view
-rw-r--r--public/assets/css/style.css45
-rw-r--r--public/assets/images/map4.svg88
-rw-r--r--public/index.html58
-rw-r--r--src/index.js35
-rw-r--r--src/modules/gameboard.js16
-rw-r--r--src/modules/record_sheet.js95
6 files changed, 232 insertions, 105 deletions
diff --git a/public/assets/css/style.css b/public/assets/css/style.css
index f3dbc4d..bd90a4e 100644
--- a/public/assets/css/style.css
+++ b/public/assets/css/style.css
@@ -271,26 +271,35 @@ div#content {
overflow-x: hidden;
}
-.soldier-record {
- display: none;
-}
-
-#record-sheet [data-view-squad-number="1"].records .soldier-record[data-squad="1"] {
- display: block;
-}
-
-#record-sheet [data-view-squad-number="2"].records .soldier-record[data-squad="2"] {
- display: block;
+#record-sheet .records [class^="squad-"] {
+ transition: transform 0.125s;
}
-
-#record-sheet [data-view-squad-number="3"].records .soldier-record[data-squad="3"] {
- display: block;
-}
-
-#record-sheet [data-view-squad-number="4"].records .soldier-record[data-squad="4"] {
- display: block;
-}
+#record-sheet .records > :not(:first-child) {
+ display: none;
+ transform: translateX(100%);
+}
+
+/*.soldier-record {*/
+/* display: none;*/
+/*}*/
+
+/*#record-sheet [data-view-squad-number="1"].records .soldier-record[data-squad="1"] {*/
+/* display: block;*/
+/*}*/
+/**/
+/*#record-sheet [data-view-squad-number="2"].records .soldier-record[data-squad="2"] {*/
+/* display: block;*/
+/*}*/
+/**/
+/**/
+/*#record-sheet [data-view-squad-number="3"].records .soldier-record[data-squad="3"] {*/
+/* display: block;*/
+/*}*/
+/**/
+/*#record-sheet [data-view-squad-number="4"].records .soldier-record[data-squad="4"] {*/
+/* display: block;*/
+/*}*/
#record-sheet .name {
text-transform: capitalize;
diff --git a/public/assets/images/map4.svg b/public/assets/images/map4.svg
index 2603ed5..0113404 100644
--- a/public/assets/images/map4.svg
+++ b/public/assets/images/map4.svg
@@ -4,7 +4,6 @@
<g id="building1" class="building">
<g class="footprint">
<g data-q="0" data-r="0" data-s="0" data-left="1" data-top="3" data-right="2" data-bottom="4" data-offset="left" />
- <g data-q="0" data-r="0" data-s="0" data-left="1" data-top="3" data-right="4" data-bottom="4" data-offset="left" />
</g>
<g class="structure">
@@ -25,7 +24,7 @@
<rect id="cabinet" x="-2.5" y="-4.75" width="5" height="9.5" />
<g id="mapsheet" class="mapsheet">
- <g class="building1" data-q="1" data-r="-2" data-s="1">
+ <g class="building1" data-q="3" data-r="-5" data-s="2">
<use href="#building1"/>
<g class="furniture">
<use href="#couch" transform="rotate(90,10.34,-27.66)" />
@@ -44,7 +43,6 @@
</g>
<use href="counters.svg#mech-template"/>
<use href="counters.svg#fallen-mech-template"/>
- <use href="counters.svg#standing-mech-template"/>
<use href="counters.svg#vehicle-template"/>
</defs>
@@ -57,22 +55,82 @@
<g class="start-locations" data-attacker-name="liao" data-defender-name="davion">
<g data-edge="north" style="--i: -2">
- <g data-x="13">
- <g class="counter" data-allegiance="attacker" data-number="1">
- <use class="primary-weapon" href="counters.svg#blazer"/>
- <use class="troop-number" href="counters.svg#number-1"/>
- <use class="squad-number" href="counters.svg#number-1"/>
- </g>
+ <g class="counter" data-allegiance="attacker" data-number="1" data-squad="1">
+ <use class="primary-weapon" href="counters.svg#blazer"/>
+ <use class="troop-number" href="counters.svg#number-1"/>
+ <use class="squad-number" href="counters.svg#number-1"/>
+ </g>
+ <g class="counter" data-allegiance="attacker" data-number="2" data-squad="1">
+ <use class="primary-weapon" href="counters.svg#hsplaser"/>
+ <use class="troop-number" href="counters.svg#number-2"/>
+ <use class="squad-number" href="counters.svg#number-1"/>
+ </g>
+
+ <g class="counter" data-allegiance="attacker" data-number="1" data-squad="2">
+ <use class="primary-weapon" href="counters.svg#smg"/>
+ <use class="troop-number" href="counters.svg#number-1"/>
+ <use class="squad-number" href="counters.svg#number-2"/>
+ </g>
+ <g class="counter" data-allegiance="attacker" data-number="2" data-squad="2">
+ <use class="primary-weapon" href="counters.svg#smg"/>
+ <use class="troop-number" href="counters.svg#number-2"/>
+ <use class="squad-number" href="counters.svg#number-2"/>
+ </g>
+ <g class="counter" data-allegiance="attacker" data-number="3" data-squad="2">
+ <use class="primary-weapon" href="counters.svg#smg"/>
+ <use class="troop-number" href="counters.svg#number-3"/>
+ <use class="squad-number" href="counters.svg#number-2"/>
+ </g>
+
+ <g class="counter" data-allegiance="attacker" data-number="1" data-squad="3">
+ <use class="primary-weapon" href="counters.svg#rifle"/>
+ <use class="troop-number" href="counters.svg#number-1"/>
+ <use class="squad-number" href="counters.svg#number-3"/>
+ </g>
+
+ <g class="counter" data-allegiance="attacker" data-number="1" data-squad="4">
+ <use class="primary-weapon" href="counters.svg#rifle"/>
+ <use class="troop-number" href="counters.svg#number-1"/>
+ <use class="squad-number" href="counters.svg#number-4"/>
+ </g>
+ <g class="counter" data-allegiance="attacker" data-number="2" data-squad="4">
+ <use class="primary-weapon" href="counters.svg#rifle"/>
+ <use class="troop-number" href="counters.svg#number-2"/>
+ <use class="squad-number" href="counters.svg#number-4"/>
+ </g>
+
+ <g class="counter" data-allegiance="attacker" data-number="1" data-squad="5">
+ <use class="primary-weapon" href="counters.svg#rifle"/>
+ <use class="troop-number" href="counters.svg#number-1"/>
+ <use class="squad-number" href="counters.svg#number-5"/>
+ </g>
+ <g class="counter" data-allegiance="attacker" data-number="2" data-squad="5">
+ <use class="primary-weapon" href="counters.svg#rifle"/>
+ <use class="troop-number" href="counters.svg#number-2"/>
+ <use class="squad-number" href="counters.svg#number-5"/>
</g>
</g>
<g data-edge="south" style="--i: 53">
- <g data-x="13">
- <g class="counter" data-allegiance="defender" data-number="1">
- <use class="primary-weapon" href="counters.svg#blazer"/>
- <use class="troop-number" href="counters.svg#number-1"/>
- <use class="squad-number" href="counters.svg#number-1"/>
- </g>
+ <g class="counter" data-allegiance="defender" data-number="1" data-squad="1">
+ <use class="primary-weapon" href="counters.svg#blazer"/>
+ <use class="troop-number" href="counters.svg#number-1"/>
+ <use class="squad-number" href="counters.svg#number-1"/>
+ </g>
+ <!--<g class="counter" data-allegiance="defender" data-number="2" data-squad="1">-->
+ <!-- <use class="primary-weapon" href="counters.svg#hsplaser"/>-->
+ <!-- <use class="troop-number" href="counters.svg#number-2"/>-->
+ <!-- <use class="squad-number" href="counters.svg#number-1"/>-->
+ <!--</g>-->
+ <g class="counter" data-allegiance="defender" data-number="1" data-squad="2">
+ <use class="primary-weapon" href="counters.svg#smg"/>
+ <use class="troop-number" href="counters.svg#number-1"/>
+ <use class="squad-number" href="counters.svg#number-2"/>
+ </g>
+ <g class="counter" data-allegiance="defender" data-number="2" data-squad="2">
+ <use class="primary-weapon" href="counters.svg#smg"/>
+ <use class="troop-number" href="counters.svg#number-2"/>
+ <use class="squad-number" href="counters.svg#number-2"/>
</g>
</g>
</g>
diff --git a/public/index.html b/public/index.html
index 51c4fcf..c3a1c75 100644
--- a/public/index.html
+++ b/public/index.html
@@ -263,7 +263,7 @@
<div id="record-sheet">
<div id="attacker-record" data-allegiance="attacker">
<!-- <img class="logo" src="logo-davion.png" /> -->
- <div>
+ <div class="records-header">
<div><strong class="name">Attacker</strong></div>
<div><button type="button" class="end-move" data-allegiance="attacker">
End Movement
@@ -271,30 +271,14 @@
<div><button type="button" class="end-turn" data-allegiance="defender">
End Turn
</button></div>
- <div class="squad-number selected" data-number="1">
+ <div><button type="button" class="view-squad" value="previous">&lt;</button></div>
+ <div class="squad-number">
<svg viewBox="-5 -5 10 10" xmlns="http://www.w3.org/2000/svg">
<circle id="counter-base" r="5" cx="0" cy="0"></circle>
<text>1</text>
</svg>
</div>
- <div class="squad-number" data-number="2">
- <svg viewBox="-5 -5 10 10" xmlns="http://www.w3.org/2000/svg">
- <circle id="counter-base" r="5" cx="0" cy="0"></circle>
- <text>2</text>
- </svg>
- </div>
- <div class="squad-number" data-number="3">
- <svg viewBox="-5 -5 10 10" xmlns="http://www.w3.org/2000/svg">
- <circle id="counter-base" r="5" cx="0" cy="0"></circle>
- <text>3</text>
- </svg>
- </div>
- <div class="squad-number" data-number="4">
- <svg viewBox="-5 -5 10 10" xmlns="http://www.w3.org/2000/svg">
- <circle id="counter-base" r="5" cx="0" cy="0"></circle>
- <text>4</text>
- </svg>
- </div>
+ <div><button type="button" class="view-squad" value="next">&gt;</button></div>
<!-- 1st Squad, 3rd Platoon, Bravo Company, 2nd Battalion<br>
17th Kestral Mechanized Infantry -->
</div>
@@ -302,7 +286,7 @@
</div>
<div id="defender-record" data-allegiance="defender">
<!-- <img class="logo" src="logo-liao.png" /> -->
- <div>
+ <div class="records-header">
<div><strong class="name">Defender</strong></div>
<div><button type="button" class="end-move" data-allegiance="defender">
End Movement
@@ -310,30 +294,16 @@
<div><button type="button" class="end-turn" data-allegiance="attacker">
End Turn
</button></div>
- <div class="squad-number selected" data-number="1">
- <svg viewBox="-5 -5 10 10" xmlns="http://www.w3.org/2000/svg">
- <circle id="counter-base" r="5" cx="0" cy="0"></circle>
- <text>1</text>
- </svg>
- </div>
- <div class="squad-number" data-number="2">
- <svg viewBox="-5 -5 10 10" xmlns="http://www.w3.org/2000/svg">
- <circle id="counter-base" r="5" cx="0" cy="0"></circle>
- <text>2</text>
- </svg>
- </div>
- <div class="squad-number" data-number="3">
- <svg viewBox="-5 -5 10 10" xmlns="http://www.w3.org/2000/svg">
- <circle id="counter-base" r="5" cx="0" cy="0"></circle>
- <text>3</text>
- </svg>
- </div>
- <div class="squad-number" data-number="4">
- <svg viewBox="-5 -5 10 10" xmlns="http://www.w3.org/2000/svg">
- <circle id="counter-base" r="5" cx="0" cy="0"></circle>
- <text>4</text>
- </svg>
+ <div><button type="button" class="view-squad" value="previous">&lt;</button></div>
+ <div>
+ <div class="squad-number">
+ <svg viewBox="-5 -5 10 10" xmlns="http://www.w3.org/2000/svg">
+ <circle id="counter-base" r="5" cx="0" cy="0"></circle>
+ <text>1</text>
+ </svg>
+ </div>
</div>
+ <div><button type="button" class="view-squad" value="next">&gt;</button></div>
<!-- 2nd Squad, 1st Platoon, 3rd Company, 2nd Battalion<br>
Aldebaran Home Guard -->
</div>
diff --git a/src/index.js b/src/index.js
index e6a8802..62c1128 100644
--- a/src/index.js
+++ b/src/index.js
@@ -279,6 +279,41 @@ document.querySelectorAll('#record-sheet [data-allegiance]').forEach(el => {
);
});
+document.querySelectorAll('.view-squad').forEach(b => b.addEventListener('click', e => {
+ const currentSquad = b.closest('.records-header').querySelector('.squad-number text');
+ const currentSquadContainer = b.closest('[id$="-record"]').querySelector(`.records > .squad-${currentSquad.textContent}`);
+
+ if (b.value === 'next') {
+ //const toSquad = currentSquadContainer.nextElementSibling || b.closest('[id$="-record"]').querySelector('.records > :first-child');
+ const toSquad = currentSquadContainer.nextElementSibling;
+ if (!toSquad) return;
+ currentSquad.textContent = +toSquad.className.match(/\d+/);
+
+ currentSquadContainer.addEventListener('transitionend', e => {
+ console.log('transitionend', 'current', currentSquadContainer, 'next', toSquad);
+ currentSquadContainer.style.display = 'none';
+ toSquad.style.display = 'block';
+ b.closest('[id$="-record"]').querySelector('.records').scrollTo(0, 0);
+ toSquad.style.transform = 'translateX(0)';
+ }, { once: true });
+
+ currentSquadContainer.style.transform = 'translateX(-100%)';
+ } else {
+ const toSquad = currentSquadContainer.previousElementSibling;
+ if (!toSquad) return;
+ currentSquad.textContent = +toSquad.className.match(/\d+/);
+
+ currentSquadContainer.addEventListener('transitionend', e => {
+ currentSquadContainer.style.display = 'none';
+ toSquad.style.display = 'block';
+ b.closest('[id$="-record"]').querySelector('.records').scrollTo(0, 0);
+ toSquad.style.transform = 'translateX(0)';
+ }, { once: true });
+
+ currentSquadContainer.style.transform = 'translateX(100%)';
+ }
+}));
+
contentVisToggleEl.addEventListener('input', toggleContentVis);
contentVisToggleEl.checked = (localStorage.getItem('content-visibility') !== 'false');
toggleContentVis();
diff --git a/src/modules/gameboard.js b/src/modules/gameboard.js
index 74e5582..8cb6af1 100644
--- a/src/modules/gameboard.js
+++ b/src/modules/gameboard.js
@@ -378,10 +378,18 @@ export function start(el) {
//frontmost.append(trooper2);
//cell2.classList.add('hover');
//
- //const cell = getCell(0, 0, 0, 0);
- //const attacker = { dataset: { allegiance: 'attacker', number: 1, squad: 1 }};
- //const trooper = soldier.createCounter(attacker, 'blazer');
- //soldier.place(svg, trooper2, cell2);
+
+ soldier.place(
+ svg,
+ soldier.createCounter({ dataset: { allegiance: 'attacker', number: 2, squad: 1 }}, 'hsplaser'),
+ getCell(-2, 3, -1, 0)
+ );
+
+ soldier.place(
+ svg,
+ soldier.createCounter({ dataset: { allegiance: 'attacker', number: 2, squad: 5 }}, 'rifle'),
+ getCell(-3, 3, 0, 0)
+ );
// Add some counters in an unoccupied cell
//const countersCell = getCell(-1, 1, 0, 0);
diff --git a/src/modules/record_sheet.js b/src/modules/record_sheet.js
index 01a9051..824668e 100644
--- a/src/modules/record_sheet.js
+++ b/src/modules/record_sheet.js
@@ -38,12 +38,6 @@ const weapons = {
shortRange: '1-44',
longRange: '45-108'
},
- lmg: {
- name: 'Light MG',
- damage: '5L',
- shortRange: '1-30',
- longRange: '31-84'
- },
gl: {
name: 'SMG w/Grenade Launcher',
damage: '4/2/1 L',
@@ -52,8 +46,6 @@ const weapons = {
}
}
-const cacheBuster = Array(20).fill(null).map(() => getRandomIntInclusive(0, 9)).join('');
-
function createIcon(number) {
const [icon, use, text] = ['svg', 'use', 'text'].map(t => document.createElementNS(svgns, t));
@@ -172,16 +164,18 @@ function createRecord(unit) {
}
function createRecords(units) {
- const grouped = Array.from(units).reduce((acc, unit) => {
- acc[unit.dataset.allegiance]?.push(unit) || (acc[unit.dataset.allegiance] = [unit]);
- return acc;
- }, {});
+ return Array.from(units).reduce((acc, unit) => {
+ const record = createRecord(unit),
+ { allegiance, squad } = unit.dataset;
- for (const al in grouped) {
- grouped[al] = grouped[al].map(createRecord);
- }
+ if (acc[allegiance]) {
+ acc[allegiance][squad]?.push(record) || (acc[allegiance][squad] = [record])
+ } else {
+ acc[allegiance] = { [squad]: [record] }
+ }
- return grouped;
+ return acc;
+ }, {});
}
function getRecord({ dataset: { allegiance: al, number: n, squad: s }}) {
@@ -199,7 +193,12 @@ function deselect() {
}
function clear() {
- document.querySelectorAll('#record-sheet .soldier-record').forEach(el => el.remove());
+ document.querySelectorAll('#record-sheet > *').forEach(el => {
+ //el.querySelectorAll('.squad-number').forEach(sn => sn.remove());
+ const records = el.querySelector('.records');
+ records.dataset.viewSquadNumber = 1;
+ [...records.children].forEach(c => c.remove());
+ });
//document.querySelector('#attacker-record .name').textContent = 'attacker';
//document.querySelector('#defender-record .name').textContent = 'defender';
}
@@ -212,8 +211,52 @@ function select(data) {
if (isSelected || !data) return;
- record.classList.add('selected');
- record.scrollIntoView({ behavior: 'smooth' });
+ const currentSquadView = document.querySelector(`#record-sheet #${record.dataset.allegiance}-record .records-header .squad-number text`);
+ const records = document.querySelector(`#record-sheet #${record.dataset.allegiance}-record .records`);
+ const target = records.querySelector(`.squad-${record.dataset.squad}`);
+ const currentSquad = records.querySelector(`.squad-${currentSquadView.textContent}`);
+
+ let direction;
+ let next = prev = currentSquad;
+
+ while (!direction && (next || prev)) {
+ next = next?.nextElementSibling;
+ prev = prev?.previousElementSibling;
+ if (next === target) direction = 'next';
+ else if (prev === target) direction = 'previous';
+ }
+
+ function showSquad(current, target, direction) {
+ current.addEventListener('transitionend', e => {
+ const toSquad = current[`${direction}ElementSibling`];
+ currentSquadView.textContent = +toSquad.className.match(/\d+/);
+ current.style.display = 'none';
+
+ // There needs to be a delay between making it visible and the
+ // transformation. ScrollTo seems to create enough delay.
+ toSquad.style.display = 'block';
+ records.scrollTo(0, 0);
+ if (toSquad[`${direction}ElementSibling`] && toSquad !== target) {
+ showSquad(toSquad, target, direction);
+ } else {
+ toSquad.style.transform = 'translateX(0)';
+
+ toSquad.addEventListener('transitionend', e => {
+ record.classList.add('selected');
+ record.scrollIntoView({ behavior: 'smooth' });
+ }, { once: true });
+ }
+ }, { once: true });
+
+ current.style.transform = `translateX(${direction === 'next' ? '-' : ''}100%)`;
+ }
+
+ if (currentSquad !== target)
+ showSquad(currentSquad, target, direction);
+ else {
+ record.classList.add('selected');
+ record.scrollIntoView({ behavior: 'smooth' });
+ }
}
function endMove() {
@@ -254,12 +297,16 @@ export function start(startLoc, units) {
for (const affiliation in forces) {
const container = document.querySelector(`#${affiliation}-record`);
const records = container.querySelector('.records');
- // const name = startLoc?.dataset[`${affiliation}Name`];
+ const viewSquadIndicator = container.querySelector('.squad-number svg text');
+
+ for (const squadNumber in forces[affiliation]) {
+ const squadContainer = document.createElement('div');
+ squadContainer.classList.add(`squad-${squadNumber}`);
+ forces[affiliation][squadNumber].forEach(r => squadContainer.append(r));
+ records.append(squadContainer);
+ }
- // if (name) {
- // container.querySelector('.name').textContent = name;
- // }
- forces[affiliation].forEach(r => records.appendChild(r));
+ viewSquadIndicator.textContent = Object.keys(forces[affiliation])[0];
}
document.querySelectorAll('.soldier-record').forEach(el =>