From 87777cd5a4ee2be5f1ffd36f9e765bed278dd464 Mon Sep 17 00:00:00 2001 From: moanos Date: Tue, 7 Jan 2025 14:56:23 +0100 Subject: [PATCH] feat: add pin of map center --- .../static/fellchensammlung/img/pin.png | Bin 0 -> 4340 bytes .../partials/partial-map.html | 130 ++++++++++++++++++ src/fellchensammlung/views.py | 1 + 3 files changed, 131 insertions(+) create mode 100644 src/fellchensammlung/static/fellchensammlung/img/pin.png diff --git a/src/fellchensammlung/static/fellchensammlung/img/pin.png b/src/fellchensammlung/static/fellchensammlung/img/pin.png new file mode 100644 index 0000000000000000000000000000000000000000..8b5b31de589620fa93bd4607fe84159e814f2da6 GIT binary patch literal 4340 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

oK-E=BW;t zrYSGaIgWRXZavlT(9l+6)_Te`>1OBno5oP2W$QP@B!w>5@RS{)6fgm;C-KwlghNPU zgQdk)DP5|}V2|mA(8t+0tg~YdMe@&sY(HhsB66NuE-Y=H1EO7U?RY#$bl7-|dc=tr zQM;?_*f?@tQ!h7f!h?ad?3!Pk9FgK|W9X{a(Y1Mos04!tBd)W8-BhNflH%C`ukX~E zI!Rl;tbM1h$8{*QN~8M z^9>i~N%a|6QF1gncsBSB^%5gLIFa5FW$cbDA`hwMa`RBn-W#e{q;&27)YO(UkpO51#-@GCg*{5uao?j zCs@=})BvKY30u8%BA5}U7(m(UJ1-f;a4e+^9xX!V9qxP&ZPyn5zr zwBb^nX-{4=21}8;u&o(yF2VkYKBN{=U)a3XOL*53147_2@X>{_7z{HQW-f#F*FVOC zD5}gczYQ!5uTbdayB5|7gevd<-A@gfZ9q4d5Z-AS+F9P=<@p^_wE6wslQBMoSw3#* z?6Q59Z(A$FY+=XC2ehDh?`*Ojyg;wRNoD3x_O$oren37I!-Rh<1*qeGxDEW)1$^Iu9|1-33mAgs~JY^ zQ6AX_-;V^M4y6aBGqqjT>$1|nc2qcLpO~Shrufrkpy2d!tNBG$I{7MiwxQ^MAHY3K zUEm$G&n-p?v^tjCK}a)r%xVG+QH{MAO-cb?^|Bz*YK^aeq&LxIwzWTny_~4S&t9dk zo_EaaBvf4vpie^UL9@5%RKJfR)!1sc#;)95UgLoIhgBH0XiDe!d7Nzv+erI3n2W>R z0;GO2$XVCD#NFwl2o|Z(A%)@?zrWgs5sS2Jn#W&j#5>mL4*Pudv`L^a)tF|6MIoPbiM&6Gx4FAiyGG(e2Z|KX7bL{5sPTko{uR0J(C_rhUx#Q5j z7o3QN2*{MPMu%Y$=gXz*yTFEqh@5H$7MbFY{^Nx0dr@bvx1fx#ZWsGzT7 zO|;MpR{%5@?ZMorDCxqH+t>Fo%GwVl&yW>mx{ioL7}~-I>d5$ zHJ)2Cmc89~Z2q9;quP&KN^@K0Da^1&7O%L}spjH24n>o^_t|t=vaZ27M9Js<&~Col z91OTAmY*hYYJ$1^Ouf=R#+GBP=&&5tr;>M)RLj`3o|6aqdiaY^?jbhTcErDg8 { + image = await map.loadImage('{% static "fellchensammlung/img/pin.png" %}'); + map.addImage('pin', image.data); + {% for map_pin in map_pins %} + map.addSource('point', { + 'type': 'geojson', + 'data': { + 'type': 'FeatureCollection', + 'features': [ + { + 'type': 'Feature', + 'geometry': { + 'type': 'Point', + 'coordinates': [parseFloat({{ map_pin.location.longitude }}), + parseFloat({{ map_pin.location.latitude }})] + } + } + ] + } + }); + {% endfor %} + map.addLayer({ + 'id': 'pints', + 'type': 'symbol', + 'source': 'point', + 'layout': { + 'icon-image': 'pin', + 'icon-size': 0.1 + } + }); + }); + + const size = 200; + + // implementation of StyleImageInterface to draw a pulsing dot icon on the map + // Search for StyleImageInterface in https://maplibre.org/maplibre-gl-js/docs/API/ + const pulsingDot = { + width: size, + height: size, + data: new Uint8Array(size * size * 4), + + // get rendering context for the map canvas when layer is added to the map + onAdd() { + const canvas = document.createElement('canvas'); + canvas.width = this.width; + canvas.height = this.height; + this.context = canvas.getContext('2d'); + }, + + // called once before every frame where the icon will be used + render() { + const duration = 1000; + const t = (performance.now() % duration) / duration; + + const radius = (size / 2) * 0.3; + const outerRadius = (size / 2) * 0.7 * t + radius; + const context = this.context; + + // draw outer circle + context.clearRect(0, 0, this.width, this.height); + context.beginPath(); + context.arc( + this.width / 2, + this.height / 2, + outerRadius, + 0, + Math.PI * 2 + ); + context.fillStyle = `rgba(255, 200, 200,${1 - t})`; + context.fill(); + + // draw inner circle + context.beginPath(); + context.arc( + this.width / 2, + this.height / 2, + radius, + 0, + Math.PI * 2 + ); + context.fillStyle = 'rgba(255, 100, 100, 1)'; + context.strokeStyle = 'white'; + context.lineWidth = 2 + 4 * (1 - t); + context.fill(); + context.stroke(); + + // update this image's data with data from the canvas + this.data = context.getImageData( + 0, + 0, + this.width, + this.height + ).data; + + // continuously repaint the map, resulting in the smooth animation of the dot + map.triggerRepaint(); + + // return `true` to let the map know that the image was updated + return true; + } + }; + + map.on('load', () => { + map.addImage('pulsing-dot', pulsingDot, {pixelRatio: 2}); + + map.addSource('points', { + 'type': 'geojson', + 'data': { + 'type': 'FeatureCollection', + 'features': [ + { + 'type': 'Feature', + 'geometry': { + 'type': 'Point', + 'coordinates': [0, 0] + } + } + ] + } + }); + map.addLayer({ + 'id': 'points', + 'type': 'symbol', + 'source': 'points', + 'layout': { + 'icon-image': 'pulsing-dot' + } + }); + }); + {% if search_radius %} map.on('load', () => { const radius = {{ search_radius }}; // kilometer diff --git a/src/fellchensammlung/views.py b/src/fellchensammlung/views.py index 1b18c2f..64e99fd 100644 --- a/src/fellchensammlung/views.py +++ b/src/fellchensammlung/views.py @@ -204,6 +204,7 @@ def search(request): "searched": searched, "adoption_notices_map": AdoptionNotice.get_active_ANs(), "map_center": search.position, + "map_pins": [search], "location": search.location, "search_radius": search.max_distance, "zoom_level": zoom_level_for_radius(search.max_distance)}