@jupytergis/base 0.1.4 → 0.1.6
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/commands.js +0 -37
- package/lib/constants.d.ts +0 -2
- package/lib/constants.js +0 -4
- package/lib/dialogs/components/symbology/SingleBandPseudoColor.js +6 -4
- package/lib/mainview/mainView.js +13 -10
- package/lib/toolbar/widget.d.ts +2 -2
- package/lib/toolbar/widget.js +4 -4
- package/package.json +2 -2
- package/style/base.css +0 -1
- package/style/symbologyDialog.css +28 -0
- package/lib/dialogs/terrainDialog.d.ts +0 -21
- package/lib/dialogs/terrainDialog.js +0 -60
- package/style/terrainDialog.css +0 -14
package/lib/commands.js
CHANGED
|
@@ -3,7 +3,6 @@ import { CommandIDs, icons } from './constants';
|
|
|
3
3
|
import { CreationFormDialog } from './dialogs/formdialog';
|
|
4
4
|
import { LayerBrowserWidget } from './dialogs/layerBrowserDialog';
|
|
5
5
|
import { SymbologyWidget } from './dialogs/symbologyDialog';
|
|
6
|
-
import { TerrainDialogWidget } from './dialogs/terrainDialog';
|
|
7
6
|
/**
|
|
8
7
|
* Add the commands to the application's command registry.
|
|
9
8
|
*/
|
|
@@ -538,29 +537,6 @@ export function addCommands(app, tracker, translator, formSchemaRegistry, layerB
|
|
|
538
537
|
});
|
|
539
538
|
}
|
|
540
539
|
});
|
|
541
|
-
/**
|
|
542
|
-
* Terrain commands
|
|
543
|
-
*/
|
|
544
|
-
commands.addCommand(CommandIDs.newTerrain, Object.assign({ label: trans.__('New Terrain'), isEnabled: () => {
|
|
545
|
-
return tracker.currentWidget
|
|
546
|
-
? tracker.currentWidget.context.model.sharedModel.editable
|
|
547
|
-
: false;
|
|
548
|
-
}, execute: Private.createTerrainDialog(tracker) }, icons.get(CommandIDs.newTerrain)));
|
|
549
|
-
commands.addCommand(CommandIDs.removeTerrain, {
|
|
550
|
-
label: trans.__('Remove Terrain'),
|
|
551
|
-
isEnabled: () => {
|
|
552
|
-
return tracker.currentWidget
|
|
553
|
-
? tracker.currentWidget.context.model.sharedModel.editable
|
|
554
|
-
: false;
|
|
555
|
-
},
|
|
556
|
-
execute: () => {
|
|
557
|
-
var _a;
|
|
558
|
-
(_a = tracker.currentWidget) === null || _a === void 0 ? void 0 : _a.context.model.setTerrain({
|
|
559
|
-
source: '',
|
|
560
|
-
exaggeration: 0
|
|
561
|
-
});
|
|
562
|
-
}
|
|
563
|
-
});
|
|
564
540
|
// Console commands
|
|
565
541
|
commands.addCommand(CommandIDs.toggleConsole, {
|
|
566
542
|
label: trans.__('Toggle console'),
|
|
@@ -635,19 +611,6 @@ var Private;
|
|
|
635
611
|
};
|
|
636
612
|
}
|
|
637
613
|
Private.createLayerBrowser = createLayerBrowser;
|
|
638
|
-
function createTerrainDialog(tracker) {
|
|
639
|
-
return async () => {
|
|
640
|
-
const current = tracker.currentWidget;
|
|
641
|
-
if (!current) {
|
|
642
|
-
return;
|
|
643
|
-
}
|
|
644
|
-
const dialog = new TerrainDialogWidget({
|
|
645
|
-
context: current.context
|
|
646
|
-
});
|
|
647
|
-
await dialog.launch();
|
|
648
|
-
};
|
|
649
|
-
}
|
|
650
|
-
Private.createTerrainDialog = createTerrainDialog;
|
|
651
614
|
function createSymbologyDialog(tracker, state) {
|
|
652
615
|
return async () => {
|
|
653
616
|
const current = tracker.currentWidget;
|
package/lib/constants.d.ts
CHANGED
|
@@ -38,8 +38,6 @@ export declare namespace CommandIDs {
|
|
|
38
38
|
const moveLayerToNewGroup = "jupytergis:moveLayerToNewGroup";
|
|
39
39
|
const renameSource = "jupytergis:renameSource";
|
|
40
40
|
const removeSource = "jupytergis:removeSource";
|
|
41
|
-
const newTerrain = "jupytergis:newTerrain";
|
|
42
|
-
const removeTerrain = "jupytergis:removeTerrain";
|
|
43
41
|
const toggleConsole = "jupytergis:toggleConsole";
|
|
44
42
|
const invokeCompleter = "jupytergis:invokeConsoleCompleter";
|
|
45
43
|
const removeConsole = "jupytergis:removeConsole";
|
package/lib/constants.js
CHANGED
|
@@ -46,9 +46,6 @@ export var CommandIDs;
|
|
|
46
46
|
// Source actions
|
|
47
47
|
CommandIDs.renameSource = 'jupytergis:renameSource';
|
|
48
48
|
CommandIDs.removeSource = 'jupytergis:removeSource';
|
|
49
|
-
// Terrain stuff
|
|
50
|
-
CommandIDs.newTerrain = 'jupytergis:newTerrain';
|
|
51
|
-
CommandIDs.removeTerrain = 'jupytergis:removeTerrain';
|
|
52
49
|
// Console commands
|
|
53
50
|
CommandIDs.toggleConsole = 'jupytergis:toggleConsole';
|
|
54
51
|
CommandIDs.invokeCompleter = 'jupytergis:invokeConsoleCompleter';
|
|
@@ -80,7 +77,6 @@ const iconObject = {
|
|
|
80
77
|
[CommandIDs.newVideoEntry]: { iconClass: 'fa fa-video' },
|
|
81
78
|
[CommandIDs.newShapefileLayer]: { iconClass: 'fa fa-file' },
|
|
82
79
|
[CommandIDs.newGeoTiffEntry]: { iconClass: 'fa fa-image' },
|
|
83
|
-
[CommandIDs.newTerrain]: { iconClass: 'fa fa-mountain' },
|
|
84
80
|
[CommandIDs.symbology]: { iconClass: 'fa fa-brush' }
|
|
85
81
|
};
|
|
86
82
|
/**
|
|
@@ -2,9 +2,9 @@ import { faSpinner } from '@fortawesome/free-solid-svg-icons';
|
|
|
2
2
|
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
|
3
3
|
import { Button } from '@jupyterlab/ui-components';
|
|
4
4
|
import React, { useEffect, useRef, useState } from 'react';
|
|
5
|
+
import { getGdal } from '../../../gdal';
|
|
5
6
|
import BandRow from './BandRow';
|
|
6
7
|
import StopRow from './StopRow';
|
|
7
|
-
import { getGdal } from '../../../gdal';
|
|
8
8
|
const SingleBandPseudoColor = ({ context, state, okSignalPromise, cancel, layerId }) => {
|
|
9
9
|
const functions = ['discrete', 'linear', 'exact'];
|
|
10
10
|
const stopRowsRef = useRef();
|
|
@@ -191,7 +191,7 @@ const SingleBandPseudoColor = ({ context, state, okSignalPromise, cancel, layerI
|
|
|
191
191
|
colorExpr.push(stop.output);
|
|
192
192
|
});
|
|
193
193
|
// fallback value
|
|
194
|
-
colorExpr.push([0, 0, 0,
|
|
194
|
+
colorExpr.push([0, 0, 0, 0.0]);
|
|
195
195
|
break;
|
|
196
196
|
}
|
|
197
197
|
case 'exact': {
|
|
@@ -208,7 +208,7 @@ const SingleBandPseudoColor = ({ context, state, okSignalPromise, cancel, layerI
|
|
|
208
208
|
colorExpr.push(stop.output);
|
|
209
209
|
});
|
|
210
210
|
// fallback value
|
|
211
|
-
colorExpr.push([0, 0, 0,
|
|
211
|
+
colorExpr.push([0, 0, 0, 0.0]);
|
|
212
212
|
break;
|
|
213
213
|
}
|
|
214
214
|
}
|
|
@@ -248,7 +248,9 @@ const SingleBandPseudoColor = ({ context, state, okSignalPromise, cancel, layerI
|
|
|
248
248
|
(currentBand.stats.maximum - currentBand.stats.minimum));
|
|
249
249
|
};
|
|
250
250
|
return (React.createElement("div", { className: "jp-gis-layer-symbology-container" },
|
|
251
|
-
React.createElement("div", { className: "jp-gis-band-container" }, bandRows.length === 0 ? (React.createElement(
|
|
251
|
+
React.createElement("div", { className: "jp-gis-band-container" }, bandRows.length === 0 ? (React.createElement("div", { className: "jp-gis-band-info-loading-container" },
|
|
252
|
+
React.createElement("span", null, "Fetching band info..."),
|
|
253
|
+
React.createElement(FontAwesomeIcon, { icon: faSpinner, className: "jp-gis-loading-spinner" }))) : (React.createElement(BandRow
|
|
252
254
|
// Band numbers are 1 indexed
|
|
253
255
|
, {
|
|
254
256
|
// Band numbers are 1 indexed
|
package/lib/mainview/mainView.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { JupyterGISModel } from '@jupytergis/schema';
|
|
2
2
|
import { UUID } from '@lumino/coreutils';
|
|
3
|
-
import { Map as OlMap, View } from 'ol';
|
|
3
|
+
import { Collection, Map as OlMap, View } from 'ol';
|
|
4
4
|
import { ScaleLine } from 'ol/control';
|
|
5
5
|
import { GeoJSON, MVT } from 'ol/format';
|
|
6
6
|
import DragAndDrop from 'ol/interaction/DragAndDrop';
|
|
@@ -37,7 +37,9 @@ export class MainView extends React.Component {
|
|
|
37
37
|
style: defaultStyle
|
|
38
38
|
};
|
|
39
39
|
const layerStyle = Object.assign({}, defaultRules);
|
|
40
|
-
if (layer.filters &&
|
|
40
|
+
if (layer.filters &&
|
|
41
|
+
layer.filters.logicalOp &&
|
|
42
|
+
layer.filters.appliedFilters.length !== 0) {
|
|
41
43
|
const filterExpr = [];
|
|
42
44
|
// 'Any' and 'All' operators require more than one argument
|
|
43
45
|
// So if there's only one filter, skip that part to avoid error
|
|
@@ -303,13 +305,17 @@ export class MainView extends React.Component {
|
|
|
303
305
|
case 'GeoJSONSource': {
|
|
304
306
|
const data = ((_a = source.parameters) === null || _a === void 0 ? void 0 : _a.data) ||
|
|
305
307
|
(await this._model.readGeoJSON((_b = source.parameters) === null || _b === void 0 ? void 0 : _b.path));
|
|
306
|
-
const format = new GeoJSON(
|
|
308
|
+
const format = new GeoJSON({
|
|
309
|
+
featureProjection: this._Map.getView().getProjection()
|
|
310
|
+
});
|
|
307
311
|
// TODO: Don't hardcode projection
|
|
312
|
+
const featureArray = format.readFeatures(data, {
|
|
313
|
+
dataProjection: 'EPSG:4326',
|
|
314
|
+
featureProjection: this._Map.getView().getProjection()
|
|
315
|
+
});
|
|
316
|
+
const featureCollection = new Collection(featureArray);
|
|
308
317
|
newSource = new VectorSource({
|
|
309
|
-
features:
|
|
310
|
-
dataProjection: 'EPSG:4326',
|
|
311
|
-
featureProjection: this._Map.getView().getProjection()
|
|
312
|
-
})
|
|
318
|
+
features: featureCollection
|
|
313
319
|
});
|
|
314
320
|
break;
|
|
315
321
|
}
|
|
@@ -481,9 +487,6 @@ export class MainView extends React.Component {
|
|
|
481
487
|
}
|
|
482
488
|
case 'VectorTileLayer': {
|
|
483
489
|
layerParameters = layer.parameters;
|
|
484
|
-
if (!layerParameters.color) {
|
|
485
|
-
return;
|
|
486
|
-
}
|
|
487
490
|
newMapLayer = new VectorTileLayer({
|
|
488
491
|
opacity: layerParameters.opacity,
|
|
489
492
|
source: this._sources[layerParameters.source]
|
package/lib/toolbar/widget.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { IJGISExternalCommand, JupyterGISModel } from '@jupytergis/schema';
|
|
2
|
-
import { Toolbar } from '@jupyterlab/ui-components';
|
|
2
|
+
import { Toolbar, ReactiveToolbar } from '@jupyterlab/ui-components';
|
|
3
3
|
import { CommandRegistry } from '@lumino/commands';
|
|
4
4
|
import { Widget } from '@lumino/widgets';
|
|
5
5
|
export declare const TOOLBAR_SEPARATOR_CLASS = "jGIS-Toolbar-Separator";
|
|
@@ -10,7 +10,7 @@ export declare class Separator extends Widget {
|
|
|
10
10
|
*/
|
|
11
11
|
constructor();
|
|
12
12
|
}
|
|
13
|
-
export declare class ToolbarWidget extends
|
|
13
|
+
export declare class ToolbarWidget extends ReactiveToolbar {
|
|
14
14
|
constructor(options: ToolbarWidget.IOptions);
|
|
15
15
|
}
|
|
16
16
|
export declare namespace ToolbarWidget {
|
package/lib/toolbar/widget.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { CommandToolbarButton } from '@jupyterlab/apputils';
|
|
2
|
-
import { ReactWidget,
|
|
2
|
+
import { ReactWidget, ReactiveToolbar, ToolbarButton, addIcon, redoIcon, undoIcon, terminalIcon } from '@jupyterlab/ui-components';
|
|
3
3
|
import { Menu, Widget } from '@lumino/widgets';
|
|
4
4
|
import * as React from 'react';
|
|
5
5
|
import { CommandIDs } from '../constants';
|
|
@@ -15,9 +15,9 @@ export class Separator extends Widget {
|
|
|
15
15
|
this.addClass(TOOLBAR_SEPARATOR_CLASS);
|
|
16
16
|
}
|
|
17
17
|
}
|
|
18
|
-
export class ToolbarWidget extends
|
|
18
|
+
export class ToolbarWidget extends ReactiveToolbar {
|
|
19
19
|
constructor(options) {
|
|
20
|
-
super(
|
|
20
|
+
super();
|
|
21
21
|
this.addClass('jGIS-toolbar-widget');
|
|
22
22
|
if (options.commands) {
|
|
23
23
|
this.addItem('undo', new CommandToolbarButton({
|
|
@@ -96,7 +96,7 @@ export class ToolbarWidget extends Toolbar {
|
|
|
96
96
|
}
|
|
97
97
|
});
|
|
98
98
|
this.addItem('New', NewButton);
|
|
99
|
-
this.addItem('spacer',
|
|
99
|
+
this.addItem('spacer', ReactiveToolbar.createSpacerItem());
|
|
100
100
|
// Users
|
|
101
101
|
this.addItem('users', ReactWidget.create(React.createElement(UsersItem, { model: options.model })));
|
|
102
102
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jupytergis/base",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.6",
|
|
4
4
|
"description": "A JupyterLab extension for 3D modelling.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"jupyter",
|
|
@@ -41,7 +41,7 @@
|
|
|
41
41
|
"@deathbeds/jupyterlab-rjsf": "^1.1.0",
|
|
42
42
|
"@jupyter/docprovider": "^2.0.0",
|
|
43
43
|
"@jupyter/ydoc": "^1.0.0",
|
|
44
|
-
"@jupytergis/schema": "^0.1.
|
|
44
|
+
"@jupytergis/schema": "^0.1.6",
|
|
45
45
|
"@jupyterlab/application": "^4.0.0",
|
|
46
46
|
"@jupyterlab/apputils": "^4.0.0",
|
|
47
47
|
"@jupyterlab/completer": "^4.2.4",
|
package/style/base.css
CHANGED
|
@@ -92,3 +92,31 @@
|
|
|
92
92
|
.jp-gis-symbology-button-container {
|
|
93
93
|
padding-top: 0.5rem;
|
|
94
94
|
}
|
|
95
|
+
|
|
96
|
+
.jp-gis-band-info-loading-container {
|
|
97
|
+
display: flex;
|
|
98
|
+
justify-content: center;
|
|
99
|
+
align-items: center;
|
|
100
|
+
gap: 2rem;
|
|
101
|
+
margin: auto;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
.jp-gis-loading-spinner {
|
|
105
|
+
animation: spin 4s linear infinite;
|
|
106
|
+
font-size: 1.5rem;
|
|
107
|
+
padding: 1rem 0;
|
|
108
|
+
margin: auto;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
.jp-gis-band-info-loading-container > span {
|
|
112
|
+
font-size: 1rem;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
@keyframes spin {
|
|
116
|
+
from {
|
|
117
|
+
transform: rotate(0deg);
|
|
118
|
+
}
|
|
119
|
+
to {
|
|
120
|
+
transform: rotate(360deg);
|
|
121
|
+
}
|
|
122
|
+
}
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
import { IJupyterGISModel } from '@jupytergis/schema';
|
|
2
|
-
import { Dialog } from '@jupyterlab/apputils';
|
|
3
|
-
import { DocumentRegistry } from '@jupyterlab/docregistry';
|
|
4
|
-
import { PromiseDelegate } from '@lumino/coreutils';
|
|
5
|
-
import { Signal } from '@lumino/signaling';
|
|
6
|
-
import React from 'react';
|
|
7
|
-
interface ITerrainDialogProps {
|
|
8
|
-
context: DocumentRegistry.IContext<IJupyterGISModel>;
|
|
9
|
-
okSignalPromise: PromiseDelegate<Signal<TerrainDialogWidget, null>>;
|
|
10
|
-
cancel: () => void;
|
|
11
|
-
}
|
|
12
|
-
declare const TerrainDialog: ({ context, okSignalPromise, cancel }: ITerrainDialogProps) => React.JSX.Element;
|
|
13
|
-
export interface ITerrainDialogOptions {
|
|
14
|
-
context: DocumentRegistry.IContext<IJupyterGISModel>;
|
|
15
|
-
}
|
|
16
|
-
export declare class TerrainDialogWidget extends Dialog<boolean> {
|
|
17
|
-
private okSignal;
|
|
18
|
-
constructor(options: ITerrainDialogOptions);
|
|
19
|
-
resolve(index?: number): void;
|
|
20
|
-
}
|
|
21
|
-
export default TerrainDialog;
|
|
@@ -1,60 +0,0 @@
|
|
|
1
|
-
import { Dialog } from '@jupyterlab/apputils';
|
|
2
|
-
import { PromiseDelegate } from '@lumino/coreutils';
|
|
3
|
-
import { Signal } from '@lumino/signaling';
|
|
4
|
-
import React, { useEffect, useRef, useState } from 'react';
|
|
5
|
-
const TerrainDialog = ({ context, okSignalPromise, cancel }) => {
|
|
6
|
-
const rasterDemSources = context.model.getSourcesByType('RasterDemSource');
|
|
7
|
-
const [selectedSource, setSelectedSource] = useState(Object.keys(rasterDemSources)[0]);
|
|
8
|
-
const [exaggerationInput, setExaggerationInput] = useState(1);
|
|
9
|
-
const selectedSourceRef = useRef(selectedSource);
|
|
10
|
-
const exaggerationInputRef = useRef(exaggerationInput);
|
|
11
|
-
useEffect(() => {
|
|
12
|
-
selectedSourceRef.current = selectedSource;
|
|
13
|
-
exaggerationInputRef.current = exaggerationInput;
|
|
14
|
-
}, [selectedSource, exaggerationInput]);
|
|
15
|
-
// Handler for changing the selected option
|
|
16
|
-
const handleSourceChange = (event) => {
|
|
17
|
-
setSelectedSource(event.target.value);
|
|
18
|
-
};
|
|
19
|
-
// Handler for changing the number input
|
|
20
|
-
const handleExaggerationChange = (event) => {
|
|
21
|
-
setExaggerationInput(Number(event.target.value));
|
|
22
|
-
};
|
|
23
|
-
const handleOk = () => {
|
|
24
|
-
context.model.setTerrain({
|
|
25
|
-
source: selectedSourceRef.current,
|
|
26
|
-
exaggeration: exaggerationInputRef.current
|
|
27
|
-
});
|
|
28
|
-
cancel();
|
|
29
|
-
};
|
|
30
|
-
okSignalPromise.promise.then(okSignal => {
|
|
31
|
-
okSignal.connect(handleOk);
|
|
32
|
-
});
|
|
33
|
-
return (React.createElement("div", { className: "jp-gis-terrain-main" },
|
|
34
|
-
React.createElement("label", { className: "jp-gis-terrain-label", htmlFor: "source" }, "Source:"),
|
|
35
|
-
React.createElement("select", { id: "source", className: "jp-mod-styled", value: selectedSource, onChange: handleSourceChange, "aria-label": "Select source" }, Object.entries(rasterDemSources).map(([key, value]) => (React.createElement("option", { key: key, value: key }, value)))),
|
|
36
|
-
React.createElement("label", { className: "jp-gis-terrain-label", htmlFor: "exaggeration" }, "Exaggeration:"),
|
|
37
|
-
React.createElement("input", { id: "exaggeration", className: "jp-mod-styled", type: "number", min: 0, step: 0.1, value: exaggerationInput, onChange: handleExaggerationChange, placeholder: "Enter an exaggeration value", "aria-label": "Enter exaggeration value" })));
|
|
38
|
-
};
|
|
39
|
-
export class TerrainDialogWidget extends Dialog {
|
|
40
|
-
constructor(options) {
|
|
41
|
-
const cancelCallback = () => {
|
|
42
|
-
this.resolve(0);
|
|
43
|
-
};
|
|
44
|
-
const okSignalPromise = new PromiseDelegate();
|
|
45
|
-
const body = (React.createElement(TerrainDialog, { context: options.context, okSignalPromise: okSignalPromise, cancel: cancelCallback }));
|
|
46
|
-
super({ title: 'Add New Terrain', body });
|
|
47
|
-
this.id = 'jupytergis::terrain';
|
|
48
|
-
this.okSignal = new Signal(this);
|
|
49
|
-
okSignalPromise.resolve(this.okSignal);
|
|
50
|
-
}
|
|
51
|
-
resolve(index) {
|
|
52
|
-
if (index === 0) {
|
|
53
|
-
super.resolve(index);
|
|
54
|
-
}
|
|
55
|
-
if (index === 1) {
|
|
56
|
-
this.okSignal.emit(null);
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
export default TerrainDialog;
|
package/style/terrainDialog.css
DELETED