OpenLayers 与视频监控
本章将介绍如何在 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>