mapshaper 0.5.109 → 0.5.112

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.
package/www/mapshaper.js CHANGED
@@ -1,6 +1,6 @@
1
1
  (function () {
2
2
 
3
- var VERSION = "0.5.109";
3
+ var VERSION = "0.5.112";
4
4
 
5
5
 
6
6
  var utils = /*#__PURE__*/Object.freeze({
@@ -101,6 +101,37 @@
101
101
  get trimQuotes () { return trimQuotes; }
102
102
  });
103
103
 
104
+ // This module provides a way for multiple jobs to run together asynchronously
105
+ // while keeping job-level context variables (like "defs") separate.
106
+
107
+ var stash = {};
108
+
109
+ function stashVar(key, val) {
110
+ if (key in stash) {
111
+ error('Tried to replace a stashed variable:', key);
112
+ }
113
+ stash[key] = val;
114
+ }
115
+
116
+ function getStashedVar(key) {
117
+ if (key in stash === false) {
118
+ return undefined; // to support running commands in tests
119
+ // error('Tried to read a nonexistent variable from the stash:', key);
120
+ }
121
+ return stash[key];
122
+ }
123
+
124
+ function clearStash() {
125
+ stash = {};
126
+ }
127
+
128
+ var Stash = /*#__PURE__*/Object.freeze({
129
+ __proto__: null,
130
+ stashVar: stashVar,
131
+ getStashedVar: getStashedVar,
132
+ clearStash: clearStash
133
+ });
134
+
104
135
  var Buffer = require('buffer').Buffer; // works with browserify
105
136
 
106
137
  var uniqCount = 0;
@@ -1133,62 +1164,6 @@
1133
1164
  return raw;
1134
1165
  }
1135
1166
 
1136
- var context = createContext(); // command context (persist for the current command cycle)
1137
-
1138
- function runningInBrowser() {
1139
- return typeof window !== 'undefined' && typeof window.document !== 'undefined';
1140
- }
1141
-
1142
- function getStateVar(key) {
1143
- return context[key];
1144
- }
1145
-
1146
- function setStateVar(key, val) {
1147
- context[key] = val;
1148
- }
1149
-
1150
- function createContext() {
1151
- return {
1152
- DEBUG: false,
1153
- QUIET: false,
1154
- VERBOSE: false,
1155
- defs: {},
1156
- input_files: []
1157
- };
1158
- }
1159
-
1160
- // Install a new set of context variables, clear them when an async callback is called.
1161
- // @cb callback function to wrap
1162
- // returns wrapped callback function
1163
- function createAsyncContext(cb) {
1164
- context = createContext();
1165
- return function() {
1166
- cb.apply(null, utils.toArray(arguments));
1167
- // clear context after cb(), so output/errors can be handled in current context
1168
- context = createContext();
1169
- };
1170
- }
1171
-
1172
- // Save the current context, restore it when an async callback is called
1173
- // @cb callback function to wrap
1174
- // returns wrapped callback function
1175
- function preserveContext(cb) {
1176
- var ctx = context;
1177
- return function() {
1178
- context = ctx;
1179
- cb.apply(null, utils.toArray(arguments));
1180
- };
1181
- }
1182
-
1183
- var State = /*#__PURE__*/Object.freeze({
1184
- __proto__: null,
1185
- runningInBrowser: runningInBrowser,
1186
- getStateVar: getStateVar,
1187
- setStateVar: setStateVar,
1188
- createAsyncContext: createAsyncContext,
1189
- preserveContext: preserveContext
1190
- });
1191
-
1192
1167
  var LOGGING = false;
1193
1168
  var STDOUT = false; // use stdout for status messages
1194
1169
  var _error, _stop, _message;
@@ -1268,13 +1243,13 @@
1268
1243
 
1269
1244
  function verbose() {
1270
1245
  // verbose can be set globally with the -verbose command or separately for each command
1271
- if (getStateVar('VERBOSE') || getStateVar('verbose')) {
1246
+ if (getStashedVar('VERBOSE')) {
1272
1247
  message.apply(null, arguments);
1273
1248
  }
1274
1249
  }
1275
1250
 
1276
1251
  function debug() {
1277
- if (getStateVar('DEBUG') || getStateVar('debug')) {
1252
+ if (getStashedVar('DEBUG')) {
1278
1253
  logArgs(arguments);
1279
1254
  }
1280
1255
  }
@@ -1354,7 +1329,7 @@
1354
1329
 
1355
1330
  function messageArgs(args) {
1356
1331
  var arr = utils.toArray(args);
1357
- var cmd = getStateVar('current_command');
1332
+ var cmd = getStashedVar('current_command');
1358
1333
  if (cmd && cmd != 'help') {
1359
1334
  arr.unshift('[' + cmd + ']');
1360
1335
  }
@@ -1362,7 +1337,7 @@
1362
1337
  }
1363
1338
 
1364
1339
  function logArgs(args) {
1365
- if (!LOGGING || getStateVar('QUIET') || !utils.isArrayLike(args)) return;
1340
+ if (!LOGGING || getStashedVar('QUIET') || !utils.isArrayLike(args)) return;
1366
1341
  var msg = formatLogArgs(args);
1367
1342
  if (STDOUT) console.log(msg);
1368
1343
  else console.error(msg);
@@ -2750,21 +2725,30 @@
2750
2725
  message(utils.format("Snapped %s point%s", snapCount, utils.pluralSuffix(snapCount)));
2751
2726
  }
2752
2727
 
2728
+ function snapCoordsByInterval(arcs, snapDist) {
2729
+ if (snapDist > 0 === false) return 0;
2730
+ var ids = getCoordinateIds(arcs);
2731
+ return snapCoordsInternal(ids, arcs, snapDist);
2732
+ }
2733
+
2734
+ function snapEndpointsByInterval(arcs, snapDist) {
2735
+ if (snapDist > 0 === false) return 0;
2736
+ var ids = getEndpointIds(arcs);
2737
+ return snapCoordsInternal(ids, arcs, snapDist);
2738
+ }
2739
+
2753
2740
  // Snap together points within a small threshold
2754
2741
  //
2755
- function snapCoordsByInterval(arcs, snapDist) {
2742
+ function snapCoordsInternal(ids, arcs, snapDist) {
2756
2743
  var snapCount = 0,
2757
- data = arcs.getVertexData(),
2758
- ids;
2744
+ n = ids.length,
2745
+ data = arcs.getVertexData();
2759
2746
 
2760
- if (snapDist > 0) {
2761
- // Get sorted coordinate ids
2762
- // Consider: speed up sorting -- try bucket sort as first pass.
2763
- //
2764
- ids = sortCoordinateIds(data.xx);
2765
- for (var i=0, n=ids.length; i<n; i++) {
2766
- snapCount += snapPoint(i, snapDist, ids, data.xx, data.yy);
2767
- }
2747
+ quicksortIds(data.xx, ids, 0, n-1);
2748
+
2749
+ // Consider: speed up sorting -- try bucket sort as first pass.
2750
+ for (var i=0; i<n; i++) {
2751
+ snapCount += snapPoint(i, snapDist, ids, data.xx, data.yy);
2768
2752
  }
2769
2753
  return snapCount;
2770
2754
 
@@ -2790,13 +2774,25 @@
2790
2774
  }
2791
2775
  }
2792
2776
 
2793
- function sortCoordinateIds(a) {
2794
- var n = a.length,
2777
+ function getCoordinateIds(arcs) {
2778
+ var data = arcs.getVertexData(),
2779
+ n = data.xx.length,
2795
2780
  ids = new Uint32Array(n);
2796
2781
  for (var i=0; i<n; i++) {
2797
2782
  ids[i] = i;
2798
2783
  }
2799
- quicksortIds(a, ids, 0, ids.length-1);
2784
+ return ids;
2785
+ }
2786
+
2787
+ function getEndpointIds(arcs) {
2788
+ var i = 0;
2789
+ var ids = [];
2790
+ var data = arcs.getVertexData();
2791
+ data.nn.forEach(function(n) {
2792
+ if (n > 0 === false) return;
2793
+ ids.push(i, i+n-1);
2794
+ i += n;
2795
+ });
2800
2796
  return ids;
2801
2797
  }
2802
2798
 
@@ -2896,7 +2892,9 @@
2896
2892
  getHighPrecisionSnapInterval: getHighPrecisionSnapInterval,
2897
2893
  snapCoords: snapCoords,
2898
2894
  snapCoordsByInterval: snapCoordsByInterval,
2899
- sortCoordinateIds: sortCoordinateIds
2895
+ snapEndpointsByInterval: snapEndpointsByInterval,
2896
+ getCoordinateIds: getCoordinateIds,
2897
+ getEndpointIds: getEndpointIds
2900
2898
  });
2901
2899
 
2902
2900
  // Find the intersection between two 2D segments
@@ -4122,6 +4120,7 @@
4122
4120
  s = [],
4123
4121
  dataNulls = 0,
4124
4122
  rec;
4123
+
4125
4124
  for (var i=0, n=shapes.length; i<n; i++) {
4126
4125
  if (types[i] != geoType) continue;
4127
4126
  if (geoType) s.push(shapes[i]);
@@ -4132,7 +4131,7 @@
4132
4131
  return {
4133
4132
  geometry_type: geoType,
4134
4133
  shapes: s,
4135
- data: dataNulls < s.length ? new DataTable(p) : null
4134
+ data: dataNulls < p.length ? new DataTable(p) : null
4136
4135
  };
4137
4136
  });
4138
4137
  return layers;
@@ -4742,9 +4741,9 @@
4742
4741
  defn = projectionAliases[str]; // defn is a function
4743
4742
  } else if (looksLikeInitString(str)) {
4744
4743
  defn = '+init=' + str.toLowerCase();
4745
- } else if (str in getStateVar('defs')) {
4744
+ } else if (str in (getStashedVar('defs') || {})) {
4746
4745
  // a proj4 alias could be dynamically created in a -calc expression
4747
- defn = getStateVar('defs')[str];
4746
+ defn = getStashedVar('defs')[str];
4748
4747
  } else {
4749
4748
  defn = parseCustomProjection(str);
4750
4749
  }
@@ -7031,6 +7030,15 @@
7031
7030
  transformPoints: transformPoints
7032
7031
  });
7033
7032
 
7033
+ function runningInBrowser() {
7034
+ return typeof window !== 'undefined' && typeof window.document !== 'undefined';
7035
+ }
7036
+
7037
+ var State = /*#__PURE__*/Object.freeze({
7038
+ __proto__: null,
7039
+ runningInBrowser: runningInBrowser
7040
+ });
7041
+
7034
7042
  function getPathSep(path) {
7035
7043
  // TODO: improve
7036
7044
  return path.indexOf('/') == -1 && path.indexOf('\\') != -1 ? '\\' : '/';
@@ -7139,7 +7147,8 @@
7139
7147
  } else if (fname == '/dev/stdin') {
7140
7148
  content = require('rw').readFileSync(fname);
7141
7149
  } else {
7142
- getStateVar('input_files').push(fname);
7150
+ // kludge to prevent overwriting of input files
7151
+ (getStashedVar('input_files') || []).push(fname);
7143
7152
  content = require('fs').readFileSync(fname);
7144
7153
  }
