Skip to main content

Full control of SVG elements in Cesium billboards

This is a guest post by Yonatan Kra of BIKS Intelligence Solutions originally posted on BIKS Blog. BIKS initiates, designs, and develops complex web applications for big data analytics and information & knowledge extraction.

Cesium billboards are an easy way to mark a point on the globe with an image. For example:

viewer.entities.add({
  position: position,
  billboard: {
    image: svgUrl
  }
});

How can we support more complex symbology? For instance, how do we show several variations based on parameters, e.g., different colors for different categories.

Our solution is to use dataURI. First, we get the text of the SVG (using the textjs plugin for requirejs, for example), then we change the fill attribute color, and finally we create the data URI.

Here’s a live example and the code:

define(['./module', 'text!mySVGFile1.svg', 'text!mySVGFile2.svg'], 
  function (services, mySVGFile1, mySVGFile2) {

    function cesiumRgb2Hex(rgb) {
      return("#" + ((1 << 24) + (rgb.red*255 << 16) + (rgb.green*255 << 8) + rgb.blue*255))
        .toString(16)
        .slice(1);
    }

    function exportSVG(svg){
      // https://developer.mozilla.org/en/DOM/window.btoa;
      return "data:image/svg+xml;base64," + btoa(svg); 
    }

    services.value('mapBillboards', {
      /**
       * @param typeOfSVG - user should know what files are preloaded...
       * @param color - a cesium color object => {red: 1, green: 0 ...}
       */
      getDataURI: function (typeOfSVG, color) {
        var hexColor = cesiumRgb2Hex(color); // get the hex color to fill
        return exportSVG(this[type].replace('<svg', '<svg fill="' + hexColor + '"'));
      },
      mySVGFile1: mySVGFile1,
      mySVGFile2: mySVGFile2
    });
  }
);

The actual color magic happens in the return statement in the getDataURI function. This replaces the <svg with <svg fill="#123432″ (or any color).

Similarly, we can replace any SVG element, including different <g> sections; for instance, to show/hide different elements in order to create complex combinations. Check it out in the live demo.

I haven’t tried it yet, but using svgElement = angular.element(svg); would enable us to better control the SVG itself. We can turn the element back to string using XMLSerializer

(new XMLSerializer()).serializeToString(svgElement));