mapshaper 0.6.12 → 0.6.14

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.
@@ -682,11 +682,10 @@
682
682
  El.setStyle = function(el, name, val) {
683
683
  var jsName = El.toCamelCase(name);
684
684
  if (el.style[jsName] == void 0) {
685
- console.error("[Element.setStyle()] css property:", jsName);
686
685
  return;
687
686
  }
688
687
  var cssVal = val;
689
- if (isFinite(val)) {
688
+ if (isFinite(val) && val !== null) {
690
689
  cssVal = String(val); // problem if converted to scientific notation
691
690
  if (jsName != 'opacity' && jsName != 'zIndex') {
692
691
  cssVal += "px";
@@ -763,16 +762,14 @@
763
762
 
764
763
  // Apply inline css styles to this Element, either as string or object.
765
764
  css: function(css, val) {
766
- if (val != null) {
767
- El.setStyle(this.el, css, val);
768
- }
769
- else if (utils$1.isString(css)) {
770
- addCSS(this.el, css);
771
- }
772
- else if (utils$1.isObject(css)) {
765
+ if (utils$1.isObject(css)) {
773
766
  utils$1.forEachProperty(css, function(val, key) {
774
767
  El.setStyle(this.el, key, val);
775
768
  }, this);
769
+ } else if (val === void 0) {
770
+ addCSS(this.el, css);
771
+ } else {
772
+ El.setStyle(this.el, css, val);
776
773
  }
777
774
  return this;
778
775
  },
@@ -2469,13 +2466,13 @@
2469
2466
  // if map is at full extent, show full extent
2470
2467
  // TODO: handle case that scale is 1 and map is panned away from center
2471
2468
  if (ext.scale() == 1 || !dest) {
2472
- ext.setBounds(newBounds, strictBounds);
2469
+ ext.setFullBounds(newBounds, strictBounds);
2473
2470
  ext.home(); // sets full extent and triggers redraw
2474
2471
  } else {
2475
2472
  // if map is zoomed, stay centered on the same geographic location, at the same relative scale
2476
2473
  proj = internal.getProjTransform2(src, dest);
2477
2474
  newCP = proj(oldBounds.centerX(), oldBounds.centerY());
2478
- ext.setBounds(newBounds, strictBounds);
2475
+ ext.setFullBounds(newBounds, strictBounds);
2479
2476
  if (!newCP) {
2480
2477
  // projection of center point failed; use center of bounds
2481
2478
  // (also consider just resetting the view using ext.home())
@@ -3901,6 +3898,11 @@
3901
3898
  var history, offset, stashedUndo;
3902
3899
  reset();
3903
3900
 
3901
+ // Undo history is cleared when the editing mode changes.
3902
+ gui.on('interaction_mode_change', function(e) {
3903
+ gui.undo.clear();
3904
+ });
3905
+
3904
3906
  function reset() {
3905
3907
  history = [];
3906
3908
  stashedUndo = null;
@@ -4170,12 +4172,28 @@
4170
4172
 
4171
4173
  function InteractionMode(gui) {
4172
4174
 
4175
+ // TODO: finish this list
4176
+ // var modes = [{
4177
+ // name: 'info',
4178
+ // label: 'inspect features',
4179
+ // selection: true,
4180
+ // popup: true,
4181
+ // types: ['standard', 'polygons', 'lines', 'labels', 'points']
4182
+ // }, {
4183
+ // name: 'selection',
4184
+ // label: 'select features',
4185
+ // selection: true,
4186
+ // popup: true,
4187
+ // types: ['standard', 'polygons', 'lines', 'table', 'labels']
4188
+ // }]
4189
+
4173
4190
  var menus = {
4174
4191
  standard: ['info', 'selection', 'data', 'box'],
4175
4192
  polygons: ['info', 'selection', 'data', 'box', 'vertices'],
4176
4193
  lines: ['info', 'selection', 'data', 'box', 'vertices'],
4177
4194
  table: ['info', 'selection', 'data'],
4178
4195
  labels: ['info', 'selection', 'data', 'box', 'labels', 'location'],
4196
+ // points: ['info', 'selection', 'data', 'box', 'location', 'add-points']
4179
4197
  points: ['info', 'selection', 'data', 'box', 'location']
4180
4198
  };
4181
4199
 
@@ -4194,6 +4212,7 @@
4194
4212
  location: 'drag points',
4195
4213
  vertices: 'edit vertices',
4196
4214
  selection: 'select features',
4215
+ 'add-points': 'add points',
4197
4216
  off: 'turn off'
4198
4217
  };
4199
4218
  var btn, menu;
@@ -4246,6 +4265,10 @@
4246
4265
  setMode('off');
4247
4266
  };
4248
4267
 
4268
+ this.modeUsesSelection = function(mode) {
4269
+ return ['info', 'selection', 'data', 'labels', 'location', 'vertices'].includes(mode);
4270
+ };
4271
+
4249
4272
  this.modeUsesPopup = function(mode) {
4250
4273
  return ['info', 'selection', 'data', 'box', 'labels', 'location'].includes(mode);
4251
4274
  };
@@ -6292,10 +6315,11 @@
6292
6315
  // (some modes do not support pinning)
6293
6316
  gui.on('interaction_mode_change', function(e) {
6294
6317
  updateSelectionState(null);
6295
- if (e.mode == 'off' || e.mode == 'box') {
6296
- turnOff();
6297
- } else {
6318
+ // if (e.mode == 'off' || e.mode == 'box') {
6319
+ if (gui.interaction.modeUsesSelection(e.mode)) {
6298
6320
  turnOn(e.mode);
6321
+ } else {
6322
+ turnOff();
6299
6323
  }
6300
6324
  });
6301
6325
 
@@ -6990,6 +7014,7 @@
6990
7014
  handles.forEach(function(handle) {
6991
7015
  handle.el.on('mousedown', function(e) {
6992
7016
  activeHandle = handle;
7017
+ activeHandle.el.css('background', 'black');
6993
7018
  prevXY = {x: e.pageX, y: e.pageY};
6994
7019
  });
6995
7020
  });
@@ -7017,6 +7042,7 @@
7017
7042
 
7018
7043
  document.addEventListener('mouseup', function() {
7019
7044
  if (activeHandle && _on) {
7045
+ activeHandle.el.css('background', null);
7020
7046
  activeHandle = null;
7021
7047
  prevXY = null;
7022
7048
  box.dispatchEvent('handle_up');
@@ -7059,7 +7085,7 @@
7059
7085
  el.css(props);
7060
7086
  el.show();
7061
7087
  if (handles) {
7062
- showHandles(handles, props);
7088
+ showHandles(handles, props, x2 < x1, y2 < y1);
7063
7089
  }
7064
7090
  };
7065
7091
 
@@ -7124,25 +7150,26 @@
7124
7150
  return handles;
7125
7151
  }
7126
7152
 
7127
- function showHandles(handles, props) {
7128
- var scaledSize = Math.ceil(Math.min(props.width, props.height) / 5);
7153
+ function showHandles(handles, props, xinv, yinv) {
7154
+ var scaledSize = Math.ceil(Math.min(props.width, props.height) / 3) - 1;
7129
7155
  var HANDLE_SIZE = Math.min(scaledSize, 7);
7156
+ var OFFS = Math.floor(HANDLE_SIZE / 2) + 1;
7130
7157
  handles.forEach(function(handle) {
7131
7158
  var top = 0,
7132
7159
  left = 0;
7133
7160
  if (handle.col == 'center') {
7134
7161
  left += props.width / 2 - HANDLE_SIZE / 2;
7135
- } else if (handle.col == 'right') {
7136
- left += props.width - HANDLE_SIZE + 1;
7162
+ } else if (handle.col == 'left' && xinv || handle.col == 'right' && !xinv) {
7163
+ left += props.width - HANDLE_SIZE + OFFS;
7137
7164
  } else {
7138
- left -= 1;
7165
+ left -= OFFS;
7139
7166
  }
7140
7167
  if (handle.row == 'center') {
7141
7168
  top += props.height / 2 - HANDLE_SIZE / 2;
7142
- } else if (handle.row == 'bottom') {
7143
- top += props.height - HANDLE_SIZE + 1;
7169
+ } else if (handle.row == 'top' && yinv || handle.row == 'bottom' && !yinv) {
7170
+ top += props.height - HANDLE_SIZE + OFFS;
7144
7171
  } else {
7145
- top -= 1;
7172
+ top -= OFFS;
7146
7173
  }
7147
7174
 
7148
7175
  handle.el.css({
@@ -7637,7 +7664,14 @@
7637
7664
  });
7638
7665
 
7639
7666
  _popup.on('update', function(e) {
7640
- _self.dispatchEvent('data_change', e.data); // let map know which field has changed
7667
+ // data_change event no longer needed (update is handled below)
7668
+ // _self.dispatchEvent('data_change', e.data); // let map know which field has changed
7669
+ gui.session.dataValueUpdated(e.id, e.field, e.value);
7670
+ // Refresh the display if a style variable has been changed interactively
7671
+ if (internal.isSupportedSvgStyleProperty(e.field)) {
7672
+ // drawLayers();
7673
+ gui.dispatchEvent('map-needs-refresh');
7674
+ }
7641
7675
  });
7642
7676
 
7643
7677
  hit.on('change', function(e) {
@@ -8135,10 +8169,6 @@
8135
8169
  initPointDragging(gui, ext, hit);
8136
8170
  initVertexDragging(gui, ext, hit);
8137
8171
 
8138
- gui.on('interaction_mode_change', function(e) {
8139
- gui.undo.clear(); // TODO: put this elsewhere?
8140
- });
8141
-
8142
8172
  // function isClickEvent(up, down) {
8143
8173
  // var elapsed = Math.abs(down.timeStamp - up.timeStamp);
8144
8174
  // var dx = up.screenX - down.screenX;
@@ -8148,6 +8178,39 @@
8148
8178
  // }
8149
8179
  }
8150
8180
 
8181
+ function initPointDrawing(gui, ext, hit) {
8182
+ function active(e) {
8183
+ return e.id > -1 && gui.interaction.getMode() == 'add-points';
8184
+ }
8185
+
8186
+ }
8187
+
8188
+ function Pencil(gui, mouse, hit) {
8189
+ var self = this;
8190
+ var _on = false;
8191
+
8192
+ self.turnOn = function() {
8193
+ _on = true;
8194
+ };
8195
+
8196
+ self.turnOff = function() {
8197
+ _on = false;
8198
+ };
8199
+
8200
+
8201
+
8202
+
8203
+
8204
+
8205
+ }
8206
+
8207
+ function initDrawing(gui, ext, mouse, hit) {
8208
+
8209
+ initPointDrawing(gui, new Pencil(gui, mouse, hit));
8210
+
8211
+
8212
+ }
8213
+
8151
8214
  var darkStroke = "#334",
8152
8215
  lightStroke = "#b7d9ea",
8153
8216
  violet = "#cc6acc",
@@ -8473,27 +8536,27 @@
8473
8536
  function MapExtent(_position) {
8474
8537
  var _scale = 1,
8475
8538
  _cx, _cy, // center in geographic units
8476
- _contentBounds,
8539
+ _fullBounds, // full (zoomed-out) content bounds, including any padding
8477
8540
  _strictBounds, // full extent must fit inside, if set
8478
8541
  _self = this,
8479
8542
  _frame;
8480
8543
 
8481
8544
  _position.on('resize', function(e) {
8482
8545
  if (ready()) {
8483
- onChange({resize: true});
8546
+ triggerChangeEvent({resize: true});
8484
8547
  }
8485
8548
  });
8486
8549
 
8487
- function ready() { return !!_contentBounds; }
8550
+ function ready() { return !!_fullBounds; }
8488
8551
 
8489
8552
  this.reset = function() {
8490
8553
  if (!ready()) return;
8491
- recenter(_contentBounds.centerX(), _contentBounds.centerY(), 1, {reset: true});
8554
+ recenter(_fullBounds.centerX(), _fullBounds.centerY(), 1, {reset: true});
8492
8555
  };
8493
8556
 
8494
8557
  this.home = function() {
8495
8558
  if (!ready()) return;
8496
- recenter(_contentBounds.centerX(), _contentBounds.centerY(), 1);
8559
+ recenter(_fullBounds.centerX(), _fullBounds.centerY(), 1);
8497
8560
  };
8498
8561
 
8499
8562
  this.pan = function(xpix, ypix) {
@@ -8560,30 +8623,29 @@
8560
8623
 
8561
8624
  // k scales the size of the bbox (used by gui to control fp error when zoomed very far)
8562
8625
  this.getBounds = function(k) {
8563
- if (!_contentBounds) return new Bounds();
8626
+ if (!_fullBounds) return new Bounds();
8564
8627
  return calcBounds(_cx, _cy, _scale / (k || 1));
8565
8628
  };
8566
8629
 
8567
8630
  // Update the extent of 'full' zoom without navigating the current view
8568
8631
  //
8569
- this.setBounds = function(contentBounds, strictBounds) {
8570
- var b = contentBounds;
8571
- var prev = _contentBounds;
8632
+ this.setFullBounds = function(fullBounds, strictBounds) {
8633
+ var prev = _fullBounds;
8634
+ var b = _fullBounds = fullBounds;
8572
8635
  if (!b.hasBounds()) return; // kludge
8573
8636
  if (strictBounds) {
8574
8637
  _strictBounds = Array.isArray(strictBounds) ? new Bounds(strictBounds) : strictBounds;
8575
8638
  } else {
8576
8639
  _strictBounds = null;
8577
8640
  }
8578
- _contentBounds = _frame ? b : padBounds(b, 4); // padding if not in frame mode
8579
8641
  if (_strictBounds) {
8580
- _contentBounds = fitIn(_contentBounds, _strictBounds);
8642
+ _fullBounds = fitIn(_fullBounds, _strictBounds);
8581
8643
  }
8582
8644
  if (prev) {
8583
- _scale = _scale * fillOut(_contentBounds).width() / fillOut(prev).width();
8645
+ _scale = _scale * fillOut(_fullBounds).width() / fillOut(prev).width();
8584
8646
  } else {
8585
- _cx = _contentBounds.centerX();
8586
- _cy = _contentBounds.centerY();
8647
+ _cx = _fullBounds.centerX();
8648
+ _cy = _fullBounds.centerY();
8587
8649
  }
8588
8650
  };
8589
8651
 
@@ -8614,12 +8676,12 @@
8614
8676
  scale = scale ? limitScale(scale) : _scale;
8615
8677
  if (cx == _cx && cy == _cy && scale == _scale) return;
8616
8678
  navigate(cx, cy, scale);
8617
- onChange(data);
8679
+ triggerChangeEvent(data);
8618
8680
  }
8619
8681
 
8620
8682
  function navigate(cx, cy, scale) {
8621
8683
  if (_strictBounds) {
8622
- var full = fillOut(_contentBounds);
8684
+ var full = fillOut(_fullBounds);
8623
8685
  var minScale = full.height() / _strictBounds.height();
8624
8686
  if (scale < minScale) {
8625
8687
  var dx = cx - _cx;
@@ -8641,7 +8703,7 @@
8641
8703
  _scale = scale;
8642
8704
  }
8643
8705
 
8644
- function onChange(data) {
8706
+ function triggerChangeEvent(data) {
8645
8707
  data = data || {};
8646
8708
  _self.dispatchEvent('change', data);
8647
8709
  }
@@ -8649,10 +8711,10 @@
8649
8711
  // stop zooming before rounding errors become too obvious
8650
8712
  function maxScale() {
8651
8713
  var minPixelScale = 1e-16;
8652
- var xmax = maxAbs(_contentBounds.xmin, _contentBounds.xmax, _contentBounds.centerX());
8653
- var ymax = maxAbs(_contentBounds.ymin, _contentBounds.ymax, _contentBounds.centerY());
8654
- var xscale = _contentBounds.width() / _position.width() / xmax / minPixelScale;
8655
- var yscale = _contentBounds.height() / _position.height() / ymax / minPixelScale;
8714
+ var xmax = maxAbs(_fullBounds.xmin, _fullBounds.xmax, _fullBounds.centerX());
8715
+ var ymax = maxAbs(_fullBounds.ymin, _fullBounds.ymax, _fullBounds.centerY());
8716
+ var xscale = _fullBounds.width() / _position.width() / xmax / minPixelScale;
8717
+ var yscale = _fullBounds.height() / _position.height() / ymax / minPixelScale;
8656
8718
  return Math.min(xscale, yscale);
8657
8719
  }
8658
8720
 
@@ -8669,7 +8731,7 @@
8669
8731
  if (_frame) {
8670
8732
  full = fillOutFrameBounds(_frame);
8671
8733
  } else {
8672
- full = fillOut(_contentBounds);
8734
+ full = fillOut(_fullBounds);
8673
8735
  }
8674
8736
  if (_strictBounds) {
8675
8737
  full = fitIn(full, _strictBounds);
@@ -8689,9 +8751,9 @@
8689
8751
  return bounds;
8690
8752
  }
8691
8753
 
8692
- function padBounds(b, margin) {
8693
- var wpix = _position.width() - 2 * margin,
8694
- hpix = _position.height() - 2 * margin,
8754
+ function padBounds(b, marginpix) {
8755
+ var wpix = _position.width() - 2 * marginpix,
8756
+ hpix = _position.height() - 2 * marginpix,
8695
8757
  xpad, ypad, b2;
8696
8758
  if (wpix <= 0 || hpix <= 0) {
8697
8759
  return new Bounds(0, 0, 0, 0);
@@ -8699,8 +8761,8 @@
8699
8761
  b = b.clone();
8700
8762
  b2 = b.clone();
8701
8763
  b2.fillOut(wpix / hpix);
8702
- xpad = b2.width() / wpix * margin;
8703
- ypad = b2.height() / hpix * margin;
8764
+ xpad = b2.width() / wpix * marginpix;
8765
+ ypad = b2.height() / hpix * marginpix;
8704
8766
  b.padBounds(xpad, ypad, xpad, ypad);
8705
8767
  return b;
8706
8768
  }
@@ -8830,8 +8892,8 @@
8830
8892
  function getPixelColorFunction() {
8831
8893
  var canv = El('canvas').node();
8832
8894
  canv.width = canv.height = 1;
8895
+ var ctx = canv.getContext('2d', {willReadFrequently: true});
8833
8896
  return function(col) {
8834
- var ctx = canv.getContext('2d');
8835
8897
  var pixels;
8836
8898
  ctx.fillStyle = col;
8837
8899
  ctx.fillRect(0, 0, 1, 1);
@@ -8843,6 +8905,8 @@
8843
8905
  function DisplayCanvas() {
8844
8906
  var _self = El('canvas'),
8845
8907
  _canvas = _self.node(),
8908
+ // TODO: compare performance of willReadFrequently setting
8909
+ // _ctx = _canvas.getContext('2d', {willReadFrequently: true}),
8846
8910
  _ctx = _canvas.getContext('2d'),
8847
8911
  _pixelColor = getPixelColorFunction(),
8848
8912
  _ext;
@@ -8997,7 +9061,6 @@
8997
9061
  var w = _canvas.width,
8998
9062
  h = _canvas.height,
8999
9063
  rgba = _pixelColor(color),
9000
- // imageData = _ctx.createImageData(w, h),
9001
9064
  imageData = _ctx.getImageData(0, 0, w, h),
9002
9065
  pixels = new Uint32Array(imageData.data.buffer),
9003
9066
  shp, x, y, i, j, n, m,
@@ -10083,7 +10146,6 @@
10083
10146
  return bl.concat(tr);
10084
10147
  }
10085
10148
 
10086
-
10087
10149
  function initMap() {
10088
10150
  if (!enabled() || map || loading) return;
10089
10151
  loading = true;
@@ -10177,17 +10239,15 @@
10177
10239
  map = this,
10178
10240
  _mouse = new MouseArea(el, position),
10179
10241
  _ext = new MapExtent(position),
10180
- _hit = new InteractiveSelection(gui, _ext, _mouse),
10181
10242
  _nav = new MapNav(gui, _ext, _mouse),
10182
- _boxTool = new BoxTool(gui, _ext, _nav),
10183
- _selectionTool = new SelectionTool(gui, _ext, _hit),
10184
10243
  _visibleLayers = [], // cached visible map layers
10185
10244
  _fullBounds = null,
10245
+ _hit,
10246
+ _basemap,
10186
10247
  _intersectionLyr, _activeLyr, _overlayLyr,
10187
- _inspector, _stack,
10188
- _dynamicCRS;
10248
+ _stack, _dynamicCRS;
10189
10249
 
10190
- var _basemap = new Basemap(gui, _ext);
10250
+ _basemap = new Basemap(gui, _ext);
10191
10251
 
10192
10252
  if (gui.options.showMouseCoordinates) {
10193
10253
  new CoordinatesDisplay(gui, _ext, _mouse);
@@ -10326,16 +10386,16 @@
10326
10386
 
10327
10387
  _activeLyr = getDisplayLayer(e.layer, e.dataset, getDisplayOptions());
10328
10388
  _activeLyr.style = getActiveStyle(_activeLyr.layer, gui.state.dark_basemap);
10329
-
10330
10389
  _activeLyr.active = true;
10331
- // if (_inspector) _inspector.updateLayer(_activeLyr);
10332
- _hit.setLayer(_activeLyr);
10390
+
10333
10391
  if (e.flags.same_table) {
10334
10392
  // data may have changed; if popup is open, it needs to be refreshed
10335
10393
  gui.dispatchEvent('popup-needs-refresh');
10336
- } else {
10394
+ } else if (_hit) {
10395
+ _hit.setLayer(_activeLyr);
10337
10396
  _hit.clearSelection();
10338
10397
  }
10398
+
10339
10399
  updateVisibleMapLayers();
10340
10400
  fullBounds = getFullBounds();
10341
10401
 
@@ -10352,7 +10412,8 @@
10352
10412
  } else {
10353
10413
  _nav.setZoomFactor(1);
10354
10414
  }
10355
- _ext.setBounds(fullBounds, getStrictBounds()); // update 'home' button extent
10415
+ _ext.setFullBounds(fullBounds, getStrictBounds()); // update 'home' button extent
10416
+
10356
10417
  _fullBounds = fullBounds;
10357
10418
  if (needReset) {
10358
10419
  _ext.reset();
@@ -10368,19 +10429,13 @@
10368
10429
  gui.buttons.show();
10369
10430
 
10370
10431
  if (opts.inspectorControl) {
10371
- _inspector = new InspectionControl2(gui, _hit);
10372
- _inspector.on('data_change', function(e) {
10373
- // Add an entry to the session history
10374
- gui.session.dataValueUpdated(e.id, e.field, e.value);
10375
- // Refresh the display if a style variable has been changed interactively
10376
- if (internal.isSupportedSvgStyleProperty(e.field)) {
10377
- drawLayers();
10378
- }
10379
- });
10380
- }
10381
-
10382
- if (gui.interaction) {
10432
+ _hit = new InteractiveSelection(gui, _ext, _mouse),
10433
+ new InspectionControl2(gui, _hit);
10434
+ new SelectionTool(gui, _ext, _hit),
10435
+ new BoxTool(gui, _ext, _nav),
10383
10436
  initInteractiveEditing(gui, _ext, _hit);
10437
+ // initDrawing(gui, _ext, _mouse, _hit);
10438
+ _hit.on('change', updateOverlayLayer);
10384
10439
  }
10385
10440
 
10386
10441
  _ext.on('change', function(e) {
@@ -10392,8 +10447,6 @@
10392
10447
  drawLayers('nav');
10393
10448
  });
10394
10449
 
10395
- _hit.on('change', updateOverlayLayer);
10396
-
10397
10450
  gui.on('resize', function() {
10398
10451
  position.update(); // kludge to detect new map size after console toggle
10399
10452
  });
@@ -10438,7 +10491,7 @@
10438
10491
  var cy = viewBounds.centerY();
10439
10492
  rec.bbox = [cx - w/2, cy - h/2, cx + w/2, cy + h/2];
10440
10493
  _ext.setFrame(getFrameData());
10441
- _ext.setBounds(new Bounds(rec.bbox));
10494
+ _ext.setFullBounds(new Bounds(rec.bbox));
10442
10495
  _ext.reset();
10443
10496
  }
10444
10497
 
@@ -10450,39 +10503,33 @@
10450
10503
  }
10451
10504
 
10452
10505
  function getFullBounds() {
10453
- var b = new Bounds();
10454
- var marginPct = 0.025;
10455
- var pad = 1e-4;
10456
10506
  if (isPreviewView()) {
10457
10507
  return internal.getFrameLayerBounds(internal.findFrameLayer(model));
10458
10508
  }
10509
+ var b = new Bounds();
10459
10510
  getDrawableContentLayers().forEach(function(lyr) {
10460
10511
  b.mergeBounds(lyr.bounds);
10461
- if (isTableView()) {
10462
- marginPct = getTableMargin(lyr.layer);
10463
- }
10464
10512
  });
10513
+
10465
10514
  if (!b.hasBounds()) {
10466
10515
  // assign bounds to empty layers, to prevent rendering errors downstream
10467
10516
  b.setBounds(0,0,0,0);
10468
10517
  }
10469
- // Inflate display bounding box by a tiny amount (gives extent to single-point layers and collapsed shapes)
10470
- b.padBounds(pad,pad,pad,pad);
10471
- // add margin
10472
- b.scale(1 + marginPct * 2);
10473
- return b;
10474
- }
10475
10518
 
10476
- // Calculate margin when displaying content at full zoom, as pct of screen size
10477
- function getTableMargin(lyr) {
10478
- var n = internal.getFeatureCount(lyr);
10479
- var pct = 0.04;
10480
- if (n < 5) {
10481
- pct = 0.2;
10482
- } else if (n < 100) {
10483
- pct = 0.1;
10519
+ // add margin
10520
+ // use larger margin for small sizes
10521
+ var widthPx = _ext.width();
10522
+ var marginPct = widthPx < 700 && 3.5 || widthPx < 800 && 3 || 2.5;
10523
+ if (isTableView()) {
10524
+ var n = internal.getFeatureCount(_activeLyr.layer);
10525
+ marginPct = n < 5 && 20 || n < 100 && 10 || 4;
10484
10526
  }
10485
- return pct;
10527
+ b.scale(1 + marginPct / 100 * 2);
10528
+
10529
+ // Inflate display bounding box by a tiny amount (gives extent to single-point layers and collapsed shapes)
10530
+ b.padBounds(1e-4, 1e-4, 1e-4, 1e-4);
10531
+
10532
+ return b;
10486
10533
  }
10487
10534
 
10488
10535
  function isActiveLayer(lyr) {
@@ -10615,7 +10662,7 @@
10615
10662
  if (layersMayHaveChanged) {
10616
10663
  // kludge to handle layer visibility toggling
10617
10664
  _ext.setFrame(isPreviewView() ? getFrameData() : null);
10618
- _ext.setBounds(getFullBounds(), getStrictBounds());
10665
+ _ext.setFullBounds(getFullBounds(), getStrictBounds());
10619
10666
  updateLayerStyles(contentLayers);
10620
10667
  updateLayerStackOrder(model.getLayers());// update stack_id property of all layers
10621
10668
  }