diff --git a/css/style.css b/css/style.css
index 43f2c5d..40d1e36 100644
--- a/css/style.css
+++ b/css/style.css
@@ -1,90 +1 @@
-body {
- font-family: Verdana, Geneva, Tahoma, sans-serif
-}
-
-.rope input, button, input {
- min-height: 1.5rem;
- min-width: 1.5rem;
- margin: 1px;
-}
-
-.rope, label {
- display: block;
-}
-
-label * {
- vertical-align: middle;
-}
-
-input#join {
- margin-right: 0.25rem;
- margin-bottom: 0.25rem;
-}
-
-#lengths, #results {
- margin: 1rem 0rem;
-}
-
-table, td {
- border: 1px solid #333;
-}
-
-/* Leaflet map */
-
-div#map {
- height: 20rem;
- width: 40rem;
- max-height: 95%;
- max-width: 100%;
-}
-
-.leaflet-marker-icon.black {
- filter: saturate(0);
-}
-
-.leaflet-marker-icon:not(.black) {
- filter: hue-rotate(190deg) brightness(200%);
-}
-
-#lost_message {
- display: none;
-}
-
-/* Install */
-p.install {
- display: none;
-}
-
-/* Colours */
-html {
- background-color: #eee;
-}
-
-thead, tfoot {
- background-color: #333;
- color: #fff;
-}
-
-input:checked + .join, tr.join {
- background: #ff9;
-}
-
-@media (prefers-color-scheme: dark) {
-
- body {
- filter: invert(100%);
- }
-
- div#map {
- filter: invert(100%);
- }
-
- html {
- background-color: #111;
- }
-
- .leaflet-marker-icon:not(.black) {
- filter: invert(0%);
- }
-
-}
+body{font-family:Verdana,Geneva,Tahoma,sans-serif}.rope input,button,input{min-height:1.5rem;min-width:1.5rem;margin:1px}.rope,label{display:block}label *{vertical-align:middle}input#join{margin-right:.25rem;margin-bottom:.25rem}#lengths,#results{margin:1rem 0}table,td{border:1px solid #333}div#map{height:20rem;width:40rem;max-height:95%;max-width:100%}.leaflet-marker-icon.black{filter:saturate(0)}.leaflet-marker-icon:not(.black){filter:hue-rotate(190deg) brightness(200%)}#lost_message,p.install{display:none}html{background-color:#eee}tfoot,thead{background-color:#333;color:#fff}input:checked+.join,tr.join{background:#ff9}@media (prefers-color-scheme:dark){body,div#map{filter:invert(100%)}html{background-color:#111}.leaflet-marker-icon:not(.black){filter:invert(0%)}}
\ No newline at end of file
diff --git a/index.html b/index.html
index 4d14494..6ecd535 100644
--- a/index.html
+++ b/index.html
@@ -1,65 +1 @@
-
-
-
- What can I rig?
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- What can I rig?
- Given the ropes you've got, what caving trips can you rig in
-
- ?
This data is not necessarily accurate, nor have I asked for permission to use it.
- Psst! This site is a PWA, so you can it on your phone to use offline!
-
- Inspiration: caving_fox.
- Data: Braemoor, CNCC, Northern Caves, Not for the Faint Hearted, Simon Wilson, CCPC Rigging Guide.
- Code: Ari Cooper-Davis.
-
- Rope lengths:
-
-
-
-
-
-
- Results:
-
-
-
-
- Trip |
- Rope lengths required |
-
-
-
-
-
-
- Map view:
- Note: results include 0 trip(s) with unknown locations that can't be mapped.
-
-
-
-
+What can I rig?What can I rig?
Given the ropes you've got, what caving trips can you rig in ?
This data is not necessarily accurate, nor have I asked for permission to use it.
Psst! This site is a PWA, so you can it on your phone to use offline!
Inspiration: caving_fox.
Data: Braemoor, CNCC, Northern Caves, Not for the Faint Hearted, Simon Wilson, CCPC Rigging Guide.
Code: Ari Cooper-Davis.
Rope lengths:
Results:
Trip | Rope lengths required |
---|
Map view:
Note: results include 0 trip(s) with unknown locations that can't be mapped.
\ No newline at end of file
diff --git a/script.js b/script.js
index e1dc4d1..68f7f2b 100644
--- a/script.js
+++ b/script.js
@@ -1,215 +1 @@
-// Vars
-let views = {
- 'derbyshire': {'coords': [53.2,-1.78], 'zoom': 9},
- 'scotland': {'coords': [57.9,-5.17], 'zoom': 7},
- 'yorkshire': {'coords': [54.17,-2.19], 'zoom': 10},
-};
-
-// Register service worker for PWA
-if ("serviceWorker" in navigator) {
- navigator.serviceWorker.register('/what-can-I-rig/sw.js', {scope: '/what-can-I-rig/'});
-};
-
-// Make installable
-let deferredPrompt;
-let installBtn = document.querySelector("#install");
-let installP = document.querySelector(".install");
-
-window.addEventListener("beforeinstallprompt", (e) => {
- e.preventDefault();
- deferredPrompt = e;
- installP.style.display = "block";
-
- installBtn.addEventListener("click", (e) => {
- deferredPrompt.prompt();
- deferredPrompt.userChoice.then((result) => {
- deferredPrompt = null;
- });
- });
-});
-
-// Remove rope input
-function removeRope(event) {
- event.target.parentNode.remove();
-}
-
-// Add rope input
-function addRope(el) {
- let newInput = ropeInput.cloneNode(true);
- newInput.lastChild.disabled = false;
- newInput.firstChild.value = '';
- newInput.firstChild.onkeydown = handleTabs;
- addButton.parentNode.insertBefore(newInput, el.target ?? el);
- for (let el of document.getElementsByClassName('rope')) {
- el.lastChild.onclick = removeRope;
- };
- return newInput;
-};
-let addButton = document.getElementById('add');
-addButton.onclick = addRope;
-
-function handleTabs (event) {
- if (event.code == 'Tab') {
- let newInput = addRope(event.target.parentNode.nextElementSibling);
- event.preventDefault();
- newInput.firstChild.focus();
-
- }
-}
-let ropeInput = document.getElementsByClassName('rope')[0];
-ropeInput.onkeydown = handleTabs;
-
-// Init leaflet map
-function showMap() {
- let map = L.map('map').setView([54.17, -2.19], 10);
- L.tileLayer('https://tile.openstreetmap.org/{z}/{x}/{y}.png', {
- maxZoom: 19,
- attribution: '© OpenStreetMap'
- }).addTo(map);
- return map;
-}
-let caveMap = showMap();
-
-// Handle region selection
-let regionSel = document.getElementById('region');
-let region = new URLSearchParams(window.location.search).get('region') ?? '';
-function updateRegion(reg) {
- region = ['yorkshire','derbyshire','scotland'].filter(r => r == reg.toLowerCase())[0] ?? 'yorkshire';
- regionSel.value = region;
- caveMap.flyTo(views[region]['coords'], views[region]['zoom']);
-}
-updateRegion(region);
-regionSel.addEventListener('change', event => updateRegion(event.target.value));
-
-// Handle reset button
-let tableData = document.getElementById('data');
-let resetButton = document.getElementById('reset');
-resetButton.onclick = function reset() {
- // remove all rope inputs
- for (let el of document.querySelectorAll('.rope')) {
- if (!el.lastChild.disabled) {
- el.remove();
- } else {
- el.firstChild.value = '';
- };
- };
- // remove results data
- tableData.innerHTML = '';
- clearMap();
- // Uncheck join
- document.getElementById('join').checked = false;
-};
-
-// Handle go button
-let goButton = document.getElementById('go');
-goButton.onclick = function calculate() {
- // Get values of inputs
- let ropes = [];
- for (let el of document.getElementsByClassName('rope')) {
- ropes.push(el.firstChild.value);
- };
- ropes = ropes.map(el => parseInt(el)).filter(el => el).sort((a, b) => a < b);
- let join_ropes = document.getElementById('join').checked;
-
- // Reset output
- tableData.innerHTML = '';
- clearMap();
-
- // Get trip lengths
- fetch(`./pitchlengths/${region}.txt`).then(response => response.text()).then(function (trips) {
- // Parse and sort pitch lengths
- trips = trips.split('\n').filter(
- line => !(line.startsWith('#') | line.length < 3)
- );
- for (let [_, trip] of Object.entries(trips.sort())) {
- trip = trip.split(',');
- // Trips can't have more pitches than we have ropes
- if (trip.filter(el => !el.includes('[')).length - 1 > ropes.length) {
- continue;
- };
- // Pitches must be possible
- pitches = trip.slice(1).filter(el => !el.includes('[')).map(x => parseInt(x.trim())).sort((a, b) => a < b);
- if (pitches.every((pitch, i) => { return pitch <= ropes[i] })) {
- let td_el = (trip[1].includes('[') ? `${trip[0]}` : trip[0]);
- let td_rp = trip.slice(1).filter(el => !el.includes('[')).join(', ') || 'Ropes in-situ';
- let row = `${td_el} | ${td_rp} |
`;
- tableData.insertAdjacentHTML('beforeend', row);
- displayOnMap(trip, false);
- continue;
- };
- if (join_ropes) {
- for (let [_, _join] of Object.entries(join_combs(ropes))) {
- if (pitches.every((pitch, i) => { return pitch <= _join[i] })) {
- let td_el = (trip[1].includes('[') ? `${trip[0]}` : trip[0]);
- let td_rp = trip.slice(1).filter(el => !el.includes('[')).join(', ') || 'Ropes in-situ';
- let row = `${td_el} | ${td_rp} |
`;
- tableData.insertAdjacentHTML('beforeend', row);
- displayOnMap(trip, true);
- break;
- };
- };
- };
- };
- // Fit map to markers
- fitBounds();
- });
-};
-
-// Get all unique rope join combinations (reverse sorted)
-function join_combs(ropes) {
- function join(ropes) {
- let joins = [];
- for (var i = 0; i < ropes.length - 1; i++) {
- for (var j = i + 1; j < ropes.length; j++) {
- joins.push(ropes.slice(0, i).concat(ropes[i] + ropes[j], ropes.slice(i + 1, j), ropes.slice(j + 1)));
- }
- }
- return joins;
- }
-
- let joins = join(ropes);
- joins.forEach(i => {
- if (i.length > 1) {
- join(i).forEach(j => {
- joins.push(j.sort().reverse());
- });
- }
- });
- joins = Object.values(joins.reduce((p, c) => (p[JSON.stringify(c)] = c, p), {}));
- return (joins);
-}
-
-// Display on map
-let markers = [];
-let lost_count = document.getElementById('lost_count');
-let lost_message = document.getElementById('lost_message');
-function displayOnMap(trip, join) {
- if (trip[1].includes('[')) {
- let marker = L.marker(trip.slice(1,3).map(el => parseFloat(el.slice(1,-1)))).addTo(caveMap);
- if (!join) {
- marker._icon.classList.add('black');
- }
- marker.bindPopup(`${trip[0]}`);
- markers.push(marker);
- } else {
- lost_count.textContent = parseInt(lost_count.textContent)+1;
- lost_message.style.display = 'block';
- }
-}
-
-// Clear map of existing markers
-function clearMap() {
- markers.forEach(marker => caveMap.removeLayer(marker));
- markers = [];
- lost_count.textContent = '0';
- lost_message.style.display = 'none';
-}
-
-// Move map to show all markers
-let group = null;
-function fitBounds() {
- if ( markers.length > 0 ) {
- group = new L.featureGroup(markers);
- caveMap.flyToBounds(group.getBounds().pad(0.1), );
- }
-}
\ No newline at end of file
+let deferredPrompt,views={derbyshire:{coords:[53.2,-1.78],zoom:9},scotland:{coords:[57.9,-5.17],zoom:7},yorkshire:{coords:[54.17,-2.19],zoom:10}};"serviceWorker"in navigator&&navigator.serviceWorker.register("/what-can-I-rig/sw.js",{scope:"/what-can-I-rig/"});let installBtn=document.querySelector("#install"),installP=document.querySelector(".install");function removeRope(e){e.target.parentNode.remove()}function addRope(e){let t=ropeInput.cloneNode(!0);t.lastChild.disabled=!1,t.firstChild.value="",t.firstChild.onkeydown=handleTabs,addButton.parentNode.insertBefore(t,e.target??e);for(let e of document.getElementsByClassName("rope"))e.lastChild.onclick=removeRope;return t}window.addEventListener("beforeinstallprompt",(e=>{e.preventDefault(),deferredPrompt=e,installP.style.display="block",installBtn.addEventListener("click",(e=>{deferredPrompt.prompt(),deferredPrompt.userChoice.then((e=>{deferredPrompt=null}))}))}));let addButton=document.getElementById("add");function handleTabs(e){if("Tab"==e.code){let t=addRope(e.target.parentNode.nextElementSibling);e.preventDefault(),t.firstChild.focus()}}addButton.onclick=addRope;let ropeInput=document.getElementsByClassName("rope")[0];function showMap(){let e=L.map("map").setView([54.17,-2.19],10);return L.tileLayer("https://tile.openstreetmap.org/{z}/{x}/{y}.png",{maxZoom:19,attribution:'© OpenStreetMap'}).addTo(e),e}ropeInput.onkeydown=handleTabs;let caveMap=showMap(),regionSel=document.getElementById("region"),region=new URLSearchParams(window.location.search).get("region")??"";function updateRegion(e){region=["yorkshire","derbyshire","scotland"].filter((t=>t==e.toLowerCase()))[0]??"yorkshire",regionSel.value=region,caveMap.flyTo(views[region].coords,views[region].zoom)}updateRegion(region),regionSel.addEventListener("change",(e=>updateRegion(e.target.value)));let tableData=document.getElementById("data"),resetButton=document.getElementById("reset");resetButton.onclick=function(){for(let e of document.querySelectorAll(".rope"))e.lastChild.disabled?e.firstChild.value="":e.remove();tableData.innerHTML="",clearMap(),document.getElementById("join").checked=!1};let goButton=document.getElementById("go");function join_combs(e){function t(e){let t=[];for(var n=0;n{e.length>1&&t(e).forEach((e=>{n.push(e.sort().reverse())}))})),n=Object.values(n.reduce(((e,t)=>(e[JSON.stringify(t)]=t,e)),{})),n}goButton.onclick=function(){let e=[];for(let t of document.getElementsByClassName("rope"))e.push(t.firstChild.value);e=e.map((e=>parseInt(e))).filter((e=>e)).sort(((e,t)=>ee.text())).then((function(n){n=n.split("\n").filter((e=>!(e.startsWith("#")|e.length<3)));for(let[o,r]of Object.entries(n.sort()))if(r=r.split(","),!(r.filter((e=>!e.includes("["))).length-1>e.length))if(pitches=r.slice(1).filter((e=>!e.includes("["))).map((e=>parseInt(e.trim()))).sort(((e,t)=>et<=e[n]))){let e=`${r[1].includes("[")?`${r[0]}`:r[0]} | ${r.slice(1).filter((e=>!e.includes("["))).join(", ")||"Ropes in-situ"} |
`;tableData.insertAdjacentHTML("beforeend",e),displayOnMap(r,!1)}else if(t)for(let[t,n]of Object.entries(join_combs(e)))if(pitches.every(((e,t)=>e<=n[t]))){let e=`${r[1].includes("[")?`${r[0]}`:r[0]} | ${r.slice(1).filter((e=>!e.includes("["))).join(", ")||"Ropes in-situ"} |
`;tableData.insertAdjacentHTML("beforeend",e),displayOnMap(r,!0);break}fitBounds()}))};let markers=[],lost_count=document.getElementById("lost_count"),lost_message=document.getElementById("lost_message");function displayOnMap(e,t){if(e[1].includes("[")){let n=L.marker(e.slice(1,3).map((e=>parseFloat(e.slice(1,-1))))).addTo(caveMap);t||n._icon.classList.add("black"),n.bindPopup(`${e[0]}`),markers.push(n)}else lost_count.textContent=parseInt(lost_count.textContent)+1,lost_message.style.display="block"}function clearMap(){markers.forEach((e=>caveMap.removeLayer(e))),markers=[],lost_count.textContent="0",lost_message.style.display="none"}let group=null;function fitBounds(){markers.length>0&&(group=new L.featureGroup(markers),caveMap.flyToBounds(group.getBounds().pad(.1)))}
\ No newline at end of file
diff --git a/sw.js b/sw.js
index e1ffecd..04c41b9 100644
--- a/sw.js
+++ b/sw.js
@@ -1,47 +1 @@
-let cacheName = 'what-can-i-rig-v1';
-let cacheableContent = [
- '/what-can-I-rig/',
- '/what-can-I-rig/index.html',
- '/what-can-I-rig/icons/favicon.png',
- '/what-can-I-rig/script.js',
- '/what-can-I-rig/sw.js',
- '/what-can-I-rig/css/style.css',
- '/what-can-I-rig/pitchlengths/yorkshire.txt',
- '/what-can-I-rig/pitchlengths/derbyshire.txt',
- '/what-can-I-rig/pitchlengths/scotland.txt',
-];
-
-// On install cache required assets
-self.addEventListener('install', (e) => {
- e.waitUntil((async () => {
- let cache = await caches.open(cacheName);
- await cache.addAll(cacheableContent);
- })());
-});
-
-// Clear old caches when cacheName is updated (i.e. pitchlengths.txt is update)
-self.addEventListener('activate', (e) => {
- e.waitUntil(caches.keys().then((keyList) => {
- return Promise.all(keyList.map((key) => {
- if (key === cacheName) { return; }
- return caches.delete(key);
- }));
- }));
- });
-
-// On fetch serve files from cache (if available)
-self.addEventListener('fetch', (e) => {
- e.responseWith((async () => {
- let r = await caches.match(e.request, {ignoreSearch: true});
- // Serve cached file
- if (r) { return r; }
- // Else fetch remote, cache, and serve
- let response = await fetch(e.request);
- // Don't cache map tiles
- if (!e.request.url.includes('openstreetmap')) {
- let cache = await caches.open(cacheName)
- cache.put(e.request, response.clone());
- }
- return response;
- })());
-});
\ No newline at end of file
+let cacheName="what-can-i-rig-v1",cacheableContent=["/what-can-I-rig/","/what-can-I-rig/index.html","/what-can-I-rig/icons/favicon.png","/what-can-I-rig/script.js","/what-can-I-rig/sw.js","/what-can-I-rig/css/style.css","/what-can-I-rig/pitchlengths/yorkshire.txt","/what-can-I-rig/pitchlengths/derbyshire.txt","/what-can-I-rig/pitchlengths/scotland.txt"];self.addEventListener("install",(e=>{e.waitUntil((async()=>{let e=await caches.open(cacheName);await e.addAll(cacheableContent)})())})),self.addEventListener("activate",(e=>{e.waitUntil(caches.keys().then((e=>Promise.all(e.map((e=>{if(e!==cacheName)return caches.delete(e)}))))))})),self.addEventListener("fetch",(e=>{e.responseWith((async()=>{let t=await caches.match(e.request,{ignoreSearch:!0});if(t)return t;let a=await fetch(e.request);if(!e.request.url.includes("openstreetmap")){(await caches.open(cacheName)).put(e.request,a.clone())}return a})())}));
\ No newline at end of file