除了点本身之外,我还想围绕点特征绘制一个圆。但是,我不希望圆圈可点击。仅通过单击点本身,我想获取指针事件。
例如在我的样式函数中,它是为矢量图层定义的:
styleFunction = (feature, res) => {
const featureCoordinates = feature.getGeometry().getCoordinates()
const pointStyle = new Style({
image: new CircleStyle({
fill: new Fill({
color: 'rgba(200,180,150,0.5)'
}),
radius: 10,
stroke: new Stroke({
color: 'red,
width: 3
}),
}),
});
const nearSearch300m = new Style({
geometry: new Circle(featureCoordinates, 300 / pointresolution),
stroke: new Stroke({
color: 'blue',
width: 2,
lineDash: [2, 3]
})
});
return [pointStyle, nearSearch300m]
实际上,我的合成样式有中点、阴影、文本标签和四个带有标签的同心圆。
从性能角度来看,能够使用尽可能简单的命中检测图像(例如留下文本标签而不进行检测)会更好吗?就我而言,我可以为点背景阴影样式启用命中检测,并从其他样式禁用它。
我尝试定义一个自定义
hitDetectionRenderer = (coordinates, state) => {...
来手动绘制一个10px半径的圆并将其设置为两种样式,但这似乎并不能解决问题。
我还尝试了为 Style hitDetectionRenderer 设置 null 的所有可能版本,但没有成功。
怎样才能达到圆圈对点击事件没有反应的效果?
hitDetectionRenderer
仅覆盖使用 renderer
选项创建的样式。
您可以在两层中使用源代码,将一层设置为您想要检测的样式,另一层设置为您不想检测的样式,然后使用图层过滤器进行命中检测:
<html>
<head>
<style>
html, body, .map {
margin: 0;
padding: 0;
width: 100%;
height: 100%;
}
</style>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/ol.js"></script>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/[email protected]/ol.css">
</head>
<body>
<div id="map" class="map"></div>
<script>
{
const {Circle: CircleStyle, Fill, Stroke, Style} = ol.style;
const {Feature, Map, View} = ol;
const {OSM, Vector: VectorSource} = ol.source;
const {Point, Circle} = ol.geom;
const {ScaleLine, defaults: {defaults: defaultControls}} = ol.control;
const {Tile: TileLayer, Vector: VectorLayer} = ol.layer;
const {fromLonLat, getPointResolution} = ol.proj;
const center = fromLonLat([18.955, 69.652]);
const source = new VectorSource({
features: [
new Feature(new Point(center)),
],
});
const map = new Map({
target: 'map',
controls: defaultControls().extend([new ScaleLine()]),
layers: [
new TileLayer({
source: new OSM(),
}),
new VectorLayer({
source: source,
style: [
new Style({
image: new CircleStyle({
fill: new Fill({
color: 'rgba(200,180,150,0.5)',
}),
radius: 10,
stroke: new Stroke({
color: 'red',
width: 3,
}),
}),
}),
],
}),
new VectorLayer({
source: source,
style: [
new Style({
geometry: (feature) => {
const featureCoordinates = feature.getGeometry().getCoordinates();
const pointresolution = getPointResolution(
map.getView().getProjection(),
1,
featureCoordinates,
);
return new Circle(featureCoordinates, 300 / pointresolution);
},
stroke: new Stroke({
color: 'blue',
width: 2,
lineDash: [2, 3],
}),
}),
],
}),
],
view: new View({
center: center,
zoom: 14,
}),
});
map.on('pointermove', (e) => {
map.getTargetElement().style.cursor = map.hasFeatureAtPixel(
e.pixel,
{layerFilter: (l) => l === map.getLayers().item(1)},
) ? 'pointer' : '';
});
}
</script>
</body>
</html>
或者您可以使用单个图层,其中包含您不希望通过
renderer
选项和 void hitDetectionRenderer
检测到的样式。 传递给 renderer
函数的像素坐标需要用于重新创建几何图形,然后可以使用矢量上下文方法来设计几何图形
<html>
<head>
<style>
html, body, .map {
margin: 0;
padding: 0;
width: 100%;
height: 100%;
}
</style>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/ol.js"></script>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/[email protected]/ol.css">
</head>
<body>
<div id="map" class="map"></div>
<script>
{
const {Circle: CircleStyle, Fill, Stroke, Style} = ol.style;
const {Feature, Map, View} = ol;
const {OSM, Vector: VectorSource} = ol.source;
const {Point, Circle} = ol.geom;
const {ScaleLine, defaults: {defaults: defaultControls}} = ol.control;
const {Tile: TileLayer, Vector: VectorLayer} = ol.layer;
const {fromLonLat, getPointResolution} = ol.proj;
const {toContext} = ol.render;
const center = fromLonLat([18.955, 69.652]);
const source = new VectorSource({
features: [
new Feature(new Point(center)),
],
});
const map = new Map({
target: 'map',
controls: defaultControls().extend([new ScaleLine()]),
layers: [
new TileLayer({
source: new OSM(),
}),
new VectorLayer({
source: source,
style: [
new Style({
image: new CircleStyle({
fill: new Fill({
color: 'rgba(200,180,150,0.5)',
}),
radius: 10,
stroke: new Stroke({
color: 'red',
width: 3,
}),
}),
}),
new Style({
geometry: (feature) => {
const featureCoordinates = feature.getGeometry().getCoordinates();
const pointresolution = getPointResolution(
map.getView().getProjection(),
1,
featureCoordinates,
);
return new Circle(featureCoordinates, 300 / pointresolution);
},
renderer: (coordinates, state) => {
const [[x, y], [x1, y1]] = coordinates;
const dx = x1 - x;
const dy = y1 - y;
const radius = Math.sqrt(dx * dx + dy * dy);
const vectorContext = toContext(
state.context,
{pixelRatio: state.pixelRatio},
);
vectorContext.setStyle(
new Style({
stroke: new Stroke({
color: 'blue',
width: 2,
lineDash: [2, 3],
}),
}),
);
vectorContext.drawGeometry(
new Circle([x, y], radius),
);
},
hitDetectionRenderer: () => {},
}),
],
}),
],
view: new View({
center: center,
zoom: 14,
}),
});
map.on('pointermove', (e) => {
map.getTargetElement().style.cursor = map.hasFeatureAtPixel(
e.pixel,
) ? 'pointer' : '';
});
}
</script>
</body>
</html>