Skip to content

Commit

Permalink
Iterate
Browse files Browse the repository at this point in the history
  • Loading branch information
martinRenou committed Jun 20, 2024
1 parent 48608dc commit 1d1bd4e
Show file tree
Hide file tree
Showing 12 changed files with 172 additions and 139 deletions.
5 changes: 3 additions & 2 deletions examples/test.jGIS
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
{
"layers": [],
"layers": {},
"sources": {},
"options": {}
}
}
106 changes: 51 additions & 55 deletions packages/base/src/commands.ts
Original file line number Diff line number Diff line change
@@ -1,41 +1,14 @@
import { JupyterFrontEnd } from '@jupyterlab/application';
import { WidgetTracker, showErrorMessage } from '@jupyterlab/apputils';
import { WidgetTracker } from '@jupyterlab/apputils';
import { ITranslator } from '@jupyterlab/translation';
import { redoIcon, undoIcon } from '@jupyterlab/ui-components';

import { JupyterGISWidget } from './widget';
import { IDict, IJGISFormSchemaRegistry, IJGISLayer, IJupyterGISModel, LayerType } from '@jupytergis/schema';
import { IDict, IJGISFormSchemaRegistry, IJGISLayer, IJGISSource, IJupyterGISModel } from '@jupytergis/schema';
import { FormDialog } from './formdialog';
import { UUID } from '@lumino/coreutils';


export function newName(type: string, model: IJupyterGISModel): string {
const sharedModel = model.sharedModel;

let n = 1;
let name = `${type} 1`;
while (sharedModel.layerExists(name)) {
name = `${type} ${++n}`;
}

return name;
}


const LAYERS = {
TileLayer: {
title: 'Tile Layer parameters',
layerType: 'TileLayer',
default: (model: IJupyterGISModel) => {
return {
name: newName('TileLayer', model),
url: "https://tile.openstreetmap.org/{z}/{x}/{y}.png",
maxZoom: 24,
minZoom: 0
};
}
},
};

/**
* Add the commands to the application's command registry.
*/
Expand Down Expand Up @@ -82,15 +55,15 @@ export function addCommands(
icon: undoIcon
});

commands.addCommand(CommandIDs.newTileLayer, {
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.createLayer('TileLayer', tracker)
execute: Private.createRasterSourceAndLayer(tracker)
});
}

Expand All @@ -101,7 +74,7 @@ export namespace CommandIDs {
export const redo = 'jupytergis:redo';
export const undo = 'jupytergis:undo';

export const newTileLayer = 'jupytergis:newTileLayer';
export const newRasterLayer = 'jupytergis:newRasterLayer';
}


Expand All @@ -119,14 +92,16 @@ namespace Private {
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' },
name: { type: 'string', description: 'The name of the layer/source' },
...value['properties']
};
});
}

