From 47ebac6a8ac6008803a0c06a6c47986734f45fb2 Mon Sep 17 00:00:00 2001
From: "Vink, S.A. (Sjoerd)" <s.a.vink@uu.nl>
Date: Tue, 9 Jul 2024 12:11:22 +0200
Subject: [PATCH] feat(map_nodelink): cleanup

---
 .../layers/heatmap-layer/HeatLayerOptions.tsx | 27 +++------
 .../visualizations/mapvis/layers/index.tsx    |  8 +--
 .../layers/nodelink-layer/NodeLinkLayer.tsx   | 23 +++++---
 .../layers/nodelink-layer/NodeLinkOptions.tsx | 51 +++++++++++++---
 .../visualizations/mapvis/mapvis.stories.tsx  | 58 -------------------
 5 files changed, 70 insertions(+), 97 deletions(-)

diff --git a/libs/shared/lib/vis/visualizations/mapvis/layers/heatmap-layer/HeatLayerOptions.tsx b/libs/shared/lib/vis/visualizations/mapvis/layers/heatmap-layer/HeatLayerOptions.tsx
index 374870547..2007d3330 100644
--- a/libs/shared/lib/vis/visualizations/mapvis/layers/heatmap-layer/HeatLayerOptions.tsx
+++ b/libs/shared/lib/vis/visualizations/mapvis/layers/heatmap-layer/HeatLayerOptions.tsx
@@ -1,8 +1,8 @@
 import React, { useState, useMemo, useEffect } from 'react';
 import { VisualizationSettingsPropTypes } from '@graphpolaris/shared/lib/vis/common';
 import { MapProps } from '../../mapvis';
