@foodmarketmaker/mapag 0.0.46 → 0.0.48

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,7 +7,7 @@ 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';
@@ -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;
@@ -21357,8 +21384,8 @@ class NAASMapper {
21357
21384
  return ds.name;
21358
21385
  }
21359
21386
  if (ds) {
21360
- const commodity = DataSetFieldValue(ds, -1, "COMMODITY_DESC") || 'UNKNOWN';
21361
- const year = DataSetFieldValue(ds, -1, "YEAR");
21387
+ const commodity = DataSetFieldValue$1(ds, -1, "COMMODITY_DESC") || 'UNKNOWN';
21388
+ const year = DataSetFieldValue$1(ds, -1, "YEAR");
21362
21389
  if (year) {
21363
21390
  return `${commodity} (${year})`;
21364
21391
  }
@@ -21378,8 +21405,8 @@ class NAASMapper {
21378
21405
  return ds.name;
21379
21406
  }
21380
21407
  if (ds) {
21381
- const commodity = DataSetFieldValue(ds, -1, "PRODN_PRACTICE_DESC") || '';
21382
- const units = DataSetFieldValue(ds, -1, "UNIT_DESC") || '';
21408
+ const commodity = DataSetFieldValue$1(ds, -1, "PRODN_PRACTICE_DESC") || '';
21409
+ const units = DataSetFieldValue$1(ds, -1, "UNIT_DESC") || '';
21383
21410
  return `${commodity} (${units})`;
21384
21411
  }
21385
21412
  return 'NASS Data';
@@ -21418,7 +21445,7 @@ class NAASMapper {
21418
21445
  if (!row || !row.cells) {
21419
21446
  continue;
21420
21447
  }
21421
- const fips = FipsFromDataSet(dataSet, i);
21448
+ const fips = FipsFromDataSet$1(dataSet, i);
21422
21449
  if (!fips || fips.endsWith("998") || fips.endsWith("999")) {
21423
21450
  // Skip invalid or unknown FIPS
21424
21451
  continue;
@@ -21707,17 +21734,17 @@ class NAASMapper {
21707
21734
  return Promise.resolve(undefined);
21708
21735
  }
21709
21736
  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") || "");
21737
+ tab.add("Source", DataSetFieldValue$1(ds, nState.row, "SOURCE_DESC") || "");
21738
+ tab.add("Sector", DataSetFieldValue$1(ds, nState.row, "SECTOR_DESC") || "");
21739
+ tab.add("Group", DataSetFieldValue$1(ds, nState.row, "GROUP_DESC") || "");
21740
+ tab.add("Commodity", DataSetFieldValue$1(ds, nState.row, "COMMODITY_DESC") || "");
21741
+ tab.add("Production", DataSetFieldValue$1(ds, nState.row, "PRODN_PRACTICE_DESC") || "");
21742
+ tab.add("Utilization", DataSetFieldValue$1(ds, nState.row, "UTIL_PRACTICE_DESC") || "");
21743
+ tab.add("Statistic", DataSetFieldValue$1(ds, nState.row, "STATISTICCAT_DESC") || "");
21744
+ tab.add("Unit", DataSetFieldValue$1(ds, nState.row, "UNIT_DESC") || "");
21745
+ tab.add("State", DataSetFieldValue$1(ds, nState.row, "STATE_ABBR") || "");
21746
+ tab.add("County", DataSetFieldValue$1(ds, nState.row, "COUNTY_CODE") || "");
21747
+ tab.add("Year", DataSetFieldValue$1(ds, nState.row, "YEAR") || "");
21721
21748
  tab.add("Value", nState?.value);
21722
21749
  tab.add("RAW Value", nState?.raw);
21723
21750
  tab.add("MIN Value", nState?.min || "");
@@ -21725,12 +21752,12 @@ class NAASMapper {
21725
21752
  return Promise.resolve(tab.toHtml());
21726
21753
  }
21727
21754
  }
21728
- function FipsFromDataSet(ds, rowIndex) {
21755
+ function FipsFromDataSet$1(ds, rowIndex) {
21729
21756
  if (!ds.schema || !ds.schema.fields) {
21730
21757
  return null;
21731
21758
  }
21732
- const state = DataSetFieldValue(ds, rowIndex, "STATE_FIPS_CODE");
21733
- const county = DataSetFieldValue(ds, rowIndex, "COUNTY_CODE");
21759
+ const state = DataSetFieldValue$1(ds, rowIndex, "STATE_FIPS_CODE");
21760
+ const county = DataSetFieldValue$1(ds, rowIndex, "COUNTY_CODE");
21734
21761
  if (county) {
21735
21762
  return county;
21736
21763
  }
@@ -21739,7 +21766,7 @@ function FipsFromDataSet(ds, rowIndex) {
21739
21766
  }
21740
21767
  return null;
21741
21768
  }
21742
- function DataSetFieldValue(ds, rowIndex, field) {
21769
+ function DataSetFieldValue$1(ds, rowIndex, field) {
21743
21770
  if (!ds.schema || !ds.data) {
21744
21771
  return null;
21745
21772
  }
@@ -23845,6 +23872,7 @@ class PointDataMapperSettings {
23845
23872
  filterState;
23846
23873
  filterStates = [];
23847
23874
  showLegend = false;
23875
+ 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
23876
  }
23849
23877
  class PointDataMapper {
23850
23878
  static CLUSTERS = [
@@ -23885,6 +23913,7 @@ class PointDataMapper {
23885
23913
  itemsFC;
23886
23914
  popupRenderer;
23887
23915
  id;
23916
+ watcher = new SourceLoadWatcher();
23888
23917
  POINT_LAYER_ID;
23889
23918
  HEAT_LAYER_ID;
23890
23919
  ICON_LAYER_ID;
@@ -23897,6 +23926,7 @@ class PointDataMapper {
23897
23926
  return settings.source;
23898
23927
  }, ...(ngDevMode ? [{ debugName: "geoJsonUrl" }] : []));
23899
23928
  geoJsonResource = httpResource(() => this.geoJsonUrl() || undefined);
23929
+ dataCnt = 0;
23900
23930
  constructor(popupRenderer, settings) {
23901
23931
  this.id = 'points-' + Math.random().toString(36).substring(2, 15);
23902
23932
  this.popupRenderer = popupRenderer;
@@ -23933,32 +23963,42 @@ class PointDataMapper {
23933
23963
  }, ...(ngDevMode ? [{ debugName: "_updateGlobal" }] : []));
23934
23964
  }
23935
23965
  data = computed(() => {
23936
- // Check if data is still loading or has an error
23966
+ this.dataCnt++;
23967
+ this.watcher.updated(); // depend on source data changes
23937
23968
  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()) {
23969
+ console.log('Data computed for', this.id, 'count', this.dataCnt);
23970
+ if (!this.map) {
23947
23971
  return [];
23948
23972
  }
23949
- const svc = this.svc();
23950
- if (!svc) {
23951
- return [];
23973
+ const map = this.map;
23974
+ const filter = this.getFilter(settings);
23975
+ if (settings.externalLoad) {
23976
+ // Check if data is still loading or has an error
23977
+ if (this.geoJsonResource.isLoading()) {
23978
+ return [];
23979
+ }
23980
+ if (this.geoJsonResource.error()) {
23981
+ console.error('Failed to load GeoJSON:', this.geoJsonResource.error());
23982
+ return [];
23983
+ }
23984
+ // Check if we have loaded data
23985
+ if (!this.geoJsonResource.hasValue()) {
23986
+ return [];
23987
+ }
23988
+ const geoJsonData = this.geoJsonResource.value();
23989
+ const features = geoJsonData?.features || [];
23990
+ if (!features || features.length === 0) {
23991
+ return [];
23992
+ }
23993
+ const filtered = Filter(features, filter);
23994
+ return filtered || [];
23952
23995
  }
23953
- svc.stateCountyFilter(); // depend
23954
- const geoJsonData = this.geoJsonResource.value();
23955
- const features = geoJsonData?.features || [];
23956
- if (!features || features.length === 0) {
23957
- return [];
23996
+ else {
23997
+ const features = map.querySourceFeatures(this.id, {
23998
+ filter: filter ? filter : undefined,
23999
+ });
24000
+ return features || [];
23958
24001
  }
23959
- const filter = this.getFilter(settings);
23960
- const filtered = Filter(features, filter);
23961
- return filtered || [];
23962
24002
  }, ...(ngDevMode ? [{ debugName: "data" }] : []));
23963
24003
  update(settings) {
23964
24004
  this.settings.set({ ...this.settings(), ...settings });
@@ -24039,7 +24079,7 @@ class PointDataMapper {
24039
24079
  getFilter(settings) {
24040
24080
  // Build filter conditions for each field
24041
24081
  const conditions = ['all'];
24042
- const fipsFilter = this.getFipsFilter();
24082
+ const fipsFilter = this.getFipsFilter(settings);
24043
24083
  if (fipsFilter && fipsFilter.length > 0) {
24044
24084
  const filter = [
24045
24085
  'any',
@@ -24068,6 +24108,7 @@ class PointDataMapper {
24068
24108
  }
24069
24109
  onReady(map, svc) {
24070
24110
  this.map = map;
24111
+ this.watcher.on(map, this.id);
24071
24112
  this.svc.set(svc);
24072
24113
  this.loadSource();
24073
24114
  }
@@ -24126,8 +24167,7 @@ class PointDataMapper {
24126
24167
  currentSource.setData(sourceURL);
24127
24168
  }
24128
24169
  }
24129
- getFipsFilter() {
24130
- const settings = this.settings();
24170
+ getFipsFilter(settings) {
24131
24171
  if (settings.filterOverrideGlobal) {
24132
24172
  if (settings.filterStates && settings.filterStates.length > 0) {
24133
24173
  return settings.filterStates;
@@ -25637,101 +25677,1561 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImpo
25637
25677
  ` }]
25638
25678
  }] });
25639
25679
 
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 });
25647
- }
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"] }] });
25680
+ function ConsumerSpendingFromPath(path) {
25681
+ const parts = path.split('/');
25682
+ if (parts.length < 3) {
25683
+ throw new Error('Invalid path format');
25684
+ }
25685
+ const year = parts[0];
25686
+ const measure = parts[1];
25687
+ const valueType = parts[2];
25688
+ // A = Avgerage Spending, T = Total Spending, I = Index
25689
+ // Year/Measure/(A|T|I)
25690
+ return { measure, year, valueType };
25655
25691
  }
25656
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: ShowHideBtn, decorators: [{
25657
- 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 }] }] } });
25665
25692
 
25666
- class HubCropSequencePanel {
25667
- DefaultName = 'cropsequence';
25668
- faFill = faFill;
25669
- faPaintBrush = faPaintBrush;
25670
- faText = faFill;
25671
- map = input(...(ngDevMode ? [undefined, { debugName: "map" }] : []));
25672
- mapper = new CropSequenceMapper({ visible: false });
25673
- customizeDialog = viewChild('customizeDialog', ...(ngDevMode ? [{ debugName: "customizeDialog" }] : []));
25674
- constructor() {
25675
- const _mapInit = effect(() => {
25676
- const mapComp = this.map();
25677
- if (mapComp) {
25678
- mapComp.mapper().set('cropSequence', this.mapper);
25693
+ /**
25694
+ * The DataSetMapper is responsible for making a Choropleth Map with
25695
+ * a single DataSet dataset.
25696
+ */
25697
+ class DataSetMapper {
25698
+ http = inject(HttpClient);
25699
+ ID = Math.random().toString(36).substring(2, 15);
25700
+ LAYER_ID = 'naas-layer-fill-' + this.ID;
25701
+ SOURCE_ID = 'naas-source-' + this.ID;
25702
+ settings = signal(new DataSetSettings(), ...(ngDevMode ? [{ debugName: "settings" }] : []));
25703
+ current = null;
25704
+ currentFeatureID = undefined;
25705
+ over = signal(null, ...(ngDevMode ? [{ debugName: "over" }] : []));
25706
+ map = undefined;
25707
+ svc = signal(null, ...(ngDevMode ? [{ debugName: "svc" }] : []));
25708
+ legends;
25709
+ count = 0;
25710
+ total = 0;
25711
+ // Resource to download and parse the PBF file
25712
+ dataResource = rxResource({
25713
+ params: () => this.settings().path,
25714
+ stream: ({ params }) => {
25715
+ const url = `https://static.foodmarketmaker.com/${params}.pbf`;
25716
+ return this.http.get(url, { responseType: 'arraybuffer' }).pipe(map((buffer) => TabularDataSetP.decode(new Uint8Array(buffer))));
25717
+ }
25718
+ });
25719
+ info = computed(() => {
25720
+ const path = this.settings().path;
25721
+ return this.InfoFromPath(path);
25722
+ }, ...(ngDevMode ? [{ debugName: "info" }] : []));
25723
+ name = computed(() => {
25724
+ if (this.dataResource.isLoading()) {
25725
+ return 'DataSet Loading...';
25726
+ }
25727
+ if (this.dataResource.error()) {
25728
+ return 'DataSet Error...';
25729
+ }
25730
+ const ds = this.dataResource.value();
25731
+ if (ds?.name) {
25732
+ return ds.name;
25733
+ }
25734
+ if (ds) {
25735
+ return this.NameFrom(ds);
25736
+ }
25737
+ return 'Unknown';
25738
+ }, ...(ngDevMode ? [{ debugName: "name" }] : []));
25739
+ desc = computed(() => {
25740
+ if (this.dataResource.isLoading()) {
25741
+ return ' ';
25742
+ }
25743
+ if (this.dataResource.error()) {
25744
+ return ' ';
25745
+ }
25746
+ const ds = this.dataResource.value();
25747
+ if (ds?.description) {
25748
+ return ds.name;
25749
+ }
25750
+ if (ds) {
25751
+ const commodity = DataSetFieldValue(ds, -1, "PRODN_PRACTICE_DESC") || '';
25752
+ const units = DataSetFieldValue(ds, -1, "UNIT_DESC") || '';
25753
+ return `${commodity} (${units})`;
25754
+ }
25755
+ return 'NASS Data';
25756
+ }, ...(ngDevMode ? [{ debugName: "desc" }] : []));
25757
+ // Generate the availble feature states
25758
+ featureStates = computed(() => {
25759
+ const dataSet = this.dataResource.value();
25760
+ if (!dataSet) {
25761
+ return {
25762
+ states: [],
25763
+ min: 0,
25764
+ max: 1,
25765
+ };
25766
+ }
25767
+ const filters = this.svc()?.stateCountyFilter() || [];
25768
+ const fieldState = this.findFirstType(dataSet, TabularFieldUsage.TABULAR_USAGE_FIPS_STATE);
25769
+ const fieldCounty = this.findFirstType(dataSet, TabularFieldUsage.TABULAR_USAGE_FIPS_COUNTY);
25770
+ const fieldValue = this.findFirstType(dataSet, TabularFieldUsage.TABULAR_USAGE_VALUE);
25771
+ let maxV = Number.NEGATIVE_INFINITY;
25772
+ let minV = Number.POSITIVE_INFINITY;
25773
+ // Caclulate min/max if not provided and filter out the rows that are necessary
25774
+ const keep = [];
25775
+ for (let i = 0; i < (dataSet.data?.length || 0); i++) {
25776
+ const row = dataSet.data ? dataSet.data[i] : undefined;
25777
+ if (!row || !row.cells) {
25778
+ continue;
25779
+ }
25780
+ const fips = FipsFromDataSet(dataSet, i);
25781
+ if (!fips || fips.endsWith("998") || fips.endsWith("999")) {
25782
+ // Skip invalid or unknown FIPS
25783
+ continue;
25784
+ }
25785
+ let found = false;
25786
+ for (let f of filters) {
25787
+ if (fips.startsWith(f)) {
25788
+ // Match filter
25789
+ found = true;
25790
+ break;
25791
+ }
25792
+ }
25793
+ if (!found && filters.length > 0) {
25794
+ continue;
25795
+ }
25796
+ const value = row.cells[fieldValue?.index || 0].floatValue || NaN;
25797
+ if (!isNaN(value)) {
25798
+ maxV = Math.max(maxV, value);
25799
+ minV = Math.min(minV, value);
25800
+ keep.push(row);
25679
25801
  }
25680
- }, ...(ngDevMode ? [{ debugName: "_mapInit" }] : []));
25681
- }
25682
- setVisible(visible) {
25683
- this.mapper.update({ visible: visible });
25684
- }
25685
- toggleDialog() {
25686
- const dialog = this.customizeDialog();
25687
- if (!dialog) {
25688
- return;
25689
25802
  }
25690
- const dialogElement = dialog.nativeElement;
25691
- if (dialogElement.open) {
25692
- dialogElement.close();
25803
+ // handle edge case
25804
+ if (maxV === Number.NEGATIVE_INFINITY) {
25805
+ maxV = 1;
25693
25806
  }
25694
- else {
25695
- dialogElement.show();
25807
+ if (minV === Number.POSITIVE_INFINITY) {
25808
+ minV = 0;
25696
25809
  }
25697
- // Implement dialog toggle logic here
25698
- }
25699
- update(field, value) {
25700
- this.mapper.update({
25701
- [field]: value,
25702
- });
25703
- }
25704
- reset() {
25705
- this.mapper.update(new CropSequenceSettings());
25706
- }
25707
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: HubCropSequencePanel, deps: [], target: i0.ɵɵFactoryTarget.Component });
25708
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.2.0", version: "20.3.15", type: HubCropSequencePanel, isStandalone: true, selector: "hub-crop-sequence-panel", inputs: { map: { classPropertyName: "map", publicName: "map", isSignal: true, isRequired: false, transformFunction: null } }, viewQueries: [{ propertyName: "customizeDialog", first: true, predicate: ["customizeDialog"], descendants: true, isSignal: true }], ngImport: i0, template: `
25709
- <hub-data-layer
25710
- [visible]="mapper.settings().visible"
25711
- [name]="'USDA - NASS - Crop Sequences'"
25712
- [desc]="'Crop field boundary estimates, crop acreage, and crop rotations '"
25713
- shape="area"
25714
- (onCheck)="setVisible($event)"
25715
- (onCustomize)="toggleDialog()"
25716
- >
25717
- <area-icon></area-icon>
25718
- </hub-data-layer>
25719
- <dialog draggable mapagBringToFront onBody #customizeDialog>
25720
- <h2>USDA - NASS - Crop Sequence Boundaries</h2>
25721
-
25722
- <div class="dlg-body">
25723
- <img src="https://foodmarketmaker-upload-data.s3.us-west-2.amazonaws.com/assets/mapag/csbbanner2025.png" alt="Crop Sequence Boundaries Sample Image" style="max-width: 100%; height: auto; margin-bottom: 6px; border-radius: 6px;" />
25724
- <p>
25725
- The Crop Sequence Boundaries (CSB) developed with USDA's Economic Research Service, produces estimates of field boundaries, crop acreage, and crop rotations across the
25726
- contiguous United States. It uses satellite imagery with other public data and is open source allowing users to conduct area and statistical analysis of planted U.S.
25727
- commodities and provides insight on farmer cropping decisions. NASS needed a representative field to predict crop planting based on common crop rotations such as corn-soy
25728
- and ERS is using this product to study changes in farm management practices like tillage or cover cropping over time. CSB represents non-confidential single crop field
25729
- boundaries over a set time frame. It does not contain personal identifying information. The boundaries captured are of crops grown only, not ownership boundaries or tax
25730
- parcels (unit of property). The data are from satellite imagery and publicly available data, it does not come from producers or agencies like the Farm Service Agency.
25731
- </p>
25732
-
25733
- <h3>Customize Display Settings</h3>
25734
- <div class="zones">
25810
+ // Set the min max
25811
+ // Feature state is an object with id and value
25812
+ const states = [];
25813
+ for (let i = 0; i < keep.length; i++) {
25814
+ const row = keep[i];
25815
+ if (!row || !row.cells) {
25816
+ continue;
25817
+ }
25818
+ const state = row.cells[fieldState?.index || 0].stringValue;
25819
+ const county = row.cells[fieldCounty?.index || 0].stringValue;
25820
+ const value = row.cells[fieldValue?.index || 0].floatValue || 0.0;
25821
+ const normValue = normalize(value, minV, maxV);
25822
+ const fs = {
25823
+ id: county || state || "UNKNOWN",
25824
+ raw: value || 0.0,
25825
+ value: normValue,
25826
+ row: i,
25827
+ dataset: dataSet,
25828
+ state: state || '',
25829
+ max: maxV,
25830
+ min: minV,
25831
+ };
25832
+ states.push(fs);
25833
+ }
25834
+ return {
25835
+ states: states,
25836
+ min: minV,
25837
+ max: maxV,
25838
+ };
25839
+ }, ...(ngDevMode ? [{ debugName: "featureStates" }] : []));
25840
+ constructor(settings) {
25841
+ if (settings) {
25842
+ this.settings.update(current => ({
25843
+ ...current,
25844
+ ...settings,
25845
+ }));
25846
+ }
25847
+ const _ = effect(() => {
25848
+ const settings = this.settings();
25849
+ const dataset = this.dataResource.value();
25850
+ const features = this.featureStates();
25851
+ this._update(settings, dataset, features.states);
25852
+ }, ...(ngDevMode ? [{ debugName: "_" }] : []));
25853
+ const _updateGlobal = effect(() => {
25854
+ const svc = this.svc();
25855
+ if (!svc) {
25856
+ return;
25857
+ }
25858
+ const _ = svc.stateCountyFilter(); // depend
25859
+ this._update(this.settings(), this.dataResource.value(), this.featureStates().states);
25860
+ }, ...(ngDevMode ? [{ debugName: "_updateGlobal" }] : []));
25861
+ }
25862
+ update(settings) {
25863
+ this.settings.update(current => ({ ...current, ...settings }));
25864
+ }
25865
+ _update(settings, dataSet, featureStates) {
25866
+ if (!this.map) {
25867
+ return;
25868
+ }
25869
+ const map = this.map;
25870
+ this.create();
25871
+ this.setFeatureStates(this.settings(), featureStates);
25872
+ this.updateStyle(settings);
25873
+ }
25874
+ create() {
25875
+ if (!this.map) {
25876
+ return;
25877
+ }
25878
+ const map = this.map;
25879
+ const area = Layers.FindVector(this.settings().areaType);
25880
+ if (!area) {
25881
+ console.error('NAASMapper: Unknown area type ' + this.settings().areaType);
25882
+ return;
25883
+ }
25884
+ AddSource(this.map, this.SOURCE_ID, {
25885
+ type: area.SourceType || 'vector',
25886
+ tiles: [area.URL],
25887
+ promoteId: area.IDField || "GEOID", // promote field to be used as a foreign key
25888
+ });
25889
+ const addedFill = AddLayer(this.map, {
25890
+ id: this.LAYER_ID,
25891
+ type: 'fill',
25892
+ source: this.SOURCE_ID,
25893
+ 'source-layer': area.Source,
25894
+ paint: {
25895
+ 'fill-outline-color': '#e5541c',
25896
+ 'fill-opacity': this.settings().fillOpacity,
25897
+ 'fill-color': this.settings().fillColor,
25898
+ },
25899
+ layout: {
25900
+ visibility: 'none',
25901
+ },
25902
+ }, StandardLayersMapper.POLYGONS_BACKGROUND);
25903
+ map.off('click', this.LAYER_ID, this.onClick);
25904
+ map.on('click', this.LAYER_ID, this.onClick);
25905
+ }
25906
+ setFeatureStates(settings, fs) {
25907
+ if (!this.map) {
25908
+ return;
25909
+ }
25910
+ const map = this.map;
25911
+ const states = fs || [];
25912
+ const dataSet = this.dataResource.value();
25913
+ const src = Layers.FindVector(settings.areaType);
25914
+ if (!src) {
25915
+ console.error('NAASMapper: Unknown area type ' + settings.areaType);
25916
+ return;
25917
+ }
25918
+ // Remove all the previous feature states
25919
+ map.removeFeatureState({
25920
+ source: this.SOURCE_ID,
25921
+ sourceLayer: src.Source,
25922
+ });
25923
+ if (!dataSet || !fs) {
25924
+ return;
25925
+ }
25926
+ for (let state of states) {
25927
+ try {
25928
+ map.setFeatureState({
25929
+ source: this.SOURCE_ID,
25930
+ sourceLayer: src.Source,
25931
+ id: state.id,
25932
+ }, state);
25933
+ }
25934
+ catch (e) {
25935
+ console.warn('NAASMapper: Failed to set feature state for id ' + state.id, e);
25936
+ }
25937
+ }
25938
+ }
25939
+ getFipsFilter() {
25940
+ const settings = this.settings();
25941
+ if (settings.filterOverrideGlobal) {
25942
+ if (settings.filterStates && settings.filterStates.length > 0) {
25943
+ return settings.filterStates;
25944
+ }
25945
+ else if (settings.filterState) {
25946
+ return [settings.filterState];
25947
+ }
25948
+ }
25949
+ return this.svc()?.stateCountyFilter();
25950
+ }
25951
+ updateStyle(settings) {
25952
+ if (!this.map) {
25953
+ return;
25954
+ }
25955
+ const map = this.map;
25956
+ if (settings.visible) {
25957
+ map.setLayoutProperty(this.LAYER_ID, 'visibility', 'visible');
25958
+ }
25959
+ else {
25960
+ map.setLayoutProperty(this.LAYER_ID, 'visibility', 'none');
25961
+ }
25962
+ if (settings.fillType === 'palette') {
25963
+ this.map.setPaintProperty(this.LAYER_ID, 'fill-color', [
25964
+ 'interpolate',
25965
+ ['linear'],
25966
+ ['feature-state', 'value'],
25967
+ ...ColorPalettes.fromPalette(settings.fillPalette)
25968
+ ]);
25969
+ }
25970
+ else if (settings.fillType === 'gradient') {
25971
+ this.map.setPaintProperty(this.LAYER_ID, 'fill-color', fromGradient(settings.fillGradient, ['feature-state', 'value']));
25972
+ }
25973
+ else if (settings.fillType === 'solid') {
25974
+ this.map.setPaintProperty(this.LAYER_ID, 'fill-color', settings.fillColor);
25975
+ }
25976
+ const filterExpr = prefixMatch(["feature-state", "id"], this.getFipsFilter());
25977
+ if (filterExpr && filterExpr.length > 0) {
25978
+ const conditions = ['all'];
25979
+ conditions.push(['!=', ['feature-state', 'value'], null]),
25980
+ conditions.push(filterExpr);
25981
+ map.setPaintProperty(this.LAYER_ID, 'fill-opacity', [
25982
+ 'case',
25983
+ conditions,
25984
+ settings.fillOpacity,
25985
+ 0
25986
+ ]);
25987
+ }
25988
+ else {
25989
+ map.setPaintProperty(this.LAYER_ID, 'fill-opacity', [
25990
+ 'case',
25991
+ ['!=', ['feature-state', 'value'], null],
25992
+ settings.fillOpacity,
25993
+ 0
25994
+ ]);
25995
+ }
25996
+ map.setPaintProperty(this.LAYER_ID, 'fill-outline-color', settings.borderColor);
25997
+ }
25998
+ findFirstType(dataset, usage) {
25999
+ if (!dataset.schema) {
26000
+ return null;
26001
+ }
26002
+ if (!dataset.schema.fields) {
26003
+ return null;
26004
+ }
26005
+ for (let field of Object.keys(dataset.schema?.fields)) {
26006
+ const fieldDef = dataset.schema?.fields[field];
26007
+ if (fieldDef.usage == usage) {
26008
+ return fieldDef;
26009
+ }
26010
+ }
26011
+ return null;
26012
+ }
26013
+ onReady(map, svc) {
26014
+ this.map = map;
26015
+ this.svc.set(svc);
26016
+ this._update(this.settings(), this.dataResource.value(), this.featureStates().states);
26017
+ }
26018
+ reset() {
26019
+ this.clear();
26020
+ }
26021
+ clear() {
26022
+ if (this.map) {
26023
+ this.map.off('click', this.LAYER_ID, this.onClick);
26024
+ RemoveLayer(this.map, this.LAYER_ID);
26025
+ RemoveLayer(this.map, this.SOURCE_ID);
26026
+ }
26027
+ }
26028
+ onClick = async (e) => {
26029
+ if (!this.map) {
26030
+ return;
26031
+ }
26032
+ const settings = this.settings();
26033
+ const src = Layers.FindVector(settings.areaType);
26034
+ if (!src) {
26035
+ console.warn('ChoroplethMapper: No source found for area type ', settings.areaType);
26036
+ return;
26037
+ }
26038
+ const features = this.map.queryRenderedFeatures(e.point, {
26039
+ layers: [this.LAYER_ID],
26040
+ });
26041
+ if (features.length > 0) {
26042
+ e.preventDefault();
26043
+ if (this.current) {
26044
+ this.current.remove();
26045
+ this.current = null;
26046
+ }
26047
+ const f = features[0];
26048
+ const state = this.map.getFeatureState({
26049
+ source: this.SOURCE_ID,
26050
+ sourceLayer: src.Source,
26051
+ id: f.id
26052
+ });
26053
+ const html = await this.RenderPopup(f, state);
26054
+ if (html) {
26055
+ this.current = new Popup().setLngLat(e.lngLat).setHTML(html).addTo(this.map);
26056
+ }
26057
+ }
26058
+ };
26059
+ }
26060
+ function FipsFromDataSet(ds, rowIndex) {
26061
+ if (!ds.schema || !ds.schema.fields) {
26062
+ return null;
26063
+ }
26064
+ const state = DataSetFieldValue(ds, rowIndex, "STATE_FIPS_CODE");
26065
+ const county = DataSetFieldValue(ds, rowIndex, "COUNTY_CODE");
26066
+ if (county) {
26067
+ return county;
26068
+ }
26069
+ if (state) {
26070
+ return state;
26071
+ }
26072
+ return null;
26073
+ }
26074
+ function DataSetFieldValue(ds, rowIndex, field) {
26075
+ if (!ds.schema || !ds.data) {
26076
+ return null;
26077
+ }
26078
+ const fieldDef = ds.schema.fields ? ds.schema.fields[field] : null;
26079
+ if (!fieldDef) {
26080
+ return null;
26081
+ }
26082
+ if (fieldDef.staticvalue) {
26083
+ switch (fieldDef.datatype || 0) {
26084
+ case TabularDatatype.TABULAR_DATATYPE_STRING:
26085
+ return fieldDef.staticvalue.stringValue || null;
26086
+ case TabularDatatype.TABULAR_DATATYPE_FLOAT:
26087
+ return fieldDef.staticvalue.floatValue || null;
26088
+ case TabularDatatype.TABULAR_DATATYPE_INTEGER:
26089
+ return fieldDef.staticvalue.intValue || null;
26090
+ default:
26091
+ return null;
26092
+ }
26093
+ }
26094
+ if (rowIndex < 0) {
26095
+ return null;
26096
+ }
26097
+ const index = fieldDef.index || -1;
26098
+ if (index < 0 || rowIndex < 0 || rowIndex >= ds.data.length) {
26099
+ return null;
26100
+ }
26101
+ const row = ds.data[rowIndex];
26102
+ const cell = row.cells ? row.cells[index] : null;
26103
+ if (!cell) {
26104
+ return null;
26105
+ }
26106
+ switch (fieldDef.datatype || 0) {
26107
+ case TabularDatatype.TABULAR_DATATYPE_STRING:
26108
+ return cell.stringValue || null;
26109
+ case TabularDatatype.TABULAR_DATATYPE_FLOAT:
26110
+ return cell.floatValue || null;
26111
+ case TabularDatatype.TABULAR_DATATYPE_INTEGER:
26112
+ return cell.intValue || null;
26113
+ default:
26114
+ return null;
26115
+ }
26116
+ }
26117
+ class DataSetSettings {
26118
+ path = "";
26119
+ areaType = "county";
26120
+ visible = true;
26121
+ palette = allColors['Spectral']['10'];
26122
+ fillType = 'gradient';
26123
+ fillColor = '#e5541c';
26124
+ fillPalette = ColorPalettes.find('Spectral.10') || ColorPalettes.default();
26125
+ fillGradient = [{ "value": 0.0, "color": "#ffffcc" }, { "value": 1.0, "color": "#000000" }];
26126
+ fillOpacity = 1;
26127
+ filterState = '';
26128
+ filterStates = [];
26129
+ filterOverrideGlobal = false;
26130
+ borderColor = '#e5541c';
26131
+ labelsVisible = true;
26132
+ labelsSize = 10;
26133
+ labelsColor = '#000000';
26134
+ labelsHaloColor = '#ffffff';
26135
+ labelsHaloWidth = 1;
26136
+ labelsOpacity = 1.0;
26137
+ labelOverlap = false;
26138
+ showLegend = false;
26139
+ fipsExcludeSuffixes = ['999', '998', '000'];
26140
+ }
26141
+
26142
+ class ConsumerSpendingMapper extends DataSetMapper {
26143
+ RenderPopup(feature, state) {
26144
+ if (!state.dataset)
26145
+ return undefined;
26146
+ const data = state.dataset;
26147
+ const name = feature.properties?.['name'] || 'Unknown';
26148
+ const totalSpending = 0;
26149
+ const avgSpending = 0;
26150
+ return `
26151
+ <div>
26152
+ <h3>${name}</h3>
26153
+ <p>Total Spending: $${totalSpending.toLocaleString()}</p>
26154
+ <p>Average Spending: $${avgSpending.toLocaleString()}</p>
26155
+ </div>
26156
+ `;
26157
+ }
26158
+ InfoFromPath(path) {
26159
+ return ConsumerSpendingFromPath(path);
26160
+ }
26161
+ NameFrom(ds) {
26162
+ return ds.name || 'Unknown';
26163
+ }
26164
+ }
26165
+
26166
+ class DialogHeader {
26167
+ faTimes = faTimes;
26168
+ dialog = input(...(ngDevMode ? [undefined, { debugName: "dialog" }] : []));
26169
+ close() {
26170
+ // Close the dialog by finding the closest dialog element and calling its close method
26171
+ const d = this.dialog();
26172
+ if (d) {
26173
+ d.close();
26174
+ }
26175
+ }
26176
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: DialogHeader, deps: [], target: i0.ɵɵFactoryTarget.Component });
26177
+ 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: `
26178
+ <h2><ng-content></ng-content></h2>
26179
+ <button class="btn-icon" (click)="close()"><fa-icon [icon]="faTimes" size="lg"></fa-icon></button>
26180
+ `, 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"] }] });
26181
+ }
26182
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: DialogHeader, decorators: [{
26183
+ type: Component,
26184
+ args: [{ selector: 'mapag-dialog-header', imports: [CommonModule, FaIconComponent], template: `
26185
+ <h2><ng-content></ng-content></h2>
26186
+ <button class="btn-icon" (click)="close()"><fa-icon [icon]="faTimes" size="lg"></fa-icon></button>
26187
+ `, 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"] }]
26188
+ }], propDecorators: { dialog: [{ type: i0.Input, args: [{ isSignal: true, alias: "dialog", required: false }] }] } });
26189
+
26190
+ class GradientLegend {
26191
+ topStyle = signal({}, ...(ngDevMode ? [{ debugName: "topStyle" }] : []));
26192
+ bottomStyle = signal({}, ...(ngDevMode ? [{ debugName: "bottomStyle" }] : []));
26193
+ gradientStyle = signal({}, ...(ngDevMode ? [{ debugName: "gradientStyle" }] : []));
26194
+ settings = input(new GradientSettings(), ...(ngDevMode ? [{ debugName: "settings" }] : []));
26195
+ renderer = inject(Renderer2);
26196
+ host = inject((ElementRef));
26197
+ constructor() {
26198
+ const onUpdateSettings = effect(() => {
26199
+ const settings = this.settings();
26200
+ this.topStyle.set({
26201
+ background: settings.minTop ? settings.minColor : settings.maxColor,
26202
+ value: settings.minValue
26203
+ });
26204
+ this.bottomStyle.set({
26205
+ background: settings.minTop ? settings.maxColor : settings.minColor,
26206
+ value: settings.maxValue
26207
+ });
26208
+ this.gradientStyle.set({
26209
+ background: `linear-gradient(${settings.dir === 'horizontal' ? 'to right' : 'to top'}, ${settings.minColor}, ${settings.maxColor})`,
26210
+ height: settings.dir === 'horizontal' ? '30px' : '100%',
26211
+ width: settings.dir === 'horizontal' ? '100%' : '30px'
26212
+ });
26213
+ }, ...(ngDevMode ? [{ debugName: "onUpdateSettings" }] : []));
26214
+ }
26215
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: GradientLegend, deps: [], target: i0.ɵɵFactoryTarget.Component });
26216
+ 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: `
26217
+ <div class="top" [ngStyle]="topStyle()"></div>
26218
+ <div>{{settings().unitPrefix}}{{ settings().maxValue | number:"1.0-2" }}{{settings().unitSuffix}}</div>
26219
+ <div class="gradient" [ngStyle]="gradientStyle()"></div>
26220
+ <div></div>
26221
+ <div class="bottom" [ngStyle]="bottomStyle()"></div>
26222
+ <div>{{settings().unitPrefix}}{{ settings().minValue | number:"1.0-2" }}{{settings().unitSuffix}}</div>
26223
+ `, 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" }] });
26224
+ }
26225
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: GradientLegend, decorators: [{
26226
+ type: Component,
26227
+ args: [{ selector: 'mapag-gradient-legend', imports: [CommonModule, FormsModule], template: `
26228
+ <div class="top" [ngStyle]="topStyle()"></div>
26229
+ <div>{{settings().unitPrefix}}{{ settings().maxValue | number:"1.0-2" }}{{settings().unitSuffix}}</div>
26230
+ <div class="gradient" [ngStyle]="gradientStyle()"></div>
26231
+ <div></div>
26232
+ <div class="bottom" [ngStyle]="bottomStyle()"></div>
26233
+ <div>{{settings().unitPrefix}}{{ settings().minValue | number:"1.0-2" }}{{settings().unitSuffix}}</div>
26234
+ `, 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"] }]
26235
+ }], ctorParameters: () => [], propDecorators: { settings: [{ type: i0.Input, args: [{ isSignal: true, alias: "settings", required: false }] }] } });
26236
+ class GradientSettings {
26237
+ minColor = "#000000";
26238
+ maxColor = "#FFFFFF";
26239
+ minValue = 0.0;
26240
+ maxValue = 1.0;
26241
+ height = "100px";
26242
+ width = "30px";
26243
+ minTop = false;
26244
+ dir = 'vertical';
26245
+ unitPrefix = '';
26246
+ unitSuffix = '';
26247
+ }
26248
+
26249
+ class ShowHideBtn {
26250
+ faEye = faEye;
26251
+ faEyeSlash = faEyeSlash;
26252
+ mapper = input.required(...(ngDevMode ? [{ debugName: "mapper" }] : []));
26253
+ toggleShowHide() {
26254
+ const current = this.mapper().settings().visible;
26255
+ this.mapper().update({ visible: !current });
26256
+ }
26257
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: ShowHideBtn, deps: [], target: i0.ɵɵFactoryTarget.Component });
26258
+ 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: `
26259
+ <button class="btn" (click)="toggleShowHide()">
26260
+ <fa-icon [icon]="mapper().settings().visible ? faEyeSlash : faEye"></fa-icon>
26261
+ {{ mapper().settings().visible ? 'Hide' : 'Show' }}
26262
+ </button>
26263
+ `, 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"] }] });
26264
+ }
26265
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: ShowHideBtn, decorators: [{
26266
+ type: Component,
26267
+ args: [{ selector: 'mapag-show-hide-btn', imports: [CommonModule, FaIconComponent], template: `
26268
+ <button class="btn" (click)="toggleShowHide()">
26269
+ <fa-icon [icon]="mapper().settings().visible ? faEyeSlash : faEye"></fa-icon>
26270
+ {{ mapper().settings().visible ? 'Hide' : 'Show' }}
26271
+ </button>
26272
+ `, 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"] }]
26273
+ }], propDecorators: { mapper: [{ type: i0.Input, args: [{ isSignal: true, alias: "mapper", required: true }] }] } });
26274
+
26275
+ class StdLegend {
26276
+ items = input([], ...(ngDevMode ? [{ debugName: "items" }] : []));
26277
+ columns = input(1, ...(ngDevMode ? [{ debugName: "columns" }] : []));
26278
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: StdLegend, deps: [], target: i0.ɵɵFactoryTarget.Component });
26279
+ 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: `
26280
+ <div class="legend" [style.grid-template-columns]="'repeat(' + columns() + ',1fr)'">
26281
+ @for (item of items(); track item) {
26282
+ <div class="legend-row">
26283
+ <div class="legend-item" [style.background-color]="item.value" [ngStyle]="item.style"></div>
26284
+ <div>{{ item.label }}</div>
26285
+ </div>
26286
+ }
26287
+ </div>
26288
+ `, 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"] }] });
26289
+ }
26290
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: StdLegend, decorators: [{
26291
+ type: Component,
26292
+ args: [{ selector: 'mapag-std-legend', imports: [CommonModule], template: `
26293
+ <div class="legend" [style.grid-template-columns]="'repeat(' + columns() + ',1fr)'">
26294
+ @for (item of items(); track item) {
26295
+ <div class="legend-row">
26296
+ <div class="legend-item" [style.background-color]="item.value" [ngStyle]="item.style"></div>
26297
+ <div>{{ item.label }}</div>
26298
+ </div>
26299
+ }
26300
+ </div>
26301
+ `, 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"] }]
26302
+ }], propDecorators: { items: [{ type: i0.Input, args: [{ isSignal: true, alias: "items", required: false }] }], columns: [{ type: i0.Input, args: [{ isSignal: true, alias: "columns", required: false }] }] } });
26303
+
26304
+ class TextPipe {
26305
+ transform(value, ...args) {
26306
+ if (value === null || value === undefined) {
26307
+ return '';
26308
+ }
26309
+ if (typeof value === 'string') {
26310
+ return fixText(value);
26311
+ }
26312
+ return value;
26313
+ }
26314
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: TextPipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe });
26315
+ static ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "20.3.15", ngImport: i0, type: TextPipe, isStandalone: true, name: "text" });
26316
+ }
26317
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: TextPipe, decorators: [{
26318
+ type: Pipe,
26319
+ args: [{
26320
+ name: 'text'
26321
+ }]
26322
+ }] });
26323
+
26324
+ class ConsumerSpendingPanel {
26325
+ map = input(...(ngDevMode ? [undefined, { debugName: "map" }] : []));
26326
+ mapper = new ConsumerSpendingMapper();
26327
+ customizeDialog = viewChild('customizeDialog', ...(ngDevMode ? [{ debugName: "customizeDialog" }] : []));
26328
+ legendDialog = viewChild('legendDialog', ...(ngDevMode ? [{ debugName: "legendDialog" }] : []));
26329
+ onRemove = output();
26330
+ settings = input(new DataSetSettings(), ...(ngDevMode ? [{ debugName: "settings" }] : []));
26331
+ USStates = states;
26332
+ constructor() {
26333
+ const _mapInit = effect(() => {
26334
+ const mapComp = this.map();
26335
+ if (mapComp) {
26336
+ mapComp.mapper().set(this.mapper.ID, this.mapper);
26337
+ }
26338
+ }, ...(ngDevMode ? [{ debugName: "_mapInit" }] : []));
26339
+ const _item = effect(() => {
26340
+ const item = this.settings();
26341
+ untracked(() => this.mapper.update(item));
26342
+ }, ...(ngDevMode ? [{ debugName: "_item" }] : []));
26343
+ }
26344
+ setVisible(visible) {
26345
+ this.mapper.update({ visible: visible });
26346
+ }
26347
+ updateGradient(v1, v2) {
26348
+ const current = this.mapper.settings().fillGradient;
26349
+ if (v1) {
26350
+ current[0].color = v1;
26351
+ }
26352
+ if (v2) {
26353
+ current[1].color = v2;
26354
+ }
26355
+ this.mapper.update({
26356
+ fillGradient: current,
26357
+ });
26358
+ }
26359
+ paletteLegend = computed(() => {
26360
+ const info = this.mapper.info();
26361
+ const minmax = this.mapper.featureStates();
26362
+ const palette = this.mapper.settings().fillPalette;
26363
+ return ColorPalettes.ToLegend(palette, minmax.min || 0, minmax.max || 1, { unitSuffix: " " + fixText(info.Unit) });
26364
+ }, ...(ngDevMode ? [{ debugName: "paletteLegend" }] : []));
26365
+ gradientSettings = computed(() => {
26366
+ const info = this.mapper.info();
26367
+ const minmax = this.mapper.featureStates();
26368
+ return {
26369
+ minColor: this.mapper.settings().fillGradient[0].color,
26370
+ maxColor: this.mapper.settings().fillGradient[1].color,
26371
+ minValue: minmax.min || 0,
26372
+ maxValue: minmax.max || 1,
26373
+ dir: 'vertical',
26374
+ height: '150px',
26375
+ width: '30px',
26376
+ unitPrefix: " ",
26377
+ unitSuffix: " " + fixText(info.Unit)
26378
+ };
26379
+ }, ...(ngDevMode ? [{ debugName: "gradientSettings" }] : []));
26380
+ toggleDialog() {
26381
+ const dialog = this.customizeDialog();
26382
+ if (!dialog) {
26383
+ return;
26384
+ }
26385
+ const dialogElement = dialog.nativeElement;
26386
+ if (dialogElement.open) {
26387
+ dialogElement.close();
26388
+ }
26389
+ else {
26390
+ dialogElement.show();
26391
+ }
26392
+ // Implement dialog toggle logic here
26393
+ }
26394
+ toggleLegend() {
26395
+ const dialog = this.legendDialog();
26396
+ if (!dialog) {
26397
+ return;
26398
+ }
26399
+ const dialogElement = dialog.nativeElement;
26400
+ if (dialogElement.open) {
26401
+ dialogElement.close();
26402
+ }
26403
+ else {
26404
+ dialogElement.show();
26405
+ }
26406
+ // Implement dialog toggle logic here
26407
+ }
26408
+ update(field, value) {
26409
+ this.mapper.update({
26410
+ [field]: value,
26411
+ });
26412
+ }
26413
+ reset() {
26414
+ this.mapper.update(new DataSetSettings());
26415
+ }
26416
+ remove() {
26417
+ this.mapper.update({ visible: false });
26418
+ this.toggleDialog();
26419
+ this.onRemove.emit();
26420
+ }
26421
+ ngOnDestroy() {
26422
+ this.mapper.clear();
26423
+ }
26424
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: ConsumerSpendingPanel, deps: [], target: i0.ɵɵFactoryTarget.Component });
26425
+ 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: `
26426
+ <hub-data-layer
26427
+ [visible]="mapper.settings().visible"
26428
+ [name]="mapper.info().Commodity + ' (' + mapper.info().Year + ')'"
26429
+ [desc]="mapper.desc()"
26430
+ shape="area"
26431
+ (onCheck)="setVisible($event)"
26432
+ (onCustomize)="toggleDialog()"
26433
+ >
26434
+ <area-icon></area-icon>
26435
+ </hub-data-layer>
26436
+
26437
+ <dialog draggable mapagBringToFront onBody #customizeDialog>
26438
+ <h2>{{ mapper.name() }}</h2>
26439
+
26440
+ <div class="dlg-body">
26441
+ <p>
26442
+ The Consumer Spending dataset from Esri provides a rigorously modeled representation of how U.S. households
26443
+ allocate their budgets across a wide spectrum of goods and services, integrating source data from the U.S.
26444
+ Bureau of Labor Statistics’ Consumer Expenditure and Diary Surveys to estimate both current spending patterns
26445
+ and five‑year forecasts. It offers detailed, category‑level insights into consumer purchasing behavior,
26446
+ enabling analysts to understand market demand, evaluate economic conditions, and support data‑driven
26447
+ decision‑making within geographic contexts.
26448
+ </p>
26449
+ <h3>Information</h3>
26450
+ <div class="info-grid">
26451
+ <div class="info">
26452
+ <div class="info-label">Source</div>
26453
+ <div class="info-value">{{ mapper.info().Source | text }}</div>
26454
+ </div>
26455
+ <div class="info">
26456
+ <div class="info-label">Sector</div>
26457
+ <div class="info-value">{{ mapper.info().Sector | text }}</div>
26458
+ </div>
26459
+ <div class="info">
26460
+ <div class="info-label">Group</div>
26461
+ <div class="info-value">{{ mapper.info().Group | text }}</div>
26462
+ </div>
26463
+ <div class="info">
26464
+ <div class="info-label">Commodity</div>
26465
+ <div class="info-value">{{ mapper.info().Commodity | text }}</div>
26466
+ </div>
26467
+ <div class="info">
26468
+ <div class="info-label">Class</div>
26469
+ <div class="info-value">{{ mapper.info().Class | text }}</div>
26470
+ </div>
26471
+ <div class="info">
26472
+ <div class="info-label">Statistic</div>
26473
+ <div class="info-value">{{ mapper.info().Statistic | text }}</div>
26474
+ </div>
26475
+ <div class="info">
26476
+ <div class="info-label">Production</div>
26477
+ <div class="info-value">{{ mapper.info().Production | text }}</div>
26478
+ </div>
26479
+ <div class="info">
26480
+ <div class="info-label">Utilization</div>
26481
+ <div class="info-value">{{ mapper.info().Utilization | text }}</div>
26482
+ </div>
26483
+ <div class="info">
26484
+ <div class="info-label">Unit</div>
26485
+ <div class="info-value">{{ mapper.info().Unit | text }}</div>
26486
+ </div>
26487
+ </div>
26488
+ <h3>Customize Display Settings</h3>
26489
+ <div class="zones">
26490
+ <div class="ctrl-group">
26491
+ <div class="radio-tabs">
26492
+ <label>
26493
+ <input
26494
+ type="radio"
26495
+ name="fillType"
26496
+ value="solid"
26497
+ [checked]="mapper.settings().fillType == 'solid'"
26498
+ (change)="update('fillType', 'solid')"
26499
+ />
26500
+ Solid
26501
+ </label>
26502
+ <label>
26503
+ <input
26504
+ type="radio"
26505
+ name="fillType"
26506
+ value="gradient"
26507
+ [checked]="mapper.settings().fillType == 'gradient'"
26508
+ (change)="update('fillType', 'gradient')"
26509
+ />
26510
+ Gradient
26511
+ </label>
26512
+ <label>
26513
+ <input
26514
+ type="radio"
26515
+ name="fillType"
26516
+ value="palette"
26517
+ [checked]="mapper.settings().fillType == 'palette'"
26518
+ (change)="update('fillType', 'palette')"
26519
+ />
26520
+ Palette
26521
+ </label>
26522
+ </div>
26523
+ <div class="ctrl-row">
26524
+ @switch (mapper.settings().fillType) { @case ('solid') {
26525
+ <label for="colorPicker">Color:</label>
26526
+ <input
26527
+ type="color"
26528
+ id="colorPicker"
26529
+ [ngModel]="mapper.settings().fillColor"
26530
+ (ngModelChange)="update('fillColor', $event)"
26531
+ />
26532
+ } @case ('gradient') {
26533
+ <label for="gradientSelect">Gradient:</label>
26534
+ <input
26535
+ type="color"
26536
+ [ngModel]="mapper.settings().fillGradient[0].color"
26537
+ (ngModelChange)="updateGradient($event, undefined)"
26538
+ />
26539
+ <input
26540
+ type="color"
26541
+ [ngModel]="mapper.settings().fillGradient[1].color"
26542
+ (ngModelChange)="updateGradient(undefined, $event)"
26543
+ />
26544
+ } @case ('palette') {
26545
+ <label for="paletteSelect">Palette:</label>
26546
+ <mapag-palette-select
26547
+ [palette]="mapper.settings().fillPalette"
26548
+ (paletteChange)="update('fillPalette', $event)"
26549
+ >
26550
+ </mapag-palette-select>
26551
+ } }
26552
+ </div>
26553
+ <div class="ctrl-row">
26554
+ <label for="fillOpacity">Opacity:</label>
26555
+ <input
26556
+ type="range"
26557
+ id="fillOpacity"
26558
+ min="0"
26559
+ max="1"
26560
+ step="0.01"
26561
+ [ngModel]="mapper.settings().fillOpacity"
26562
+ (ngModelChange)="update('fillOpacity', $event)"
26563
+ />
26564
+ </div>
26565
+ <div class="ctrl-row">
26566
+ <label for="borderColor">Border Color:</label>
26567
+ <input
26568
+ type="color"
26569
+ id="borderColor"
26570
+ [ngModel]="mapper.settings().borderColor"
26571
+ (ngModelChange)="update('borderColor', $event)"
26572
+ />
26573
+ </div>
26574
+ </div>
26575
+ <div class="ctrl-group">
26576
+ <h4>Filters</h4>
26577
+ <h5>State</h5>
26578
+ <div class="filter-row" style="padding: 3px;">
26579
+ <ng-select
26580
+ [items]="USStates"
26581
+ bindLabel="Name"
26582
+ bindValue="Abbr"
26583
+ [ngModel]="mapper.settings().filterStates"
26584
+ [multiple]="true"
26585
+ appendTo="body"
26586
+ (ngModelChange)="update('filterStates', $event)"
26587
+ >
26588
+ </ng-select>
26589
+ </div>
26590
+ </div>
26591
+ </div>
26592
+
26593
+ <h3>References</h3>
26594
+ <div style="display: flex; flex-direction: column;">
26595
+ <a href="https://www.nass.usda.gov/" target="_blank">USDA NASS</a>
26596
+ <a href="https://quickstats.nass.usda.gov/" target="_blank">USDA NASS Quick Stats</a>
26597
+ </div>
26598
+ </div>
26599
+ <div class="dlg-buttons">
26600
+ <button class="btn" (click)="toggleLegend()">Legend</button>
26601
+ <button class="btn" (click)="remove()">Remove</button>
26602
+ <button class="btn" (click)="reset()">Reset</button>
26603
+ <mapag-show-hide-btn [mapper]="mapper"></mapag-show-hide-btn>
26604
+ <button class="btn" (click)="toggleDialog()">Close</button>
26605
+ </div>
26606
+ </dialog>
26607
+
26608
+ <dialog class="legend" #legendDialog draggable mapagBringToFront onbody>
26609
+ <mapag-dialog-header class="drag-handle"[dialog]="legendDialog">{{ mapper.name() }}</mapag-dialog-header>
26610
+ @switch (mapper.settings().fillType) {
26611
+ @case ('solid') {
26612
+ <div style="width: 30px; height: 30px; background-color: {{ mapper.settings().fillColor }}; border: 1px solid #000;"></div>
26613
+ }
26614
+ @case ('gradient') {
26615
+ <mapag-gradient-legend [settings]="gradientSettings()"> </mapag-gradient-legend>
26616
+ }
26617
+ @case ('palette') {
26618
+ <mapag-std-legend [items]="paletteLegend()"></mapag-std-legend>
26619
+ }
26620
+ }
26621
+ </dialog>
26622
+ `, 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 });
26623
+ }
26624
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: ConsumerSpendingPanel, decorators: [{
26625
+ type: Component,
26626
+ args: [{ selector: 'mapag-consumer-spending-panel', changeDetection: ChangeDetectionStrategy.OnPush, imports: [
26627
+ CommonModule,
26628
+ FormsModule,
26629
+ HubDataLayer,
26630
+ DraggableDialogDirective,
26631
+ AreaIcon,
26632
+ PaletteSelect,
26633
+ BringToFrontDirective,
26634
+ NgSelectComponent,
26635
+ ShowHideBtn,
26636
+ GradientLegend,
26637
+ StdLegend,
26638
+ DialogHeader,
26639
+ TextPipe,
26640
+ OnBodyDirective
26641
+ ], template: `
26642
+ <hub-data-layer
26643
+ [visible]="mapper.settings().visible"
26644
+ [name]="mapper.info().Commodity + ' (' + mapper.info().Year + ')'"
26645
+ [desc]="mapper.desc()"
26646
+ shape="area"
26647
+ (onCheck)="setVisible($event)"
26648
+ (onCustomize)="toggleDialog()"
26649
+ >
26650
+ <area-icon></area-icon>
26651
+ </hub-data-layer>
26652
+
26653
+ <dialog draggable mapagBringToFront onBody #customizeDialog>
26654
+ <h2>{{ mapper.name() }}</h2>
26655
+
26656
+ <div class="dlg-body">
26657
+ <p>
26658
+ The Consumer Spending dataset from Esri provides a rigorously modeled representation of how U.S. households
26659
+ allocate their budgets across a wide spectrum of goods and services, integrating source data from the U.S.
26660
+ Bureau of Labor Statistics’ Consumer Expenditure and Diary Surveys to estimate both current spending patterns
26661
+ and five‑year forecasts. It offers detailed, category‑level insights into consumer purchasing behavior,
26662
+ enabling analysts to understand market demand, evaluate economic conditions, and support data‑driven
26663
+ decision‑making within geographic contexts.
26664
+ </p>
26665
+ <h3>Information</h3>
26666
+ <div class="info-grid">
26667
+ <div class="info">
26668
+ <div class="info-label">Source</div>
26669
+ <div class="info-value">{{ mapper.info().Source | text }}</div>
26670
+ </div>
26671
+ <div class="info">
26672
+ <div class="info-label">Sector</div>
26673
+ <div class="info-value">{{ mapper.info().Sector | text }}</div>
26674
+ </div>
26675
+ <div class="info">
26676
+ <div class="info-label">Group</div>
26677
+ <div class="info-value">{{ mapper.info().Group | text }}</div>
26678
+ </div>
26679
+ <div class="info">
26680
+ <div class="info-label">Commodity</div>
26681
+ <div class="info-value">{{ mapper.info().Commodity | text }}</div>
26682
+ </div>
26683
+ <div class="info">
26684
+ <div class="info-label">Class</div>
26685
+ <div class="info-value">{{ mapper.info().Class | text }}</div>
26686
+ </div>
26687
+ <div class="info">
26688
+ <div class="info-label">Statistic</div>
26689
+ <div class="info-value">{{ mapper.info().Statistic | text }}</div>
26690
+ </div>
26691
+ <div class="info">
26692
+ <div class="info-label">Production</div>
26693
+ <div class="info-value">{{ mapper.info().Production | text }}</div>
26694
+ </div>
26695
+ <div class="info">
26696
+ <div class="info-label">Utilization</div>
26697
+ <div class="info-value">{{ mapper.info().Utilization | text }}</div>
26698
+ </div>
26699
+ <div class="info">
26700
+ <div class="info-label">Unit</div>
26701
+ <div class="info-value">{{ mapper.info().Unit | text }}</div>
26702
+ </div>
26703
+ </div>
26704
+ <h3>Customize Display Settings</h3>
26705
+ <div class="zones">
26706
+ <div class="ctrl-group">
26707
+ <div class="radio-tabs">
26708
+ <label>
26709
+ <input
26710
+ type="radio"
26711
+ name="fillType"
26712
+ value="solid"
26713
+ [checked]="mapper.settings().fillType == 'solid'"
26714
+ (change)="update('fillType', 'solid')"
26715
+ />
26716
+ Solid
26717
+ </label>
26718
+ <label>
26719
+ <input
26720
+ type="radio"
26721
+ name="fillType"
26722
+ value="gradient"
26723
+ [checked]="mapper.settings().fillType == 'gradient'"
26724
+ (change)="update('fillType', 'gradient')"
26725
+ />
26726
+ Gradient
26727
+ </label>
26728
+ <label>
26729
+ <input
26730
+ type="radio"
26731
+ name="fillType"
26732
+ value="palette"
26733
+ [checked]="mapper.settings().fillType == 'palette'"
26734
+ (change)="update('fillType', 'palette')"
26735
+ />
26736
+ Palette
26737
+ </label>
26738
+ </div>
26739
+ <div class="ctrl-row">
26740
+ @switch (mapper.settings().fillType) { @case ('solid') {
26741
+ <label for="colorPicker">Color:</label>
26742
+ <input
26743
+ type="color"
26744
+ id="colorPicker"
26745
+ [ngModel]="mapper.settings().fillColor"
26746
+ (ngModelChange)="update('fillColor', $event)"
26747
+ />
26748
+ } @case ('gradient') {
26749
+ <label for="gradientSelect">Gradient:</label>
26750
+ <input
26751
+ type="color"
26752
+ [ngModel]="mapper.settings().fillGradient[0].color"
26753
+ (ngModelChange)="updateGradient($event, undefined)"
26754
+ />
26755
+ <input
26756
+ type="color"
26757
+ [ngModel]="mapper.settings().fillGradient[1].color"
26758
+ (ngModelChange)="updateGradient(undefined, $event)"
26759
+ />
26760
+ } @case ('palette') {
26761
+ <label for="paletteSelect">Palette:</label>
26762
+ <mapag-palette-select
26763
+ [palette]="mapper.settings().fillPalette"
26764
+ (paletteChange)="update('fillPalette', $event)"
26765
+ >
26766
+ </mapag-palette-select>
26767
+ } }
26768
+ </div>
26769
+ <div class="ctrl-row">
26770
+ <label for="fillOpacity">Opacity:</label>
26771
+ <input
26772
+ type="range"
26773
+ id="fillOpacity"
26774
+ min="0"
26775
+ max="1"
26776
+ step="0.01"
26777
+ [ngModel]="mapper.settings().fillOpacity"
26778
+ (ngModelChange)="update('fillOpacity', $event)"
26779
+ />
26780
+ </div>
26781
+ <div class="ctrl-row">
26782
+ <label for="borderColor">Border Color:</label>
26783
+ <input
26784
+ type="color"
26785
+ id="borderColor"
26786
+ [ngModel]="mapper.settings().borderColor"
26787
+ (ngModelChange)="update('borderColor', $event)"
26788
+ />
26789
+ </div>
26790
+ </div>
26791
+ <div class="ctrl-group">
26792
+ <h4>Filters</h4>
26793
+ <h5>State</h5>
26794
+ <div class="filter-row" style="padding: 3px;">
26795
+ <ng-select
26796
+ [items]="USStates"
26797
+ bindLabel="Name"
26798
+ bindValue="Abbr"
26799
+ [ngModel]="mapper.settings().filterStates"
26800
+ [multiple]="true"
26801
+ appendTo="body"
26802
+ (ngModelChange)="update('filterStates', $event)"
26803
+ >
26804
+ </ng-select>
26805
+ </div>
26806
+ </div>
26807
+ </div>
26808
+
26809
+ <h3>References</h3>
26810
+ <div style="display: flex; flex-direction: column;">
26811
+ <a href="https://www.nass.usda.gov/" target="_blank">USDA NASS</a>
26812
+ <a href="https://quickstats.nass.usda.gov/" target="_blank">USDA NASS Quick Stats</a>
26813
+ </div>
26814
+ </div>
26815
+ <div class="dlg-buttons">
26816
+ <button class="btn" (click)="toggleLegend()">Legend</button>
26817
+ <button class="btn" (click)="remove()">Remove</button>
26818
+ <button class="btn" (click)="reset()">Reset</button>
26819
+ <mapag-show-hide-btn [mapper]="mapper"></mapag-show-hide-btn>
26820
+ <button class="btn" (click)="toggleDialog()">Close</button>
26821
+ </div>
26822
+ </dialog>
26823
+
26824
+ <dialog class="legend" #legendDialog draggable mapagBringToFront onbody>
26825
+ <mapag-dialog-header class="drag-handle"[dialog]="legendDialog">{{ mapper.name() }}</mapag-dialog-header>
26826
+ @switch (mapper.settings().fillType) {
26827
+ @case ('solid') {
26828
+ <div style="width: 30px; height: 30px; background-color: {{ mapper.settings().fillColor }}; border: 1px solid #000;"></div>
26829
+ }
26830
+ @case ('gradient') {
26831
+ <mapag-gradient-legend [settings]="gradientSettings()"> </mapag-gradient-legend>
26832
+ }
26833
+ @case ('palette') {
26834
+ <mapag-std-legend [items]="paletteLegend()"></mapag-std-legend>
26835
+ }
26836
+ }
26837
+ </dialog>
26838
+ `, 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"] }]
26839
+ }], 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 }] }] } });
26840
+
26841
+ class ConsumerSpendingGroups {
26842
+ static DairyFruitVegetables = [
26843
+ { ID: "X1053", Name: "Dairy Products", Level: 0 },
26844
+ { ID: "X1054", Name: "Fresh Milk (All Types)", Level: 1 },
26845
+ { ID: "X1055", Name: "Cream", Level: 1 },
26846
+ { ID: "X1056", Name: "Butter", Level: 1 },
26847
+ { ID: "X1057", Name: "Cheese", Level: 1 },
26848
+ { ID: "X1058", Name: "Ice Cream & Rel Prod", Level: 1 },
26849
+ { ID: "X1059", Name: "Other Dairy Products", Level: 1 },
26850
+ { ID: "X1060", Name: "Fruit & Vegetables", Level: 0 },
26851
+ { ID: "X1061", Name: "Fresh Fruit", Level: 1 },
26852
+ { ID: "X1062", Name: "Apples", Level: 2 },
26853
+ { ID: "X1063", Name: "Bananas", Level: 2 },
26854
+ { ID: "X1064", Name: "Oranges", Level: 2 },
26855
+ { ID: "X1065", Name: "Citrus Fruit excluding Oranges", Level: 2 },
26856
+ { ID: "X1066", Name: "Other Fresh Fruit", Level: 2 },
26857
+ { ID: "X1067", Name: "Fresh Vegetables", Level: 1 },
26858
+ { ID: "X1068", Name: "Potatoes", Level: 2 },
26859
+ { ID: "X1069", Name: "Lettuce", Level: 2 },
26860
+ { ID: "X1070", Name: "Tomatoes", Level: 2 },
26861
+ { ID: "X1071", Name: "Other Fresh Vegetables", Level: 2 },
26862
+ { ID: "X1072", Name: "Processed Fruit", Level: 1 },
26863
+ { ID: "X1073", Name: "Frozen Fruit & Juice", Level: 2 },
26864
+ { ID: "X1074", Name: "Frozen Orange Juice", Level: 2 },
26865
+ { ID: "X1075", Name: "Frozen Fruit", Level: 2 },
26866
+ { ID: "X1076", Name: "Frozen Fruit Juice", Level: 2 },
26867
+ { ID: "X1077", Name: "Canned Fruit", Level: 2 },
26868
+ { ID: "X1078", Name: "Dried Fruit", Level: 2 },
26869
+ { ID: "X1079", Name: "Fresh Fruit Juice", Level: 2 },
26870
+ { ID: "X1080", Name: "Canned/Bottled Fruit Juice", Level: 2 },
26871
+ { ID: "X1081", Name: "Processed Vegetables", Level: 2 },
26872
+ { ID: "X1082", Name: "Frozen Vegetables", Level: 2 },
26873
+ { ID: "X1083", Name: "Vegetables: Canned/Dried/Juice", Level: 2 },
26874
+ { ID: "X1084", Name: "Canned Beans", Level: 3 },
26875
+ { ID: "X1085", Name: "Canned Corn", Level: 3 },
26876
+ { ID: "X1086", Name: "Misc Canned Vegetables", Level: 3 },
26877
+ { ID: "X1087", Name: "Dried Beans & Peas", Level: 3 },
26878
+ { ID: "X1088", Name: "Misc Dried Vegetables", Level: 3 },
26879
+ { ID: "X1089", Name: "Vegetable Juice", Level: 3 },
26880
+ ];
26881
+ static Alcoholic = [
26882
+ { ID: "X2001", Name: "Alcoholic Beverages" },
26883
+ { ID: "X2002", Name: "Alcoholic Beverage at Home", Level: 1 },
26884
+ { ID: "X2003", Name: "Beer & Ale", Level: 2 },
26885
+ { ID: "X2004", Name: "Whiskey", Level: 2 },
26886
+ { ID: "X2005", Name: "Wine", Level: 2 },
26887
+ { ID: "X2006", Name: "Other Alcoholic Beverages", Level: 2 },
26888
+ { ID: "X2007", Name: "Alcoholic Beverage Away from Home", Level: 1 },
26889
+ { ID: "X2008", Name: "Beer & Ale Away from Home", Level: 2 },
26890
+ { ID: "X2009", Name: "Beer at Full Service Restaurants", Level: 3 },
26891
+ { ID: "X2010", Name: "Beer at Fast Food Restaurants/Other", Level: 3 },
26892
+ { ID: "X2011", Name: "Wine Away from Home", Level: 2 },
26893
+ { ID: "X2012", Name: "Wine at Full Service Restaurants", Level: 3 },
26894
+ { ID: "X2013", Name: "Wine at Fast Food Restaurants", Level: 3 },
26895
+ { ID: "X2014", Name: "Other Alcohol Away from Home", Level: 2 },
26896
+ { ID: "X2015", Name: "Other Alcohol at Full Service Restaurants", Level: 3 },
26897
+ { ID: "X2016", Name: "Other Alcohol at Fast Food Restaurants", Level: 3 },
26898
+ ];
26899
+ static BakedGoods = [
26900
+ { ID: "X1004", Name: "Bakery & Cereal Prod" },
26901
+ { ID: "X1005", Name: "Flour" },
26902
+ { ID: "X1006", Name: "Prepared Flour Mixes" },
26903
+ { ID: "X1007", Name: "Ready-to-eat & Cooked Cereal" },
26904
+ { ID: "X1008", Name: "Rice" },
26905
+ { ID: "X1009", Name: "Pasta/Cornmeal/Other Cereal" },
26906
+ { ID: "X1010", Name: "Bread" },
26907
+ { ID: "X1011", Name: "White Bread" },
26908
+ { ID: "X1012", Name: "Bread excluding White" },
26909
+ { ID: "X1013", Name: "Crackers & Cookies" },
26910
+ { ID: "X1014", Name: "Cookies" },
26911
+ { ID: "X1015", Name: "Crackers" },
26912
+ { ID: "X1016", Name: "Frozen & Refrigerated Bakery Goods" },
26913
+ { ID: "X1017", Name: "Other Bakery Products" },
26914
+ { ID: "X1018", Name: "Fresh Biscuits/Rolls/Muffins" },
26915
+ { ID: "X1019", Name: "Fresh Cakes & Cupcakes" },
26916
+ { ID: "X1020", Name: "Bread & Cracker Products" },
26917
+ { ID: "X1021", Name: "Sweet Rolls/Coffee Cakes/Donuts" },
26918
+ { ID: "X1022", Name: "Fresh Pies/Tarts/Turnovers" },
26919
+ ];
26920
+ static MeatPoultryFishEggs = [
26921
+ { ID: "X1023", Name: "Meat/Poultry/Fish/Eggs" },
26922
+ { ID: "X1024", Name: "Beef", Level: 1 },
26923
+ { ID: "X1025", Name: "Ground Beef", Level: 2 },
26924
+ { ID: "X1026", Name: "Chuck Roast", Level: 2 },
26925
+ { ID: "X1027", Name: "Round Roast", Level: 2 },
26926
+ { ID: "X1028", Name: "Other Roast", Level: 2 },
26927
+ { ID: "X1029", Name: "Round Steak", Level: 2 },
26928
+ { ID: "X1030", Name: "Sirloin Steak", Level: 2 },
26929
+ { ID: "X1031", Name: "Other Steak", Level: 2 },
26930
+ { ID: "X1032", Name: "Other Beef", Level: 2 },
26931
+ { ID: "X1033", Name: "Pork", Level: 1 },
26932
+ { ID: "X1034", Name: "Bacon", Level: 2 },
26933
+ { ID: "X1035", Name: "Pork Chops", Level: 2 },
26934
+ { ID: "X1036", Name: "Ham", Level: 2 },
26935
+ { ID: "X1037", Name: "Pork Sausage", Level: 2 },
26936
+ { ID: "X1038", Name: "Other Pork", Level: 2 },
26937
+ { ID: "X1039", Name: "Other Meat", Level: 1 },
26938
+ { ID: "X1040", Name: "Frankfurters", Level: 2 },
26939
+ { ID: "X1041", Name: "Bologna/Liverwurst/Salami", Level: 2 },
26940
+ { ID: "X1042", Name: "Other Lunchmeat", Level: 2 },
26941
+ { ID: "X1043", Name: "Lamb & Other Meat", Level: 2 },
26942
+ { ID: "X1044", Name: "Poultry", Level: 1 },
26943
+ { ID: "X1045", Name: "Whole Chickens", Level: 2 },
26944
+ { ID: "X1046", Name: "Chicken Parts", Level: 2 },
26945
+ { ID: "X1047", Name: "Other Poultry", Level: 2 },
26946
+ { ID: "X1048", Name: "Seafood", Level: 1 },
26947
+ { ID: "X1049", Name: "Canned Fish & Shellfish", Level: 2 },
26948
+ { ID: "X1050", Name: "Fresh Fish & Shellfish", Level: 2 },
26949
+ { ID: "X1051", Name: "Frozen Fish & Shellfish", Level: 2 },
26950
+ { ID: "X1052", Name: "Eggs", Level: 1 },
26951
+ ];
26952
+ static Groups = [
26953
+ { ID: "dairy", Name: "Dairy / Fruit and Vegetables", Children: ConsumerSpendingGroups.DairyFruitVegetables },
26954
+ { ID: "alcholoic", Name: "Alcoholic Beverages", Children: ConsumerSpendingGroups.Alcoholic },
26955
+ { ID: "baked", Name: "Bakery & Cereal Prod", Children: ConsumerSpendingGroups.BakedGoods },
26956
+ { ID: "meat", Name: "Meat / Poultry / Fish / Eggs", Children: ConsumerSpendingGroups.MeatPoultryFishEggs }
26957
+ ];
26958
+ static All() {
26959
+ const all = [];
26960
+ const dairy = ConsumerSpendingGroups.DairyFruitVegetables.map(i => {
26961
+ return {
26962
+ ID: i.ID,
26963
+ Name: i.Name,
26964
+ Level: i.Level,
26965
+ Parent: "Dairy / Fruit and Vegetables"
26966
+ };
26967
+ });
26968
+ const alcholoic = ConsumerSpendingGroups.Alcoholic.map(i => {
26969
+ return {
26970
+ ID: i.ID,
26971
+ Name: i.Name,
26972
+ Level: i.Level,
26973
+ Parent: "Alcoholic Beverages"
26974
+ };
26975
+ });
26976
+ const baked = ConsumerSpendingGroups.BakedGoods.map(i => {
26977
+ return {
26978
+ ID: i.ID,
26979
+ Name: i.Name,
26980
+ Level: i.Level,
26981
+ Parent: "Bakery & Cereal Prod"
26982
+ };
26983
+ });
26984
+ const meat = ConsumerSpendingGroups.MeatPoultryFishEggs.map(i => {
26985
+ return {
26986
+ ID: i.ID,
26987
+ Name: i.Name,
26988
+ Level: i.Level,
26989
+ Parent: "Meat / Poultry / Fish / Eggs"
26990
+ };
26991
+ });
26992
+ return [...dairy, ...alcholoic, ...baked, ...meat];
26993
+ }
26994
+ }
26995
+
26996
+ class ConsumerSpendingSelectPanel {
26997
+ faCircle = faCircle;
26998
+ faFire = faFire;
26999
+ faThLarge = faThLarge;
27000
+ faList = faList;
27001
+ options = ConsumerSpendingGroups.Groups;
27002
+ nassSvc = inject(NassService);
27003
+ canAdd = input(true, ...(ngDevMode ? [{ debugName: "canAdd" }] : []));
27004
+ // Map Component
27005
+ map = input(...(ngDevMode ? [undefined, { debugName: "map" }] : []));
27006
+ // Currently selected NAICS codes
27007
+ current = model([], ...(ngDevMode ? [{ debugName: "current" }] : []));
27008
+ customizeDialog = viewChild('customizeDialog', ...(ngDevMode ? [{ debugName: "customizeDialog" }] : []));
27009
+ // Mapper group to hold NAICS layers
27010
+ mappers = new MapboxMapperGroup();
27011
+ constructor() {
27012
+ const _mapInit = effect(() => {
27013
+ const mapComp = this.map();
27014
+ if (mapComp) {
27015
+ mapComp.mapper().set('naicsmgr', this.mappers);
27016
+ }
27017
+ }, ...(ngDevMode ? [{ debugName: "_mapInit" }] : []));
27018
+ }
27019
+ isSelected(code) {
27020
+ return this.current().some((c) => c.ID === code.ID);
27021
+ }
27022
+ selectInfo(info) {
27023
+ const currentInfos = this.current();
27024
+ const index = currentInfos.findIndex((c) => c.ID === info.ID);
27025
+ if (index >= 0) {
27026
+ // Remove if already selected
27027
+ this.current.set(currentInfos.filter((c) => c.ID !== info.ID));
27028
+ }
27029
+ else {
27030
+ // Add if not selected - ensure no duplicates
27031
+ const newInfos = [...currentInfos, info];
27032
+ // Remove any potential duplicates by creating a Map
27033
+ const uniqueMap = new Map(newInfos.map((c) => [c.ID, c]));
27034
+ this.current.set(Array.from(uniqueMap.values()));
27035
+ }
27036
+ }
27037
+ removeInfo(info) {
27038
+ const currentInfos = this.current();
27039
+ this.current.set(currentInfos.filter((c) => c.ID !== info.ID));
27040
+ }
27041
+ toggleDialog() {
27042
+ const dialog = this.customizeDialog();
27043
+ if (!dialog) {
27044
+ return;
27045
+ }
27046
+ const dialogElement = dialog.nativeElement;
27047
+ if (dialogElement.open) {
27048
+ dialogElement.close();
27049
+ }
27050
+ else {
27051
+ dialogElement.show();
27052
+ }
27053
+ }
27054
+ fixTextSet(input) {
27055
+ const output = [];
27056
+ input.forEach((text) => {
27057
+ output.push({ key: text, value: this.fixText(text) });
27058
+ });
27059
+ return output;
27060
+ }
27061
+ fixText(text) {
27062
+ const parts = text
27063
+ .toLocaleLowerCase()
27064
+ .split('_')
27065
+ .map((part) => part.charAt(0).toUpperCase() + part.slice(1));
27066
+ return parts.join(' ');
27067
+ }
27068
+ reset() {
27069
+ }
27070
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: ConsumerSpendingSelectPanel, deps: [], target: i0.ɵɵFactoryTarget.Component });
27071
+ 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: `
27072
+ <mapag-details [open]="true" style="margin-top: 16px;">
27073
+ <span summary>Consumer Spending</span>
27074
+
27075
+ <!-- @for (info of current(); track info.ID) {
27076
+ <hub-nass-panel [map]="map()" [settings]="inf" (onRemove)="removeInfo(info)"></hub-nass-panel>
27077
+ } -->
27078
+
27079
+ @if (canAdd()) {
27080
+ <button class="mgr-btn" (click)="toggleDialog()" style="justify-self: center;">Add & Remove Layers</button>
27081
+ }
27082
+ </mapag-details>
27083
+ <dialog draggable mapagBringToFront onBody #customizeDialog>
27084
+ <h2>Consumer Spending Layers</h2>
27085
+
27086
+ <div class="dlg-body">
27087
+ <p>
27088
+ Select a consumer spending category from the list below to add it as a layer on the map. You can select multiple
27089
+ categories to compare them. Use the filters to narrow down the options. The data is sourced from the USDA Economic
27090
+ Research Service and represents average annual consumer spending in the United States for various food categories.
27091
+ </p>
27092
+
27093
+ <div class="zones results">
27094
+ @for (group of options; track group.ID) {
27095
+ <h3>{{group.Name}}</h3>
27096
+ @for (item of group.Children; track item.ID) {
27097
+ <label>
27098
+ <input type="checkbox" [checked]="isSelected(item)" (change)="selectInfo(item)" [ngClass]="'indent-' + (item.Level || 0)">
27099
+ {{item.Name}}
27100
+ </label>
27101
+ }
27102
+ }
27103
+ </div>
27104
+
27105
+ <h3>References</h3>
27106
+ <div style="display: flex; flex-direction: column;">
27107
+ <a href="https://doc.arcgis.com/en/esri-demographics/latest/esri-demographics/consumer-spending.htm" target="_blank">ESRi Consumer Spending Data</a>
27108
+ </div>
27109
+ </div>
27110
+ <div class="dlg-buttons">
27111
+ <button class="btn" (click)="reset()">Reset</button>
27112
+ <button class="btn" (click)="toggleDialog()">Close</button>
27113
+ </div>
27114
+ </dialog>
27115
+ `, 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 });
27116
+ }
27117
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: ConsumerSpendingSelectPanel, decorators: [{
27118
+ type: Component,
27119
+ args: [{ selector: 'mapag-consumer-spending-select-panel', changeDetection: ChangeDetectionStrategy.OnPush, imports: [CommonModule, FormsModule, DraggableDialogDirective, BringToFrontDirective, MapagDetails, OnBodyDirective], template: `
27120
+ <mapag-details [open]="true" style="margin-top: 16px;">
27121
+ <span summary>Consumer Spending</span>
27122
+
27123
+ <!-- @for (info of current(); track info.ID) {
27124
+ <hub-nass-panel [map]="map()" [settings]="inf" (onRemove)="removeInfo(info)"></hub-nass-panel>
27125
+ } -->
27126
+
27127
+ @if (canAdd()) {
27128
+ <button class="mgr-btn" (click)="toggleDialog()" style="justify-self: center;">Add & Remove Layers</button>
27129
+ }
27130
+ </mapag-details>
27131
+ <dialog draggable mapagBringToFront onBody #customizeDialog>
27132
+ <h2>Consumer Spending Layers</h2>
27133
+
27134
+ <div class="dlg-body">
27135
+ <p>
27136
+ Select a consumer spending category from the list below to add it as a layer on the map. You can select multiple
27137
+ categories to compare them. Use the filters to narrow down the options. The data is sourced from the USDA Economic
27138
+ Research Service and represents average annual consumer spending in the United States for various food categories.
27139
+ </p>
27140
+
27141
+ <div class="zones results">
27142
+ @for (group of options; track group.ID) {
27143
+ <h3>{{group.Name}}</h3>
27144
+ @for (item of group.Children; track item.ID) {
27145
+ <label>
27146
+ <input type="checkbox" [checked]="isSelected(item)" (change)="selectInfo(item)" [ngClass]="'indent-' + (item.Level || 0)">
27147
+ {{item.Name}}
27148
+ </label>
27149
+ }
27150
+ }
27151
+ </div>
27152
+
27153
+ <h3>References</h3>
27154
+ <div style="display: flex; flex-direction: column;">
27155
+ <a href="https://doc.arcgis.com/en/esri-demographics/latest/esri-demographics/consumer-spending.htm" target="_blank">ESRi Consumer Spending Data</a>
27156
+ </div>
27157
+ </div>
27158
+ <div class="dlg-buttons">
27159
+ <button class="btn" (click)="reset()">Reset</button>
27160
+ <button class="btn" (click)="toggleDialog()">Close</button>
27161
+ </div>
27162
+ </dialog>
27163
+ `, 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"] }]
27164
+ }], 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 }] }] } });
27165
+
27166
+ class HubCropSequencePanel {
27167
+ DefaultName = 'cropsequence';
27168
+ faFill = faFill;
27169
+ faPaintBrush = faPaintBrush;
27170
+ faText = faFill;
27171
+ map = input(...(ngDevMode ? [undefined, { debugName: "map" }] : []));
27172
+ mapper = new CropSequenceMapper({ visible: false });
27173
+ customizeDialog = viewChild('customizeDialog', ...(ngDevMode ? [{ debugName: "customizeDialog" }] : []));
27174
+ constructor() {
27175
+ const _mapInit = effect(() => {
27176
+ const mapComp = this.map();
27177
+ if (mapComp) {
27178
+ mapComp.mapper().set('cropSequence', this.mapper);
27179
+ }
27180
+ }, ...(ngDevMode ? [{ debugName: "_mapInit" }] : []));
27181
+ }
27182
+ setVisible(visible) {
27183
+ this.mapper.update({ visible: visible });
27184
+ }
27185
+ toggleDialog() {
27186
+ const dialog = this.customizeDialog();
27187
+ if (!dialog) {
27188
+ return;
27189
+ }
27190
+ const dialogElement = dialog.nativeElement;
27191
+ if (dialogElement.open) {
27192
+ dialogElement.close();
27193
+ }
27194
+ else {
27195
+ dialogElement.show();
27196
+ }
27197
+ // Implement dialog toggle logic here
27198
+ }
27199
+ update(field, value) {
27200
+ this.mapper.update({
27201
+ [field]: value,
27202
+ });
27203
+ }
27204
+ reset() {
27205
+ this.mapper.update(new CropSequenceSettings());
27206
+ }
27207
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: HubCropSequencePanel, deps: [], target: i0.ɵɵFactoryTarget.Component });
27208
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.2.0", version: "20.3.15", type: HubCropSequencePanel, isStandalone: true, selector: "hub-crop-sequence-panel", inputs: { map: { classPropertyName: "map", publicName: "map", isSignal: true, isRequired: false, transformFunction: null } }, viewQueries: [{ propertyName: "customizeDialog", first: true, predicate: ["customizeDialog"], descendants: true, isSignal: true }], ngImport: i0, template: `
27209
+ <hub-data-layer
27210
+ [visible]="mapper.settings().visible"
27211
+ [name]="'USDA - NASS - Crop Sequences'"
27212
+ [desc]="'Crop field boundary estimates, crop acreage, and crop rotations '"
27213
+ shape="area"
27214
+ (onCheck)="setVisible($event)"
27215
+ (onCustomize)="toggleDialog()"
27216
+ >
27217
+ <area-icon></area-icon>
27218
+ </hub-data-layer>
27219
+ <dialog draggable mapagBringToFront onBody #customizeDialog>
27220
+ <h2>USDA - NASS - Crop Sequence Boundaries</h2>
27221
+
27222
+ <div class="dlg-body">
27223
+ <img src="https://foodmarketmaker-upload-data.s3.us-west-2.amazonaws.com/assets/mapag/csbbanner2025.png" alt="Crop Sequence Boundaries Sample Image" style="max-width: 100%; height: auto; margin-bottom: 6px; border-radius: 6px;" />
27224
+ <p>
27225
+ The Crop Sequence Boundaries (CSB) developed with USDA's Economic Research Service, produces estimates of field boundaries, crop acreage, and crop rotations across the
27226
+ contiguous United States. It uses satellite imagery with other public data and is open source allowing users to conduct area and statistical analysis of planted U.S.
27227
+ commodities and provides insight on farmer cropping decisions. NASS needed a representative field to predict crop planting based on common crop rotations such as corn-soy
27228
+ and ERS is using this product to study changes in farm management practices like tillage or cover cropping over time. CSB represents non-confidential single crop field
27229
+ boundaries over a set time frame. It does not contain personal identifying information. The boundaries captured are of crops grown only, not ownership boundaries or tax
27230
+ parcels (unit of property). The data are from satellite imagery and publicly available data, it does not come from producers or agencies like the Farm Service Agency.
27231
+ </p>
27232
+
27233
+ <h3>Customize Display Settings</h3>
27234
+ <div class="zones">
25735
27235
  <div class="ctrl-group">
