mapshaper 0.6.112 → 0.6.115

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.
@@ -462,6 +462,16 @@
462
462
  }
463
463
  }
464
464
 
465
+ async function loadScript(src) {
466
+ return new Promise((resolve, reject) => {
467
+ const script = document.createElement('script');
468
+ script.src = src;
469
+ script.onload = () => resolve(script);
470
+ script.onerror = () => reject(new Error(`Failed to load script: ${src}`));
471
+ document.head.appendChild(script);
472
+ });
473
+ }
474
+
465
475
  var tagOrIdSelectorRE = /^#?[\w-]+$/;
466
476
 
467
477
  El.__select = function(selector, root) {
@@ -655,9 +665,14 @@
655
665
  },
656
666
 
657
667
  show: function(css) {
658
- var tag = this.el && this.el.tagName;
668
+ // var tag = this.el && this.el.tagName;
659
669
  if (!this.visible()) {
660
- this.css('display', tag == 'SPAN' ? 'inline-block' : 'block');
670
+ // don't assume 'display:block'
671
+ this.el?.style.removeProperty('display');
672
+ if (this.computedStyle().display == 'none') {
673
+ this.css('display', 'block');
674
+ }
675
+ // this.css('display', tag == 'SPAN' ? 'inline-block' : 'block');
661
676
  this._hidden = false;
662
677
  }
663
678
  return this;
@@ -666,13 +681,15 @@
666
681
  html: function(html) {
667
682
  if (arguments.length == 0) {
668
683
  return this.el.innerHTML;
669
- } else {
670
- this.el.innerHTML = html;
671
- return this;
672
684
  }
685
+ this.el.innerHTML = html;
686
+ return this;
673
687
  },
674
688
 
675
689
  text: function(str) {
690
+ if (arguments.length == 0) {
691
+ return this.el.innerText;
692
+ }
676
693
  this.html(utils$1.htmlEscape(str));
677
694
  return this;
678
695
  },
@@ -1927,6 +1944,18 @@
1927
1944
  }
1928
1945
  }
1929
1946
 
1947
+ var geopackagePromise = null;
1948
+
1949
+ async function loadGeopackageLib() {
1950
+ if (!window.modules || !window.modules['@ngageoint/geopackage']) {
1951
+ if (!geopackagePromise) {
1952
+ geopackagePromise = loadScript('geopackage.js');
1953
+ }
1954
+ await geopackagePromise;
1955
+ geopackagePromise = null;
1956
+ }
1957
+ }
1958
+
1930
1959
  // @cb function(<FileList>)
