diff --git a/ipyleaflet/leaflet.py b/ipyleaflet/leaflet.py index 8e981f7f0..9d2a2272d 100644 --- a/ipyleaflet/leaflet.py +++ b/ipyleaflet/leaflet.py @@ -982,6 +982,30 @@ def redraw(self): self.send({'msg': 'redraw'}) +class PMTilesLayer(Layer): + """PMTilesLayer class, with Layer as parent class. + + PMTiles layer. + + + Attributes + ---------- + url: string, default "" + Url to the vector tile service. + attribution: string, default "" + Vector tile service attribution. + style: dict, default {} + CSS Styles to apply to the vector data. + """ + + _view_name = Unicode('LeafletPMTilesLayerView').tag(sync=True) + _model_name = Unicode('LeafletPMTilesLayerModel').tag(sync=True) + + url = Unicode().tag(sync=True, o=True) + attribution = Unicode().tag(sync=True, o=True) + style = Dict().tag(sync=True, o=True) + + class VectorLayer(Layer): """VectorLayer abstract class.""" diff --git a/js/package.json b/js/package.json index 5654238e7..90b9bf6fe 100644 --- a/js/package.json +++ b/js/package.json @@ -47,7 +47,10 @@ "proj4": "^2.6.0", "proj4leaflet": "^1.0.1", "spin.js": "^4.1.0", - "stream-browserify": "^3.0.0" + "stream-browserify": "^3.0.0", + "pmtiles": "^2.5.0", + "maplibre-lib": "^2.2.1", + "maplibre-leaflet": "^0.0.17" }, "devDependencies": { "@jupyterlab/builder": "^3.6.0", diff --git a/js/src/jupyter-leaflet.js b/js/src/jupyter-leaflet.js index 508cfed25..794feac36 100644 --- a/js/src/jupyter-leaflet.js +++ b/js/src/jupyter-leaflet.js @@ -9,6 +9,7 @@ export * from './layers/AwesomeIcon.js'; export * from './layers/Popup.js'; export * from './layers/RasterLayer.js'; export * from './layers/TileLayer.js'; +export * from './layers/PMTilesLayer.js'; export * from './layers/VectorTileLayer.js'; export * from './layers/LocalTileLayer.js'; export * from './layers/WMSLayer.js'; diff --git a/js/src/layers/PMTilesLayer.js b/js/src/layers/PMTilesLayer.js new file mode 100644 index 000000000..34029e96c --- /dev/null +++ b/js/src/layers/PMTilesLayer.js @@ -0,0 +1,55 @@ +// Copyright (c) Jupyter Development Team. +// Distributed under the terms of the Modified BSD License. + +const layer = require('./Layer.js'); + +export class LeafletPMTilesLayerModel extends layer.LeafletLayerModel { + defaults() { + return { + ...super.defaults(), + _view_name: 'LeafletPMTilesLayerView', + _model_name: 'LeafletPMTilesLayerModel', + url: '', + style: {}, + }; + } +} + +export class LeafletPMTilesLayerView extends layer.LeafletLayerView { + render() { + this.create_obj(); + this.listenTo(this.model, 'change:url', this.url_changed.bind(this)); + this.listenTo(this.model, 'change:style', this.style_changed.bind(this)); + } + + create_obj() { + var protocol = new pmtiles.Protocol(); + maplibregl.addProtocol("pmtiles", protocol.tile); + + var mapStyle = { + ...this.model.get('style'), + sources: { + ...this.model.get('style').sources, + "pmtiles_source": { + "type": "vector", + "url": "pmtiles://" + this.model.get('url') + } + } + }; + + this.obj = L.maplibreGL({ + style: mapStyle + }); + } + + url_changed() { + var newUrl = "pmtiles://" + this.model.get('url'); + var currentStyle = this.obj.getStyle(); + currentStyle.sources["pmtiles_source"].url = newUrl; + this.obj.setStyle(currentStyle); + } + + style_changed() { + this.obj.setStyle(this.model.get('style')); + } +} diff --git a/js/src/leaflet.js b/js/src/leaflet.js index a4f6a2fa0..1d7dc8cde 100644 --- a/js/src/leaflet.js +++ b/js/src/leaflet.js @@ -16,6 +16,9 @@ require('leaflet-fullscreen'); require('leaflet-transform'); require('leaflet.awesome-markers'); require('leaflet-search'); +require('pmtiles'); +require('maplibre-lib'); +require('maplibre-leaflet'); // Monkey patch GridLayer for smoother URL updates L.patchGridLayer = function (layer) {