source: Dev/branches/jos-branch/d3/src/geo/path.js @ 238

Last change on this file since 238 was 76, checked in by fpvanagthoven, 14 years ago

d3

File size: 7.6 KB
Line 
1/**
2 * Returns a function that, given a GeoJSON object (e.g., a feature), returns
3 * the corresponding SVG path. The function can be customized by overriding the
4 * projection. Point features are mapped to circles with a default radius of
5 * 4.5px; the radius can be specified either as a constant or a function that
6 * is evaluated per object.
7 */
8d3.geo.path = function() {
9  var pointRadius = 4.5,
10      pointCircle = d3_path_circle(pointRadius),
11      projection = d3.geo.albersUsa();
12
13  function path(d, i) {
14    if (typeof pointRadius === "function") {
15      pointCircle = d3_path_circle(pointRadius.apply(this, arguments));
16    }
17    return d3_geo_pathType(pathTypes, d);
18  }
19
20  function project(coordinates) {
21    return projection(coordinates).join(",");
22  }
23
24  var pathTypes = {
25
26    FeatureCollection: function(f) {
27      var path = [],
28          features = f.features,
29          i = -1, // features.index
30          n = features.length;
31      while (++i < n) path.push(d3_geo_pathType(pathTypes, features[i].geometry));
32      return path.join("");
33    },
34
35    Feature: function(f) {
36      return d3_geo_pathType(pathTypes, f.geometry);
37    },
38
39    Point: function(o) {
40      return "M" + project(o.coordinates) + pointCircle;
41    },
42
43    MultiPoint: function(o) {
44      var path = [],
45          coordinates = o.coordinates,
46          i = -1, // coordinates.index
47          n = coordinates.length;
48      while (++i < n) path.push("M", project(coordinates[i]), pointCircle);
49      return path.join("");
50    },
51
52    LineString: function(o) {
53      var path = ["M"],
54          coordinates = o.coordinates,
55          i = -1, // coordinates.index
56          n = coordinates.length;
57      while (++i < n) path.push(project(coordinates[i]), "L");
58      path.pop();
59      return path.join("");
60    },
61
62    MultiLineString: function(o) {
63      var path = [],
64          coordinates = o.coordinates,
65          i = -1, // coordinates.index
66          n = coordinates.length,
67          subcoordinates, // coordinates[i]
68          j, // subcoordinates.index
69          m; // subcoordinates.length
70      while (++i < n) {
71        subcoordinates = coordinates[i];
72        j = -1;
73        m = subcoordinates.length;
74        path.push("M");
75        while (++j < m) path.push(project(subcoordinates[j]), "L");
76        path.pop();
77      }
78      return path.join("");
79    },
80
81    Polygon: function(o) {
82      var path = [],
83          coordinates = o.coordinates,
84          i = -1, // coordinates.index
85          n = coordinates.length,
86          subcoordinates, // coordinates[i]
87          j, // subcoordinates.index
88          m; // subcoordinates.length
89      while (++i < n) {
90        subcoordinates = coordinates[i];
91        j = -1;
92        m = subcoordinates.length;
93        path.push("M");
94        while (++j < m) path.push(project(subcoordinates[j]), "L");
95        path[path.length - 1] = "Z";
96      }
97      return path.join("");
98    },
99
100    MultiPolygon: function(o) {
101      var path = [],
102          coordinates = o.coordinates,
103          i = -1, // coordinates index
104          n = coordinates.length,
105          subcoordinates, // coordinates[i]
106          j, // subcoordinates index
107          m, // subcoordinates.length
108          subsubcoordinates, // subcoordinates[j]
109          k, // subsubcoordinates index
110          p; // subsubcoordinates.length
111      while (++i < n) {
112        subcoordinates = coordinates[i];
113        j = -1;
114        m = subcoordinates.length;
115        while (++j < m) {
116          subsubcoordinates = subcoordinates[j];
117          k = -1;
118          p = subsubcoordinates.length - 1;
119          path.push("M");
120          while (++k < p) path.push(project(subsubcoordinates[k]), "L");
121          path[path.length - 1] = "Z";
122        }
123      }
124      return path.join("");
125    },
126
127    GeometryCollection: function(o) {
128      var path = [],
129          geometries = o.geometries,
130          i = -1, // geometries index
131          n = geometries.length;
132      while (++i < n) path.push(d3_geo_pathType(pathTypes, geometries[i]));
133      return path.join("");
134    }
135
136  };
137
138  var areaTypes = {
139
140    FeatureCollection: function(f) {
141      var area = 0,
142          features = f.features,
143          i = -1, // features.index
144          n = features.length;
145      while (++i < n) area += d3_geo_pathType(areaTypes, features[i]);
146      return area;
147    },
148
149    Feature: function(f) {
150      return d3_geo_pathType(areaTypes, f.geometry);
151    },
152
153    Point: d3_geo_pathZero,
154    MultiPoint: d3_geo_pathZero,
155    LineString: d3_geo_pathZero,
156    MultiLineString: d3_geo_pathZero,
157
158    Polygon: function(o) {
159      return polygonArea(o.coordinates);
160    },
161
162    MultiPolygon: function(o) {
163      var sum = 0,
164          coordinates = o.coordinates,
165          i = -1, // coordinates index
166          n = coordinates.length;
167      while (++i < n) sum += polygonArea(coordinates[i]);
168      return sum;
169    },
170
171    GeometryCollection: function(o) {
172      var sum = 0,
173          geometries = o.geometries,
174          i = -1, // geometries index
175          n = geometries.length;
176      while (++i < n) sum += d3_geo_pathType(areaTypes, geometries[i]);
177      return sum;
178    }
179
180  };
181
182  function polygonArea(coordinates) {
183    var sum = area(coordinates[0]), // exterior ring
184        i = 0, // coordinates.index
185        n = coordinates.length;
186    while (++i < n) sum -= area(coordinates[i]); // holes
187    return sum;
188  }
189
190  function polygonCentroid(coordinates) {
191    var polygon = d3.geom.polygon(coordinates[0].map(projection)), // exterior ring
192        centroid = polygon.centroid(1),
193        x = centroid[0],
194        y = centroid[1],
195        z = Math.abs(polygon.area()),
196        i = 0, // coordinates index
197        n = coordinates.length;
198    while (++i < n) {
199      polygon = d3.geom.polygon(coordinates[i].map(projection)); // holes
200      centroid = polygon.centroid(1);
201      x -= centroid[0];
202      y -= centroid[1];
203      z -= Math.abs(polygon.area());
204    }
205    return [x, y, 6 * z]; // weighted centroid
206  }
207
208  var centroidTypes = {
209
210    // TODO FeatureCollection
211    // TODO Point
212    // TODO MultiPoint
213    // TODO LineString
214    // TODO MultiLineString
215    // TODO GeometryCollection
216
217    Feature: function(f) {
218      return d3_geo_pathType(centroidTypes, f.geometry);
219    },
220
221    Polygon: function(o) {
222      var centroid = polygonCentroid(o.coordinates);
223      return [centroid[0] / centroid[2], centroid[1] / centroid[2]];
224    },
225
226    MultiPolygon: function(o) {
227      var area = 0,
228          coordinates = o.coordinates,
229          centroid,
230          x = 0,
231          y = 0,
232          z = 0,
233          i = -1, // coordinates index
234          n = coordinates.length;
235      while (++i < n) {
236        centroid = polygonCentroid(coordinates[i]);
237        x += centroid[0];
238        y += centroid[1];
239        z += centroid[2];
240      }
241      return [x / z, y / z];
242    }
243
244  };
245
246
247  function area(coordinates) {
248    return Math.abs(d3.geom.polygon(coordinates.map(projection)).area());
249  }
250
251  path.projection = function(x) {
252    projection = x;
253    return path;
254  };
255
256  path.area = function(d) {
257    return d3_geo_pathType(areaTypes, d);
258  };
259
260  path.centroid = function(d) {
261    return d3_geo_pathType(centroidTypes, d);
262  };
263
264  path.pointRadius = function(x) {
265    if (typeof x === "function") pointRadius = x;
266    else {
267      pointRadius = +x;
268      pointCircle = d3_path_circle(pointRadius);
269    }
270    return path;
271  };
272
273  return path;
274};
275
276function d3_path_circle(radius) {
277  return "m0," + radius
278      + "a" + radius + "," + radius + " 0 1,1 0," + (-2 * radius)
279      + "a" + radius + "," + radius + " 0 1,1 0," + (+2 * radius)
280      + "z";
281}
282
283function d3_geo_pathZero() {
284  return 0;
285}
286
287function d3_geo_pathType(types, o) {
288  return o && o.type in types ? types[o.type](o) : "";
289}
Note: See TracBrowser for help on using the repository browser.