Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 25 additions & 1 deletion packages/base/src/commands.ts
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,8 @@ export function addCommands(
const isValidLayer = [
'VectorLayer',
'VectorTileLayer',
'WebGlLayer'
'WebGlLayer',
'HeatmapLayer'
].includes(layer.type);

return isValidLayer;
Expand Down Expand Up @@ -665,6 +666,29 @@ export function addCommands(
...icons.get(CommandIDs.newShapefileLayer)
});

commands.addCommand(CommandIDs.newHeatmapLayer, {
label: args =>
args.from === 'contextMenu'
? trans.__('Heatmap')
: trans.__('Add HeatmapLayer'),
isEnabled: () => {
return tracker.currentWidget
? tracker.currentWidget.context.model.sharedModel.editable
: false;
},
execute: Private.createEntry({
tracker,
formSchemaRegistry,
title: 'Create Heatmap Layer',
createLayer: true,
createSource: false,
layerData: { name: 'Custom Heatmap Layer' },
sourceType: 'GeoJSONSource',
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it the only possible source type?

I'm only asking because I'm curious, allowing the form to create multiple source types is another task on itself (also not sure we want to allow it)

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it the only possible source type?

I think it should work with any vector source that uses points.

layerType: 'HeatmapLayer'
}),
...icons.get(CommandIDs.newHeatmapLayer)
});

