@jupytergis/base 0.3.0 → 0.4.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 (77) hide show
  1. package/lib/annotations/components/Annotation.js +1 -1
  2. package/lib/annotations/model.d.ts +6 -7
  3. package/lib/annotations/model.js +15 -15
  4. package/lib/commands.d.ts +2 -3
  5. package/lib/commands.js +117 -62
  6. package/lib/constants.d.ts +2 -0
  7. package/lib/constants.js +4 -1
  8. package/lib/dialogs/formdialog.js +2 -2
  9. package/lib/dialogs/layerBrowserDialog.d.ts +4 -5
  10. package/lib/dialogs/layerBrowserDialog.js +9 -9
  11. package/lib/dialogs/symbology/hooks/useGetBandInfo.d.ts +3 -8
  12. package/lib/dialogs/symbology/hooks/useGetBandInfo.js +16 -28
  13. package/lib/dialogs/symbology/hooks/useGetProperties.d.ts +1 -1
  14. package/lib/dialogs/symbology/hooks/useGetProperties.js +6 -8
  15. package/lib/dialogs/symbology/symbologyDialog.d.ts +2 -3
  16. package/lib/dialogs/symbology/symbologyDialog.js +10 -9
  17. package/lib/dialogs/symbology/tiff_layer/TiffRendering.d.ts +1 -1
  18. package/lib/dialogs/symbology/tiff_layer/TiffRendering.js +6 -6
  19. package/lib/dialogs/symbology/tiff_layer/components/BandRow.js +3 -1
  20. package/lib/dialogs/symbology/tiff_layer/types/MultibandColor.d.ts +1 -1
  21. package/lib/dialogs/symbology/tiff_layer/types/MultibandColor.js +5 -4
  22. package/lib/dialogs/symbology/tiff_layer/types/SingleBandPseudoColor.d.ts +1 -1
  23. package/lib/dialogs/symbology/tiff_layer/types/SingleBandPseudoColor.js +8 -7
  24. package/lib/dialogs/symbology/vector_layer/VectorRendering.d.ts +1 -1
  25. package/lib/dialogs/symbology/vector_layer/VectorRendering.js +18 -13
  26. package/lib/dialogs/symbology/vector_layer/types/Categorized.d.ts +1 -1
  27. package/lib/dialogs/symbology/vector_layer/types/Categorized.js +30 -19
  28. package/lib/dialogs/symbology/vector_layer/types/Graduated.d.ts +1 -1
  29. package/lib/dialogs/symbology/vector_layer/types/Graduated.js +16 -13
  30. package/lib/dialogs/symbology/vector_layer/types/Heatmap.d.ts +4 -0
  31. package/lib/dialogs/symbology/vector_layer/types/Heatmap.js +77 -0
  32. package/lib/dialogs/symbology/vector_layer/types/SimpleSymbol.d.ts +1 -1
  33. package/lib/dialogs/symbology/vector_layer/types/SimpleSymbol.js +4 -3
  34. package/lib/formbuilder/creationform.d.ts +1 -2
  35. package/lib/formbuilder/creationform.js +4 -4
  36. package/lib/formbuilder/editform.d.ts +1 -2
  37. package/lib/formbuilder/editform.js +7 -7
  38. package/lib/formbuilder/formselectors.js +5 -2
  39. package/lib/formbuilder/objectform/baseform.d.ts +3 -4
  40. package/lib/formbuilder/objectform/baseform.js +2 -2
  41. package/lib/formbuilder/objectform/fileselectorwidget.js +13 -6
  42. package/lib/formbuilder/objectform/geotiffsource.d.ts +5 -1
  43. package/lib/formbuilder/objectform/geotiffsource.js +51 -18
  44. package/lib/formbuilder/objectform/heatmapLayerForm.d.ts +11 -0
  45. package/lib/formbuilder/objectform/heatmapLayerForm.js +60 -0
  46. package/lib/formbuilder/objectform/vectorlayerform.d.ts +0 -2
  47. package/lib/formbuilder/objectform/vectorlayerform.js +0 -59
  48. package/lib/mainview/TemporalSlider.d.ts +8 -0
  49. package/lib/mainview/TemporalSlider.js +303 -0
  50. package/lib/mainview/mainView.d.ts +26 -5
  51. package/lib/mainview/mainView.js +221 -108
  52. package/lib/mainview/mainviewmodel.d.ts +4 -0
  53. package/lib/mainview/mainviewmodel.js +4 -0
  54. package/lib/mainview/mainviewwidget.d.ts +0 -2
  55. package/lib/mainview/mainviewwidget.js +0 -2
  56. package/lib/panelview/annotationPanel.js +5 -5
  57. package/lib/panelview/components/filter-panel/Filter.js +4 -25
  58. package/lib/panelview/components/identify-panel/IdentifyPanel.js +1 -1
  59. package/lib/panelview/components/layers.js +2 -2
  60. package/lib/panelview/components/sources.js +1 -1
  61. package/lib/panelview/leftpanel.d.ts +3 -0
  62. package/lib/panelview/leftpanel.js +5 -1
  63. package/lib/panelview/model.js +8 -8
  64. package/lib/panelview/objectproperties.js +10 -10
  65. package/lib/panelview/rightpanel.d.ts +1 -1
  66. package/lib/panelview/rightpanel.js +10 -10
  67. package/lib/toolbar/widget.d.ts +1 -1
  68. package/lib/toolbar/widget.js +44 -32
  69. package/lib/tools.d.ts +6 -16
  70. package/lib/tools.js +54 -56
  71. package/lib/types.d.ts +2 -0
  72. package/lib/widget.d.ts +30 -6
  73. package/lib/widget.js +43 -9
  74. package/package.json +4 -3
  75. package/style/base.css +10 -0
  76. package/style/symbologyDialog.css +7 -1
  77. package/style/temporalSlider.css +47 -0
