@foodmarketmaker/mapag 0.0.47 → 0.0.49

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -7,16 +7,16 @@ import * as i1$1 from '@angular/forms';
7
7
  import { FormsModule, NG_VALUE_ACCESSOR } from '@angular/forms';
8
8
  import { takeUntilDestroyed, rxResource } from '@angular/core/rxjs-interop';
9
9
  import { FaIconComponent } from '@fortawesome/angular-fontawesome';
10
- import { faMousePointer, faList, faTrashAlt, faChevronRight, faGear, faEye, faEyeSlash, faFill, faPaintBrush, faTimes, faImage, faFilter, faCircle, faFont, faFire, faThLarge, faPrint, faInfoCircle } from '@fortawesome/free-solid-svg-icons';
10
+ import { faMousePointer, faList, faTrashAlt, faChevronRight, faGear, faTimes, faEye, faEyeSlash, faCircle, faFire, faThLarge, faFill, faPaintBrush, faImage, faFilter, faFont, faPrint, faInfoCircle } from '@fortawesome/free-solid-svg-icons';
11
11
  import booleanContains from '@turf/boolean-contains';
12
12
  import booleanOverlap from '@turf/boolean-overlap';
13
13
  import { polygon, feature } from '@turf/helpers';
14
14
  import { Subject, firstValueFrom, map } from 'rxjs';
15
+ import maplibregl, { Popup } from 'maplibre-gl';
15
16
  import MapboxDraw from 'maplibre-gl-draw';
16
17
  import RectangleMode from 'mapbox-gl-draw-rectangle-mode';
17
18
  import { saveAs } from 'file-saver';
18
19
  import 'mapbox-gl-infobox/styles.css';
19
- import maplibregl, { Popup } from 'maplibre-gl';
20
20
  import bbox from '@turf/bbox';
21
21
  import bboxPolygon from '@turf/bbox-polygon';
22
22
  import buffer from '@turf/buffer';
@@ -26,6 +26,7 @@ import { BinaryWriter, BinaryReader } from '@bufbuild/protobuf/wire';
26
26
  import { featureFilter } from '@mapbox/mapbox-gl-style-spec';
27
27
  import { NgSelectComponent, NgLabelTemplateDirective, NgOptionTemplateDirective } from '@ng-select/ng-select';
28
28
  import { CdkVirtualScrollViewport, CdkVirtualForOf, CdkFixedSizeVirtualScroll } from '@angular/cdk/scrolling';
29
+ import { DomSanitizer } from '@angular/platform-browser';
29
30
 
30
31
  function SaveMap(map) {
31
32
  var mapCanvas = map.getCanvas();
@@ -33,6 +34,19 @@ function SaveMap(map) {
33
34
  // here is the most important part because if you dont replace you will get a DOM 18 exception.
34
35
  window.location.href = image;
35
36
  }
37
+ function flyToFeature(map, f, zoom = 12) {
38
+ if (!map) {
39
+ return;
40
+ }
41
+ if (!f.geometry || f.geometry.type !== 'Point') {
42
+ return;
43
+ }
44
+ const coords = f.geometry.coordinates;
45
+ map.flyTo({
46
+ center: [coords[0], coords[1]],
47
+ zoom: zoom,
48
+ });
49
+ }
36
50
  function AddLayer(map, layer, afterId) {
37
51
  if (!map)
38
52
  return false;
@@ -48,6 +62,19 @@ function AddLayer(map, layer, afterId) {
48
62
  return false;
49
63
  }
50
64
  }
65
+ function ToggleDialog(dialogSignal) {
66
+ const dialog = dialogSignal();
67
+ if (!dialog) {
68
+ return;
69
+ }
70
+ const dialogElement = dialog.nativeElement;
71
+ if (dialogElement.open) {
72
+ dialogElement.close();
73
+ }
74
+ else {
75
+ dialogElement.show();
76
+ }
77
+ }
51
78
  function RemoveLayer(map, layerId) {
52
79
  if (!map)
53
80
  return;
@@ -181,9 +208,8 @@ async function sampleTilesForLayers(pmtiles) {
181
208
  return [];
182
209
  }
183
210
  }
184
- async function pmtilesPixelInfo(url, map, e) {
211
+ async function pmtilesPixelInfo(url, map, lngLat) {
185
212
  const pmtiles = new PMTiles(url.replace('pmtiles://', ''));
186
- const lngLat = e.lngLat; // {lng, lat}
187
213
  // Convert lat/lon to tile coordinates at a chosen zoom
188
214
  const zoom = 10; // pick a zoom level for sampling
189
215
  const x = Math.floor(((lngLat.lng + 180) / 360) * Math.pow(2, zoom));
@@ -13596,6 +13622,17 @@ class MapboxMapperGroup {
13596
13622
  clear() {
13597
13623
  this.mappers.forEach((mapper) => mapper.clear());
13598
13624
  }
13625
+ renderPopup(f) {
13626
+ for (const [name, mapper] of this.mappers) {
13627
+ if (mapper.renderPopup) {
13628
+ const result = mapper.renderPopup(f);
13629
+ if (result) {
13630
+ return result;
13631
+ }
13632
+ }
13633
+ }
13634
+ return undefined;
13635
+ }
13599
13636
  }
13600
13637
 
13601
13638
  class StandardLayersMapper {
@@ -13797,8 +13834,14 @@ class AreaMapperMapper {
13797
13834
  this.map.setZoom(src.minZoom);
13798
13835
  }
13799
13836
  }
13800
- renderPopup(item) {
13801
- return 'NO POPUP';
13837
+ renderPopup(feature) {
13838
+ if (!this.map) {
13839
+ return undefined;
13840
+ }
13841
+ if (feature.layer.id !== this.layer) {
13842
+ return undefined;
13843
+ }
13844
+ return undefined;
13802
13845
  }
13803
13846
  useStat(id, stats) {
13804
13847
  const i = stats.findIndex((a) => a.id == id);
@@ -14179,6 +14222,31 @@ class MapService {
14179
14222
  this.map.getCanvas().style.cursor = 'pointer';
14180
14223
  }
14181
14224
  }
14225
+ currentPopup = null;
14226
+ handleMapClick(point, lngLat) {
14227
+ if (!this.map)
14228
+ return;
14229
+ if (!this.mapper)
14230
+ return;
14231
+ // Get the features
14232
+ const features = this.map.queryRenderedFeatures(point);
14233
+ let html = undefined;
14234
+ for (const feature of features) {
14235
+ html = this.mapper.renderPopup(feature);
14236
+ if (html) {
14237
+ break;
14238
+ }
14239
+ }
14240
+ if (html) {
14241
+ if (this.currentPopup) {
14242
+ this.currentPopup.remove();
14243
+ }
14244
+ this.currentPopup = new Popup()
14245
+ .setLngLat(lngLat)
14246
+ .setHTML(html)
14247
+ .addTo(this.map);
14248
+ }
14249
+ }
14182
14250
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: MapService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
14183
14251
  static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: MapService, providedIn: 'root' });
14184
14252
  }
@@ -15092,6 +15160,15 @@ class MapComponent {
15092
15160
  this.mapper().onReady(map, this.svc);
15093
15161
  });
15094
15162
  });
15163
+ map.on('click', (e) => {
15164
+ this.svc.handleMapClick(e.point, e.lngLat);
15165
+ });
15166
+ map.on('touchend', (e) => {
15167
+ // Ignore multi-touch events
15168
+ if (e.points && e.points.length == 1) {
15169
+ this.svc.handleMapClick(e.point, e.lngLat);
15170
+ }
15171
+ });
15095
15172
  }
15096
15173
  });
15097
15174
  }
