@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.
Files changed (108) hide show
  1. package/lib/commands.d.ts +11 -0
  2. package/lib/commands.js +809 -0
  3. package/lib/console/consoleview.d.ts +24 -0
  4. package/lib/console/consoleview.js +55 -0
  5. package/lib/console/index.d.ts +1 -0
  6. package/lib/console/index.js +1 -0
  7. package/lib/constants.d.ts +57 -0
  8. package/lib/constants.js +89 -0
  9. package/lib/dialogs/components/symbology/BandRendering.d.ts +4 -0
  10. package/lib/dialogs/components/symbology/BandRendering.js +29 -0
  11. package/lib/dialogs/components/symbology/BandRow.d.ts +10 -0
  12. package/lib/dialogs/components/symbology/BandRow.js +43 -0
  13. package/lib/dialogs/components/symbology/SingleBandPseudoColor.d.ts +20 -0
  14. package/lib/dialogs/components/symbology/SingleBandPseudoColor.js +281 -0
  15. package/lib/dialogs/components/symbology/StopRow.d.ts +11 -0
  16. package/lib/dialogs/components/symbology/StopRow.js +58 -0
  17. package/lib/dialogs/formdialog.d.ts +31 -0
  18. package/lib/dialogs/formdialog.js +68 -0
  19. package/lib/dialogs/layerBrowserDialog.d.ts +25 -0
  20. package/lib/dialogs/layerBrowserDialog.js +141 -0
  21. package/lib/dialogs/symbologyDialog.d.ts +23 -0
  22. package/lib/dialogs/symbologyDialog.js +68 -0
  23. package/lib/dialogs/terrainDialog.d.ts +21 -0
  24. package/lib/dialogs/terrainDialog.js +60 -0
  25. package/lib/formbuilder/creationform.d.ts +56 -0
  26. package/lib/formbuilder/creationform.js +117 -0
  27. package/lib/formbuilder/editform.d.ts +24 -0
  28. package/lib/formbuilder/editform.js +60 -0
  29. package/lib/formbuilder/formselectors.d.ts +5 -0
  30. package/lib/formbuilder/formselectors.js +38 -0
  31. package/lib/formbuilder/index.d.ts +6 -0
  32. package/lib/formbuilder/index.js +6 -0
  33. package/lib/formbuilder/objectform/baseform.d.ts +79 -0
  34. package/lib/formbuilder/objectform/baseform.js +167 -0
  35. package/lib/formbuilder/objectform/geojsonsource.d.ts +19 -0
  36. package/lib/formbuilder/objectform/geojsonsource.js +80 -0
  37. package/lib/formbuilder/objectform/hillshadeLayerForm.d.ts +8 -0
  38. package/lib/formbuilder/objectform/hillshadeLayerForm.js +12 -0
  39. package/lib/formbuilder/objectform/layerform.d.ts +19 -0
  40. package/lib/formbuilder/objectform/layerform.js +17 -0
  41. package/lib/formbuilder/objectform/tilesourceform.d.ts +7 -0
  42. package/lib/formbuilder/objectform/tilesourceform.js +60 -0
  43. package/lib/formbuilder/objectform/vectorlayerform.d.ts +15 -0
  44. package/lib/formbuilder/objectform/vectorlayerform.js +88 -0
  45. package/lib/formbuilder/objectform/webGlLayerForm.d.ts +8 -0
  46. package/lib/formbuilder/objectform/webGlLayerForm.js +10 -0
  47. package/lib/icons.d.ts +6 -0
  48. package/lib/icons.js +31 -0
  49. package/lib/index.d.ts +10 -0
  50. package/lib/index.js +10 -0
  51. package/lib/mainview/index.d.ts +3 -0
  52. package/lib/mainview/index.js +3 -0
  53. package/lib/mainview/mainView.d.ts +113 -0
  54. package/lib/mainview/mainView.js +743 -0
  55. package/lib/mainview/mainviewmodel.d.ts +24 -0
  56. package/lib/mainview/mainviewmodel.js +34 -0
  57. package/lib/mainview/mainviewwidget.d.ts +14 -0
  58. package/lib/mainview/mainviewwidget.js +18 -0
  59. package/lib/mainview/spinner.d.ts +6 -0
  60. package/lib/mainview/spinner.js +5 -0
  61. package/lib/panelview/components/filter-panel/Filter.d.ts +19 -0
  62. package/lib/panelview/components/filter-panel/Filter.js +223 -0
  63. package/lib/panelview/components/filter-panel/FilterRow.d.ts +9 -0
  64. package/lib/panelview/components/filter-panel/FilterRow.js +61 -0
  65. package/lib/panelview/components/layers.d.ts +13 -0
  66. package/lib/panelview/components/layers.js +275 -0
  67. package/lib/panelview/components/sources.d.ts +10 -0
  68. package/lib/panelview/components/sources.js +147 -0
  69. package/lib/panelview/header.d.ts +11 -0
  70. package/lib/panelview/header.js +20 -0
  71. package/lib/panelview/index.d.ts +5 -0
  72. package/lib/panelview/index.js +5 -0
  73. package/lib/panelview/leftpanel.d.ts +51 -0
  74. package/lib/panelview/leftpanel.js +125 -0
  75. package/lib/panelview/model.d.ts +19 -0
  76. package/lib/panelview/model.js +30 -0
  77. package/lib/panelview/objectproperties.d.ts +17 -0
  78. package/lib/panelview/objectproperties.js +92 -0
  79. package/lib/panelview/rightpanel.d.ts +19 -0
  80. package/lib/panelview/rightpanel.js +45 -0
  81. package/lib/toolbar/index.d.ts +2 -0
  82. package/lib/toolbar/index.js +2 -0
  83. package/lib/toolbar/usertoolbaritem.d.ts +19 -0
  84. package/lib/toolbar/usertoolbaritem.js +57 -0
  85. package/lib/toolbar/widget.d.ts +22 -0
  86. package/lib/toolbar/widget.js +104 -0
  87. package/lib/tools.d.ts +25 -0
  88. package/lib/tools.js +215 -0
  89. package/lib/types.d.ts +11 -0
  90. package/lib/types.js +1 -0
  91. package/lib/widget.d.ts +49 -0
  92. package/lib/widget.js +144 -0
  93. package/package.json +95 -0
  94. package/style/base.css +55 -0
  95. package/style/colorExpression.css +36 -0
  96. package/style/dialog.css +8 -0
  97. package/style/filterPanel.css +70 -0
  98. package/style/icons/geojson.svg +12 -0
  99. package/style/icons/mound.svg +9 -0
  100. package/style/icons/nonvisibility.svg +8 -0
  101. package/style/icons/raster.svg +5 -0
  102. package/style/icons/visibility.svg +7 -0
  103. package/style/index.css +6 -0
  104. package/style/index.js +6 -0
  105. package/style/layerBrowser.css +256 -0
  106. package/style/leftPanel.css +150 -0
  107. package/style/symbologyDialog.css +86 -0
  108. 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 {};
@@ -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,4 @@
1
+ import React from 'react';
2
+ import { ISymbologyDialogProps } from '../../symbologyDialog';
3
+ declare const BandRendering: ({ context, state, okSignalPromise, cancel, layerId }: ISymbologyDialogProps) => React.JSX.Element;
4
+ export default BandRendering;
@@ -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;