Skip to content

Commit

Permalink
Merge pull request #13 from jtmiclat/feat/maplibre-tooltip
Browse files Browse the repository at this point in the history
Feat/maplibre tooltip
  • Loading branch information
jtmiclat authored Nov 20, 2023
2 parents e17683f + 8a0ac21 commit d56c5d9
Show file tree
Hide file tree
Showing 2 changed files with 143 additions and 19 deletions.
91 changes: 75 additions & 16 deletions example/pmtiles_vector_maplibre.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
},
{
"cell_type": "code",
"execution_count": 2,
"execution_count": 4,
"metadata": {},
"outputs": [
{
Expand Down Expand Up @@ -52,7 +52,7 @@
" <meta name="viewport" content="width=device-width,\n",
" initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />\n",
" <style>\n",
" #map_d34a97ecee5af4140e5dd7a9382c1680 {\n",
" #map_8ceea388252b5185b95d0ea5c2320ce3 {\n",
" position: relative;\n",
" width: 100.0%;\n",
" height: 100.0%;\n",
Expand All @@ -66,18 +66,32 @@
" <script src="https://unpkg.com/maplibre-gl@2.2.1/dist/maplibre-gl.js"></script>\n",
" <script src="https://unpkg.com/@maplibre/maplibre-gl-leaflet@0.0.17/leaflet-maplibre-gl.js"></script>\n",
" <link rel="stylesheet" href="https://unpkg.com/maplibre-gl@2.2.1/dist/maplibre-gl.css"/>\n",
" \n",
" <style>\n",
" .maplibregl-popup {\n",
" font: 12px/20px 'Helvetica Neue', Arial, Helvetica, sans-serif;\n",
" z-index: 651;\n",
" }\n",
" .feature-row{\n",
" margin-bottom: 0.5em;\n",
" &:not(:last-of-type) {\n",
" border-bottom: 1px solid black;\n",
" }\n",
" }\n",
" </style>\n",
" \n",
"</head>\n",
"<body>\n",
" \n",
" \n",
" <div class="folium-map" id="map_d34a97ecee5af4140e5dd7a9382c1680" ></div>\n",
" <div class="folium-map" id="map_8ceea388252b5185b95d0ea5c2320ce3" ></div>\n",
" \n",
"</body>\n",
"<script>\n",
" \n",
" \n",
" var map_d34a97ecee5af4140e5dd7a9382c1680 = L.map(\n",
" "map_d34a97ecee5af4140e5dd7a9382c1680",\n",
" var map_8ceea388252b5185b95d0ea5c2320ce3 = L.map(\n",
" "map_8ceea388252b5185b95d0ea5c2320ce3",\n",
" {\n",
" center: [43.7798, 11.24148],\n",
" crs: L.CRS.EPSG3857,\n",
Expand All @@ -91,40 +105,77 @@
"\n",
" \n",
" \n",
" var tile_layer_970cfaba433b3d24eb90977fd91848ad = L.tileLayer(\n",
" var tile_layer_5a2feba28e385044e79a0f410db9a067 = L.tileLayer(\n",
" "https://cartodb-basemaps-{s}.global.ssl.fastly.net/light_all/{z}/{x}/{y}.png",\n",
" {"attribution": "\\u0026copy; \\u003ca target=\\"_blank\\" href=\\"http://www.openstreetmap.org/copyright\\"\\u003eOpenStreetMap\\u003c/a\\u003e contributors \\u0026copy; \\u003ca target=\\"_blank\\" href=\\"http://cartodb.com/attributions\\"\\u003eCartoDB\\u003c/a\\u003e, CartoDB \\u003ca target=\\"_blank\\" href =\\"http://cartodb.com/attributions\\"\\u003eattributions\\u003c/a\\u003e", "detectRetina": false, "maxNativeZoom": 18, "maxZoom": 18, "minZoom": 0, "noWrap": false, "opacity": 1, "subdomains": "abc", "tms": false}\n",
" ).addTo(map_d34a97ecee5af4140e5dd7a9382c1680);\n",
" ).addTo(map_8ceea388252b5185b95d0ea5c2320ce3);\n",
" \n",
" let protocol = new pmtiles.Protocol();\n",
" maplibregl.addProtocol("pmtiles", protocol.tile);\n",
"\n",
" map_d34a97ecee5af4140e5dd7a9382c1680.createPane('overlay');\n",
" map_d34a97ecee5af4140e5dd7a9382c1680.getPane('overlay').style.zIndex = 650;\n",
" map_d34a97ecee5af4140e5dd7a9382c1680.getPane('overlay').style.pointerEvents = 'none';\n",
" map_8ceea388252b5185b95d0ea5c2320ce3.createPane('overlay');\n",
" map_8ceea388252b5185b95d0ea5c2320ce3.getPane('overlay').style.zIndex = 650;\n",
" map_8ceea388252b5185b95d0ea5c2320ce3.getPane('overlay').style.pointerEvents = 'none';\n",
"\n",
" var pm_tiles_vector_c7480b01a9398330d3ed304391192d30 = L.maplibreGL({\n",
" var pm_tiles_vector_4fdb6d0235d2b8dab13fcabaaa150826 = L.maplibreGL({\n",
" pane: 'overlay',\n",
" style: {"layers": [{"id": "buildings", "paint": {"fill-color": "steelblue"}, "source": "example_source", "source-layer": "landuse", "type": "fill"}, {"id": "roads", "paint": {"line-color": "black"}, "source": "example_source", "source-layer": "roads", "type": "line"}], "sources": {"example_source": {"attribution": "\\u003ca href=\\"https://protomaps.com\\"\\u003eProtomaps\\u003c/a\\u003e \\u00a9 \\u003ca href=\\"https://openstreetmap.org/copyright\\"\\u003eOpenStreetMap\\u003c/a\\u003e", "type": "vector", "url": "pmtiles://https://pmtiles.jtmiclat.me/protomaps(vector)ODbL_firenze.pmtiles"}}, "version": 8}\n",
" }).addTo(map_d34a97ecee5af4140e5dd7a9382c1680);\n",
" style: {"layers": [{"id": "buildings", "paint": {"fill-color": "steelblue"}, "source": "example_source", "source-layer": "landuse", "type": "fill"}, {"id": "roads", "paint": {"line-color": "black"}, "source": "example_source", "source-layer": "roads", "type": "line"}], "sources": {"example_source": {"attribution": "\\u003ca href=\\"https://protomaps.com\\"\\u003eProtomaps\\u003c/a\\u003e \\u00a9 \\u003ca href=\\"https://openstreetmap.org/copyright\\"\\u003eOpenStreetMap\\u003c/a\\u003e", "type": "vector", "url": "pmtiles://https://pmtiles.jtmiclat.me/protomaps(vector)ODbL_firenze.pmtiles"}}, "version": 8},\n",
" interactive: true,\n",
" }).addTo(map_8ceea388252b5185b95d0ea5c2320ce3);\n",
" var macro_element_5b7f9c4652c49e795ed7432c4302c347 = pm_tiles_vector_4fdb6d0235d2b8dab13fcabaaa150826.getMaplibreMap();\n",
" const popup = new maplibregl.Popup({\n",
" closeButton: false,\n",
" closeOnClick: false\n",
" });\n",
" macro_element_5b7f9c4652c49e795ed7432c4302c347.on('load', () => {\n",
" macro_element_5b7f9c4652c49e795ed7432c4302c347.on('mousemove', null, (e) => { \n",
" macro_element_5b7f9c4652c49e795ed7432c4302c347.getCanvas().style.cursor = 'pointer';\n",
" const { x, y } = e.point;\n",
" const r = 2; // radius around the point\n",
" const features = macro_element_5b7f9c4652c49e795ed7432c4302c347.queryRenderedFeatures([\n",
" [x - r, y - r],\n",
" [x + r, y + r],\n",
" ]);\n",
"\n",
" const {lng, lat} = e.lngLat;\n",
" const coordinates = [lng, lat]\n",
" const html = features.map(f=>`\n",
" <div class="feature-row">\n",
" <span>\n",
" <strong>${f.layer['source-layer']}</strong>\n",
" <span style="fontSize: 0.8em" }> (${f.geometry.type})</span>\n",
" </span>\n",
" <table>\n",
" ${Object.entries(f.properties).map(([key, value]) =>`<tr><td>${key}</td><td style="text-align: right">${value}</td></tr>`).join("")}\n",
" </table>\n",
" </div>\n",
" `).join("")\n",
" if(features.length){\n",
" popup.setLngLat(e.lngLat).setHTML(html).addTo(macro_element_5b7f9c4652c49e795ed7432c4302c347);\n",
" } else {\n",
" popup.remove();\n",
" }\n",
" });\n",
" });\n",
"</script>\n",
"&lt;/html&gt;\" style=\"position:absolute;width:100%;height:100%;left:0;top:0;border:none !important;\" allowfullscreen webkitallowfullscreen mozallowfullscreen></iframe></div></div>"
],
"text/plain": [
"<folium.folium.Map at 0x1056bf8e0>"
"<folium.folium.Map at 0x109332580>"
]
},
"execution_count": 2,
"execution_count": 4,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"import folium\n",
"\n",
"from folium_pmtiles.vector import PMTilesMapLibreLayer\n",
"from folium_pmtiles.vector import PMTilesMapLibreLayer, PMTilesMapLibreTooltip\n",
"\n",
"m = folium.Map(location=[43.7798, 11.24148], zoom_start=13, tiles=\"cartodb positron\")\n",
"tooltip = PMTilesMapLibreTooltip()\n",
"pmtiles_url = \"https://pmtiles.jtmiclat.me/protomaps(vector)ODbL_firenze.pmtiles\"\n",
"pmtiles_layer = PMTilesMapLibreLayer(\n",
" \"folium_layer_name\",\n",
Expand Down Expand Up @@ -154,9 +205,17 @@
" },\n",
" ],\n",
" },\n",
" tooltip=tooltip,\n",
")\n",
"m.add_child(pmtiles_layer)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": []
}
],
"metadata": {
Expand Down
71 changes: 68 additions & 3 deletions folium_pmtiles/vector.py
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,8 @@ class PMTilesMapLibreLayer(JSCSSMixin, Layer):
var {{ this.get_name() }} = L.maplibreGL({
pane: 'overlay',
style: {{ this.style|tojson}}
style: {{ this.style|tojson}},
interactive: true,
}).addTo({{ this._parent.get_name() }});
{%- endmacro %}
Expand All @@ -86,15 +87,79 @@ class PMTilesMapLibreLayer(JSCSSMixin, Layer):
),
]

