267 lines
8.9 KiB
JavaScript
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: '© <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();
|