25736
27236
  <h4>
25737
27237
  <fa-icon [icon]="faFill" size="lg"></fa-icon>
@@ -25846,59 +27346,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImpo
25846
27346
  `, 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
27347
  }], ctorParameters: () => [], propDecorators: { map: [{ type: i0.Input, args: [{ isSignal: true, alias: "map", required: false }] }], customizeDialog: [{ type: i0.ViewChild, args: ['customizeDialog', { isSignal: true }] }] } });
25848
27348
 
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
27349
  class HubCroplandPanel {
25903
27350
  DefaultName = 'cropland';
25904
27351
  faImage = faImage;
@@ -27341,91 +28788,21 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImpo
27341
28788
  `, 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
28789
  }], 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
28790
 
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();
28791
+ class SafeHtmlPipe {
28792
+ sanitizer = inject(DomSanitizer);
28793
+ transform(url) {
28794
+ if (!url) {
28795
+ return undefined;
27363
28796
  }
28797
+ return this.sanitizer.bypassSecurityTrustHtml(url);
27364
28798
  }
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 });
28799
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: SafeHtmlPipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe });
28800
+ static ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "20.3.15", ngImport: i0, type: SafeHtmlPipe, isStandalone: true, name: "safeHtml" });
27393
28801
  }
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 }] }] } });
28802
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: SafeHtmlPipe, decorators: [{
28803
+ type: Pipe,
28804
+ args: [{ name: 'safeHtml' }]
28805
+ }] });
27429
28806
 