1931
1960
  function DropControl(gui, el, cb) {
1932
1961
  var area = El(el);
@@ -1936,6 +1965,7 @@
1936
1965
  .on('drop', ondrop)
1937
1966
  .on('paste', onpaste);
1938
1967
  area.node().addEventListener('paste', onpaste);
1968
+ // TODO: use same function for drop and paste
1939
1969
  function ondrop(e) {
1940
1970
  var files = e.dataTransfer.files;
1941
1971
  var types = e.dataTransfer.types;
@@ -1946,7 +1976,7 @@
1946
1976
  cb(e.dataTransfer.getData('text/uri-list').split(','));
1947
1977
  } else if (types.includes('text/html')) {
1948
1978
  // drag-dropping a highlighted link may pull in a chunk of html
1949
- var urls = e.dataTransfer.getData('text/html').match(/https?:[^"']+/);
1979
+ var urls = pastedHtmlToUrls(e.dataTransfer.getData('text/html'));
1950
1980
  if (urls.length) {
1951
1981
  cb(urls);
1952
1982
  }
@@ -1955,7 +1985,7 @@
1955
1985
  function onpaste(e) {
1956
1986
  var types = Array.from(e.clipboardData.types || []).join(',');
1957
1987
  var items = Array.from(e.clipboardData.items || []);
1958
- var files;
1988
+ var files, str, urls;
1959
1989
  if (GUI.textIsSelected()) {
1960
1990
  // user is probably pasting text into an editable text field
1961
1991
  return;
@@ -1971,12 +2001,22 @@
1971
2001
  // formatted text can be available as both text/plain and text/html (e.g.
1972
2002
  // a JSON data object copied from a GitHub issue).
1973
2003
  //
2004
+
2005
+ // if html is present, it could be data (e.g. from Google Sheets) or a pasted link.
2006
+ // first we check for a link
2007
+ if (types.includes('text/html')) {
2008
+ urls = pastedHtmlToUrls(e.clipboardData.getData('text/html'));
2009
+ if (urls.length) {
2010
+ return cb(urls);
2011
+ }
2012
+ }
1974
2013
  if (types.includes('text/plain')) {
1975
2014
  // text from clipboard (supported by Chrome, FF, Safari)
1976
2015
  // TODO: handle FF case of string containing multiple file names.
1977
- var str = e.clipboardData.getData('text/plain');
1978
- if (isUrl(str)) {
1979
- return cb(str.split(','));
2016
+ str = e.clipboardData.getData('text/plain');
2017
+ urls = pastedTextToUrls(str);
2018
+ if (urls.length) {
2019
+ return cb(urls);
1980
2020
  }
1981
2021
  files = [pastedTextToFile(str)];
1982
2022
  } else {
@@ -1998,6 +2038,21 @@
1998
2038
  }
1999
2039
  }
2000
2040
 
2041
+ function pastedHtmlToUrls(html) {
2042
+ var hrefRegex = /href\s*=\s*["']([^"']+)["']/gi;
2043
+ var matches = html.matchAll(hrefRegex);
2044
+ var urls = Array.from(matches, match => match[1]);
2045
+ return urls;
2046
+ }
2047
+
2048
+ function pastedTextToUrls(str) {
2049
+ if (!looksLikeUrl(str)) return [];
2050
+ var regex = /https?:\/\/[^\s]+?(?=[\s,]|$)/g;
2051
+ var matches = str.matchAll(regex);
2052
+ var urls = Array.from(matches, match => match[0]);
2053
+ return urls;
2054
+ }
2055
+
2001
2056
  function pastedTextToFile(str) {
2002
2057
  var type = internal.guessInputContentType(str);
2003
2058
  var name;
@@ -2012,7 +2067,7 @@
2012
2067
  return new File([blob], name);
2013
2068
  }
2014
2069
 
2015
- function isUrl(str) {
2070
+ function looksLikeUrl(str) {
2016
2071
  return /^https?:\/\//.test(str);
2017
2072
  }
2018
2073
 
@@ -2272,7 +2327,15 @@
2272
2327
  }
2273
2328
 
2274
2329
  async function importDataset(group, importOpts) {
2275
- var dataset = internal.importContent(group, importOpts);
2330
+ var dataset;
2331
+ if (group.gpkg) {
2332
+ await loadGeopackageLib();
2333
+ }
2334
+ if (group.gpkg || group.fgb) {
2335
+ dataset = await internal.importContentAsync(group, importOpts);
2336
+ } else {
2337
+ dataset = internal.importContent(group, importOpts);
2338
+ }
2276
2339
  if (datasetIsEmpty(dataset)) return false;
2277
2340
  if (group.layername) {
2278
2341
  dataset.layers.forEach(lyr => lyr.name = group.layername);
@@ -2340,7 +2403,7 @@
2340
2403
  function prepFilesForDownload(names) {
2341
2404
  var items = names.map(function(name) {
2342
2405
  var item = {name: name};
2343
- if (isUrl(name)) {
2406
+ if (looksLikeUrl(name)) {
2344
2407
  item.url = name;
2345
2408
  item.basename = GUI.getUrlFilename(name);
2346
2409
 
@@ -2459,6 +2522,8 @@
2459
2522
  }
2460
2523
  }
2461
2524
 
2525
+ // Group multiple files belonging to the same dataset together
2526
+ // (applies to Shapefiles)
2462
2527
  function groupFilesForImport(data, importOpts) {
2463
2528
  var names = importOpts.name ? [importOpts.name] : null;
2464
2529
  if (initialImport && opts.name) { // name from mapshaper-gui --name option
@@ -4518,8 +4583,16 @@
4518
4583
  async function exportMenuSelection(targets) {
4519
4584
  // note: command line "target" option gets ignored
4520
4585
  var opts = getExportOpts();
4586
+ if (opts.format == 'geopackage') {
4587
+ await loadGeopackageLib();
4588
+ }
4521
4589
  opts.active_layer = gui.model.getActiveLayer().layer; // kludge to support restoring active layer in gui
4522
- var files = await internal.exportTargetLayers(model, targets, opts);
4590
+ try {
4591
+ var files = await internal.exportTargetLayers(model, targets, opts);
4592
+ } catch(e) {
4593
+ console.error(e);
4594
+ throw e;
4595
+ }
4523
4596
  gui.session.layersExported(getTargetLayerIds(), getExportOptsAsString());
4524
4597
  if (files.length == 1 && checkboxOn(clipboardCheckbox)) {
4525
4598
  await saveFileContentToClipboard(files[0].content);
@@ -4641,7 +4714,7 @@
4641
4714
 
4642
4715
  function getExportFormats() {
4643
4716
  // return ['shapefile', 'geojson', 'topojson', 'json', 'dsv', 'kml', 'svg', internal.PACKAGE_EXT];
4644
- return ['shapefile', 'json', 'geojson', 'dsv', 'topojson', 'kml', internal.PACKAGE_EXT, 'svg'];
4717
+ return ['shapefile', 'json', 'geojson', 'dsv', 'topojson', 'flatgeobuf', 'geopackage', 'kml', internal.PACKAGE_EXT, 'svg'];
4645
4718
  }
4646
4719
 
4647
4720
  function initFormatMenu() {
@@ -5297,7 +5370,7 @@
5297
5370
  if (!lyr.data) {
5298
5371
  missing.push('.dbf');
5299
5372
  }
5300
- if (!dataset.info.prj && !dataset.info.crs) {
5373
+ if (!dataset.info.wkt1 && !dataset.info.crs) {
5301
5374
  missing.push('.prj');
5302
5375
  }
5303
5376
  }
@@ -6206,6 +6279,8 @@
6206
6279
  throw new NonFatalError(formatLogArgs(arguments));
6207
6280
  };
6208
6281
 
6282
+ var onceMessages = [];
6283
+
6209
6284
  setLoggingForCLI();
6210
6285
 
6211
6286
  function getLoggingSetter() {
@@ -6267,6 +6342,13 @@
6267
6342
  _warn.apply(null, messageArgs(arguments));
6268
6343
  }
6269
6344
 
6345
+ function warnOnce() {
6346
+ var str = formatLogArgs(arguments);
6347
+ if (onceMessages.includes(str)) return;
6348
+ onceMessages.push(str);
6349
+ _warn.apply(null, messageArgs(arguments));
6350
+ }
6351
+
6270
6352
  // A way for the GUI to replace the CLI logging functions
6271
6353
  function setLoggingFunctions(message, error, stop, warn) {
6272
6354
  _message = message;
@@ -13548,12 +13630,18 @@ GUI and setting the size and crop of SVG output.</p><div><input type="text" clas
13548
13630
  });
13549
13631
  }
13550
13632
 
13551
- function loadScript(url, cb) {
13552
- var script = document.createElement('script');
13553
- script.onload = cb;
13554
- script.src = url;
13555
- document.head.appendChild(script);
13556
- }
13633
+ var EMPTY_STYLE = {
13634
+ version: 8,
13635
+ sources: {},
13636
+ layers: []
13637
+ };
13638
+
13639
+ // function loadScript(url, cb) {
13640
+ // var script = document.createElement('script');
13641
+ // script.onload = cb;
13642
+ // script.src = url;
13643
+ // document.head.appendChild(script);
13644
+ // }
13557
13645
 
13558
13646
  function loadStylesheet(url) {
13559
13647
  var el = document.createElement('link');
@@ -13565,60 +13653,107 @@ GUI and setting the size and crop of SVG output.</p><div><input type="text" clas
13565
13653
  }
13566
13654
 
13567
13655
  function Basemap(gui) {
13568
- var menu = gui.container.findChild('.display-options');
13569
- var fadeBtn = new SimpleButton(menu.findChild('.fade-btn'));
13570
- var clearBtn = new SimpleButton(menu.findChild('.clear-btn'));
13571
- var menuButtons = menu.findChild('.basemap-styles');
13656
+ var menuWrapper = gui.container.findChild('.display-options');
13657
+ var mainMenu = gui.container.findChild('.display-main-options');
13658
+ var addLayerMenu = gui.container.findChild('.add-basemap-menu').hide();
13659
+ var basemapList = gui.container.findChild('.added-basemaps');
13572
13660
  var overlayButtons = gui.container.findChild('.basemap-overlay-buttons');
13573
13661
  var container = gui.container.findChild('.basemap-container');
13574
13662
  var basemapNote = gui.container.findChild('.basemap-note');
13575
- var basemapWarning = gui.container.findChild('.basemap-warning');
13663
+ var addBasemap = gui.container.findChild('.add-basemap');
13664
+ var basemapWarning = gui.container.findChild('.basemap-warning').hide();
13576
13665
  var mapEl = gui.container.findChild('.basemap');
13577
13666
  var extentNote = El('div').addClass('basemap-prompt').appendTo(container).hide();
13578
13667
  var params = window.mapboxParams;
13579
13668
  var map;
13580
13669
  var activeStyle;
13581
13670
  var loading = false;
13582
- var faded = false;
13671
+ // var faded = false;
13672
+ // var fadeBtn, clearBtn; // not in use
13673
+ var addBtn, addLayerBtn, cancelBtn;
13674
+ var customStyles = [];
13583
13675
 
13584
13676
  if (params) {
13585
13677
  // TODO: check page URL for compatibility with mapbox key
13586
13678
  init();
13587
13679
  } else {
13588
- menu.findChild('.basemap-opts').hide();
13680
+ menuWrapper.findChild('.basemap-opts').hide();
13589
13681
  }
13590
13682
 
13591
13683
  function init() {
13592
13684
  gui.on('mode', function(e) {
13593
13685
  if (e.prev == 'display_options') {
13594
- basemapWarning.hide();
13595
- basemapNote.hide();
13686
+ // reset UI when leaving display options mode
13687
+ basemapWarning.hide();
13688
+ basemapNote.hide();
13689
+ // make sure secondary options menu gets closed
13690
+ mainMenu.show();
13691
+ addLayerMenu.hide();
13596
13692
  }
13597
13693
  if (e.name == 'display_options') {
13598
13694
  onUpdate();
13599
13695
  }
13600
13696
  });
13601
13697
 
13602
- clearBtn.on('click', function() {
13603
- if (activeStyle) {
13604
- turnOffBasemap();
13605
- updateButtons();
13606
- // closeMenu();
13607
- }
13698
+ customStyles = GUI.getSavedValue('custom_basemaps') || [];
13699
+ updateBasemapList();
13700
+
13701
+ addBtn = new SimpleButton(menuWrapper.findChild('.add-btn'));
13702
+ addBtn.on('click', function(e) {
13703
+ addLayerMenu.show();
13704
+ mainMenu.hide();
13608
13705
  });
13609
13706
 
13610
- fadeBtn.on('click', function() {
13611
- if (faded) {
13612
- mapEl.css('opacity', 1);
13613
- faded = false;
13614
- fadeBtn.text('Fade');
13615
- } else if (activeStyle) {
13616
- mapEl.css('opacity', 0.35);
13617
- faded = true;
13618
- fadeBtn.text('Unfade');
13619
- }
13707
+ addLayerBtn = new SimpleButton(menuWrapper.findChild('.add-layer-btn'));
13708
+ addLayerBtn.on('click', function(e) {
13709
+ var name = menuWrapper.findChild('.add-layer-name').el.value || 'Custom layer';
13710
+ var mapboxUrl = menuWrapper.findChild('.add-mapbox-url').el.value;
13711
+ var mapboxKey = menuWrapper.findChild('.add-mapbox-key')?.el?.value;
13712
+ var templateUrl = menuWrapper.findChild('.add-template-url').el.value;
13713
+ var style = {name};
13714
+
13715
+ if (mapboxUrl) {
13716
+ style.url = mapboxUrl;
13717
+ style.key = mapboxKey; // may be undefined
13718
+ style.type = 'mapbox';
13719
+ } else if (templateUrl) {
13720
+ style.url = templateUrl;
13721
+ style.type = menuWrapper.findChild('.tms').el.checked ? 'tms' : 'xyz';
13722
+ }
13723
+
13724
+ customStyles.push(style);
13725
+ updateBasemapList();
13726
+ showBasemap(style);
13727
+ addLayerMenu.hide();
13728
+ mainMenu.show();
13729
+ });
13730
+
13731
+ cancelBtn = new SimpleButton(menuWrapper.findChild('.add-cancel-btn'));
13732
+ cancelBtn.on('click', function() {
13733
+ addLayerMenu.hide();
13734
+ mainMenu.show();
13620
13735
  });
13621
13736
 
13737
+ // fadeBtn = new SimpleButton(menuWrapper.findChild('.fade-btn'));
13738
+ // clearBtn = new SimpleButton(menuWrapper.findChild('.clear-btn'));
13739
+ // clearBtn.on('click', function() {
13740
+ // if (activeStyle) {
13741
+ // turnOffBasemap();
13742
+ // }
13743
+ // });
13744
+
13745
+ // fadeBtn.on('click', function() {
13746
+ // if (faded) {
13747
+ // mapEl.css('opacity', 1);
13748
+ // faded = false;
13749
+ // fadeBtn.text('Fade');
13750
+ // } else if (activeStyle) {
13751
+ // mapEl.css('opacity', 0.35);
13752
+ // faded = true;
13753
+ // fadeBtn.text('Unfade');
13754
+ // }
13755
+ // });
13756
+
13622
13757
  gui.model.on('update', onUpdate);
13623
13758
 
13624
13759
  gui.on('map_click', function() {
@@ -13627,10 +13762,10 @@ GUI and setting the size and crop of SVG output.</p><div><input type="text" clas
13627
13762
  });
13628
13763
 
13629
13764
  params.styles.forEach(function(style) {
13630
- El('div')
13631
- .html(`<div class="basemap-style-btn"><img src="${style.icon}"></img></div><div class="basemap-style-label">${style.name}</div>`)
13632
- .appendTo(menuButtons)
13633
- .findChild('.basemap-style-btn').on('click', onClick);
13765
+ // El('div')
13766
+ // .html(`<div class="basemap-style-btn"><img src="${style.icon}"></img></div><div class="basemap-style-label">${style.name}</div>`)
13767
+ // .appendTo(menuButtons)
13768
+ // .findChild('.basemap-style-btn').on('click', onClick);
13634
13769
 
13635
13770
  El('div').addClass('basemap-overlay-btn basemap-style-btn')
13636
13771
  .html(`<img src="${style.icon}"></img>`).on('click', onClick)
@@ -13644,7 +13779,6 @@ GUI and setting the size and crop of SVG output.</p><div><input type="text" clas
13644
13779
  showBasemap(style);
13645
13780
  }
13646
13781
  updateButtons();
13647
- // closeMenu();
13648
13782
  }
13649
13783
  });
13650
13784
  }
@@ -13659,7 +13793,6 @@ GUI and setting the size and crop of SVG output.</p><div><input type="text" clas
13659
13793
  function turnOffBasemap() {
13660
13794
  activeStyle = null;
13661
13795
  gui.map.setDisplayCRS(null);
13662
- refresh();
13663
13796
  }
13664
13797
 
13665
13798
  function showBasemap(style) {
@@ -13668,20 +13801,98 @@ GUI and setting the size and crop of SVG output.</p><div><input type="text" clas
13668
13801
  // Make sure that the selected layer style gets updated in gui-map.js
13669
13802
  // gui.state.dark_basemap = style && style.dark || false;
13670
13803
  if (map) {
13671
- map.setStyle(style.url);
13804
+ setStyle(activeStyle);
13672
13805
  refresh();
13673
13806
  } else if (prepareMapView()) {
13674
13807
  initMap();
13675
13808
  }
13676
13809
  }
13677
13810
 
13678
- function updateButtons() {
13679
- menuButtons.findChildren('.basemap-style-btn').forEach(function(el, i) {
13680
- el.classed('active', params.styles[i] == activeStyle);
13811
+ function updateBasemapList() {
13812
+ var styles = params.styles.concat(customStyles);
13813
+ basemapList.empty();
13814
+ styles.forEach(function(style) {
13815
+ renderBasemapListItem(basemapList, style);
13816
+ });
13817
+ updateButtons();
13818
+ GUI.setSavedValue('custom_basemaps', customStyles);
13819
+ }
13820
+
13821
+ function isActiveStyle(style) {
13822
+ return style.url == activeStyle?.url;
13823
+ }
13824
+
13825
+ function renderBasemapListItem(parent, style) {
13826
+ var isCustomStyle = !!style.type;
13827
+ var el = El('div').html(`<div data-slug="${getStyleId(style)}" class="basemap-list-item"><img class="on-icon" src="images/eye3.png"><img class="off-icon" src="images/eye.png"> ${style.name} ${isCustomStyle ? '<img class="close-btn" draggable="false" src="images/close.png">' : ''}</div>`);
13828
+ el.appendTo(parent);
13829
+ el.findChild('.basemap-list-item').on('click', function() {
13830
+ if (isActiveStyle(style)) {
13831
+ turnOffBasemap();
13832
+ } else {
13833
+ showBasemap(style);
13834
+ }
13835
+ });
13836
+
13837
+ var closeBtn = el.findChild('.close-btn');
13838
+ closeBtn?.on('click', function(e) {
13839
+ e.stopPropagation();
13840
+ customStyles = customStyles.filter(function(o) {
13841
+ return o.url != style.url;
13842
+ });
13843
+ updateBasemapList();
13844
+ if (isActiveStyle(style)) {
13845
+ turnOffBasemap();
13846
+ }
13681
13847
  });
13848
+ el.appendTo(parent);
13849
+ }
13850
+
13851
+ function getStyleId(style) {
13852
+ return ((style.name || '') + style.url).replace(/[^a-z0-9_]+/ig, '_');
13853
+ }
13854
+
13855
+ function setStyle(style) {
13856
+ // update mapbox access token (user-defined styles may have a different key)
13857
+ window.mapboxgl.accessToken = style.key || (window.location.hostname == 'localhost' ?
13858
+ params.localhost_key : params.production_key) || params.key;
13859
+
13860
+ if (style.type == 'mapbox' || !style.type) {
13861
+ map.setStyle(style.url);
13862
+ } else if (style.type == 'xyz' || style.type == 'tms') {
13863
+ map.setStyle({
13864
+ 'version': 8,
13865
+ 'sources': {
13866
+ 'raster-tiles': {
13867
+ 'type': 'raster',
13868
+ 'tiles': [style.url],
13869
+ 'scheme': style.type, // xyz or tms
13870
+ 'tileSize': 256, // style.url.includes('@2x') ? 512 : 256
13871
+ }
13872
+ },
13873
+ 'layers': [
13874
+ {
13875
+ 'id': getStyleId(style),
13876
+ 'type': 'raster',
13877
+ 'source': 'raster-tiles',
13878
+ 'minzoom': 0
13879
+ // 'maxzoom': 22
13880
+ }
13881
+ ]
13882
+ });
13883
+ } else {
13884
+ error$1('unsupported map style:', style);
13885
+ }
13886
+ }
13887
+
13888
+ function updateButtons() {
13682
13889
  overlayButtons.findChildren('.basemap-style-btn').forEach(function(el, i) {
13683
13890
  el.classed('active', params.styles[i] == activeStyle);
13684
13891
  });
13892
+
13893
+ menuWrapper.findChildren('.basemap-list-item').forEach(function(el, i) {
13894
+ el.classed('active', el.node().getAttribute('data-slug') == (activeStyle ? getStyleId(activeStyle) : ''));
13895
+ });
13685
13896
  }
13686
13897
 
13687
13898
  function onUpdate() {
@@ -13689,16 +13900,18 @@ GUI and setting the size and crop of SVG output.</p><div><input type="text" clas
13689
13900
  var info = getDatasetCrsInfo(activeLyr?.dataset); // defaults to wgs84
13690
13901
  var dataCRS = info.crs || null;
13691
13902
  var displayCRS = gui.map.getDisplayCRS();
13903
+ var basemapsNotAvailable = !dataCRS || !displayCRS || !crsIsUsable(displayCRS) || !crsIsUsable(dataCRS);
13692
13904
  var warning, note;
13693
13905
 
13694
-
13695
- if (!dataCRS || !displayCRS || !crsIsUsable(displayCRS) || !crsIsUsable(dataCRS)) {
13906
+ if (basemapsNotAvailable) {
13696
13907
  warning = 'This data is incompatible with the basemaps.';
13697
- if (!internal.layerHasGeometry(activeLyr.layer)) {
13908
+ if (activeLyr && !internal.layerHasGeometry(activeLyr.layer)) {
13698
13909
  warning += ' Reason: layer is missing geographic data';
13699
13910
  } else if (!dataCRS) {
13700
13911
  warning += ' Reason: unknown projection.';
13701
13912
  }
13913
+ basemapList.hide();
13914
+ addBasemap.hide();
13702
13915
  basemapWarning.html(warning).show();
13703
13916
  basemapNote.hide();
13704
13917
  overlayButtons.addClass('disabled');
@@ -13708,6 +13921,8 @@ GUI and setting the size and crop of SVG output.</p><div><input type="text" clas
13708
13921
  note = `Note: basemaps use the Mercator projection.`;
13709
13922
  basemapNote.text(note).show();
13710
13923
  overlayButtons.show();
13924
+ basemapList.show();
13925
+ addBasemap.show();
13711
13926
  overlayButtons.removeClass('disabled');
13712
13927
  }
13713
13928
  }
@@ -13734,32 +13949,33 @@ GUI and setting the size and crop of SVG output.</p><div><input type="text" clas
13734
13949
  return bbox2;
13735
13950
  }
13736
13951
 
13737
- function initMap() {
13738
- var accessToken = (window.location.hostname == 'localhost' ?
13739
- params.localhost_key : params.production_key) || params.key;
13952
+ async function initMap() {
13953
+ // var accessToken = (window.location.hostname == 'localhost' ?
13954
+ // params.localhost_key : params.production_key) || params.key;
13740
13955
  if (!enabled() || map || loading) return;
13741
13956
  loading = true;
13742
13957
  loadStylesheet(params.css);
13743
- loadScript(params.js, function() {
13744
- map = new window.mapboxgl.Map({
13745
- accessToken: accessToken,
13746
- logoPosition: 'bottom-left',
13747
- container: mapEl.node(),
13748
- style: activeStyle.url,
13749
- bounds: getLonLatBounds(),
13750
- doubleClickZoom: false,
13751
- dragPan: false,
13752
- dragRotate: false,
13753
- scrollZoom: false,
13754
- interactive: false,
13755
- keyboard: false,
13756
- maxPitch: 0,
13757
- renderWorldCopies: true // false // false prevents panning off the map
13758
- });
13759
- map.on('load', function() {
13760
- loading = false;
13761
- refresh();
13762
- });
13958
+ await loadScript(params.js);
13959
+ map = new window.mapboxgl.Map({
13960
+ logoPosition: 'bottom-left',
13961
+ container: mapEl.node(),
13962
+ // style: activeStyle.url,
13963
+ style: EMPTY_STYLE, // initializing with empty style to support custom styles
13964
+ bounds: getLonLatBounds(),
13965
+ doubleClickZoom: false,
13966
+ dragPan: false,
13967
+ dragRotate: false,
13968
+ scrollZoom: false,
13969
+ interactive: false,
13970
+ keyboard: false,
13971
+ maxPitch: 0,
13972
+ projection: 'mercator', // prevent globe view when zoomed out
13973
+ renderWorldCopies: true // false // false prevents panning off the map
13974
+ });
13975
+ setStyle(activeStyle);
13976
+ map.on('load', function() {
13977
+ loading = false;
13978
+ refresh();
13763
13979
  });
13764
13980
  }
13765
13981
 
@@ -13804,8 +14020,11 @@ GUI and setting the size and crop of SVG output.</p><div><input type="text" clas
13804
14020
  function refresh() {
13805
14021
  var off = !enabled() || !map || loading || !activeStyle ||
13806
14022
  !gui.map.getDisplayCRS(); // may be slow if getting bounds of many shapes
13807
- fadeBtn.active(!off);
13808
- clearBtn.active(!off);
14023
+ // fadeBtn.active(!off);
14024
+ // clearBtn.active(!off);
14025
+
14026
+ updateButtons();
14027
+
13809
14028
  if (off) {
13810
14029
  hide();
13811
14030
  extentNote.hide();