vue3基于openlayers 实现多轨迹扩散效果
思路:以点到点的轨迹连线,一个点沿着轨迹移动,多条线就绘制多条线移动,线太多就会卡顿
// 热力图图层,包含点、线、热力点
function drawHeatmapLayer(point) {
animating.value = props.points.length > 0;
let featureLine = new LineString(point);
let routeFeature = new Feature({
type: "line",
geometry: featureLine,
});
const startMarker = new Feature({
geometry: new Point(featureLine.getFirstCoordinate()),
});
const endMarker = new Feature({
geometry: new Point(featureLine.getLastCoordinate()),
});
const position = startMarker.getGeometry().clone();
// 热力点
var heatPointFeature = new Feature({
geometry: position,
});
layer.value.getSource().addFeature(heatPointFeature);
const styles = {
line: new Style({
stroke: new Stroke({
width: 3,
color: "transparent",
}),
}),
};
vectorLayer = new VectorLayer({
source: new VectorSource({
features: [routeFeature, startMarker, endMarker],
}),
style: function(feature) {
return styles[feature.get("type")];
},
});
MapRef.value.map.addLayer(vectorLayer);
mapAnimation(featureLine, position);
}
// 获取所有热力点的中心点
function getCenterPoint(geoCoordinateList) {
let X = 0;
let Y = 0;
let total = geoCoordinateList.length;
for (const g of geoCoordinateList) {
X += g[0];
Y += g[1];
}
X = X / total;
Y = Y / total;
return [X, Y];
}
// 改变地图中心点
function getHeatPointInfo() {
let heatMapFeaturesPoints = [];
layer.value
.getSource()
.getFeatures()
.forEach((item) => {
heatMapFeaturesPoints.push(item.getGeometry().getCoordinates());
});
// 当前的位置范围
let positionRange = refreshMapLocation();
let heatMapCenter = getCenterPoint(heatMapFeaturesPoints);
if (
heatMapCenter[1] > positionRange.currentExtentRight[1] ||
heatMapCenter[1] < positionRange.currentExtentLeft[1] ||
heatMapCenter[0] > positionRange.currentExtentRight[0] ||
heatMapCenter[0] < positionRange.currentExtentLeft[0]
) {
// 热力图中心点超出屏幕范围,改变当前中心点为地图中心
centerPoint.value = heatMapCenter;
// MapRef.value
const zoom = MapRef.value.getZoomSize();
MapRef.value.moveTo(heatMapCenter, 10, "inAndOut", {
zoom: zoom,
});
}
}
// 地图动画
function mapAnimation(featureLine, position) {
let distance = 0;
function moveFeature() {
if (isAnimating) {
const speed = props.spreed;
let speedRondom = parseFloat(Math.random().toFixed(3)) * 100;
distance = (distance + (speed * speedRondom) / 1e6) % 2;
const currentCoordinate = featureLine.getCoordinateAt(distance);
if (distance > 1) {
stopAnimation();
} else {
position.setCoordinates(currentCoordinate);
}
}
}
if (animating.value) {
startAnimation();
} else {
stopAnimation();
}
function startAnimation() {
vectorLayer.on("postrender", moveFeature);
vectorLayer.dispatchEvent("postrender");
}
function stopAnimation() {
animating.value = false;
vectorLayer.on("postrender", moveFeature);
}
}
function initHeatmapLayer() {
isAnimating = true;
refreshMapLocation();
layer.value = new HeatmapLayer({
source: new VectorSource(),
blur: props.blur,
radius: props.radius,
gradient: props.colors,
});
addSubLayer();
props.points.forEach((item) => {
drawHeatmapLayer(item);
});
}
// 添加图层到map
function addSubLayer() {
const map = MapRef.value.map;
if (layer.value) {
map.addLayer(layer.value);
}
}
function refreshMapLocation() {
// 获取视图对角位置
let postions = MapRef.value.getDotSize();
// 计算出视图经度长度
let Long = (postions[2] - postions[0]) / 2;
// 计算出视图纬度长度
let Lat = (postions[3] - postions[1]) / 2;
//计算出当前范围内的经度纬度(右)
let currentExtentRight = [
centerPoint.value[0] + Long,
centerPoint.value[1] + Lat,
];
//计算出当前范围内的经度纬度(左)
let currentExtentLeft = [
centerPoint.value[0] - Long,
centerPoint.value[1] - Lat,
];
return {
currentExtentRight,
currentExtentLeft,
};
}