export function createLayer(
layer: keyof typeof LAYERS,
// 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<JupyterGISWidget>
) {
return async (args: any) => {
Expand All @@ -136,9 +111,19 @@ namespace Private {
return;
}

const value = LAYERS[layer];
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(value);
current.context.model.syncFormData(form);

const syncSelectedField = (
id: string | null,
Expand All @@ -159,29 +144,40 @@ namespace Private {

const dialog = new FormDialog({
context: current.context,
title: value.title,
sourceData: value.default(current.context.model),
schema: FORM_SCHEMA[value.layerType],
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 = {
layerType: value.layerType as LayerType,
parameters,
type: "RasterLayer",
parameters: {
source: sourceId
},
visible: true,
name: name
name: name + " Layer"
};

const sharedModel = current.context.model.sharedModel;
if (sharedModel) {
if (!sharedModel.layerExists(layerModel.name)) {
sharedModel.addLayer(layerModel);
} else {
showErrorMessage(
'The object already exists',
'There is an existing object with the same name.'
);
}
}
sharedModel.addSource(sourceId, sourceModel)
sharedModel.addLayer(UUID.uuid4(), layerModel);
},
cancelButton: () => {
current.context.model.syncFormData(undefined);
Expand Down
51 changes: 39 additions & 12 deletions packages/base/src/mainview/mainview.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import {
IJupyterGISClientState,
IJupyterGISDoc,
IJupyterGISModel,
ITileLayer,
IRasterSource,
} from '@jupytergis/schema';
import { IObservableMap, ObservableMap } from '@jupyterlab/observables';
import { User } from '@jupyterlab/services';
Expand Down Expand Up @@ -131,26 +131,53 @@ export class MainView extends React.Component<IProps, IStates> {
// console.log('new change', change);
// })

for (const layer of this._model.sharedModel.layers) {
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 tileLayerParameters = layer.parameters as ITileLayer;
this._Map.addSource('raster-source', {
type: 'raster',
tiles: [tileLayerParameters.url],
tileSize: 256,
});
const sourceId = layer.parameters?.source;
const source = this.getSource<IRasterSource>(sourceId);

if (!source) {
continue;
}

if (!this._Map.getSource(sourceId)) {
this._Map.addSource(sourceId, {
type: 'raster',
tiles: [source.url],
tileSize: 256,
});
}

this._Map.addLayer({
id: 'simple-tiles',
id: layerId,
type: 'raster',
source: 'raster-source',
minzoom: tileLayerParameters.minZoom,
maxzoom: tileLayerParameters.maxZoom,
source: sourceId,
minzoom: source.minZoom,
maxzoom: source.maxZoom,
});
}
}
}

private getSource<T>(id: string): T | undefined {
const source = this._model.sharedModel.getSource(id);

if (source) {
console.log(`Source id ${id} does not exist`);
return;
}

return source as T;
}

private _handleThemeChange = (): void => {
const lightTheme = isLightTheme();

Expand Down
49 changes: 9 additions & 40 deletions packages/base/src/panelview/objectproperties.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import {
IDict,
IJGISFormSchemaRegistry,
IJGISLayers,
IJGISLayerDocChange,
IJupyterGISClientState,
IJupyterGISDoc,
Expand All @@ -16,7 +15,6 @@ import { v4 as uuid } from 'uuid';

import {
focusInputField,
itemFromName,
removeStyleFromProperty
} from '../tools';
import { IControlPanelModel } from '../types';
Expand All @@ -42,7 +40,6 @@ export class ObjectProperties extends PanelWithToolbar {
interface IStates {
jGISOption?: IDict;
filePath?: string;
jGISLayers?: IJGISLayers;
selectedObjectData?: IDict;
selectedObject?: string;
schema?: IDict;
Expand All @@ -62,7 +59,6 @@ class ObjectPropertiesReact extends React.Component<IProps, IStates> {
super(props);
this.state = {
filePath: this.props.cpModel.filePath,
jGISLayers: this.props.cpModel.jGISModel?.getLayers(),
clientId: null,
id: uuid()
};
Expand All @@ -84,14 +80,12 @@ class ObjectPropertiesReact extends React.Component<IProps, IStates> {
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
Expand All @@ -100,11 +94,11 @@ class ObjectPropertiesReact extends React.Component<IProps, IStates> {
});
}

async syncLayerProperties(
objectName: string | undefined,
async syncObjectProperties(
id: string | undefined,
properties: { [key: string]: any }
) {
if (!this.state.jGISLayers || !objectName) {
if (!id) {
return;
}

Expand All @@ -119,24 +113,7 @@ class ObjectPropertiesReact extends React.Component<IProps, IStates> {
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 = (
Expand All @@ -162,26 +139,18 @@ class ObjectPropertiesReact extends React.Component<IProps, IStates> {
): 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;
}
});
};
Expand Down Expand Up @@ -228,7 +197,7 @@ class ObjectPropertiesReact extends React.Component<IProps, IStates> {
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}
/>
Expand Down
4 changes: 2 additions & 2 deletions packages/base/src/toolbar/widget.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -55,9 +55,9 @@ export class ToolbarWidget extends Toolbar {
this.addItem('separator1', new Separator());

this.addItem(
'newTileLayer',
'newRasterLayer',
new CommandToolbarButton({
id: CommandIDs.newTileLayer,
id: CommandIDs.newRasterLayer,
label: '',
commands: options.commands
})
Expand Down
Loading

0 comments on commit 1d1bd4e

Please sign in to comment.