Search code examples
openlayersangular-openlayers

Openlayers ol.style.Text with multiple colors


Is there a way to set multiple font colors for ol.style.Text class for openlayers 4+?

I am trying to do something like

const label = new ol.style.Style({
        text: new ol.style.Text({
            text: '<color1>X</color1> other text',
            textAlign: 'center',

            font: '11px roboto,sans-serif',
            fill: new ol.style.Fill({
                color: 'white'
            }),
            stroke: new ol.style.Stroke({
                color: 'black',
                lineCap: 'butt',
                width: 4
            }),
            offsetX: 0,
            offsetY: 25.5,
        })

since "other text" length or width is unknown and textAlign must be set to center, i can't add two ol.style.Text classes and position them side by side.

Thanks in advance


Solution

  • There is no solution for this on the library level, but you can quite easily achieve it with two text styles. The trick is to measure the width of both texts using e.g. CanvasRenderingContext2D.measureText, and to adjust the offsetX property of both text styles accordingly:

    var map = new ol.Map({
      target: 'map',
      view: new ol.View({
        center: [0, 0],
        zoom: 0
      })
    });
    
    var point = new ol.Feature(
        new ol.geom.Point([0, 0]));
    
    var text1 = 'X'
    var text2 = ' other text';
    var font = '11px roboto,sans-serif';
    var canvas = document.createElement('canvas');
    var context = canvas.getContext('2d');
    context.font = font;
    var width1 = context.measureText(text1).width;
    var width2 = context.measureText(text2).width;
    
    var layer = new ol.layer.Vector({
      source: new ol.source.Vector({
        features: [point]
      }),
      style: [
        new ol.style.Style({
          image: new ol.style.Circle({
            radius: 4,
            fill: new ol.style.Fill({
              color: 'blue'
            })
          }),
          text: new ol.style.Text({
            font: font,
            text: text1,
            fill: new ol.style.Fill({
              color: 'red'
            }),
            textAlign: 'center',
            textBaseline: 'bottom',
            offsetY: -5,
            offsetX: -width2 / 2
          })
        }),
        new ol.style.Style({
          text: new ol.style.Text({
            font: font,
            text: text2,
            fill: new ol.style.Fill({
              color: 'black'
            }),
            textAlign: 'center',
            textBaseline: 'bottom',
            offsetY: -5,
            offsetX: width1 / 2
          })
        })
      ]
    });
    map.addLayer(layer);
    html, body, #map {
      width: 100%;
      height: 100%;
      margin: 0;
     }
    <link href="https://openlayers.org/en/v4.3.2/css/ol.css" rel="stylesheet"/>
    <script src="https://cdn.rawgit.com/openlayers/openlayers.github.io/master/en/v5.3.0/build/ol.js"></script>
    <div id="map"></div>