@@ -16083,7 +16160,7 @@ class CroplandDataLayerMapper {
16083
16160
  if (!this.settings().visible) {
16084
16161
  return;
16085
16162
  }
16086
- const pixel = await pmtilesPixelInfo(CroplandDataLayerMapper.PMTILES, map, e);
16163
+ const pixel = await pmtilesPixelInfo(CroplandDataLayerMapper.PMTILES, map, e.lngLat);
16087
16164
  if (!pixel) {
16088
16165
  console.error('No pixel data returned');
16089
16166
  return;
@@ -16614,53 +16691,40 @@ class CropSequenceMapper {
16614
16691
  type: 'line',
16615
16692
  }, StandardLayersMapper.POLYGONS_BACKGROUND);
16616
16693
  this._update(this.settings());
16617
- if (!addedFill) {
16618
- return;
16694
+ }
16695
+ renderPopup(feature) {
16696
+ if (!this.map) {
16697
+ return undefined;
16619
16698
  }
16620
- map.on('mousemove', this.FILL_LAYER_ID, (e) => {
16621
- this.over.set(e.features && e.features.length > 0 ? e.features[0] : null);
16622
- });
16623
- map.on('click', this.FILL_LAYER_ID, (e) => {
16624
- // Publish
16625
- this.over.set(e.features && e.features.length > 0 ? e.features[0] : null);
16626
- if (e.features && e.features.length > 0) {
16627
- const feature = e.features[0];
16628
- const coordinates = e.lngLat;
16629
- if (this.popup) {
16630
- this.popup.remove();
16631
- }
16632
- const tb = new TableBuilder();
16633
- const crop2017 = this.lookupClass(feature.properties ? feature.properties['CDL2017'] : null);
16634
- const crop2018 = this.lookupClass(feature.properties ? feature.properties['CDL2018'] : null);
16635
- const crop2019 = this.lookupClass(feature.properties ? feature.properties['CDL2019'] : null);
16636
- const crop2020 = this.lookupClass(feature.properties ? feature.properties['CDL2020'] : null);
16637
- const crop2021 = this.lookupClass(feature.properties ? feature.properties['CDL2021'] : null);
16638
- const crop2022 = this.lookupClass(feature.properties ? feature.properties['CDL2022'] : null);
16639
- const crop2023 = this.lookupClass(feature.properties ? feature.properties['CDL2023'] : null);
16640
- const crop2024 = this.lookupClass(feature.properties ? feature.properties['CDL2024'] : null);
16641
- tb.addHeader('Year', 'Crop Type');
16642
- tb.add('2024', crop2024 ?? 'Unknown');
16643
- tb.add('2023', crop2023 ?? 'Unknown');
16644
- tb.add('2022', crop2022 ?? 'Unknown');
16645
- tb.add('2021', crop2021 ?? 'Unknown');
16646
- tb.add('2020', crop2020 ?? 'Unknown');
16647
- tb.add('2019', crop2019 ?? 'Unknown');
16648
- tb.add('2018', crop2018 ?? 'Unknown');
16649
- tb.add('2017', crop2017 ?? 'Unknown');
16650
- tb.addHeader('Location', "");
16651
- tb.add('State FIPS', feature.properties ? feature.properties['STATEFIPS'] : 'Unknown');
16652
- tb.add('County', feature.properties ? feature.properties['CNTY'] : 'Unknown');
16653
- tb.add('County FIPS', feature.properties ? feature.properties['CNTYFIPS'] : 'Unknown');
16654
- tb.add('ASD', feature.properties ? feature.properties['ASD'] : 'Unknown');
16655
- tb.add('Area (M²)', feature.properties ? feature.properties['Shape_Area'] : 'Unknown');
16656
- const fieldsHtml = tb.toHtml();
16657
- this.currentFeatureID = feature?.properties?.['globalid'];
16658
- this.popup = new Popup({ maxWidth: '400px' })
16659
- .setLngLat(coordinates)
16660
- .setHTML(`<strong>Crop Sequence</strong><br/>${fieldsHtml}`)
16661
- .addTo(map);
16662
- }
16663
- });
16699
+ if (feature.layer.id !== this.FILL_LAYER_ID && feature.layer.id !== this.LINE_LAYER_ID) {
16700
+ return undefined;
16701
+ }
16702
+ const tb = new TableBuilder();
16703
+ const crop2017 = this.lookupClass(feature.properties ? feature.properties['CDL2017'] : null);
16704
+ const crop2018 = this.lookupClass(feature.properties ? feature.properties['CDL2018'] : null);
16705
+ const crop2019 = this.lookupClass(feature.properties ? feature.properties['CDL2019'] : null);
16706
+ const crop2020 = this.lookupClass(feature.properties ? feature.properties['CDL2020'] : null);
16707
+ const crop2021 = this.lookupClass(feature.properties ? feature.properties['CDL2021'] : null);
16708
+ const crop2022 = this.lookupClass(feature.properties ? feature.properties['CDL2022'] : null);
16709
+ const crop2023 = this.lookupClass(feature.properties ? feature.properties['CDL2023'] : null);
16710
+ const crop2024 = this.lookupClass(feature.properties ? feature.properties['CDL2024'] : null);
16711
+ tb.addHeader('Year', 'Crop Type');
16712
+ tb.add('2024', crop2024 ?? 'Unknown');
16713
+ tb.add('2023', crop2023 ?? 'Unknown');
16714
+ tb.add('2022', crop2022 ?? 'Unknown');
16715
+ tb.add('2021', crop2021 ?? 'Unknown');
16716
+ tb.add('2020', crop2020 ?? 'Unknown');
16717
+ tb.add('2019', crop2019 ?? 'Unknown');
16718
+ tb.add('2018', crop2018 ?? 'Unknown');
16719
+ tb.add('2017', crop2017 ?? 'Unknown');
16720
+ tb.addHeader('Location', "");
16721
+ tb.add('State FIPS', feature.properties ? feature.properties['STATEFIPS'] : 'Unknown');
16722
+ tb.add('County', feature.properties ? feature.properties['CNTY'] : 'Unknown');
16723
+ tb.add('County FIPS', feature.properties ? feature.properties['CNTYFIPS'] : 'Unknown');
16724
+ tb.add('ASD', feature.properties ? feature.properties['ASD'] : 'Unknown');
16725
+ tb.add('Area (M²)', feature.properties ? feature.properties['Shape_Area'] : 'Unknown');
16726
+ const fieldsHtml = tb.toHtml();
16727
+ return fieldsHtml;
16664
16728
  }
16665
16729
  lookupClass(code) {
16666
16730
  const found = CroplandLegend.find((item) => {
@@ -16693,7 +16757,6 @@ class CropSequenceMapper {
16693
16757
  count = 0;
16694
16758
  total = 0;
16695
16759
  map;
16696
- popup = null;
16697
16760
  }
16698
16761
  class CropSequenceSettings {
16699
16762
  visible = true;
@@ -16951,10 +17014,10 @@ class FoodhubMapper {
16951
17014
  RemoveLayer(this.map, this.CIRCLE_LAYER_ID);
16952
17015
  RemoveLayer(this.map, this.ICON_LAYER_ID);
16953
17016
  RemoveLayer(this.map, this.HEATMAP_LAYER_ID);
16954
- this.map.off('click', this.CIRCLE_LAYER_ID, this.onClick);
16955
- this.map.off('click', this.ICON_LAYER_ID, this.onClick);
16956
- this.map.off('touchend', this.CIRCLE_LAYER_ID, this.onClick);
16957
- this.map.off('touchend', this.ICON_LAYER_ID, this.onClick);
17017
+ // this.map.off('click', this.CIRCLE_LAYER_ID, this.onClick);
17018
+ // this.map.off('click', this.ICON_LAYER_ID, this.onClick);
17019
+ // this.map.off('touchend', this.CIRCLE_LAYER_ID, this.onClick);
17020
+ // this.map.off('touchend', this.ICON_LAYER_ID, this.onClick);
16958
17021
  this.count = 0;
16959
17022
  }
16960
17023
  updateLegend(settings) {
@@ -16993,14 +17056,14 @@ class FoodhubMapper {
16993
17056
  // this.addClusterLayers(map);
16994
17057
  }
16995
17058
  // Add popup on click
16996
- this.map.off('click', this.CIRCLE_LAYER_ID, this.onClick);
16997
- this.map.off('click', this.ICON_LAYER_ID, this.onClick);
16998
- this.map.off('touchend', this.CIRCLE_LAYER_ID, this.onClick);
16999
- this.map.off('touchend', this.ICON_LAYER_ID, this.onClick);
17000
- map.on('click', this.CIRCLE_LAYER_ID, this.onClick);
17001
- map.on('click', this.ICON_LAYER_ID, this.onClick);
17002
- map.on('touchend', this.CIRCLE_LAYER_ID, this.onClick);
17003
- map.on('touchend', this.ICON_LAYER_ID, this.onClick);
17059
+ // this.map.off('click', this.CIRCLE_LAYER_ID, this.onClick);
17060
+ // this.map.off('click', this.ICON_LAYER_ID, this.onClick);
17061
+ // this.map.off('touchend', this.CIRCLE_LAYER_ID, this.onClick);
17062
+ // this.map.off('touchend', this.ICON_LAYER_ID, this.onClick);
17063
+ // map.on('click', this.CIRCLE_LAYER_ID, this.onClick);
17064
+ // map.on('click', this.ICON_LAYER_ID, this.onClick);
17065
+ // map.on('touchend', this.CIRCLE_LAYER_ID, this.onClick);
17066
+ // map.on('touchend', this.ICON_LAYER_ID, this.onClick);
17004
17067
  this.filter(map);
17005
17068
  untracked(() => this.updateLegend(settings));
17006
17069
  }
@@ -17159,40 +17222,44 @@ class FoodhubMapper {
17159
17222
  getSettings() {
17160
17223
  return { ...this.settings() };
17161
17224
  }
17162
- onClick = (e) => {
17225
+ // onClick = (e: MapLayerMouseEvent | MapLayerTouchEvent) => {
17226
+ // if (!this.map) {
17227
+ // return;
17228
+ // }
17229
+ // const map = this.map;
17230
+ // let features;
17231
+ // const settings = this.settings();
17232
+ // if (settings.type == 'circle') {
17233
+ // features = this.map.queryRenderedFeatures(e.point, {
17234
+ // layers: [this.CIRCLE_LAYER_ID],
17235
+ // });
17236
+ // } else if (settings.type == 'icon') {
17237
+ // features = this.map.queryRenderedFeatures(e.point, {
17238
+ // layers: [this.ICON_LAYER_ID],
17239
+ // });
17240
+ // }
17241
+ // if (!features || features.length == 0) {
17242
+ // return;
17243
+ // }
17244
+ // if (features.length > 0) {
17245
+ // const item = features[0];
17246
+ // if (item) {
17247
+ // console.debug('Rendering Popup for ' + item.id + ' in ' + this.ICON_LAYER_ID);
17248
+ // const html = this.renderPopup(item);
17249
+ // if (!html) {
17250
+ // return;
17251
+ // }
17252
+ // new Popup().setLngLat(e.lngLat).setHTML(html).addTo(map);
17253
+ // }
17254
+ // }
17255
+ // };
17256
+ renderPopup(f) {
17163
17257
  if (!this.map) {
17164
- return;
17165
- }
17166
- const map = this.map;
17167
- let features;
17168
- const settings = this.settings();
17169
- if (settings.type == 'circle') {
17170
- features = this.map.queryRenderedFeatures(e.point, {
17171
- layers: [this.CIRCLE_LAYER_ID],
17172
- });
17173
- }
17174
- else if (settings.type == 'icon') {
17175
- features = this.map.queryRenderedFeatures(e.point, {
17176
- layers: [this.ICON_LAYER_ID],
17177
- });
17178
- }
17179
- if (!features || features.length == 0) {
17180
- return;
17258
+ return undefined;
17181
17259
  }
17182
- if (features.length > 0) {
17183
- const item = features[0];
17184
- if (item) {
17185
- console.debug('Rendering Popup for ' + item.id + ' in ' + this.ICON_LAYER_ID);
17186
- this.renderPopup(item).then((html) => {
17187
- if (!html) {
17188
- return;
17189
- }
17190
- new Popup().setLngLat(e.lngLat).setHTML(html).addTo(map);
17191
- });
17192
- }
17260
+ if (f.layer.id !== this.CIRCLE_LAYER_ID && f.layer.id !== this.ICON_LAYER_ID && f.layer.id !== this.HEATMAP_LAYER_ID) {
17261
+ return undefined;
17193
17262
  }
17194
- };
17195
- async renderPopup(f) {
17196
17263
  if (!f || !f.properties) {
17197
17264
  return undefined;
17198
17265
  }
@@ -17286,36 +17353,27 @@ class HardinessMapper {
17286
17353
  type: 'fill',
17287
17354
  }, StandardLayersMapper.POLYGONS_BACKGROUND);
17288
17355
  this._update(this.settings());
17289
- if (added) {
17290
- map.on('mousemove', this.LAYER_ID, (e) => {
17291
- this.over.set(e.features && e.features.length > 0 ? e.features[0] : null);
17292
- });
17293
- map.on('click', this.LAYER_ID, (e) => {
17294
- // Publish
17295
- this.over.set(e.features && e.features.length > 0 ? e.features[0] : null);
17296
- if (e.features && e.features.length > 0) {
17297
- const feature = e.features[0];
17298
- const coordinates = e.lngLat;
17299
- const name = feature.properties
17300
- ? feature.properties['zone']
17301
- : 'Unknown';
17302
- // Ensure that if the popup is already open, we don't create a new one
17303
- if (this.popup) {
17304
- this.popup.remove();
17305
- }
17306
- const fields = feature.properties
17307
- ? Object.entries(feature.properties)
17308
- .map(([key, value]) => `<strong>${key}:</strong> ${value}`)
17309
- .join('<br/>')
17310
- : '';
17311
- this.currentFeatureID = feature?.properties?.['globalid'];
17312
- this.popup = new Popup({ maxWidth: '400px' })
17313
- .setLngLat(coordinates)
17314
- .setHTML(`<strong>Hardiness:</strong> ${name}<hr /><br/>${fields}`)
17315
- .addTo(map);
17316
- }
17317
- });
17356
+ }
17357
+ renderPopup(feature) {
17358
+ if (!this.map) {
17359
+ return undefined;
17360
+ }
17361
+ if (feature.layer.id !== this.LAYER_ID) {
17362
+ return undefined;
17363
+ }
17364
+ const name = feature.properties
17365
+ ? feature.properties['zone']
17366
+ : 'Unknown';
17367
+ // Ensure that if the popup is already open, we don't create a new one
17368
+ if (this.popup) {
17369
+ this.popup.remove();
17318
17370
  }
17371
+ const fields = feature.properties
17372
+ ? Object.entries(feature.properties)
17373
+ .map(([key, value]) => `<strong>${key}:</strong> ${value}`)
17374
+ .join('<br/>')
17375
+ : '';
17376
+ return `<strong>Hardiness:</strong> ${name}<hr /><br/>${fields}`;
17319
17377
  }
17320
17378
  update(newSettings) {
17321
17379
  this.settings.set({ ...this.settings(), ...newSettings });
@@ -21357,8 +21415,8 @@ class NAASMapper {
21357
21415
  return ds.name;
21358
21416
  }
21359
21417
  if (ds) {
21360
- const commodity = DataSetFieldValue(ds, -1, "COMMODITY_DESC") || 'UNKNOWN';
21361
- const year = DataSetFieldValue(ds, -1, "YEAR");
21418
+ const commodity = DataSetFieldValue$1(ds, -1, "COMMODITY_DESC") || 'UNKNOWN';
21419
+ const year = DataSetFieldValue$1(ds, -1, "YEAR");
21362
21420
  if (year) {
21363
21421
  return `${commodity} (${year})`;
21364
21422
  }
@@ -21378,8 +21436,8 @@ class NAASMapper {
21378
21436
  return ds.name;
21379
21437
  }
21380
21438
  if (ds) {
21381
- const commodity = DataSetFieldValue(ds, -1, "PRODN_PRACTICE_DESC") || '';
21382
- const units = DataSetFieldValue(ds, -1, "UNIT_DESC") || '';
21439
+ const commodity = DataSetFieldValue$1(ds, -1, "PRODN_PRACTICE_DESC") || '';
21440
+ const units = DataSetFieldValue$1(ds, -1, "UNIT_DESC") || '';
21383
21441
  return `${commodity} (${units})`;
21384
21442
  }
21385
21443
  return 'NASS Data';
@@ -21418,7 +21476,7 @@ class NAASMapper {
21418
21476
  if (!row || !row.cells) {
21419
21477
  continue;
21420
21478
  }
21421
- const fips = FipsFromDataSet(dataSet, i);
21479
+ const fips = FipsFromDataSet$1(dataSet, i);
21422
21480
  if (!fips || fips.endsWith("998") || fips.endsWith("999")) {
21423
21481
  // Skip invalid or unknown FIPS
21424
21482
  continue;
@@ -21541,8 +21599,6 @@ class NAASMapper {
21541
21599
  visibility: 'none',
21542
21600
  },
21543
21601
  }, StandardLayersMapper.POLYGONS_BACKGROUND);
21544
- map.off('click', this.LAYER_ID, this.onClick);
21545
- map.on('click', this.LAYER_ID, this.onClick);
21546
21602
  }
21547
21603
  setFeatureStates(settings, fs) {
21548
21604
  if (!this.map) {
@@ -21661,76 +21717,72 @@ class NAASMapper {
21661
21717
  }
21662
21718
  clear() {
21663
21719
  if (this.map) {
21664
- this.map.off('click', this.LAYER_ID, this.onClick);
21665
21720
  RemoveLayer(this.map, this.LAYER_ID);
21666
21721
  RemoveLayer(this.map, this.SOURCE_ID);
21667
21722
  }
21668
21723
  }
21669
- onClick = async (e) => {
21724
+ renderPopup(feature) {
21725
+ // Determine if this is mine
21670
21726
  if (!this.map) {
21671
- return;
21727
+ return undefined;
21728
+ }
21729
+ if (feature.layer.id !== this.LAYER_ID) {
21730
+ return undefined;
21672
21731
  }
21673
21732
  const settings = this.settings();
21674
21733
  const src = Layers.FindVector(settings.areaType);
21675
21734
  if (!src) {
21676
21735
  console.warn('ChoroplethMapper: No source found for area type ', settings.areaType);
21677
- return;
21736
+ return undefined;
21678
21737
  }
21679
- const features = this.map.queryRenderedFeatures(e.point, {
21680
- layers: [this.LAYER_ID],
21738
+ const state = this.map.getFeatureState({
21739
+ source: this.SOURCE_ID,
21740
+ sourceLayer: src.Source,
21741
+ id: feature.id
21681
21742
  });
21682
- if (features.length > 0) {
21683
- e.preventDefault();
21684
- if (this.current) {
21685
- this.current.remove();
21686
- this.current = null;
21687
- }
21688
- const f = features[0];
21689
- const state = this.map.getFeatureState({
21690
- source: this.SOURCE_ID,
21691
- sourceLayer: src.Source,
21692
- id: f.id
21693
- });
21694
- const html = await this.RenderPopup(f, state);
21695
- if (html) {
21696
- this.current = new Popup().setLngLat(e.lngLat).setHTML(html).addTo(this.map);
21697
- }
21698
- }
21699
- };
21743
+ return this.RenderPopup(feature, state);
21744
+ }
21700
21745
  RenderPopup(feature, state) {
21701
21746
  const nState = state;
21702
21747
  if (!nState) {
21703
- return Promise.resolve(undefined);
21748
+ return undefined;
21704
21749
  }
21705
21750
  const ds = nState.dataset;
21706
21751
  if (!ds) {
21707
- return Promise.resolve(undefined);
21752
+ return undefined;
21708
21753
  }
21709
21754
  const tab = new TableBuilder();
21710
- tab.add("Source", DataSetFieldValue(ds, nState.row, "SOURCE_DESC") || "");
21711
- tab.add("Sector", DataSetFieldValue(ds, nState.row, "SECTOR_DESC") || "");
21712
- tab.add("Group", DataSetFieldValue(ds, nState.row, "GROUP_DESC") || "");
21713
- tab.add("Commodity", DataSetFieldValue(ds, nState.row, "COMMODITY_DESC") || "");
21714
- tab.add("Production", DataSetFieldValue(ds, nState.row, "PRODN_PRACTICE_DESC") || "");
21715
- tab.add("Utilization", DataSetFieldValue(ds, nState.row, "UTIL_PRACTICE_DESC") || "");
21716
- tab.add("Statistic", DataSetFieldValue(ds, nState.row, "STATISTICCAT_DESC") || "");
21717
- tab.add("Unit", DataSetFieldValue(ds, nState.row, "UNIT_DESC") || "");
21718
- tab.add("State", DataSetFieldValue(ds, nState.row, "STATE_ABBR") || "");
21719
- tab.add("County", DataSetFieldValue(ds, nState.row, "COUNTY_CODE") || "");
21720
- tab.add("Year", DataSetFieldValue(ds, nState.row, "YEAR") || "");
21721
- tab.add("Value", nState?.value);
21722
- tab.add("RAW Value", nState?.raw);
21723
- tab.add("MIN Value", nState?.min || "");
21724
- tab.add("MAX Value", nState?.max || "");
21725
- return Promise.resolve(tab.toHtml());
21755
+ tab.add("Source", DataSetFieldValue$1(ds, nState.row, "SOURCE_DESC") || "");
21756
+ tab.add("Sector", DataSetFieldValue$1(ds, nState.row, "SECTOR_DESC") || "");
21757
+ tab.add("Group", DataSetFieldValue$1(ds, nState.row, "GROUP_DESC") || "");
21758
+ tab.add("Commodity", DataSetFieldValue$1(ds, nState.row, "COMMODITY_DESC") || "");
21759
+ tab.add("Production", DataSetFieldValue$1(ds, nState.row, "PRODN_PRACTICE_DESC") || "");
21760
+ tab.add("Utilization", DataSetFieldValue$1(ds, nState.row, "UTIL_PRACTICE_DESC") || "");
21761
+ tab.add("Statistic", DataSetFieldValue$1(ds, nState.row, "STATISTICCAT_DESC") || "");
21762
+ tab.add("Unit", DataSetFieldValue$1(ds, nState.row, "UNIT_DESC") || "");
21763
+ // tab.add("State", DataSetFieldValue(ds, nState.row, "STATE_ABBR") || "")
21764
+ // tab.add("County", DataSetFieldValue(ds, nState.row, "COUNTY_CODE") || "")
21765
+ // tab.add("Year", DataSetFieldValue(ds, nState.row, "YEAR") || "")
21766
+ // tab.add("Value", nState?.value)
21767
+ if (nState.raw !== undefined) {
21768
+ tab.add("Value", nState.raw.toLocaleString());
21769
+ }
21770
+ if (nState.min !== undefined) {
21771
+ tab.add("MIN Value", nState.min.toLocaleString());
21772
+ }
21773
+ if (nState.max !== undefined) {
21774
+ tab.add("MAX Value", nState.max.toLocaleString());
21775
+ }
21776
+ tab.add("GEOID", nState.id);
21777
+ return tab.toHtml();
21726
21778
  }
21727
21779
  }
21728
- function FipsFromDataSet(ds, rowIndex) {
21780
+ function FipsFromDataSet$1(ds, rowIndex) {
21729
21781
  if (!ds.schema || !ds.schema.fields) {
21730
21782
  return null;
21731
21783
  }
21732
- const state = DataSetFieldValue(ds, rowIndex, "STATE_FIPS_CODE");
21733
- const county = DataSetFieldValue(ds, rowIndex, "COUNTY_CODE");
21784
+ const state = DataSetFieldValue$1(ds, rowIndex, "STATE_FIPS_CODE");
21785
+ const county = DataSetFieldValue$1(ds, rowIndex, "COUNTY_CODE");
21734
21786
  if (county) {
21735
21787
  return county;
21736
21788
  }
@@ -21739,7 +21791,7 @@ function FipsFromDataSet(ds, rowIndex) {
21739
21791
  }
21740
21792
  return null;
21741
21793
  }
21742
- function DataSetFieldValue(ds, rowIndex, field) {
21794
+ function DataSetFieldValue$1(ds, rowIndex, field) {
21743
21795
  if (!ds.schema || !ds.data) {
21744
21796
  return null;
21745
21797
  }
@@ -22059,10 +22111,6 @@ class NaicsMapper {
22059
22111
  RemoveLayer(this.map, this.CIRCLE_LAYER_ID);
22060
22112
  RemoveLayer(this.map, this.ICON_LAYER_ID);
22061
22113
  RemoveLayer(this.map, this.HEATMAP_LAYER_ID);
22062
- this.map.off('click', this.CIRCLE_LAYER_ID, this.onClick);
22063
- this.map.off('click', this.ICON_LAYER_ID, this.onClick);
22064
- this.map.off('touchend', this.CIRCLE_LAYER_ID, this.onClick);
22065
- this.map.off('touchend', this.ICON_LAYER_ID, this.onClick);
22066
22114
  const svc = this.svc();
22067
22115
  if (svc) {
22068
22116
  svc.UpdateLegend(this.id, undefined);
@@ -22140,15 +22188,6 @@ class NaicsMapper {
22140
22188
  // this.addClusterLayers(map);
22141
22189
  }
22142
22190
  console.log('NAICS Mapper created/updated:', this.id, settings);
22143
- // Add popup on click
22144
- this.map.off('click', this.CIRCLE_LAYER_ID, this.onClick);
22145
- this.map.off('click', this.ICON_LAYER_ID, this.onClick);
22146
- this.map.off('touchend', this.CIRCLE_LAYER_ID, this.onClick);
22147
- this.map.off('touchend', this.ICON_LAYER_ID, this.onClick);
22148
- map.on('click', this.CIRCLE_LAYER_ID, this.onClick);
22149
- map.on('click', this.ICON_LAYER_ID, this.onClick);
22150
- map.on('touchend', this.CIRCLE_LAYER_ID, this.onClick);
22151
- map.on('touchend', this.ICON_LAYER_ID, this.onClick);
22152
22191
  this.filter(map, settings);
22153
22192
  untracked(() => this.updateLegend(settings));
22154
22193
  }
@@ -22372,37 +22411,16 @@ class NaicsMapper {
22372
22411
  zoom: 12,
22373
22412
  });
22374
22413
  }
22375
- onClick = async (e) => {
22376
- if (!this.map) {
22377
- return;
22378
- }
22379
- const map = this.map;
22380
- let features;
22381
- const settings = this.settings();
22382
- if (settings.type == 'circle') {
22383
- features = this.map.queryRenderedFeatures(e.point, {
22384
- layers: [this.CIRCLE_LAYER_ID],
22385
- });
22386
- }
22387
- else if (settings.type == 'icon') {
22388
- features = this.map.queryRenderedFeatures(e.point, {
22389
- layers: [this.ICON_LAYER_ID],
22390
- });
22391
- }
22392
- if (!features || features.length == 0) {
22393
- return;
22394
- }
22395
- e.preventDefault();
22396
- if (this.current) {
22397
- this.current.remove();
22398
- this.current = null;
22414
+ renderPopup(f) {
22415
+ if (!this.map || !f || !f.layer) {
22416
+ return undefined;
22399
22417
  }
22400
- const html = this.renderPopup(features[0]);
22401
- if (html) {
22402
- this.current = new Popup().setLngLat(e.lngLat).setHTML(html).addTo(this.map);
22418
+ if (f.layer.id !== this.CIRCLE_LAYER_ID && f.layer.id !== this.ICON_LAYER_ID && f.layer.id !== this.HEATMAP_LAYER_ID) {
22419
+ return undefined;
22403
22420
  }
22404
- };
22405
- renderPopup(f) {
22421
+ return this.renderInfo(f);
22422
+ }
22423
+ renderInfo(f) {
22406
22424
  if (!f || !f.properties) {
22407
22425
  return undefined;
22408
22426
  }
@@ -23845,6 +23863,7 @@ class PointDataMapperSettings {
23845
23863
  filterState;
23846
23864
  filterStates = [];
23847
23865
  showLegend = false;
23866
+ externalLoad = true; // If true, the mapper will load data from the provided source URL instead of relying on mapbox source loading. This allows for better handling of large datasets and loading states.
23848
23867
  }
23849
23868
  class PointDataMapper {
23850
23869
  static CLUSTERS = [
@@ -23885,6 +23904,7 @@ class PointDataMapper {
23885
23904
  itemsFC;
23886
23905
  popupRenderer;
23887
23906
  id;
23907
+ watcher = new SourceLoadWatcher();
23888
23908
  POINT_LAYER_ID;
23889
23909
  HEAT_LAYER_ID;
23890
23910
  ICON_LAYER_ID;
@@ -23897,6 +23917,7 @@ class PointDataMapper {
23897
23917
  return settings.source;
23898
23918
  }, ...(ngDevMode ? [{ debugName: "geoJsonUrl" }] : []));
23899
23919
  geoJsonResource = httpResource(() => this.geoJsonUrl() || undefined);
23920
+ dataCnt = 0;
23900
23921
  constructor(popupRenderer, settings) {
23901
23922
  this.id = 'points-' + Math.random().toString(36).substring(2, 15);
23902
23923
  this.popupRenderer = popupRenderer;
@@ -23932,34 +23953,56 @@ class PointDataMapper {
23932
23953
  this._update(this.settings());
23933
23954
  }, ...(ngDevMode ? [{ debugName: "_updateGlobal" }] : []));
23934
23955
  }
23935
- // data = computed(() => {
23936
- // // Check if data is still loading or has an error
23937
- // const settings = this.settings();
23938
- // if (this.geoJsonResource.isLoading()) {
23939
- // return [];
23940
- // }
23941
- // if (this.geoJsonResource.error()) {
23942
- // console.error('Failed to load GeoJSON:', this.geoJsonResource.error());
23943
- // return [];
23944
- // }
23945
- // // Check if we have loaded data
23946
- // if (!this.geoJsonResource.hasValue()) {
23947
- // return [];
23948
- // }
23949
- // const svc = this.svc();
23950
- // if (!svc) {
23951
- // return [];
23952
- // }
23953
- // svc.stateCountyFilter(); // depend
23954
- // const geoJsonData = this.geoJsonResource.value() as FeatureCollection;
23955
- // const features = geoJsonData?.features || [];
23956
- // if (!features || features.length === 0) {
23957
- // return [];
23958
- // }
23959
- // const filter = this.getFilter(settings);
23960
- // const filtered = Filter(features, filter as any);
23961
- // return filtered || [];
23962
- // })
23956
+ data = computed(() => {
23957
+ this.dataCnt++;
23958
+ this.watcher.updated(); // depend on source data changes
23959
+ const settings = this.settings();
23960
+ console.log('Data computed for', this.id, 'count', this.dataCnt);
23961
+ if (!this.map) {
23962
+ return [];
23963
+ }
23964
+ const map = this.map;
23965
+ const filter = this.getFilter(settings);
23966
+ if (settings.externalLoad) {
23967
+ // Check if data is still loading or has an error
23968
+ if (this.geoJsonResource.isLoading()) {
23969
+ return [];
23970
+ }
23971
+ if (this.geoJsonResource.error()) {
23972
+ console.error('Failed to load GeoJSON:', this.geoJsonResource.error());
23973
+ return [];
23974
+ }
23975
+ // Check if we have loaded data
23976
+ if (!this.geoJsonResource.hasValue()) {
23977
+ return [];
23978
+ }
23979
+ const geoJsonData = this.geoJsonResource.value();
23980
+ const features = geoJsonData?.features || [];
23981
+ if (!features || features.length === 0) {
23982
+ return [];
23983
+ }
23984
+ const filtered = Filter(features, filter);
23985
+ return filtered || [];
23986
+ }
23987
+ else {
23988
+ const features = map.querySourceFeatures(this.id, {
23989
+ filter: filter ? filter : undefined,
23990
+ });
23991
+ return features || [];
23992
+ }
23993
+ }, ...(ngDevMode ? [{ debugName: "data" }] : []));
23994
+ renderPopup(f) {
23995
+ if (!this.map) {
23996
+ return undefined;
23997
+ }
23998
+ if (f.layer.id !== this.HEAT_LAYER_ID && f.layer.id !== this.ICON_LAYER_ID && f.layer.id !== this.POINT_LAYER_ID) {
23999
+ return undefined;
24000
+ }
24001
+ if (this.popupRenderer) {
24002
+ return this.popupRenderer.RenderPopup(f);
24003
+ }
24004
+ return undefined;
24005
+ }
23963
24006
  update(settings) {
23964
24007
  this.settings.set({ ...this.settings(), ...settings });
23965
24008
  }
@@ -24039,7 +24082,7 @@ class PointDataMapper {
24039
24082
  getFilter(settings) {
24040
24083
  // Build filter conditions for each field
24041
24084
  const conditions = ['all'];
24042
- const fipsFilter = this.getFipsFilter();
24085
+ const fipsFilter = this.getFipsFilter(settings);
24043
24086
  if (fipsFilter && fipsFilter.length > 0) {
24044
24087
  const filter = [
24045
24088
  'any',
@@ -24068,6 +24111,7 @@ class PointDataMapper {
24068
24111
  }
24069
24112
  onReady(map, svc) {
24070
24113
  this.map = map;
24114
+ this.watcher.on(map, this.id);
24071
24115
  this.svc.set(svc);
24072
24116
  this.loadSource();
24073
24117
  }
@@ -24094,10 +24138,10 @@ class PointDataMapper {
24094
24138
  RemoveLayer(this.map, c.iconLayer);
24095
24139
  }
24096
24140
  }
24097
- this.map.off('click', this.POINT_LAYER_ID, this.onClick);
24098
- this.map.off('touchend', this.POINT_LAYER_ID, this.onClick);
24099
- this.map.off('click', this.ICON_LAYER_ID, this.onClick);
24100
- this.map.off('touchend', this.ICON_LAYER_ID, this.onClick);
24141
+ // this.map.off('click', this.POINT_LAYER_ID, this.onClick);
24142
+ // this.map.off('touchend', this.POINT_LAYER_ID, this.onClick);
24143
+ // this.map.off('click', this.ICON_LAYER_ID, this.onClick);
24144
+ // this.map.off('touchend', this.ICON_LAYER_ID, this.onClick);
24101
24145
  RemoveSource(this.map, `${this.id}-source`);
24102
24146
  }
24103
24147
  loadSource() {
@@ -24117,17 +24161,16 @@ class PointDataMapper {
24117
24161
  type: 'geojson',
24118
24162
  data: sourceURL,
24119
24163
  });
24120
- map.on('click', this.POINT_LAYER_ID, this.onClick);
24121
- map.on('touchend', this.POINT_LAYER_ID, this.onClick);
24122
- map.on('click', this.ICON_LAYER_ID, this.onClick);
24123
- map.on('touchend', this.ICON_LAYER_ID, this.onClick);
24164
+ // map.on('click', this.POINT_LAYER_ID, this.onClick);
24165
+ // map.on('touchend', this.POINT_LAYER_ID, this.onClick);
24166
+ // map.on('click', this.ICON_LAYER_ID, this.onClick);
24167
+ // map.on('touchend', this.ICON_LAYER_ID, this.onClick);
24124
24168
  }
24125
24169
  else if (currentSource._data !== sourceURL) {
24126
24170
  currentSource.setData(sourceURL);
24127
24171
  }
24128
24172
  }
24129
- getFipsFilter() {
24130
- const settings = this.settings();
24173
+ getFipsFilter(settings) {
24131
24174
  if (settings.filterOverrideGlobal) {
24132
24175
  if (settings.filterStates && settings.filterStates.length > 0) {
24133
24176
  return settings.filterStates;
@@ -24312,32 +24355,31 @@ class PointDataMapper {
24312
24355
  }, StandardLayersMapper.POINTS);
24313
24356
  });
24314
24357
  }
24315
- onClick = async (e) => {
24316
- if (!this.map) {
24317
- return;
24318
- }
24319
- let features = [];
24320
- const settings = this.settings();
24321
- if (settings.type == 'circle') {
24322
- features = this.map.queryRenderedFeatures(e.point, { layers: [this.POINT_LAYER_ID] });
24323
- }
24324
- else if (settings.type == 'icon') {
24325
- features = this.map.queryRenderedFeatures(e.point, { layers: [this.ICON_LAYER_ID] });
24326
- }
24327
- if (!features || features.length == 0) {
24328
- return;
24329
- }
24330
- if (this.current) {
24331
- this.current.remove();
24332
- this.current = null;
24333
- }
24334
- if (this.popupRenderer) {
24335
- const html = await this.popupRenderer.RenderPopup(features[0]);
24336
- if (html) {
24337
- this.current = new Popup().setLngLat(e.lngLat).setHTML(html).addTo(this.map);
24338
- }
24339
- }
24340
- };
24358
+ // onClick = async (e: MapLayerMouseEvent | MapLayerTouchEvent) => {
24359
+ // if (!this.map) {
24360
+ // return;
24361
+ // }
24362
+ // let features: GeoJSON.Feature[] = [];
24363
+ // const settings = this.settings();
24364
+ // if (settings.type == 'circle') {
24365
+ // features = this.map.queryRenderedFeatures(e.point, { layers: [this.POINT_LAYER_ID] });
24366
+ // } else if (settings.type == 'icon') {
24367
+ // features = this.map.queryRenderedFeatures(e.point, { layers: [this.ICON_LAYER_ID] });
24368
+ // }
24369
+ // if (!features || features.length == 0) {
24370
+ // return;
24371
+ // }
24372
+ // if (this.current) {
24373
+ // this.current.remove();
24374
+ // this.current = null;
24375
+ // }
24376
+ // if (this.popupRenderer) {
24377
+ // const html = await this.popupRenderer.RenderPopup(features[0]);
24378
+ // if (html) {
24379
+ // this.current = new Popup().setLngLat(e.lngLat).setHTML(html).addTo(this.map);
24380
+ // }
24381
+ // }
24382
+ // };
24341
24383
  getSettings() {
24342
24384
  return { ...this.settings() };
24343
24385
  }
@@ -24442,40 +24484,30 @@ class RailroadsMapper {
24442
24484
  console.warn('RailroadsMapper: style has no `glyphs` URL — skipping labels layer to avoid PBF/glyph parse errors. Switch to a style with glyphs to enable labels.');
24443
24485
  }
24444
24486
  this._update(this.settings());
24445
- if (!added) {
24446
- return;
24487
+ }
24488
+ renderPopup(feature) {
24489
+ if (!this.map) {
24490
+ return undefined;
24447
24491
  }
24448
- map.on('click', this.LINE_LAYER_ID, (e) => {
24449
- // Publish
24450
- this.over.set(e.features && e.features.length > 0 ? e.features[0] : null);
24451
- if (e.features && e.features.length > 0) {
24452
- const feature = e.features[0];
24453
- const coordinates = e.lngLat;
24454
- if (this.popup) {
24455
- this.popup.remove();
24456
- }
24457
- const name = feature.properties['name'];
24458
- const tb = new TableBuilder();
24459
- tb.add('Length', this.fmtDistance(feature.properties['lengthkm']));
24460
- tb.add('Owner', feature.properties['railowner'] ?? '');
24461
- tb.add('Owner Code', feature.properties['railownercode'] ?? '');
24462
- tb.add('Usage', this.usageLabel(feature.properties['railusage'] ?? 0));
24463
- tb.add('Source', feature.properties['source_datadesc'] ?? '');
24464
- tb.add('Originator', feature.properties['source_originator'] ?? '');
24465
- tb.add('Load Date', feature.properties['loaddate'] ?? '');
24466
- const fieldsHtml = tb.toHtml();
24467
- let html = "";
24468
- if (name) {
24469
- html += `<strong>${name}</strong><br/>`;
24470
- }
24471
- html += fieldsHtml;
24472
- this.currentFeatureID = feature?.properties?.['globalid'];
24473
- this.popup = new Popup({ maxWidth: '400px' })
24474
- .setLngLat(coordinates)
24475
- .setHTML(html)
24476
- .addTo(map);
24477
- }
24478
- });
24492
+ if (feature.layer.id !== this.LINE_LAYER_ID && feature.layer.id !== this.LABEL_LAYER_ID) {
24493
+ return undefined;
24494
+ }
24495
+ const name = feature.properties['name'];
24496
+ const tb = new TableBuilder();
24497
+ tb.add('Length', this.fmtDistance(feature.properties['lengthkm']));
24498
+ tb.add('Owner', feature.properties['railowner'] ?? '');
24499
+ tb.add('Owner Code', feature.properties['railownercode'] ?? '');
24500
+ tb.add('Usage', this.usageLabel(feature.properties['railusage'] ?? 0));
24501
+ tb.add('Source', feature.properties['source_datadesc'] ?? '');
24502
+ tb.add('Originator', feature.properties['source_originator'] ?? '');
24503
+ tb.add('Load Date', feature.properties['loaddate'] ?? '');
24504
+ const fieldsHtml = tb.toHtml();
24505
+ let html = "";
24506
+ if (name) {
24507
+ html += `<strong>${name}</strong><br/>`;
24508
+ }
24509
+ html += fieldsHtml;
24510
+ return html;
24479
24511
  }
24480
24512
  fmtDistance(km) {
24481
24513
  if (!km) {
@@ -25023,42 +25055,34 @@ class WatershedMapper {
25023
25055
  }
25024
25056
  }
25025
25057
  });
25026
- map.on('mousemove', this.FILL_LAYER_ID, (e) => {
25027
- this.over.set(e.features && e.features.length > 0 ? e.features[0] : null);
25028
- });
25029
- map.on('click', this.FILL_LAYER_ID, (e) => {
25030
- // Publish
25031
- this.over.set(e.features && e.features.length > 0 ? e.features[0] : null);
25032
- if (e.features && e.features.length > 0) {
25033
- const feature = e.features[0];
25034
- const coordinates = e.lngLat;
25035
- console.log('Feature properties:', feature.properties);
25036
- const name = feature.properties
25037
- ? feature.properties['name']
25038
- : 'Unknown';
25039
- // Ensure that if the popup is already open, we don't create a new one
25040
- if (this.popup) {
25041
- this.popup.remove();
25042
- }
25043
- const fields = feature.properties
25044
- ? Object.entries(feature.properties)
25045
- .map(([key, value]) => `<strong>${key}:</strong> ${value}`)
25046
- .join('<br/>')
25047
- : '';
25048
- this.currentFeatureID = feature?.properties?.['globalid'];
25049
- this.popup = new Popup({ maxWidth: '400px' })
25050
- .setLngLat(coordinates)
25051
- .setHTML(`<strong>Watershed:</strong> ${name}<hr /><br/>${fields}`)
25052
- .addTo(map);
25053
- }
25054
- });
25055
- }
25056
- async onReady(map, svc) {
25057
- this.map = map;
25058
- this.create();
25059
25058
  }
25060
- reset() { }
25061
- clear() {
25059
+ renderPopup(feature) {
25060
+ if (!this.map) {
25061
+ return undefined;
25062
+ }
25063
+ if (feature.layer.id !== this.FILL_LAYER_ID && feature.layer.id !== this.LINE_LAYER_ID && feature.layer.id !== this.LABEL_LAYER_ID) {
25064
+ return undefined;
25065
+ }
25066
+ const name = feature.properties
25067
+ ? feature.properties['name']
25068
+ : 'Unknown';
25069
+ // Ensure that if the popup is already open, we don't create a new one
25070
+ if (this.popup) {
25071
+ this.popup.remove();
25072
+ }
25073
+ const fields = feature.properties
25074
+ ? Object.entries(feature.properties)
25075
+ .map(([key, value]) => `<strong>${key}:</strong> ${value}`)
25076
+ .join('<br/>')
25077
+ : '';
25078
+ return `<strong>Watershed:</strong> ${name}<hr /><br/>${fields}`;
25079
+ }
25080
+ async onReady(map, svc) {
25081
+ this.map = map;
25082
+ this.create();
25083
+ }
25084
+ reset() { }
25085
+ clear() {
25062
25086
  if (this.map) {
25063
25087
  this.map.removeLayer(this.FILL_LAYER_ID);
25064
25088
  this.map.removeLayer(this.LINE_LAYER_ID);
@@ -25637,31 +25661,1491 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImpo
25637
25661
  ` }]
25638
25662
  }] });
25639
25663
 
25640
- class ShowHideBtn {
25641
- faEye = faEye;
25642
- faEyeSlash = faEyeSlash;
25643
- mapper = input.required(...(ngDevMode ? [{ debugName: "mapper" }] : []));
25644
- toggleShowHide() {
25645
- const current = this.mapper().settings().visible;
25646
- this.mapper().update({ visible: !current });
25664
+ function ConsumerSpendingFromPath(path) {
25665
+ const parts = path.split('/');
25666
+ if (parts.length < 3) {
25667
+ throw new Error('Invalid path format');
25668
+ }
25669
+ const year = parts[0];
25670
+ const measure = parts[1];
25671
+ const valueType = parts[2];
25672
+ // A = Avgerage Spending, T = Total Spending, I = Index
25673
+ // Year/Measure/(A|T|I)
25674
+ return { measure, year, valueType };
25675
+ }
25676
+
25677
+ /**
25678
+ * The DataSetMapper is responsible for making a Choropleth Map with
25679
+ * a single DataSet dataset.
25680
+ */
25681
+ class DataSetMapper {
25682
+ http = inject(HttpClient);
25683
+ ID = Math.random().toString(36).substring(2, 15);
25684
+ LAYER_ID = 'naas-layer-fill-' + this.ID;
25685
+ SOURCE_ID = 'naas-source-' + this.ID;
25686
+ settings = signal(new DataSetSettings(), ...(ngDevMode ? [{ debugName: "settings" }] : []));
25687
+ current = null;
25688
+ currentFeatureID = undefined;
25689
+ over = signal(null, ...(ngDevMode ? [{ debugName: "over" }] : []));
25690
+ map = undefined;
25691
+ svc = signal(null, ...(ngDevMode ? [{ debugName: "svc" }] : []));
25692
+ legends;
25693
+ count = 0;
25694
+ total = 0;
25695
+ // Resource to download and parse the PBF file
25696
+ dataResource = rxResource({
25697
+ params: () => this.settings().path,
25698
+ stream: ({ params }) => {
25699
+ const url = `https://static.foodmarketmaker.com/${params}.pbf`;
25700
+ return this.http.get(url, { responseType: 'arraybuffer' }).pipe(map((buffer) => TabularDataSetP.decode(new Uint8Array(buffer))));
25701
+ }
25702
+ });
25703
+ info = computed(() => {
25704
+ const path = this.settings().path;
25705
+ return this.InfoFromPath(path);
25706
+ }, ...(ngDevMode ? [{ debugName: "info" }] : []));
25707
+ name = computed(() => {
25708
+ if (this.dataResource.isLoading()) {
25709
+ return 'DataSet Loading...';
25710
+ }
25711
+ if (this.dataResource.error()) {
25712
+ return 'DataSet Error...';
25713
+ }
25714
+ const ds = this.dataResource.value();
25715
+ if (ds?.name) {
25716
+ return ds.name;
25717
+ }
25718
+ if (ds) {
25719
+ return this.NameFrom(ds);
25720
+ }
25721
+ return 'Unknown';
25722
+ }, ...(ngDevMode ? [{ debugName: "name" }] : []));
25723
+ desc = computed(() => {
25724
+ if (this.dataResource.isLoading()) {
25725
+ return ' ';
25726
+ }
25727
+ if (this.dataResource.error()) {
25728
+ return ' ';
25729
+ }
25730
+ const ds = this.dataResource.value();
25731
+ if (ds?.description) {
25732
+ return ds.name;
25733
+ }
25734
+ if (ds) {
25735
+ const commodity = DataSetFieldValue(ds, -1, "PRODN_PRACTICE_DESC") || '';
25736
+ const units = DataSetFieldValue(ds, -1, "UNIT_DESC") || '';
25737
+ return `${commodity} (${units})`;
25738
+ }
25739
+ return 'NASS Data';
25740
+ }, ...(ngDevMode ? [{ debugName: "desc" }] : []));
25741
+ // Generate the availble feature states
25742
+ featureStates = computed(() => {
25743
+ const dataSet = this.dataResource.value();
25744
+ if (!dataSet) {
25745
+ return {
25746
+ states: [],
25747
+ min: 0,
25748
+ max: 1,
25749
+ };
25750
+ }
25751
+ const filters = this.svc()?.stateCountyFilter() || [];
25752
+ const fieldState = this.findFirstType(dataSet, TabularFieldUsage.TABULAR_USAGE_FIPS_STATE);
25753
+ const fieldCounty = this.findFirstType(dataSet, TabularFieldUsage.TABULAR_USAGE_FIPS_COUNTY);
25754
+ const fieldValue = this.findFirstType(dataSet, TabularFieldUsage.TABULAR_USAGE_VALUE);
25755
+ let maxV = Number.NEGATIVE_INFINITY;
25756
+ let minV = Number.POSITIVE_INFINITY;
25757
+ // Caclulate min/max if not provided and filter out the rows that are necessary
25758
+ const keep = [];
25759
+ for (let i = 0; i < (dataSet.data?.length || 0); i++) {
25760
+ const row = dataSet.data ? dataSet.data[i] : undefined;
25761
+ if (!row || !row.cells) {
25762
+ continue;
25763
+ }
25764
+ const fips = FipsFromDataSet(dataSet, i);
25765
+ if (!fips || fips.endsWith("998") || fips.endsWith("999")) {
25766
+ // Skip invalid or unknown FIPS
25767
+ continue;
25768
+ }
25769
+ let found = false;
25770
+ for (let f of filters) {
25771
+ if (fips.startsWith(f)) {
25772
+ // Match filter
25773
+ found = true;
25774
+ break;
25775
+ }
25776
+ }
25777
+ if (!found && filters.length > 0) {
25778
+ continue;
25779
+ }
25780
+ const value = row.cells[fieldValue?.index || 0].floatValue || NaN;
25781
+ if (!isNaN(value)) {
25782
+ maxV = Math.max(maxV, value);
25783
+ minV = Math.min(minV, value);
25784
+ keep.push(row);
25785
+ }
25786
+ }
25787
+ // handle edge case
25788
+ if (maxV === Number.NEGATIVE_INFINITY) {
25789
+ maxV = 1;
25790
+ }
25791
+ if (minV === Number.POSITIVE_INFINITY) {
25792
+ minV = 0;
25793
+ }
25794
+ // Set the min max
25795
+ // Feature state is an object with id and value
25796
+ const states = [];
25797
+ for (let i = 0; i < keep.length; i++) {
25798
+ const row = keep[i];
25799
+ if (!row || !row.cells) {
25800
+ continue;
25801
+ }
25802
+ const state = row.cells[fieldState?.index || 0].stringValue;
25803
+ const county = row.cells[fieldCounty?.index || 0].stringValue;
25804
+ const value = row.cells[fieldValue?.index || 0].floatValue || 0.0;
25805
+ const normValue = normalize(value, minV, maxV);
25806
+ const fs = {
25807
+ id: county || state || "UNKNOWN",
25808
+ raw: value || 0.0,
25809
+ value: normValue,
25810
+ row: i,
25811
+ dataset: dataSet,
25812
+ state: state || '',
25813
+ max: maxV,
25814
+ min: minV,
25815
+ };
25816
+ states.push(fs);
25817
+ }
25818
+ return {
25819
+ states: states,
25820
+ min: minV,
25821
+ max: maxV,
25822
+ };
25823
+ }, ...(ngDevMode ? [{ debugName: "featureStates" }] : []));
25824
+ constructor(settings) {
25825
+ if (settings) {
25826
+ this.settings.update(current => ({
25827
+ ...current,
25828
+ ...settings,
25829
+ }));
25830
+ }
25831
+ const _ = effect(() => {
25832
+ const settings = this.settings();
25833
+ const dataset = this.dataResource.value();
25834
+ const features = this.featureStates();
25835
+ this._update(settings, dataset, features.states);
25836
+ }, ...(ngDevMode ? [{ debugName: "_" }] : []));
25837
+ const _updateGlobal = effect(() => {
25838
+ const svc = this.svc();
25839
+ if (!svc) {
25840
+ return;
25841
+ }
25842
+ const _ = svc.stateCountyFilter(); // depend
25843
+ this._update(this.settings(), this.dataResource.value(), this.featureStates().states);
25844
+ }, ...(ngDevMode ? [{ debugName: "_updateGlobal" }] : []));
25647
25845
  }
25648
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: ShowHideBtn, deps: [], target: i0.ɵɵFactoryTarget.Component });
25649
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "20.3.15", type: ShowHideBtn, isStandalone: true, selector: "mapag-show-hide-btn", inputs: { mapper: { classPropertyName: "mapper", publicName: "mapper", isSignal: true, isRequired: true, transformFunction: null } }, ngImport: i0, template: `
25650
- <button class="btn" (click)="toggleShowHide()">
25651
- <fa-icon [icon]="mapper().settings().visible ? faEyeSlash : faEye"></fa-icon>
25652
- {{ mapper().settings().visible ? 'Hide' : 'Show' }}
25653
- </button>
25654
- `, isInline: true, styles: ["dialog{font-size:14pt;width:100%;max-width:700px;border:none;border-radius:8px;box-shadow:0 2px 10px #0003;padding:16px;position:fixed;top:50%;left:50%;transform:translate(-50%,-50%);margin:0;flex-direction:column}dialog:open{display:flex}dialog .dlg-body{flex-grow:1;overflow-y:auto}dialog.legend{width:fit-content}dialog.legend h2{font-size:smaller}dialog select{max-width:90vw}dialog h2{color:#000}dialog h2:before{content:\"\\22ee\\22ee \";padding-right:4px}dialog h3{color:#000;border-bottom:2px solid gray;font-weight:500;font-size:.9em;margin-top:16px;margin-bottom:8px}dialog h4{color:#000;font-weight:500;margin-bottom:8px;margin-top:12px;font-size:.85em;border:none}dialog p{font-size:.8em}dialog a{text-decoration:none;color:#0a3773;font-weight:500;font-size:.8em;padding-left:4px}dialog a:hover{text-decoration:underline;cursor:pointer}dialog a:before{content:\"\\1f517\";padding-right:2px}.ctrl-group{display:flex;flex-direction:column}.ctrl-row{display:grid;grid-template-columns:auto 1fr auto 1fr;align-items:center;gap:4px;justify-items:start;padding-left:20px}.ctrl-first{grid-column:1}.ctrl-row label{font-size:.8em;margin:0;padding:0;font-weight:400}.ctrl.wide{grid-column:span 3}input[type=range]{grid-column:span 3;justify-self:stretch}input[type=color]{width:40px;height:24px;border-radius:4px;cursor:pointer}input[type=number]{width:6ch;font-size:.8em}.dlg-buttons{display:flex;justify-content:flex-end;gap:8px;margin-top:16px}button{background-color:#0a3773;color:#fff;border:none;border-radius:4px;padding:8px 16px;cursor:pointer;font-size:.8em}button:hover{background-color:#083a5c}summary{font-size:1em;font-weight:600;color:#000;cursor:pointer;padding:8px 0;border-bottom:2px solid gray;list-style:none;-webkit-user-select:none;user-select:none;margin-bottom:8px}summary::-webkit-details-marker{display:none}summary:before{content:\"\\304f\";display:inline-block;margin-right:8px;transform:rotate(180deg);transition:transform .2s}details[open] summary:before{transform:rotate(270deg)}.radio-tabs{margin-bottom:12px;font-size:.8em;display:flex;flex-direction:row}.radio-tabs label{display:grid;grid-template-columns:auto 1fr;gap:4px;grid-template-rows:30px;align-items:center}.radio-tabs input[type=radio]{display:none}.radio-tabs label{padding:8px 12px;border:2px solid transparent;border-radius:6px;cursor:pointer;transition:all .2s ease}.radio-tabs label:has(input[type=radio]:checked){background-color:#fff;border-color:#333}.mgr-btn{justify-self:center;background-color:transparent;color:#4c4c4c;text-align:center;width:100%;font-weight:600;cursor:pointer;display:flex;align-items:center;justify-content:center;margin:4px 0;padding:6px;gap:4px;border:1px solid rgb(218,218,218)}.mgr-btn:hover{background-color:transparent;border-color:#4c4c4c}.legend-row{display:grid;grid-template-columns:auto 1fr;gap:8px;padding:4px 0;align-items:center}.legend-title{font-weight:700;text-align:center;margin-bottom:8px}.legend-item{height:15px;width:15px;border:1px solid #ccc}.maplibregl-popup-close-button{top:13px;right:15px}@media screen and (max-width: 600px){dialog{width:100vw;max-width:100vw;height:100dvh;max-height:100dvh;border-radius:0;border:none;box-shadow:none;overflow:hidden}.dlg-buttons{flex-direction:row;flex-wrap:wrap;align-items:center;justify-content:center}dialog h2:before{content:\"\";padding-right:0}}:host{display:content}.btn{width:12ch}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "component", type: FaIconComponent, selector: "fa-icon", inputs: ["icon", "title", "animation", "mask", "flip", "size", "pull", "border", "inverse", "symbol", "rotate", "fixedWidth", "transform", "a11yRole"], outputs: ["iconChange", "titleChange", "animationChange", "maskChange", "flipChange", "sizeChange", "pullChange", "borderChange", "inverseChange", "symbolChange", "rotateChange", "fixedWidthChange", "transformChange", "a11yRoleChange"] }] });
25846
+ update(settings) {
25847
+ this.settings.update(current => ({ ...current, ...settings }));
25848
+ }
25849
+ _update(settings, dataSet, featureStates) {
25850
+ if (!this.map) {
25851
+ return;
25852
+ }
25853
+ const map = this.map;
25854
+ this.create();
25855
+ this.setFeatureStates(this.settings(), featureStates);
25856
+ this.updateStyle(settings);
25857
+ }
25858
+ create() {
25859
+ if (!this.map) {
25860
+ return;
25861
+ }
25862
+ const map = this.map;
25863
+ const area = Layers.FindVector(this.settings().areaType);
25864
+ if (!area) {
25865
+ console.error('NAASMapper: Unknown area type ' + this.settings().areaType);
25866
+ return;
25867
+ }
25868
+ AddSource(this.map, this.SOURCE_ID, {
25869
+ type: area.SourceType || 'vector',
25870
+ tiles: [area.URL],
25871
+ promoteId: area.IDField || "GEOID", // promote field to be used as a foreign key
25872
+ });
25873
+ const addedFill = AddLayer(this.map, {
25874
+ id: this.LAYER_ID,
25875
+ type: 'fill',
25876
+ source: this.SOURCE_ID,
25877
+ 'source-layer': area.Source,
25878
+ paint: {
25879
+ 'fill-outline-color': '#e5541c',
25880
+ 'fill-opacity': this.settings().fillOpacity,
25881
+ 'fill-color': this.settings().fillColor,
25882
+ },
25883
+ layout: {
25884
+ visibility: 'none',
25885
+ },
25886
+ }, StandardLayersMapper.POLYGONS_BACKGROUND);
25887
+ map.off('click', this.LAYER_ID, this.onClick);
25888
+ map.on('click', this.LAYER_ID, this.onClick);
25889
+ }
25890
+ setFeatureStates(settings, fs) {
25891
+ if (!this.map) {
25892
+ return;
25893
+ }
25894
+ const map = this.map;
25895
+ const states = fs || [];
25896
+ const dataSet = this.dataResource.value();
25897
+ const src = Layers.FindVector(settings.areaType);
25898
+ if (!src) {
25899
+ console.error('NAASMapper: Unknown area type ' + settings.areaType);
25900
+ return;
25901
+ }
25902
+ // Remove all the previous feature states
25903
+ map.removeFeatureState({
25904
+ source: this.SOURCE_ID,
25905
+ sourceLayer: src.Source,
25906
+ });
25907
+ if (!dataSet || !fs) {
25908
+ return;
25909
+ }
25910
+ for (let state of states) {
25911
+ try {
25912
+ map.setFeatureState({
25913
+ source: this.SOURCE_ID,
25914
+ sourceLayer: src.Source,
25915
+ id: state.id,
25916
+ }, state);
25917
+ }
25918
+ catch (e) {
25919
+ console.warn('NAASMapper: Failed to set feature state for id ' + state.id, e);
25920
+ }
25921
+ }
25922
+ }
25923
+ getFipsFilter() {
25924
+ const settings = this.settings();
25925
+ if (settings.filterOverrideGlobal) {
25926
+ if (settings.filterStates && settings.filterStates.length > 0) {
25927
+ return settings.filterStates;
25928
+ }
25929
+ else if (settings.filterState) {
25930
+ return [settings.filterState];
25931
+ }
25932
+ }
25933
+ return this.svc()?.stateCountyFilter();
25934
+ }
25935
+ updateStyle(settings) {
25936
+ if (!this.map) {
25937
+ return;
25938
+ }
25939
+ const map = this.map;
25940
+ if (settings.visible) {
25941
+ map.setLayoutProperty(this.LAYER_ID, 'visibility', 'visible');
25942
+ }
25943
+ else {
25944
+ map.setLayoutProperty(this.LAYER_ID, 'visibility', 'none');
25945
+ }
25946
+ if (settings.fillType === 'palette') {
25947
+ this.map.setPaintProperty(this.LAYER_ID, 'fill-color', [
25948
+ 'interpolate',
25949
+ ['linear'],
25950
+ ['feature-state', 'value'],
25951
+ ...ColorPalettes.fromPalette(settings.fillPalette)
25952
+ ]);
25953
+ }
25954
+ else if (settings.fillType === 'gradient') {
25955
+ this.map.setPaintProperty(this.LAYER_ID, 'fill-color', fromGradient(settings.fillGradient, ['feature-state', 'value']));
25956
+ }
25957
+ else if (settings.fillType === 'solid') {
25958
+ this.map.setPaintProperty(this.LAYER_ID, 'fill-color', settings.fillColor);
25959
+ }
25960
+ const filterExpr = prefixMatch(["feature-state", "id"], this.getFipsFilter());
25961
+ if (filterExpr && filterExpr.length > 0) {
25962
+ const conditions = ['all'];
25963
+ conditions.push(['!=', ['feature-state', 'value'], null]),
25964
+ conditions.push(filterExpr);
25965
+ map.setPaintProperty(this.LAYER_ID, 'fill-opacity', [
25966
+ 'case',
25967
+ conditions,
25968
+ settings.fillOpacity,
25969
+ 0
25970
+ ]);
25971
+ }
25972
+ else {
25973
+ map.setPaintProperty(this.LAYER_ID, 'fill-opacity', [
25974
+ 'case',
25975
+ ['!=', ['feature-state', 'value'], null],
25976
+ settings.fillOpacity,
25977
+ 0
25978
+ ]);
25979
+ }
25980
+ map.setPaintProperty(this.LAYER_ID, 'fill-outline-color', settings.borderColor);
25981
+ }
25982
+ findFirstType(dataset, usage) {
25983
+ if (!dataset.schema) {
25984
+ return null;
25985
+ }
25986
+ if (!dataset.schema.fields) {
25987
+ return null;
25988
+ }
25989
+ for (let field of Object.keys(dataset.schema?.fields)) {
25990
+ const fieldDef = dataset.schema?.fields[field];
25991
+ if (fieldDef.usage == usage) {
25992
+ return fieldDef;
25993
+ }
25994
+ }
25995
+ return null;
25996
+ }
25997
+ onReady(map, svc) {
25998
+ this.map = map;
25999
+ this.svc.set(svc);
26000
+ this._update(this.settings(), this.dataResource.value(), this.featureStates().states);
26001
+ }
26002
+ reset() {
26003
+ this.clear();
26004
+ }
26005
+ clear() {
26006
+ if (this.map) {
26007
+ this.map.off('click', this.LAYER_ID, this.onClick);
26008
+ RemoveLayer(this.map, this.LAYER_ID);
26009
+ RemoveLayer(this.map, this.SOURCE_ID);
26010
+ }
26011
+ }
26012
+ onClick = async (e) => {
26013
+ if (!this.map) {
26014
+ return;
26015
+ }
26016
+ const settings = this.settings();
26017
+ const src = Layers.FindVector(settings.areaType);
26018
+ if (!src) {
26019
+ console.warn('ChoroplethMapper: No source found for area type ', settings.areaType);
26020
+ return;
26021
+ }
26022
+ const features = this.map.queryRenderedFeatures(e.point, {
26023
+ layers: [this.LAYER_ID],
26024
+ });
26025
+ if (features.length > 0) {
26026
+ e.preventDefault();
26027
+ if (this.current) {
26028
+ this.current.remove();
26029
+ this.current = null;
26030
+ }
26031
+ const f = features[0];
26032
+ const state = this.map.getFeatureState({
26033
+ source: this.SOURCE_ID,
26034
+ sourceLayer: src.Source,
26035
+ id: f.id
26036
+ });
26037
+ const html = await this.RenderPopup(f, state);
26038
+ if (html) {
26039
+ this.current = new Popup().setLngLat(e.lngLat).setHTML(html).addTo(this.map);
26040
+ }
26041
+ }
26042
+ };
26043
+ }
26044
+ function FipsFromDataSet(ds, rowIndex) {
26045
+ if (!ds.schema || !ds.schema.fields) {
26046
+ return null;
26047
+ }
26048
+ const state = DataSetFieldValue(ds, rowIndex, "STATE_FIPS_CODE");
26049
+ const county = DataSetFieldValue(ds, rowIndex, "COUNTY_CODE");
26050
+ if (county) {
26051
+ return county;
26052
+ }
26053
+ if (state) {
26054
+ return state;
26055
+ }
26056
+ return null;
26057
+ }
26058
+ function DataSetFieldValue(ds, rowIndex, field) {
26059
+ if (!ds.schema || !ds.data) {
26060
+ return null;
26061
+ }
26062
+ const fieldDef = ds.schema.fields ? ds.schema.fields[field] : null;
26063
+ if (!fieldDef) {
26064
+ return null;
26065
+ }
26066
+ if (fieldDef.staticvalue) {
26067
+ switch (fieldDef.datatype || 0) {
26068
+ case TabularDatatype.TABULAR_DATATYPE_STRING:
26069
+ return fieldDef.staticvalue.stringValue || null;
26070
+ case TabularDatatype.TABULAR_DATATYPE_FLOAT:
26071
+ return fieldDef.staticvalue.floatValue || null;
26072
+ case TabularDatatype.TABULAR_DATATYPE_INTEGER:
26073
+ return fieldDef.staticvalue.intValue || null;
26074
+ default:
26075
+ return null;
26076
+ }
26077
+ }
26078
+ if (rowIndex < 0) {
26079
+ return null;
26080
+ }
26081
+ const index = fieldDef.index || -1;
26082
+ if (index < 0 || rowIndex < 0 || rowIndex >= ds.data.length) {
26083
+ return null;
26084
+ }
26085
+ const row = ds.data[rowIndex];
26086
+ const cell = row.cells ? row.cells[index] : null;
26087
+ if (!cell) {
26088
+ return null;
26089
+ }
26090
+ switch (fieldDef.datatype || 0) {
26091
+ case TabularDatatype.TABULAR_DATATYPE_STRING:
26092
+ return cell.stringValue || null;
26093
+ case TabularDatatype.TABULAR_DATATYPE_FLOAT:
26094
+ return cell.floatValue || null;
26095
+ case TabularDatatype.TABULAR_DATATYPE_INTEGER:
26096
+ return cell.intValue || null;
26097
+ default:
26098
+ return null;
26099
+ }
26100
+ }
26101
+ class DataSetSettings {
26102
+ path = "";
26103
+ areaType = "county";
26104
+ visible = true;
26105
+ palette = allColors['Spectral']['10'];
26106
+ fillType = 'gradient';
26107
+ fillColor = '#e5541c';
26108
+ fillPalette = ColorPalettes.find('Spectral.10') || ColorPalettes.default();
26109
+ fillGradient = [{ "value": 0.0, "color": "#ffffcc" }, { "value": 1.0, "color": "#000000" }];
26110
+ fillOpacity = 1;
26111
+ filterState = '';
26112
+ filterStates = [];
26113
+ filterOverrideGlobal = false;
26114
+ borderColor = '#e5541c';
26115
+ labelsVisible = true;
26116
+ labelsSize = 10;
26117
+ labelsColor = '#000000';
26118
+ labelsHaloColor = '#ffffff';
26119
+ labelsHaloWidth = 1;
26120
+ labelsOpacity = 1.0;
26121
+ labelOverlap = false;
26122
+ showLegend = false;
26123
+ fipsExcludeSuffixes = ['999', '998', '000'];
26124
+ }
26125
+
26126
+ class ConsumerSpendingMapper extends DataSetMapper {
26127
+ RenderPopup(feature, state) {
26128
+ if (!state.dataset)
26129
+ return undefined;
26130
+ const data = state.dataset;
26131
+ const name = feature.properties?.['name'] || 'Unknown';
26132
+ const totalSpending = 0;
26133
+ const avgSpending = 0;
26134
+ return `
26135
+ <div>
26136
+ <h3>${name}</h3>
26137
+ <p>Total Spending: $${totalSpending.toLocaleString()}</p>
26138
+ <p>Average Spending: $${avgSpending.toLocaleString()}</p>
26139
+ </div>
26140
+ `;
26141
+ }
26142
+ InfoFromPath(path) {
26143
+ return ConsumerSpendingFromPath(path);
26144
+ }
26145
+ NameFrom(ds) {
26146
+ return ds.name || 'Unknown';
26147
+ }
26148
+ }
26149
+
26150
+ class DialogHeader {
26151
+ faTimes = faTimes;
26152
+ dialog = input(...(ngDevMode ? [undefined, { debugName: "dialog" }] : []));
26153
+ close() {
26154
+ // Close the dialog by finding the closest dialog element and calling its close method
26155
+ const d = this.dialog();
26156
+ if (d) {
26157
+ d.close();
26158
+ }
26159
+ }
26160
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: DialogHeader, deps: [], target: i0.ɵɵFactoryTarget.Component });
26161
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "20.3.15", type: DialogHeader, isStandalone: true, selector: "mapag-dialog-header", inputs: { dialog: { classPropertyName: "dialog", publicName: "dialog", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: `
26162
+ <h2><ng-content></ng-content></h2>
26163
+ <button class="btn-icon" (click)="close()"><fa-icon [icon]="faTimes" size="lg"></fa-icon></button>
26164
+ `, isInline: true, styles: ["dialog{font-size:14pt;width:100%;max-width:700px;border:none;border-radius:8px;box-shadow:0 2px 10px #0003;padding:16px;position:fixed;top:50%;left:50%;transform:translate(-50%,-50%);margin:0;flex-direction:column}dialog:open{display:flex}dialog .dlg-body{flex-grow:1;overflow-y:auto}dialog.legend{width:fit-content}dialog.legend h2{font-size:smaller}dialog select{max-width:90vw}dialog h2{color:#000}dialog h2:before{content:\"\\22ee\\22ee \";padding-right:4px}dialog h3{color:#000;border-bottom:2px solid gray;font-weight:500;font-size:.9em;margin-top:16px;margin-bottom:8px}dialog h4{color:#000;font-weight:500;margin-bottom:8px;margin-top:12px;font-size:.85em;border:none}dialog p{font-size:.8em}dialog a{text-decoration:none;color:#0a3773;font-weight:500;font-size:.8em;padding-left:4px}dialog a:hover{text-decoration:underline;cursor:pointer}dialog a:before{content:\"\\1f517\";padding-right:2px}.ctrl-group{display:flex;flex-direction:column}.ctrl-row{display:grid;grid-template-columns:auto 1fr auto 1fr;align-items:center;gap:4px;justify-items:start;padding-left:20px}.ctrl-first{grid-column:1}.ctrl-row label{font-size:.8em;margin:0;padding:0;font-weight:400}.ctrl.wide{grid-column:span 3}input[type=range]{grid-column:span 3;justify-self:stretch}input[type=color]{width:40px;height:24px;border-radius:4px;cursor:pointer}input[type=number]{width:6ch;font-size:.8em}.dlg-buttons{display:flex;justify-content:flex-end;gap:8px;margin-top:16px}button{background-color:#0a3773;color:#fff;border:none;border-radius:4px;padding:8px 16px;cursor:pointer;font-size:.8em}button:hover{background-color:#083a5c}summary{font-size:1em;font-weight:600;color:#000;cursor:pointer;padding:8px 0;border-bottom:2px solid gray;list-style:none;-webkit-user-select:none;user-select:none;margin-bottom:8px}summary::-webkit-details-marker{display:none}summary:before{content:\"\\304f\";display:inline-block;margin-right:8px;transform:rotate(180deg);transition:transform .2s}details[open] summary:before{transform:rotate(270deg)}.radio-tabs{margin-bottom:12px;font-size:.8em;display:flex;flex-direction:row}.radio-tabs label{display:grid;grid-template-columns:auto 1fr;gap:4px;grid-template-rows:30px;align-items:center}.radio-tabs input[type=radio]{display:none}.radio-tabs label{padding:8px 12px;border:2px solid transparent;border-radius:6px;cursor:pointer;transition:all .2s ease}.radio-tabs label:has(input[type=radio]:checked){background-color:#fff;border-color:#333}.mgr-btn{justify-self:center;background-color:transparent;color:#4c4c4c;text-align:center;width:100%;font-weight:600;cursor:pointer;display:flex;align-items:center;justify-content:center;margin:4px 0;padding:6px;gap:4px;border:1px solid rgb(218,218,218)}.mgr-btn:hover{background-color:transparent;border-color:#4c4c4c}.legend-row{display:grid;grid-template-columns:auto 1fr;gap:8px;padding:4px 0;align-items:center}.legend-title{font-weight:700;text-align:center;margin-bottom:8px}.legend-item{height:15px;width:15px;border:1px solid #ccc}.maplibregl-popup-close-button{top:13px;right:15px}@media screen and (max-width: 600px){dialog{width:100vw;max-width:100vw;height:100dvh;max-height:100dvh;border-radius:0;border:none;box-shadow:none;overflow:hidden}.dlg-buttons{flex-direction:row;flex-wrap:wrap;align-items:center;justify-content:center}dialog h2:before{content:\"\";padding-right:0}}:host{display:flex;align-items:center}:host:first-child{flex-grow:1}:host h2{margin:0;flex-grow:1}.btn-icon{padding:2px;border:none;background:transparent;cursor:pointer;border-radius:4px;color:gray}.btn-icon:hover{color:#000;background-color:transparent}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "component", type: FaIconComponent, selector: "fa-icon", inputs: ["icon", "title", "animation", "mask", "flip", "size", "pull", "border", "inverse", "symbol", "rotate", "fixedWidth", "transform", "a11yRole"], outputs: ["iconChange", "titleChange", "animationChange", "maskChange", "flipChange", "sizeChange", "pullChange", "borderChange", "inverseChange", "symbolChange", "rotateChange", "fixedWidthChange", "transformChange", "a11yRoleChange"] }] });
26165
+ }
26166
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: DialogHeader, decorators: [{
26167
+ type: Component,
26168
+ args: [{ selector: 'mapag-dialog-header', imports: [CommonModule, FaIconComponent], template: `
26169
+ <h2><ng-content></ng-content></h2>
26170
+ <button class="btn-icon" (click)="close()"><fa-icon [icon]="faTimes" size="lg"></fa-icon></button>
26171
+ `, styles: ["dialog{font-size:14pt;width:100%;max-width:700px;border:none;border-radius:8px;box-shadow:0 2px 10px #0003;padding:16px;position:fixed;top:50%;left:50%;transform:translate(-50%,-50%);margin:0;flex-direction:column}dialog:open{display:flex}dialog .dlg-body{flex-grow:1;overflow-y:auto}dialog.legend{width:fit-content}dialog.legend h2{font-size:smaller}dialog select{max-width:90vw}dialog h2{color:#000}dialog h2:before{content:\"\\22ee\\22ee \";padding-right:4px}dialog h3{color:#000;border-bottom:2px solid gray;font-weight:500;font-size:.9em;margin-top:16px;margin-bottom:8px}dialog h4{color:#000;font-weight:500;margin-bottom:8px;margin-top:12px;font-size:.85em;border:none}dialog p{font-size:.8em}dialog a{text-decoration:none;color:#0a3773;font-weight:500;font-size:.8em;padding-left:4px}dialog a:hover{text-decoration:underline;cursor:pointer}dialog a:before{content:\"\\1f517\";padding-right:2px}.ctrl-group{display:flex;flex-direction:column}.ctrl-row{display:grid;grid-template-columns:auto 1fr auto 1fr;align-items:center;gap:4px;justify-items:start;padding-left:20px}.ctrl-first{grid-column:1}.ctrl-row label{font-size:.8em;margin:0;padding:0;font-weight:400}.ctrl.wide{grid-column:span 3}input[type=range]{grid-column:span 3;justify-self:stretch}input[type=color]{width:40px;height:24px;border-radius:4px;cursor:pointer}input[type=number]{width:6ch;font-size:.8em}.dlg-buttons{display:flex;justify-content:flex-end;gap:8px;margin-top:16px}button{background-color:#0a3773;color:#fff;border:none;border-radius:4px;padding:8px 16px;cursor:pointer;font-size:.8em}button:hover{background-color:#083a5c}summary{font-size:1em;font-weight:600;color:#000;cursor:pointer;padding:8px 0;border-bottom:2px solid gray;list-style:none;-webkit-user-select:none;user-select:none;margin-bottom:8px}summary::-webkit-details-marker{display:none}summary:before{content:\"\\304f\";display:inline-block;margin-right:8px;transform:rotate(180deg);transition:transform .2s}details[open] summary:before{transform:rotate(270deg)}.radio-tabs{margin-bottom:12px;font-size:.8em;display:flex;flex-direction:row}.radio-tabs label{display:grid;grid-template-columns:auto 1fr;gap:4px;grid-template-rows:30px;align-items:center}.radio-tabs input[type=radio]{display:none}.radio-tabs label{padding:8px 12px;border:2px solid transparent;border-radius:6px;cursor:pointer;transition:all .2s ease}.radio-tabs label:has(input[type=radio]:checked){background-color:#fff;border-color:#333}.mgr-btn{justify-self:center;background-color:transparent;color:#4c4c4c;text-align:center;width:100%;font-weight:600;cursor:pointer;display:flex;align-items:center;justify-content:center;margin:4px 0;padding:6px;gap:4px;border:1px solid rgb(218,218,218)}.mgr-btn:hover{background-color:transparent;border-color:#4c4c4c}.legend-row{display:grid;grid-template-columns:auto 1fr;gap:8px;padding:4px 0;align-items:center}.legend-title{font-weight:700;text-align:center;margin-bottom:8px}.legend-item{height:15px;width:15px;border:1px solid #ccc}.maplibregl-popup-close-button{top:13px;right:15px}@media screen and (max-width: 600px){dialog{width:100vw;max-width:100vw;height:100dvh;max-height:100dvh;border-radius:0;border:none;box-shadow:none;overflow:hidden}.dlg-buttons{flex-direction:row;flex-wrap:wrap;align-items:center;justify-content:center}dialog h2:before{content:\"\";padding-right:0}}:host{display:flex;align-items:center}:host:first-child{flex-grow:1}:host h2{margin:0;flex-grow:1}.btn-icon{padding:2px;border:none;background:transparent;cursor:pointer;border-radius:4px;color:gray}.btn-icon:hover{color:#000;background-color:transparent}\n"] }]
26172
+ }], propDecorators: { dialog: [{ type: i0.Input, args: [{ isSignal: true, alias: "dialog", required: false }] }] } });
26173
+
26174
+ class GradientLegend {
26175
+ topStyle = signal({}, ...(ngDevMode ? [{ debugName: "topStyle" }] : []));
26176
+ bottomStyle = signal({}, ...(ngDevMode ? [{ debugName: "bottomStyle" }] : []));
26177
+ gradientStyle = signal({}, ...(ngDevMode ? [{ debugName: "gradientStyle" }] : []));
26178
+ settings = input(new GradientSettings(), ...(ngDevMode ? [{ debugName: "settings" }] : []));
26179
+ renderer = inject(Renderer2);
26180
+ host = inject((ElementRef));
26181
+ constructor() {
26182
+ const onUpdateSettings = effect(() => {
26183
+ const settings = this.settings();
26184
+ this.topStyle.set({
26185
+ background: settings.minTop ? settings.minColor : settings.maxColor,
26186
+ value: settings.minValue
26187
+ });
26188
+ this.bottomStyle.set({
26189
+ background: settings.minTop ? settings.maxColor : settings.minColor,
26190
+ value: settings.maxValue
26191
+ });
26192
+ this.gradientStyle.set({
26193
+ background: `linear-gradient(${settings.dir === 'horizontal' ? 'to right' : 'to top'}, ${settings.minColor}, ${settings.maxColor})`,
26194
+ height: settings.dir === 'horizontal' ? '30px' : '100%',
26195
+ width: settings.dir === 'horizontal' ? '100%' : '30px'
26196
+ });
26197
+ }, ...(ngDevMode ? [{ debugName: "onUpdateSettings" }] : []));
26198
+ }
26199
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: GradientLegend, deps: [], target: i0.ɵɵFactoryTarget.Component });
26200
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "20.3.15", type: GradientLegend, isStandalone: true, selector: "mapag-gradient-legend", inputs: { settings: { classPropertyName: "settings", publicName: "settings", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: `
26201
+ <div class="top" [ngStyle]="topStyle()"></div>
26202
+ <div>{{settings().unitPrefix}}{{ settings().maxValue | number:"1.0-2" }}{{settings().unitSuffix}}</div>
26203
+ <div class="gradient" [ngStyle]="gradientStyle()"></div>
26204
+ <div></div>
26205
+ <div class="bottom" [ngStyle]="bottomStyle()"></div>
26206
+ <div>{{settings().unitPrefix}}{{ settings().minValue | number:"1.0-2" }}{{settings().unitSuffix}}</div>
26207
+ `, isInline: true, styles: [":host{display:grid;grid-template-rows:auto 1fr auto;grid-template-columns:auto max-content;align-items:center;font-size:.8em;height:var(--legend-height, 150px);column-gap:4px}.h2{margin-bottom:8px}.top,.bottom{height:50%}.top{background:var(--top-color, green);align-self:end}.bottom{background:var(--bottom-color, black);align-self:start}.gradient{width:20px;flex-grow:1;height:100%;align-self:center;justify-self:center}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "ngmodule", type: FormsModule }, { kind: "pipe", type: i1.DecimalPipe, name: "number" }] });
26208
+ }
26209
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: GradientLegend, decorators: [{
26210
+ type: Component,
26211
+ args: [{ selector: 'mapag-gradient-legend', imports: [CommonModule, FormsModule], template: `
26212
+ <div class="top" [ngStyle]="topStyle()"></div>
26213
+ <div>{{settings().unitPrefix}}{{ settings().maxValue | number:"1.0-2" }}{{settings().unitSuffix}}</div>
26214
+ <div class="gradient" [ngStyle]="gradientStyle()"></div>
26215
+ <div></div>
26216
+ <div class="bottom" [ngStyle]="bottomStyle()"></div>
26217
+ <div>{{settings().unitPrefix}}{{ settings().minValue | number:"1.0-2" }}{{settings().unitSuffix}}</div>
26218
+ `, styles: [":host{display:grid;grid-template-rows:auto 1fr auto;grid-template-columns:auto max-content;align-items:center;font-size:.8em;height:var(--legend-height, 150px);column-gap:4px}.h2{margin-bottom:8px}.top,.bottom{height:50%}.top{background:var(--top-color, green);align-self:end}.bottom{background:var(--bottom-color, black);align-self:start}.gradient{width:20px;flex-grow:1;height:100%;align-self:center;justify-self:center}\n"] }]
26219
+ }], ctorParameters: () => [], propDecorators: { settings: [{ type: i0.Input, args: [{ isSignal: true, alias: "settings", required: false }] }] } });
26220
+ class GradientSettings {
26221
+ minColor = "#000000";
26222
+ maxColor = "#FFFFFF";
26223
+ minValue = 0.0;
26224
+ maxValue = 1.0;
26225
+ height = "100px";
26226
+ width = "30px";
26227
+ minTop = false;
26228
+ dir = 'vertical';
26229
+ unitPrefix = '';
26230
+ unitSuffix = '';
26231
+ }
26232
+
26233
+ class ShowHideBtn {
26234
+ faEye = faEye;
26235
+ faEyeSlash = faEyeSlash;
26236
+ mapper = input.required(...(ngDevMode ? [{ debugName: "mapper" }] : []));
26237
+ toggleShowHide() {
26238
+ const current = this.mapper().settings().visible;
26239
+ this.mapper().update({ visible: !current });
26240
+ }
26241
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: ShowHideBtn, deps: [], target: i0.ɵɵFactoryTarget.Component });
26242
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "20.3.15", type: ShowHideBtn, isStandalone: true, selector: "mapag-show-hide-btn", inputs: { mapper: { classPropertyName: "mapper", publicName: "mapper", isSignal: true, isRequired: true, transformFunction: null } }, ngImport: i0, template: `
26243
+ <button class="btn" (click)="toggleShowHide()">
26244
+ <fa-icon [icon]="mapper().settings().visible ? faEyeSlash : faEye"></fa-icon>
26245
+ {{ mapper().settings().visible ? 'Hide' : 'Show' }}
26246
+ </button>
26247
+ `, isInline: true, styles: ["dialog{font-size:14pt;width:100%;max-width:700px;border:none;border-radius:8px;box-shadow:0 2px 10px #0003;padding:16px;position:fixed;top:50%;left:50%;transform:translate(-50%,-50%);margin:0;flex-direction:column}dialog:open{display:flex}dialog .dlg-body{flex-grow:1;overflow-y:auto}dialog.legend{width:fit-content}dialog.legend h2{font-size:smaller}dialog select{max-width:90vw}dialog h2{color:#000}dialog h2:before{content:\"\\22ee\\22ee \";padding-right:4px}dialog h3{color:#000;border-bottom:2px solid gray;font-weight:500;font-size:.9em;margin-top:16px;margin-bottom:8px}dialog h4{color:#000;font-weight:500;margin-bottom:8px;margin-top:12px;font-size:.85em;border:none}dialog p{font-size:.8em}dialog a{text-decoration:none;color:#0a3773;font-weight:500;font-size:.8em;padding-left:4px}dialog a:hover{text-decoration:underline;cursor:pointer}dialog a:before{content:\"\\1f517\";padding-right:2px}.ctrl-group{display:flex;flex-direction:column}.ctrl-row{display:grid;grid-template-columns:auto 1fr auto 1fr;align-items:center;gap:4px;justify-items:start;padding-left:20px}.ctrl-first{grid-column:1}.ctrl-row label{font-size:.8em;margin:0;padding:0;font-weight:400}.ctrl.wide{grid-column:span 3}input[type=range]{grid-column:span 3;justify-self:stretch}input[type=color]{width:40px;height:24px;border-radius:4px;cursor:pointer}input[type=number]{width:6ch;font-size:.8em}.dlg-buttons{display:flex;justify-content:flex-end;gap:8px;margin-top:16px}button{background-color:#0a3773;color:#fff;border:none;border-radius:4px;padding:8px 16px;cursor:pointer;font-size:.8em}button:hover{background-color:#083a5c}summary{font-size:1em;font-weight:600;color:#000;cursor:pointer;padding:8px 0;border-bottom:2px solid gray;list-style:none;-webkit-user-select:none;user-select:none;margin-bottom:8px}summary::-webkit-details-marker{display:none}summary:before{content:\"\\304f\";display:inline-block;margin-right:8px;transform:rotate(180deg);transition:transform .2s}details[open] summary:before{transform:rotate(270deg)}.radio-tabs{margin-bottom:12px;font-size:.8em;display:flex;flex-direction:row}.radio-tabs label{display:grid;grid-template-columns:auto 1fr;gap:4px;grid-template-rows:30px;align-items:center}.radio-tabs input[type=radio]{display:none}.radio-tabs label{padding:8px 12px;border:2px solid transparent;border-radius:6px;cursor:pointer;transition:all .2s ease}.radio-tabs label:has(input[type=radio]:checked){background-color:#fff;border-color:#333}.mgr-btn{justify-self:center;background-color:transparent;color:#4c4c4c;text-align:center;width:100%;font-weight:600;cursor:pointer;display:flex;align-items:center;justify-content:center;margin:4px 0;padding:6px;gap:4px;border:1px solid rgb(218,218,218)}.mgr-btn:hover{background-color:transparent;border-color:#4c4c4c}.legend-row{display:grid;grid-template-columns:auto 1fr;gap:8px;padding:4px 0;align-items:center}.legend-title{font-weight:700;text-align:center;margin-bottom:8px}.legend-item{height:15px;width:15px;border:1px solid #ccc}.maplibregl-popup-close-button{top:13px;right:15px}@media screen and (max-width: 600px){dialog{width:100vw;max-width:100vw;height:100dvh;max-height:100dvh;border-radius:0;border:none;box-shadow:none;overflow:hidden}.dlg-buttons{flex-direction:row;flex-wrap:wrap;align-items:center;justify-content:center}dialog h2:before{content:\"\";padding-right:0}}:host{display:content}.btn{width:12ch}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "component", type: FaIconComponent, selector: "fa-icon", inputs: ["icon", "title", "animation", "mask", "flip", "size", "pull", "border", "inverse", "symbol", "rotate", "fixedWidth", "transform", "a11yRole"], outputs: ["iconChange", "titleChange", "animationChange", "maskChange", "flipChange", "sizeChange", "pullChange", "borderChange", "inverseChange", "symbolChange", "rotateChange", "fixedWidthChange", "transformChange", "a11yRoleChange"] }] });
26248
+ }
26249
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: ShowHideBtn, decorators: [{
26250
+ type: Component,
26251
+ args: [{ selector: 'mapag-show-hide-btn', imports: [CommonModule, FaIconComponent], template: `
26252
+ <button class="btn" (click)="toggleShowHide()">
26253
+ <fa-icon [icon]="mapper().settings().visible ? faEyeSlash : faEye"></fa-icon>
26254
+ {{ mapper().settings().visible ? 'Hide' : 'Show' }}
26255
+ </button>
26256
+ `, styles: ["dialog{font-size:14pt;width:100%;max-width:700px;border:none;border-radius:8px;box-shadow:0 2px 10px #0003;padding:16px;position:fixed;top:50%;left:50%;transform:translate(-50%,-50%);margin:0;flex-direction:column}dialog:open{display:flex}dialog .dlg-body{flex-grow:1;overflow-y:auto}dialog.legend{width:fit-content}dialog.legend h2{font-size:smaller}dialog select{max-width:90vw}dialog h2{color:#000}dialog h2:before{content:\"\\22ee\\22ee \";padding-right:4px}dialog h3{color:#000;border-bottom:2px solid gray;font-weight:500;font-size:.9em;margin-top:16px;margin-bottom:8px}dialog h4{color:#000;font-weight:500;margin-bottom:8px;margin-top:12px;font-size:.85em;border:none}dialog p{font-size:.8em}dialog a{text-decoration:none;color:#0a3773;font-weight:500;font-size:.8em;padding-left:4px}dialog a:hover{text-decoration:underline;cursor:pointer}dialog a:before{content:\"\\1f517\";padding-right:2px}.ctrl-group{display:flex;flex-direction:column}.ctrl-row{display:grid;grid-template-columns:auto 1fr auto 1fr;align-items:center;gap:4px;justify-items:start;padding-left:20px}.ctrl-first{grid-column:1}.ctrl-row label{font-size:.8em;margin:0;padding:0;font-weight:400}.ctrl.wide{grid-column:span 3}input[type=range]{grid-column:span 3;justify-self:stretch}input[type=color]{width:40px;height:24px;border-radius:4px;cursor:pointer}input[type=number]{width:6ch;font-size:.8em}.dlg-buttons{display:flex;justify-content:flex-end;gap:8px;margin-top:16px}button{background-color:#0a3773;color:#fff;border:none;border-radius:4px;padding:8px 16px;cursor:pointer;font-size:.8em}button:hover{background-color:#083a5c}summary{font-size:1em;font-weight:600;color:#000;cursor:pointer;padding:8px 0;border-bottom:2px solid gray;list-style:none;-webkit-user-select:none;user-select:none;margin-bottom:8px}summary::-webkit-details-marker{display:none}summary:before{content:\"\\304f\";display:inline-block;margin-right:8px;transform:rotate(180deg);transition:transform .2s}details[open] summary:before{transform:rotate(270deg)}.radio-tabs{margin-bottom:12px;font-size:.8em;display:flex;flex-direction:row}.radio-tabs label{display:grid;grid-template-columns:auto 1fr;gap:4px;grid-template-rows:30px;align-items:center}.radio-tabs input[type=radio]{display:none}.radio-tabs label{padding:8px 12px;border:2px solid transparent;border-radius:6px;cursor:pointer;transition:all .2s ease}.radio-tabs label:has(input[type=radio]:checked){background-color:#fff;border-color:#333}.mgr-btn{justify-self:center;background-color:transparent;color:#4c4c4c;text-align:center;width:100%;font-weight:600;cursor:pointer;display:flex;align-items:center;justify-content:center;margin:4px 0;padding:6px;gap:4px;border:1px solid rgb(218,218,218)}.mgr-btn:hover{background-color:transparent;border-color:#4c4c4c}.legend-row{display:grid;grid-template-columns:auto 1fr;gap:8px;padding:4px 0;align-items:center}.legend-title{font-weight:700;text-align:center;margin-bottom:8px}.legend-item{height:15px;width:15px;border:1px solid #ccc}.maplibregl-popup-close-button{top:13px;right:15px}@media screen and (max-width: 600px){dialog{width:100vw;max-width:100vw;height:100dvh;max-height:100dvh;border-radius:0;border:none;box-shadow:none;overflow:hidden}.dlg-buttons{flex-direction:row;flex-wrap:wrap;align-items:center;justify-content:center}dialog h2:before{content:\"\";padding-right:0}}:host{display:content}.btn{width:12ch}\n"] }]
26257
+ }], propDecorators: { mapper: [{ type: i0.Input, args: [{ isSignal: true, alias: "mapper", required: true }] }] } });
26258
+
26259
+ class StdLegend {
26260
+ items = input([], ...(ngDevMode ? [{ debugName: "items" }] : []));
26261
+ columns = input(1, ...(ngDevMode ? [{ debugName: "columns" }] : []));
26262
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: StdLegend, deps: [], target: i0.ɵɵFactoryTarget.Component });
26263
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.15", type: StdLegend, isStandalone: true, selector: "mapag-std-legend", inputs: { items: { classPropertyName: "items", publicName: "items", isSignal: true, isRequired: false, transformFunction: null }, columns: { classPropertyName: "columns", publicName: "columns", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: `
26264
+ <div class="legend" [style.grid-template-columns]="'repeat(' + columns() + ',1fr)'">
26265
+ @for (item of items(); track item) {
26266
+ <div class="legend-row">
26267
+ <div class="legend-item" [style.background-color]="item.value" [ngStyle]="item.style"></div>
26268
+ <div>{{ item.label }}</div>
26269
+ </div>
26270
+ }
26271
+ </div>
26272
+ `, isInline: true, styles: ["dialog{font-size:14pt;width:100%;max-width:700px;border:none;border-radius:8px;box-shadow:0 2px 10px #0003;padding:16px;position:fixed;top:50%;left:50%;transform:translate(-50%,-50%);margin:0;flex-direction:column}dialog:open{display:flex}dialog .dlg-body{flex-grow:1;overflow-y:auto}dialog.legend{width:fit-content}dialog.legend h2{font-size:smaller}dialog select{max-width:90vw}dialog h2{color:#000}dialog h2:before{content:\"\\22ee\\22ee \";padding-right:4px}dialog h3{color:#000;border-bottom:2px solid gray;font-weight:500;font-size:.9em;margin-top:16px;margin-bottom:8px}dialog h4{color:#000;font-weight:500;margin-bottom:8px;margin-top:12px;font-size:.85em;border:none}dialog p{font-size:.8em}dialog a{text-decoration:none;color:#0a3773;font-weight:500;font-size:.8em;padding-left:4px}dialog a:hover{text-decoration:underline;cursor:pointer}dialog a:before{content:\"\\1f517\";padding-right:2px}.ctrl-group{display:flex;flex-direction:column}.ctrl-row{display:grid;grid-template-columns:auto 1fr auto 1fr;align-items:center;gap:4px;justify-items:start;padding-left:20px}.ctrl-first{grid-column:1}.ctrl-row label{font-size:.8em;margin:0;padding:0;font-weight:400}.ctrl.wide{grid-column:span 3}input[type=range]{grid-column:span 3;justify-self:stretch}input[type=color]{width:40px;height:24px;border-radius:4px;cursor:pointer}input[type=number]{width:6ch;font-size:.8em}.dlg-buttons{display:flex;justify-content:flex-end;gap:8px;margin-top:16px}button{background-color:#0a3773;color:#fff;border:none;border-radius:4px;padding:8px 16px;cursor:pointer;font-size:.8em}button:hover{background-color:#083a5c}summary{font-size:1em;font-weight:600;color:#000;cursor:pointer;padding:8px 0;border-bottom:2px solid gray;list-style:none;-webkit-user-select:none;user-select:none;margin-bottom:8px}summary::-webkit-details-marker{display:none}summary:before{content:\"\\304f\";display:inline-block;margin-right:8px;transform:rotate(180deg);transition:transform .2s}details[open] summary:before{transform:rotate(270deg)}.radio-tabs{margin-bottom:12px;font-size:.8em;display:flex;flex-direction:row}.radio-tabs label{display:grid;grid-template-columns:auto 1fr;gap:4px;grid-template-rows:30px;align-items:center}.radio-tabs input[type=radio]{display:none}.radio-tabs label{padding:8px 12px;border:2px solid transparent;border-radius:6px;cursor:pointer;transition:all .2s ease}.radio-tabs label:has(input[type=radio]:checked){background-color:#fff;border-color:#333}.mgr-btn{justify-self:center;background-color:transparent;color:#4c4c4c;text-align:center;width:100%;font-weight:600;cursor:pointer;display:flex;align-items:center;justify-content:center;margin:4px 0;padding:6px;gap:4px;border:1px solid rgb(218,218,218)}.mgr-btn:hover{background-color:transparent;border-color:#4c4c4c}.legend-row{display:grid;grid-template-columns:auto 1fr;gap:8px;padding:4px 0;align-items:center}.legend-title{font-weight:700;text-align:center;margin-bottom:8px}.legend-item{height:15px;width:15px;border:1px solid #ccc}.maplibregl-popup-close-button{top:13px;right:15px}@media screen and (max-width: 600px){dialog{width:100vw;max-width:100vw;height:100dvh;max-height:100dvh;border-radius:0;border:none;box-shadow:none;overflow:hidden}.dlg-buttons{flex-direction:row;flex-wrap:wrap;align-items:center;justify-content:center}dialog h2:before{content:\"\";padding-right:0}}.legend{display:grid;column-gap:8px;font-size:.8em}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }] });
26273
+ }
26274
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: StdLegend, decorators: [{
26275
+ type: Component,
26276
+ args: [{ selector: 'mapag-std-legend', imports: [CommonModule], template: `
26277
+ <div class="legend" [style.grid-template-columns]="'repeat(' + columns() + ',1fr)'">
26278
+ @for (item of items(); track item) {
26279
+ <div class="legend-row">
26280
+ <div class="legend-item" [style.background-color]="item.value" [ngStyle]="item.style"></div>
26281
+ <div>{{ item.label }}</div>
26282
+ </div>
26283
+ }
26284
+ </div>
26285
+ `, styles: ["dialog{font-size:14pt;width:100%;max-width:700px;border:none;border-radius:8px;box-shadow:0 2px 10px #0003;padding:16px;position:fixed;top:50%;left:50%;transform:translate(-50%,-50%);margin:0;flex-direction:column}dialog:open{display:flex}dialog .dlg-body{flex-grow:1;overflow-y:auto}dialog.legend{width:fit-content}dialog.legend h2{font-size:smaller}dialog select{max-width:90vw}dialog h2{color:#000}dialog h2:before{content:\"\\22ee\\22ee \";padding-right:4px}dialog h3{color:#000;border-bottom:2px solid gray;font-weight:500;font-size:.9em;margin-top:16px;margin-bottom:8px}dialog h4{color:#000;font-weight:500;margin-bottom:8px;margin-top:12px;font-size:.85em;border:none}dialog p{font-size:.8em}dialog a{text-decoration:none;color:#0a3773;font-weight:500;font-size:.8em;padding-left:4px}dialog a:hover{text-decoration:underline;cursor:pointer}dialog a:before{content:\"\\1f517\";padding-right:2px}.ctrl-group{display:flex;flex-direction:column}.ctrl-row{display:grid;grid-template-columns:auto 1fr auto 1fr;align-items:center;gap:4px;justify-items:start;padding-left:20px}.ctrl-first{grid-column:1}.ctrl-row label{font-size:.8em;margin:0;padding:0;font-weight:400}.ctrl.wide{grid-column:span 3}input[type=range]{grid-column:span 3;justify-self:stretch}input[type=color]{width:40px;height:24px;border-radius:4px;cursor:pointer}input[type=number]{width:6ch;font-size:.8em}.dlg-buttons{display:flex;justify-content:flex-end;gap:8px;margin-top:16px}button{background-color:#0a3773;color:#fff;border:none;border-radius:4px;padding:8px 16px;cursor:pointer;font-size:.8em}button:hover{background-color:#083a5c}summary{font-size:1em;font-weight:600;color:#000;cursor:pointer;padding:8px 0;border-bottom:2px solid gray;list-style:none;-webkit-user-select:none;user-select:none;margin-bottom:8px}summary::-webkit-details-marker{display:none}summary:before{content:\"\\304f\";display:inline-block;margin-right:8px;transform:rotate(180deg);transition:transform .2s}details[open] summary:before{transform:rotate(270deg)}.radio-tabs{margin-bottom:12px;font-size:.8em;display:flex;flex-direction:row}.radio-tabs label{display:grid;grid-template-columns:auto 1fr;gap:4px;grid-template-rows:30px;align-items:center}.radio-tabs input[type=radio]{display:none}.radio-tabs label{padding:8px 12px;border:2px solid transparent;border-radius:6px;cursor:pointer;transition:all .2s ease}.radio-tabs label:has(input[type=radio]:checked){background-color:#fff;border-color:#333}.mgr-btn{justify-self:center;background-color:transparent;color:#4c4c4c;text-align:center;width:100%;font-weight:600;cursor:pointer;display:flex;align-items:center;justify-content:center;margin:4px 0;padding:6px;gap:4px;border:1px solid rgb(218,218,218)}.mgr-btn:hover{background-color:transparent;border-color:#4c4c4c}.legend-row{display:grid;grid-template-columns:auto 1fr;gap:8px;padding:4px 0;align-items:center}.legend-title{font-weight:700;text-align:center;margin-bottom:8px}.legend-item{height:15px;width:15px;border:1px solid #ccc}.maplibregl-popup-close-button{top:13px;right:15px}@media screen and (max-width: 600px){dialog{width:100vw;max-width:100vw;height:100dvh;max-height:100dvh;border-radius:0;border:none;box-shadow:none;overflow:hidden}.dlg-buttons{flex-direction:row;flex-wrap:wrap;align-items:center;justify-content:center}dialog h2:before{content:\"\";padding-right:0}}.legend{display:grid;column-gap:8px;font-size:.8em}\n"] }]
26286
+ }], propDecorators: { items: [{ type: i0.Input, args: [{ isSignal: true, alias: "items", required: false }] }], columns: [{ type: i0.Input, args: [{ isSignal: true, alias: "columns", required: false }] }] } });
26287
+
26288
+ class TextPipe {
26289
+ transform(value, ...args) {
26290
+ if (value === null || value === undefined) {
26291
+ return '';
26292
+ }
26293
+ if (typeof value === 'string') {
26294
+ return fixText(value);
26295
+ }
26296
+ return value;
26297
+ }
26298
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: TextPipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe });
26299
+ static ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "20.3.15", ngImport: i0, type: TextPipe, isStandalone: true, name: "text" });
26300
+ }
26301
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: TextPipe, decorators: [{
26302
+ type: Pipe,
26303
+ args: [{
26304
+ name: 'text'
26305
+ }]
26306
+ }] });
26307
+
26308
+ class ConsumerSpendingPanel {
26309
+ map = input(...(ngDevMode ? [undefined, { debugName: "map" }] : []));
26310
+ mapper = new ConsumerSpendingMapper();
26311
+ customizeDialog = viewChild('customizeDialog', ...(ngDevMode ? [{ debugName: "customizeDialog" }] : []));
26312
+ legendDialog = viewChild('legendDialog', ...(ngDevMode ? [{ debugName: "legendDialog" }] : []));
26313
+ onRemove = output();
26314
+ settings = input(new DataSetSettings(), ...(ngDevMode ? [{ debugName: "settings" }] : []));
26315
+ USStates = states;
26316
+ constructor() {
26317
+ const _mapInit = effect(() => {
26318
+ const mapComp = this.map();
26319
+ if (mapComp) {
26320
+ mapComp.mapper().set(this.mapper.ID, this.mapper);
26321
+ }
26322
+ }, ...(ngDevMode ? [{ debugName: "_mapInit" }] : []));
26323
+ const _item = effect(() => {
26324
+ const item = this.settings();
26325
+ untracked(() => this.mapper.update(item));
26326
+ }, ...(ngDevMode ? [{ debugName: "_item" }] : []));
26327
+ }
26328
+ setVisible(visible) {
26329
+ this.mapper.update({ visible: visible });
26330
+ }
26331
+ updateGradient(v1, v2) {
26332
+ const current = this.mapper.settings().fillGradient;
26333
+ if (v1) {
26334
+ current[0].color = v1;
26335
+ }
26336
+ if (v2) {
26337
+ current[1].color = v2;
26338
+ }
26339
+ this.mapper.update({
26340
+ fillGradient: current,
26341
+ });
26342
+ }
26343
+ paletteLegend = computed(() => {
26344
+ const info = this.mapper.info();
26345
+ const minmax = this.mapper.featureStates();
26346
+ const palette = this.mapper.settings().fillPalette;
26347
+ return ColorPalettes.ToLegend(palette, minmax.min || 0, minmax.max || 1, { unitSuffix: " " + fixText(info.Unit) });
26348
+ }, ...(ngDevMode ? [{ debugName: "paletteLegend" }] : []));
26349
+ gradientSettings = computed(() => {
26350
+ const info = this.mapper.info();
26351
+ const minmax = this.mapper.featureStates();
26352
+ return {
26353
+ minColor: this.mapper.settings().fillGradient[0].color,
26354
+ maxColor: this.mapper.settings().fillGradient[1].color,
26355
+ minValue: minmax.min || 0,
26356
+ maxValue: minmax.max || 1,
26357
+ dir: 'vertical',
26358
+ height: '150px',
26359
+ width: '30px',
26360
+ unitPrefix: " ",
26361
+ unitSuffix: " " + fixText(info.Unit)
26362
+ };
26363
+ }, ...(ngDevMode ? [{ debugName: "gradientSettings" }] : []));
26364
+ toggleDialog() {
26365
+ const dialog = this.customizeDialog();
26366
+ if (!dialog) {
26367
+ return;
26368
+ }
26369
+ const dialogElement = dialog.nativeElement;
26370
+ if (dialogElement.open) {
26371
+ dialogElement.close();
26372
+ }
26373
+ else {
26374
+ dialogElement.show();
26375
+ }
26376
+ // Implement dialog toggle logic here
26377
+ }
26378
+ toggleLegend() {
26379
+ const dialog = this.legendDialog();
26380
+ if (!dialog) {
26381
+ return;
26382
+ }
26383
+ const dialogElement = dialog.nativeElement;
26384
+ if (dialogElement.open) {
26385
+ dialogElement.close();
26386
+ }
26387
+ else {
26388
+ dialogElement.show();
26389
+ }
26390
+ // Implement dialog toggle logic here
26391
+ }
26392
+ update(field, value) {
26393
+ this.mapper.update({
26394
+ [field]: value,
26395
+ });
26396
+ }
26397
+ reset() {
26398
+ this.mapper.update(new DataSetSettings());
26399
+ }
26400
+ remove() {
26401
+ this.mapper.update({ visible: false });
26402
+ this.toggleDialog();
26403
+ this.onRemove.emit();
26404
+ }
26405
+ ngOnDestroy() {
26406
+ this.mapper.clear();
26407
+ }
26408
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: ConsumerSpendingPanel, deps: [], target: i0.ɵɵFactoryTarget.Component });
26409
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.15", type: ConsumerSpendingPanel, isStandalone: true, selector: "mapag-consumer-spending-panel", inputs: { map: { classPropertyName: "map", publicName: "map", isSignal: true, isRequired: false, transformFunction: null }, settings: { classPropertyName: "settings", publicName: "settings", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { onRemove: "onRemove" }, viewQueries: [{ propertyName: "customizeDialog", first: true, predicate: ["customizeDialog"], descendants: true, isSignal: true }, { propertyName: "legendDialog", first: true, predicate: ["legendDialog"], descendants: true, isSignal: true }], ngImport: i0, template: `
26410
+ <hub-data-layer
26411
+ [visible]="mapper.settings().visible"
26412
+ [name]="mapper.info().Commodity + ' (' + mapper.info().Year + ')'"
26413
+ [desc]="mapper.desc()"
26414
+ shape="area"
26415
+ (onCheck)="setVisible($event)"
26416
+ (onCustomize)="toggleDialog()"
26417
+ >
26418
+ <area-icon></area-icon>
26419
+ </hub-data-layer>
26420
+
26421
+ <dialog draggable mapagBringToFront onBody #customizeDialog>
26422
+ <h2>{{ mapper.name() }}</h2>
26423
+
26424
+ <div class="dlg-body">
26425
+ <p>
26426
+ The Consumer Spending dataset from Esri provides a rigorously modeled representation of how U.S. households
26427
+ allocate their budgets across a wide spectrum of goods and services, integrating source data from the U.S.
26428
+ Bureau of Labor Statistics’ Consumer Expenditure and Diary Surveys to estimate both current spending patterns
26429
+ and five‑year forecasts. It offers detailed, category‑level insights into consumer purchasing behavior,
26430
+ enabling analysts to understand market demand, evaluate economic conditions, and support data‑driven
26431
+ decision‑making within geographic contexts.
26432
+ </p>
26433
+ <h3>Information</h3>
26434
+ <div class="info-grid">
26435
+ <div class="info">
26436
+ <div class="info-label">Source</div>
26437
+ <div class="info-value">{{ mapper.info().Source | text }}</div>
26438
+ </div>
26439
+ <div class="info">
26440
+ <div class="info-label">Sector</div>
26441
+ <div class="info-value">{{ mapper.info().Sector | text }}</div>
26442
+ </div>
26443
+ <div class="info">
26444
+ <div class="info-label">Group</div>
26445
+ <div class="info-value">{{ mapper.info().Group | text }}</div>
26446
+ </div>
26447
+ <div class="info">
26448
+ <div class="info-label">Commodity</div>
26449
+ <div class="info-value">{{ mapper.info().Commodity | text }}</div>
26450
+ </div>
26451
+ <div class="info">
26452
+ <div class="info-label">Class</div>
26453
+ <div class="info-value">{{ mapper.info().Class | text }}</div>
26454
+ </div>
26455
+ <div class="info">
26456
+ <div class="info-label">Statistic</div>
26457
+ <div class="info-value">{{ mapper.info().Statistic | text }}</div>
26458
+ </div>
26459
+ <div class="info">
26460
+ <div class="info-label">Production</div>
26461
+ <div class="info-value">{{ mapper.info().Production | text }}</div>
26462
+ </div>
26463
+ <div class="info">
26464
+ <div class="info-label">Utilization</div>
26465
+ <div class="info-value">{{ mapper.info().Utilization | text }}</div>
26466
+ </div>
26467
+ <div class="info">
26468
+ <div class="info-label">Unit</div>
26469
+ <div class="info-value">{{ mapper.info().Unit | text }}</div>
26470
+ </div>
26471
+ </div>
26472
+ <h3>Customize Display Settings</h3>
26473
+ <div class="zones">
26474
+ <div class="ctrl-group">
26475
+ <div class="radio-tabs">
26476
+ <label>
26477
+ <input
26478
+ type="radio"
26479
+ name="fillType"
26480
+ value="solid"
26481
+ [checked]="mapper.settings().fillType == 'solid'"
26482
+ (change)="update('fillType', 'solid')"
26483
+ />
26484
+ Solid
26485
+ </label>
26486
+ <label>
26487
+ <input
26488
+ type="radio"
26489
+ name="fillType"
26490
+ value="gradient"
26491
+ [checked]="mapper.settings().fillType == 'gradient'"
26492
+ (change)="update('fillType', 'gradient')"
26493
+ />
26494
+ Gradient
26495
+ </label>
26496
+ <label>
26497
+ <input
26498
+ type="radio"
26499
+ name="fillType"
26500
+ value="palette"
26501
+ [checked]="mapper.settings().fillType == 'palette'"
26502
+ (change)="update('fillType', 'palette')"
26503
+ />
26504
+ Palette
26505
+ </label>
26506
+ </div>
26507
+ <div class="ctrl-row">
26508
+ @switch (mapper.settings().fillType) { @case ('solid') {
26509
+ <label for="colorPicker">Color:</label>
26510
+ <input
26511
+ type="color"
26512
+ id="colorPicker"
26513
+ [ngModel]="mapper.settings().fillColor"
26514
+ (ngModelChange)="update('fillColor', $event)"
26515
+ />
26516
+ } @case ('gradient') {
26517
+ <label for="gradientSelect">Gradient:</label>
26518
+ <input
26519
+ type="color"
26520
+ [ngModel]="mapper.settings().fillGradient[0].color"
26521
+ (ngModelChange)="updateGradient($event, undefined)"
26522
+ />
26523
+ <input
26524
+ type="color"
26525
+ [ngModel]="mapper.settings().fillGradient[1].color"
26526
+ (ngModelChange)="updateGradient(undefined, $event)"
26527
+ />
26528
+ } @case ('palette') {
26529
+ <label for="paletteSelect">Palette:</label>
26530
+ <mapag-palette-select
26531
+ [palette]="mapper.settings().fillPalette"
26532
+ (paletteChange)="update('fillPalette', $event)"
26533
+ >
26534
+ </mapag-palette-select>
26535
+ } }
26536
+ </div>
26537
+ <div class="ctrl-row">
26538
+ <label for="fillOpacity">Opacity:</label>
26539
+ <input
26540
+ type="range"
26541
+ id="fillOpacity"
26542
+ min="0"
26543
+ max="1"
26544
+ step="0.01"
26545
+ [ngModel]="mapper.settings().fillOpacity"
26546
+ (ngModelChange)="update('fillOpacity', $event)"
26547
+ />
26548
+ </div>
26549
+ <div class="ctrl-row">
26550
+ <label for="borderColor">Border Color:</label>
26551
+ <input
26552
+ type="color"
26553
+ id="borderColor"
26554
+ [ngModel]="mapper.settings().borderColor"
26555
+ (ngModelChange)="update('borderColor', $event)"
26556
+ />
26557
+ </div>
26558
+ </div>
26559
+ <div class="ctrl-group">
26560
+ <h4>Filters</h4>
26561
+ <h5>State</h5>
26562
+ <div class="filter-row" style="padding: 3px;">
26563
+ <ng-select
26564
+ [items]="USStates"
26565
+ bindLabel="Name"
26566
+ bindValue="Abbr"
26567
+ [ngModel]="mapper.settings().filterStates"
26568
+ [multiple]="true"
26569
+ appendTo="body"
26570
+ (ngModelChange)="update('filterStates', $event)"
26571
+ >
26572
+ </ng-select>
26573
+ </div>
26574
+ </div>
26575
+ </div>
26576
+
26577
+ <h3>References</h3>
26578
+ <div style="display: flex; flex-direction: column;">
26579
+ <a href="https://www.nass.usda.gov/" target="_blank">USDA NASS</a>
26580
+ <a href="https://quickstats.nass.usda.gov/" target="_blank">USDA NASS Quick Stats</a>
26581
+ </div>
26582
+ </div>
26583
+ <div class="dlg-buttons">
26584
+ <button class="btn" (click)="toggleLegend()">Legend</button>
26585
+ <button class="btn" (click)="remove()">Remove</button>
26586
+ <button class="btn" (click)="reset()">Reset</button>
26587
+ <mapag-show-hide-btn [mapper]="mapper"></mapag-show-hide-btn>
26588
+ <button class="btn" (click)="toggleDialog()">Close</button>
26589
+ </div>
26590
+ </dialog>
26591
+
26592
+ <dialog class="legend" #legendDialog draggable mapagBringToFront onbody>
26593
+ <mapag-dialog-header class="drag-handle"[dialog]="legendDialog">{{ mapper.name() }}</mapag-dialog-header>
26594
+ @switch (mapper.settings().fillType) {
26595
+ @case ('solid') {
26596
+ <div style="width: 30px; height: 30px; background-color: {{ mapper.settings().fillColor }}; border: 1px solid #000;"></div>
26597
+ }
26598
+ @case ('gradient') {
26599
+ <mapag-gradient-legend [settings]="gradientSettings()"> </mapag-gradient-legend>
26600
+ }
26601
+ @case ('palette') {
26602
+ <mapag-std-legend [items]="paletteLegend()"></mapag-std-legend>
26603
+ }
26604
+ }
26605
+ </dialog>
26606
+ `, isInline: true, styles: ["dialog{font-size:14pt;width:100%;max-width:700px;border:none;border-radius:8px;box-shadow:0 2px 10px #0003;padding:16px;position:fixed;top:50%;left:50%;transform:translate(-50%,-50%);margin:0;flex-direction:column}dialog:open{display:flex}dialog .dlg-body{flex-grow:1;overflow-y:auto}dialog.legend{width:fit-content}dialog.legend h2{font-size:smaller}dialog select{max-width:90vw}dialog h2{color:#000}dialog h2:before{content:\"\\22ee\\22ee \";padding-right:4px}dialog h3{color:#000;border-bottom:2px solid gray;font-weight:500;font-size:.9em;margin-top:16px;margin-bottom:8px}dialog h4{color:#000;font-weight:500;margin-bottom:8px;margin-top:12px;font-size:.85em;border:none}dialog p{font-size:.8em}dialog a{text-decoration:none;color:#0a3773;font-weight:500;font-size:.8em;padding-left:4px}dialog a:hover{text-decoration:underline;cursor:pointer}dialog a:before{content:\"\\1f517\";padding-right:2px}.ctrl-group{display:flex;flex-direction:column}.ctrl-row{display:grid;grid-template-columns:auto 1fr auto 1fr;align-items:center;gap:4px;justify-items:start;padding-left:20px}.ctrl-first{grid-column:1}.ctrl-row label{font-size:.8em;margin:0;padding:0;font-weight:400}.ctrl.wide{grid-column:span 3}input[type=range]{grid-column:span 3;justify-self:stretch}input[type=color]{width:40px;height:24px;border-radius:4px;cursor:pointer}input[type=number]{width:6ch;font-size:.8em}.dlg-buttons{display:flex;justify-content:flex-end;gap:8px;margin-top:16px}button{background-color:#0a3773;color:#fff;border:none;border-radius:4px;padding:8px 16px;cursor:pointer;font-size:.8em}button:hover{background-color:#083a5c}summary{font-size:1em;font-weight:600;color:#000;cursor:pointer;padding:8px 0;border-bottom:2px solid gray;list-style:none;-webkit-user-select:none;user-select:none;margin-bottom:8px}summary::-webkit-details-marker{display:none}summary:before{content:\"\\304f\";display:inline-block;margin-right:8px;transform:rotate(180deg);transition:transform .2s}details[open] summary:before{transform:rotate(270deg)}.radio-tabs{margin-bottom:12px;font-size:.8em;display:flex;flex-direction:row}.radio-tabs label{display:grid;grid-template-columns:auto 1fr;gap:4px;grid-template-rows:30px;align-items:center}.radio-tabs input[type=radio]{display:none}.radio-tabs label{padding:8px 12px;border:2px solid transparent;border-radius:6px;cursor:pointer;transition:all .2s ease}.radio-tabs label:has(input[type=radio]:checked){background-color:#fff;border-color:#333}.mgr-btn{justify-self:center;background-color:transparent;color:#4c4c4c;text-align:center;width:100%;font-weight:600;cursor:pointer;display:flex;align-items:center;justify-content:center;margin:4px 0;padding:6px;gap:4px;border:1px solid rgb(218,218,218)}.mgr-btn:hover{background-color:transparent;border-color:#4c4c4c}.legend-row{display:grid;grid-template-columns:auto 1fr;gap:8px;padding:4px 0;align-items:center}.legend-title{font-weight:700;text-align:center;margin-bottom:8px}.legend-item{height:15px;width:15px;border:1px solid #ccc}.maplibregl-popup-close-button{top:13px;right:15px}@media screen and (max-width: 600px){dialog{width:100vw;max-width:100vw;height:100dvh;max-height:100dvh;border-radius:0;border:none;box-shadow:none;overflow:hidden}.dlg-buttons{flex-direction:row;flex-wrap:wrap;align-items:center;justify-content:center}dialog h2:before{content:\"\";padding-right:0}}.ctrl-group{display:flex;flex-direction:column;gap:8px}.filter-row{display:flex;flex-direction:column;margin-bottom:8px;font-size:.8em}.filter-row-cols{display:block;column-count:2}.zone{display:flex;align-items:center;gap:8px;margin:0;padding:0}.zones{display:grid;grid-template-columns:1fr 1fr;column-gap:24px;row-gap:8px;overflow-y:auto;max-height:420px}.svgicon{height:30px;width:30px;-webkit-mask-size:contain;mask-size:contain}h4,label{display:flex;align-items:center;gap:4px}.info-grid{display:grid;grid-template-columns:1fr 1fr 1fr;gap:8px;margin-bottom:16px}.info{display:flex;flex-direction:column}.info-label{font-weight:600;font-size:.7em;color:#333}.info-value{font-size:.8em;color:#555}@media (max-width: 600px){.zones{grid-template-columns:1fr}}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1$1.RangeValueAccessor, selector: "input[type=range][formControlName],input[type=range][formControl],input[type=range][ngModel]" }, { kind: "directive", type: i1$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: HubDataLayer, selector: "hub-data-layer", inputs: ["visible", "name", "desc", "icon", "shape"], outputs: ["onCustomize", "onCheck"] }, { kind: "directive", type: DraggableDialogDirective, selector: "dialog[draggable]" }, { kind: "component", type: AreaIcon, selector: "area-icon" }, { kind: "component", type: PaletteSelect, selector: "mapag-palette-select", inputs: ["palettes", "palette"], outputs: ["paletteChange"] }, { kind: "directive", type: BringToFrontDirective, selector: "[mapagBringToFront]" }, { kind: "component", type: NgSelectComponent, selector: "ng-select", inputs: ["bindLabel", "bindValue", "appearance", "ariaLabelDropdown", "ariaLabel", "markFirst", "placeholder", "fixedPlaceholder", "notFoundText", "typeToSearchText", "preventToggleOnRightClick", "addTagText", "loadingText", "clearAllText", "dropdownPosition", "appendTo", "loading", "closeOnSelect", "hideSelected", "selectOnTab", "openOnEnter", "maxSelectedItems", "groupBy", "groupValue", "bufferAmount", "virtualScroll", "selectableGroup", "tabFocusOnClearButton", "selectableGroupAsModel", "searchFn", "trackByFn", "clearOnBackspace", "labelForId", "inputAttrs", "tabIndex", "readonly", "searchWhileComposing", "minTermLength", "editableSearchTerm", "ngClass", "typeahead", "multiple", "addTag", "searchable", "clearable", "isOpen", "items", "compareWith", "clearSearchOnAdd", "deselectOnClick", "keyDownFn"], outputs: ["bindLabelChange", "bindValueChange", "appearanceChange", "isOpenChange", "blur", "focus", "change", "open", "close", "search", "clear", "add", "remove", "scroll", "scrollToEnd", "itemsChange"] }, { kind: "component", type: ShowHideBtn, selector: "mapag-show-hide-btn", inputs: ["mapper"] }, { kind: "component", type: GradientLegend, selector: "mapag-gradient-legend", inputs: ["settings"] }, { kind: "component", type: StdLegend, selector: "mapag-std-legend", inputs: ["items", "columns"] }, { kind: "component", type: DialogHeader, selector: "mapag-dialog-header", inputs: ["dialog"] }, { kind: "directive", type: OnBodyDirective, selector: "dialog[onBody]" }, { kind: "pipe", type: TextPipe, name: "text" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
26607
+ }
26608
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: ConsumerSpendingPanel, decorators: [{
26609
+ type: Component,
26610
+ args: [{ selector: 'mapag-consumer-spending-panel', changeDetection: ChangeDetectionStrategy.OnPush, imports: [
26611
+ CommonModule,
26612
+ FormsModule,
26613
+ HubDataLayer,
26614
+ DraggableDialogDirective,
26615
+ AreaIcon,
26616
+ PaletteSelect,
26617
+ BringToFrontDirective,
26618
+ NgSelectComponent,
26619
+ ShowHideBtn,
26620
+ GradientLegend,
26621
+ StdLegend,
26622
+ DialogHeader,
26623
+ TextPipe,
26624
+ OnBodyDirective
26625
+ ], template: `
26626
+ <hub-data-layer
26627
+ [visible]="mapper.settings().visible"
26628
+ [name]="mapper.info().Commodity + ' (' + mapper.info().Year + ')'"
26629
+ [desc]="mapper.desc()"
26630
+ shape="area"
26631
+ (onCheck)="setVisible($event)"
26632
+ (onCustomize)="toggleDialog()"
26633
+ >
26634
+ <area-icon></area-icon>
26635
+ </hub-data-layer>
26636
+
26637
+ <dialog draggable mapagBringToFront onBody #customizeDialog>
26638
+ <h2>{{ mapper.name() }}</h2>
26639
+
26640
+ <div class="dlg-body">
26641
+ <p>
26642
+ The Consumer Spending dataset from Esri provides a rigorously modeled representation of how U.S. households
26643
+ allocate their budgets across a wide spectrum of goods and services, integrating source data from the U.S.
26644
+ Bureau of Labor Statistics’ Consumer Expenditure and Diary Surveys to estimate both current spending patterns
26645
+ and five‑year forecasts. It offers detailed, category‑level insights into consumer purchasing behavior,
26646
+ enabling analysts to understand market demand, evaluate economic conditions, and support data‑driven
26647
+ decision‑making within geographic contexts.
26648
+ </p>
26649
+ <h3>Information</h3>
26650
+ <div class="info-grid">
26651
+ <div class="info">
26652
+ <div class="info-label">Source</div>
26653
+ <div class="info-value">{{ mapper.info().Source | text }}</div>
26654
+ </div>
26655
+ <div class="info">
26656
+ <div class="info-label">Sector</div>
26657
+ <div class="info-value">{{ mapper.info().Sector | text }}</div>
26658
+ </div>
26659
+ <div class="info">
26660
+ <div class="info-label">Group</div>
26661
+ <div class="info-value">{{ mapper.info().Group | text }}</div>
26662
+ </div>
26663
+ <div class="info">
26664
+ <div class="info-label">Commodity</div>
26665
+ <div class="info-value">{{ mapper.info().Commodity | text }}</div>
26666
+ </div>
26667
+ <div class="info">
26668
+ <div class="info-label">Class</div>
26669
+ <div class="info-value">{{ mapper.info().Class | text }}</div>
26670
+ </div>
26671
+ <div class="info">
26672
+ <div class="info-label">Statistic</div>
26673
+ <div class="info-value">{{ mapper.info().Statistic | text }}</div>
26674
+ </div>
26675
+ <div class="info">
26676
+ <div class="info-label">Production</div>
26677
+ <div class="info-value">{{ mapper.info().Production | text }}</div>
26678
+ </div>
26679
+ <div class="info">
26680
+ <div class="info-label">Utilization</div>
26681
+ <div class="info-value">{{ mapper.info().Utilization | text }}</div>
26682
+ </div>
26683
+ <div class="info">
26684
+ <div class="info-label">Unit</div>
26685
+ <div class="info-value">{{ mapper.info().Unit | text }}</div>
26686
+ </div>
26687
+ </div>
26688
+ <h3>Customize Display Settings</h3>
26689
+ <div class="zones">
26690
+ <div class="ctrl-group">
26691
+ <div class="radio-tabs">
26692
+ <label>
26693
+ <input
26694
+ type="radio"
26695
+ name="fillType"
26696
+ value="solid"
26697
+ [checked]="mapper.settings().fillType == 'solid'"
26698
+ (change)="update('fillType', 'solid')"
26699
+ />
26700
+ Solid
26701
+ </label>
26702
+ <label>
26703
+ <input
26704
+ type="radio"
26705
+ name="fillType"
26706
+ value="gradient"
26707
+ [checked]="mapper.settings().fillType == 'gradient'"
26708
+ (change)="update('fillType', 'gradient')"
26709
+ />
26710
+ Gradient
26711
+ </label>
26712
+ <label>
26713
+ <input
26714
+ type="radio"
26715
+ name="fillType"
26716
+ value="palette"
26717
+ [checked]="mapper.settings().fillType == 'palette'"
26718
+ (change)="update('fillType', 'palette')"
26719
+ />
26720
+ Palette
26721
+ </label>
26722
+ </div>
26723
+ <div class="ctrl-row">
26724
+ @switch (mapper.settings().fillType) { @case ('solid') {
26725
+ <label for="colorPicker">Color:</label>
26726
+ <input
26727
+ type="color"
26728
+ id="colorPicker"
26729
+ [ngModel]="mapper.settings().fillColor"
26730
+ (ngModelChange)="update('fillColor', $event)"
26731
+ />
26732
+ } @case ('gradient') {
26733
+ <label for="gradientSelect">Gradient:</label>
26734
+ <input
26735
+ type="color"
26736
+ [ngModel]="mapper.settings().fillGradient[0].color"
26737
+ (ngModelChange)="updateGradient($event, undefined)"
26738
+ />
26739
+ <input
26740
+ type="color"
26741
+ [ngModel]="mapper.settings().fillGradient[1].color"
26742
+ (ngModelChange)="updateGradient(undefined, $event)"
26743
+ />
26744
+ } @case ('palette') {
26745
+ <label for="paletteSelect">Palette:</label>
26746
+ <mapag-palette-select
26747
+ [palette]="mapper.settings().fillPalette"
26748
+ (paletteChange)="update('fillPalette', $event)"
26749
+ >
26750
+ </mapag-palette-select>
26751
+ } }
26752
+ </div>
26753
+ <div class="ctrl-row">
26754
+ <label for="fillOpacity">Opacity:</label>
26755
+ <input
26756
+ type="range"
26757
+ id="fillOpacity"
26758
+ min="0"
26759
+ max="1"
26760
+ step="0.01"
26761
+ [ngModel]="mapper.settings().fillOpacity"
26762
+ (ngModelChange)="update('fillOpacity', $event)"
26763
+ />
26764
+ </div>
26765
+ <div class="ctrl-row">
26766
+ <label for="borderColor">Border Color:</label>
26767
+ <input
26768
+ type="color"
26769
+ id="borderColor"
26770
+ [ngModel]="mapper.settings().borderColor"
26771
+ (ngModelChange)="update('borderColor', $event)"
26772
+ />
26773
+ </div>
26774
+ </div>
26775
+ <div class="ctrl-group">
26776
+ <h4>Filters</h4>
26777
+ <h5>State</h5>
26778
+ <div class="filter-row" style="padding: 3px;">
26779
+ <ng-select
26780
+ [items]="USStates"
26781
+ bindLabel="Name"
26782
+ bindValue="Abbr"
26783
+ [ngModel]="mapper.settings().filterStates"
26784
+ [multiple]="true"
26785
+ appendTo="body"
26786
+ (ngModelChange)="update('filterStates', $event)"
26787
+ >
26788
+ </ng-select>
26789
+ </div>
26790
+ </div>
26791
+ </div>
26792
+
26793
+ <h3>References</h3>
26794
+ <div style="display: flex; flex-direction: column;">
26795
+ <a href="https://www.nass.usda.gov/" target="_blank">USDA NASS</a>
26796
+ <a href="https://quickstats.nass.usda.gov/" target="_blank">USDA NASS Quick Stats</a>
26797
+ </div>
26798
+ </div>
26799
+ <div class="dlg-buttons">
26800
+ <button class="btn" (click)="toggleLegend()">Legend</button>
26801
+ <button class="btn" (click)="remove()">Remove</button>
26802
+ <button class="btn" (click)="reset()">Reset</button>
26803
+ <mapag-show-hide-btn [mapper]="mapper"></mapag-show-hide-btn>
26804
+ <button class="btn" (click)="toggleDialog()">Close</button>
26805
+ </div>
26806
+ </dialog>
26807
+
26808
+ <dialog class="legend" #legendDialog draggable mapagBringToFront onbody>
26809
+ <mapag-dialog-header class="drag-handle"[dialog]="legendDialog">{{ mapper.name() }}</mapag-dialog-header>
26810
+ @switch (mapper.settings().fillType) {
26811
+ @case ('solid') {
26812
+ <div style="width: 30px; height: 30px; background-color: {{ mapper.settings().fillColor }}; border: 1px solid #000;"></div>
26813
+ }
26814
+ @case ('gradient') {
26815
+ <mapag-gradient-legend [settings]="gradientSettings()"> </mapag-gradient-legend>
26816
+ }
26817
+ @case ('palette') {
26818
+ <mapag-std-legend [items]="paletteLegend()"></mapag-std-legend>
26819
+ }
26820
+ }
26821
+ </dialog>
26822
+ `, styles: ["dialog{font-size:14pt;width:100%;max-width:700px;border:none;border-radius:8px;box-shadow:0 2px 10px #0003;padding:16px;position:fixed;top:50%;left:50%;transform:translate(-50%,-50%);margin:0;flex-direction:column}dialog:open{display:flex}dialog .dlg-body{flex-grow:1;overflow-y:auto}dialog.legend{width:fit-content}dialog.legend h2{font-size:smaller}dialog select{max-width:90vw}dialog h2{color:#000}dialog h2:before{content:\"\\22ee\\22ee \";padding-right:4px}dialog h3{color:#000;border-bottom:2px solid gray;font-weight:500;font-size:.9em;margin-top:16px;margin-bottom:8px}dialog h4{color:#000;font-weight:500;margin-bottom:8px;margin-top:12px;font-size:.85em;border:none}dialog p{font-size:.8em}dialog a{text-decoration:none;color:#0a3773;font-weight:500;font-size:.8em;padding-left:4px}dialog a:hover{text-decoration:underline;cursor:pointer}dialog a:before{content:\"\\1f517\";padding-right:2px}.ctrl-group{display:flex;flex-direction:column}.ctrl-row{display:grid;grid-template-columns:auto 1fr auto 1fr;align-items:center;gap:4px;justify-items:start;padding-left:20px}.ctrl-first{grid-column:1}.ctrl-row label{font-size:.8em;margin:0;padding:0;font-weight:400}.ctrl.wide{grid-column:span 3}input[type=range]{grid-column:span 3;justify-self:stretch}input[type=color]{width:40px;height:24px;border-radius:4px;cursor:pointer}input[type=number]{width:6ch;font-size:.8em}.dlg-buttons{display:flex;justify-content:flex-end;gap:8px;margin-top:16px}button{background-color:#0a3773;color:#fff;border:none;border-radius:4px;padding:8px 16px;cursor:pointer;font-size:.8em}button:hover{background-color:#083a5c}summary{font-size:1em;font-weight:600;color:#000;cursor:pointer;padding:8px 0;border-bottom:2px solid gray;list-style:none;-webkit-user-select:none;user-select:none;margin-bottom:8px}summary::-webkit-details-marker{display:none}summary:before{content:\"\\304f\";display:inline-block;margin-right:8px;transform:rotate(180deg);transition:transform .2s}details[open] summary:before{transform:rotate(270deg)}.radio-tabs{margin-bottom:12px;font-size:.8em;display:flex;flex-direction:row}.radio-tabs label{display:grid;grid-template-columns:auto 1fr;gap:4px;grid-template-rows:30px;align-items:center}.radio-tabs input[type=radio]{display:none}.radio-tabs label{padding:8px 12px;border:2px solid transparent;border-radius:6px;cursor:pointer;transition:all .2s ease}.radio-tabs label:has(input[type=radio]:checked){background-color:#fff;border-color:#333}.mgr-btn{justify-self:center;background-color:transparent;color:#4c4c4c;text-align:center;width:100%;font-weight:600;cursor:pointer;display:flex;align-items:center;justify-content:center;margin:4px 0;padding:6px;gap:4px;border:1px solid rgb(218,218,218)}.mgr-btn:hover{background-color:transparent;border-color:#4c4c4c}.legend-row{display:grid;grid-template-columns:auto 1fr;gap:8px;padding:4px 0;align-items:center}.legend-title{font-weight:700;text-align:center;margin-bottom:8px}.legend-item{height:15px;width:15px;border:1px solid #ccc}.maplibregl-popup-close-button{top:13px;right:15px}@media screen and (max-width: 600px){dialog{width:100vw;max-width:100vw;height:100dvh;max-height:100dvh;border-radius:0;border:none;box-shadow:none;overflow:hidden}.dlg-buttons{flex-direction:row;flex-wrap:wrap;align-items:center;justify-content:center}dialog h2:before{content:\"\";padding-right:0}}.ctrl-group{display:flex;flex-direction:column;gap:8px}.filter-row{display:flex;flex-direction:column;margin-bottom:8px;font-size:.8em}.filter-row-cols{display:block;column-count:2}.zone{display:flex;align-items:center;gap:8px;margin:0;padding:0}.zones{display:grid;grid-template-columns:1fr 1fr;column-gap:24px;row-gap:8px;overflow-y:auto;max-height:420px}.svgicon{height:30px;width:30px;-webkit-mask-size:contain;mask-size:contain}h4,label{display:flex;align-items:center;gap:4px}.info-grid{display:grid;grid-template-columns:1fr 1fr 1fr;gap:8px;margin-bottom:16px}.info{display:flex;flex-direction:column}.info-label{font-weight:600;font-size:.7em;color:#333}.info-value{font-size:.8em;color:#555}@media (max-width: 600px){.zones{grid-template-columns:1fr}}\n"] }]
26823
+ }], ctorParameters: () => [], propDecorators: { map: [{ type: i0.Input, args: [{ isSignal: true, alias: "map", required: false }] }], customizeDialog: [{ type: i0.ViewChild, args: ['customizeDialog', { isSignal: true }] }], legendDialog: [{ type: i0.ViewChild, args: ['legendDialog', { isSignal: true }] }], onRemove: [{ type: i0.Output, args: ["onRemove"] }], settings: [{ type: i0.Input, args: [{ isSignal: true, alias: "settings", required: false }] }] } });
26824
+
26825
+ class ConsumerSpendingGroups {
26826
+ static DairyFruitVegetables = [
26827
+ { ID: "X1053", Name: "Dairy Products", Level: 0 },
26828
+ { ID: "X1054", Name: "Fresh Milk (All Types)", Level: 1 },
26829
+ { ID: "X1055", Name: "Cream", Level: 1 },
26830
+ { ID: "X1056", Name: "Butter", Level: 1 },
26831
+ { ID: "X1057", Name: "Cheese", Level: 1 },
26832
+ { ID: "X1058", Name: "Ice Cream & Rel Prod", Level: 1 },
26833
+ { ID: "X1059", Name: "Other Dairy Products", Level: 1 },
26834
+ { ID: "X1060", Name: "Fruit & Vegetables", Level: 0 },
26835
+ { ID: "X1061", Name: "Fresh Fruit", Level: 1 },
26836
+ { ID: "X1062", Name: "Apples", Level: 2 },
26837
+ { ID: "X1063", Name: "Bananas", Level: 2 },
26838
+ { ID: "X1064", Name: "Oranges", Level: 2 },
26839
+ { ID: "X1065", Name: "Citrus Fruit excluding Oranges", Level: 2 },
26840
+ { ID: "X1066", Name: "Other Fresh Fruit", Level: 2 },
26841
+ { ID: "X1067", Name: "Fresh Vegetables", Level: 1 },
26842
+ { ID: "X1068", Name: "Potatoes", Level: 2 },
26843
+ { ID: "X1069", Name: "Lettuce", Level: 2 },
26844
+ { ID: "X1070", Name: "Tomatoes", Level: 2 },
26845
+ { ID: "X1071", Name: "Other Fresh Vegetables", Level: 2 },
26846
+ { ID: "X1072", Name: "Processed Fruit", Level: 1 },
26847
+ { ID: "X1073", Name: "Frozen Fruit & Juice", Level: 2 },
26848
+ { ID: "X1074", Name: "Frozen Orange Juice", Level: 2 },
26849
+ { ID: "X1075", Name: "Frozen Fruit", Level: 2 },
26850
+ { ID: "X1076", Name: "Frozen Fruit Juice", Level: 2 },
26851
+ { ID: "X1077", Name: "Canned Fruit", Level: 2 },
26852
+ { ID: "X1078", Name: "Dried Fruit", Level: 2 },
26853
+ { ID: "X1079", Name: "Fresh Fruit Juice", Level: 2 },
26854
+ { ID: "X1080", Name: "Canned/Bottled Fruit Juice", Level: 2 },
26855
+ { ID: "X1081", Name: "Processed Vegetables", Level: 2 },
26856
+ { ID: "X1082", Name: "Frozen Vegetables", Level: 2 },
26857
+ { ID: "X1083", Name: "Vegetables: Canned/Dried/Juice", Level: 2 },
26858
+ { ID: "X1084", Name: "Canned Beans", Level: 3 },
26859
+ { ID: "X1085", Name: "Canned Corn", Level: 3 },
26860
+ { ID: "X1086", Name: "Misc Canned Vegetables", Level: 3 },
26861
+ { ID: "X1087", Name: "Dried Beans & Peas", Level: 3 },
26862
+ { ID: "X1088", Name: "Misc Dried Vegetables", Level: 3 },
26863
+ { ID: "X1089", Name: "Vegetable Juice", Level: 3 },
26864
+ ];
26865
+ static Alcoholic = [
26866
+ { ID: "X2001", Name: "Alcoholic Beverages" },
26867
+ { ID: "X2002", Name: "Alcoholic Beverage at Home", Level: 1 },
26868
+ { ID: "X2003", Name: "Beer & Ale", Level: 2 },
26869
+ { ID: "X2004", Name: "Whiskey", Level: 2 },
26870
+ { ID: "X2005", Name: "Wine", Level: 2 },
26871
+ { ID: "X2006", Name: "Other Alcoholic Beverages", Level: 2 },
26872
+ { ID: "X2007", Name: "Alcoholic Beverage Away from Home", Level: 1 },
26873
+ { ID: "X2008", Name: "Beer & Ale Away from Home", Level: 2 },
26874
+ { ID: "X2009", Name: "Beer at Full Service Restaurants", Level: 3 },
26875
+ { ID: "X2010", Name: "Beer at Fast Food Restaurants/Other", Level: 3 },
26876
+ { ID: "X2011", Name: "Wine Away from Home", Level: 2 },
26877
+ { ID: "X2012", Name: "Wine at Full Service Restaurants", Level: 3 },
26878
+ { ID: "X2013", Name: "Wine at Fast Food Restaurants", Level: 3 },
26879
+ { ID: "X2014", Name: "Other Alcohol Away from Home", Level: 2 },
26880
+ { ID: "X2015", Name: "Other Alcohol at Full Service Restaurants", Level: 3 },
26881
+ { ID: "X2016", Name: "Other Alcohol at Fast Food Restaurants", Level: 3 },
26882
+ ];
26883
+ static BakedGoods = [
26884
+ { ID: "X1004", Name: "Bakery & Cereal Prod" },
26885
+ { ID: "X1005", Name: "Flour" },
26886
+ { ID: "X1006", Name: "Prepared Flour Mixes" },
26887
+ { ID: "X1007", Name: "Ready-to-eat & Cooked Cereal" },
26888
+ { ID: "X1008", Name: "Rice" },
26889
+ { ID: "X1009", Name: "Pasta/Cornmeal/Other Cereal" },
26890
+ { ID: "X1010", Name: "Bread" },
26891
+ { ID: "X1011", Name: "White Bread" },
26892
+ { ID: "X1012", Name: "Bread excluding White" },
26893
+ { ID: "X1013", Name: "Crackers & Cookies" },
26894
+ { ID: "X1014", Name: "Cookies" },
26895
+ { ID: "X1015", Name: "Crackers" },
26896
+ { ID: "X1016", Name: "Frozen & Refrigerated Bakery Goods" },
26897
+ { ID: "X1017", Name: "Other Bakery Products" },
26898
+ { ID: "X1018", Name: "Fresh Biscuits/Rolls/Muffins" },
26899
+ { ID: "X1019", Name: "Fresh Cakes & Cupcakes" },
26900
+ { ID: "X1020", Name: "Bread & Cracker Products" },
26901
+ { ID: "X1021", Name: "Sweet Rolls/Coffee Cakes/Donuts" },
26902
+ { ID: "X1022", Name: "Fresh Pies/Tarts/Turnovers" },
26903
+ ];
26904
+ static MeatPoultryFishEggs = [
26905
+ { ID: "X1023", Name: "Meat/Poultry/Fish/Eggs" },
26906
+ { ID: "X1024", Name: "Beef", Level: 1 },
26907
+ { ID: "X1025", Name: "Ground Beef", Level: 2 },
26908
+ { ID: "X1026", Name: "Chuck Roast", Level: 2 },
26909
+ { ID: "X1027", Name: "Round Roast", Level: 2 },
26910
+ { ID: "X1028", Name: "Other Roast", Level: 2 },
26911
+ { ID: "X1029", Name: "Round Steak", Level: 2 },
26912
+ { ID: "X1030", Name: "Sirloin Steak", Level: 2 },
26913
+ { ID: "X1031", Name: "Other Steak", Level: 2 },
26914
+ { ID: "X1032", Name: "Other Beef", Level: 2 },
26915
+ { ID: "X1033", Name: "Pork", Level: 1 },
26916
+ { ID: "X1034", Name: "Bacon", Level: 2 },
26917
+ { ID: "X1035", Name: "Pork Chops", Level: 2 },
26918
+ { ID: "X1036", Name: "Ham", Level: 2 },
26919
+ { ID: "X1037", Name: "Pork Sausage", Level: 2 },
26920
+ { ID: "X1038", Name: "Other Pork", Level: 2 },
26921
+ { ID: "X1039", Name: "Other Meat", Level: 1 },
26922
+ { ID: "X1040", Name: "Frankfurters", Level: 2 },
26923
+ { ID: "X1041", Name: "Bologna/Liverwurst/Salami", Level: 2 },
26924
+ { ID: "X1042", Name: "Other Lunchmeat", Level: 2 },
26925
+ { ID: "X1043", Name: "Lamb & Other Meat", Level: 2 },
26926
+ { ID: "X1044", Name: "Poultry", Level: 1 },
26927
+ { ID: "X1045", Name: "Whole Chickens", Level: 2 },
26928
+ { ID: "X1046", Name: "Chicken Parts", Level: 2 },
26929
+ { ID: "X1047", Name: "Other Poultry", Level: 2 },
26930
+ { ID: "X1048", Name: "Seafood", Level: 1 },
26931
+ { ID: "X1049", Name: "Canned Fish & Shellfish", Level: 2 },
26932
+ { ID: "X1050", Name: "Fresh Fish & Shellfish", Level: 2 },
26933
+ { ID: "X1051", Name: "Frozen Fish & Shellfish", Level: 2 },
26934
+ { ID: "X1052", Name: "Eggs", Level: 1 },
26935
+ ];
26936
+ static Groups = [
26937
+ { ID: "dairy", Name: "Dairy / Fruit and Vegetables", Children: ConsumerSpendingGroups.DairyFruitVegetables },
26938
+ { ID: "alcholoic", Name: "Alcoholic Beverages", Children: ConsumerSpendingGroups.Alcoholic },
26939
+ { ID: "baked", Name: "Bakery & Cereal Prod", Children: ConsumerSpendingGroups.BakedGoods },
26940
+ { ID: "meat", Name: "Meat / Poultry / Fish / Eggs", Children: ConsumerSpendingGroups.MeatPoultryFishEggs }
26941
+ ];
26942
+ static All() {
26943
+ const all = [];
26944
+ const dairy = ConsumerSpendingGroups.DairyFruitVegetables.map(i => {
26945
+ return {
26946
+ ID: i.ID,
26947
+ Name: i.Name,
26948
+ Level: i.Level,
26949
+ Parent: "Dairy / Fruit and Vegetables"
26950
+ };
26951
+ });
26952
+ const alcholoic = ConsumerSpendingGroups.Alcoholic.map(i => {
26953
+ return {
26954
+ ID: i.ID,
26955
+ Name: i.Name,
26956
+ Level: i.Level,
26957
+ Parent: "Alcoholic Beverages"
26958
+ };
26959
+ });
26960
+ const baked = ConsumerSpendingGroups.BakedGoods.map(i => {
26961
+ return {
26962
+ ID: i.ID,
26963
+ Name: i.Name,
26964
+ Level: i.Level,
26965
+ Parent: "Bakery & Cereal Prod"
26966
+ };
26967
+ });
26968
+ const meat = ConsumerSpendingGroups.MeatPoultryFishEggs.map(i => {
26969
+ return {
26970
+ ID: i.ID,
26971
+ Name: i.Name,
26972
+ Level: i.Level,
26973
+ Parent: "Meat / Poultry / Fish / Eggs"
26974
+ };
26975
+ });
26976
+ return [...dairy, ...alcholoic, ...baked, ...meat];
26977
+ }
26978
+ }
26979
+
26980
+ class ConsumerSpendingSelectPanel {
26981
+ faCircle = faCircle;
26982
+ faFire = faFire;
26983
+ faThLarge = faThLarge;
26984
+ faList = faList;
26985
+ options = ConsumerSpendingGroups.Groups;
26986
+ nassSvc = inject(NassService);
26987
+ canAdd = input(true, ...(ngDevMode ? [{ debugName: "canAdd" }] : []));
26988
+ // Map Component
26989
+ map = input(...(ngDevMode ? [undefined, { debugName: "map" }] : []));
26990
+ // Currently selected NAICS codes
26991
+ current = model([], ...(ngDevMode ? [{ debugName: "current" }] : []));
26992
+ customizeDialog = viewChild('customizeDialog', ...(ngDevMode ? [{ debugName: "customizeDialog" }] : []));
26993
+ // Mapper group to hold NAICS layers
26994
+ mappers = new MapboxMapperGroup();
26995
+ constructor() {
26996
+ const _mapInit = effect(() => {
26997
+ const mapComp = this.map();
26998
+ if (mapComp) {
26999
+ mapComp.mapper().set('naicsmgr', this.mappers);
27000
+ }
27001
+ }, ...(ngDevMode ? [{ debugName: "_mapInit" }] : []));
27002
+ }
27003
+ isSelected(code) {
27004
+ return this.current().some((c) => c.ID === code.ID);
27005
+ }
27006
+ selectInfo(info) {
27007
+ const currentInfos = this.current();
27008
+ const index = currentInfos.findIndex((c) => c.ID === info.ID);
27009
+ if (index >= 0) {
27010
+ // Remove if already selected
27011
+ this.current.set(currentInfos.filter((c) => c.ID !== info.ID));
27012
+ }
27013
+ else {
27014
+ // Add if not selected - ensure no duplicates
27015
+ const newInfos = [...currentInfos, info];
27016
+ // Remove any potential duplicates by creating a Map
27017
+ const uniqueMap = new Map(newInfos.map((c) => [c.ID, c]));
27018
+ this.current.set(Array.from(uniqueMap.values()));
27019
+ }
27020
+ }
27021
+ removeInfo(info) {
27022
+ const currentInfos = this.current();
27023
+ this.current.set(currentInfos.filter((c) => c.ID !== info.ID));
27024
+ }
27025
+ toggleDialog() {
27026
+ const dialog = this.customizeDialog();
27027
+ if (!dialog) {
27028
+ return;
27029
+ }
27030
+ const dialogElement = dialog.nativeElement;
27031
+ if (dialogElement.open) {
27032
+ dialogElement.close();
27033
+ }
27034
+ else {
27035
+ dialogElement.show();
27036
+ }
27037
+ }
27038
+ fixTextSet(input) {
27039
+ const output = [];
27040
+ input.forEach((text) => {
27041
+ output.push({ key: text, value: this.fixText(text) });
27042
+ });
27043
+ return output;
27044
+ }
27045
+ fixText(text) {
27046
+ const parts = text
27047
+ .toLocaleLowerCase()
27048
+ .split('_')
27049
+ .map((part) => part.charAt(0).toUpperCase() + part.slice(1));
27050
+ return parts.join(' ');
27051
+ }
27052
+ reset() {
27053
+ }
27054
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: ConsumerSpendingSelectPanel, deps: [], target: i0.ɵɵFactoryTarget.Component });
27055
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.15", type: ConsumerSpendingSelectPanel, isStandalone: true, selector: "mapag-consumer-spending-select-panel", inputs: { canAdd: { classPropertyName: "canAdd", publicName: "canAdd", isSignal: true, isRequired: false, transformFunction: null }, map: { classPropertyName: "map", publicName: "map", isSignal: true, isRequired: false, transformFunction: null }, current: { classPropertyName: "current", publicName: "current", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { current: "currentChange" }, viewQueries: [{ propertyName: "customizeDialog", first: true, predicate: ["customizeDialog"], descendants: true, isSignal: true }], ngImport: i0, template: `
27056
+ <mapag-details [open]="true" style="margin-top: 16px;">
27057
+ <span summary>Consumer Spending</span>
27058
+
27059
+ <!-- @for (info of current(); track info.ID) {
27060
+ <hub-nass-panel [map]="map()" [settings]="inf" (onRemove)="removeInfo(info)"></hub-nass-panel>
27061
+ } -->
27062
+
27063
+ @if (canAdd()) {
27064
+ <button class="mgr-btn" (click)="toggleDialog()" style="justify-self: center;">Add & Remove Layers</button>
27065
+ }
27066
+ </mapag-details>
27067
+ <dialog draggable mapagBringToFront onBody #customizeDialog>
27068
+ <h2>Consumer Spending Layers</h2>
27069
+
27070
+ <div class="dlg-body">
27071
+ <p>
27072
+ Select a consumer spending category from the list below to add it as a layer on the map. You can select multiple
27073
+ categories to compare them. Use the filters to narrow down the options. The data is sourced from the USDA Economic
27074
+ Research Service and represents average annual consumer spending in the United States for various food categories.
27075
+ </p>
27076
+
27077
+ <div class="zones results">
27078
+ @for (group of options; track group.ID) {
27079
+ <h3>{{group.Name}}</h3>
27080
+ @for (item of group.Children; track item.ID) {
27081
+ <label>
27082
+ <input type="checkbox" [checked]="isSelected(item)" (change)="selectInfo(item)" [ngClass]="'indent-' + (item.Level || 0)">
27083
+ {{item.Name}}
27084
+ </label>
27085
+ }
27086
+ }
27087
+ </div>
27088
+
27089
+ <h3>References</h3>
27090
+ <div style="display: flex; flex-direction: column;">
27091
+ <a href="https://doc.arcgis.com/en/esri-demographics/latest/esri-demographics/consumer-spending.htm" target="_blank">ESRi Consumer Spending Data</a>
27092
+ </div>
27093
+ </div>
27094
+ <div class="dlg-buttons">
27095
+ <button class="btn" (click)="reset()">Reset</button>
27096
+ <button class="btn" (click)="toggleDialog()">Close</button>
27097
+ </div>
27098
+ </dialog>
27099
+ `, isInline: true, styles: ["dialog{font-size:14pt;width:100%;max-width:700px;border:none;border-radius:8px;box-shadow:0 2px 10px #0003;padding:16px;position:fixed;top:50%;left:50%;transform:translate(-50%,-50%);margin:0;flex-direction:column}dialog:open{display:flex}dialog .dlg-body{flex-grow:1;overflow-y:auto}dialog.legend{width:fit-content}dialog.legend h2{font-size:smaller}dialog select{max-width:90vw}dialog h2{color:#000}dialog h2:before{content:\"\\22ee\\22ee \";padding-right:4px}dialog h3{color:#000;border-bottom:2px solid gray;font-weight:500;font-size:.9em;margin-top:16px;margin-bottom:8px}dialog h4{color:#000;font-weight:500;margin-bottom:8px;margin-top:12px;font-size:.85em;border:none}dialog p{font-size:.8em}dialog a{text-decoration:none;color:#0a3773;font-weight:500;font-size:.8em;padding-left:4px}dialog a:hover{text-decoration:underline;cursor:pointer}dialog a:before{content:\"\\1f517\";padding-right:2px}.ctrl-group{display:flex;flex-direction:column}.ctrl-row{display:grid;grid-template-columns:auto 1fr auto 1fr;align-items:center;gap:4px;justify-items:start;padding-left:20px}.ctrl-first{grid-column:1}.ctrl-row label{font-size:.8em;margin:0;padding:0;font-weight:400}.ctrl.wide{grid-column:span 3}input[type=range]{grid-column:span 3;justify-self:stretch}input[type=color]{width:40px;height:24px;border-radius:4px;cursor:pointer}input[type=number]{width:6ch;font-size:.8em}.dlg-buttons{display:flex;justify-content:flex-end;gap:8px;margin-top:16px}button{background-color:#0a3773;color:#fff;border:none;border-radius:4px;padding:8px 16px;cursor:pointer;font-size:.8em}button:hover{background-color:#083a5c}summary{font-size:1em;font-weight:600;color:#000;cursor:pointer;padding:8px 0;border-bottom:2px solid gray;list-style:none;-webkit-user-select:none;user-select:none;margin-bottom:8px}summary::-webkit-details-marker{display:none}summary:before{content:\"\\304f\";display:inline-block;margin-right:8px;transform:rotate(180deg);transition:transform .2s}details[open] summary:before{transform:rotate(270deg)}.radio-tabs{margin-bottom:12px;font-size:.8em;display:flex;flex-direction:row}.radio-tabs label{display:grid;grid-template-columns:auto 1fr;gap:4px;grid-template-rows:30px;align-items:center}.radio-tabs input[type=radio]{display:none}.radio-tabs label{padding:8px 12px;border:2px solid transparent;border-radius:6px;cursor:pointer;transition:all .2s ease}.radio-tabs label:has(input[type=radio]:checked){background-color:#fff;border-color:#333}.mgr-btn{justify-self:center;background-color:transparent;color:#4c4c4c;text-align:center;width:100%;font-weight:600;cursor:pointer;display:flex;align-items:center;justify-content:center;margin:4px 0;padding:6px;gap:4px;border:1px solid rgb(218,218,218)}.mgr-btn:hover{background-color:transparent;border-color:#4c4c4c}.legend-row{display:grid;grid-template-columns:auto 1fr;gap:8px;padding:4px 0;align-items:center}.legend-title{font-weight:700;text-align:center;margin-bottom:8px}.legend-item{height:15px;width:15px;border:1px solid #ccc}.maplibregl-popup-close-button{top:13px;right:15px}@media screen and (max-width: 600px){dialog{width:100vw;max-width:100vw;height:100dvh;max-height:100dvh;border-radius:0;border:none;box-shadow:none;overflow:hidden}.dlg-buttons{flex-direction:row;flex-wrap:wrap;align-items:center;justify-content:center}dialog h2:before{content:\"\";padding-right:0}}.zones{font-size:.8em}.indent-1{margin-left:16px}.indent-2{margin-left:32px}.filters{display:flex;gap:8px;margin-bottom:8px;flex-wrap:wrap;flex-direction:row}.results{overflow-y:auto}.resultcont{display:flex;flex-direction:column;flex-grow:1}.search{display:flex;gap:4px;align-items:center;margin-bottom:8px;font-size:.8em}.search input[type=radio]{display:none}.search label{display:flex;align-items:center;gap:4px;padding:2px 4px;border:1px solid transparent;cursor:pointer}.search label:has(input[type=radio]:checked){border:1px solid #333;border-radius:4px;background-color:#f0f0f0}.filters select{padding:3px;border:1px solid grey;border-radius:4px}.filters label{font-size:.8em;font-weight:600}dialog h4{display:flex;justify-content:space-between;align-items:center;margin-bottom:4px;margin-top:4px}.ctrl-row{grid-template-columns:1fr;font-size:.8em}.zones{max-height:400px;height:400px;overflow-y:auto;margin-top:0}input[type=search]{width:100%;font-size:1em;padding:4px 8px;border-radius:4px;border:1px solid #ccc}label{display:flex;align-items:center;gap:4px}@media (max-width: 600px){.dlg-body{display:flex;flex-direction:column}.zones{max-height:unset;height:auto;flex-grow:1}}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: DraggableDialogDirective, selector: "dialog[draggable]" }, { kind: "directive", type: BringToFrontDirective, selector: "[mapagBringToFront]" }, { kind: "component", type: MapagDetails, selector: "mapag-details", inputs: ["open"] }, { kind: "directive", type: OnBodyDirective, selector: "dialog[onBody]" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
25655
27100
  }
25656
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: ShowHideBtn, decorators: [{
27101
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: ConsumerSpendingSelectPanel, decorators: [{
25657
27102
  type: Component,
25658
- args: [{ selector: 'mapag-show-hide-btn', imports: [CommonModule, FaIconComponent], template: `
25659
- <button class="btn" (click)="toggleShowHide()">
25660
- <fa-icon [icon]="mapper().settings().visible ? faEyeSlash : faEye"></fa-icon>
25661
- {{ mapper().settings().visible ? 'Hide' : 'Show' }}
25662
- </button>
25663
- `, styles: ["dialog{font-size:14pt;width:100%;max-width:700px;border:none;border-radius:8px;box-shadow:0 2px 10px #0003;padding:16px;position:fixed;top:50%;left:50%;transform:translate(-50%,-50%);margin:0;flex-direction:column}dialog:open{display:flex}dialog .dlg-body{flex-grow:1;overflow-y:auto}dialog.legend{width:fit-content}dialog.legend h2{font-size:smaller}dialog select{max-width:90vw}dialog h2{color:#000}dialog h2:before{content:\"\\22ee\\22ee \";padding-right:4px}dialog h3{color:#000;border-bottom:2px solid gray;font-weight:500;font-size:.9em;margin-top:16px;margin-bottom:8px}dialog h4{color:#000;font-weight:500;margin-bottom:8px;margin-top:12px;font-size:.85em;border:none}dialog p{font-size:.8em}dialog a{text-decoration:none;color:#0a3773;font-weight:500;font-size:.8em;padding-left:4px}dialog a:hover{text-decoration:underline;cursor:pointer}dialog a:before{content:\"\\1f517\";padding-right:2px}.ctrl-group{display:flex;flex-direction:column}.ctrl-row{display:grid;grid-template-columns:auto 1fr auto 1fr;align-items:center;gap:4px;justify-items:start;padding-left:20px}.ctrl-first{grid-column:1}.ctrl-row label{font-size:.8em;margin:0;padding:0;font-weight:400}.ctrl.wide{grid-column:span 3}input[type=range]{grid-column:span 3;justify-self:stretch}input[type=color]{width:40px;height:24px;border-radius:4px;cursor:pointer}input[type=number]{width:6ch;font-size:.8em}.dlg-buttons{display:flex;justify-content:flex-end;gap:8px;margin-top:16px}button{background-color:#0a3773;color:#fff;border:none;border-radius:4px;padding:8px 16px;cursor:pointer;font-size:.8em}button:hover{background-color:#083a5c}summary{font-size:1em;font-weight:600;color:#000;cursor:pointer;padding:8px 0;border-bottom:2px solid gray;list-style:none;-webkit-user-select:none;user-select:none;margin-bottom:8px}summary::-webkit-details-marker{display:none}summary:before{content:\"\\304f\";display:inline-block;margin-right:8px;transform:rotate(180deg);transition:transform .2s}details[open] summary:before{transform:rotate(270deg)}.radio-tabs{margin-bottom:12px;font-size:.8em;display:flex;flex-direction:row}.radio-tabs label{display:grid;grid-template-columns:auto 1fr;gap:4px;grid-template-rows:30px;align-items:center}.radio-tabs input[type=radio]{display:none}.radio-tabs label{padding:8px 12px;border:2px solid transparent;border-radius:6px;cursor:pointer;transition:all .2s ease}.radio-tabs label:has(input[type=radio]:checked){background-color:#fff;border-color:#333}.mgr-btn{justify-self:center;background-color:transparent;color:#4c4c4c;text-align:center;width:100%;font-weight:600;cursor:pointer;display:flex;align-items:center;justify-content:center;margin:4px 0;padding:6px;gap:4px;border:1px solid rgb(218,218,218)}.mgr-btn:hover{background-color:transparent;border-color:#4c4c4c}.legend-row{display:grid;grid-template-columns:auto 1fr;gap:8px;padding:4px 0;align-items:center}.legend-title{font-weight:700;text-align:center;margin-bottom:8px}.legend-item{height:15px;width:15px;border:1px solid #ccc}.maplibregl-popup-close-button{top:13px;right:15px}@media screen and (max-width: 600px){dialog{width:100vw;max-width:100vw;height:100dvh;max-height:100dvh;border-radius:0;border:none;box-shadow:none;overflow:hidden}.dlg-buttons{flex-direction:row;flex-wrap:wrap;align-items:center;justify-content:center}dialog h2:before{content:\"\";padding-right:0}}:host{display:content}.btn{width:12ch}\n"] }]
25664
- }], propDecorators: { mapper: [{ type: i0.Input, args: [{ isSignal: true, alias: "mapper", required: true }] }] } });
27103
+ args: [{ selector: 'mapag-consumer-spending-select-panel', changeDetection: ChangeDetectionStrategy.OnPush, imports: [CommonModule, FormsModule, DraggableDialogDirective, BringToFrontDirective, MapagDetails, OnBodyDirective], template: `
27104
+ <mapag-details [open]="true" style="margin-top: 16px;">
27105
+ <span summary>Consumer Spending</span>
27106
+
27107
+ <!-- @for (info of current(); track info.ID) {
27108
+ <hub-nass-panel [map]="map()" [settings]="inf" (onRemove)="removeInfo(info)"></hub-nass-panel>
27109
+ } -->
27110
+
27111
+ @if (canAdd()) {
27112
+ <button class="mgr-btn" (click)="toggleDialog()" style="justify-self: center;">Add & Remove Layers</button>
27113
+ }
27114
+ </mapag-details>
27115
+ <dialog draggable mapagBringToFront onBody #customizeDialog>
27116
+ <h2>Consumer Spending Layers</h2>
27117
+
27118
+ <div class="dlg-body">
27119
+ <p>
27120
+ Select a consumer spending category from the list below to add it as a layer on the map. You can select multiple
27121
+ categories to compare them. Use the filters to narrow down the options. The data is sourced from the USDA Economic
27122
+ Research Service and represents average annual consumer spending in the United States for various food categories.
27123
+ </p>
27124
+
27125
+ <div class="zones results">
27126
+ @for (group of options; track group.ID) {
27127
+ <h3>{{group.Name}}</h3>
27128
+ @for (item of group.Children; track item.ID) {
27129
+ <label>
27130
+ <input type="checkbox" [checked]="isSelected(item)" (change)="selectInfo(item)" [ngClass]="'indent-' + (item.Level || 0)">
27131
+ {{item.Name}}
27132
+ </label>
27133
+ }
27134
+ }
27135
+ </div>
27136
+
27137
+ <h3>References</h3>
27138
+ <div style="display: flex; flex-direction: column;">
27139
+ <a href="https://doc.arcgis.com/en/esri-demographics/latest/esri-demographics/consumer-spending.htm" target="_blank">ESRi Consumer Spending Data</a>
27140
+ </div>
27141
+ </div>
27142
+ <div class="dlg-buttons">
27143
+ <button class="btn" (click)="reset()">Reset</button>
27144
+ <button class="btn" (click)="toggleDialog()">Close</button>
27145
+ </div>
27146
+ </dialog>
27147
+ `, styles: ["dialog{font-size:14pt;width:100%;max-width:700px;border:none;border-radius:8px;box-shadow:0 2px 10px #0003;padding:16px;position:fixed;top:50%;left:50%;transform:translate(-50%,-50%);margin:0;flex-direction:column}dialog:open{display:flex}dialog .dlg-body{flex-grow:1;overflow-y:auto}dialog.legend{width:fit-content}dialog.legend h2{font-size:smaller}dialog select{max-width:90vw}dialog h2{color:#000}dialog h2:before{content:\"\\22ee\\22ee \";padding-right:4px}dialog h3{color:#000;border-bottom:2px solid gray;font-weight:500;font-size:.9em;margin-top:16px;margin-bottom:8px}dialog h4{color:#000;font-weight:500;margin-bottom:8px;margin-top:12px;font-size:.85em;border:none}dialog p{font-size:.8em}dialog a{text-decoration:none;color:#0a3773;font-weight:500;font-size:.8em;padding-left:4px}dialog a:hover{text-decoration:underline;cursor:pointer}dialog a:before{content:\"\\1f517\";padding-right:2px}.ctrl-group{display:flex;flex-direction:column}.ctrl-row{display:grid;grid-template-columns:auto 1fr auto 1fr;align-items:center;gap:4px;justify-items:start;padding-left:20px}.ctrl-first{grid-column:1}.ctrl-row label{font-size:.8em;margin:0;padding:0;font-weight:400}.ctrl.wide{grid-column:span 3}input[type=range]{grid-column:span 3;justify-self:stretch}input[type=color]{width:40px;height:24px;border-radius:4px;cursor:pointer}input[type=number]{width:6ch;font-size:.8em}.dlg-buttons{display:flex;justify-content:flex-end;gap:8px;margin-top:16px}button{background-color:#0a3773;color:#fff;border:none;border-radius:4px;padding:8px 16px;cursor:pointer;font-size:.8em}button:hover{background-color:#083a5c}summary{font-size:1em;font-weight:600;color:#000;cursor:pointer;padding:8px 0;border-bottom:2px solid gray;list-style:none;-webkit-user-select:none;user-select:none;margin-bottom:8px}summary::-webkit-details-marker{display:none}summary:before{content:\"\\304f\";display:inline-block;margin-right:8px;transform:rotate(180deg);transition:transform .2s}details[open] summary:before{transform:rotate(270deg)}.radio-tabs{margin-bottom:12px;font-size:.8em;display:flex;flex-direction:row}.radio-tabs label{display:grid;grid-template-columns:auto 1fr;gap:4px;grid-template-rows:30px;align-items:center}.radio-tabs input[type=radio]{display:none}.radio-tabs label{padding:8px 12px;border:2px solid transparent;border-radius:6px;cursor:pointer;transition:all .2s ease}.radio-tabs label:has(input[type=radio]:checked){background-color:#fff;border-color:#333}.mgr-btn{justify-self:center;background-color:transparent;color:#4c4c4c;text-align:center;width:100%;font-weight:600;cursor:pointer;display:flex;align-items:center;justify-content:center;margin:4px 0;padding:6px;gap:4px;border:1px solid rgb(218,218,218)}.mgr-btn:hover{background-color:transparent;border-color:#4c4c4c}.legend-row{display:grid;grid-template-columns:auto 1fr;gap:8px;padding:4px 0;align-items:center}.legend-title{font-weight:700;text-align:center;margin-bottom:8px}.legend-item{height:15px;width:15px;border:1px solid #ccc}.maplibregl-popup-close-button{top:13px;right:15px}@media screen and (max-width: 600px){dialog{width:100vw;max-width:100vw;height:100dvh;max-height:100dvh;border-radius:0;border:none;box-shadow:none;overflow:hidden}.dlg-buttons{flex-direction:row;flex-wrap:wrap;align-items:center;justify-content:center}dialog h2:before{content:\"\";padding-right:0}}.zones{font-size:.8em}.indent-1{margin-left:16px}.indent-2{margin-left:32px}.filters{display:flex;gap:8px;margin-bottom:8px;flex-wrap:wrap;flex-direction:row}.results{overflow-y:auto}.resultcont{display:flex;flex-direction:column;flex-grow:1}.search{display:flex;gap:4px;align-items:center;margin-bottom:8px;font-size:.8em}.search input[type=radio]{display:none}.search label{display:flex;align-items:center;gap:4px;padding:2px 4px;border:1px solid transparent;cursor:pointer}.search label:has(input[type=radio]:checked){border:1px solid #333;border-radius:4px;background-color:#f0f0f0}.filters select{padding:3px;border:1px solid grey;border-radius:4px}.filters label{font-size:.8em;font-weight:600}dialog h4{display:flex;justify-content:space-between;align-items:center;margin-bottom:4px;margin-top:4px}.ctrl-row{grid-template-columns:1fr;font-size:.8em}.zones{max-height:400px;height:400px;overflow-y:auto;margin-top:0}input[type=search]{width:100%;font-size:1em;padding:4px 8px;border-radius:4px;border:1px solid #ccc}label{display:flex;align-items:center;gap:4px}@media (max-width: 600px){.dlg-body{display:flex;flex-direction:column}.zones{max-height:unset;height:auto;flex-grow:1}}\n"] }]
27148
+ }], ctorParameters: () => [], propDecorators: { canAdd: [{ type: i0.Input, args: [{ isSignal: true, alias: "canAdd", required: false }] }], map: [{ type: i0.Input, args: [{ isSignal: true, alias: "map", required: false }] }], current: [{ type: i0.Input, args: [{ isSignal: true, alias: "current", required: false }] }, { type: i0.Output, args: ["currentChange"] }], customizeDialog: [{ type: i0.ViewChild, args: ['customizeDialog', { isSignal: true }] }] } });
25665
27149
 
25666
27150
  class HubCropSequencePanel {
25667
27151
  DefaultName = 'cropsequence';
@@ -25846,59 +27330,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImpo
25846
27330
  `, styles: ["dialog{font-size:14pt;width:100%;max-width:700px;border:none;border-radius:8px;box-shadow:0 2px 10px #0003;padding:16px;position:fixed;top:50%;left:50%;transform:translate(-50%,-50%);margin:0;flex-direction:column}dialog:open{display:flex}dialog .dlg-body{flex-grow:1;overflow-y:auto}dialog.legend{width:fit-content}dialog.legend h2{font-size:smaller}dialog select{max-width:90vw}dialog h2{color:#000}dialog h2:before{content:\"\\22ee\\22ee \";padding-right:4px}dialog h3{color:#000;border-bottom:2px solid gray;font-weight:500;font-size:.9em;margin-top:16px;margin-bottom:8px}dialog h4{color:#000;font-weight:500;margin-bottom:8px;margin-top:12px;font-size:.85em;border:none}dialog p{font-size:.8em}dialog a{text-decoration:none;color:#0a3773;font-weight:500;font-size:.8em;padding-left:4px}dialog a:hover{text-decoration:underline;cursor:pointer}dialog a:before{content:\"\\1f517\";padding-right:2px}.ctrl-group{display:flex;flex-direction:column}.ctrl-row{display:grid;grid-template-columns:auto 1fr auto 1fr;align-items:center;gap:4px;justify-items:start;padding-left:20px}.ctrl-first{grid-column:1}.ctrl-row label{font-size:.8em;margin:0;padding:0;font-weight:400}.ctrl.wide{grid-column:span 3}input[type=range]{grid-column:span 3;justify-self:stretch}input[type=color]{width:40px;height:24px;border-radius:4px;cursor:pointer}input[type=number]{width:6ch;font-size:.8em}.dlg-buttons{display:flex;justify-content:flex-end;gap:8px;margin-top:16px}button{background-color:#0a3773;color:#fff;border:none;border-radius:4px;padding:8px 16px;cursor:pointer;font-size:.8em}button:hover{background-color:#083a5c}summary{font-size:1em;font-weight:600;color:#000;cursor:pointer;padding:8px 0;border-bottom:2px solid gray;list-style:none;-webkit-user-select:none;user-select:none;margin-bottom:8px}summary::-webkit-details-marker{display:none}summary:before{content:\"\\304f\";display:inline-block;margin-right:8px;transform:rotate(180deg);transition:transform .2s}details[open] summary:before{transform:rotate(270deg)}.radio-tabs{margin-bottom:12px;font-size:.8em;display:flex;flex-direction:row}.radio-tabs label{display:grid;grid-template-columns:auto 1fr;gap:4px;grid-template-rows:30px;align-items:center}.radio-tabs input[type=radio]{display:none}.radio-tabs label{padding:8px 12px;border:2px solid transparent;border-radius:6px;cursor:pointer;transition:all .2s ease}.radio-tabs label:has(input[type=radio]:checked){background-color:#fff;border-color:#333}.mgr-btn{justify-self:center;background-color:transparent;color:#4c4c4c;text-align:center;width:100%;font-weight:600;cursor:pointer;display:flex;align-items:center;justify-content:center;margin:4px 0;padding:6px;gap:4px;border:1px solid rgb(218,218,218)}.mgr-btn:hover{background-color:transparent;border-color:#4c4c4c}.legend-row{display:grid;grid-template-columns:auto 1fr;gap:8px;padding:4px 0;align-items:center}.legend-title{font-weight:700;text-align:center;margin-bottom:8px}.legend-item{height:15px;width:15px;border:1px solid #ccc}.maplibregl-popup-close-button{top:13px;right:15px}@media screen and (max-width: 600px){dialog{width:100vw;max-width:100vw;height:100dvh;max-height:100dvh;border-radius:0;border:none;box-shadow:none;overflow:hidden}.dlg-buttons{flex-direction:row;flex-wrap:wrap;align-items:center;justify-content:center}dialog h2:before{content:\"\";padding-right:0}}dialog{max-width:700px}.zones{display:grid;grid-template-columns:1fr 1fr;column-gap:16px;row-gap:8px;overflow-y:auto;max-height:420px}@media (max-width: 600px){.zones{grid-template-columns:1fr}}\n"] }]
25847
27331
  }], ctorParameters: () => [], propDecorators: { map: [{ type: i0.Input, args: [{ isSignal: true, alias: "map", required: false }] }], customizeDialog: [{ type: i0.ViewChild, args: ['customizeDialog', { isSignal: true }] }] } });
25848
27332
 
25849
- class DialogHeader {
25850
- faTimes = faTimes;
25851
- dialog = input(...(ngDevMode ? [undefined, { debugName: "dialog" }] : []));
25852
- close() {
25853
- // Close the dialog by finding the closest dialog element and calling its close method
25854
- const d = this.dialog();
25855
- if (d) {
25856
- d.close();
25857
- }
25858
- }
25859
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: DialogHeader, deps: [], target: i0.ɵɵFactoryTarget.Component });
25860
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "20.3.15", type: DialogHeader, isStandalone: true, selector: "mapag-dialog-header", inputs: { dialog: { classPropertyName: "dialog", publicName: "dialog", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: `
25861
- <h2><ng-content></ng-content></h2>
25862
- <button class="btn-icon" (click)="close()"><fa-icon [icon]="faTimes" size="lg"></fa-icon></button>
25863
- `, isInline: true, styles: ["dialog{font-size:14pt;width:100%;max-width:700px;border:none;border-radius:8px;box-shadow:0 2px 10px #0003;padding:16px;position:fixed;top:50%;left:50%;transform:translate(-50%,-50%);margin:0;flex-direction:column}dialog:open{display:flex}dialog .dlg-body{flex-grow:1;overflow-y:auto}dialog.legend{width:fit-content}dialog.legend h2{font-size:smaller}dialog select{max-width:90vw}dialog h2{color:#000}dialog h2:before{content:\"\\22ee\\22ee \";padding-right:4px}dialog h3{color:#000;border-bottom:2px solid gray;font-weight:500;font-size:.9em;margin-top:16px;margin-bottom:8px}dialog h4{color:#000;font-weight:500;margin-bottom:8px;margin-top:12px;font-size:.85em;border:none}dialog p{font-size:.8em}dialog a{text-decoration:none;color:#0a3773;font-weight:500;font-size:.8em;padding-left:4px}dialog a:hover{text-decoration:underline;cursor:pointer}dialog a:before{content:\"\\1f517\";padding-right:2px}.ctrl-group{display:flex;flex-direction:column}.ctrl-row{display:grid;grid-template-columns:auto 1fr auto 1fr;align-items:center;gap:4px;justify-items:start;padding-left:20px}.ctrl-first{grid-column:1}.ctrl-row label{font-size:.8em;margin:0;padding:0;font-weight:400}.ctrl.wide{grid-column:span 3}input[type=range]{grid-column:span 3;justify-self:stretch}input[type=color]{width:40px;height:24px;border-radius:4px;cursor:pointer}input[type=number]{width:6ch;font-size:.8em}.dlg-buttons{display:flex;justify-content:flex-end;gap:8px;margin-top:16px}button{background-color:#0a3773;color:#fff;border:none;border-radius:4px;padding:8px 16px;cursor:pointer;font-size:.8em}button:hover{background-color:#083a5c}summary{font-size:1em;font-weight:600;color:#000;cursor:pointer;padding:8px 0;border-bottom:2px solid gray;list-style:none;-webkit-user-select:none;user-select:none;margin-bottom:8px}summary::-webkit-details-marker{display:none}summary:before{content:\"\\304f\";display:inline-block;margin-right:8px;transform:rotate(180deg);transition:transform .2s}details[open] summary:before{transform:rotate(270deg)}.radio-tabs{margin-bottom:12px;font-size:.8em;display:flex;flex-direction:row}.radio-tabs label{display:grid;grid-template-columns:auto 1fr;gap:4px;grid-template-rows:30px;align-items:center}.radio-tabs input[type=radio]{display:none}.radio-tabs label{padding:8px 12px;border:2px solid transparent;border-radius:6px;cursor:pointer;transition:all .2s ease}.radio-tabs label:has(input[type=radio]:checked){background-color:#fff;border-color:#333}.mgr-btn{justify-self:center;background-color:transparent;color:#4c4c4c;text-align:center;width:100%;font-weight:600;cursor:pointer;display:flex;align-items:center;justify-content:center;margin:4px 0;padding:6px;gap:4px;border:1px solid rgb(218,218,218)}.mgr-btn:hover{background-color:transparent;border-color:#4c4c4c}.legend-row{display:grid;grid-template-columns:auto 1fr;gap:8px;padding:4px 0;align-items:center}.legend-title{font-weight:700;text-align:center;margin-bottom:8px}.legend-item{height:15px;width:15px;border:1px solid #ccc}.maplibregl-popup-close-button{top:13px;right:15px}@media screen and (max-width: 600px){dialog{width:100vw;max-width:100vw;height:100dvh;max-height:100dvh;border-radius:0;border:none;box-shadow:none;overflow:hidden}.dlg-buttons{flex-direction:row;flex-wrap:wrap;align-items:center;justify-content:center}dialog h2:before{content:\"\";padding-right:0}}:host{display:flex;align-items:center}:host:first-child{flex-grow:1}:host h2{margin:0;flex-grow:1}.btn-icon{padding:2px;border:none;background:transparent;cursor:pointer;border-radius:4px;color:gray}.btn-icon:hover{color:#000;background-color:transparent}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "component", type: FaIconComponent, selector: "fa-icon", inputs: ["icon", "title", "animation", "mask", "flip", "size", "pull", "border", "inverse", "symbol", "rotate", "fixedWidth", "transform", "a11yRole"], outputs: ["iconChange", "titleChange", "animationChange", "maskChange", "flipChange", "sizeChange", "pullChange", "borderChange", "inverseChange", "symbolChange", "rotateChange", "fixedWidthChange", "transformChange", "a11yRoleChange"] }] });
25864
- }
25865
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: DialogHeader, decorators: [{
25866
- type: Component,
25867
- args: [{ selector: 'mapag-dialog-header', imports: [CommonModule, FaIconComponent], template: `
25868
- <h2><ng-content></ng-content></h2>
25869
- <button class="btn-icon" (click)="close()"><fa-icon [icon]="faTimes" size="lg"></fa-icon></button>
25870
- `, styles: ["dialog{font-size:14pt;width:100%;max-width:700px;border:none;border-radius:8px;box-shadow:0 2px 10px #0003;padding:16px;position:fixed;top:50%;left:50%;transform:translate(-50%,-50%);margin:0;flex-direction:column}dialog:open{display:flex}dialog .dlg-body{flex-grow:1;overflow-y:auto}dialog.legend{width:fit-content}dialog.legend h2{font-size:smaller}dialog select{max-width:90vw}dialog h2{color:#000}dialog h2:before{content:\"\\22ee\\22ee \";padding-right:4px}dialog h3{color:#000;border-bottom:2px solid gray;font-weight:500;font-size:.9em;margin-top:16px;margin-bottom:8px}dialog h4{color:#000;font-weight:500;margin-bottom:8px;margin-top:12px;font-size:.85em;border:none}dialog p{font-size:.8em}dialog a{text-decoration:none;color:#0a3773;font-weight:500;font-size:.8em;padding-left:4px}dialog a:hover{text-decoration:underline;cursor:pointer}dialog a:before{content:\"\\1f517\";padding-right:2px}.ctrl-group{display:flex;flex-direction:column}.ctrl-row{display:grid;grid-template-columns:auto 1fr auto 1fr;align-items:center;gap:4px;justify-items:start;padding-left:20px}.ctrl-first{grid-column:1}.ctrl-row label{font-size:.8em;margin:0;padding:0;font-weight:400}.ctrl.wide{grid-column:span 3}input[type=range]{grid-column:span 3;justify-self:stretch}input[type=color]{width:40px;height:24px;border-radius:4px;cursor:pointer}input[type=number]{width:6ch;font-size:.8em}.dlg-buttons{display:flex;justify-content:flex-end;gap:8px;margin-top:16px}button{background-color:#0a3773;color:#fff;border:none;border-radius:4px;padding:8px 16px;cursor:pointer;font-size:.8em}button:hover{background-color:#083a5c}summary{font-size:1em;font-weight:600;color:#000;cursor:pointer;padding:8px 0;border-bottom:2px solid gray;list-style:none;-webkit-user-select:none;user-select:none;margin-bottom:8px}summary::-webkit-details-marker{display:none}summary:before{content:\"\\304f\";display:inline-block;margin-right:8px;transform:rotate(180deg);transition:transform .2s}details[open] summary:before{transform:rotate(270deg)}.radio-tabs{margin-bottom:12px;font-size:.8em;display:flex;flex-direction:row}.radio-tabs label{display:grid;grid-template-columns:auto 1fr;gap:4px;grid-template-rows:30px;align-items:center}.radio-tabs input[type=radio]{display:none}.radio-tabs label{padding:8px 12px;border:2px solid transparent;border-radius:6px;cursor:pointer;transition:all .2s ease}.radio-tabs label:has(input[type=radio]:checked){background-color:#fff;border-color:#333}.mgr-btn{justify-self:center;background-color:transparent;color:#4c4c4c;text-align:center;width:100%;font-weight:600;cursor:pointer;display:flex;align-items:center;justify-content:center;margin:4px 0;padding:6px;gap:4px;border:1px solid rgb(218,218,218)}.mgr-btn:hover{background-color:transparent;border-color:#4c4c4c}.legend-row{display:grid;grid-template-columns:auto 1fr;gap:8px;padding:4px 0;align-items:center}.legend-title{font-weight:700;text-align:center;margin-bottom:8px}.legend-item{height:15px;width:15px;border:1px solid #ccc}.maplibregl-popup-close-button{top:13px;right:15px}@media screen and (max-width: 600px){dialog{width:100vw;max-width:100vw;height:100dvh;max-height:100dvh;border-radius:0;border:none;box-shadow:none;overflow:hidden}.dlg-buttons{flex-direction:row;flex-wrap:wrap;align-items:center;justify-content:center}dialog h2:before{content:\"\";padding-right:0}}:host{display:flex;align-items:center}:host:first-child{flex-grow:1}:host h2{margin:0;flex-grow:1}.btn-icon{padding:2px;border:none;background:transparent;cursor:pointer;border-radius:4px;color:gray}.btn-icon:hover{color:#000;background-color:transparent}\n"] }]
25871
- }], propDecorators: { dialog: [{ type: i0.Input, args: [{ isSignal: true, alias: "dialog", required: false }] }] } });
25872
-
25873
- class StdLegend {
25874
- items = input([], ...(ngDevMode ? [{ debugName: "items" }] : []));
25875
- columns = input(1, ...(ngDevMode ? [{ debugName: "columns" }] : []));
25876
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: StdLegend, deps: [], target: i0.ɵɵFactoryTarget.Component });
25877
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.15", type: StdLegend, isStandalone: true, selector: "mapag-std-legend", inputs: { items: { classPropertyName: "items", publicName: "items", isSignal: true, isRequired: false, transformFunction: null }, columns: { classPropertyName: "columns", publicName: "columns", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: `
25878
- <div class="legend" [style.grid-template-columns]="'repeat(' + columns() + ',1fr)'">
25879
- @for (item of items(); track item) {
25880
- <div class="legend-row">
25881
- <div class="legend-item" [style.background-color]="item.value" [ngStyle]="item.style"></div>
25882
- <div>{{ item.label }}</div>
25883
- </div>
25884
- }
25885
- </div>
25886
- `, isInline: true, styles: ["dialog{font-size:14pt;width:100%;max-width:700px;border:none;border-radius:8px;box-shadow:0 2px 10px #0003;padding:16px;position:fixed;top:50%;left:50%;transform:translate(-50%,-50%);margin:0;flex-direction:column}dialog:open{display:flex}dialog .dlg-body{flex-grow:1;overflow-y:auto}dialog.legend{width:fit-content}dialog.legend h2{font-size:smaller}dialog select{max-width:90vw}dialog h2{color:#000}dialog h2:before{content:\"\\22ee\\22ee \";padding-right:4px}dialog h3{color:#000;border-bottom:2px solid gray;font-weight:500;font-size:.9em;margin-top:16px;margin-bottom:8px}dialog h4{color:#000;font-weight:500;margin-bottom:8px;margin-top:12px;font-size:.85em;border:none}dialog p{font-size:.8em}dialog a{text-decoration:none;color:#0a3773;font-weight:500;font-size:.8em;padding-left:4px}dialog a:hover{text-decoration:underline;cursor:pointer}dialog a:before{content:\"\\1f517\";padding-right:2px}.ctrl-group{display:flex;flex-direction:column}.ctrl-row{display:grid;grid-template-columns:auto 1fr auto 1fr;align-items:center;gap:4px;justify-items:start;padding-left:20px}.ctrl-first{grid-column:1}.ctrl-row label{font-size:.8em;margin:0;padding:0;font-weight:400}.ctrl.wide{grid-column:span 3}input[type=range]{grid-column:span 3;justify-self:stretch}input[type=color]{width:40px;height:24px;border-radius:4px;cursor:pointer}input[type=number]{width:6ch;font-size:.8em}.dlg-buttons{display:flex;justify-content:flex-end;gap:8px;margin-top:16px}button{background-color:#0a3773;color:#fff;border:none;border-radius:4px;padding:8px 16px;cursor:pointer;font-size:.8em}button:hover{background-color:#083a5c}summary{font-size:1em;font-weight:600;color:#000;cursor:pointer;padding:8px 0;border-bottom:2px solid gray;list-style:none;-webkit-user-select:none;user-select:none;margin-bottom:8px}summary::-webkit-details-marker{display:none}summary:before{content:\"\\304f\";display:inline-block;margin-right:8px;transform:rotate(180deg);transition:transform .2s}details[open] summary:before{transform:rotate(270deg)}.radio-tabs{margin-bottom:12px;font-size:.8em;display:flex;flex-direction:row}.radio-tabs label{display:grid;grid-template-columns:auto 1fr;gap:4px;grid-template-rows:30px;align-items:center}.radio-tabs input[type=radio]{display:none}.radio-tabs label{padding:8px 12px;border:2px solid transparent;border-radius:6px;cursor:pointer;transition:all .2s ease}.radio-tabs label:has(input[type=radio]:checked){background-color:#fff;border-color:#333}.mgr-btn{justify-self:center;background-color:transparent;color:#4c4c4c;text-align:center;width:100%;font-weight:600;cursor:pointer;display:flex;align-items:center;justify-content:center;margin:4px 0;padding:6px;gap:4px;border:1px solid rgb(218,218,218)}.mgr-btn:hover{background-color:transparent;border-color:#4c4c4c}.legend-row{display:grid;grid-template-columns:auto 1fr;gap:8px;padding:4px 0;align-items:center}.legend-title{font-weight:700;text-align:center;margin-bottom:8px}.legend-item{height:15px;width:15px;border:1px solid #ccc}.maplibregl-popup-close-button{top:13px;right:15px}@media screen and (max-width: 600px){dialog{width:100vw;max-width:100vw;height:100dvh;max-height:100dvh;border-radius:0;border:none;box-shadow:none;overflow:hidden}.dlg-buttons{flex-direction:row;flex-wrap:wrap;align-items:center;justify-content:center}dialog h2:before{content:\"\";padding-right:0}}.legend{display:grid;column-gap:8px;font-size:.8em}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }] });
25887
- }
25888
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: StdLegend, decorators: [{
25889
- type: Component,
25890
- args: [{ selector: 'mapag-std-legend', imports: [CommonModule], template: `
25891
- <div class="legend" [style.grid-template-columns]="'repeat(' + columns() + ',1fr)'">
25892
- @for (item of items(); track item) {
25893
- <div class="legend-row">
25894
- <div class="legend-item" [style.background-color]="item.value" [ngStyle]="item.style"></div>
25895
- <div>{{ item.label }}</div>
25896
- </div>
25897
- }
25898
- </div>
25899
- `, styles: ["dialog{font-size:14pt;width:100%;max-width:700px;border:none;border-radius:8px;box-shadow:0 2px 10px #0003;padding:16px;position:fixed;top:50%;left:50%;transform:translate(-50%,-50%);margin:0;flex-direction:column}dialog:open{display:flex}dialog .dlg-body{flex-grow:1;overflow-y:auto}dialog.legend{width:fit-content}dialog.legend h2{font-size:smaller}dialog select{max-width:90vw}dialog h2{color:#000}dialog h2:before{content:\"\\22ee\\22ee \";padding-right:4px}dialog h3{color:#000;border-bottom:2px solid gray;font-weight:500;font-size:.9em;margin-top:16px;margin-bottom:8px}dialog h4{color:#000;font-weight:500;margin-bottom:8px;margin-top:12px;font-size:.85em;border:none}dialog p{font-size:.8em}dialog a{text-decoration:none;color:#0a3773;font-weight:500;font-size:.8em;padding-left:4px}dialog a:hover{text-decoration:underline;cursor:pointer}dialog a:before{content:\"\\1f517\";padding-right:2px}.ctrl-group{display:flex;flex-direction:column}.ctrl-row{display:grid;grid-template-columns:auto 1fr auto 1fr;align-items:center;gap:4px;justify-items:start;padding-left:20px}.ctrl-first{grid-column:1}.ctrl-row label{font-size:.8em;margin:0;padding:0;font-weight:400}.ctrl.wide{grid-column:span 3}input[type=range]{grid-column:span 3;justify-self:stretch}input[type=color]{width:40px;height:24px;border-radius:4px;cursor:pointer}input[type=number]{width:6ch;font-size:.8em}.dlg-buttons{display:flex;justify-content:flex-end;gap:8px;margin-top:16px}button{background-color:#0a3773;color:#fff;border:none;border-radius:4px;padding:8px 16px;cursor:pointer;font-size:.8em}button:hover{background-color:#083a5c}summary{font-size:1em;font-weight:600;color:#000;cursor:pointer;padding:8px 0;border-bottom:2px solid gray;list-style:none;-webkit-user-select:none;user-select:none;margin-bottom:8px}summary::-webkit-details-marker{display:none}summary:before{content:\"\\304f\";display:inline-block;margin-right:8px;transform:rotate(180deg);transition:transform .2s}details[open] summary:before{transform:rotate(270deg)}.radio-tabs{margin-bottom:12px;font-size:.8em;display:flex;flex-direction:row}.radio-tabs label{display:grid;grid-template-columns:auto 1fr;gap:4px;grid-template-rows:30px;align-items:center}.radio-tabs input[type=radio]{display:none}.radio-tabs label{padding:8px 12px;border:2px solid transparent;border-radius:6px;cursor:pointer;transition:all .2s ease}.radio-tabs label:has(input[type=radio]:checked){background-color:#fff;border-color:#333}.mgr-btn{justify-self:center;background-color:transparent;color:#4c4c4c;text-align:center;width:100%;font-weight:600;cursor:pointer;display:flex;align-items:center;justify-content:center;margin:4px 0;padding:6px;gap:4px;border:1px solid rgb(218,218,218)}.mgr-btn:hover{background-color:transparent;border-color:#4c4c4c}.legend-row{display:grid;grid-template-columns:auto 1fr;gap:8px;padding:4px 0;align-items:center}.legend-title{font-weight:700;text-align:center;margin-bottom:8px}.legend-item{height:15px;width:15px;border:1px solid #ccc}.maplibregl-popup-close-button{top:13px;right:15px}@media screen and (max-width: 600px){dialog{width:100vw;max-width:100vw;height:100dvh;max-height:100dvh;border-radius:0;border:none;box-shadow:none;overflow:hidden}.dlg-buttons{flex-direction:row;flex-wrap:wrap;align-items:center;justify-content:center}dialog h2:before{content:\"\";padding-right:0}}.legend{display:grid;column-gap:8px;font-size:.8em}\n"] }]
25900
- }], propDecorators: { items: [{ type: i0.Input, args: [{ isSignal: true, alias: "items", required: false }] }], columns: [{ type: i0.Input, args: [{ isSignal: true, alias: "columns", required: false }] }] } });
25901
-
25902
27333
  class HubCroplandPanel {
25903
27334
  DefaultName = 'cropland';
25904
27335
  faImage = faImage;
@@ -27341,91 +28772,21 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImpo
27341
28772
  `, styles: ["dialog{font-size:14pt;width:100%;max-width:700px;border:none;border-radius:8px;box-shadow:0 2px 10px #0003;padding:16px;position:fixed;top:50%;left:50%;transform:translate(-50%,-50%);margin:0;flex-direction:column}dialog:open{display:flex}dialog .dlg-body{flex-grow:1;overflow-y:auto}dialog.legend{width:fit-content}dialog.legend h2{font-size:smaller}dialog select{max-width:90vw}dialog h2{color:#000}dialog h2:before{content:\"\\22ee\\22ee \";padding-right:4px}dialog h3{color:#000;border-bottom:2px solid gray;font-weight:500;font-size:.9em;margin-top:16px;margin-bottom:8px}dialog h4{color:#000;font-weight:500;margin-bottom:8px;margin-top:12px;font-size:.85em;border:none}dialog p{font-size:.8em}dialog a{text-decoration:none;color:#0a3773;font-weight:500;font-size:.8em;padding-left:4px}dialog a:hover{text-decoration:underline;cursor:pointer}dialog a:before{content:\"\\1f517\";padding-right:2px}.ctrl-group{display:flex;flex-direction:column}.ctrl-row{display:grid;grid-template-columns:auto 1fr auto 1fr;align-items:center;gap:4px;justify-items:start;padding-left:20px}.ctrl-first{grid-column:1}.ctrl-row label{font-size:.8em;margin:0;padding:0;font-weight:400}.ctrl.wide{grid-column:span 3}input[type=range]{grid-column:span 3;justify-self:stretch}input[type=color]{width:40px;height:24px;border-radius:4px;cursor:pointer}input[type=number]{width:6ch;font-size:.8em}.dlg-buttons{display:flex;justify-content:flex-end;gap:8px;margin-top:16px}button{background-color:#0a3773;color:#fff;border:none;border-radius:4px;padding:8px 16px;cursor:pointer;font-size:.8em}button:hover{background-color:#083a5c}summary{font-size:1em;font-weight:600;color:#000;cursor:pointer;padding:8px 0;border-bottom:2px solid gray;list-style:none;-webkit-user-select:none;user-select:none;margin-bottom:8px}summary::-webkit-details-marker{display:none}summary:before{content:\"\\304f\";display:inline-block;margin-right:8px;transform:rotate(180deg);transition:transform .2s}details[open] summary:before{transform:rotate(270deg)}.radio-tabs{margin-bottom:12px;font-size:.8em;display:flex;flex-direction:row}.radio-tabs label{display:grid;grid-template-columns:auto 1fr;gap:4px;grid-template-rows:30px;align-items:center}.radio-tabs input[type=radio]{display:none}.radio-tabs label{padding:8px 12px;border:2px solid transparent;border-radius:6px;cursor:pointer;transition:all .2s ease}.radio-tabs label:has(input[type=radio]:checked){background-color:#fff;border-color:#333}.mgr-btn{justify-self:center;background-color:transparent;color:#4c4c4c;text-align:center;width:100%;font-weight:600;cursor:pointer;display:flex;align-items:center;justify-content:center;margin:4px 0;padding:6px;gap:4px;border:1px solid rgb(218,218,218)}.mgr-btn:hover{background-color:transparent;border-color:#4c4c4c}.legend-row{display:grid;grid-template-columns:auto 1fr;gap:8px;padding:4px 0;align-items:center}.legend-title{font-weight:700;text-align:center;margin-bottom:8px}.legend-item{height:15px;width:15px;border:1px solid #ccc}.maplibregl-popup-close-button{top:13px;right:15px}@media screen and (max-width: 600px){dialog{width:100vw;max-width:100vw;height:100dvh;max-height:100dvh;border-radius:0;border:none;box-shadow:none;overflow:hidden}.dlg-buttons{flex-direction:row;flex-wrap:wrap;align-items:center;justify-content:center}dialog h2:before{content:\"\";padding-right:0}}dialog{max-width:700px}.zone{display:flex;align-items:center;gap:8px;margin:0;padding:0;font-size:11pt}.zones{display:grid;grid-template-columns:1fr 1fr;column-gap:16px;row-gap:8px}@media (max-width: 600px){.zones{grid-template-columns:1fr}}\n"] }]
