Search code examples
javascriptstyleslineopenlayers

Symbolization of lines on the OpenLayers map


How to make a complex symbolization of the line?

I do not know what this style is called, but you need something like this:

  1. broken line?

  2. dotted line (helped here):

    [
        new ol.style.Style({
            stroke: new ol.style.Stroke({
                width: 5,
                color: 'black'
            })
        }),
        new ol.style.Style({
            stroke: new ol.style.Stroke({
                width: 3,
                color: 'white',
                lineCap: 'butt',
                lineDash: [9, 9]
            })
        })
    ]
    

I can't find information anywhere on how to set such a style, although they are often found on schematic maps.


Solution

  • Number 2 can be done using a style function which sets a zigzag line geometry in the style. This code is based on OpenLayers 3: Offset stroke style but instead of showing the parallel lines it works along the original line alternately plotting the closest points on each of the parallel lines.

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="utf-8" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0" />
        <link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/openlayers/openlayers.github.io@master/en/v6.6.1/css/ol.css" />
        <style>
          html, body, .map {
            margin: 0;
            padding: 0;
            width: 100%;
            height: 100%;
          }
        </style>
    </head>
    <body>
    
    <div id="map" class="map"></div>
    <script src="https://cdn.jsdelivr.net/gh/openlayers/openlayers.github.io@master/en/v6.6.1/build/ol.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/mathjs/9.4.4/math.min.js"></script>
    <script>
    
    function styleFunction(width, strokeWidth, color) {
      var style = new ol.style.Style({
        stroke: new ol.style.Stroke({
          color: color,
          width: strokeWidth
        })
      });
      return function(feature, resolution) {
        var lines = [];
        var geom = feature.getGeometry();
        if (geom.getType() == "LineString") {
          for (var line = 0; line < 2; line++) {
            var dist = width * resolution * (line - 1/2);
            var coords = [];
            var counter = 0;
            geom.forEachSegment(function(from, to) {
              var angle = Math.atan2(to[1] - from[1], to[0] - from[0]);
              var newFrom = [
                Math.sin(angle) * dist + from[0],
                -Math.cos(angle) * dist + from[1]
              ];
              var newTo = [
                Math.sin(angle) * dist + to[0],
                -Math.cos(angle) * dist + to[1]
              ];
              coords.push(newFrom);
              coords.push(newTo);
              if (coords.length > 2) {
                var intersection = math.intersect(coords[counter], coords[counter+1], coords[counter+2], coords[counter+3]);
                coords[counter+1] = (intersection) ? intersection : coords[counter+1];
                coords[counter+2] = (intersection) ? intersection : coords[counter+2];
                counter += 2;
              }
            });
            lines.push(new ol.geom.LineString(coords));
          }
          var length = geom.getLength();
          var intervals = Math.ceil(length / (width * resolution));
          var coords = [];
          coords.push(geom.getCoordinateAt(0));
          for (var i= 0; i < intervals; i++) {
            coords.push(
              lines[i % 2].getClosestPoint(
                geom.getCoordinateAt((2 * i + 1) / (intervals * 2))
              )
            );
          }
          coords.push(geom.getCoordinateAt(1));
          style.setGeometry(new ol.geom.LineString(coords));
          return style;
        }
      };
    }
    
    
    var raster = new ol.layer.Tile({
      source:  new ol.source.OSM() 
    });
    
    var source = new ol.source.Vector();
    
    var vector = new ol.layer.Vector({
      source: source,
      style: styleFunction(4, 2, 'black')
    });
    
    var map = new ol.Map({
      layers: [raster, vector],
      target: 'map',
      view: new ol.View({
        center: [-11000000, 4600000],
        zoom: 4
      })
    });
    
    map.addInteraction(new ol.interaction.Draw({
      source: source,
      type: 'LineString',
      style: styleFunction(4, 2, 'red')
    }));
    
    </script>
    
    </body>
    </html>