Openlayers 4 中的 LineString 方向箭头

LineString direction arrows in Openlayers 4

我正在尝试制作一个 LineString,它在每条线的末尾都有箭头以显示路线的方向。我使用官方网站的示例:https://openlayers.org/en/latest/examples/line-arrows.html 示例代码通过用户的绘图创建箭头,但我需要给定 LineString 的箭头。 我的代码包含路线终点和终点的图标。 当我使用

'route': new ol.style.Style({
      stroke: new ol.style.Stroke({
        width: 6, color: [23, 120, 22, 0.6]
      })
    }),

在样式中,我的代码有效。但是当我从示例中为 Linestring 设置样式时,它给我一个错误提示 "Uncaught TypeError: c.Y is not a function".

这是我的代码:

var points = [
  [76.8412, 43.2245], [76.8405, 43.2210], [76.8479, 43.2200], [76.8512, 43.2220]
];

var route = new ol.geom.LineString(points);
route.transform('EPSG:4326', 'EPSG:3857');

var routeFeature = new ol.Feature({
  type: 'route',
  geometry: route
});
var startMarker = new ol.Feature({
  type: 'icon-a',
  geometry: new ol.geom.Point(ol.proj.fromLonLat(points[0]))
});
var endMarker = new ol.Feature({
  type: 'icon-b',
  geometry: new ol.geom.Point(ol.proj.fromLonLat(points[points.length - 1]))
});

var styles = {
  'route': function(feature) {
    var geometry = feature.getGeometry();
    var styles = [
      // linestring
      new ol.style.Style({
        stroke: new ol.style.Stroke({
          color: '#ffcc33',
          width: 2
        }),
        image: new ol.style.Icon({
      anchor: [0.5, 1],
      src: 'img/icon-a.png'
    })
      })
    ];

    geometry.forEachSegment(function(start, end) {
      var dx = end[0] - start[0];
      var dy = end[1] - start[1];
      var rotation = Math.atan2(dy, dx);
      // arrows
      styles.push(new ol.style.Style({
        geometry: new ol.geom.Point(end),
        image: new ol.style.Icon({
          src: 'https://openlayers.org/en/v4.6.3/examples/data/arrow.png',
          anchor: [0.75, 0.5],
          rotateWithView: true,
          rotation: -rotation
        })
      }));
    });

    return styles;
  },
  'icon-a': new ol.style.Style({
    image: new ol.style.Icon({
      anchor: [0.5, 1],
      src: 'img/icon-a.png'
    })
  }),
  'icon-b': new ol.style.Style({
    image: new ol.style.Icon({
      anchor: [0.5, 1],
      src: 'img/icon-b.png'
    })
  })
};

var vectorLayer = new ol.layer.Vector({
  source: new ol.source.Vector({
    features: [routeFeature, startMarker, endMarker]
  }),
  style: function(feature) {
    return styles[feature.get('type')];
  }
});

var center = ol.proj.fromLonLat([76.8512, 43.2220]);
var map = new ol.Map({
  target: document.getElementById('map'),
  view: new ol.View({
    center: center,
    zoom: 15,
    minZoom: 2,
    maxZoom: 19
  }),
  layers: [
    new ol.layer.Tile({
      source: new ol.source.OSM()
    }),
    vectorLayer
  ]
});
#map {
  /* just for testing purposes */
  width: 100%;
  min-width: 100px;
  max-width: 500px;
  margin-top: 50px;
  height: 50px;
}
<link href="https://openlayers.org/en/v4.6.4/css/ol.css" rel="stylesheet"/>
<script src="https://openlayers.org/en/v4.6.4/build/ol-debug.js"></script>
<div id="map"></div>

首先,您可以使用ol-debug.js代替ol.js,它是未压缩的并且有助于调试。你得到的例外是

TypeError: style.getImage is not a function (Line 30443)

