From f50d1c85d8fb17eee1e2f2b9e892559d3ec5e078 Mon Sep 17 00:00:00 2001 From: pgiraud Date: Thu, 15 Sep 2011 12:27:56 +0000 Subject: [PATCH] Adding support for write in the GPX format, r=marcjansen, (Closes #3495) git-svn-id: http://svn.openlayers.org/trunk/openlayers@12370 dc9f47b5-9b13-0410-9fdd-eb0c1a62fdaf --- examples/vector-formats.html | 7 +- lib/OpenLayers/Format/GPX.js | 181 +++++++++++++++++++++++++++++++++++ tests/Format/GPX.html | 79 +++++++++++++++ 3 files changed, 265 insertions(+), 2 deletions(-) diff --git a/examples/vector-formats.html b/examples/vector-formats.html index 7848cf3d9e..97b51c7d2f 100644 --- a/examples/vector-formats.html +++ b/examples/vector-formats.html @@ -86,7 +86,8 @@ gml2: new OpenLayers.Format.GML.v2(gmlOptionsIn), gml3: new OpenLayers.Format.GML.v3(gmlOptionsIn), kml: new OpenLayers.Format.KML(kmlOptionsIn), - atom: new OpenLayers.Format.Atom(in_options) + atom: new OpenLayers.Format.Atom(in_options), + gpx: new OpenLayers.Format.GPX(in_options) }, 'out': { wkt: new OpenLayers.Format.WKT(out_options), @@ -95,7 +96,8 @@ gml2: new OpenLayers.Format.GML.v2(gmlOptionsOut), gml3: new OpenLayers.Format.GML.v3(gmlOptionsOut), kml: new OpenLayers.Format.KML(out_options), - atom: new OpenLayers.Format.Atom(out_options) + atom: new OpenLayers.Format.Atom(out_options), + gpx: new OpenLayers.Format.GPX(out_options) } }; } @@ -199,6 +201,7 @@

Vector Formats Example

+   diff --git a/lib/OpenLayers/Format/GPX.js b/lib/OpenLayers/Format/GPX.js index 63170feea3..2344de9e53 100644 --- a/lib/OpenLayers/Format/GPX.js +++ b/lib/OpenLayers/Format/GPX.js @@ -20,6 +20,16 @@ * - */ OpenLayers.Format.GPX = OpenLayers.Class(OpenLayers.Format.XML, { + + + /** + * APIProperty: defaultDesc + * {String} Default description for the waypoints/tracks in the case + * where the feature has no "description" attribute. + * Default is "No description available". + */ + defaultDesc: "No description available", + /** * APIProperty: extractWaypoints * {Boolean} Extract waypoints from GPX. (default: true) @@ -45,6 +55,13 @@ OpenLayers.Format.GPX = OpenLayers.Class(OpenLayers.Format.XML, { * be extracted. */ extractAttributes: true, + + /** + * APIProperty: gpxns + * {String} GPX namespace to use. Defaults to + * "http://www.topografix.com/GPX/1/1" + */ + gpxns: "http://www.topografix.com/GPX/1/1", /** * Constructor: OpenLayers.Format.GPX @@ -179,6 +196,170 @@ OpenLayers.Format.GPX = OpenLayers.Class(OpenLayers.Format.XML, { } return attributes; }, + + /** + * APIMethod: write + * Accepts Feature Collection, and returns a string. + * + * Parameters: + * features - {Array()} List of features to serialize into a string. + * metadata - {Object} A key/value pairs object to build a metadata node to + * add to the gpx. Supported keys are 'name', 'desc', 'author'. + */ + write: function(features, metadata) { + var gpx; + features = OpenLayers.Util.isArray(features) ? + features : [features]; + gpx = this.createElementNS(this.gpxns, "gpx"); + + for(var i=0, len=features.length; i, and builds a node for it. + * + * Parameters: + * feature - {} + * + * Returns: + * {DOMElement} - The created node, either a 'wpt' or a 'trk'. + */ + buildFeatureNode: function(feature) { + var geometry = feature.geometry; + geometry = geometry.clone(); + if (this.internalProjection && this.externalProjection) { + geometry.transform(this.internalProjection, + this.externalProjection); + } + if (geometry.CLASS_NAME == "OpenLayers.Geometry.Point") { + var wpt = this.buildWptNode(feature); + return wpt; + } else { + var trkNode = this.createElementNS(this.gpxns, "trk"); + this.appendAttributesNode(trkNode, feature); + var trkSegNodes = this.buildTrkSegNode(geometry); + trkSegNodes = OpenLayers.Util.isArray(trkSegNodes) ? + trkSegNodes : [trkSegNodes]; + for (var i = 0, len = trkSegNodes.length; i < len; i++) { + trkNode.appendChild(trkSegNodes[i]); + } + return trkNode; + } + }, + + /** + * Method: buildTrkSegNode + * Builds trkseg node(s) given a geometry + * + * Parameters: + * trknode + * geometry - {OpenLayers.Geometry} + */ + buildTrkSegNode: function(geometry) { + var node, + i, + len, + point, + nodes; + if (geometry.CLASS_NAME == "OpenLayers.Geometry.LineString" || + geometry.CLASS_NAME == "OpenLayers.Geometry.LinearRing") { + node = this.createElementNS(this.gpxns, "trkseg"); + for (i = 0, len=geometry.components.length; i < len; i++) { + point = geometry.components[i]; + node.appendChild(this.buildTrkPtNode(point)); + } + return node; + } else { + nodes = []; + for (i = 0, len = geometry.components.length; i < len; i++) { + nodes.push(this.buildTrkSegNode(geometry.components[i])); + } + return nodes; + } + }, + /** + * Method: buildTrkPtNode + * Builds a trkpt node given a point + * + * Parameters: + * line - {OpenLayers.Geometry.Point} + * + * Returns: + * {DOMElement} A trkpt node + */ + buildTrkPtNode: function(point) { + var node = this.createElementNS(this.gpxns, "trkpt"); + node.setAttribute("lon", point.x); + node.setAttribute("lat", point.y); + return node; + }, + + /** + * Method: buildWptNode + * Builds a wpt node given a point + * + * Parameters: + * feature - {OpenLayers.Feature.Vector} + * + * Returns: + * {DOMElement} A wpt node + */ + buildWptNode: function(feature) { + var node = this.createElementNS(this.gpxns, "wpt"); + node.setAttribute("lon", feature.geometry.x); + node.setAttribute("lat", feature.geometry.y); + this.appendAttributesNode(node, feature); + return node; + }, + + /** + * Method: appendAttributesNode + * Adds some attributes node. + * + * Parameters: + * node - {DOMElement} the node to append the attribute nodes to. + * feature - {OpenLayers.Feature.Vector} + */ + appendAttributesNode: function(node, feature) { + var name = this.createElementNS(this.gpxns, 'name'); + name.appendChild(this.createTextNode( + feature.attributes.name || feature.id)); + node.appendChild(name); + var desc = this.createElementNS(this.gpxns, 'desc'); + desc.appendChild(this.createTextNode( + feature.attributes.description || this.defaultDesc)); + node.appendChild(desc); + // TBD - deal with remaining (non name/description) attributes. + }, + CLASS_NAME: "OpenLayers.Format.GPX" }); diff --git a/tests/Format/GPX.html b/tests/Format/GPX.html index 0bf897d8d7..2b88e7a9de 100644 --- a/tests/Format/GPX.html +++ b/tests/Format/GPX.html @@ -34,6 +34,85 @@ t.eq(features[2].attributes['name'], "Mark", "Text attribute node read correctly."); t.eq(features[2].attributes['sym'], "Flag", "CDATA attribute node read correctly."); } + function test_Format_GPX_serialize_points(t) { + t.plan(1); + + var parser = new OpenLayers.Format.GPX(); + + var point = new OpenLayers.Geometry.Point(-111.04, 45.68); + var point2 = new OpenLayers.Geometry.Point(-112.04, 45.68); + var features = [ + new OpenLayers.Feature.Vector(point, {name: 'foo', description: 'bar'}), + new OpenLayers.Feature.Vector(point2, {name: 'foo', description: 'bar'}) + ]; + var data = parser.write(features); + t.xml_eq(data, 'foobarfoobar', 'GPX serializes points correctly'); + } + function test_Format_GPX_serialize_line(t) { + t.plan(1); + + var parser = new OpenLayers.Format.GPX(); + + var point = new OpenLayers.Geometry.Point(-111.04, 45.68); + var point2 = new OpenLayers.Geometry.Point(-112.04, 45.68); + var line = new OpenLayers.Geometry.LineString([point, point2]); + var f = new OpenLayers.Feature.Vector(line, {name: 'foo', description: 'bar'}); + var data = parser.write(f); + t.xml_eq(data, 'foobar', 'GPX serializes line correctly'); + } + function test_Format_GPX_serialize_lines(t) { + t.plan(1); + + var parser = new OpenLayers.Format.GPX(); + + var point = new OpenLayers.Geometry.Point(-111.04, 45.68); + var point2 = new OpenLayers.Geometry.Point(-112.04, 45.68); + var line = new OpenLayers.Geometry.LineString([point, point2]); + var point3 = new OpenLayers.Geometry.Point(1, 2); + var point4 = new OpenLayers.Geometry.Point(3, 4); + var line2 = new OpenLayers.Geometry.LineString([point3, point4]); + var f = new OpenLayers.Feature.Vector(line, {name: 'foo', description: 'bar'}); + var f2 = new OpenLayers.Feature.Vector(line2, {name: 'dude', description: 'truite'}); + var data = parser.write([f, f2]); + t.xml_eq(data, 'foobardudetruite', 'GPX serializes lines correctly'); + } + function test_Format_GPX_serialize_multiline(t) { + t.plan(1); + + var parser = new OpenLayers.Format.GPX(); + + var point = new OpenLayers.Geometry.Point(-111.04, 45.68); + var point2 = new OpenLayers.Geometry.Point(-112.04, 45.68); + var line = new OpenLayers.Geometry.LineString([point, point2]); + var point3 = new OpenLayers.Geometry.Point(1, 2); + var point4 = new OpenLayers.Geometry.Point(3, 4); + var line2 = new OpenLayers.Geometry.LineString([point3, point4]); + var multiline = new OpenLayers.Geometry.MultiLineString([line, line2]); + var f = new OpenLayers.Feature.Vector(multiline, {name: 'foo', description: 'bar'}); + var data = parser.write([f]); + t.xml_eq(data, 'foobar', 'GPX serializes multiline correctly'); + } + function test_Format_GPX_serialize_polygon(t) { + t.plan(1); + + var parser = new OpenLayers.Format.GPX(); + + var point = new OpenLayers.Geometry.Point(-111.04, 45.68); + var point2 = new OpenLayers.Geometry.Point(-112.04, 45.68); + var linearRing = new OpenLayers.Geometry.LinearRing([point, point2, point.clone()]); + var polygon = new OpenLayers.Geometry.Polygon([linearRing]); + var f = new OpenLayers.Feature.Vector(polygon, {name: 'foo', description: 'bar'}); + var data = parser.write([f]); + t.xml_eq(data, 'foobar', 'GPX serializes polygon correctly'); + } + function test_Format_GPX_serialize_metadata(t) { + t.plan(1); + + var parser = new OpenLayers.Format.GPX(); + + var data = parser.write([], {name: 'foo', desc: 'bar'}); + t.xml_eq(data, 'foobar', 'GPX serializes metadata correctly'); + }