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-a、icon-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>
我正在尝试制作一个 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-a、icon-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>