1 | var area = require('turf-area')
|
2 | var clip = require('geojson-clip-polygon')
|
3 | var xtend = require('xtend')
|
4 | var uniq = require('uniq')
|
5 | var through = require('through2')
|
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 | module.exports = function (groups, data, aggregations) {
|
35 | if (!data) {
|
36 | aggregations = groups
|
37 | return aggregateStream(aggregations)
|
38 | }
|
39 |
|
40 | if (!aggregations) {
|
41 | aggregations = data
|
42 | data = groups
|
43 | return aggregateAll(data, aggregations)
|
44 | }
|
45 |
|
46 | groups = Array.isArray(groups) ? groups : groups.features
|
47 | data = Array.isArray(data) ? data : data.features
|
48 |
|
49 | return {
|
50 | type: 'FeatureCollection',
|
51 | features: groups.map(aggregate)
|
52 | }
|
53 |
|
54 | function aggregate (group) {
|
55 | var properties = xtend({}, group.properties)
|
56 | data
|
57 | .map(function (f) { return clip(group, f, { threshold: 0 }) })
|
58 | .filter(function (clipped) { return !!clipped })
|
59 | .forEach(function (clipped) {
|
60 | for (var prop in aggregations) {
|
61 | properties[prop] = aggregations[prop](properties[prop], clipped)
|
62 | }
|
63 | })
|
64 |
|
65 | for (var prop in aggregations) {
|
66 | if (typeof aggregations[prop].finish === 'function') {
|
67 | properties[prop] = aggregations[prop].finish(properties[prop], group)
|
68 | }
|
69 | }
|
70 |
|
71 | return {
|
72 | type: group.type,
|
73 | properties: properties,
|
74 | geometry: group.geometry
|
75 | }
|
76 | }
|
77 | }
|
78 |
|
79 | function aggregateAll (features, aggregations) {
|
80 | if (!Array.isArray(features)) { features = features.features }
|
81 | var properties = {}
|
82 | for (var prop in aggregations) {
|
83 | for (var i = features.length - 1; i >= 0; i--) {
|
84 | properties[prop] = aggregations[prop](properties[prop], features[i])
|
85 | }
|
86 |
|
87 | if (typeof aggregations[prop].finish === 'function') {
|
88 | properties[prop] = aggregations[prop].finish(properties[prop])
|
89 | }
|
90 | }
|
91 | return properties
|
92 | }
|
93 |
|
94 | function aggregateStream (aggregations) {
|
95 | var properties = {}
|
96 | return through.obj(function write (feature, enc, next) {
|
97 | for (var prop in aggregations) {
|
98 | properties[prop] = aggregations[prop](properties[prop], feature)
|
99 | }
|
100 | next()
|
101 | }, function end () {
|
102 | for (var prop in aggregations) {
|
103 | if (typeof aggregations[prop].finish === 'function') {
|
104 | properties[prop] = aggregations[prop].finish(properties[prop])
|
105 | }
|
106 | }
|
107 |
|
108 | this.push(properties)
|
109 | this.push(null)
|
110 | })
|
111 | }
|
112 |
|
113 | module.exports.count = function () {
|
114 | return function (c) { return (c || 0) + 1 }
|
115 | }
|
116 |
|
117 |
|
118 |
|
119 |
|
120 |
|
121 |
|
122 |
|
123 | module.exports.union = function (property) {
|
124 | function collect (memo, feature) {
|
125 | memo = (memo || [])
|
126 | if (!(property in feature.properties)) { return memo }
|
127 |
|
128 |
|
129 | var value = JSON.parse(feature.properties[property])
|
130 |
|
131 | if (Array.isArray(value)) {
|
132 | memo.push.apply(memo, value)
|
133 | } else {
|
134 | memo.push(value)
|
135 | }
|
136 | return memo
|
137 | }
|
138 |
|
139 | collect.finish = function (memo) {
|
140 | return memo ? JSON.stringify(uniq(memo, false, false)) : '[]'
|
141 | }
|
142 |
|
143 | return collect
|
144 | }
|
145 |
|
146 | module.exports.totalArea = function () {
|
147 | return function (a, feature) {
|
148 | return (a || 0) + area(feature)
|
149 | }
|
150 | }
|
151 |
|
152 | module.exports.sum = function (property) {
|
153 | return function (s, feature) {
|
154 | return (s || 0) + (feature.properties[property] || 0)
|
155 | }
|
156 | }
|
157 |
|
158 | module.exports.areaWeightedSum = function (property) {
|
159 | return function (s, feature) {
|
160 | return (s || 0) + area(feature) * (feature.properties[property] || 0)
|
161 | }
|
162 | }
|
163 |
|
164 | module.exports.areaWeightedMean = function (property) {
|
165 | var ws = module.exports.areaWeightedSum(property)
|
166 | var ta = module.exports.totalArea()
|
167 |
|
168 | function weightedMean (memo, feature) {
|
169 | memo = memo || {}
|
170 | memo.sum = ws(memo.sum, feature)
|
171 | memo.area = ta(memo.area, feature)
|
172 | return memo
|
173 | }
|
174 |
|
175 | weightedMean.finish = function (memo) {
|
176 | return memo ? memo.sum / memo.area : 0
|
177 | }
|
178 |
|
179 | return weightedMean
|
180 | }
|