@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,58 @@
|
|
|
1
|
+
import { faTrash } from '@fortawesome/free-solid-svg-icons';
|
|
2
|
+
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
|
3
|
+
import { Button } from '@jupyterlab/ui-components';
|
|
4
|
+
import React from 'react';
|
|
5
|
+
const StopRow = ({ index, value, outputValue, stopRows, setStopRows, deleteRow }) => {
|
|
6
|
+
const rgbArrToHex = (rgbArr) => {
|
|
7
|
+
const hex = rgbArr
|
|
8
|
+
.slice(0, -1) // Color input doesn't support hex alpha values so cut that out
|
|
9
|
+
.map((val) => {
|
|
10
|
+
return val.toString(16).padStart(2, '0');
|
|
11
|
+
})
|
|
12
|
+
.join('');
|
|
13
|
+
return '#' + hex;
|
|
14
|
+
};
|
|
15
|
+
const hexToRgb = (hex) => {
|
|
16
|
+
const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
|
|
17
|
+
if (!result) {
|
|
18
|
+
console.warn('Unable to parse hex value, defaulting to black');
|
|
19
|
+
return [parseInt('0', 16), parseInt('0', 16), parseInt('0', 16)];
|
|
20
|
+
}
|
|
21
|
+
const rgbValues = [
|
|
22
|
+
parseInt(result[1], 16),
|
|
23
|
+
parseInt(result[2], 16),
|
|
24
|
+
parseInt(result[3], 16),
|
|
25
|
+
1 // TODO: Make alpha customizable?
|
|
26
|
+
];
|
|
27
|
+
return rgbValues;
|
|
28
|
+
};
|
|
29
|
+
const handleValueChange = (event) => {
|
|
30
|
+
const newRows = [...stopRows];
|
|
31
|
+
newRows[index].value = +event.target.value;
|
|
32
|
+
setStopRows(newRows);
|
|
33
|
+
};
|
|
34
|
+
const handleBlur = () => {
|
|
35
|
+
const newRows = [...stopRows];
|
|
36
|
+
newRows.sort((a, b) => {
|
|
37
|
+
if (a.value < b.value) {
|
|
38
|
+
return -1;
|
|
39
|
+
}
|
|
40
|
+
if (a.value > b.value) {
|
|
41
|
+
return 1;
|
|
42
|
+
}
|
|
43
|
+
return 0;
|
|
44
|
+
});
|
|
45
|
+
setStopRows(newRows);
|
|
46
|
+
};
|
|
47
|
+
const handleColorChange = (event) => {
|
|
48
|
+
const newRows = [...stopRows];
|
|
49
|
+
newRows[index].color = hexToRgb(event.target.value);
|
|
50
|
+
setStopRows(newRows);
|
|
51
|
+
};
|
|
52
|
+
return (React.createElement("div", { className: "jp-gis-color-row" },
|
|
53
|
+
React.createElement("input", { id: `jp-gis-color-value-${index}`, type: "number", value: value, onChange: handleValueChange, onBlur: handleBlur, className: "jp-mod-styled" }),
|
|
54
|
+
React.createElement("input", { id: `jp-gis-color-color-${index}`, value: rgbArrToHex(outputValue), type: "color", onChange: handleColorChange, className: "jp-mod-styled" }),
|
|
55
|
+
React.createElement(Button, { id: `jp-gis-remove-color-${index}`, className: "jp-Button jp-gis-filter-icon" },
|
|
56
|
+
React.createElement(FontAwesomeIcon, { icon: faTrash, onClick: deleteRow }))));
|
|
57
|
+
};
|
|
58
|
+
export default StopRow;
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { IDict } from '@jupytergis/schema';
|
|
2
|
+
import { Dialog } from '@jupyterlab/apputils';
|
|
3
|
+
import * as React from 'react';
|
|
4
|
+
import { ICreationFormProps } from '../formbuilder';
|
|
5
|
+
import { Signal } from '@lumino/signaling';
|
|
6
|
+
import { PromiseDelegate } from '@lumino/coreutils';
|
|
7
|
+
export interface ICreationFormWrapperProps extends ICreationFormProps {
|
|
8
|
+
/**
|
|
9
|
+
* A promise resolving when the dialog is ready.
|
|
10
|
+
* Return a signal emitting when OK button is pressed.
|
|
11
|
+
*/
|
|
12
|
+
okSignalPromise: PromiseDelegate<Signal<Dialog<any>, number>>;
|
|
13
|
+
/**
|
|
14
|
+
* A promise resolving when the dialog is ready.
|
|
15
|
+
* Return a signal emitting when the form changed, with a boolean whether there are
|
|
16
|
+
* some extra errors or not.
|
|
17
|
+
*/
|
|
18
|
+
formErrorSignalPromise?: PromiseDelegate<Signal<Dialog<any>, boolean>>;
|
|
19
|
+
}
|
|
20
|
+
export interface ICreationFormDialogOptions extends ICreationFormProps {
|
|
21
|
+
title: string;
|
|
22
|
+
}
|
|
23
|
+
export declare const CreationFormWrapper: (props: ICreationFormWrapperProps) => false | React.JSX.Element;
|
|
24
|
+
/**
|
|
25
|
+
* Form for creating a source, a layer or both at the same time
|
|
26
|
+
*/
|
|
27
|
+
export declare class CreationFormDialog extends Dialog<IDict> {
|
|
28
|
+
constructor(options: ICreationFormDialogOptions);
|
|
29
|
+
resolve(index?: number): void;
|
|
30
|
+
private okSignal;
|
|
31
|
+
}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { Dialog } from '@jupyterlab/apputils';
|
|
2
|
+
import * as React from 'react';
|
|
3
|
+
import { CreationForm } from '../formbuilder';
|
|
4
|
+
import { Signal } from '@lumino/signaling';
|
|
5
|
+
import { PromiseDelegate } from '@lumino/coreutils';
|
|
6
|
+
export const CreationFormWrapper = (props) => {
|
|
7
|
+
var _a;
|
|
8
|
+
const [ready, setReady] = React.useState(false);
|
|
9
|
+
const okSignal = React.useRef();
|
|
10
|
+
const formErrorSignal = React.useRef();
|
|
11
|
+
Promise.all([
|
|
12
|
+
props.okSignalPromise.promise,
|
|
13
|
+
(_a = props.formErrorSignalPromise) === null || _a === void 0 ? void 0 : _a.promise
|
|
14
|
+
]).then(([ok, formChanged]) => {
|
|
15
|
+
okSignal.current = ok;
|
|
16
|
+
formErrorSignal.current = formChanged;
|
|
17
|
+
setReady(true);
|
|
18
|
+
});
|
|
19
|
+
return (ready && (React.createElement(CreationForm, { context: props.context, formSchemaRegistry: props.formSchemaRegistry, createLayer: props.createLayer, createSource: props.createSource, layerType: props.layerType, sourceType: props.sourceType, sourceData: props.sourceData, layerData: props.layerData, ok: okSignal.current, cancel: props.cancel, formErrorSignal: formErrorSignal.current })));
|
|
20
|
+
};
|
|
21
|
+
/**
|
|
22
|
+
* Form for creating a source, a layer or both at the same time
|
|
23
|
+
*/
|
|
24
|
+
export class CreationFormDialog extends Dialog {
|
|
25
|
+
constructor(options) {
|
|
26
|
+
const cancelCallback = () => {
|
|
27
|
+
this.resolve(0);
|
|
28
|
+
};
|
|
29
|
+
const okSignalPromise = new PromiseDelegate();
|
|
30
|
+
const formErrorSignalPromise = new PromiseDelegate();
|
|
31
|
+
const body = (React.createElement("div", { style: { overflow: 'auto' } },
|
|
32
|
+
React.createElement(CreationFormWrapper, { context: options.context, formSchemaRegistry: options.formSchemaRegistry, createLayer: options.createLayer, createSource: options.createSource, layerType: options.layerType, sourceType: options.sourceType, sourceData: options.sourceData, layerData: options.layerData, okSignalPromise: okSignalPromise, cancel: cancelCallback, formErrorSignalPromise: formErrorSignalPromise })));
|
|
33
|
+
super({
|
|
34
|
+
title: options.title,
|
|
35
|
+
body,
|
|
36
|
+
buttons: [Dialog.cancelButton(), Dialog.okButton()]
|
|
37
|
+
});
|
|
38
|
+
this.okSignal = new Signal(this);
|
|
39
|
+
const formErrorSignal = new Signal(this);
|
|
40
|
+
/**
|
|
41
|
+
* Disable the OK button if the form is invalid.
|
|
42
|
+
*/
|
|
43
|
+
formErrorSignal.connect((_, extraErrors) => {
|
|
44
|
+
const invalid = extraErrors || !!this.node.querySelector(':invalid');
|
|
45
|
+
if (invalid) {
|
|
46
|
+
this.node
|
|
47
|
+
.getElementsByClassName('jp-mod-accept')[0]
|
|
48
|
+
.setAttribute('disabled', '');
|
|
49
|
+
}
|
|
50
|
+
else {
|
|
51
|
+
this.node
|
|
52
|
+
.getElementsByClassName('jp-mod-accept')[0]
|
|
53
|
+
.removeAttribute('disabled');
|
|
54
|
+
}
|
|
55
|
+
});
|
|
56
|
+
okSignalPromise.resolve(this.okSignal);
|
|
57
|
+
formErrorSignalPromise.resolve(formErrorSignal);
|
|
58
|
+
this.addClass('jGIS-layer-CreationFormDialog');
|
|
59
|
+
}
|
|
60
|
+
resolve(index) {
|
|
61
|
+
if (index === 0) {
|
|
62
|
+
super.resolve(index);
|
|
63
|
+
}
|
|
64
|
+
if (index === 1) {
|
|
65
|
+
this.okSignal.emit(1);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { IJGISFormSchemaRegistry, IJupyterGISModel, IRasterLayerGalleryEntry } from '@jupytergis/schema';
|
|
2
|
+
import { Dialog } from '@jupyterlab/apputils';
|
|
3
|
+
import { PromiseDelegate } from '@lumino/coreutils';
|
|
4
|
+
import React from 'react';
|
|
5
|
+
import { DocumentRegistry } from '@jupyterlab/docregistry';
|
|
6
|
+
import { Signal } from '@lumino/signaling';
|
|
7
|
+
interface ILayerBrowserDialogProps {
|
|
8
|
+
context: DocumentRegistry.IContext<IJupyterGISModel>;
|
|
9
|
+
registry: IRasterLayerGalleryEntry[];
|
|
10
|
+
formSchemaRegistry: IJGISFormSchemaRegistry;
|
|
11
|
+
okSignalPromise: PromiseDelegate<Signal<Dialog<any>, number>>;
|
|
12
|
+
cancel: () => void;
|
|
13
|
+
}
|
|
14
|
+
export declare const LayerBrowserComponent: ({ context, registry, formSchemaRegistry, okSignalPromise, cancel }: ILayerBrowserDialogProps) => React.JSX.Element;
|
|
15
|
+
export interface ILayerBrowserOptions {
|
|
16
|
+
context: DocumentRegistry.IContext<IJupyterGISModel>;
|
|
17
|
+
registry: IRasterLayerGalleryEntry[];
|
|
18
|
+
formSchemaRegistry: IJGISFormSchemaRegistry;
|
|
19
|
+
}
|
|
20
|
+
export declare class LayerBrowserWidget extends Dialog<boolean> {
|
|
21
|
+
constructor(options: ILayerBrowserOptions);
|
|
22
|
+
resolve(index?: number): void;
|
|
23
|
+
private okSignal;
|
|
24
|
+
}
|
|
25
|
+
export {};
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
import { faCheck, faPlus } from '@fortawesome/free-solid-svg-icons';
|
|
2
|
+
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
|
3
|
+
import { Dialog } from '@jupyterlab/apputils';
|
|
4
|
+
import { PromiseDelegate, UUID } from '@lumino/coreutils';
|
|
5
|
+
import React, { useEffect, useState } from 'react';
|
|
6
|
+
import CUSTOM_RASTER_IMAGE from '../../rasterlayer_gallery/custom_raster.png';
|
|
7
|
+
import { CreationFormWrapper } from './formdialog';
|
|
8
|
+
import { Signal } from '@lumino/signaling';
|
|
9
|
+
export const LayerBrowserComponent = ({ context, registry, formSchemaRegistry, okSignalPromise, cancel }) => {
|
|
10
|
+
const [searchTerm, setSearchTerm] = useState('');
|
|
11
|
+
const [activeLayers, setActiveLayers] = useState([]);
|
|
12
|
+
const [selectedCategory, setSelectedCategory] = useState();
|
|
13
|
+
const [creatingCustomRaster, setCreatingCustomRaster] = useState(false);
|
|
14
|
+
const [galleryWithCategory, setGalleryWithCategory] = useState(registry);
|
|
15
|
+
const providers = [...new Set(registry.map(item => item.source.provider))];
|
|
16
|
+
const filteredGallery = galleryWithCategory.filter(item => item.name.toLowerCase().includes(searchTerm));
|
|
17
|
+
useEffect(() => {
|
|
18
|
+
context.model.sharedModel.layersChanged.connect(handleLayerChange);
|
|
19
|
+
return () => {
|
|
20
|
+
context.model.sharedModel.layersChanged.disconnect(handleLayerChange);
|
|
21
|
+
};
|
|
22
|
+
}, []);
|
|
23
|
+
/**
|
|
24
|
+
* Track which layers are currently added to the map
|
|
25
|
+
*/
|
|
26
|
+
const handleLayerChange = (_, change) => {
|
|
27
|
+
// The split is to get rid of the 'Layer' part of the name to match the names in the gallery
|
|
28
|
+
setActiveLayers(Object.values(context.model.sharedModel.layers).map(layer => layer.name.split(' ')[0]));
|
|
29
|
+
};
|
|
30
|
+
const handleSearchInput = (event) => {
|
|
31
|
+
setSearchTerm(event.target.value.toLowerCase());
|
|
32
|
+
};
|
|
33
|
+
const handleCategoryClick = (event) => {
|
|
34
|
+
const categoryTab = event.target;
|
|
35
|
+
const sameAsOld = categoryTab.innerText === (selectedCategory === null || selectedCategory === void 0 ? void 0 : selectedCategory.innerText);
|
|
36
|
+
categoryTab.classList.toggle('jGIS-layer-browser-category-selected');
|
|
37
|
+
selectedCategory === null || selectedCategory === void 0 ? void 0 : selectedCategory.classList.remove('jGIS-layer-browser-category-selected');
|
|
38
|
+
const filteredGallery = sameAsOld
|
|
39
|
+
? registry
|
|
40
|
+
: registry.filter(item => { var _a; return (_a = item.source.provider) === null || _a === void 0 ? void 0 : _a.includes(categoryTab.innerText); });
|
|
41
|
+
setGalleryWithCategory(filteredGallery);
|
|
42
|
+
setSearchTerm('');
|
|
43
|
+
setSelectedCategory(sameAsOld ? null : categoryTab);
|
|
44
|
+
};
|
|
45
|
+
const handleCustomTileClick = () => {
|
|
46
|
+
setCreatingCustomRaster(true);
|
|
47
|
+
};
|
|
48
|
+
/**
|
|
49
|
+
* Add tile layer and source to model
|
|
50
|
+
* @param tile Tile to add
|
|
51
|
+
*/
|
|
52
|
+
const handleTileClick = (tile) => {
|
|
53
|
+
const sourceId = UUID.uuid4();
|
|
54
|
+
const sourceModel = {
|
|
55
|
+
type: 'RasterSource',
|
|
56
|
+
name: tile.name,
|
|
57
|
+
parameters: tile.source
|
|
58
|
+
};
|
|
59
|
+
const layerModel = {
|
|
60
|
+
type: 'RasterLayer',
|
|
61
|
+
parameters: {
|
|
62
|
+
source: sourceId
|
|
63
|
+
},
|
|
64
|
+
visible: true,
|
|
65
|
+
name: tile.name + ' Layer'
|
|
66
|
+
};
|
|
67
|
+
context.model.sharedModel.addSource(sourceId, sourceModel);
|
|
68
|
+
context.model.addLayer(UUID.uuid4(), layerModel);
|
|
69
|
+
};
|
|
70
|
+
if (creatingCustomRaster) {
|
|
71
|
+
// Disconnect any previous handler
|
|
72
|
+
okSignalPromise.promise.then(value => {
|
|
73
|
+
value.disconnect(cancel, this);
|
|
74
|
+
});
|
|
75
|
+
return (React.createElement("div", { className: "jGIS-customlayer-form" },
|
|
76
|
+
React.createElement(CreationFormWrapper, { context: context, formSchemaRegistry: formSchemaRegistry, createLayer: true, createSource: true, layerType: 'RasterLayer', sourceType: 'RasterSource', layerData: {
|
|
77
|
+
name: 'Custom Raster'
|
|
78
|
+
}, sourceData: {
|
|
79
|
+
url: 'https://tile.openstreetmap.org/{z}/{x}/{y}.png',
|
|
80
|
+
maxZoom: 24,
|
|
81
|
+
minZoom: 0,
|
|
82
|
+
attribution: '(C) OpenStreetMap contributors'
|
|
83
|
+
}, okSignalPromise: okSignalPromise, cancel: cancel })));
|
|
84
|
+
}
|
|
85
|
+
// Ok is like cancel in the case of gallery item selections
|
|
86
|
+
okSignalPromise.promise.then(value => {
|
|
87
|
+
value.connect(cancel, this);
|
|
88
|
+
});
|
|
89
|
+
return (React.createElement("div", { className: "jGIS-layer-browser-container" },
|
|
90
|
+
React.createElement("div", { className: "jGIS-layer-browser-header-container" },
|
|
91
|
+
React.createElement("div", { className: "jGIS-layer-browser-header" },
|
|
92
|
+
React.createElement("h2", { className: "jGIS-layer-browser-header-text" }, "Layer Browser"),
|
|
93
|
+
React.createElement("div", { className: "jGIS-layer-browser-header-search-container" },
|
|
94
|
+
React.createElement("input", { type: "text", placeholder: "Search...", value: searchTerm, onChange: handleSearchInput, className: "jGIS-layer-browser-header-search" }))),
|
|
95
|
+
React.createElement("div", { className: "jGIS-layer-browser-categories" }, providers.map(provider => (React.createElement("span", { className: "jGIS-layer-browser-category", onClick: handleCategoryClick }, provider))))),
|
|
96
|
+
React.createElement("div", { className: "jGIS-layer-browser-grid" },
|
|
97
|
+
React.createElement("div", { className: "jGIS-layer-browser-tile jGIS-layer-browser-custom-tile", onClick: () => handleCustomTileClick() },
|
|
98
|
+
React.createElement("div", { className: "jGIS-layer-browser-tile-img-container" },
|
|
99
|
+
React.createElement("img", { className: "jGIS-layer-browser-img", src: CUSTOM_RASTER_IMAGE }),
|
|
100
|
+
React.createElement("div", { className: "jGIS-layer-browser-icon" },
|
|
101
|
+
React.createElement(FontAwesomeIcon, { style: { height: 20 }, icon: faPlus }))),
|
|
102
|
+
React.createElement("div", { className: "jGIS-layer-browser-text-container" },
|
|
103
|
+
React.createElement("div", { className: "jGIS-layer-browser-text-info" },
|
|
104
|
+
React.createElement("h3", { className: "jGIS-layer-browser-text-header jGIS-layer-browser-text-general" }, "Custom Raster Layer")),
|
|
105
|
+
React.createElement("p", { className: "jGIS-layer-browser-text-general jGIS-layer-browser-text-source" }, "Create A Custom Raster Layer"))),
|
|
106
|
+
filteredGallery.map(tile => (React.createElement("div", { className: "jGIS-layer-browser-tile", onClick: () => handleTileClick(tile) },
|
|
107
|
+
React.createElement("div", { className: "jGIS-layer-browser-tile-img-container" },
|
|
108
|
+
React.createElement("img", { className: "jGIS-layer-browser-img", src: tile.thumbnail }),
|
|
109
|
+
activeLayers.indexOf(tile.name) === -1 ? (React.createElement("div", { className: "jGIS-layer-browser-icon" },
|
|
110
|
+
React.createElement(FontAwesomeIcon, { style: { height: 20 }, icon: faPlus }))) : (React.createElement("div", { className: "jGIS-layer-browser-icon jGIS-layer-browser-added" },
|
|
111
|
+
React.createElement(FontAwesomeIcon, { style: { height: 20 }, icon: faCheck }),
|
|
112
|
+
React.createElement("p", { className: "jGIS-layer-browser-text-general" }, "Added!")))),
|
|
113
|
+
React.createElement("div", { className: "jGIS-layer-browser-text-container" },
|
|
114
|
+
React.createElement("div", { className: "jGIS-layer-browser-text-info" },
|
|
115
|
+
React.createElement("h3", { className: "jGIS-layer-browser-text-header jGIS-layer-browser-text-general" }, tile.name)),
|
|
116
|
+
React.createElement("p", { className: "jGIS-layer-browser-text-general jGIS-layer-browser-text-source" }, tile.source.attribution))))))));
|
|
117
|
+
};
|
|
118
|
+
export class LayerBrowserWidget extends Dialog {
|
|
119
|
+
constructor(options) {
|
|
120
|
+
let cancelCallback = undefined;
|
|
121
|
+
cancelCallback = () => {
|
|
122
|
+
this.resolve(0);
|
|
123
|
+
};
|
|
124
|
+
const okSignalPromise = new PromiseDelegate();
|
|
125
|
+
const body = (React.createElement(LayerBrowserComponent, { context: options.context, registry: options.registry, formSchemaRegistry: options.formSchemaRegistry, okSignalPromise: okSignalPromise, cancel: cancelCallback }));
|
|
126
|
+
super({ body, buttons: [Dialog.cancelButton(), Dialog.okButton()] });
|
|
127
|
+
this.id = 'jupytergis::layerBrowser';
|
|
128
|
+
this.okSignal = new Signal(this);
|
|
129
|
+
okSignalPromise.resolve(this.okSignal);
|
|
130
|
+
// Override default dialog style
|
|
131
|
+
this.addClass('jGIS-layerbrowser-FormDialog');
|
|
132
|
+
}
|
|
133
|
+
resolve(index) {
|
|
134
|
+
if (index === 0) {
|
|
135
|
+
super.resolve(index);
|
|
136
|
+
}
|
|
137
|
+
if (index === 1) {
|
|
138
|
+
this.okSignal.emit(1);
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { IJupyterGISModel } from '@jupytergis/schema';
|
|
2
|
+
import { Dialog } from '@jupyterlab/apputils';
|
|
3
|
+
import { DocumentRegistry } from '@jupyterlab/docregistry';
|
|
4
|
+
import { IStateDB } from '@jupyterlab/statedb';
|
|
5
|
+
import { PromiseDelegate } from '@lumino/coreutils';
|
|
6
|
+
import { Signal } from '@lumino/signaling';
|
|
7
|
+
export interface ISymbologyDialogProps {
|
|
8
|
+
context: DocumentRegistry.IContext<IJupyterGISModel>;
|
|
9
|
+
state: IStateDB;
|
|
10
|
+
okSignalPromise: PromiseDelegate<Signal<SymbologyWidget, null>>;
|
|
11
|
+
cancel: () => void;
|
|
12
|
+
layerId?: string;
|
|
13
|
+
}
|
|
14
|
+
export interface ISymbologyWidgetOptions {
|
|
15
|
+
context: DocumentRegistry.IContext<IJupyterGISModel>;
|
|
16
|
+
state: IStateDB;
|
|
17
|
+
}
|
|
18
|
+
export declare class SymbologyWidget extends Dialog<boolean> {
|
|
19
|
+
private okSignal;
|
|
20
|
+
constructor(options: ISymbologyWidgetOptions);
|
|
21
|
+
resolve(index: number): void;
|
|
22
|
+
}
|
|
23
|
+
export default SymbologyWidget;
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { Dialog } from '@jupyterlab/apputils';
|
|
2
|
+
import { PromiseDelegate } from '@lumino/coreutils';
|
|
3
|
+
import { Signal } from '@lumino/signaling';
|
|
4
|
+
import React, { useEffect, useState } from 'react';
|
|
5
|
+
import BandRendering from './components/symbology/BandRendering';
|
|
6
|
+
const SymbologyDialog = ({ context, state, okSignalPromise, cancel }) => {
|
|
7
|
+
const [selectedLayer, setSelectedLayer] = useState(null);
|
|
8
|
+
const [componentToRender, setComponentToRender] = useState(null);
|
|
9
|
+
let LayerSymbology;
|
|
10
|
+
useEffect(() => {
|
|
11
|
+
const handleClientStateChanged = () => {
|
|
12
|
+
var _a, _b;
|
|
13
|
+
if (!((_b = (_a = context.model.localState) === null || _a === void 0 ? void 0 : _a.selected) === null || _b === void 0 ? void 0 : _b.value)) {
|
|
14
|
+
return;
|
|
15
|
+
}
|
|
16
|
+
const currentLayer = Object.keys(context.model.localState.selected.value)[0];
|
|
17
|
+
setSelectedLayer(currentLayer);
|
|
18
|
+
};
|
|
19
|
+
// Initial state
|
|
20
|
+
handleClientStateChanged();
|
|
21
|
+
context.model.clientStateChanged.connect(handleClientStateChanged);
|
|
22
|
+
return () => {
|
|
23
|
+
context.model.clientStateChanged.disconnect(handleClientStateChanged);
|
|
24
|
+
};
|
|
25
|
+
}, []);
|
|
26
|
+
useEffect(() => {
|
|
27
|
+
if (!selectedLayer) {
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
const layer = context.model.getLayer(selectedLayer);
|
|
31
|
+
if (!layer) {
|
|
32
|
+
return;
|
|
33
|
+
}
|
|
34
|
+
// TODO WebGlLayers can also be used for other layers, need a better way to determine source + layer combo
|
|
35
|
+
switch (layer.type) {
|
|
36
|
+
case 'WebGlLayer':
|
|
37
|
+
LayerSymbology = (React.createElement(BandRendering, { context: context, state: state, okSignalPromise: okSignalPromise, cancel: cancel, layerId: selectedLayer }));
|
|
38
|
+
break;
|
|
39
|
+
default:
|
|
40
|
+
LayerSymbology = React.createElement("div", null, "Layer Type Not Supported");
|
|
41
|
+
}
|
|
42
|
+
setComponentToRender(LayerSymbology);
|
|
43
|
+
}, [selectedLayer]);
|
|
44
|
+
return React.createElement(React.Fragment, null, componentToRender);
|
|
45
|
+
};
|
|
46
|
+
export class SymbologyWidget extends Dialog {
|
|
47
|
+
constructor(options) {
|
|
48
|
+
const cancelCallback = () => {
|
|
49
|
+
this.resolve(0);
|
|
50
|
+
};
|
|
51
|
+
const okSignalPromise = new PromiseDelegate();
|
|
52
|
+
const body = (React.createElement(SymbologyDialog, { context: options.context, okSignalPromise: okSignalPromise, cancel: cancelCallback, state: options.state }));
|
|
53
|
+
super({ title: 'Symbology', body });
|
|
54
|
+
this.id = 'jupytergis::symbologyWidget';
|
|
55
|
+
this.okSignal = new Signal(this);
|
|
56
|
+
okSignalPromise.resolve(this.okSignal);
|
|
57
|
+
this.addClass('jp-gis-symbology-dialog');
|
|
58
|
+
}
|
|
59
|
+
resolve(index) {
|
|
60
|
+
if (index === 0) {
|
|
61
|
+
super.resolve(index);
|
|
62
|
+
}
|
|
63
|
+
if (index === 1) {
|
|
64
|
+
this.okSignal.emit(null);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
export default SymbologyWidget;
|
|
@@ -0,0 +1,21 @@
|
|
|
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;
|
|
@@ -0,0 +1,60 @@
|
|
|
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;
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { DocumentRegistry } from '@jupyterlab/docregistry';
|
|
2
|
+
import { IDict, IJGISFormSchemaRegistry, IJupyterGISModel, LayerType, SourceType } from '@jupytergis/schema';
|
|
3
|
+
import { Dialog } from '@jupyterlab/apputils';
|
|
4
|
+
import { Signal } from '@lumino/signaling';
|
|
5
|
+
import * as React from 'react';
|
|
6
|
+
export interface ICreationFormProps {
|
|
7
|
+
/**
|
|
8
|
+
* Whether or not to create a layer
|
|
9
|
+
*/
|
|
10
|
+
createLayer: boolean;
|
|
11
|
+
/**
|
|
12
|
+
* Whether or not to create a source
|
|
13
|
+
*/
|
|
14
|
+
createSource: boolean;
|
|
15
|
+
/**
|
|
16
|
+
* The type of layer to create.
|
|
17
|
+
*/
|
|
18
|
+
layerType?: LayerType;
|
|
19
|
+
/**
|
|
20
|
+
* The type of source to create or to select in the case where we only create a layer.
|
|
21
|
+
*/
|
|
22
|
+
sourceType: SourceType;
|
|
23
|
+
/**
|
|
24
|
+
* The initial layer data, if it applies.
|
|
25
|
+
*/
|
|
26
|
+
layerData?: IDict;
|
|
27
|
+
/**
|
|
28
|
+
* The initial source data, if it applies.
|
|
29
|
+
*/
|
|
30
|
+
sourceData?: IDict;
|
|
31
|
+
/**
|
|
32
|
+
* Ok signal. This is the signal sent by the parent dialog upon "Ok" button click. No ok button will be displayed if defined.
|
|
33
|
+
*/
|
|
34
|
+
ok?: Signal<Dialog<any>, number>;
|
|
35
|
+
/**
|
|
36
|
+
* Cancel callback
|
|
37
|
+
*/
|
|
38
|
+
cancel?: () => void;
|
|
39
|
+
formSchemaRegistry: IJGISFormSchemaRegistry;
|
|
40
|
+
context: DocumentRegistry.IContext<IJupyterGISModel>;
|
|
41
|
+
/**
|
|
42
|
+
* A signal emitting when the form changed, with a boolean whether there are some
|
|
43
|
+
* extra errors or not.
|
|
44
|
+
*/
|
|
45
|
+
formErrorSignal?: Signal<Dialog<any>, boolean>;
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Form for creating a source, a layer or both at the same time
|
|
49
|
+
*/
|
|
50
|
+
export declare class CreationForm extends React.Component<ICreationFormProps, any> {
|
|
51
|
+
constructor(props: ICreationFormProps);
|
|
52
|
+
render(): React.JSX.Element | undefined;
|
|
53
|
+
private jGISModel;
|
|
54
|
+
private filePath;
|
|
55
|
+
private sourceFormChangedSignal;
|
|
56
|
+
}
|