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