mapshaper 0.6.111 → 0.6.113

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.
@@ -655,9 +655,14 @@
655
655
  },
656
656
 
657
657
  show: function(css) {
658
- var tag = this.el && this.el.tagName;
658
+ // var tag = this.el && this.el.tagName;
659
659
  if (!this.visible()) {
660
- this.css('display', tag == 'SPAN' ? 'inline-block' : 'block');
660
+ // don't assume 'display:block'
661
+ this.el?.style.removeProperty('display');
662
+ if (this.computedStyle().display == 'none') {
663
+ this.css('display', 'block');
664
+ }
665
+ // this.css('display', tag == 'SPAN' ? 'inline-block' : 'block');
661
666
  this._hidden = false;
662
667
  }
663
668
  return this;
@@ -666,13 +671,15 @@
666
671
  html: function(html) {
667
672
  if (arguments.length == 0) {
668
673
  return this.el.innerHTML;
669
- } else {
670
- this.el.innerHTML = html;
671
- return this;
672
674
  }
675
+ this.el.innerHTML = html;
676
+ return this;
673
677
  },
674
678
 
675
679
  text: function(str) {
680
+ if (arguments.length == 0) {
681
+ return this.el.innerText;
682
+ }
676
683
  this.html(utils$1.htmlEscape(str));
677
684
  return this;
678
685
  },
@@ -1936,14 +1943,27 @@
1936
1943
  .on('drop', ondrop)
1937
1944
  .on('paste', onpaste);
1938
1945
  area.node().addEventListener('paste', onpaste);
1946
+ // TODO: use same function for drop and paste
1939
1947
  function ondrop(e) {
1948
+ var files = e.dataTransfer.files;
1949
+ var types = e.dataTransfer.types;
1940
1950
  block(e);
1941
- cb(e.dataTransfer.files);
1951
+ if (files.length) {
1952
+ cb(files);
1953
+ } else if (types.includes('text/uri-list')) {
1954
+ cb(e.dataTransfer.getData('text/uri-list').split(','));
1955
+ } else if (types.includes('text/html')) {
1956
+ // drag-dropping a highlighted link may pull in a chunk of html
1957
+ var urls = pastedHtmlToUrls(e.dataTransfer.getData('text/html'));
1958
+ if (urls.length) {
1959
+ cb(urls);
1960
+ }
1961
+ }
1942
1962
  }
1943
1963
  function onpaste(e) {
1944
1964
  var types = Array.from(e.clipboardData.types || []).join(',');
1945
1965
  var items = Array.from(e.clipboardData.items || []);
1946
- var files;
1966
+ var files, str, urls;
1947
1967
  if (GUI.textIsSelected()) {
1948
1968
  // user is probably pasting text into an editable text field
1949
1969
  return;
@@ -1955,15 +1975,28 @@
1955
1975
  // Single files of all types are pasted as a string and an image/png
1956
1976
  // Multiple files are pasted as a string containing a list of file names
1957
1977
 
1958
- // import text from the clipboard (could be csv, json, etc)
1978
+ // import text from the clipboard (could be csv, json, a url, etc)
1959
1979
  // formatted text can be available as both text/plain and text/html (e.g.
1960
1980
  // a JSON data object copied from a GitHub issue).
1961
1981
  //
1982
+
1983
+ // if html is present, it could be data (e.g. from Google Sheets) or a pasted link.
1984
+ // first we check for a link
1985
+ if (types.includes('text/html')) {
1986
+ urls = pastedHtmlToUrls(e.clipboardData.getData('text/html'));
1987
+ if (urls.length) {
1988
+ return cb(urls);
1989
+ }
1990
+ }
1962
1991
  if (types.includes('text/plain')) {
1963
- // if (types == 'text/plain') {
1964
1992
  // text from clipboard (supported by Chrome, FF, Safari)
1965
1993
  // TODO: handle FF case of string containing multiple file names.
1966
- files = [pastedTextToFile(e.clipboardData.getData('text/plain'))];
1994
+ str = e.clipboardData.getData('text/plain');
1995
+ urls = pastedTextToUrls(str);
1996
+ if (urls.length) {
1997
+ return cb(urls);
1998
+ }
1999
+ files = [pastedTextToFile(str)];
1967
2000
  } else {
1968
2001
  files = items.map(function(item) {
1969
2002
  return item.kind == 'file' && !item.type.includes('image') ?
@@ -1983,6 +2016,21 @@
1983
2016
  }
1984
2017
  }
1985
2018
 
2019
+ function pastedHtmlToUrls(html) {
2020
+ var hrefRegex = /href\s*=\s*["']([^"']+)["']/gi;
2021
+ var matches = html.matchAll(hrefRegex);
2022
+ var urls = Array.from(matches, match => match[1]);
2023
+ return urls;
2024
+ }
2025
+
2026
+ function pastedTextToUrls(str) {
2027
+ if (!looksLikeUrl(str)) return [];
2028
+ var regex = /https?:\/\/[^\s]+?(?=[\s,]|$)/g;
2029
+ var matches = str.matchAll(regex);
2030
+ var urls = Array.from(matches, match => match[0]);
2031
+ return urls;
2032
+ }
2033
+
1986
2034
  function pastedTextToFile(str) {
1987
2035
  var type = internal.guessInputContentType(str);
1988
2036
  var name;
@@ -1997,6 +2045,10 @@
1997
2045
  return new File([blob], name);
1998
2046
  }
1999
2047
 
2048
+ function looksLikeUrl(str) {
2049
+ return /^https?:\/\//.test(str);
2050
+ }
2051
+
2000
2052
  // @el DOM element for select button
2001
2053
  // @cb function(<FileList>)
2002
2054
  function FileChooser(el, cb) {
@@ -2040,7 +2092,7 @@
2040
2092
 
2041
2093
  var submitBtn = new SimpleButton('#import-options .submit-btn').on('click', importQueuedFiles);
2042
2094
  new SimpleButton('#import-options .cancel-btn').on('click', gui.clearMode);
2043
- new DropControl(gui, 'body', receiveFilesWithOption);
2095
+ new DropControl(gui, 'body', receiveDroppedItems);
2044
2096
  new FileChooser('#import-options .add-btn', receiveFilesWithOption);
2045
2097
  new FileChooser('#add-file-btn', receiveFiles);
2046
2098
  new SimpleButton('#add-empty-btn').on('click', function() {
@@ -2056,7 +2108,7 @@
2056
2108
 
2057
2109
  function turnOn() {
2058
2110
  if (manifestFiles.length > 0) {
2059
- downloadFiles(manifestFiles, true);
2111
+ downloadFiles(manifestFiles);
2060
2112
  manifestFiles = [];
2061
2113
  } else if (model.isEmpty()) {
2062
2114
  showImportMenu();
@@ -2157,6 +2209,14 @@
2157
2209
  submitBtn.classed('disabled', queuedFiles.length === 0);
2158
2210
  }
2159
2211
 
2212
+ function receiveDroppedItems(arr) {
2213
+ if (utils$1.isString(arr[0])) { // assume array of URLs
2214
+ downloadFiles(arr);
2215
+ } else { // assume array of Files
2216
+ receiveFilesWithOption(arr);
2217
+ }
2218
+ }
2219
+
2160
2220
  function receiveFilesWithOption(files) {
2161
2221
  var quickView = !El('.advanced-import-options').node().checked;
2162
2222
  receiveFiles(files, quickView);
@@ -2312,9 +2372,8 @@
2312
2372
 
2313
2373
  function prepFilesForDownload(names) {
2314
2374
  var items = names.map(function(name) {
2315
- var isUrl = /:\/\//.test(name);
2316
2375
  var item = {name: name};
2317
- if (isUrl) {
2376
+ if (looksLikeUrl(name)) {
2318
2377
  item.url = name;
2319
2378
  item.basename = GUI.getUrlFilename(name);
2320
2379
 
@@ -2667,7 +2726,7 @@
2667
2726
  var lyr;
2668
2727
  if (memo) return memo; // already found a match
2669
2728
  // try to match import filename of this dataset
2670
- if (d.info.input_files[0] == src) return d;
2729
+ if (d.info?.input_files?.[0] == src) return d;
2671
2730
  // try to match name of a layer in this dataset
2672
2731
  lyr = utils$1.find(d.layers, function(lyr) {return lyr.name == src;});
2673
2732
  return lyr ? internal.isolateLayer(lyr, d) : null;
@@ -5068,7 +5127,7 @@
5068
5127
  var lyr = o.layer;
5069
5128
  var opts = {
5070
5129
  show_source: layerCount < 5,
5071
- pinnable: pinnableCount > 1 && isPinnable(lyr)
5130
+ pinnable: pinnableCount > 0 && isPinnable(lyr)
5072
5131
  };
5073
5132
  var html, element;
5074
5133
  html = renderLayer(lyr, o.dataset, opts);
@@ -6299,6 +6358,18 @@
6299
6358
  }
6300
6359
  }
6301
6360
 
6361
+ function time(slug) {
6362
+ if (useDebug()) {
6363
+ console.time(slug);
6364
+ }
6365
+ }
6366
+
6367
+ function timeEnd(slug) {
6368
+ if (useDebug()) {
6369
+ console.timeEnd(slug);
6370
+ }
6371
+ }
6372
+
6302
6373
  function printError(err) {
6303
6374
  var msg;
6304
6375
  if (!LOGGING) return;
@@ -7462,8 +7533,13 @@
7462
7533
  if (len >= 2) {
7463
7534
  first = str.charAt(0);
7464
7535
  last = str.charAt(len-1);
7465
- if (first == '"' && last == '"' && !str.includes('","') ||
7466
- first == "'" && last == "'" && !str.includes("','")) {
7536
+ // if (first == '"' && last == '"' && !str.includes('","') ||
7537
+ // first == "'" && last == "'" && !str.includes("','")) {
7538
+ // don't strip if there are unescaped quotes
7539
+ // e.g. expressions that start and end with quotes
7540
+ // e.g. comma-separated list of quoted values
7541
+ if (first == '"' && last == '"' && !/[^\\]"./.test(str) ||
7542
+ first == "'" && last == "'" && !/[^\\]'./.test(str)) {
7467
7543
  str = str.substr(1, len-2);
7468
7544
  // remove string escapes
7469
7545
  str = str.replace(first == '"' ? /\\(?=")/g : /\\(?=')/g, '');
@@ -13505,6 +13581,12 @@ GUI and setting the size and crop of SVG output.</p><div><input type="text" clas
13505
13581
  });
13506
13582
  }
13507
13583
 
13584
+ var EMPTY_STYLE = {
13585
+ version: 8,
13586
+ sources: {},
13587
+ layers: []
13588
+ };
13589
+
13508
13590
  function loadScript(url, cb) {
13509
13591
  var script = document.createElement('script');
13510
13592
  script.onload = cb;
@@ -13522,60 +13604,107 @@ GUI and setting the size and crop of SVG output.</p><div><input type="text" clas
13522
13604
  }
13523
13605
 
13524
13606
  function Basemap(gui) {
13525
- var menu = gui.container.findChild('.display-options');
13526
- var fadeBtn = new SimpleButton(menu.findChild('.fade-btn'));
13527
- var clearBtn = new SimpleButton(menu.findChild('.clear-btn'));
13528
- var menuButtons = menu.findChild('.basemap-styles');
13607
+ var menuWrapper = gui.container.findChild('.display-options');
13608
+ var mainMenu = gui.container.findChild('.display-main-options');
13609
+ var addLayerMenu = gui.container.findChild('.add-basemap-menu').hide();
13610
+ var basemapList = gui.container.findChild('.added-basemaps');
13529
13611
  var overlayButtons = gui.container.findChild('.basemap-overlay-buttons');
13530
13612
  var container = gui.container.findChild('.basemap-container');
13531
13613
  var basemapNote = gui.container.findChild('.basemap-note');
13532
- var basemapWarning = gui.container.findChild('.basemap-warning');
13614
+ var addBasemap = gui.container.findChild('.add-basemap');
13615
+ var basemapWarning = gui.container.findChild('.basemap-warning').hide();
13533
13616
  var mapEl = gui.container.findChild('.basemap');
13534
13617
  var extentNote = El('div').addClass('basemap-prompt').appendTo(container).hide();
13535
13618
  var params = window.mapboxParams;
13536
13619
  var map;
13537
13620
  var activeStyle;
13538
13621
  var loading = false;
13539
- var faded = false;
13622
+ // var faded = false;
13623
+ // var fadeBtn, clearBtn; // not in use
13624
+ var addBtn, addLayerBtn, cancelBtn;
13625
+ var customStyles = [];
13540
13626
 
13541
13627
  if (params) {
13542
13628
  // TODO: check page URL for compatibility with mapbox key
13543
13629
  init();
13544
13630
  } else {
13545
- menu.findChild('.basemap-opts').hide();
13631
+ menuWrapper.findChild('.basemap-opts').hide();
13546
13632
  }
13547
13633
 
13548
13634
  function init() {
13549
13635
  gui.on('mode', function(e) {
13550
13636
  if (e.prev == 'display_options') {
13551
- basemapWarning.hide();
13552
- basemapNote.hide();
13637
+ // reset UI when leaving display options mode
13638
+ basemapWarning.hide();
13639
+ basemapNote.hide();
13640
+ // make sure secondary options menu gets closed
13641
+ mainMenu.show();
13642
+ addLayerMenu.hide();
13553
13643
  }
13554
13644
  if (e.name == 'display_options') {
13555
13645
  onUpdate();
13556
13646
  }
13557
13647
  });
13558
13648
 
13559
- clearBtn.on('click', function() {
13560
- if (activeStyle) {
13561
- turnOffBasemap();
13562
- updateButtons();
13563
- // closeMenu();
13564
- }
13649
+ customStyles = GUI.getSavedValue('custom_basemaps') || [];
13650
+ updateBasemapList();
13651
+
13652
+ addBtn = new SimpleButton(menuWrapper.findChild('.add-btn'));
13653
+ addBtn.on('click', function(e) {
13654
+ addLayerMenu.show();
13655
+ mainMenu.hide();
13565
13656
  });
13566
13657
 
13567
- fadeBtn.on('click', function() {
13568
- if (faded) {
13569
- mapEl.css('opacity', 1);
13570
- faded = false;
13571
- fadeBtn.text('Fade');
13572
- } else if (activeStyle) {
13573
- mapEl.css('opacity', 0.35);
13574
- faded = true;
13575
- fadeBtn.text('Unfade');
13576
- }
13658
+ addLayerBtn = new SimpleButton(menuWrapper.findChild('.add-layer-btn'));
13659
+ addLayerBtn.on('click', function(e) {
13660
+ var name = menuWrapper.findChild('.add-layer-name').el.value || 'Custom layer';
13661
+ var mapboxUrl = menuWrapper.findChild('.add-mapbox-url').el.value;
13662
+ var mapboxKey = menuWrapper.findChild('.add-mapbox-key')?.el?.value;
13663
+ var templateUrl = menuWrapper.findChild('.add-template-url').el.value;
13664
+ var style = {name};
13665
+
13666
+ if (mapboxUrl) {
13667
+ style.url = mapboxUrl;
13668
+ style.key = mapboxKey; // may be undefined
13669
+ style.type = 'mapbox';
13670
+ } else if (templateUrl) {
13671
+ style.url = templateUrl;
13672
+ style.type = menuWrapper.findChild('.tms').el.checked ? 'tms' : 'xyz';
13673
+ }
13674
+
13675
+ customStyles.push(style);
13676
+ updateBasemapList();
13677
+ showBasemap(style);
13678
+ addLayerMenu.hide();
13679
+ mainMenu.show();
13577
13680
  });
13578
13681
 
13682
+ cancelBtn = new SimpleButton(menuWrapper.findChild('.add-cancel-btn'));
13683
+ cancelBtn.on('click', function() {
13684
+ addLayerMenu.hide();
13685
+ mainMenu.show();
13686
+ });
13687
+
13688
+ // fadeBtn = new SimpleButton(menuWrapper.findChild('.fade-btn'));
13689
+ // clearBtn = new SimpleButton(menuWrapper.findChild('.clear-btn'));
13690
+ // clearBtn.on('click', function() {
13691
+ // if (activeStyle) {
13692
+ // turnOffBasemap();
13693
+ // }
13694
+ // });
13695
+
13696
+ // fadeBtn.on('click', function() {
13697
+ // if (faded) {
13698
+ // mapEl.css('opacity', 1);
13699
+ // faded = false;
13700
+ // fadeBtn.text('Fade');
13701
+ // } else if (activeStyle) {
13702
+ // mapEl.css('opacity', 0.35);
13703
+ // faded = true;
13704
+ // fadeBtn.text('Unfade');
13705
+ // }
13706
+ // });
13707
+
13579
13708
  gui.model.on('update', onUpdate);
13580
13709
 
13581
13710
  gui.on('map_click', function() {
@@ -13584,10 +13713,10 @@ GUI and setting the size and crop of SVG output.</p><div><input type="text" clas
13584
13713
  });
13585
13714
 
13586
13715
  params.styles.forEach(function(style) {
13587
- El('div')
13588
- .html(`<div class="basemap-style-btn"><img src="${style.icon}"></img></div><div class="basemap-style-label">${style.name}</div>`)
13589
- .appendTo(menuButtons)
13590
- .findChild('.basemap-style-btn').on('click', onClick);
13716
+ // El('div')
13717
+ // .html(`<div class="basemap-style-btn"><img src="${style.icon}"></img></div><div class="basemap-style-label">${style.name}</div>`)
13718
+ // .appendTo(menuButtons)
13719
+ // .findChild('.basemap-style-btn').on('click', onClick);
13591
13720
 
13592
13721
  El('div').addClass('basemap-overlay-btn basemap-style-btn')
13593
13722
  .html(`<img src="${style.icon}"></img>`).on('click', onClick)
@@ -13601,7 +13730,6 @@ GUI and setting the size and crop of SVG output.</p><div><input type="text" clas
13601
13730
  showBasemap(style);
13602
13731
  }
13603
13732
  updateButtons();
13604
- // closeMenu();
13605
13733
  }
13606
13734
  });
13607
13735
  }
@@ -13616,7 +13744,6 @@ GUI and setting the size and crop of SVG output.</p><div><input type="text" clas
13616
13744
  function turnOffBasemap() {
13617
13745
  activeStyle = null;
13618
13746
  gui.map.setDisplayCRS(null);
13619
- refresh();
13620
13747
  }
13621
13748
 
13622
13749
  function showBasemap(style) {
@@ -13625,20 +13752,98 @@ GUI and setting the size and crop of SVG output.</p><div><input type="text" clas
13625
13752
  // Make sure that the selected layer style gets updated in gui-map.js
13626
13753
  // gui.state.dark_basemap = style && style.dark || false;
13627
13754
  if (map) {
13628
- map.setStyle(style.url);
13755
+ setStyle(activeStyle);
13629
13756
  refresh();
13630
13757
  } else if (prepareMapView()) {
13631
13758
  initMap();
13632
13759
  }
13633
13760
  }
13634
13761
 
13635
- function updateButtons() {
13636
- menuButtons.findChildren('.basemap-style-btn').forEach(function(el, i) {
13637
- el.classed('active', params.styles[i] == activeStyle);
13762
+ function updateBasemapList() {
13763
+ var styles = params.styles.concat(customStyles);
13764
+ basemapList.empty();
13765
+ styles.forEach(function(style) {
13766
+ renderBasemapListItem(basemapList, style);
13767
+ });
13768
+ updateButtons();
13769
+ GUI.setSavedValue('custom_basemaps', customStyles);
13770
+ }
13771
+
13772
+ function isActiveStyle(style) {
13773
+ return style.url == activeStyle?.url;
13774
+ }
13775
+
13776
+ function renderBasemapListItem(parent, style) {
13777
+ var isCustomStyle = !!style.type;
13778
+ 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>`);
13779
+ el.appendTo(parent);
13780
+ el.findChild('.basemap-list-item').on('click', function() {
13781
+ if (isActiveStyle(style)) {
13782
+ turnOffBasemap();
13783
+ } else {
13784
+ showBasemap(style);
13785
+ }
13786
+ });
13787
+
13788
+ var closeBtn = el.findChild('.close-btn');
13789
+ closeBtn?.on('click', function(e) {
13790
+ e.stopPropagation();
13791
+ customStyles = customStyles.filter(function(o) {
13792
+ return o.url != style.url;
13793
+ });
13794
+ updateBasemapList();
13795
+ if (isActiveStyle(style)) {
13796
+ turnOffBasemap();
13797
+ }
13638
13798
  });
13799
+ el.appendTo(parent);
13800
+ }
13801
+
13802
+ function getStyleId(style) {
13803
+ return ((style.name || '') + style.url).replace(/[^a-z0-9_]+/ig, '_');
13804
+ }
13805
+
13806
+ function setStyle(style) {
13807
+ // update mapbox access token (user-defined styles may have a different key)
13808
+ window.mapboxgl.accessToken = style.key || (window.location.hostname == 'localhost' ?
13809
+ params.localhost_key : params.production_key) || params.key;
13810
+
13811
+ if (style.type == 'mapbox' || !style.type) {
13812
+ map.setStyle(style.url);
13813
+ } else if (style.type == 'xyz' || style.type == 'tms') {
13814
+ map.setStyle({
13815
+ 'version': 8,
13816
+ 'sources': {
13817
+ 'raster-tiles': {
13818
+ 'type': 'raster',
13819
+ 'tiles': [style.url],
13820
+ 'scheme': style.type, // xyz or tms
13821
+ 'tileSize': 256, // style.url.includes('@2x') ? 512 : 256
13822
+ }
13823
+ },
13824
+ 'layers': [
13825
+ {
13826
+ 'id': getStyleId(style),
13827
+ 'type': 'raster',
13828
+ 'source': 'raster-tiles',
13829
+ 'minzoom': 0
13830
+ // 'maxzoom': 22
13831
+ }
13832
+ ]
13833
+ });
13834
+ } else {
13835
+ error$1('unsupported map style:', style);
13836
+ }
13837
+ }
13838
+
13839
+ function updateButtons() {
13639
13840
  overlayButtons.findChildren('.basemap-style-btn').forEach(function(el, i) {
13640
13841
  el.classed('active', params.styles[i] == activeStyle);
13641
13842
  });
13843
+
13844
+ menuWrapper.findChildren('.basemap-list-item').forEach(function(el, i) {
13845
+ el.classed('active', el.node().getAttribute('data-slug') == (activeStyle ? getStyleId(activeStyle) : ''));
13846
+ });
13642
13847
  }
13643
13848
 
13644
13849
  function onUpdate() {
@@ -13646,16 +13851,18 @@ GUI and setting the size and crop of SVG output.</p><div><input type="text" clas
13646
13851
  var info = getDatasetCrsInfo(activeLyr?.dataset); // defaults to wgs84
13647
13852
  var dataCRS = info.crs || null;
13648
13853
  var displayCRS = gui.map.getDisplayCRS();
13854
+ var basemapsNotAvailable = !dataCRS || !displayCRS || !crsIsUsable(displayCRS) || !crsIsUsable(dataCRS);
13649
13855
  var warning, note;
13650
13856
 
13651
-
13652
- if (!dataCRS || !displayCRS || !crsIsUsable(displayCRS) || !crsIsUsable(dataCRS)) {
13857
+ if (basemapsNotAvailable) {
13653
13858
  warning = 'This data is incompatible with the basemaps.';
13654
- if (!internal.layerHasGeometry(activeLyr.layer)) {
13859
+ if (activeLyr && !internal.layerHasGeometry(activeLyr.layer)) {
13655
13860
  warning += ' Reason: layer is missing geographic data';
13656
13861
  } else if (!dataCRS) {
13657
13862
  warning += ' Reason: unknown projection.';
13658
13863
  }
13864
+ basemapList.hide();
13865
+ addBasemap.hide();
13659
13866
  basemapWarning.html(warning).show();
13660
13867
  basemapNote.hide();
13661
13868
  overlayButtons.addClass('disabled');
@@ -13665,6 +13872,8 @@ GUI and setting the size and crop of SVG output.</p><div><input type="text" clas
13665
13872
  note = `Note: basemaps use the Mercator projection.`;
13666
13873
  basemapNote.text(note).show();
13667
13874
  overlayButtons.show();
13875
+ basemapList.show();
13876
+ addBasemap.show();
13668
13877
  overlayButtons.removeClass('disabled');
13669
13878
  }
13670
13879
  }
@@ -13692,17 +13901,17 @@ GUI and setting the size and crop of SVG output.</p><div><input type="text" clas
13692
13901
  }
13693
13902
 
13694
13903
  function initMap() {
13695
- var accessToken = (window.location.hostname == 'localhost' ?
13696
- params.localhost_key : params.production_key) || params.key;
13904
+ // var accessToken = (window.location.hostname == 'localhost' ?
13905
+ // params.localhost_key : params.production_key) || params.key;
13697
13906
  if (!enabled() || map || loading) return;
13698
13907
  loading = true;
13699
13908
  loadStylesheet(params.css);
13700
13909
  loadScript(params.js, function() {
13701
13910
  map = new window.mapboxgl.Map({
13702
- accessToken: accessToken,
13703
13911
  logoPosition: 'bottom-left',
13704
13912
  container: mapEl.node(),
13705
- style: activeStyle.url,
13913
+ // style: activeStyle.url,
13914
+ style: EMPTY_STYLE, // initializing with empty style to support custom styles
13706
13915
  bounds: getLonLatBounds(),
13707
13916
  doubleClickZoom: false,
13708
13917
  dragPan: false,
@@ -13711,8 +13920,10 @@ GUI and setting the size and crop of SVG output.</p><div><input type="text" clas
13711
13920
  interactive: false,
13712
13921
  keyboard: false,
13713
13922
  maxPitch: 0,
13923
+ projection: 'mercator', // prevent globe view when zoomed out
13714
13924
  renderWorldCopies: true // false // false prevents panning off the map
13715
13925
  });
13926
+ setStyle(activeStyle);
13716
13927
  map.on('load', function() {
13717
13928
  loading = false;
13718
13929
  refresh();
@@ -13761,8 +13972,11 @@ GUI and setting the size and crop of SVG output.</p><div><input type="text" clas
13761
13972
  function refresh() {
13762
13973
  var off = !enabled() || !map || loading || !activeStyle ||
13763
13974
  !gui.map.getDisplayCRS(); // may be slow if getting bounds of many shapes
13764
- fadeBtn.active(!off);
13765
- clearBtn.active(!off);
13975
+ // fadeBtn.active(!off);
13976
+ // clearBtn.active(!off);
13977
+
13978
+ updateButtons();
13979
+
13766
13980
  if (off) {
13767
13981
  hide();
13768
13982
  extentNote.hide();