treeadvisor/server/static/app.js

267 lines
8.9 KiB
JavaScript

const TREES_MIN_ZOOM = 17;
const TREE_LABELS_MIN_ZOOM = 19;
var map = L.map('map', {
maxZoom: 30,
}).setView([51.05, 13.75], TREES_MIN_ZOOM);
L.tileLayer('/tiles/{z}/{x}/{y}/tile.png', {
attribution: '&copy; <a href="https://osm.org/copyright">OpenStreetMap</a> contributors',
maxZoom: 30,
}).addTo(map);
L.tileLayer('/heatmap/{z}/{x}/{y}/tile.png', {
opacity: 0.6,
maxZoom: TREES_MIN_ZOOM - 1,
}).addTo(map);
function temperature(x) {
x = Math.min(1, Math.max(0, x));
var MAX = 255 * 0.95;
var r, g, b;
if (x < 0.4) {
r = MAX * x / 0.4;
g = MAX;
b = 0.0;
} else if (x < 0.8) {
r = MAX;
g = MAX - MAX * (x - 0.4) / 0.4;
b = 0.0;
} else {
r = MAX;
g = 0.0;
b = MAX * (x - 0.8) / 0.2;
}
return "rgb(" + r + "," + g + "," + b + ")";
}
function treeIcon(entry) {
var size = entry.age ? Math.ceil(8 + (24 * Math.min(1, entry.age / 60))) : 32;
var div = document.createElement("div");
div.setAttribute("class", "tree-icon");
var img = document.createElement("img");
img.setAttribute("src", "tree.png");
img.setAttribute("width", size);
img.setAttribute("height", size);
var imgBorder = Math.ceil(size / 10);
img.style.border = imgBorder + "px solid " + temperature(1 - entry.score);
div.appendChild(img);
var label = document.createElement("p");
label.setAttribute("class", "tree-label");
label.style.width = (size + 2 * imgBorder) + "px";
label.textContent = entry.german;
div.appendChild(label);
function updateLabel() {
label.style.visibility = map.getZoom() >= TREE_LABELS_MIN_ZOOM ? "visible" : "hidden";
label.style.fontSize = (80 + 20 * (map.getZoom() - TREE_LABELS_MIN_ZOOM)) + "%";
}
updateLabel();
var icon = L.divIcon({
html: div,
iconSize: [size, size],
iconAnchor: [size / 2 + 1, size / 2 + 1],
popupAnchor: [0, -size / 2 - 1],
updateLabel: updateLabel,
});
return icon;
}
map.on('zoom', function() {
map.eachLayer(function(layer) {
if (layer.getIcon) {
var icon = layer.getIcon();
if (icon.options.updateLabel) {
icon.options.updateLabel();
}
}
});
});
function treePopup(coords, entry) {
var popup = L.popup({
minWidth: 600,
maxWidth: window.innerWidth / 3,
maxHeight: window.innerHeight * 0.7,
}).setLatLng(coords);
popup.on('add', function() {
var info = {};
function update(newInfo) {
console.log("info +=", newInfo);
Object.keys(newInfo).forEach(function(k) {
info[k] = newInfo[k];
});
popup.setContent(function() {
var div = document.createElement("div");
div.setAttribute("class", "tree-popup");
var div1 = document.createElement("div");
div.appendChild(div1);
var h2 = document.createElement("h2");
h2.textContent = entry.german;
if (entry.age)
h2.textContent += " (" + entry.age + ")";
div1.appendChild(h2);
var p = document.createElement("p");
p.textContent = entry.botanic;
div1.appendChild(p);
if (info.area) {
function getArea(key) {
var result = null;
info.area.forEach(function(area) {
if (!result && area[key]) result = area[key];
});
return result;
}
function addH3(text) {
var h3 = document.createElement("h3");
h3.textContent = text;
div1.appendChild(h3);
}
function addP(text) {
var p = document.createElement("p");
p.textContent = text;
div1.appendChild(p);
}
addH3("Bodenqualität");
var schutt = getArea("schutt");
if (schutt != null) {
addP("Schutt: " + schutt);
}
var versiegelung = getArea("versiegelung");
if (versiegelung != null) {
addP("Versiegelung: " + versiegelung);
}
var gebietstyp = getArea("gebietstyp");
if (gebietstyp != null) {
addP("Gebietstyp: " + gebietstyp);
}
var natuerliche_bodenfunktion = getArea("natuerliche_bodenfunktion");
if (natuerliche_bodenfunktion != null) {
addP("Natürliche Bodenfunktion: " + natuerliche_bodenfunktion);
}
}
if (info.tree && info.tree.details) {
var details = info.tree.details;
var div2 = document.createElement("div");
function addH(level, text) {
var h = document.createElement("h" + level);
h.textContent = text;
div2.appendChild(h);
}
function addP(text) {
var p = document.createElement("p");
p.textContent = text;
div2.appendChild(p);
}
div.appendChild(div2);
addH(2, details["Latin name"]);
if (details.Wildlife == "1") {
addP("Geliebt von der Fauna.");
}
addH(3, "Boden");
if (details.Acid == "1") {
addP("Sauer");
}
if (details.Alkaline == "1") {
addP("Alkalisch");
}
if (details.Soil) {
addP("Boden: " + details.Soil);
}
addH(3, "Wachstum");
if (details["Growth rate"]) {
addP("Wachstumsrate: " + details["Growth rate"]);
}
if (details.Height) {
addP("Höhe: " + details.Height);
}
}
return div;
});
}
update({});
fetch(["", "area", coords[1], coords[0]].join("/"))
.then(res => res.json())
.then(data => {
update({ area: data });
});
fetch(["", "tree", entry.id].join("/"))
.then(res => res.json())
.then(data => {
update({ tree: data });
});
});
return popup;
}
var trees;
var trees_pending = false;
var visible_trees;
function updateTrees() {
if (map.getZoom() < TREES_MIN_ZOOM) {
if (trees) {
trees.remove();
trees = null;
}
return;
}
var bounds = map.getBounds();
if (!trees) {
trees = L.layerGroup().addTo(map);
visible_trees = {};
} else {
trees.eachLayer(function(marker) {
var ll = marker.getLatLng();
if (ll.lng < bounds.getWest() || ll.lng > bounds.getEast() ||
ll.lat < bounds.getSouth() || ll.lat > bounds.getNorth()) {
delete visible_trees[marker.options.id];
trees.removeLayer(marker);
}
});
}
if (trees_pending) return;
trees_pending = true;
fetch(["", "trees", bounds.getWest(), bounds.getSouth(), bounds.getEast(), bounds.getNorth()].join("/"))
.then(function(res) { return res.json(); })
.then(function(data) {
if (map.getZoom() < TREES_MIN_ZOOM) {
return;
}
data.forEach(function(entry) {
var coords = [entry.coords[1], entry.coords[0]];
if (entry.planted) {
entry.age = Math.round((Date.now() - Date.parse(entry.planted)) / (365.25 * 24 * 60 * 60 * 1000));
}
if (!visible_trees[entry.id]) {
visible_trees[entry.id] = true;
var marker = L.marker(coords, {
id: entry.id,
title: entry.german,
icon: treeIcon(entry),
}).bindPopup(treePopup(coords, entry));
trees.addLayer(marker);
}
});
trees_pending = false;
})
.catch(function(error) {
console.error('Error:' + error.stack)
trees_pending = false;
});
}
map.on('moveend', updateTrees);
map.on('zoomend', updateTrees);
updateTrees();