index.js 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157
  1. /**
  2. * Returns a cloned copy of the passed GeoJSON Object, including possible 'Foreign Members'.
  3. * ~3-5x faster than the common JSON.parse + JSON.stringify combo method.
  4. *
  5. * @name clone
  6. * @param {GeoJSON} geojson GeoJSON Object
  7. * @returns {GeoJSON} cloned GeoJSON Object
  8. * @example
  9. * var line = turf.lineString([[-74, 40], [-78, 42], [-82, 35]], {color: 'red'});
  10. *
  11. * var lineCloned = turf.clone(line);
  12. */
  13. function clone(geojson) {
  14. if (!geojson) {
  15. throw new Error("geojson is required");
  16. }
  17. switch (geojson.type) {
  18. case "Feature":
  19. return cloneFeature(geojson);
  20. case "FeatureCollection":
  21. return cloneFeatureCollection(geojson);
  22. case "Point":
  23. case "LineString":
  24. case "Polygon":
  25. case "MultiPoint":
  26. case "MultiLineString":
  27. case "MultiPolygon":
  28. case "GeometryCollection":
  29. return cloneGeometry(geojson);
  30. default:
  31. throw new Error("unknown GeoJSON type");
  32. }
  33. }
  34. /**
  35. * Clone Feature
  36. *
  37. * @private
  38. * @param {Feature<any>} geojson GeoJSON Feature
  39. * @returns {Feature<any>} cloned Feature
  40. */
  41. function cloneFeature(geojson) {
  42. var cloned = { type: "Feature" };
  43. // Preserve Foreign Members
  44. Object.keys(geojson).forEach(function (key) {
  45. switch (key) {
  46. case "type":
  47. case "properties":
  48. case "geometry":
  49. return;
  50. default:
  51. cloned[key] = geojson[key];
  52. }
  53. });
  54. // Add properties & geometry last
  55. cloned.properties = cloneProperties(geojson.properties);
  56. cloned.geometry = cloneGeometry(geojson.geometry);
  57. return cloned;
  58. }
  59. /**
  60. * Clone Properties
  61. *
  62. * @private
  63. * @param {Object} properties GeoJSON Properties
  64. * @returns {Object} cloned Properties
  65. */
  66. function cloneProperties(properties) {
  67. var cloned = {};
  68. if (!properties) {
  69. return cloned;
  70. }
  71. Object.keys(properties).forEach(function (key) {
  72. var value = properties[key];
  73. if (typeof value === "object") {
  74. if (value === null) {
  75. // handle null
  76. cloned[key] = null;
  77. }
  78. else if (Array.isArray(value)) {
  79. // handle Array
  80. cloned[key] = value.map(function (item) {
  81. return item;
  82. });
  83. }
  84. else {
  85. // handle generic Object
  86. cloned[key] = cloneProperties(value);
  87. }
  88. }
  89. else {
  90. cloned[key] = value;
  91. }
  92. });
  93. return cloned;
  94. }
  95. /**
  96. * Clone Feature Collection
  97. *
  98. * @private
  99. * @param {FeatureCollection<any>} geojson GeoJSON Feature Collection
  100. * @returns {FeatureCollection<any>} cloned Feature Collection
  101. */
  102. function cloneFeatureCollection(geojson) {
  103. var cloned = { type: "FeatureCollection" };
  104. // Preserve Foreign Members
  105. Object.keys(geojson).forEach(function (key) {
  106. switch (key) {
  107. case "type":
  108. case "features":
  109. return;
  110. default:
  111. cloned[key] = geojson[key];
  112. }
  113. });
  114. // Add features
  115. cloned.features = geojson.features.map(function (feature) {
  116. return cloneFeature(feature);
  117. });
  118. return cloned;
  119. }
  120. /**
  121. * Clone Geometry
  122. *
  123. * @private
  124. * @param {Geometry<any>} geometry GeoJSON Geometry
  125. * @returns {Geometry<any>} cloned Geometry
  126. */
  127. function cloneGeometry(geometry) {
  128. var geom = { type: geometry.type };
  129. if (geometry.bbox) {
  130. geom.bbox = geometry.bbox;
  131. }
  132. if (geometry.type === "GeometryCollection") {
  133. geom.geometries = geometry.geometries.map(function (g) {
  134. return cloneGeometry(g);
  135. });
  136. return geom;
  137. }
  138. geom.coordinates = deepSlice(geometry.coordinates);
  139. return geom;
  140. }
  141. /**
  142. * Deep Slice coordinates
  143. *
  144. * @private
  145. * @param {Coordinates} coords Coordinates
  146. * @returns {Coordinates} all coordinates sliced
  147. */
  148. function deepSlice(coords) {
  149. var cloned = coords;
  150. if (typeof cloned[0] !== "object") {
  151. return cloned.slice();
  152. }
  153. return cloned.map(function (coord) {
  154. return deepSlice(coord);
  155. });
  156. }
  157. export default clone;