@@ -40,41 +40,45 @@ export class CropLegendControl extends Control {
4040 } ) ;
4141
4242 this . attribute = options . attribute ;
43- this . mapping = options . mapping || { } ;
43+ this . mapping = options . mapping || [ ] ;
4444 this . legendItems = [ ] ;
45+ this . level = this . mapping . length - 1 ;
4546 this . render ( ) ;
4647 this . tileLoadEnd = this . tileLoadEnd . bind ( this ) ;
4748 this . changeSource = this . changeSource . bind ( this ) ;
4849 this . updateFeatureCount = debounce ( this . updateFeatureCount , 1000 ) . bind ( this ) ;
4950 }
5051 updateFeatureCount ( e ) {
5152 const map = this . getMap ( ) ;
52- const vectortiles = map . getLayers ( ) . getArray ( ) . filter ( f => f instanceof VectorTile ) ;
53+ const mapping = this . mapping [ this . level ] ;
54+ const vectorTiles = map . getLayers ( ) . getArray ( ) . filter ( f => f instanceof VectorTile ) ;
5355 const extent = map . getView ( ) . calculateExtentInternal ( ) ;
54- let totalArea = 0 , count = 0 , cropArea = { } , cropCount = { } ;
55- for ( const vt of vectortiles ) {
56+ let totalArea = 0 , count = 0 , cropArea = { } , cropCount = { } , byName = { } ;
57+ for ( const vt of vectorTiles ) {
5658 forFeaturesInExtent ( vt , extent , ( feature ) => {
5759 const area = feature . properties_ [ "area" ] || toGeometry ( feature ) . getArea ( ) ;
5860 const crop = feature . properties_ [ this . attribute ] ;
61+ const name = mapping [ crop ] ?. name ;
62+ if ( ! byName [ name ] ) byName [ name ] = mapping [ crop ] ;
5963 count ++ ;
6064 totalArea += area ;
61- cropCount [ crop ] = ( cropCount [ crop ] || 0 ) + 1 ;
62- cropArea [ crop ] = ( cropArea [ crop ] || 0 ) + area ;
65+ cropCount [ name ] = ( cropCount [ name ] || 0 ) + 1 ;
66+ cropArea [ name ] = ( cropArea [ name ] || 0 ) + area ;
6367 } ) ;
6468 }
6569 const topCrops = Object . entries ( cropArea )
66- . map ( ( [ crop , area ] ) => ( { crop , area } ) )
70+ . map ( ( [ name , area ] ) => ( { name , area } ) )
6771 . sort ( ( a , b ) => b . area - a . area ) // Descending order
6872 . slice ( 0 , 5 ) ;
6973
70- this . legendItems = topCrops . map ( ( { crop , area} ) =>
74+ this . legendItems = topCrops . map ( ( { name , area} ) =>
7175 {
72- const c = this . mapping [ crop ] ;
76+ const c = byName [ name ] ;
7377 const percent = ( area / totalArea ) * 100 ;
7478 return {
7579 label : c . name . replaceAll ( "_" , " " ) ,
7680 color : c . color || "#99bbccaa" ,
77- percent : percent . toFixed ( 2 ) + "%" ,
81+ percent : percent >= 1 ? percent . toFixed ( 0 ) + "%" : "<1 %",
7882 area : area . toFixed ( 2 ) ,
7983 }
8084 }
@@ -84,9 +88,10 @@ export class CropLegendControl extends Control {
8488
8589 tileLoadEnd ( e ) {
8690 const features = e . tile . getFeatures ( ) ;
91+ const m = this . mapping . at ( - 1 ) ;
8792 for ( const feature of features ) {
8893 const p = feature . getProperties ( ) ;
89- p . color = this . mapping [ p [ this . attribute ] ] ?. color || "#99bbccaa" ;
94+ p . color = m [ p [ this . attribute ] ] ?. color || "#99bbccaa" ;
9095 }
9196 this . updateFeatureCount ( e )
9297 }
@@ -113,34 +118,32 @@ export class CropLegendControl extends Control {
113118 }
114119 render ( ) {
115120 const element = this . element ;
116- element . innerHTML = '' ; // Clear previous content
117-
118- const legendTitle = document . createElement ( 'div' ) ;
119- legendTitle . className = 'legend-title' ;
120- legendTitle . innerText = 'Legend' ;
121- element . appendChild ( legendTitle ) ;
122-
123- const list = document . createElement ( 'ul' ) ;
124- list . className = 'legend-list' ;
125-
126- this . legendItems . forEach ( ( item ) => {
127- const listItem = document . createElement ( 'li' ) ;
128- const colorBox = document . createElement ( 'span' ) ;
129- const text = document . createElement ( 'span' ) ;
130-
131- colorBox . className = 'legend-color' ;
132- colorBox . style . backgroundColor = item . color ;
133-
134- text . className = 'legend-text' ;
135- text . innerText = item . label ;
136-
137- listItem . appendChild ( colorBox ) ;
138- listItem . appendChild ( text ) ;
139-
140- list . appendChild ( listItem ) ;
141- } ) ;
142-
143- element . appendChild ( list ) ;
121+ if ( ! this . legendItems ?. length ) {
122+ element . innerHTML = "" ;
123+ return ;
124+ }
125+ let levels = "" ;
126+ if ( this . mapping . length ) {
127+ levels = `<span style="font-weight: normal">Levels: </span>` ;
128+ for ( let i = 0 ; i < this . mapping . length ; i ++ ) {
129+ levels += `<button class="legend-level${ i === this . level ?" active" :"" } ">${ i } </button>` ;
130+ }
131+ }
132+ element . innerHTML = `
133+ <div class="legend-title">Legend ${ levels } </div>
134+ ${ this . legendItems . map ( ( { color, label, percent} ) => `
135+ <ul class="legend-list">
136+ <li>
137+ <span class="legend-color" style="background-color: ${ color } ;"></span>
138+ <span class="legend-text">${ label } ${ percent } </span>
139+ </li>
140+ </ul>
141+ ` ) . join ( "" ) }
142+ ` ;
143+ this . element . querySelectorAll ( ".legend-level" ) . forEach ( e => e . addEventListener ( "click" , ( e ) => {
144+ this . level = parseInt ( e . target . innerText ) ;
145+ this . updateFeatureCount ( ) ;
146+ } ) )
144147 }
145148
146149}
0 commit comments