@@ -2,11 +2,11 @@ import { faCheck, faPlus } from '@fortawesome/free-solid-svg-icons';
2
2
  import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
3
3
  import { Dialog } from '@jupyterlab/apputils';
4
4
  import { PromiseDelegate, UUID } from '@lumino/coreutils';
5
+ import { Signal } from '@lumino/signaling';
5
6
  import React, { useEffect, useState } from 'react';
6
7
  import CUSTOM_RASTER_IMAGE from '../../rasterlayer_gallery/custom_raster.png';
7
8
  import { CreationFormWrapper } from './formdialog';
8
- import { Signal } from '@lumino/signaling';
9
- export const LayerBrowserComponent = ({ context, registry, formSchemaRegistry, okSignalPromise, cancel }) => {
9
+ export const LayerBrowserComponent = ({ model, registry, formSchemaRegistry, okSignalPromise, cancel }) => {
10
10
  const [searchTerm, setSearchTerm] = useState('');
11
11
  const [activeLayers, setActiveLayers] = useState([]);
12
12
  const [selectedCategory, setSelectedCategory] = useState();
@@ -15,9 +15,9 @@ export const LayerBrowserComponent = ({ context, registry, formSchemaRegistry, o
15
15
  const providers = [...new Set(registry.map(item => item.source.provider))];
16
16
  const filteredGallery = galleryWithCategory.filter(item => item.name.toLowerCase().includes(searchTerm));
17
17
  useEffect(() => {
18
- context.model.sharedModel.layersChanged.connect(handleLayerChange);
18
+ model.sharedModel.layersChanged.connect(handleLayerChange);
19
19
  return () => {
20
- context.model.sharedModel.layersChanged.disconnect(handleLayerChange);
20
+ model.sharedModel.layersChanged.disconnect(handleLayerChange);
21
21
  };
22
22
  }, []);
23
23
  /**
@@ -25,7 +25,7 @@ export const LayerBrowserComponent = ({ context, registry, formSchemaRegistry, o
25
25
  */
26
26
  const handleLayerChange = (_, change) => {
27
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]));
28
+ setActiveLayers(Object.values(model.sharedModel.layers).map(layer => layer.name.split(' ')[0]));
29
29
  };
30
30
  const handleSearchInput = (event) => {
31
31
  setSearchTerm(event.target.value.toLowerCase());
@@ -64,8 +64,8 @@ export const LayerBrowserComponent = ({ context, registry, formSchemaRegistry, o
64
64
  visible: true,
65
65
  name: tile.name + ' Layer'
66
66
  };
67
- context.model.sharedModel.addSource(sourceId, sourceModel);
68
- context.model.addLayer(UUID.uuid4(), layerModel);
67
+ model.sharedModel.addSource(sourceId, sourceModel);
68
+ model.addLayer(UUID.uuid4(), layerModel);
69
69
  };
70
70
  if (creatingCustomRaster) {
71
71
  // Disconnect any previous handler
@@ -73,7 +73,7 @@ export const LayerBrowserComponent = ({ context, registry, formSchemaRegistry, o
73
73
  value.disconnect(cancel, this);
74
74
  });
75
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: {
76
+ React.createElement(CreationFormWrapper, { model: model, formSchemaRegistry: formSchemaRegistry, createLayer: true, createSource: true, layerType: 'RasterLayer', sourceType: 'RasterSource', layerData: {
77
77
  name: 'Custom Raster'
78
78
  }, sourceData: {
79
79
  url: 'https://tile.openstreetmap.org/{z}/{x}/{y}.png',
@@ -122,7 +122,7 @@ export class LayerBrowserWidget extends Dialog {
122
122
  this.resolve(0);
123
123
  };
124
124
  const okSignalPromise = new PromiseDelegate();
125
- const body = (React.createElement(LayerBrowserComponent, { context: options.context, registry: options.registry, formSchemaRegistry: options.formSchemaRegistry, okSignalPromise: okSignalPromise, cancel: cancelCallback }));
125
+ const body = (React.createElement(LayerBrowserComponent, { model: options.model, registry: options.registry, formSchemaRegistry: options.formSchemaRegistry, okSignalPromise: okSignalPromise, cancel: cancelCallback }));
126
126
  super({ body, buttons: [Dialog.cancelButton(), Dialog.okButton()] });
127
127
  this.id = 'jupytergis::layerBrowser';
128
128
  this.okSignal = new Signal(this);
@@ -1,5 +1,4 @@
1
- import { IDict, IJGISLayer, IJupyterGISModel } from '@jupytergis/schema';
2
- import { DocumentRegistry } from '@jupyterlab/docregistry';
1
+ import { IJGISLayer, IJupyterGISModel } from '@jupytergis/schema';
3
2
  export interface IBandHistogram {
4
3
  buckets: number[];
5
4
  count: number;
@@ -8,17 +7,13 @@ export interface IBandHistogram {
8
7
  }
9
8
  export interface IBandRow {
10
9
  band: number;
11
- colorInterpretation: string;
10
+ colorInterpretation?: string;
12
11
  stats: {
13
12
  minimum: number;
14
13
  maximum: number;
15
- mean: number;
16
- stdDev: number;
17
14
  };
18
- metadata: IDict;
19
- histogram: IBandHistogram;
20
15
  }
21
- declare const useGetBandInfo: (context: DocumentRegistry.IContext<IJupyterGISModel>, layer: IJGISLayer) => {
16
+ declare const useGetBandInfo: (model: IJupyterGISModel, layer: IJGISLayer) => {
22
17
  bandRows: IBandRow[];
23
18
  setBandRows: import("react").Dispatch<import("react").SetStateAction<IBandRow[]>>;
24
19
  loading: boolean;
@@ -1,48 +1,36 @@
1
1
  import { useEffect, useState } from 'react';
2
- import { loadGeoTIFFWithCache } from '../../../tools';
3
- const preloadGeoTiffFile = async (sourceInfo) => {
4
- return await loadGeoTIFFWithCache(sourceInfo);
5
- };
6
- const useGetBandInfo = (context, layer) => {
2
+ import { fromUrl } from 'geotiff';
3
+ const useGetBandInfo = (model, layer) => {
7
4
  const [bandRows, setBandRows] = useState([]);
8
5
  const [loading, setLoading] = useState(false);
9
6
  const [error, setError] = useState(null);
10
7
  const fetchBandInfo = async () => {
11
- var _a, _b;
8
+ var _a, _b, _c, _d;
12
9
  setLoading(true);
13
10
  setError(null);
14
11
  try {
15
12
  const bandsArr = [];
16
- const source = context.model.getSource((_a = layer === null || layer === void 0 ? void 0 : layer.parameters) === null || _a === void 0 ? void 0 : _a.source);
13
+ const source = model.getSource((_a = layer === null || layer === void 0 ? void 0 : layer.parameters) === null || _a === void 0 ? void 0 : _a.source);
17
14
  const sourceInfo = (_b = source === null || source === void 0 ? void 0 : source.parameters) === null || _b === void 0 ? void 0 : _b.urls[0];
18
15
  if (!(sourceInfo === null || sourceInfo === void 0 ? void 0 : sourceInfo.url)) {
19
16
  setError('No source URL found.');
20
17
  setLoading(false);
21
18
  return;
22
19
  }
23
- const preloadedFile = await preloadGeoTiffFile(sourceInfo);
24
- const { file, metadata, sourceUrl } = Object.assign({}, preloadedFile);
25
- if (file && metadata && sourceUrl === sourceInfo.url) {
26
- metadata['bands'].forEach((bandData) => {
27
- var _a, _b;
28
- bandsArr.push({
29
- band: bandData.band,
30
- colorInterpretation: bandData.colorInterpretation,
31
- stats: {
32
- minimum: (_a = sourceInfo.min) !== null && _a !== void 0 ? _a : bandData.minimum,
33
- maximum: (_b = sourceInfo.max) !== null && _b !== void 0 ? _b : bandData.maximum,
34
- mean: bandData.mean,
35
- stdDev: bandData.stdDev
36
- },
37
- metadata: bandData.metadata,
38
- histogram: bandData.histogram
39
- });
20
+ // TODO Get band names + get band stats
21
+ const tiff = await fromUrl(sourceInfo.url);
22
+ const image = await tiff.getImage();
23
+ const numberOfBands = image.getSamplesPerPixel();
24
+ for (let i = 0; i < numberOfBands; i++) {
25
+ bandsArr.push({
26
+ band: i,
27
+ stats: {
28
+ minimum: (_c = sourceInfo.min) !== null && _c !== void 0 ? _c : 0,
29
+ maximum: (_d = sourceInfo.max) !== null && _d !== void 0 ? _d : 100
30
+ }
40
31
  });
41
- setBandRows(bandsArr);
42
- }
43
- else {
44
- setError('Failed to preload the file or metadata mismatch.');
45
32
  }
33
+ setBandRows(bandsArr);
46
34
  }
47
35
  catch (err) {
48
36
  setError(`Error fetching band info: ${err.message}`);
@@ -4,7 +4,7 @@ interface IUseGetPropertiesProps {
4
4
  model: IJupyterGISModel;
5
5
  }
6
6
  interface IUseGetPropertiesResult {
7
- featureProps: Record<string, Set<any>>;
7
+ featureProperties: Record<string, Set<any>>;
8
8
  isLoading: boolean;
9
9
  error?: Error;
10
10
  }
@@ -2,7 +2,7 @@
2
2
  import { useEffect, useState } from 'react';
3
3
  import { loadFile } from '../../../tools';
4
4
  export const useGetProperties = ({ layerId, model }) => {
5
- const [featureProps, setFeatureProps] = useState({});
5
+ const [featureProperties, setFeatureProperties] = useState({});
6
6
  const [isLoading, setIsLoading] = useState(true);
7
7
  const [error, setError] = useState(undefined);
8
8
  const getProperties = async () => {
@@ -28,16 +28,14 @@ export const useGetProperties = ({ layerId, model }) => {
28
28
  data.features.forEach((feature) => {
29
29
  if (feature.properties) {
30
30
  Object.entries(feature.properties).forEach(([key, value]) => {
31
- if (typeof value !== 'string') {
32
- if (!(key in result)) {
33
- result[key] = new Set();
34
- }
35
- result[key].add(value);
31
+ if (!(key in result)) {
32
+ result[key] = new Set();
36
33
  }
34
+ result[key].add(value);
37
35
  });
38
36
  }
39
37
  });
40
- setFeatureProps(result);
38
+ setFeatureProperties(result);
41
39
  setIsLoading(false);
42
40
  }
43
41
  catch (err) {
@@ -48,5 +46,5 @@ export const useGetProperties = ({ layerId, model }) => {
48
46
  useEffect(() => {
49
47
  getProperties();
50
48
  }, [model, layerId]);
51
- return { featureProps, isLoading, error };
49
+ return { featureProperties, isLoading, error };
52
50
  };
@@ -1,18 +1,17 @@
1
1
  import { IJupyterGISModel } from '@jupytergis/schema';
2
2
  import { Dialog } from '@jupyterlab/apputils';
3
- import { DocumentRegistry } from '@jupyterlab/docregistry';
4
3
  import { IStateDB } from '@jupyterlab/statedb';
5
4
  import { PromiseDelegate } from '@lumino/coreutils';
6
5
  import { Signal } from '@lumino/signaling';
7
6
  export interface ISymbologyDialogProps {
8
- context: DocumentRegistry.IContext<IJupyterGISModel>;
7
+ model: IJupyterGISModel;
9
8
  state: IStateDB;
10
9
  okSignalPromise: PromiseDelegate<Signal<SymbologyWidget, null>>;
11
10
  cancel: () => void;
12
11
  layerId?: string;
13
12
  }
14
13
  export interface ISymbologyWidgetOptions {
15
- context: DocumentRegistry.IContext<IJupyterGISModel>;
14
+ model: IJupyterGISModel;
16
15
  state: IStateDB;
17
16
  }
18
17
  export interface IStopRow {
@@ -4,31 +4,31 @@ import { Signal } from '@lumino/signaling';
4
4
  import React, { useEffect, useState } from 'react';
5
5
  import TiffRendering from './tiff_layer/TiffRendering';
6
6
  import VectorRendering from './vector_layer/VectorRendering';
7
- const SymbologyDialog = ({ context, state, okSignalPromise, cancel }) => {
7
+ const SymbologyDialog = ({ model, state, okSignalPromise, cancel }) => {
8
8
  const [selectedLayer, setSelectedLayer] = useState(null);
9
9
  const [componentToRender, setComponentToRender] = useState(null);
10
10
  let LayerSymbology;
11
11
  useEffect(() => {
12
12
  const handleClientStateChanged = () => {
13
13
  var _a, _b;
14
- if (!((_b = (_a = context.model.localState) === null || _a === void 0 ? void 0 : _a.selected) === null || _b === void 0 ? void 0 : _b.value)) {
14
+ if (!((_b = (_a = model.localState) === null || _a === void 0 ? void 0 : _a.selected) === null || _b === void 0 ? void 0 : _b.value)) {
15
15
  return;
16
16
  }
17
- const currentLayer = Object.keys(context.model.localState.selected.value)[0];
17
+ const currentLayer = Object.keys(model.localState.selected.value)[0];
18
18
  setSelectedLayer(currentLayer);
19
19
  };
20
20
  // Initial state
21
21
  handleClientStateChanged();
22
- context.model.clientStateChanged.connect(handleClientStateChanged);
22
+ model.clientStateChanged.connect(handleClientStateChanged);
23
23
  return () => {
24
- context.model.clientStateChanged.disconnect(handleClientStateChanged);
24
+ model.clientStateChanged.disconnect(handleClientStateChanged);
25
25
  };
26
26
  }, []);
27
27
  useEffect(() => {
28
28
  if (!selectedLayer) {
29
29
  return;
30
30
  }
31
- const layer = context.model.getLayer(selectedLayer);
31
+ const layer = model.getLayer(selectedLayer);
32
32
  if (!layer) {
33
33
  return;
34
34
  }
@@ -36,10 +36,11 @@ const SymbologyDialog = ({ context, state, okSignalPromise, cancel }) => {
36
36
  switch (layer.type) {
37
37
  case 'VectorLayer':
38
38
  case 'VectorTileLayer':
39
- LayerSymbology = (React.createElement(VectorRendering, { context: context, state: state, okSignalPromise: okSignalPromise, cancel: cancel, layerId: selectedLayer }));
39
+ case 'HeatmapLayer':
40
+ LayerSymbology = (React.createElement(VectorRendering, { model: model, state: state, okSignalPromise: okSignalPromise, cancel: cancel, layerId: selectedLayer }));
40
41
  break;
41
42
  case 'WebGlLayer':
42
- LayerSymbology = (React.createElement(TiffRendering, { context: context, state: state, okSignalPromise: okSignalPromise, cancel: cancel, layerId: selectedLayer }));
43
+ LayerSymbology = (React.createElement(TiffRendering, { model: model, state: state, okSignalPromise: okSignalPromise, cancel: cancel, layerId: selectedLayer }));
43
44
  break;
44
45
  default:
45
46
  LayerSymbology = React.createElement("div", null, "Layer Type Not Supported");
@@ -54,7 +55,7 @@ export class SymbologyWidget extends Dialog {
54
55
  this.resolve(0);
55
56
  };
56
57
  const okSignalPromise = new PromiseDelegate();
57
- const body = (React.createElement(SymbologyDialog, { context: options.context, okSignalPromise: okSignalPromise, cancel: cancelCallback, state: options.state }));
58
+ const body = (React.createElement(SymbologyDialog, { model: options.model, okSignalPromise: okSignalPromise, cancel: cancelCallback, state: options.state }));
58
59
  super({ title: 'Symbology', body });
59
60
  this.id = 'jupytergis::symbologyWidget';
60
61
  this.okSignal = new Signal(this);
@@ -1,4 +1,4 @@
1
1
  import React from 'react';
2
2
  import { ISymbologyDialogProps } from '../symbologyDialog';
3
- declare const TiffRendering: ({ context, state, okSignalPromise, cancel, layerId }: ISymbologyDialogProps) => React.JSX.Element | undefined;
3
+ declare const TiffRendering: ({ model, state, okSignalPromise, cancel, layerId }: ISymbologyDialogProps) => React.JSX.Element | undefined;
4
4
  export default TiffRendering;
@@ -1,7 +1,7 @@
1
1
  import React, { useEffect, useState } from 'react';
2
2
  import SingleBandPseudoColor from './types/SingleBandPseudoColor';
3
3
  import MultibandColor from './types/MultibandColor';
4
- const TiffRendering = ({ context, state, okSignalPromise, cancel, layerId }) => {
4
+ const TiffRendering = ({ model, state, okSignalPromise, cancel, layerId }) => {
5
5
  const renderTypes = ['Singleband Pseudocolor', 'Multiband Color'];
6
6
  const [selectedRenderType, setSelectedRenderType] = useState();
7
7
  const [componentToRender, setComponentToRender] = useState(null);
@@ -10,9 +10,9 @@ const TiffRendering = ({ context, state, okSignalPromise, cancel, layerId }) =>
10
10
  return;
11
11
  }
12
12
  useEffect(() => {
13
- var _a;
14
- const layer = context.model.getLayer(layerId);
15
- const renderType = (_a = layer === null || layer === void 0 ? void 0 : layer.parameters) === null || _a === void 0 ? void 0 : _a.symbologyState.renderType;
13
+ var _a, _b;
14
+ const layer = model.getLayer(layerId);
15
+ const renderType = (_b = (_a = layer === null || layer === void 0 ? void 0 : layer.parameters) === null || _a === void 0 ? void 0 : _a.symbologyState) === null || _b === void 0 ? void 0 : _b.renderType;
16
16
  setSelectedRenderType(renderType !== null && renderType !== void 0 ? renderType : 'Singleband Pseudocolor');
17
17
  }, []);
18
18
  useEffect(() => {
@@ -21,10 +21,10 @@ const TiffRendering = ({ context, state, okSignalPromise, cancel, layerId }) =>
21
21
  }
22
22
  switch (selectedRenderType) {
23
23
  case 'Singleband Pseudocolor':
24
- RenderComponent = (React.createElement(SingleBandPseudoColor, { context: context, state: state, okSignalPromise: okSignalPromise, cancel: cancel, layerId: layerId }));
24
+ RenderComponent = (React.createElement(SingleBandPseudoColor, { model: model, state: state, okSignalPromise: okSignalPromise, cancel: cancel, layerId: layerId }));
25
25
  break;
26
26
  case 'Multiband Color':
27
- RenderComponent = (React.createElement(MultibandColor, { context: context, state: state, okSignalPromise: okSignalPromise, cancel: cancel, layerId: layerId }));
27
+ RenderComponent = (React.createElement(MultibandColor, { model: model, state: state, okSignalPromise: okSignalPromise, cancel: cancel, layerId: layerId }));
28
28
  break;
29
29
  default:
30
30
  RenderComponent = React.createElement("div", null, "Render Type Not Implemented (yet)");
@@ -33,7 +33,9 @@ const BandRow = ({ label, index, bandRow, bandRows, setSelectedBand, setBandRows
33
33
  ":"),
34
34
  React.createElement("div", { className: "jp-select-wrapper" },
35
35
  React.createElement("select", { name: `band-select-${index}`, onChange: event => setSelectedBand(+event.target.value), className: "jp-mod-styled" },
36
- bandRows.map((band, bandIndex) => (React.createElement("option", { key: bandIndex, value: band.band, selected: band.band === (bandRow === null || bandRow === void 0 ? void 0 : bandRow.band), className: "jp-mod-styled" }, `Band ${band.band} (${band.colorInterpretation})`))),
36
+ bandRows.map((band, bandIndex) => (React.createElement("option", { key: bandIndex, value: band.band, selected: band.band === (bandRow === null || bandRow === void 0 ? void 0 : bandRow.band), className: "jp-mod-styled" }, band.colorInterpretation
37
+ ? `Band ${band.band} (${band.colorInterpretation})`
38
+ : `Band ${band.band}`))),
37
39
  isMultibandColor ? (React.createElement("option", { key: 'unset', value: 0, selected: !bandRow, className: "jp-mod-styled" }, "Unset")) : null))),
38
40
  isMultibandColor ? null : (React.createElement("div", { className: "jp-gis-symbology-row", style: { gap: '0.5rem' } },
39
41
  React.createElement("div", { style: {
@@ -1,4 +1,4 @@
1
1
  import React from 'react';
2
2
  import { ISymbologyDialogProps } from '../../symbologyDialog';
3
- declare const MultibandColor: ({ context, okSignalPromise, cancel, layerId }: ISymbologyDialogProps) => React.JSX.Element | undefined;
3
+ declare const MultibandColor: ({ model, okSignalPromise, cancel, layerId }: ISymbologyDialogProps) => React.JSX.Element | undefined;
4
4
  export default MultibandColor;
@@ -2,15 +2,15 @@ import React, { useEffect, useRef, useState } from 'react';
2
2
  import { Spinner } from '../../../../mainview/spinner';
3
3
  import useGetBandInfo from '../../hooks/useGetBandInfo';
4
4
  import BandRow from '../components/BandRow';
5
- const MultibandColor = ({ context, okSignalPromise, cancel, layerId }) => {
5
+ const MultibandColor = ({ model, okSignalPromise, cancel, layerId }) => {
6
6
  if (!layerId) {
7
7
  return;
8
8
  }
9
- const layer = context.model.getLayer(layerId);
9
+ const layer = model.getLayer(layerId);
10
10
  if (!(layer === null || layer === void 0 ? void 0 : layer.parameters)) {
11
11
  return;
12
12
  }
13
- const { bandRows, setBandRows, loading } = useGetBandInfo(context, layer);
13
+ const { bandRows, setBandRows, loading } = useGetBandInfo(model, layer);
14
14
  const [selectedBands, setSelectedBands] = useState({
15
15
  red: 1,
16
16
  green: 2,
@@ -72,7 +72,8 @@ const MultibandColor = ({ context, okSignalPromise, cancel, layerId }) => {
72
72
  };
73
73
  layer.parameters.symbologyState = symbologyState;
74
74
  layer.parameters.color = colorExpr;
75
- context.model.sharedModel.updateLayer(layerId, layer);
75
+ layer.type = 'WebGlLayer';
76
+ model.sharedModel.updateLayer(layerId, layer);
76
77
  cancel();
77
78
  };
78
79
  return (React.createElement("div", { className: "jp-gis-layer-symbology-container" },
@@ -1,5 +1,5 @@
1
1
  import React from 'react';
2
2
  import { ISymbologyDialogProps } from '../../symbologyDialog';
3
3
  export type InterpolationType = 'discrete' | 'linear' | 'exact';
4
- declare const SingleBandPseudoColor: ({ context, okSignalPromise, cancel, layerId }: ISymbologyDialogProps) => React.JSX.Element | undefined;
4
+ declare const SingleBandPseudoColor: ({ model, okSignalPromise, cancel, layerId }: ISymbologyDialogProps) => React.JSX.Element | undefined;
5
5
  export default SingleBandPseudoColor;
@@ -8,18 +8,18 @@ import StopRow from '../../components/color_stops/StopRow';
8
8
  import useGetBandInfo from '../../hooks/useGetBandInfo';
9
9
  import { Utils } from '../../symbologyUtils';
10
10
  import BandRow from '../components/BandRow';
11
- const SingleBandPseudoColor = ({ context, okSignalPromise, cancel, layerId }) => {
11
+ const SingleBandPseudoColor = ({ model, okSignalPromise, cancel, layerId }) => {
12
12
  if (!layerId) {
13
13
  return;
14
14
  }
15
- const layer = context.model.getLayer(layerId);
15
+ const layer = model.getLayer(layerId);
16
16
  if (!(layer === null || layer === void 0 ? void 0 : layer.parameters)) {
17
17
  return;
18
18
  }
19
19
  const functions = ['discrete', 'linear', 'exact'];
20
20
  const modeOptions = ['continuous', 'equal interval', 'quantile'];
21
21
  const stateDb = GlobalStateDbManager.getInstance().getStateDb();
22
- const { bandRows, setBandRows, loading } = useGetBandInfo(context, layer);
22
+ const { bandRows, setBandRows, loading } = useGetBandInfo(model, layer);
23
23
  const [layerState, setLayerState] = useState();
24
24
  const [selectedBand, setSelectedBand] = useState(1);
25
25
  const [stopRows, setStopRows] = useState([]);
@@ -120,7 +120,7 @@ const SingleBandPseudoColor = ({ context, okSignalPromise, cancel, layerId }) =>
120
120
  return;
121
121
  }
122
122
  const sourceId = (_a = layer.parameters) === null || _a === void 0 ? void 0 : _a.source;
123
- const source = context.model.getSource(sourceId);
123
+ const source = model.getSource(sourceId);
124
124
  if (!source || !source.parameters) {
125
125
  return;
126
126
  }
@@ -129,7 +129,7 @@ const SingleBandPseudoColor = ({ context, okSignalPromise, cancel, layerId }) =>
129
129
  sourceInfo.min = bandRow.stats.minimum;
130
130
  sourceInfo.max = bandRow.stats.maximum;
131
131
  source.parameters.urls[0] = sourceInfo;
132
- context.model.sharedModel.updateSource(sourceId, source);
132
+ model.sharedModel.updateSource(sourceId, source);
133
133
  // Update layer
134
134
  if (!layer.parameters) {
135
135
  return;
@@ -193,7 +193,8 @@ const SingleBandPseudoColor = ({ context, okSignalPromise, cancel, layerId }) =>
193
193
  };
194
194
  layer.parameters.symbologyState = symbologyState;
195
195
  layer.parameters.color = colorExpr;
196
- context.model.sharedModel.updateLayer(layerId, layer);
196
+ layer.type = 'WebGlLayer';
197
+ model.sharedModel.updateLayer(layerId, layer);
197
198
  cancel();
198
199
  };
199
200
  const addStopRow = () => {
@@ -220,7 +221,7 @@ const SingleBandPseudoColor = ({ context, okSignalPromise, cancel, layerId }) =>
220
221
  });
221
222
  let stops = [];
222
223
  const currentBand = bandRows[selectedBand - 1];
223
- const source = context.model.getSource((_a = layer === null || layer === void 0 ? void 0 : layer.parameters) === null || _a === void 0 ? void 0 : _a.source);
224
+ const source = model.getSource((_a = layer === null || layer === void 0 ? void 0 : layer.parameters) === null || _a === void 0 ? void 0 : _a.source);
224
225
  const sourceInfo = (_b = source === null || source === void 0 ? void 0 : source.parameters) === null || _b === void 0 ? void 0 : _b.urls[0];
225
226
  const nClasses = selectedMode === 'continuous' ? 52 : +numberOfShades;
226
227
  setIsLoading(true);
@@ -1,4 +1,4 @@
1
1
  import React from 'react';
2
2
  import { ISymbologyDialogProps } from '../symbologyDialog';
3
- declare const VectorRendering: ({ context, state, okSignalPromise, cancel, layerId }: ISymbologyDialogProps) => React.JSX.Element | undefined;
3
+ declare const VectorRendering: ({ model, state, okSignalPromise, cancel, layerId }: ISymbologyDialogProps) => React.JSX.Element | undefined;
4
4
  export default VectorRendering;
@@ -1,9 +1,10 @@
1
1
  import React, { useEffect, useState } from 'react';
2
+ import Categorized from './types/Categorized';
2
3
  import Graduated from './types/Graduated';
4
+ import Heatmap from './types/Heatmap';
3
5
  import SimpleSymbol from './types/SimpleSymbol';
4
- import Categorized from './types/Categorized';
5
- const VectorRendering = ({ context, state, okSignalPromise, cancel, layerId }) => {
6
- const [selectedRenderType, setSelectedRenderType] = useState('Single Symbol');
6
+ const VectorRendering = ({ model, state, okSignalPromise, cancel, layerId }) => {
7
+ const [selectedRenderType, setSelectedRenderType] = useState('');
7
8
  const [componentToRender, setComponentToRender] = useState(null);
8
9
  const [renderTypeOptions, setRenderTypeOptions] = useState([
9
10
  'Single Symbol'
@@ -12,32 +13,36 @@ const VectorRendering = ({ context, state, okSignalPromise, cancel, layerId }) =
12
13
  if (!layerId) {
13
14
  return;
14
15
  }
15
- const layer = context.model.getLayer(layerId);
16
+ const layer = model.getLayer(layerId);
16
17
  if (!(layer === null || layer === void 0 ? void 0 : layer.parameters)) {
17
18
  return;
18
19
  }
19
20
  useEffect(() => {
20
21
  var _a, _b;
21
- const renderType = (_b = (_a = layer.parameters) === null || _a === void 0 ? void 0 : _a.symbologyState) === null || _b === void 0 ? void 0 : _b.renderType;
22
- setSelectedRenderType(renderType !== null && renderType !== void 0 ? renderType : 'Single Symbol');
23
- if (layer.type === 'VectorLayer') {
24
- const options = ['Single Symbol', 'Graduated', 'Categorized'];
25
- setRenderTypeOptions(options);
22
+ let renderType = (_b = (_a = layer.parameters) === null || _a === void 0 ? void 0 : _a.symbologyState) === null || _b === void 0 ? void 0 : _b.renderType;
23
+ if (!renderType) {
24
+ renderType = layer.type === 'HeatmapLayer' ? 'Heatmap' : 'Single Symbol';
26
25
  }
26
+ setSelectedRenderType(renderType);
27
+ const options = ['Single Symbol', 'Graduated', 'Categorized', 'Heatmap'];
28
+ setRenderTypeOptions(options);
27
29
  }, []);
28
30
  useEffect(() => {
29
31
  switch (selectedRenderType) {
30
32
  case 'Single Symbol':
31
- RenderComponent = (React.createElement(SimpleSymbol, { context: context, state: state, okSignalPromise: okSignalPromise, cancel: cancel, layerId: layerId }));
33
+ RenderComponent = (React.createElement(SimpleSymbol, { model: model, state: state, okSignalPromise: okSignalPromise, cancel: cancel, layerId: layerId }));
32
34
  break;
33
35
  case 'Graduated':
34
- RenderComponent = (React.createElement(Graduated, { context: context, state: state, okSignalPromise: okSignalPromise, cancel: cancel, layerId: layerId }));
36
+ RenderComponent = (React.createElement(Graduated, { model: model, state: state, okSignalPromise: okSignalPromise, cancel: cancel, layerId: layerId }));
35
37
  break;
36
38
  case 'Categorized':
37
- RenderComponent = (React.createElement(Categorized, { context: context, state: state, okSignalPromise: okSignalPromise, cancel: cancel, layerId: layerId }));
39
+ RenderComponent = (React.createElement(Categorized, { model: model, state: state, okSignalPromise: okSignalPromise, cancel: cancel, layerId: layerId }));
40
+ break;
41
+ case 'Heatmap':
42
+ RenderComponent = (React.createElement(Heatmap, { model: model, state: state, okSignalPromise: okSignalPromise, cancel: cancel, layerId: layerId }));
38
43
  break;
39
44
  default:
40
- RenderComponent = React.createElement("div", null, "Render Type Not Implemented (yet)");
45
+ RenderComponent = React.createElement("div", null, "Select a render type");
41
46
  }
42
47
  setComponentToRender(RenderComponent);
43
48
  }, [selectedRenderType]);
@@ -1,4 +1,4 @@
1
1
  import React from 'react';
2
2
  import { ISymbologyDialogProps } from '../../symbologyDialog';
3
- declare const Categorized: ({ context, state, okSignalPromise, cancel, layerId }: ISymbologyDialogProps) => React.JSX.Element | undefined;
3
+ declare const Categorized: ({ model, state, okSignalPromise, cancel, layerId }: ISymbologyDialogProps) => React.JSX.Element | undefined;
4
4
  export default Categorized;
@@ -1,26 +1,28 @@
1
1
  import React, { useEffect, useRef, useState } from 'react';
2
- import ValueSelect from '../components/ValueSelect';
3
- import { useGetProperties } from '../../hooks/useGetProperties';
2
+ import { getNumericFeatureAttributes } from '../../../../tools';
3
+ import ColorRamp from '../../components/color_ramp/ColorRamp';
4
4
  import StopContainer from '../../components/color_stops/StopContainer';
5
+ import { useGetProperties } from '../../hooks/useGetProperties';
5
6
  import { Utils, VectorUtils } from '../../symbologyUtils';
6
- import ColorRamp from '../../components/color_ramp/ColorRamp';
7
- const Categorized = ({ context, state, okSignalPromise, cancel, layerId }) => {
7
+ import ValueSelect from '../components/ValueSelect';
8
+ const Categorized = ({ model, state, okSignalPromise, cancel, layerId }) => {
8
9
  const selectedValueRef = useRef();
9
10
  const stopRowsRef = useRef();
10
11
  const colorRampOptionsRef = useRef();
11
12
  const [selectedValue, setSelectedValue] = useState('');
12
13
  const [stopRows, setStopRows] = useState([]);
13
14
  const [colorRampOptions, setColorRampOptions] = useState();
15
+ const [features, setFeatures] = useState({});
14
16
  if (!layerId) {
15
17
  return;
16
18
  }
17
- const layer = context.model.getLayer(layerId);
19
+ const layer = model.getLayer(layerId);
18
20
  if (!(layer === null || layer === void 0 ? void 0 : layer.parameters)) {
19
21
  return;
20
22
  }
21
- const { featureProps } = useGetProperties({
23
+ const { featureProperties } = useGetProperties({
22
24
  layerId,
23
- model: context.model
25
+ model: model
24
26
  });
25
27
  useEffect(() => {
26
28
  const valueColorPairs = VectorUtils.buildColorInfo(layer);
@@ -35,19 +37,19 @@ const Categorized = ({ context, state, okSignalPromise, cancel, layerId }) => {
35
37
  };
36
38
  }, []);
37
39
  useEffect(() => {
38
- populateOptions();
39
- }, [featureProps]);
40
+ var _a, _b;
41
+ // We only want number values here
42
+ const numericFeatures = getNumericFeatureAttributes(featureProperties);
43
+ setFeatures(numericFeatures);
44
+ const layerParams = layer.parameters;
45
+ const value = (_b = (_a = layerParams.symbologyState) === null || _a === void 0 ? void 0 : _a.value) !== null && _b !== void 0 ? _b : Object.keys(numericFeatures)[0];
46
+ setSelectedValue(value);
47
+ }, [featureProperties]);
40
48
  useEffect(() => {
41
49
  selectedValueRef.current = selectedValue;
42
50
  stopRowsRef.current = stopRows;
43
51
  colorRampOptionsRef.current = colorRampOptions;
44
52
  }, [selectedValue, stopRows, colorRampOptions]);
45
- const populateOptions = async () => {
46
- var _a, _b;
47
- const layerParams = layer.parameters;
48
- const value = (_b = (_a = layerParams.symbologyState) === null || _a === void 0 ? void 0 : _a.value) !== null && _b !== void 0 ? _b : Object.keys(featureProps)[0];
49
- setSelectedValue(value);
50
- };
51
53
  const buildColorInfoFromClassification = (selectedMode, numberOfShades, selectedRamp, setIsLoading) => {
52
54
  setColorRampOptions({
53
55
  selectedFunction: '',
@@ -55,7 +57,7 @@ const Categorized = ({ context, state, okSignalPromise, cancel, layerId }) => {
55
57
  numberOfShades: '',
56
58
  selectedMode: ''
57
59
  });
58
- const stops = Array.from(featureProps[selectedValue]).sort((a, b) => a - b);
60
+ const stops = Array.from(features[selectedValue]).sort((a, b) => a - b);
59
61
  const valueColorPairs = Utils.getValueColorPairs(stops, selectedRamp, stops.length);
60
62
  setStopRows(valueColorPairs);
61
63
  };
@@ -73,7 +75,15 @@ const Categorized = ({ context, state, okSignalPromise, cancel, layerId }) => {
73
75
  // fallback value
74
76
  colorExpr.push([0, 0, 0, 0.0]);
75
77
  const newStyle = Object.assign({}, layer.parameters.color);
76
- newStyle['circle-fill-color'] = colorExpr;
78
+ if (layer.parameters.type === 'fill') {
79
+ newStyle['fill-color'] = colorExpr;
80
+ }
81
+ if (layer.parameters.type === 'line') {
82
+ newStyle['stroke-color'] = colorExpr;
83
+ }
84
+ if (layer.parameters.type === 'circle') {
85
+ newStyle['circle-fill-color'] = colorExpr;
86
+ }
77
87
  const symbologyState = {
78
88
  renderType: 'Categorized',
79
89
  value: selectedValueRef.current,
@@ -83,11 +93,12 @@ const Categorized = ({ context, state, okSignalPromise, cancel, layerId }) => {
83
93
  };
84
94
  layer.parameters.symbologyState = symbologyState;
85
95
  layer.parameters.color = newStyle;
86
- context.model.sharedModel.updateLayer(layerId, layer);
96
+ layer.type = 'VectorLayer';
97
+ model.sharedModel.updateLayer(layerId, layer);
87
98
  cancel();
88
99
  };
89
100
  return (React.createElement("div", { className: "jp-gis-layer-symbology-container" },
90
- React.createElement(ValueSelect, { featureProperties: featureProps, selectedValue: selectedValue, setSelectedValue: setSelectedValue }),
101
+ React.createElement(ValueSelect, { featureProperties: features, selectedValue: selectedValue, setSelectedValue: setSelectedValue }),
91
102
  React.createElement(ColorRamp, { layerParams: layer.parameters, modeOptions: [], classifyFunc: buildColorInfoFromClassification, showModeRow: false }),
92
103
  React.createElement(StopContainer, { selectedMethod: '', stopRows: stopRows, setStopRows: setStopRows })));
93
104
  };