diff --git a/.gitignore b/.gitignore index b6a0822..cbcce01 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ .venv __pycache__ notes.txt -react_OLD \ No newline at end of file +react_OLD +envs.py \ No newline at end of file diff --git a/src/app.py b/src/app.py index b114eb9..ab9ef69 100644 --- a/src/app.py +++ b/src/app.py @@ -1,8 +1,9 @@ import flask from flask_minify import Minify import json -from tasks import TaskHandler import werkzeug.exceptions as HTTPerror +import requests +from config import * proj = json.load(open("./static/json/projects.json", "r")) books = json.load(open("./static/json/books.json", "r")) @@ -16,8 +17,6 @@ pages['home']['books'] = books pages['books']['books'] = books app = flask.Flask(__name__) -tasks = TaskHandler() - @app.route('/api/goto/') @app.route('/api/goto/') @@ -32,11 +31,6 @@ def goto(location='home'): page = page404(e) return [pagevars, page] -# I am literally insane -# There was no reason for me to do this -# it saved some lines of code I guess -# infinite flaskless flask here we comes - def funcGen(pagename, pages): def dynamicRule(): try: @@ -62,16 +56,17 @@ def resume(): @app.route("/hotspots") def hotspotsRIT(): - return flask.render_template("hotspots.html") - -@app.route("/hotspotsrit/cached") -def getCached(): - return json.dumps(tasks.getCache()) - -@app.route("/hotspotsrit/current") -def getLive(): - return json.dumps(tasks.getCurrent()) + pagevars = { + "template": "iframe.html", + "title": f"Hotspots @ RIT", + "description": "Hotspots @ RIT by Andrew Simonson", + "canonical": "/hotspots", + } + return flask.render_template("iframe.html", url=HotspotsURL, var=pagevars) +@app.route("/hotspots/") +def hotspotsProxy(path): + return requests.get(f"{HotspotsURL}/{path}").content @app.errorhandler(Exception) def page404(e): diff --git a/src/config.py b/src/config.py new file mode 100644 index 0000000..1c932de --- /dev/null +++ b/src/config.py @@ -0,0 +1,8 @@ +from os import environ as env +# automatically updates some dev envs. need to remove for production. +try: + __import__('envs.py') +except ImportError: + pass + +HotspotsURL = env.get('HotspotsURL', 'https://asimonson.com/hotspots') \ No newline at end of file diff --git a/src/static/css/App.css b/src/static/css/App.css index 10dee33..9580d7a 100644 --- a/src/static/css/App.css +++ b/src/static/css/App.css @@ -38,6 +38,11 @@ body { font-family: "Roboto Condensed", sans-serif; } +#fullIframe { + width:100vw; + height: 100vh; +} + #menu { height: 2rem; display: none; diff --git a/src/static/css/hotspots.css b/src/static/css/hotspots.css deleted file mode 100644 index f6f7ed7..0000000 --- a/src/static/css/hotspots.css +++ /dev/null @@ -1,40 +0,0 @@ -body { - margin: 0; - padding: 0; - overflow: visible; -} - -#map { - height: 100vh; -} - -html, body, #map { - height: 100%; - width: 100vw; -} - -.leaflet-layer, -.leaflet-control-zoom-in, -.leaflet-control-zoom-out, -.leaflet-control-attribution { - filter: brightness(500%) contrast(130%); -} - -.leaflet-tile-pane { - filter: brightness(50%); -} - -.legend { - border: solid #999999 3px; - color: #eee; - background-color: rgba(44, 44, 44, .8); - padding: 1em; - border-radius: 1em; -} - -#legendOccGrad { - background-image: linear-gradient(to right, transparent, red); - padding: 0 2em; - text-align: center; - text-shadow: black .2em .2em; -} \ No newline at end of file diff --git a/src/static/js/hotspots.js b/src/static/js/hotspots.js deleted file mode 100644 index 078f829..0000000 --- a/src/static/js/hotspots.js +++ /dev/null @@ -1,550 +0,0 @@ -let map = L.map("map", { - zoomControl: false, - attributionControl: false, -}).setView([43.084679, -77.674702], 17); -// L.tileLayer('https://tile.openstreetmap.org/{z}/{x}/{y}.png', { -// maxZoom: 19, -// attribution: '© OpenStreetMap' -// }).addTo(map); - -var CartoDB_DarkMatterNoLabels = L.tileLayer( - "https://{s}.basemaps.cartocdn.com/dark_nolabels/{z}/{x}/{y}{r}.png", - { - attribution: - '© OpenStreetMap contributors © CARTO', - subdomains: "abcd", - maxZoom: 20, - } -).addTo(map); - -// var CartoDB_PositronNoLabels = L.tileLayer('https://{s}.basemaps.cartocdn.com/light_nolabels/{z}/{x}/{y}{r}.png', { -// attribution: '© OpenStreetMap contributors © CARTO', -// subdomains: 'abcd', -// maxZoom: 20 -// }).addTo(map); // good hacky filter: invert(100%) hue-rotate(180deg) brightness(100%) contrast(100%); - -// var CartoDB_Positron = L.tileLayer('https://{s}.basemaps.cartocdn.com/light_all/{z}/{x}/{y}{r}.png', { -// attribution: '© OpenStreetMap contributors © CARTO', -// subdomains: 'abcd', -// maxZoom: 20 -// }).addTo(map); - -function sleep(ms) { - return new Promise((resolve) => setTimeout(resolve, ms)); -} - -function shuffle(array) { - let currentIndex = array.length, - randomIndex; - - // While there remain elements to shuffle. - while (currentIndex > 0) { - // Pick a remaining element. - randomIndex = Math.floor(Math.random() * currentIndex); - currentIndex--; - - // And swap it with the current element. - [array[currentIndex], array[randomIndex]] = [ - array[randomIndex], - array[currentIndex], - ]; - } - - return array; -} - -function setMarker(attrs, ref) { - // let red = parseInt("ff", 16); - // let green = parseInt("78", 16); - // let style = {"fillColor": `#${red.toString(16)}${green.toString(16)}00`}; - let ratio = attrs.properties.count / attrs.properties.capacity; - let adjustedratio = ratio > 1 ? 1 : ratio; - let red = 255 * adjustedratio; - let style = { fillColor: `rgba(255, 0, 0, ${adjustedratio})` }; - ref.setStyle(style); - ref.bindPopup( - `${attrs.properties.name}
Current Occupation: ${ - attrs.properties.count - }
${Math.round(ratio * 100)}% capacity` - ); -} - -function onEachFeature(feature, layer) { - // does this feature have a property named popupContent? - if (!feature.properties || !feature.properties.name) { - return; - } - setMarker(feature, layer); -} - -const polyStyle = { - color: "#ff7800", - weight: 5, - opacity: 0.65, -}; - -const geojsonMarkerOptions = { - pane: "nodePane", - radius: 8, - fillColor: "#ff7800", - color: "#ff7800", - weight: 3, - opacity: 1, - fillOpacity: 1, -}; - -const pointStyle = {}; - -function ritCustomize(input) { - badOnes = [166]; // Nathan's (166) is a duplicate of Ben and Jerry's - for (let i = input.length - 1; i >= 0; i--) { - if (badOnes.indexOf(input[i].mdo_id) >= 0) { - input.splice(i, 1); - } - } - return input; -} - -// Unused: "Campus", "Gleason_Engineering_Student_Area" -const no_mdo_ids = { - Library_A_Level: { type: "Point", coordinates: [-77.676355, 43.083974] }, - Library_1st_Floor: { type: "Point", coordinates: [-77.676355, 43.083874] }, - Library_2nd_Floor: { type: "Point", coordinates: [-77.676355, 43.083774] }, - Library_3rd_Floor: { type: "Point", coordinates: [-77.676355, 43.083674] }, - Library_4th_Floor: { type: "Point", coordinates: [-77.676355, 43.083574] }, - Ross_Hall: { type: "Point", coordinates: [-77.677937, 43.082379] }, - Gordon_Field_House: { type: "Point", coordinates: [-77.671725, 43.085149] }, - Golisano_Institute_for_Sustainability_Lobby: { - type: "Point", - coordinates: [-77.681365, 43.085376], - }, -}; - -function ritCustomizeCoords(input) { - try { - if (input.properties.name == "Beanz") { - input.geometry.coordinates = [-77.66904, 43.083876]; - } - return input; - } catch {} - try { - if (no_mdo_ids[input.location] == undefined) return; - let geojsonObj = { - geometry: no_mdo_ids[input.location], - properties: { - mdo_id: input.location, - name: input.location.replaceAll("_", " "), - }, - type: "Feature", - }; - return geojsonObj; - } catch {} -} - -let pts; -let nodePane = map.createPane("nodePane"); -nodePane.style.zIndex = "600"; -let nodeGroup; -const densityMapUrl = "/hotspotsrit"; // https://maps.rit.edu/proxySearch/densityMapDetail.php?mdo=1 - -async function init(legend = false) { - let counts = fetch(densityMapUrl + "/cached"); - - let locations = fetch( - "https://maps.rit.edu/proxySearch/locations.search.php" - ); - - counts = Object.values(await (await counts).json()); - counts = ritCustomize(counts); - locations = await (await locations).json(); - - pts = {}; - locations.forEach((x) => { - for (let i = 0; i < counts.length; i++) { - if (counts[i].mdo_id == x.properties.mdo_id) { - x.properties.count = counts[i].count; - x.properties.capacity = - counts[i].max_occ == null ? 100 : counts[i].max_occ; - x = ritCustomizeCoords(x); - pts[x.properties.mdo_id] = x; - break; - } - } - }); - - counts.forEach((x) => { - if (pts[x.mdo_id] == undefined) { - let geojson = ritCustomizeCoords(x); - if (geojson !== undefined) { - geojson.properties.count = x.count; - geojson.properties.capacity = x.max_occ == null ? 100 : x.max_occ; - pts[x.location] = geojson; - } - } - }); - - nodeGroup = L.geoJSON(Object.values(pts), { - pane: "nodePane", - pointToLayer: function (feature, latlng) { - return L.circleMarker(latlng, geojsonMarkerOptions); - }, - style: function (feature) { - switch (feature.geometry.type) { - case "Polygon": - return polyStyle; - case "Point": - return pointStyle; - } - }, - onEachFeature: onEachFeature, - }); - nodeGroup.addTo(map); - nodeGroup.bringToFront(); - - const features = nodeGroup.getLayers(); - for (let i = 0; i < features.length; i++) { - const key = features[i].feature.properties.mdo_id; - pts[key].properties.reference = features[i]; - } - - legend ? makeLegend() : null; -} - -function makeLegend() { - let legend = L.control({ position: "bottomright" }); - - legend.onAdd = function (mapref) { - let div = L.DomUtil.create("div", "info legend"); - div.innerHTML = - "
Occupancy / Max Occupancy Gradient
"; - div.innerHTML += `