27342
28773
  }], ctorParameters: () => [], propDecorators: { map: [{ type: i0.Input, args: [{ isSignal: true, alias: "map", required: false }] }], customizeDialog: [{ type: i0.ViewChild, args: ['customizeDialog', { isSignal: true }] }], legendDialog: [{ type: i0.ViewChild, args: ['legendDialog', { isSignal: true }] }] } });
27343
28774
 
27344
- class TileDialog {
27345
- data = input(...(ngDevMode ? [undefined, { debugName: "data" }] : []));
27346
- name = input('', ...(ngDevMode ? [{ debugName: "name" }] : []));
27347
- contentTemplate = input(null, ...(ngDevMode ? [{ debugName: "contentTemplate" }] : []));
27348
- selection = signal(null, ...(ngDevMode ? [{ debugName: "selection" }] : []));
27349
- onSelect = output();
27350
- dataDialog = viewChild('dataDialog', ...(ngDevMode ? [{ debugName: "dataDialog" }] : []));
27351
- defaultTemplate = viewChild('defaultTemplate', ...(ngDevMode ? [{ debugName: "defaultTemplate" }] : []));
27352
- toggle() {
27353
- const dialog = this.dataDialog();
27354
- if (!dialog) {
27355
- return;
27356
- }
27357
- const dialogElement = dialog.nativeElement;
27358
- if (dialogElement.open) {
27359
- dialogElement.close();
27360
- }
27361
- else {
27362
- dialogElement.show();
28775
+ class SafeHtmlPipe {
28776
+ sanitizer = inject(DomSanitizer);
28777
+ transform(url) {
28778
+ if (!url) {
28779
+ return undefined;
27363
28780
  }
28781
+ return this.sanitizer.bypassSecurityTrustHtml(url);
27364
28782
  }
27365
- onClick(feature) {
27366
- this.selection.set(feature);
27367
- this.onSelect.emit(feature);
27368
- }
27369
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: TileDialog, deps: [], target: i0.ɵɵFactoryTarget.Component });
27370
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.15", type: TileDialog, isStandalone: true, selector: "mapag-tile-dialog", inputs: { data: { classPropertyName: "data", publicName: "data", isSignal: true, isRequired: false, transformFunction: null }, name: { classPropertyName: "name", publicName: "name", isSignal: true, isRequired: false, transformFunction: null }, contentTemplate: { classPropertyName: "contentTemplate", publicName: "contentTemplate", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { onSelect: "onSelect" }, viewQueries: [{ propertyName: "dataDialog", first: true, predicate: ["dataDialog"], descendants: true, isSignal: true }, { propertyName: "defaultTemplate", first: true, predicate: ["defaultTemplate"], descendants: true, isSignal: true }], ngImport: i0, template: `
27371
- <ng-template #defaultTemplate let-feature>
27372
- <div>{{ feature }}</div>
27373
- </ng-template>
27374
- <dialog draggable mapagBringToFront onBody #dataDialog class="data-dialog">
27375
- <h2>{{ name() }}</h2>
27376
- <div class="dlg-body dlg-body-list ">
27377
- {{ data()?.length }} records matching current filters.
27378
- @if (data()?.length === 0) {
27379
- <p>No data to display.</p>
27380
- } @else {
27381
- <cdk-virtual-scroll-viewport [itemSize]="10">
27382
- <div *cdkVirtualFor="let feature of data()" (click)="onClick(feature)">
27383
- <ng-container *ngTemplateOutlet="contentTemplate() || defaultTemplate; context: { $implicit: feature }"></ng-container>
27384
- </div>
27385
- </cdk-virtual-scroll-viewport>
27386
- }
27387
- </div>
27388
- <div class="dlg-buttons">
27389
- <button class="btn" (click)="toggle()">Close</button>
27390
- </div>
27391
- </dialog>
27392
- `, isInline: true, styles: [""], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: DraggableDialogDirective, selector: "dialog[draggable]" }, { kind: "directive", type: BringToFrontDirective, selector: "[mapagBringToFront]" }, { kind: "directive", type: OnBodyDirective, selector: "dialog[onBody]" }, { kind: "component", type: CdkVirtualScrollViewport, selector: "cdk-virtual-scroll-viewport", inputs: ["orientation", "appendOnly"], outputs: ["scrolledIndexChange"] }, { kind: "directive", type: CdkVirtualForOf, selector: "[cdkVirtualFor][cdkVirtualForOf]", inputs: ["cdkVirtualForOf", "cdkVirtualForTrackBy", "cdkVirtualForTemplate", "cdkVirtualForTemplateCacheSize"] }, { kind: "directive", type: CdkFixedSizeVirtualScroll, selector: "cdk-virtual-scroll-viewport[itemSize]", inputs: ["itemSize", "minBufferPx", "maxBufferPx"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
28783
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: SafeHtmlPipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe });
28784
+ static ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "20.3.15", ngImport: i0, type: SafeHtmlPipe, isStandalone: true, name: "safeHtml" });
27393
28785
  }
27394
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: TileDialog, decorators: [{
27395
- type: Component,
27396
- args: [{ selector: 'mapag-tile-dialog', changeDetection: ChangeDetectionStrategy.OnPush, imports: [
27397
- CommonModule,
27398
- FormsModule,
27399
- DraggableDialogDirective,
27400
- BringToFrontDirective,
27401
- OnBodyDirective,
27402
- CdkVirtualScrollViewport,
27403
- CdkVirtualForOf,
27404
- CdkFixedSizeVirtualScroll,
27405
- ], template: `
27406
- <ng-template #defaultTemplate let-feature>
27407
- <div>{{ feature }}</div>
27408
- </ng-template>
27409
- <dialog draggable mapagBringToFront onBody #dataDialog class="data-dialog">
27410
- <h2>{{ name() }}</h2>
27411
- <div class="dlg-body dlg-body-list ">
27412
- {{ data()?.length }} records matching current filters.
27413
- @if (data()?.length === 0) {
27414
- <p>No data to display.</p>
27415
- } @else {
27416
- <cdk-virtual-scroll-viewport [itemSize]="10">
27417
- <div *cdkVirtualFor="let feature of data()" (click)="onClick(feature)">
27418
- <ng-container *ngTemplateOutlet="contentTemplate() || defaultTemplate; context: { $implicit: feature }"></ng-container>
27419
- </div>
27420
- </cdk-virtual-scroll-viewport>
27421
- }
27422
- </div>
27423
- <div class="dlg-buttons">
27424
- <button class="btn" (click)="toggle()">Close</button>
27425
- </div>
27426
- </dialog>
27427
- ` }]
27428
- }], propDecorators: { data: [{ type: i0.Input, args: [{ isSignal: true, alias: "data", required: false }] }], name: [{ type: i0.Input, args: [{ isSignal: true, alias: "name", required: false }] }], contentTemplate: [{ type: i0.Input, args: [{ isSignal: true, alias: "contentTemplate", required: false }] }], onSelect: [{ type: i0.Output, args: ["onSelect"] }], dataDialog: [{ type: i0.ViewChild, args: ['dataDialog', { isSignal: true }] }], defaultTemplate: [{ type: i0.ViewChild, args: ['defaultTemplate', { isSignal: true }] }] } });
28786
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: SafeHtmlPipe, decorators: [{
28787
+ type: Pipe,
28788
+ args: [{ name: 'safeHtml' }]
28789
+ }] });
27429
28790
 
27430
28791
  class MMPanel {
27431
28792
  // Icons and static data
@@ -27439,8 +28800,10 @@ class MMPanel {
27439
28800
  USStates = states;
27440
28801
  map = input(...(ngDevMode ? [undefined, { debugName: "map" }] : []));
27441
28802
  settings = input(new PointDataMapperSettings(), ...(ngDevMode ? [{ debugName: "settings" }] : []));
27442
- mapper = new PointDataMapper(new MarketMakerPopupRenderer());
28803
+ popupRenderer = new MarketMakerPopupRenderer();
28804
+ mapper = new PointDataMapper(this.popupRenderer);
27443
28805
  customizeDialog = viewChild('customizeDialog', ...(ngDevMode ? [{ debugName: "customizeDialog" }] : []));
28806
+ dataDialog = viewChild('dataDialog', ...(ngDevMode ? [{ debugName: "dataDialog" }] : []));
27444
28807
  onRemove = output();
27445
28808
  style = computed(() => {
27446
28809
  const sel = this.mapper.settings().type;
@@ -27556,10 +28919,17 @@ class MMPanel {
27556
28919
  this.mapper.clear();
27557
28920
  }
27558
28921
  toggleData() {
27559
- // Implement dialog toggle logic here
28922
+ ToggleDialog(this.dataDialog);
28923
+ }
28924
+ onTileClick(feature) {
28925
+ const comp = this.map();
28926
+ if (!comp) {
28927
+ return;
28928
+ }
28929
+ flyToFeature(comp.map, feature);
27560
28930
  }
27561
28931
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: MMPanel, deps: [], target: i0.ɵɵFactoryTarget.Component });
27562
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.15", type: MMPanel, isStandalone: true, selector: "mapag-mm-panel", inputs: { map: { classPropertyName: "map", publicName: "map", isSignal: true, isRequired: false, transformFunction: null }, settings: { classPropertyName: "settings", publicName: "settings", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { onRemove: "onRemove" }, viewQueries: [{ propertyName: "customizeDialog", first: true, predicate: ["customizeDialog"], descendants: true, isSignal: true }], ngImport: i0, template: `
28932
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.15", type: MMPanel, isStandalone: true, selector: "mapag-mm-panel", inputs: { map: { classPropertyName: "map", publicName: "map", isSignal: true, isRequired: false, transformFunction: null }, settings: { classPropertyName: "settings", publicName: "settings", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { onRemove: "onRemove" }, viewQueries: [{ propertyName: "customizeDialog", first: true, predicate: ["customizeDialog"], descendants: true, isSignal: true }, { propertyName: "dataDialog", first: true, predicate: ["dataDialog"], descendants: true, isSignal: true }], ngImport: i0, template: `
27563
28933
  <hub-data-layer [visible]="mapper.settings().visible" [name]="mapper.settings().name"
27564
28934
  [desc]="mapper.settings().description || 'MarketMaker Business'" shape="point" (onCheck)="setVisible($event)" (onCustomize)="toggleDialog()">
27565
28935
 
@@ -27700,7 +29070,7 @@ class MMPanel {
27700
29070
  </div>
27701
29071
  <div class="dlg-buttons">
27702
29072
  <button class="btn" (click)="toggleLegend()">Legend</button>
27703
- <!-- <button class="btn" (click)="dataDialog.toggle()">Data</button> -->
29073
+ <button class="btn" (click)="toggleData()">Data</button>
27704
29074
  <button class="btn" (click)="remove()">Remove</button>
27705
29075
  <button class="btn" (click)="reset()">Reset</button>
27706
29076
  <button class="btn" (click)="toggleShowHide()">
@@ -27711,6 +29081,21 @@ class MMPanel {
27711
29081
  </div>
27712
29082
  </dialog>
27713
29083
 
29084
+ <dialog draggable mapagBringToFront onBody #dataDialog class="data-dialog">
29085
+ <h2>{{mapper.settings().name}}</h2>
29086
+ <div class="dlg-body dlg-body-list ">
29087
+ {{ mapper.data().length }} records matching current filters.
29088
+
29089
+ <cdk-virtual-scroll-viewport [itemSize]="40">
29090
+ <div *cdkVirtualFor="let feature of mapper.data()" (click)="onTileClick(feature)"
29091
+ class="data-tile" [innerHTML]="popupRenderer.RenderPopupSync(feature) | safeHtml"></div>
29092
+ </cdk-virtual-scroll-viewport>
29093
+ </div>
29094
+ <div class="dlg-buttons">
29095
+ <button class="btn" (click)="toggleData()">Close</button>
29096
+ </div>
29097
+ </dialog>
29098
+
27714
29099
  <!-- <ng-template #dataTemplate let-feature>
27715
29100
  <div [innerHTML]="mapper.popupRenderer?.RenderPopup(feature) | async"></div>
27716
29101
  </ng-template>
@@ -27721,11 +29106,12 @@ class MMPanel {
27721
29106
  [contentTemplate]="dataTemplate"
27722
29107
  (onSelect)="onSelect($event)">
27723
29108
  </mapag-tile-dialog> -->
27724
- `, isInline: true, styles: ["dialog{font-size:14pt;width:100%;max-width:700px;border:none;border-radius:8px;box-shadow:0 2px 10px #0003;padding:16px;position:fixed;top:50%;left:50%;transform:translate(-50%,-50%);margin:0;flex-direction:column}dialog:open{display:flex}dialog .dlg-body{flex-grow:1;overflow-y:auto}dialog.legend{width:fit-content}dialog.legend h2{font-size:smaller}dialog select{max-width:90vw}dialog h2{color:#000}dialog h2:before{content:\"\\22ee\\22ee \";padding-right:4px}dialog h3{color:#000;border-bottom:2px solid gray;font-weight:500;font-size:.9em;margin-top:16px;margin-bottom:8px}dialog h4{color:#000;font-weight:500;margin-bottom:8px;margin-top:12px;font-size:.85em;border:none}dialog p{font-size:.8em}dialog a{text-decoration:none;color:#0a3773;font-weight:500;font-size:.8em;padding-left:4px}dialog a:hover{text-decoration:underline;cursor:pointer}dialog a:before{content:\"\\1f517\";padding-right:2px}.ctrl-group{display:flex;flex-direction:column}.ctrl-row{display:grid;grid-template-columns:auto 1fr auto 1fr;align-items:center;gap:4px;justify-items:start;padding-left:20px}.ctrl-first{grid-column:1}.ctrl-row label{font-size:.8em;margin:0;padding:0;font-weight:400}.ctrl.wide{grid-column:span 3}input[type=range]{grid-column:span 3;justify-self:stretch}input[type=color]{width:40px;height:24px;border-radius:4px;cursor:pointer}input[type=number]{width:6ch;font-size:.8em}.dlg-buttons{display:flex;justify-content:flex-end;gap:8px;margin-top:16px}button{background-color:#0a3773;color:#fff;border:none;border-radius:4px;padding:8px 16px;cursor:pointer;font-size:.8em}button:hover{background-color:#083a5c}summary{font-size:1em;font-weight:600;color:#000;cursor:pointer;padding:8px 0;border-bottom:2px solid gray;list-style:none;-webkit-user-select:none;user-select:none;margin-bottom:8px}summary::-webkit-details-marker{display:none}summary:before{content:\"\\304f\";display:inline-block;margin-right:8px;transform:rotate(180deg);transition:transform .2s}details[open] summary:before{transform:rotate(270deg)}.radio-tabs{margin-bottom:12px;font-size:.8em;display:flex;flex-direction:row}.radio-tabs label{display:grid;grid-template-columns:auto 1fr;gap:4px;grid-template-rows:30px;align-items:center}.radio-tabs input[type=radio]{display:none}.radio-tabs label{padding:8px 12px;border:2px solid transparent;border-radius:6px;cursor:pointer;transition:all .2s ease}.radio-tabs label:has(input[type=radio]:checked){background-color:#fff;border-color:#333}.mgr-btn{justify-self:center;background-color:transparent;color:#4c4c4c;text-align:center;width:100%;font-weight:600;cursor:pointer;display:flex;align-items:center;justify-content:center;margin:4px 0;padding:6px;gap:4px;border:1px solid rgb(218,218,218)}.mgr-btn:hover{background-color:transparent;border-color:#4c4c4c}.legend-row{display:grid;grid-template-columns:auto 1fr;gap:8px;padding:4px 0;align-items:center}.legend-title{font-weight:700;text-align:center;margin-bottom:8px}.legend-item{height:15px;width:15px;border:1px solid #ccc}.maplibregl-popup-close-button{top:13px;right:15px}@media screen and (max-width: 600px){dialog{width:100vw;max-width:100vw;height:100dvh;max-height:100dvh;border-radius:0;border:none;box-shadow:none;overflow:hidden}.dlg-buttons{flex-direction:row;flex-wrap:wrap;align-items:center;justify-content:center}dialog h2:before{content:\"\";padding-right:0}}::deep .ng-select-container,::deep .ng-select{font-size:.8em}.filter-row{display:flex;flex-direction:column;margin-bottom:8px;font-size:.8em}.filter-row-cols{display:block;column-count:2}.zone{display:flex;align-items:center;gap:8px;margin:0;padding:0}.zones{display:grid;grid-template-columns:1fr 1fr;column-gap:24px;row-gap:8px;overflow-y:auto;max-height:420px;font-size:.8em}.svgicon{height:30px;width:30px;-webkit-mask-size:contain;mask-size:contain}h4,label{display:flex;align-items:center;gap:4px}@media (max-width: 600px){.zones{grid-template-columns:1fr}}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1$1.RangeValueAccessor, selector: "input[type=range][formControlName],input[type=range][formControl],input[type=range][ngModel]" }, { kind: "directive", type: i1$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: HubDataLayer, selector: "hub-data-layer", inputs: ["visible", "name", "desc", "icon", "shape"], outputs: ["onCustomize", "onCheck"] }, { kind: "directive", type: DraggableDialogDirective, selector: "dialog[draggable]" }, { kind: "component", type: FaIconComponent, selector: "fa-icon", inputs: ["icon", "title", "animation", "mask", "flip", "size", "pull", "border", "inverse", "symbol", "rotate", "fixedWidth", "transform", "a11yRole"], outputs: ["iconChange", "titleChange", "animationChange", "maskChange", "flipChange", "sizeChange", "pullChange", "borderChange", "inverseChange", "symbolChange", "rotateChange", "fixedWidthChange", "transformChange", "a11yRoleChange"] }, { kind: "directive", type: BringToFrontDirective, selector: "[mapagBringToFront]" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
29109
+ `, isInline: true, styles: ["dialog{font-size:14pt;width:100%;max-width:700px;border:none;border-radius:8px;box-shadow:0 2px 10px #0003;padding:16px;position:fixed;top:50%;left:50%;transform:translate(-50%,-50%);margin:0;flex-direction:column}dialog:open{display:flex}dialog .dlg-body{flex-grow:1;overflow-y:auto}dialog.legend{width:fit-content}dialog.legend h2{font-size:smaller}dialog select{max-width:90vw}dialog h2{color:#000}dialog h2:before{content:\"\\22ee\\22ee \";padding-right:4px}dialog h3{color:#000;border-bottom:2px solid gray;font-weight:500;font-size:.9em;margin-top:16px;margin-bottom:8px}dialog h4{color:#000;font-weight:500;margin-bottom:8px;margin-top:12px;font-size:.85em;border:none}dialog p{font-size:.8em}dialog a{text-decoration:none;color:#0a3773;font-weight:500;font-size:.8em;padding-left:4px}dialog a:hover{text-decoration:underline;cursor:pointer}dialog a:before{content:\"\\1f517\";padding-right:2px}.ctrl-group{display:flex;flex-direction:column}.ctrl-row{display:grid;grid-template-columns:auto 1fr auto 1fr;align-items:center;gap:4px;justify-items:start;padding-left:20px}.ctrl-first{grid-column:1}.ctrl-row label{font-size:.8em;margin:0;padding:0;font-weight:400}.ctrl.wide{grid-column:span 3}input[type=range]{grid-column:span 3;justify-self:stretch}input[type=color]{width:40px;height:24px;border-radius:4px;cursor:pointer}input[type=number]{width:6ch;font-size:.8em}.dlg-buttons{display:flex;justify-content:flex-end;gap:8px;margin-top:16px}button{background-color:#0a3773;color:#fff;border:none;border-radius:4px;padding:8px 16px;cursor:pointer;font-size:.8em}button:hover{background-color:#083a5c}summary{font-size:1em;font-weight:600;color:#000;cursor:pointer;padding:8px 0;border-bottom:2px solid gray;list-style:none;-webkit-user-select:none;user-select:none;margin-bottom:8px}summary::-webkit-details-marker{display:none}summary:before{content:\"\\304f\";display:inline-block;margin-right:8px;transform:rotate(180deg);transition:transform .2s}details[open] summary:before{transform:rotate(270deg)}.radio-tabs{margin-bottom:12px;font-size:.8em;display:flex;flex-direction:row}.radio-tabs label{display:grid;grid-template-columns:auto 1fr;gap:4px;grid-template-rows:30px;align-items:center}.radio-tabs input[type=radio]{display:none}.radio-tabs label{padding:8px 12px;border:2px solid transparent;border-radius:6px;cursor:pointer;transition:all .2s ease}.radio-tabs label:has(input[type=radio]:checked){background-color:#fff;border-color:#333}.mgr-btn{justify-self:center;background-color:transparent;color:#4c4c4c;text-align:center;width:100%;font-weight:600;cursor:pointer;display:flex;align-items:center;justify-content:center;margin:4px 0;padding:6px;gap:4px;border:1px solid rgb(218,218,218)}.mgr-btn:hover{background-color:transparent;border-color:#4c4c4c}.legend-row{display:grid;grid-template-columns:auto 1fr;gap:8px;padding:4px 0;align-items:center}.legend-title{font-weight:700;text-align:center;margin-bottom:8px}.legend-item{height:15px;width:15px;border:1px solid #ccc}.maplibregl-popup-close-button{top:13px;right:15px}@media screen and (max-width: 600px){dialog{width:100vw;max-width:100vw;height:100dvh;max-height:100dvh;border-radius:0;border:none;box-shadow:none;overflow:hidden}.dlg-buttons{flex-direction:row;flex-wrap:wrap;align-items:center;justify-content:center}dialog h2:before{content:\"\";padding-right:0}}::deep .ng-select-container,::deep .ng-select{font-size:.8em}.filter-row{display:flex;flex-direction:column;margin-bottom:8px;font-size:.8em}.filter-row-cols{display:block;column-count:2}.zone{display:flex;align-items:center;gap:8px;margin:0;padding:0}.zones{display:grid;grid-template-columns:1fr 1fr;column-gap:24px;row-gap:8px;overflow-y:auto;max-height:420px;font-size:.8em}.svgicon{height:30px;width:30px;-webkit-mask-size:contain;mask-size:contain}h4,label{display:flex;align-items:center;gap:4px}.dlg-body-list{display:grid;grid-template-rows:auto 1fr;row-gap:12px}.data-dialog{width:auto;max-width:min(450px,100vw);height:90dvh}.data-tile{padding:6px;border:1px solid #ccc;margin:4px;font-size:10pt;box-shadow:0 2px 4px #0000001a;cursor:pointer}.data-tile:hover{background-color:#f0f0f0}.data-tile:last-child{border-bottom:none}.tile-title{font-weight:600;color:#222}.tile-sub{color:#555;font-size:.85em}@media (max-width: 600px){.zones{grid-template-columns:1fr}}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1$1.RangeValueAccessor, selector: "input[type=range][formControlName],input[type=range][formControl],input[type=range][ngModel]" }, { kind: "directive", type: i1$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: HubDataLayer, selector: "hub-data-layer", inputs: ["visible", "name", "desc", "icon", "shape"], outputs: ["onCustomize", "onCheck"] }, { kind: "directive", type: DraggableDialogDirective, selector: "dialog[draggable]" }, { kind: "component", type: FaIconComponent, selector: "fa-icon", inputs: ["icon", "title", "animation", "mask", "flip", "size", "pull", "border", "inverse", "symbol", "rotate", "fixedWidth", "transform", "a11yRole"], outputs: ["iconChange", "titleChange", "animationChange", "maskChange", "flipChange", "sizeChange", "pullChange", "borderChange", "inverseChange", "symbolChange", "rotateChange", "fixedWidthChange", "transformChange", "a11yRoleChange"] }, { kind: "directive", type: BringToFrontDirective, selector: "[mapagBringToFront]" }, { kind: "component", type: CdkVirtualScrollViewport, selector: "cdk-virtual-scroll-viewport", inputs: ["orientation", "appendOnly"], outputs: ["scrolledIndexChange"] }, { kind: "directive", type: CdkVirtualForOf, selector: "[cdkVirtualFor][cdkVirtualForOf]", inputs: ["cdkVirtualForOf", "cdkVirtualForTrackBy", "cdkVirtualForTemplate", "cdkVirtualForTemplateCacheSize"] }, { kind: "directive", type: CdkFixedSizeVirtualScroll, selector: "cdk-virtual-scroll-viewport[itemSize]", inputs: ["itemSize", "minBufferPx", "maxBufferPx"] }, { kind: "pipe", type: SafeHtmlPipe, name: "safeHtml" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
27725
29110
  }
27726
29111
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: MMPanel, decorators: [{
27727
29112
  type: Component,
27728
- args: [{ selector: 'mapag-mm-panel', changeDetection: ChangeDetectionStrategy.OnPush, imports: [CommonModule, FormsModule, HubDataLayer, DraggableDialogDirective, FaIconComponent, BringToFrontDirective, TileDialog], template: `
29113
+ args: [{ selector: 'mapag-mm-panel', changeDetection: ChangeDetectionStrategy.OnPush, imports: [CommonModule, FormsModule, HubDataLayer, DraggableDialogDirective, FaIconComponent,
29114
+ BringToFrontDirective, CdkVirtualScrollViewport, CdkVirtualForOf, CdkFixedSizeVirtualScroll, SafeHtmlPipe], template: `
27729
29115
  <hub-data-layer [visible]="mapper.settings().visible" [name]="mapper.settings().name"
27730
29116
  [desc]="mapper.settings().description || 'MarketMaker Business'" shape="point" (onCheck)="setVisible($event)" (onCustomize)="toggleDialog()">
27731
29117
 
@@ -27866,7 +29252,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImpo
27866
29252
  </div>
27867
29253
  <div class="dlg-buttons">
27868
29254
  <button class="btn" (click)="toggleLegend()">Legend</button>
27869
- <!-- <button class="btn" (click)="dataDialog.toggle()">Data</button> -->
29255
+ <button class="btn" (click)="toggleData()">Data</button>
27870
29256
  <button class="btn" (click)="remove()">Remove</button>
27871
29257
  <button class="btn" (click)="reset()">Reset</button>
27872
29258
  <button class="btn" (click)="toggleShowHide()">
@@ -27877,6 +29263,21 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImpo
27877
29263
  </div>
27878
29264
  </dialog>
27879
29265
 
29266
+ <dialog draggable mapagBringToFront onBody #dataDialog class="data-dialog">
29267
+ <h2>{{mapper.settings().name}}</h2>
29268
+ <div class="dlg-body dlg-body-list ">
29269
+ {{ mapper.data().length }} records matching current filters.
29270
+
29271
+ <cdk-virtual-scroll-viewport [itemSize]="40">
29272
+ <div *cdkVirtualFor="let feature of mapper.data()" (click)="onTileClick(feature)"
29273
+ class="data-tile" [innerHTML]="popupRenderer.RenderPopupSync(feature) | safeHtml"></div>
29274
+ </cdk-virtual-scroll-viewport>
29275
+ </div>
29276
+ <div class="dlg-buttons">
29277
+ <button class="btn" (click)="toggleData()">Close</button>
29278
+ </div>
29279
+ </dialog>
29280
+
27880
29281
  <!-- <ng-template #dataTemplate let-feature>
27881
29282
  <div [innerHTML]="mapper.popupRenderer?.RenderPopup(feature) | async"></div>
27882
29283
  </ng-template>
@@ -27887,13 +29288,13 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImpo
27887
29288
  [contentTemplate]="dataTemplate"
27888
29289
  (onSelect)="onSelect($event)">
27889
29290
  </mapag-tile-dialog> -->
27890
- `, styles: ["dialog{font-size:14pt;width:100%;max-width:700px;border:none;border-radius:8px;box-shadow:0 2px 10px #0003;padding:16px;position:fixed;top:50%;left:50%;transform:translate(-50%,-50%);margin:0;flex-direction:column}dialog:open{display:flex}dialog .dlg-body{flex-grow:1;overflow-y:auto}dialog.legend{width:fit-content}dialog.legend h2{font-size:smaller}dialog select{max-width:90vw}dialog h2{color:#000}dialog h2:before{content:\"\\22ee\\22ee \";padding-right:4px}dialog h3{color:#000;border-bottom:2px solid gray;font-weight:500;font-size:.9em;margin-top:16px;margin-bottom:8px}dialog h4{color:#000;font-weight:500;margin-bottom:8px;margin-top:12px;font-size:.85em;border:none}dialog p{font-size:.8em}dialog a{text-decoration:none;color:#0a3773;font-weight:500;font-size:.8em;padding-left:4px}dialog a:hover{text-decoration:underline;cursor:pointer}dialog a:before{content:\"\\1f517\";padding-right:2px}.ctrl-group{display:flex;flex-direction:column}.ctrl-row{display:grid;grid-template-columns:auto 1fr auto 1fr;align-items:center;gap:4px;justify-items:start;padding-left:20px}.ctrl-first{grid-column:1}.ctrl-row label{font-size:.8em;margin:0;padding:0;font-weight:400}.ctrl.wide{grid-column:span 3}input[type=range]{grid-column:span 3;justify-self:stretch}input[type=color]{width:40px;height:24px;border-radius:4px;cursor:pointer}input[type=number]{width:6ch;font-size:.8em}.dlg-buttons{display:flex;justify-content:flex-end;gap:8px;margin-top:16px}button{background-color:#0a3773;color:#fff;border:none;border-radius:4px;padding:8px 16px;cursor:pointer;font-size:.8em}button:hover{background-color:#083a5c}summary{font-size:1em;font-weight:600;color:#000;cursor:pointer;padding:8px 0;border-bottom:2px solid gray;list-style:none;-webkit-user-select:none;user-select:none;margin-bottom:8px}summary::-webkit-details-marker{display:none}summary:before{content:\"\\304f\";display:inline-block;margin-right:8px;transform:rotate(180deg);transition:transform .2s}details[open] summary:before{transform:rotate(270deg)}.radio-tabs{margin-bottom:12px;font-size:.8em;display:flex;flex-direction:row}.radio-tabs label{display:grid;grid-template-columns:auto 1fr;gap:4px;grid-template-rows:30px;align-items:center}.radio-tabs input[type=radio]{display:none}.radio-tabs label{padding:8px 12px;border:2px solid transparent;border-radius:6px;cursor:pointer;transition:all .2s ease}.radio-tabs label:has(input[type=radio]:checked){background-color:#fff;border-color:#333}.mgr-btn{justify-self:center;background-color:transparent;color:#4c4c4c;text-align:center;width:100%;font-weight:600;cursor:pointer;display:flex;align-items:center;justify-content:center;margin:4px 0;padding:6px;gap:4px;border:1px solid rgb(218,218,218)}.mgr-btn:hover{background-color:transparent;border-color:#4c4c4c}.legend-row{display:grid;grid-template-columns:auto 1fr;gap:8px;padding:4px 0;align-items:center}.legend-title{font-weight:700;text-align:center;margin-bottom:8px}.legend-item{height:15px;width:15px;border:1px solid #ccc}.maplibregl-popup-close-button{top:13px;right:15px}@media screen and (max-width: 600px){dialog{width:100vw;max-width:100vw;height:100dvh;max-height:100dvh;border-radius:0;border:none;box-shadow:none;overflow:hidden}.dlg-buttons{flex-direction:row;flex-wrap:wrap;align-items:center;justify-content:center}dialog h2:before{content:\"\";padding-right:0}}::deep .ng-select-container,::deep .ng-select{font-size:.8em}.filter-row{display:flex;flex-direction:column;margin-bottom:8px;font-size:.8em}.filter-row-cols{display:block;column-count:2}.zone{display:flex;align-items:center;gap:8px;margin:0;padding:0}.zones{display:grid;grid-template-columns:1fr 1fr;column-gap:24px;row-gap:8px;overflow-y:auto;max-height:420px;font-size:.8em}.svgicon{height:30px;width:30px;-webkit-mask-size:contain;mask-size:contain}h4,label{display:flex;align-items:center;gap:4px}@media (max-width: 600px){.zones{grid-template-columns:1fr}}\n"] }]
27891
- }], ctorParameters: () => [], propDecorators: { map: [{ type: i0.Input, args: [{ isSignal: true, alias: "map", required: false }] }], settings: [{ type: i0.Input, args: [{ isSignal: true, alias: "settings", required: false }] }], customizeDialog: [{ type: i0.ViewChild, args: ['customizeDialog', { isSignal: true }] }], onRemove: [{ type: i0.Output, args: ["onRemove"] }] } });
29291
+ `, styles: ["dialog{font-size:14pt;width:100%;max-width:700px;border:none;border-radius:8px;box-shadow:0 2px 10px #0003;padding:16px;position:fixed;top:50%;left:50%;transform:translate(-50%,-50%);margin:0;flex-direction:column}dialog:open{display:flex}dialog .dlg-body{flex-grow:1;overflow-y:auto}dialog.legend{width:fit-content}dialog.legend h2{font-size:smaller}dialog select{max-width:90vw}dialog h2{color:#000}dialog h2:before{content:\"\\22ee\\22ee \";padding-right:4px}dialog h3{color:#000;border-bottom:2px solid gray;font-weight:500;font-size:.9em;margin-top:16px;margin-bottom:8px}dialog h4{color:#000;font-weight:500;margin-bottom:8px;margin-top:12px;font-size:.85em;border:none}dialog p{font-size:.8em}dialog a{text-decoration:none;color:#0a3773;font-weight:500;font-size:.8em;padding-left:4px}dialog a:hover{text-decoration:underline;cursor:pointer}dialog a:before{content:\"\\1f517\";padding-right:2px}.ctrl-group{display:flex;flex-direction:column}.ctrl-row{display:grid;grid-template-columns:auto 1fr auto 1fr;align-items:center;gap:4px;justify-items:start;padding-left:20px}.ctrl-first{grid-column:1}.ctrl-row label{font-size:.8em;margin:0;padding:0;font-weight:400}.ctrl.wide{grid-column:span 3}input[type=range]{grid-column:span 3;justify-self:stretch}input[type=color]{width:40px;height:24px;border-radius:4px;cursor:pointer}input[type=number]{width:6ch;font-size:.8em}.dlg-buttons{display:flex;justify-content:flex-end;gap:8px;margin-top:16px}button{background-color:#0a3773;color:#fff;border:none;border-radius:4px;padding:8px 16px;cursor:pointer;font-size:.8em}button:hover{background-color:#083a5c}summary{font-size:1em;font-weight:600;color:#000;cursor:pointer;padding:8px 0;border-bottom:2px solid gray;list-style:none;-webkit-user-select:none;user-select:none;margin-bottom:8px}summary::-webkit-details-marker{display:none}summary:before{content:\"\\304f\";display:inline-block;margin-right:8px;transform:rotate(180deg);transition:transform .2s}details[open] summary:before{transform:rotate(270deg)}.radio-tabs{margin-bottom:12px;font-size:.8em;display:flex;flex-direction:row}.radio-tabs label{display:grid;grid-template-columns:auto 1fr;gap:4px;grid-template-rows:30px;align-items:center}.radio-tabs input[type=radio]{display:none}.radio-tabs label{padding:8px 12px;border:2px solid transparent;border-radius:6px;cursor:pointer;transition:all .2s ease}.radio-tabs label:has(input[type=radio]:checked){background-color:#fff;border-color:#333}.mgr-btn{justify-self:center;background-color:transparent;color:#4c4c4c;text-align:center;width:100%;font-weight:600;cursor:pointer;display:flex;align-items:center;justify-content:center;margin:4px 0;padding:6px;gap:4px;border:1px solid rgb(218,218,218)}.mgr-btn:hover{background-color:transparent;border-color:#4c4c4c}.legend-row{display:grid;grid-template-columns:auto 1fr;gap:8px;padding:4px 0;align-items:center}.legend-title{font-weight:700;text-align:center;margin-bottom:8px}.legend-item{height:15px;width:15px;border:1px solid #ccc}.maplibregl-popup-close-button{top:13px;right:15px}@media screen and (max-width: 600px){dialog{width:100vw;max-width:100vw;height:100dvh;max-height:100dvh;border-radius:0;border:none;box-shadow:none;overflow:hidden}.dlg-buttons{flex-direction:row;flex-wrap:wrap;align-items:center;justify-content:center}dialog h2:before{content:\"\";padding-right:0}}::deep .ng-select-container,::deep .ng-select{font-size:.8em}.filter-row{display:flex;flex-direction:column;margin-bottom:8px;font-size:.8em}.filter-row-cols{display:block;column-count:2}.zone{display:flex;align-items:center;gap:8px;margin:0;padding:0}.zones{display:grid;grid-template-columns:1fr 1fr;column-gap:24px;row-gap:8px;overflow-y:auto;max-height:420px;font-size:.8em}.svgicon{height:30px;width:30px;-webkit-mask-size:contain;mask-size:contain}h4,label{display:flex;align-items:center;gap:4px}.dlg-body-list{display:grid;grid-template-rows:auto 1fr;row-gap:12px}.data-dialog{width:auto;max-width:min(450px,100vw);height:90dvh}.data-tile{padding:6px;border:1px solid #ccc;margin:4px;font-size:10pt;box-shadow:0 2px 4px #0000001a;cursor:pointer}.data-tile:hover{background-color:#f0f0f0}.data-tile:last-child{border-bottom:none}.tile-title{font-weight:600;color:#222}.tile-sub{color:#555;font-size:.85em}@media (max-width: 600px){.zones{grid-template-columns:1fr}}\n"] }]
29292
+ }], ctorParameters: () => [], propDecorators: { map: [{ type: i0.Input, args: [{ isSignal: true, alias: "map", required: false }] }], settings: [{ type: i0.Input, args: [{ isSignal: true, alias: "settings", required: false }] }], customizeDialog: [{ type: i0.ViewChild, args: ['customizeDialog', { isSignal: true }] }], dataDialog: [{ type: i0.ViewChild, args: ['dataDialog', { isSignal: true }] }], onRemove: [{ type: i0.Output, args: ["onRemove"] }] } });
27892
29293
  class MarketMakerPopupRenderer {
27893
- RenderPopup(feature) {
29294
+ RenderPopupSync(feature) {
27894
29295
  const props = feature.properties;
27895
29296
  if (!props) {
27896
- return Promise.resolve(undefined);
29297
+ return undefined;
27897
29298
  }
27898
29299
  let html = `<div>`;
27899
29300
  html += `<h3>${props.Name || 'MarketMaker Business'}</h3>`;
@@ -27925,7 +29326,10 @@ class MarketMakerPopupRenderer {
27925
29326
  onclick="window.open('https://foodmarketmaker.com/business/${props.ID}', '_blank')">Learn More...</button>
27926
29327
  `;
27927
29328
  html += `</div>`;
27928
- return Promise.resolve(html);
29329
+ return html;
29330
+ }
29331
+ RenderPopup(feature) {
29332
+ return this.RenderPopupSync(feature);
27929
29333
  }
27930
29334
  getArrayProperty(value) {
27931
29335
  const arr = this.parseArrayProperty(value) || [];
@@ -28304,7 +29708,7 @@ class HubNaicsPanel {
28304
29708
  {{ mapper.data().length }} records matching current filters.
28305
29709
  <cdk-virtual-scroll-viewport [itemSize]="10">
28306
29710
  <div *cdkVirtualFor="let feature of mapper.data()" (click)="mapper.flyToFeature(feature)"
28307
- class="data-tile" [innerHTML]="mapper.renderPopup(feature)">
29711
+ class="data-tile" [innerHTML]="mapper.renderInfo(feature)">
28308
29712
  </div>
28309
29713
 
28310
29714
  </cdk-virtual-scroll-viewport>
@@ -28504,7 +29908,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImpo
28504
29908
  {{ mapper.data().length }} records matching current filters.
28505
29909
  <cdk-virtual-scroll-viewport [itemSize]="10">
28506
29910
  <div *cdkVirtualFor="let feature of mapper.data()" (click)="mapper.flyToFeature(feature)"
28507
- class="data-tile" [innerHTML]="mapper.renderPopup(feature)">
29911
+ class="data-tile" [innerHTML]="mapper.renderInfo(feature)">
28508
29912
  </div>
28509
29913
 
28510
29914
  </cdk-virtual-scroll-viewport>
@@ -28808,85 +30212,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImpo
28808
30212
  `, styles: ["dialog{font-size:14pt;width:100%;max-width:700px;border:none;border-radius:8px;box-shadow:0 2px 10px #0003;padding:16px;position:fixed;top:50%;left:50%;transform:translate(-50%,-50%);margin:0;flex-direction:column}dialog:open{display:flex}dialog .dlg-body{flex-grow:1;overflow-y:auto}dialog.legend{width:fit-content}dialog.legend h2{font-size:smaller}dialog select{max-width:90vw}dialog h2{color:#000}dialog h2:before{content:\"\\22ee\\22ee \";padding-right:4px}dialog h3{color:#000;border-bottom:2px solid gray;font-weight:500;font-size:.9em;margin-top:16px;margin-bottom:8px}dialog h4{color:#000;font-weight:500;margin-bottom:8px;margin-top:12px;font-size:.85em;border:none}dialog p{font-size:.8em}dialog a{text-decoration:none;color:#0a3773;font-weight:500;font-size:.8em;padding-left:4px}dialog a:hover{text-decoration:underline;cursor:pointer}dialog a:before{content:\"\\1f517\";padding-right:2px}.ctrl-group{display:flex;flex-direction:column}.ctrl-row{display:grid;grid-template-columns:auto 1fr auto 1fr;align-items:center;gap:4px;justify-items:start;padding-left:20px}.ctrl-first{grid-column:1}.ctrl-row label{font-size:.8em;margin:0;padding:0;font-weight:400}.ctrl.wide{grid-column:span 3}input[type=range]{grid-column:span 3;justify-self:stretch}input[type=color]{width:40px;height:24px;border-radius:4px;cursor:pointer}input[type=number]{width:6ch;font-size:.8em}.dlg-buttons{display:flex;justify-content:flex-end;gap:8px;margin-top:16px}button{background-color:#0a3773;color:#fff;border:none;border-radius:4px;padding:8px 16px;cursor:pointer;font-size:.8em}button:hover{background-color:#083a5c}summary{font-size:1em;font-weight:600;color:#000;cursor:pointer;padding:8px 0;border-bottom:2px solid gray;list-style:none;-webkit-user-select:none;user-select:none;margin-bottom:8px}summary::-webkit-details-marker{display:none}summary:before{content:\"\\304f\";display:inline-block;margin-right:8px;transform:rotate(180deg);transition:transform .2s}details[open] summary:before{transform:rotate(270deg)}.radio-tabs{margin-bottom:12px;font-size:.8em;display:flex;flex-direction:row}.radio-tabs label{display:grid;grid-template-columns:auto 1fr;gap:4px;grid-template-rows:30px;align-items:center}.radio-tabs input[type=radio]{display:none}.radio-tabs label{padding:8px 12px;border:2px solid transparent;border-radius:6px;cursor:pointer;transition:all .2s ease}.radio-tabs label:has(input[type=radio]:checked){background-color:#fff;border-color:#333}.mgr-btn{justify-self:center;background-color:transparent;color:#4c4c4c;text-align:center;width:100%;font-weight:600;cursor:pointer;display:flex;align-items:center;justify-content:center;margin:4px 0;padding:6px;gap:4px;border:1px solid rgb(218,218,218)}.mgr-btn:hover{background-color:transparent;border-color:#4c4c4c}.legend-row{display:grid;grid-template-columns:auto 1fr;gap:8px;padding:4px 0;align-items:center}.legend-title{font-weight:700;text-align:center;margin-bottom:8px}.legend-item{height:15px;width:15px;border:1px solid #ccc}.maplibregl-popup-close-button{top:13px;right:15px}@media screen and (max-width: 600px){dialog{width:100vw;max-width:100vw;height:100dvh;max-height:100dvh;border-radius:0;border:none;box-shadow:none;overflow:hidden}.dlg-buttons{flex-direction:row;flex-wrap:wrap;align-items:center;justify-content:center}dialog h2:before{content:\"\";padding-right:0}}.search{display:flex;gap:4px;align-items:center;margin-bottom:8px;font-size:.8em}.search input[type=radio]{display:none}.search label{display:flex;align-items:center;gap:4px;padding:2px 4px;border:1px solid transparent;cursor:pointer}.search label:has(input[type=radio]:checked){border:1px solid #333;border-radius:4px;background-color:#f0f0f0}dialog h4{display:flex;justify-content:space-between;align-items:center;margin-bottom:4px;margin-top:4px}.ctrl-row{grid-template-columns:1fr;font-size:.8em}.zones{max-height:400px;height:400px;overflow-y:auto;margin-top:0}input[type=search]{width:100%;font-size:1em;padding:4px 8px;border-radius:4px;border:1px solid #ccc}label{display:flex;align-items:center;gap:4px}.svgicon{height:20px;width:20px;-webkit-mask-size:contain;mask-size:contain}.tiles{display:grid;grid-template-columns:repeat(auto-fit,115px);gap:8px;margin-top:8px;text-align:center;align-items:start}.tiles label{display:grid;grid-template-columns:1fr;grid-template-rows:auto 1fr;align-items:start;justify-items:center;height:100%;padding:2px;border:1px solid transparent;cursor:pointer}.tiles label:hover{background-color:#f0f0f0;border:1px solid #999;border-radius:4px}.tiles label:has(input[type=checkbox]:checked){border:1px solid #333;border-radius:4px}.tiles .svgicon{height:50px;width:50px;margin-bottom:4px}.tiles input[type=checkbox]{display:none}@media (max-width: 600px){.dlg-body{display:flex;flex-direction:column}.zones{max-height:unset;flex-grow:1}}\n"] }]
28809
30213
  }], ctorParameters: () => [], propDecorators: { canAdd: [{ type: i0.Input, args: [{ isSignal: true, alias: "canAdd", required: false }] }], map: [{ type: i0.Input, args: [{ isSignal: true, alias: "map", required: false }] }], codes: [{ type: i0.Input, args: [{ isSignal: true, alias: "codes", required: false }] }], current: [{ type: i0.Input, args: [{ isSignal: true, alias: "current", required: false }] }], currentChange: [{ type: i0.Output, args: ["currentChange"] }], customizeDialog: [{ type: i0.ViewChild, args: ['customizeDialog', { isSignal: true }] }], legendDialog: [{ type: i0.ViewChild, args: ['legendDialog', { isSignal: true }] }] } });
28810
30214
 
28811
- class GradientLegend {
28812
- topStyle = signal({}, ...(ngDevMode ? [{ debugName: "topStyle" }] : []));
28813
- bottomStyle = signal({}, ...(ngDevMode ? [{ debugName: "bottomStyle" }] : []));
28814
- gradientStyle = signal({}, ...(ngDevMode ? [{ debugName: "gradientStyle" }] : []));
28815
- settings = input(new GradientSettings(), ...(ngDevMode ? [{ debugName: "settings" }] : []));
28816
- renderer = inject(Renderer2);
28817
- host = inject((ElementRef));
28818
- constructor() {
28819
- const onUpdateSettings = effect(() => {
28820
- const settings = this.settings();
28821
- this.topStyle.set({
28822
- background: settings.minTop ? settings.minColor : settings.maxColor,
28823
- value: settings.minValue
28824
- });
28825
- this.bottomStyle.set({
28826
- background: settings.minTop ? settings.maxColor : settings.minColor,
28827
- value: settings.maxValue
28828
- });
28829
- this.gradientStyle.set({
28830
- background: `linear-gradient(${settings.dir === 'horizontal' ? 'to right' : 'to top'}, ${settings.minColor}, ${settings.maxColor})`,
28831
- height: settings.dir === 'horizontal' ? '30px' : '100%',
28832
- width: settings.dir === 'horizontal' ? '100%' : '30px'
28833
- });
28834
- }, ...(ngDevMode ? [{ debugName: "onUpdateSettings" }] : []));
28835
- }
28836
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: GradientLegend, deps: [], target: i0.ɵɵFactoryTarget.Component });
28837
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "20.3.15", type: GradientLegend, isStandalone: true, selector: "mapag-gradient-legend", inputs: { settings: { classPropertyName: "settings", publicName: "settings", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: `
28838
- <div class="top" [ngStyle]="topStyle()"></div>
28839
- <div>{{settings().unitPrefix}}{{ settings().maxValue | number:"1.0-2" }}{{settings().unitSuffix}}</div>
28840
- <div class="gradient" [ngStyle]="gradientStyle()"></div>
28841
- <div></div>
28842
- <div class="bottom" [ngStyle]="bottomStyle()"></div>
28843
- <div>{{settings().unitPrefix}}{{ settings().minValue | number:"1.0-2" }}{{settings().unitSuffix}}</div>
28844
- `, isInline: true, styles: [":host{display:grid;grid-template-rows:auto 1fr auto;grid-template-columns:auto max-content;align-items:center;font-size:.8em;height:var(--legend-height, 150px);column-gap:4px}.h2{margin-bottom:8px}.top,.bottom{height:50%}.top{background:var(--top-color, green);align-self:end}.bottom{background:var(--bottom-color, black);align-self:start}.gradient{width:20px;flex-grow:1;height:100%;align-self:center;justify-self:center}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "ngmodule", type: FormsModule }, { kind: "pipe", type: i1.DecimalPipe, name: "number" }] });
28845
- }
28846
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: GradientLegend, decorators: [{
28847
- type: Component,
28848
- args: [{ selector: 'mapag-gradient-legend', imports: [CommonModule, FormsModule], template: `
28849
- <div class="top" [ngStyle]="topStyle()"></div>
28850
- <div>{{settings().unitPrefix}}{{ settings().maxValue | number:"1.0-2" }}{{settings().unitSuffix}}</div>
28851
- <div class="gradient" [ngStyle]="gradientStyle()"></div>
28852
- <div></div>
28853
- <div class="bottom" [ngStyle]="bottomStyle()"></div>
28854
- <div>{{settings().unitPrefix}}{{ settings().minValue | number:"1.0-2" }}{{settings().unitSuffix}}</div>
28855
- `, styles: [":host{display:grid;grid-template-rows:auto 1fr auto;grid-template-columns:auto max-content;align-items:center;font-size:.8em;height:var(--legend-height, 150px);column-gap:4px}.h2{margin-bottom:8px}.top,.bottom{height:50%}.top{background:var(--top-color, green);align-self:end}.bottom{background:var(--bottom-color, black);align-self:start}.gradient{width:20px;flex-grow:1;height:100%;align-self:center;justify-self:center}\n"] }]
28856
- }], ctorParameters: () => [], propDecorators: { settings: [{ type: i0.Input, args: [{ isSignal: true, alias: "settings", required: false }] }] } });
28857
- class GradientSettings {
28858
- minColor = "#000000";
28859
- maxColor = "#FFFFFF";
28860
- minValue = 0.0;
28861
- maxValue = 1.0;
28862
- height = "100px";
28863
- width = "30px";
28864
- minTop = false;
28865
- dir = 'vertical';
28866
- unitPrefix = '';
28867
- unitSuffix = '';
28868
- }
28869
-
28870
- class TextPipe {
28871
- transform(value, ...args) {
28872
- if (value === null || value === undefined) {
28873
- return '';
28874
- }
28875
- if (typeof value === 'string') {
28876
- return fixText(value);
28877
- }
28878
- return value;
28879
- }
28880
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: TextPipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe });
28881
- static ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "20.3.15", ngImport: i0, type: TextPipe, isStandalone: true, name: "text" });
28882
- }
28883
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: TextPipe, decorators: [{
28884
- type: Pipe,
28885
- args: [{
28886
- name: 'text'
28887
- }]
28888
- }] });
28889
-
28890
30215
  class NassPanel {
28891
30216
  map = input(...(ngDevMode ? [undefined, { debugName: "map" }] : []));
28892
30217
  mapper = new NAASMapper();
@@ -30935,13 +32260,13 @@ class SettingsPanel {
30935
32260
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: SettingsPanel, deps: [], target: i0.ɵɵFactoryTarget.Component });
30936
32261
  static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.15", type: SettingsPanel, isStandalone: true, selector: "app-settings-panel", ngImport: i0, template: `
