@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 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;
@@ -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, 1.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, 1.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(FontAwesomeIcon, { icon: faSpinner })) : (React.createElement(BandRow
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
@@ -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 && layer.filters.appliedFilters.length !== 0) {
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: format.readFeatures(data, {
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]
@@ -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 Toolbar {
13
+ export declare class ToolbarWidget extends ReactiveToolbar {
14
14
  constructor(options: ToolbarWidget.IOptions);
15
15
  }
16
16
  export declare namespace ToolbarWidget {
@@ -1,5 +1,5 @@
1
1
  import { CommandToolbarButton } from '@jupyterlab/apputils';
2
- import { ReactWidget, Toolbar, ToolbarButton, addIcon, redoIcon, undoIcon, terminalIcon } from '@jupyterlab/ui-components';
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 Toolbar {
18
+ export class ToolbarWidget extends ReactiveToolbar {
19
19
  constructor(options) {
20
- super(options);
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', Toolbar.createSpacerItem());
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.4",
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.4",
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
@@ -6,7 +6,6 @@
6
6
  @import url('./dialog.css');
7
7
  @import url('./layerBrowser.css');
8
8
  @import url('./leftPanel.css');
9
- @import url('./terrainDialog.css');
10
9
  @import url('./filterPanel.css');
11
10
  @import url('./symbologyDialog.css');
12
11
  @import url('ol/ol.css');
@@ -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;
@@ -1,14 +0,0 @@
1
- .jp-gis-terrain-main {
2
- display: flex;
3
- flex-direction: column;
4
- gap: 0.5rem;
5
- overflow: hidden;
6
- }
7
-
8
- .jp-gis-terrain-label {
9
- margin: 0;
10
- padding: 0;
11
- font-weight: bold;
12
- display: block;
13
- position: relative;
14
- }