Wednesday, April 2, 2014

Adding Icon Labels to Openlayers with KML styles

I've been working on a project that uses OpenLayers, KML, Extjs4, GeoExt, and a few other libraries.  On this project, customers would like to use a map to track assets.  They want to see a specific icon for a type of asset with a label below the icon.  What we found was that OpenLayers doesn't support KML styles along with OpenLayers styleMap on a Vector layer.

Searching online turned up a handful of individuals with the same issue, but no solution. Here is how I solved it:

Problematic Code example:
Setup a styleMap:
var styleMap = new OpenLayers.StyleMap({'default':{
    label : "${name}",
    fontColor: "#000000",
    fontSize: "11px",
    labelAlign: "center",
    pointRadius: 2,
    labelXOffset : -16,
    labelYOffset : 0,
    labelSelect: true

Setup to get and parse KML:
var myKmlFormat = new OpenLayers.Format.KML({
    internalProjection: sphericalMercatorProj,
    externalProjection: mapProj,
    extractStyles: true,
    extractAttributes: true,
    maxDepth: 2

Finally, setup the vector layer:
var layer = new OpenLayers.Layer.Vector("KML", {
    projection: latLonProj,
    strategies: [new OpenLayers.Strategy.Fixed()],
    protocol: new OpenLayers.Protocol.HTTP({
    url: myKmlUrl,
    format: myKmlForma 
    styleMap: kmlStyleMap,
    eventListeners: { 'loadend': kmlLoaded },
    renderers: renderer

The KML:
 <name>Geolocation Case: 17564</name>
  <style id="style1">
   <name>My Point</name>

Google Earth will use the Placemark Name as the label, OpenLayers does not.  The line "extractStyles: true," in the OpenLayers KML section tells OpenLayers to parse the styles in the KML.  Setting it to false tells OpenLayers to ignore the style sections of the KML.

When this boolean is set to true, OpenLayers.Format.KML ignores manually added styleMap, such as the line "styleMap: kmlStyleMap".  So if your wanting a label on your placemark, it won't happen.  It is an 'or', not an 'and'.  This is a bug in OpenLayers in my opinion.

So, how do you get around this issue and add a label?  Well, read on.

Here is the Solution Code:

First off, don't create a styleMap and add it to the Vector constructor.  Add a listener to the layer:{
  loadend : this.addLabel

Now, go through each icon (feature) and give the style a label, an offset, and anything else your label may need.
addLabel : function(event) {
    var features = event.object.features;

    for (var i = 0, len = features.length; i < len; i++) {
        var style = features[i]['style'];
        var attributes = features[i]['attributes'];
        if (!Ext.isEmpty(style) && !Ext.isEmpty(attributes)){
            style.label =;
            style.labelYOffset = -16;
            style.fontSize = '11px';
            style.fontColor = '#000000';
            style.labelSelect = true;

The icons on the map should now have labels.