diff options
Diffstat (limited to 'public/app.js')
| -rw-r--r-- | public/app.js | 63 |
1 files changed, 49 insertions, 14 deletions
diff --git a/public/app.js b/public/app.js index 6411bf7..181c583 100644 --- a/public/app.js +++ b/public/app.js @@ -74,38 +74,69 @@ function baseRect(w, h, from, dir) { return { x: from.x - w - GAP, y: from.y + (from.h - h) / 2, w, h } } +function slackScore(rect, slide) { + let lo = -Infinity + let hi = Infinity + for (const t of tiles.values()) { + const r = t.rect + if (slide === "x") { + if (r.y + r.h <= rect.y - GAP || rect.y + rect.h <= r.y - GAP) continue + if (r.x + r.w <= rect.x) lo = Math.max(lo, r.x + r.w) + else if (r.x >= rect.x + rect.w) hi = Math.min(hi, r.x) + } else { + if (r.x + r.w <= rect.x - GAP || rect.x + rect.w <= r.x - GAP) continue + if (r.y + r.h <= rect.y) lo = Math.max(lo, r.y + r.h) + else if (r.y >= rect.y + rect.h) hi = Math.min(hi, r.y) + } + } + const start = slide === "x" ? rect.x : rect.y + const end = slide === "x" ? rect.x + rect.w : rect.y + rect.h + const gLo = lo === -Infinity ? 0 : start - lo + const gHi = hi === Infinity ? 0 : hi - end + return Math.max(0, gLo) + Math.max(0, gHi) +} + function placeRect(w, h, from, dir) { const base = baseRect(w, h, from, dir) if (!collides(base)) return base const horiz = dir === "N" || dir === "S" + const slide = horiz ? "x" : "y" const fixed = horiz ? base.y : base.x const slide0 = horiz ? base.x : base.y - let best = null + const at = (c) => (horiz ? { x: c, y: fixed, w, h } : { x: fixed, y: c, w, h }) + let nearest = null for (let k = 1; k < 1000; k++) { for (const off of [k * 2, -k * 2]) { - const rect = horiz ? { x: slide0 + off, y: fixed, w, h } : { x: fixed, y: slide0 + off, w, h } - if (!collides(rect)) { - best = rect + if (!collides(at(slide0 + off))) { + nearest = at(slide0 + off) break } } - if (best) break + if (nearest) break } - if (!best) return base - let snap = null + if (!nearest) return base + const cands = new Map() + cands.set(horiz ? nearest.x : nearest.y, nearest) for (const t of tiles.values()) { const r = t.rect const lines = horiz ? [r.x - w - GAP, r.x + r.w + GAP, r.x + (r.w - w) / 2] : [r.y - h - GAP, r.y + r.h + GAP, r.y + (r.h - h) / 2] for (const c of lines) { - const at = horiz ? best.x : best.y - if (Math.abs(c - at) > GAP) continue - const rect = horiz ? { x: c, y: fixed, w, h } : { x: fixed, y: c, w, h } - if (!collides(rect)) snap = rect + const rect = at(c) + if (!collides(rect)) cands.set(c, rect) + } + } + let best = null + let bestScore = Infinity + for (const [c, rect] of cands) { + const score = slackScore(rect, slide) + 0.35 * Math.abs(c - slide0) + if (score < bestScore) { + best = rect + bestScore = score } } - return snap || best + return best || nearest } function addTile(info, rect) { @@ -263,8 +294,12 @@ startBtn.addEventListener("click", async () => { const data = await r.json() const photo = data.photo photoInfo.set(photo.id, photo) - const minDim = Math.min(window.innerWidth, window.innerHeight) - U = Math.max(100, Math.round((minDim * 0.92) / Math.max(aspect(photo), 1))) + const a = aspect(photo) + const wf = a >= 1 ? a : 1 + const hf = a >= 1 ? 1 : 1 / a + const uW = (window.innerWidth * 0.92) / wf + const uH = (window.innerHeight * 0.92) / hf + U = Math.max(100, Math.min(640, Math.round(Math.min(uW, uH)))) const rect = { x: 0, y: 0, w: tileW(photo), h: tileH(photo) } addTile(photo, rect) setCurrent(photo.id, rect) |
