add tree labels
This commit is contained in:
parent
4f01097362
commit
f59d4da577
|
@ -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),
|
||||
}
|
||||
})
|
||||
}
|
||||
|
|
|
@ -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: '© <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;
|
||||
});
|
||||
}
|
||||
|
|
|
@ -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>
|
||||
|
|
Loading…
Reference in New Issue