diff --git a/packages/base/src/commands/index.ts b/packages/base/src/commands/index.ts index d702984cf..826f3220e 100644 --- a/packages/base/src/commands/index.ts +++ b/packages/base/src/commands/index.ts @@ -758,7 +758,9 @@ export function addCommands( isEnabled: () => { const selectedLayer = getSingleSelectedLayer(tracker); return selectedLayer - ? ['VectorLayer', 'ShapefileLayer'].includes(selectedLayer.type) + ? ['VectorLayer', 'ShapefileLayer', 'VectorTileLayer'].includes( + selectedLayer.type, + ) : false; }, execute: async () => { @@ -800,7 +802,11 @@ export function addCommands( const sourceId = selectedLayer.parameters.source; const source = sources[sourceId]; - const geojsonString = await getGeoJSONDataFromLayerSource(source, model); + const geojsonString = await getGeoJSONDataFromLayerSource( + selectedLayer, + source, + model, + ); if (!geojsonString) { return; } diff --git a/packages/base/src/mainview/mainView.tsx b/packages/base/src/mainview/mainView.tsx index cfa42a40c..b5763b547 100644 --- a/packages/base/src/mainview/mainView.tsx +++ b/packages/base/src/mainview/mainView.tsx @@ -72,7 +72,7 @@ import { transformExtent, } from 'ol/proj'; import { register } from 'ol/proj/proj4.js'; -import RenderFeature from 'ol/render/Feature'; +import RenderFeature, { toGeometry } from 'ol/render/Feature'; import { GeoTIFF as GeoTIFFSource, ImageTile as ImageTileSource, @@ -643,10 +643,15 @@ export class MainView extends React.Component { newSource.on('tileloadend', (event: TileSourceEvent) => { const tile = event.tile as VectorTile; - const features = tile.getFeatures(); - - if (features && features.length > 0) { - this._model.syncTileFeatures({ sourceId: id, features }); + const rawFeatures = tile.getFeatures() as RenderFeature[]; + + if (rawFeatures && rawFeatures.length > 0) { + const realFeatures = + this.convertRenderFeaturesToFeatures(rawFeatures); + this._model.syncTileFeatures({ + sourceId: id, + features: realFeatures, + }); } }); @@ -828,6 +833,27 @@ export class MainView extends React.Component { this._sources[id] = newSource; } + private convertRenderFeaturesToFeatures( + renderFeatures: RenderFeature[], + ): Feature[] { + const features: Feature[] = []; + + for (const rf of renderFeatures) { + const properties = rf.getProperties(); + const geometry = toGeometry(rf); + + if (!geometry) { + continue; + } + + const feature = new Feature({ ...properties }); + feature.setGeometry(geometry); + features.push(feature); + } + + return features; + } + private computeSourceUrl(source: IJGISSource): string { const parameters = source.parameters as IRasterSource; const urlParameters = parameters.urlParameters || {}; diff --git a/packages/base/src/processing/index.ts b/packages/base/src/processing/index.ts index 20b1942b9..159e200ab 100644 --- a/packages/base/src/processing/index.ts +++ b/packages/base/src/processing/index.ts @@ -79,7 +79,7 @@ export async function getLayerGeoJSON( return null; } - return await getGeoJSONDataFromLayerSource(source, model); + return await getGeoJSONDataFromLayerSource(layer, source, model); } export type GdalFunctions = diff --git a/packages/base/src/tools.ts b/packages/base/src/tools.ts index 855d98374..1479ab04b 100644 --- a/packages/base/src/tools.ts +++ b/packages/base/src/tools.ts @@ -3,6 +3,7 @@ import { IJGISLayerBrowserRegistry, IJGISOptions, IJGISSource, + IJGISLayer, IJupyterGISModel, IRasterLayerGalleryEntry, SourceType, @@ -13,6 +14,8 @@ import { Contents, ServerConnection } from '@jupyterlab/services'; import { VectorTile } from '@mapbox/vector-tile'; import * as d3Color from 'd3-color'; import { compressors } from 'hyparquet-compressors'; +import Feature from 'ol/Feature'; +import GeoJSON from 'ol/format/GeoJSON'; import Protobuf from 'pbf'; import shp from 'shpjs'; @@ -949,10 +952,15 @@ export function downloadFile( } export async function getGeoJSONDataFromLayerSource( + selectedLayer: IJGISLayer, source: IJGISSource, model: IJupyterGISModel, ): Promise { - const vectorSourceTypes: SourceType[] = ['GeoJSONSource', 'ShapefileSource']; + const vectorSourceTypes: SourceType[] = [ + 'GeoJSONSource', + 'ShapefileSource', + 'VectorTileSource', + ]; if (!vectorSourceTypes.includes(source.type as SourceType)) { console.error( @@ -961,6 +969,16 @@ export async function getGeoJSONDataFromLayerSource( return null; } + const sourceId = selectedLayer.parameters?.source; + if (source.type === 'VectorTileSource' && sourceId) { + const features = model.getFeaturesForCurrentTile({ sourceId }); + + const format = new GeoJSON(); + const geojson = format.writeFeaturesObject(features as Feature[]); + + return JSON.stringify(geojson); + } + if (!source.parameters) { console.error('Source parameters are missing.'); return null;