7145
7154
  if (encoding && Buffer.isBuffer(content)) {
@@ -7164,7 +7173,7 @@
7164
7173
  var fs = require('rw');
7165
7174
  cli.createDirIfNeeded(fname);
7166
7175
  if (cb) {
7167
- fs.writeFile(fname, content, preserveContext(cb));
7176
+ fs.writeFile(fname, content, cb);
7168
7177
  } else {
7169
7178
  fs.writeFileSync(fname, content);
7170
7179
  }
@@ -7259,7 +7268,7 @@
7259
7268
  return cli.writeFile('/dev/stdout', exports[0].content, cb);
7260
7269
  } else {
7261
7270
  var paths = getOutputPaths(utils.pluck(exports, 'filename'), opts);
7262
- var inputFiles = getStateVar('input_files');
7271
+ var inputFiles = getStashedVar('input_files');
7263
7272
  exports.forEach(function(obj, i) {
7264
7273
  var path = paths[i];
7265
7274
  if (obj.content instanceof ArrayBuffer) {
@@ -9514,6 +9523,140 @@
9514
9523
  };
9515
9524
  }
9516
9525
 
9526
+ // convert targets from [{layers: [...], dataset: <>}, ...] format to
9527
+ // [{layer: <>, dataset: <>}, ...] format
9528
+ function expandCommandTargets(targets) {
9529
+ return targets.reduce(function(memo, target) {
9530
+ target.layers.forEach(function(lyr) {
9531
+ memo.push({layer: lyr, dataset: target.dataset});
9532
+ });
9533
+ return memo;
9534
+ }, []);
9535
+ }
9536
+
9537
+
9538
+ function findCommandTargets(layers, pattern, type) {
9539
+ var targets = [];
9540
+ var matches = findMatchingLayers(layers, pattern, true);
9541
+ if (type) {
9542
+ matches = matches.filter(function(o) {return o.layer.geometry_type == type;});
9543
+ }
9544
+ // assign target_id to matched layers
9545
+ // (kludge so layers can be sorted in the order that they match; used by -o command)
9546
+ layers.forEach(function(o) {o.layer.target_id = -1;});
9547
+ matches.forEach(function(o, i) {o.layer.target_id = i;});
9548
+ return groupLayersByDataset(matches);
9549
+ }
9550
+
9551
+ // arr: array of {layer: <>, dataset: <>} objects
9552
+ function groupLayersByDataset(arr) {
9553
+ var datasets = [];
9554
+ var targets = [];
9555
+ arr.forEach(function(o) {
9556
+ var i = datasets.indexOf(o.dataset);
9557
+ if (i == -1) {
9558
+ datasets.push(o.dataset);
9559
+ targets.push({layers: [o.layer], dataset: o.dataset});
9560
+ } else {
9561
+ targets[i].layers.push(o.layer);
9562
+ }
9563
+ });
9564
+ return targets;
9565
+ }
9566
+
9567
+ // layers: array of {layer: <>, dataset: <>} objects
9568
+ // pattern: is a layer identifier or a comma-sep. list of identifiers.
9569
+ // An identifier is a literal name, a pattern containing "*" wildcard or
9570
+ // a 1-based index (1..n)
9571
+ function findMatchingLayers(layers, pattern, throws) {
9572
+ var matchedLayers = [];
9573
+ var unmatchedIds = [];
9574
+ var index = {};
9575
+ pattern.split(',').forEach(function(subpattern, i) {
9576
+ var test = getLayerMatch(subpattern);
9577
+ var matched = false;
9578
+ layers.forEach(function(o, layerId) {
9579
+ // if (matchedLayers.indexOf(lyr) > -1) return; // performance bottleneck with 1000s of layers
9580
+ if (layerId in index) {
9581
+ matched = true;
9582
+ } else if (test(o.layer, layerId + 1)) { // layers are 1-indexed
9583
+ matchedLayers.push(o);
9584
+ index[layerId] = true;
9585
+ matched = true;
9586
+ }
9587
+ });
9588
+ if (matched == false) {
9589
+ unmatchedIds.push(subpattern);
9590
+ }
9591
+ });
9592
+ if (throws && unmatchedIds.length) {
9593
+ stop(utils.format('Missing layer%s: %s', unmatchedIds.length == 1 ? '' : 's', unmatchedIds.join(',')));
9594
+ }
9595
+ return matchedLayers;
9596
+ }
9597
+
9598
+ function getLayerMatch(pattern) {
9599
+ var isIndex = utils.isInteger(Number(pattern));
9600
+ var nameRxp = isIndex ? null : utils.wildcardToRegExp(pattern);
9601
+ return function(lyr, i) {
9602
+ return isIndex ? String(i) == pattern : nameRxp.test(lyr.name || '');
9603
+ };
9604
+ }
9605
+
9606
+ function countTargetLayers(targets) {
9607
+ return targets.reduce(function(memo, target) {
9608
+ return memo + target.layers.length;
9609
+ }, 0);
9610
+ }
9611
+
9612
+ // get an identifier for a layer that can be used in a target= option
9613
+ // (returns name if layer has a unique name, or a numerical id)
9614
+ function getLayerTargetId(catalog, lyr) {
9615
+ var nameCount = 0,
9616
+ name = lyr.name,
9617
+ id;
9618
+ catalog.getLayers().forEach(function(o, i) {
9619
+ if (lyr.name && o.layer.name == lyr.name) nameCount++;
9620
+ if (lyr == o.layer) id = String(i + 1);
9621
+ });
9622
+ if (!id) error('Layer not found');
9623
+ return nameCount == 1 ? lyr.name : id;
9624
+ }
9625
+
9626
+ var TargetUtils = /*#__PURE__*/Object.freeze({
9627
+ __proto__: null,
9628
+ expandCommandTargets: expandCommandTargets,
9629
+ findCommandTargets: findCommandTargets,
9630
+ groupLayersByDataset: groupLayersByDataset,
9631
+ findMatchingLayers: findMatchingLayers,
9632
+ getLayerMatch: getLayerMatch,
9633
+ countTargetLayers: countTargetLayers,
9634
+ getLayerTargetId: getLayerTargetId
9635
+ });
9636
+
9637
+ function getNullLayerProxy(targets) {
9638
+ var obj = {};
9639
+ var n = countTargetLayers(targets);
9640
+ var getters = {
9641
+ name: error,
9642
+ data: error,
9643
+ type: error,
9644
+ size: error,
9645
+ empty: error,
9646
+ bbox: error
9647
+ };
9648
+ addGetters(obj, getters);
9649
+ obj.field_exists = error;
9650
+ obj.field_type = error;
9651
+ obj.field_includes = error;
9652
+ return obj;
9653
+ function error() {
9654
+ throw Error(`This expression requires a single target layer; Received ${n} layers.`);
9655
+ }
9656
+ }
9657
+
9658
+
9659
+
9517
9660
  // Returns an object representing a layer in a JS expression
9518
9661
  function getLayerProxy(lyr, arcs) {
9519
9662
  var obj = {};
@@ -9523,10 +9666,10 @@
9523
9666
  data: records,
9524
9667
  type: lyr.geometry_type,
9525
9668
  size: getFeatureCount(lyr),
9526
- empty: getFeatureCount(lyr) === 0
9669
+ empty: getFeatureCount(lyr) === 0,
9670
+ bbox: getBBoxGetter(obj, lyr, arcs)
9527
9671
  };
9528
9672
  addGetters(obj, getters);
9529
- addBBoxGetter(obj, lyr, arcs);
9530
9673
  obj.field_exists = function(name) {
9531
9674
  return lyr.data && lyr.data.fieldExists(name) ? true : false;
9532
9675
  };
@@ -9555,16 +9698,14 @@
9555
9698
  return ctx;
9556
9699
  }
9557
9700
 
9558
- function addBBoxGetter(obj, lyr, arcs) {
9701
+ function getBBoxGetter(obj, lyr, arcs) {
9559
9702
  var bbox;
9560
- addGetters(obj, {
9561
- bbox: function() {
9562
- if (!bbox) {
9563
- bbox = getBBox$1(lyr, arcs);
9564
- }
9565
- return bbox;
9703
+ return function() {
9704
+ if (!bbox) {
9705
+ bbox = getBBox$1(lyr, arcs);
9566
9706
  }
9567
- });
9707
+ return bbox;
9708
+ };
9568
9709
  }
9569
9710
 
9570
9711
  function getBBox$1(lyr, arcs) {
@@ -9965,7 +10106,7 @@
9965
10106
  }
9966
10107
 
9967
10108
  function getExpressionContext(lyr, mixins, opts) {
9968
- var defs = getStateVar('defs');
10109
+ var defs = getStashedVar('defs');
9969
10110
  var env = getBaseContext();
9970
10111
  var ctx = {};
9971
10112
  var fields = lyr.data ? lyr.data.getFields() : [];
@@ -10154,7 +10295,7 @@
10154
10295
  }
10155
10296
  // Save any assigned variables to the defs object, so they will be available
10156
10297
  // for later -each expressions to use.
10157
- defs = getStateVar('defs');
10298
+ defs = getStashedVar('defs');
10158
10299
  compiled = compileCalcExpression(lyr, arcs, opts.expression);
10159
10300
  result = compiled(null, defs);
10160
10301
  message(msg + ": " + result);
@@ -13937,9 +14078,27 @@
13937
14078
  polyline: utils.arrayToIndex(commonProperties.concat('stroke-linecap', 'stroke-linejoin')),
13938
14079
  point: utils.arrayToIndex(commonProperties.concat('fill', 'r')),
13939
14080
  label: utils.arrayToIndex(commonProperties.concat(
13940
- 'fill,r,font-family,font-size,text-anchor,font-weight,font-style,letter-spacing,dominant-baseline'.split(',')))
14081
+ 'fill,font-family,font-size,text-anchor,font-weight,font-style,letter-spacing,dominant-baseline'.split(',')))
13941
14082
  };
13942
14083
 
14084
+ // symType: point, polygon, polyline, label
14085
+ function applyStyleAttributes(svgObj, symType, rec, filter) {
14086
+ var fields = findPropertiesBySymbolGeom(Object.keys(rec || {}), symType);
14087
+ for (var i=0, n=fields.length; i<n; i++) {
14088
+ if (filter && !filter(fields[i])) continue;
14089
+ setAttribute(svgObj, fields[i], rec[fields[i]]);
14090
+ }
14091
+ }
14092
+
14093
+ function setAttribute(obj, k, v) {
14094
+ if (!obj.properties) obj.properties = {};
14095
+ obj.properties[k] = v;
14096
+ if (k == 'stroke-dasharray' && v) {
14097
+ // kludge for cleaner dashes... make butt the default?
14098
+ obj.properties['stroke-linecap'] = 'butt';
14099
+ }
14100
+ }
14101
+
13943
14102
  function isSupportedSvgStyleProperty(name) {
13944
14103
  return name in stylePropertyTypes;
13945
14104
  }
