Skip to content

OpenLayers 与视频监控

上次更新 2025年8月20日星期三 3:16:20 字数 0 字 时长 0 分钟

本章将介绍如何在 OpenLayers 中实现视频监控功能。

示例

新标签页预览

代码实现

vue
<template>
  <div class="h-screen">
    <div id="map" class="w-full h-full"></div>
  </div>
</template>

<script setup>
import { onMounted, ref } from "vue";
import "ol/ol.css";
import Map from "ol/Map";
import View from "ol/View";
import TileLayer from "ol/layer/Tile";
import XYZ from "ol/source/XYZ";
import { fromLonLat } from "ol/proj";
import Feature from "ol/Feature";
import Point from "ol/geom/Point";
import { Vector as VectorLayer } from "ol/layer";
import { Vector as VectorSource } from "ol/source";
import Overlay from "ol/Overlay";
import { Style, Icon } from "ol/style";

onMounted(() => {
  // 创建地图
  const map = new Map({
    target: "map",
    view: new View({
      center: fromLonLat([117.18704223632814, 39.11967296689395]),
      zoom: 12,
    }),
  });

  // 添加天地图图层
  const tdtLayer = new TileLayer({
    source: new XYZ({
      url: "http://t0.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=d32c6748c80f81a44acd8633cea41dfd",
      crossOrigin: "anonymous",
    }),
  });
  map.addLayer(tdtLayer);

  // 模拟监控点位数据
  const cameras = [
    {
      name: "监控点1",
      location: [117.215, 39.117],
      url: "https://stream7.iqilu.com/10339/upload_transcode/202002/18/20200218114723HDu3hhxqIT.mp4",
    },
    {
      name: "监控点2",
      location: [117.223, 39.109],
      url: "https://vip.lz-cdn5.com/20220401/3315_dbd60bc0/index.m3u8",
    },
  ];

  // 创建矢量图层
  const vectorSource = new VectorSource();
  const vectorLayer = new VectorLayer({
    source: vectorSource,
  });
  map.addLayer(vectorLayer);

  // 添加监控点位标记
  cameras.forEach((camera) => {
    const feature = new Feature({
      geometry: new Point(fromLonLat(camera.location)),
      name: camera.name,
      url: camera.url,
    });

    // 设置标记样式
    feature.setStyle(
      new Style({
        image: new Icon({
          src:
            "data:image/svg+xml;charset=utf-8," +
            encodeURIComponent(`
            <svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32">
              <circle cx="16" cy="16" r="14" fill="url(#grad)" stroke="white" stroke-width="2"/>
              <defs>
                <linearGradient id="grad" x1="0%" y1="0%" x2="100%" y2="100%">
                  <stop offset="0%" style="stop-color:#2196f3"/>
                  <stop offset="100%" style="stop-color:#1976d2"/>
                </linearGradient>
              </defs>
              <text x="16" y="20" text-anchor="middle" fill="white" font-size="14">📹</text>
            </svg>
          `),
          scale: 1,
          anchor: [0.5, 0.5],
        }),
      })
    );

    vectorSource.addFeature(feature);

    // 创建弹窗元素
    const popupElement = document.createElement("div");
    popupElement.className = "video-popup";
    popupElement.id = "video-popup-" + camera.name;

    // 创建弹窗
    const popup = new Overlay({
      element: popupElement,
      positioning: "bottom-center",
      stopEvent: true,
      offset: [0, -20],
    });
    map.addOverlay(popup);

    // 点击事件处理
    map.on("click", (evt) => {
      const feature = map.forEachFeatureAtPixel(
        evt.pixel,
        (feature) => feature
      );

      if (feature && feature.get("name") === camera.name) {
        const coordinates = feature.getGeometry().getCoordinates();
        popup.setPosition(coordinates);

        // 初始化视频播放器
        let plugins = [];
        if (camera.url.includes(".flv")) {
          plugins = [window.FlvPlayer];
        } else if (camera.url.includes(".m3u8")) {
          plugins = [window.HlsPlayer];
        } else if (camera.url.includes(".mp4")) {
          plugins = [window.Mp4Player];
        }

        new window.Player({
          id: "video-popup-" + camera.name,
          url: camera.url,
          fluid: true,
          fitVideoSize: "auto",
          volume: 0.6,
          autoplay: true,
          videoInit: true,
          plugins,
          controls: true,
        });
      } else {
        // 关闭其他弹窗
        const players = document.getElementsByTagName("video");
        if (players && players.length > 0) {
          players[0].pause();
        }
        popup.setPosition(undefined);
      }
    });
  });
});
</script>

<style scoped>
.h-screen {
  height: 24rem;
}

.w-full {
  width: 100%;
}

.h-full {
  height: 100%;
}

.video-popup {
  width: 480px;
  height: 320px;
  background: #000;
  border-radius: 8px;
  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
}
</style>
关注公众号