filters saved in the URL
This commit is contained in:
parent
99db3476e8
commit
ed8b91db46
1 changed files with 80 additions and 6 deletions
|
|
@ -4,15 +4,48 @@
|
||||||
(function () {
|
(function () {
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
let currentFuel = 'regular';
|
// ── URL param helpers ──────────────────────────────────────
|
||||||
let currentRegion = '';
|
function getParams() {
|
||||||
let clusterMode = 'avg'; // 'min' | 'avg' | 'max'
|
return new URLSearchParams(window.location.search);
|
||||||
let showCostco = true;
|
}
|
||||||
|
|
||||||
|
function updateURL() {
|
||||||
|
const p = new URLSearchParams();
|
||||||
|
if (currentFuel !== 'regular') p.set('fuel', currentFuel);
|
||||||
|
if (currentRegion !== '') p.set('region', currentRegion);
|
||||||
|
if (clusterMode !== 'avg') p.set('cluster', clusterMode);
|
||||||
|
if (!showCostco) p.set('costco', '0');
|
||||||
|
const slider = document.getElementById('price-slider');
|
||||||
|
if (slider && parseFloat(slider.value) < parseFloat(slider.max)) {
|
||||||
|
p.set('price', slider.value);
|
||||||
|
}
|
||||||
|
if (map) {
|
||||||
|
const c = map.getCenter();
|
||||||
|
p.set('lat', c.lat.toFixed(5));
|
||||||
|
p.set('lng', c.lng.toFixed(5));
|
||||||
|
p.set('zoom', map.getZoom());
|
||||||
|
}
|
||||||
|
const qs = p.toString();
|
||||||
|
history.replaceState(null, '', qs ? '?' + qs : window.location.pathname);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read initial state from URL params (fall back to defaults).
|
||||||
|
const _p = getParams();
|
||||||
|
let currentFuel = ['regular','super','diesel'].includes(_p.get('fuel')) ? _p.get('fuel') : 'regular';
|
||||||
|
let currentRegion = _p.get('region') || '';
|
||||||
|
let clusterMode = ['min','avg','max'].includes(_p.get('cluster')) ? _p.get('cluster') : 'avg';
|
||||||
|
let showCostco = _p.get('costco') !== '0';
|
||||||
|
let _initPrice = _p.has('price') ? parseFloat(_p.get('price')) : null;
|
||||||
|
let _initLat = _p.has('lat') ? parseFloat(_p.get('lat')) : null;
|
||||||
|
let _initLng = _p.has('lng') ? parseFloat(_p.get('lng')) : null;
|
||||||
|
let _initZoom = _p.has('zoom') ? parseInt(_p.get('zoom'), 10) : null;
|
||||||
|
|
||||||
let allStations = window.__stations || [];
|
let allStations = window.__stations || [];
|
||||||
let allMarkers = [];
|
let allMarkers = [];
|
||||||
let visibleSet = new Set();
|
let visibleSet = new Set();
|
||||||
let minPrice = 0, maxPrice = 300;
|
let minPrice = 0, maxPrice = 300;
|
||||||
let sliderTimer = null;
|
let sliderTimer = null;
|
||||||
|
let mapMoveTimer = null;
|
||||||
const stationDeltas = window.__deltas || {};
|
const stationDeltas = window.__deltas || {};
|
||||||
|
|
||||||
// ── Map setup (deferred to init section below) ─────────────
|
// ── Map setup (deferred to init section below) ─────────────
|
||||||
|
|
@ -221,13 +254,14 @@
|
||||||
document.getElementById('region-select').addEventListener('change', function () {
|
document.getElementById('region-select').addEventListener('change', function () {
|
||||||
currentRegion = this.value;
|
currentRegion = this.value;
|
||||||
rebuildMarkers(true);
|
rebuildMarkers(true);
|
||||||
|
updateURL();
|
||||||
});
|
});
|
||||||
|
|
||||||
document.getElementById('price-slider').addEventListener('input', function () {
|
document.getElementById('price-slider').addEventListener('input', function () {
|
||||||
const val = parseFloat(this.value);
|
const val = parseFloat(this.value);
|
||||||
document.getElementById('slider-label').textContent = val.toFixed(1) + '¢/L';
|
document.getElementById('slider-label').textContent = val.toFixed(1) + '¢/L';
|
||||||
clearTimeout(sliderTimer);
|
clearTimeout(sliderTimer);
|
||||||
sliderTimer = setTimeout(() => applyPriceFilter(val), 80);
|
sliderTimer = setTimeout(() => { applyPriceFilter(val); updateURL(); }, 80);
|
||||||
});
|
});
|
||||||
|
|
||||||
document.querySelectorAll('.cluster-btn').forEach(btn => {
|
document.querySelectorAll('.cluster-btn').forEach(btn => {
|
||||||
|
|
@ -237,6 +271,7 @@
|
||||||
document.querySelectorAll('.cluster-btn').forEach(b =>
|
document.querySelectorAll('.cluster-btn').forEach(b =>
|
||||||
b.classList.toggle('active', b.dataset.mode === clusterMode));
|
b.classList.toggle('active', b.dataset.mode === clusterMode));
|
||||||
if (allStations.length) clusterGroup.refreshClusters();
|
if (allStations.length) clusterGroup.refreshClusters();
|
||||||
|
updateURL();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -247,12 +282,14 @@
|
||||||
document.querySelectorAll('.fuel-btn[data-fuel]').forEach(b =>
|
document.querySelectorAll('.fuel-btn[data-fuel]').forEach(b =>
|
||||||
b.classList.toggle('active', b.dataset.fuel === currentFuel));
|
b.classList.toggle('active', b.dataset.fuel === currentFuel));
|
||||||
rebuildMarkers();
|
rebuildMarkers();
|
||||||
|
updateURL();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
document.getElementById('costco-toggle').addEventListener('change', function () {
|
document.getElementById('costco-toggle').addEventListener('change', function () {
|
||||||
showCostco = this.checked;
|
showCostco = this.checked;
|
||||||
rebuildMarkers();
|
rebuildMarkers();
|
||||||
|
updateURL();
|
||||||
});
|
});
|
||||||
|
|
||||||
// ── Locate-me button ───────────────────────────────────
|
// ── Locate-me button ───────────────────────────────────
|
||||||
|
|
@ -306,7 +343,9 @@
|
||||||
const loadingEl = document.getElementById('loading');
|
const loadingEl = document.getElementById('loading');
|
||||||
try {
|
try {
|
||||||
// Create map and cluster group now that the DOM is ready.
|
// Create map and cluster group now that the DOM is ready.
|
||||||
map = L.map('map', { zoomControl: false }).setView([46.8, -71.2], 7);
|
const initCenter = (_initLat !== null && _initLng !== null) ? [_initLat, _initLng] : [46.8, -71.2];
|
||||||
|
const initZoom = _initZoom !== null ? _initZoom : 7;
|
||||||
|
map = L.map('map', { zoomControl: false }).setView(initCenter, initZoom);
|
||||||
map.createPane('locatePane').style.zIndex = 650;
|
map.createPane('locatePane').style.zIndex = 650;
|
||||||
L.control.zoom({ position: 'topright' }).addTo(map);
|
L.control.zoom({ position: 'topright' }).addTo(map);
|
||||||
var lastUpdatedText = (document.getElementById('last-updated') || {}).textContent || '';
|
var lastUpdatedText = (document.getElementById('last-updated') || {}).textContent || '';
|
||||||
|
|
@ -354,11 +393,46 @@
|
||||||
|
|
||||||
loadingEl.style.display = 'none';
|
loadingEl.style.display = 'none';
|
||||||
|
|
||||||
|
// Apply initial state from URL params to UI controls.
|
||||||
|
if (currentFuel !== 'regular') {
|
||||||
|
document.querySelectorAll('.fuel-btn[data-fuel]').forEach(b =>
|
||||||
|
b.classList.toggle('active', b.dataset.fuel === currentFuel));
|
||||||
|
}
|
||||||
|
if (clusterMode !== 'avg') {
|
||||||
|
document.querySelectorAll('.cluster-btn').forEach(b =>
|
||||||
|
b.classList.toggle('active', b.dataset.mode === clusterMode));
|
||||||
|
}
|
||||||
|
if (!showCostco) {
|
||||||
|
const ct = document.getElementById('costco-toggle');
|
||||||
|
if (ct) ct.checked = false;
|
||||||
|
}
|
||||||
|
if (currentRegion) {
|
||||||
|
const rs = document.getElementById('region-select');
|
||||||
|
if (rs) rs.value = currentRegion;
|
||||||
|
}
|
||||||
|
|
||||||
rebuildMarkers();
|
rebuildMarkers();
|
||||||
|
|
||||||
|
// Override slider value from URL after rebuildMarkers set it.
|
||||||
|
if (_initPrice !== null) {
|
||||||
|
const slider = document.getElementById('price-slider');
|
||||||
|
if (slider && _initPrice < parseFloat(slider.max)) {
|
||||||
|
slider.value = _initPrice;
|
||||||
|
document.getElementById('slider-label').textContent = _initPrice.toFixed(1) + '¢/L';
|
||||||
|
applyPriceFilter(_initPrice, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
map.addLayer(clusterGroup);
|
map.addLayer(clusterGroup);
|
||||||
|
|
||||||
bindControls();
|
bindControls();
|
||||||
|
|
||||||
|
// Update URL on map move/zoom.
|
||||||
|
map.on('moveend zoomend', function () {
|
||||||
|
clearTimeout(mapMoveTimer);
|
||||||
|
mapMoveTimer = setTimeout(updateURL, 200);
|
||||||
|
});
|
||||||
|
|
||||||
// Expose for use after htmx page-swap back to the map page.
|
// Expose for use after htmx page-swap back to the map page.
|
||||||
window.__mapInvalidate = function () {
|
window.__mapInvalidate = function () {
|
||||||
setTimeout(() => map.invalidateSize(), 50);
|
setTimeout(() => map.invalidateSize(), 50);
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue