官网demo地址:
这个示例主要主要介绍了使用hitDetectionRenderer来优化点击检测的性能。
什么叫点击检测?
点击检测(hit detection)是指用户在地图上点击时,确定他们点击的具体地图要素的过程。
示例中使用renderer函数给feature添加了 渐变效果,还添加了一行渐变文字。其原理解释上篇已经说过了,这篇就不再说了。
二十、openlayers官方示例Custom Circle Render解析——自定义圆形渲染、绘制渐变色圆形-CSDN博客
示例中定义了一个鼠标经过事件,鼠标经过时会给当前的feature设置不同的颜色属性label-color值。
//map.forEachFeatureAtPixel 方法检查鼠标位置是否悬停在某个要素上,
//如果是,则改变其 label-color 为白色。
map.on("pointermove", (evt) => {
console.log('鼠标经过事件');
const featureOver = map.forEachFeatureAtPixel(evt.pixel, (feature) => {
feature.set("label-color", "rgba(255,255,255,1)");
return feature;
});
//如果鼠标移出当前要素,则将之前的要素颜色重置为原来的 labelTextStroke。
if (pointerOverFeature && pointerOverFeature != featureOver) {
pointerOverFeature.set("label-color", labelTextStroke);
}
//更新 pointerOverFeature 为当前悬停的要素
pointerOverFeature = featureOver;
});
先不写hitDetectionRenderer函数,鼠标经过的时候 ,在renderer里面打印,会发现renderer会一直执行。
也就是说,renderer中的代码会一直绘制圆形,这显然不利于性能。这个时候加上hitDetectionRenderer函数,当鼠标经过就会执行hitDetectionRenderer函数而不是renderer,由此来提高性能。
renderer(coordinates, state) {
console.log("renderer执行了");
}
hitDetectionRenderer(coordinates, state) {
console.log("hitDetectionRenderer执行了");
},
hitDetectionRenderer函数里再一次绘制文字,结合鼠标事件就可以实现鼠标移入改变文字描边颜色效果。
hitDetectionRenderer(coordinates, state) {
const [x, y] = coordinates[0];
const ctx = state.context;
renderLabelText(ctx, x, y, circleFeature.get("label-color"));
},
完整代码:
<template>
<div class="box">
<h1>
Custom Hit Detection Render
使用hitDetectionRenderer优化在复杂地图应用中要素的点击检测性能,优化鼠标经过事件性能
</h1>
<div id="map"></div>
</div>
</template>
<script>
import Feature from "ol/Feature.js";
import Map from "ol/Map.js";
import View from "ol/View.js";
import { Circle } from "ol/geom.js";
import { OSM, Vector as VectorSource } from "ol/source.js";
import { Style } from "ol/style.js";
import { Tile as TileLayer, Vector as VectorLayer } from "ol/layer.js";
import { fromLonLat } from "ol/proj.js";
export default {
name: "",
components: {},
data() {
return {
vectorLayer: null,
};
},
computed: {},
created() {},
methods: {},
mounted() {
//使用 fromLonLat 函数将其转换为投影坐标
const columbusCircleCoords = fromLonLat([-73.98189, 40.76805]);
const labelTextStroke = "rgba(120, 120, 120, 1)";
const labelText = "Columbus Circle";
let pointerOverFeature = null;
//文本渲染函数
const renderLabelText = (ctx, x, y, stroke) => {
ctx.fillStyle = "rgba(255,0,0,1)";
ctx.strokeStyle = stroke;
ctx.lineWidth = 1;
ctx.textAlign = "center";
ctx.textBaseline = "middle";
ctx.font = `bold 30px verdana`;
ctx.filter = "drop-shadow(7px 7px 2px #e81)";
ctx.fillText(labelText, x, y);
ctx.strokeText(labelText, x, y);
};
const circleFeature = new Feature({
geometry: new Circle(columbusCircleCoords, 50),
});
circleFeature.set("label-color", labelTextStroke);
circleFeature.setStyle(
new Style({
renderer(coordinates, state) {
const [[x, y], [x1, y1]] = coordinates;
const ctx = state.context;
const dx = x1 - x;
const dy = y1 - y;
const radius = Math.sqrt(dx * dx + dy * dy);
const innerRadius = 0;
const outerRadius = radius * 1.4;
const gradient = ctx.createRadialGradient(
x,
y,
innerRadius,
x,
y,
outerRadius
);
gradient.addColorStop(0, "rgba(255,0,0,0)");
gradient.addColorStop(0.6, "rgba(255,0,0,0.2)");
gradient.addColorStop(1, "rgba(255,0,0,0.8)");
ctx.beginPath();
ctx.arc(x, y, radius, 0, 2 * Math.PI, true);
ctx.fillStyle = gradient;
ctx.fill();
ctx.strokeStyle = "rgba(255,0,0,1)";
ctx.stroke();
renderLabelText(ctx, x, y, circleFeature.get("label-color"));
},
hitDetectionRenderer(coordinates, state) {
const [x, y] = coordinates[0];
const ctx = state.context;
renderLabelText(ctx, x, y, circleFeature.get("label-color"));
},
})
);
const map = new Map({
layers: [
new TileLayer({
source: new OSM(),
visible: true,
}),
new VectorLayer({
source: new VectorSource({
features: [circleFeature],
}),
}),
],
target: "map",
view: new View({
center: columbusCircleCoords,
zoom: 19,
}),
});
//map.forEachFeatureAtPixel 方法检查鼠标位置是否悬停在某个要素上,如果是,则改变其 label-color 为白色。
map.on("pointermove", (evt) => {
const featureOver = map.forEachFeatureAtPixel(evt.pixel, (feature) => {
feature.set("label-color", "rgba(255,255,255,1)");
return feature;
});
//如果鼠标移出当前要素,则将之前的要素颜色重置为原来的 labelTextStroke。
if (pointerOverFeature && pointerOverFeature != featureOver) {
pointerOverFeature.set("label-color", labelTextStroke);
}
//更新 pointerOverFeature 为当前悬停的要素
pointerOverFeature = featureOver;
});
},
};
</script>
<style lang="scss" scoped>
#map {
width: 100%;
height: 500px;
}
.box {
height: 100%;
}
</style>