直接上代码:
<template>
<div class="container">
<div id="Map"></div>
</div>
</template>
<script setup>
import 'ol/ol.css';
import { ref, onMounted } from 'vue';
import { Map, View } from 'ol';
import Tile from 'ol/layer/Tile';
import XYZ from 'ol/source/XYZ';
import VectorLayer from 'ol/layer/Vector';
import VectorSource from 'ol/source/Vector';
import Style from 'ol/style/Style';
import Fill from 'ol/style/Fill';
import Stroke from 'ol/style/Stroke';
import Feature from 'ol/Feature';
import Polygon from 'ol/geom/Polygon';
import Circle from 'ol/geom/Circle';
import LineString from 'ol/geom/LineString';
import * as olProj from 'ol/proj';
import { fromLonLat } from 'ol/proj';
// 定义角度变量
const center = fromLonLat([108.94704, 34.3456]); // 转换为 EPSG:3857 坐标系
console.log(center, "center");
const angle = ref(0);
const radius = 5000;
const map = ref(null);
const source = ref(new XYZ({}));
const source1 = ref(new XYZ({}));
let radarLayers = ref(null);
let animationFrameId = null
// 天地图切换函数
const tdMap = (n = 5) => {
source.value.setUrl(getUrl(5));
source1.value.setUrl(getUrl(3));
};
// 获取天地图的WMTS URL
const getUrl = (n) => {
const key = ''; // 天地图key自己申请
let url = '';
switch (n) {
case 1:
url = 'http://t{1-7}.tianditu.gov.cn/cva_w/wmts?SERVICE=WMTS&REQUEST=GetTile&VERSION=1.0.0&LAYER=cva&STYLE=default&TILEMATRIXSET=w&FORMAT=tiles&TILEMATRIX={z}&TILEROW={y}&TILECOL={x}&tk=';
break;
case 2:
url = 'http://t{1-7}.tianditu.gov.cn/eva_w/wmts?SERVICE=WMTS&REQUEST=GetTile&VERSION=1.0.0&LAYER=eva&STYLE=default&TILEMATRIXSET=w&FORMAT=tiles&TILEMATRIX={z}&TILEROW={y}&TILECOL={x}&tk=';
break;
case 3:
url = 'http://t{1-7}.tianditu.gov.cn/cia_w/wmts?SERVICE=WMTS&REQUEST=GetTile&VERSION=1.0.0&LAYER=cia&STYLE=default&TILEMATRIXSET=w&FORMAT=tiles&TILEMATRIX={z}&TILEROW={y}&TILECOL={x}&tk=';
break;
case 4:
url = 'http://t{1-7}.tianditu.gov.cn/eia_w/wmts?SERVICE=WMTS&REQUEST=GetTile&VERSION=1.0.0&LAYER=eia&STYLE=default&TILEMATRIXSET=w&FORMAT=tiles&TILEMATRIX={z}&TILEROW={y}&TILECOL={x}&tk=';
break;
case 5:
url = 'http://t{1-7}.tianditu.gov.cn/img_w/wmts?SERVICE=WMTS&REQUEST=GetTile&VERSION=1.0.0&LAYER=img&STYLE=default&TILEMATRIXSET=w&FORMAT=tiles&TILEMATRIX={z}&TILEROW={y}&TILECOL={x}&tk=';
break;
default:
url = 'http://t{1-7}.tianditu.gov.cn/vec_w/wmts?SERVICE=WMTS&REQUEST=GetTile&VERSION=1.0.0&LAYER=vec&STYLE=default&TILEMATRIXSET=w&FORMAT=tiles&TILEMATRIX={z}&TILEROW={y}&TILECOL={x}&tk=';
}
return url + key;
};
// 初始化地图
const initMap = () => {
const tiandiMap = new Tile({
source: source.value,
});
const tiandiMap1 = new Tile({
source: source1.value,
});
// 创建矢量图层
const radarLayer = new VectorLayer({
source: new VectorSource(),
style: new Style({
fill: new Fill({
color: "rgba(55, 204, 190, 0.15)", // 填充颜色
}),
stroke: new Stroke({
color: "rgba(55, 204, 190)", // 边框颜色
width: 2,
}),
}),
});
map.value = new Map({
target: 'Map',
layers: [tiandiMap, tiandiMap1, radarLayer], // 添加雷达图层
view: new View({
projection: 'EPSG:3857', // 使用 EPSG:3857 投影
center: fromLonLat([108.94704, 34.3456]), // 适应正确的投影
zoom: 13,
rotation: Math.PI / 8,
}),
});
radarLayers.value = radarLayer
// 调用动画函数
animate(radarLayer);
};
// 雷达图层
function createRadarPolygon (center, radius, startAngle, endAngle, fillColor) {
const points = [];
points.push(center);
for (let i = startAngle; i <= endAngle; i += 1) {
const radian = (i * Math.PI) / 180;
const x = center[0] + radius * Math.cos(radian);
const y = center[1] + radius * Math.sin(radian);
points.push([x, y]);
}
points.push(center);
const polygon = new Feature({
geometry: new Polygon([points]),
});
// 设置扇形样式
polygon.setStyle(new Style({
fill: new Fill({
color: fillColor, // 使用传递的颜色
}),
stroke: new Stroke({
color: "rgba(120, 213, 241, 0.8)",
width: 1,
}),
}));
return polygon;
}
// 删除
function clear () {
if (animationFrameId) {
cancelIdleCallback(animationFrameId);
animationFrameId = null;
}
radarLayers.value.getSource().clear();
}
// 动画函数
function animate (radarLayer) {
const startAngle = angle.value - 30;
const endAngle = angle.value;
radarLayer.getSource().clear();
const circleCount = 5;
const colors = [
"rgba(251, 74, 35,0.15)", // 第一圈的颜色
"rgba(120, 213, 241, 0.1)", // 第二圈的颜色
"rgba(120, 213, 241, 0.1)", // 第三圈的颜色
"rgba(120, 213, 241, 0.2)", // 第四圈的颜色
"rgba(95, 166, 152, 0.1)", // 第五圈的颜色
];
for (let i = 1; i <= circleCount; i++) {
const circleRadius = (radius * i) / circleCount;
const circle = new Feature({
geometry: new Circle(center, circleRadius),
});
radarLayer.getSource().addFeature(circle);
}
// 使用不同的颜色来创建扇形
for (let i = 0; i < circleCount; i++) {
const radarPolygon = createRadarPolygon(center, radius, startAngle, endAngle, colors[i]);
radarLayer.getSource().addFeature(radarPolygon);
}
const scanLineEnd = [
center[0] + radius * Math.cos((angle.value * Math.PI) / 180),
center[1] + radius * Math.sin((angle.value * Math.PI) / 180),
];
const scanLine = new Feature({
geometry: new LineString([center, scanLineEnd]),
});
scanLine.setStyle(
new Style({
stroke: new Stroke({
color: "rgba(120, 213, 241, 0.8)",
width: 2,
}),
})
);
radarLayer.getSource().addFeature(scanLine);
angle.value = (angle.value + 1) % 360;
animationFrameId = requestIdleCallback(() => animate(radarLayer));
}
// 初始化地图时调用
onMounted(() => {
initMap();
tdMap();
});
</script>
<style scoped>
.container {
width: 80vw;
height: 100wh;
}
#Map {
width: 100%;
height: 800px;
margin: 0 auto;
border: 1px solid #42b983;
position: relative;
}
</style>