Skip to content

Create and edit vector layers #692

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 30 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
2fff268
Add a toggle button to enable to add a draw vector layer.
HaudinFlorence May 12, 2025
80284cc
Remove the VectorLayerDropdown component and move the logics that was…
HaudinFlorence May 14, 2025
fec7155
Change _handleDrawVectorLayerChanged method to _updateIsDrawVectorLay…
HaudinFlorence May 14, 2025
0efbcac
Add logics to create the vector layer and to add it to the map.
HaudinFlorence May 14, 2025
5ca4df4
Add logics to remove the draw interaction when isDrawVectorLayerEnabl…
HaudinFlorence May 15, 2025
399b381
Add an enabled method to the newVDrawVectorLayer, update the toggle m…
HaudinFlorence May 15, 2025
cc5c66a
Add logics to use the source of the currently selected layer in the _…
HaudinFlorence May 19, 2025
52a5926
Update the _handleDrawGeometryTypeChange method with removing the cre…
HaudinFlorence May 19, 2025
4732246
Update packages/base/src/commands.ts
HaudinFlorence May 20, 2025
c43d67d
Update newDrawVectorLayer command.
HaudinFlorence May 20, 2025
cc2ec6c
Remove test-results/.last-run.json from the git history tracking and …
HaudinFlorence May 20, 2025
b042477
Update the newDrawVectorLayer command and the _handleDrawGeometryType…
HaudinFlorence May 20, 2025
c41b05b
Remove the enabled method in the the newDrawVectorLayer command.
HaudinFlorence May 27, 2025
1f4a637
Update _handleDrawGeometryTypeChange with replacing the drawend event…
HaudinFlorence May 27, 2025
f5db4da
Change the ui : use the toolbar button for the creation of a new empt…
HaudinFlorence Jun 2, 2025
5152236
Update the GeoJSONSourcePropertiesForm class to enable the possibilit…
HaudinFlorence Jun 2, 2025
d234d9c
Change the ui to create a new empty vector layer by clicking on the …
HaudinFlorence Jun 4, 2025
0fb6a4d
Provide a onFormSubmit method to the GeoJSONSourcePropertiesForm and …
HaudinFlorence Jun 6, 2025
c3e28e0
Try to modify the path description in the processSchema method of Geo…
HaudinFlorence Jun 6, 2025
0cfe644
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Jun 9, 2025
8a1cb38
Apply suggestions from code review
HaudinFlorence Jun 10, 2025
2107d46
Take review comments into account.
HaudinFlorence Jun 10, 2025
ddaa088
Restore toggle toolbar button for the toggleDrawFeatures command.
HaudinFlorence Jun 11, 2025
43f20b9
Refactor the code.
HaudinFlorence Jun 12, 2025
4a1c7e6
Update methods related to draw interactions in MainView class.
HaudinFlorence Jun 13, 2025
ce17370
Update all interactions in a single updateInteractions.
HaudinFlorence Jun 16, 2025
f42d24b
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Jun 17, 2025
0459a30
Apply suggestions from code review
HaudinFlorence Jun 17, 2025
673bfd6
Take review comments into account.
HaudinFlorence Jun 17, 2025
65e400e
Add a check on the type of the layer in onSelectedLayerChange to prev…
HaudinFlorence Jun 18, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,9 @@ dmypy.json
**/ui-tests/test-results/
**/ui-tests/playwright-report/

# tests_results
**/test-results/

