diff --git a/libs/shared/lib/vis/visualizations/mapvis/components/layers/node-layer/NodeLayer.tsx b/libs/shared/lib/vis/visualizations/mapvis/components/layers/node-layer/NodeLayer.tsx index b4743857a0e8967adc314c71fbc59aa3dfdc241f..9b1b68f2da5fce1453c07ed8eba26ca4276ff0c3 100644 --- a/libs/shared/lib/vis/visualizations/mapvis/components/layers/node-layer/NodeLayer.tsx +++ b/libs/shared/lib/vis/visualizations/mapvis/components/layers/node-layer/NodeLayer.tsx @@ -73,7 +73,7 @@ export class NodeLayer extends CompositeLayer<LayerProps> { } renderLayers() { - const { graph, config, visible } = this.props; + const { graph, config, visible, getNodeLocation } = this.props; return new ScatterplotLayer({ hidden: visible, @@ -85,7 +85,7 @@ export class NodeLayer extends CompositeLayer<LayerProps> { radiusMinPixels: 7, radiusMaxPixels: 100, lineWidthMinPixels: 1, - getPosition: (d: any) => [d.attributes.long, d.attributes.lat], + getPosition: (d: any) => getNodeLocation(d.id), getFillColor: (d: any) => this.getColor(d, config.fillColor), getRadius: (d: any) => 5, }); diff --git a/libs/shared/lib/vis/visualizations/mapvis/mapvis.tsx b/libs/shared/lib/vis/visualizations/mapvis/mapvis.tsx index 31061e1ca0b8e1674d13aff4c1395d2cdcc80157..c8aed62f7579addc33eb9c985754c90e90d67cba 100644 --- a/libs/shared/lib/vis/visualizations/mapvis/mapvis.tsx +++ b/libs/shared/lib/vis/visualizations/mapvis/mapvis.tsx @@ -2,22 +2,25 @@ import React, { useEffect } from 'react'; import DeckGL from '@deck.gl/react/typed'; import { FlyToInterpolator, MapView, WebMercatorViewport } from '@deck.gl/core/typed'; import { SelectionLayer } from '@nebula.gl/layers'; - -import GraphModel from './graphModel'; -import { GraphType, Layer } from './mapvis.types'; +import { Coordinate, Layer } from './mapvis.types'; import { VISComponentType, VisualizationPropTypes } from '../../common'; import { GraphMetaData } from '@graphpolaris/shared/lib/data-access/statistics'; import { SettingsContainer } from '../../components/config'; import { layerTypes } from './components/layers'; import { createBaseMap } from './components/BaseMap'; import { Input } from '../../..'; +import { getProperty } from './utlis'; export type MapProps = { layer: undefined | 'node' | 'nodelink' | 'choropleth' | 'heatmap'; + lat: undefined; + lon: undefined; }; const configuration: MapProps = { layer: 'node', + lat: undefined, + lon: undefined, }; const INITIAL_VIEW_STATE = { @@ -31,7 +34,7 @@ const INITIAL_VIEW_STATE = { const FLY_SPEED = 1000; export const MapVis = ({ data, configuration }: VisualizationPropTypes) => { - const [layers, setLayers] = React.useState<Layer | undefined>(undefined); + const [layer, setLayer] = React.useState<Layer | undefined>(undefined); const [viewport, setViewport] = React.useState<Record<string, any>>(INITIAL_VIEW_STATE); const [hoverObject, setHoverObject] = React.useState<any>(null); const [selected, setSelected] = React.useState<any[]>([]); @@ -65,7 +68,7 @@ export const MapVis = ({ data, configuration }: VisualizationPropTypes) => { if (configuration.layer) { const layerType = layerTypes[configuration.layer] as any; - setLayers({ + setLayer({ id: Date.now(), name: 'New layer', type: layerType, @@ -77,16 +80,31 @@ export const MapVis = ({ data, configuration }: VisualizationPropTypes) => { } }, [configuration.layer]); + const coordinateLookup: { [id: string]: Coordinate } = data.nodes.reduce( + (acc, node) => { + const latitude = getProperty(node, configuration.lat.split('.')); + const longitude = getProperty(node, configuration.lon.split('.')); + + if (latitude !== undefined && longitude !== undefined) { + acc[node.id] = [latitude, longitude]; + } + + return acc; + }, + {} as { [id: string]: Coordinate }, + ); + const dataLayer = - layers && - new layers.type({ - id: `${layers.id}`, + layer && + new layer.type({ + id: `${layer.id}`, graph: data, - visible: layers.visible, - config: layers.config, + visible: layer.visible, + config: layer.config, selected: selected, hoverObject: hoverObject, isSelecting: isSelecting, + getNodeLocation: (id: string) => coordinateLookup[id], flyToBoundingBox: flyToBoundingBox, }); @@ -99,7 +117,7 @@ export const MapVis = ({ data, configuration }: VisualizationPropTypes) => { setSelected(pickingInfos.map((item: any) => item.object)); setSelectingRectangle(false); }, - layerIds: [layers?.id ? layers.id : ''], + layerIds: [layer?.id ? layer.id : ''], getTentativeFillColor: () => [22, 37, 67, 100], }); @@ -144,14 +162,35 @@ const MapSettings = ({ graph: GraphMetaData; updateSettings: (val: any) => void; }) => { + const attributePaths = new Set(Object.values(graph.nodes.types).flatMap((type) => Object.keys(type.attributes))); + return ( <SettingsContainer> + <span className="text-xs font-semibold">Data layer</span> <Input type="dropdown" value={configuration.layer} options={['node', 'nodelink', 'choropleth', 'heatmap']} onChange={(val) => updateSettings({ layer: val })} /> + + <span className="text-xs font-semibold">Location accessor (lat)</span> + <Input + type="dropdown" + value={configuration.lat} + options={[...attributePaths]} + disabled={attributePaths.size < 1} + onChange={(val) => updateSettings({ lat: val })} + /> + + <span className="text-xs font-semibold">Location accessor (lon)</span> + <Input + type="dropdown" + value={configuration.lon} + options={[...attributePaths]} + disabled={attributePaths.size < 1} + onChange={(val) => updateSettings({ lon: val })} + /> </SettingsContainer> ); }; diff --git a/libs/shared/lib/vis/visualizations/mapvis/utlis.tsx b/libs/shared/lib/vis/visualizations/mapvis/utlis.tsx index 9865d0806bbb4409e26ce545dcbdc329585a7c39..4c10b45774ef0f10857d5cb32123ef5857ab7a26 100644 --- a/libs/shared/lib/vis/visualizations/mapvis/utlis.tsx +++ b/libs/shared/lib/vis/visualizations/mapvis/utlis.tsx @@ -14,24 +14,6 @@ export const getProperty = (obj: any, accessorString: string): any => { return value; }; -export const makeLayer = (type: string): Layer => { - const layerType = layerTypes[type] as any; - - if (!layerType) { - throw new Error(`Invalid layer type: ${type}`); - } - - return { - id: Date.now(), - name: 'New layer', - type: layerType, - config: { - ...layerType.layerOptions, - }, - visible: true, - }; -}; - export const getLocationInfo = async (search: string) => { try { const query: string = encodeURIComponent(search);