Markers represent locations where data is collected
- Vectors represent the migration of aggregate occupation
- vectors to/from nodeless points involve locations not tracked by RIT

`; - - return div; - }; - - let statControl = L.control({ position: "topright" }); - - statControl.onAdd = function (mapref) { - let div = L.DomUtil.create("div", "info legend"); - div.innerHTML = - "

Occupancy is updated every 5 minutes


Next update in seconds

"; - return div; - // - }; - - statControl.addTo(map); - legend.addTo(map); -} - -function updateLegend(shotcount = undefined) { - if (!useLegend) return; - try { - document.getElementById( - "shotCounter" - ).textContent = `Previous update created ${shotcount} migrations`; - } catch {} -} - -const space_coords = [43.09224, -77.674799]; -const UC_coords = [43.080361, -77.683296]; -const perkins_coords = [43.08616, -77.661796]; -function setSpace(features) { - features.forEach((x) => { - const centroid = getCoordArray(x); - if (centroid[1] > -77.673157) { - x.properties.space = perkins_coords; - } else if (centroid[1] < -77.677503 && centroid[0] < 43.08395) { - x.properties.space = UC_coords; - } else { - x.properties.space = space_coords; - } - }); -} - -let bullets = L.layerGroup([]); -async function shootVector( - from, - to, - { speed = 500, color = null, onlyAnimate = true, trail = true } = {} -) { - options = { - onlyAnimate: onlyAnimate, - animate: { - duration: speed, - }, - }; - if (color) options.color = color; - const fromC = getCoordArray(from); - const toC = getCoordArray(to); - arcGen(fromC, toC, (options = options)); - - if (trail) { - updateTrailers(from, to); - } -} - -let trailers = []; -let lastTrailerUpdate = new Date().getTime(); -async function updateTrailers(from = undefined, to = undefined) { - let found = false; - if (from !== undefined && to !== undefined) { - // check if vector already exists and increase count - trailers.forEach((x) => { - if (x.from == from && x.to == to) { - found = true; - x.count += 1; - } - }); - if (!found) { - let newtrail = arcGen(getCoordArray(from), getCoordArray(to), { - color: "rgb(152,76, 0)", - }); - trailers.push({ to: to, from: from, count: 1, ref: newtrail }); - } - } - - // We don't want this calculation killing the processor, so it can only happen once every 5 seconds - // unless there's a new vector to the party so its opacity gets set - const now = new Date().getTime(); - if (found && now - lastTrailerUpdate < 5000) { - return; - } else { - lastTrailerUpdate = now; - } - - // weight brightness of vectors - let sum = 0; - const trailCount = trailers.length; - let max = 10; - trailers.forEach((x) => { - sum += x.count; - if (x.count > max) max = x.count; - }); - trailers.forEach((x, i) => { - let opacity = Math.sqrt(x.count / max); - x.ref._path.style.opacity = opacity; - }); -} - -function getCoordArray(ref) { - if (ref.properties == undefined) return ref; - let coords; - try { - coords = ref.properties.reference.getLatLng(); - } catch { - coords = ref.properties.reference.getBounds().getCenter(); - } - return [coords.lat, coords.lng]; -} - -function arcGen(latlng1, latlng2, options = {}) { - var latlngs = []; - - var offsetX = latlng2[1] - latlng1[1], - offsetY = latlng2[0] - latlng1[0]; - - var r = Math.sqrt(Math.pow(offsetX, 2) + Math.pow(offsetY, 2)), - theta = Math.atan2(offsetY, offsetX); - - var thetaOffset = 3.14 / 10; - - var r2 = r / 2 / Math.cos(thetaOffset), - theta2 = theta + thetaOffset; - - var midpointX = r2 * Math.cos(theta2) + latlng1[1], - midpointY = r2 * Math.sin(theta2) + latlng1[0]; - - var midpointLatLng = [midpointY, midpointX]; - - latlngs.push(latlng1, midpointLatLng, latlng2); - - var pathDefaults = { - color: "#b35900", - weight: 3, - hasBalls: true, - }; - - let pathOptions = Object.assign(pathDefaults, options); - - var curvedPath = L.curve( - ["M", latlng1, "Q", midpointLatLng, latlng2], - pathOptions - ).addTo(map); - - return curvedPath; -} - -function calcDistances(nodes) { - nodes.forEach((x) => { - x.properties.distances = {}; - const coords1 = getCoordArray(x); - nodes.forEach((y) => { - const coords2 = getCoordArray(y); - x.properties.distances[y.properties.mdo_id] = Math.sqrt( - Math.pow(coords1[0] - coords2[0], 2) + - Math.pow(coords1[1] - coords2[1], 2) - ); - }); - }); -} - -let countdownTo = new Date().getTime() + 5 * 60 * 1000; -function updateCountdown() { - const now = new Date().getTime(); - const countdown = countdownTo - now; - if (countdown < 1000) { - countdownTo = now + 5 * 60 * 1000; - getUpdate(); - } - try { - document.getElementById("countdownClock").textContent = Math.floor( - countdown / 1000 - ); - } catch {} -} - -async function getUpdate() { - console.log("Updating Occupancy Matrix"); - - let counts = await fetch(densityMapUrl + "/current"); - counts = await counts.json(); - - for (let i = 0; i < counts.length; i++) { - const pt = - counts[i].mdo_id == null - ? pts[counts[i].location] - : pts[counts[i].mdo_id]; - if (pt == undefined) continue; - pt.properties.diff = counts[i].count - pt.properties.count; - pt.properties.count = counts[i].count; - setMarker(pt, pt.properties.reference); - } - - let shots = getShots(Object.values(pts)); - shots = shuffle(shuffle(shots)); - const timeBetween = (60000 * 5 + 1) / shots.length; - - // randomize time delay - let timeDelay = []; - shots.forEach(() => { - timeDelay.push(Math.random()); - }); - const interval = 60000 * 5; // 5 minute delay - for (let i = 0; i < timeDelay.length; i++) { - timeDelay[i] = timeDelay[i] * interval; - } - - console.log( - `Shot total for next 5 minutes: ${shots.length} - ${ - timeBetween / 1000 - } second intervals` - ); - updateLegend(shots.length); - for (let i = 0; i < shots.length; i++) { - loadShot(shots[i], timeDelay[i], { trail: true }); - } -} - -async function loadShot(shot, delay, { trail = false } = {}) { - await sleep(delay); - shootVector(shot[0], shot[1], { trail: trail }); -} - -function findOneShot(nodes, target) { - let sortedByDistance = nodes.sort((a, b) => { - return ( - target.properties.distances[a.properties.mdo_id] - - target.properties.distances[b.properties.mdo_id] - ); - }); - const sign = target.properties.diff > 0; - for (let x = 1; x < sortedByDistance.length; x++) { - if (sortedByDistance[x].properties.diff > 0 !== sign) { - return sortedByDistance[x]; - } - } -} - -function getShots(nodes) { - let noChange = false; - let shots = []; - let sourcesAndSinks = nodes.filter((x) => { - return x.properties.diff !== 0; - }); - - let i; - while (!noChange && sourcesAndSinks.length > 0) { - noChange = true; - // sourcesAndSinks.forEach((x) => { - // x.properties.changed = false; - // }); - // for (let i = sourcesAndSinks.length - 1; i >= 0; i--) { - // try { - // if (sourcesAndSinks[i].properties.changed) continue; // this node is a prior recipient this iteration - // } catch { - // continue; - // } - let sorted = sourcesAndSinks.sort((a, b) => { - Math.abs(a.properties.diff) - Math.abs(b.properties.diff); - }); - i = sourcesAndSinks.indexOf(sorted[0]); - let recipient = findOneShot(sourcesAndSinks, sourcesAndSinks[i]); - if (recipient) { - let shotArr; - if (sourcesAndSinks[i].properties.diff > 0) { - shotArr = [sourcesAndSinks[i], recipient]; - sourcesAndSinks[i].properties.diff--; - recipient.properties.diff++; - } else { - shotArr = [recipient, sourcesAndSinks[i]]; - sourcesAndSinks[i].properties.diff++; - recipient.properties.diff--; - } - shots.push(shotArr); - noChange = false; - sourcesAndSinks[i].properties.changed = true; - recipient.properties.changed = true; - - let tmpRef = recipient; - if (sourcesAndSinks[i].properties.diff == 0) { - sourcesAndSinks.splice(i, 1); - } - if ( - sourcesAndSinks[sourcesAndSinks.indexOf(tmpRef)].properties.diff == 0 - ) { - sourcesAndSinks.splice(recipient, 1); - } - } - // } - } - - // if no more people on campus, get them from space - sourcesAndSinks.forEach((x) => { - while (x.properties.diff > 0) { - shots.push([x, x.properties.space]); - x.properties.diff--; - } - - while (x.properties.diff < 0) { - shots.push([x.properties.space, x]); - x.properties.diff++; - } - }); - - return shots; -} - -const useLegend = window.location.pathname.replaceAll("/", "") == "hotspots"; -init(useLegend).then(() => { - // map.on("click", () => { - // shootVector(pts[2], pts[8]); - // }); - // shootVector(pts[0], pts[1], {speed: 500}); - let ptsarr = Object.values(pts); - calcDistances(ptsarr); - setSpace(ptsarr); - getUpdate(); - setInterval(updateCountdown, 1000); -}); diff --git a/src/static/js/lib/CUSTOM.leaflet.curve.js b/src/static/js/lib/CUSTOM.leaflet.curve.js deleted file mode 100644 index fb99f63..0000000 --- a/src/static/js/lib/CUSTOM.leaflet.curve.js +++ /dev/null @@ -1,558 +0,0 @@ -/* - * Leaflet.curve v0.9.2 - a plugin for Leaflet mapping library. https://github.com/elfalem/Leaflet.curve - * (c) elfalem 2015-2023 - */ -/* - * note that SVG (x, y) corresponds to (long, lat) - */ - -L.Curve = L.Path.extend({ - options: {}, - - initialize: function (path, options) { - L.setOptions(this, options); - this._setPath(path); - }, - - // Added to follow the naming convention of L.Polyline and other Leaflet component classes: - // (https://leafletjs.com/reference-1.6.0.html#polyline-setlatlngs) - setLatLngs: function (path) { - return this.setPath(path); - }, - - getLatLngs: function () { - return this.getPath(); - }, - - _updateBounds: function () { - var tolerance = this._clickTolerance(); - var tolerancePoint = new L.Point(tolerance, tolerance); - - //_pxBounds is critical for canvas renderer, used to determine area that needs redrawing - this._pxBounds = new L.Bounds([ - this._rawPxBounds.min.subtract(tolerancePoint), - this._rawPxBounds.max.add(tolerancePoint), - ]); - }, - - getPath: function () { - return this._coords; - }, - - setPath: function (path) { - this._setPath(path); - return this.redraw(); - }, - - getBounds: function () { - return this._bounds; - }, - - _setPath: function (path) { - this._coords = path; - this._bounds = this._computeBounds(); - }, - - _computeBounds: function () { - var bound = new L.LatLngBounds(); - var lastPoint; - var lastCommand; - var coord; - for (var i = 0; i < this._coords.length; i++) { - coord = this._coords[i]; - if (typeof coord == "string" || coord instanceof String) { - lastCommand = coord; - } else if (lastCommand == "H") { - bound.extend([lastPoint.lat, coord[0]]); - lastPoint = new L.latLng(lastPoint.lat, coord[0]); - } else if (lastCommand == "V") { - bound.extend([coord[0], lastPoint.lng]); - lastPoint = new L.latLng(coord[0], lastPoint.lng); - } else if (lastCommand == "C") { - var controlPoint1 = new L.latLng(coord[0], coord[1]); - coord = this._coords[++i]; - var controlPoint2 = new L.latLng(coord[0], coord[1]); - coord = this._coords[++i]; - var endPoint = new L.latLng(coord[0], coord[1]); - - bound.extend(controlPoint1); - bound.extend(controlPoint2); - bound.extend(endPoint); - - endPoint.controlPoint1 = controlPoint1; - endPoint.controlPoint2 = controlPoint2; - lastPoint = endPoint; - } else if (lastCommand == "S") { - var controlPoint2 = new L.latLng(coord[0], coord[1]); - coord = this._coords[++i]; - var endPoint = new L.latLng(coord[0], coord[1]); - - var controlPoint1 = lastPoint; - if (lastPoint.controlPoint2) { - var diffLat = lastPoint.lat - lastPoint.controlPoint2.lat; - var diffLng = lastPoint.lng - lastPoint.controlPoint2.lng; - controlPoint1 = new L.latLng( - lastPoint.lat + diffLat, - lastPoint.lng + diffLng - ); - } - - bound.extend(controlPoint1); - bound.extend(controlPoint2); - bound.extend(endPoint); - - endPoint.controlPoint1 = controlPoint1; - endPoint.controlPoint2 = controlPoint2; - lastPoint = endPoint; - } else if (lastCommand == "Q") { - var controlPoint = new L.latLng(coord[0], coord[1]); - coord = this._coords[++i]; - var endPoint = new L.latLng(coord[0], coord[1]); - - bound.extend(controlPoint); - bound.extend(endPoint); - - endPoint.controlPoint = controlPoint; - lastPoint = endPoint; - } else if (lastCommand == "T") { - var endPoint = new L.latLng(coord[0], coord[1]); - - var controlPoint = lastPoint; - if (lastPoint.controlPoint) { - var diffLat = lastPoint.lat - lastPoint.controlPoint.lat; - var diffLng = lastPoint.lng - lastPoint.controlPoint.lng; - controlPoint = new L.latLng( - lastPoint.lat + diffLat, - lastPoint.lng + diffLng - ); - } - - bound.extend(controlPoint); - bound.extend(endPoint); - - endPoint.controlPoint = controlPoint; - lastPoint = endPoint; - } else { - bound.extend(coord); - lastPoint = new L.latLng(coord[0], coord[1]); - } - } - return bound; - }, - - getCenter: function () { - return this._bounds.getCenter(); - }, - - // _update() is invoked by Path._reset() - _update: function () { - if (!this._map) { - return; - } - - // TODO: consider implementing this._clipPoints(); and this._simplifyPoints(); to improve performance - this._updatePath(); - }, - - _updatePath: function () { - // the following can be thought of as this._renderer.updateCurve() in both SVG/Canvas renderers - // similar to Canvas._updatePoly(), Canvas._updateCircle(), etc... - if (this._usingCanvas) { - this._updateCurveCanvas(); - } else { - this._updateCurveSvg(); - } - }, - - //_project() is invoked by Path._reset() - _project: function () { - var coord, lastCoord, curCommand, curPoint; - - this._points = []; - - for (var i = 0; i < this._coords.length; i++) { - coord = this._coords[i]; - if (typeof coord == "string" || coord instanceof String) { - this._points.push(coord); - curCommand = coord; - } else { - switch (coord.length) { - case 2: - curPoint = this._map.latLngToLayerPoint(coord); - lastCoord = coord; - break; - case 1: - if (curCommand == "H") { - curPoint = this._map.latLngToLayerPoint([lastCoord[0], coord[0]]); - lastCoord = [lastCoord[0], coord[0]]; - } else { - curPoint = this._map.latLngToLayerPoint([coord[0], lastCoord[1]]); - lastCoord = [coord[0], lastCoord[1]]; - } - break; - } - this._points.push(curPoint); - } - } - - if (this._bounds.isValid()) { - var northWestLayerPoint = this._map.latLngToLayerPoint( - this._bounds.getNorthWest() - ); - var southEastLayerPoint = this._map.latLngToLayerPoint( - this._bounds.getSouthEast() - ); - this._rawPxBounds = new L.Bounds( - northWestLayerPoint, - southEastLayerPoint - ); - this._updateBounds(); - } - }, - - _curvePointsToPath: function (points) { - var point, - curCommand, - str = ""; - for (var i = 0; i < points.length; i++) { - point = points[i]; - if (typeof point == "string" || point instanceof String) { - curCommand = point; - str += curCommand; - } else { - switch (curCommand) { - case "H": - str += point.x + " "; - break; - case "V": - str += point.y + " "; - break; - default: - str += point.x + "," + point.y + " "; - break; - } - } - } - return str || "M0 0"; - }, - - beforeAdd: function (map) { - L.Path.prototype.beforeAdd.call(this, map); - - this._usingCanvas = this._renderer instanceof L.Canvas; - - if (this._usingCanvas) { - this._pathSvgElement = document.createElementNS( - "http://www.w3.org/2000/svg", - "path" - ); - } - }, - - onAdd: function (map) { - if (this._usingCanvas) { - // determine if dash array is set by user - this._canvasSetDashArray = !this.options.dashArray; - } - - L.Path.prototype.onAdd.call(this, map); // calls _update() - - if (this._usingCanvas) { - if (this.options.animate && typeof TWEEN === "object") { - this._normalizeCanvasAnimationOptions(); - - this._tweenedObject = { offset: this._pathSvgElement.getTotalLength() }; - this._tween = new TWEEN.Tween(this._tweenedObject) - .to({ offset: 0 }, this.options.animate.duration) - // difference of behavior with SVG, delay occurs on every iteration - .delay(this.options.animate.delay) - .repeat(this.options.animate.iterations - 1) - .onComplete( - (function (scope) { - return function () { - scope._canvasAnimating = false; - }; - })(this) - ) - .start(); - - this._canvasAnimating = true; - this._animateCanvas(); - } else { - this._canvasAnimating = false; - } - } else { - if (this.options.animate && this._path.animate) { - var length = Math.min(this._svgSetDashArray(), 1000); - this._path.pathLength.baseVal = length; - keyframes = [ - { strokeDashoffset: length }, - { strokeDashoffset: 0 } - ] - if (!this.options.fade) keyframes.push({ strokeDashoffset: -length }); - let animation = this._path.animate( - keyframes, - this.options.animate - ); - if (this.options.fade) { - animation.onfinish = () => { - this._path.animate( - [{ opacity: 1 }, { opacity: 0 }], - this.options.fadeSpeed - ).onfinish = () => { this.remove()}; - }; - } else if (this.options.onlyAnimate) { - animation.onfinish = () => { - this.remove(); - }; - } - } - } - }, - - // SVG specific logic - _updateCurveSvg: function () { - this._renderer._setPath(this, this._curvePointsToPath(this._points)); - - if (this.options.animate) { - this._svgSetDashArray(); - } - }, - - _svgSetDashArray: function () { - var path = this._path; - var length = path.getTotalLength(); - - if (!this.options.dashArray) { - path.style.strokeDasharray = length + " " + length; - } - return length; - }, - - // Needed by the `Canvas` renderer for interactivity - _containsPoint: function (layerPoint) { - if (!this._bounds.isValid()) { - return false; - } - return this._bounds.contains(this._map.layerPointToLatLng(layerPoint)); - }, - - // Canvas specific logic below here - _normalizeCanvasAnimationOptions: function () { - var opts = { - delay: 0, - duration: 0, - iterations: 1, - }; - if (typeof this.options.animate == "number") { - opts.duration = this.options.animate; - } else { - if (this.options.animate.duration) { - opts.duration = this.options.animate.duration; - } - if (this.options.animate.delay) { - opts.delay = this.options.animate.delay; - } - if (this.options.animate.iterations) { - opts.iterations = this.options.animate.iterations; - } - } - - this.options.animate = opts; - }, - - _updateCurveCanvas: function () { - var pathString = this._curvePointsToPath(this._points); - this._pathSvgElement.setAttribute("d", pathString); - - if ( - this.options.animate && - typeof TWEEN === "object" && - this._canvasSetDashArray - ) { - this.options.dashArray = this._pathSvgElement.getTotalLength() + ""; - this._renderer._updateDashArray(this); - } - - this._curveFillStroke(new Path2D(pathString), this._renderer._ctx); - }, - - _animateCanvas: function () { - TWEEN.update(); - - // clear out area and re-render all layers - this._renderer._updatePaths(); - - if (this._canvasAnimating) { - this._animationFrameId = L.Util.requestAnimFrame( - this._animateCanvas, - this - ); - } - }, - - // similar to Canvas._fillStroke(ctx, layer) - _curveFillStroke: function (path2d, ctx) { - ctx.lineDashOffset = this._canvasAnimating - ? this._tweenedObject.offset - : 0.0; - - var options = this.options; - - if (options.fill) { - ctx.globalAlpha = options.fillOpacity; - ctx.fillStyle = options.fillColor || options.color; - ctx.fill(path2d, options.fillRule || "evenodd"); - } - - if (options.stroke && options.weight !== 0) { - if (ctx.setLineDash) { - ctx.setLineDash((this.options && this.options._dashArray) || []); - } - ctx.globalAlpha = options.opacity; - ctx.lineWidth = options.weight; - ctx.strokeStyle = options.color; - ctx.lineCap = options.lineCap; - ctx.lineJoin = options.lineJoin; - ctx.stroke(path2d); - } - }, - - // path tracing logic below here - trace: function (t) { - // initially map is undefined, but then null if curve was added and removed - if (this._map === undefined || this._map === null) { - return []; - } - - t = t.filter(function (element) { - return element >= 0 && element <= 1; - }); - - var point, curCommand, curStartPoint, curEndPoint; - var p1, p2, p3; - var samples = []; - for (var i = 0; i < this._points.length; i++) { - point = this._points[i]; - if (typeof point == "string" || point instanceof String) { - curCommand = point; - - if (curCommand == "Z") { - samples = samples.concat( - this._linearTrace(t, curEndPoint, curStartPoint) - ); - } - } else { - switch (curCommand) { - case "M": - curStartPoint = point; - curEndPoint = point; - break; - case "L": - case "H": - case "V": - samples = samples.concat(this._linearTrace(t, curEndPoint, point)); - - curEndPoint = point; - break; - case "C": - p1 = point; - p2 = this._points[++i]; - p3 = this._points[++i]; - samples = samples.concat( - this._cubicTrace(t, curEndPoint, p1, p2, p3) - ); - - curEndPoint = p3; - break; - case "S": - p1 = this._reflectPoint(p2, curEndPoint); - p2 = point; - p3 = this._points[++i]; - samples = samples.concat( - this._cubicTrace(t, curEndPoint, p1, p2, p3) - ); - - curEndPoint = p3; - break; - case "Q": - p1 = point; - p2 = this._points[++i]; - samples = samples.concat( - this._quadraticTrace(t, curEndPoint, p1, p2) - ); - - curEndPoint = p2; - break; - case "T": - p1 = this._reflectPoint(p1, curEndPoint); - p2 = point; - samples = samples.concat( - this._quadraticTrace(t, curEndPoint, p1, p2) - ); - - curEndPoint = p2; - break; - default: - break; - } - } - } - return samples; - }, - _linearTrace: function (t, p0, p1) { - return t.map((interval) => { - var x = this._singleLinearTrace(interval, p0.x, p1.x); - var y = this._singleLinearTrace(interval, p0.y, p1.y); - return this._map.layerPointToLatLng([x, y]); - }); - }, - _quadraticTrace: function (t, p0, p1, p2) { - return t.map((interval) => { - var x = this._singleQuadraticTrace(interval, p0.x, p1.x, p2.x); - var y = this._singleQuadraticTrace(interval, p0.y, p1.y, p2.y); - return this._map.layerPointToLatLng([x, y]); - }); - }, - _cubicTrace: function (t, p0, p1, p2, p3) { - return t.map((interval) => { - var x = this._singleCubicTrace(interval, p0.x, p1.x, p2.x, p3.x); - var y = this._singleCubicTrace(interval, p0.y, p1.y, p2.y, p3.y); - return this._map.layerPointToLatLng([x, y]); - }); - }, - _singleLinearTrace: function (t, p0, p1) { - return p0 + t * (p1 - p0); - }, - _singleQuadraticTrace: function (t, p0, p1, p2) { - var oneMinusT = 1 - t; - return ( - Math.pow(oneMinusT, 2) * p0 + 2 * oneMinusT * t * p1 + Math.pow(t, 2) * p2 - ); - }, - _singleCubicTrace: function (t, p0, p1, p2, p3) { - var oneMinusT = 1 - t; - return ( - Math.pow(oneMinusT, 3) * p0 + - 3 * Math.pow(oneMinusT, 2) * t * p1 + - 3 * oneMinusT * Math.pow(t, 2) * p2 + - Math.pow(t, 3) * p3 - ); - }, - _reflectPoint: function (point, over) { - x = over.x + (over.x - point.x); - y = over.y + (over.y - point.y); - return L.point(x, y); - }, -}); - -L.curve = function (path, options) { - return new L.Curve(path, options); -}; - -// async function killMe(promise, obj){ -// await promise; -// // obj.remove(); -// console.log("killed"); -// console.log(promise); -// } diff --git a/src/static/js/lib/leaflet-providers.js b/src/static/js/lib/leaflet-providers.js deleted file mode 100644 index bcde1ed..0000000 --- a/src/static/js/lib/leaflet-providers.js +++ /dev/null @@ -1,1178 +0,0 @@ -(function (root, factory) { - if (typeof define === 'function' && define.amd) { - // AMD. Register as an anonymous module. - define(['leaflet'], factory); - } else if (typeof modules === 'object' && module.exports) { - // define a Common JS module that relies on 'leaflet' - module.exports = factory(require('leaflet')); - } else { - // Assume Leaflet is loaded into global object L already - factory(L); - } -}(this, function (L) { - 'use strict'; - - L.TileLayer.Provider = L.TileLayer.extend({ - initialize: function (arg, options) { - var providers = L.TileLayer.Provider.providers; - - var parts = arg.split('.'); - - var providerName = parts[0]; - var variantName = parts[1]; - - if (!providers[providerName]) { - throw 'No such provider (' + providerName + ')'; - } - - var provider = { - url: providers[providerName].url, - options: providers[providerName].options - }; - - // overwrite values in provider from variant. - if (variantName && 'variants' in providers[providerName]) { - if (!(variantName in providers[providerName].variants)) { - throw 'No such variant of ' + providerName + ' (' + variantName + ')'; - } - var variant = providers[providerName].variants[variantName]; - var variantOptions; - if (typeof variant === 'string') { - variantOptions = { - variant: variant - }; - } else { - variantOptions = variant.options; - } - provider = { - url: variant.url || provider.url, - options: L.Util.extend({}, provider.options, variantOptions) - }; - } - - // replace attribution placeholders with their values from toplevel provider attribution, - // recursively - var attributionReplacer = function (attr) { - if (attr.indexOf('{attribution.') === -1) { - return attr; - } - return attr.replace(/\{attribution.(\w*)\}/g, - function (match, attributionName) { - return attributionReplacer(providers[attributionName].options.attribution); - } - ); - }; - provider.options.attribution = attributionReplacer(provider.options.attribution); - - // Compute final options combining provider options with any user overrides - var layerOpts = L.Util.extend({}, provider.options, options); - L.TileLayer.prototype.initialize.call(this, provider.url, layerOpts); - } - }); - - /** - * Definition of providers. - * see http://leafletjs.com/reference.html#tilelayer for options in the options map. - */ - - L.TileLayer.Provider.providers = { - OpenStreetMap: { - url: 'https://tile.openstreetmap.org/{z}/{x}/{y}.png', - options: { - maxZoom: 19, - attribution: - '© OpenStreetMap contributors' - }, - variants: { - Mapnik: {}, - DE: { - url: 'https://tile.openstreetmap.de/{z}/{x}/{y}.png', - options: { - maxZoom: 18 - } - }, - CH: { - url: 'https://tile.osm.ch/switzerland/{z}/{x}/{y}.png', - options: { - maxZoom: 18, - bounds: [[45, 5], [48, 11]] - } - }, - France: { - url: 'https://{s}.tile.openstreetmap.fr/osmfr/{z}/{x}/{y}.png', - options: { - maxZoom: 20, - attribution: '© OpenStreetMap France | {attribution.OpenStreetMap}' - } - }, - HOT: { - url: 'https://{s}.tile.openstreetmap.fr/hot/{z}/{x}/{y}.png', - options: { - attribution: - '{attribution.OpenStreetMap}, ' + - 'Tiles style by Humanitarian OpenStreetMap Team ' + - 'hosted by OpenStreetMap France' - } - }, - BZH: { - url: 'https://tile.openstreetmap.bzh/br/{z}/{x}/{y}.png', - options: { - attribution: '{attribution.OpenStreetMap}, Tiles courtesy of Breton OpenStreetMap Team', - bounds: [[46.2, -5.5], [50, 0.7]] - } - } - } - }, - MapTilesAPI: { - url: 'https://maptiles.p.rapidapi.com/{variant}/{z}/{x}/{y}.png?rapidapi-key={apikey}', - options: { - attribution: - '© MapTiles API, {attribution.OpenStreetMap}', - variant: 'en/map/v1', - // Get your own MapTiles API access token here : https://www.maptilesapi.com/ - // NB : this is a demonstration key that comes with no guarantee and not to be used in production - apikey: '', - maxZoom: 19 - }, - variants: { - OSMEnglish: { - options: { - variant: 'en/map/v1' - } - }, - OSMFrancais: { - options: { - variant: 'fr/map/v1' - } - }, - OSMEspagnol: { - options: { - variant: 'es/map/v1' - } - } - } - }, - OpenSeaMap: { - url: 'https://tiles.openseamap.org/seamark/{z}/{x}/{y}.png', - options: { - attribution: 'Map data: © OpenSeaMap contributors' - } - }, - OPNVKarte: { - url: 'https://tileserver.memomaps.de/tilegen/{z}/{x}/{y}.png', - options: { - maxZoom: 18, - attribution: 'Map memomaps.de CC-BY-SA, map data {attribution.OpenStreetMap}' - } - }, - OpenTopoMap: { - url: 'https://{s}.tile.opentopomap.org/{z}/{x}/{y}.png', - options: { - maxZoom: 17, - attribution: 'Map data: {attribution.OpenStreetMap}, SRTM | Map style: © OpenTopoMap (CC-BY-SA)' - } - }, - OpenRailwayMap: { - url: 'https://{s}.tiles.openrailwaymap.org/standard/{z}/{x}/{y}.png', - options: { - maxZoom: 19, - attribution: 'Map data: {attribution.OpenStreetMap} | Map style: © OpenRailwayMap (CC-BY-SA)' - } - }, - OpenFireMap: { - url: 'http://openfiremap.org/hytiles/{z}/{x}/{y}.png', - options: { - maxZoom: 19, - attribution: 'Map data: {attribution.OpenStreetMap} | Map style: © OpenFireMap (CC-BY-SA)' - } - }, - SafeCast: { - url: 'https://s3.amazonaws.com/te512.safecast.org/{z}/{x}/{y}.png', - options: { - maxZoom: 16, - attribution: 'Map data: {attribution.OpenStreetMap} | Map style: © SafeCast (CC-BY-SA)' - } - }, - Stadia: { - url: 'https://tiles.stadiamaps.com/tiles/{variant}/{z}/{x}/{y}{r}.{ext}', - options: { - minZoom: 0, - maxZoom: 20, - attribution: - '© Stadia Maps ' + - '© OpenMapTiles ' + - '{attribution.OpenStreetMap}', - variant: 'alidade_smooth', - ext: 'png' - }, - variants: { - AlidadeSmooth: 'alidade_smooth', - AlidadeSmoothDark: 'alidade_smooth_dark', - OSMBright: 'osm_bright', - Outdoors: 'outdoors', - StamenToner: { - options: { - attribution: - '© Stadia Maps ' + - '© Stamen Design ' + - '© OpenMapTiles ' + - '{attribution.OpenStreetMap}', - variant: 'stamen_toner' - } - }, - StamenTonerBackground: { - options: { - attribution: - '© Stadia Maps ' + - '© Stamen Design ' + - '© OpenMapTiles ' + - '{attribution.OpenStreetMap}', - variant: 'stamen_toner_background' - } - }, - StamenTonerLines: { - options: { - attribution: - '© Stadia Maps ' + - '© Stamen Design ' + - '© OpenMapTiles ' + - '{attribution.OpenStreetMap}', - variant: 'stamen_toner_lines' - } - }, - StamenTonerLabels: { - options: { - attribution: - '© Stadia Maps ' + - '© Stamen Design ' + - '© OpenMapTiles ' + - '{attribution.OpenStreetMap}', - variant: 'stamen_toner_labels' - } - }, - StamenTonerLite: { - options: { - attribution: - '© Stadia Maps ' + - '© Stamen Design ' + - '© OpenMapTiles ' + - '{attribution.OpenStreetMap}', - variant: 'stamen_toner_lite' - } - }, - StamenWatercolor: { - url: 'https://tiles.stadiamaps.com/tiles/{variant}/{z}/{x}/{y}.{ext}', - options: { - attribution: - '© Stadia Maps ' + - '© Stamen Design ' + - '© OpenMapTiles ' + - '{attribution.OpenStreetMap}', - variant: 'stamen_watercolor', - ext: 'jpg', - minZoom: 1, - maxZoom: 16 - } - }, - StamenTerrain: { - options: { - attribution: - '© Stadia Maps ' + - '© Stamen Design ' + - '© OpenMapTiles ' + - '{attribution.OpenStreetMap}', - variant: 'stamen_terrain', - minZoom: 0, - maxZoom: 18 - } - }, - StamenTerrainBackground: { - options: { - attribution: - '© Stadia Maps ' + - '© Stamen Design ' + - '© OpenMapTiles ' + - '{attribution.OpenStreetMap}', - variant: 'stamen_terrain_background', - minZoom: 0, - maxZoom: 18 - } - }, - StamenTerrainLabels: { - options: { - attribution: - '© Stadia Maps ' + - '© Stamen Design ' + - '© OpenMapTiles ' + - '{attribution.OpenStreetMap}', - variant: 'stamen_terrain_labels', - minZoom: 0, - maxZoom: 18 - } - }, - StamenTerrainLines: { - options: { - attribution: - '© Stadia Maps ' + - '© Stamen Design ' + - '© OpenMapTiles ' + - '{attribution.OpenStreetMap}', - variant: 'stamen_terrain_lines', - minZoom: 0, - maxZoom: 18 - } - } - } - }, - Thunderforest: { - url: 'https://{s}.tile.thunderforest.com/{variant}/{z}/{x}/{y}.png?apikey={apikey}', - options: { - attribution: - '© Thunderforest, {attribution.OpenStreetMap}', - variant: 'cycle', - apikey: '', - maxZoom: 22 - }, - variants: { - OpenCycleMap: 'cycle', - Transport: { - options: { - variant: 'transport' - } - }, - TransportDark: { - options: { - variant: 'transport-dark' - } - }, - SpinalMap: { - options: { - variant: 'spinal-map' - } - }, - Landscape: 'landscape', - Outdoors: 'outdoors', - Pioneer: 'pioneer', - MobileAtlas: 'mobile-atlas', - Neighbourhood: 'neighbourhood' - } - }, - CyclOSM: { - url: 'https://{s}.tile-cyclosm.openstreetmap.fr/cyclosm/{z}/{x}/{y}.png', - options: { - maxZoom: 20, - attribution: 'CyclOSM | Map data: {attribution.OpenStreetMap}' - } - }, - Jawg: { - url: 'https://{s}.tile.jawg.io/{variant}/{z}/{x}/{y}{r}.png?access-token={accessToken}', - options: { - attribution: - '© JawgMaps ' + - '{attribution.OpenStreetMap}', - minZoom: 0, - maxZoom: 22, - subdomains: 'abcd', - variant: 'jawg-terrain', - // Get your own Jawg access token here : https://www.jawg.io/lab/ - // NB : this is a demonstration key that comes with no guarantee - accessToken: '', - }, - variants: { - Streets: 'jawg-streets', - Terrain: 'jawg-terrain', - Sunny: 'jawg-sunny', - Dark: 'jawg-dark', - Light: 'jawg-light', - Matrix: 'jawg-matrix' - } - }, - MapBox: { - url: 'https://api.mapbox.com/styles/v1/{id}/tiles/{z}/{x}/{y}{r}?access_token={accessToken}', - options: { - attribution: - '© Mapbox ' + - '{attribution.OpenStreetMap} ' + - 'Improve this map', - tileSize: 512, - maxZoom: 18, - zoomOffset: -1, - id: 'mapbox/streets-v11', - accessToken: '', - } - }, - MapTiler: { - url: 'https://api.maptiler.com/maps/{variant}/{z}/{x}/{y}{r}.{ext}?key={key}', - options: { - attribution: - '© MapTiler © OpenStreetMap contributors', - variant: 'streets', - ext: 'png', - key: '', - tileSize: 512, - zoomOffset: -1, - minZoom: 0, - maxZoom: 21 - }, - variants: { - Streets: 'streets', - Basic: 'basic', - Bright: 'bright', - Pastel: 'pastel', - Positron: 'positron', - Hybrid: { - options: { - variant: 'hybrid', - ext: 'jpg' - } - }, - Toner: 'toner', - Topo: 'topo', - Voyager: 'voyager' - } - }, - TomTom: { - url: 'https://{s}.api.tomtom.com/map/1/tile/{variant}/{style}/{z}/{x}/{y}.{ext}?key={apikey}', - options: { - variant: 'basic', - maxZoom: 22, - attribution: - '© 1992 - ' + new Date().getFullYear() + ' TomTom. ', - subdomains: 'abcd', - style: 'main', - ext: 'png', - apikey: '', - }, - variants: { - Basic: 'basic', - Hybrid: 'hybrid', - Labels: 'labels' - } - }, - Esri: { - url: 'https://server.arcgisonline.com/ArcGIS/rest/services/{variant}/MapServer/tile/{z}/{y}/{x}', - options: { - variant: 'World_Street_Map', - attribution: 'Tiles © Esri' - }, - variants: { - WorldStreetMap: { - options: { - attribution: - '{attribution.Esri} — ' + - 'Source: Esri, DeLorme, NAVTEQ, USGS, Intermap, iPC, NRCAN, Esri Japan, METI, Esri China (Hong Kong), Esri (Thailand), TomTom, 2012' - } - }, - DeLorme: { - options: { - variant: 'Specialty/DeLorme_World_Base_Map', - minZoom: 1, - maxZoom: 11, - attribution: '{attribution.Esri} — Copyright: ©2012 DeLorme' - } - }, - WorldTopoMap: { - options: { - variant: 'World_Topo_Map', - attribution: - '{attribution.Esri} — ' + - 'Esri, DeLorme, NAVTEQ, TomTom, Intermap, iPC, USGS, FAO, NPS, NRCAN, GeoBase, Kadaster NL, Ordnance Survey, Esri Japan, METI, Esri China (Hong Kong), and the GIS User Community' - } - }, - WorldImagery: { - options: { - variant: 'World_Imagery', - attribution: - '{attribution.Esri} — ' + - 'Source: Esri, i-cubed, USDA, USGS, AEX, GeoEye, Getmapping, Aerogrid, IGN, IGP, UPR-EGP, and the GIS User Community' - } - }, - WorldTerrain: { - options: { - variant: 'World_Terrain_Base', - maxZoom: 13, - attribution: - '{attribution.Esri} — ' + - 'Source: USGS, Esri, TANA, DeLorme, and NPS' - } - }, - WorldShadedRelief: { - options: { - variant: 'World_Shaded_Relief', - maxZoom: 13, - attribution: '{attribution.Esri} — Source: Esri' - } - }, - WorldPhysical: { - options: { - variant: 'World_Physical_Map', - maxZoom: 8, - attribution: '{attribution.Esri} — Source: US National Park Service' - } - }, - OceanBasemap: { - options: { - variant: 'Ocean/World_Ocean_Base', - maxZoom: 13, - attribution: '{attribution.Esri} — Sources: GEBCO, NOAA, CHS, OSU, UNH, CSUMB, National Geographic, DeLorme, NAVTEQ, and Esri' - } - }, - NatGeoWorldMap: { - options: { - variant: 'NatGeo_World_Map', - maxZoom: 16, - attribution: '{attribution.Esri} — National Geographic, Esri, DeLorme, NAVTEQ, UNEP-WCMC, USGS, NASA, ESA, METI, NRCAN, GEBCO, NOAA, iPC' - } - }, - WorldGrayCanvas: { - options: { - variant: 'Canvas/World_Light_Gray_Base', - maxZoom: 16, - attribution: '{attribution.Esri} — Esri, DeLorme, NAVTEQ' - } - } - } - }, - OpenWeatherMap: { - url: 'http://{s}.tile.openweathermap.org/map/{variant}/{z}/{x}/{y}.png?appid={apiKey}', - options: { - maxZoom: 19, - attribution: 'Map data © OpenWeatherMap', - apiKey: '', - opacity: 0.5 - }, - variants: { - Clouds: 'clouds', - CloudsClassic: 'clouds_cls', - Precipitation: 'precipitation', - PrecipitationClassic: 'precipitation_cls', - Rain: 'rain', - RainClassic: 'rain_cls', - Pressure: 'pressure', - PressureContour: 'pressure_cntr', - Wind: 'wind', - Temperature: 'temp', - Snow: 'snow' - } - }, - HERE: { - /* - * HERE maps, formerly Nokia maps. - * These basemaps are free, but you need an api id and app key. Please sign up at - * https://developer.here.com/plans - */ - url: - 'https://{s}.{base}.maps.api.here.com/maptile/2.1/' + - '{type}/{mapID}/{variant}/{z}/{x}/{y}/{size}/{format}?' + - 'app_id={app_id}&app_code={app_code}&lg={language}', - options: { - attribution: - 'Map © 1987-' + new Date().getFullYear() + ' HERE', - subdomains: '1234', - mapID: 'newest', - 'app_id': '', - 'app_code': '', - base: 'base', - variant: 'normal.day', - maxZoom: 20, - type: 'maptile', - language: 'eng', - format: 'png8', - size: '256' - }, - variants: { - normalDay: 'normal.day', - normalDayCustom: 'normal.day.custom', - normalDayGrey: 'normal.day.grey', - normalDayMobile: 'normal.day.mobile', - normalDayGreyMobile: 'normal.day.grey.mobile', - normalDayTransit: 'normal.day.transit', - normalDayTransitMobile: 'normal.day.transit.mobile', - normalDayTraffic: { - options: { - variant: 'normal.traffic.day', - base: 'traffic', - type: 'traffictile' - } - }, - normalNight: 'normal.night', - normalNightMobile: 'normal.night.mobile', - normalNightGrey: 'normal.night.grey', - normalNightGreyMobile: 'normal.night.grey.mobile', - normalNightTransit: 'normal.night.transit', - normalNightTransitMobile: 'normal.night.transit.mobile', - reducedDay: 'reduced.day', - reducedNight: 'reduced.night', - basicMap: { - options: { - type: 'basetile' - } - }, - mapLabels: { - options: { - type: 'labeltile', - format: 'png' - } - }, - trafficFlow: { - options: { - base: 'traffic', - type: 'flowtile' - } - }, - carnavDayGrey: 'carnav.day.grey', - hybridDay: { - options: { - base: 'aerial', - variant: 'hybrid.day' - } - }, - hybridDayMobile: { - options: { - base: 'aerial', - variant: 'hybrid.day.mobile' - } - }, - hybridDayTransit: { - options: { - base: 'aerial', - variant: 'hybrid.day.transit' - } - }, - hybridDayGrey: { - options: { - base: 'aerial', - variant: 'hybrid.grey.day' - } - }, - hybridDayTraffic: { - options: { - variant: 'hybrid.traffic.day', - base: 'traffic', - type: 'traffictile' - } - }, - pedestrianDay: 'pedestrian.day', - pedestrianNight: 'pedestrian.night', - satelliteDay: { - options: { - base: 'aerial', - variant: 'satellite.day' - } - }, - terrainDay: { - options: { - base: 'aerial', - variant: 'terrain.day' - } - }, - terrainDayMobile: { - options: { - base: 'aerial', - variant: 'terrain.day.mobile' - } - } - } - }, - HEREv3: { - /* - * HERE maps API Version 3. - * These basemaps are free, but you need an API key. Please sign up at - * https://developer.here.com/plans - * Version 3 deprecates the app_id and app_code access in favor of apiKey - * - * Supported access methods as of 2019/12/21: - * @see https://developer.here.com/faqs#access-control-1--how-do-you-control-access-to-here-location-services - */ - url: - 'https://{s}.{base}.maps.ls.hereapi.com/maptile/2.1/' + - '{type}/{mapID}/{variant}/{z}/{x}/{y}/{size}/{format}?' + - 'apiKey={apiKey}&lg={language}', - options: { - attribution: - 'Map © 1987-' + new Date().getFullYear() + ' HERE', - subdomains: '1234', - mapID: 'newest', - apiKey: '', - base: 'base', - variant: 'normal.day', - maxZoom: 20, - type: 'maptile', - language: 'eng', - format: 'png8', - size: '256' - }, - variants: { - normalDay: 'normal.day', - normalDayCustom: 'normal.day.custom', - normalDayGrey: 'normal.day.grey', - normalDayMobile: 'normal.day.mobile', - normalDayGreyMobile: 'normal.day.grey.mobile', - normalDayTransit: 'normal.day.transit', - normalDayTransitMobile: 'normal.day.transit.mobile', - normalNight: 'normal.night', - normalNightMobile: 'normal.night.mobile', - normalNightGrey: 'normal.night.grey', - normalNightGreyMobile: 'normal.night.grey.mobile', - normalNightTransit: 'normal.night.transit', - normalNightTransitMobile: 'normal.night.transit.mobile', - reducedDay: 'reduced.day', - reducedNight: 'reduced.night', - basicMap: { - options: { - type: 'basetile' - } - }, - mapLabels: { - options: { - type: 'labeltile', - format: 'png' - } - }, - trafficFlow: { - options: { - base: 'traffic', - type: 'flowtile' - } - }, - carnavDayGrey: 'carnav.day.grey', - hybridDay: { - options: { - base: 'aerial', - variant: 'hybrid.day' - } - }, - hybridDayMobile: { - options: { - base: 'aerial', - variant: 'hybrid.day.mobile' - } - }, - hybridDayTransit: { - options: { - base: 'aerial', - variant: 'hybrid.day.transit' - } - }, - hybridDayGrey: { - options: { - base: 'aerial', - variant: 'hybrid.grey.day' - } - }, - pedestrianDay: 'pedestrian.day', - pedestrianNight: 'pedestrian.night', - satelliteDay: { - options: { - base: 'aerial', - variant: 'satellite.day' - } - }, - terrainDay: { - options: { - base: 'aerial', - variant: 'terrain.day' - } - }, - terrainDayMobile: { - options: { - base: 'aerial', - variant: 'terrain.day.mobile' - } - } - } - }, - FreeMapSK: { - url: 'https://{s}.freemap.sk/T/{z}/{x}/{y}.jpeg', - options: { - minZoom: 8, - maxZoom: 16, - subdomains: 'abcd', - bounds: [[47.204642, 15.996093], [49.830896, 22.576904]], - attribution: - '{attribution.OpenStreetMap}, visualization CC-By-SA 2.0 Freemap.sk' - } - }, - MtbMap: { - url: 'http://tile.mtbmap.cz/mtbmap_tiles/{z}/{x}/{y}.png', - options: { - attribution: - '{attribution.OpenStreetMap} & USGS' - } - }, - CartoDB: { - url: 'https://{s}.basemaps.cartocdn.com/{variant}/{z}/{x}/{y}{r}.png', - options: { - attribution: '{attribution.OpenStreetMap} © CARTO', - subdomains: 'abcd', - maxZoom: 20, - variant: 'light_all' - }, - variants: { - Positron: 'light_all', - PositronNoLabels: 'light_nolabels', - PositronOnlyLabels: 'light_only_labels', - DarkMatter: 'dark_all', - DarkMatterNoLabels: 'dark_nolabels', - DarkMatterOnlyLabels: 'dark_only_labels', - Voyager: 'rastertiles/voyager', - VoyagerNoLabels: 'rastertiles/voyager_nolabels', - VoyagerOnlyLabels: 'rastertiles/voyager_only_labels', - VoyagerLabelsUnder: 'rastertiles/voyager_labels_under' - } - }, - HikeBike: { - url: 'https://tiles.wmflabs.org/{variant}/{z}/{x}/{y}.png', - options: { - maxZoom: 19, - attribution: '{attribution.OpenStreetMap}', - variant: 'hikebike' - }, - variants: { - HikeBike: {}, - HillShading: { - options: { - maxZoom: 15, - variant: 'hillshading' - } - } - } - }, - BasemapAT: { - url: 'https://mapsneu.wien.gv.at/basemap/{variant}/{type}/google3857/{z}/{y}/{x}.{format}', - options: { - maxZoom: 19, - attribution: 'Datenquelle: basemap.at', - type: 'normal', - format: 'png', - bounds: [[46.358770, 8.782379], [49.037872, 17.189532]], - variant: 'geolandbasemap' - }, - variants: { - basemap: { - options: { - maxZoom: 20, // currently only in Vienna - variant: 'geolandbasemap' - } - }, - grau: 'bmapgrau', - overlay: 'bmapoverlay', - terrain: { - options: { - variant: 'bmapgelaende', - type: 'grau', - format: 'jpeg' - } - }, - surface: { - options: { - variant: 'bmapoberflaeche', - type: 'grau', - format: 'jpeg' - } - }, - highdpi: { - options: { - variant: 'bmaphidpi', - format: 'jpeg' - } - }, - orthofoto: { - options: { - maxZoom: 20, // currently only in Vienna - variant: 'bmaporthofoto30cm', - format: 'jpeg' - } - } - } - }, - nlmaps: { - url: 'https://service.pdok.nl/brt/achtergrondkaart/wmts/v2_0/{variant}/EPSG:3857/{z}/{x}/{y}.png', - options: { - minZoom: 6, - maxZoom: 19, - bounds: [[50.5, 3.25], [54, 7.6]], - attribution: 'Kaartgegevens © Kadaster' - }, - variants: { - 'standaard': 'standaard', - 'pastel': 'pastel', - 'grijs': 'grijs', - 'water': 'water', - 'luchtfoto': { - 'url': 'https://service.pdok.nl/hwh/luchtfotorgb/wmts/v1_0/Actueel_ortho25/EPSG:3857/{z}/{x}/{y}.jpeg', - } - } - }, - NASAGIBS: { - url: 'https://map1.vis.earthdata.nasa.gov/wmts-webmerc/{variant}/default/{time}/{tilematrixset}{maxZoom}/{z}/{y}/{x}.{format}', - options: { - attribution: - 'Imagery provided by services from the Global Imagery Browse Services (GIBS), operated by the NASA/GSFC/Earth Science Data and Information System ' + - '(ESDIS) with funding provided by NASA/HQ.', - bounds: [[-85.0511287776, -179.999999975], [85.0511287776, 179.999999975]], - minZoom: 1, - maxZoom: 9, - format: 'jpg', - time: '', - tilematrixset: 'GoogleMapsCompatible_Level' - }, - variants: { - ModisTerraTrueColorCR: 'MODIS_Terra_CorrectedReflectance_TrueColor', - ModisTerraBands367CR: 'MODIS_Terra_CorrectedReflectance_Bands367', - ViirsEarthAtNight2012: { - options: { - variant: 'VIIRS_CityLights_2012', - maxZoom: 8 - } - }, - ModisTerraLSTDay: { - options: { - variant: 'MODIS_Terra_Land_Surface_Temp_Day', - format: 'png', - maxZoom: 7, - opacity: 0.75 - } - }, - ModisTerraSnowCover: { - options: { - variant: 'MODIS_Terra_NDSI_Snow_Cover', - format: 'png', - maxZoom: 8, - opacity: 0.75 - } - }, - ModisTerraAOD: { - options: { - variant: 'MODIS_Terra_Aerosol', - format: 'png', - maxZoom: 6, - opacity: 0.75 - } - }, - ModisTerraChlorophyll: { - options: { - variant: 'MODIS_Terra_Chlorophyll_A', - format: 'png', - maxZoom: 7, - opacity: 0.75 - } - } - } - }, - NLS: { - // NLS maps are copyright National library of Scotland. - // http://maps.nls.uk/projects/api/index.html - // Please contact NLS for anything other than non-commercial low volume usage - // - // Map sources: Ordnance Survey 1:1m to 1:63K, 1920s-1940s - // z0-9 - 1:1m - // z10-11 - quarter inch (1:253440) - // z12-18 - one inch (1:63360) - url: 'https://nls-{s}.tileserver.com/nls/{z}/{x}/{y}.jpg', - options: { - attribution: 'National Library of Scotland Historic Maps', - bounds: [[49.6, -12], [61.7, 3]], - minZoom: 1, - maxZoom: 18, - subdomains: '0123', - } - }, - JusticeMap: { - // Justice Map (http://www.justicemap.org/) - // Visualize race and income data for your community, county and country. - // Includes tools for data journalists, bloggers and community activists. - url: 'https://www.justicemap.org/tile/{size}/{variant}/{z}/{x}/{y}.png', - options: { - attribution: 'Justice Map', - // one of 'county', 'tract', 'block' - size: 'county', - // Bounds for USA, including Alaska and Hawaii - bounds: [[14, -180], [72, -56]] - }, - variants: { - income: 'income', - americanIndian: 'indian', - asian: 'asian', - black: 'black', - hispanic: 'hispanic', - multi: 'multi', - nonWhite: 'nonwhite', - white: 'white', - plurality: 'plural' - } - }, - GeoportailFrance: { - url: 'https://wxs.ign.fr/{apikey}/geoportail/wmts?REQUEST=GetTile&SERVICE=WMTS&VERSION=1.0.0&STYLE={style}&TILEMATRIXSET=PM&FORMAT={format}&LAYER={variant}&TILEMATRIX={z}&TILEROW={y}&TILECOL={x}', - options: { - attribution: 'Geoportail France', - bounds: [[-75, -180], [81, 180]], - minZoom: 2, - maxZoom: 18, - // Get your own geoportail apikey here : http://professionnels.ign.fr/ign/contrats/ - // NB : 'choisirgeoportail' is a demonstration key that comes with no guarantee - apikey: 'choisirgeoportail', - format: 'image/png', - style: 'normal', - variant: 'GEOGRAPHICALGRIDSYSTEMS.PLANIGNV2' - }, - variants: { - plan: 'GEOGRAPHICALGRIDSYSTEMS.PLANIGNV2', - parcels: { - options: { - variant: 'CADASTRALPARCELS.PARCELLAIRE_EXPRESS', - style: 'PCI vecteur', - maxZoom: 20 - } - }, - orthos: { - options: { - maxZoom: 19, - format: 'image/jpeg', - variant: 'ORTHOIMAGERY.ORTHOPHOTOS' - } - } - } - }, - OneMapSG: { - url: 'https://maps-{s}.onemap.sg/v3/{variant}/{z}/{x}/{y}.png', - options: { - variant: 'Default', - minZoom: 11, - maxZoom: 18, - bounds: [[1.56073, 104.11475], [1.16, 103.502]], - attribution: ' New OneMap | Map data © contributors, Singapore Land Authority' - }, - variants: { - Default: 'Default', - Night: 'Night', - Original: 'Original', - Grey: 'Grey', - LandLot: 'LandLot' - } - }, - USGS: { - url: 'https://basemap.nationalmap.gov/arcgis/rest/services/USGSTopo/MapServer/tile/{z}/{y}/{x}', - options: { - maxZoom: 20, - attribution: 'Tiles courtesy of the U.S. Geological Survey' - }, - variants: { - USTopo: {}, - USImagery: { - url: 'https://basemap.nationalmap.gov/arcgis/rest/services/USGSImageryOnly/MapServer/tile/{z}/{y}/{x}' - }, - USImageryTopo: { - url: 'https://basemap.nationalmap.gov/arcgis/rest/services/USGSImageryTopo/MapServer/tile/{z}/{y}/{x}' - } - } - }, - WaymarkedTrails: { - url: 'https://tile.waymarkedtrails.org/{variant}/{z}/{x}/{y}.png', - options: { - maxZoom: 18, - attribution: 'Map data: {attribution.OpenStreetMap} | Map style: © waymarkedtrails.org (CC-BY-SA)' - }, - variants: { - hiking: 'hiking', - cycling: 'cycling', - mtb: 'mtb', - slopes: 'slopes', - riding: 'riding', - skating: 'skating' - } - }, - OpenAIP: { - url: 'https://{s}.tile.maps.openaip.net/geowebcache/service/tms/1.0.0/openaip_basemap@EPSG%3A900913@png/{z}/{x}/{y}.{ext}', - options: { - attribution: 'openAIP Data (CC-BY-NC-SA)', - ext: 'png', - minZoom: 4, - maxZoom: 14, - tms: true, - detectRetina: true, - subdomains: '12' - } - }, - OpenSnowMap: { - url: 'https://tiles.opensnowmap.org/{variant}/{z}/{x}/{y}.png', - options: { - minZoom: 9, - maxZoom: 18, - attribution: 'Map data: {attribution.OpenStreetMap} & ODbL, © www.opensnowmap.org CC-BY-SA' - }, - variants: { - pistes: 'pistes', - } - }, - AzureMaps: { - url: - 'https://atlas.microsoft.com/map/tile?api-version={apiVersion}'+ - '&tilesetId={variant}&x={x}&y={y}&zoom={z}&language={language}'+ - '&subscription-key={subscriptionKey}', - options: { - attribution: 'See https://docs.microsoft.com/en-us/rest/api/maps/render-v2/get-map-tile for details.', - apiVersion: '2.0', - variant: 'microsoft.imagery', - subscriptionKey: '', - language: 'en-US', - }, - variants: { - MicrosoftImagery: 'microsoft.imagery', - MicrosoftBaseDarkGrey: 'microsoft.base.darkgrey', - MicrosoftBaseRoad: 'microsoft.base.road', - MicrosoftBaseHybridRoad: 'microsoft.base.hybrid.road', - MicrosoftTerraMain: 'microsoft.terra.main', - MicrosoftWeatherInfraredMain: { - url: - 'https://atlas.microsoft.com/map/tile?api-version={apiVersion}'+ - '&tilesetId={variant}&x={x}&y={y}&zoom={z}'+ - '&timeStamp={timeStamp}&language={language}' + - '&subscription-key={subscriptionKey}', - options: { - timeStamp: '2021-05-08T09:03:00Z', - attribution: 'See https://docs.microsoft.com/en-us/rest/api/maps/render-v2/get-map-tile#uri-parameters for details.', - variant: 'microsoft.weather.infrared.main', - }, - }, - MicrosoftWeatherRadarMain: { - url: - 'https://atlas.microsoft.com/map/tile?api-version={apiVersion}'+ - '&tilesetId={variant}&x={x}&y={y}&zoom={z}'+ - '&timeStamp={timeStamp}&language={language}' + - '&subscription-key={subscriptionKey}', - options: { - timeStamp: '2021-05-08T09:03:00Z', - attribution: 'See https://docs.microsoft.com/en-us/rest/api/maps/render-v2/get-map-tile#uri-parameters for details.', - variant: 'microsoft.weather.radar.main', - }, - } - }, - }, - SwissFederalGeoportal: { - url: 'https://wmts.geo.admin.ch/1.0.0/{variant}/default/current/3857/{z}/{x}/{y}.jpeg', - options: { - attribution: '© swisstopo', - minZoom: 2, - maxZoom: 18, - bounds: [[45.398181, 5.140242], [48.230651, 11.47757]] - }, - variants: { - NationalMapColor: 'ch.swisstopo.pixelkarte-farbe', - NationalMapGrey: 'ch.swisstopo.pixelkarte-grau', - SWISSIMAGE: { - options: { - variant: 'ch.swisstopo.swissimage', - maxZoom: 19 - } - } - } - } - }; - - L.tileLayer.provider = function (provider, options) { - return new L.TileLayer.Provider(provider, options); - }; - - return L; -})); diff --git a/src/tasks.py b/src/tasks.py deleted file mode 100644 index fb8daeb..0000000 --- a/src/tasks.py +++ /dev/null @@ -1,57 +0,0 @@ -import requests -import threading -import json - - -class TaskHandler: - def __init__(self): - self.hRIT_delayed = {} - self.hRIT_current = {} - self.updateCache() - TaskHandler.set_interval(self.updateCache, 60*5) - -# Start HotspotsRIT webworker - # Source for corrections: I made it up - corrections = { - "Library_3rd_Floor": {"max_occ": 550}, - "Library_2nd_Floor": {"max_occ": 250}, - "Library_1st_Floor": {"max_occ": 350}, - "Library_4th_Floor": {"max_occ": 400}, - "Library_A_Level": {"max_occ": 300}, - "Ross_Hall": {"max_occ": 200}, - "Gordon_Field_House": {"max_occ": 750} - } - - def getCache(self): - return self.hRIT_delayed - - def getCurrent(self): - return self.hRIT_current - - def updateCache(self): - r = requests.get("https://maps.rit.edu/proxySearch/densityMapDetail.php?mdo=1") - if r.status_code == 200: - if self.hRIT_current == {}: - self.hRIT_delayed = TaskHandler.dataAdjustments(r.json()) - else: - self.hRIT_delayed = json.loads(json.dumps(self.hRIT_current)) # deepcopy was returning a function for some reason - self.hRIT_current = TaskHandler.dataAdjustments(r.json()) - return self.hRIT_delayed, self.hRIT_current - else: - print("FUCK!", r.status_code) - - def dataAdjustments(data): - for dp in data: - if dp['location'] in TaskHandler.corrections: - for correction in TaskHandler.corrections[dp['location']]: - dp[correction] = TaskHandler.corrections[dp['location']][correction] - return data - - def set_interval(func, sec): - def func_wrapper(): - TaskHandler.set_interval(func, sec) - func() - t = threading.Timer(sec, func_wrapper) - t.start() - return t - diff --git a/src/templates/header.html b/src/templates/header.html index 33deea0..6d76ec5 100644 --- a/src/templates/header.html +++ b/src/templates/header.html @@ -39,10 +39,6 @@ gtag("config", "G-E2V93W9CNV"); - - - - - {{ var['title'] }} - + {% block header %} -
- +
@@ -115,7 +97,12 @@
+ {% endblock %} + {% block content%}
{% include var['template'] %}
+ {% endblock %} + {% block footer %} + {% endblock %} diff --git a/src/templates/iframe.html b/src/templates/iframe.html new file mode 100644 index 0000000..55f2097 --- /dev/null +++ b/src/templates/iframe.html @@ -0,0 +1,4 @@ +{% extends "header.html" %} +{% block header %}{% endblock %} +{% block footer %}{% endblock %} +{% block content %}{% endblock %} \ No newline at end of file