def __init__(self, url, layer_name=None, style=None, **kwargs):
def __init__(self, url, layer_name=None, style=None, tooltip=None, **kwargs):
self.layer_name = layer_name if layer_name else "PMTilesVector"

super().__init__(name=self.layer_name, **kwargs)

self.url = url
self._name = "PMTilesVector"

if tooltip is not None:
self.add_child(tooltip)
if style is not None:
self.style = style
else:
self.style = {}


class PMTilesMapLibreTooltip(JSCSSMixin, Layer):
_template = Template(
"""
{% macro header(this, kwargs) %}
<style>
.maplibregl-popup {
font: 12px/20px 'Helvetica Neue', Arial, Helvetica, sans-serif;
z-index: 651;
}
.feature-row{
margin-bottom: 0.5em;
&:not(:last-of-type) {
border-bottom: 1px solid black;
}
}
</style>
{% endmacro %}
{% macro script(this, kwargs) -%}
var {{ this.get_name() }} = {{ this._parent.get_name() }}.getMaplibreMap();
const popup = new maplibregl.Popup({
closeButton: false,
closeOnClick: false
});
{{ this.get_name() }}.on('load', () => {
{{ this.get_name() }}.on('mousemove', (e) => {
{{ this.get_name() }}.getCanvas().style.cursor = 'pointer';
const { x, y } = e.point;
const r = 2; // radius around the point
const features = {{ this.get_name() }}.queryRenderedFeatures([
[x - r, y - r],
[x + r, y + r],
]);
const {lng, lat} = e.lngLat;
const coordinates = [lng, lat]
const html = features.map(f=>`
<div class="feature-row">
<span>
<strong>${f.layer['source-layer']}</strong>
<span style="fontSize: 0.8em" }> (${f.geometry.type})</span>
</span>
<table>
${Object.entries(f.properties).map(([key, value]) =>`<tr><td>${key}</td><td style="text-align: right">${value}</td></tr>`).join("")}
</table>
</div>
`).join("")
if(features.length){
popup.setLngLat(e.lngLat).setHTML(html).addTo({{ this.get_name() }});
} else {
popup.remove();
}
});
{{ this.get_name() }}.on('mouseleave', () => {popup.remove();});
});
{%- endmacro %}
"""
)

def __init__(self, name=None, **kwargs):
super().__init__(name=name if name else "PMTilesTooltip", **kwargs)

0 comments on commit d56c5d9

Please sign in to comment.