add tree labels

This commit is contained in:
Astro 2021-08-28 21:58:29 +02:00
parent 4f01097362
commit f59d4da577
3 changed files with 97 additions and 26 deletions

View File

@ -35,13 +35,14 @@ struct Tree {
botanic: Option<String>,
details: Option<HashMap<String, String>>,
planted: Option<NaiveDate>,
score: f64,
}
pub fn get_trees(state: State) -> (State, Response<Body>) {
let pe = AreaExtractor::borrow_from(&state);
let app_state = AppState::borrow_from(&state);
let result = app_state.with_db(|db| {
db.query("SELECT id, coord, botanic, german, planted FROM trees WHERE coord <@ $1::box ORDER BY coord <-> center($1::box) ASC LIMIT 2000", &[
db.query("SELECT id, coord, botanic, german, planted, score FROM trees WHERE coord <@ $1::box ORDER BY coord <-> center($1::box) ASC LIMIT 2000", &[
&pe.to_rect()
]).unwrap()
}).into_iter().map(|row| {
@ -53,6 +54,7 @@ pub fn get_trees(state: State) -> (State, Response<Body>) {
details: None,
german: row.get(3),
planted: row.get(4),
score: row.get(5),
}
}).collect::<Vec<_>>();
@ -82,7 +84,7 @@ pub fn get_tree(state: State) -> (State, Response<Body>) {
let ie = IdExtractor::borrow_from(&state);
let app_state = AppState::borrow_from(&state);
let result = app_state.with_db(|db| {
match db.query("SELECT id, coord, botanic, botanic_pfaf, german, planted FROM trees WHERE id=$1 LIMIT 1", &[&ie.id]).unwrap()
match db.query("SELECT id, coord, botanic, botanic_pfaf, german, planted, score FROM trees WHERE id=$1 LIMIT 1", &[&ie.id]).unwrap()
.into_iter()
.next() {
None => None,
@ -113,6 +115,7 @@ pub fn get_tree(state: State) -> (State, Response<Body>) {
german: row.get(4),
details: Some(details),
planted: row.get(5),
score: row.get(6),
}
})
}

View File

@ -1,34 +1,82 @@
const TREES_MIN_ZOOM = 17;
const TREE_LABELS_MIN_ZOOM = 20;
var map = L.map('map').setView([51.05, 13.75], TREES_MIN_ZOOM, {
// maxZoom: 20,
});
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);
var HeatmapLayer = L.TileLayer.extend({
getTileUrl: function (coords) {
var cs = this._tileCoordsToNwSe(coords);
var x1 = Math.min(cs[0].lng, cs[1].lng);
var y1 = Math.min(cs[0].lat, cs[1].lat);
var x2 = Math.max(cs[0].lng, cs[1].lng);
var y2 = Math.max(cs[0].lat, cs[1].lat);
return ["", "heatmap", x1, y1, x2, y2].join("/");
},
});
L.tileLayer('/heatmap/{z}/{x}/{y}/tile.png', {
opacity: 0.6,
maxZoom: TREES_MIN_ZOOM - 1,
opacity: 0.8,
}).addTo(map);
var treeIcon = L.icon({
iconUrl: "tree.png",
iconSize: [12, 12],
iconAnchor: [6, 6],
popupAnchor: [0, -6],
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 = (75 + 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) {
@ -117,8 +165,8 @@ function updateTrees() {
trees_pending = true;
fetch(["", "trees", bounds.getWest(), bounds.getSouth(), bounds.getEast(), bounds.getNorth()].join("/"))
.then(res => res.json())
.then(data => {
.then(function(res) { return res.json(); })
.then(function(data) {
if (map.getZoom() < TREES_MIN_ZOOM) {
return;
}
@ -134,15 +182,15 @@ function updateTrees() {
var marker = L.marker(coords, {
id: entry.id,
title: entry.german,
icon: treeIcon,
icon: treeIcon(entry),
}).bindPopup(treePopup(coords, entry));
trees.addLayer(marker);
}
});
trees_pending = false;
})
.catch (error => {
console.error('Error:' + error)
.catch(function(error) {
console.error('Error:' + error.stack)
trees_pending = false;
});
}

View File

@ -8,6 +8,26 @@
<style>
#map { margin: 0; padding: 0; width: 100vw; height: 100vh; }
body { margin: 0; padding: 0; font-family: sans-serif; }
.leaflet-div-icon {
background: none;
border: none;
}
.tree-icon {
overflow: visible;
}
.tree-icon img {
border-radius: 100%;
}
.tree-label {
margin: 0;
overflow: visible;
text-align: center;
font-size: small;
line-height: 1.1em;
color: black;
text-shadow: -1px -1px 0px white, 1px -1px 0px white, -1px 1px 0px white, 1px 1px 0px white;
}
</style>
<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1, maximum-scale=1, user-scalable=no">
</head>