index.js 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687
  1. import length from '@turf/length';
  2. import lineSliceAlong from '@turf/line-slice-along';
  3. import { flattenEach } from '@turf/meta';
  4. import { isObject, featureCollection } from '@turf/helpers';
  5. /**
  6. * Divides a {@link LineString} into chunks of a specified length.
  7. * If the line is shorter than the segment length then the original line is returned.
  8. *
  9. * @name lineChunk
  10. * @param {FeatureCollection|Geometry|Feature<LineString|MultiLineString>} geojson the lines to split
  11. * @param {number} segmentLength how long to make each segment
  12. * @param {Object} [options={}] Optional parameters
  13. * @param {string} [options.units='kilometers'] units can be degrees, radians, miles, or kilometers
  14. * @param {boolean} [options.reverse=false] reverses coordinates to start the first chunked segment at the end
  15. * @returns {FeatureCollection<LineString>} collection of line segments
  16. * @example
  17. * var line = turf.lineString([[-95, 40], [-93, 45], [-85, 50]]);
  18. *
  19. * var chunk = turf.lineChunk(line, 15, {units: 'miles'});
  20. *
  21. * //addToMap
  22. * var addToMap = [chunk];
  23. */
  24. function lineChunk(geojson, segmentLength, options) {
  25. // Optional parameters
  26. options = options || {};
  27. if (!isObject(options)) throw new Error("options is invalid");
  28. var units = options.units;
  29. var reverse = options.reverse;
  30. // Validation
  31. if (!geojson) throw new Error("geojson is required");
  32. if (segmentLength <= 0)
  33. throw new Error("segmentLength must be greater than 0");
  34. // Container
  35. var results = [];
  36. // Flatten each feature to simple LineString
  37. flattenEach(geojson, function (feature) {
  38. // reverses coordinates to start the first chunked segment at the end
  39. if (reverse)
  40. feature.geometry.coordinates = feature.geometry.coordinates.reverse();
  41. sliceLineSegments(feature, segmentLength, units, function (segment) {
  42. results.push(segment);
  43. });
  44. });
  45. return featureCollection(results);
  46. }
  47. /**
  48. * Slice Line Segments
  49. *
  50. * @private
  51. * @param {Feature<LineString>} line GeoJSON LineString
  52. * @param {number} segmentLength how long to make each segment
  53. * @param {string}[units='kilometers'] units can be degrees, radians, miles, or kilometers
  54. * @param {Function} callback iterate over sliced line segments
  55. * @returns {void}
  56. */
  57. function sliceLineSegments(line, segmentLength, units, callback) {
  58. var lineLength = length(line, { units: units });
  59. // If the line is shorter than the segment length then the orginal line is returned.
  60. if (lineLength <= segmentLength) return callback(line);
  61. var numberOfSegments = lineLength / segmentLength;
  62. // If numberOfSegments is integer, no need to plus 1
  63. if (!Number.isInteger(numberOfSegments)) {
  64. numberOfSegments = Math.floor(numberOfSegments) + 1;
  65. }
  66. for (var i = 0; i < numberOfSegments; i++) {
  67. var outline = lineSliceAlong(
  68. line,
  69. segmentLength * i,
  70. segmentLength * (i + 1),
  71. { units: units }
  72. );
  73. callback(outline, i);
  74. }
  75. }
  76. export default lineChunk;