/**
* LAYERS and LAYER GROUP actions.
*/
Expand Down
1 change: 1 addition & 0 deletions packages/base/src/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ export namespace CommandIDs {
export const newVideoLayer = 'jupytergis:newVideoLayer';
export const newShapefileLayer = 'jupytergis:newShapefileLayer';
export const newWebGlTileLayer = 'jupytergis:newWebGlTileLayer';
export const newHeatmapLayer = 'jupytergis:newHeatmapLayer';

// Layer and group actions
export const renameLayer = 'jupytergis:renameLayer';
Expand Down
1 change: 1 addition & 0 deletions packages/base/src/dialogs/symbology/symbologyDialog.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ const SymbologyDialog = ({
switch (layer.type) {
case 'VectorLayer':
case 'VectorTileLayer':
case 'HeatmapLayer':
LayerSymbology = (
<VectorRendering
context={context}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,7 @@ const MultibandColor = ({

layer.parameters.symbologyState = symbologyState;
layer.parameters.color = colorExpr;
layer.type = 'WebGlLayer';

context.model.sharedModel.updateLayer(layerId, layer);
cancel();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -252,6 +252,7 @@ const SingleBandPseudoColor = ({

layer.parameters.symbologyState = symbologyState;
layer.parameters.color = colorExpr;
layer.type = 'WebGlLayer';

context.model.sharedModel.updateLayer(layerId, layer);
cancel();
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import React, { useEffect, useState } from 'react';
import { ISymbologyDialogProps } from '../symbologyDialog';
import Categorized from './types/Categorized';
import Graduated from './types/Graduated';
import Heatmap from './types/Heatmap';
import SimpleSymbol from './types/SimpleSymbol';
import Categorized from './types/Categorized';

const VectorRendering = ({
context,
Expand All @@ -11,7 +12,7 @@ const VectorRendering = ({
cancel,
layerId
}: ISymbologyDialogProps) => {
const [selectedRenderType, setSelectedRenderType] = useState('Single Symbol');
const [selectedRenderType, setSelectedRenderType] = useState('');
const [componentToRender, setComponentToRender] = useState<any>(null);
const [renderTypeOptions, setRenderTypeOptions] = useState<string[]>([
'Single Symbol'
Expand All @@ -28,13 +29,14 @@ const VectorRendering = ({
}

useEffect(() => {
const renderType = layer.parameters?.symbologyState?.renderType;
setSelectedRenderType(renderType ?? 'Single Symbol');

if (layer.type === 'VectorLayer') {
const options = ['Single Symbol', 'Graduated', 'Categorized'];
setRenderTypeOptions(options);
let renderType = layer.parameters?.symbologyState?.renderType;
if (!renderType) {
renderType = layer.type === 'HeatmapLayer' ? 'Heatmap' : 'Single Symbol';
}
setSelectedRenderType(renderType);

const options = ['Single Symbol', 'Graduated', 'Categorized', 'Heatmap'];
setRenderTypeOptions(options);
}, []);

useEffect(() => {
Expand Down Expand Up @@ -72,8 +74,19 @@ const VectorRendering = ({
/>
);
break;
case 'Heatmap':
RenderComponent = (
<Heatmap
context={context}
state={state}
okSignalPromise={okSignalPromise}
cancel={cancel}
layerId={layerId}
/>
);
break;
default:
RenderComponent = <div>Render Type Not Implemented (yet)</div>;
RenderComponent = <div>Select a render type</div>;
}
setComponentToRender(RenderComponent);
}, [selectedRenderType]);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
import { IVectorLayer } from '@jupytergis/schema';
import { ReadonlyJSONObject } from '@lumino/coreutils';
import { ExpressionValue } from 'ol/expr/expression';
import React, { useEffect, useRef, useState } from 'react';
import ValueSelect from '../components/ValueSelect';
import { IStopRow, ISymbologyDialogProps } from '../../symbologyDialog';
import { useGetProperties } from '../../hooks/useGetProperties';
import ColorRamp from '../../components/color_ramp/ColorRamp';
import StopContainer from '../../components/color_stops/StopContainer';
import { useGetProperties } from '../../hooks/useGetProperties';
import { IStopRow, ISymbologyDialogProps } from '../../symbologyDialog';
import { Utils, VectorUtils } from '../../symbologyUtils';
import ColorRamp from '../../components/color_ramp/ColorRamp';
import { ReadonlyJSONObject } from '@lumino/coreutils';
import { ExpressionValue } from 'ol/expr/expression';
import { IVectorLayer } from '@jupytergis/schema';
import ValueSelect from '../components/ValueSelect';

const Categorized = ({
context,
Expand Down Expand Up @@ -125,6 +125,7 @@ const Categorized = ({

layer.parameters.symbologyState = symbologyState;
layer.parameters.color = newStyle;
layer.type = 'VectorLayer';

context.model.sharedModel.updateLayer(layerId, layer);
cancel();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,7 @@ const Graduated = ({

layer.parameters.symbologyState = symbologyState;
layer.parameters.color = newStyle;
layer.type = 'VectorLayer';

context.model.sharedModel.updateLayer(layerId, layer);
cancel();
Expand Down
128 changes: 128 additions & 0 deletions packages/base/src/dialogs/symbology/vector_layer/types/Heatmap.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
import colormap from 'colormap';
import React, { useEffect, useRef, useState } from 'react';
import CanvasSelectComponent from '../../components/color_ramp/CanvasSelectComponent';
import { ISymbologyDialogProps } from '../../symbologyDialog';

const Heatmap = ({
context,
state,
okSignalPromise,
cancel,
layerId
}: ISymbologyDialogProps) => {
if (!layerId) {
return;
}
const layer = context.model.getLayer(layerId);
if (!layer?.parameters) {
return;
}
const [selectedRamp, setSelectedRamp] = useState('');
const [heatmapOptions, setHetamapOptions] = useState({
radius: 8,
blur: 15
});
const selectedRampRef = useRef('cool');
const heatmapOptionsRef = useRef({
radius: 8,
blur: 15
});

useEffect(() => {
populateOptions();

okSignalPromise.promise.then(okSignal => {
okSignal.connect(handleOk, this);
});

return () => {
okSignalPromise.promise.then(okSignal => {
okSignal.disconnect(handleOk, this);
});
};
}, []);

useEffect(() => {
selectedRampRef.current = selectedRamp;
heatmapOptionsRef.current = heatmapOptions;
}, [selectedRamp, heatmapOptions]);

const populateOptions = async () => {
let colorRamp;

if (layer.parameters?.symbologyState) {
colorRamp = layer.parameters.symbologyState.colorRamp;
}

setSelectedRamp(colorRamp ? colorRamp : 'cool');
};

const handleOk = () => {
if (!layer.parameters) {
return;
}

const colorMap = colormap({
colormap: selectedRampRef.current,
nshades: 9,
format: 'hex'
});

const symbologyState = {
renderType: 'Heatmap',
colorRamp: selectedRampRef.current
};

layer.parameters.symbologyState = symbologyState;
layer.parameters.color = colorMap;
layer.parameters.blur = heatmapOptionsRef.current.blur;
layer.parameters.radius = heatmapOptionsRef.current.radius;
layer.type = 'HeatmapLayer';

context.model.sharedModel.updateLayer(layerId, layer);

cancel();
};

return (
<div className="jp-gis-layer-symbology-container">
<div className="jp-gis-symbology-row">
<label htmlFor="color-ramp-select">Color Ramp:</label>
<CanvasSelectComponent
selectedRamp={selectedRamp}
setSelected={setSelectedRamp}
/>
</div>
<div className="jp-gis-symbology-row">
<label htmlFor={'vector-value-select'}>Radius:</label>
<input
type="number"
value={heatmapOptions.radius}
className="jp-mod-styled"
onChange={event =>
setHetamapOptions(prevState => ({
...prevState,
radius: +event.target.value
}))
}
/>
</div>
<div className="jp-gis-symbology-row">
<label htmlFor={'vector-value-select'}>Blur:</label>
<input
type="number"
value={heatmapOptions.blur}
className="jp-mod-styled"
onChange={event =>
setHetamapOptions(prevState => ({
...prevState,
blur: +event.target.value
}))
}
/>
</div>
</div>
);
};

export default Heatmap;
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,7 @@ const SimpleSymbol = ({

layer.parameters.symbologyState = symbologyState;
layer.parameters.color = styleExpr;
layer.type = 'VectorLayer';

context.model.sharedModel.updateLayer(layerId, layer);
cancel();
Expand Down
7 changes: 5 additions & 2 deletions packages/base/src/formbuilder/formselectors.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
import { LayerType, SourceType } from '@jupytergis/schema';
import { BaseForm } from './objectform/baseform';
import { GeoJSONSourcePropertiesForm } from './objectform/geojsonsource';
import { GeoTiffSourcePropertiesForm } from './objectform/geotiffsource';
import { HeatmapLayerPropertiesForm } from './objectform/heatmapLayerForm';
import { HillshadeLayerPropertiesForm } from './objectform/hillshadeLayerForm';
import { LayerPropertiesForm } from './objectform/layerform';
import { PathBasedSourcePropertiesForm } from './objectform/pathbasedsource';
import { TileSourcePropertiesForm } from './objectform/tilesourceform';
import { VectorLayerPropertiesForm } from './objectform/vectorlayerform';
import { WebGlLayerPropertiesForm } from './objectform/webGlLayerForm';
import { GeoTiffSourcePropertiesForm } from './objectform/geotiffsource';
import { PathBasedSourcePropertiesForm } from './objectform/pathbasedsource';

export function getLayerTypeForm(
layerType: LayerType
Expand All @@ -25,6 +26,8 @@ export function getLayerTypeForm(
case 'WebGlLayer':
LayerForm = WebGlLayerPropertiesForm;
break;
case 'HeatmapLayer':
LayerForm = HeatmapLayerPropertiesForm;
// ADD MORE FORM TYPES HERE
}

Expand Down
Loading