examples/Untitled*.ipynb
# Hatchling
jupytergis/_version.py
Expand Down
102 changes: 102 additions & 0 deletions examples/editable.jGIS
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
{
"layerTree": [
"8de7c2c0-6024-4716-b542-031a89fb87f9",
"3e21d680-406f-4099-bd9e-3a4edb9a2c8b"
],
"layers": {
"3e21d680-406f-4099-bd9e-3a4edb9a2c8b": {
"filters": {
"appliedFilters": [],
"logicalOp": "all"
},
"name": "Editable GeoJSON Layer",
"parameters": {
"color": {
"circle-fill-color": "#f66151",
"circle-radius": 5.0,
"circle-stroke-color": "#62a0ea",
"circle-stroke-line-cap": "round",
"circle-stroke-line-join": "round",
"circle-stroke-width": 1.25
},
"opacity": 1.0,
"source": "348d85fa-3a71-447f-8a64-e283ec47cc7c",
"symbologyState": {
"renderType": "Single Symbol"
},
"type": "circle"
},
"type": "VectorLayer",
"visible": true
},
"8de7c2c0-6024-4716-b542-031a89fb87f9": {
"name": "OpenStreetMap.Mapnik Layer",
"parameters": {
"source": "b2ea427a-a51b-43ad-ae72-02cd900736d5"
},
"type": "RasterLayer",
"visible": true
}
},
"metadata": {},
"options": {
"bearing": 0.0,
"extent": [
-14181614.437015302,
-5303433.533961326,
-2473763.273952904,
13774201.834902454
],
"latitude": 35.52446437432016,
"longitude": -74.80890180273175,
"pitch": 0.0,
"projection": "EPSG:3857",
"zoom": 2.6670105136699993
},
"schemaVersion": "0.5.0",
"sources": {
"348d85fa-3a71-447f-8a64-e283ec47cc7c": {
"name": "Editable GeoJSON Layer Source",
"parameters": {
"data": {
"features": [
{
"geometry": {
"coordinates": [
102.0,
0.5
],
"type": "Point"
},
"type": "Feature"
},
{
"geometry": {
"coordinates": [
102.0,
0.5
],
"type": "Point"
},
"type": "Feature"
}
],
"type": "FeatureCollection"
}
},
"type": "GeoJSONSource"
},
"b2ea427a-a51b-43ad-ae72-02cd900736d5": {
"name": "OpenStreetMap.Mapnik",
"parameters": {
"attribution": "(C) OpenStreetMap contributors",
"maxZoom": 19.0,
"minZoom": 0.0,
"provider": "OpenStreetMap",
"url": "https://tile.openstreetmap.org/{z}/{x}/{y}.png",
"urlParameters": {}
},
"type": "RasterSource"
}
}
}
62 changes: 61 additions & 1 deletion packages/base/src/commands.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ import { ProcessingFormDialog } from './dialogs/ProcessingFormDialog';
import { LayerBrowserWidget } from './dialogs/layerBrowserDialog';
import { LayerCreationFormDialog } from './dialogs/layerCreationFormDialog';
import { SymbologyWidget } from './dialogs/symbology/symbologyDialog';
import { targetWithCenterIcon } from './icons';
import { pencilSolidIcon, targetWithCenterIcon } from './icons';
import keybindings from './keybindings.json';
import {
getSingleSelectedLayer,
Expand Down Expand Up @@ -938,6 +938,66 @@ export function addCommands(
icon: targetWithCenterIcon,
});

commands.addCommand(CommandIDs.toggleDrawFeatures, {
label: trans.__('Edit Features'),
isToggled: () => {
if (tracker.currentWidget instanceof JupyterGISDocumentWidget) {
const model = tracker.currentWidget?.content.currentViewModel
.jGISModel as IJupyterGISModel;
const selectedLayer = getSingleSelectedLayer(tracker);
if (!selectedLayer) {
return false;
} else if (model.checkIfIsADrawVectorLayer(selectedLayer) === true) {
return model.editingVectorLayer;
} else {
model.editingVectorLayer === false;
return false;
}
} else {
return false;
}
},
isEnabled: () => {
if (tracker.currentWidget instanceof JupyterGISDocumentWidget) {
const model = tracker.currentWidget?.content.currentViewModel
.jGISModel as IJupyterGISModel;
const selectedLayer = getSingleSelectedLayer(tracker);

if (!selectedLayer) {
return false;
}
if (model.checkIfIsADrawVectorLayer(selectedLayer) === true) {
return true;
} else {
return false;
}
} else {
return false;
}
},
execute: async () => {
if (tracker.currentWidget instanceof JupyterGISDocumentWidget) {
const selectedLayer = getSingleSelectedLayer(tracker);
const model = tracker.currentWidget?.content.currentViewModel
.jGISModel as IJupyterGISModel;
if (!selectedLayer) {
return false;
} else {
if (model.editingVectorLayer === false) {
model.editingVectorLayer = true;
} else {
model.editingVectorLayer = false;
}
}

model.updateEditingVectorLayer();
commands.notifyCommandChanged(CommandIDs.toggleDrawFeatures);
}
},

icon: pencilSolidIcon,
});

