GeoJSON.js 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716
  1. /* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for
  2. * full list of contributors). Published under the 2-clause BSD license.
  3. * See license.txt in the OpenLayers distribution or repository for the
  4. * full text of the license. */
  5. /**
  6. * @requires OpenLayers/Format/JSON.js
  7. * @requires OpenLayers/Feature/Vector.js
  8. * @requires OpenLayers/Geometry/Point.js
  9. * @requires OpenLayers/Geometry/MultiPoint.js
  10. * @requires OpenLayers/Geometry/LineString.js
  11. * @requires OpenLayers/Geometry/MultiLineString.js
  12. * @requires OpenLayers/Geometry/Polygon.js
  13. * @requires OpenLayers/Geometry/MultiPolygon.js
  14. * @requires OpenLayers/Console.js
  15. */
  16. /**
  17. * Class: OpenLayers.Format.GeoJSON
  18. * Read and write GeoJSON. Create a new parser with the
  19. * <OpenLayers.Format.GeoJSON> constructor.
  20. *
  21. * Inherits from:
  22. * - <OpenLayers.Format.JSON>
  23. */
  24. OpenLayers.Format.GeoJSON = OpenLayers.Class(OpenLayers.Format.JSON, {
  25. /**
  26. * APIProperty: ignoreExtraDims
  27. * {Boolean} Ignore dimensions higher than 2 when reading geometry
  28. * coordinates.
  29. */
  30. ignoreExtraDims: false,
  31. /**
  32. * Constructor: OpenLayers.Format.GeoJSON
  33. * Create a new parser for GeoJSON.
  34. *
  35. * Parameters:
  36. * options - {Object} An optional object whose properties will be set on
  37. * this instance.
  38. */
  39. /**
  40. * APIMethod: read
  41. * Deserialize a GeoJSON string.
  42. *
  43. * Parameters:
  44. * json - {String} A GeoJSON string
  45. * type - {String} Optional string that determines the structure of
  46. * the output. Supported values are "Geometry", "Feature", and
  47. * "FeatureCollection". If absent or null, a default of
  48. * "FeatureCollection" is assumed.
  49. * filter - {Function} A function which will be called for every key and
  50. * value at every level of the final result. Each value will be
  51. * replaced by the result of the filter function. This can be used to
  52. * reform generic objects into instances of classes, or to transform
  53. * date strings into Date objects.
  54. *
  55. * Returns:
  56. * {Object} The return depends on the value of the type argument. If type
  57. * is "FeatureCollection" (the default), the return will be an array
  58. * of <OpenLayers.Feature.Vector>. If type is "Geometry", the input json
  59. * must represent a single geometry, and the return will be an
  60. * <OpenLayers.Geometry>. If type is "Feature", the input json must
  61. * represent a single feature, and the return will be an
  62. * <OpenLayers.Feature.Vector>.
  63. */
  64. read: function(json, type, filter) {
  65. type = (type) ? type : "FeatureCollection";
  66. var results = null;
  67. var obj = null;
  68. if (typeof json == "string") {
  69. obj = OpenLayers.Format.JSON.prototype.read.apply(this,
  70. [json, filter]);
  71. } else {
  72. obj = json;
  73. }
  74. if(!obj) {
  75. OpenLayers.Console.error("Bad JSON: " + json);
  76. } else if(typeof(obj.type) != "string") {
  77. OpenLayers.Console.error("Bad GeoJSON - no type: " + json);
  78. } else if(this.isValidType(obj, type)) {
  79. switch(type) {
  80. case "Geometry":
  81. try {
  82. results = this.parseGeometry(obj);
  83. } catch(err) {
  84. OpenLayers.Console.error(err);
  85. }
  86. break;
  87. case "Feature":
  88. try {
  89. results = this.parseFeature(obj);
  90. results.type = "Feature";
  91. } catch(err) {
  92. OpenLayers.Console.error(err);
  93. }
  94. break;
  95. case "FeatureCollection":
  96. // for type FeatureCollection, we allow input to be any type
  97. results = [];
  98. switch(obj.type) {
  99. case "Feature":
  100. try {
  101. results.push(this.parseFeature(obj));
  102. } catch(err) {
  103. results = null;
  104. OpenLayers.Console.error(err);
  105. }
  106. break;
  107. case "FeatureCollection":
  108. for(var i=0, len=obj.features.length; i<len; ++i) {
  109. try {
  110. results.push(this.parseFeature(obj.features[i]));
  111. } catch(err) {
  112. results = null;
  113. OpenLayers.Console.error(err);
  114. }
  115. }
  116. break;
  117. default:
  118. try {
  119. var geom = this.parseGeometry(obj);
  120. results.push(new OpenLayers.Feature.Vector(geom));
  121. } catch(err) {
  122. results = null;
  123. OpenLayers.Console.error(err);
  124. }
  125. }
  126. break;
  127. }
  128. }
  129. return results;
  130. },
  131. /**
  132. * Method: isValidType
  133. * Check if a GeoJSON object is a valid representative of the given type.
  134. *
  135. * Returns:
  136. * {Boolean} The object is valid GeoJSON object of the given type.
  137. */
  138. isValidType: function(obj, type) {
  139. var valid = false;
  140. switch(type) {
  141. case "Geometry":
  142. if(OpenLayers.Util.indexOf(
  143. ["Point", "MultiPoint", "LineString", "MultiLineString",
  144. "Polygon", "MultiPolygon", "Box", "GeometryCollection"],
  145. obj.type) == -1) {
  146. // unsupported geometry type
  147. OpenLayers.Console.error("Unsupported geometry type: " +
  148. obj.type);
  149. } else {
  150. valid = true;
  151. }
  152. break;
  153. case "FeatureCollection":
  154. // allow for any type to be converted to a feature collection
  155. valid = true;
  156. break;
  157. default:
  158. // for Feature types must match
  159. if(obj.type == type) {
  160. valid = true;
  161. } else {
  162. OpenLayers.Console.error("Cannot convert types from " +
  163. obj.type + " to " + type);
  164. }
  165. }
  166. return valid;
  167. },
  168. /**
  169. * Method: parseFeature
  170. * Convert a feature object from GeoJSON into an
  171. * <OpenLayers.Feature.Vector>.
  172. *
  173. * Parameters:
  174. * obj - {Object} An object created from a GeoJSON object
  175. *
  176. * Returns:
  177. * {<OpenLayers.Feature.Vector>} A feature.
  178. */
  179. parseFeature: function(obj) {
  180. var feature, geometry, attributes, bbox;
  181. attributes = (obj.properties) ? obj.properties : {};
  182. bbox = (obj.geometry && obj.geometry.bbox) || obj.bbox;
  183. try {
  184. geometry = this.parseGeometry(obj.geometry);
  185. } catch(err) {
  186. // deal with bad geometries
  187. throw err;
  188. }
  189. feature = new OpenLayers.Feature.Vector(geometry, attributes);
  190. if(bbox) {
  191. feature.bounds = OpenLayers.Bounds.fromArray(bbox);
  192. }
  193. if(obj.id) {
  194. feature.fid = obj.id;
  195. }
  196. return feature;
  197. },
  198. /**
  199. * Method: parseGeometry
  200. * Convert a geometry object from GeoJSON into an <OpenLayers.Geometry>.
  201. *
  202. * Parameters:
  203. * obj - {Object} An object created from a GeoJSON object
  204. *
  205. * Returns:
  206. * {<OpenLayers.Geometry>} A geometry.
  207. */
  208. parseGeometry: function(obj) {
  209. if (obj == null) {
  210. return null;
  211. }
  212. var geometry, collection = false;
  213. if(obj.type == "GeometryCollection") {
  214. if(!(OpenLayers.Util.isArray(obj.geometries))) {
  215. throw "GeometryCollection must have geometries array: " + obj;
  216. }
  217. var numGeom = obj.geometries.length;
  218. var components = new Array(numGeom);
  219. for(var i=0; i<numGeom; ++i) {
  220. components[i] = this.parseGeometry.apply(
  221. this, [obj.geometries[i]]
  222. );
  223. }
  224. geometry = new OpenLayers.Geometry.Collection(components);
  225. collection = true;
  226. } else {
  227. if(!(OpenLayers.Util.isArray(obj.coordinates))) {
  228. throw "Geometry must have coordinates array: " + obj;
  229. }
  230. if(!this.parseCoords[obj.type.toLowerCase()]) {
  231. throw "Unsupported geometry type: " + obj.type;
  232. }
  233. try {
  234. geometry = this.parseCoords[obj.type.toLowerCase()].apply(
  235. this, [obj.coordinates]
  236. );
  237. } catch(err) {
  238. // deal with bad coordinates
  239. throw err;
  240. }
  241. }
  242. // We don't reproject collections because the children are reprojected
  243. // for us when they are created.
  244. if (this.internalProjection && this.externalProjection && !collection) {
  245. geometry.transform(this.externalProjection,
  246. this.internalProjection);
  247. }
  248. return geometry;
  249. },
  250. /**
  251. * Property: parseCoords
  252. * Object with properties corresponding to the GeoJSON geometry types.
  253. * Property values are functions that do the actual parsing.
  254. */
  255. parseCoords: {
  256. /**
  257. * Method: parseCoords.point
  258. * Convert a coordinate array from GeoJSON into an
  259. * <OpenLayers.Geometry>.
  260. *
  261. * Parameters:
  262. * array - {Object} The coordinates array from the GeoJSON fragment.
  263. *
  264. * Returns:
  265. * {<OpenLayers.Geometry>} A geometry.
  266. */
  267. "point": function(array) {
  268. if (this.ignoreExtraDims == false &&
  269. array.length != 2) {
  270. throw "Only 2D points are supported: " + array;
  271. }
  272. return new OpenLayers.Geometry.Point(array[0], array[1]);
  273. },
  274. /**
  275. * Method: parseCoords.multipoint
  276. * Convert a coordinate array from GeoJSON into an
  277. * <OpenLayers.Geometry>.
  278. *
  279. * Parameters:
  280. * array - {Object} The coordinates array from the GeoJSON fragment.
  281. *
  282. * Returns:
  283. * {<OpenLayers.Geometry>} A geometry.
  284. */
  285. "multipoint": function(array) {
  286. var points = [];
  287. var p = null;
  288. for(var i=0, len=array.length; i<len; ++i) {
  289. try {
  290. p = this.parseCoords["point"].apply(this, [array[i]]);
  291. } catch(err) {
  292. throw err;
  293. }
  294. points.push(p);
  295. }
  296. return new OpenLayers.Geometry.MultiPoint(points);
  297. },
  298. /**
  299. * Method: parseCoords.linestring
  300. * Convert a coordinate array from GeoJSON into an
  301. * <OpenLayers.Geometry>.
  302. *
  303. * Parameters:
  304. * array - {Object} The coordinates array from the GeoJSON fragment.
  305. *
  306. * Returns:
  307. * {<OpenLayers.Geometry>} A geometry.
  308. */
  309. "linestring": function(array) {
  310. var points = [];
  311. var p = null;
  312. for(var i=0, len=array.length; i<len; ++i) {
  313. try {
  314. p = this.parseCoords["point"].apply(this, [array[i]]);
  315. } catch(err) {
  316. throw err;
  317. }
  318. points.push(p);
  319. }
  320. return new OpenLayers.Geometry.LineString(points);
  321. },
  322. /**
  323. * Method: parseCoords.multilinestring
  324. * Convert a coordinate array from GeoJSON into an
  325. * <OpenLayers.Geometry>.
  326. *
  327. * Parameters:
  328. * array - {Object} The coordinates array from the GeoJSON fragment.
  329. *
  330. * Returns:
  331. * {<OpenLayers.Geometry>} A geometry.
  332. */
  333. "multilinestring": function(array) {
  334. var lines = [];
  335. var l = null;
  336. for(var i=0, len=array.length; i<len; ++i) {
  337. try {
  338. l = this.parseCoords["linestring"].apply(this, [array[i]]);
  339. } catch(err) {
  340. throw err;
  341. }
  342. lines.push(l);
  343. }
  344. return new OpenLayers.Geometry.MultiLineString(lines);
  345. },
  346. /**
  347. * Method: parseCoords.polygon
  348. * Convert a coordinate array from GeoJSON into an
  349. * <OpenLayers.Geometry>.
  350. *
  351. * Returns:
  352. * {<OpenLayers.Geometry>} A geometry.
  353. */
  354. "polygon": function(array) {
  355. var rings = [];
  356. var r, l;
  357. for(var i=0, len=array.length; i<len; ++i) {
  358. try {
  359. l = this.parseCoords["linestring"].apply(this, [array[i]]);
  360. } catch(err) {
  361. throw err;
  362. }
  363. r = new OpenLayers.Geometry.LinearRing(l.components);
  364. rings.push(r);
  365. }
  366. return new OpenLayers.Geometry.Polygon(rings);
  367. },
  368. /**
  369. * Method: parseCoords.multipolygon
  370. * Convert a coordinate array from GeoJSON into an
  371. * <OpenLayers.Geometry>.
  372. *
  373. * Parameters:
  374. * array - {Object} The coordinates array from the GeoJSON fragment.
  375. *
  376. * Returns:
  377. * {<OpenLayers.Geometry>} A geometry.
  378. */
  379. "multipolygon": function(array) {
  380. var polys = [];
  381. var p = null;
  382. for(var i=0, len=array.length; i<len; ++i) {
  383. try {
  384. p = this.parseCoords["polygon"].apply(this, [array[i]]);
  385. } catch(err) {
  386. throw err;
  387. }
  388. polys.push(p);
  389. }
  390. return new OpenLayers.Geometry.MultiPolygon(polys);
  391. },
  392. /**
  393. * Method: parseCoords.box
  394. * Convert a coordinate array from GeoJSON into an
  395. * <OpenLayers.Geometry>.
  396. *
  397. * Parameters:
  398. * array - {Object} The coordinates array from the GeoJSON fragment.
  399. *
  400. * Returns:
  401. * {<OpenLayers.Geometry>} A geometry.
  402. */
  403. "box": function(array) {
  404. if(array.length != 2) {
  405. throw "GeoJSON box coordinates must have 2 elements";
  406. }
  407. return new OpenLayers.Geometry.Polygon([
  408. new OpenLayers.Geometry.LinearRing([
  409. new OpenLayers.Geometry.Point(array[0][0], array[0][1]),
  410. new OpenLayers.Geometry.Point(array[1][0], array[0][1]),
  411. new OpenLayers.Geometry.Point(array[1][0], array[1][1]),
  412. new OpenLayers.Geometry.Point(array[0][0], array[1][1]),
  413. new OpenLayers.Geometry.Point(array[0][0], array[0][1])
  414. ])
  415. ]);
  416. }
  417. },
  418. /**
  419. * APIMethod: write
  420. * Serialize a feature, geometry, array of features into a GeoJSON string.
  421. *
  422. * Parameters:
  423. * obj - {Object} An <OpenLayers.Feature.Vector>, <OpenLayers.Geometry>,
  424. * or an array of features.
  425. * pretty - {Boolean} Structure the output with newlines and indentation.
  426. * Default is false.
  427. *
  428. * Returns:
  429. * {String} The GeoJSON string representation of the input geometry,
  430. * features, or array of features.
  431. */
  432. write: function(obj, pretty) {
  433. var geojson = {
  434. "type": null
  435. };
  436. if(OpenLayers.Util.isArray(obj)) {
  437. geojson.type = "FeatureCollection";
  438. var numFeatures = obj.length;
  439. geojson.features = new Array(numFeatures);
  440. for(var i=0; i<numFeatures; ++i) {
  441. var element = obj[i];
  442. if(!element instanceof OpenLayers.Feature.Vector) {
  443. var msg = "FeatureCollection only supports collections " +
  444. "of features: " + element;
  445. throw msg;
  446. }
  447. geojson.features[i] = this.extract.feature.apply(
  448. this, [element]
  449. );
  450. }
  451. } else if (obj.CLASS_NAME.indexOf("OpenLayers.Geometry") == 0) {
  452. geojson = this.extract.geometry.apply(this, [obj]);
  453. } else if (obj instanceof OpenLayers.Feature.Vector) {
  454. geojson = this.extract.feature.apply(this, [obj]);
  455. if(obj.layer && obj.layer.projection) {
  456. geojson.crs = this.createCRSObject(obj);
  457. }
  458. }
  459. return OpenLayers.Format.JSON.prototype.write.apply(this,
  460. [geojson, pretty]);
  461. },
  462. /**
  463. * Method: createCRSObject
  464. * Create the CRS object for an object.
  465. *
  466. * Parameters:
  467. * object - {<OpenLayers.Feature.Vector>}
  468. *
  469. * Returns:
  470. * {Object} An object which can be assigned to the crs property
  471. * of a GeoJSON object.
  472. */
  473. createCRSObject: function(object) {
  474. var proj = object.layer.projection.toString();
  475. var crs = {};
  476. if (proj.match(/epsg:/i)) {
  477. var code = parseInt(proj.substring(proj.indexOf(":") + 1));
  478. if (code == 4326) {
  479. crs = {
  480. "type": "name",
  481. "properties": {
  482. "name": "urn:ogc:def:crs:OGC:1.3:CRS84"
  483. }
  484. };
  485. } else {
  486. crs = {
  487. "type": "name",
  488. "properties": {
  489. "name": "EPSG:" + code
  490. }
  491. };
  492. }
  493. }
  494. return crs;
  495. },
  496. /**
  497. * Property: extract
  498. * Object with properties corresponding to the GeoJSON types.
  499. * Property values are functions that do the actual value extraction.
  500. */
  501. extract: {
  502. /**
  503. * Method: extract.feature
  504. * Return a partial GeoJSON object representing a single feature.
  505. *
  506. * Parameters:
  507. * feature - {<OpenLayers.Feature.Vector>}
  508. *
  509. * Returns:
  510. * {Object} An object representing the point.
  511. */
  512. 'feature': function(feature) {
  513. var geom = this.extract.geometry.apply(this, [feature.geometry]);
  514. var json = {
  515. "type": "Feature",
  516. "properties": feature.attributes,
  517. "geometry": geom
  518. };
  519. if (feature.fid != null) {
  520. json.id = feature.fid;
  521. }
  522. return json;
  523. },
  524. /**
  525. * Method: extract.geometry
  526. * Return a GeoJSON object representing a single geometry.
  527. *
  528. * Parameters:
  529. * geometry - {<OpenLayers.Geometry>}
  530. *
  531. * Returns:
  532. * {Object} An object representing the geometry.
  533. */
  534. 'geometry': function(geometry) {
  535. if (geometry == null) {
  536. return null;
  537. }
  538. if (this.internalProjection && this.externalProjection) {
  539. geometry = geometry.clone();
  540. geometry.transform(this.internalProjection,
  541. this.externalProjection);
  542. }
  543. var geometryType = geometry.CLASS_NAME.split('.')[2];
  544. var data = this.extract[geometryType.toLowerCase()].apply(this, [geometry]);
  545. var json;
  546. if(geometryType == "Collection") {
  547. json = {
  548. "type": "GeometryCollection",
  549. "geometries": data
  550. };
  551. } else {
  552. json = {
  553. "type": geometryType,
  554. "coordinates": data
  555. };
  556. }
  557. return json;
  558. },
  559. /**
  560. * Method: extract.point
  561. * Return an array of coordinates from a point.
  562. *
  563. * Parameters:
  564. * point - {<OpenLayers.Geometry.Point>}
  565. *
  566. * Returns:
  567. * {Array} An array of coordinates representing the point.
  568. */
  569. 'point': function(point) {
  570. return [point.x, point.y];
  571. },
  572. /**
  573. * Method: extract.multipoint
  574. * Return an array of point coordinates from a multipoint.
  575. *
  576. * Parameters:
  577. * multipoint - {<OpenLayers.Geometry.MultiPoint>}
  578. *
  579. * Returns:
  580. * {Array} An array of point coordinate arrays representing
  581. * the multipoint.
  582. */
  583. 'multipoint': function(multipoint) {
  584. var array = [];
  585. for(var i=0, len=multipoint.components.length; i<len; ++i) {
  586. array.push(this.extract.point.apply(this, [multipoint.components[i]]));
  587. }
  588. return array;
  589. },
  590. /**
  591. * Method: extract.linestring
  592. * Return an array of coordinate arrays from a linestring.
  593. *
  594. * Parameters:
  595. * linestring - {<OpenLayers.Geometry.LineString>}
  596. *
  597. * Returns:
  598. * {Array} An array of coordinate arrays representing
  599. * the linestring.
  600. */
  601. 'linestring': function(linestring) {
  602. var array = [];
  603. for(var i=0, len=linestring.components.length; i<len; ++i) {
  604. array.push(this.extract.point.apply(this, [linestring.components[i]]));
  605. }
  606. return array;
  607. },
  608. /**
  609. * Method: extract.multilinestring
  610. * Return an array of linestring arrays from a linestring.
  611. *
  612. * Parameters:
  613. * multilinestring - {<OpenLayers.Geometry.MultiLineString>}
  614. *
  615. * Returns:
  616. * {Array} An array of linestring arrays representing
  617. * the multilinestring.
  618. */
  619. 'multilinestring': function(multilinestring) {
  620. var array = [];
  621. for(var i=0, len=multilinestring.components.length; i<len; ++i) {
  622. array.push(this.extract.linestring.apply(this, [multilinestring.components[i]]));
  623. }
  624. return array;
  625. },
  626. /**
  627. * Method: extract.polygon
  628. * Return an array of linear ring arrays from a polygon.
  629. *
  630. * Parameters:
  631. * polygon - {<OpenLayers.Geometry.Polygon>}
  632. *
  633. * Returns:
  634. * {Array} An array of linear ring arrays representing the polygon.
  635. */
  636. 'polygon': function(polygon) {
  637. var array = [];
  638. for(var i=0, len=polygon.components.length; i<len; ++i) {
  639. array.push(this.extract.linestring.apply(this, [polygon.components[i]]));
  640. }
  641. return array;
  642. },
  643. /**
  644. * Method: extract.multipolygon
  645. * Return an array of polygon arrays from a multipolygon.
  646. *
  647. * Parameters:
  648. * multipolygon - {<OpenLayers.Geometry.MultiPolygon>}
  649. *
  650. * Returns:
  651. * {Array} An array of polygon arrays representing
  652. * the multipolygon
  653. */
  654. 'multipolygon': function(multipolygon) {
  655. var array = [];
  656. for(var i=0, len=multipolygon.components.length; i<len; ++i) {
  657. array.push(this.extract.polygon.apply(this, [multipolygon.components[i]]));
  658. }
  659. return array;
  660. },
  661. /**
  662. * Method: extract.collection
  663. * Return an array of geometries from a geometry collection.
  664. *
  665. * Parameters:
  666. * collection - {<OpenLayers.Geometry.Collection>}
  667. *
  668. * Returns:
  669. * {Array} An array of geometry objects representing the geometry
  670. * collection.
  671. */
  672. 'collection': function(collection) {
  673. var len = collection.components.length;
  674. var array = new Array(len);
  675. for(var i=0; i<len; ++i) {
  676. array[i] = this.extract.geometry.apply(
  677. this, [collection.components[i]]
  678. );
  679. }
  680. return array;
  681. }
  682. },
  683. CLASS_NAME: "OpenLayers.Format.GeoJSON"
  684. });