diff --git a/examples/test.jGIS b/examples/test.jGIS index 9a33d4ff..e98c00f5 100644 --- a/examples/test.jGIS +++ b/examples/test.jGIS @@ -1,4 +1,24 @@ { - "layers": [], + "sources": { + "699facc9-e7c4-4f38-acf1-1fd7f02d9f36": { + "type": "RasterSource", + "name": "RasterSource", + "parameters": { + "url": "https://tile.openstreetmap.org/{z}/{x}/{y}.png", + "minZoom": 0, + "maxZoom": 24 + } + } + }, + "layers": { + "2467576f-b527-4cb7-998d-fa1d056fb8a1": { + "type": "RasterLayer", + "parameters": { + "source": "699facc9-e7c4-4f38-acf1-1fd7f02d9f36" + }, + "visible": true, + "name": "RasterSource Layer" + } + }, "options": {} } \ No newline at end of file diff --git a/packages/base/package.json b/packages/base/package.json index a7e374f0..3a4f9fa0 100644 --- a/packages/base/package.json +++ b/packages/base/package.json @@ -59,7 +59,7 @@ "@types/d3-color": "^3.1.0", "@types/three": "^0.134.0", "d3-color": "^3.1.0", - "ol": "^9.2.4", + "maplibre-gl": "^4.4.1", "react": "^18.0.1", "styled-components": "^5.3.6", "three": "^0.135.0", diff --git a/packages/base/src/commands.ts b/packages/base/src/commands.ts index 78cf2998..9a6ace86 100644 --- a/packages/base/src/commands.ts +++ b/packages/base/src/commands.ts @@ -4,6 +4,10 @@ import { ITranslator } from '@jupyterlab/translation'; import { redoIcon, undoIcon } from '@jupyterlab/ui-components'; import { JupyterGISWidget } from './widget'; +import { IDict, IJGISFormSchemaRegistry, IJGISLayer, IJGISSource, IJupyterGISModel } from '@jupytergis/schema'; +import { FormDialog } from './formdialog'; +import { UUID } from '@lumino/coreutils'; + /** * Add the commands to the application's command registry. @@ -11,8 +15,10 @@ import { JupyterGISWidget } from './widget'; export function addCommands( app: JupyterFrontEnd, tracker: WidgetTracker, - translator: ITranslator + translator: ITranslator, + formSchemaRegistry: IJGISFormSchemaRegistry ): void { + Private.updateFormSchema(formSchemaRegistry); const trans = translator.load('jupyterlab'); const { commands } = app; commands.addCommand(CommandIDs.redo, { @@ -48,6 +54,17 @@ export function addCommands( }, icon: undoIcon }); + + commands.addCommand(CommandIDs.newRasterLayer, { + label: trans.__('New Tile Layer'), + isEnabled: () => { + return tracker.currentWidget + ? tracker.currentWidget.context.model.sharedModel.editable + : false; + }, + iconClass: 'fa fa-map', + execute: Private.createRasterSourceAndLayer(tracker) + }); } /** @@ -56,4 +73,119 @@ export function addCommands( export namespace CommandIDs { export const redo = 'jupytergis:redo'; export const undo = 'jupytergis:undo'; + + export const newRasterLayer = 'jupytergis:newRasterLayer'; +} + + +namespace Private { + export const FORM_SCHEMA = {}; + + export function updateFormSchema( + formSchemaRegistry: IJGISFormSchemaRegistry + ) { + if (Object.keys(FORM_SCHEMA).length > 0) { + return; + } + const formSchema = formSchemaRegistry.getSchemas(); + formSchema.forEach((val, key) => { + const value = (FORM_SCHEMA[key] = JSON.parse(JSON.stringify(val))); + value['required'] = ['name', ...value['required']]; + value['properties'] = { + name: { type: 'string', description: 'The name of the layer/source' }, + ...value['properties'] + }; + }); + } + + // TODO Allow for creating only a source (e.g. loading a CSV file) + // TODO Allow for creating only a layer (e.g. creating a vector layer given a source selected from a dropdown) + + export function createRasterSourceAndLayer( + tracker: WidgetTracker + ) { + return async (args: any) => { + const current = tracker.currentWidget; + + if (!current) { + return; + } + + const form = { + title: 'Raster Layer parameters', + default: (model: IJupyterGISModel) => { + return { + name: 'RasterSource', + url: "https://tile.openstreetmap.org/{z}/{x}/{y}.png", + maxZoom: 24, + minZoom: 0 + }; + } + }; + + current.context.model.syncFormData(form); + + const syncSelectedField = ( + id: string | null, + value: any, + parentType: 'panel' | 'dialog' + ): void => { + let property: string | null = null; + if (id) { + const prefix = id.split('_')[0]; + property = id.substring(prefix.length); + } + current.context.model.syncSelectedPropField({ + id: property, + value, + parentType + }); + }; + + const dialog = new FormDialog({ + context: current.context, + title: form.title, + sourceData: form.default(current.context.model), + schema: FORM_SCHEMA["RasterSource"], + syncData: (props: IDict) => { + const sharedModel = current.context.model.sharedModel; + if (!sharedModel) { + return; + } + + const { name, ...parameters } = props; + + const sourceId = UUID.uuid4(); + + const sourceModel: IJGISSource = { + type: "RasterSource", + name, + parameters: { + url: parameters.url, + minZoom: parameters.minZoom, + maxZoom: parameters.maxZoom + } + }; + + const layerModel: IJGISLayer = { + type: "RasterLayer", + parameters: { + source: sourceId + }, + visible: true, + name: name + " Layer" + }; + + sharedModel.addSource(sourceId, sourceModel) + sharedModel.addLayer(UUID.uuid4(), layerModel); + }, + cancelButton: () => { + current.context.model.syncFormData(undefined); + }, + syncSelectedPropField: syncSelectedField + }); + await dialog.launch(); + }; + } + } diff --git a/packages/base/src/mainview/mainview.tsx b/packages/base/src/mainview/mainview.tsx index 9c654730..76e6c78a 100644 --- a/packages/base/src/mainview/mainview.tsx +++ b/packages/base/src/mainview/mainview.tsx @@ -1,19 +1,19 @@ import { MapChange } from '@jupyter/ydoc'; import { + IJGISLayerDocChange, IJupyterGISClientState, IJupyterGISDoc, IJupyterGISModel, + IRasterSource, } from '@jupytergis/schema'; import { IObservableMap, ObservableMap } from '@jupyterlab/observables'; import { User } from '@jupyterlab/services'; import { JSONValue } from '@lumino/coreutils'; import * as React from 'react'; -import * as OpenLayer from 'ol'; -import TileLayer from 'ol/layer/Tile'; -import XYZ from 'ol/source/XYZ'; +import * as MapLibre from 'maplibre-gl'; -import 'ol/ol.css'; +// import 'maplibre-gl.css'; import { isLightTheme } from '../tools'; import { MainViewModel } from './mainviewmodel'; @@ -51,6 +51,11 @@ export class MainView extends React.Component { this ); + this._model.sharedLayersChanged.connect( + this._onLayersChanged, + this + ); + this.state = { id: this._mainViewModel.id, lightTheme: isLightTheme(), @@ -88,23 +93,10 @@ export class MainView extends React.Component { generateScene = (): void => { if (this.divRef.current) { - this._openLayersMap = new OpenLayer.Map({ - target: this.divRef.current, - layers: [ - new TileLayer({ - source: new XYZ({ - url: 'https://tile.openstreetmap.org/{z}/{x}/{y}.png' - }) - }) - ], - view: new OpenLayer.View({ - center: [0, 0], - zoom: 2 - }) + this._Map = new MapLibre.Map({ + container: this.divRef.current }); - console.log('created map', this._openLayersMap); - this.setState(old => ({ ...old, loading: false })); } }; @@ -130,6 +122,68 @@ export class MainView extends React.Component { // TODO SOMETHING } + private _onLayersChanged( + sender: IJupyterGISDoc, + change: IJGISLayerDocChange + ): void { + // TODO Why is this empty?? We need this for granular updates + // change.layerChange?.forEach((change) => { + // console.log('new change', change); + // }) + + for (const layerId of Object.keys(this._model.sharedModel.layers)) { + const layer = this._model.sharedModel.getLayer(layerId); + + if (!layer) { + console.log(`Layer id ${layerId} does not exist`); + continue; + } + + switch(layer.type) { + case 'RasterLayer': + const sourceId = layer.parameters?.source; + const source = this.getSource(sourceId); + + if (!source) { + continue; + } + + // Workaround stupid maplibre issue + this._Map._lazyInitEmptyStyle(); + + // If the source does not exist, create it + if (!this._Map.getSource(sourceId)) { + this._Map.addSource(sourceId, { + type: 'raster', + tiles: [source.url], + tileSize: 256, + }); + } else { + // TODO If the source already existed, update it + } + + this._Map.addLayer({ + id: layerId, + type: 'raster', + source: sourceId, + minzoom: source.minZoom || 0, + maxzoom: source.maxZoom || 24, + }); + } + } + } + + private getSource(id: string): T | undefined { + const source = this._model.sharedModel.getSource(id); + + if (!source || !source.parameters) { + console.log(`Source id ${id} does not exist`); + return; + } + + return source.parameters as T; + } + private _handleThemeChange = (): void => { const lightTheme = isLightTheme(); @@ -167,7 +221,7 @@ export class MainView extends React.Component { private divRef = React.createRef(); // Reference of render div - private _openLayersMap: OpenLayer.Map; + private _Map: MapLibre.Map; private _model: IJupyterGISModel; private _mainViewModel: MainViewModel; diff --git a/packages/base/src/panelview/objectproperties.tsx b/packages/base/src/panelview/objectproperties.tsx index e05e57bc..85a0a13c 100644 --- a/packages/base/src/panelview/objectproperties.tsx +++ b/packages/base/src/panelview/objectproperties.tsx @@ -1,7 +1,6 @@ import { IDict, IJGISFormSchemaRegistry, - IJGISLayers, IJGISLayerDocChange, IJupyterGISClientState, IJupyterGISDoc, @@ -16,7 +15,6 @@ import { v4 as uuid } from 'uuid'; import { focusInputField, - itemFromName, removeStyleFromProperty } from '../tools'; import { IControlPanelModel } from '../types'; @@ -42,7 +40,6 @@ export class ObjectProperties extends PanelWithToolbar { interface IStates { jGISOption?: IDict; filePath?: string; - jGISLayers?: IJGISLayers; selectedObjectData?: IDict; selectedObject?: string; schema?: IDict; @@ -62,7 +59,6 @@ class ObjectPropertiesReact extends React.Component { super(props); this.state = { filePath: this.props.cpModel.filePath, - jGISLayers: this.props.cpModel.jGISModel?.getLayers(), clientId: null, id: uuid() }; @@ -84,14 +80,12 @@ class ObjectPropertiesReact extends React.Component { this.setState(old => ({ ...old, filePath: changed.context.localPath, - jGISLayers: this.props.cpModel.jGISModel?.getLayers(), clientId: changed.context.model.getClientId() })); } else { this.setState({ jGISOption: undefined, filePath: undefined, - jGISLayers: undefined, selectedObjectData: undefined, selectedObject: undefined, schema: undefined @@ -100,11 +94,11 @@ class ObjectPropertiesReact extends React.Component { }); } - async syncLayerProperties( - objectName: string | undefined, + async syncObjectProperties( + id: string | undefined, properties: { [key: string]: any } ) { - if (!this.state.jGISLayers || !objectName) { + if (!id) { return; } @@ -119,24 +113,7 @@ class ObjectPropertiesReact extends React.Component { return; } - // getContent already returns a deep copy of the content, we can change it safely here - const updatedContent = model.getContent(); - for (const object of updatedContent.layers) { - if (object.name === objectName) { - object.parameters = { - ...object.parameters, - ...properties - }; - } - } - - const obj = model.sharedModel.getLayerByName(objectName); - if (obj) { - model.sharedModel.updateLayerByName(objectName, 'parameters', { - ...obj['parameters'], - ...properties - }); - } + model.sharedModel.updateObjectParameters(id, properties); } syncSelectedField = ( @@ -162,26 +139,18 @@ class ObjectPropertiesReact extends React.Component { ): void => { this.setState(old => { if (old.selectedObject) { - const jGISLayers = this.props.cpModel.jGISModel?.getLayers(); - if (jGISLayers) { - const selectedObj = itemFromName(old.selectedObject, jGISLayers); - if (!selectedObj) { - return old; - } - const selectedObjectData = selectedObj['parameters']; + const selectedObject = this.props.cpModel.jGISModel?.sharedModel.getObject(old.selectedObject); + if (selectedObject) { + const selectedObjectData = selectedObject.parameters; return { ...old, - jGISLayers: jGISLayers, selectedObjectData }; } else { return old; } } else { - return { - ...old, - jGISLayers: this.props.cpModel.jGISModel?.getLayers() - }; + return old; } }); }; @@ -228,7 +197,7 @@ class ObjectPropertiesReact extends React.Component { schema={this.state.schema} sourceData={this.state.selectedObjectData} syncData={(properties: { [key: string]: any }) => { - this.syncLayerProperties(this.state.selectedObject, properties); + this.syncObjectProperties(this.state.selectedObject, properties); }} syncSelectedField={this.syncSelectedField} /> diff --git a/packages/base/src/toolbar/widget.tsx b/packages/base/src/toolbar/widget.tsx index dff18d31..4e632925 100644 --- a/packages/base/src/toolbar/widget.tsx +++ b/packages/base/src/toolbar/widget.tsx @@ -54,6 +54,15 @@ export class ToolbarWidget extends Toolbar { this.addItem('separator1', new Separator()); + this.addItem( + 'newRasterLayer', + new CommandToolbarButton({ + id: CommandIDs.newRasterLayer, + label: '', + commands: options.commands + }) + ); + // Add more commands here this.addItem('spacer', Toolbar.createSpacerItem()); diff --git a/packages/base/src/tools.ts b/packages/base/src/tools.ts index 505d2fad..7616990a 100644 --- a/packages/base/src/tools.ts +++ b/packages/base/src/tools.ts @@ -37,18 +37,6 @@ export function throttle void>( } as T; } -export function itemFromName( - name: string, - arr: T[] -): T | undefined { - for (const it of arr) { - if (it.name === name) { - return it; - } - } - return undefined; -} - export function focusInputField( filePath?: string, fieldId?: string | null, diff --git a/packages/schema/src/doc.ts b/packages/schema/src/doc.ts index eb042095..4adc9340 100644 --- a/packages/schema/src/doc.ts +++ b/packages/schema/src/doc.ts @@ -3,10 +3,11 @@ import { JSONExt, JSONObject } from '@lumino/coreutils'; import { ISignal, Signal } from '@lumino/signaling'; import * as Y from 'yjs'; -import { IJGISLayer, IJGISOptions } from './_interface/jgis'; +import { IJGISLayer, IJGISLayers, IJGISOptions, IJGISSource, IJGISSources } from './_interface/jgis'; import { IDict, IJGISLayerDocChange, + IJGISSourceDocChange, IJupyterGISDoc, IJupyterGISDocChange } from './interfaces'; @@ -19,11 +20,14 @@ export class JupyterGISDoc super(); this._options = this.ydoc.getMap>('options'); - this._layers = this.ydoc.getArray>('layers'); + this._layers = this.ydoc.getMap>('layers'); + this._sources = this.ydoc.getMap>('sources'); this.undoManager.addToScope(this._layers); + this.undoManager.addToScope(this._sources); - this._layers.observeDeep(this._layersObserver); - this._options.observe(this._optionsObserver); + this._layers.observeDeep(this._layersObserver.bind(this)); + this._sources.observeDeep(this._sourcesObserver.bind(this)); + this._options.observe(this._optionsObserver.bind(this)); } dispose(): void { @@ -34,11 +38,50 @@ export class JupyterGISDoc return '0.1.0'; } - get layers(): Array { - const objs = this._layers.map( - obj => JSONExt.deepCopy(obj.toJSON()) as IJGISLayer - ); - return objs; + get layers(): IJGISLayers { + return JSONExt.deepCopy(this._layers.toJSON()); + } + + set layers(layers: IJGISLayers) { + this.transact(() => { + for (const [key, value] of Object.entries(layers)) { + this._layers.set(key, value); + } + }); + } + + set sources(sources: IJGISSources) { + this.transact(() => { + for (const [key, value] of Object.entries(sources)) { + this._sources.set(key, value); + } + }); + } + + get sources(): IJGISSources { + return JSONExt.deepCopy(this._sources.toJSON()); + } + + getLayer(id: string): IJGISLayer | undefined { + if (!this._layers.has(id)) { + return undefined; + } + return JSONExt.deepCopy(this._layers.get(id)); + } + + getSource(id: string): IJGISSource | undefined { + if (!this._sources.has(id)) { + return undefined; + } + return JSONExt.deepCopy(this._sources.get(id)); + } + + set options(options: IJGISOptions) { + this.transact(() => { + for (const [key, value] of Object.entries(options)) { + this._options.set(key, value); + } + }); } get options(): JSONObject { @@ -49,60 +92,94 @@ export class JupyterGISDoc return this._layersChanged; } + get sourcesChanged(): ISignal { + return this._sourcesChanged; + } + get optionsChanged(): ISignal { return this._optionsChanged; } - layerExists(name: string): boolean { - return Boolean(this._getLayertAsYMapByName(name)); + layerExists(id: string): boolean { + return Boolean(this._getLayerAsYMap(id)); } - getLayerByName(name: string): IJGISLayer | undefined { - const obj = this._getLayertAsYMapByName(name); - if (obj) { - return JSONExt.deepCopy(obj.toJSON()) as IJGISLayer; + removeLayer(id: string): void { + this.transact(() => { + this._layers.delete(id); + }); + } + + addLayer(id: string, value: IJGISLayer): void { + this.transact(() => { + this._layers.set(id, value); + }); + } + + updateLayer(id: string, value: IJGISLayer): void { + const obj = this._getLayerAsYMap(id); + if (!obj) { + return; } - return undefined; + this.transact(() => obj.set(id, value)); } - removeLayerByName(name: string): void { - let index = 0; - for (const obj of this._layers) { - if (obj.get('name') === name) { - break; - } - index++; + getObject(id: string): IJGISLayer | IJGISSource | undefined { + const layer = this.getLayer(id); + if (layer) { + return layer; } - if (this._layers.length > index) { - this.transact(() => { - this._layers.delete(index); - }); + const source = this.getSource(id); + if (source) { + return source; } } - addLayer(value: IJGISLayer): void { - this.addLayers([value]); + updateObjectParameters(id: string, value: IJGISLayer['parameters'] | IJGISSource['parameters']) { + const layer = this.getLayer(id); + if (layer) { + layer.parameters = { + ...layer.parameters, + ...value + }; + + this.updateLayer(id, layer); + } + + const source = this.getSource(id); + if (source) { + source.parameters = { + ...source.parameters, + ...value + }; + + this.updateSource(id, source); + } } - addLayers(value: Array): void { + sourceExists(id: string): boolean { + return Boolean(this._getSourceAsYMap(id)); + } + + removeSource(id: string): void { this.transact(() => { - value.map(obj => { - if (!this.layerExists(obj.name)) { - this._layers.push([new Y.Map(Object.entries(obj))]); - } else { - console.error('There is already a layer with the name:', obj.name); - } - }); + this._sources.delete(id); + }); + } + + addSource(id: string, value: IJGISSource): void { + this.transact(() => { + this._sources.set(id, value); }); } - updateLayerByName(name: string, key: string, value: any): void { - const obj = this._getLayertAsYMapByName(name); + updateSource(id: string, value: any): void { + const obj = this._getSourceAsYMap(id); if (!obj) { return; } - this.transact(() => obj.set(key, value)); + this.transact(() => obj.set(id, value)); } getOption(key: keyof IJGISOptions): IDict | undefined { @@ -117,67 +194,84 @@ export class JupyterGISDoc this.transact(() => void this._options.set(key, value)); } - setOptions(options: IJGISOptions): void { - this.transact(() => { - for (const [key, value] of Object.entries(options)) { - this._options.set(key, value); - } - }); - } - static create(): IJupyterGISDoc { return new JupyterGISDoc(); } editable = true; - private _getLayertAsYMapByName(name: string): Y.Map | undefined { - for (const obj of this._layers) { - if (obj.get('name') === name) { - return obj; - } + private _getLayerAsYMap(id: string): Y.Map | undefined { + if (this._layers.has(id)) { + return this._layers.get(id); } return undefined; } - private _layersObserver = (events: Y.YEvent[]): void => { + private _getSourceAsYMap(id: string): Y.Map | undefined { + if (this._sources.has(id)) { + return this._sources.get(id); + } + return undefined; + } + + private _layersObserver(events: Y.YEvent[]): void { const changes: Array<{ - name: string; - key: keyof IJGISLayer; + id: string; newValue: IJGISLayer; }> = []; let needEmit = false; events.forEach(event => { - const name = event.target.get('name'); - - if (name) { - event.keys.forEach((change, key) => { - if (!needEmit) { - needEmit = true; - } - changes.push({ - name, - key: key as any, - newValue: JSONExt.deepCopy(event.target.toJSON()) - }); + event.keys.forEach((change, key) => { + if (!needEmit) { + needEmit = true; + } + changes.push({ + id: key as string, + newValue: JSONExt.deepCopy(event.target.toJSON()[key]) }); - } + }); }); needEmit = changes.length === 0 ? true : needEmit; if (needEmit) { this._layersChanged.emit({ layerChange: changes }); } - this._changed.emit({ layerChange: changes }); + }; + + private _sourcesObserver(events: Y.YEvent[]): void { + const changes: Array<{ + id: string; + newValue: IJGISSource; + }> = []; + let needEmit = false; + events.forEach(event => { + event.keys.forEach((change, key) => { + if (!needEmit) { + needEmit = true; + } + changes.push({ + id: key as string, + newValue: JSONExt.deepCopy(event.target.toJSON()[key]) + }); + }); + }); + needEmit = changes.length === 0 ? true : needEmit; + if (needEmit) { + this._sourcesChanged.emit({ sourceChange: changes }); + } }; private _optionsObserver = (event: Y.YMapEvent>): void => { this._optionsChanged.emit(event.keys); }; - private _layers: Y.Array>; + private _layers: Y.Map; + private _sources: Y.Map; private _options: Y.Map; private _optionsChanged = new Signal(this); private _layersChanged = new Signal( this ); + private _sourcesChanged = new Signal( + this + ); } diff --git a/packages/schema/src/interfaces.ts b/packages/schema/src/interfaces.ts index 11d48382..df710c28 100644 --- a/packages/schema/src/interfaces.ts +++ b/packages/schema/src/interfaces.ts @@ -9,14 +9,15 @@ import { IChangedArgs } from '@jupyterlab/coreutils'; import { DocumentRegistry, IDocumentWidget } from '@jupyterlab/docregistry'; import { User } from '@jupyterlab/services'; import { ReactWidget } from '@jupyterlab/ui-components'; -import { JSONObject } from '@lumino/coreutils'; import { ISignal, Signal } from '@lumino/signaling'; import { IJGISContent, IJGISLayers, IJGISLayer, - IJGISOptions + IJGISSource, + IJGISOptions, + IJGISSources } from './_interface/jgis'; export interface IDict { @@ -25,12 +26,18 @@ export interface IDict { export interface IJGISLayerDocChange { layerChange?: Array<{ - name: string; - key: keyof IJGISLayer; + id: string; newValue: IJGISLayer | undefined; }>; } +export interface IJGISSourceDocChange { + sourceChange?: Array<{ + id: string; + newValue: IJGISSource | undefined; + }>; +} + export interface IJupyterGISClientState { selectedPropField?: { id: string | null; @@ -43,25 +50,34 @@ export interface IJupyterGISClientState { } export interface IJupyterGISDoc extends YDocument { - layers: Array; - options: JSONObject; + options: IJGISOptions; + layers: IJGISLayers; + sources: IJGISSources; readonly editable: boolean; readonly toJGISEndpoint?: string; - layerExists(name: string): boolean; - getLayerByName(name: string): IJGISLayer | undefined; - removeLayerByName(name: string): void; - addLayer(value: IJGISLayer): void; - addLayers(value: Array): void; - updateLayerByName(name: string, key: string, value: any): void; + layerExists(id: string): boolean; + getLayer(id: string): IJGISLayer | undefined; + removeLayer(id: string): void; + addLayer(id: string, value: IJGISLayer): void; + updateLayer(id: string, value: IJGISLayer): void; + + sourceExists(id: string): boolean; + getSource(id: string): IJGISSource | undefined; + removeSource(id: string): void; + addSource(id: string, value: IJGISSource): void; + updateSource(id: string, value: IJGISSource): void; + + updateObjectParameters(id: string, value: IJGISLayer['parameters'] | IJGISSource['parameters']): void; + getObject(id: string): IJGISLayer | IJGISSource | undefined; getOption(key: keyof IJGISOptions): IDict | undefined; setOption(key: keyof IJGISOptions, value: IDict): void; - setOptions(options: IJGISOptions): void; optionsChanged: ISignal; layersChanged: ISignal; + sourcesChanged: ISignal; } export interface IJupyterGISDocChange extends DocumentChange { @@ -94,6 +110,9 @@ export interface IJupyterGISModel extends DocumentRegistry.IModel { getContent(): IJGISContent; getLayers(): IJGISLayers; + getLayer(id: string): IJGISLayer | undefined; + getSources(): IJGISSources; + getSource(id: string): IJGISSource | undefined; syncSelectedPropField(data: { id: string | null; diff --git a/packages/schema/src/model.ts b/packages/schema/src/model.ts index 85e9488b..4c416a64 100644 --- a/packages/schema/src/model.ts +++ b/packages/schema/src/model.ts @@ -5,7 +5,7 @@ import { PartialJSONObject } from '@lumino/coreutils'; import { ISignal, Signal } from '@lumino/signaling'; import Ajv from 'ajv'; -import { IJGISContent, IJGISLayers } from './_interface/jgis'; +import { IJGISContent, IJGISLayer, IJGISLayers, IJGISSource, IJGISSources } from './_interface/jgis'; import { JupyterGISDoc } from './doc'; import { IJGISLayerDocChange, @@ -139,8 +139,9 @@ export class JupyterGISModel implements IJupyterGISModel { } this.sharedModel.transact(() => { - this.sharedModel.addLayers(jsonData.layers); - this.sharedModel.setOptions(jsonData.options ?? {}); + this.sharedModel.sources = jsonData.sources ?? {}; + this.sharedModel.layers = jsonData.layers ?? {}; + this.sharedModel.options = jsonData.options ?? {}; }); this.dirty = true; } @@ -163,6 +164,7 @@ export class JupyterGISModel implements IJupyterGISModel { getContent(): IJGISContent { return { + sources: this.sharedModel.sources, layers: this.sharedModel.layers, options: this.sharedModel.options }; @@ -172,6 +174,18 @@ export class JupyterGISModel implements IJupyterGISModel { return this.sharedModel.layers; } + getSources(): IJGISSources { + return this.sharedModel.sources; + } + + getLayer(id: string): IJGISLayer | undefined { + return this.sharedModel.getLayer(id); + } + + getSource(id: string): IJGISSource | undefined { + return this.sharedModel.getSource(id); + } + syncSelectedPropField(data: { id: string | null; value: any; diff --git a/packages/schema/src/schema/jgis.json b/packages/schema/src/schema/jgis.json index a128cff5..e3210ed4 100644 --- a/packages/schema/src/schema/jgis.json +++ b/packages/schema/src/schema/jgis.json @@ -1,26 +1,44 @@ { "type": "object", "title": "IJGISContent", - "required": ["layers"], + "required": ["layers", "sources"], "additionalProperties": false, "properties": { "layers": { "$ref": "#/definitions/jGISLayers" }, + "sources": { + "$ref": "#/definitions/jGISSources" + }, "options": { "$ref": "#/definitions/jGISOptions" } }, "definitions": { + "layerType": { + "type": "string", + "enum": [ + "RasterLayer" + ] + }, + "sourceType": { + "type": "string", + "enum": [ + "RasterSource" + ] + }, "jGISLayer": { "title": "IJGISLayer", "type": "object", "additionalProperties": false, - "required": ["name", "visible"], + "required": ["name", "type", "visible"], "properties": { "name": { "type": "string" }, + "type": { + "$ref": "#/definitions/layerType" + }, "visible": { "type": "boolean" }, @@ -29,14 +47,39 @@ } } }, + "jGISSource": { + "title": "IJGISSource", + "type": "object", + "additionalProperties": false, + "required": ["name", "type"], + "properties": { + "name": { + "type": "string" + }, + "type": { + "$ref": "#/definitions/sourceType" + }, + "parameters": { + "type": "object" + } + } + }, "jGISLayers": { "title": "IJGISLayers", - "type": "array", - "default": [], - "items": { + "type": "object", + "default": {}, + "additionalProperties": { "$ref": "#/definitions/jGISLayer" } }, + "jGISSources": { + "title": "IJGISSources", + "type": "object", + "default": {}, + "additionalProperties": { + "$ref": "#/definitions/jGISSource" + } + }, "jGISOptions": { "title": "IJGISOptions", "type": "object", diff --git a/packages/schema/src/schema/rasterlayer.json b/packages/schema/src/schema/rasterlayer.json new file mode 100644 index 00000000..515157a5 --- /dev/null +++ b/packages/schema/src/schema/rasterlayer.json @@ -0,0 +1,13 @@ +{ + "type": "object", + "description": "RasterLayer", + "title": "IRasterLayer", + "required": ["source"], + "additionalProperties": false, + "properties": { + "source": { + "type": "string", + "description": "The id of the source" + } + } + } diff --git a/packages/schema/src/schema/rastersource.json b/packages/schema/src/schema/rastersource.json new file mode 100644 index 00000000..91853582 --- /dev/null +++ b/packages/schema/src/schema/rastersource.json @@ -0,0 +1,25 @@ +{ + "type": "object", + "description": "RasterSource", + "title": "IRasterSource", + "required": ["url", "maxZoom", "minZoom"], + "additionalProperties": false, + "properties": { + "url": { + "type": "string", + "description": "The url to the tile provider" + }, + "maxZoom": { + "type": "number", + "minimum": 0, + "maximum": 24, + "description": "The maximum zoom level for the raster source" + }, + "minZoom": { + "type": "number", + "minimum": 0, + "maximum": 24, + "description": "The minimum zoom level for the raster source" + } + } +} diff --git a/packages/schema/src/types.ts b/packages/schema/src/types.ts index 50db5153..d3ebc8bc 100644 --- a/packages/schema/src/types.ts +++ b/packages/schema/src/types.ts @@ -1,4 +1,6 @@ export * from './_interface/jgis'; +export * from './_interface/rasterlayer'; +export * from './_interface/rastersource'; export * from './interfaces'; export * from './model'; export * from './doc'; diff --git a/python/jupytergis_core/install.json b/python/jupytergis_core/install.json deleted file mode 100644 index 5d1e6e3f..00000000 --- a/python/jupytergis_core/install.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "packageManager": "python", - "packageName": "jupytergis_core", - "uninstallInstructions": "Use your Python package manager (pip, conda, etc.) to uninstall the package jupytergis_core" -} diff --git a/python/jupytergis_core/jupytergis_core/jgis_ydoc.py b/python/jupytergis_core/jupytergis_core/jgis_ydoc.py index 86f7ebd6..e2a9449f 100644 --- a/python/jupytergis_core/jupytergis_core/jgis_ydoc.py +++ b/python/jupytergis_core/jupytergis_core/jgis_ydoc.py @@ -2,7 +2,7 @@ from typing import Any, Callable from functools import partial -from pycrdt import Array, Map, Text +from pycrdt import Map, Text from jupyter_ydoc.ybasedoc import YBaseDoc @@ -10,7 +10,8 @@ class YJGIS(YBaseDoc): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self._ydoc["source"] = self._ysource = Text() - self._ydoc["layers"] = self._ylayers = Array() + self._ydoc["layers"] = self._ylayers = Map() + self._ydoc["sources"] = self._ysources = Map() self._ydoc["options"] = self._yoptions = Map() def version(self) -> str: @@ -23,9 +24,10 @@ def get(self) -> str: :rtype: Any """ layers = self._ylayers.to_py() + sources = self._ysources.to_py() options = self._yoptions.to_py() return json.dumps( - dict(layers=layers, options=options), + dict(layers=layers, sources=sources, options=options), indent=2, ) @@ -36,12 +38,12 @@ def set(self, value: str) -> None: :type value: Any """ valueDict = json.loads(value) - newObj = [] - for obj in valueDict["layers"]: - newObj.append(Map(obj)) self._ylayers.clear() - self._ylayers.extend(newObj) + self._ylayers.update(valueDict.get("layers", {})) + + self._ysources.clear() + self._ysources.update(valueDict.get("sources", {})) self._yoptions.clear() self._yoptions.update(valueDict.get("options", {})) @@ -57,6 +59,9 @@ def observe(self, callback: Callable[[str, Any], None]): self._subscriptions[self._ylayers] = self._ylayers.observe_deep( partial(callback, "layers") ) + self._subscriptions[self._ysources] = self._ysources.observe_deep( + partial(callback, "sources") + ) self._subscriptions[self._yoptions] = self._yoptions.observe_deep( partial(callback, "options") ) diff --git a/python/jupytergis_core/pyproject.toml b/python/jupytergis_core/pyproject.toml index b7a650e3..3ed27835 100644 --- a/python/jupytergis_core/pyproject.toml +++ b/python/jupytergis_core/pyproject.toml @@ -19,7 +19,6 @@ classifiers = [ "Programming Language :: Python :: 3.12", ] dependencies = [ - "jupyter_server>=2.0.6,<3", "jupyter_ydoc>=2,<3", "jupyter-collaboration>=2,<3", ] @@ -43,7 +42,6 @@ artifacts = ["jupytergis_core/labextension"] exclude = [".github", "binder"] [tool.hatch.build.targets.wheel.shared-data] -"install.json" = "share/jupyter/labextensions/@jupytergis/jupytergis-core/install.json" "jupytergis_core/labextension" = "share/jupyter/labextensions/@jupytergis/jupytergis-core" [tool.hatch.build.hooks.version] diff --git a/python/jupytergis_core/src/jgisplugin/plugins.ts b/python/jupytergis_core/src/jgisplugin/plugins.ts index 78273391..c96c1b77 100644 --- a/python/jupytergis_core/src/jgisplugin/plugins.ts +++ b/python/jupytergis_core/src/jgisplugin/plugins.ts @@ -111,7 +111,7 @@ const activate = ( format: 'text', size: undefined, content: - '{\n\t"layers": [],\n\t"options": {}\n}' + '{\n\t"layers": {},\n\t"sources": {},\n\t"options": {}\n}' }); // Open the newly created file with the 'Editor' diff --git a/python/jupytergis_lab/src/index.ts b/python/jupytergis_lab/src/index.ts index 8ab6a1ce..a77075c9 100644 --- a/python/jupytergis_lab/src/index.ts +++ b/python/jupytergis_lab/src/index.ts @@ -29,12 +29,14 @@ const plugin: JupyterFrontEndPlugin = { id: 'jupytergis:lab:main-menu', autoStart: true, requires: [ - IJupyterGISDocTracker + IJupyterGISDocTracker, + IJGISFormSchemaRegistryToken ], optional: [IMainMenu, ITranslator], activate: ( app: JupyterFrontEnd, tracker: WidgetTracker, + formSchemaRegistry: IJGISFormSchemaRegistry, mainMenu?: IMainMenu, translator?: ITranslator ): void => { @@ -47,7 +49,7 @@ const plugin: JupyterFrontEndPlugin = { ); }; - addCommands(app, tracker, translator); + addCommands(app, tracker, translator, formSchemaRegistry); if (mainMenu) { populateMenus(mainMenu, isEnabled); } diff --git a/ui-tests/tests/notebook.spec.ts-snapshots/dark-Notebook-ipynb-cell-0-linux.png b/ui-tests/tests/notebook.spec.ts-snapshots/dark-Notebook-ipynb-cell-0-linux.png index 40b5df0b..8ffd1b4f 100644 Binary files a/ui-tests/tests/notebook.spec.ts-snapshots/dark-Notebook-ipynb-cell-0-linux.png and b/ui-tests/tests/notebook.spec.ts-snapshots/dark-Notebook-ipynb-cell-0-linux.png differ diff --git a/ui-tests/tests/notebook.spec.ts-snapshots/light-Notebook-ipynb-cell-0-linux.png b/ui-tests/tests/notebook.spec.ts-snapshots/light-Notebook-ipynb-cell-0-linux.png index 3ff7a571..9fe5d5fa 100644 Binary files a/ui-tests/tests/notebook.spec.ts-snapshots/light-Notebook-ipynb-cell-0-linux.png and b/ui-tests/tests/notebook.spec.ts-snapshots/light-Notebook-ipynb-cell-0-linux.png differ diff --git a/yarn.lock b/yarn.lock index 417f9034..2923fe0e 100644 --- a/yarn.lock +++ b/yarn.lock @@ -926,7 +926,7 @@ __metadata: "@types/node": ^18.15.11 "@types/three": ^0.135.0 d3-color: ^3.1.0 - ol: ^9.2.4 + maplibre-gl: ^4.4.1 react: ^18.0.1 rimraf: ^3.0.2 styled-components: ^5.3.6 @@ -2403,6 +2403,82 @@ __metadata: languageName: node linkType: hard +"@mapbox/geojson-rewind@npm:^0.5.2": + version: 0.5.2 + resolution: "@mapbox/geojson-rewind@npm:0.5.2" + dependencies: + get-stream: ^6.0.1 + minimist: ^1.2.6 + bin: + geojson-rewind: geojson-rewind + checksum: 721470ab5e8912d69aef06fa4db891bade8b028d6708a35a982b1dfec0f40eb4ba05a749258867f5844cf4e776e53866813bf9c97e3289054b21cbf7840d3608 + languageName: node + linkType: hard + +"@mapbox/jsonlint-lines-primitives@npm:^2.0.2, @mapbox/jsonlint-lines-primitives@npm:~2.0.2": + version: 2.0.2 + resolution: "@mapbox/jsonlint-lines-primitives@npm:2.0.2" + checksum: 4eb31edd3ccff530f7b687ddc6d813d6e24fc66e9a563460882e7861b49f9331c5ded6fd7e927b37affbbd98f83bff1f7b916119044f1931df03c6ffedba2cfb + languageName: node + linkType: hard + +"@mapbox/point-geometry@npm:0.1.0, @mapbox/point-geometry@npm:^0.1.0, @mapbox/point-geometry@npm:~0.1.0": + version: 0.1.0 + resolution: "@mapbox/point-geometry@npm:0.1.0" + checksum: ed41c1ce0140de81039424415d9a199abba72cdb2287314e1b8c3e295da3224f7e8c1b0ae99a9b097703e7abe63e1978a518e29896989cc8bba3d482360bc22f + languageName: node + linkType: hard + +"@mapbox/tiny-sdf@npm:^2.0.6": + version: 2.0.6 + resolution: "@mapbox/tiny-sdf@npm:2.0.6" + checksum: efff5b5a7599aaa995e3c2fd8f2acd071226096458eebb694ffd7258043c46c52b1d09bb3c7343d2126eb257b3cd7d34e6dc7ccaaad7619e6f3e7dd76229a3cd + languageName: node + linkType: hard + +"@mapbox/unitbezier@npm:^0.0.1": + version: 0.0.1 + resolution: "@mapbox/unitbezier@npm:0.0.1" + checksum: bf104c85dbff37bf47d3217d9457a3abbf23714f78fefadea64e56bdc7c538491b626166809ef28db134f09baccd6ca3df6988a6422df90d8d0c9a23b0686043 + languageName: node + linkType: hard + +"@mapbox/vector-tile@npm:^1.3.1": + version: 1.3.1 + resolution: "@mapbox/vector-tile@npm:1.3.1" + dependencies: + "@mapbox/point-geometry": ~0.1.0 + checksum: 7093d4fa7d0382a0eae9d79526c5ad57c32099300b013d3afb4ab7499ac2a096f6f0a487cc81151ef81e0432a4b157513666b1592a4a4c1497341cde835551aa + languageName: node + linkType: hard + +"@mapbox/whoots-js@npm:^3.1.0": + version: 3.1.0 + resolution: "@mapbox/whoots-js@npm:3.1.0" + checksum: c1837c04effd205b207f441356d952eae7e8aad6c58f7c4900de50318c2147cf175936fc9434f20dfa409f9e6a78ec604d61e70c1c20572db0cc7655fbb65f50 + languageName: node + linkType: hard + +"@maplibre/maplibre-gl-style-spec@npm:^20.3.0": + version: 20.3.0 + resolution: "@maplibre/maplibre-gl-style-spec@npm:20.3.0" + dependencies: + "@mapbox/jsonlint-lines-primitives": ~2.0.2 + "@mapbox/unitbezier": ^0.0.1 + json-stringify-pretty-compact: ^4.0.0 + minimist: ^1.2.8 + quickselect: ^2.0.0 + rw: ^1.3.3 + sort-object: ^3.0.3 + tinyqueue: ^2.0.3 + bin: + gl-style-format: dist/gl-style-format.mjs + gl-style-migrate: dist/gl-style-migrate.mjs + gl-style-validate: dist/gl-style-validate.mjs + checksum: 2674af49727fc225aaae18ad1f5f121aaa7cae83ba397f44664765b94d7d87260145e9bae1eb8740103520025d563649a9ca588b028cc25b80ec8ea636b5a262 + languageName: node + linkType: hard + "@microsoft/fast-colors@npm:^5.3.1": version: 5.3.1 resolution: "@microsoft/fast-colors@npm:5.3.1" @@ -2862,13 +2938,6 @@ __metadata: languageName: node linkType: hard -"@petamoriken/float16@npm:^3.4.7": - version: 3.8.7 - resolution: "@petamoriken/float16@npm:3.8.7" - checksum: 0e4c12e9d88aac08f125a2e804a28207bafd1ea0cdc2ddbde95cc9a3b19c155747f5001a5d5b42f9dca18f697df553d42680067817ce5dc4e3456f9c605a6d88 - languageName: node - linkType: hard - "@pkgjs/parseargs@npm:^0.11.0": version: 0.11.0 resolution: "@pkgjs/parseargs@npm:0.11.0" @@ -3082,6 +3151,22 @@ __metadata: languageName: node linkType: hard +"@types/geojson-vt@npm:3.2.5": + version: 3.2.5 + resolution: "@types/geojson-vt@npm:3.2.5" + dependencies: + "@types/geojson": "*" + checksum: 3c77f52c4a82b8087d3e04b86a62027ad1dccf4d339df7c7c191cfcf288564e050b241664e072fc9fd3bb5b71e217dc0dcfb7c467bded4be303ab2b283612b72 + languageName: node + linkType: hard + +"@types/geojson@npm:*, @types/geojson@npm:^7946.0.14": + version: 7946.0.14 + resolution: "@types/geojson@npm:7946.0.14" + checksum: ae511bee6488ae3bd5a3a3347aedb0371e997b14225b8983679284e22fa4ebd88627c6e3ff8b08bf4cc35068cb29310c89427311ffc9322c255615821a922e71 + languageName: node + linkType: hard + "@types/glob@npm:*": version: 8.1.0 resolution: "@types/glob@npm:8.1.0" @@ -3108,6 +3193,13 @@ __metadata: languageName: node linkType: hard +"@types/junit-report-builder@npm:^3.0.2": + version: 3.0.2 + resolution: "@types/junit-report-builder@npm:3.0.2" + checksum: 7fead0b771f95cd8e607223ace2f43cc881b3e7944db405f903590b56379d14132032b7d89c9afa7dff266b95f516a476a39ad40f9200bfb61fc8ed7f6b1bff6 + languageName: node + linkType: hard + "@types/lodash@npm:^4.14.134, @types/lodash@npm:^4.14.168": version: 4.17.4 resolution: "@types/lodash@npm:4.17.4" @@ -3115,6 +3207,24 @@ __metadata: languageName: node linkType: hard +"@types/mapbox__point-geometry@npm:*, @types/mapbox__point-geometry@npm:^0.1.4": + version: 0.1.4 + resolution: "@types/mapbox__point-geometry@npm:0.1.4" + checksum: d315f3e396bebd40f1cab682595f3d1c5ac46c5ddb080cf65dfcd0401dc6a3f235a7ac9ada2d28e6c49485fa5f231458f29fee87069e42a137e20e5865801dd1 + languageName: node + linkType: hard + +"@types/mapbox__vector-tile@npm:^1.3.4": + version: 1.3.4 + resolution: "@types/mapbox__vector-tile@npm:1.3.4" + dependencies: + "@types/geojson": "*" + "@types/mapbox__point-geometry": "*" + "@types/pbf": "*" + checksum: 5715d9da88a5ecadb63e3ca4d52272ead2c1d63fcf616841932719788e458fc10dd9919ad01aa9c95b15c83e9074dae9ffc7193a7ae4ae7b8436d26630f0e269 + languageName: node + linkType: hard + "@types/minimatch@npm:^3.0.3": version: 3.0.5 resolution: "@types/minimatch@npm:3.0.5" @@ -3161,6 +3271,13 @@ __metadata: languageName: node linkType: hard +"@types/pbf@npm:*, @types/pbf@npm:^3.0.5": + version: 3.0.5 + resolution: "@types/pbf@npm:3.0.5" + checksum: 9115eb3cc61e535748dd6de98c7a8bd64e02a4052646796013b075fed66fd52a3a2aaae6b75648e9c0361e8ed462a50549ca0af1015e2e48296cd8c31bb54577 + languageName: node + linkType: hard + "@types/prettier@npm:^2.1.5": version: 2.7.3 resolution: "@types/prettier@npm:2.7.3" @@ -3216,6 +3333,15 @@ __metadata: languageName: node linkType: hard +"@types/supercluster@npm:^7.1.3": + version: 7.1.3 + resolution: "@types/supercluster@npm:7.1.3" + dependencies: + "@types/geojson": "*" + checksum: 724188fb6ebdf0835821559da5480e5951c3e51afa86fcf83f5bf6984b89652f947081a3f6835cb082a6865fe5f1f8f667e92346f237d3518c2159121bb7c5cc + languageName: node + linkType: hard + "@types/three@npm:^0.135.0": version: 0.135.0 resolution: "@types/three@npm:0.135.0" @@ -3890,6 +4016,13 @@ __metadata: languageName: node linkType: hard +"arr-union@npm:^3.1.0": + version: 3.1.0 + resolution: "arr-union@npm:3.1.0" + checksum: b5b0408c6eb7591143c394f3be082fee690ddd21f0fdde0a0a01106799e847f67fcae1b7e56b0a0c173290e29c6aca9562e82b300708a268bc8f88f3d6613cb9 + languageName: node + linkType: hard + "array-buffer-byte-length@npm:^1.0.1": version: 1.0.1 resolution: "array-buffer-byte-length@npm:1.0.1" @@ -3958,6 +4091,13 @@ __metadata: languageName: node linkType: hard +"assign-symbols@npm:^1.0.0": + version: 1.0.0 + resolution: "assign-symbols@npm:1.0.0" + checksum: c0eb895911d05b6b2d245154f70461c5e42c107457972e5ebba38d48967870dee53bcdf6c7047990586daa80fab8dab3cc6300800fbd47b454247fdedd859a2c + languageName: node + linkType: hard + "astral-regex@npm:^2.0.0": version: 2.0.0 resolution: "astral-regex@npm:2.0.0" @@ -4158,6 +4298,25 @@ __metadata: languageName: node linkType: hard +"bytewise-core@npm:^1.2.2": + version: 1.2.3 + resolution: "bytewise-core@npm:1.2.3" + dependencies: + typewise-core: ^1.2 + checksum: e0d28fb7ff5bb6fd9320eef31c6b37e98da3b9a24d9893e2c17e0ee544457e0c76c2d3fc642c99d82daa0f18dcd49e7dce8dcc338711200e9ced79107cb78e8e + languageName: node + linkType: hard + +"bytewise@npm:^1.1.0": + version: 1.1.0 + resolution: "bytewise@npm:1.1.0" + dependencies: + bytewise-core: ^1.2.2 + typewise: ^1.0.3 + checksum: 20d7387ecf8c29adc4740e626fb02eaa27f34ae4c5ca881657d403e792730c0625ba4fed824462b3ddb7d3ebe41b7abbfe24f1cd3bf07cecc5a631f154d2d8d2 + languageName: node + linkType: hard + "cacache@npm:^16.1.0": version: 16.1.3 resolution: "cacache@npm:16.1.3" @@ -4504,13 +4663,6 @@ __metadata: languageName: node linkType: hard -"color-name@npm:^2.0.0": - version: 2.0.0 - resolution: "color-name@npm:2.0.0" - checksum: 10a1addae41de2987d6b90dbd3cfade266c2e6f680ce21749911df4493b4fae07654862c6b5358bdd13e155461acb4eedaa5e0ba172bf13542cdcca10866cf2b - languageName: node - linkType: hard - "color-name@npm:~1.1.4": version: 1.1.4 resolution: "color-name@npm:1.1.4" @@ -4518,32 +4670,6 @@ __metadata: languageName: node linkType: hard -"color-parse@npm:^2.0.0": - version: 2.0.2 - resolution: "color-parse@npm:2.0.2" - dependencies: - color-name: ^2.0.0 - checksum: 4e9446a9b1320da14e9b552b9be767b4fa78c18fbadf8a5c37e83f7fc9687723e2083cf2a17cecc818dcc9d64771f74db7815f218251e18535d1e8f52951c841 - languageName: node - linkType: hard - -"color-rgba@npm:^3.0.0": - version: 3.0.0 - resolution: "color-rgba@npm:3.0.0" - dependencies: - color-parse: ^2.0.0 - color-space: ^2.0.0 - checksum: 003b5fa70a77f46df3753e4b941154986163ccabbd9a8a80b2ca6cc4a0c9e505f3d4909c46a0b085e095d19b80297cf1c02dfefa33666b9ea1661ff52b3597bc - languageName: node - linkType: hard - -"color-space@npm:^2.0.0, color-space@npm:^2.0.1": - version: 2.0.1 - resolution: "color-space@npm:2.0.1" - checksum: 98f8f6acc716d2332705ef6a98876b47e8e39094256b83eec1df17246a5b5c37d107ae682e87d96488b06da12df3595ed5ad4f0e354a45571e23fb2196e4c6e7 - languageName: node - linkType: hard - "color-support@npm:^1.1.3": version: 1.1.3 resolution: "color-support@npm:1.1.3" @@ -5269,7 +5395,7 @@ __metadata: languageName: node linkType: hard -"earcut@npm:^2.2.3": +"earcut@npm:^2.2.4": version: 2.2.4 resolution: "earcut@npm:2.2.4" checksum: aea0466cb2f24e0c3c57148d8d28ac9846f53c4f43ee66780826474303ac851b305ef988152d0bdeb31e8f7ca939dc0df737e7505cfb1c1bdf2ff9d7f9ea2faa @@ -5864,6 +5990,25 @@ __metadata: languageName: node linkType: hard +"extend-shallow@npm:^2.0.1": + version: 2.0.1 + resolution: "extend-shallow@npm:2.0.1" + dependencies: + is-extendable: ^0.1.0 + checksum: 8fb58d9d7a511f4baf78d383e637bd7d2e80843bd9cd0853649108ea835208fb614da502a553acc30208e1325240bb7cc4a68473021612496bb89725483656d8 + languageName: node + linkType: hard + +"extend-shallow@npm:^3.0.0": + version: 3.0.2 + resolution: "extend-shallow@npm:3.0.2" + dependencies: + assign-symbols: ^1.0.0 + is-extendable: ^1.0.1 + checksum: a920b0cd5838a9995ace31dfd11ab5e79bf6e295aa566910ce53dff19f4b1c0fda2ef21f26b28586c7a2450ca2b42d97bd8c0f5cec9351a819222bf861e02461 + languageName: node + linkType: hard + "external-editor@npm:^3.0.3": version: 3.1.0 resolution: "external-editor@npm:3.1.0" @@ -6183,19 +6328,10 @@ __metadata: languageName: node linkType: hard -"geotiff@npm:^2.0.7": - version: 2.1.3 - resolution: "geotiff@npm:2.1.3" - dependencies: - "@petamoriken/float16": ^3.4.7 - lerc: ^3.0.0 - pako: ^2.0.4 - parse-headers: ^2.0.2 - quick-lru: ^6.1.1 - web-worker: ^1.2.0 - xml-utils: ^1.0.2 - zstddec: ^0.1.0 - checksum: e966c735339fe121d7cf22fad71c68dbe5f6c88c252baed40bc596c662829bdc6df1c2463855c2dfc5453d191425f6151945b2ad063837cb82a99fe3eb482b50 +"geojson-vt@npm:^3.2.1": + version: 3.2.1 + resolution: "geojson-vt@npm:3.2.1" + checksum: 7c7973cfaf9e3bb1c1dc9578ec00e602efb6f8d57f4dd7f6b28baeb7825bcaeb1684018b850211e333ab4b90a4a89a02ff7793732c505d67101ccbc38e307e02 languageName: node linkType: hard @@ -6254,7 +6390,7 @@ __metadata: languageName: node linkType: hard -"get-stream@npm:^6.0.0": +"get-stream@npm:^6.0.0, get-stream@npm:^6.0.1": version: 6.0.1 resolution: "get-stream@npm:6.0.1" checksum: e04ecece32c92eebf5b8c940f51468cd53554dcbb0ea725b2748be583c9523d00128137966afce410b9b051eb2ef16d657cd2b120ca8edafcf5a65e81af63cad @@ -6272,6 +6408,13 @@ __metadata: languageName: node linkType: hard +"get-value@npm:^2.0.2, get-value@npm:^2.0.6": + version: 2.0.6 + resolution: "get-value@npm:2.0.6" + checksum: 5c3b99cb5398ea8016bf46ff17afc5d1d286874d2ad38ca5edb6e87d75c0965b0094cb9a9dddef2c59c23d250702323539a7fbdd870620db38c7e7d7ec87c1eb + languageName: node + linkType: hard + "git-raw-commits@npm:^3.0.0": version: 3.0.0 resolution: "git-raw-commits@npm:3.0.0" @@ -6335,6 +6478,13 @@ __metadata: languageName: node linkType: hard +"gl-matrix@npm:^3.4.3": + version: 3.4.3 + resolution: "gl-matrix@npm:3.4.3" + checksum: c47830ba727f3d0fab635c48135af96aef66274079a3e0afd6f68b68c98eae9fc1bcfdc7312fe2301e4fd22dd24c5e0f1b5d025960a208e50d07101ed8d940f9 + languageName: node + linkType: hard + "glob-parent@npm:5.1.2, glob-parent@npm:^5.1.2": version: 5.1.2 resolution: "glob-parent@npm:5.1.2" @@ -7097,6 +7247,22 @@ __metadata: languageName: node linkType: hard +"is-extendable@npm:^0.1.0, is-extendable@npm:^0.1.1": + version: 0.1.1 + resolution: "is-extendable@npm:0.1.1" + checksum: 3875571d20a7563772ecc7a5f36cb03167e9be31ad259041b4a8f73f33f885441f778cee1f1fe0085eb4bc71679b9d8c923690003a36a6a5fdf8023e6e3f0672 + languageName: node + linkType: hard + +"is-extendable@npm:^1.0.1": + version: 1.0.1 + resolution: "is-extendable@npm:1.0.1" + dependencies: + is-plain-object: ^2.0.4 + checksum: db07bc1e9de6170de70eff7001943691f05b9d1547730b11be01c0ebfe67362912ba743cf4be6fd20a5e03b4180c685dad80b7c509fe717037e3eee30ad8e84f + languageName: node + linkType: hard + "is-extglob@npm:^2.1.1": version: 2.1.1 resolution: "is-extglob@npm:2.1.1" @@ -7187,7 +7353,7 @@ __metadata: languageName: node linkType: hard -"is-plain-object@npm:^2.0.4": +"is-plain-object@npm:^2.0.3, is-plain-object@npm:^2.0.4": version: 2.0.4 resolution: "is-plain-object@npm:2.0.4" dependencies: @@ -7586,6 +7752,13 @@ __metadata: languageName: node linkType: hard +"json-stringify-pretty-compact@npm:^4.0.0": + version: 4.0.0 + resolution: "json-stringify-pretty-compact@npm:4.0.0" + checksum: a10d5c423e467872994a49c5c1b56b073f277ce02d899cf567fc625f3783b89406bee6408bfb3b4bdeeff509b6a562f5259227e26754a6186f721809ca895f0c + languageName: node + linkType: hard + "json-stringify-safe@npm:^5.0.1": version: 5.0.1 resolution: "json-stringify-safe@npm:5.0.1" @@ -7636,6 +7809,13 @@ __metadata: languageName: node linkType: hard +"kdbush@npm:^4.0.2": + version: 4.0.2 + resolution: "kdbush@npm:4.0.2" + checksum: 6782ef2cdaec9322376b9955a16b0163beda0cefa2f87da76e8970ade2572d8b63bec915347aaeac609484b0c6e84d7b591f229ef353b68b460238095bacde2d + languageName: node + linkType: hard + "keyv@npm:^4.5.3": version: 4.5.4 resolution: "keyv@npm:4.5.4" @@ -7659,13 +7839,6 @@ __metadata: languageName: node linkType: hard -"lerc@npm:^3.0.0": - version: 3.0.0 - resolution: "lerc@npm:3.0.0" - checksum: 637699a1359cd80e581bac4bd66dd7ac09e6681fe97346c97939abdbc0170deac1b79ea00a17e334ef5d9d510973ca382abb43c39c8294788dd8391daeb75c32 - languageName: node - linkType: hard - "lerna@npm:^7.0.0": version: 7.4.2 resolution: "lerna@npm:7.4.2" @@ -8216,6 +8389,41 @@ __metadata: languageName: node linkType: hard +"maplibre-gl@npm:^4.4.1": + version: 4.4.1 + resolution: "maplibre-gl@npm:4.4.1" + dependencies: + "@mapbox/geojson-rewind": ^0.5.2 + "@mapbox/jsonlint-lines-primitives": ^2.0.2 + "@mapbox/point-geometry": ^0.1.0 + "@mapbox/tiny-sdf": ^2.0.6 + "@mapbox/unitbezier": ^0.0.1 + "@mapbox/vector-tile": ^1.3.1 + "@mapbox/whoots-js": ^3.1.0 + "@maplibre/maplibre-gl-style-spec": ^20.3.0 + "@types/geojson": ^7946.0.14 + "@types/geojson-vt": 3.2.5 + "@types/junit-report-builder": ^3.0.2 + "@types/mapbox__point-geometry": ^0.1.4 + "@types/mapbox__vector-tile": ^1.3.4 + "@types/pbf": ^3.0.5 + "@types/supercluster": ^7.1.3 + earcut: ^2.2.4 + geojson-vt: ^3.2.1 + gl-matrix: ^3.4.3 + global-prefix: ^3.0.0 + kdbush: ^4.0.2 + murmurhash-js: ^1.0.0 + pbf: ^3.2.1 + potpack: ^2.0.0 + quickselect: ^2.0.0 + supercluster: ^8.0.1 + tinyqueue: ^2.0.3 + vt-pbf: ^3.1.3 + checksum: 52f7ad6edb1ee932b8d946bb35f9d293a692317ae51321bc22ff865a7f1f58abcf5e4d8f30607c61d674bda8fe741022fa9d81a69c7e26e2385176bc2eb2a283 + languageName: node + linkType: hard + "markdown-to-jsx@npm:^7.4.1": version: 7.4.7 resolution: "markdown-to-jsx@npm:7.4.7" @@ -8441,7 +8649,7 @@ __metadata: languageName: node linkType: hard -"minimist@npm:^1.2.0, minimist@npm:^1.2.5, minimist@npm:^1.2.6, minimist@npm:~1.2.0": +"minimist@npm:^1.2.0, minimist@npm:^1.2.5, minimist@npm:^1.2.6, minimist@npm:^1.2.8, minimist@npm:~1.2.0": version: 1.2.8 resolution: "minimist@npm:1.2.8" checksum: 75a6d645fb122dad29c06a7597bddea977258957ed88d7a6df59b5cd3fe4a527e253e9bbf2e783e4b73657f9098b96a5fe96ab8a113655d4109108577ecf85b0 @@ -8623,6 +8831,13 @@ __metadata: languageName: node linkType: hard +"murmurhash-js@npm:^1.0.0": + version: 1.0.0 + resolution: "murmurhash-js@npm:1.0.0" + checksum: 083cea92a11bc9eb25be1446fc92eded3f49731bc1ad34fa8023afd68c234d1dd59458d70eb20e667b1383bedeeb8dfb1a16c89913b6ffe3584fd22fb598739d + languageName: node + linkType: hard + "mute-stream@npm:0.0.8": version: 0.0.8 resolution: "mute-stream@npm:0.0.8" @@ -9185,20 +9400,6 @@ __metadata: languageName: node linkType: hard -"ol@npm:^9.2.4": - version: 9.2.4 - resolution: "ol@npm:9.2.4" - dependencies: - color-rgba: ^3.0.0 - color-space: ^2.0.1 - earcut: ^2.2.3 - geotiff: ^2.0.7 - pbf: 3.2.1 - rbush: ^3.0.1 - checksum: 71bf31f8b69ff06f94c800bf9621c996c14e579803aa40ac944d1bbbc04bf48b04f498a542fa4154a9902a2724c9d20af1c5852e901e611627f3ae4c428b5a1f - languageName: node - linkType: hard - "once@npm:^1.3.0, once@npm:^1.4.0": version: 1.4.0 resolution: "once@npm:1.4.0" @@ -9427,13 +9628,6 @@ __metadata: languageName: node linkType: hard -"pako@npm:^2.0.4": - version: 2.1.0 - resolution: "pako@npm:2.1.0" - checksum: 71666548644c9a4d056bcaba849ca6fd7242c6cf1af0646d3346f3079a1c7f4a66ffec6f7369ee0dc88f61926c10d6ab05da3e1fca44b83551839e89edd75a3e - languageName: node - linkType: hard - "parent-module@npm:^1.0.0": version: 1.0.1 resolution: "parent-module@npm:1.0.1" @@ -9443,13 +9637,6 @@ __metadata: languageName: node linkType: hard -"parse-headers@npm:^2.0.2": - version: 2.0.5 - resolution: "parse-headers@npm:2.0.5" - checksum: 3e97f01e4c7f960bfbfd0ee489f0bd8d3c72b6c814f1f79b66abec2cca8eaf8e4ecd89deba0b6e61266469aed87350bc932001181c01ff8c29a59e696abe251f - languageName: node - linkType: hard - "parse-json@npm:^4.0.0": version: 4.0.0 resolution: "parse-json@npm:4.0.0" @@ -9572,7 +9759,7 @@ __metadata: languageName: node linkType: hard -"pbf@npm:3.2.1": +"pbf@npm:^3.2.1": version: 3.2.1 resolution: "pbf@npm:3.2.1" dependencies: @@ -9746,6 +9933,13 @@ __metadata: languageName: node linkType: hard +"potpack@npm:^2.0.0": + version: 2.0.0 + resolution: "potpack@npm:2.0.0" + checksum: 6dd41692349936b436c29c28cf9ff1268c03ed6ec96c4384b2d9eb95e58e422fab75d428648f475507dd167934984d1002df2010b83e5747b5c358bea371e8f7 + languageName: node + linkType: hard + "prelude-ls@npm:^1.2.1": version: 1.2.1 resolution: "prelude-ls@npm:1.2.1" @@ -9919,13 +10113,6 @@ __metadata: languageName: node linkType: hard -"quick-lru@npm:^6.1.1": - version: 6.1.2 - resolution: "quick-lru@npm:6.1.2" - checksum: 0491a24dcd39b8a325e9d3ae719fad7690a1da7a0dbfa8f16613663dc7d262d08b565005ce16a04497ed4700f1f477b8e06cd46e10a7a112a481a18d056c38f7 - languageName: node - linkType: hard - "quickselect@npm:^2.0.0": version: 2.0.0 resolution: "quickselect@npm:2.0.0" @@ -9942,15 +10129,6 @@ __metadata: languageName: node linkType: hard -"rbush@npm:^3.0.1": - version: 3.0.1 - resolution: "rbush@npm:3.0.1" - dependencies: - quickselect: ^2.0.0 - checksum: b7def5ba762ca01b6c7c032098ef61b86bd4fef4afb82e4a1d70a07a929b39e779290446c2d4730f577e8a1c8fd0dfd349605b5ea0229258d5f013debdffa65a - languageName: node - linkType: hard - "react-codemirror2@npm:^7.2.1": version: 7.3.0 resolution: "react-codemirror2@npm:7.3.0" @@ -10407,6 +10585,13 @@ __metadata: languageName: node linkType: hard +"rw@npm:^1.3.3": + version: 1.3.3 + resolution: "rw@npm:1.3.3" + checksum: c20d82421f5a71c86a13f76121b751553a99cd4a70ea27db86f9b23f33db941f3f06019c30f60d50c356d0bd674c8e74764ac146ea55e217c091bde6fba82aa3 + languageName: node + linkType: hard + "rxjs@npm:^7.5.5": version: 7.8.1 resolution: "rxjs@npm:7.8.1" @@ -10598,6 +10783,18 @@ __metadata: languageName: node linkType: hard +"set-value@npm:^2.0.1": + version: 2.0.1 + resolution: "set-value@npm:2.0.1" + dependencies: + extend-shallow: ^2.0.1 + is-extendable: ^0.1.1 + is-plain-object: ^2.0.3 + split-string: ^3.0.1 + checksum: 09a4bc72c94641aeae950eb60dc2755943b863780fcc32e441eda964b64df5e3f50603d5ebdd33394ede722528bd55ed43aae26e9df469b4d32e2292b427b601 + languageName: node + linkType: hard + "shallow-clone@npm:^3.0.0": version: 3.0.1 resolution: "shallow-clone@npm:3.0.1" @@ -10758,6 +10955,20 @@ __metadata: languageName: node linkType: hard +"sort-asc@npm:^0.2.0": + version: 0.2.0 + resolution: "sort-asc@npm:0.2.0" + checksum: b3610ab695dc8b2cba1c3e6ead06ce97a41f013ed0a002ff7a0d2a39ca297fd2f58c92d3de67dda3a9313ecb1073de4eacc30da3a740ff8d57eb668c9bb151bd + languageName: node + linkType: hard + +"sort-desc@npm:^0.2.0": + version: 0.2.0 + resolution: "sort-desc@npm:0.2.0" + checksum: fb2c02ea38815c79c0127d014f18926a473a1988c01f4c00de467584b99fc7e9f6e4f61c8386f4c2ac3501c60842931c5a499330b3086be6d8cff4d0b8602bed + languageName: node + linkType: hard + "sort-keys@npm:^2.0.0": version: 2.0.0 resolution: "sort-keys@npm:2.0.0" @@ -10767,6 +10978,20 @@ __metadata: languageName: node linkType: hard +"sort-object@npm:^3.0.3": + version: 3.0.3 + resolution: "sort-object@npm:3.0.3" + dependencies: + bytewise: ^1.1.0 + get-value: ^2.0.2 + is-extendable: ^0.1.1 + sort-asc: ^0.2.0 + sort-desc: ^0.2.0 + union-value: ^1.0.1 + checksum: 381a6b6fe2309d400bd6ae3a8d0188b2b3b3855345d16d953b4bb5875d28fd5512501c85bd4eb951543056cd3095ff8e197ab3efc11389dcfa0e3334bf4a23a5 + languageName: node + linkType: hard + "source-list-map@npm:^2.0.0": version: 2.0.1 resolution: "source-list-map@npm:2.0.1" @@ -10867,6 +11092,15 @@ __metadata: languageName: node linkType: hard +"split-string@npm:^3.0.1": + version: 3.1.0 + resolution: "split-string@npm:3.1.0" + dependencies: + extend-shallow: ^3.0.0 + checksum: ae5af5c91bdc3633628821bde92fdf9492fa0e8a63cf6a0376ed6afde93c701422a1610916f59be61972717070119e848d10dfbbd5024b7729d6a71972d2a84c + languageName: node + linkType: hard + "split2@npm:^3.2.2": version: 3.2.2 resolution: "split2@npm:3.2.2" @@ -11218,6 +11452,15 @@ __metadata: languageName: node linkType: hard +"supercluster@npm:^8.0.1": + version: 8.0.1 + resolution: "supercluster@npm:8.0.1" + dependencies: + kdbush: ^4.0.2 + checksum: 39d141f768a511efa53260252f9dab9a2ce0228b334e55482c8d3019e151932f05e1a9a0252d681737651b13c741c665542a6ddb40ec27de96159ea7ad41f7f4 + languageName: node + linkType: hard + "supports-color@npm:^5.3.0, supports-color@npm:^5.5.0": version: 5.5.0 resolution: "supports-color@npm:5.5.0" @@ -11465,6 +11708,13 @@ __metadata: languageName: node linkType: hard +"tinyqueue@npm:^2.0.3": + version: 2.0.3 + resolution: "tinyqueue@npm:2.0.3" + checksum: 0b6bda46b680dca072f84aef1acd22a7085a2ff2aa8e222bb41045c61a056943805056d77d7f976587ed6a0597872beb5c416043f65f0314304432d6c178dd20 + languageName: node + linkType: hard + "tmp@npm:^0.0.33": version: 0.0.33 resolution: "tmp@npm:0.0.33" @@ -11765,6 +12015,22 @@ __metadata: languageName: node linkType: hard +"typewise-core@npm:^1.2, typewise-core@npm:^1.2.0": + version: 1.2.0 + resolution: "typewise-core@npm:1.2.0" + checksum: c21e83544546d1aba2f17377c25ae0eb571c2153b2e3705932515bef103dbe43e05d2286f238ad139341b1000da40583115a44cb5e69a2ef408572b13dab844b + languageName: node + linkType: hard + +"typewise@npm:^1.0.3": + version: 1.0.3 + resolution: "typewise@npm:1.0.3" + dependencies: + typewise-core: ^1.2.0 + checksum: eb3452b1387df8bf8e3b620720d240425a50ce402d7c064c21ac4b5d88c551ee4d1f26cd649b8a17a6d06f7a3675733de841723f8e06bb3edabfeacc4924af4a + languageName: node + linkType: hard + "uglify-js@npm:^3.1.4": version: 3.17.4 resolution: "uglify-js@npm:3.17.4" @@ -11800,6 +12066,18 @@ __metadata: languageName: node linkType: hard +"union-value@npm:^1.0.1": + version: 1.0.1 + resolution: "union-value@npm:1.0.1" + dependencies: + arr-union: ^3.1.0 + get-value: ^2.0.6 + is-extendable: ^0.1.1 + set-value: ^2.0.1 + checksum: a3464097d3f27f6aa90cf103ed9387541bccfc006517559381a10e0dffa62f465a9d9a09c9b9c3d26d0f4cbe61d4d010e2fbd710fd4bf1267a768ba8a774b0ba + languageName: node + linkType: hard + "unique-filename@npm:^2.0.0": version: 2.0.1 resolution: "unique-filename@npm:2.0.1" @@ -12057,6 +12335,17 @@ __metadata: languageName: node linkType: hard +"vt-pbf@npm:^3.1.3": + version: 3.1.3 + resolution: "vt-pbf@npm:3.1.3" + dependencies: + "@mapbox/point-geometry": 0.1.0 + "@mapbox/vector-tile": ^1.3.1 + pbf: ^3.2.1 + checksum: 83375b7ffe2e92ab2a4c9924cf2cd80e311b38e9e616c244656140a76090c037c55a1b1379b234cb6567444f32e9cb40fd2c5b6e555ffff4330feba56250f90c + languageName: node + linkType: hard + "w3c-keyname@npm:^2.2.4": version: 2.2.8 resolution: "w3c-keyname@npm:2.2.8" @@ -12092,13 +12381,6 @@ __metadata: languageName: node linkType: hard -"web-worker@npm:^1.2.0": - version: 1.3.0 - resolution: "web-worker@npm:1.3.0" - checksum: ed1f869aefd1d81a43d0fbfe7b315a65beb6d7d2486b378c436a7047eed4216be34b2e6afca738b6fa95d016326b765f5f816355db33267dbf43b2b8a1837c0c - languageName: node - linkType: hard - "webidl-conversions@npm:^3.0.0": version: 3.0.1 resolution: "webidl-conversions@npm:3.0.1" @@ -12460,13 +12742,6 @@ __metadata: languageName: node linkType: hard -"xml-utils@npm:^1.0.2": - version: 1.10.1 - resolution: "xml-utils@npm:1.10.1" - checksum: 60a312734f93a98b9c6cc97a9f7d2a14b315ad1528e8c55f44c2d7d0af6eee61255d0aafd6589b41b72fe6e9f6e9727a51c4ab42cfa24f8616724c741cc151ef - languageName: node - linkType: hard - "xtend@npm:^4.0.2, xtend@npm:~4.0.0, xtend@npm:~4.0.1": version: 4.0.2 resolution: "xtend@npm:4.0.2" @@ -12635,10 +12910,3 @@ __metadata: checksum: f77b3d8d00310def622123df93d4ee654fc6a0096182af8bd60679ddcdfb3474c56c6c7190817c84a2785648cdee9d721c0154eb45698c62176c322fb46fc700 languageName: node linkType: hard - -"zstddec@npm:^0.1.0": - version: 0.1.0 - resolution: "zstddec@npm:0.1.0" - checksum: 76113b43ec4031f9a120285c830e43bafae4c25c0a72f7a9e228af815c3e52432a8414c5d4eb6cfd3282443a4a3d2bc18b445dd702e770b1e330b6e39081750f - languageName: node - linkType: hard