loadKeybindings(commands, keybindings);
}

Expand Down
3 changes: 3 additions & 0 deletions packages/base/src/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,9 @@ export namespace CommandIDs {
export const renameSource = 'jupytergis:renameSource';
export const removeSource = 'jupytergis:removeSource';

// Add draw features to a geoGSON source
export const toggleDrawFeatures = 'jupytergis:toggleDrawFeatures';

// Console commands
export const toggleConsole = 'jupytergis:toggleConsole';
export const invokeCompleter = 'jupytergis:invokeConsoleCompleter';
Expand Down
26 changes: 21 additions & 5 deletions packages/base/src/formbuilder/objectform/source/geojsonsource.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import { IDict } from '@jupytergis/schema';
import * as geojson from '@jupytergis/schema/src/schema/geojson.json';
import { showErrorMessage } from '@jupyterlab/apputils';
import { ISubmitEvent } from '@rjsf/core';
import { Ajv, ValidateFunction } from 'ajv';

import { loadFile } from '@/src/tools';
Expand Down Expand Up @@ -27,8 +29,11 @@ export class GeoJSONSourcePropertiesForm extends PathBasedSourcePropertiesForm {
if (data?.path !== '') {
this.removeFormEntry('data', data, schema, uiSchema);
}

super.processSchema(data, schema, uiSchema);
if (this.props.formContext === 'create') {
(schema.properties.path.description =
'The local path to a GeoJSON file. (If no path/url is provided, an empty GeoJSON is created.)'),
super.processSchema(data, schema, uiSchema);
}
}

/**
Expand All @@ -40,7 +45,7 @@ export class GeoJSONSourcePropertiesForm extends PathBasedSourcePropertiesForm {
const extraErrors: IDict = this.state.extraErrors;

let error = '';
let valid = false;
let valid = true;
if (path) {
try {
const geoJSONData = await loadFile({
Expand All @@ -55,8 +60,6 @@ export class GeoJSONSourcePropertiesForm extends PathBasedSourcePropertiesForm {
} catch (e) {
error = `"${path}" is not a valid GeoJSON file: ${e}`;
}
} else {
error = 'Path is required';
}

if (!valid) {
Expand All @@ -79,4 +82,17 @@ export class GeoJSONSourcePropertiesForm extends PathBasedSourcePropertiesForm {
this.props.formErrorSignal.emit(!valid);
}
}
protected onFormSubmit(e: ISubmitEvent<any>) {
if (this.state.extraErrors?.path?.__errors?.length >= 1) {
showErrorMessage('Invalid file', this.state.extraErrors.path.__errors[0]);
return;
}
if (!e.formData.path) {
e.formData.data = {
type: 'FeatureCollection',
features: [],
};
}
super.onFormSubmit(e);
}
}
6 changes: 6 additions & 0 deletions packages/base/src/icons.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import logoMiniAlternativeSvgStr from '../style/icons/logo_mini_alternative.svg'
import logoMiniQGZ from '../style/icons/logo_mini_qgz.svg';
import moundSvgStr from '../style/icons/mound.svg';
import nonVisibilitySvgStr from '../style/icons/nonvisibility.svg';
import pencilSolidSvgStr from '../style/icons/pencil_solid.svg';
import rasterSvgStr from '../style/icons/raster.svg';
import targetWithCenterSvgStr from '../style/icons/target_with_center.svg';
import targetWithoutCenterSvgStr from '../style/icons/target_without_center.svg';
Expand Down Expand Up @@ -109,3 +110,8 @@ export const targetWithCenterIcon = new LabIcon({
name: 'jupytergis::targetWithoutCenter',
svgstr: targetWithoutCenterSvgStr,
});

export const pencilSolidIcon = new LabIcon({
name: 'jupytergis::pencilSolid',
svgstr: pencilSolidSvgStr,
});
Loading
Loading