diff --git a/examples/data/gpx/yahoo.xml b/examples/data/gpx/fells_loop.gpx similarity index 95% rename from examples/data/gpx/yahoo.xml rename to examples/data/gpx/fells_loop.gpx index ccaa9bc5cc..d8a1df557e 100644 --- a/examples/data/gpx/yahoo.xml +++ b/examples/data/gpx/fells_loop.gpx @@ -1,1073 +1,1077 @@ - - - - - - 44.586548 - - 5066 - - Crossing - - - - 57.607200 - - 5067 - - Dot - - - - 44.826904 - - 5096 - - Dot - - - - 50.594727 - - 5142 - - Dot - - - - 127.711200 - - 5156 - - Dot - - - - 96.926400 - - 5224 - - Dot - - - - 82.600800 - - 5229 - - Dot - - - - 82.905600 - - 5237 - - Dot - - - - 66.696655 - - 5254 - - Dot - - - - 74.627442 - - 5258 - - Dot - - - - 65.254761 - - 5264 - - Dot - - - - 77.419200 - - 526708 - - Dot - - - - 74.676000 - - 526750 - - Dot - - - - 78.713135 - - 527614 - - Dot - - - - 78.713135 - - 527631 - - Dot - - - - 68.275200 - - 5278 - - Dot - - - - 64.008000 - - 5289 - - Dot - - - - 52.997925 - - 5374FIRE - - Dot - - - - 56.388000 - - 5376 - - Dot - - - - 56.388000 - - 6006 - - Dot - - - - 46.028564 - - 6006BLUE - - Dot - - - - 37.616943 - - 6014MEADOW - - Dot - - - - 56.388000 - - 6029 - - Dot - - - - 50.292000 - - 6053 - - Dot - - - - 25.603200 - - 6066 - - Dot - - - - 34.442400 - - 6067 - - Dot - - - - 30.480000 - - 6071 - - Dot - - - - 15.240000 - - 6073 - - Dot - - - - 37.795200 - - 6084 - - Dot - - - - 64.008000 - - 6130 - - Dot - - - - 64.008000 - - 6131 - - Dot - - - - 62.788800 - - 6153 - - Dot - - - - 55.473600 - - 6171 - - Dot - - - - 62.484000 - - 6176 - - Dot - - - - 62.179200 - - 6177 - - Dot - - - - 69.799200 - - 6272 - - Dot - - - - 73.152000 - - 6272 - - Dot - - - - 70.104000 - - 6278 - - Dot - - - - 57.564209 - - 6280 - - Dot - - - - 66.696655 - - 6283 - - Dot - - - - 72.945191 - - 6289 - - Dot - - - - 72.847200 - - 6297 - - Dot - - - - 53.644800 - - 6328 - - Dot - - - - 43.891200 - - 6354 - - Dot - - - - 48.768000 - - 635722 - - Dot - - - - 49.072800 - - 635783 - - Dot - - - - 62.484000 - - 6373 - - Dot - - - - 3.962400 - - 6634 - - Dot - - - - 13.411200 - - 6979 - - Dot - - - - 34.012085 - - 6997 - - Dot - - - - 87.782400 - - BEAR HILL - BEAR HILL TOWER - - Tall Tower - - - - 23.469600 - - BELLEVUE - BELLEVUE - - Parking Area - - - - 43.384766 - - 6016 - - Trailhead - - - - 89.916000 - - 5236BRIDGE - - Bridge - - - - 55.473600 - - 5376BRIDGE - - Bridge - - - - 52.730400 - - 6181CROSS - - Crossing - - - - 45.110400 - - 6042CROSS - - Crossing - - - - DARKHOLLPO - - Fishing Area - - - 56.083200 - - 6121DEAD - - Danger Area - - - - 117.043200 - - 5179DEAD - - Danger Area - - - - 69.494400 - - 5299DEAD - - Danger Area - - - - 56.997600 - - 5376DEAD - - Danger Area - - - - 46.939200 - - 6353DEAD - - Danger Area - - - - 61.264800 - - 6155DEAD - - Danger Area - - - - 110.947200 - - GATE14 - - Truck Stop - - - - 77.724000 - - GATE16 - - Truck Stop - - - - 65.836800 - - GATE17 - - Truck Stop - - - - 57.302400 - - GATE19 - - Truck Stop - - - - 49.377600 - - GATE21 - - Truck Stop - - - - 81.076800 - - GATE24 - - Truck Stop - - - - 21.515015 - - GATE5 - - Truck Stop - - - - 26.561890 - - GATE6 - - Trailhead - - - - 32.004000 - - 6077LOGS - - Amusement Park - - - - 119.809082 - - 5148NANEPA - - Trailhead - - - - 73.761600 - - 5267OBSTAC - - Amusement Park - - - - 45.307495 - - PANTHRCAVE - - Tunnel - - - - 77.992066 - - 5252PURPLE - - Summit - - - - 67.970400 - - 5287WATER - - Swimming Area - - - - 81.076800 - - 5239ROAD - - Truck Stop - - - - 67.360800 - - 5278ROAD - - Truck Stop - - - - 53.949600 - - 5058ROAD - ROAD CROSSING - - Dot - - - - 69.799200 - - SHEEPFOLD - - Parking Area - - - - 64.008000 - - SOAPBOX - - Cemetery - - - - 64.533692 - - 5376STREAM - - Bridge - - - - 61.649902 - - 5144SUMMIT - - Summit - - - - 67.360800 - - 5150TANK - WATER TANK - - Museum - - - - BELLEVUE - - 1 - - 23.469600 - - BELLEVUE - BELLEVUE - - Parking Area - - - - 26.561890 - - GATE6 - - Trailhead - - - - 45.307495 - - PANTHRCAVE - - Tunnel - - - - 37.616943 - - 6014MEADOW - - Dot - - - - 56.388000 - - 6006 - - Dot - - - - 46.028564 - - 6006BLUE - - Dot - - - - 44.826904 - - 5096 - - Dot - - - - 44.586548 - - 5066 - - Crossing - - - - 57.607200 - - 5067 - - Dot - - - - 53.949600 - - 5058ROAD - ROAD CROSSING - - Dot - - - - 67.360800 - - 5150TANK - WATER TANK - - Museum - - - - 50.594727 - - 5142 - - Dot - - - - 61.649902 - - 5144SUMMIT - - Summit - - - - 127.711200 - - 5156 - - Dot - - - - 119.809082 - - 5148NANEPA - - Trailhead - - - - 74.627442 - - 5258 - - Dot - - - - 77.992066 - - 5252PURPLE - - Summit - - - - 78.713135 - - 527631 - - Dot - - - - 78.713135 - - 527614 - - Dot - - - - 73.761600 - - 5267OBSTAC - - Amusement Park - - - - 68.275200 - - 5278 - - Dot - - - - 64.008000 - - 5289 - - Dot - - - - 52.997925 - - 5374FIRE - - Dot - - - - 56.388000 - - 5376 - - Dot - - - - 64.533692 - - 5376STREAM - - Bridge - - - - 53.644800 - - 6328 - - Dot - - - - 48.768000 - - 635722 - - Dot - - - - 49.072800 - - 635783 - - Dot - - - - 62.484000 - - 6373 - - Dot - - - - 87.782400 - - BEAR HILL - BEAR HILL TOWER - - Tall Tower - - - - 72.945191 - - 6289 - - Dot - - - - 72.847200 - - 6297 - - Dot - - - - 66.696655 - - 6283 - - Dot - - - - 57.564209 - - 6280 - - Dot - - - - 62.179200 - - 6177 - - Dot - - - - 62.484000 - - 6176 - - Dot - - - - 62.788800 - - 6153 - - Dot - - - - 55.473600 - - 6171 - - Dot - - - - 64.008000 - - 6131 - - Dot - - - - 64.008000 - - 6130 - - Dot - - - - 56.388000 - - 6029 - - Dot - - - - 56.388000 - - 6006 - - Dot - - - - 37.616943 - - 6014MEADOW - - Dot - - - - 45.307495 - - PANTHRCAVE - - Tunnel - - - - 26.561890 - - GATE6 - - Trailhead - - - - 23.469600 - - BELLEVUE - BELLEVUE - - Parking Area - - - - - + + + + + + 44.586548 + + 5066 + + Crossing + + + + 57.607200 + + 5067 + + Dot + + + + 44.826904 + + 5096 + + Dot + + + + 50.594727 + + 5142 + + Dot + + + + 127.711200 + + 5156 + + Dot + + + + 96.926400 + + 5224 + + Dot + + + + 82.600800 + + 5229 + + Dot + + + + 82.905600 + + 5237 + + Dot + + + + 66.696655 + + 5254 + + Dot + + + + 74.627442 + + 5258 + + Dot + + + + 65.254761 + + 5264 + + Dot + + + + 77.419200 + + 526708 + + Dot + + + + 74.676000 + + 526750 + + Dot + + + + 78.713135 + + 527614 + + Dot + + + + 78.713135 + + 527631 + + Dot + + + + 68.275200 + + 5278 + + Dot + + + + 64.008000 + + 5289 + + Dot + + + + 52.997925 + + 5374FIRE + + Dot + + + + 56.388000 + + 5376 + + Dot + + + + 56.388000 + + 6006 + + Dot + + + + 46.028564 + + 6006BLUE + + Dot + + + + 37.616943 + + 6014MEADOW + + Dot + + + + 56.388000 + + 6029 + + Dot + + + + 50.292000 + + 6053 + + Dot + + + + 25.603200 + + 6066 + + Dot + + + + 34.442400 + + 6067 + + Dot + + + + 30.480000 + + 6071 + + Dot + + + + 15.240000 + + 6073 + + Dot + + + + 37.795200 + + 6084 + + Dot + + + + 64.008000 + + 6130 + + Dot + + + + 64.008000 + + 6131 + + Dot + + + + 62.788800 + + 6153 + + Dot + + + + 55.473600 + + 6171 + + Dot + + + + 62.484000 + + 6176 + + Dot + + + + 62.179200 + + 6177 + + Dot + + + + 69.799200 + + 6272 + + Dot + + + + 73.152000 + + 6272 + + Dot + + + + 70.104000 + + 6278 + + Dot + + + + 57.564209 + + 6280 + + Dot + + + + 66.696655 + + 6283 + + Dot + + + + 72.945191 + + 6289 + + Dot + + + + 72.847200 + + 6297 + + Dot + + + + 53.644800 + + 6328 + + Dot + + + + 43.891200 + + 6354 + + Dot + + + + 48.768000 + + 635722 + + Dot + + + + 49.072800 + + 635783 + + Dot + + + + 62.484000 + + 6373 + + Dot + + + + 3.962400 + + 6634 + + Dot + + + + 13.411200 + + 6979 + + Dot + + + + 34.012085 + + 6997 + + Dot + + + + 87.782400 + + BEAR HILL + BEAR HILL TOWER + + Tall Tower + + + + 23.469600 + + BELLEVUE + BELLEVUE + + Parking Area + + + + 43.384766 + + 6016 + + Trailhead + + + + 89.916000 + + 5236BRIDGE + + Bridge + + + + 55.473600 + + 5376BRIDGE + + Bridge + + + + 52.730400 + + 6181CROSS + + Crossing + + + + 45.110400 + + 6042CROSS + + Crossing + + + + DARKHOLLPO + + Fishing Area + + + 56.083200 + + 6121DEAD + + Danger Area + + + + 117.043200 + + 5179DEAD + + Danger Area + + + + 69.494400 + + 5299DEAD + + Danger Area + + + + 56.997600 + + 5376DEAD + + Danger Area + + + + 46.939200 + + 6353DEAD + + Danger Area + + + + 61.264800 + + 6155DEAD + + Danger Area + + + + 110.947200 + + GATE14 + + Truck Stop + + + + 77.724000 + + GATE16 + + Truck Stop + + + + 65.836800 + + GATE17 + + Truck Stop + + + + 57.302400 + + GATE19 + + Truck Stop + + + + 49.377600 + + GATE21 + + Truck Stop + + + + 81.076800 + + GATE24 + + Truck Stop + + + + 21.515015 + + GATE5 + + Truck Stop + + + + 26.561890 + + GATE6 + + Trailhead + + + + 32.004000 + + 6077LOGS + + Amusement Park + + + + 119.809082 + + 5148NANEPA + + Trailhead + + + + 73.761600 + + 5267OBSTAC + + Amusement Park + + + + 45.307495 + + PANTHRCAVE + + Tunnel + + + + 77.992066 + + 5252PURPLE + + Summit + + + + 67.970400 + + 5287WATER + + Swimming Area + + + + 81.076800 + + 5239ROAD + + Truck Stop + + + + 67.360800 + + 5278ROAD + + Truck Stop + + + + 53.949600 + + 5058ROAD + ROAD CROSSING + + Dot + + + + 69.799200 + + SHEEPFOLD + + Parking Area + + + + 64.008000 + + SOAPBOX + + Cemetery + + + + 64.533692 + + 5376STREAM + + Bridge + + + + 61.649902 + + 5144SUMMIT + + Summit + + + + 67.360800 + + 5150TANK + WATER TANK + + Museum + + + + BELLEVUE + + 1 + + 23.469600 + + BELLEVUE + BELLEVUE + + Parking Area + + + + 26.561890 + + GATE6 + + Trailhead + + + + 45.307495 + + PANTHRCAVE + + Tunnel + + + + 37.616943 + + 6014MEADOW + + Dot + + + + 56.388000 + + 6006 + + Dot + + + + 46.028564 + + 6006BLUE + + Dot + + + + 44.826904 + + 5096 + + Dot + + + + 44.586548 + + 5066 + + Crossing + + + + 57.607200 + + 5067 + + Dot + + + + 53.949600 + + 5058ROAD + ROAD CROSSING + + Dot + + + + 67.360800 + + 5150TANK + WATER TANK + + Museum + + + + 50.594727 + + 5142 + + Dot + + + + 61.649902 + + 5144SUMMIT + + Summit + + + + 127.711200 + + 5156 + + Dot + + + + 119.809082 + + 5148NANEPA + + Trailhead + + + + 74.627442 + + 5258 + + Dot + + + + 77.992066 + + 5252PURPLE + + Summit + + + + 78.713135 + + 527631 + + Dot + + + + 78.713135 + + 527614 + + Dot + + + + 73.761600 + + 5267OBSTAC + + Amusement Park + + + + 68.275200 + + 5278 + + Dot + + + + 64.008000 + + 5289 + + Dot + + + + 52.997925 + + 5374FIRE + + Dot + + + + 56.388000 + + 5376 + + Dot + + + + 64.533692 + + 5376STREAM + + Bridge + + + + 53.644800 + + 6328 + + Dot + + + + 48.768000 + + 635722 + + Dot + + + + 49.072800 + + 635783 + + Dot + + + + 62.484000 + + 6373 + + Dot + + + + 87.782400 + + BEAR HILL + BEAR HILL TOWER + + Tall Tower + + + + 72.945191 + + 6289 + + Dot + + + + 72.847200 + + 6297 + + Dot + + + + 66.696655 + + 6283 + + Dot + + + + 57.564209 + + 6280 + + Dot + + + + 62.179200 + + 6177 + + Dot + + + + 62.484000 + + 6176 + + Dot + + + + 62.788800 + + 6153 + + Dot + + + + 55.473600 + + 6171 + + Dot + + + + 64.008000 + + 6131 + + Dot + + + + 64.008000 + + 6130 + + Dot + + + + 56.388000 + + 6029 + + Dot + + + + 56.388000 + + 6006 + + Dot + + + + 37.616943 + + 6014MEADOW + + Dot + + + + 45.307495 + + PANTHRCAVE + + Tunnel + + + + 26.561890 + + GATE6 + + Trailhead + + + + 23.469600 + + BELLEVUE + BELLEVUE + + Parking Area + + + + \ No newline at end of file diff --git a/examples/data/gpx/gpx4j.xml b/examples/data/gpx/gpx4j.xml deleted file mode 100644 index 7c58942267..0000000000 --- a/examples/data/gpx/gpx4j.xml +++ /dev/null @@ -1,37 +0,0 @@ - - - - 290311 - (null) - - - 126.951324 - - - - 122.974365 - - - - 122.974365 - - - - 120.310211 - - - - 117.177261 - - - - 116.083771 - - - - 115.956726 - - - - - diff --git a/examples/drag-and-drop.html b/examples/drag-and-drop.html index 7a87401793..96b881a317 100644 --- a/examples/drag-and-drop.html +++ b/examples/drag-and-drop.html @@ -31,11 +31,11 @@

