Ensure correct card overlap on mobile by using actual rendered dimensions
This commit is contained in:
parent
5c8357f47b
commit
542b131cd8
75
pyramid.js
75
pyramid.js
@ -141,51 +141,47 @@
|
|||||||
function renderBoard() {
|
function renderBoard() {
|
||||||
if (!isActive) return;
|
if (!isActive) return;
|
||||||
|
|
||||||
const boardRect = gameBoard.getBoundingClientRect();
|
|
||||||
const layoutRect = pyramidLayout.getBoundingClientRect();
|
const layoutRect = pyramidLayout.getBoundingClientRect();
|
||||||
|
|
||||||
// If the board isn't visible yet or dimensions aren't ready, wait for the next frame
|
// If the board isn't visible yet or dimensions aren't ready, wait
|
||||||
if (boardRect.width === 0 || layoutRect.width === 0) {
|
if (layoutRect.width === 0) {
|
||||||
requestAnimationFrame(renderBoard);
|
requestAnimationFrame(renderBoard);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const rootStyle = getComputedStyle(document.documentElement);
|
// Use the first available card to get the REAL pixel width/height calculated by CSS
|
||||||
let cardWidth = parseFloat(rootStyle.getPropertyValue('--card-width'));
|
const firstCardId = Object.keys(cardElements)[0];
|
||||||
let horizontalGap = parseFloat(rootStyle.getPropertyValue('--gap'));
|
if (!firstCardId) return;
|
||||||
|
const sampleCard = cardElements[firstCardId];
|
||||||
|
const cardRect = sampleCard.getBoundingClientRect();
|
||||||
|
const cardWidth = cardRect.width;
|
||||||
|
const cardHeight = cardRect.height;
|
||||||
|
|
||||||
if (isNaN(cardWidth) || cardWidth === 0) cardWidth = 80;
|
// Calculate gap based on 1.5vw or fallback (matching style.css)
|
||||||
if (isNaN(horizontalGap)) horizontalGap = 10;
|
let horizontalGap = (window.innerWidth * 1.5) / 100;
|
||||||
|
if (window.innerWidth > 600) horizontalGap = (window.innerWidth * 1.2) / 100; // Desktop gap
|
||||||
const cardHeight = cardWidth * 1.4;
|
|
||||||
const rowOverlap = 0.45;
|
const verticalStep = cardHeight * 0.45; // Row overlap ratio
|
||||||
|
|
||||||
const boardTop = boardRect.top;
|
|
||||||
const boardLeft = boardRect.left;
|
|
||||||
|
|
||||||
// Position Pyramid Cards
|
// Position Pyramid Cards
|
||||||
let index = 0;
|
let index = 0;
|
||||||
for (let row = 0; row < 7; row++) {
|
for (let row = 0; row < 7; row++) {
|
||||||
// Calculate total width of this row to center it
|
|
||||||
const numCards = row + 1;
|
const numCards = row + 1;
|
||||||
const totalRowWidth = numCards * cardWidth + (numCards - 1) * horizontalGap;
|
const totalRowWidth = numCards * cardWidth + (numCards - 1) * horizontalGap;
|
||||||
const startX = (layoutRect.width - totalRowWidth) / 2;
|
const startX = (layoutRect.width - totalRowWidth) / 2;
|
||||||
const y = row * (cardHeight * rowOverlap);
|
const y = row * verticalStep;
|
||||||
|
|
||||||
for (let i = 0; i <= row; i++) {
|
for (let i = 0; i <= row; i++) {
|
||||||
const card = pyramid[index];
|
const card = pyramid[index];
|
||||||
if (card) {
|
if (card) {
|
||||||
const el = cardElements[card.id];
|
const el = cardElements[card.id];
|
||||||
// Absolute position relative to the gameBoard
|
// Position relative to the pyramid-layout container
|
||||||
const finalTop = y + (layoutRect.top - boardTop);
|
// Note: pyramid-layout has position: relative in pyramid.css
|
||||||
const finalLeft = startX + i * (cardWidth + horizontalGap) + (layoutRect.left - boardLeft);
|
el.style.top = `${y}px`;
|
||||||
|
el.style.left = `${startX + i * (cardWidth + horizontalGap)}px`;
|
||||||
el.style.top = `${finalTop}px`;
|
|
||||||
el.style.left = `${finalLeft}px`;
|
|
||||||
el.style.zIndex = 100 + index;
|
el.style.zIndex = 100 + index;
|
||||||
el.classList.add('is-flipped');
|
el.classList.add('is-flipped');
|
||||||
|
|
||||||
// Mark if it's currently playable for visual feedback
|
|
||||||
const exposed = isExposed(card.id);
|
const exposed = isExposed(card.id);
|
||||||
el.classList.toggle('is-exposed', exposed);
|
el.classList.toggle('is-exposed', exposed);
|
||||||
}
|
}
|
||||||
@ -193,41 +189,38 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Position Stock
|
// Position Stock, Waste, Discard (these are in a separate container at the bottom)
|
||||||
|
// We'll use a slightly different approach for these to ensure they stay in their piles
|
||||||
const sRect = stockEl.getBoundingClientRect();
|
const sRect = stockEl.getBoundingClientRect();
|
||||||
|
const wRect = wasteEl.getBoundingClientRect();
|
||||||
|
const dRect = discardEl.getBoundingClientRect();
|
||||||
|
const bRect = gameBoard.getBoundingClientRect();
|
||||||
|
|
||||||
stock.forEach((card, i) => {
|
stock.forEach((card, i) => {
|
||||||
const el = cardElements[card.id];
|
const el = cardElements[card.id];
|
||||||
el.style.top = `${sRect.top - boardTop + PILE_BORDER_WIDTH}px`;
|
el.style.top = `${sRect.top - bRect.top + PILE_BORDER_WIDTH}px`;
|
||||||
el.style.left = `${sRect.left - boardLeft + PILE_BORDER_WIDTH}px`;
|
el.style.left = `${sRect.left - bRect.left + PILE_BORDER_WIDTH}px`;
|
||||||
el.style.zIndex = 10 + i;
|
el.style.zIndex = 10 + i;
|
||||||
el.classList.remove('is-flipped');
|
el.classList.remove('is-flipped', 'is-selected', 'is-exposed');
|
||||||
el.classList.remove('is-selected');
|
|
||||||
el.classList.remove('is-exposed');
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// Position Waste
|
|
||||||
const wRect = wasteEl.getBoundingClientRect();
|
|
||||||
waste.forEach((card, i) => {
|
waste.forEach((card, i) => {
|
||||||
const el = cardElements[card.id];
|
const el = cardElements[card.id];
|
||||||
const isTop = (i === waste.length - 1);
|
const isTop = (i === waste.length - 1);
|
||||||
el.style.top = `${wRect.top - boardTop + PILE_BORDER_WIDTH}px`;
|
el.style.top = `${wRect.top - bRect.top + PILE_BORDER_WIDTH}px`;
|
||||||
el.style.left = `${wRect.left - boardLeft + PILE_BORDER_WIDTH}px`;
|
el.style.left = `${wRect.left - bRect.left + PILE_BORDER_WIDTH}px`;
|
||||||
// Base z-index for waste is 500, +i to stack correctly
|
el.style.zIndex = 500 + i;
|
||||||
el.style.zIndex = 500 + i;
|
|
||||||
el.classList.add('is-flipped');
|
el.classList.add('is-flipped');
|
||||||
el.classList.toggle('is-exposed', isTop);
|
el.classList.toggle('is-exposed', isTop);
|
||||||
});
|
});
|
||||||
|
|
||||||
// Position Discard
|
|
||||||
const dRect = discardEl.getBoundingClientRect();
|
|
||||||
discard.forEach((card, i) => {
|
discard.forEach((card, i) => {
|
||||||
const el = cardElements[card.id];
|
const el = cardElements[card.id];
|
||||||
el.style.top = `${dRect.top - boardTop + PILE_BORDER_WIDTH}px`;
|
el.style.top = `${dRect.top - bRect.top + PILE_BORDER_WIDTH}px`;
|
||||||
el.style.left = `${dRect.left - boardLeft + PILE_BORDER_WIDTH}px`;
|
el.style.left = `${dRect.left - bRect.left + PILE_BORDER_WIDTH}px`;
|
||||||
el.style.zIndex = 10 + i;
|
el.style.zIndex = 10 + i;
|
||||||
el.classList.add('is-flipped');
|
el.classList.add('is-flipped');
|
||||||
el.classList.remove('is-selected');
|
el.classList.remove('is-selected', 'is-exposed');
|
||||||
el.classList.remove('is-exposed');
|
|
||||||
});
|
});
|
||||||
|
|
||||||
checkWin();
|
checkWin();
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user