30937
32262
  <ng-content></ng-content>
30938
- `, isInline: true, styles: [":host{position:fixed;padding:16px;border:1px solid #ccc;border-radius:8px;background-color:#efe9e1;right:16px;top:16px;bottom:16px;width:300px;box-shadow:0 2px 8px #0000001a;overflow-y:auto}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
32263
+ `, isInline: true, styles: [":host{position:fixed;padding:16px;border:1px solid #ccc;border-radius:8px;background-color:#efe9e1;right:16px;top:16px;bottom:16px;width:320px;box-shadow:0 2px 8px #0000001a;overflow-y:auto}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
30939
32264
  }
30940
32265
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: SettingsPanel, decorators: [{
30941
32266
  type: Component,
30942
32267
  args: [{ selector: 'app-settings-panel', changeDetection: ChangeDetectionStrategy.OnPush, imports: [], template: `
30943
32268
  <ng-content></ng-content>
30944
- `, styles: [":host{position:fixed;padding:16px;border:1px solid #ccc;border-radius:8px;background-color:#efe9e1;right:16px;top:16px;bottom:16px;width:300px;box-shadow:0 2px 8px #0000001a;overflow-y:auto}\n"] }]
32269
+ `, styles: [":host{position:fixed;padding:16px;border:1px solid #ccc;border-radius:8px;background-color:#efe9e1;right:16px;top:16px;bottom:16px;width:320px;box-shadow:0 2px 8px #0000001a;overflow-y:auto}\n"] }]
30945
32270
  }] });
30946
32271
 
30947
32272
  /*
@@ -30953,5 +32278,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImpo
30953
32278
  * Generated bundle index. Do not edit.
30954
32279
  */
30955
32280
 
30956
- export { AddLayer, AddSource, AreaIcon, AreaMapperMapper, BackgroundMaskMapper, BackgroundMaskSettings, BaseMapLight, BasemapSelect, BasemapSelectMenu, BringToFrontDirective, BringToFrontService, CensusTractMapper, Codes, CropSequenceMapper, CropSequenceSettings, CroplandDataLayerMapper, CroplandDataLayerSettings, CroplandLegend, DEFAULT_GLYPHS, DEFAULT_GLYPHS2, DEFAULT_PIN_URL, DataSetFieldValue, DirectoryIndexPToTable, DirectoryIndexToTable, DraggableDialogDirective, DrawPolygon, DrawSquare, DrawingMapper, EsriMapper, EsriSettings, ExpandArrows, FilterPanel, FipsFromDataSet, FoodHubPanel, FoodhubMapper, FoodhubMapperSettings, HardinessMapper, HardinessSettings, HttpBoundaryLoader, HubCropSequencePanel, HubCroplandPanel, HubDataLayer, HubHardinessPanel, HubNaicsPanel, HubRailroadPanel, HubWatershedPanel, Icons, LineIcon, MMPanel, MapAreaSelectComponent, MapComponent, MapSelectionService, MapService, MapStyles, MapagDetails, MapboxMapperGroup, MarketMakerPopupRenderer, NAASMapper, NAASSettings, NASSInfo, NaicsEmployeesOptions, NaicsMapper, NaicsMapperSettings, NaicsMgrPanel, NaicsSalesOptions, NassIndex, NassInfoFromIndex, NassInfoFromIndexP, NassInfoFromPath, NassMgrPanel, NassPanel, NassService, NoOpMapper, PaletteDisplay, PaletteSelect, PointDataMapper, PointDataMapperSettings, PrintPanel, RailroadSettings, RailroadUsageSettings, RailroadsMapper, RasterIcon, ReferenceDataService, RemoveLayer, RemoveSource, SaveMap, SelectMode, SettingsPanel, SimpleMapper, SourceLoadWatcher, StandardLayersMapper, StateCountySelectComponent, Styles, TableBuilder, TableRow, VectorTileServerMapper, WatershedMapper, WatershedSettings, WelcomePanel, discoverLayers, fixText, isGeoloader, isMultiPolygon, isNumber2DArray, isNumber3DArray, isPolygon, mapboxImageName, mapboxLoadImages, mapboxloadImage, normalize, normalizeArray, pmtilesPixelInfo, prefixMatch, propertiesToTableHtml, randomColor, sampleTilesForLayers, simpleClone, toMultiPolygon, trySync };
32281
+ export { AddLayer, AddSource, AreaIcon, AreaMapperMapper, BackgroundMaskMapper, BackgroundMaskSettings, BaseMapLight, BasemapSelect, BasemapSelectMenu, BringToFrontDirective, BringToFrontService, CensusTractMapper, Codes, ConsumerSpendingPanel, ConsumerSpendingSelectPanel, CropSequenceMapper, CropSequenceSettings, CroplandDataLayerMapper, CroplandDataLayerSettings, CroplandLegend, DEFAULT_GLYPHS, DEFAULT_GLYPHS2, DEFAULT_PIN_URL, DataSetFieldValue$1 as DataSetFieldValue, DirectoryIndexPToTable, DirectoryIndexToTable, DraggableDialogDirective, DrawPolygon, DrawSquare, DrawingMapper, EsriMapper, EsriSettings, ExpandArrows, FilterPanel, FipsFromDataSet$1 as FipsFromDataSet, FoodHubPanel, FoodhubMapper, FoodhubMapperSettings, HardinessMapper, HardinessSettings, HttpBoundaryLoader, HubCropSequencePanel, HubCroplandPanel, HubDataLayer, HubHardinessPanel, HubNaicsPanel, HubRailroadPanel, HubWatershedPanel, Icons, LineIcon, MMPanel, MapAreaSelectComponent, MapComponent, MapSelectionService, MapService, MapStyles, MapagDetails, MapboxMapperGroup, MarketMakerPopupRenderer, NAASMapper, NAASSettings, NASSInfo, NaicsEmployeesOptions, NaicsMapper, NaicsMapperSettings, NaicsMgrPanel, NaicsSalesOptions, NassIndex, NassInfoFromIndex, NassInfoFromIndexP, NassInfoFromPath, NassMgrPanel, NassPanel, NassService, NoOpMapper, PaletteDisplay, PaletteSelect, PointDataMapper, PointDataMapperSettings, PrintPanel, RailroadSettings, RailroadUsageSettings, RailroadsMapper, RasterIcon, ReferenceDataService, RemoveLayer, RemoveSource, SaveMap, SelectMode, SettingsPanel, SimpleMapper, SourceLoadWatcher, StandardLayersMapper, StateCountySelectComponent, Styles, TableBuilder, TableRow, ToggleDialog, VectorTileServerMapper, WatershedMapper, WatershedSettings, WelcomePanel, discoverLayers, fixText, flyToFeature, isGeoloader, isMultiPolygon, isNumber2DArray, isNumber3DArray, isPolygon, mapboxImageName, mapboxLoadImages, mapboxloadImage, normalize, normalizeArray, pmtilesPixelInfo, prefixMatch, propertiesToTableHtml, randomColor, sampleTilesForLayers, simpleClone, toMultiPolygon, trySync };
30957
32282
  //# sourceMappingURL=foodmarketmaker-mapag.mjs.map