vue中,使用OpenLayers制作动态雷达扫描效果

直接上代码:

<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>

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值