@@ -40,41 +40,45 @@ export class CropLegendControl extends Control {
40
40
} ) ;
41
41
42
42
this . attribute = options . attribute ;
43
- this . mapping = options . mapping || { } ;
43
+ this . mapping = options . mapping || [ ] ;
44
44
this . legendItems = [ ] ;
45
+ this . level = this . mapping . length - 1 ;
45
46
this . render ( ) ;
46
47
this . tileLoadEnd = this . tileLoadEnd . bind ( this ) ;
47
48
this . changeSource = this . changeSource . bind ( this ) ;
48
49
this . updateFeatureCount = debounce ( this . updateFeatureCount , 1000 ) . bind ( this ) ;
49
50
}
50
51
updateFeatureCount ( e ) {
51
52
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 ) ;
53
55
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 ) {
56
58
forFeaturesInExtent ( vt , extent , ( feature ) => {
57
59
const area = feature . properties_ [ "area" ] || toGeometry ( feature ) . getArea ( ) ;
58
60
const crop = feature . properties_ [ this . attribute ] ;
61
+ const name = mapping [ crop ] ?. name ;
62
+ if ( ! byName [ name ] ) byName [ name ] = mapping [ crop ] ;
59
63
count ++ ;
60
64
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 ;
63
67
} ) ;
64
68
}
65
69
const topCrops = Object . entries ( cropArea )
66
- . map ( ( [ crop , area ] ) => ( { crop , area } ) )
70
+ . map ( ( [ name , area ] ) => ( { name , area } ) )
67
71
. sort ( ( a , b ) => b . area - a . area ) // Descending order
68
72
. slice ( 0 , 5 ) ;
69
73
70
- this . legendItems = topCrops . map ( ( { crop , area} ) =>
74
+ this . legendItems = topCrops . map ( ( { name , area} ) =>
71
75
{
72
- const c = this . mapping [ crop ] ;
76
+ const c = byName [ name ] ;
73
77
const percent = ( area / totalArea ) * 100 ;
74
78
return {
75
79
label : c . name . replaceAll ( "_" , " " ) ,
76
80
color : c . color || "#99bbccaa" ,
77
- percent : percent . toFixed ( 2 ) + "%" ,
81
+ percent : percent >= 1 ? percent . toFixed ( 0 ) + "%" : "<1 %",
78
82
area : area . toFixed ( 2 ) ,
79
83
}
80
84
}
@@ -84,9 +88,10 @@ export class CropLegendControl extends Control {
84
88
85
89
tileLoadEnd ( e ) {
86
90
const features = e . tile . getFeatures ( ) ;
91
+ const m = this . mapping . at ( - 1 ) ;
87
92
for ( const feature of features ) {
88
93
const p = feature . getProperties ( ) ;
89
- p . color = this . mapping [ p [ this . attribute ] ] ?. color || "#99bbccaa" ;
94
+ p . color = m [ p [ this . attribute ] ] ?. color || "#99bbccaa" ;
90
95
}
91
96
this . updateFeatureCount ( e )
92
97
}
@@ -113,34 +118,32 @@ export class CropLegendControl extends Control {
113
118
}
114
119
render ( ) {
115
120
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
+ } ) )
144
147
}
145
148
146
149
}
0 commit comments