1 /* 2 * Timemap.js Copyright 2010 Nick Rabinowitz. 3 * Licensed under the MIT License (see LICENSE.txt) 4 */ 5 6 /** 7 * @fileOverview 8 * KML Loader 9 * 10 * @author Nick Rabinowitz (www.nickrabinowitz.com) 11 */ 12 13 /*globals TimeMap */ 14 15 /** 16 * @class 17 * KML loader: load KML files. 18 * 19 * <p>This is a loader class for KML files. Currently supports all geometry 20 * types (point, polyline, polygon, and overlay) and multiple geometries. Supports loading 21 * <a href="http://code.google.com/apis/kml/documentation/extendeddata.html">ExtendedData</a> 22 * through the extendedData parameter. 23 * </p> 24 * 25 * @augments TimeMap.loaders.xml 26 * @requires loaders/xml.js 27 * @requires param.js 28 * @borrows TimeMap.loaders.kml.parse as #parse 29 * 30 * @example 31 TimeMap.init({ 32 datasets: [ 33 { 34 title: "KML Dataset", 35 type: "kml", 36 options: { 37 url: "mydata.kml" // Must be local 38 } 39 } 40 ], 41 // etc... 42 }); 43 * @see <a href="../../examples/kenya.html">KML Example</a> 44 * @see <a href="../../examples/kml_extendeddata.html">KML ExtendedData Example</a> 45 * 46 * @param {Object} options All options for the loader 47 * @param {String} options.url URL of KML file to load (NB: must be local address) 48 * @param {String[]} [options.extendedData] Array of names for ExtendedData data elements 49 * @param {mixed} [options[...]] Other options (see {@link TimeMap.loaders.xml}) 50 * @return {TimeMap.loaders.xml} Loader configured for KML 51 */ 52 TimeMap.loaders.kml = function(options) { 53 var loader = new TimeMap.loaders.xml(options), 54 tagMap = options.tagMap || {}, 55 extendedData = options.extendedData || []; 56 57 // Add ExtendedData parameters to extra params 58 extendedData.forEach(function(tagName) { 59 loader.extraParams.push( 60 new TimeMap.params.ExtendedDataParam(tagMap[tagName] || tagName, tagName) 61 ); 62 }); 63 64 // set custom parser 65 loader.parse = TimeMap.loaders.kml.parse; 66 return loader; 67 }; 68 69 /** 70 * Static function to parse KML with time data. 71 * 72 * @param {XML} kml KML node to be parsed 73 * @return {TimeMapItem Array} Array of TimeMapItems 74 */ 75 TimeMap.loaders.kml.parse = function(kmlnode) { 76 var loader = this, 77 items = [], 78 data, placemarks, nList, coords, pmobj; 79 80 // get TimeMap utilty functions 81 // assigning to variables should compress better 82 var util = TimeMap.util, 83 getTagValue = util.getTagValue, 84 getNodeList = util.getNodeList, 85 makePoint = util.makePoint, 86 makePoly = util.makePoly, 87 formatDate = util.formatDate; 88 89 // recursive time data search 90 function findNodeTime(n, data) { 91 var tstamp = $(n).children("TimeStamp"), 92 tspan = $(n).children("TimeSpan"); 93 // set start if found 94 if (tspan.length) { 95 data.start = getTagValue(tspan, 'begin'); 96 data.end = getTagValue(tspan, 'end') || 97 // unbounded spans end at the present time 98 formatDate(new Date()); 99 } else { 100 data.start = getTagValue(tstamp, 'when'); 101 } 102 // try looking recursively at parent nodes 103 if (!data.start) { 104 var $pn = $(n).parent(); 105 if ($pn.is("Folder") || $pn.is("Document")) { 106 findNodeTime($pn, data); 107 } 108 } 109 } 110 111 // look for placemarks 112 getNodeList(kmlnode, "Placemark").each(function() { 113 var pm = this; 114 data = { options: {} }; 115 // get title & description 116 data.title = getTagValue(pm, "name"); 117 data.options.description = getTagValue(pm, "description"); 118 // get time information 119 findNodeTime(pm, data); 120 // find placemark(s) 121 data.placemarks = []; 122 // look for marker 123 getNodeList(pm, "Point").each(function() { 124 pmobj = { point: {} }; 125 // get lat/lon 126 coords = getTagValue(this, "coordinates"); 127 pmobj.point = makePoint(coords, 1); 128 data.placemarks.push(pmobj); 129 }); 130 // look for polylines 131 getNodeList(pm, "LineString").each(function() { 132 pmobj = { polyline: [] }; 133 // get lat/lon 134 coords = getTagValue(this, "coordinates"); 135 pmobj.polyline = makePoly(coords, 1); 136 data.placemarks.push(pmobj); 137 }); 138 // look for polygons 139 getNodeList(pm, "Polygon").each(function() { 140 pmobj = { polygon: [] }; 141 // get lat/lon 142 coords = getTagValue(this, "coordinates"); 143 pmobj.polygon = makePoly(coords, 1); 144 data.placemarks.push(pmobj); 145 }); 146 // look for any extra tags and/or ExtendedData specified 147 loader.parseExtra(data, pm); 148 149 items.push(data); 150 }); 151 152 // look for ground overlays 153 getNodeList(kmlnode, "GroundOverlay").each(function() { 154 var pm = this; 155 data = { options: {}, overlay: {} }; 156 // get title & description 157 data.title = getTagValue(pm, "name"); 158 data.options.description = getTagValue(pm, "description"); 159 // get time information 160 findNodeTime(pm, data); 161 // get image 162 data.overlay.image = getTagValue(pm, "Icon href"); 163 // get coordinates 164 nList = getNodeList(pm, "LatLonBox"); 165 data.overlay.north = getTagValue(nList, "north"); 166 data.overlay.south = getTagValue(nList, "south"); 167 data.overlay.east = getTagValue(nList, "east"); 168 data.overlay.west = getTagValue(nList, "west"); 169 // look for any extra tags and/or ExtendedData specified 170 loader.parseExtra(data, pm); 171 items.push(data); 172 }); 173 174 // clean up 175 kmlnode = null; 176 177 return items; 178 }; 179 180 /** 181 * @class 182 * Class for parameters loaded from KML ExtendedData elements 183 * 184 * @augments TimeMap.params.OptionParam 185 * 186 * @constructor 187 * @param {String} paramName String name of the parameter 188 * @param {String} [tagName] Tag name, if different 189 */ 190 TimeMap.params.ExtendedDataParam = function(paramName, tagName) { 191 return new TimeMap.params.OptionParam(paramName, { 192 193 /** 194 * Set a config object based on an ExtendedData element 195 * @name TimeMap.params.ExtendedDataParam#setConfigKML 196 * @function 197 * 198 * @param {Object} config Config object to modify 199 * @param {XML NodeList} node Parent node to look for tags in 200 */ 201 setConfigXML: function(config, node) { 202 var util = TimeMap.util, 203 param = this; 204 util.getNodeList(node, "Data").each(function() { 205 var $n = $(this); 206 if ($n.attr("name") == tagName) { 207 param.setConfig(config, util.getTagValue($n, "value")); 208 } 209 }); 210 }, 211 212 sourceName: tagName 213 214 }); 215 }; 216