diff --git a/site/assets/css/main.scss b/site/assets/css/main.scss index 0af6a19..b046360 100644 --- a/site/assets/css/main.scss +++ b/site/assets/css/main.scss @@ -135,7 +135,9 @@ ol { margin: auto; width: 100%; height: calc(100vh - 3.6em - 2px); - height: calc(100svh - 3.6em - 2px); // Correct size on mobile Safari + + /* Correct size on mobile Safari */ + height: calc(100svh - 3.6em - 2px); code { font-size: 1.5rem; @@ -167,6 +169,9 @@ ol { } >article { + max-width: var(--full-width); + margin: auto; + padding: 1em 1.25em 1.25em; h2, h3, @@ -183,16 +188,18 @@ ol { margin: 2.5em auto; } + blockquote p, + .notice p, + .warning p { + margin: 0; + } + summary { cursor: pointer; margin-top: 1em; font-size: 1.17em; font-weight: bold; } - - max-width: var(--full-width); - margin: auto; - padding: 1em 1.25em 1.25em; } } @@ -284,12 +291,6 @@ blockquote, box-sizing: border-box; } -blockquote p, -.notice p, -.warning p { - margin: 0; -} - .notice::before, .warning::before { border-right: 2px solid var(--text-color); @@ -365,6 +366,27 @@ blockquote p, border-radius: 5px; box-shadow: 0 0 0 2px rgba(0, 0, 0, 0.1); min-width: 90px; + + div { + position: relative; + display: flex; + margin-bottom: 3px; + + div { + width: 20px; + height: 20px; + margin-right: 10px; + } + + h3 { + margin-top: 0; + margin-bottom: 0.6em; + } + + &:last-child { + margin-bottom: 0; + } + } } #map-color-scale.collapsed { @@ -377,27 +399,6 @@ blockquote p, } } -#map-color-scale div { - position: relative; - display: flex; - margin-bottom: 3px; - - &:last-child { - margin-bottom: 0px; - } -} - -#map-color-scale div div { - width: 20px; - height: 20px; - margin-right: 10px; -} - -#map-color-scale div h3 { - margin-top: 0; - margin-bottom: 0.6em; -} - #map-color-scale-toggle { position: absolute; top: 0; @@ -434,7 +435,7 @@ blockquote p, } /* adjustment when very small */ -@media only screen and (max-width: 720px) { +@media only screen and (min-width: 1px) and (max-width: 720px) { html { scroll-padding-top: 1.5em; } @@ -456,6 +457,7 @@ blockquote p, li { padding: 0 0 0 1em; + &:last-of-type { padding-right: 1em; } diff --git a/site/assets/js/map.js b/site/assets/js/map.js index 70b1a69..e3b1a71 100644 --- a/site/assets/js/map.js +++ b/site/assets/js/map.js @@ -7,9 +7,31 @@ maplibregl.addProtocol("pmtiles", protocol.tile); class ColorScale { constructor(map) { this.map = map; - this.scaleContainer = document.createElement("div"); - this.toggleButton = document.createElement("button"); - this.colors = [ + this.scaleContainer = this.createScaleContainer(); + this.toggleButton = this.createToggleButton(); + this.colors = this.getColors(); + this.init(); + } + + createScaleContainer() { + const container = document.createElement("div"); + container.id = "map-color-scale"; + return container; + } + + createToggleButton() { + const button = document.createElement("button"); + button.id = "map-color-scale-toggle"; + button.innerHTML = "−"; + button.onclick = () => { + const isCollapsed = this.scaleContainer.classList.toggle("collapsed"); + button.innerHTML = isCollapsed ? "+" : "−"; + }; + return button; + } + + getColors() { + return [ { color: "var(--map-color-1)", label: "< 15 min" }, { color: "var(--map-color-2)", label: "15-30 min" }, { color: "var(--map-color-3)", label: "30-45 min" }, @@ -17,19 +39,9 @@ class ColorScale { { color: "var(--map-color-5)", label: "60-75 min" }, { color: "var(--map-color-6)", label: "75-90 min" }, ]; - this.init(); } init() { - this.scaleContainer.id = "map-color-scale"; - this.toggleButton.id = "map-color-scale-toggle"; - - this.toggleButton.innerHTML = "−"; // Unicode for minus sign - this.toggleButton.onclick = () => { - const isCollapsed = this.scaleContainer.classList.toggle("collapsed"); - this.toggleButton.innerHTML = isCollapsed ? "+" : "−"; // Unicode for plus and minus signs - }; - const legendTitle = document.createElement("div"); legendTitle.innerHTML = "

Travel time
(driving)

"; this.scaleContainer.append(legendTitle); @@ -69,10 +81,20 @@ class ColorScale { class Spinner { constructor() { - this.spinner = document.createElement("div"); - this.spinner.id = "map-spinner"; - this.overlay = document.createElement("div"); - this.overlay.id = "map-overlay"; + this.spinner = this.createSpinner(); + this.overlay = this.createOverlay(); + } + + createSpinner() { + const spinner = document.createElement("div"); + spinner.id = "map-spinner"; + return spinner; + } + + createOverlay() { + const overlay = document.createElement("div"); + overlay.id = "map-overlay"; + return overlay; } show() { @@ -96,11 +118,9 @@ async function instantiateDB() { await db.instantiate(bundle.mainModule, bundle.pthreadWorker); URL.revokeObjectURL(workerUrl); - return db; } -// Initialize and configure map instance async function instantiateMap() { const map = new maplibregl.Map({ style: "https://tiles.openfreemap.org/styles/positron", @@ -195,7 +215,6 @@ function wipeMapPreviousState(map, previousStates) { ); } -// Create display for current tract function createTractIdDisplay() { const display = document.createElement("div"); display.id = "map-info"; @@ -204,7 +223,6 @@ function createTractIdDisplay() { return display; } -// Color scale based on duration and zoom const getColorScale = (duration, zoom) => { const thresholds = getThresholdsForZoom(zoom); if (duration < thresholds[0]) return "color_1"; @@ -233,10 +251,7 @@ function getThresholdsForZoom(zoom) { const [DuckDB, map, tractIdDisplay] = await Promise.all([ instantiateDB(), instantiateMap(), - (async () => { - const display = createTractIdDisplay(); - return display; - })() + (async () => createTractIdDisplay())() ]); const colorScale = new ColorScale(map); @@ -319,7 +334,7 @@ function getThresholdsForZoom(zoom) { }); let previousZoomLevel = null; - map.on("zoom", () => { + map.on("zoom", debounce(() => { const currentZoomLevel = map.getZoom(); if (previousZoomLevel !== null) { const crossedThreshold = zoomThresholds.some( @@ -334,5 +349,13 @@ function getThresholdsForZoom(zoom) { } } previousZoomLevel = currentZoomLevel; - }); + }, 100)); })(); + +function debounce(func, wait) { + let timeout; + return function(...args) { + clearTimeout(timeout); + timeout = setTimeout(() => func.apply(this, args), wait); + }; +}