I'm trying to make a LineString which has arrows in the end of each line to show direction of the route. I use an example from the official site: https://openlayers.org/en/latest/examples/line-arrows.html The example code creates arrows by user's drawing, but I need arrows for given LineString. My code contains icons for end and finish of the route. When I use
'route': new ol.style.Style({
stroke: new ol.style.Stroke({
width: 6, color: [23, 120, 22, 0.6]
})
}),
in styles, my code works. But when I put style for Linestring from the example, it gives me an error saying "Uncaught TypeError: cY is not a function".
Here is my code:
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>
Firstly, you can use ol-debug.js
instead of ol.js
, which is uncompressed and helps debugging. The exception you get is
TypeError: style.getImage is not a function (Line 30443)
You get that error because your styles object is mixed: some styles are functions, some are plain Style objects.
You might think that OL can handle both, and you are normally right. However, you provide a function to vectorLayer
, so OL detects that you provided a function and calls it. The return value of that function is expected to be a style object. But for route
, that returns a function instead!
So when OL calls
style: function(feature) {
return styles[feature.get('type')];
}
It gets styles for the types icon-a , icon-b , but an function for route . You need to enhance your style function to handle that special case:
style: function(feature) {
const myStyle = stylesMap[feature.get('type')];
if (myStyle instanceof Function) {
return myStyle(feature);
}
return myStyle;
}
PS: Using the same name for a variable twice (styles) is bad practice and can lead to weird bugs.
Here is the runnable example:
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>
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.