improve openlayers snippets; read header min/maxzoom [#3]

This commit is contained in:
Brandon Liu
2023-04-26 16:19:58 +02:00
parent f15fa2f6ce
commit d15e9a5760
2 changed files with 115 additions and 116 deletions

View File

@@ -2,8 +2,8 @@
<head> <head>
<title>PMTiles OpenLayers Vector Example</title> <title>PMTiles OpenLayers Vector Example</title>
<meta charset="utf-8"/> <meta charset="utf-8"/>
<script src="https://cdn.jsdelivr.net/npm/ol@v7.1.0/dist/ol.js"></script> <script src="https://cdn.jsdelivr.net/npm/ol@v7.3.0/dist/ol.js"></script>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/ol@v7.1.0/ol.css"> <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/ol@v7.3.0/ol.css">
<script src="https://unpkg.com/pmtiles@2.7.2/dist/index.js"></script> <script src="https://unpkg.com/pmtiles@2.7.2/dist/index.js"></script>
<style> <style>
body, #map { body, #map {
@@ -15,79 +15,80 @@
<body> <body>
<div id="map"></div> <div id="map"></div>
<script type="text/javascript"> <script type="text/javascript">
class OLPMTilesSource { class VectorPMTilesSource extends ol.source.VectorTile {
constructor(url) { tileLoadFunction = (tile,url) => {
this._url = url; // the URL construction is done internally by OL, so we need to parse it
this._p = new pmtiles.PMTiles(url) // back out here using a hacky regex
} const re = new RegExp(/pmtiles:\/\/(.+)\/(\d+)\/(\d+)\/(\d+)/);
const result = url.match(re);
const z = +result[2];
const x = +result[3];
const y = +result[4];
url = () => { tile.setLoader((extent, resolution, projection) => {
return "pmtiles://" + this._url + "/{z}/{x}/{y}"; tile.setState(1); // LOADING
} this._p.getZxy(z,x,y).then((tile_result) => {
if (tile_result) {
vectorTileLoadFunction = (tile,url) => { const format = tile.getFormat();
// the URL construction is done internally by OL, so we need to parse it const features = format.readFeatures(tile_result.data.buffer, {
// back out here using a hacky regex extent: extent,
const re = new RegExp(/pmtiles:\/\/(.+)\/(\d+)\/(\d+)\/(\d+)/); featureProjection: projection
const result = url.match(re); });
const z = +result[2]; tile.setFeatures(features);
const x = +result[3]; tile.setState(2); // LOADED
const y = +result[4]; } else {
tile.setFeatures([]);
tile.setLoader((extent, resolution, projection) => { tile.setState(4); // EMPTY
tile.setState(1); // LOADING }
this._p.getZxy(z,x,y).then((tile_result) => {
if (tile_result) {
const format = tile.getFormat();
const features = format.readFeatures(tile_result.data.buffer, {
extent: extent,
featureProjection: projection
});
tile.setFeatures(features);
tile.setState(2); // LOADED
} else {
tile.setFeatures([]);
tile.setState(4); // EMPTY
}
});
}); });
} });
} }
const source = new OLPMTilesSource("https://r2-public.protomaps.com/protomaps-sample-datasets/nz-buildings-v3.pmtiles"); constructor(options) {
super({
state:"loading",
url: "pmtiles://" + options.url + "/{z}/{x}/{y}",
format: new ol.format.MVT(),
attributions: options.attributions
});
const style = new ol.style.Style({ this._p = new pmtiles.PMTiles(options.url);
this._p.getHeader().then(h => {
// TODO: set extent based on header
this.tileGrid.minZoom = h.minZoom;
this.tileGrid.maxZoom = h.maxZoom;
this.setTileLoadFunction(this.tileLoadFunction);
this.setState("ready");
});
}
}
const vectorLayer = new ol.layer.VectorTile({
declutter: true,
source: new VectorPMTilesSource({
url: "https://r2-public.protomaps.com/protomaps-sample-datasets/nz-buildings-v3.pmtiles",
attributions: ["© Land Information New Zealand"]
}),
style: new ol.style.Style({
stroke: new ol.style.Stroke({ stroke: new ol.style.Stroke({
color: 'gray', color: 'gray',
width: 1, width: 1,
}), }),
fill: new ol.style.Fill({ fill: new ol.style.Fill({
color: 'rgba(20,20,20,0.9)', color: 'rgba(20,20,20,0.9)',
}), })
}); })
});
const vtLayer = new ol.layer.VectorTile({ ol.proj.useGeographic();
declutter: true, const map = new ol.Map({
source: new ol.source.VectorTile({ layers: [vectorLayer],
attributions:["© Land Information New Zealand"], target: 'map',
maxZoom: 14, // this could come from the PMTiles header (async) view: new ol.View({
format: new ol.format.MVT(), // this could come from the PMTiles header (async) center: [172.606201,-43.556510],
url:source.url(), zoom: 7
tileLoadFunction: source.vectorTileLoadFunction }),
}), });
style: style,
});
ol.proj.useGeographic();
const map = new ol.Map({
layers: [vtLayer],
target: 'map',
view: new ol.View({
center: [172.606201,-43.556510],
zoom: 7,
multiWorld: true,
}),
});
</script> </script>
</body> </body>
</html> </html>

