@jupytergis/base 0.6.2 → 0.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/annotations/components/Annotation.d.ts +2 -3
- package/lib/annotations/components/Annotation.js +2 -9
- package/lib/commands/BaseCommandIDs.d.ts +1 -0
- package/lib/commands/BaseCommandIDs.js +1 -0
- package/lib/commands/index.js +15 -0
- package/lib/constants.js +1 -0
- package/lib/dialogs/symbology/components/color_ramp/ColorRamp.js +1 -1
- package/lib/dialogs/symbology/hooks/useGetProperties.js +53 -19
- package/lib/dialogs/symbology/vector_layer/VectorRendering.js +3 -3
- package/lib/dialogs/symbology/vector_layer/types/Graduated.js +4 -2
- package/lib/dialogs/symbology/vector_layer/types/Heatmap.js +2 -2
- package/lib/formbuilder/formselectors.js +3 -0
- package/lib/formbuilder/objectform/source/geojsonsource.d.ts +3 -1
- package/lib/formbuilder/objectform/source/geojsonsource.js +20 -4
- package/lib/index.d.ts +1 -1
- package/lib/index.js +1 -1
- package/lib/keybindings.json +2 -2
- package/lib/mainview/mainView.d.ts +8 -1
- package/lib/mainview/mainView.js +33 -4
- package/lib/mainview/mainviewwidget.d.ts +11 -4
- package/lib/mainview/mainviewwidget.js +3 -2
- package/lib/menus.js +4 -0
- package/lib/panelview/annotationPanel.d.ts +3 -17
- package/lib/panelview/annotationPanel.js +5 -22
- package/lib/panelview/components/filter-panel/Filter.d.ts +2 -19
- package/lib/panelview/components/filter-panel/Filter.js +26 -59
- package/lib/panelview/components/identify-panel/IdentifyPanel.d.ts +6 -14
- package/lib/panelview/components/identify-panel/IdentifyPanel.js +14 -52
- package/lib/panelview/components/layers.d.ts +10 -12
- package/lib/panelview/components/layers.js +109 -79
- package/lib/panelview/index.d.ts +0 -1
- package/lib/panelview/index.js +0 -1
- package/lib/panelview/leftpanel.d.ts +8 -47
- package/lib/panelview/leftpanel.js +32 -154
- package/lib/panelview/objectproperties.d.ts +20 -15
- package/lib/panelview/objectproperties.js +12 -34
- package/lib/panelview/rightpanel.d.ts +8 -22
- package/lib/panelview/rightpanel.js +32 -77
- package/lib/shared/components/Tabs.d.ts +7 -1
- package/lib/shared/components/Tabs.js +6 -1
- package/lib/stacBrowser/components/{StacPanelView.d.ts → StacPanel.d.ts} +2 -2
- package/lib/stacBrowser/components/{StacPanelView.js → StacPanel.js} +3 -3
- package/lib/stacBrowser/index.d.ts +1 -1
- package/lib/stacBrowser/index.js +1 -1
- package/lib/tools.js +26 -0
- package/lib/types.d.ts +1 -9
- package/lib/widget.d.ts +8 -3
- package/lib/widget.js +8 -4
- package/package.json +4 -2
- package/style/base.css +18 -2
- package/style/shared/tabs.css +16 -2
- package/style/stacBrowser.css +0 -6
- package/style/tabPanel.css +91 -0
- package/style/temporalSlider.css +1 -0
- package/lib/panelview/model.d.ts +0 -19
- package/lib/panelview/model.js +0 -30
- package/lib/stacBrowser/StacBrowser.d.ts +0 -7
- package/lib/stacBrowser/StacBrowser.js +0 -16
- package/lib/stacBrowser/StacPanel.d.ts +0 -14
- package/lib/stacBrowser/StacPanel.js +0 -16
|
@@ -1,10 +1,9 @@
|
|
|
1
|
-
import { IAnnotationModel } from '@jupytergis/schema';
|
|
1
|
+
import { IAnnotationModel, IJupyterGISModel } from '@jupytergis/schema';
|
|
2
2
|
import React from 'react';
|
|
3
|
-
import { IControlPanelModel } from "../../types";
|
|
4
3
|
export interface IAnnotationProps {
|
|
5
4
|
itemId: string;
|
|
6
5
|
annotationModel: IAnnotationModel;
|
|
7
|
-
|
|
6
|
+
jgisModel?: IJupyterGISModel;
|
|
8
7
|
children?: JSX.Element[] | JSX.Element;
|
|
9
8
|
}
|
|
10
9
|
declare const Annotation: React.FC<IAnnotationProps>;
|
|
@@ -4,17 +4,10 @@ import { showDialog, Dialog } from '@jupyterlab/apputils';
|
|
|
4
4
|
import { Button } from '@jupyterlab/ui-components';
|
|
5
5
|
import React, { useMemo, useState } from 'react';
|
|
6
6
|
import { Message } from './Message';
|
|
7
|
-
const Annotation = ({ itemId, annotationModel,
|
|
7
|
+
const Annotation = ({ itemId, annotationModel, jgisModel, children, }) => {
|
|
8
8
|
const [messageContent, setMessageContent] = useState('');
|
|
9
|
-
const [jgisModel, setJgisModel] = useState(rightPanelModel === null || rightPanelModel === void 0 ? void 0 : rightPanelModel.jGISModel);
|
|
10
9
|
const annotation = annotationModel.getAnnotation(itemId);
|
|
11
10
|
const contents = useMemo(() => { var _a; return (_a = annotation === null || annotation === void 0 ? void 0 : annotation.contents) !== null && _a !== void 0 ? _a : []; }, [annotation]);
|
|
12
|
-
/**
|
|
13
|
-
* Update the model when it changes.
|
|
14
|
-
*/
|
|
15
|
-
rightPanelModel === null || rightPanelModel === void 0 ? void 0 : rightPanelModel.documentChanged.connect((_, widget) => {
|
|
16
|
-
setJgisModel(widget === null || widget === void 0 ? void 0 : widget.model);
|
|
17
|
-
});
|
|
18
11
|
const handleSubmit = () => {
|
|
19
12
|
annotationModel.addContent(itemId, messageContent);
|
|
20
13
|
setMessageContent('');
|
|
@@ -53,7 +46,7 @@ const Annotation = ({ itemId, annotationModel, rightPanelModel, children, }) =>
|
|
|
53
46
|
React.createElement("div", { className: "jGIS-Annotation-Buttons" },
|
|
54
47
|
React.createElement(Button, { className: "jp-mod-styled jp-mod-warn", onClick: handleDelete },
|
|
55
48
|
React.createElement(FontAwesomeIcon, { icon: faTrash })),
|
|
56
|
-
|
|
49
|
+
jgisModel && (React.createElement(Button, { className: "jp-mod-styled jp-mod-accept", onClick: centerOnAnnotation },
|
|
57
50
|
React.createElement(FontAwesomeIcon, { icon: faArrowsToDot }))),
|
|
58
51
|
React.createElement(Button, { className: "jp-mod-styled jp-mod-accept", onClick: handleSubmit },
|
|
59
52
|
React.createElement(FontAwesomeIcon, { icon: faPaperPlane })))));
|
|
@@ -14,6 +14,7 @@ export declare const newHillshadeEntry = "jupytergis:newHillshadeEntry";
|
|
|
14
14
|
export declare const newImageEntry = "jupytergis:newImageEntry";
|
|
15
15
|
export declare const newVideoEntry = "jupytergis:newVideoEntry";
|
|
16
16
|
export declare const newGeoTiffEntry = "jupytergis:newGeoTiffEntry";
|
|
17
|
+
export declare const newGeoParquetEntry = "jupytergis:newGeoParquetEntry";
|
|
17
18
|
export declare const renameLayer = "jupytergis:renameLayer";
|
|
18
19
|
export declare const removeLayer = "jupytergis:removeLayer";
|
|
19
20
|
export declare const renameGroup = "jupytergis:renameGroup";
|
|
@@ -21,6 +21,7 @@ export const newHillshadeEntry = 'jupytergis:newHillshadeEntry';
|
|
|
21
21
|
export const newImageEntry = 'jupytergis:newImageEntry';
|
|
22
22
|
export const newVideoEntry = 'jupytergis:newVideoEntry';
|
|
23
23
|
export const newGeoTiffEntry = 'jupytergis:newGeoTiffEntry';
|
|
24
|
+
export const newGeoParquetEntry = 'jupytergis:newGeoParquetEntry';
|
|
24
25
|
// Layer and group actions
|
|
25
26
|
export const renameLayer = 'jupytergis:renameLayer';
|
|
26
27
|
export const removeLayer = 'jupytergis:removeLayer';
|
package/lib/commands/index.js
CHANGED
|
@@ -198,6 +198,21 @@ export function addCommands(app, tracker, translator, formSchemaRegistry, layerB
|
|
|
198
198
|
sourceType: 'VectorTileSource',
|
|
199
199
|
layerType: 'VectorTileLayer',
|
|
200
200
|
}) }, icons.get(CommandIDs.newVectorTileEntry)));
|
|
201
|
+
commands.addCommand(CommandIDs.newGeoParquetEntry, Object.assign({ label: trans.__('New GeoParquet Layer'), isEnabled: () => {
|
|
202
|
+
return tracker.currentWidget
|
|
203
|
+
? tracker.currentWidget.model.sharedModel.editable
|
|
204
|
+
: false;
|
|
205
|
+
}, execute: Private.createEntry({
|
|
206
|
+
tracker,
|
|
207
|
+
formSchemaRegistry,
|
|
208
|
+
title: 'Create GeoParquet Layer',
|
|
209
|
+
createLayer: true,
|
|
210
|
+
createSource: true,
|
|
211
|
+
sourceData: { name: 'Custom GeoParquet Source' },
|
|
212
|
+
layerData: { name: 'Custom GeoParquet Layer' },
|
|
213
|
+
sourceType: 'GeoParquetSource',
|
|
214
|
+
layerType: 'VectorLayer',
|
|
215
|
+
}) }, icons.get(CommandIDs.newGeoParquetEntry)));
|
|
201
216
|
commands.addCommand(CommandIDs.newGeoJSONEntry, Object.assign({ label: trans.__('New GeoJSON layer'), isEnabled: () => {
|
|
202
217
|
return tracker.currentWidget
|
|
203
218
|
? tracker.currentWidget.model.sharedModel.editable
|
package/lib/constants.js
CHANGED
|
@@ -30,6 +30,7 @@ const iconObject = {
|
|
|
30
30
|
[CommandIDs.newVideoEntry]: { iconClass: 'fa fa-video' },
|
|
31
31
|
[CommandIDs.newShapefileEntry]: { iconClass: 'fa fa-file' },
|
|
32
32
|
[CommandIDs.newGeoTiffEntry]: { iconClass: 'fa fa-image' },
|
|
33
|
+
[CommandIDs.newGeoParquetEntry]: { iconClass: 'fa fa-file' },
|
|
33
34
|
[CommandIDs.symbology]: { iconClass: 'fa fa-brush' },
|
|
34
35
|
[CommandIDs.identify]: { icon: infoIcon },
|
|
35
36
|
[CommandIDs.temporalController]: { icon: clockIcon },
|
|
@@ -20,7 +20,7 @@ const ColorRamp = ({ layerParams, modeOptions, classifyFunc, showModeRow, showRa
|
|
|
20
20
|
}
|
|
21
21
|
setNumberOfShades(nClasses ? nClasses : '9');
|
|
22
22
|
setSelectedMode(singleBandMode ? singleBandMode : 'equal interval');
|
|
23
|
-
setSelectedRamp(colorRamp ? colorRamp : '
|
|
23
|
+
setSelectedRamp(colorRamp ? colorRamp : 'viridis');
|
|
24
24
|
};
|
|
25
25
|
return (React.createElement("div", { className: "jp-gis-color-ramp-container" },
|
|
26
26
|
showRampSelector && (React.createElement("div", { className: "jp-gis-symbology-row" },
|
|
@@ -1,6 +1,46 @@
|
|
|
1
1
|
// import { GeoJSONFeature } from 'geojson';
|
|
2
2
|
import { useEffect, useState } from 'react';
|
|
3
3
|
import { loadFile } from "../../../tools";
|
|
4
|
+
async function getGeoJsonProperties({ source, model, }) {
|
|
5
|
+
var _a;
|
|
6
|
+
const result = {};
|
|
7
|
+
const data = await loadFile({
|
|
8
|
+
filepath: (_a = source.parameters) === null || _a === void 0 ? void 0 : _a.path,
|
|
9
|
+
type: 'GeoJSONSource',
|
|
10
|
+
model,
|
|
11
|
+
});
|
|
12
|
+
if (!data) {
|
|
13
|
+
throw new Error('Failed to read GeoJSON data');
|
|
14
|
+
}
|
|
15
|
+
data.features.forEach((feature) => {
|
|
16
|
+
if (feature.properties) {
|
|
17
|
+
for (const [key, value] of Object.entries(feature.properties)) {
|
|
18
|
+
if (!result[key]) {
|
|
19
|
+
result[key] = new Set();
|
|
20
|
+
}
|
|
21
|
+
result[key].add(value);
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
});
|
|
25
|
+
return result;
|
|
26
|
+
}
|
|
27
|
+
function getVectorTileProperties({ model, sourceId, }) {
|
|
28
|
+
const result = {};
|
|
29
|
+
const features = model.getFeaturesForCurrentTile({ sourceId });
|
|
30
|
+
features.forEach(feature => {
|
|
31
|
+
var _a;
|
|
32
|
+
const props = (_a = feature.getProperties) === null || _a === void 0 ? void 0 : _a.call(feature);
|
|
33
|
+
if (props) {
|
|
34
|
+
for (const [key, value] of Object.entries(props)) {
|
|
35
|
+
if (!result[key]) {
|
|
36
|
+
result[key] = new Set();
|
|
37
|
+
}
|
|
38
|
+
result[key].add(value);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
});
|
|
42
|
+
return result;
|
|
43
|
+
}
|
|
4
44
|
export const useGetProperties = ({ layerId, model, }) => {
|
|
5
45
|
const [featureProperties, setFeatureProperties] = useState({});
|
|
6
46
|
const [isLoading, setIsLoading] = useState(true);
|
|
@@ -16,30 +56,24 @@ export const useGetProperties = ({ layerId, model, }) => {
|
|
|
16
56
|
if (!source) {
|
|
17
57
|
throw new Error('Source not found');
|
|
18
58
|
}
|
|
19
|
-
const
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
model
|
|
23
|
-
}
|
|
24
|
-
if (
|
|
25
|
-
|
|
59
|
+
const sourceType = source === null || source === void 0 ? void 0 : source.type;
|
|
60
|
+
let result = {};
|
|
61
|
+
if (sourceType === 'GeoJSONSource') {
|
|
62
|
+
result = await getGeoJsonProperties({ source, model });
|
|
63
|
+
}
|
|
64
|
+
else if (sourceType === 'VectorTileSource') {
|
|
65
|
+
const sourceId = (_b = layer === null || layer === void 0 ? void 0 : layer.parameters) === null || _b === void 0 ? void 0 : _b.source;
|
|
66
|
+
result = getVectorTileProperties({ model, sourceId });
|
|
67
|
+
}
|
|
68
|
+
else {
|
|
69
|
+
throw new Error(`Unsupported source type: ${sourceType}`);
|
|
26
70
|
}
|
|
27
|
-
const result = {};
|
|
28
|
-
data.features.forEach((feature) => {
|
|
29
|
-
if (feature.properties) {
|
|
30
|
-
Object.entries(feature.properties).forEach(([key, value]) => {
|
|
31
|
-
if (!(key in result)) {
|
|
32
|
-
result[key] = new Set();
|
|
33
|
-
}
|
|
34
|
-
result[key].add(value);
|
|
35
|
-
});
|
|
36
|
-
}
|
|
37
|
-
});
|
|
38
71
|
setFeatureProperties(result);
|
|
39
|
-
setIsLoading(false);
|
|
40
72
|
}
|
|
41
73
|
catch (err) {
|
|
42
74
|
setError(err);
|
|
75
|
+
}
|
|
76
|
+
finally {
|
|
43
77
|
setIsLoading(false);
|
|
44
78
|
}
|
|
45
79
|
};
|
|
@@ -15,19 +15,19 @@ const RENDER_TYPE_OPTIONS = {
|
|
|
15
15
|
Canonical: {
|
|
16
16
|
component: Canonical,
|
|
17
17
|
attributeChecker: getColorCodeFeatureAttributes,
|
|
18
|
-
supportedLayerTypes: ['VectorLayer', 'HeatmapLayer'],
|
|
18
|
+
supportedLayerTypes: ['VectorLayer', 'VectorTileLayer', 'HeatmapLayer'],
|
|
19
19
|
isTabbed: false,
|
|
20
20
|
},
|
|
21
21
|
Graduated: {
|
|
22
22
|
component: Graduated,
|
|
23
23
|
attributeChecker: getNumericFeatureAttributes,
|
|
24
|
-
supportedLayerTypes: ['VectorLayer', 'HeatmapLayer'],
|
|
24
|
+
supportedLayerTypes: ['VectorLayer', 'VectorTileLayer', 'HeatmapLayer'],
|
|
25
25
|
isTabbed: true,
|
|
26
26
|
},
|
|
27
27
|
Categorized: {
|
|
28
28
|
component: Categorized,
|
|
29
29
|
attributeChecker: getNumericFeatureAttributes,
|
|
30
|
-
supportedLayerTypes: ['VectorLayer', 'HeatmapLayer'],
|
|
30
|
+
supportedLayerTypes: ['VectorLayer', 'VectorTileLayer', 'HeatmapLayer'],
|
|
31
31
|
isTabbed: true,
|
|
32
32
|
},
|
|
33
33
|
Heatmap: {
|
|
@@ -126,13 +126,15 @@ const Graduated = ({ model, state, okSignalPromise, cancel, layerId, symbologyTa
|
|
|
126
126
|
});
|
|
127
127
|
newStyle['fill-color'] = colorExpr;
|
|
128
128
|
newStyle['circle-fill-color'] = colorExpr;
|
|
129
|
+
newStyle['stroke-color'] = colorExpr;
|
|
130
|
+
newStyle['circle-stroke-color'] = colorExpr;
|
|
129
131
|
}
|
|
130
132
|
else {
|
|
131
133
|
newStyle['fill-color'] = undefined;
|
|
132
134
|
newStyle['circle-fill-color'] = undefined;
|
|
135
|
+
newStyle['stroke-color'] = colorManualStyleRef.current.strokeColor;
|
|
136
|
+
newStyle['circle-stroke-color'] = colorManualStyleRef.current.strokeColor;
|
|
133
137
|
}
|
|
134
|
-
newStyle['stroke-color'] = colorManualStyleRef.current.strokeColor;
|
|
135
|
-
newStyle['circle-stroke-color'] = colorManualStyleRef.current.strokeColor;
|
|
136
138
|
newStyle['stroke-width'] = colorManualStyleRef.current.strokeWidth;
|
|
137
139
|
newStyle['circle-stroke-width'] = colorManualStyleRef.current.strokeWidth;
|
|
138
140
|
// Apply radius symbology
|
|
@@ -14,7 +14,7 @@ const Heatmap = ({ model, state, okSignalPromise, cancel, layerId, }) => {
|
|
|
14
14
|
radius: 8,
|
|
15
15
|
blur: 15,
|
|
16
16
|
});
|
|
17
|
-
const selectedRampRef = useRef('
|
|
17
|
+
const selectedRampRef = useRef('viridis');
|
|
18
18
|
const heatmapOptionsRef = useRef({
|
|
19
19
|
radius: 8,
|
|
20
20
|
blur: 15,
|
|
@@ -40,7 +40,7 @@ const Heatmap = ({ model, state, okSignalPromise, cancel, layerId, }) => {
|
|
|
40
40
|
if ((_a = layer.parameters) === null || _a === void 0 ? void 0 : _a.symbologyState) {
|
|
41
41
|
colorRamp = layer.parameters.symbologyState.colorRamp;
|
|
42
42
|
}
|
|
43
|
-
setSelectedRamp(colorRamp ? colorRamp : '
|
|
43
|
+
setSelectedRamp(colorRamp ? colorRamp : 'viridis');
|
|
44
44
|
};
|
|
45
45
|
const handleOk = () => {
|
|
46
46
|
if (!layer.parameters) {
|
|
@@ -38,6 +38,9 @@ export function getSourceTypeForm(sourceType) {
|
|
|
38
38
|
case 'VectorTileSource':
|
|
39
39
|
SourceForm = TileSourcePropertiesForm;
|
|
40
40
|
break;
|
|
41
|
+
case 'GeoParquetSource':
|
|
42
|
+
SourceForm = PathBasedSourcePropertiesForm;
|
|
43
|
+
break;
|
|
41
44
|
// ADD MORE FORM TYPES HERE
|
|
42
45
|
}
|
|
43
46
|
return SourceForm;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { IDict } from '@jupytergis/schema';
|
|
2
|
+
import { ISubmitEvent } from '@rjsf/core';
|
|
2
3
|
import { PathBasedSourcePropertiesForm } from './pathbasedsource';
|
|
3
4
|
import { ISourceFormProps } from './sourceform';
|
|
4
5
|
/**
|
|
@@ -13,5 +14,6 @@ export declare class GeoJSONSourcePropertiesForm extends PathBasedSourceProperti
|
|
|
13
14
|
*
|
|
14
15
|
* @param path - the path to validate.
|
|
15
16
|
*/
|
|
16
|
-
protected _validatePath(path: string): Promise<void>;
|
|
17
|
+
protected _validatePath(path: string | undefined): Promise<void>;
|
|
18
|
+
protected onFormSubmit(e: ISubmitEvent<any>): void;
|
|
17
19
|
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import * as geojson from '@jupytergis/schema/src/schema/geojson.json';
|
|
2
|
+
import { showErrorMessage } from '@jupyterlab/apputils';
|
|
2
3
|
import { Ajv } from 'ajv';
|
|
3
4
|
import { loadFile } from "../../../tools";
|
|
4
5
|
import { PathBasedSourcePropertiesForm } from './pathbasedsource';
|
|
@@ -17,6 +18,10 @@ export class GeoJSONSourcePropertiesForm extends PathBasedSourcePropertiesForm {
|
|
|
17
18
|
if ((data === null || data === void 0 ? void 0 : data.path) !== '') {
|
|
18
19
|
this.removeFormEntry('data', data, schema, uiSchema);
|
|
19
20
|
}
|
|
21
|
+
if (this.props.formContext === 'create') {
|
|
22
|
+
schema.properties.path.description =
|
|
23
|
+
'The local path to a GeoJSON file. (If no path/url is provided, an empty GeoJSON is created.)';
|
|
24
|
+
}
|
|
20
25
|
super.processSchema(data, schema, uiSchema);
|
|
21
26
|
}
|
|
22
27
|
/**
|
|
@@ -28,7 +33,7 @@ export class GeoJSONSourcePropertiesForm extends PathBasedSourcePropertiesForm {
|
|
|
28
33
|
var _a;
|
|
29
34
|
const extraErrors = this.state.extraErrors;
|
|
30
35
|
let error = '';
|
|
31
|
-
let valid =
|
|
36
|
+
let valid = true;
|
|
32
37
|
if (path) {
|
|
33
38
|
try {
|
|
34
39
|
const geoJSONData = await loadFile({
|
|
@@ -45,9 +50,6 @@ export class GeoJSONSourcePropertiesForm extends PathBasedSourcePropertiesForm {
|
|
|
45
50
|
error = `"${path}" is not a valid GeoJSON file: ${e}`;
|
|
46
51
|
}
|
|
47
52
|
}
|
|
48
|
-
else {
|
|
49
|
-
error = 'Path is required';
|
|
50
|
-
}
|
|
51
53
|
if (!valid) {
|
|
52
54
|
extraErrors.path = {
|
|
53
55
|
__errors: [error],
|
|
@@ -64,4 +66,18 @@ export class GeoJSONSourcePropertiesForm extends PathBasedSourcePropertiesForm {
|
|
|
64
66
|
this.props.formErrorSignal.emit(!valid);
|
|
65
67
|
}
|
|
66
68
|
}
|
|
69
|
+
onFormSubmit(e) {
|
|
70
|
+
var _a, _b, _c;
|
|
71
|
+
if (((_c = (_b = (_a = this.state.extraErrors) === null || _a === void 0 ? void 0 : _a.path) === null || _b === void 0 ? void 0 : _b.__errors) === null || _c === void 0 ? void 0 : _c.length) >= 1) {
|
|
72
|
+
showErrorMessage('Invalid file', this.state.extraErrors.path.__errors[0]);
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
75
|
+
if (!e.formData.path) {
|
|
76
|
+
e.formData.data = {
|
|
77
|
+
type: 'FeatureCollection',
|
|
78
|
+
features: [],
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
super.onFormSubmit(e);
|
|
82
|
+
}
|
|
67
83
|
}
|
package/lib/index.d.ts
CHANGED
|
@@ -8,8 +8,8 @@ export * from './icons';
|
|
|
8
8
|
export * from './mainview';
|
|
9
9
|
export * from './menus';
|
|
10
10
|
export * from './panelview';
|
|
11
|
-
export * from './stacBrowser';
|
|
12
11
|
export * from './store';
|
|
12
|
+
export * from './stacBrowser';
|
|
13
13
|
export * from './toolbar';
|
|
14
14
|
export * from './tools';
|
|
15
15
|
export * from './types';
|
package/lib/index.js
CHANGED
|
@@ -8,8 +8,8 @@ export * from './icons';
|
|
|
8
8
|
export * from './mainview';
|
|
9
9
|
export * from './menus';
|
|
10
10
|
export * from './panelview';
|
|
11
|
-
export * from './stacBrowser';
|
|
12
11
|
export * from './store';
|
|
12
|
+
export * from './stacBrowser';
|
|
13
13
|
export * from './toolbar';
|
|
14
14
|
export * from './tools';
|
|
15
15
|
export * from './types';
|
package/lib/keybindings.json
CHANGED
|
@@ -37,7 +37,7 @@
|
|
|
37
37
|
{
|
|
38
38
|
"command": "jupytergis:renameLayer",
|
|
39
39
|
"keys": ["F2"],
|
|
40
|
-
"selector": ".
|
|
40
|
+
"selector": ".jp-gis-layerItem"
|
|
41
41
|
},
|
|
42
42
|
{
|
|
43
43
|
"command": "jupytergis:removeGroup",
|
|
@@ -47,7 +47,7 @@
|
|
|
47
47
|
{
|
|
48
48
|
"command": "jupytergis:renameGroup",
|
|
49
49
|
"keys": ["F2"],
|
|
50
|
-
"selector": ".
|
|
50
|
+
"selector": ".jp-gis-layerGroupHeader"
|
|
51
51
|
},
|
|
52
52
|
{
|
|
53
53
|
"command": "jupytergis:executeConsole",
|
|
@@ -1,11 +1,15 @@
|
|
|
1
|
-
import { IAnnotation, IDict, IJGISFilterItem, IJGISLayer, IJGISSource } from '@jupytergis/schema';
|
|
1
|
+
import { IAnnotation, IAnnotationModel, IDict, IJGISFilterItem, IJGISFormSchemaRegistry, IJGISLayer, IJGISSource } from '@jupytergis/schema';
|
|
2
2
|
import { User } from '@jupyterlab/services';
|
|
3
|
+
import { IStateDB } from '@jupyterlab/statedb';
|
|
3
4
|
import { Layer } from 'ol/layer';
|
|
4
5
|
import * as React from 'react';
|
|
5
6
|
import { ClientPointer } from './CollaboratorPointers';
|
|
6
7
|
import { MainViewModel } from './mainviewmodel';
|
|
7
8
|
interface IProps {
|
|
8
9
|
viewModel: MainViewModel;
|
|
10
|
+
state?: IStateDB;
|
|
11
|
+
formSchemaRegistry?: IJGISFormSchemaRegistry;
|
|
12
|
+
annotationModel?: IAnnotationModel;
|
|
9
13
|
}
|
|
10
14
|
interface IStates {
|
|
11
15
|
id: string;
|
|
@@ -194,5 +198,8 @@ export declare class MainView extends React.Component<IProps, IStates> {
|
|
|
194
198
|
private _originalFeatures;
|
|
195
199
|
private _highlightLayer;
|
|
196
200
|
private _updateCenter;
|
|
201
|
+
private _state?;
|
|
202
|
+
private _formSchemaRegistry?;
|
|
203
|
+
private _annotationModel?;
|
|
197
204
|
}
|
|
198
205
|
export {};
|
package/lib/mainview/mainView.js
CHANGED
|
@@ -3,7 +3,7 @@ import { showErrorMessage } from '@jupyterlab/apputils';
|
|
|
3
3
|
import { CommandRegistry } from '@lumino/commands';
|
|
4
4
|
import { UUID } from '@lumino/coreutils';
|
|
5
5
|
import { ContextMenu } from '@lumino/widgets';
|
|
6
|
-
import { Collection, Map as OlMap, View, getUid } from 'ol';
|
|
6
|
+
import { Collection, Map as OlMap, View, getUid, } from 'ol';
|
|
7
7
|
import Feature from 'ol/Feature';
|
|
8
8
|
import { FullScreen, ScaleLine } from 'ol/control';
|
|
9
9
|
import { singleClick } from 'ol/events/condition';
|
|
@@ -15,9 +15,8 @@ import TileLayer from 'ol/layer/Tile';
|
|
|
15
15
|
import { fromLonLat, get as getProjection, toLonLat, transformExtent, } from 'ol/proj';
|
|
16
16
|
import { register } from 'ol/proj/proj4.js';
|
|
17
17
|
import RenderFeature from 'ol/render/Feature';
|
|
18
|
-
import { GeoTIFF as GeoTIFFSource, ImageTile as ImageTileSource, Vector as VectorSource, VectorTile as VectorTileSource, XYZ as XYZSource, } from 'ol/source';
|
|
18
|
+
import { GeoTIFF as GeoTIFFSource, ImageTile as ImageTileSource, Vector as VectorSource, VectorTile as VectorTileSource, XYZ as XYZSource, Tile as TileSource, } from 'ol/source';
|
|
19
19
|
import Static from 'ol/source/ImageStatic';
|
|
20
|
-
import TileSource from 'ol/source/Tile';
|
|
21
20
|
import { Circle, Fill, Stroke, Style } from 'ol/style';
|
|
22
21
|
//@ts-expect-error no types for ol-pmtiles
|
|
23
22
|
import { PMTilesRasterSource, PMTilesVectorSource } from 'ol-pmtiles';
|
|
@@ -33,6 +32,7 @@ import { debounce, isLightTheme, loadFile, throttle } from "../tools";
|
|
|
33
32
|
import CollaboratorPointers from './CollaboratorPointers';
|
|
34
33
|
import { FollowIndicator } from './FollowIndicator';
|
|
35
34
|
import TemporalSlider from './TemporalSlider';
|
|
35
|
+
import { LeftPanel, RightPanel } from '../panelview';
|
|
36
36
|
export class MainView extends React.Component {
|
|
37
37
|
constructor(props) {
|
|
38
38
|
super(props);
|
|
@@ -441,6 +441,9 @@ export class MainView extends React.Component {
|
|
|
441
441
|
this._ready = false;
|
|
442
442
|
this._sourceToLayerMap = new Map();
|
|
443
443
|
this._originalFeatures = {};
|
|
444
|
+
this._state = props.state;
|
|
445
|
+
this._formSchemaRegistry = props.formSchemaRegistry;
|
|
446
|
+
this._annotationModel = props.annotationModel;
|
|
444
447
|
// Enforce the map to take the full available width in the case of Jupyter Notebook viewer
|
|
445
448
|
const el = document.getElementById('main-panel');
|
|
446
449
|
if (el) {
|
|
@@ -713,6 +716,13 @@ export class MainView extends React.Component {
|
|
|
713
716
|
url: url,
|
|
714
717
|
});
|
|
715
718
|
}
|
|
719
|
+
newSource.on('tileloadend', (event) => {
|
|
720
|
+
const tile = event.tile;
|
|
721
|
+
const features = tile.getFeatures();
|
|
722
|
+
if (features && features.length > 0) {
|
|
723
|
+
this._model.syncTileFeatures({ sourceId: id, features });
|
|
724
|
+
}
|
|
725
|
+
});
|
|
716
726
|
break;
|
|
717
727
|
}
|
|
718
728
|
case 'GeoJSONSource': {
|
|
@@ -819,6 +829,23 @@ export class MainView extends React.Component {
|
|
|
819
829
|
});
|
|
820
830
|
break;
|
|
821
831
|
}
|
|
832
|
+
case 'GeoParquetSource': {
|
|
833
|
+
const parameters = source.parameters;
|
|
834
|
+
const geojson = await loadFile({
|
|
835
|
+
filepath: parameters.path,
|
|
836
|
+
type: 'GeoParquetSource',
|
|
837
|
+
model: this._model,
|
|
838
|
+
});
|
|
839
|
+
const geojsonData = Array.isArray(geojson) ? geojson[0] : geojson;
|
|
840
|
+
const format = new GeoJSON();
|
|
841
|
+
newSource = new VectorSource({
|
|
842
|
+
features: format.readFeatures(geojsonData, {
|
|
843
|
+
dataProjection: parameters.projection,
|
|
844
|
+
featureProjection: this._Map.getView().getProjection(),
|
|
845
|
+
}),
|
|
846
|
+
});
|
|
847
|
+
break;
|
|
848
|
+
}
|
|
822
849
|
}
|
|
823
850
|
newSource.set('id', id);
|
|
824
851
|
// _sources is a list of OpenLayers sources
|
|
@@ -1642,6 +1669,8 @@ export class MainView extends React.Component {
|
|
|
1642
1669
|
width: '100%',
|
|
1643
1670
|
height: '100%',
|
|
1644
1671
|
} })),
|
|
1645
|
-
React.createElement(StatusBar, { jgisModel: this._model, loading: this.state.loadingLayer, projection: this.state.viewProjection, scale: this.state.scale }))
|
|
1672
|
+
React.createElement(StatusBar, { jgisModel: this._model, loading: this.state.loadingLayer, projection: this.state.viewProjection, scale: this.state.scale })),
|
|
1673
|
+
this._state && (React.createElement(LeftPanel, { model: this._model, commands: this._mainViewModel.commands, state: this._state })),
|
|
1674
|
+
this._formSchemaRegistry && this._annotationModel && (React.createElement(RightPanel, { model: this._model, formSchemaRegistry: this._formSchemaRegistry, annotationModel: this._annotationModel }))));
|
|
1646
1675
|
}
|
|
1647
1676
|
}
|
|
@@ -1,12 +1,19 @@
|
|
|
1
|
+
import { IAnnotationModel, IJGISFormSchemaRegistry } from '@jupytergis/schema';
|
|
1
2
|
import { ReactWidget } from '@jupyterlab/apputils';
|
|
3
|
+
import { IStateDB } from '@jupyterlab/statedb';
|
|
2
4
|
import { MainViewModel } from './mainviewmodel';
|
|
5
|
+
export interface IOptions {
|
|
6
|
+
mainViewModel: MainViewModel;
|
|
7
|
+
state?: IStateDB;
|
|
8
|
+
formSchemaRegistry?: IJGISFormSchemaRegistry;
|
|
9
|
+
annotationModel?: IAnnotationModel;
|
|
10
|
+
}
|
|
3
11
|
export declare class JupyterGISMainViewPanel extends ReactWidget {
|
|
4
12
|
/**
|
|
5
13
|
* Construct a `JupyterGISPanel`.
|
|
6
14
|
*/
|
|
7
|
-
constructor(options:
|
|
8
|
-
mainViewModel: MainViewModel;
|
|
9
|
-
});
|
|
15
|
+
constructor(options: IOptions);
|
|
10
16
|
render(): JSX.Element;
|
|
11
|
-
private
|
|
17
|
+
private _state?;
|
|
18
|
+
private _options;
|
|
12
19
|
}
|
|
@@ -7,10 +7,11 @@ export class JupyterGISMainViewPanel extends ReactWidget {
|
|
|
7
7
|
*/
|
|
8
8
|
constructor(options) {
|
|
9
9
|
super();
|
|
10
|
-
this.
|
|
10
|
+
this._state = options.state;
|
|
11
11
|
this.addClass('jp-jupytergis-panel');
|
|
12
|
+
this._options = options;
|
|
12
13
|
}
|
|
13
14
|
render() {
|
|
14
|
-
return React.createElement(MainView, { viewModel: this.
|
|
15
|
+
return (React.createElement(MainView, { state: this._state, viewModel: this._options.mainViewModel, formSchemaRegistry: this._options.formSchemaRegistry, annotationModel: this._options.annotationModel }));
|
|
15
16
|
}
|
|
16
17
|
}
|
package/lib/menus.js
CHANGED
|
@@ -18,6 +18,10 @@ export const vectorSubMenu = (commands) => {
|
|
|
18
18
|
type: 'command',
|
|
19
19
|
command: CommandIDs.newShapefileEntry,
|
|
20
20
|
});
|
|
21
|
+
subMenu.addItem({
|
|
22
|
+
type: 'command',
|
|
23
|
+
command: CommandIDs.newGeoParquetEntry,
|
|
24
|
+
});
|
|
21
25
|
return subMenu;
|
|
22
26
|
};
|
|
23
27
|
export const rasterSubMenu = (commands) => {
|
|
@@ -1,27 +1,13 @@
|
|
|
1
|
-
import { IAnnotationModel } from '@jupytergis/schema';
|
|
2
|
-
import { PanelWithToolbar } from '@jupyterlab/ui-components';
|
|
1
|
+
import { IAnnotationModel, IJupyterGISModel } from '@jupytergis/schema';
|
|
3
2
|
import { Component } from 'react';
|
|
4
|
-
import { IControlPanelModel } from "../types";
|
|
5
3
|
interface IAnnotationPanelProps {
|
|
6
4
|
annotationModel: IAnnotationModel;
|
|
7
|
-
|
|
5
|
+
jgisModel: IJupyterGISModel;
|
|
8
6
|
}
|
|
9
7
|
export declare class AnnotationsPanel extends Component<IAnnotationPanelProps> {
|
|
10
8
|
constructor(props: IAnnotationPanelProps);
|
|
11
9
|
render(): JSX.Element;
|
|
12
10
|
private _annotationModel;
|
|
13
|
-
private
|
|
14
|
-
}
|
|
15
|
-
export declare class Annotations extends PanelWithToolbar {
|
|
16
|
-
constructor(options: Annotations.IOptions);
|
|
17
|
-
private _widget;
|
|
18
|
-
private _annotationModel;
|
|
19
|
-
private _rightPanelModel;
|
|
20
|
-
}
|
|
21
|
-
export declare namespace Annotations {
|
|
22
|
-
interface IOptions {
|
|
23
|
-
annotationModel: IAnnotationModel;
|
|
24
|
-
rightPanelModel: IControlPanelModel;
|
|
25
|
-
}
|
|
11
|
+
private _jgisModel;
|
|
26
12
|
}
|
|
27
13
|
export {};
|
|
@@ -1,22 +1,16 @@
|
|
|
1
|
-
import { PanelWithToolbar, ReactWidget } from '@jupyterlab/ui-components';
|
|
2
1
|
import React, { Component } from 'react';
|
|
3
2
|
import Annotation from "../annotations/components/Annotation";
|
|
4
3
|
export class AnnotationsPanel extends Component {
|
|
5
4
|
constructor(props) {
|
|
5
|
+
var _a, _b;
|
|
6
6
|
super(props);
|
|
7
7
|
const updateCallback = () => {
|
|
8
8
|
this.forceUpdate();
|
|
9
9
|
};
|
|
10
10
|
this._annotationModel = props.annotationModel;
|
|
11
|
-
this.
|
|
12
|
-
this._annotationModel.
|
|
13
|
-
|
|
14
|
-
var _a, _b, _c, _d;
|
|
15
|
-
(_b = (_a = this._annotationModel) === null || _a === void 0 ? void 0 : _a.model) === null || _b === void 0 ? void 0 : _b.sharedMetadataChanged.disconnect(updateCallback);
|
|
16
|
-
this._annotationModel = props.annotationModel;
|
|
17
|
-
(_d = (_c = this._annotationModel) === null || _c === void 0 ? void 0 : _c.model) === null || _d === void 0 ? void 0 : _d.sharedMetadataChanged.connect(updateCallback);
|
|
18
|
-
this.forceUpdate();
|
|
19
|
-
});
|
|
11
|
+
this._jgisModel = props.jgisModel;
|
|
12
|
+
(_b = (_a = this._annotationModel) === null || _a === void 0 ? void 0 : _a.model) === null || _b === void 0 ? void 0 : _b.sharedMetadataChanged.connect(updateCallback);
|
|
13
|
+
this.forceUpdate();
|
|
20
14
|
}
|
|
21
15
|
render() {
|
|
22
16
|
var _a;
|
|
@@ -26,20 +20,9 @@ export class AnnotationsPanel extends Component {
|
|
|
26
20
|
}
|
|
27
21
|
const annotations = annotationIds.map((id) => {
|
|
28
22
|
return (React.createElement("div", null,
|
|
29
|
-
React.createElement(Annotation, {
|
|
23
|
+
React.createElement(Annotation, { jgisModel: this._jgisModel, annotationModel: this._annotationModel, itemId: id }),
|
|
30
24
|
React.createElement("hr", { className: "jGIS-Annotations-Separator" })));
|
|
31
25
|
});
|
|
32
26
|
return React.createElement("div", { className: "jgis-scrollable" }, annotations);
|
|
33
27
|
}
|
|
34
28
|
}
|
|
35
|
-
export class Annotations extends PanelWithToolbar {
|
|
36
|
-
constructor(options) {
|
|
37
|
-
super({});
|
|
38
|
-
this.title.label = 'Annotations';
|
|
39
|
-
this.addClass('jgis-scrollable');
|
|
40
|
-
this._annotationModel = options.annotationModel;
|
|
41
|
-
this._rightPanelModel = options.rightPanelModel;
|
|
42
|
-
this._widget = ReactWidget.create(React.createElement(AnnotationsPanel, { rightPanelModel: this._rightPanelModel, annotationModel: this._annotationModel }));
|
|
43
|
-
this.addWidget(this._widget);
|
|
44
|
-
}
|
|
45
|
-
}
|
|
@@ -1,24 +1,7 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { Panel } from '@lumino/widgets';
|
|
1
|
+
import { IJupyterGISModel } from '@jupytergis/schema';
|
|
3
2
|
import React from 'react';
|
|
4
|
-
import { IControlPanelModel } from "../../../types";
|
|
5
|
-
/**
|
|
6
|
-
* The filters panel widget.
|
|
7
|
-
*/
|
|
8
|
-
export declare class FilterPanel extends Panel {
|
|
9
|
-
constructor(options: FilterPanel.IOptions);
|
|
10
|
-
private _model;
|
|
11
|
-
private _tracker;
|
|
12
|
-
}
|
|
13
|
-
export declare namespace FilterPanel {
|
|
14
|
-
interface IOptions {
|
|
15
|
-
model: IControlPanelModel;
|
|
16
|
-
tracker: IJupyterGISTracker;
|
|
17
|
-
}
|
|
18
|
-
}
|
|
19
3
|
interface IFilterComponentProps {
|
|
20
|
-
model:
|
|
21
|
-
tracker: IJupyterGISTracker;
|
|
4
|
+
model: IJupyterGISModel;
|
|
22
5
|
}
|
|
23
6
|
declare const FilterComponent: React.FC<IFilterComponentProps>;
|
|
24
7
|
export default FilterComponent;
|