@@ -3,6 +3,7 @@ import { useRef, useEffect, useState, useMemo, useCallback } from 'react';
33import { DeckGL } from '@deck.gl/react' ;
44import {
55 GeoJsonLayer ,
6+ IconLayer ,
67 PointCloudLayer ,
78 PolygonLayer ,
89 TextLayer ,
@@ -11,6 +12,8 @@ import { DataFilterExtension, PathStyleExtension } from '@deck.gl/extensions';
1112
1213import positron from 'constants/mapStyles/positron.json' ;
1314import no_label from 'constants/mapStyles/positron_nolabel.json' ;
15+ // eslint-disable-next-line import/no-unresolved
16+ import starFillIcon from 'assets/icons/star-fill.svg?url' ;
1417
1518import * as turf from '@turf/turf' ;
1619import './Map.css' ;
@@ -244,23 +247,114 @@ const useMapLayers = (onHover = () => {}) => {
244247 } ) ,
245248 ) ;
246249
247- _layers . push (
248- new GeoJsonLayer ( {
249- id : `${ name } -nodes` ,
250- data : mapLayers [ name ] ?. nodes ,
251- getFillColor : ( f ) => nodeFillColor ( f . properties [ 'type' ] ) ,
252- getPointRadius : ( f ) => nodeRadius ( f . properties [ 'type' ] ) ,
253- getLineColor : ( f ) => nodeLineColor ( f . properties [ 'type' ] ) ,
254- getLineWidth : 1 ,
255- updateTriggers : {
256- getPointRadius : [ scale ] ,
257- } ,
258- onHover : onHover ,
259- pickable : true ,
260-
261- parameters : { depthTest : false } ,
262- } ) ,
250+ // Partition nodes by type
251+ const nodesData = mapLayers [ name ] ?. nodes ;
252+ const { plantNodes, consumerNodes, noneNodes } = (
253+ nodesData ?. features ?? [ ]
254+ ) . reduce (
255+ ( acc , feature ) => {
256+ const type = feature . properties [ 'type' ] ;
257+ if ( type === 'PLANT' ) {
258+ acc . plantNodes . push ( feature ) ;
259+ } else if ( type === 'CONSUMER' ) {
260+ acc . consumerNodes . push ( feature ) ;
261+ } else {
262+ acc . noneNodes . push ( feature ) ;
263+ }
264+ return acc ;
265+ } ,
266+ { plantNodes : [ ] , consumerNodes : [ ] , noneNodes : [ ] } ,
263267 ) ;
268+
269+ // Add GeoJsonLayer for NONE nodes - rendered first (bottom layer)
270+ if ( noneNodes . length > 0 ) {
271+ _layers . push (
272+ new GeoJsonLayer ( {
273+ id : `${ name } -none-nodes` ,
274+ data : {
275+ type : 'FeatureCollection' ,
276+ features : noneNodes ,
277+ } ,
278+ getFillColor : ( f ) => nodeFillColor ( f . properties [ 'type' ] ) ,
279+ getPointRadius : ( f ) => nodeRadius ( f . properties [ 'type' ] ) ,
280+ getLineColor : ( f ) => nodeLineColor ( f . properties [ 'type' ] ) ,
281+ getLineWidth : 1 ,
282+ updateTriggers : {
283+ getPointRadius : [ scale ] ,
284+ } ,
285+ onHover : onHover ,
286+ pickable : true ,
287+ parameters : { depthTest : false } ,
288+ } ) ,
289+ ) ;
290+ }
291+
292+ // Add GeoJsonLayer for CONSUMER nodes - rendered second (above NONE nodes)
293+ if ( consumerNodes . length > 0 ) {
294+ _layers . push (
295+ new GeoJsonLayer ( {
296+ id : `${ name } -consumer-nodes` ,
297+ data : {
298+ type : 'FeatureCollection' ,
299+ features : consumerNodes ,
300+ } ,
301+ getFillColor : ( f ) => nodeFillColor ( f . properties [ 'type' ] ) ,
302+ getPointRadius : ( f ) => nodeRadius ( f . properties [ 'type' ] ) ,
303+ getLineColor : ( f ) => nodeLineColor ( f . properties [ 'type' ] ) ,
304+ getLineWidth : 1 ,
305+ updateTriggers : {
306+ getPointRadius : [ scale ] ,
307+ } ,
308+ onHover : onHover ,
309+ pickable : true ,
310+ parameters : { depthTest : false } ,
311+ } ) ,
312+ ) ;
313+ }
314+
315+ // Add IconLayer for plant nodes with star icon
316+ // Rendered after other nodes to appear on top
317+ if ( plantNodes . length > 0 ) {
318+ // Use bright yellow for high visibility and to complement blue/red edges
319+ const plantColor = [ 255 , 209 , 29 , 255 ] ; // Bright yellow
320+
321+ _layers . push (
322+ new IconLayer ( {
323+ id : `${ name } -plant-nodes` ,
324+ data : plantNodes ,
325+ getIcon : ( ) => ( {
326+ url : starFillIcon ,
327+ width : 64 ,
328+ height : 64 ,
329+ anchorY : 32 ,
330+ mask : true ,
331+ } ) ,
332+ getPosition : ( f ) => {
333+ const coords = f . geometry . coordinates ;
334+ // Add z-elevation of 3 meters to lift icon above the map
335+ return [ coords [ 0 ] , coords [ 1 ] , 3 ] ;
336+ } ,
337+ getSize : 10 * scale ,
338+ getColor : plantColor ,
339+ sizeUnits : 'meters' ,
340+ sizeMinPixels : 20 ,
341+ billboard : true ,
342+ loadOptions : {
343+ imagebitmap : {
344+ resizeWidth : 64 ,
345+ resizeHeight : 64 ,
346+ resizeQuality : 'high' ,
347+ } ,
348+ } ,
349+ onHover : onHover ,
350+ pickable : true ,
351+ updateTriggers : {
352+ getSize : [ scale ] ,
353+ } ,
354+ parameters : { depthTest : false } ,
355+ } ) ,
356+ ) ;
357+ }
264358 }
265359
266360 if ( name == DEMAND && mapLayers ?. [ name ] ) {
0 commit comments