27430
28807
  class MMPanel {
27431
28808
  // Icons and static data
@@ -27439,8 +28816,10 @@ class MMPanel {
27439
28816
  USStates = states;
27440
28817
  map = input(...(ngDevMode ? [undefined, { debugName: "map" }] : []));
27441
28818
  settings = input(new PointDataMapperSettings(), ...(ngDevMode ? [{ debugName: "settings" }] : []));
27442
- mapper = new PointDataMapper(new MarketMakerPopupRenderer());
28819
+ popupRenderer = new MarketMakerPopupRenderer();
28820
+ mapper = new PointDataMapper(this.popupRenderer);
27443
28821
  customizeDialog = viewChild('customizeDialog', ...(ngDevMode ? [{ debugName: "customizeDialog" }] : []));
28822
+ dataDialog = viewChild('dataDialog', ...(ngDevMode ? [{ debugName: "dataDialog" }] : []));
27444
28823
  onRemove = output();
27445
28824
  style = computed(() => {
27446
28825
  const sel = this.mapper.settings().type;
@@ -27556,10 +28935,17 @@ class MMPanel {
27556
28935
  this.mapper.clear();
27557
28936
  }
27558
28937
  toggleData() {
27559
- // Implement dialog toggle logic here
28938
+ ToggleDialog(this.dataDialog);
28939
+ }
28940
+ onTileClick(feature) {
28941
+ const comp = this.map();
28942
+ if (!comp) {
28943
+ return;
28944
+ }
28945
+ flyToFeature(comp.map, feature);
27560
28946
  }
27561
28947
  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: `
28948
+ 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
28949
  <hub-data-layer [visible]="mapper.settings().visible" [name]="mapper.settings().name"
27564
28950
  [desc]="mapper.settings().description || 'MarketMaker Business'" shape="point" (onCheck)="setVisible($event)" (onCustomize)="toggleDialog()">
27565
28951
 
@@ -27700,7 +29086,7 @@ class MMPanel {
27700
29086
  </div>
27701
29087
  <div class="dlg-buttons">
27702
29088
  <button class="btn" (click)="toggleLegend()">Legend</button>
27703
- <button class="btn" (click)="dataDialog.toggle()">Data</button>
29089
+ <button class="btn" (click)="toggleData()">Data</button>
27704
29090
  <button class="btn" (click)="remove()">Remove</button>
27705
29091
  <button class="btn" (click)="reset()">Reset</button>
27706
29092
  <button class="btn" (click)="toggleShowHide()">
@@ -27711,7 +29097,22 @@ class MMPanel {
27711
29097
  </div>
27712
29098
  </dialog>
27713
29099
 
27714
- <ng-template #dataTemplate let-feature>
29100
+ <dialog draggable mapagBringToFront onBody #dataDialog class="data-dialog">
29101
+ <h2>{{mapper.settings().name}}</h2>
29102
+ <div class="dlg-body dlg-body-list ">
29103
+ {{ mapper.data().length }} records matching current filters.
29104
+
29105
+ <cdk-virtual-scroll-viewport [itemSize]="40">
29106
+ <div *cdkVirtualFor="let feature of mapper.data()" (click)="onTileClick(feature)"
29107
+ class="data-tile" [innerHTML]="popupRenderer.RenderPopupSync(feature) | safeHtml"></div>
29108
+ </cdk-virtual-scroll-viewport>
29109
+ </div>
29110
+ <div class="dlg-buttons">
29111
+ <button class="btn" (click)="toggleData()">Close</button>
29112
+ </div>
29113
+ </dialog>
29114
+
29115
+ <!-- <ng-template #dataTemplate let-feature>
27715
29116
  <div [innerHTML]="mapper.popupRenderer?.RenderPopup(feature) | async"></div>
27716
29117
  </ng-template>
27717
29118
  <mapag-tile-dialog
@@ -27720,12 +29121,13 @@ class MMPanel {
27720
29121
  [name]="mapper.settings().name"
27721
29122
  [contentTemplate]="dataTemplate"
27722
29123
  (onSelect)="onSelect($event)">
27723
- </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]" }, { kind: "component", type: TileDialog, selector: "mapag-tile-dialog", inputs: ["data", "name", "contentTemplate"], outputs: ["onSelect"] }, { kind: "pipe", type: i1.AsyncPipe, name: "async" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
29124
+ </mapag-tile-dialog> -->
29125
+ `, 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
29126
  }
27726
29127
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: MMPanel, decorators: [{
27727
29128
  type: Component,
27728
- args: [{ selector: 'mapag-mm-panel', changeDetection: ChangeDetectionStrategy.OnPush, imports: [CommonModule, FormsModule, HubDataLayer, DraggableDialogDirective, FaIconComponent, BringToFrontDirective, TileDialog], template: `
29129
+ args: [{ selector: 'mapag-mm-panel', changeDetection: ChangeDetectionStrategy.OnPush, imports: [CommonModule, FormsModule, HubDataLayer, DraggableDialogDirective, FaIconComponent,
29130
+ BringToFrontDirective, CdkVirtualScrollViewport, CdkVirtualForOf, CdkFixedSizeVirtualScroll, SafeHtmlPipe], template: `
27729
29131
  <hub-data-layer [visible]="mapper.settings().visible" [name]="mapper.settings().name"
27730
29132
  [desc]="mapper.settings().description || 'MarketMaker Business'" shape="point" (onCheck)="setVisible($event)" (onCustomize)="toggleDialog()">
27731
29133
 
@@ -27866,7 +29268,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImpo
27866
29268
  </div>
27867
29269
  <div class="dlg-buttons">
27868
29270
  <button class="btn" (click)="toggleLegend()">Legend</button>
27869
- <button class="btn" (click)="dataDialog.toggle()">Data</button>
29271
+ <button class="btn" (click)="toggleData()">Data</button>
27870
29272
  <button class="btn" (click)="remove()">Remove</button>
27871
29273
  <button class="btn" (click)="reset()">Reset</button>
27872
29274
  <button class="btn" (click)="toggleShowHide()">
@@ -27877,7 +29279,22 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImpo
27877
29279
  </div>
27878
29280
  </dialog>
27879
29281
 
27880
- <ng-template #dataTemplate let-feature>
29282
+ <dialog draggable mapagBringToFront onBody #dataDialog class="data-dialog">
29283
+ <h2>{{mapper.settings().name}}</h2>
29284
+ <div class="dlg-body dlg-body-list ">
29285
+ {{ mapper.data().length }} records matching current filters.
29286
+
29287
+ <cdk-virtual-scroll-viewport [itemSize]="40">
29288
+ <div *cdkVirtualFor="let feature of mapper.data()" (click)="onTileClick(feature)"
29289
+ class="data-tile" [innerHTML]="popupRenderer.RenderPopupSync(feature) | safeHtml"></div>
29290
+ </cdk-virtual-scroll-viewport>
29291
+ </div>
29292
+ <div class="dlg-buttons">
29293
+ <button class="btn" (click)="toggleData()">Close</button>
29294
+ </div>
29295
+ </dialog>
29296
+
29297
+ <!-- <ng-template #dataTemplate let-feature>
27881
29298
  <div [innerHTML]="mapper.popupRenderer?.RenderPopup(feature) | async"></div>
27882
29299
  </ng-template>
27883
29300
  <mapag-tile-dialog
@@ -27886,14 +29303,14 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImpo
27886
29303
  [name]="mapper.settings().name"
27887
29304
  [contentTemplate]="dataTemplate"
27888
29305
  (onSelect)="onSelect($event)">
27889
- </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"] }] } });
29306
+ </mapag-tile-dialog> -->
29307
+ `, 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"] }]
29308
+ }], 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
29309
  class MarketMakerPopupRenderer {
27893
- RenderPopup(feature) {
29310
+ RenderPopupSync(feature) {
27894
29311
  const props = feature.properties;
27895
29312
  if (!props) {
27896
- return Promise.resolve(undefined);
29313
+ return undefined;
27897
29314
  }
27898
29315
  let html = `<div>`;
27899
29316
  html += `<h3>${props.Name || 'MarketMaker Business'}</h3>`;
@@ -27925,7 +29342,10 @@ class MarketMakerPopupRenderer {
27925
29342
  onclick="window.open('https://foodmarketmaker.com/business/${props.ID}', '_blank')">Learn More...</button>
27926
29343
  `;
27927
29344
  html += `</div>`;
27928
- return Promise.resolve(html);
29345
+ return html;
29346
+ }
29347
+ RenderPopup(feature) {
29348
+ return Promise.resolve(this.RenderPopupSync(feature));
27929
29349
  }
27930
29350
  getArrayProperty(value) {
27931
29351
  const arr = this.parseArrayProperty(value) || [];
@@ -28808,85 +30228,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImpo
28808
30228
  `, 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
30229
  }], 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
30230
 
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
30231
  class NassPanel {
28891
30232
  map = input(...(ngDevMode ? [undefined, { debugName: "map" }] : []));
28892
30233
  mapper = new NAASMapper();
@@ -30953,5 +32294,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImpo
30953
32294
  * Generated bundle index. Do not edit.
30954
32295
  */
30955
32296
 
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 };
32297
+ 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
32298
  //# sourceMappingURL=foodmarketmaker-mapag.mjs.map