@jupytergis/base 0.7.0 → 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/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/formbuilder/objectform/source/geojsonsource.d.ts +3 -1
- package/lib/formbuilder/objectform/source/geojsonsource.js +20 -4
- package/lib/mainview/mainView.js +9 -3
- package/package.json +2 -2
|
@@ -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
|
|
@@ -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/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';
|
|
@@ -717,6 +716,13 @@ export class MainView extends React.Component {
|
|
|
717
716
|
url: url,
|
|
718
717
|
});
|
|
719
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
|
+
});
|
|
720
726
|
break;
|
|
721
727
|
}
|
|
722
728
|
case 'GeoJSONSource': {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jupytergis/base",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.8.0",
|
|
4
4
|
"description": "A JupyterLab extension for 3D modelling.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"jupyter",
|
|
@@ -44,7 +44,7 @@
|
|
|
44
44
|
"@jupyter/collaboration": "^3.1.0",
|
|
45
45
|
"@jupyter/react-components": "^0.16.6",
|
|
46
46
|
"@jupyter/ydoc": "^2.0.0 || ^3.0.0",
|
|
47
|
-
"@jupytergis/schema": "^0.
|
|
47
|
+
"@jupytergis/schema": "^0.8.0",
|
|
48
48
|
"@jupyterlab/application": "^4.3.0",
|
|
49
49
|
"@jupyterlab/apputils": "^4.3.0",
|
|
50
50
|
"@jupyterlab/completer": "^4.3.0",
|