Drag-and-Drop example

-

Example of using the drag-and-drop interaction. Drag and drop KML files on to the map.

+

Example of using the drag-and-drop interaction. Drag and drop GPX, GeoJSON, IGC, KML, or TopoJSON files on to the map.

See the drag-and-drop.js source to see how this is done.

-
drag-and-drop, kml
+
drag-and-drop, gpx, geojson, igc, kml, topojson
diff --git a/examples/drag-and-drop.js b/examples/drag-and-drop.js index dc79f50a73..ce8d40780d 100644 --- a/examples/drag-and-drop.js +++ b/examples/drag-and-drop.js @@ -1,19 +1,98 @@ goog.require('ol.Map'); goog.require('ol.RendererHint'); goog.require('ol.View2D'); +goog.require('ol.format.GPX'); +goog.require('ol.format.GeoJSON'); +goog.require('ol.format.IGC'); goog.require('ol.format.KML'); +goog.require('ol.format.TopoJSON'); goog.require('ol.interaction'); goog.require('ol.interaction.DragAndDrop'); goog.require('ol.layer.Tile'); goog.require('ol.source.BingMaps'); +goog.require('ol.style.Circle'); +goog.require('ol.style.Fill'); +goog.require('ol.style.Stroke'); +goog.require('ol.style.Style'); +var defaultStyle = { + 'Point': [new ol.style.Style({ + image: new ol.style.Circle({ + fill: new ol.style.Fill({ + color: 'rgba(255,255,0,0.5)' + }), + radius: 5, + stroke: new ol.style.Stroke({ + color: '#ff0', + width: 1 + }) + }) + })], + 'LineString': [new ol.style.Style({ + stroke: new ol.style.Stroke({ + color: '#f00', + width: 3 + }) + })], + 'Polygon': [new ol.style.Style({ + fill: new ol.style.Fill({ + color: 'rgba(0,255,255,0.5)' + }), + stroke: new ol.style.Stroke({ + color: '#0ff', + width: 1 + }) + })], + 'MultiPoint': [new ol.style.Style({ + image: new ol.style.Circle({ + fill: new ol.style.Fill({ + color: 'rgba(255,0,255,0.5)' + }), + radius: 5, + stroke: new ol.style.Stroke({ + color: '#f0f', + width: 1 + }) + }) + })], + 'MultiLineString': [new ol.style.Style({ + stroke: new ol.style.Stroke({ + color: '#0f0', + width: 3 + }) + })], + 'MultiPolygon': [new ol.style.Style({ + fill: new ol.style.Fill({ + color: 'rgba(0,0,255,0.5)' + }), + stroke: new ol.style.Stroke({ + color: '#00f', + width: 1 + }) + })] +}; + +var styleFunction = function(feature, resolution) { + var featureStyleFunction = feature.getStyleFunction(); + if (featureStyleFunction) { + return featureStyleFunction.call(feature, resolution); + } else { + return defaultStyle[feature.getGeometry().getType()]; + } +}; + var map = new ol.Map({ interactions: ol.interaction.defaults().extend([ new ol.interaction.DragAndDrop({ formatConstructors: [ - ol.format.KML - ] + ol.format.GPX, + ol.format.GeoJSON, + ol.format.IGC, + ol.format.KML, + ol.format.TopoJSON + ], + styleFunction: styleFunction }) ]), layers: [ diff --git a/examples/gpx.html b/examples/gpx.html new file mode 100644 index 0000000000..6e12988b2b --- /dev/null +++ b/examples/gpx.html @@ -0,0 +1,55 @@ + + + + + + + + + + GPX example + + + + + +
+ +
+
+
+
+
+ +
+ +
+

GPX example

+

Example of using the GPX source.

+
+

See the gpx.js source to see how this is done.

+
+
GPX
+
+
+
+   +
+
+ +
+ +
+ + + + + + + diff --git a/examples/gpx.js b/examples/gpx.js new file mode 100644 index 0000000000..181f5b56a7 --- /dev/null +++ b/examples/gpx.js @@ -0,0 +1,94 @@ +goog.require('ol.Map'); +goog.require('ol.RendererHint'); +goog.require('ol.View2D'); +goog.require('ol.layer.Tile'); +goog.require('ol.layer.Vector'); +goog.require('ol.source.BingMaps'); +goog.require('ol.source.GPX'); +goog.require('ol.style.Circle'); +goog.require('ol.style.Fill'); +goog.require('ol.style.Stroke'); +goog.require('ol.style.Style'); + +var raster = new ol.layer.Tile({ + source: new ol.source.BingMaps({ + imagerySet: 'Aerial', + key: 'Ak-dzM4wZjSqTlzveKz5u0d4IQ4bRzVI309GxmkgSVr1ewS6iPSrOvOKhA-CJlm3' + }) +}); + +var style = { + 'Point': [new ol.style.Style({ + image: new ol.style.Circle({ + fill: new ol.style.Fill({ + color: 'rgba(255,255,0,0.4)' + }), + radius: 5, + stroke: new ol.style.Stroke({ + color: '#ff0', + width: 1 + }) + }) + })], + 'LineString': [new ol.style.Style({ + stroke: new ol.style.Stroke({ + color: '#f00', + width: 3 + }) + })], + 'MultiLineString': [new ol.style.Style({ + stroke: new ol.style.Stroke({ + color: '#0f0', + width: 3 + }) + })] +}; + +var vector = new ol.layer.Vector({ + source: new ol.source.GPX({ + reprojectTo: 'EPSG:3857', + url: 'data/gpx/fells_loop.gpx' + }), + styleFunction: function(feature, resolution) { + return style[feature.getGeometry().getType()]; + } +}); + +var map = new ol.Map({ + layers: [raster, vector], + renderer: ol.RendererHint.CANVAS, + target: document.getElementById('map'), + view: new ol.View2D({ + center: [-7916041.528716288, 5228379.045749711], + zoom: 12 + }) +}); + +var displayFeatureInfo = function(pixel) { + var features = []; + map.forEachFeatureAtPixel(pixel, function(feature, layer) { + features.push(feature); + }); + if (features.length > 0) { + var info = []; + var i, ii; + for (i = 0, ii = features.length; i < ii; ++i) { + info.push(features[i].get('desc')); + } + document.getElementById('info').innerHTML = info.join(', ') || '(unknown)'; + map.getTarget().style.cursor = 'pointer'; + } else { + document.getElementById('info').innerHTML = ' '; + map.getTarget().style.cursor = ''; + } +}; + +$(map.getViewport()).on('mousemove', function(evt) { + var pixel = map.getEventPixel(evt.originalEvent); + displayFeatureInfo(pixel); +}); + +map.on('singleclick', function(evt) { + var pixel = evt.getPixel(); + displayFeatureInfo(pixel); +}); diff --git a/src/objectliterals.jsdoc b/src/objectliterals.jsdoc index 20bc1e9ac5..9cbdc7efbd 100644 --- a/src/objectliterals.jsdoc +++ b/src/objectliterals.jsdoc @@ -291,6 +291,8 @@ * features will be added to this layer's source. If neither `source` nor * `layer` are defined then the dropped features will be added as a new * layer. + * @property {ol.feature.StyleFunction|undefined} styleFunction Style function. + * This is used to configure any new layers created. */ /** @@ -554,6 +556,20 @@ * @property {Array.|undefined} urls URLs. */ +/** + * @typedef {Object} olx.source.GPXOptions + * @property {Array.|undefined} attributions Attributions. + * @property {Document|undefined} doc Document. + * @property {ol.Extent|undefined} extent Extent. + * @property {string|undefined} logo Logo. + * @property {Node|undefined| node Node. + * @property {ol.proj.ProjectionLike} projection Projection. + * @property {ol.proj.ProjectionLike} reprojectTo Re-project to. + * @property {string|undefined} text Text. + * @property {string|undefined} url URL. + * @property {Array.|undefined} urls URLs. + */ + /** * @typedef {Object} olx.source.TopoJSONOptions * @property {Array.|undefined} attributions Attributions. diff --git a/src/ol/format/gpxformat.exports b/src/ol/format/gpxformat.exports new file mode 100644 index 0000000000..82582fd4ac --- /dev/null +++ b/src/ol/format/gpxformat.exports @@ -0,0 +1,3 @@ +@exportSymbol ol.format.GPX +@exportProperty ol.format.GPX.prototype.readFeature +@exportProperty ol.format.GPX.prototype.readFeatures diff --git a/src/ol/format/gpxformat.js b/src/ol/format/gpxformat.js new file mode 100644 index 0000000000..5b1b1e0ddb --- /dev/null +++ b/src/ol/format/gpxformat.js @@ -0,0 +1,420 @@ +goog.provide('ol.format.GPX'); + +goog.require('goog.array'); +goog.require('goog.asserts'); +goog.require('goog.dom.NodeType'); +goog.require('goog.object'); +goog.require('ol.Feature'); +goog.require('ol.format.XML'); +goog.require('ol.format.XSD'); +goog.require('ol.geom.LineString'); +goog.require('ol.geom.MultiLineString'); +goog.require('ol.geom.Point'); +goog.require('ol.proj'); +goog.require('ol.xml'); + + + +/** + * @constructor + * @extends {ol.format.XML} + */ +ol.format.GPX = function() { + goog.base(this); +}; +goog.inherits(ol.format.GPX, ol.format.XML); + + +/** + * @const + * @private + * @type {Array.} + */ +ol.format.GPX.NAMESPACE_URIS_ = [ + null, + 'http://www.topografix.com/GPX/1/0', + 'http://www.topografix.com/GPX/1/1' +]; + + +/** + * @param {Array.} flatCoordinates Flat coordinates. + * @param {Node} node Node. + * @param {Object} values Values. + * @private + * @return {Array.} Flat coordinates. + */ +ol.format.GPX.appendCoordinate_ = function(flatCoordinates, node, values) { + goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT); + flatCoordinates.push( + parseFloat(node.getAttribute('lon')), + parseFloat(node.getAttribute('lat'))); + if (goog.object.containsKey(values, 'ele')) { + flatCoordinates.push( + /** @type {number} */ (goog.object.get(values, 'ele'))); + goog.object.remove(values, 'ele'); + } else { + flatCoordinates.push(0); + } + if (goog.object.containsKey(values, 'time')) { + flatCoordinates.push( + /** @type {number} */ (goog.object.get(values, 'time'))); + goog.object.remove(values, 'time'); + } else { + flatCoordinates.push(0); + } + return flatCoordinates; +}; + + +/** + * @param {Node} node Node. + * @param {Array.<*>} objectStack Object stack. + * @private + */ +ol.format.GPX.parseLink_ = function(node, objectStack) { + goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT); + goog.asserts.assert(node.localName == 'link'); + var values = /** @type {Object} */ (objectStack[objectStack.length - 1]); + var href = node.getAttribute('href'); + if (!goog.isNull(href)) { + goog.object.set(values, 'link', href); + } + ol.xml.parse(ol.format.GPX.LINK_PARSERS_, node, objectStack); +}; + + +/** + * @param {Node} node Node. + * @param {Array.<*>} objectStack Object stack. + * @private + */ +ol.format.GPX.parseRtePt_ = function(node, objectStack) { + goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT); + goog.asserts.assert(node.localName == 'rtept'); + var values = ol.xml.pushAndParse( + {}, ol.format.GPX.RTEPT_PARSERS_, node, objectStack); + if (goog.isDef(values)) { + var rteValues = /** @type {Object} */ (objectStack[objectStack.length - 1]); + var flatCoordinates = /** @type {Array.} */ + (goog.object.get(rteValues, 'flatCoordinates')); + ol.format.GPX.appendCoordinate_(flatCoordinates, node, values); + } +}; + + +/** + * @param {Node} node Node. + * @param {Array.<*>} objectStack Object stack. + * @private + */ +ol.format.GPX.parseTrkPt_ = function(node, objectStack) { + goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT); + goog.asserts.assert(node.localName == 'trkpt'); + var values = ol.xml.pushAndParse( + {}, ol.format.GPX.TRKPT_PARSERS_, node, objectStack); + if (goog.isDef(values)) { + var trkValues = /** @type {Object} */ (objectStack[objectStack.length - 1]); + var flatCoordinates = /** @type {Array.} */ + (goog.object.get(trkValues, 'flatCoordinates')); + ol.format.GPX.appendCoordinate_(flatCoordinates, node, values); + } +}; + + +/** + * @param {Node} node Node. + * @param {Array.<*>} objectStack Object stack. + * @private + */ +ol.format.GPX.parseTrkSeg_ = function(node, objectStack) { + goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT); + goog.asserts.assert(node.localName == 'trkseg'); + var values = /** @type {Object} */ (objectStack[objectStack.length - 1]); + ol.xml.parse(ol.format.GPX.TRKSEG_PARSERS_, node, objectStack); + var flatCoordinates = /** @type {Array.} */ + (goog.object.get(values, 'flatCoordinates')); + var ends = /** @type {Array.} */ (goog.object.get(values, 'ends')); + ends.push(flatCoordinates.length); +}; + + +/** + * @param {Node} node Node. + * @param {Array.<*>} objectStack Object stack. + * @private + * @return {ol.Feature|undefined} Track. + */ +ol.format.GPX.readRte_ = function(node, objectStack) { + goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT); + goog.asserts.assert(node.localName == 'rte'); + var values = ol.xml.pushAndParse({ + 'flatCoordinates': [] + }, ol.format.GPX.RTE_PARSERS_, node, objectStack); + if (!goog.isDef(values)) { + return undefined; + } + var flatCoordinates = /** @type {Array.} */ + (goog.object.get(values, 'flatCoordinates')); + goog.object.remove(values, 'flatCoordinates'); + var geometry = new ol.geom.LineString(null); + geometry.setFlatCoordinates(ol.geom.GeometryLayout.XYZM, flatCoordinates); + var feature = new ol.Feature(geometry); + feature.setValues(values); + return feature; +}; + + +/** + * @param {Node} node Node. + * @param {Array.<*>} objectStack Object stack. + * @private + * @return {ol.Feature|undefined} Track. + */ +ol.format.GPX.readTrk_ = function(node, objectStack) { + goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT); + goog.asserts.assert(node.localName == 'trk'); + var values = ol.xml.pushAndParse({ + 'flatCoordinates': [], + 'ends': [] + }, ol.format.GPX.TRK_PARSERS_, node, objectStack); + if (!goog.isDef(values)) { + return undefined; + } + var flatCoordinates = /** @type {Array.} */ + (goog.object.get(values, 'flatCoordinates')); + goog.object.remove(values, 'flatCoordinates'); + var ends = /** @type {Array.} */ (goog.object.get(values, 'ends')); + goog.object.remove(values, 'ends'); + var geometry = new ol.geom.MultiLineString(null); + geometry.setFlatCoordinates( + ol.geom.GeometryLayout.XYZM, flatCoordinates, ends); + var feature = new ol.Feature(geometry); + feature.setValues(values); + return feature; +}; + + +/** + * @param {Node} node Node. + * @param {Array.<*>} objectStack Object stack. + * @private + * @return {ol.Feature|undefined} Waypoint. + */ +ol.format.GPX.readWpt_ = function(node, objectStack) { + goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT); + goog.asserts.assert(node.localName == 'wpt'); + var values = ol.xml.pushAndParse( + {}, ol.format.GPX.WPT_PARSERS_, node, objectStack); + if (!goog.isDef(values)) { + return undefined; + } + var coordinates = ol.format.GPX.appendCoordinate_([], node, values); + var geometry = new ol.geom.Point( + coordinates, ol.geom.GeometryLayout.XYZM); + var feature = new ol.Feature(geometry); + feature.setValues(values); + return feature; +}; + + +/** + * @const + * @type {Object.): (ol.Feature|undefined)>} + * @private + */ +ol.format.GPX.FEATURE_READER_ = { + 'rte': ol.format.GPX.readRte_, + 'trk': ol.format.GPX.readTrk_, + 'wpt': ol.format.GPX.readWpt_ +}; + + +/** + * @const + * @type {Object.>} + * @private + */ +ol.format.GPX.GPX_PARSERS_ = ol.xml.makeParsersNS( + ol.format.GPX.NAMESPACE_URIS_, { + 'rte': ol.xml.makeArrayPusher(ol.format.GPX.readRte_), + 'trk': ol.xml.makeArrayPusher(ol.format.GPX.readTrk_), + 'wpt': ol.xml.makeArrayPusher(ol.format.GPX.readWpt_) + }); + + +/** + * @const + * @type {Object.>} + * @private + */ +ol.format.GPX.LINK_PARSERS_ = ol.xml.makeParsersNS( + ol.format.GPX.NAMESPACE_URIS_, { + 'text': + ol.xml.makeObjectPropertySetter(ol.format.XSD.readString, 'linkText'), + 'type': + ol.xml.makeObjectPropertySetter(ol.format.XSD.readString, 'linkType') + }); + + +/** + * @const + * @type {Object.>} + * @private + */ +ol.format.GPX.RTE_PARSERS_ = ol.xml.makeParsersNS( + ol.format.GPX.NAMESPACE_URIS_, { + 'name': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString), + 'cmt': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString), + 'desc': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString), + 'src': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString), + 'link': ol.format.GPX.parseLink_, + 'number': + ol.xml.makeObjectPropertySetter(ol.format.XSD.readNonNegativeInteger), + 'type': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString), + 'rtept': ol.format.GPX.parseRtePt_ + }); + + +/** + * @const + * @type {Object.>} + * @private + */ +ol.format.GPX.RTEPT_PARSERS_ = ol.xml.makeParsersNS( + ol.format.GPX.NAMESPACE_URIS_, { + 'ele': ol.xml.makeObjectPropertySetter(ol.format.XSD.readDecimal), + 'time': ol.xml.makeObjectPropertySetter(ol.format.XSD.readDateTime) + }); + + +/** + * @const + * @type {Object.>} + * @private + */ +ol.format.GPX.TRK_PARSERS_ = ol.xml.makeParsersNS( + ol.format.GPX.NAMESPACE_URIS_, { + 'name': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString), + 'cmt': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString), + 'desc': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString), + 'src': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString), + 'link': ol.format.GPX.parseLink_, + 'number': + ol.xml.makeObjectPropertySetter(ol.format.XSD.readNonNegativeInteger), + 'type': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString), + 'trkseg': ol.format.GPX.parseTrkSeg_ + }); + + +/** + * @const + * @type {Object.>} + * @private + */ +ol.format.GPX.TRKSEG_PARSERS_ = ol.xml.makeParsersNS( + ol.format.GPX.NAMESPACE_URIS_, { + 'trkpt': ol.format.GPX.parseTrkPt_ + }); + + +/** + * @const + * @type {Object.>} + * @private + */ +ol.format.GPX.TRKPT_PARSERS_ = ol.xml.makeParsersNS( + ol.format.GPX.NAMESPACE_URIS_, { + 'ele': ol.xml.makeObjectPropertySetter(ol.format.XSD.readDecimal), + 'time': ol.xml.makeObjectPropertySetter(ol.format.XSD.readDateTime) + }); + + +/** + * @const + * @type {Object.>} + * @private + */ +ol.format.GPX.WPT_PARSERS_ = ol.xml.makeParsersNS( + ol.format.GPX.NAMESPACE_URIS_, { + 'ele': ol.xml.makeObjectPropertySetter(ol.format.XSD.readDecimal), + 'time': ol.xml.makeObjectPropertySetter(ol.format.XSD.readDateTime), + 'magvar': ol.xml.makeObjectPropertySetter(ol.format.XSD.readDecimal), + 'geoidheight': ol.xml.makeObjectPropertySetter(ol.format.XSD.readDecimal), + 'name': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString), + 'cmt': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString), + 'desc': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString), + 'src': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString), + 'link': ol.format.GPX.parseLink_, + 'sym': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString), + 'type': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString), + 'fix': ol.xml.makeObjectPropertySetter(ol.format.XSD.readString), + 'sat': ol.xml.makeObjectPropertySetter( + ol.format.XSD.readNonNegativeInteger), + 'hdop': ol.xml.makeObjectPropertySetter(ol.format.XSD.readDecimal), + 'vdop': ol.xml.makeObjectPropertySetter(ol.format.XSD.readDecimal), + 'pdop': ol.xml.makeObjectPropertySetter(ol.format.XSD.readDecimal), + 'ageofdgpsdata': + ol.xml.makeObjectPropertySetter(ol.format.XSD.readDecimal), + 'dgpsid': + ol.xml.makeObjectPropertySetter(ol.format.XSD.readNonNegativeInteger) + }); + + +/** + * @inheritDoc + */ +ol.format.GPX.prototype.readFeatureFromNode = function(node) { + goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT); + if (goog.array.indexOf(ol.format.GPX.NAMESPACE_URIS_, node.namespaceURI) == + -1) { + return null; + } + var featureReader = ol.format.GPX.FEATURE_READER_[node.localName]; + if (!goog.isDef(featureReader)) { + return null; + } + var feature = featureReader(node, []); + if (!goog.isDef(feature)) { + return null; + } + return feature; +}; + + +/** + * @inheritDoc + */ +ol.format.GPX.prototype.readFeaturesFromNode = function(node) { + goog.asserts.assert(node.nodeType == goog.dom.NodeType.ELEMENT); + if (goog.array.indexOf(ol.format.GPX.NAMESPACE_URIS_, node.namespaceURI) == + -1) { + return []; + } + if (node.localName == 'gpx') { + var features = ol.xml.pushAndParse(/** @type {Array.} */ ([]), + ol.format.GPX.GPX_PARSERS_, node, []); + if (goog.isDef(features)) { + return features; + } else { + return []; + } + } + return []; +}; + + +/** + * @inheritDoc + */ +ol.format.GPX.prototype.readProjectionFromDocument = function(doc) { + return ol.proj.get('EPSG:4326'); +}; + + +/** + * @inheritDoc + */ +ol.format.GPX.prototype.readProjectionFromNode = function(node) { + return ol.proj.get('EPSG:4326'); +}; diff --git a/src/ol/format/xsdformat.js b/src/ol/format/xsdformat.js new file mode 100644 index 0000000000..71a2a9f9dd --- /dev/null +++ b/src/ol/format/xsdformat.js @@ -0,0 +1,83 @@ +goog.provide('ol.format.XSD'); + +goog.require('goog.string'); +goog.require('ol.xml'); + + +/** + * @const + * @type {string} + */ +ol.format.XSD.NAMESPACE_URI = 'http://www.w3.org/2001/XMLSchema'; + + +/** + * @param {Node} node Node. + * @return {number|undefined} DateTime. + */ +ol.format.XSD.readDateTime = function(node) { + var s = ol.xml.getAllTextContent(node, false); + var re = + /^\s*(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2})(Z|(?:([+\-])(\d{2})(?::(\d{2}))?))\s*$/; + var m = re.exec(s); + if (m) { + var year = parseInt(m[1], 10); + var month = parseInt(m[2], 10) - 1; + var day = parseInt(m[3], 10); + var hour = parseInt(m[4], 10); + var minute = parseInt(m[5], 10); + var second = parseInt(m[6], 10); + var dateTime = Date.UTC(year, month, day, hour, minute, second, 0) / 1000; + if (m[7] != 'Z') { + var sign = m[8] == '-' ? -1 : 1; + dateTime += sign * 60 * parseInt(m[9], 10); + if (goog.isDef(m[10])) { + dateTime += sign * 60 * 60 * parseInt(m[10], 10); + } + } + return dateTime; + } else { + return undefined; + } +}; + + +/** + * @param {Node} node Node. + * @return {number|undefined} Decimal. + */ +ol.format.XSD.readDecimal = function(node) { + // FIXME check spec + var s = ol.xml.getAllTextContent(node, false); + var m = /^\s*([+\-]?\d+(?:\.\d*)?)\s*$/.exec(s); + if (m) { + return parseFloat(m[1]); + } else { + return undefined; + } +}; + + +/** + * @param {Node} node Node. + * @return {number|undefined} Decimal. + */ +ol.format.XSD.readNonNegativeInteger = function(node) { + var s = ol.xml.getAllTextContent(node, false); + var m = /^\s*(\d+)\s*$/.exec(s); + if (m) { + return parseInt(m[1], 10); + } else { + return undefined; + } +}; + + +/** + * @param {Node} node Node. + * @return {string|undefined} String. + */ +ol.format.XSD.readString = function(node) { + var s = ol.xml.getAllTextContent(node, false); + return goog.string.trim(s); +}; diff --git a/src/ol/interaction/draganddropinteraction.js b/src/ol/interaction/draganddropinteraction.js index 0ed09d211f..329a3c5172 100644 --- a/src/ol/interaction/draganddropinteraction.js +++ b/src/ol/interaction/draganddropinteraction.js @@ -52,6 +52,12 @@ ol.interaction.DragAndDrop = function(opt_options) { */ this.layer_ = goog.isDef(options.layer) ? options.layer : null; + /** + * @private + * @type {ol.feature.StyleFunction|undefined} + */ + this.styleFunction_ = options.styleFunction; + /** * @private * @type {goog.events.FileDropHandler} @@ -149,6 +155,7 @@ ol.interaction.DragAndDrop.prototype.handleResult_ = function(result) { } if (goog.isNull(this.layer_)) { map.getLayers().push(new ol.layer.Vector({ + styleFunction: this.styleFunction_, source: source })); } diff --git a/src/ol/source/gpxsource.exports b/src/ol/source/gpxsource.exports new file mode 100644 index 0000000000..0dfabb47be --- /dev/null +++ b/src/ol/source/gpxsource.exports @@ -0,0 +1 @@ +@exportSymbol ol.source.GPX diff --git a/src/ol/source/gpxsource.js b/src/ol/source/gpxsource.js new file mode 100644 index 0000000000..4cf8da99ce --- /dev/null +++ b/src/ol/source/gpxsource.js @@ -0,0 +1,32 @@ +goog.provide('ol.source.GPX'); + +goog.require('ol.format.GPX'); +goog.require('ol.source.VectorFile'); + + + +/** + * @constructor + * @extends {ol.source.VectorFile} + * @param {olx.source.GPXOptions=} opt_options Options. + */ +ol.source.GPX = function(opt_options) { + + var options = goog.isDef(opt_options) ? opt_options : {}; + + goog.base(this, { + attributions: options.attributions, + doc: options.doc, + extent: options.extent, + format: new ol.format.GPX(), + logo: options.logo, + node: options.node, + projection: options.projection, + reprojectTo: options.reprojectTo, + text: options.text, + url: options.url, + urls: options.urls + }); + +}; +goog.inherits(ol.source.GPX, ol.source.VectorFile); diff --git a/test/spec/ol/format/gpxformat.test.js b/test/spec/ol/format/gpxformat.test.js new file mode 100644 index 0000000000..b146289a61 --- /dev/null +++ b/test/spec/ol/format/gpxformat.test.js @@ -0,0 +1,380 @@ +goog.provide('ol.test.format.GPX'); + + +describe('ol.format.GPX', function() { + + var format; + beforeEach(function() { + format = new ol.format.GPX(); + }); + + describe('readFeatures', function() { + + describe('rte', function() { + + it('can read an empty rte', function() { + var text = + '' + + ' ' + + ''; + var fs = format.readFeatures(text); + expect(fs).to.have.length(1); + var f = fs[0]; + expect(f).to.be.an(ol.Feature); + var g = f.getGeometry(); + expect(g).to.be.an(ol.geom.LineString); + expect(g.getCoordinates()).to.eql([]); + expect(g.getLayout()).to.be(ol.geom.GeometryLayout.XYZM); + }); + + it('can read various rte attributes', function() { + var text = + '' + + ' ' + + ' Name' + + ' Comment' + + ' Description' + + ' Source' + + ' ' + + ' Link text' + + ' Link type' + + ' ' + + ' 1' + + ' Type' + + ' ' + + ''; + var fs = format.readFeatures(text); + expect(fs).to.have.length(1); + var f = fs[0]; + expect(f).to.be.an(ol.Feature); + expect(f.get('name')).to.be('Name'); + expect(f.get('cmt')).to.be('Comment'); + expect(f.get('desc')).to.be('Description'); + expect(f.get('src')).to.be('Source'); + expect(f.get('link')).to.be('http://example.com/'); + expect(f.get('linkText')).to.be('Link text'); + expect(f.get('linkType')).to.be('Link type'); + expect(f.get('number')).to.be(1); + expect(f.get('type')).to.be('Type'); + }); + + it('can read a rte with multiple rtepts', function() { + var text = + '' + + ' ' + + ' ' + + ' ' + + ' ' + + ''; + var fs = format.readFeatures(text); + expect(fs).to.have.length(1); + var f = fs[0]; + expect(f).to.be.an(ol.Feature); + var g = f.getGeometry(); + expect(g).to.be.an(ol.geom.LineString); + expect(g.getCoordinates()).to.eql([[2, 1, 0, 0], [4, 3, 0, 0]]); + expect(g.getLayout()).to.be(ol.geom.GeometryLayout.XYZM); + }); + + }); + + describe('trk', function() { + + it('can read an empty trk', function() { + var text = + '' + + ' ' + + ''; + var fs = format.readFeatures(text); + expect(fs).to.have.length(1); + var f = fs[0]; + expect(f).to.be.an(ol.Feature); + var g = f.getGeometry(); + expect(g).to.be.an(ol.geom.MultiLineString); + expect(g.getCoordinates()).to.eql([]); + expect(g.getLayout()).to.be(ol.geom.GeometryLayout.XYZM); + }); + + it('can read various trk attributes', function() { + var text = + '' + + ' ' + + ' Name' + + ' Comment' + + ' Description' + + ' Source' + + ' ' + + ' Link text' + + ' Link type' + + ' ' + + ' 1' + + ' Type' + + ' ' + + ''; + var fs = format.readFeatures(text); + expect(fs).to.have.length(1); + var f = fs[0]; + expect(f).to.be.an(ol.Feature); + expect(f.get('name')).to.be('Name'); + expect(f.get('cmt')).to.be('Comment'); + expect(f.get('desc')).to.be('Description'); + expect(f.get('src')).to.be('Source'); + expect(f.get('link')).to.be('http://example.com/'); + expect(f.get('linkText')).to.be('Link text'); + expect(f.get('linkType')).to.be('Link type'); + expect(f.get('number')).to.be(1); + expect(f.get('type')).to.be('Type'); + }); + + it('can read a trk with an empty trkseg', function() { + var text = + '' + + ' ' + + ' ' + + ' ' + + ''; + var fs = format.readFeatures(text); + expect(fs).to.have.length(1); + var f = fs[0]; + expect(f).to.be.an(ol.Feature); + var g = f.getGeometry(); + expect(g).to.be.an(ol.geom.MultiLineString); + expect(g.getCoordinates()).to.eql([[]]); + expect(g.getLayout()).to.be(ol.geom.GeometryLayout.XYZM); + }); + + it('can read a trk with a trkseg with multiple trkpts', function() { + var text = + '' + + ' ' + + ' ' + + ' ' + + ' 3' + + ' ' + + ' ' + + ' ' + + ' 7' + + ' ' + + ' ' + + ' ' + + ' ' + + ''; + var fs = format.readFeatures(text); + expect(fs).to.have.length(1); + var f = fs[0]; + expect(f).to.be.an(ol.Feature); + var g = f.getGeometry(); + expect(g).to.be.an(ol.geom.MultiLineString); + expect(g.getCoordinates()).to.eql([ + [[2, 1, 3, 1263115752], [6, 5, 7, 1263115812]] + ]); + expect(g.getLayout()).to.be(ol.geom.GeometryLayout.XYZM); + }); + + it('can read a trk with multiple trksegs', function() { + var text = + '' + + ' ' + + ' ' + + ' ' + + ' 3' + + ' ' + + ' ' + + ' ' + + ' 7' + + ' ' + + ' ' + + ' ' + + ' ' + + ' ' + + ' 10' + + ' ' + + ' ' + + ' ' + + ' 13' + + ' ' + + ' ' + + ' ' + + ' ' + + ''; + var fs = format.readFeatures(text); + expect(fs).to.have.length(1); + var f = fs[0]; + expect(f).to.be.an(ol.Feature); + var g = f.getGeometry(); + expect(g).to.be.an(ol.geom.MultiLineString); + expect(g.getCoordinates()).to.eql([ + [[2, 1, 3, 1263115752], [6, 5, 7, 1263115812]], + [[9, 8, 10, 1263115872], [12, 11, 13, 1263115932]] + ]); + expect(g.getLayout()).to.be(ol.geom.GeometryLayout.XYZM); + }); + + }); + + describe('wpt', function() { + + it('can read a wpt', function() { + var text = + '' + + ' ' + + ''; + var fs = format.readFeatures(text); + expect(fs).to.have.length(1); + var f = fs[0]; + expect(f).to.be.an(ol.Feature); + var g = f.getGeometry(); + expect(g).to.be.an(ol.geom.Point); + expect(g.getCoordinates()).to.eql([2, 1, 0, 0]); + expect(g.getLayout()).to.be(ol.geom.GeometryLayout.XYZM); + }); + + it('can read a wpt with ele', function() { + var text = + '' + + ' ' + + ' 3' + + ' ' + + ''; + var fs = format.readFeatures(text); + expect(fs).to.have.length(1); + var f = fs[0]; + expect(f).to.be.an(ol.Feature); + var g = f.getGeometry(); + expect(g).to.be.an(ol.geom.Point); + expect(g.getCoordinates()).to.eql([2, 1, 3, 0]); + expect(g.getLayout()).to.be(ol.geom.GeometryLayout.XYZM); + }); + + it('can read a wpt with time', function() { + var text = + '' + + ' ' + + ' ' + + ' ' + + ''; + var fs = format.readFeatures(text); + expect(fs).to.have.length(1); + var f = fs[0]; + expect(f).to.be.an(ol.Feature); + var g = f.getGeometry(); + expect(g).to.be.an(ol.geom.Point); + expect(g.getCoordinates()).to.eql([2, 1, 0, 1263115752]); + expect(g.getLayout()).to.be(ol.geom.GeometryLayout.XYZM); + }); + + it('can read a wpt with ele and time', function() { + var text = + '' + + ' ' + + ' 3' + + ' ' + + ' ' + + ''; + var fs = format.readFeatures(text); + expect(fs).to.have.length(1); + var f = fs[0]; + expect(f).to.be.an(ol.Feature); + var g = f.getGeometry(); + expect(g).to.be.an(ol.geom.Point); + expect(g.getCoordinates()).to.eql([2, 1, 3, 1263115752]); + expect(g.getLayout()).to.be(ol.geom.GeometryLayout.XYZM); + }); + + it('can read various wpt attributes', function() { + var text = + '' + + ' ' + + ' 11' + + ' 4' + + ' Name' + + ' Comment' + + ' Description' + + ' Source' + + ' ' + + ' Link text' + + ' Link type' + + ' ' + + ' Symbol' + + ' Type' + + ' 2d' + + ' 5' + + ' 6' + + ' 7' + + ' 8' + + ' 9' + + ' 10' + + ' ' + + ''; + var fs = format.readFeatures(text); + expect(fs).to.have.length(1); + var f = fs[0]; + expect(f).to.be.an(ol.Feature); + expect(f.get('magvar')).to.be(11); + expect(f.get('geoidheight')).to.be(4); + expect(f.get('name')).to.be('Name'); + expect(f.get('cmt')).to.be('Comment'); + expect(f.get('desc')).to.be('Description'); + expect(f.get('src')).to.be('Source'); + expect(f.get('link')).to.be('http://example.com/'); + expect(f.get('linkText')).to.be('Link text'); + expect(f.get('linkType')).to.be('Link type'); + expect(f.get('sym')).to.be('Symbol'); + expect(f.get('type')).to.be('Type'); + expect(f.get('fix')).to.be('2d'); + expect(f.get('hdop')).to.be(6); + expect(f.get('vdop')).to.be(7); + expect(f.get('pdop')).to.be(8); + expect(f.get('ageofdgpsdata')).to.be(9); + expect(f.get('dgpsid')).to.be(10); + }); + + }); + + describe('XML namespace support', function() { + + it('can read features with a version 1.0 namespace', function() { + var text = + '' + + ' ' + + ' ' + + ' ' + + ''; + var fs = format.readFeatures(text); + expect(fs).to.have.length(3); + }); + + it('can read features with a version 1.1 namespace', function() { + var text = + '' + + ' ' + + ' ' + + ' ' + + ''; + var fs = format.readFeatures(text); + expect(fs).to.have.length(3); + }); + + it('can read features with no namespace', function() { + var text = + '' + + ' ' + + ' ' + + ' ' + + ''; + var fs = format.readFeatures(text); + expect(fs).to.have.length(3); + }); + + }); + + }); + +}); + + +goog.require('ol.Feature'); +goog.require('ol.format.GPX'); +goog.require('ol.geom.LineString'); +goog.require('ol.geom.MultiLineString'); +goog.require('ol.geom.Point');