mapshaper 0.5.69 → 0.5.70

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/CHANGELOG.md CHANGED
@@ -1,3 +1,6 @@
1
+ v0.5.70
2
+ * Added -join duplication option, which duplicates features in the target layer when many-to-one joins occur.
3
+
1
4
  v0.5.69
2
5
  * Added undocumented -ignore command.
3
6
  * Bug fix
package/mapshaper.js CHANGED
@@ -1,6 +1,6 @@
1
1
  (function () {
2
2
 
3
- var VERSION = "0.5.68";
3
+ var VERSION = "0.5.69";
4
4
 
5
5
 
6
6
  var utils = /*#__PURE__*/Object.freeze({
@@ -19270,6 +19270,10 @@ ${svg}
19270
19270
  // describe: 'use planar geometry when interpolating by area' // useful for testing
19271
19271
  type: 'flag'
19272
19272
  })
19273
+ .option('duplication', {
19274
+ describe: 'duplicate target features on many-to-one joins',
19275
+ type: 'flag'
19276
+ })
19273
19277
  .option('string-fields', stringFieldsOpt)
19274
19278
  .option('field-types', fieldTypesOpt)
19275
19279
  .option('sum-fields', {
@@ -29836,13 +29840,19 @@ ${svg}
29836
29840
  getJoinFilter: getJoinFilter
29837
29841
  });
29838
29842
 
29843
+ function joinTables(dest, src, join, opts) {
29844
+ return joinTableToLayer({data: dest}, src, join, opts);
29845
+ }
29846
+
29839
29847
  // Join data from @src table to records in @dest table
29840
29848
  // @join function
29841
29849
  // Receives index of record in the dest table
29842
29850
  // Returns array of matching records in src table, or null if no matches
29843
29851
  //
29844
- function joinTables(dest, src, join, opts) {
29845
- var srcRecords = src.getRecords(),
29852
+ function joinTableToLayer(destLyr, src, join, opts) {
29853
+ var dest = destLyr.data,
29854
+ useDuplication = !!opts.duplication,
29855
+ srcRecords = src.getRecords(),
29846
29856
  destRecords = dest.getRecords(),
29847
29857
  prefix = opts.prefix || '',
29848
29858
  unmatchedRecords = [],
@@ -29857,6 +29867,14 @@ ${svg}
29857
29867
  retn = {},
29858
29868
  srcRec, srcId, destRec, joins, count, filter, calc, i, j, n, m;
29859
29869
 
29870
+ // support for duplication
29871
+ var duplicateRecords, destShapes;
29872
+ if (useDuplication) {
29873
+ if (opts.calc) stop('duplication and calc options cannot be used together');
29874
+ duplicateRecords = dest.clone().getRecords();
29875
+ destShapes = destLyr.shapes || [];
29876
+ }
29877
+
29860
29878
  if (opts.where) {
29861
29879
  filter = getJoinFilter(src, opts.where);
29862
29880
  }
@@ -29866,7 +29884,8 @@ ${svg}
29866
29884
  }
29867
29885
 
29868
29886
  // join source records to target records
29869
- for (i=0, n=destRecords.length; i<n; i++) {
29887
+ n = destRecords.length;
29888
+ for (i=0; i<n; i++) {
29870
29889
  destRec = destRecords[i];
29871
29890
  joins = join(i);
29872
29891
  if (joins && filter) {
@@ -29877,7 +29896,12 @@ ${svg}
29877
29896
  for (j=0, count=0, m=joins ? joins.length : 0; j<m; j++) {
29878
29897
  srcId = joins[j];
29879
29898
  srcRec = srcRecords[srcId];
29880
- if (count === 0) {
29899
+ if (count > 0 && useDuplication) {
29900
+ destRec = copyRecord(duplicateRecords[i]);
29901
+ destRecords.push(destRec);
29902
+ destShapes.push(cloneShape(destShapes[i]));
29903
+ }
29904
+ if (count === 0 || useDuplication) {
29881
29905
  if (copyFields.length > 0) {
29882
29906
  // only copying the first match
29883
29907
  joinByCopy(destRec, srcRec, copyFields, prefix);
@@ -29909,7 +29933,7 @@ ${svg}
29909
29933
  }
29910
29934
  }
29911
29935
 
29912
- printJoinMessage(matchCount, destRecords.length,
29936
+ printJoinMessage(matchCount, n,
29913
29937
  countJoins(joinCounts), srcRecords.length, skipCount, collisionCount, collisionFields);
29914
29938
 
29915
29939
  if (opts.unjoined) {
@@ -29937,6 +29961,7 @@ ${svg}
29937
29961
  });
29938
29962
  }
29939
29963
 
29964
+
29940
29965
  function countJoins(counts) {
29941
29966
  var joinCount = 0;
29942
29967
  for (var i=0, n=counts.length; i<n; i++) {
@@ -29999,14 +30024,16 @@ ${svg}
29999
30024
 
30000
30025
  function printJoinMessage(matches, n, joins, m, skipped, collisions, collisionFields) {
30001
30026
  // TODO: add tip for troubleshooting join problems, if join is less than perfect.
30027
+ var unmatched = n - matches;
30002
30028
  if (matches > 0 === false) {
30003
30029
  message("No records could be joined");
30004
30030
  return;
30005
30031
  }
30006
30032
  message(utils.format("Joined data from %'d source record%s to %'d target record%s",
30007
30033
  joins, utils.pluralSuffix(joins), matches, utils.pluralSuffix(matches)));
30008
- if (matches < n) {
30009
- message(utils.format('%d/%d target records received no data', n-matches, n));
30034
+ if (unmatched > 0) {
30035
+ message(utils.format('%d target record%s received no data', unmatched, utils.pluralSuffix(unmatched)));
30036
+ // message(utils.format('%d target records received no data', n-matches));
30010
30037
  }
30011
30038
  if (joins < m) {
30012
30039
  message(utils.format("%d/%d source records could not be joined", m-joins, m));
@@ -30055,6 +30082,7 @@ ${svg}
30055
30082
  var JoinTables = /*#__PURE__*/Object.freeze({
30056
30083
  __proto__: null,
30057
30084
  joinTables: joinTables,
30085
+ joinTableToLayer: joinTableToLayer,
30058
30086
  validateFieldNames: validateFieldNames,
30059
30087
  updateUnmatchedRecord: updateUnmatchedRecord,
30060
30088
  findCollisionFields: findCollisionFields,
@@ -31521,13 +31549,13 @@ ${svg}
31521
31549
  // TODO: option to copy points that can't be joined to a new layer
31522
31550
  var joinFunction = getPolygonToPointsFunction(targetLyr, arcs, pointLyr, opts);
31523
31551
  prepJoinLayers(targetLyr, pointLyr);
31524
- return joinTables(targetLyr.data, pointLyr.data, joinFunction, opts);
31552
+ return joinTableToLayer(targetLyr, pointLyr.data, joinFunction, opts);
31525
31553
  }
31526
31554
 
31527
31555
  function joinPolygonsToPoints(targetLyr, polygonLyr, arcs, opts) {
31528
31556
  var joinFunction = getPointToPolygonsFunction(targetLyr, polygonLyr, arcs, opts);
31529
31557
  prepJoinLayers(targetLyr, polygonLyr);
31530
- return joinTables(targetLyr.data, polygonLyr.data, joinFunction, opts);
31558
+ return joinTableToLayer(targetLyr, polygonLyr.data, joinFunction, opts);
31531
31559
  }
31532
31560
 
31533
31561
 
@@ -33694,9 +33722,10 @@ ${svg}
33694
33722
 
33695
33723
  var joinOpts = utils.extend({}, opts);
33696
33724
  var joinFunction = getPolygonToPolygonFunction(targetLyr, sourceLyr, mosaicIndex, opts);
33697
- var retn = joinTables(targetLyr.data, sourceLyr.data, joinFunction, joinOpts);
33725
+ var retn = joinTableToLayer(targetLyr, sourceLyr.data, joinFunction, joinOpts);
33698
33726
 
33699
33727
  if (opts.interpolate) {
33728
+ if (opts.duplication) stop('duplication and interpolate options cannot be used together');
33700
33729
  interpolateFieldsByArea(targetLyr, sourceLyr, mosaicIndex, opts);
33701
33730
  }
33702
33731
  return retn;
@@ -34611,7 +34640,7 @@ ${svg}
34611
34640
  function joinPointsToPoints(targetLyr, srcLyr, crs, opts) {
34612
34641
  var joinFunction = getPointToPointFunction(targetLyr, srcLyr, crs, opts);
34613
34642
  prepJoinLayers(targetLyr, srcLyr);
34614
- return joinTables(targetLyr.data, srcLyr.data, joinFunction, opts);
34643
+ return joinTableToLayer(targetLyr, srcLyr.data, joinFunction, opts);
34615
34644
  }
34616
34645
 
34617
34646
  function getPointToPointFunction(targetLyr, srcLyr, crs, opts) {
@@ -34661,14 +34690,14 @@ ${svg}
34661
34690
  }
34662
34691
  };
34663
34692
 
34664
- function joinAttributesToFeatures(lyr, srcTable, opts) {
34693
+ function joinAttributesToFeatures(destLyr, srcTable, opts) {
34665
34694
  var keys = opts.keys,
34666
34695
  destKey = keys[0],
34667
34696
  srcKey = keys[1],
34668
- destTable = lyr.data,
34697
+ destTable = destLyr.data,
34669
34698
  joinFunction = getJoinByKey(destTable, destKey, srcTable, srcKey);
34670
34699
  validateFieldNames(keys);
34671
- return joinTables(destTable, srcTable, joinFunction, opts);
34700
+ return joinTableToLayer(destLyr, srcTable, joinFunction, opts);
34672
34701
  }
34673
34702
 
34674
34703
  // Return a function for translating a target id to an array of source ids based on values
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mapshaper",
3
- "version": "0.5.69",
3
+ "version": "0.5.70",
4
4
  "description": "A tool for editing vector datasets for mapping and GIS.",
5
5
  "keywords": [
6
6
  "shapefile",
package/www/mapshaper.js CHANGED
@@ -1,6 +1,6 @@
1
1
  (function () {
2
2
 
3
- var VERSION = "0.5.68";
3
+ var VERSION = "0.5.69";
4
4
 
5
5
 
6
6
  var utils = /*#__PURE__*/Object.freeze({
@@ -19270,6 +19270,10 @@ ${svg}
19270
19270
  // describe: 'use planar geometry when interpolating by area' // useful for testing
19271
19271
  type: 'flag'
19272
19272
  })
19273
+ .option('duplication', {
19274
+ describe: 'duplicate target features on many-to-one joins',
19275
+ type: 'flag'
19276
+ })
19273
19277
  .option('string-fields', stringFieldsOpt)
19274
19278
  .option('field-types', fieldTypesOpt)
19275
19279
  .option('sum-fields', {
@@ -29836,13 +29840,19 @@ ${svg}
29836
29840
  getJoinFilter: getJoinFilter
29837
29841
  });
29838
29842
 
29843
+ function joinTables(dest, src, join, opts) {
29844
+ return joinTableToLayer({data: dest}, src, join, opts);
29845
+ }
29846
+
29839
29847
  // Join data from @src table to records in @dest table
29840
29848
  // @join function
29841
29849
  // Receives index of record in the dest table
29842
29850
  // Returns array of matching records in src table, or null if no matches
29843
29851
  //
29844
- function joinTables(dest, src, join, opts) {
29845
- var srcRecords = src.getRecords(),
29852
+ function joinTableToLayer(destLyr, src, join, opts) {
29853
+ var dest = destLyr.data,
29854
+ useDuplication = !!opts.duplication,
29855
+ srcRecords = src.getRecords(),
29846
29856
  destRecords = dest.getRecords(),
29847
29857
  prefix = opts.prefix || '',
29848
29858
  unmatchedRecords = [],
@@ -29857,6 +29867,14 @@ ${svg}
29857
29867
  retn = {},
29858
29868
  srcRec, srcId, destRec, joins, count, filter, calc, i, j, n, m;
29859
29869
 
29870
+ // support for duplication
29871
+ var duplicateRecords, destShapes;
29872
+ if (useDuplication) {
29873
+ if (opts.calc) stop('duplication and calc options cannot be used together');
29874
+ duplicateRecords = dest.clone().getRecords();
29875
+ destShapes = destLyr.shapes || [];
29876
+ }
29877
+
29860
29878
  if (opts.where) {
29861
29879
  filter = getJoinFilter(src, opts.where);
29862
29880
  }
@@ -29866,7 +29884,8 @@ ${svg}
29866
29884
  }
29867
29885
 
29868
29886
  // join source records to target records
29869
- for (i=0, n=destRecords.length; i<n; i++) {
29887
+ n = destRecords.length;
29888
+ for (i=0; i<n; i++) {
29870
29889
  destRec = destRecords[i];
29871
29890
  joins = join(i);
29872
29891
  if (joins && filter) {
@@ -29877,7 +29896,12 @@ ${svg}
29877
29896
  for (j=0, count=0, m=joins ? joins.length : 0; j<m; j++) {
29878
29897
  srcId = joins[j];
29879
29898
  srcRec = srcRecords[srcId];
29880
- if (count === 0) {
29899
+ if (count > 0 && useDuplication) {
29900
+ destRec = copyRecord(duplicateRecords[i]);
29901
+ destRecords.push(destRec);
29902
+ destShapes.push(cloneShape(destShapes[i]));
29903
+ }
29904
+ if (count === 0 || useDuplication) {
29881
29905
  if (copyFields.length > 0) {
29882
29906
  // only copying the first match
29883
29907
  joinByCopy(destRec, srcRec, copyFields, prefix);
@@ -29909,7 +29933,7 @@ ${svg}
29909
29933
  }
29910
29934
  }
29911
29935
 
29912
- printJoinMessage(matchCount, destRecords.length,
29936
+ printJoinMessage(matchCount, n,
29913
29937
  countJoins(joinCounts), srcRecords.length, skipCount, collisionCount, collisionFields);
29914
29938
 
29915
29939
  if (opts.unjoined) {
@@ -29937,6 +29961,7 @@ ${svg}
29937
29961
  });
29938
29962
  }
29939
29963
 
29964
+
29940
29965
  function countJoins(counts) {
29941
29966
  var joinCount = 0;
29942
29967
  for (var i=0, n=counts.length; i<n; i++) {
@@ -29999,14 +30024,16 @@ ${svg}
29999
30024
 
30000
30025
  function printJoinMessage(matches, n, joins, m, skipped, collisions, collisionFields) {
30001
30026
  // TODO: add tip for troubleshooting join problems, if join is less than perfect.
30027
+ var unmatched = n - matches;
30002
30028
  if (matches > 0 === false) {
30003
30029
  message("No records could be joined");
30004
30030
  return;
30005
30031
  }
30006
30032
  message(utils.format("Joined data from %'d source record%s to %'d target record%s",
30007
30033
  joins, utils.pluralSuffix(joins), matches, utils.pluralSuffix(matches)));
30008
- if (matches < n) {
30009
- message(utils.format('%d/%d target records received no data', n-matches, n));
30034
+ if (unmatched > 0) {
30035
+ message(utils.format('%d target record%s received no data', unmatched, utils.pluralSuffix(unmatched)));
30036
+ // message(utils.format('%d target records received no data', n-matches));
30010
30037
  }
30011
30038
  if (joins < m) {
30012
30039
  message(utils.format("%d/%d source records could not be joined", m-joins, m));
@@ -30055,6 +30082,7 @@ ${svg}
30055
30082
  var JoinTables = /*#__PURE__*/Object.freeze({
30056
30083
  __proto__: null,
30057
30084
  joinTables: joinTables,
30085
+ joinTableToLayer: joinTableToLayer,
30058
30086
  validateFieldNames: validateFieldNames,
30059
30087
  updateUnmatchedRecord: updateUnmatchedRecord,
30060
30088
  findCollisionFields: findCollisionFields,
@@ -31521,13 +31549,13 @@ ${svg}
31521
31549
  // TODO: option to copy points that can't be joined to a new layer
31522
31550
  var joinFunction = getPolygonToPointsFunction(targetLyr, arcs, pointLyr, opts);
31523
31551
  prepJoinLayers(targetLyr, pointLyr);
31524
- return joinTables(targetLyr.data, pointLyr.data, joinFunction, opts);
31552
+ return joinTableToLayer(targetLyr, pointLyr.data, joinFunction, opts);
31525
31553
  }
31526
31554
 
31527
31555
  function joinPolygonsToPoints(targetLyr, polygonLyr, arcs, opts) {
31528
31556
  var joinFunction = getPointToPolygonsFunction(targetLyr, polygonLyr, arcs, opts);
31529
31557
  prepJoinLayers(targetLyr, polygonLyr);
31530
- return joinTables(targetLyr.data, polygonLyr.data, joinFunction, opts);
31558
+ return joinTableToLayer(targetLyr, polygonLyr.data, joinFunction, opts);
31531
31559
  }
31532
31560
 
31533
31561
 
@@ -33694,9 +33722,10 @@ ${svg}
33694
33722
 
33695
33723
  var joinOpts = utils.extend({}, opts);
33696
33724
  var joinFunction = getPolygonToPolygonFunction(targetLyr, sourceLyr, mosaicIndex, opts);
33697
- var retn = joinTables(targetLyr.data, sourceLyr.data, joinFunction, joinOpts);
33725
+ var retn = joinTableToLayer(targetLyr, sourceLyr.data, joinFunction, joinOpts);
33698
33726
 
33699
33727
  if (opts.interpolate) {
33728
+ if (opts.duplication) stop('duplication and interpolate options cannot be used together');
33700
33729
  interpolateFieldsByArea(targetLyr, sourceLyr, mosaicIndex, opts);
33701
33730
  }
33702
33731
  return retn;
@@ -34611,7 +34640,7 @@ ${svg}
34611
34640
  function joinPointsToPoints(targetLyr, srcLyr, crs, opts) {
34612
34641
  var joinFunction = getPointToPointFunction(targetLyr, srcLyr, crs, opts);
34613
34642
  prepJoinLayers(targetLyr, srcLyr);
34614
- return joinTables(targetLyr.data, srcLyr.data, joinFunction, opts);
34643
+ return joinTableToLayer(targetLyr, srcLyr.data, joinFunction, opts);
34615
34644
  }
34616
34645
 
34617
34646
  function getPointToPointFunction(targetLyr, srcLyr, crs, opts) {
@@ -34661,14 +34690,14 @@ ${svg}
34661
34690
  }
34662
34691
  };
34663
34692
 
34664
- function joinAttributesToFeatures(lyr, srcTable, opts) {
34693
+ function joinAttributesToFeatures(destLyr, srcTable, opts) {
34665
34694
  var keys = opts.keys,
34666
34695
  destKey = keys[0],
34667
34696
  srcKey = keys[1],
34668
- destTable = lyr.data,
34697
+ destTable = destLyr.data,
34669
34698
  joinFunction = getJoinByKey(destTable, destKey, srcTable, srcKey);
34670
34699
  validateFieldNames(keys);
34671
- return joinTables(destTable, srcTable, joinFunction, opts);
34700
+ return joinTableToLayer(destLyr, srcTable, joinFunction, opts);
34672
34701
  }
34673
34702
 
34674
34703
  // Return a function for translating a target id to an array of source ids based on values