83 lines
3.2 KiB
HTML
83 lines
3.2 KiB
HTML
<!DOCTYPE html>
|
|
<html lang="en">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<title>Gas Prices</title>
|
|
<meta name="description" content="Track the gas prices of Sam's Club and Costco locations across the United States">
|
|
<meta name="viewport" content="width=device-width,initial-scale=1">
|
|
<link rel="icon" href="gas.svg" type="image/svg+xml">
|
|
<script src="https://static.stevenalexander.org/leaflet/leaflet.js" integrity="sha256-20nQCchB9co0qIjJZRGuk2/Z9VM+kNiyxNV1lvTlZBo=" crossorigin="anonymous"></script>
|
|
<link rel="stylesheet" href="https://static.stevenalexander.org/leaflet/leaflet.css" integrity="sha256-p4NxAoJBhIIN+hmNHrzRCf9tD/miZyoHS5obTRR9BMY=" crossorigin="anonymous">
|
|
<base target="_blank">
|
|
<style>html,body{height:100%;margin:0;}#map{height:100vh;}
|
|
.leaflet-container a{
|
|
color:black;
|
|
text-decoration:none;
|
|
}
|
|
.samsclub,.costco{
|
|
display:flex;
|
|
border-radius:33%;
|
|
text-align:center;
|
|
align-items:center;
|
|
font-size:14px;
|
|
font-weight:bold;
|
|
}
|
|
.samsclub{background-color:rgba(0,103,160,0.5);}
|
|
.costco{background-color:rgba(227,42,54,0.5);}
|
|
</style>
|
|
</head>
|
|
<body>
|
|
<div id="map"></div>
|
|
<script>
|
|
let map=L.map("map",{center:[38.243,-85.647],zoom:11,layers:[L.tileLayer("https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png")]});
|
|
let layerControl=L.control.layers(null,null,{collapsed:false}).addTo(map);
|
|
let chains={"Sam's Club":"https://www.samsclub.com/local/fuel-center/-/X","Costco":"https://www.costco.com/warehouse-locations-X.html#:~:text=Gas%20Station"};
|
|
for (const [chain,url] of Object.entries(chains)){
|
|
const chainId=chain.toLowerCase().replace(/[^a-z]/g,'');
|
|
chains[chain]=L.layerGroup().addTo(map);
|
|
layerControl.addOverlay(chains[chain],`${chain} loading...`)
|
|
fetch(chainId+".csv").then(response=>{
|
|
if(!response.ok){throw new Error(response.status)}
|
|
return response.text()
|
|
}).then(csv=>{
|
|
csv.split("\n").forEach(line=>{
|
|
let [u,p,lat,lng,id]=line.split(",");
|
|
[u,p]=[u,p].map(cents=>"$"+(cents/100).toFixed(2));
|
|
L.marker([lat,lng],{icon:L.divIcon({className:chainId,html:`<a href="${url.replace("X",id)}">${u}\n${p}</a>`,iconSize:[44,44]})}).addTo(chains[chain])
|
|
})
|
|
layerControl.removeLayer(chains[chain]);
|
|
layerControl.addOverlay(chains[chain],`${chain} (${chains[chain].getLayers().length} locations)`)
|
|
}).catch(error=>{
|
|
console.error(error);
|
|
layerControl.removeLayer(chains[chain]);
|
|
layerControl.addOverlay(L.layerGroup(),`${chain} request was blocked :(`)
|
|
})
|
|
}
|
|
const lastPosition=localStorage.getItem("lastPosition");
|
|
if(lastPosition){
|
|
const pos=JSON.parse(lastPosition);
|
|
map.setView(pos.coords,pos.zoom);
|
|
}
|
|
map.on("moveend zoomend",function(){
|
|
const center=map.getCenter();
|
|
localStorage.setItem("lastPosition",JSON.stringify({coords:[center.lat,center.lng],zoom:map.getZoom()}));
|
|
});
|
|
const ResetViewControl=L.Control.extend({
|
|
onAdd:function(map){
|
|
const btn=L.DomUtil.create('button','leaflet-bar leaflet-control');
|
|
btn.innerHTML='⌂';
|
|
btn.title='Reset view';
|
|
btn.style.backgroundColor='white';
|
|
btn.style.font='22px bold';
|
|
btn.style.cursor='pointer';
|
|
L.DomEvent.on(btn,'click',function(e){
|
|
localStorage.removeItem("lastPosition");
|
|
location.reload();
|
|
});
|
|
return btn;
|
|
}
|
|
});
|
|
map.addControl(new ResetViewControl({position:'topleft'}));
|
|
</script>
|
|
</body>
|
|
</html>
|