OpenLayers OpenLayers

Ticket #927: kml.patch

File kml.patch, 32.8 kB (added by tschaub, 10 months ago)

Read/write KML, tests, and example

  • tests/Format/test_KML.html

    old new  
    33    <script src="../../lib/OpenLayers.js"></script>  
    44    <script type="text/javascript"> 
    55 
     6    var test_content = '<kml xmlns="http://earth.google.com/kml/2.0"><Folder><name>OpenLayers export</name><description>Vector geometries from OpenLayers</description><Placemark id="KML.Polygon"><name>OpenLayers.Feature.Vector_344</name><description>A KLM Polygon</description><Polygon><outerBoundaryIs><LinearRing><coordinates>5.001370157823406,49.26855713824488 8.214706453896161,49.630662409673505 8.397385910100951,48.45172350357396 5.001370157823406,49.26855713824488</coordinates></LinearRing></outerBoundaryIs></Polygon></Placemark><Placemark id="KML.LineString"><name>OpenLayers.Feature.Vector_402</name><description>A KML LineString</description><LineString><coordinates>5.838523393080493,49.74814616928052 5.787079558782349,48.410795432216574 8.91427702008381,49.28932499608202</coordinates></LineString></Placemark><Placemark id="KML.Point"><name>OpenLayers.Feature.Vector_451</name><description>A KML Point</description><Point><coordinates>6.985073041685488,49.8682250149058</coordinates></Point></Placemark><Placemark id="KML.MultiGeometry"><name>SF Marina Harbor Master</name><description>KML MultiGeometry</description><MultiGeometry><LineString><coordinates>-122.4425587930444,37.80666418607323 -122.4428379594768,37.80663578323093</coordinates></LineString><LineString><coordinates>-122.4425509770566,37.80662588061205 -122.4428340530617,37.8065999493009</coordinates></LineString></MultiGeometry></Placemark></Folder></kml>'; 
    67 
    78    function test_Format_KML_constructor(t) {  
    89        t.plan(4);  
     
    1415        t.eq(format.foo, "bar", "constructor sets options correctly");  
    1516        t.eq(typeof format.read, "function", "format has a read function");  
    1617        t.eq(typeof format.write, "function", "format has a write function"); 
    17  
    1818    } 
    1919 
    2020    function test_Format_KML_read(t) { 
    21         t.plan(1); 
    22         t.ok(true, "Read tests not done yet."); 
     21        t.plan(5); 
     22        var features = (new OpenLayers.Format.KML()).read(this.test_content); 
     23        t.eq(features.length, 4, "Number of features read is correct"); 
     24        t.ok(features[0].geometry.toString() == "POLYGON((5.001370157823406 49.26855713824488,8.214706453896161 49.630662409673505,8.397385910100951 48.45172350357396,5.001370157823406 49.26855713824488))", "polygon feature geometry correctly created"); 
     25        t.ok(features[1].geometry.toString() == "LINESTRING(5.838523393080493 49.74814616928052,5.787079558782349 48.410795432216574,8.91427702008381 49.28932499608202)", "linestring feature geometry correctly created"); 
     26        t.ok(features[2].geometry.toString() == "POINT(6.985073041685488 49.8682250149058)", "point feature geometry correctly created"); 
     27        t.ok(features[3].geometry.CLASS_NAME == "OpenLayers.Geometry.Collection", 
     28             "read geometry collection"); 
    2329    } 
    2430 
    2531    function test_Format_KML_write(t) { 
     32        // make sure id, name, and description are preserved 
    2633        t.plan(1); 
    27         t.ok(true, "Write tests not done yet."); 
     34        var kmlExpected = this.test_content; 
     35        var options = { 
     36            folderName: "OpenLayers export", 
     37            foldersDesc: "Vector geometries from OpenLayers" 
     38        } 
    2839 
    29         var format = new OpenLayers.Format.KML(); 
    30         //var doc = format.read(text); 
    31         //var out = format.write(doc); 
    32         //out = out.replace(/[\r\n]/g, ''); 
    33         //t.eq(text, out, 
    34         //     "correctly writes an KML DOM doc"); 
     40        var format = new OpenLayers.Format.KML(options); 
     41        var features = format.read(kmlExpected); 
     42        var kmlOut = format.write(features); 
     43        t.eq(kmlOut, kmlExpected, "correctly writes an KML doc string"); 
    3544    } 
    3645 
    3746    </script>  
  • lib/OpenLayers/Format/KML.js

    old new  
    55/** 
    66 * @requires OpenLayers/Format.js 
    77 * @requires OpenLayers/Feature/Vector.js 
    8  * @requires OpenLayers/Ajax.js 
     8 * 
     9 * Class: OpenLayers.Format.KML 
     10 * Read/Wite KML. Create a new instance with the <OpenLayers.Format.KML> 
     11 *     constructor.  
    912 *  
    10  * Class: OpenLayers.Format.KML 
    11  * Read only KML. Largely Proof of Concept: does not support advanced Features, 
    12  *     including Polygons.  Create a new instance with the  
    13  *     <OpenLayers.Format.KML> constructor. 
    14  * 
    1513 * Inherits from: 
    16  *  - <OpenLayers.Format
     14 *  - <OpenLayers.Format.XML
    1715 */ 
    18 OpenLayers.Format.KML = OpenLayers.Class(OpenLayers.Format, { 
     16OpenLayers.Format.KML = OpenLayers.Class(OpenLayers.Format.XML, { 
    1917     
    2018    /** 
    2119     * APIProperty: kmlns 
    22      * KML Namespace to use. Defaults to 2.0 namespace. 
     20     * {String} KML Namespace to use. Defaults to 2.0 namespace. 
    2321     */ 
    2422    kmlns: "http://earth.google.com/kml/2.0", 
    2523     
     24    /**  
     25     * APIProperty: placemarksDesc 
     26     * {String} Name of the placemarks.  Default is "No description available." 
     27     */ 
     28    placemarksDesc: "No description available", 
     29     
     30    /**  
     31     * APIProperty: foldersName 
     32     * {String} Name of the folders.  Default is "OpenLayers export." 
     33     */ 
     34    foldersName: "OpenLayers export", 
     35     
     36    /**  
     37     * APIProperty: foldersDesc 
     38     * {String} Description of the folders. Default is "Exported on [date]." 
     39     */ 
     40    foldersDesc: "Exported on " + new Date(), 
     41     
    2642    /** 
     43     * APIProperty: extractAttributes 
     44     * {Boolean} Extract attributes from KML.  Default is true. 
     45     */ 
     46    extractAttributes: true, 
     47 
     48    /** 
    2749     * Constructor: OpenLayers.Format.KML 
    28      * Create a new parser for KML 
     50     * Create a new parser for KML. 
    2951     * 
    3052     * Parameters: 
    3153     * options - {Object} An optional object whose properties will be set on 
    32      *                    this instance. 
     54     *     this instance. 
    3355     */ 
    3456    initialize: function(options) { 
    35         OpenLayers.Format.prototype.initialize.apply(this, [options]); 
     57        // compile regular expressions once instead of every time they are used 
     58        this.regExes = { 
     59            trimSpace: (/^\s*|\s*$/g), 
     60            removeSpace: (/\s*/g), 
     61            splitSpace: (/\s+/), 
     62            trimComma: (/\s*,\s*/g) 
     63        }; 
     64        OpenLayers.Format.XML.prototype.initialize.apply(this, [options]); 
    3665    }, 
    3766 
    3867    /** 
     
    4069     * Read data from a string, and return a list of features.  
    4170     *  
    4271     * Parameters:  
    43      * data - {string} or {XMLNode>} data to read/parse. 
     72     * data - {String} or {DOMElement} data to read/parse. 
     73     * 
     74     * Returns: 
     75     * {Array(<OpenLayers.Feature.Vector>)} List of features. 
    4476     */ 
    45      read: function(data) { 
    46         if (typeof data == "string") {  
    47             data = OpenLayers.parseXMLString(data); 
    48         }     
    49         var featureNodes = OpenLayers.Ajax.getElementsByTagNameNS(data, this.kmlns, "", "Placemark"); 
    50          
    51         var features = []; 
    52          
    53         // Process all the featureMembers 
    54         for (var i = 0; i < featureNodes.length; i++) { 
     77    read: function(data) { 
     78        if(typeof data == "string") { 
     79            data = OpenLayers.Format.XML.prototype.read.apply(this, [data]); 
     80        } 
     81        var featureNodes = this.getElementsByTagNameNS(data, 
     82                                                       this.kmlns, 
     83                                                       "Placemark"); 
     84        var features = [];         
     85        for(var i=0; i<featureNodes.length; i++) { 
    5586            var feature = this.parseFeature(featureNodes[i]); 
    56  
    57             if (feature) { 
     87            if(feature) { 
    5888                features.push(feature); 
    5989            } 
    6090        } 
    6191        return features; 
    62     }, 
     92    }, 
    6393 
    64      /** 
    65       * Method: parseFeature 
    66       * This function is the core of the KML parsing code in OpenLayers. 
    67       * It creates the geometries that are then attached to the returned 
    68       * feature, and calls parseAttributes() to get attribute data out. 
    69       * 
    70       * Parameters: 
    71       * xmlNode - {<DOMElement>}  
    72       */ 
    73      parseFeature: function(xmlNode) { 
    74         var geom; 
    75         var p; // [points,bounds] 
     94    /** 
     95     * Method: parseFeature 
     96     * This function is the core of the KML parsing code in OpenLayers. 
     97     *     It creates the geometries that are then attached to the returned 
     98     *     feature, and calls parseAttributes() to get attribute data out. 
     99     * 
     100     * Parameters: 
     101     * node - {<DOMElement>} 
     102     * 
     103     * Returns: 
     104     * {<OpenLayers.Feature.Vector>} A vector feature. 
     105     */ 
     106    parseFeature: function(node) { 
     107        // only accept one geometry per feature - look for highest "order" 
     108        var order = ["MultiGeometry", "Polygon", "LineString", "Point"]; 
     109        var type, nodeList, geometry, parser; 
     110        for(var i=0; i<order.length; ++i) { 
     111            type = order[i]; 
     112            nodeList = this.getElementsByTagNameNS(node, this.kmlns, type); 
     113            if(nodeList.length > 0) { 
     114                // only deal with first geometry of this type 
     115                var parser = this.parseGeometry[type.toLowerCase()]; 
     116                if(parser) { 
     117                    geometry = parser.apply(this, [nodeList[0]]); 
     118                } else { 
     119                    OpenLayers.Console.error("Unsupported geometry type: " + 
     120                                             type); 
     121                } 
     122                // stop looking for different geometry types 
     123                break; 
     124            } 
     125        } 
    76126 
    77         var feature = new OpenLayers.Feature.Vector(); 
     127        // construct feature (optionally with attributes) 
     128        var attributes; 
     129        if(this.extractAttributes) { 
     130            attributes = this.parseAttributes(node); 
     131        } 
     132        var feature = new OpenLayers.Feature.Vector(geometry, attributes); 
    78133 
    79         // match Point 
    80         if (OpenLayers.Ajax.getElementsByTagNameNS(xmlNode, 
    81             this.kmlns, "", "Point").length != 0) { 
    82             var point = OpenLayers.Ajax.getElementsByTagNameNS(xmlNode, 
    83                 this.kmlns, "", "Point")[0]; 
    84              
    85             p = this.parseCoords(point); 
    86             if (p.points) { 
    87                 geom = p.points[0]; 
    88                 // TBD Bounds only set for one of multiple geometries 
    89                 geom.extendBounds(p.bounds); 
     134        var fid = node.getAttribute("id"); 
     135        if(fid != null) { 
     136            feature.fid = fid; 
     137        } 
     138 
     139        return feature; 
     140    },         
     141     
     142    /** 
     143     * Property: parseGeometry 
     144     * Properties of this object are the functions that parse geometries based 
     145     *     on their type. 
     146     */ 
     147    parseGeometry: { 
     148         
     149        /** 
     150         * Method: parseGeometry.point 
     151         * Given a KML node representing a point geometry, create an OpenLayers 
     152         *     point geometry. 
     153         * 
     154         * Parameters: 
     155         * node - {DOMElement} A KML Point node. 
     156         * 
     157         * Returns: 
     158         * {<OpenLayers.Geometry.Point>} A point geometry. 
     159         */ 
     160        point: function(node) { 
     161            var nodeList = this.getElementsByTagNameNS(node, this.kmlns, 
     162                                                       "coordinates"); 
     163            var coords = []; 
     164            if(nodeList.length > 0) { 
     165                var coordString = nodeList[0].firstChild.nodeValue; 
     166                coordString = coordString.replace(this.regExes.removeSpace, ""); 
     167                coords = coordString.split(","); 
    90168            } 
     169 
     170            var point = null; 
     171            if(coords.length) { 
     172                // preserve third dimension 
     173                if(coords.length == 2) { 
     174                    coords[2] = null; 
     175                } 
     176                point = new OpenLayers.Geometry.Point(coords[0], coords[1], 
     177                                                      coords[2]); 
     178            } 
     179            return point; 
     180        }, 
    91181         
    92         // match LineString  
    93         } else if (OpenLayers.Ajax.getElementsByTagNameNS(xmlNode, 
    94             this.kmlns, "", "LineString").length != 0) { 
    95             var linestring = OpenLayers.Ajax.getElementsByTagNameNS(xmlNode, 
    96                 this.kmlns, "", "LineString")[0]; 
    97             p = this.parseCoords(linestring); 
    98             if (p.points) { 
    99                 geom = new OpenLayers.Geometry.LineString(p.points); 
    100                 // TBD Bounds only set for one of multiple geometries 
    101                 geom.extendBounds(p.bounds); 
     182        /** 
     183         * Method: parseGeometry.linestring 
     184         * Given a KML node representing a linestring geometry, create an 
     185         *     OpenLayers linestring geometry. 
     186         * 
     187         * Parameters: 
     188         * node - {DOMElement} A KML LineString node. 
     189         * 
     190         * Returns: 
     191         * {<OpenLayers.Geometry.LineString>} A linestring geometry. 
     192         */ 
     193        linestring: function(node, ring) { 
     194            var nodeList = this.getElementsByTagNameNS(node, this.kmlns, 
     195                                                       "coordinates"); 
     196            var coords; 
     197            var numPoints; 
     198            if(nodeList.length > 0) { 
     199                var coordString = nodeList[0].firstChild.nodeValue; 
     200                coordString = coordString.replace(this.regExes.trimSpace, 
     201                                                  ""); 
     202                coordString = coordString.replace(this.regExes.trimComma, 
     203                                                  ","); 
     204                var pointList = coordString.split(this.regExes.splitSpace); 
     205                numPoints = pointList.length; 
     206                var points = new Array(numPoints); 
     207                var numCoords; 
     208                for(var i=0; i<numPoints; ++i) { 
     209                    coords = pointList[i].split(","); 
     210                    numCoords = coords.length; 
     211                    if(numCoords > 1) { 
     212                        if(coords.length == 2) { 
     213                            coords[2] = null; 
     214                        } 
     215                        points[i] = new OpenLayers.Geometry.Point(coords[0], 
     216                                                                  coords[1], 
     217                                                                  coords[2]); 
     218                    } else { 
     219                        points[i] = new OpenLayers.Geometry.Point(); 
     220                    } 
     221                } 
    102222            } 
     223 
     224            var line = null; 
     225            if(numPoints) { 
     226                if(ring) { 
     227                    line = new OpenLayers.Geometry.LinearRing(points); 
     228                } else { 
     229                    line = new OpenLayers.Geometry.LineString(points); 
     230                } 
     231            } 
     232            return line; 
     233        }, 
     234         
     235        /** 
     236         * Method: parseGeometry.polygon 
     237         * Given a KML node representing a polygon geometry, create an 
     238         *     OpenLayers polygon geometry. 
     239         * 
     240         * Parameters: 
     241         * node - {DOMElement} A KML Polygon node. 
     242         * 
     243         * Returns: 
     244         * {<OpenLayers.Geometry.Polygon>} A polygon geometry. 
     245         */ 
     246        polygon: function(node) { 
     247            var nodeList = this.getElementsByTagNameNS(node, this.kmlns, 
     248                                                       "LinearRing"); 
     249            var components = []; 
     250            if(nodeList.length > 0) { 
     251                // this assumes exterior ring first, inner rings after 
     252                var ring; 
     253                for(var i=0; i<nodeList.length; ++i) { 
     254                    ring = this.parseGeometry.linestring.apply(this, 
     255                                                        [nodeList[i], true]); 
     256                    if(ring) { 
     257                        components.push(ring); 
     258                    } 
     259                } 
     260            } 
     261            return new OpenLayers.Geometry.Polygon(components); 
     262        }, 
     263         
     264        /** 
     265         * Method: parseGeometry.multigeometry 
     266         * Given a KML node representing a multigeometry, create an 
     267         *     OpenLayers geometry collection. 
     268         * 
     269         * Parameters: 
     270         * node - {DOMElement} A KML MultiGeometry node. 
     271         * 
     272         * Returns: 
     273         * {<OpenLayers.Geometry.Polygon>} A geometry collection. 
     274         */ 
     275        multigeometry: function(node) { 
     276            var child, parser; 
     277            var parts = []; 
     278            var children = node.childNodes; 
     279            for(var i=0; i<children.length; ++i ) { 
     280                child = children[i]; 
     281                if(child.nodeType == 1) { 
     282                    type = (child.prefix) ? 
     283                            child.nodeName.split(":")[1] : 
     284                            child.nodeName; 
     285                    var parser = this.parseGeometry[type.toLowerCase()]; 
     286                    if(parser) { 
     287                        parts.push(parser.apply(this, [child])); 
     288                    } 
     289                } 
     290            } 
     291            return new OpenLayers.Geometry.Collection(parts); 
    103292        } 
    104293         
    105         feature.geometry = geom; 
    106         feature.attributes = this.parseAttributes(xmlNode); 
    107          
    108         return feature; 
    109     },         
    110      
     294    }, 
     295 
    111296    /** 
    112297     * Method: parseAttributes 
    113      * recursive function parse the attributes of a KML node. 
    114      * Searches for any child nodes which aren't geometries, 
    115      * and gets their value. 
    116298     * 
    117299     * Parameters: 
    118      * xmlNode - {<DOMElement>}  
     300     * node - {<DOMElement>} 
     301     * 
     302     * Returns: 
     303     * {Object} An attributes object. 
    119304     */ 
    120     parseAttributes: function(xmlNode) { 
    121         var nodes = xmlNode.childNodes; 
     305    parseAttributes: function(node) { 
    122306        var attributes = {}; 
    123         for(var i = 0; i < nodes.length; i++) { 
    124             var name = nodes[i].nodeName; 
    125             var value = OpenLayers.Util.getXmlNodeValue(nodes[i]); 
    126             // Ignore Geometry attributes 
    127             // match ".//gml:pos|.//gml:posList|.//gml:coordinates" 
    128             if((name.search(":pos")!=-1) 
    129               ||(name.search(":posList")!=-1) 
    130               ||(name.search(":coordinates")!=-1)){ 
    131                continue;     
     307        // assume attribute nodes are type 1 children with a type 3 child 
     308        var child, grandchildren, grandchild; 
     309        var children = node.childNodes; 
     310        for(var i=0; i<children.length; ++i) { 
     311            child = children[i]; 
     312            if(child.nodeType == 1) { 
     313                grandchildren = child.childNodes; 
     314                if(grandchildren.length == 1) { 
     315                    grandchild = grandchildren[0]; 
     316                    if(grandchild.nodeType == 3) { 
     317                        name = (child.prefix) ? 
     318                                child.nodeName.split(":")[1] : 
     319                                child.nodeName; 
     320                        value = grandchild.nodeValue.replace( 
     321                                                this.regExes.trimSpace, ""); 
     322                        attributes[name] = value; 
     323                    } 
     324                } 
    132325            } 
    133              
    134             // Check for a leaf node 
    135             if((nodes[i].childNodes.length == 1 && nodes[i].childNodes[0].nodeName == "#text") 
    136                 || (nodes[i].childNodes.length == 0 && nodes[i].nodeName!="#text")) { 
    137                 attributes[name] = value; 
    138             } 
    139             OpenLayers.Util.extend(attributes, this.parseAttributes(nodes[i])) 
    140         }    
     326        } 
    141327        return attributes; 
    142328    }, 
    143      
     329 
    144330    /** 
    145      * Method: parseCoords 
    146      * Extract Geographic coordinates from an XML node. 
     331     * APIMethod: write 
     332     * Accept Feature Collection, and return a string.  
     333     *  
     334     * Parameters: 
     335     * features - An array of <OpenLayers.Feature.Vector> features. 
    147336     * 
     337     * Returns: 
     338     * {String} A KML string. 
     339     */ 
     340     write: function(features) { 
     341        if(!(features instanceof Array)) { 
     342            features = [features]; 
     343        } 
     344        var kml = this.createElementNS(this.kmlns, "kml"); 
     345        var folder = this.createFolderXML(); 
     346        for(var i=0; i<features.length; ++i) { 
     347            folder.appendChild(this.createPlacemarkXML(features[i])); 
     348        } 
     349        kml.appendChild(folder); 
     350        return OpenLayers.Format.XML.prototype.write.apply(this, [kml]); 
     351     }, 
     352 
     353    /** 
     354     * Method: createFolderXML 
     355     * Creates and returns a KML folder node 
     356     *  
     357     * Returns: 
     358     * {DOMElement} 
     359     */ 
     360    createFolderXML: function() { 
     361        // Folder name 
     362        var folderName = this.createElementNS(this.kmlns, "name"); 
     363        var folderNameText = this.createTextNode(this.foldersName);  
     364        folderName.appendChild(folderNameText); 
     365 
     366        // Folder description 
     367        var folderDesc = this.createElementNS(this.kmlns, "description");         
     368        var folderDescText = this.createTextNode(this.foldersDesc);  
     369        folderDesc.appendChild(folderDescText); 
     370 
     371        // Folder 
     372        var folder = this.createElementNS(this.kmlns, "Folder"); 
     373        folder.appendChild(folderName); 
     374        folder.appendChild(folderDesc); 
     375         
     376        return folder; 
     377    }, 
     378 
     379    /** 
     380     * Method: createPlacemarkXML 
     381     * Creates and returns a KML placemark node representing the given feature.  
     382     *  
    148383     * Parameters: 
    149      * xmlNode - {<XMLNode>}  
     384     * feature - {<OpenLayers.Feature.Vector>} 
    150385     *  
    151386     * Returns: 
    152      * An array of <OpenLayers.Geometry.Point> points. 
     387     * {DOMElement} 
    153388     */ 
    154     parseCoords: function(xmlNode) { 
    155         var p = []; 
    156         p.points = []; 
    157         // TBD: Need to handle an array of coordNodes not just coordNodes[0] 
     389    createPlacemarkXML: function(feature) {         
     390        // Placemark name 
     391        var placemarkName = this.createElementNS(this.kmlns, "name"); 
     392        var name = (feature.attributes.name) ? 
     393                    feature.attributes.name : feature.id; 
     394        placemarkName.appendChild(this.createTextNode(name)); 
     395 
     396        // Placemark description 
     397        var placemarkDesc = this.createElementNS(this.kmlns, "description"); 
     398        var desc = (feature.attributes.description) ? 
     399                    feature.attributes.description : this.placemarksDesc; 
     400        placemarkDesc.appendChild(this.createTextNode(desc)); 
    158401         
    159         var coordNodes = OpenLayers.Ajax.getElementsByTagNameNS(xmlNode, this.kmlns, "", "coordinates")[0]; 
    160         var coordString = OpenLayers.Util.getXmlNodeValue(coordNodes); 
     402        // Placemark 
     403        var placemarkNode = this.createElementNS(this.kmlns, "Placemark"); 
     404        if(feature.fid != null) { 
     405            placemarkNode.setAttribute("id", feature.fid); 
     406        } 
     407        placemarkNode.appendChild(placemarkName); 
     408        placemarkNode.appendChild(placemarkDesc); 
     409 
     410        // Geometry node (Point, LineString, etc. nodes) 
     411        var geometryNode = this.buildGeometryNode(feature.geometry); 
     412        placemarkNode.appendChild(geometryNode);         
    161413         
    162         var firstCoord = coordString.split(" "); 
     414        // TBD - deal with remaining (non name/description) attributes. 
     415        return placemarkNode; 
     416    },     
     417 
     418    /** 
     419     * Method: buildGeometryNode 
     420     * Builds and returns a KML geometry node with the given geometry. 
     421     *  
     422     * Parameters: 
     423     * geometry - {<OpenLayers.Geometry>} 
     424     *  
     425     * Returns: 
     426     * {DOMElement} 
     427     */ 
     428    buildGeometryNode: function(geometry) { 
     429        var className = geometry.CLASS_NAME; 
     430        var type = className.substring(className.lastIndexOf(".") + 1); 
     431        var builder = this.buildGeometry[type.toLowerCase()]; 
     432        var node = null; 
     433        if(builder) { 
     434            node = builder.apply(this, [geometry]); 
     435        } 
     436        return node; 
     437    }, 
     438 
     439    /** 
     440     * Property: buildGeometry 
     441     * Object containing methods to do the actual geometry node building 
     442     *     based on geometry type. 
     443     */ 
     444    buildGeometry: { 
     445        // TBD: Anybody care about namespace aliases here (these nodes have 
     446        //    no prefixes)? 
     447 
     448        /** 
     449         * Method: buildGeometry.point 
     450         * Given an OpenLayers point geometry, create a KML point. 
     451         * 
     452         * Parameters: 
     453         * geometry - {<OpenLayers.Geometry.Point>} A point geometry. 
     454         * 
     455         * Returns: 
     456         * {DOMElement} A KML point node. 
     457         */ 
     458        point: function(geometry) { 
     459            var kml = this.createElementNS(this.kmlns, "Point"); 
     460            kml.appendChild(this.buildCoordinatesNode(geometry)); 
     461            return kml; 
     462        }, 
    163463         
    164         while (firstCoord[0] == "")  
    165             firstCoord.shift(); 
     464        /** 
     465         * Method: buildGeometry.multipoint 
     466         * Given an OpenLayers multipoint geometry, create a KML 
     467         *     GeometryCollection. 
     468         * 
     469         * Parameters: 
     470         * geometry - {<OpenLayers.Geometry.Point>} A multipoint geometry. 
     471         * 
     472         * Returns: 
     473         * {DOMElement} A KML GeometryCollection node. 
     474         */ 
     475        multipoint: function(geometry) { 
     476            return this.buildGeometry.collection(geometry); 
     477        }, 
     478 
     479        /** 
     480         * Method: buildGeometry.linestring 
     481         * Given an OpenLayers linestring geometry, create a KML linestring. 
     482         * 
     483         * Parameters: 
     484         * geometry - {<OpenLayers.Geometry.LineString>} A linestring geometry. 
     485         * 
     486         * Returns: 
     487         * {DOMElement} A KML linestring node. 
     488         */ 
     489        linestring: function(geometry) { 
     490            var kml = this.createElementNS(this.kmlns, "LineString"); 
     491            kml.appendChild(this.buildCoordinatesNode(geometry)); 
     492            return kml; 
     493        }, 
    166494         
    167         var dim = firstCoord[0].split(",").length; 
     495        /** 
     496         * Method: buildGeometry.multilinestring 
     497         * Given an OpenLayers multilinestring geometry, create a KML 
     498         *     GeometryCollection. 
     499         * 
     500         * Parameters: 
     501         * geometry - {<OpenLayers.Geometry.Point>} A multilinestring geometry. 
     502         * 
     503         * Returns: 
     504         * {DOMElement} A KML GeometryCollection node. 
     505         */ 
     506        multilinestring: function(geometry) { 
     507            return this.buildGeometry.collection(geometry); 
     508        }, 
    168509 
    169         // Extract an array of Numbers from CoordString 
    170         var nums = (coordString) ? coordString.split(/[, \n\t]+/) : []; 
     510        /** 
     511         * Method: buildGeometry.linearring 
     512         * Given an OpenLayers linearring geometry, create a KML linearring. 
     513         * 
     514         * Parameters: 
     515         * geometry - {<OpenLayers.Geometry.LinearRing>} A linearring geometry. 
     516         * 
     517         * Returns: 
     518         * {DOMElement} A KML linearring node. 
     519         */ 
     520        linearring: function(geometry) { 
     521            var kml = this.createElementNS(this.kmlns, "LinearRing"); 
     522            kml.appendChild(this.buildCoordinatesNode(geometry)); 
     523            return kml; 
     524        }, 
    171525         
     526        /** 
     527         * Method: buildGeometry.polygon 
     528         * Given an OpenLayers polygon geometry, create a KML polygon. 
     529         * 
     530         * Parameters: 
     531         * geometry - {<OpenLayers.Geometry.Polygon>} A polygon geometry. 
     532         * 
     533         * Returns: 
     534         * {DOMElement} A KML polygon node. 
     535         */ 
     536        polygon: function(geometry) { 
     537            var kml = this.createElementNS(this.kmlns, "Polygon"); 
     538            var rings = geometry.components; 
     539            var ringMember, ringGeom, type; 
     540            for(var i=0; i<rings.length; ++i) { 
     541                type = (i==0) ? "outerBoundaryIs" : "innerBoundaryIs"; 
     542                ringMember = this.createElementNS(this.kmlns, type); 
     543                ringGeom = this.buildGeometry.linearring.apply(this, 
     544                                                               [rings[i]]); 
     545                ringMember.appendChild(ringGeom); 
     546                kml.appendChild(ringMember); 
     547            } 
     548            return kml; 
     549        }, 
    172550         
    173         // Remove elements caused by leading and trailing white space 
    174         while (nums[0] == "")  
    175             nums.shift(); 
    176          
    177         while (nums[nums.length-1] == "")  
    178             nums.pop(); 
    179          
    180         for(i = 0; i < nums.length; i = i + dim) { 
    181             x = parseFloat(nums[i]); 
    182             y = parseFloat(nums[i+1]); 
    183             p.points.push(new OpenLayers.Geometry.Point(x, y)); 
    184              
    185             if (!p.bounds) { 
    186                 p.bounds = new OpenLayers.Bounds(x, y, x, y); 
    187             } else { 
    188                 p.bounds.extend(x, y); 
     551        /** 
     552         * Method: buildGeometry.multipolygon 
     553         * Given an OpenLayers multipolygon geometry, create a KML 
     554         *     GeometryCollection. 
     555         * 
     556         * Parameters: 
     557         * geometry - {<OpenLayers.Geometry.Point>} A multipolygon geometry. 
     558         * 
     559         * Returns: 
     560         * {DOMElement} A KML GeometryCollection node. 
     561         */ 
     562        multipolygon: function(geometry) { 
     563            return this.buildGeometry.collection(geometry); 
     564        }, 
     565 
     566        /** 
     567         * Method: buildGeometry.collection 
     568         * Given an OpenLayers geometry collection, create a KML MultiGeometry. 
     569         * 
     570         * Parameters: 
     571         * geometry - {<OpenLayers.Geometry.Collection>} A geometry collection. 
     572         * 
     573         * Returns: 
     574         * {DOMElement} A KML MultiGeometry node. 
     575         */ 
     576        collection: function(geometry) { 
     577            var kml = this.createElementNS(this.kmlns, "MultiGeometry"); 
     578            var child; 
     579            for(var i=0; i<geometry.components.length; ++i) { 
     580                child = this.buildGeometryNode.apply(this, 
     581                                                     [geometry.components[i]]); 
     582                if(child) { 
     583                    kml.appendChild(child); 
     584                } 
    189585            } 
     586            return kml; 
    190587        } 
    191         return p; 
    192588    }, 
    193589 
     590    /** 
     591     * Method: buildCoordinatesNode 
     592     * Builds and returns the KML coordinates node with the given geometry 
     593     * <coordinates>...</coordinates> 
     594     *  
     595     * Parameters: 
     596     * geometry - {<OpenLayers.Geometry>} 
     597     *  
     598     * Return: 
     599     * {DOMElement} 
     600     */      
     601    buildCoordinatesNode: function(geometry) { 
     602        var coordinatesNode = this.createElementNS(this.kmlns, "coordinates"); 
     603         
     604        var path; 
     605        var points = geometry.components; 
     606        if(points) { 
     607            // LineString or LinearRing 
     608            var point; 
     609            var numPoints = points.length; 
     610            var parts = new Array(numPoints); 
     611            for(var i=0; i<numPoints; ++i) { 
     612                point = points[i]; 
     613                parts[i] = point.x + "," + point.y; 
     614            } 
     615            path = parts.join(" "); 
     616        } else { 
     617            // Point 
     618            path = geometry.x + "," + geometry.y; 
     619        } 
     620         
     621        var txtNode = this.createTextNode(path); 
     622        coordinatesNode.appendChild(txtNode); 
     623         
     624        return coordinatesNode; 
     625    },     
     626 
    194627    CLASS_NAME: "OpenLayers.Format.KML"  
    195 });      
     628}); 
  • lib/OpenLayers/Renderer/Elements.js

    old new  
    110110     * featureId - {String} 
    111111     */ 
    112112    drawGeometry: function(geometry, style, featureId) { 
    113  
    114         if ((geometry.CLASS_NAME == "OpenLayers.Geometry.MultiPoint") || 
    115             (geometry.CLASS_NAME == "OpenLayers.Geometry.MultiLineString") || 
    116             (geometry.CLASS_NAME == "OpenLayers.Geometry.MultiPolygon")) { 
     113        var className = geometry.CLASS_NAME; 
     114        if ((className == "OpenLayers.Geometry.Collection") || 
     115            (className == "OpenLayers.Geometry.MultiPoint") || 
     116            (className == "OpenLayers.Geometry.MultiLineString") || 
     117            (className == "OpenLayers.Geometry.MultiPolygon")) { 
    117118            for (var i = 0; i < geometry.components.length; i++) { 
    118119                this.drawGeometry(geometry.components[i], style, featureId); 
    119120            } 
  • examples/vector-formats.html

    old new  
    7777            formats = { 
    7878                wkt: new OpenLayers.Format.WKT(), 
    7979                geojson: new OpenLayers.Format.GeoJSON(), 
    80                 gml: new OpenLayers.Format.GML() //
    81                 //kml: new OpenLayers.Format.KML() 
     80                gml: new OpenLayers.Format.GML()
     81                kml: new OpenLayers.Format.KML() 
    8282            }; 
    8383             
    8484            map.setCenter(new OpenLayers.LonLat(0, 0), 1); 
     
    146146            <label for="formatType">Format</label> 
    147147            <select name="formatType" id="formatType"> 
    148148                <option value="geojson" selected="selected">GeoJSON</option> 
    149                 <!--<option value="kml">KML</option>--
     149                <option value="kml">KML</option
    150150                <option value="gml">GML</option> 
    151151                <option value="wkt">Well-Known Text (WKT)</option> 
    152152            </select>