-import { EntityPill, Icon, Input } from '@graphpolaris/shared/lib/components';
-import { SubdirectoryArrowRight } from '@mui/icons-material';
+import { Button, EntityPill, Icon, Input } from '@graphpolaris/shared/lib/components';
+import { SubdirectoryArrowRight, Visibility, VisibilityOff } from '@mui/icons-material';
 
 export default function HeatLayerOptions({ settings, graphMetadata, updateSettings }: VisualizationSettingsPropTypes<MapProps>) {
   const [collapsed, setCollapsed] = useState<Record<string, boolean>>({});
@@ -49,10 +49,13 @@ export default function HeatLayerOptions({ settings, graphMetadata, updateSettin
               <EntityPill title={nodeType} />
             </div>
             <div className="w-1/2">
-              {/* <ColorPicker
-                value={settings?.[nodeType]?.['color'] ? settings?.[nodeType]?.['color'] : [0, 0, 0]}
-                updateValue={(val: number[]) => updateSettings({ [nodeType]: { ...settings?.[nodeType], color: val } })}
-              /> */}
+              <Button
+                iconComponent={settings?.[nodeType].hidden ? <VisibilityOff /> : <Visibility />}
+                variant="ghost"
+                onClick={() => {
+                  updateSettings({ [nodeType]: { ...settings?.[nodeType], hidden: !settings?.[nodeType].hidden as boolean } });
+                }}
+              />
             </div>
           </div>
 
@@ -77,18 +80,6 @@ export default function HeatLayerOptions({ settings, graphMetadata, updateSettin
                 disabled={!settings.node || spatialAttributes[nodeType].length < 1}
                 onChange={(val) => updateSettings({ [nodeType]: { ...settings?.[nodeType], lat: val as string } })}
               />
-
-              <div className="ml-2">
-                <div className="flex items-center gap-1">
-                  <Icon component={<SubdirectoryArrowRight />} size={16} color="text-secondary-300" />
-                  <Input
-                    label="Hidden"
-                    type="boolean"
-                    value={settings?.[nodeType]?.hidden ?? false}
-                    onChange={(val: boolean) => updateSettings({ [nodeType]: { ...settings?.[nodeType], hidden: val } })}
-                  />
-                </div>
-              </div>
             </div>
           )}
         </div>
diff --git a/libs/shared/lib/vis/visualizations/mapvis/layers/index.tsx b/libs/shared/lib/vis/visualizations/mapvis/layers/index.tsx
index bda96ae30..fc09070cc 100644
--- a/libs/shared/lib/vis/visualizations/mapvis/layers/index.tsx
+++ b/libs/shared/lib/vis/visualizations/mapvis/layers/index.tsx
@@ -11,18 +11,18 @@ import ChoroplethOptions from './choropleth-layer/ChoroplethOptions';
 import { TileLayer, BitmapLayer } from 'deck.gl';
 
 export const layerTypes: Record<string, any> = {
-  node: NodeLayer,
-  icon: NodeIconLayer,
+  // node: NodeLayer,
+  // icon: NodeIconLayer,
   nodelink: NodeLinkLayer,
   heatmap: HeatLayer,
   // choropleth: ChoroplethLayer,
 };
 
 export const layerSettings: Record<string, any> = {
-  node: NodeOptions,
   nodelink: NodeLinkOptions,
-  icon: IconOptions,
   heatmap: HeatLayerOptions,
+  // node: NodeOptions,
+  // icon: IconOptions,
   // choropleth: ChoroplethOptions,
 };
 
diff --git a/libs/shared/lib/vis/visualizations/mapvis/layers/nodelink-layer/NodeLinkLayer.tsx b/libs/shared/lib/vis/visualizations/mapvis/layers/nodelink-layer/NodeLinkLayer.tsx
index 97bc58e72..25677d432 100644
--- a/libs/shared/lib/vis/visualizations/mapvis/layers/nodelink-layer/NodeLinkLayer.tsx
+++ b/libs/shared/lib/vis/visualizations/mapvis/layers/nodelink-layer/NodeLinkLayer.tsx
@@ -1,9 +1,10 @@
 import React from 'react';
 import { CompositeLayer } from 'deck.gl';
-import { LineLayer, ScatterplotLayer, TextLayer } from '@deck.gl/layers';
+import { IconLayer, LineLayer, ScatterplotLayer, TextLayer } from '@deck.gl/layers';
 import { LayerProps } from '../../mapvis.types';
 import { BrushingExtension, CollisionFilterExtension } from '@deck.gl/extensions';
 import { Edge, Node } from '@graphpolaris/shared/lib/data-access';
+import { createIcon } from './shapeFactory';
 
 export class NodeLinkLayer extends CompositeLayer<LayerProps> {
   static type = 'NodeLink';
@@ -26,19 +27,22 @@ export class NodeLinkLayer extends CompositeLayer<LayerProps> {
       layerIds.push(layerId);
 
       layers.push(
-        new ScatterplotLayer({
+        new IconLayer({
           id: layerId,
           visible: !config[label].hidden,
           data: graph.nodes.filter((node: Node) => node.label === label),
           pickable: true,
-          filled: true,
-          radiusScale: 6,
-          radiusMinPixels: 7,
-          radiusMaxPixels: 100,
-          lineWidthMinPixels: 1,
+          getColor: (d) => [200, 140, 0],
+          getSize: (d: any) => config[label].size,
           getPosition: (d: any) => getNodeLocation(d._id),
-          getFillColor: (d: any) => config[label].color,
-          getRadius: (d: any) => 5,
+          getIcon: (d: any) => {
+            return {
+              url: createIcon(config[label].shape ?? 'circle', config[label].color),
+              width: 24,
+              height: 24,
+            };
+          },
+          mask: true,
         }),
       );
     });
@@ -54,6 +58,7 @@ export class NodeLinkLayer extends CompositeLayer<LayerProps> {
         new LineLayer({
           id: layerId,
           data: edgeData,
+          visible: !config[label].hidden,
           pickable: true,
           getWidth: (d: any) => config[label].width,
           getSourcePosition: (d: any) => getNodeLocation(d.from),
diff --git a/libs/shared/lib/vis/visualizations/mapvis/layers/nodelink-layer/NodeLinkOptions.tsx b/libs/shared/lib/vis/visualizations/mapvis/layers/nodelink-layer/NodeLinkOptions.tsx
index abab54f01..07d7e97f8 100644
--- a/libs/shared/lib/vis/visualizations/mapvis/layers/nodelink-layer/NodeLinkOptions.tsx
+++ b/libs/shared/lib/vis/visualizations/mapvis/layers/nodelink-layer/NodeLinkOptions.tsx
@@ -1,9 +1,10 @@
-import React, { useState, useMemo, useEffect } from 'react';
+import React, { useState, useEffect } from 'react';
 import ColorPicker from '@graphpolaris/shared/lib/components/colorComponents/colorPicker';
 import { VisualizationSettingsPropTypes } from '@graphpolaris/shared/lib/vis/common';
 import { MapProps } from '../../mapvis';
-import { EntityPill, Icon, Input, RelationPill } from '@graphpolaris/shared/lib/components';
-import { SubdirectoryArrowRight } from '@mui/icons-material';
+import { Button, EntityPill, Icon, Input, RelationPill } from '@graphpolaris/shared/lib/components';
+import { SubdirectoryArrowRight, Visibility, VisibilityOff } from '@mui/icons-material';
+import { IconButton } from '@graphpolaris/shared/lib/components/buttons/button.stories';
 
 export default function NodeLinkOptions({ settings, graphMetadata, updateSettings }: VisualizationSettingsPropTypes<MapProps>) {
   const [collapsed, setCollapsed] = useState<Record<string, boolean>>({});
@@ -14,6 +15,8 @@ export default function NodeLinkOptions({ settings, graphMetadata, updateSetting
         [node]: {
           color: [0, 0, 0],
           hidden: false,
+          shape: '',
+          size: 10,
           fixed: true,
           min: 0,
           max: 10,
@@ -60,14 +63,21 @@ export default function NodeLinkOptions({ settings, graphMetadata, updateSetting
       {graphMetadata.nodes.labels.map((nodeType) => (
         <div className="mt-2" key={nodeType}>
           <div className="flex items-center">
-            <div className="w-3/4 mr-6 cursor-pointer" onClick={() => handleCollapseToggle(nodeType)}>
+            <div className="flex flex-grow mr-2 cursor-pointer" onClick={() => handleCollapseToggle(nodeType)}>
               <EntityPill title={nodeType} />
             </div>
-            <div className="w-1/2">
+            <div className="flex items-center space-x-2">
               <ColorPicker
                 value={settings?.[nodeType]?.['color'] ? settings?.[nodeType]?.['color'] : [0, 0, 0]}
                 updateValue={(val: number[]) => updateSettings({ [nodeType]: { ...settings?.[nodeType], color: val } })}
               />
+              <Button
+                iconComponent={settings?.[nodeType].hidden ? <VisibilityOff /> : <Visibility />}
+                variant="ghost"
+                onClick={() => {
+                  updateSettings({ [nodeType]: { ...settings?.[nodeType], hidden: !settings?.[nodeType].hidden as boolean } });
+                }}
+              />
             </div>
           </div>
 
@@ -92,6 +102,24 @@ export default function NodeLinkOptions({ settings, graphMetadata, updateSetting
                 disabled={!settings.node || spatialAttributes[nodeType].length < 1}
                 onChange={(val) => updateSettings({ [nodeType]: { ...settings?.[nodeType], lat: val as string } })}
               />
+              <Input
+                inline
+                label="Shape"
+                type="dropdown"
+                value={settings?.[nodeType]?.shape}
+                options={['circle', 'square', 'triangle', 'diamond', 'location', 'star']}
+                disabled={!settings.shape}
+                onChange={(val) => updateSettings({ [nodeType]: { ...settings?.[nodeType], shape: val as string } })}
+              />
+              <Input
+                label="Size"
+                type="slider"
+                min={0}
+                max={20}
+                step={1}
+                value={settings?.[nodeType]?.size}
+                onChange={(val) => updateSettings({ [nodeType]: { ...settings?.[nodeType], size: val as number } })}
+              />
             </div>
           )}
         </div>
@@ -99,15 +127,22 @@ export default function NodeLinkOptions({ settings, graphMetadata, updateSetting
 
       {graphMetadata.edges.labels.map((edgeType) => (
         <div className="mt-2" key={edgeType}>
-          <div className="flex items-center" onClick={() => handleCollapseToggle(edgeType)}>
-            <div className="w-3/4 mr-6 cursor-pointer">
+          <div className="flex items-center">
+            <div className="w-3/4 mr-6 cursor-pointer" onClick={() => handleCollapseToggle(edgeType)}>
               <RelationPill title={edgeType} />
             </div>
-            <div className="w-1/2">
+            <div className="w-1/2 flex">
               <ColorPicker
                 value={settings?.[edgeType]?.['color'] ? settings?.[edgeType]?.['color'] : [0, 0, 0]}
                 updateValue={(val: number[]) => updateSettings({ [edgeType]: { ...settings?.[edgeType], color: val } })}
               />
+              <Button
+                iconComponent={settings?.[edgeType].hidden ? <VisibilityOff /> : <Visibility />}
+                variant="ghost"
+                onClick={() => {
+                  updateSettings({ [edgeType]: { ...settings?.[edgeType], hidden: !settings?.[edgeType].hidden as boolean } });
+                }}
+              />
             </div>
           </div>
 
diff --git a/libs/shared/lib/vis/visualizations/mapvis/mapvis.stories.tsx b/libs/shared/lib/vis/visualizations/mapvis/mapvis.stories.tsx
index 6fbf525ff..a590ae956 100644
--- a/libs/shared/lib/vis/visualizations/mapvis/mapvis.stories.tsx
+++ b/libs/shared/lib/vis/visualizations/mapvis/mapvis.stories.tsx
@@ -34,64 +34,6 @@ const Component: Meta<typeof MapComponent.component> = {
   ],
 };
 
-export const Node = {
-  args: {
-    ...(await mockData.mockMobilityQueryResult()),
-    settings: {
-      layer: 'node',
-      parkings: {
-        color: [6, 147, 227],
-        fixed: true,
-        hidden: false,
-        lat: 'lat',
-        lon: 'long',
-        max: 10,
-        min: 0,
-        radius: 1,
-        sizeAttribute: '',
-      },
-      rides: {
-        color: [6, 147, 227],
-        fixed: true,
-        hidden: false,
-        max: 10,
-        min: 0,
-        width: 1,
-        widthAttribute: '',
-      },
-    },
-  },
-};
-
-export const Icon = {
-  args: {
-    ...(await mockData.mockMobilityQueryResult()),
-    settings: {
-      layer: 'icon',
-      parkings: {
-        color: [6, 147, 227],
-        fixed: true,
-        hidden: false,
-        lat: 'lat',
-        lon: 'long',
-        max: 10,
-        min: 0,
-        radius: 1,
-        sizeAttribute: '',
-      },
-      rides: {
-        color: [6, 147, 227],
-        fixed: true,
-        hidden: false,
-        max: 10,
-        min: 0,
-        width: 1,
-        widthAttribute: '',
-      },
-    },
-  },
-};
-
 export const NodeLink = {
   args: {
     ...(await mockData.mockMobilityQueryResult()),
-- 
GitLab