@jupytergis/base 0.1.1
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.d.ts +11 -0
- package/lib/commands.js +809 -0
- package/lib/console/consoleview.d.ts +24 -0
- package/lib/console/consoleview.js +55 -0
- package/lib/console/index.d.ts +1 -0
- package/lib/console/index.js +1 -0
- package/lib/constants.d.ts +57 -0
- package/lib/constants.js +89 -0
- package/lib/dialogs/components/symbology/BandRendering.d.ts +4 -0
- package/lib/dialogs/components/symbology/BandRendering.js +29 -0
- package/lib/dialogs/components/symbology/BandRow.d.ts +10 -0
- package/lib/dialogs/components/symbology/BandRow.js +43 -0
- package/lib/dialogs/components/symbology/SingleBandPseudoColor.d.ts +20 -0
- package/lib/dialogs/components/symbology/SingleBandPseudoColor.js +281 -0
- package/lib/dialogs/components/symbology/StopRow.d.ts +11 -0
- package/lib/dialogs/components/symbology/StopRow.js +58 -0
- package/lib/dialogs/formdialog.d.ts +31 -0
- package/lib/dialogs/formdialog.js +68 -0
- package/lib/dialogs/layerBrowserDialog.d.ts +25 -0
- package/lib/dialogs/layerBrowserDialog.js +141 -0
- package/lib/dialogs/symbologyDialog.d.ts +23 -0
- package/lib/dialogs/symbologyDialog.js +68 -0
- package/lib/dialogs/terrainDialog.d.ts +21 -0
- package/lib/dialogs/terrainDialog.js +60 -0
- package/lib/formbuilder/creationform.d.ts +56 -0
- package/lib/formbuilder/creationform.js +117 -0
- package/lib/formbuilder/editform.d.ts +24 -0
- package/lib/formbuilder/editform.js +60 -0
- package/lib/formbuilder/formselectors.d.ts +5 -0
- package/lib/formbuilder/formselectors.js +38 -0
- package/lib/formbuilder/index.d.ts +6 -0
- package/lib/formbuilder/index.js +6 -0
- package/lib/formbuilder/objectform/baseform.d.ts +79 -0
- package/lib/formbuilder/objectform/baseform.js +167 -0
- package/lib/formbuilder/objectform/geojsonsource.d.ts +19 -0
- package/lib/formbuilder/objectform/geojsonsource.js +80 -0
- package/lib/formbuilder/objectform/hillshadeLayerForm.d.ts +8 -0
- package/lib/formbuilder/objectform/hillshadeLayerForm.js +12 -0
- package/lib/formbuilder/objectform/layerform.d.ts +19 -0
- package/lib/formbuilder/objectform/layerform.js +17 -0
- package/lib/formbuilder/objectform/tilesourceform.d.ts +7 -0
- package/lib/formbuilder/objectform/tilesourceform.js +60 -0
- package/lib/formbuilder/objectform/vectorlayerform.d.ts +15 -0
- package/lib/formbuilder/objectform/vectorlayerform.js +88 -0
- package/lib/formbuilder/objectform/webGlLayerForm.d.ts +8 -0
- package/lib/formbuilder/objectform/webGlLayerForm.js +10 -0
- package/lib/icons.d.ts +6 -0
- package/lib/icons.js +31 -0
- package/lib/index.d.ts +10 -0
- package/lib/index.js +10 -0
- package/lib/mainview/index.d.ts +3 -0
- package/lib/mainview/index.js +3 -0
- package/lib/mainview/mainView.d.ts +113 -0
- package/lib/mainview/mainView.js +743 -0
- package/lib/mainview/mainviewmodel.d.ts +24 -0
- package/lib/mainview/mainviewmodel.js +34 -0
- package/lib/mainview/mainviewwidget.d.ts +14 -0
- package/lib/mainview/mainviewwidget.js +18 -0
- package/lib/mainview/spinner.d.ts +6 -0
- package/lib/mainview/spinner.js +5 -0
- package/lib/panelview/components/filter-panel/Filter.d.ts +19 -0
- package/lib/panelview/components/filter-panel/Filter.js +223 -0
- package/lib/panelview/components/filter-panel/FilterRow.d.ts +9 -0
- package/lib/panelview/components/filter-panel/FilterRow.js +61 -0
- package/lib/panelview/components/layers.d.ts +13 -0
- package/lib/panelview/components/layers.js +275 -0
- package/lib/panelview/components/sources.d.ts +10 -0
- package/lib/panelview/components/sources.js +147 -0
- package/lib/panelview/header.d.ts +11 -0
- package/lib/panelview/header.js +20 -0
- package/lib/panelview/index.d.ts +5 -0
- package/lib/panelview/index.js +5 -0
- package/lib/panelview/leftpanel.d.ts +51 -0
- package/lib/panelview/leftpanel.js +125 -0
- package/lib/panelview/model.d.ts +19 -0
- package/lib/panelview/model.js +30 -0
- package/lib/panelview/objectproperties.d.ts +17 -0
- package/lib/panelview/objectproperties.js +92 -0
- package/lib/panelview/rightpanel.d.ts +19 -0
- package/lib/panelview/rightpanel.js +45 -0
- package/lib/toolbar/index.d.ts +2 -0
- package/lib/toolbar/index.js +2 -0
- package/lib/toolbar/usertoolbaritem.d.ts +19 -0
- package/lib/toolbar/usertoolbaritem.js +57 -0
- package/lib/toolbar/widget.d.ts +22 -0
- package/lib/toolbar/widget.js +104 -0
- package/lib/tools.d.ts +25 -0
- package/lib/tools.js +215 -0
- package/lib/types.d.ts +11 -0
- package/lib/types.js +1 -0
- package/lib/widget.d.ts +49 -0
- package/lib/widget.js +144 -0
- package/package.json +95 -0
- package/style/base.css +55 -0
- package/style/colorExpression.css +36 -0
- package/style/dialog.css +8 -0
- package/style/filterPanel.css +70 -0
- package/style/icons/geojson.svg +12 -0
- package/style/icons/mound.svg +9 -0
- package/style/icons/nonvisibility.svg +8 -0
- package/style/icons/raster.svg +5 -0
- package/style/icons/visibility.svg +7 -0
- package/style/index.css +6 -0
- package/style/index.js +6 -0
- package/style/layerBrowser.css +256 -0
- package/style/leftPanel.css +150 -0
- package/style/symbologyDialog.css +86 -0
- package/style/terrainDialog.css +14 -0
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { ConsolePanel } from '@jupyterlab/console';
|
|
2
|
+
import { ServiceManager } from '@jupyterlab/services';
|
|
3
|
+
import { BoxPanel, Widget } from '@lumino/widgets';
|
|
4
|
+
import { IRenderMimeRegistry } from '@jupyterlab/rendermime';
|
|
5
|
+
import { IEditorMimeTypeService } from '@jupyterlab/codeeditor';
|
|
6
|
+
import { CommandRegistry } from '@lumino/commands';
|
|
7
|
+
export declare class ConsoleView extends BoxPanel {
|
|
8
|
+
constructor(options: ConsoleView.IOptions);
|
|
9
|
+
get consolePanel(): ConsolePanel;
|
|
10
|
+
dispose(): void;
|
|
11
|
+
execute(): void;
|
|
12
|
+
protected onResize(msg: Widget.ResizeMessage): void;
|
|
13
|
+
private _consolePanel;
|
|
14
|
+
private _resize;
|
|
15
|
+
}
|
|
16
|
+
export declare namespace ConsoleView {
|
|
17
|
+
interface IOptions {
|
|
18
|
+
manager: ServiceManager.IManager;
|
|
19
|
+
contentFactory: ConsolePanel.IContentFactory;
|
|
20
|
+
mimeTypeService: IEditorMimeTypeService;
|
|
21
|
+
rendermime: IRenderMimeRegistry;
|
|
22
|
+
commandRegistry: CommandRegistry;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { ConsolePanel } from '@jupyterlab/console';
|
|
2
|
+
import { BoxPanel } from '@lumino/widgets';
|
|
3
|
+
import { debounce } from '../tools';
|
|
4
|
+
import { closeIcon, CommandToolbarButton, expandIcon, Toolbar } from '@jupyterlab/ui-components';
|
|
5
|
+
export class ConsoleView extends BoxPanel {
|
|
6
|
+
constructor(options) {
|
|
7
|
+
super({ direction: 'top-to-bottom' });
|
|
8
|
+
this._resize = debounce(() => {
|
|
9
|
+
window.dispatchEvent(new Event('resize'));
|
|
10
|
+
}, 200);
|
|
11
|
+
this.addClass('jpgis-console');
|
|
12
|
+
const { manager, contentFactory, mimeTypeService, rendermime } = options;
|
|
13
|
+
const clonedRendermime = rendermime.clone();
|
|
14
|
+
this._consolePanel = new ConsolePanel({
|
|
15
|
+
manager,
|
|
16
|
+
contentFactory,
|
|
17
|
+
mimeTypeService,
|
|
18
|
+
rendermime: clonedRendermime,
|
|
19
|
+
kernelPreference: { name: 'python3', shutdownOnDispose: true }
|
|
20
|
+
});
|
|
21
|
+
this._consolePanel.console.node.dataset.jpInteractionMode = 'notebook';
|
|
22
|
+
this.addWidget(this._consolePanel);
|
|
23
|
+
BoxPanel.setStretch(this._consolePanel, 1);
|
|
24
|
+
this._consolePanel.toolbar.addItem('spacer', Toolbar.createSpacerItem());
|
|
25
|
+
this._consolePanel.toolbar.addItem('toggle', new CommandToolbarButton({
|
|
26
|
+
label: '',
|
|
27
|
+
icon: expandIcon,
|
|
28
|
+
id: 'jupytergis:toggleConsole',
|
|
29
|
+
commands: options.commandRegistry
|
|
30
|
+
}));
|
|
31
|
+
this._consolePanel.toolbar.addItem('close', new CommandToolbarButton({
|
|
32
|
+
label: '',
|
|
33
|
+
icon: closeIcon,
|
|
34
|
+
id: 'jupytergis:removeConsole',
|
|
35
|
+
commands: options.commandRegistry
|
|
36
|
+
}));
|
|
37
|
+
}
|
|
38
|
+
get consolePanel() {
|
|
39
|
+
return this._consolePanel;
|
|
40
|
+
}
|
|
41
|
+
dispose() {
|
|
42
|
+
if (this.isDisposed) {
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
this._consolePanel.dispose();
|
|
46
|
+
super.dispose();
|
|
47
|
+
}
|
|
48
|
+
execute() {
|
|
49
|
+
this._consolePanel.console.execute(false);
|
|
50
|
+
}
|
|
51
|
+
onResize(msg) {
|
|
52
|
+
super.onResize(msg);
|
|
53
|
+
this._resize();
|
|
54
|
+
}
|
|
55
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './consoleview';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './consoleview';
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { LabIcon } from '@jupyterlab/ui-components';
|
|
2
|
+
/**
|
|
3
|
+
* The command IDs.
|
|
4
|
+
*/
|
|
5
|
+
export declare namespace CommandIDs {
|
|
6
|
+
const createNew = "jupytergis:create-new-jGIS-file";
|
|
7
|
+
const redo = "jupytergis:redo";
|
|
8
|
+
const undo = "jupytergis:undo";
|
|
9
|
+
const symbology = "jupytergis:symbology";
|
|
10
|
+
const openLayerBrowser = "jupytergis:openLayerBrowser";
|
|
11
|
+
const newRasterEntry = "jupytergis:newRasterEntry";
|
|
12
|
+
const newVectorTileEntry = "jupytergis:newVectorTileEntry";
|
|
13
|
+
const newGeoJSONEntry = "jupytergis:newGeoJSONEntry";
|
|
14
|
+
const newHillshadeEntry = "jupytergis:newHillshadeEntry";
|
|
15
|
+
const newImageEntry = "jupytergis:newImageEntry";
|
|
16
|
+
const newVideoEntry = "jupytergis:newVideoEntry";
|
|
17
|
+
const newGeoTiffEntry = "jupytergis:newGeoTiffEntry";
|
|
18
|
+
const newRasterSource = "jupytergis:newRasterSource";
|
|
19
|
+
const newRasterDemSource = "jupytergis:newRasterDemSource";
|
|
20
|
+
const newVectorSource = "jupytergis:newVectorSource";
|
|
21
|
+
const newGeoJSONSource = "jupytergis:newGeoJSONSource";
|
|
22
|
+
const newImageSource = "jupytergis:imageSource";
|
|
23
|
+
const newVideoSource = "jupytergis:videoSource";
|
|
24
|
+
const newShapefileSource = "jupytergis:shapefileSource";
|
|
25
|
+
const newGeoTiffSource = "jupytergis:newGeoTiffSource";
|
|
26
|
+
const newRasterLayer = "jupytergis:newRasterLayer";
|
|
27
|
+
const newVectorLayer = "jupytergis:newVectorLayer";
|
|
28
|
+
const newHillshadeLayer = "jupytergis:newHillshadeLayer";
|
|
29
|
+
const newImageLayer = "jupytergis:newImageLayer";
|
|
30
|
+
const newVideoLayer = "jupytergis:newVideoLayer";
|
|
31
|
+
const newShapefileLayer = "jupytergis:newShapefileLayer";
|
|
32
|
+
const newWebGlTileLayer = "jupytergis:newWebGlTileLayer";
|
|
33
|
+
const renameLayer = "jupytergis:renameLayer";
|
|
34
|
+
const removeLayer = "jupytergis:removeLayer";
|
|
35
|
+
const renameGroup = "jupytergis:renameGroup";
|
|
36
|
+
const removeGroup = "jupytergis:removeGroup";
|
|
37
|
+
const moveLayersToGroup = "jupytergis:moveLayersToGroup";
|
|
38
|
+
const moveLayerToNewGroup = "jupytergis:moveLayerToNewGroup";
|
|
39
|
+
const renameSource = "jupytergis:renameSource";
|
|
40
|
+
const removeSource = "jupytergis:removeSource";
|
|
41
|
+
const newTerrain = "jupytergis:newTerrain";
|
|
42
|
+
const removeTerrain = "jupytergis:removeTerrain";
|
|
43
|
+
const toggleConsole = "jupytergis:toggleConsole";
|
|
44
|
+
const invokeCompleter = "jupytergis:invokeConsoleCompleter";
|
|
45
|
+
const removeConsole = "jupytergis:removeConsole";
|
|
46
|
+
const executeConsole = "jupytergis:executeConsole";
|
|
47
|
+
const selectCompleter = "jupytergis:selectConsoleCompleter";
|
|
48
|
+
}
|
|
49
|
+
interface IRegisteredIcon {
|
|
50
|
+
icon?: LabIcon;
|
|
51
|
+
iconClass?: string;
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* The registered icons
|
|
55
|
+
*/
|
|
56
|
+
export declare const icons: Map<string, IRegisteredIcon>;
|
|
57
|
+
export {};
|
package/lib/constants.js
ADDED
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import { redoIcon, undoIcon } from '@jupyterlab/ui-components';
|
|
2
|
+
import { geoJSONIcon, moundIcon, rasterIcon } from './icons';
|
|
3
|
+
/**
|
|
4
|
+
* The command IDs.
|
|
5
|
+
*/
|
|
6
|
+
export var CommandIDs;
|
|
7
|
+
(function (CommandIDs) {
|
|
8
|
+
CommandIDs.createNew = 'jupytergis:create-new-jGIS-file';
|
|
9
|
+
CommandIDs.redo = 'jupytergis:redo';
|
|
10
|
+
CommandIDs.undo = 'jupytergis:undo';
|
|
11
|
+
CommandIDs.symbology = 'jupytergis:symbology';
|
|
12
|
+
// Layers and sources creation commands
|
|
13
|
+
CommandIDs.openLayerBrowser = 'jupytergis:openLayerBrowser';
|
|
14
|
+
// Layer and source
|
|
15
|
+
CommandIDs.newRasterEntry = 'jupytergis:newRasterEntry';
|
|
16
|
+
CommandIDs.newVectorTileEntry = 'jupytergis:newVectorTileEntry';
|
|
17
|
+
CommandIDs.newGeoJSONEntry = 'jupytergis:newGeoJSONEntry';
|
|
18
|
+
CommandIDs.newHillshadeEntry = 'jupytergis:newHillshadeEntry';
|
|
19
|
+
CommandIDs.newImageEntry = 'jupytergis:newImageEntry';
|
|
20
|
+
CommandIDs.newVideoEntry = 'jupytergis:newVideoEntry';
|
|
21
|
+
CommandIDs.newGeoTiffEntry = 'jupytergis:newGeoTiffEntry';
|
|
22
|
+
// Sources only commands
|
|
23
|
+
CommandIDs.newRasterSource = 'jupytergis:newRasterSource';
|
|
24
|
+
CommandIDs.newRasterDemSource = 'jupytergis:newRasterDemSource';
|
|
25
|
+
CommandIDs.newVectorSource = 'jupytergis:newVectorSource';
|
|
26
|
+
CommandIDs.newGeoJSONSource = 'jupytergis:newGeoJSONSource';
|
|
27
|
+
CommandIDs.newImageSource = 'jupytergis:imageSource';
|
|
28
|
+
CommandIDs.newVideoSource = 'jupytergis:videoSource';
|
|
29
|
+
CommandIDs.newShapefileSource = 'jupytergis:shapefileSource';
|
|
30
|
+
CommandIDs.newGeoTiffSource = 'jupytergis:newGeoTiffSource';
|
|
31
|
+
// Layers only commands
|
|
32
|
+
CommandIDs.newRasterLayer = 'jupytergis:newRasterLayer';
|
|
33
|
+
CommandIDs.newVectorLayer = 'jupytergis:newVectorLayer';
|
|
34
|
+
CommandIDs.newHillshadeLayer = 'jupytergis:newHillshadeLayer';
|
|
35
|
+
CommandIDs.newImageLayer = 'jupytergis:newImageLayer';
|
|
36
|
+
CommandIDs.newVideoLayer = 'jupytergis:newVideoLayer';
|
|
37
|
+
CommandIDs.newShapefileLayer = 'jupytergis:newShapefileLayer';
|
|
38
|
+
CommandIDs.newWebGlTileLayer = 'jupytergis:newWebGlTileLayer';
|
|
39
|
+
// Layer and group actions
|
|
40
|
+
CommandIDs.renameLayer = 'jupytergis:renameLayer';
|
|
41
|
+
CommandIDs.removeLayer = 'jupytergis:removeLayer';
|
|
42
|
+
CommandIDs.renameGroup = 'jupytergis:renameGroup';
|
|
43
|
+
CommandIDs.removeGroup = 'jupytergis:removeGroup';
|
|
44
|
+
CommandIDs.moveLayersToGroup = 'jupytergis:moveLayersToGroup';
|
|
45
|
+
CommandIDs.moveLayerToNewGroup = 'jupytergis:moveLayerToNewGroup';
|
|
46
|
+
// Source actions
|
|
47
|
+
CommandIDs.renameSource = 'jupytergis:renameSource';
|
|
48
|
+
CommandIDs.removeSource = 'jupytergis:removeSource';
|
|
49
|
+
// Terrain stuff
|
|
50
|
+
CommandIDs.newTerrain = 'jupytergis:newTerrain';
|
|
51
|
+
CommandIDs.removeTerrain = 'jupytergis:removeTerrain';
|
|
52
|
+
// Console commands
|
|
53
|
+
CommandIDs.toggleConsole = 'jupytergis:toggleConsole';
|
|
54
|
+
CommandIDs.invokeCompleter = 'jupytergis:invokeConsoleCompleter';
|
|
55
|
+
CommandIDs.removeConsole = 'jupytergis:removeConsole';
|
|
56
|
+
CommandIDs.executeConsole = 'jupytergis:executeConsole';
|
|
57
|
+
CommandIDs.selectCompleter = 'jupytergis:selectConsoleCompleter';
|
|
58
|
+
})(CommandIDs || (CommandIDs = {}));
|
|
59
|
+
const iconObject = {
|
|
60
|
+
RasterSource: { icon: rasterIcon },
|
|
61
|
+
RasterDemSource: { icon: moundIcon },
|
|
62
|
+
VectorTileSource: { iconClass: 'fa fa-vector-square' },
|
|
63
|
+
GeoJSONSource: { icon: geoJSONIcon },
|
|
64
|
+
ImageSource: { iconClass: 'fa fa-image' },
|
|
65
|
+
VideoSource: { iconClass: 'fa fa-video' },
|
|
66
|
+
ShapefileSource: { iconClass: 'fa fa-file' },
|
|
67
|
+
RasterLayer: { icon: rasterIcon },
|
|
68
|
+
VectorLayer: { iconClass: 'fa fa-vector-square' },
|
|
69
|
+
HillshadeLayer: { icon: moundIcon },
|
|
70
|
+
ImageLayer: { iconClass: 'fa fa-image' },
|
|
71
|
+
VideoLayer: { iconClass: 'fa fa-video' },
|
|
72
|
+
[CommandIDs.redo]: { icon: redoIcon },
|
|
73
|
+
[CommandIDs.undo]: { icon: undoIcon },
|
|
74
|
+
[CommandIDs.openLayerBrowser]: { iconClass: 'fa fa-book-open' },
|
|
75
|
+
[CommandIDs.newRasterEntry]: { icon: rasterIcon },
|
|
76
|
+
[CommandIDs.newVectorTileEntry]: { iconClass: 'fa fa-vector-square' },
|
|
77
|
+
[CommandIDs.newGeoJSONEntry]: { icon: geoJSONIcon },
|
|
78
|
+
[CommandIDs.newHillshadeEntry]: { icon: moundIcon },
|
|
79
|
+
[CommandIDs.newImageEntry]: { iconClass: 'fa fa-image' },
|
|
80
|
+
[CommandIDs.newVideoEntry]: { iconClass: 'fa fa-video' },
|
|
81
|
+
[CommandIDs.newShapefileLayer]: { iconClass: 'fa fa-file' },
|
|
82
|
+
[CommandIDs.newGeoTiffEntry]: { iconClass: 'fa fa-image' },
|
|
83
|
+
[CommandIDs.newTerrain]: { iconClass: 'fa fa-mountain' },
|
|
84
|
+
[CommandIDs.symbology]: { iconClass: 'fa fa-brush' }
|
|
85
|
+
};
|
|
86
|
+
/**
|
|
87
|
+
* The registered icons
|
|
88
|
+
*/
|
|
89
|
+
export const icons = new Map(Object.entries(iconObject));
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import React, { useEffect, useState } from 'react';
|
|
2
|
+
import SingleBandPseudoColor from './SingleBandPseudoColor';
|
|
3
|
+
const BandRendering = ({ context, state, okSignalPromise, cancel, layerId }) => {
|
|
4
|
+
const renderTypes = ['Singleband Pseudocolor', 'Multiband Color'];
|
|
5
|
+
const [selectedRenderType, setSelectedRenderType] = useState('Singleband Pseudocolor');
|
|
6
|
+
const [componentToRender, setComponentToRender] = useState(null);
|
|
7
|
+
let RenderComponent;
|
|
8
|
+
useEffect(() => {
|
|
9
|
+
if (!selectedRenderType) {
|
|
10
|
+
return;
|
|
11
|
+
}
|
|
12
|
+
switch (selectedRenderType) {
|
|
13
|
+
case 'Singleband Pseudocolor':
|
|
14
|
+
RenderComponent = (React.createElement(SingleBandPseudoColor, { context: context, state: state, okSignalPromise: okSignalPromise, cancel: cancel, layerId: layerId }));
|
|
15
|
+
break;
|
|
16
|
+
default:
|
|
17
|
+
RenderComponent = React.createElement("div", null, "Render Type Not Implemented (yet)");
|
|
18
|
+
}
|
|
19
|
+
setComponentToRender(RenderComponent);
|
|
20
|
+
}, [selectedRenderType]);
|
|
21
|
+
return (React.createElement(React.Fragment, null,
|
|
22
|
+
React.createElement("div", { className: "jp-gis-symbology-row" },
|
|
23
|
+
React.createElement("label", { htmlFor: "render-type-select" }, "Render Type:"),
|
|
24
|
+
React.createElement("select", { name: "render-type-select", id: "render-type-select", value: selectedRenderType, onChange: event => {
|
|
25
|
+
setSelectedRenderType(event.target.value);
|
|
26
|
+
} }, renderTypes.map((func, funcIndex) => (React.createElement("option", { key: func, value: func }, func))))),
|
|
27
|
+
componentToRender));
|
|
28
|
+
};
|
|
29
|
+
export default BandRendering;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { IBandRow } from './SingleBandPseudoColor';
|
|
3
|
+
declare const BandRow: ({ index, bandRow, bandRows, setSelectedBand, setBandRows }: {
|
|
4
|
+
index: number;
|
|
5
|
+
bandRow: IBandRow;
|
|
6
|
+
bandRows: IBandRow[];
|
|
7
|
+
setSelectedBand: (band: number) => void;
|
|
8
|
+
setBandRows: (bandRows: IBandRow[]) => void;
|
|
9
|
+
}) => React.JSX.Element;
|
|
10
|
+
export default BandRow;
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import React, { useState } from 'react';
|
|
2
|
+
const BandRow = ({ index, bandRow, bandRows, setSelectedBand, setBandRows }) => {
|
|
3
|
+
const [minValue, setMinValue] = useState(bandRow.stats.minimum);
|
|
4
|
+
const [maxValue, setMaxValue] = useState(bandRow.stats.maximum);
|
|
5
|
+
const handleMinValueChange = (event) => {
|
|
6
|
+
setMinValue(+event.target.value);
|
|
7
|
+
setNewBands();
|
|
8
|
+
};
|
|
9
|
+
const handleMaxValueChange = (event) => {
|
|
10
|
+
setMaxValue(+event.target.value);
|
|
11
|
+
setNewBands();
|
|
12
|
+
};
|
|
13
|
+
const setNewBands = () => {
|
|
14
|
+
const newBandRows = [...bandRows];
|
|
15
|
+
newBandRows[index].stats.minimum = minValue;
|
|
16
|
+
newBandRows[index].stats.maximum = maxValue;
|
|
17
|
+
setBandRows(newBandRows);
|
|
18
|
+
};
|
|
19
|
+
return (React.createElement(React.Fragment, null,
|
|
20
|
+
React.createElement("div", { className: "jp-gis-symbology-row" },
|
|
21
|
+
React.createElement("label", { htmlFor: `band-select-${index}` }, "Band:"),
|
|
22
|
+
React.createElement("div", { className: "jp-select-wrapper" },
|
|
23
|
+
React.createElement("select", { name: `band-select-${index}`, onChange: event => setSelectedBand(+event.target.value), className: "jp-mod-styled" }, bandRows.map((band, bandIndex) => (React.createElement("option", { key: bandIndex, value: band.band, selected: band.band === bandRow.band, className: "jp-mod-styled" }, `Band ${band.band} (${band.colorInterpretation})`)))))),
|
|
24
|
+
React.createElement("div", { className: "jp-gis-symbology-row", style: { gap: '0.5rem' } },
|
|
25
|
+
React.createElement("div", { style: {
|
|
26
|
+
display: 'flex',
|
|
27
|
+
justifyContent: 'space-between',
|
|
28
|
+
width: '50%'
|
|
29
|
+
} },
|
|
30
|
+
React.createElement("label", { htmlFor: "band-min", style: { alignSelf: 'center' } }, "Min"),
|
|
31
|
+
React.createElement("input", { type: "number", className: "jp-mod-styled", style: { marginRight: 15 }, value: minValue, onChange: handleMinValueChange })),
|
|
32
|
+
React.createElement("div", { style: {
|
|
33
|
+
display: 'flex',
|
|
34
|
+
justifyContent: 'space-between',
|
|
35
|
+
width: '50%',
|
|
36
|
+
paddingRight: '2px'
|
|
37
|
+
} },
|
|
38
|
+
React.createElement("label", { htmlFor: "band-max", style: { alignSelf: 'center' } }, "Max"),
|
|
39
|
+
React.createElement("input", { type: "number", className: "jp-mod-styled",
|
|
40
|
+
// defaultValue={bandRow.stats.maximum}
|
|
41
|
+
value: maxValue, onChange: handleMaxValueChange, onBlur: setNewBands })))));
|
|
42
|
+
};
|
|
43
|
+
export default BandRow;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { IDict } from '@jupytergis/schema';
|
|
2
|
+
import React from 'react';
|
|
3
|
+
import { ISymbologyDialogProps } from '../../symbologyDialog';
|
|
4
|
+
export interface IStopRow {
|
|
5
|
+
value: number;
|
|
6
|
+
color: number[];
|
|
7
|
+
}
|
|
8
|
+
export interface IBandRow {
|
|
9
|
+
band: number;
|
|
10
|
+
colorInterpretation: string;
|
|
11
|
+
stats: {
|
|
12
|
+
minimum: number;
|
|
13
|
+
maximum: number;
|
|
14
|
+
mean: number;
|
|
15
|
+
stdDev: number;
|
|
16
|
+
};
|
|
17
|
+
metadata: IDict;
|
|
18
|
+
}
|
|
19
|
+
declare const SingleBandPseudoColor: ({ context, state, okSignalPromise, cancel, layerId }: ISymbologyDialogProps) => React.JSX.Element | undefined;
|
|
20
|
+
export default SingleBandPseudoColor;
|
|
@@ -0,0 +1,281 @@
|
|
|
1
|
+
import { faSpinner } from '@fortawesome/free-solid-svg-icons';
|
|
2
|
+
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
|
3
|
+
import { Button } from '@jupyterlab/ui-components';
|
|
4
|
+
import initGdalJs from 'gdal3.js';
|
|
5
|
+
import React, { useEffect, useRef, useState } from 'react';
|
|
6
|
+
import BandRow from './BandRow';
|
|
7
|
+
import StopRow from './StopRow';
|
|
8
|
+
const SingleBandPseudoColor = ({ context, state, okSignalPromise, cancel, layerId }) => {
|
|
9
|
+
const functions = ['discrete', 'linear', 'exact'];
|
|
10
|
+
const stopRowsRef = useRef();
|
|
11
|
+
const bandRowsRef = useRef([]);
|
|
12
|
+
const selectedFunctionRef = useRef();
|
|
13
|
+
const [selectedFunction, setSelectedFunction] = useState();
|
|
14
|
+
const [selectedBand, setSelectedBand] = useState(1);
|
|
15
|
+
const [stopRows, setStopRows] = useState([]);
|
|
16
|
+
const [bandRows, setBandRows] = useState([]);
|
|
17
|
+
if (!layerId) {
|
|
18
|
+
return;
|
|
19
|
+
}
|
|
20
|
+
const layer = context.model.getLayer(layerId);
|
|
21
|
+
if (!layer) {
|
|
22
|
+
return;
|
|
23
|
+
}
|
|
24
|
+
useEffect(() => {
|
|
25
|
+
getBandInfo();
|
|
26
|
+
setInitialFunction();
|
|
27
|
+
}, []);
|
|
28
|
+
useEffect(() => {
|
|
29
|
+
bandRowsRef.current = bandRows;
|
|
30
|
+
buildColorInfo();
|
|
31
|
+
}, [bandRows]);
|
|
32
|
+
useEffect(() => {
|
|
33
|
+
stopRowsRef.current = stopRows;
|
|
34
|
+
}, [stopRows]);
|
|
35
|
+
useEffect(() => {
|
|
36
|
+
selectedFunctionRef.current = selectedFunction;
|
|
37
|
+
}, [selectedFunction]);
|
|
38
|
+
const setInitialFunction = () => {
|
|
39
|
+
var _a;
|
|
40
|
+
if (!((_a = layer.parameters) === null || _a === void 0 ? void 0 : _a.color)) {
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
const color = layer.parameters.color;
|
|
44
|
+
if (color[0] === 'interpolate') {
|
|
45
|
+
setSelectedFunction('linear');
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
// If expression is using 'case' we look at the comparison operator to set selected function
|
|
49
|
+
// Looking at fourth element because second is for nodata
|
|
50
|
+
const operator = color[3][0];
|
|
51
|
+
operator === '<='
|
|
52
|
+
? setSelectedFunction('discrete')
|
|
53
|
+
: setSelectedFunction('exact');
|
|
54
|
+
};
|
|
55
|
+
const getBandInfo = async () => {
|
|
56
|
+
var _a, _b;
|
|
57
|
+
const bandsArr = [];
|
|
58
|
+
const source = context.model.getSource((_a = layer === null || layer === void 0 ? void 0 : layer.parameters) === null || _a === void 0 ? void 0 : _a.source);
|
|
59
|
+
const sourceInfo = (_b = source === null || source === void 0 ? void 0 : source.parameters) === null || _b === void 0 ? void 0 : _b.urls[0];
|
|
60
|
+
if (!sourceInfo.url) {
|
|
61
|
+
return;
|
|
62
|
+
}
|
|
63
|
+
let tifData;
|
|
64
|
+
const tifDataState = (await state.fetch(layerId));
|
|
65
|
+
if (tifDataState) {
|
|
66
|
+
tifData = JSON.parse(tifDataState);
|
|
67
|
+
}
|
|
68
|
+
else {
|
|
69
|
+
//! This takes so long, maybe do when adding source instead
|
|
70
|
+
const Gdal = await initGdalJs({
|
|
71
|
+
path: 'lab/extensions/@jupytergis/jupytergis-core/static',
|
|
72
|
+
useWorker: false
|
|
73
|
+
});
|
|
74
|
+
const fileData = await fetch(sourceInfo.url);
|
|
75
|
+
const file = new File([await fileData.blob()], 'loaded.tif');
|
|
76
|
+
const result = await Gdal.open(file);
|
|
77
|
+
const tifDataset = result.datasets[0];
|
|
78
|
+
tifData = await Gdal.gdalinfo(tifDataset, ['-stats']);
|
|
79
|
+
Gdal.close(tifDataset);
|
|
80
|
+
}
|
|
81
|
+
tifData['bands'].forEach((bandData) => {
|
|
82
|
+
var _a, _b;
|
|
83
|
+
bandsArr.push({
|
|
84
|
+
band: bandData.band,
|
|
85
|
+
colorInterpretation: bandData.colorInterpretation,
|
|
86
|
+
stats: {
|
|
87
|
+
minimum: (_a = sourceInfo.min) !== null && _a !== void 0 ? _a : bandData.minimum,
|
|
88
|
+
maximum: (_b = sourceInfo.max) !== null && _b !== void 0 ? _b : bandData.maximum,
|
|
89
|
+
mean: bandData.mean,
|
|
90
|
+
stdDev: bandData.stdDev
|
|
91
|
+
},
|
|
92
|
+
metadata: bandData.metadata
|
|
93
|
+
});
|
|
94
|
+
});
|
|
95
|
+
setBandRows(bandsArr);
|
|
96
|
+
console.log('tifData', tifData);
|
|
97
|
+
console.log('bandsArr', bandsArr);
|
|
98
|
+
};
|
|
99
|
+
const buildColorInfo = () => {
|
|
100
|
+
var _a;
|
|
101
|
+
// This it to parse a color object on the layer
|
|
102
|
+
if (!((_a = layer.parameters) === null || _a === void 0 ? void 0 : _a.color)) {
|
|
103
|
+
return;
|
|
104
|
+
}
|
|
105
|
+
const color = layer.parameters.color;
|
|
106
|
+
// If color is a string we don't need to parse
|
|
107
|
+
if (typeof color === 'string') {
|
|
108
|
+
return;
|
|
109
|
+
}
|
|
110
|
+
const valueColorPairs = [];
|
|
111
|
+
// So if it's not a string then it's an array and we parse
|
|
112
|
+
// Color[0] is the operator used for the color expression
|
|
113
|
+
switch (color[0]) {
|
|
114
|
+
case 'interpolate': {
|
|
115
|
+
// First element is interpolate for linear selection
|
|
116
|
+
// Second element is type of interpolation (ie linear)
|
|
117
|
+
// Third is input value that stop values are compared with
|
|
118
|
+
// Fourth and Fifth are the transparent value for NoData values
|
|
119
|
+
// Sixth and on is value:color pairs
|
|
120
|
+
for (let i = 5; i < color.length; i += 2) {
|
|
121
|
+
const obj = {
|
|
122
|
+
value: scaleValue(color[i]),
|
|
123
|
+
color: color[i + 1]
|
|
124
|
+
};
|
|
125
|
+
valueColorPairs.push(obj);
|
|
126
|
+
}
|
|
127
|
+
break;
|
|
128
|
+
}
|
|
129
|
+
case 'case': {
|
|
130
|
+
// First element is case for discrete and exact selections
|
|
131
|
+
// Second element is the condition for NoData values
|
|
132
|
+
// Third element is transparent
|
|
133
|
+
// Fourth is the condition for actual values
|
|
134
|
+
// Within that, first is logical operator, second is band, third is value
|
|
135
|
+
// Fifth is color
|
|
136
|
+
// Last element is fallback value
|
|
137
|
+
for (let i = 3; i < color.length - 1; i += 2) {
|
|
138
|
+
const obj = {
|
|
139
|
+
value: scaleValue(color[i][2]),
|
|
140
|
+
color: color[i + 1]
|
|
141
|
+
};
|
|
142
|
+
valueColorPairs.push(obj);
|
|
143
|
+
}
|
|
144
|
+
break;
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
setStopRows(valueColorPairs);
|
|
148
|
+
};
|
|
149
|
+
const handleOk = () => {
|
|
150
|
+
var _a, _b, _c, _d;
|
|
151
|
+
// Update source
|
|
152
|
+
const bandRow = bandRowsRef.current[selectedBand - 1];
|
|
153
|
+
if (!bandRow) {
|
|
154
|
+
return;
|
|
155
|
+
}
|
|
156
|
+
const sourceId = (_a = layer.parameters) === null || _a === void 0 ? void 0 : _a.source;
|
|
157
|
+
const source = context.model.getSource(sourceId);
|
|
158
|
+
if (!source || !source.parameters) {
|
|
159
|
+
return;
|
|
160
|
+
}
|
|
161
|
+
const sourceInfo = source.parameters.urls[0];
|
|
162
|
+
sourceInfo.min = bandRow.stats.minimum;
|
|
163
|
+
sourceInfo.max = bandRow.stats.maximum;
|
|
164
|
+
source.parameters.urls[0] = sourceInfo;
|
|
165
|
+
context.model.sharedModel.updateSource(sourceId, source);
|
|
166
|
+
// Update layer
|
|
167
|
+
if (!layer.parameters) {
|
|
168
|
+
return;
|
|
169
|
+
}
|
|
170
|
+
// TODO: Different viewers will have different types
|
|
171
|
+
let colorExpr = [];
|
|
172
|
+
switch (selectedFunctionRef.current) {
|
|
173
|
+
case 'linear': {
|
|
174
|
+
colorExpr = ['interpolate', ['linear']];
|
|
175
|
+
colorExpr.push(['band', selectedBand]);
|
|
176
|
+
// Set NoData values to transparent
|
|
177
|
+
colorExpr.push(0.0, [0.0, 0.0, 0.0, 0.0]);
|
|
178
|
+
(_b = stopRowsRef.current) === null || _b === void 0 ? void 0 : _b.map(stop => {
|
|
179
|
+
colorExpr.push(unscaleValue(stop.value));
|
|
180
|
+
colorExpr.push(stop.color);
|
|
181
|
+
});
|
|
182
|
+
break;
|
|
183
|
+
}
|
|
184
|
+
case 'discrete': {
|
|
185
|
+
colorExpr = ['case'];
|
|
186
|
+
// Set NoData values to transparent
|
|
187
|
+
colorExpr.push(['==', ['band', selectedBand], 0]);
|
|
188
|
+
colorExpr.push([0.0, 0.0, 0.0, 0.0]);
|
|
189
|
+
(_c = stopRowsRef.current) === null || _c === void 0 ? void 0 : _c.map(stop => {
|
|
190
|
+
colorExpr.push([
|
|
191
|
+
'<=',
|
|
192
|
+
['band', selectedBand],
|
|
193
|
+
unscaleValue(stop.value)
|
|
194
|
+
]);
|
|
195
|
+
colorExpr.push(stop.color);
|
|
196
|
+
});
|
|
197
|
+
// fallback value
|
|
198
|
+
colorExpr.push([0, 0, 0]);
|
|
199
|
+
break;
|
|
200
|
+
}
|
|
201
|
+
case 'exact': {
|
|
202
|
+
colorExpr = ['case'];
|
|
203
|
+
// Set NoData values to transparent
|
|
204
|
+
colorExpr.push(['==', ['band', selectedBand], 0]);
|
|
205
|
+
colorExpr.push([0.0, 0.0, 0.0, 0.0]);
|
|
206
|
+
(_d = stopRowsRef.current) === null || _d === void 0 ? void 0 : _d.map(stop => {
|
|
207
|
+
colorExpr.push([
|
|
208
|
+
'==',
|
|
209
|
+
['band', selectedBand],
|
|
210
|
+
unscaleValue(stop.value)
|
|
211
|
+
]);
|
|
212
|
+
colorExpr.push(stop.color);
|
|
213
|
+
});
|
|
214
|
+
// fallback value
|
|
215
|
+
colorExpr.push([0, 0, 0]);
|
|
216
|
+
break;
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
layer.parameters.color = colorExpr;
|
|
220
|
+
context.model.sharedModel.updateLayer(layerId, layer);
|
|
221
|
+
cancel();
|
|
222
|
+
};
|
|
223
|
+
okSignalPromise.promise.then(okSignal => {
|
|
224
|
+
okSignal.connect(handleOk);
|
|
225
|
+
});
|
|
226
|
+
const addStopRow = () => {
|
|
227
|
+
setStopRows([
|
|
228
|
+
{
|
|
229
|
+
value: 0,
|
|
230
|
+
color: [0, 0, 0, 1]
|
|
231
|
+
},
|
|
232
|
+
...stopRows
|
|
233
|
+
]);
|
|
234
|
+
};
|
|
235
|
+
const deleteStopRow = (index) => {
|
|
236
|
+
const newFilters = [...stopRows];
|
|
237
|
+
newFilters.splice(index, 1);
|
|
238
|
+
setStopRows(newFilters);
|
|
239
|
+
};
|
|
240
|
+
const scaleValue = (bandValue) => {
|
|
241
|
+
const currentBand = bandRows[selectedBand - 1];
|
|
242
|
+
if (!currentBand) {
|
|
243
|
+
return bandValue;
|
|
244
|
+
}
|
|
245
|
+
return ((bandValue * (currentBand.stats.maximum - currentBand.stats.minimum)) /
|
|
246
|
+
(1 - 0) +
|
|
247
|
+
currentBand.stats.minimum);
|
|
248
|
+
};
|
|
249
|
+
const unscaleValue = (value) => {
|
|
250
|
+
const currentBand = bandRowsRef.current[selectedBand - 1];
|
|
251
|
+
return ((value * (1 - 0) - currentBand.stats.minimum * (1 - 0)) /
|
|
252
|
+
(currentBand.stats.maximum - currentBand.stats.minimum));
|
|
253
|
+
};
|
|
254
|
+
return (React.createElement("div", { className: "jp-gis-layer-symbology-container" },
|
|
255
|
+
React.createElement("div", { className: "jp-gis-band-container" }, bandRows.length === 0 ? (React.createElement(FontAwesomeIcon, { icon: faSpinner })) : (React.createElement(BandRow
|
|
256
|
+
// Band numbers are 1 indexed
|
|
257
|
+
, {
|
|
258
|
+
// Band numbers are 1 indexed
|
|
259
|
+
index: selectedBand - 1, bandRow: bandRows[selectedBand - 1], bandRows: bandRows, setSelectedBand: setSelectedBand, setBandRows: setBandRows }))),
|
|
260
|
+
React.createElement("div", { className: "jp-gis-symbology-row" },
|
|
261
|
+
React.createElement("label", { htmlFor: "function-select" }, "Interpolation:"),
|
|
262
|
+
React.createElement("div", { className: "jp-select-wrapper" },
|
|
263
|
+
React.createElement("select", { name: "function-select", id: "function-select", className: "jp-mod-styled", value: selectedFunction, style: { textTransform: 'capitalize' }, onChange: event => {
|
|
264
|
+
setSelectedFunction(event.target.value);
|
|
265
|
+
} }, functions.map((func, funcIndex) => (React.createElement("option", { key: func, value: func, style: { textTransform: 'capitalize' } }, func)))))),
|
|
266
|
+
React.createElement("div", { className: "jp-gis-stop-container" },
|
|
267
|
+
React.createElement("div", { className: "jp-gis-stop-labels", style: { display: 'flex', gap: 6 } },
|
|
268
|
+
React.createElement("span", { style: { flex: '0 0 18%' } },
|
|
269
|
+
"Value",
|
|
270
|
+
' ',
|
|
271
|
+
selectedFunction === 'discrete'
|
|
272
|
+
? '<='
|
|
273
|
+
: selectedFunction === 'exact'
|
|
274
|
+
? '='
|
|
275
|
+
: ''),
|
|
276
|
+
React.createElement("span", null, "Output Value")),
|
|
277
|
+
stopRows.map((stop, index) => (React.createElement(StopRow, { key: `${index}-${stop.color}`, index: index, value: stop.value, outputValue: stop.color, stopRows: stopRows, setStopRows: setStopRows, deleteRow: () => deleteStopRow(index) })))),
|
|
278
|
+
React.createElement("div", { className: "jp-gis-symbology-button-container" },
|
|
279
|
+
React.createElement(Button, { className: "jp-Dialog-button jp-mod-accept jp-mod-styled", onClick: addStopRow }, "Add Stop"))));
|
|
280
|
+
};
|
|
281
|
+
export default SingleBandPseudoColor;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { IStopRow } from './SingleBandPseudoColor';
|
|
3
|
+
declare const StopRow: ({ index, value, outputValue, stopRows, setStopRows, deleteRow }: {
|
|
4
|
+
index: number;
|
|
5
|
+
value: number;
|
|
6
|
+
outputValue: number[];
|
|
7
|
+
stopRows: IStopRow[];
|
|
8
|
+
setStopRows: (stopRows: IStopRow[]) => void;
|
|
9
|
+
deleteRow: () => void;
|
|
10
|
+
}) => React.JSX.Element;
|
|
11
|
+
export default StopRow;
|