index.js 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144
  1. import clone from '@turf/clone';
  2. import center from '@turf/center';
  3. import centroid from '@turf/centroid';
  4. import turfBBox from '@turf/bbox';
  5. import rhumbBearing from '@turf/rhumb-bearing';
  6. import rhumbDistance from '@turf/rhumb-distance';
  7. import rhumbDestination from '@turf/rhumb-destination';
  8. import { featureEach, coordEach } from '@turf/meta';
  9. import { isObject, point } from '@turf/helpers';
  10. import { getType, getCoords, getCoord } from '@turf/invariant';
  11. /**
  12. * Scale a GeoJSON from a given point by a factor of scaling (ex: factor=2 would make the GeoJSON 200% larger).
  13. * If a FeatureCollection is provided, the origin point will be calculated based on each individual Feature.
  14. *
  15. * @name transformScale
  16. * @param {GeoJSON} geojson GeoJSON to be scaled
  17. * @param {number} factor of scaling, positive or negative values greater than 0
  18. * @param {Object} [options={}] Optional parameters
  19. * @param {string|Coord} [options.origin='centroid'] Point from which the scaling will occur (string options: sw/se/nw/ne/center/centroid)
  20. * @param {boolean} [options.mutate=false] allows GeoJSON input to be mutated (significant performance increase if true)
  21. * @returns {GeoJSON} scaled GeoJSON
  22. * @example
  23. * var poly = turf.polygon([[[0,29],[3.5,29],[2.5,32],[0,29]]]);
  24. * var scaledPoly = turf.transformScale(poly, 3);
  25. *
  26. * //addToMap
  27. * var addToMap = [poly, scaledPoly];
  28. * scaledPoly.properties = {stroke: '#F00', 'stroke-width': 4};
  29. */
  30. function transformScale(geojson, factor, options) {
  31. // Optional parameters
  32. options = options || {};
  33. if (!isObject(options)) throw new Error("options is invalid");
  34. var origin = options.origin;
  35. var mutate = options.mutate;
  36. // Input validation
  37. if (!geojson) throw new Error("geojson required");
  38. if (typeof factor !== "number" || factor === 0)
  39. throw new Error("invalid factor");
  40. var originIsPoint = Array.isArray(origin) || typeof origin === "object";
  41. // Clone geojson to avoid side effects
  42. if (mutate !== true) geojson = clone(geojson);
  43. // Scale each Feature separately
  44. if (geojson.type === "FeatureCollection" && !originIsPoint) {
  45. featureEach(geojson, function (feature, index) {
  46. geojson.features[index] = scale(feature, factor, origin);
  47. });
  48. return geojson;
  49. }
  50. // Scale Feature/Geometry
  51. return scale(geojson, factor, origin);
  52. }
  53. /**
  54. * Scale Feature/Geometry
  55. *
  56. * @private
  57. * @param {Feature|Geometry} feature GeoJSON Feature/Geometry
  58. * @param {number} factor of scaling, positive or negative values greater than 0
  59. * @param {string|Coord} [origin="centroid"] Point from which the scaling will occur (string options: sw/se/nw/ne/center/centroid)
  60. * @returns {Feature|Geometry} scaled GeoJSON Feature/Geometry
  61. */
  62. function scale(feature, factor, origin) {
  63. // Default params
  64. var isPoint = getType(feature) === "Point";
  65. origin = defineOrigin(feature, origin);
  66. // Shortcut no-scaling
  67. if (factor === 1 || isPoint) return feature;
  68. // Scale each coordinate
  69. coordEach(feature, function (coord) {
  70. var originalDistance = rhumbDistance(origin, coord);
  71. var bearing = rhumbBearing(origin, coord);
  72. var newDistance = originalDistance * factor;
  73. var newCoord = getCoords(rhumbDestination(origin, newDistance, bearing));
  74. coord[0] = newCoord[0];
  75. coord[1] = newCoord[1];
  76. if (coord.length === 3) coord[2] *= factor;
  77. });
  78. return feature;
  79. }
  80. /**
  81. * Define Origin
  82. *
  83. * @private
  84. * @param {GeoJSON} geojson GeoJSON
  85. * @param {string|Coord} origin sw/se/nw/ne/center/centroid
  86. * @returns {Feature<Point>} Point origin
  87. */
  88. function defineOrigin(geojson, origin) {
  89. // Default params
  90. if (origin === undefined || origin === null) origin = "centroid";
  91. // Input Coord
  92. if (Array.isArray(origin) || typeof origin === "object")
  93. return getCoord(origin);
  94. // Define BBox
  95. var bbox = geojson.bbox ? geojson.bbox : turfBBox(geojson);
  96. var west = bbox[0];
  97. var south = bbox[1];
  98. var east = bbox[2];
  99. var north = bbox[3];
  100. switch (origin) {
  101. case "sw":
  102. case "southwest":
  103. case "westsouth":
  104. case "bottomleft":
  105. return point([west, south]);
  106. case "se":
  107. case "southeast":
  108. case "eastsouth":
  109. case "bottomright":
  110. return point([east, south]);
  111. case "nw":
  112. case "northwest":
  113. case "westnorth":
  114. case "topleft":
  115. return point([west, north]);
  116. case "ne":
  117. case "northeast":
  118. case "eastnorth":
  119. case "topright":
  120. return point([east, north]);
  121. case "center":
  122. return center(geojson);
  123. case undefined:
  124. case null:
  125. case "centroid":
  126. return centroid(geojson);
  127. default:
  128. throw new Error("invalid origin");
  129. }
  130. }
  131. export default transformScale;