@@ -14022,7 +14181,6 @@
14022
14181
  function parseStyleExpression(strVal, lyr) {
14023
14182
  var func;
14024
14183
  try {
14025
- // func = compileValueExpression(strVal, lyr, null, {context: getStateVar('defs'), no_warn: true});
14026
14184
  func = compileValueExpression(strVal, lyr, null, {no_warn: true});
14027
14185
  func(0); // check for runtime errors (e.g. undefined variables)
14028
14186
  } catch(e) {
@@ -14096,6 +14254,7 @@
14096
14254
 
14097
14255
  var SvgProperties = /*#__PURE__*/Object.freeze({
14098
14256
  __proto__: null,
14257
+ applyStyleAttributes: applyStyleAttributes,
14099
14258
  isSupportedSvgStyleProperty: isSupportedSvgStyleProperty,
14100
14259
  findPropertiesBySymbolGeom: findPropertiesBySymbolGeom,
14101
14260
  getSymbolDataAccessor: getSymbolDataAccessor,
@@ -14109,7 +14268,69 @@
14109
14268
  isSvgColor: isSvgColor
14110
14269
  });
14111
14270
 
14112
- var symbolRenderers = {};
14271
+ function toLabelString(val) {
14272
+ if (val || val === 0 || val === false) return String(val);
14273
+ return '';
14274
+ }
14275
+
14276
+ // Kludge for applying fill and other styles to a <text> element
14277
+ // (for rendering labels in the GUI with the dot in Canvas, not SVG)
14278
+ function renderStyledLabel(rec) {
14279
+ var o = renderLabel(rec);
14280
+ applyStyleAttributes(o, 'label', rec);
14281
+ return o;
14282
+ }
14283
+
14284
+ function renderLabel(rec) {
14285
+ var line = toLabelString(rec['label-text']);
14286
+ var morelines, obj;
14287
+ // Accepting \n (two chars) as an alternative to the newline character
14288
+ // (sometimes, '\n' is not converted to newline, e.g. in a Makefile)
14289
+ // Also accepting <br>
14290
+ var newline = /\n|\\n|<br>/i;
14291
+ var dx = rec.dx || 0;
14292
+ var dy = rec.dy || 0;
14293
+ var properties = {
14294
+ // using x, y instead of dx, dy for shift, because Illustrator doesn't apply
14295
+ // dx value when importing text with text-anchor=end
14296
+ y: dy,
14297
+ x: dx
14298
+ };
14299
+ if (newline.test(line)) {
14300
+ morelines = line.split(newline);
14301
+ line = morelines.shift();
14302
+ }
14303
+ obj = {
14304
+ tag: 'text',
14305
+ value: line,
14306
+ properties: properties
14307
+ };
14308
+ if (morelines) {
14309
+ // multiline label
14310
+ obj.children = [];
14311
+ morelines.forEach(function(line) {
14312
+ var tspan = {
14313
+ tag: 'tspan',
14314
+ value: line,
14315
+ properties: {
14316
+ x: dx,
14317
+ dy: rec['line-height'] || '1.1em'
14318
+ }
14319
+ };
14320
+ obj.children.push(tspan);
14321
+ });
14322
+ }
14323
+ return obj;
14324
+ }
14325
+
14326
+ var SvgLabels = /*#__PURE__*/Object.freeze({
14327
+ __proto__: null,
14328
+ renderStyledLabel: renderStyledLabel,
14329
+ renderLabel: renderLabel
14330
+ });
14331
+
14332
+ // convert data records (properties like svg-symbol, label-text, fill, r) to svg symbols
14333
+
14113
14334
 
14114
14335
  function getTransform(xy, scale) {
14115
14336
  var str = 'translate(' + roundToTenths(xy[0]) + ' ' + roundToTenths(xy[1]) + ')';
@@ -14119,10 +14340,149 @@
14119
14340
  return str;
14120
14341
  }
14121
14342
 
14122
- var SvgCommon = /*#__PURE__*/Object.freeze({
14343
+ var symbolRenderers = {
14344
+ line: line,
14345
+ polygon: polygon,
14346
+ polyline: polyline,
14347
+ circle: circle,
14348
+ square: square,
14349
+ image: image,
14350
+ group: group,
14351
+ label: label
14352
+ };
14353
+
14354
+ // render label and/or point symbol
14355
+ function renderPoint(rec) {
14356
+ var children = [];
14357
+ // var halfSize = rec.r || 0; // radius or half of symbol size
14358
+ if (featureHasSvgSymbol(rec)) {
14359
+ children.push(renderSymbol(rec));
14360
+ }
14361
+ if (featureHasLabel(rec)) {
14362
+ children.push(renderStyledLabel(rec));
14363
+ }
14364
+ var o = children.length > 1 ? {tag: 'g', children: children} : children[0];
14365
+ if (!o) return null;
14366
+ o.properties = o.properties || {};
14367
+ return o;
14368
+ }
14369
+
14370
+ function renderSymbol(d) {
14371
+ if (d['svg-symbol']) {
14372
+ return renderComplexSymbol(d['svg-symbol']);
14373
+ }
14374
+ if (d.r > 0) {
14375
+ return circle(d);
14376
+ }
14377
+ return empty();
14378
+ }
14379
+
14380
+ function renderComplexSymbol(sym) {
14381
+ if (utils.isString(sym)) {
14382
+ sym = JSON.parse(sym);
14383
+ }
14384
+ var renderer = symbolRenderers[sym.type];
14385
+ if (!renderer) {
14386
+ message(sym.type ? 'Unknown symbol type: ' + sym.type : 'Symbol is missing a type property');
14387
+ return empty();
14388
+ }
14389
+ return renderer(sym, 0, 0);
14390
+ }
14391
+
14392
+ function empty() {
14393
+ return {tag: 'g', properties: {}, children: []};
14394
+ }
14395
+
14396
+ function circle(d, x, y) {
14397
+ var o = {
14398
+ tag: 'circle',
14399
+ properties: {
14400
+ cx: x || 0,
14401
+ cy: y || 0
14402
+ }
14403
+ };
14404
+ applyStyleAttributes(o, 'point', d);
14405
+ return o;
14406
+ }
14407
+
14408
+ function label(d, x, y) {
14409
+ return renderStyledLabel(d);
14410
+ }
14411
+
14412
+ function image(d, x, y) {
14413
+ var w = d.width || 20,
14414
+ h = d.height || 20;
14415
+ var o = {
14416
+ tag: 'image',
14417
+ properties: {
14418
+ width: w,
14419
+ height: h,
14420
+ x: x - w / 2,
14421
+ y: y - h / 2,
14422
+ href: d.href || ''
14423
+ }
14424
+ };
14425
+ return o;
14426
+ }
14427
+
14428
+ function square(d, x, y) {
14429
+ var r = d.r || 0;
14430
+ var o = {
14431
+ tag: 'rect',
14432
+ properties: {
14433
+ x: x - r,
14434
+ y: y - r,
14435
+ width: r * 2,
14436
+ height: r * 2
14437
+ }
14438
+ };
14439
+ applyStyleAttributes(o, 'point', d);
14440
+ return o;
14441
+ }
14442
+
14443
+ function line(d, x, y) {
14444
+ var coords, o;
14445
+ coords = [[x, y], [x + (d.dx || 0), y + (d.dy || 0)]];
14446
+ o = importLineString(coords);
14447
+ applyStyleAttributes(o, 'polyline', d);
14448
+ return o;
14449
+ }
14450
+
14451
+ function polyline(d, x, y) {
14452
+ var coords = d.coordinates || [];
14453
+ var o = importMultiLineString(coords);
14454
+ applyStyleAttributes(o, 'polyline', d);
14455
+ return o;
14456
+ }
14457
+
14458
+ function polygon(d, x, y) {
14459
+ var coords = d.coordinates || [];
14460
+ var o = importPolygon(coords);
14461
+ applyStyleAttributes(o, 'polygon', d);
14462
+ return o;
14463
+ }
14464
+
14465
+ function group(d, x, y) {
14466
+ var parts = (d.parts || []).reduce(function(memo, o) {
14467
+ var sym = renderSymbol(o, x, y);
14468
+ if (d.chained) {
14469
+ x += (o.dx || 0);
14470
+ y += (o.dy || 0);
14471
+ }
14472
+ return memo.concat(sym);
14473
+ }, []);
14474
+ if (parts.length == 1) return parts[0];
14475
+ return {
14476
+ tag: 'g',
14477
+ children: parts
14478
+ };
14479
+ }
14480
+
14481
+ var SvgSymbols = /*#__PURE__*/Object.freeze({
14123
14482
  __proto__: null,
14483
+ getTransform: getTransform,
14124
14484
  symbolRenderers: symbolRenderers,
14125
- getTransform: getTransform
14485
+ renderPoint: renderPoint
14126
14486
  });
14127
14487
 
14128
14488
  function importGeoJSONFeatures(features, opts) {
@@ -14130,16 +14490,22 @@
14130
14490
  return features.map(function(obj, i) {
14131
14491
  var geom = obj.type == 'Feature' ? obj.geometry : obj; // could be null
14132
14492
  var geomType = geom && geom.type;
14493
+ var msType = GeoJSON.translateGeoJSONType(geomType);
14494
+ var d = obj.properties || {};
14133
14495
  var svgObj = null;
14134
14496
  if (geomType && geom.coordinates) {
14135
- svgObj = geojsonImporters[geomType](geom.coordinates, obj.properties, opts);
14497
+ svgObj = geojsonImporters[geomType](geom.coordinates, d);
14136
14498
  }
14137
14499
  if (!svgObj) {
14138
14500
  return {tag: 'g'}; // empty element
14139
- }
14140
- // TODO: fix error caused by null svgObj (caused by e.g. MultiPolygon with [] coordinates)
14141
- if (obj.properties) {
14142
- applyStyleAttributes(svgObj, geomType, obj.properties);
14501
+ } else if (msType == 'polyline' || msType == 'polygon') {
14502
+ applyStyleAttributes(svgObj, msType, d);
14503
+ } else if (msType == 'point' && isSimpleCircle(d)) {
14504
+ // kludge -- maintains bw compatibility/passes tests -- style attributes
14505
+ // are applied to the <g> container, 'r' property is applied to circle
14506
+ applyStyleAttributes(svgObj, msType, d, simpleCircleFilter);
14507
+ } else {
14508
+ // other point symbols: attributes are complicated, added downstream
14143
14509
  }
14144
14510
  if ('id' in obj) {
14145
14511
  if (!svgObj.properties) {
@@ -14151,34 +14517,37 @@
14151
14517
  });
14152
14518
  }
14153
14519
 
14154
- function applyStyleAttributes(svgObj, geomType, rec) {
14155
- var symbolType = GeoJSON.translateGeoJSONType(geomType);
14156
- if (symbolType == 'point' && ('label-text' in rec)) {
14157
- symbolType = 'label';
14158
- }
14159
- var fields = findPropertiesBySymbolGeom(Object.keys(rec), symbolType);
14160
- for (var i=0, n=fields.length; i<n; i++) {
14161
- setAttribute(svgObj, fields[i], rec[fields[i]]);
14520
+ function importPoint(coords, rec) {
14521
+ rec = rec || {};
14522
+ if (isSimpleCircle(rec)) {
14523
+ return {
14524
+ tag: 'circle',
14525
+ properties: {
14526
+ cx: coords[0],
14527
+ cy: coords[1],
14528
+ r: rec.r
14529
+ }
14530
+ };
14162
14531
  }
14532
+ var o = renderPoint(rec, coords);
14533
+ if (o) o.properties.transform = getTransform(coords);
14534
+ return o;
14163
14535
  }
14164
14536
 
14165
- function setAttribute(obj, k, v) {
14166
- if (k == 'r') {
14167
- // assigned by importPoint()
14168
- } else {
14169
- if (!obj.properties) obj.properties = {};
14170
- obj.properties[k] = v;
14171
- if (k == 'stroke-dasharray' && v) {
14172
- // kludge for cleaner dashes... make butt the default?
14173
- obj.properties['stroke-linecap'] = 'butt';
14174
- }
14175
- }
14537
+ function simpleCircleFilter(k) {
14538
+ return k != 'r';
14539
+ }
14540
+
14541
+ // just a dot, no label or icon
14542
+ function isSimpleCircle(rec) {
14543
+ return rec && (rec.r > 0 && !rec['svg-symbol'] && !rec['label-text']);
14176
14544
  }
14177
14545
 
14178
- function importMultiPoint(coords, rec, layerOpts) {
14546
+ function importMultiPoint(coords, rec) {
14179
14547
  var children = [], p;
14180
14548
  for (var i=0; i<coords.length; i++) {
14181
- p = importPoint(coords[i], rec, layerOpts);
14549
+ p = importPoint(coords[i], rec);
14550
+ if (!p) continue;
14182
14551
  if (p.tag == 'g' && p.children) {
14183
14552
  children = children.concat(p.children);
14184
14553
  } else {
@@ -14208,7 +14577,6 @@
14208
14577
  };
14209
14578
  }
14210
14579
 
14211
-
14212
14580
  function importMultiLineString(coords) {
14213
14581
  var d = coords.map(stringifyLineStringCoords).join(' ');
14214
14582
  return {
@@ -14217,104 +14585,6 @@
14217
14585
  };
14218
14586
  }
14219
14587
 
14220
- // Kludge for applying fill and other styles to a <text> element
14221
- // (for rendering labels in the GUI with the dot in Canvas, not SVG)
14222
- function importStyledLabel(rec, p) {
14223
- var o = importLabel(rec, p);
14224
- applyStyleAttributes(o, 'Point', rec);
14225
- return o;
14226
- }
14227
-
14228
- function toLabelString(val) {
14229
- if (val || val === 0 || val === false) return String(val);
14230
- return '';
14231
- }
14232
-
14233
- function importLabel(rec, p) {
14234
- var line = toLabelString(rec['label-text']);
14235
- var morelines, obj;
14236
- // Accepting \n (two chars) as an alternative to the newline character
14237
- // (sometimes, '\n' is not converted to newline, e.g. in a Makefile)
14238
- // Also accepting <br>
14239
- var newline = /\n|\\n|<br>/i;
14240
- var dx = rec.dx || 0;
14241
- var dy = rec.dy || 0;
14242
- var properties = {
14243
- // using x, y instead of dx, dy for shift, because Illustrator doesn't apply
14244
- // dx value when importing text with text-anchor=end
14245
- y: dy,
14246
- x: dx
14247
- };
14248
- if (p) {
14249
- properties.transform = getTransform(p);
14250
- }
14251
- if (newline.test(line)) {
14252
- morelines = line.split(newline);
14253
- line = morelines.shift();
14254
- }
14255
- obj = {
14256
- tag: 'text',
14257
- value: line,
14258
- properties: properties
14259
- };
14260
- if (morelines) {
14261
- // multiline label
14262
- obj.children = [];
14263
- morelines.forEach(function(line) {
14264
- var tspan = {
14265
- tag: 'tspan',
14266
- value: line,
14267
- properties: {
14268
- x: dx,
14269
- dy: rec['line-height'] || '1.1em'
14270
- }
14271
- };
14272
- obj.children.push(tspan);
14273
- });
14274
- }
14275
- return obj;
14276
- }
14277
-
14278
- function getEmptySymbol() {
14279
- return {tag: 'g', properties: {}, children: []};
14280
- }
14281
-
14282
-
14283
- function renderSymbol(d, x, y) {
14284
- var renderer = symbolRenderers[d.type];
14285
- if (!renderer) {
14286
- stop(d.type ? 'Unknown symbol type: ' + d.type : 'Symbol is missing a type property');
14287
- }
14288
- return renderer(d, x || 0, y || 0);
14289
- }
14290
-
14291
- // d: svg-symbol object from feature data object
14292
- function importSymbol(d, xy) {
14293
- var renderer;
14294
- if (!d) {
14295
- return getEmptySymbol();
14296
- }
14297
- if (utils.isString(d)) {
14298
- d = JSON.parse(d);
14299
- }
14300
- return {
14301
- tag: 'g',
14302
- properties: {
14303
- 'class': 'mapshaper-svg-symbol',
14304
- transform: xy ? getTransform(xy) : null
14305
- },
14306
- children: renderSymbol(d)
14307
- };
14308
- }
14309
-
14310
- function importPoint(coords, rec, layerOpts) {
14311
- rec = rec || {};
14312
- if ('svg-symbol' in rec) {
14313
- return importSymbol(rec['svg-symbol'], coords);
14314
- }
14315
- return importStandardPoint(coords, rec, layerOpts || {});
14316
- }
14317
-
14318
14588
  function importPolygon(coords) {
14319
14589
  var d, o;
14320
14590
  for (var i=0; i<coords.length; i++) {
@@ -14328,49 +14598,12 @@
14328
14598
  return o;
14329
14599
  }
14330
14600
 
14331
- function importStandardPoint(coords, rec, layerOpts) {
14332
- var isLabel = 'label-text' in rec;
14333
- var symbolType = layerOpts.point_symbol || '';
14334
- var children = [];
14335
- var halfSize = rec.r || 0; // radius or half of symbol size
14336
- var p;
14337
- // if not a label, create a symbol even without a size
14338
- // (circle radius can be set via CSS)
14339
- if (halfSize > 0 || !isLabel) {
14340
- if (symbolType == 'square') {
14341
- p = {
14342
- tag: 'rect',
14343
- properties: {
14344
- x: coords[0] - halfSize,
14345
- y: coords[1] - halfSize,
14346
- width: halfSize * 2,
14347
- height: halfSize * 2
14348
- }};
14349
- } else { // default is circle
14350
- p = {
14351
- tag: 'circle',
14352
- properties: {
14353
- cx: coords[0],
14354
- cy: coords[1]
14355
- }};
14356
- if (halfSize > 0) {
14357
- p.properties.r = halfSize;
14358
- }
14359
- }
14360
- children.push(p);
14361
- }
14362
- if (isLabel) {
14363
- children.push(importLabel(rec, coords));
14364
- }
14365
- return children.length > 1 ? {tag: 'g', children: children} : children[0];
14366
- }
14367
-
14368
14601
  var geojsonImporters = {
14369
14602
  Point: importPoint,
14370
14603
  Polygon: importPolygon,
14371
14604
  LineString: importLineString,
14372
- MultiPoint: function(coords, rec, opts) {
14373
- return importMultiPoint(coords, rec, opts);
14605
+ MultiPoint: function(coords, rec) {
14606
+ return importMultiPoint(coords, rec);
14374
14607
  },
14375
14608
  MultiLineString: function(coords) {
14376
14609
  return importMultiPath(coords, importLineString);
@@ -14383,14 +14616,9 @@
14383
14616
  var GeojsonToSvg = /*#__PURE__*/Object.freeze({
14384
14617
  __proto__: null,
14385
14618
  importGeoJSONFeatures: importGeoJSONFeatures,
14386
- applyStyleAttributes: applyStyleAttributes,
14619
+ importPoint: importPoint,
14387
14620
  importLineString: importLineString,
14388
14621
  importMultiLineString: importMultiLineString,
14389
- importStyledLabel: importStyledLabel,
14390
- importLabel: importLabel,
14391
- renderSymbol: renderSymbol,
14392
- importSymbol: importSymbol,
14393
- importPoint: importPoint,
14394
14622
  importPolygon: importPolygon
14395
14623
  });
14396
14624
 
@@ -15105,6 +15333,15 @@ ${svg}
15105
15333
  return layerObj;
15106
15334
  }
15107
15335
 
15336
+ function featureHasSvgSymbol(d) {
15337
+ return !!(d && (d['svg-symbol'] || d.r));
15338
+ }
15339
+
15340
+ function featureHasLabel(d) {
15341
+ var text = d && d['label-text'];
15342
+ return text || text === 0; // accept numerical 0 as label text
15343
+ }
15344
+
15108
15345
  function layerHasSvgSymbols(lyr) {
15109
15346
  return lyr.geometry_type == 'point' && lyr.data && lyr.data.fieldExists('svg-symbol');
15110
15347
  }
@@ -15124,6 +15361,8 @@ ${svg}
15124
15361
  validateSvgDataFields: validateSvgDataFields,
15125
15362
  exportDataAttributesForSVG: exportDataAttributesForSVG,
15126
15363
  getEmptyLayerForSVG: getEmptyLayerForSVG,
15364
+ featureHasSvgSymbol: featureHasSvgSymbol,
15365
+ featureHasLabel: featureHasLabel,
15127
15366
  layerHasSvgSymbols: layerHasSvgSymbols,
15128
15367
  layerHasLabels: layerHasLabels
15129
15368
  });
@@ -16804,7 +17043,7 @@ ${svg}
16804
17043
  function guessInputFileType(file) {
16805
17044
  var ext = getFileExtension(file || '').toLowerCase(),
16806
17045
  type = null;
16807
- if (ext == 'dbf' || ext == 'shp' || ext == 'prj' || ext == 'shx') {
17046
+ if (ext == 'dbf' || ext == 'shp' || ext == 'prj' || ext == 'shx' || ext == 'kml') {
16808
17047
  type = ext;
16809
17048
  } else if (/json$/.test(ext)) {
16810
17049
  type = 'json';
@@ -16817,7 +17056,8 @@ ${svg}
16817
17056
  function guessInputContentType(content) {
16818
17057
  var type = null;
16819
17058
  if (utils.isString(content)) {
16820
- type = stringLooksLikeJSON(content) ? 'json' : 'text';
17059
+ type = stringLooksLikeJSON(content) && 'json' ||
17060
+ stringLooksLikeKML(content) && 'kml' || 'text';
16821
17061
  } else if (utils.isObject(content) && content.type || utils.isArray(content)) {
16822
17062
  type = 'json';
16823
17063
  }
@@ -16828,11 +17068,15 @@ ${svg}
16828
17068
  return guessInputFileType(file) || guessInputContentType(content);
16829
17069
  }
16830
17070
 
16831
- //
16832
17071
  function stringLooksLikeJSON(str) {
16833
17072
  return /^\s*[{[]/.test(String(str));
16834
17073
  }
16835
17074
 
17075
+ function stringLooksLikeKML(str) {
17076
+ str = String(str);
17077
+ return str.includes('<kml ') && str.includes('xmlns="http://www.opengis.net/kml/');
17078
+ }
17079
+
16836
17080
  function couldBeDsvFile(name) {
16837
17081
  var ext = getFileExtension(name).toLowerCase();
16838
17082
  return /csv|tsv|txt$/.test(ext);
@@ -16877,6 +17121,7 @@ ${svg}
16877
17121
  guessInputContentType: guessInputContentType,
16878
17122
  guessInputType: guessInputType,
16879
17123
  stringLooksLikeJSON: stringLooksLikeJSON,
17124
+ stringLooksLikeKML: stringLooksLikeKML,
16880
17125
  couldBeDsvFile: couldBeDsvFile,
16881
17126
  isZipFile: isZipFile,
16882
17127
  isSupportedOutputFormat: isSupportedOutputFormat,
@@ -17178,116 +17423,6 @@ ${svg}
17178
17423
  formatVersionedFileName: formatVersionedFileName
17179
17424
  });
17180
17425
 
17181
- // convert targets from [{layers: [...], dataset: <>}, ...] format to
17182
- // [{layer: <>, dataset: <>}, ...] format
17183
- function expandCommandTargets(targets) {
17184
- return targets.reduce(function(memo, target) {
17185
- target.layers.forEach(function(lyr) {
17186
- memo.push({layer: lyr, dataset: target.dataset});
17187
- });
17188
- return memo;
17189
- }, []);
17190
- }
17191
-
17192
- function findCommandTargets(layers, pattern, type) {
17193
- var targets = [];
17194
- var matches = findMatchingLayers(layers, pattern, true);
17195
- if (type) {
17196
- matches = matches.filter(function(o) {return o.layer.geometry_type == type;});
17197
- }
17198
- // assign target_id to matched layers
17199
- // (kludge so layers can be sorted in the order that they match; used by -o command)
17200
- layers.forEach(function(o) {o.layer.target_id = -1;});
17201
- matches.forEach(function(o, i) {o.layer.target_id = i;});
17202
- return groupLayersByDataset(matches);
17203
- }
17204
-
17205
- // arr: array of {layer: <>, dataset: <>} objects
17206
- function groupLayersByDataset(arr) {
17207
- var datasets = [];
17208
- var targets = [];
17209
- arr.forEach(function(o) {
17210
- var i = datasets.indexOf(o.dataset);
17211
- if (i == -1) {
17212
- datasets.push(o.dataset);
17213
- targets.push({layers: [o.layer], dataset: o.dataset});
17214
- } else {
17215
- targets[i].layers.push(o.layer);
17216
- }
17217
- });
17218
- return targets;
17219
- }
17220
-
17221
- // layers: array of {layer: <>, dataset: <>} objects
17222
- // pattern: is a layer identifier or a comma-sep. list of identifiers.
17223
- // An identifier is a literal name, a pattern containing "*" wildcard or
17224
- // a 1-based index (1..n)
17225
- function findMatchingLayers(layers, pattern, throws) {
17226
- var matchedLayers = [];
17227
- var unmatchedIds = [];
17228
- var index = {};
17229
- pattern.split(',').forEach(function(subpattern, i) {
17230
- var test = getLayerMatch(subpattern);
17231
- var matched = false;
17232
- layers.forEach(function(o, layerId) {
17233
- // if (matchedLayers.indexOf(lyr) > -1) return; // performance bottleneck with 1000s of layers
17234
- if (layerId in index) {
17235
- matched = true;
17236
- } else if (test(o.layer, layerId + 1)) { // layers are 1-indexed
17237
- matchedLayers.push(o);
17238
- index[layerId] = true;
17239
- matched = true;
17240
- }
17241
- });
17242
- if (matched == false) {
17243
- unmatchedIds.push(subpattern);
17244
- }
17245
- });
17246
- if (throws && unmatchedIds.length) {
17247
- stop(utils.format('Missing layer%s: %s', unmatchedIds.length == 1 ? '' : 's', unmatchedIds.join(',')));
17248
- }
17249
- return matchedLayers;
17250
- }
17251
-
17252
- function getLayerMatch(pattern) {
17253
- var isIndex = utils.isInteger(Number(pattern));
17254
- var nameRxp = isIndex ? null : utils.wildcardToRegExp(pattern);
17255
- return function(lyr, i) {
17256
- return isIndex ? String(i) == pattern : nameRxp.test(lyr.name || '');
17257
- };
17258
- }
17259
-
17260
- function countTargetLayers(targets) {
17261
- return targets.reduce(function(memo, target) {
17262
- return memo + target.layers.length;
17263
- }, 0);
17264
- }
17265
-
17266
- // get an identifier for a layer that can be used in a target= option
17267
- // (returns name if layer has a unique name, or a numerical id)
17268
- function getLayerTargetId(catalog, lyr) {
17269
- var nameCount = 0,
17270
- name = lyr.name,
17271
- id;
17272
- catalog.getLayers().forEach(function(o, i) {
17273
- if (lyr.name && o.layer.name == lyr.name) nameCount++;
17274
- if (lyr == o.layer) id = String(i + 1);
17275
- });
17276
- if (!id) error('Layer not found');
17277
- return nameCount == 1 ? lyr.name : id;
17278
- }
17279
-
17280
- var TargetUtils = /*#__PURE__*/Object.freeze({
17281
- __proto__: null,
17282
- expandCommandTargets: expandCommandTargets,
17283
- findCommandTargets: findCommandTargets,
17284
- groupLayersByDataset: groupLayersByDataset,
17285
- findMatchingLayers: findMatchingLayers,
17286
- getLayerMatch: getLayerMatch,
17287
- countTargetLayers: countTargetLayers,
17288
- getLayerTargetId: getLayerTargetId
17289
- });
17290
-
17291
17426
  function readFirstChars(reader, n) {
17292
17427
  return bufferToString(reader.readSync(0, Math.min(n || 1000, reader.size())));
17293
17428
  }
@@ -17355,8 +17490,8 @@ ${svg}
17355
17490
  DEFAULT_CACHE_LEN = opts && opts.cacheSize || 0x1000000, // 16MB
17356
17491
  DEFAULT_BUFFER_LEN = opts && opts.bufferSize || 0x40000, // 256K
17357
17492
  fd, cacheOffs, cache, binArr;
17358
-
17359
- getStateVar('input_files').push(path); // bit of a kludge
17493
+ // kludge to let us check if input files are being overwritten
17494
+ (getStashedVar('input_files') || []).push(path);
17360
17495
 
17361
17496
  // Double the default size of the Buffer returned by readSync()
17362
17497
  this.expandBuffer = function() {
@@ -20163,6 +20298,10 @@ ${svg}
20163
20298
  DEFAULT: true,
20164
20299
  type: 'distance'
20165
20300
  })
20301
+ .option('endpoints', {
20302
+ describe: 'only snap together the endpoints of lines',
20303
+ type: 'flag'
20304
+ })
20166
20305
  .option('precision', {
20167
20306
  describe: 'round all coordinates to a given decimal precision (e.g. 0.000001)',
20168
20307
  type: 'number'
@@ -20704,16 +20843,16 @@ ${svg}
20704
20843
  var ifOpts = {
20705
20844
  expression: {
20706
20845
  DEFAULT: true,
20707
- describe: 'JS expression targeting a single layer'
20708
- },
20709
- empty: {
20710
- describe: 'run if layer is empty',
20711
- type: 'flag'
20712
- },
20713
- 'not-empty': {
20714
- describe: 'run if layer is not empty',
20715
- type: 'flag'
20846
+ describe: 'JS expression'
20716
20847
  },
20848
+ // empty: {
20849
+ // describe: 'run if layer is empty',
20850
+ // type: 'flag'
20851
+ // },
20852
+ // 'not-empty': {
20853
+ // describe: 'run if layer is not empty',
20854
+ // type: 'flag'
20855
+ // },
20717
20856
  layer: {
20718
20857
  describe: 'name or id of layer to test (default is current target)'
20719
20858
  },
@@ -23158,6 +23297,13 @@ ${svg}
23158
23297
  importJSON: importJSON
23159
23298
  });
23160
23299
 
23300
+ function importKML(str, opts) {
23301
+ var togeojson = require("@tmcw/togeojson");
23302
+ var Parser = typeof DOMParser == 'undefined' ? require("@xmldom/xmldom").DOMParser : DOMParser;
23303
+ var geojson = togeojson.kml(new Parser().parseFromString(str, "text/xml"));
23304
+ return importGeoJSON(geojson, opts || {});
23305
+ }
23306
+
23161
23307
  // Parse content of one or more input files and return a dataset
23162
23308
  // @obj: file data, indexed by file type
23163
23309
  // File data objects have two properties:
@@ -23194,6 +23340,11 @@ ${svg}
23194
23340
  fileFmt = 'prj';
23195
23341
  data = obj.prj;
23196
23342
  dataset = {layers: [], info: {prj: data.content}};
23343
+
23344
+ } else if (obj.kml) {
23345
+ fileFmt = 'kml';
23346
+ data = obj.kml;
23347
+ dataset = importKML(data.content, opts);
23197
23348
  }
23198
23349
 
23199
23350
  if (!dataset) {
@@ -23375,7 +23526,7 @@ ${svg}
23375
23526
  stop('Expected binary content, received a string');
23376
23527
  }
23377
23528
 
23378
- } else if (fileType) { // string type
23529
+ } else if (fileType) { // string type, e.g. kml, geojson
23379
23530
  content = cli.readFile(path, encoding || 'utf-8', cache);
23380
23531
 
23381
23532
  } else { // type can't be inferred from filename -- try reading as text
@@ -23664,6 +23815,49 @@ ${svg}
23664
23815
  getFormattedLayerList: getFormattedLayerList
23665
23816
  });
23666
23817
 
23818
+ function Job(catalog) {
23819
+ var currentCmd;
23820
+
23821
+ var job = {
23822
+ catalog: catalog || new Catalog(),
23823
+ defs: {},
23824
+ settings: {},
23825
+ input_files: []
23826
+ };
23827
+
23828
+ job.initSettings = function(o) {
23829
+ job.settings = o;
23830
+ stashVars(job, {});
23831
+ };
23832
+
23833
+ job.startCommand = function(cmd) {
23834
+ currentCmd = cmd;
23835
+ stashVars(job, cmd);
23836
+ };
23837
+
23838
+ // Rejected the idea of passing a command reference to compare with the initial command
23839
+ // (for error checking) ... the "-run" command inserts other commands before this call
23840
+ job.endCommand = function() {
23841
+ currentCmd = null;
23842
+ clearStash();
23843
+ };
23844
+
23845
+ job.resumeCommand = function() {
23846
+ stashVars(job, currentCmd);
23847
+ };
23848
+
23849
+ return job;
23850
+ }
23851
+
23852
+ function stashVars(job, cmd) {
23853
+ clearStash(); // prevent errors from overwriting stash
23854
+ stashVar('current_command', cmd.name);
23855
+ stashVar('DEBUG', job.settings.DEBUG || cmd.debug);
23856
+ stashVar('QUIET', job.settings.QUIET || cmd.quiet);
23857
+ stashVar('defs', job.defs);
23858
+ stashVar('input_files', job.input_files);
23859
+ }
23860
+
23667
23861
  const epsilon = 1.1102230246251565e-16;
23668
23862
  const splitter = 134217729;
23669
23863
  const resulterrbound = (3 + 8 * epsilon) * epsilon;
@@ -30407,7 +30601,7 @@ ${svg}
30407
30601
  if (isReservedName(opts.name)) {
30408
30602
  stop('"' + opts.name + '" is a reserved name');
30409
30603
  }
30410
- getStateVar('defs')[opts.name] = getColorizerFunction(opts);
30604
+ getStashedVar('defs')[opts.name] = getColorizerFunction(opts);
30411
30605
  };
30412
30606
 
30413
30607
  function isReservedName(name) {
@@ -30526,7 +30720,7 @@ ${svg}
30526
30720
 
30527
30721
  cmd.dashlines = function(lyr, dataset, opts) {
30528
30722
  var crs = getDatasetCRS(dataset);
30529
- var defs = getStateVar('defs');
30723
+ var defs = getStashedVar('defs');
30530
30724
  var exp = `this.geojson = splitFeature(this.geojson)`;
30531
30725
  requirePolylineLayer(lyr);
30532
30726
  defs.splitFeature = getSplitFeatureFunction(crs, opts);
@@ -30930,7 +31124,7 @@ ${svg}
30930
31124
  if (!opts.expression) {
30931
31125
  stop('Missing an assignment expression');
30932
31126
  }
30933
- var defs = getStateVar('defs');
31127
+ var defs = getStashedVar('defs');
30934
31128
  var compiled = compileFeatureExpression(opts.expression, {}, null, {no_warn: true});
30935
31129
  var result = compiled(null, defs);
30936
31130
  };
@@ -32202,8 +32396,6 @@ ${svg}
32202
32396
  if (opts && opts.where) {
32203
32397
  filter = compileValueExpression(opts.where, lyr, arcs);
32204
32398
  }
32205
- // 'defs' are now added to the context of all expressions
32206
- // compiled = compileFeatureExpression(exp, lyr, arcs, {context: getStateVar('defs')});
32207
32399
  compiled = compileFeatureExpression(exp, lyr, arcs, exprOpts);
32208
32400
  // call compiled expression with id of each record
32209
32401
  for (var i=0; i<n; i++) {
@@ -34612,48 +34804,60 @@ ${svg}
34612
34804
  };
34613
34805
  }
34614
34806
 
34615
- function resetControlFlow() {
34616
- setStateVar('control', null);
34807
+ function resetControlFlow(job) {
34808
+ job.control = null;
34617
34809
  }
34618
34810
 
34619
- function inControlBlock() {
34620
- var state = getState();
34621
- return !!state.inControlBlock;
34811
+ function inControlBlock(job) {
34812
+ return !!getState(job).inControlBlock;
34622
34813
  }
34623
34814
 
34624
- function enterActiveBranch() {
34625
- var state = getState();
34815
+ function enterActiveBranch(job) {
34816
+ var state = getState(job);
34626
34817
  state.inControlBlock = true;
34627
34818
  state.active = true;
34628
34819
  state.complete = true;
34629
34820
  }
34630
34821
 
34631
- function enterInactiveBranch() {
34632
- var state = getState();
34822
+ function enterInactiveBranch(job) {
34823
+ var state = getState(job);
34633
34824
  state.inControlBlock = true;
34634
34825
  state.active = false;
34635
34826
  }
34636
34827
 
34637
- function blockWasActive() {
34638
- return !!getState().complete;
34828
+ function blockWasActive(job) {
34829
+ return !!getState(job).complete;
34639
34830
  }
34640
34831
 
34641
- function inActiveBranch() {
34642
- return !!getState().active;
34832
+ function inActiveBranch(job) {
34833
+ return !!getState(job).active;
34643
34834
  }
34644
34835
 
34645
- function getState() {
34646
- var o = getStateVar('control') || setStateVar('control', {}) || getStateVar('control');
34647
- return o;
34836
+ function getState(job) {
34837
+ return job.control || (job.control = {});
34648
34838
  }
34649
34839
 
34650
- function compileIfCommandExpression(expr, catalog, targ, opts) {
34651
- var ctx = getLayerProxy(targ.layer, targ.dataset.arcs, opts);
34840
+ function compileIfCommandExpression(expr, catalog, opts) {
34841
+ var targetId = opts.layer || opts.target || null;
34842
+ var targets = catalog.findCommandTargets(targetId);
34843
+ var isSingle = targets.length == 1 && targets[0].layers.length == 1;
34844
+ if (targets.length === 0 && targetId) {
34845
+ stop('Layer not found:', targetId);
34846
+ }
34847
+ var ctx;
34848
+ if (isSingle) {
34849
+ ctx = getLayerProxy(targets[0].layers[0], targets[0].dataset.arcs, opts);
34850
+ } else {
34851
+ ctx = getNullLayerProxy(targets);
34852
+ }
34652
34853
  var exprOpts = Object.assign({returns: true}, opts);
34653
34854
  var func = compileExpressionToFunction(expr, exprOpts);
34654
34855
 
34655
- ctx.layer_exists = function(name) {
34656
- return !!catalog.findSingleLayer(name);
34856
+ // @geoType: optional geometry type (polygon, polyline, point, null);
34857
+ ctx.layer_exists = function(name, geoType) {
34858
+ var targets = catalog.findCommandTargets(name, geoType);
34859
+ if (targets.length === 0) return false;
34860
+ return true;
34657
34861
  };
34658
34862
 
34659
34863
  ctx.file_exists = function(file) {
@@ -34670,89 +34874,68 @@ ${svg}
34670
34874
  };
34671
34875
  }
34672
34876
 
34673
- function skipCommand(cmdName) {
34877
+ function skipCommand(cmdName, job) {
34674
34878
  // allow all control commands to run
34675
34879
  if (isControlFlowCommand(cmdName)) return false;
34676
- return inControlBlock() && !inActiveBranch();
34880
+ return inControlBlock(job) && !inActiveBranch(job);
34677
34881
  }
34678
34882
 
34679
- cmd.if = function(catalog, opts) {
34680
- if (inControlBlock()) {
34883
+ cmd.if = function(job, opts) {
34884
+ if (inControlBlock(job)) {
34681
34885
  stop('Nested -if commands are not supported.');
34682
34886
  }
34683
- evaluateIf(catalog, opts);
34887
+ evaluateIf(job, opts);
34684
34888
  };
34685
34889
 
34686
- cmd.elif = function(catalog, opts) {
34687
- if (!inControlBlock()) {
34890
+ cmd.elif = function(job, opts) {
34891
+ if (!inControlBlock(job)) {
34688
34892
  stop('-elif command must be preceded by an -if command.');
34689
34893
  }
34690
- evaluateIf(catalog, opts);
34894
+ evaluateIf(job, opts);
34691
34895
  };
34692
34896
 
34693
- cmd.else = function() {
34694
- if (!inControlBlock()) {
34897
+ cmd.else = function(job) {
34898
+ if (!inControlBlock(job)) {
34695
34899
  stop('-else command must be preceded by an -if command.');
34696
34900
  }
34697
- if (blockWasActive()) {
34698
- enterInactiveBranch();
34901
+ if (blockWasActive(job)) {
34902
+ enterInactiveBranch(job);
34699
34903
  } else {
34700
- enterActiveBranch();
34904
+ enterActiveBranch(job);
34701
34905
  }
34702
34906
  };
34703
34907
 
34704
- cmd.endif = function() {
34705
- if (!inControlBlock()) {
34908
+ cmd.endif = function(job) {
34909
+ if (!inControlBlock(job)) {
34706
34910
  stop('-endif command must be preceded by an -if command.');
34707
34911
  }
34708
- resetControlFlow();
34912
+ resetControlFlow(job);
34709
34913
  };
34710
34914
 
34711
34915
  function isControlFlowCommand(cmd) {
34712
34916
  return ['if','elif','else','endif'].includes(cmd);
34713
34917
  }
34714
34918
 
34715
- function testLayer(catalog, opts) {
34716
- var targ = getTargetLayer(catalog, opts);
34919
+ function test(catalog, opts) {
34920
+ // var targ = getTargetLayer(catalog, opts);
34717
34921
  if (opts.expression) {
34718
- return compileIfCommandExpression(opts.expression, catalog, targ, opts)();
34719
- }
34720
- if (opts.empty) {
34721
- return layerIsEmpty(targ.layer);
34722
- }
34723
- if (opts.not_empty) {
34724
- return !layerIsEmpty(targ.layer);
34922
+ return compileIfCommandExpression(opts.expression, catalog, opts)();
34725
34923
  }
34924
+ // if (opts.empty) {
34925
+ // return layerIsEmpty(targ.layer);
34926
+ // }
34927
+ // if (opts.not_empty) {
34928
+ // return !layerIsEmpty(targ.layer);
34929
+ // }
34726
34930
  return true;
34727
34931
  }
34728
34932
 
34729
- function evaluateIf(catalog, opts) {
34730
- if (!blockWasActive() && testLayer(catalog, opts)) {
34731
- enterActiveBranch();
34933
+ function evaluateIf(job, opts) {
34934
+ if (!blockWasActive(job) && test(job.catalog, opts)) {
34935
+ enterActiveBranch(job);
34732
34936
  } else {
34733
- enterInactiveBranch();
34734
- }
34735
- }
34736
-
34737
- // layerId: optional layer identifier
34738
- //
34739
- function getTargetLayer(catalog, opts) {
34740
- var layerId = opts.layer || opts.target;
34741
- var targets = catalog.findCommandTargets(layerId);
34742
- if (targets.length === 0) {
34743
- if (layerId) {
34744
- stop('Layer not found:', layerId);
34745
- } else {
34746
- stop('Missing a target layer.');
34747
- }
34937
+ enterInactiveBranch(job);
34748
34938
  }
34749
- if (targets.length > 1 || targets[0].layers.length > 1) {
34750
- stop('Command requires a single target layer.');
34751
- }
34752
- return {
34753
- layer: targets[0].layers[0],
34754
- dataset: targets[0].dataset
34755
- };
34756
34939
  }
34757
34940
 
34758
34941
  cmd.ignore = function(targetLayer, dataset, opts) {
@@ -34790,7 +34973,7 @@ ${svg}
34790
34973
  obj = content;
34791
34974
  }
34792
34975
 
34793
- utils.extend(getStateVar('defs'), obj);
34976
+ utils.extend(getStashedVar('defs'), obj);
34794
34977
  };
34795
34978
 
34796
34979
  var MAX_RULE_LEN = 50;
@@ -34849,7 +35032,7 @@ ${svg}
34849
35032
  null_shape_count: 0,
34850
35033
  null_data_count: lyr.data ? countNullRecords(lyr.data.getRecords()) : n
34851
35034
  };
34852
- if (lyr.shapes) {
35035
+ if (lyr.shapes && lyr.shapes.length > 0) {
34853
35036
  o.null_shape_count = countNullShapes(lyr.shapes);
34854
35037
  o.bbox =getLayerBounds(lyr, dataset.arcs).toArray();
34855
35038
  o.proj4 = getProjInfo(dataset);
@@ -37122,7 +37305,7 @@ ${svg}
37122
37305
  parseConsoleCommands: parseConsoleCommands
37123
37306
  });
37124
37307
 
37125
- cmd.run = function(targets, catalog, opts, cb) {
37308
+ cmd.run = function(job, targets, opts, cb) {
37126
37309
  var commandStr, commands;
37127
37310
  if (opts.include) {
37128
37311
  cmd.include({file: opts.include});
@@ -37133,7 +37316,7 @@ ${svg}
37133
37316
  commandStr = runGlobalExpression(opts.commands, targets);
37134
37317
  if (commandStr) {
37135
37318
  commands = parseCommands(commandStr);
37136
- runParsedCommands(commands, catalog, cb);
37319
+ runParsedCommands(commands, job, cb);
37137
37320
  } else {
37138
37321
  cb(null);
37139
37322
  }
@@ -37147,7 +37330,7 @@ ${svg}
37147
37330
  targetData = getRunCommandData(targets[0]);
37148
37331
  Object.defineProperty(ctx, 'target', {value: targetData});
37149
37332
  }
37150
- utils.extend(ctx, getStateVar('defs'));
37333
+ utils.extend(ctx, getStashedVar('defs'));
37151
37334
  try {
37152
37335
  output = Function('ctx', 'with(ctx) {return (' + expression + ');}').call({}, ctx);
37153
37336
  } catch(e) {
@@ -37166,7 +37349,7 @@ ${svg}
37166
37349
  }
37167
37350
 
37168
37351
  cmd.require = function(targets, opts) {
37169
- var defs = getStateVar('defs');
37352
+ var defs = getStashedVar('defs');
37170
37353
  var moduleFile, moduleName, mod;
37171
37354
  if (!opts.module) {
37172
37355
  stop("Missing module name or path to module");
@@ -37196,72 +37379,6 @@ ${svg}
37196
37379
  }
37197
37380
  };
37198
37381
 
37199
- symbolRenderers.circle = function(d, x, y) {
37200
- var o = importPoint([x, y], d, {});
37201
- applyStyleAttributes(o, 'Point', d);
37202
- return [o];
37203
- };
37204
-
37205
- symbolRenderers.label = function(d, x, y) {
37206
- var o = importStyledLabel(d, [x, y]);
37207
- return [o];
37208
- };
37209
-
37210
- symbolRenderers.image = function(d, x, y) {
37211
- var w = d.width || 20,
37212
- h = d.height || 20;
37213
- var o = {
37214
- tag: 'image',
37215
- properties: {
37216
- width: w,
37217
- height: h,
37218
- x: x - w / 2,
37219
- y: y - h / 2,
37220
- href: d.href || ''
37221
- }
37222
- };
37223
- return [o];
37224
- };
37225
-
37226
- symbolRenderers.square = function(d, x, y) {
37227
- var o = importPoint([x, y], d, {point_symbol: 'square'});
37228
- applyStyleAttributes(o, 'Point', d);
37229
- return [o];
37230
- };
37231
-
37232
- symbolRenderers.line = function(d, x, y) {
37233
- var coords, o;
37234
- coords = [[x, y], [x + (d.dx || 0), y + (d.dy || 0)]];
37235
- o = importLineString(coords);
37236
- applyStyleAttributes(o, 'LineString', d);
37237
- return [o];
37238
- };
37239
-
37240
- symbolRenderers.polyline = function(d, x, y) {
37241
- var coords = d.coordinates || [];
37242
- var o = importMultiLineString(coords);
37243
- applyStyleAttributes(o, 'LineString', d);
37244
- return [o];
37245
- };
37246
-
37247
- symbolRenderers.polygon = function(d, x, y) {
37248
- var coords = d.coordinates || [];
37249
- var o = importPolygon(coords);
37250
- applyStyleAttributes(o, 'Polygon', d);
37251
- return [o];
37252
- };
37253
-
37254
- symbolRenderers.group = function(d, x, y) {
37255
- return (d.parts || []).reduce(function(memo, o) {
37256
- var sym = renderSymbol(o, x, y);
37257
- if (d.chained) {
37258
- x += (o.dx || 0);
37259
- y += (o.dy || 0);
37260
- }
37261
- return memo.concat(sym);
37262
- }, []);
37263
- };
37264
-
37265
37382
  cmd.scalebar = function(catalog, opts) {
37266
37383
  var frame = findFrameDataset(catalog);
37267
37384
  var obj, lyr;
@@ -37345,7 +37462,7 @@ ${svg}
37345
37462
  // so I'm using 'hanging' and 'auto', which seem to be well supported.
37346
37463
  // downside: requires a kludgy multiplier to calculate scalebar height (see above)
37347
37464
  };
37348
- var labelObj = symbolRenderers.label(labelOpts, anchorX, anchorY)[0];
37465
+ var labelObj = symbolRenderers.label(labelOpts, anchorX, anchorY);
37349
37466
  var g = {
37350
37467
  tag: 'g',
37351
37468
  children: [barObj, labelObj],
@@ -38448,7 +38565,12 @@ ${svg}
38448
38565
  interval = getHighPrecisionSnapInterval(arcBounds.toArray());
38449
38566
  }
38450
38567
  arcs.flatten(); // bake in any simplification
38451
- if (interval > 0) {
38568
+ if (interval > 0 && opts.endpoints) {
38569
+ // snaps line endpoints together
38570
+ // TODO: also snap endpoints to line segments to remove undershoots and overshoots
38571
+ snapCount = snapEndpointsByInterval(arcs, interval);
38572
+ message(utils.format("Snapped %s endpoint%s", snapCount, utils.pluralSuffix(snapCount)));
38573
+ } else if (interval > 0) {
38452
38574
  snapCount = snapCoordsByInterval(arcs, interval);
38453
38575
  message(utils.format("Snapped %s point%s", snapCount, utils.pluralSuffix(snapCount)));
38454
38576
  }
@@ -38591,6 +38713,15 @@ ${svg}
38591
38713
 
38592
38714
  var roundCoord = getRoundingFunction(0.01);
38593
38715
 
38716
+ function getSymbolColor(d) {
38717
+ return d.fill || 'magenta';
38718
+ }
38719
+
38720
+ function getSymbolRadius(d) {
38721
+ if (d.radius === 0 || d.length === 0 || d.r === 0) return 0;
38722
+ return d.radius || d.length || d.r || 5; // use a default value
38723
+ }
38724
+
38594
38725
  function forEachSymbolCoord(coords, cb) {
38595
38726
  var isPoint = coords && utils.isNumber(coords[0]);
38596
38727
  var isNested = !isPoint && coords && Array.isArray(coords[0]);
@@ -38845,8 +38976,19 @@ ${svg}
38845
38976
  return coords;
38846
38977
  }
38847
38978
 
38979
+ function makeCircleSymbol(d, opts) {
38980
+ var radius = getSymbolRadius(d);
38981
+ // TODO: remove duplicatoin with svg-symbols.js
38982
+ if (+opts.scale) radius *= +opts.scale;
38983
+ return {
38984
+ type: 'circle',
38985
+ fill: getSymbolColor(d),
38986
+ r: radius
38987
+ };
38988
+ }
38989
+
38848
38990
  function getPolygonCoords(d) {
38849
- var radius = d.radius || d.length || d.r,
38991
+ var radius = getSymbolRadius(d),
38850
38992
  sides = +d.sides || getSidesByType(d.type),
38851
38993
  rotated = sides % 2 == 1,
38852
38994
  coords = [],
@@ -38883,7 +39025,7 @@ ${svg}
38883
39025
  }
38884
39026
 
38885
39027
  function getStarCoords(d) {
38886
- var radius = d.radius || d.length || d.r,
39028
+ var radius = getSymbolRadius(d),
38887
39029
  points = d.points || d.sides && d.sides / 2 || 5,
38888
39030
  sides = points * 2,
38889
39031
  minorRadius = getMinorRadius(points) * radius,
@@ -38928,6 +39070,34 @@ ${svg}
38928
39070
  return 180 - centerAngle;
38929
39071
  }
38930
39072
 
39073
+ function makeRingSymbol(d, opts) {
39074
+ var scale = +opts.scale || 1;
39075
+ var radii = parseRings(d.radii || '2').map(function(r) { return r * scale; });
39076
+ var solidCenter = utils.isOdd(radii.length);
39077
+ var color = getSymbolColor(d);
39078
+ var parts = [];
39079
+ if (solidCenter) {
39080
+ parts.push({
39081
+ type: 'circle',
39082
+ fill: color,
39083
+ r: radii.shift()
39084
+ });
39085
+ }
39086
+ for (var i=0; i<radii.length; i+= 2) {
39087
+ parts.push({
39088
+ type: 'circle',
39089
+ fill: 'none', // TODO remove default black fill so this is not needed
39090
+ stroke: color,
39091
+ 'stroke-width': roundToTenths(radii[i+1] - radii[i]),
39092
+ r: roundToTenths(radii[i+1] * 0.5 + radii[i] * 0.5)
39093
+ });
39094
+ }
39095
+ return {
39096
+ type: 'group',
39097
+ parts: parts
39098
+ };
39099
+ }
39100
+
38931
39101
  // Returns GeoJSON MultiPolygon coords
38932
39102
  function getRingCoords(d) {
38933
39103
  var radii = parseRings(d.radii || '2');
@@ -38959,6 +39129,27 @@ ${svg}
38959
39129
  return utils.uniq(arr);
38960
39130
  }
38961
39131
 
39132
+ // Returns an svg-symbol data object for one symbol
39133
+ function makePolygonSymbol(coords, properties, geojsonType) {
39134
+ if (geojsonType == 'MultiPolygon') {
39135
+ coords = convertMultiPolygonCoords(coords);
39136
+ } else if (geojsonType != 'Polygon') {
39137
+ error('Unsupported type:', geojsonType);
39138
+ }
39139
+ roundCoordsForSVG(coords);
39140
+ return {
39141
+ type: 'polygon',
39142
+ coordinates: coords,
39143
+ fill: getSymbolColor(properties)
39144
+ };
39145
+ }
39146
+
39147
+ function convertMultiPolygonCoords(coords) {
39148
+ return coords.reduce(function(memo, poly) {
39149
+ return memo.concat(poly);
39150
+ }, []);
39151
+ }
39152
+
38962
39153
  // TODO: refactor to remove duplication in mapshaper-svg-style.js
38963
39154
  cmd.symbols = function(inputLyr, dataset, opts) {
38964
39155
  requireSinglePointLayer(inputLyr);
@@ -38975,8 +39166,20 @@ ${svg}
38975
39166
  if (!shp) return null;
38976
39167
  var d = getSymbolData(i);
38977
39168
  var rec = records[i] || {};
39169
+
39170
+ // non-polygon symbols
39171
+ if (!polygonMode && d.type == 'circle') {
39172
+ rec['svg-symbol'] = makeCircleSymbol(d, opts);
39173
+ return;
39174
+ }
39175
+ if (!polygonMode && d.type == 'ring') {
39176
+ rec['svg-symbol'] = makeRingSymbol(d, opts);
39177
+ return;
39178
+ }
39179
+
38978
39180
  var geojsonType = 'Polygon';
38979
39181
  var coords;
39182
+ // these symbols get converted to polygon shapes
38980
39183
  if (d.type == 'arrow') {
38981
39184
  coords = getFilledArrowCoords(d);
38982
39185
  } else if (d.type == 'ring') {
@@ -39000,7 +39203,7 @@ ${svg}
39000
39203
  if (d.tfill) rec.fill = d.fill;
39001
39204
  return createGeometry(coords, geojsonType);
39002
39205
  } else {
39003
- rec['svg-symbol'] = makeSvgPolygonSymbol(coords, d, geojsonType);
39206
+ rec['svg-symbol'] = makePolygonSymbol(coords, d, geojsonType);
39004
39207
  }
39005
39208
  });
39006
39209
 
@@ -39039,33 +39242,11 @@ ${svg}
39039
39242
  }
39040
39243
 
39041
39244
  function getMetersPerPixel(lyr, dataset) {
39042
-
39043
39245
  // TODO: handle single point, no extent
39044
39246
  var bounds = getLayerBounds(lyr);
39045
39247
  return bounds.width() / 800;
39046
39248
  }
39047
39249
 
39048
- // Returns an svg-symbol data object for one symbol
39049
- function makeSvgPolygonSymbol(coords, properties, geojsonType) {
39050
- if (geojsonType == 'MultiPolygon') {
39051
- coords = convertMultiPolygonCoords(coords);
39052
- } else if (geojsonType != 'Polygon') {
39053
- error('Unsupported type:', geojsonType);
39054
- }
39055
- roundCoordsForSVG(coords);
39056
- return {
39057
- type: 'polygon',
39058
- coordinates: coords,
39059
- fill: properties.fill || 'magenta'
39060
- };
39061
- }
39062
-
39063
- function convertMultiPolygonCoords(coords) {
39064
- return coords.reduce(function(memo, poly) {
39065
- return memo.concat(poly);
39066
- }, []);
39067
- }
39068
-
39069
39250
  var Symbols = /*#__PURE__*/Object.freeze({
39070
39251
  __proto__: null
39071
39252
  });
@@ -39468,7 +39649,20 @@ ${svg}
39468
39649
  return [lyr1, lyr2];
39469
39650
  }
39470
39651
 
39471
- function runCommand(command, catalog, cb) {
39652
+ function commandAcceptsMultipleTargetDatasets(name) {
39653
+ return name == 'rotate' || name == 'info' || name == 'proj' ||
39654
+ name == 'drop' || name == 'target' || name == 'if' || name == 'elif' ||
39655
+ name == 'else' || name == 'endif';
39656
+ }
39657
+
39658
+ function commandAcceptsEmptyTarget(name) {
39659
+ return name == 'graticule' || name == 'i' || name == 'help' ||
39660
+ name == 'point-grid' || name == 'shape' || name == 'rectangle' ||
39661
+ name == 'include' || name == 'print' || name == 'if' || name == 'elif' ||
39662
+ name == 'else' || name == 'endif';
39663
+ }
39664
+
39665
+ function runCommand(command, job, cb) {
39472
39666
  var name = command.name,
39473
39667
  opts = command.options,
39474
39668
  source,
@@ -39481,18 +39675,19 @@ ${svg}
39481
39675
  target,
39482
39676
  arcs;
39483
39677
 
39484
- if (skipCommand(name)) {
39678
+ if (skipCommand(name, job)) {
39485
39679
  return done(null);
39486
39680
  }
39487
39681
 
39488
- try { // catch errors from synchronous functions
39682
+ if (!job) job = new Job();
39683
+ job.startCommand(command);
39489
39684
 
39685
+ try { // catch errors from synchronous functions
39490
39686
  T$1.start();
39491
- if (!catalog) catalog = new Catalog();
39492
39687
 
39493
39688
  if (name == 'rename-layers') {
39494
39689
  // default target is all layers
39495
- targets = catalog.findCommandTargets(opts.target || '*');
39690
+ targets = job.catalog.findCommandTargets(opts.target || '*');
39496
39691
  targetLayers = targets.reduce(function(memo, obj) {
39497
39692
  return memo.concat(obj.layers);
39498
39693
  }, []);
@@ -39500,19 +39695,17 @@ ${svg}
39500
39695
  } else if (name == 'o') {
39501
39696
  // when combining GeoJSON layers, default is all layers
39502
39697
  // TODO: check that combine_layers is only used w/ GeoJSON output
39503
- targets = catalog.findCommandTargets(opts.target || opts.combine_layers && '*');
39698
+ targets = job.catalog.findCommandTargets(opts.target || opts.combine_layers && '*');
39504
39699
 
39505
- } else if (name == 'rotate' || name == 'info' || name == 'proj' || name == 'drop' || name == 'target') {
39506
- // these commands accept multiple target datasets
39507
- targets = catalog.findCommandTargets(opts.target);
39700
+ } else if (commandAcceptsMultipleTargetDatasets(name)) {
39701
+ targets = job.catalog.findCommandTargets(opts.target);
39508
39702
 
39509
39703
  } else {
39510
- targets = catalog.findCommandTargets(opts.target);
39511
-
39704
+ targets = job.catalog.findCommandTargets(opts.target);
39512
39705
  // special case to allow -merge-layers and -union to combine layers from multiple datasets
39513
39706
  // TODO: support multi-dataset targets for other commands
39514
39707
  if (targets.length > 1 && (name == 'merge-layers' || name == 'union')) {
39515
- targets = mergeCommandTargets(targets, catalog);
39708
+ targets = mergeCommandTargets(targets, job.catalog);
39516
39709
  }
39517
39710
 
39518
39711
  if (targets.length == 1) {
@@ -39520,7 +39713,7 @@ ${svg}
39520
39713
  arcs = targetDataset.arcs;
39521
39714
  targetLayers = targets[0].layers;
39522
39715
  // target= option sets default target
39523
- catalog.setDefaultTarget(targetLayers, targetDataset);
39716
+ job.catalog.setDefaultTarget(targetLayers, targetDataset);
39524
39717
 
39525
39718
  } else if (targets.length > 1) {
39526
39719
  stop("This command does not support targetting layers from different datasets");
@@ -39530,17 +39723,15 @@ ${svg}
39530
39723
  if (targets.length === 0) {
39531
39724
  if (opts.target) {
39532
39725
  stop(utils.format('Missing target: %s\nAvailable layers: %s',
39533
- opts.target, getFormattedLayerList(catalog)));
39726
+ opts.target, getFormattedLayerList(job.catalog)));
39534
39727
  }
39535
- if (!(name == 'graticule' || name == 'i' || name == 'help' ||
39536
- name == 'point-grid' || name == 'shape' || name == 'rectangle' ||
39537
- name == 'include' || name == 'print')) {
39728
+ if (!commandAcceptsEmptyTarget(name)) {
39538
39729
  throw new UserError("No data is available");
39539
39730
  }
39540
39731
  }
39541
39732
 
39542
39733
  if (opts.source) {
39543
- source = findCommandSource(convertSourceName(opts.source, targets), catalog, opts);
39734
+ source = findCommandSource(convertSourceName(opts.source, targets), job.catalog, opts);
39544
39735
  }
39545
39736
 
39546
39737
  if (name == 'affine') {
@@ -39594,7 +39785,7 @@ ${svg}
39594
39785
  outputLayers = applyCommandToEachLayer(cmd.dots, targetLayers, arcs, opts);
39595
39786
 
39596
39787
  } else if (name == 'drop') {
39597
- cmd.drop2(catalog, targets, opts);
39788
+ cmd.drop2(job.catalog, targets, opts);
39598
39789
  // cmd.drop(catalog, targetLayers, targetDataset, opts);
39599
39790
 
39600
39791
  } else if (name == 'each') {
@@ -39631,33 +39822,33 @@ ${svg}
39631
39822
  applyCommandToEachLayer(cmd.filterSlivers, targetLayers, targetDataset, opts);
39632
39823
 
39633
39824
  } else if (name == 'frame') {
39634
- cmd.frame(catalog, source, opts);
39825
+ cmd.frame(job.catalog, source, opts);
39635
39826
 
39636
39827
  } else if (name == 'fuzzy-join') {
39637
39828
  applyCommandToEachLayer(cmd.fuzzyJoin, targetLayers, arcs, source, opts);
39638
39829
 
39639
39830
  } else if (name == 'graticule') {
39640
- catalog.addDataset(cmd.graticule(targetDataset, opts));
39831
+ job.catalog.addDataset(cmd.graticule(targetDataset, opts));
39641
39832
 
39642
39833
  } else if (name == 'help') {
39643
39834
  // placing this here to handle errors from invalid command names
39644
39835
  getOptionParser().printHelp(command.options.command);
39645
39836
 
39646
39837
  } else if (name == 'i') {
39647
- if (opts.replace) catalog = new Catalog();
39838
+ if (opts.replace) job.catalog = new Catalog(); // is this what we want?
39648
39839
  targetDataset = cmd.importFiles(command.options);
39649
39840
  if (targetDataset) {
39650
- catalog.addDataset(targetDataset);
39841
+ job.catalog.addDataset(targetDataset);
39651
39842
  outputLayers = targetDataset.layers; // kludge to allow layer naming below
39652
39843
  }
39653
39844
 
39654
39845
  } else if (name == 'if' || name == 'elif') {
39655
39846
  // target = findSingleTargetLayer(opts.layer, targets[0], catalog);
39656
39847
  // cmd[name](target.layer, target.dataset, opts);
39657
- cmd[name](catalog, opts);
39848
+ cmd[name](job, opts);
39658
39849
 
39659
39850
  } else if (name == 'else' || name == 'endif') {
39660
- cmd[name]();
39851
+ cmd[name](job);
39661
39852
 
39662
39853
  } else if (name == 'ignore') {
39663
39854
  applyCommandToEachLayer(cmd.ignore, targetLayers, targetDataset, opts);
@@ -39697,14 +39888,16 @@ ${svg}
39697
39888
  outputFiles = exportTargetLayers(targets, opts);
39698
39889
  if (opts.final) {
39699
39890
  // don't propagate data if output is final
39700
- catalog = null;
39891
+ //// catalog = null;
39892
+ job.catalog = new Catalog();
39701
39893
  }
39702
- return writeFiles(outputFiles, opts, done);
39894
+ writeFiles(outputFiles, opts, done);
39895
+ return; // async command
39703
39896
 
39704
39897
  } else if (name == 'point-grid') {
39705
39898
  outputLayers = [cmd.pointGrid(targetDataset, opts)];
39706
39899
  if (!targetDataset) {
39707
- catalog.addDataset({layers: outputLayers});
39900
+ job.catalog.addDataset({layers: outputLayers});
39708
39901
  }
39709
39902
 
39710
39903
  } else if (name == 'point-to-grid') {
@@ -39724,10 +39917,11 @@ ${svg}
39724
39917
 
39725
39918
  } else if (name == 'proj') {
39726
39919
  initProjLibrary(opts, function() {
39920
+ job.resumeCommand();
39727
39921
  var err = null;
39728
39922
  try {
39729
39923
  targets.forEach(function(targ) {
39730
- cmd.proj(targ.dataset, catalog, opts);
39924
+ cmd.proj(targ.dataset, job.catalog, opts);
39731
39925
  });
39732
39926
  } catch(e) {
39733
39927
  err = e;
@@ -39738,7 +39932,7 @@ ${svg}
39738
39932
 
39739
39933
  } else if (name == 'rectangle') {
39740
39934
  if (source || opts.bbox || targets.length === 0) {
39741
- catalog.addDataset(cmd.rectangle(source, opts));
39935
+ job.catalog.addDataset(cmd.rectangle(source, opts));
39742
39936
  } else {
39743
39937
  outputLayers = cmd.rectangle2(targets[0], opts);
39744
39938
  }
@@ -39750,7 +39944,7 @@ ${svg}
39750
39944
  applyCommandToEachLayer(cmd.renameFields, targetLayers, opts.fields);
39751
39945
 
39752
39946
  } else if (name == 'rename-layers') {
39753
- cmd.renameLayers(targetLayers, opts.names, catalog);
39947
+ cmd.renameLayers(targetLayers, opts.names, job.catalog);
39754
39948
 
39755
39949
  } else if (name == 'require') {
39756
39950
  cmd.require(targets, opts);
@@ -39761,14 +39955,14 @@ ${svg}
39761
39955
  });
39762
39956
 
39763
39957
  } else if (name == 'run') {
39764
- cmd.run(targets, catalog, opts, done);
39765
- return;
39958
+ cmd.run(job, targets, opts, done);
39959
+ return; // async command
39766
39960
 
39767
39961
  } else if (name == 'scalebar') {
39768
- cmd.scalebar(catalog, opts);
39962
+ cmd.scalebar(job.catalog, opts);
39769
39963
 
39770
39964
  } else if (name == 'shape') {
39771
- catalog.addDataset(cmd.shape(targetDataset, opts));
39965
+ job.catalog.addDataset(cmd.shape(targetDataset, opts));
39772
39966
 
39773
39967
  } else if (name == 'shapes') {
39774
39968
  outputLayers = applyCommandToEachLayer(cmd.shapes, targetLayers, targetDataset, opts);
@@ -39808,7 +40002,7 @@ ${svg}
39808
40002
  outputLayers = applyCommandToEachLayer(cmd.subdivideLayer, targetLayers, arcs, opts.expression);
39809
40003
 
39810
40004
  } else if (name == 'target') {
39811
- cmd.target(catalog, opts);
40005
+ cmd.target(job.catalog, opts);
39812
40006
 
39813
40007
  } else if (name == 'union') {
39814
40008
  outputLayers = cmd.union(targetLayers, targetDataset, opts);
@@ -39818,7 +40012,7 @@ ${svg}
39818
40012
 
39819
40013
  } else {
39820
40014
  // throws error if command is not registered
39821
- cmd.runExternalCommand(command, catalog);
40015
+ cmd.runExternalCommand(command, job.catalog);
39822
40016
  }
39823
40017
 
39824
40018
  // apply name parameter
@@ -39830,12 +40024,12 @@ ${svg}
39830
40024
  }
39831
40025
 
39832
40026
  if (outputDataset) {
39833
- catalog.addDataset(outputDataset); // also sets default target
40027
+ job.catalog.addDataset(outputDataset); // also sets default target
39834
40028
  outputLayers = outputDataset.layers;
39835
40029
  if (targetLayers && !opts.no_replace) {
39836
40030
  // remove target layers from target dataset
39837
40031
  targetLayers.forEach(function(lyr) {
39838
- catalog.deleteLayer(lyr, targetDataset);
40032
+ job.catalog.deleteLayer(lyr, targetDataset);
39839
40033
  });
39840
40034
  }
39841
40035
  } else if (outputLayers && targetDataset && outputLayers != targetDataset.layers) {
@@ -39858,7 +40052,7 @@ ${svg}
39858
40052
  }
39859
40053
 
39860
40054
  if (opts.apart) {
39861
- catalog.setDefaultTargets(splitApartLayers( targetDataset, outputLayers).map(function(dataset) {
40055
+ job.catalog.setDefaultTargets(splitApartLayers( targetDataset, outputLayers).map(function(dataset) {
39862
40056
  return {
39863
40057
  dataset: dataset,
39864
40058
  layers: dataset.layers.concat()
@@ -39866,9 +40060,8 @@ ${svg}
39866
40060
  }));
39867
40061
  } else {
39868
40062
  // use command output as new default target
39869
- catalog.setDefaultTarget(outputLayers, targetDataset);
40063
+ job.catalog.setDefaultTarget(outputLayers, targetDataset);
39870
40064
  }
39871
-
39872
40065
  }
39873
40066
 
39874
40067
  // delete arcs if no longer needed (e.g. after -points command)
@@ -39880,11 +40073,13 @@ ${svg}
39880
40073
  return done(e);
39881
40074
  }
39882
40075
 
40076
+ // non-erroring synchronous commands are done
39883
40077
  done(null);
39884
40078
 
39885
40079
  function done(err) {
40080
+ job.endCommand();
39886
40081
  verbose('-', T$1.stop());
39887
- cb(err, err ? null : catalog);
40082
+ cb(err, err ? null : job);
39888
40083
  }
39889
40084
  }
39890
40085
 
@@ -39894,7 +40089,6 @@ ${svg}
39894
40089
  });
39895
40090
  }
39896
40091
 
39897
-
39898
40092
  // Apply a command to an array of target layers
39899
40093
  function applyCommandToEachLayer(func, targetLayers) {
39900
40094
  var args = utils.toArray(arguments).slice(2);
@@ -40028,7 +40222,7 @@ ${svg}
40028
40222
  }
40029
40223
 
40030
40224
  // add options to -i -o -join -clip -erase commands to bypass file i/o
40031
- // TODO: find a less kludgy solution, e.g. storing input data using setStateVar()
40225
+ // TODO: find a less kludgy solution
40032
40226
  commands.forEach(function(cmd) {
40033
40227
  if (commandTakesFileInput(cmd.name) && inputObj) {
40034
40228
  cmd.options.input = inputObj;
@@ -40074,8 +40268,8 @@ ${svg}
40074
40268
 
40075
40269
  // TODO: rewrite tests and remove this function
40076
40270
  function testCommands(argv, done) {
40077
- _runCommands(argv, {}, function(err, catalog) {
40078
- var targets = catalog ? catalog.getDefaultTargets() : [];
40271
+ _runCommands(argv, {}, function(err, job) {
40272
+ var targets = job ? job.catalog.getDefaultTargets() : [];
40079
40273
  var output;
40080
40274
  if (!err && targets.length > 0) {
40081
40275
  // returns dataset for compatibility with some older tests
@@ -40087,15 +40281,12 @@ ${svg}
40087
40281
 
40088
40282
  // Execute a sequence of parsed commands
40089
40283
  // @commands Array of parsed commands
40090
- // @catalog: Optional Catalog object containing previously imported data
40284
+ // @job: Optional Job object containing previously imported data
40091
40285
  // @cb: function(<error>, <catalog>)
40092
40286
  //
40093
- function runParsedCommands(commands, catalog, cb) {
40094
- if (!catalog) {
40095
- cb = createAsyncContext(cb); // use new context when creating new catalog
40096
- catalog = new Catalog();
40097
- } else if (catalog instanceof Catalog === false) {
40098
- error("Changed in v0.4: runParsedCommands() takes a Catalog object");
40287
+ function runParsedCommands(commands, job, cb) {
40288
+ if (!job) {
40289
+ job = new Job();
40099
40290
  }
40100
40291
 
40101
40292
  if (!utils.isArray(commands)) {
@@ -40105,7 +40296,7 @@ ${svg}
40105
40296
  if (commands.length === 0) {
40106
40297
  return done(new UserError("No commands to run"));
40107
40298
  }
40108
- commands = readAndRemoveSettings(commands);
40299
+ commands = readAndRemoveSettings(job, commands);
40109
40300
  if (!runningInBrowser()) {
40110
40301
  printStartupMessages();
40111
40302
  }
@@ -40122,25 +40313,22 @@ ${svg}
40122
40313
  var groups = divideImportCommand(commands);
40123
40314
  if (groups.length == 1) {
40124
40315
  // run a simple sequence of commands (input files are not batched)
40125
- return runParsedCommands2(commands, catalog, done);
40316
+ return runParsedCommands2(commands, job, done);
40126
40317
  }
40127
40318
 
40128
40319
  // run duplicated commands (i.e. batch mode)
40129
- utils.reduceAsync(groups, catalog, nextGroup, done);
40320
+ utils.reduceAsync(groups, job, nextGroup, done);
40130
40321
 
40131
- function nextGroup(catalog, commands, next) {
40132
- runParsedCommands2(commands, catalog, function(err, catalog) {
40322
+ function nextGroup(job, commands, next) {
40323
+ runParsedCommands2(commands, job, function(err, job) {
40133
40324
  err = filterError(err);
40134
- next(err, catalog);
40325
+ next(err, job);
40135
40326
  });
40136
40327
  }
40137
40328
 
40138
- function done(err, catalog) {
40329
+ function done(err, job) {
40139
40330
  err = filterError(err);
40140
- cb(err, catalog);
40141
- setStateVar('current_command', null);
40142
- setStateVar('verbose', false);
40143
- setStateVar('debug', false);
40331
+ cb(err, job);
40144
40332
  }
40145
40333
  }
40146
40334
 
@@ -40152,16 +40340,13 @@ ${svg}
40152
40340
  return err;
40153
40341
  }
40154
40342
 
40155
- function runParsedCommands2(commands, catalog, cb) {
40343
+ function runParsedCommands2(commands, job, cb) {
40156
40344
  // resetting closes any unterminated -if blocks from a previous command sequence
40157
- resetControlFlow();
40158
- utils.reduceAsync(commands, catalog, nextCommand, cb);
40345
+ resetControlFlow(job);
40346
+ utils.reduceAsync(commands, job, nextCommand, cb);
40159
40347
 
40160
- function nextCommand(catalog, cmd, next) {
40161
- setStateVar('current_command', cmd.name); // for log msgs
40162
- setStateVar('verbose', !!cmd.options.verbose);
40163
- setStateVar('debug', !!cmd.options.debug);
40164
- runCommand(cmd, catalog, next);
40348
+ function nextCommand(job, cmd, next) {
40349
+ runCommand(cmd, job, next);
40165
40350
  }
40166
40351
  }
40167
40352
 
@@ -40207,19 +40392,22 @@ ${svg}
40207
40392
  }
40208
40393
 
40209
40394
  // Some settings use command syntax and are parsed as commands.
40210
- function readAndRemoveSettings(commands) {
40211
- return commands.filter(function(cmd) {
40395
+ function readAndRemoveSettings(job, commands) {
40396
+ var settings = {VERBOSE: false, QUIET: false, DEBUG: false};
40397
+ var filtered = commands.filter(function(cmd) {
40212
40398
  if (cmd.name == 'verbose') {
40213
- setStateVar('VERBOSE', true);
40399
+ settings.VERBOSE = true;
40214
40400
  } else if (cmd.name == 'quiet') {
40215
- setStateVar('QUIET', true);
40401
+ settings.QUIET = true;
40216
40402
  } else if (cmd.name == 'debug') {
40217
- setStateVar('DEBUG', true);
40403
+ settings.DEBUG = true;
40218
40404
  } else {
40219
40405
  return true;
40220
40406
  }
40221
40407
  return false;
40222
40408
  });
40409
+ job.initSettings(settings);
40410
+ return filtered;
40223
40411
  }
40224
40412
 
40225
40413
  // Run informational commands and remove them from the array of parsed commands
@@ -40565,12 +40753,14 @@ ${svg}
40565
40753
  // export only functions called by the GUI.
40566
40754
 
40567
40755
  var internal = {};
40568
- internal.svg = Object.assign({}, SvgCommon, SvgStringify, SvgPathUtils, GeojsonToSvg);
40756
+
40757
+ internal.svg = Object.assign({}, SvgStringify, SvgPathUtils, GeojsonToSvg, SvgLabels, SvgSymbols);
40569
40758
 
40570
40759
  // Assign functions and objects exported from modules to the 'internal' namespace
40571
40760
  // to maintain compatibility with tests and to expose (some of) them to the GUI.
40572
40761
 
40573
40762
  Object.assign(internal, {
40763
+ Job,
40574
40764
  Dbf,
40575
40765
  DbfReader,
40576
40766
  DouglasPeucker,
@@ -40694,6 +40884,7 @@ ${svg}
40694
40884
  SourceUtils,
40695
40885
  Split,
40696
40886
  State,
40887
+ Stash,
40697
40888
  Stringify,
40698
40889
  Svg,
40699
40890
  SvgProperties,