View File

@@ -2,8 +2,8 @@
<head> <head>
<title>PMTiles OpenLayers Raster Example</title> <title>PMTiles OpenLayers Raster Example</title>
<meta charset="utf-8"/> <meta charset="utf-8"/>
<script src="https://cdn.jsdelivr.net/npm/ol@v7.1.0/dist/ol.js"></script> <script src="https://cdn.jsdelivr.net/npm/ol@v7.3.0/dist/ol.js"></script>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/ol@v7.1.0/ol.css"> <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/ol@v7.3.0/ol.css">
<script src="https://unpkg.com/pmtiles@2.7.2/dist/index.js"></script> <script src="https://unpkg.com/pmtiles@2.7.2/dist/index.js"></script>
<style> <style>
body, #map { body, #map {
@@ -15,61 +15,59 @@
<body> <body>
<div id="map"></div> <div id="map"></div>
<script type="text/javascript"> <script type="text/javascript">
class OLPMTilesSource { class RasterPMTilesSource extends ol.source.DataTile {
constructor(url) { loadImage = (src) => {
this._url = url; return new Promise((resolve, reject) => {
this._p = new pmtiles.PMTiles(url) const img = new Image();
} img.addEventListener('load', () => resolve(img));
img.addEventListener('error', () => reject(new Error('load failed')));
url = () => { img.src = src;
return "pmtiles://" + this._url + "/{z}/{x}/{y}"; });
}
rasterTileLoadFunction = (tile,url) => {
tile.setState(1); // LOADING
// the URL construction is done internally by OL, so we need to parse it
// back out here using a hacky regex
const re = new RegExp(/pmtiles:\/\/(.+)\/(\d+)\/(\d+)\/(\d+)/);
const result = url.match(re);
const z = +result[2];
const x = +result[3];
const y = +result[4];
this._p.getZxy(z,x,y).then((tile_result) => {
if (tile_result) {
const blob = new Blob([tile_result.data]);
const imageUrl = window.URL.createObjectURL(blob);
tile.getImage().src = imageUrl;
tile.setState(2); // LOADED
} else {
tile.setState(4); // EMPTY
}
});
}
} }
const source = new OLPMTilesSource("https://r2-public.protomaps.com/protomaps-sample-datasets/terrarium_z9.pmtiles"); constructor(options) {
super({
state: "loading",
attributions: options.attributions
});
const rasterLayer = new ol.layer.Tile({ const p = new pmtiles.PMTiles(options.url);
source: new ol.source.XYZ({ p.getHeader().then(h => {
attributions:["https://github.com/tilezen/joerd/blob/master/docs/attribution.md"], // TODO: set extent based on header
url:source.url(), this.tileGrid.minZoom = h.minZoom;
tileLoadFunction: source.rasterTileLoadFunction, this.tileGrid.maxZoom = h.maxZoom;
tileSize:[512,512], this.setLoader(async (z,x,y) => {
maxZoom:9 // this could come from the PMTiles header (async) const response = await p.getZxy(z, x, y);
const blob = new Blob([response.data]);
const src = URL.createObjectURL(blob);
const image = await this.loadImage(src);
image.width = 512;
URL.revokeObjectURL(src);
return image;
});
this.setState("ready");
}) })
}) }
}
ol.proj.useGeographic(); // TODO: tile size 512,512
const map = new ol.Map({ const rasterLayer = new ol.layer.WebGLTile({
layers: [rasterLayer], source: new RasterPMTilesSource({
target: 'map', url:"https://r2-public.protomaps.com/protomaps-sample-datasets/terrarium_z9.pmtiles",
view: new ol.View({ attributions:["https://github.com/tilezen/joerd/blob/master/docs/attribution.md"]
center: [0,0], })
zoom: 0, });
multiWorld: true,
}), ol.proj.useGeographic();
}); const map = new ol.Map({
layers: [rasterLayer],
target: 'map',
view: new ol.View({
center: [0,0],
zoom: 0,
multiWorld: true
}),
});
</script> </script>
</body> </body>
</html> </html>