import "./legend.scss" ; import { ID , Shape , Symbol , Type } from "facilmap-types" ; import { symbolList } from "facilmap-leaflet" ; import { getBrightness } from "facilmap-utils" ; import { MapContext } from "../leaflet-map/leaflet-map" ; import { Client } from "../../utils/decorators" ; export interface LegendType { type : Type [ 'type' ] ; typeId : ID ; name : string ; items : LegendItem [ ] ; filtered : boolean ; defaultColour ? : string ; defaultShape ? : Shape ; } export interface LegendItem { value : string ; label ? : string ; field ? : string ; filtered ? : boolean ; first ? : boolean ; strikethrough ? : boolean ; colour ? : string ; symbol ? : Symbol ; shape ? : Shape ; width ? : number ; bright ? : boolean ; } export function getLegendItems ( client , mapContext ) { const legendItems = [ ] ; for ( const i in client . types ) { const type = client . types [ i ] ; if ( ! type . showInLegend ) continue ; const items = [ ] ; const fields = Object . create ( null ) ; if ( type . colourFixed || ( type . type == "marker" && type . symbolFixed && type . defaultSymbol && ( symbolList . includes ( type . defaultSymbol ) || type . defaultSymbol . length == 1 ) ) || ( type . type == "marker" && type . shapeFixed ) || ( type . type == "line" && type . widthFixed ) ) { const item = { value : type . name , label : type . name , filtered : true } ; if ( type . colourFixed ) item . colour = type . defaultColour ? `#${ type . defaultColour }` : undefined ; if ( type . type == "marker" && type . symbolFixed && type . defaultSymbol && ( symbolList . includes ( type . defaultSymbol ) || type . defaultSymbol . length == 1 ) ) item . symbol = type . defaultSymbol ; if ( type . type == "marker" && type . shapeFixed ) item . shape = type . defaultShape ?? "" ; if ( type . type == "line" && type . widthFixed ) item . width = type . defaultWidth ?? undefined ; if ( item . colour ) item . bright = getBrightness ( item . colour ) > 0.7 ; items . push ( item ) ; } for ( const field of type . fields ) { if ( ( field . type != "dropdown" && field . type != "checkbox" ) || ( ! field . controlColour && ( type . type != "marker" || ! field . controlSymbol ) && ( type . type != "marker" || ! field . controlShape ) && ( type . type != "line" || ! field . controlWidth ) ) ) continue ; fields [ field . name ] = [ ] ; ( field . options || [ ] ) . forEach ( ( option , idx ) => { const item = { value : option . value , label : option . value , field : field . name , filtered : true , first : idx == 0 } ; if ( field . type == "checkbox" ) { item . value = idx == 0 ? "0" : "1" ; if ( ! item . label || item . label == '0' || item . label == '1' ) { item . label = field . name ; if ( idx == 0 ) item . strikethrough = true ; } } if ( field . controlColour ) item . colour = `#${ option . colour }` ; if ( type . type == "marker" && field . controlSymbol ) item . symbol = option . symbol ; if ( type . type == "marker" && field . controlShape ) item . shape = option . shape ; if ( type . type == "line" && field . controlWidth ) item . width = option . width ; if ( item . colour ) item . bright = getBrightness ( item . colour ) > 0.7 ; items . push ( item ) ; fields [ field . name ] . push ( item . value ) ; } ) ; } if ( items . length == 0 ) { const item = { value : type . name , label : type . name , filtered : true } ; if ( type . type == "marker" ) item . shape = "drop" ; items . push ( item ) ; } const legendType = { type : type . type , typeId : type . id , name : type . name , items : items , filtered : true , defaultColour : type . defaultColour ?? undefined , defaultShape : type . defaultShape ?? undefined } ; allCombinations ( fields , ( data ) => { if ( mapContext . filterFunc ( { typeId : legendType . typeId , data } as any , type ) ) { legendType . filtered = false ; for ( const item of items ) { if ( ! item . field ) item . filtered = false ; } for ( const i in data ) { items . forEach ( function ( it ) { if ( it . field == i && it . value == data [ i ] ) it . filtered = false ; } ) ; } } } ) ; legendItems . push ( legendType ) ; } return legendItems ; } function allCombinations ( fields , callback ) { const fieldKeys = Object . keys ( fields ) ; function rec ( i , vals ) { if ( i == fieldKeys . length ) return callback ( vals ) ; for ( const f of fields [ fieldKeys [ i ] ] ) { vals [ fieldKeys [ i ] ] = f ; rec ( i + 1 , vals ) ; } } rec ( 0 , Object . create ( null ) ) ; }