1- import React from 'react'
21import { Feature } from 'geojson'
32import { TreeDataNode } from 'antd'
4- import { FolderOutlined , PlusCircleOutlined } from '@ant-design/icons'
5- import { Tooltip } from 'antd'
6- import { FeatureIcon } from './FeatureIcon'
73import { symbolOptions } from '../../helpers/symbolTypes'
8- import { EnvOptions } from '../../types'
4+ import { EnvOptions , FeatureTypes } from '../../types'
5+ import { featureIsVisibleInPeriod } from '../../helpers/featureIsVisibleAtTime'
6+ import { BUOY_FIELD_TYPE , ZONE_TYPE , REFERENCE_POINT_TYPE , BACKDROP_TYPE } from '../../constants'
97
108// Import node constants from the constants file
119import {
@@ -22,8 +20,20 @@ type FieldDataNode = {
2220 children : FieldDataNode [ ]
2321}
2422
23+ // Import React for type definitions
24+ import React from 'react'
25+
26+ // Using React.MouseEvent for the event type
2527export type HandleAddFunction = ( e : React . MouseEvent , key : string , title : string ) => void
2628
29+ // Interface for icon creators to be passed from Layers component
30+ export interface IconCreators {
31+ createFolderIcon : ( ) => React . ReactNode
32+ createFeatureIcon : ( dataType : string , color ?: string , environment ?: string ) => React . ReactNode
33+ createAddIcon : ( key : string , title : string , handleAdd : HandleAddFunction ) => React . ReactNode
34+ createTitleElement : ( title : string ) => React . ReactNode
35+ }
36+
2737export class TreeDataBuilder {
2838 /**
2939 * Get the name for a feature
@@ -88,74 +98,78 @@ export class TreeDataBuilder {
8898 }
8999
90100 /**
91- * Get the icon for a node
101+ * Get the appropriate icon for a node using the provided icon creators
92102 * @param feature The feature (if any)
93103 * @param key The node key
94104 * @param title The node title
95105 * @param handleAdd The add handler function
106+ * @param iconCreators The icon creator functions
96107 * @param button Optional custom button
97108 * @returns The icon React node
98109 */
99110 static getIcon (
100111 feature : Feature | undefined ,
101112 key : string ,
102113 title : string ,
103- handleAdd ?: HandleAddFunction ,
114+ handleAdd : HandleAddFunction | undefined ,
115+ iconCreators : IconCreators ,
104116 button ?: React . ReactNode
105117 ) : React . ReactNode {
106118 // If no feature is provided, this is a parent node - show plus icon
107119 if ( ! feature ) {
108120 if ( ! handleAdd ) return null
109-
110121 if ( button ) return button
111-
112- return (
113- < Tooltip title = { this . addIconLabelFor ( key , title ) } >
114- < PlusCircleOutlined
115- className = "add-icon"
116- style = { { cursor : 'copy' } }
117- onClick = { ( e : React . MouseEvent ) => handleAdd ( e , key , title ) }
118- />
119- </ Tooltip >
120- )
122+ return iconCreators . createAddIcon ( key , title , handleAdd )
121123 }
122124
123125 // For leaf nodes, show type-specific icon based on dataType
124126 const dataType = feature . properties ?. dataType
125127 const color = feature . properties ?. stroke || feature . properties ?. color || feature . properties ?. [ 'marker-color' ]
126128 const environment = feature . properties ?. env
127- return dataType ? < FeatureIcon dataType = { dataType } color = { color } environment = { environment } /> : < FolderOutlined />
129+ return dataType
130+ ? iconCreators . createFeatureIcon ( dataType , color , environment )
131+ : iconCreators . createFolderIcon ( )
128132 }
129133
130134 /**
131135 * Build a track node
132136 * @param features The features to include
133137 * @param handleAdd The add handler function
138+ * @param iconCreators The icon creator functions
139+ * @param useTimeFilter Whether to filter by time
134140 * @returns A TreeDataNode for tracks
135141 */
136- static buildTrackNode ( features : Feature [ ] , handleAdd : HandleAddFunction ) : TreeDataNode {
142+ static buildTrackNode (
143+ features : Feature [ ] ,
144+ handleAdd : HandleAddFunction ,
145+ iconCreators : IconCreators ,
146+ useTimeFilter : boolean
147+ ) : TreeDataNode {
137148 // generate new root
138149 const root : TreeDataNode = {
139150 title : 'Units' ,
140151 key : NODE_TRACKS ,
141- icon : < FolderOutlined /> ,
152+ icon : iconCreators . createFolderIcon ( ) ,
142153 children : [ ] ,
143154 }
144155 const environments = symbolOptions . map ( ( env ) : TreeDataNode => ( {
145156 title : env . label ,
146157 key : env . value ,
147- icon : this . getIcon ( undefined , NODE_TRACKS , env . value , handleAdd , undefined ) ,
158+ icon : this . getIcon ( undefined , NODE_TRACKS , env . value , handleAdd , iconCreators ) ,
148159 children : features
149160 . filter ( feature => feature . properties ?. env === env . value )
150161 . map ( ( feature ) : TreeDataNode => ( {
151162 title : this . nameFor ( feature ) ,
152163 key : this . idFor ( feature ) ,
153- icon : this . getIcon ( feature , this . idFor ( feature ) , this . nameFor ( feature ) , undefined , undefined ) ,
164+ icon : this . getIcon ( feature , this . idFor ( feature ) , this . nameFor ( feature ) , undefined , iconCreators ) ,
154165 children : [ ] ,
155166 } ) )
156167 } ) )
157168
158- root . children = root . children ? root . children . concat ( ...environments ) : [ ...environments ]
169+ // if time filter is applied, only include environments that contain features
170+ const validEnvironments = useTimeFilter ? environments . filter ( env => ! ! env . children ?. length ) : environments
171+
172+ root . children = root . children ? root . children . concat ( ...validEnvironments ) : [ ...validEnvironments ]
159173 return root
160174 }
161175
@@ -166,36 +180,37 @@ export class TreeDataBuilder {
166180 * @param key The node key
167181 * @param dType The data type to filter by
168182 * @param handleAdd The add handler function
169- * @param button Optional custom button
183+ * @param iconCreators The icon creator functions
184+ * @param useTimeFilter Whether to filter by time
170185 * @returns A TreeDataNode for the specified type
171186 */
172187 static buildTypeNode (
173188 features : Feature [ ] ,
174189 title : string ,
175190 key : string ,
176- dType : string ,
191+ dType : FeatureTypes ,
177192 handleAdd : HandleAddFunction ,
178- button ?: React . ReactNode
179- ) : TreeDataNode {
193+ iconCreators : IconCreators ,
194+ useTimeFilter : boolean ,
195+ iconOverride ?: React . ReactNode
196+ ) : TreeDataNode | null {
180197 const children = features
181198 ? this . findChildrenOfType ( features , dType ) . map ( child => {
182199 // Find the corresponding feature for this child
183200 const feature = features . find ( f => this . idFor ( f ) === child . key )
184201 return {
185202 ...child ,
186- icon : this . getIcon ( feature , child . key , child . title , handleAdd , button ) ,
203+ icon : this . getIcon ( feature , child . key , child . title , handleAdd , iconCreators ) ,
187204 }
188205 } )
189206 : [ ]
190207
208+ if ( useTimeFilter && ! children . length ) return null
209+
191210 return {
192- title : (
193- < span >
194- { title }
195- </ span >
196- ) ,
211+ title : iconCreators . createTitleElement ( title ) ,
197212 key,
198- icon : this . getIcon ( undefined , key , title , handleAdd , button ) , // Parent node gets plus icon
213+ icon : iconOverride || this . getIcon ( undefined , key , title , handleAdd , iconCreators ) , // Parent node gets plus icon
199214 children,
200215 }
201216 }
@@ -204,15 +219,37 @@ export class TreeDataBuilder {
204219 * Build the complete tree data model
205220 * @param features The features to include
206221 * @param handleAdd The add handler function
222+ * @param iconCreators The icon creator functions
223+ * @param useTimeFilter Whether to filter features by time
224+ * @param timeStart The start time for filtering (if useTimeFilter is true)
225+ * @param timeEnd The end time for filtering (if useTimeFilter is true)
207226 * @returns An array of TreeDataNode objects representing the complete tree
208227 */
209- static buildTreeModel ( features : Feature [ ] , handleAdd : HandleAddFunction ) : TreeDataNode [ ] {
228+ static buildTreeModel (
229+ features : Feature [ ] ,
230+ handleAdd : HandleAddFunction ,
231+ iconCreators : IconCreators ,
232+ useTimeFilter : boolean = false ,
233+ timeStart : number ,
234+ timeEnd : number ,
235+ zonesIcon : React . ReactNode
236+ ) : Array < TreeDataNode | null > {
237+ // If time filtering is enabled, filter the features
238+ let filteredFeatures = features
239+ if ( useTimeFilter && timeStart !== 0 && timeEnd !== 0 ) {
240+ // Filter features based on time properties
241+ filteredFeatures = features . filter ( feature =>
242+ // Include features that are visible in the current time period (or don't have time)
243+ featureIsVisibleInPeriod ( feature , timeStart , timeEnd )
244+ )
245+ }
246+
210247 return [
211- this . buildTrackNode ( features , handleAdd ) ,
212- this . buildTypeNode ( features , 'Buoy Fields' , NODE_FIELDS , 'buoy-field' , handleAdd ) ,
213- this . buildTypeNode ( features , 'Zones' , NODE_ZONES , 'zone' , handleAdd ) ,
214- this . buildTypeNode ( features , 'Reference Points' , NODE_POINTS , 'reference-point' , handleAdd ) ,
215- this . buildTypeNode ( features , 'Backdrops' , NODE_BACKDROPS , 'backdrop' , handleAdd ) ,
248+ this . buildTrackNode ( filteredFeatures , handleAdd , iconCreators , useTimeFilter ) ,
249+ this . buildTypeNode ( filteredFeatures , 'Buoy Fields' , NODE_FIELDS , BUOY_FIELD_TYPE , handleAdd , iconCreators , useTimeFilter , undefined ) ,
250+ this . buildTypeNode ( filteredFeatures , 'Zones' , NODE_ZONES , ZONE_TYPE , handleAdd , iconCreators , useTimeFilter , zonesIcon ) ,
251+ this . buildTypeNode ( filteredFeatures , 'Reference Points' , NODE_POINTS , REFERENCE_POINT_TYPE , handleAdd , iconCreators , useTimeFilter , undefined ) ,
252+ this . buildTypeNode ( filteredFeatures , 'Backdrops' , NODE_BACKDROPS , BACKDROP_TYPE , handleAdd , iconCreators , useTimeFilter , undefined ) ,
216253 ]
217254 }
218255
0 commit comments