#915 Adding support for GeoJSON vector format. Many thanks to Chris for the exhaustive tests on this one.
git-svn-id: http://svn.openlayers.org/trunk/openlayers@3994 dc9f47b5-9b13-0410-9fdd-eb0c1a62fdaf
This commit is contained in:
168
examples/geojson.html
Normal file
168
examples/geojson.html
Normal file
@@ -0,0 +1,168 @@
|
||||
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||
<head>
|
||||
<title>Vector Formats</title>
|
||||
<style type="text/css">
|
||||
html, body {
|
||||
margin: 0;
|
||||
padding: 1em;
|
||||
font: 0.9em Verdana, Arial, sans serif;
|
||||
}
|
||||
input, select, textarea {
|
||||
font: 0.9em Verdana, Arial, sans-serif;
|
||||
}
|
||||
h2 {
|
||||
margin-top: 0.75em;
|
||||
font-size: 1.6em;
|
||||
}
|
||||
#leftcol {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 1em;
|
||||
padding: 0;
|
||||
width: 455px;
|
||||
}
|
||||
#map {
|
||||
width: 450px;
|
||||
height: 225px;
|
||||
border: 1px solid #ccc;
|
||||
}
|
||||
#input {
|
||||
width: 450px;
|
||||
}
|
||||
#text {
|
||||
font-size: 0.85em;
|
||||
margin: 1em 0 1em 0;
|
||||
width: 100%;
|
||||
height: 10em;
|
||||
}
|
||||
#info {
|
||||
position: relative;
|
||||
padding: 2em 0;
|
||||
margin-left: 470px;
|
||||
}
|
||||
#output {
|
||||
font-size: 0.8em;
|
||||
width: 100%;
|
||||
height: 500px;
|
||||
border: 0;
|
||||
}
|
||||
p {
|
||||
margin: 0;
|
||||
padding: 0.75em 0 0.75em 0;
|
||||
}
|
||||
</style>
|
||||
<script src="../lib/Firebug/firebug.js"></script>
|
||||
<script src="../lib/OpenLayers.js"></script>
|
||||
<script type="text/javascript">
|
||||
<!--
|
||||
var map, vectors, drawControls, formats, select;
|
||||
function init(){
|
||||
map = new OpenLayers.Map('map');
|
||||
var wms = new OpenLayers.Layer.WMS( "OpenLayers WMS",
|
||||
"http://labs.metacarta.com/wms/vmap0?", {layers: 'basic'});
|
||||
|
||||
vectors = new OpenLayers.Layer.Vector("Vector Layer");
|
||||
|
||||
map.addLayers([wms, vectors]);
|
||||
map.addControl(new OpenLayers.Control.MousePosition());
|
||||
map.addControl(new OpenLayers.Control.EditingToolbar(vectors));
|
||||
|
||||
var options = {
|
||||
hover: true,
|
||||
onSelect: serialize
|
||||
};
|
||||
select = new OpenLayers.Control.SelectFeature(vectors, options);
|
||||
map.addControl(select);
|
||||
select.activate();
|
||||
|
||||
formats = {
|
||||
wkt: new OpenLayers.Format.WKT(),
|
||||
geojson: new OpenLayers.Format.GeoJSON()
|
||||
};
|
||||
|
||||
map.setCenter(new OpenLayers.LonLat(0, 0), 1);
|
||||
}
|
||||
|
||||
function serialize(feature) {
|
||||
var type = document.getElementById("formatType").value;
|
||||
// second argument for pretty printing (geojson only)
|
||||
var pretty = document.getElementById("prettyPrint").checked;
|
||||
var str = formats[type].write(feature, pretty);
|
||||
// not a good idea in general, just for this demo
|
||||
str = str.replace(/,/g, ', ');
|
||||
document.getElementById('output').value = str;
|
||||
}
|
||||
|
||||
function deserialize() {
|
||||
var element = document.getElementById('text');
|
||||
var type = document.getElementById("formatType").value;
|
||||
var features = formats[type].read(element.value);
|
||||
var bounds;
|
||||
if(features) {
|
||||
if(features.constructor != Array) {
|
||||
features = [features];
|
||||
}
|
||||
for(var i=0; i<features.length; ++i) {
|
||||
if (!bounds) {
|
||||
bounds = features[i].geometry.getBounds();
|
||||
} else {
|
||||
bounds.extend(features[i].geometry.getBounds());
|
||||
}
|
||||
|
||||
}
|
||||
vectors.addFeatures(features);
|
||||
map.zoomToExtent(bounds);
|
||||
var plural = (features.length > 1) ? 's' : '';
|
||||
element.value = features.length + ' feature' + plural + ' added'
|
||||
} else {
|
||||
element.value = 'Bad input ' + type;
|
||||
}
|
||||
}
|
||||
|
||||
// preload images
|
||||
(function() {
|
||||
var roots = ["draw_point", "draw_line", "draw_polygon", "pan"];
|
||||
var onImages = [];
|
||||
var offImages = [];
|
||||
for(var i=0; i<roots.length; ++i) {
|
||||
onImages[i] = new Image();
|
||||
onImages[i].src = "../theme/default/img/" + roots[i] + "_on.png";
|
||||
offImages[i] = new Image();
|
||||
offImages[i].src = "../theme/default/img/" + roots[i] + "_on.png";
|
||||
}
|
||||
})();
|
||||
|
||||
// -->
|
||||
</script>
|
||||
</head>
|
||||
<body onload="init()">
|
||||
<div id="leftcol">
|
||||
<h2>OpenLayers Vector Formats Example</h2>
|
||||
<div id="map"></div>
|
||||
<div id="input">
|
||||
<p>Use the drop-down below to select the input/output format
|
||||
for vector features. New features can be added by using the drawing
|
||||
tools above or by pasting their text representation below.</p>
|
||||
<label for="formatType">Format</label>
|
||||
<select name="formatType" id="formatType">
|
||||
<option value="geojson" selected="selected">GeoJSON</option>
|
||||
<option value="wkt">Well-Known Text (WKT)</option>
|
||||
</select>
|
||||
|
||||
<label for="prettyPrint">Pretty print</label>
|
||||
<input id="prettyPrint" type="checkbox"
|
||||
name="prettyPrint" value="1" />
|
||||
<br />
|
||||
<textarea id="text">paste text here...</textarea>
|
||||
<br />
|
||||
<input type="button" value="add feature" onclick="deserialize();" />
|
||||
</div>
|
||||
</div>
|
||||
<div id="info">
|
||||
<p>Use the tools to the left to draw new polygons, lines, and points.
|
||||
After drawing some new features, hover over a feature to see the
|
||||
serialized version below.</p>
|
||||
<textarea id="output"></textarea>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
@@ -166,6 +166,8 @@
|
||||
"OpenLayers/Format/GeoRSS.js",
|
||||
"OpenLayers/Format/WFS.js",
|
||||
"OpenLayers/Format/WKT.js",
|
||||
"OpenLayers/Format/JSON.js",
|
||||
"OpenLayers/Format/GeoJSON.js",
|
||||
"OpenLayers/Layer/WFS.js",
|
||||
"OpenLayers/Control/MouseToolbar.js",
|
||||
"OpenLayers/Control/NavToolbar.js",
|
||||
|
||||
644
lib/OpenLayers/Format/GeoJSON.js
Normal file
644
lib/OpenLayers/Format/GeoJSON.js
Normal file
@@ -0,0 +1,644 @@
|
||||
/* Copyright (c) 2006 MetaCarta, Inc., published under a modified BSD license.
|
||||
* See http://svn.openlayers.org/trunk/openlayers/repository-license.txt
|
||||
* for the full text of the license. */
|
||||
|
||||
/**
|
||||
* @requires OpenLayers/Format/JSON.js
|
||||
*
|
||||
* Class: OpenLayers.Format.GeoJSON
|
||||
* Read and write GeoJSON. Create a new parser with the
|
||||
* <OpenLayers.Format.GeoJSON> constructor.
|
||||
*
|
||||
* Inherits from:
|
||||
* - <OpenLayers.Format.JSON>
|
||||
*/
|
||||
OpenLayers.Format.GeoJSON = OpenLayers.Class(OpenLayers.Format.JSON, {
|
||||
|
||||
/**
|
||||
* Constructor: OpenLayers.Format.GeoJSON
|
||||
* Create a new parser for GeoJSON.
|
||||
*
|
||||
* Parameters:
|
||||
* options - {Object} An optional object whose properties will be set on
|
||||
* this instance.
|
||||
*/
|
||||
initialize: function(options) {
|
||||
OpenLayers.Format.JSON.prototype.initialize.apply(this, [options]);
|
||||
},
|
||||
|
||||
/**
|
||||
* APIMethod: read
|
||||
* Deserialize a GeoJSON string.
|
||||
*
|
||||
* Parameters:
|
||||
* json - {String} A GeoJSON string
|
||||
* type - {String} Optional string that determines the structure of
|
||||
* the output. Supported values are "Geometry", "Feature",
|
||||
* "GeometryCollection", and "FeatureCollection". If absent or null,
|
||||
* a default of "FeatureCollection" is assumed.
|
||||
* filter - {Function} A function which will be called for every key and
|
||||
* value at every level of the final result. Each value will be
|
||||
* replaced by the result of the filter function. This can be used to
|
||||
* reform generic objects into instances of classes, or to transform
|
||||
* date strings into Date objects.
|
||||
*
|
||||
* Returns:
|
||||
* {Object} The return depends on the value of the type argument. If type
|
||||
* is "FeatureCollection" (the default), the return will be an array
|
||||
* of <OpenLayers.Feature.Vector>. If type is "Geometry", the input json
|
||||
* must represent a single geometry, and the return will be an
|
||||
* <OpenLayers.Geometry>. If type is "Feature", the input json must
|
||||
* represent a single feature, and the return will be an
|
||||
* <OpenLayers.Feature.Vector>. If type is "GeometryCollection", the
|
||||
* input json must represent a geometry collection, and the return will
|
||||
* be an array of <OpenLayers.Geometry>.
|
||||
*/
|
||||
read: function(json, type, filter) {
|
||||
type = (type) ? type : "FeatureCollection";
|
||||
var results = null;
|
||||
var obj = null;
|
||||
if (typeof json == "string") {
|
||||
obj = OpenLayers.Format.JSON.prototype.read.apply(this,
|
||||
[json, filter]);
|
||||
} else {
|
||||
obj = json;
|
||||
}
|
||||
if(!obj) {
|
||||
OpenLayers.Console.error("Bad JSON: " + json);
|
||||
} else if(typeof(obj.type) != "string") {
|
||||
OpenLayers.Console.error("Bad GeoJSON - no type: " + json);
|
||||
} else if(this.isValidType(obj, type)) {
|
||||
switch(type) {
|
||||
case "Geometry":
|
||||
try {
|
||||
results = this.parseGeometry(obj);
|
||||
} catch(err) {
|
||||
OpenLayers.Console.error(err);
|
||||
}
|
||||
break;
|
||||
case "Feature":
|
||||
try {
|
||||
results = this.parseFeature(obj);
|
||||
results.type = "Feature";
|
||||
} catch(err) {
|
||||
OpenLayers.Console.error(err);
|
||||
}
|
||||
break;
|
||||
case "GeometryCollection":
|
||||
results = [];
|
||||
for(var i=0; i<obj.members.length; ++i) {
|
||||
try {
|
||||
results.push(this.parseGeometry(obj.members[i]));
|
||||
} catch(err) {
|
||||
results = null;
|
||||
OpenLayers.Console.error(err);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case "FeatureCollection":
|
||||
// for type FeatureCollection, we allow input to be any type
|
||||
results = [];
|
||||
switch(obj.type) {
|
||||
case "Feature":
|
||||
try {
|
||||
results.push(this.parseFeature(obj));
|
||||
} catch(err) {
|
||||
results = null;
|
||||
OpenLayers.Console.error(err);
|
||||
}
|
||||
break;
|
||||
case "FeatureCollection":
|
||||
for(var i=0; i<obj.members.length; ++i) {
|
||||
try {
|
||||
results.push(this.parseFeature(obj.members[i]));
|
||||
} catch(err) {
|
||||
results = null;
|
||||
OpenLayers.Console.error(err);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case "GeometryCollection":
|
||||
for(var i=0; i<obj.members.length; ++i) {
|
||||
try {
|
||||
var geom = this.parseGeometry(obj.members[i]);
|
||||
results.push(new OpenLayers.Feature.Vector(geom));
|
||||
} catch(err) {
|
||||
results = null;
|
||||
OpenLayers.Console.error(err);
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
try {
|
||||
var geom = this.parseGeometry(obj);
|
||||
results.push(new OpenLayers.Feature.Vector(geom));
|
||||
} catch(err) {
|
||||
results = null;
|
||||
OpenLayers.Console.error(err);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
return results;
|
||||
},
|
||||
|
||||
/**
|
||||
* Method: isValidType
|
||||
* Check if a GeoJSON object is a valid representative of the given type.
|
||||
*
|
||||
* Returns:
|
||||
* {Boolean} The object is valid GeoJSON object of the given type.
|
||||
*/
|
||||
isValidType: function(obj, type) {
|
||||
var valid = false;
|
||||
switch(type) {
|
||||
case "Geometry":
|
||||
if(OpenLayers.Util.indexOf(["Point", "MultiPoint", "LineString",
|
||||
"MultiLineString", "Polygon",
|
||||
"MultiPolygon", "Box"], obj.type) == -1) {
|
||||
// unsupported geometry type
|
||||
OpenLayers.Console.error("Unsupported geometry type: " +
|
||||
obj.type);
|
||||
} else {
|
||||
valid = true;
|
||||
}
|
||||
break;
|
||||
case "FeatureCollection":
|
||||
// allow for any type to be converted to a feature collection
|
||||
valid = true;
|
||||
break
|
||||
default:
|
||||
// for GeometryCollection and Feature, types must match
|
||||
if(obj.type == type) {
|
||||
valid = true;
|
||||
} else {
|
||||
OpenLayers.Console.error("Cannot convert types from " +
|
||||
obj.type + " to " + type);
|
||||
}
|
||||
}
|
||||
return valid;
|
||||
},
|
||||
|
||||
/**
|
||||
* Method: parseFeature
|
||||
* Convert a feature object from GeoJSON into an
|
||||
* <OpenLayers.Feature.Vector>.
|
||||
*
|
||||
* Parameters:
|
||||
* obj - {Object} An object created from a GeoJSON object
|
||||
*
|
||||
* Returns:
|
||||
* {<OpenLayers.Feature.Vector>} A feature.
|
||||
*/
|
||||
parseFeature: function(obj) {
|
||||
var feature, geometry, attributes;
|
||||
attributes = (obj.properties) ? obj.properties : {};
|
||||
try {
|
||||
geometry = this.parseGeometry(obj.geometry);
|
||||
} catch(err) {
|
||||
// deal with bad geometries
|
||||
throw err;
|
||||
}
|
||||
feature = new OpenLayers.Feature.Vector(geometry, attributes);
|
||||
if(obj.id) {
|
||||
feature.fid = obj.id;
|
||||
}
|
||||
return feature;
|
||||
},
|
||||
|
||||
/**
|
||||
* Method: parseGeometry
|
||||
* Convert a geometry object from GeoJSON into an <OpenLayers.Geometry>.
|
||||
*
|
||||
* Parameters:
|
||||
* obj - {Object} An object created from a GeoJSON object
|
||||
*
|
||||
* Returns:
|
||||
* {<OpenLayers.Geometry>} A geometry.
|
||||
*/
|
||||
parseGeometry: function(obj) {
|
||||
var geometry;
|
||||
if(!(obj.coordinates instanceof Array)) {
|
||||
throw "Geometry must have coordinates array: " + obj;
|
||||
}
|
||||
if(!this.parseCoords[obj.type.toLowerCase()]) {
|
||||
throw "Unsupported geometry type: " + obj.type;
|
||||
}
|
||||
try {
|
||||
geometry = this.parseCoords[obj.type.toLowerCase()].apply(this, [obj.coordinates]);
|
||||
} catch(err) {
|
||||
// deal with bad coordinates
|
||||
throw err;
|
||||
}
|
||||
return geometry;
|
||||
},
|
||||
|
||||
/**
|
||||
* Property: parseCoords
|
||||
* Object with properties corresponding to the GeoJSON geometry types.
|
||||
* Property values are functions that do the actual parsing.
|
||||
*/
|
||||
parseCoords: {
|
||||
/**
|
||||
* Method: parseCoords.point
|
||||
* Convert a coordinate array from GeoJSON into an
|
||||
* <OpenLayers.Geometry>.
|
||||
*
|
||||
* Parameters:
|
||||
* array - {Object} The coordinates array from the GeoJSON fragment.
|
||||
*
|
||||
* Returns:
|
||||
* {<OpenLayers.Geometry>} A geometry.
|
||||
*/
|
||||
"point": function(array) {
|
||||
if(array.length != 2) {
|
||||
throw "Only 2D points are supported: " + array;
|
||||
}
|
||||
return new OpenLayers.Geometry.Point(array[0], array[1]);
|
||||
},
|
||||
|
||||
/**
|
||||
* Method: parseCoords.multipoint
|
||||
* Convert a coordinate array from GeoJSON into an
|
||||
* <OpenLayers.Geometry>.
|
||||
*
|
||||
* Parameters:
|
||||
* array {Object} The coordinates array from the GeoJSON fragment.
|
||||
*
|
||||
* Returns:
|
||||
* {<OpenLayers.Geometry>} A geometry.
|
||||
*/
|
||||
"multipoint": function(array) {
|
||||
var points = [];
|
||||
var p = null;
|
||||
for(var i=0; i<array.length; ++i) {
|
||||
try {
|
||||
p = this.parseCoords["point"].apply(this, [array[i]]);
|
||||
} catch(err) {
|
||||
throw err;
|
||||
}
|
||||
points.push(p);
|
||||
}
|
||||
return new OpenLayers.Geometry.MultiPoint(points);
|
||||
},
|
||||
|
||||
/**
|
||||
* Method: parseCoords.linestring
|
||||
* Convert a coordinate array from GeoJSON into an
|
||||
* <OpenLayers.Geometry>.
|
||||
*
|
||||
* Parameters:
|
||||
* array - {Object} The coordinates array from the GeoJSON fragment.
|
||||
*
|
||||
* Returns:
|
||||
* {<OpenLayers.Geometry>} A geometry.
|
||||
*/
|
||||
"linestring": function(array) {
|
||||
var points = [];
|
||||
var p = null;
|
||||
for(var i=0; i<array.length; ++i) {
|
||||
try {
|
||||
p = this.parseCoords["point"].apply(this, [array[i]]);
|
||||
} catch(err) {
|
||||
throw err;
|
||||
}
|
||||
points.push(p);
|
||||
}
|
||||
return new OpenLayers.Geometry.LineString(points);
|
||||
},
|
||||
|
||||
/**
|
||||
* Method: parseCoords.multilinestring
|
||||
* Convert a coordinate array from GeoJSON into an
|
||||
* <OpenLayers.Geometry>.
|
||||
*
|
||||
* Parameters:
|
||||
* array - {Object} The coordinates array from the GeoJSON fragment.
|
||||
*
|
||||
* Returns:
|
||||
* {<OpenLayers.Geometry>} A geometry.
|
||||
*/
|
||||
"multilinestring": function(array) {
|
||||
var lines = [];
|
||||
var l = null;
|
||||
for(var i=0; i<array.length; ++i) {
|
||||
try {
|
||||
l = this.parseCoords["linestring"].apply(this, [array[i]]);
|
||||
} catch(err) {
|
||||
throw err;
|
||||
}
|
||||
lines.push(l);
|
||||
}
|
||||
return new OpenLayers.Geometry.MultiLineString(lines);
|
||||
},
|
||||
|
||||
/**
|
||||
* Method: parseCoords.polygon
|
||||
* Convert a coordinate array from GeoJSON into an
|
||||
* <OpenLayers.Geometry>.
|
||||
*
|
||||
* Returns:
|
||||
* array - {Object} The coordinates array from the GeoJSON fragment.
|
||||
*
|
||||
* Returns:
|
||||
* {<OpenLayers.Geometry>} A geometry.
|
||||
*/
|
||||
"polygon": function(array) {
|
||||
var rings = [];
|
||||
var r, l;
|
||||
for(var i=0; i<array.length; ++i) {
|
||||
try {
|
||||
l = this.parseCoords["linestring"].apply(this, [array[i]]);
|
||||
} catch(err) {
|
||||
throw err;
|
||||
}
|
||||
r = new OpenLayers.Geometry.LinearRing(l.components);
|
||||
rings.push(r);
|
||||
}
|
||||
return new OpenLayers.Geometry.Polygon(rings);
|
||||
},
|
||||
|
||||
/**
|
||||
* Method: parseCoords.multipolygon
|
||||
* Convert a coordinate array from GeoJSON into an
|
||||
* <OpenLayers.Geometry>.
|
||||
*
|
||||
* Parameters:
|
||||
* array - {Object} The coordinates array from the GeoJSON fragment.
|
||||
*
|
||||
* Returns:
|
||||
* {<OpenLayers.Geometry>} A geometry.
|
||||
*/
|
||||
"multipolygon": function(array) {
|
||||
var polys = [];
|
||||
var p = null;
|
||||
for(var i=0; i<array.length; ++i) {
|
||||
try {
|
||||
p = this.parseCoords["polygon"].apply(this, [array[i]]);
|
||||
} catch(err) {
|
||||
throw err;
|
||||
}
|
||||
polys.push(p);
|
||||
}
|
||||
return new OpenLayers.Geometry.MultiPolygon(polys);
|
||||
},
|
||||
|
||||
/**
|
||||
* Method: parseCoords.box
|
||||
* Convert a coordinate array from GeoJSON into an
|
||||
* <OpenLayers.Geometry>.
|
||||
*
|
||||
* Parameters:
|
||||
* array - {Object} The coordinates array from the GeoJSON fragment.
|
||||
*
|
||||
* Returns:
|
||||
* {<OpenLayers.Geometry>} A geometry.
|
||||
*/
|
||||
"box": function(array) {
|
||||
if(array.length != 2) {
|
||||
throw "GeoJSON box coordinates must have 2 elements";
|
||||
}
|
||||
return new OpenLayers.Geometry.Polygon([
|
||||
new OpenLayers.Geometry.LinearRing([
|
||||
new OpenLayers.Geometry.Point(array[0][0], array[0][1]),
|
||||
new OpenLayers.Geometry.Point(array[1][0], array[0][1]),
|
||||
new OpenLayers.Geometry.Point(array[1][0], array[1][1]),
|
||||
new OpenLayers.Geometry.Point(array[0][0], array[1][1]),
|
||||
new OpenLayers.Geometry.Point(array[0][0], array[0][1])
|
||||
])
|
||||
]);
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
/**
|
||||
* APIMethod: write
|
||||
* Serialize a feature, geometry, array of features, or array of geometries
|
||||
* into a GeoJSON string.
|
||||
*
|
||||
* Parameters:
|
||||
* obj - {Object} An <OpenLayers.Feature.Vector>, <OpenLayers.Geometry>,
|
||||
* or an array of either features or geometries.
|
||||
* pretty - {Boolean} Structure the output with newlines and indentation.
|
||||
* Default is false.
|
||||
*
|
||||
* Returns:
|
||||
* {String} The GeoJSON string representation of the input geometry,
|
||||
* features, array of geometries, or array of features.
|
||||
*/
|
||||
write: function(obj, pretty) {
|
||||
var geojson = {
|
||||
"type": null
|
||||
};
|
||||
if(obj instanceof Array) {
|
||||
geojson.members = [];
|
||||
for(var i=0; i<obj.length; ++i) {
|
||||
var element = obj[i];
|
||||
if(element instanceof OpenLayers.Feature.Vector) {
|
||||
if(geojson.type == null) {
|
||||
geojson.type = "FeatureCollection";
|
||||
if(element.layer && element.layer.projection) {
|
||||
var proj = element.layer.projection;
|
||||
if(proj.match(/epsg:/i)) {
|
||||
geojson.crs = {
|
||||
"type": "EPSG",
|
||||
"properties": {
|
||||
"code": parseInt(proj.substring(proj.indexOf(":") + 1))
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
} else if(geojson.type != "FeatureCollection") {
|
||||
OpenLayers.Console.error("FeatureCollection only supports collections of features: " + element);
|
||||
break;
|
||||
}
|
||||
geojson.members.push(this.extract.feature.apply(this, [element]));
|
||||
} else if (element.CLASS_NAME.search("OpenLayers.Geometry") == 0) {
|
||||
if(geojson.type == null) {
|
||||
geojson.type = "GeometryCollection";
|
||||
} else if(geojson.type != "GeometryCollection") {
|
||||
OpenLayers.Console.error("GeometryCollection only supports collections of geometries: " + element);
|
||||
break;
|
||||
}
|
||||
geojson.members.push(this.extract.geometry.apply(this, [element]));
|
||||
}
|
||||
}
|
||||
} else if (obj.CLASS_NAME.search("OpenLayers.Geometry") == 0) {
|
||||
geojson = this.extract.geometry.apply(this, [obj]);
|
||||
} else if (obj instanceof OpenLayers.Feature.Vector) {
|
||||
geojson = this.extract.feature.apply(this, [obj]);
|
||||
if(obj.layer && obj.layer.projection) {
|
||||
var proj = obj.layer.projection;
|
||||
if(proj.match(/epsg:/i)) {
|
||||
geojson.crs = {
|
||||
"type": "EPSG",
|
||||
"properties": {
|
||||
"code": parseInt(proj.substring(proj.indexOf(":") + 1))
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
return OpenLayers.Format.JSON.prototype.write.apply(this,
|
||||
[geojson, pretty]);
|
||||
},
|
||||
|
||||
/**
|
||||
* Property: extract
|
||||
* Object with properties corresponding to the GeoJSON types.
|
||||
* Property values are functions that do the actual value extraction.
|
||||
*/
|
||||
extract: {
|
||||
/**
|
||||
* Method: extract.feature
|
||||
* Return a partial GeoJSON object representing a single feature.
|
||||
*
|
||||
* Parameters:
|
||||
* feature - {<OpenLayers.Feature.Vector>}
|
||||
*
|
||||
* Returns:
|
||||
* {Object} An object representing the point.
|
||||
*/
|
||||
'feature': function(feature) {
|
||||
var geom = this.extract.geometry.apply(this, [feature.geometry]);
|
||||
return {
|
||||
"type": "Feature",
|
||||
"id": feature.fid == null ? feature.id : feature.fid,
|
||||
"properties": feature.attributes,
|
||||
"geometry": geom
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Method: extract.geometry
|
||||
* Return a GeoJSON object representing a single geometry.
|
||||
*
|
||||
* Parameters:
|
||||
* geometry - {<OpenLayers.Geometry>}
|
||||
*
|
||||
* Returns:
|
||||
* {Object} An object representing the geometry.
|
||||
*/
|
||||
'geometry': function(geometry) {
|
||||
var geometryType = geometry.CLASS_NAME.split('.')[2];
|
||||
var data = this.extract[geometryType.toLowerCase()].apply(this, [geometry]);
|
||||
return {
|
||||
"type": geometryType,
|
||||
"coordinates": data
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Method: extract.poin
|
||||
* Return an array of coordinates from a point.
|
||||
*
|
||||
* Parameters:
|
||||
* point - {<OpenLayers.Geometry.Point>}
|
||||
*
|
||||
* Returns:
|
||||
* {Array} An array of coordinates representing the point.
|
||||
*/
|
||||
'point': function(point) {
|
||||
return [point.x, point.y];
|
||||
},
|
||||
|
||||
/**
|
||||
* Method: extract.multipoint
|
||||
* Return an array of point coordinates from a multipoint.
|
||||
*
|
||||
* Parameters:
|
||||
* multipoint - {<OpenLayers.Geometry.MultiPoint>}
|
||||
*
|
||||
* Returns:
|
||||
* {Array} An array of point coordinate arrays representing
|
||||
* the multipoint.
|
||||
*/
|
||||
'multipoint': function(multipoint) {
|
||||
var array = [];
|
||||
for(var i=0; i<multipoint.components.length; ++i) {
|
||||
array.push(this.extract.point.apply(this, [multipoint.components[i]]));
|
||||
}
|
||||
return array;
|
||||
},
|
||||
|
||||
/**
|
||||
* Method: extract.linestring
|
||||
* Return an array of coordinate arrays from a linestring.
|
||||
*
|
||||
* Parameters:
|
||||
* linestring - {<OpenLayers.Geometry.LineString>}
|
||||
*
|
||||
* Returns:
|
||||
* {Array} An array of coordinate arrays representing
|
||||
* the linestring.
|
||||
*/
|
||||
'linestring': function(linestring) {
|
||||
var array = [];
|
||||
for(var i=0; i<linestring.components.length; ++i) {
|
||||
array.push(this.extract.point.apply(this, [linestring.components[i]]));
|
||||
}
|
||||
return array;
|
||||
},
|
||||
|
||||
/**
|
||||
* Method: extract.multilinestring
|
||||
* Return an array of linestring arrays from a linestring.
|
||||
*
|
||||
* Parameters:
|
||||
* linestring - {<OpenLayers.Geometry.MultiLineString>}
|
||||
*
|
||||
* Returns:
|
||||
* {Array} An array of linestring arrays representing
|
||||
* the multilinestring.
|
||||
*/
|
||||
'multilinestring': function(multilinestring) {
|
||||
var array = [];
|
||||
for(var i=0; i<multilinestring.components.length; ++i) {
|
||||
array.push(this.extract.linestring.apply(this, [multilinestring.components[i]]));
|
||||
}
|
||||
return array;
|
||||
},
|
||||
|
||||
/**
|
||||
* Method: extract.polygon
|
||||
* Return an array of linear ring arrays from a polygon.
|
||||
*
|
||||
* Parameters:
|
||||
* polygon - {<OpenLayers.Geometry.Polygon>}
|
||||
*
|
||||
* Returns:
|
||||
* {Array} An array of linear ring arrays representing the polygon.
|
||||
*/
|
||||
'polygon': function(polygon) {
|
||||
var array = [];
|
||||
for(var i=0; i<polygon.components.length; ++i) {
|
||||
array.push(this.extract.linestring.apply(this, [polygon.components[i]]));
|
||||
}
|
||||
return array;
|
||||
},
|
||||
|
||||
/**
|
||||
* Method: extract.multipolygon
|
||||
* Return an array of polygon arrays from a multipolygon.
|
||||
*
|
||||
* Parameters:
|
||||
* multipolygon - {<OpenLayers.Geometry.MultiPolygon>}
|
||||
*
|
||||
* Returns:
|
||||
* {Array} An array of polygon arrays representing
|
||||
* the multipolygon
|
||||
*/
|
||||
'multipolygon': function(multipolygon) {
|
||||
var array = [];
|
||||
for(var i=0; i<multipolygon.components.length; ++i) {
|
||||
array.push(this.extract.polygon.apply(this, [multipolygon.components[i]]));
|
||||
}
|
||||
return array;
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
CLASS_NAME: "OpenLayers.Format.GeoJSON"
|
||||
|
||||
});
|
||||
376
lib/OpenLayers/Format/JSON.js
Normal file
376
lib/OpenLayers/Format/JSON.js
Normal file
@@ -0,0 +1,376 @@
|
||||
/* Copyright (c) 2006 MetaCarta, Inc., published under a modified BSD license.
|
||||
* See http://svn.openlayers.org/trunk/openlayers/repository-license.txt
|
||||
* for the full text of the license. */
|
||||
|
||||
/**
|
||||
* Note:
|
||||
* This work draws heavily from the public domain JSON serializer/deserializer
|
||||
* at http://www.json.org/json.js. Rewritten so that it doesn't modify
|
||||
* basic data prototypes.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @requires OpenLayers/Format.js
|
||||
*
|
||||
* Class: OpenLayers.Format.JSON
|
||||
* A parser to read/write JSON safely. Create a new instance with the
|
||||
* <OpenLayers.Format.JSON> constructor.
|
||||
*
|
||||
* Inherits from:
|
||||
* - <OpenLayers.Format>
|
||||
*/
|
||||
OpenLayers.Format.JSON = OpenLayers.Class(OpenLayers.Format, {
|
||||
|
||||
/**
|
||||
* APIProperty: indent
|
||||
* {String} For "pretty" printing, the indent string will be used once for
|
||||
* each indentation level.
|
||||
*/
|
||||
indent: " ",
|
||||
|
||||
/**
|
||||
* APIProperty: space
|
||||
* {String} For "pretty" printing, the space string will be used after
|
||||
* the ":" separating a name/value pair.
|
||||
*/
|
||||
space: " ",
|
||||
|
||||
/**
|
||||
* APIProperty: newline
|
||||
* {String} For "pretty" printing, the newline string will be used at the
|
||||
* end of each name/value pair or array item.
|
||||
*/
|
||||
newline: "\n",
|
||||
|
||||
/**
|
||||
* Property: level
|
||||
* {Integer} For "pretty" printing, this is incremented/decremented during
|
||||
* serialization.
|
||||
*/
|
||||
level: 0,
|
||||
|
||||
/**
|
||||
* Property: pretty
|
||||
* {Boolean} Serialize with extra whitespace for structure. This is set
|
||||
* by the <write> method.
|
||||
*/
|
||||
pretty: false,
|
||||
|
||||
/**
|
||||
* Constructor: OpenLayers.Format.JSON
|
||||
* Create a new parser for JSON.
|
||||
*
|
||||
* Parameters:
|
||||
* options - {Object} An optional object whose properties will be set on
|
||||
* this instance.
|
||||
*/
|
||||
initialize: function(options) {
|
||||
OpenLayers.Format.prototype.initialize.apply(this, [options]);
|
||||
},
|
||||
|
||||
/**
|
||||
* APIMethod: read
|
||||
* Deserialize a json string.
|
||||
*
|
||||
* Parameters:
|
||||
* json - {String} A JSON string
|
||||
* filter - {Function} A function which will be called for every key and
|
||||
* value at every level of the final result. Each value will be
|
||||
* replaced by the result of the filter function. This can be used to
|
||||
* reform generic objects into instances of classes, or to transform
|
||||
* date strings into Date objects.
|
||||
*
|
||||
* Returns:
|
||||
* {Object} An object, array, string, or number .
|
||||
*/
|
||||
read: function(json, filter) {
|
||||
/**
|
||||
* Parsing happens in three stages. In the first stage, we run the text
|
||||
* against a regular expression which looks for non-JSON
|
||||
* characters. We are especially concerned with '()' and 'new'
|
||||
* because they can cause invocation, and '=' because it can cause
|
||||
* mutation. But just to be safe, we will reject all unexpected
|
||||
* characters.
|
||||
*/
|
||||
try {
|
||||
if(/^("(\\.|[^"\\\n\r])*?"|[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t])+?$/.
|
||||
test(json)) {
|
||||
|
||||
/**
|
||||
* In the second stage we use the eval function to compile the
|
||||
* text into a JavaScript structure. The '{' operator is
|
||||
* subject to a syntactic ambiguity in JavaScript - it can
|
||||
* begin a block or an object literal. We wrap the text in
|
||||
* parens to eliminate the ambiguity.
|
||||
*/
|
||||
var object = eval('(' + json + ')');
|
||||
|
||||
/**
|
||||
* In the optional third stage, we recursively walk the new
|
||||
* structure, passing each name/value pair to a filter
|
||||
* function for possible transformation.
|
||||
*/
|
||||
if(typeof filter === 'function') {
|
||||
function walk(k, v) {
|
||||
if(v && typeof v === 'object') {
|
||||
for(var i in v) {
|
||||
if(v.hasOwnProperty(i)) {
|
||||
v[i] = walk(i, v[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
return filter(k, v);
|
||||
}
|
||||
object = walk('', object);
|
||||
}
|
||||
return object;
|
||||
}
|
||||
} catch(e) {
|
||||
// Fall through if the regexp test fails.
|
||||
}
|
||||
return null;
|
||||
},
|
||||
|
||||
/**
|
||||
* APIMethod: write
|
||||
* Serialize an object into a JSON string.
|
||||
*
|
||||
* Parameters:
|
||||
* value - {String} The object, array, string, number, boolean or date
|
||||
* to be serialized.
|
||||
* pretty - {Boolean} Structure the output with newlines and indentation.
|
||||
* Default is false.
|
||||
*
|
||||
* Returns:
|
||||
* {String} The JSON string representation of the input value.
|
||||
*/
|
||||
write: function(value, pretty) {
|
||||
this.pretty = !!pretty;
|
||||
var json = null;
|
||||
var type = typeof value;
|
||||
if(this.serialize[type]) {
|
||||
json = this.serialize[type].apply(this, [value]);
|
||||
}
|
||||
return json;
|
||||
},
|
||||
|
||||
/**
|
||||
* Method: writeIndent
|
||||
* Output an indentation string depending on the indentation level.
|
||||
*
|
||||
* Returns:
|
||||
* {String} An appropriate indentation string.
|
||||
*/
|
||||
writeIndent: function() {
|
||||
var pieces = [];
|
||||
if(this.pretty) {
|
||||
for(var i=0; i<this.level; ++i) {
|
||||
pieces.push(this.indent);
|
||||
}
|
||||
}
|
||||
return pieces.join('');
|
||||
},
|
||||
|
||||
/**
|
||||
* Method: writeNewline
|
||||
* Output a string representing a newline if in pretty printing mode.
|
||||
*
|
||||
* Returns:
|
||||
* {String} A string representing a new line.
|
||||
*/
|
||||
writeNewline: function() {
|
||||
return (this.pretty) ? this.newline : '';
|
||||
},
|
||||
|
||||
/**
|
||||
* Method: writeSpace
|
||||
* Output a string representing a space if in pretty printing mode.
|
||||
*
|
||||
* Returns:
|
||||
* {String} A space.
|
||||
*/
|
||||
writeSpace: function() {
|
||||
return (this.pretty) ? this.space : '';
|
||||
},
|
||||
|
||||
/**
|
||||
* Property: serialize
|
||||
* Object with properties corresponding to the serializable data types.
|
||||
* Property values are functions that do the actual serializing.
|
||||
*/
|
||||
serialize: {
|
||||
/**
|
||||
* Method: serialize.object
|
||||
* Transform an object into a JSON string.
|
||||
*
|
||||
* Parameters:
|
||||
* object - {Object} The object to be serialized.
|
||||
*
|
||||
* Returns:
|
||||
* {String} A JSON string representing the object.
|
||||
*/
|
||||
'object': function(object) {
|
||||
// three special objects that we want to treat differently
|
||||
if(object == null) {
|
||||
return "null";
|
||||
}
|
||||
if(object.constructor == Date) {
|
||||
return this.serialize.date.apply(this, [object]);
|
||||
}
|
||||
if(object.constructor == Array) {
|
||||
return this.serialize.array.apply(this, [object]);
|
||||
}
|
||||
var pieces = ['{'];
|
||||
this.level += 1;
|
||||
var key, keyJSON, valueJSON;
|
||||
|
||||
var addComma = false;
|
||||
for(key in object) {
|
||||
if(object.hasOwnProperty(key)) {
|
||||
// recursive calls need to allow for sub-classing
|
||||
keyJSON = OpenLayers.Format.JSON.prototype.write.apply(this,
|
||||
[key, this.pretty]);
|
||||
valueJSON = OpenLayers.Format.JSON.prototype.write.apply(this,
|
||||
[object[key], this.pretty]);
|
||||
if(keyJSON != null && valueJSON != null) {
|
||||
if(addComma) {
|
||||
pieces.push(',');
|
||||
}
|
||||
pieces.push(this.writeNewline(), this.writeIndent(),
|
||||
keyJSON, ':', this.writeSpace(), valueJSON);
|
||||
addComma = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.level -= 1;
|
||||
pieces.push(this.writeNewline(), this.writeIndent(), '}');
|
||||
return pieces.join('');
|
||||
},
|
||||
|
||||
/**
|
||||
* Method: serialize.array
|
||||
* Transform an array into a JSON string.
|
||||
*
|
||||
* Parameters:
|
||||
* array - {Array} The array to be serialized
|
||||
*
|
||||
* Returns:
|
||||
* {String} A JSON string representing the array.
|
||||
*/
|
||||
'array': function(array) {
|
||||
var json;
|
||||
var pieces = ['['];
|
||||
this.level += 1;
|
||||
|
||||
for(var i=0; i<array.length; ++i) {
|
||||
// recursive calls need to allow for sub-classing
|
||||
json = OpenLayers.Format.JSON.prototype.write.apply(this,
|
||||
[array[i], this.pretty]);
|
||||
if(json != null) {
|
||||
if(i > 0) {
|
||||
pieces.push(',');
|
||||
}
|
||||
pieces.push(this.writeNewline(), this.writeIndent(), json);
|
||||
}
|
||||
}
|
||||
|
||||
this.level -= 1;
|
||||
pieces.push(this.writeNewline(), this.writeIndent(), ']');
|
||||
return pieces.join('');
|
||||
},
|
||||
|
||||
/**
|
||||
* Method: serialize.string
|
||||
* Transform a string into a JSON string.
|
||||
*
|
||||
* Parameters
|
||||
* string - {String} The string to be serialized
|
||||
*
|
||||
* Returns:
|
||||
* {String} A JSON string representing the string.
|
||||
*/
|
||||
'string': function(string) {
|
||||
// If the string contains no control characters, no quote characters, and no
|
||||
// backslash characters, then we can simply slap some quotes around it.
|
||||
// Otherwise we must also replace the offending characters with safe
|
||||
// sequences.
|
||||
var m = {
|
||||
'\b': '\\b',
|
||||
'\t': '\\t',
|
||||
'\n': '\\n',
|
||||
'\f': '\\f',
|
||||
'\r': '\\r',
|
||||
'"' : '\\"',
|
||||
'\\': '\\\\'
|
||||
};
|
||||
if(/["\\\x00-\x1f]/.test(string)) {
|
||||
return '"' + string.replace(/([\x00-\x1f\\"])/g, function(a, b) {
|
||||
var c = m[b];
|
||||
if(c) {
|
||||
return c;
|
||||
}
|
||||
c = b.charCodeAt();
|
||||
return '\\u00' +
|
||||
Math.floor(c / 16).toString(16) +
|
||||
(c % 16).toString(16);
|
||||
}) + '"';
|
||||
}
|
||||
return '"' + string + '"';
|
||||
},
|
||||
|
||||
/**
|
||||
* Method: serialize.number
|
||||
* Transform a number into a JSON string.
|
||||
*
|
||||
* Parameters:
|
||||
* number - {Number} The number to be serialized.
|
||||
*
|
||||
* Returns:
|
||||
* {String} A JSON string representing the number.
|
||||
*/
|
||||
'number': function(number) {
|
||||
return isFinite(number) ? String(number) : "null";
|
||||
},
|
||||
|
||||
/**
|
||||
* Method: serialize.boolean
|
||||
* Transform a boolean into a JSON string.
|
||||
*
|
||||
* Parameters:
|
||||
* bool - {Boolean} The boolean to be serialized.
|
||||
*
|
||||
* Returns:
|
||||
* {String} A JSON string representing the boolean.
|
||||
*/
|
||||
'boolean': function(bool) {
|
||||
return String(bool);
|
||||
},
|
||||
|
||||
/**
|
||||
* Method: serialize.object
|
||||
* Transform a date into a JSON string.
|
||||
*
|
||||
* Parameters:
|
||||
* date - {Date} The date to be serialized.
|
||||
*
|
||||
* Returns:
|
||||
* {String} A JSON string representing the date.
|
||||
*/
|
||||
'date': function(date) {
|
||||
function format(number) {
|
||||
// Format integers to have at least two digits.
|
||||
return (number < 10) ? '0' + number : number;
|
||||
}
|
||||
return '"' + date.getFullYear() + '-' +
|
||||
format(date.getMonth() + 1) + '-' +
|
||||
format(date.getDate()) + 'T' +
|
||||
format(date.getHours()) + ':' +
|
||||
format(date.getMinutes()) + ':' +
|
||||
format(date.getSeconds()) + '"';
|
||||
}
|
||||
},
|
||||
|
||||
CLASS_NAME: "OpenLayers.Format.JSON"
|
||||
|
||||
});
|
||||
267
tests/Format/test_GeoJSON.html
Normal file
267
tests/Format/test_GeoJSON.html
Normal file
@@ -0,0 +1,267 @@
|
||||
<html>
|
||||
<head>
|
||||
<script src="../../lib/OpenLayers.js"></script>
|
||||
<script type="text/javascript"><!--
|
||||
|
||||
var poly_content = '{"type": "FeatureCollection", "members": [{"geometry": {"type": "Polygon", "coordinates": [[[-131.484375, -5.9765625], [-112.5, -58.0078125], [-32.34375, -50.2734375], [-114.609375, 52.3828125], [-167.34375, -35.5078125], [-146.953125, -57.3046875], [-139.921875, -34.1015625], [-131.484375, -5.9765625]]]}, "type": "Feature", "id": 562, "properties": {"strokeColor": "red", "title": "Feature 2", "author": "Your Name Here"}}]}';
|
||||
var point_feature = '{"geometry": {"type": "Point", "coordinates": [94.21875, 72.94921875]}, "type": "Feature", "id": 573, "properties": {"strokeColor": "blue", "title": "Feature 5", "author": "Your Name Here"}}'
|
||||
var line_feature = '{"type": "FeatureCollection", "members": [{"geometry": {"type": "LineString", "coordinates": [[-27.0703125, 59.4140625], [-77.6953125, 20.7421875], [30.5859375, -36.2109375], [67.1484375, 34.8046875]]}, "type": "Feature", "id": 559, "properties": {"strokeColor": "red", "title": "Feature 1", "author": "Your Name Here"}}]}';
|
||||
var multiple_features = '{"type": "FeatureCollection", "members": [{"geometry": {"type": "Point", "coordinates": [-91.0546875, 43.9453125]}, "type": "Feature", "id": 577, "properties": {"strokeColor": "red", "title": "Feature 2", "image": "foo.gif", "author": "Your Name Here"}}, {"geometry": {"type": "LineString", "coordinates": [[91.40625, -1.40625], [116.015625, -42.890625], [153.28125, -28.125], [108.984375, 11.25], [75.234375, 8.4375], [76.640625, 9.140625], [67.5, -36.5625], [67.5, -35.859375]]}, "type": "Feature", "id": 576, "properties": {"strokeColor": "red", "title": "Feature 1", "author": "Your Name Here"}}, {"geometry": {"type": "Point", "coordinates": [139.5703125, 57.48046875]}, "type": "Feature", "id": 575, "properties": {"strokeColor": "blue", "title": "Feature 7", "author": "Your Name Here"}}, {"geometry": {"type": "Point", "coordinates": [107.2265625, 82.44140625]}, "type": "Feature", "id": 574, "properties": {"strokeColor": "blue", "title": "Feature 6", "author": "Your Name Here"}}, {"geometry": {"type": "Point", "coordinates": [94.21875, 72.94921875]}, "type": "Feature", "id": 573, "properties": {"strokeColor": "blue", "title": "Feature 5", "author": "Your Name Here"}}, {"geometry": {"type": "Point", "coordinates": [116.3671875, 61.69921875]}, "type": "Feature", "id": 572, "properties": {"strokeColor": "blue", "title": "Feature 4", "author": "Your Name Here"}}, {"geometry": {"type": "Point", "coordinates": [145.8984375, 73.65234375]}, "type": "Feature", "id": 571, "properties": {"strokeColor": "blue", "title": "Feature 3", "author": "Your Name Here"}}, {"geometry": {"type": "Polygon", "coordinates": [[[32.34375, 52.20703125], [87.1875, 70.13671875], [122.6953125, 37.44140625], [75.234375, 42.36328125], [40.078125, 42.36328125], [28.828125, 48.33984375], [18.6328125, 56.77734375], [23.203125, 65.56640625], [32.34375, 52.20703125]]]}, "type": "Feature", "id": 570, "properties": {"strokeColor": "blue", "title": "Feature 2", "author": "Your Name Here"}}, {"geometry": {"type": "Point", "coordinates": [62.578125, -53.4375]}, "type": "Feature", "id": 569, "properties": {"strokeColor": "red", "title": "Feature 3", "author": "Your Name Here"}}, {"geometry": {"type": "Point", "coordinates": [121.640625, 16.875]}, "type": "Feature", "id": 568, "properties": {"strokeColor": "red", "title": "Feature 6", "author": "Your Name Here"}}, {"geometry": {"type": "Point", "coordinates": [135.703125, 8.4375]}, "type": "Feature", "id": 567, "properties": {"strokeColor": "red", "title": "Feature 4", "author": "Your Name Here"}}, {"geometry": {"type": "Point", "coordinates": [137.109375, 48.515625]}, "type": "Feature", "id": 566, "properties": {"strokeColor": "red", "title": "Feature 274", "author": "Your Name Here"}}, {"geometry": {"type": "Point", "coordinates": [0, 5]}, "type": "Feature", "id": 565, "properties": {}}, {"geometry": {"type": "Point", "coordinates": [0, 5]}, "type": "Feature", "id": 564, "properties": {}}, {"geometry": {"type": "Point", "coordinates": [0, 5]}, "type": "Feature", "id": 563, "properties": {}}, {"geometry": {"type": "Polygon", "coordinates": [[[-131.484375, -5.9765625], [-112.5, -58.0078125], [-32.34375, -50.2734375], [-114.609375, 52.3828125], [-167.34375, -35.5078125], [-146.953125, -57.3046875], [-139.921875, -34.1015625], [-131.484375, -5.9765625]]]}, "type": "Feature", "id": 562, "properties": {"strokeColor": "red", "title": "Feature 2", "author": "Your Name Here"}}, {"geometry": {"type": "Point", "coordinates": [48.8671875, -15.8203125]}, "type": "Feature", "id": 560, "properties": {"strokeColor": "red", "title": "Feature 2", "author": "Your Name Here"}}, {"geometry": {"type": "LineString", "coordinates": [[-27.0703125, 59.4140625], [-77.6953125, 20.7421875], [30.5859375, -36.2109375], [67.1484375, 34.8046875]]}, "type": "Feature", "id": 559, "properties": {"strokeColor": "red", "title": "Feature 1", "author": "Your Name Here"}}, {"geometry": {"type": "Point", "coordinates": [12.65625, 16.5234375]}, "type": "Feature", "id": 558, "properties": {"styleUrl": "#allstyle", "title": "Feature 1", "strokeColor": "red", "author": "Your Name Here"}}]}';
|
||||
var parser = new OpenLayers.Format.GeoJSON();
|
||||
|
||||
|
||||
function test_Format_GeoJSON_constructor(t) {
|
||||
t.plan(4);
|
||||
|
||||
var options = {'foo': 'bar'};
|
||||
var format = new OpenLayers.Format.GeoJSON(options);
|
||||
t.ok(format instanceof OpenLayers.Format.GeoJSON,
|
||||
"new OpenLayers.Format.GeoJSON returns object" );
|
||||
t.eq(format.foo, "bar", "constructor sets options correctly");
|
||||
t.eq(typeof format.read, "function", "format has a read function");
|
||||
t.eq(typeof format.write, "function", "format has a write function");
|
||||
}
|
||||
|
||||
function test_Format_GeoJSON_valid_type(t) {
|
||||
t.plan(13);
|
||||
OpenLayers.Console.error = function(error) { window.global_error = error; }
|
||||
var types = ["Point", "MultiPoint", "LineString", "MultiLineString", "Polygon", "MultiPolygon", "Box"];
|
||||
for (var i = 0; i < types.length; i++) {
|
||||
t.ok(parser.isValidType({'type':types[i]}, "Geometry"), "Geometry with type " + types[i] + " is valid");
|
||||
}
|
||||
t.ok(!parser.isValidType({'type':"foo"}, "Geometry"), "Geometry with type foo is not valid");
|
||||
t.eq(global_error, "Unsupported geometry type: foo", "error message set correctly for 'foo' geom.");
|
||||
t.ok(parser.isValidType({}, "FeatureCollection"), "Feature collection type is always valid");
|
||||
t.ok(parser.isValidType({'type':"GeometryCollection"}, "GeometryCollection"), "Geometry Collection type is valid");
|
||||
t.ok(!parser.isValidType({'type':"GeometryCollection2"}, "GeometryCollection"), "Geometry Collection 2 type is invalid");
|
||||
t.eq(global_error, "Cannot convert types from GeometryCollection2 to GeometryCollection", "error message set correctly for bad geometrycollection type");
|
||||
}
|
||||
|
||||
function test_Format_GeoJSON_point(t) {
|
||||
t.plan(3);
|
||||
data = parser.read(point_feature);
|
||||
t.eq(data[0].fid, 573, "Fid is correct on point feature");
|
||||
t.eq(data[0].geometry.x, 94.21875, 'Reading point feature gives correct x');
|
||||
data = parser.read(point_feature, "Feature");
|
||||
t.eq(data.fid, 573, 'Reading point feature with type gives feature instead of array of features ');
|
||||
}
|
||||
function test_Format_GeoJSON_line(t) {
|
||||
t.plan(5);
|
||||
data = parser.read(line_feature);
|
||||
t.eq(data[0].fid, 559, "Fid is correct on line feature");
|
||||
t.eq(data[0].geometry.components.length, 4, 'Reading line feature gives correct length');
|
||||
t.eq(data[0].geometry.CLASS_NAME, 'OpenLayers.Geometry.LineString', 'Reading line feature gives correct class');
|
||||
t.eq(data[0].geometry.components[0].x, -27.0703125, 'Reading line feature gives correct x');
|
||||
t.eq(data[0].geometry.components[0].y, 59.4140625, 'Reading line feature gives correct y');
|
||||
}
|
||||
function test_Format_GeoJSON_poly(t) {
|
||||
t.plan(2);
|
||||
data = parser.read(poly_content);
|
||||
t.eq(data[0].fid, 562, "poly id is correct")
|
||||
t.eq(data[0].geometry.components[0].components.length, 8,
|
||||
'Reading polygon first ring on feature from featurecollection gives correct length');
|
||||
}
|
||||
|
||||
function test_Format_GeoJSON_multipoint(t) {
|
||||
t.plan(5);
|
||||
var multipoint = {
|
||||
"type": "MultiPoint",
|
||||
"coordinates": [
|
||||
[100.0, 0.0], [101.0, 1.0]
|
||||
]
|
||||
}
|
||||
data = parser.read(multipoint, "Geometry");
|
||||
t.eq(data.components.length, 2,
|
||||
"Right number of components");
|
||||
t.eq(data.components[0].CLASS_NAME, "OpenLayers.Geometry.Point", "First component is point");
|
||||
t.eq(data.components[1].CLASS_NAME, "OpenLayers.Geometry.Point", "Second component is point");
|
||||
t.eq(data.components[1].x, 101, "x of second component is right");
|
||||
t.eq(data.components[1].y, 1, "y of second component is right");
|
||||
}
|
||||
|
||||
|
||||
function test_Format_GeoJSON_multiline(t) {
|
||||
t.plan(3);
|
||||
var multiline = {
|
||||
"type": "MultiLineString",
|
||||
"coordinates": [
|
||||
[ [100.0, 0.0], [101.0, 1.0] ],
|
||||
[ [102.0, 2.0], [103.0, 3.0] ]
|
||||
]
|
||||
}
|
||||
data = parser.read(multiline, "Geometry");
|
||||
t.eq(data.CLASS_NAME, "OpenLayers.Geometry.MultiLineString", "Correct class retrieved")
|
||||
t.eq(data.components[0].components[0].CLASS_NAME, "OpenLayers.Geometry.Point", "correct type of components")
|
||||
t.eq(data.components[0].CLASS_NAME, "OpenLayers.Geometry.LineString", "correct type of components")
|
||||
}
|
||||
function test_Format_GeoJSON_multipol(t) {
|
||||
t.plan(2);
|
||||
var multipol = {
|
||||
"type": "MultiPolygon",
|
||||
"coordinates": [
|
||||
[
|
||||
[ [102.0, 2.0], [103.0, 2.0], [103.0, 3.0], [102.0, 3.0], [102.0, 2.0] ]
|
||||
],
|
||||
[
|
||||
[ [100.0, 0.0], [101.0, 0.0], [101.0, 1.0], [100.0, 1.0], [100.0, 0.0] ],
|
||||
[ [100.2, 0.2], [100.8, 0.2], [100.8, 0.8], [100.2, 0.8], [100.2, 0.2] ]
|
||||
]
|
||||
]
|
||||
}
|
||||
OpenLayers.Console.error = function(error) { window.global_error = error; }
|
||||
data = parser.read(multipol, "Geometry");
|
||||
t.eq(data.CLASS_NAME, "OpenLayers.Geometry.MultiPolygon", "Correct class retrieved")
|
||||
t.eq(data.components[1].components[0].components[0].CLASS_NAME, "OpenLayers.Geometry.Point", "correct type of components")
|
||||
}
|
||||
|
||||
function test_Format_GeoJSON_box(t) {
|
||||
t.plan(6);
|
||||
var box = {
|
||||
"type": "Box",
|
||||
"coordinates": [[100.0, 0.0], [101.0, 1.0]]
|
||||
};
|
||||
var poly = parser.read(box, "Geometry");
|
||||
t.eq(poly.CLASS_NAME, "OpenLayers.Geometry.Polygon", "Box creates polygon");
|
||||
t.eq(poly.components[0].components[1].x, 101, "x of lower right is correct");
|
||||
t.eq(poly.components[0].components[1].y, 0, "y of lower right is correct");
|
||||
t.eq(poly.components[0].components[3].x, 100, "x of upper left is correct");
|
||||
t.eq(poly.components[0].components[3].y, 1, "y of upper left is correct");
|
||||
var box = parser.write(poly );
|
||||
t.ok(box.search("Polygon") != -1 , "Serializes back to polygon");
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// This test is from the geom_collection example on geojson spec.
|
||||
function test_Format_GeoJSON_geom_collection(t) {
|
||||
t.plan(7);
|
||||
var geomcol = {
|
||||
"type": "GeometryCollection",
|
||||
"members": [
|
||||
{
|
||||
"type": "Point",
|
||||
"coordinates": [100.0, 0.0]
|
||||
},
|
||||
{
|
||||
"type": "LineString",
|
||||
"coordinates": [
|
||||
[101.0, 0.0], [102.0, 1.0]
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
data = parser.read(geomcol, "GeometryCollection");
|
||||
t.eq(data[0].CLASS_NAME,
|
||||
"OpenLayers.Geometry.Point", "First geom in geom collection is point type");
|
||||
t.eq(data[0].x, 100, "First geom in geom collection has correct x");
|
||||
t.eq(data[0].y, 0, "First geom in geom collection has correct x");
|
||||
|
||||
t.eq(data[1].CLASS_NAME,
|
||||
"OpenLayers.Geometry.LineString", "Second geom in geom collection is point linestring");
|
||||
t.eq(data[1].components.length, 2, "linestring is correct length");
|
||||
t.eq(data[1].components[1].x, 102, "linestring is correct x end");
|
||||
t.eq(data[1].components[1].y, 1, "linestring is correct y end");
|
||||
|
||||
}
|
||||
|
||||
function test_Format_GeoJSON_multipleFeatures(t) {
|
||||
t.plan(2);
|
||||
var feats = parser.read(multiple_features);
|
||||
t.eq(feats.length, 19, "parsing a feature collection returns the correct number of features.");
|
||||
var types = {'Point':0, 'LineString':0, 'Polygon':0}
|
||||
for(var i = 0; i < feats.length; i++) {
|
||||
var type = feats[i].geometry.CLASS_NAME.replace("OpenLayers.Geometry.", "");
|
||||
types[type]++;
|
||||
}
|
||||
t.eq(types, {'Point':15, 'Polygon': 2, 'LineString':2}, "Correct number of each type");
|
||||
}
|
||||
|
||||
function test_Format_GeoJSON_write(t) {
|
||||
t.plan(10);
|
||||
var line_object = {"type": "FeatureCollection",
|
||||
"members": [{"geometry":
|
||||
{"type": "LineString",
|
||||
"coordinates": [[-27.0703125, 59.4140625],
|
||||
[-77.6953125, 20.7421875],
|
||||
[30.5859375, -36.2109375],
|
||||
[67.1484375, 34.8046875]]},
|
||||
"type": "Feature",
|
||||
"id": 559,
|
||||
"properties":
|
||||
{
|
||||
"strokeColor": "red",
|
||||
"title": "Feature 1",
|
||||
"author": "Your Name Here"}}]};
|
||||
data = parser.read(line_object);
|
||||
out = parser.write(data);
|
||||
serialized = '{"type":"FeatureCollection","members":[{"type":"Feature","id":559,"properties":{"strokeColor":"red","title":"Feature 1","author":"Your Name Here"},"geometry":{"type":"LineString","coordinates":[[-27.0703125,59.4140625],[-77.6953125,20.7421875],[30.5859375,-36.2109375],[67.1484375,34.8046875]]}}]}';
|
||||
t.eq(out, serialized, "input and output on line collections are the same");
|
||||
|
||||
var serialize_tests = [
|
||||
[new OpenLayers.Feature.Vector(new OpenLayers.Geometry.Point(1,2)),
|
||||
'{"type":"Feature","id":0,"properties":{},"geometry":{"type":"Point","coordinates":[1,2]}}'],
|
||||
[new OpenLayers.Geometry.Point(1,2),
|
||||
'{"type":"Point","coordinates":[1,2]}'],
|
||||
[new OpenLayers.Geometry.MultiPoint([new OpenLayers.Geometry.Point(1,2)]),
|
||||
'{"type":"MultiPoint","coordinates":[[1,2]]}'],
|
||||
[new OpenLayers.Geometry.LineString([new OpenLayers.Geometry.Point(1,2), new OpenLayers.Geometry.Point(3,4)]),
|
||||
'{"type":"LineString","coordinates":[[1,2],[3,4]]}'],
|
||||
[new OpenLayers.Geometry.Polygon([
|
||||
new OpenLayers.Geometry.LinearRing([
|
||||
new OpenLayers.Geometry.Point(1,2),
|
||||
new OpenLayers.Geometry.Point(3,4),
|
||||
new OpenLayers.Geometry.Point(5,6)])]),
|
||||
'{"type":"Polygon","coordinates":[[[1,2],[3,4],[5,6],[1,2]]]}']
|
||||
];
|
||||
serialize_tests[0][0].fid = 0;
|
||||
multiline = new OpenLayers.Geometry.MultiLineString([serialize_tests[3][0], serialize_tests[3][0]]);
|
||||
serialize_tests.push([multiline, '{"type":"MultiLineString","coordinates":[[[1,2],[3,4]],[[1,2],[3,4]]]}']);
|
||||
multipolygon = new OpenLayers.Geometry.MultiPolygon([serialize_tests[4][0], serialize_tests[4][0]]);
|
||||
serialize_tests.push([multipolygon, '{"type":"MultiPolygon","coordinates":[[[[1,2],[3,4],[5,6],[1,2]]],[[[1,2],[3,4],[5,6],[1,2]]]]}']);
|
||||
serialize_tests.push([ [ serialize_tests[0][0] ], '{"type":"FeatureCollection","members":[{"type":"Feature","id":0,"properties":{},"geometry":{"type":"Point","coordinates":[1,2]}}]}' ]);
|
||||
serialize_tests.push([ [ serialize_tests[1][0], serialize_tests[2][0] ], '{"type":"GeometryCollection","members":[{"type":"Point","coordinates":[1,2]},{"type":"MultiPoint","coordinates":[[1,2]]}]}' ]);
|
||||
for (var i = 0; i < serialize_tests.length; i++) {
|
||||
var input = serialize_tests[i][0];
|
||||
var output = serialize_tests[i][1];
|
||||
test_out = parser.write(input);
|
||||
t.eq(test_out, output, "Serializing " + input.toString() + " saved correctly.");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function test_Format_GeoJSON_read_object(t) {
|
||||
t.plan(1);
|
||||
var line_object = {"type": "FeatureCollection",
|
||||
"members": [{"geometry":
|
||||
{"type": "LineString",
|
||||
"coordinates": [[-27.0703125, 59.4140625],
|
||||
[-77.6953125, 20.7421875],
|
||||
[30.5859375, -36.2109375],
|
||||
[67.1484375, 34.8046875]]},
|
||||
"type": "Feature",
|
||||
"id": 559,
|
||||
"properties":
|
||||
{
|
||||
"strokeColor": "red",
|
||||
"title": "Feature 1",
|
||||
"author": "Your Name Here"}}]};
|
||||
data = parser.read(line_object);
|
||||
t.eq(data[0].fid, 559, "Can read data from an object correctly.");
|
||||
}
|
||||
|
||||
function test_Format_GeoJSON_read_attributes(t) {
|
||||
t.plan(3);
|
||||
var parser = new OpenLayers.Format.GeoJSON();
|
||||
data = parser.read(line_feature);
|
||||
t.eq(data[0].attributes['strokeColor'], 'red', 'read strokeColor attribute properly');
|
||||
t.eq(data[0].attributes['title'], 'Feature 1', 'read title attribute properly');
|
||||
t.eq(data[0].attributes['author'], 'Your Name Here', 'read author attribute properly');
|
||||
}
|
||||
|
||||
// -->
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
</body>
|
||||
</html>
|
||||
41
tests/Format/test_JSON.html
Normal file
41
tests/Format/test_JSON.html
Normal file
@@ -0,0 +1,41 @@
|
||||
<html>
|
||||
<head>
|
||||
<script src="../../lib/OpenLayers.js"></script>
|
||||
<script type="text/javascript"><!--
|
||||
|
||||
|
||||
|
||||
function test_Format_JSON_constructor(t) {
|
||||
t.plan(4);
|
||||
|
||||
var options = {'foo': 'bar'};
|
||||
var format = new OpenLayers.Format.JSON(options);
|
||||
t.ok(format instanceof OpenLayers.Format.JSON,
|
||||
"new OpenLayers.Format.JSON returns object" );
|
||||
t.eq(format.foo, "bar", "constructor sets options correctly");
|
||||
t.eq(typeof format.read, "function", "format has a read function");
|
||||
t.eq(typeof format.write, "function", "format has a write function");
|
||||
}
|
||||
function test_Format_JSON_parser(t) {
|
||||
t.plan(2);
|
||||
|
||||
var format = new OpenLayers.Format.JSON();
|
||||
var data = format.read('{"a":["b"], "c":1}');
|
||||
var obj = {"a":["b"], "c":1};
|
||||
t.eq(obj['a'], data['a'], "element with array parsed correctly.");
|
||||
t.eq(obj['c'], data['c'], "element with number parsed correctly.");
|
||||
}
|
||||
function test_Format_JSON_writer(t) {
|
||||
t.plan(1);
|
||||
|
||||
var format = new OpenLayers.Format.JSON();
|
||||
var data = format.write({"a":["b"], "c":1});
|
||||
var obj = '{"a":["b"],"c":1}';
|
||||
t.eq(data, obj, "writing data to json works.");
|
||||
}
|
||||
// -->
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
</body>
|
||||
</html>
|
||||
@@ -22,6 +22,8 @@
|
||||
<li>test_Format.html</li>
|
||||
<li>Format/test_XML.html</li>
|
||||
<li>Format/test_GeoRSS.html</li>
|
||||
<li>Format/test_JSON.html</li>
|
||||
<li>Format/test_GeoJSON.html</li>
|
||||
<li>Format/test_GML.html</li>
|
||||
<li>Format/test_WKT.html</li>
|
||||
<li>test_Icon.html</li>
|
||||
|
||||
Reference in New Issue
Block a user