你得到这个错误是因为你的样式对象是混合的:一些样式是函数,一些是普通的 Style 对象。

您可能认为 OL 可以同时处理两者,通常您是对的。但是,你提供了一个函数给vectorLayer,所以OL检测到你提供了一个函数并调用它。该函数的 return 值应该是一个样式对象。但是对于 route,return 是一个函数!

所以当OL来电时

style: function(feature) {
    return styles[feature.get('type')];
}

它获取类型 icon-aicon-b 的样式,但获取 route。 您需要增强样式功能来处理这种特殊情况:

style: function(feature) {
  const myStyle = stylesMap[feature.get('type')];
  if (myStyle instanceof Function) {
    return myStyle(feature);
  }
  return myStyle;
}

PS:对一个变量使用相同的名称两次(样式)是不好的做法,会导致奇怪的错误。

这是可运行的例子:

var points = [
  [76.8412, 43.2245],
  [76.8405, 43.2210],
  [76.8479, 43.2200],
  [76.8512, 43.2220]
];

var route = new ol.geom.LineString(points);
route.transform('EPSG:4326', 'EPSG:3857');

var routeFeature = new ol.Feature({
  type: 'route',
  geometry: route
});
var startMarker = new ol.Feature({
  type: 'icon-a',
  geometry: new ol.geom.Point(ol.proj.fromLonLat(points[0]))
});
var endMarker = new ol.Feature({
  type: 'icon-b',
  geometry: new ol.geom.Point(ol.proj.fromLonLat(points[points.length - 1]))
});

var stylesMap = {
  'route': function(feature) {
    var geometry = feature.getGeometry();
    var styles = [
      // linestring
      new ol.style.Style({
        stroke: new ol.style.Stroke({
          color: '#ffcc33',
          width: 2
        }),
        image: new ol.style.Icon({
          anchor: [0.5, 1],
          src: 'img/icon-a.png'
        })
      })
    ];

    geometry.forEachSegment(function(start, end) {
      var dx = end[0] - start[0];
      var dy = end[1] - start[1];
      var rotation = Math.atan2(dy, dx);
      // arrows
      styles.push(new ol.style.Style({
        geometry: new ol.geom.Point(end),
        image: new ol.style.Icon({
          src: 'https://openlayers.org/en/v4.6.5/examples/data/arrow.png',
          anchor: [0.75, 0.5],
          rotateWithView: true,
          rotation: -rotation
        })
      }));
    });

    return styles;
  },
  'icon-a': new ol.style.Style({
    image: new ol.style.Icon({
      anchor: [0.5, 1],
      src: 'img/icon-a.png'
    })
  }),
  'icon-b': new ol.style.Style({
    image: new ol.style.Icon({
      anchor: [0.5, 1],
      src: 'img/icon-b.png'
    })
  })
};

var vectorLayer = new ol.layer.Vector({
  source: new ol.source.Vector({
    features: [routeFeature, startMarker, endMarker]
  }),
  style: function(feature) {
    const myStyle = stylesMap[feature.get('type')];
    if (myStyle instanceof Function) {
      return myStyle(feature);
    }
    return myStyle;
  }
});

var center = ol.proj.fromLonLat([76.8512, 43.2220]);
var map = new ol.Map({
  target: document.getElementById('map'),
  view: new ol.View({
    center: center,
    zoom: 15,
    minZoom: 2,
    maxZoom: 19
  }),
  layers: [
    new ol.layer.Tile({
      source: new ol.source.OSM()
    }),
    vectorLayer
  ]
});
html,
body {
  width: 100%;
  height: 100%;
  padding: 0px;
  margin: 0px;
}

#map {
  /* just for testing purposes */
  width: 100%;
  height: 100%;
}
<link href="https://openlayers.org/en/v4.6.5/css/ol.css" rel="stylesheet" />
<script src="https://openlayers.org/en/v4.6.5/build/ol-debug.js"></script>
<div id="map"></div>