merge
parent
7e31b6f37b
commit
475c57c440
File diff suppressed because one or more lines are too long
Binary file not shown.
|
|
@ -32,6 +32,11 @@
|
|||
<script src="/monitor/jquery-1.12.4.min.js"></script>
|
||||
<script src="/monitor/jsencrypt.min.js"></script>
|
||||
<script src="/monitor/jsWebControl-1.0.0.min.js"></script>
|
||||
|
||||
|
||||
<!-- easy plaer -->
|
||||
|
||||
<script src="./EasyPlayer-element.min.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<div id="app">
|
||||
|
|
|
|||
|
|
@ -73,6 +73,7 @@
|
|||
}
|
||||
},
|
||||
"dependencies": {
|
||||
"@easydarwin/easyplayer": "^5.1.1",
|
||||
"@ant-design/icons-vue": "^7.0.1",
|
||||
"@icon-park/svg": "^1.4.2",
|
||||
"@iconify/iconify": "^3.1.1",
|
||||
|
|
|
|||
|
|
@ -15,9 +15,12 @@ export function splitPolygonByLine(line, outerPolygon) {
|
|||
}
|
||||
|
||||
console.log("************** 分割开始 start **************")
|
||||
|
||||
|
||||
console.log("第1步:传入的分割线数据",line);
|
||||
console.log("第2步:传入的分割面数据",outerPolygon)
|
||||
|
||||
|
||||
// 处理被分割的面数据坐标小数点保留多少位
|
||||
let truncatedSplitter = turf.truncate(turf.lineString(outerPolygon.geometry.coordinates[0]), dealOptions);
|
||||
console.log("第3步:分割面转换为线数据",truncatedSplitter);
|
||||
|
|
@ -117,6 +120,8 @@ function getRandomPointInPolygon(polygon) {
|
|||
|
||||
// 单个面数据分割
|
||||
export async function splitPolygonByFill(drawPolygon, outerPolygon) {
|
||||
console.log("outerPolygon",outerPolygon);
|
||||
|
||||
|
||||
return new Promise((resolve,reject)=>{
|
||||
try{
|
||||
|
|
@ -124,9 +129,18 @@ export async function splitPolygonByFill(drawPolygon, outerPolygon) {
|
|||
console.log("第2步:传入的被切割面数据",outerPolygon)
|
||||
|
||||
var polygon1 = turf.polygon(drawPolygon.geometry.coordinates);
|
||||
var polygon2 = turf.polygon(outerPolygon.geometry.coordinates);
|
||||
|
||||
// 判断被分割的面类型
|
||||
var polygon2 = null;
|
||||
|
||||
if(outerPolygon.geometry.type == "MultiPolygon"){
|
||||
polygon2 = turf.multiPolygon(outerPolygon.geometry.coordinates);
|
||||
}else if(outerPolygon.geometry.type == "Polygon"){
|
||||
polygon2 = turf.polygon(outerPolygon.geometry.coordinates);
|
||||
}
|
||||
|
||||
|
||||
// var intersection = turf.intersect(polygon1, polygon2);
|
||||
|
||||
let intersection = turf.intersect(turf.featureCollection([polygon1, polygon2]));
|
||||
console.log("第4步:获取绘制图斑和分割图斑的交集",JSON.stringify(polygon2),JSON.stringify(polygon1),intersection);
|
||||
|
||||
|
|
@ -134,9 +148,7 @@ export async function splitPolygonByFill(drawPolygon, outerPolygon) {
|
|||
console.log("第3步:获取绘制图斑和分割图斑的差集",difference);
|
||||
|
||||
let splitAfterFeatures = [intersection,difference];
|
||||
setTimeout(function(){
|
||||
console.log("splitAfterFeatures9876",splitAfterFeatures);
|
||||
},3000)
|
||||
|
||||
resolve(splitAfterFeatures)
|
||||
}catch(e){
|
||||
console.log(e);
|
||||
|
|
|
|||
|
|
@ -1,8 +1,17 @@
|
|||
<template>
|
||||
<div class="statistical" id="bg-pan">
|
||||
|
||||
<Map @onload="handlerOnMapLoad" @handlerGetDetails="handlerGetDetails" style="position: absolute; top: 0px; left: 0px;height: calc( 100vh - 80px);width:100%;z-index:0;" ref="MapboxComponent"></Map>
|
||||
<Map
|
||||
@onload="handlerOnMapLoad"
|
||||
@handlerGetDetails="handlerGetDetails"
|
||||
style="position: absolute; top: 0px; left: 0px;height: calc( 100vh - 80px);width:100%;z-index:0;"
|
||||
ref="MapboxComponent"
|
||||
@showMonitor="showMonitor"
|
||||
@handlerQueryIntersectTif="handlerQueryIntersectTif"
|
||||
></Map>
|
||||
|
||||
|
||||
|
||||
<div style="position: absolute; left:60px; bottom: 20px; z-index:1;">
|
||||
<div :class="`button-item ${buttonSelect == 1? 'button-select': ''}`" style="margin-bottom: 10px" @click="changeLayer(1)">导航地图</div>
|
||||
<div :class="`button-item ${buttonSelect == 2? 'button-select': ''}`" style="margin-bottom: 10px" @click="changeLayer(2)">卫星地图</div>
|
||||
|
|
@ -30,7 +39,25 @@
|
|||
<ShowInfoModal v-if="showInfoOpen" :showInfoData="showInfoData" />
|
||||
</div>
|
||||
</a-modal>
|
||||
|
||||
|
||||
|
||||
<!-- 图层控制 视频监控-->
|
||||
|
||||
<div class="layer-center-container">
|
||||
<LayerCenter
|
||||
@drawPolygon="drawPolygon"
|
||||
@cancleDrawPolygon="cancleDrawPolygon"
|
||||
@changeTifLayer="changeTifLayer"
|
||||
ref="LayerCenterComponent"></LayerCenter>
|
||||
</div>
|
||||
|
||||
<div class="TC-videoi-container" v-if="showTCLPlayer" v-drag>
|
||||
<div class="close-button" @click="showTCLPlayer = false;">
|
||||
<CloseOutlined></CloseOutlined>
|
||||
</div>
|
||||
<Monitor v-if="showTCLPlayer" :play-url="playUrl"></Monitor>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
|
@ -128,7 +155,44 @@
|
|||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*图层控制 视频监控*/
|
||||
import LayerCenter from './mapComponent/layers/index.vue';
|
||||
|
||||
// 视频监控
|
||||
import Monitor from './mapComponent/monitor/index.vue';
|
||||
import {CloseOutlined} from "@ant-design/icons-vue"
|
||||
|
||||
const showTCLPlayer = ref(false);
|
||||
const playUrl = ref("");
|
||||
function showMonitor(info){
|
||||
playUrl.value = info.playUrl
|
||||
showTCLPlayer.value = true;
|
||||
}
|
||||
|
||||
// 历史影像
|
||||
|
||||
function drawPolygon(state){
|
||||
// 调用Map控件中的绘图方法
|
||||
MapboxComponent.value.handlerDrawPolygon();
|
||||
}
|
||||
|
||||
function cancleDrawPolygon(){
|
||||
MapboxComponent.value.handlerDeletePolygon();
|
||||
}
|
||||
|
||||
const LayerCenterComponent = ref();
|
||||
function handlerQueryIntersectTif(wktStr){
|
||||
LayerCenterComponent.value.handlerQueryIntersectTif(wktStr);
|
||||
}
|
||||
|
||||
|
||||
function changeTifLayer(layer){
|
||||
console.log("layer",layer);
|
||||
|
||||
MapboxComponent.value.handlerChangeTifLayer(layer);
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
|
|
@ -263,6 +327,53 @@
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**图层控制 视频监控**/
|
||||
.layer-center-container{
|
||||
width:208px;
|
||||
position:absolute;
|
||||
bottom:0px;
|
||||
left:20px;
|
||||
z-index:99999;
|
||||
}
|
||||
|
||||
.TC-videoi-container{
|
||||
position: absolute;
|
||||
bottom:48px;
|
||||
right:38px;
|
||||
width:418px;
|
||||
height:300px;
|
||||
.close-button{
|
||||
width:28px;
|
||||
height:28px;
|
||||
background:rgba(0, 0, 0, 0.6);
|
||||
text-align: center;
|
||||
line-height:28px;
|
||||
position:absolute;
|
||||
top:4px;
|
||||
right:4px;
|
||||
z-index:999999;
|
||||
color:#fff;
|
||||
cursor:pointer;
|
||||
}
|
||||
}
|
||||
|
||||
.selection-button{
|
||||
position:absolute;
|
||||
cursor:pointer;
|
||||
top:20px;
|
||||
left:220px;
|
||||
width:140px;
|
||||
height:40px;
|
||||
margin-left:20px;
|
||||
background-image: url(/map/change-view-btn.png);
|
||||
background-size:100% 100%;
|
||||
color:#efefef;
|
||||
text-align: center;
|
||||
line-height:46px;
|
||||
font-size:14px;
|
||||
}
|
||||
</style>
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
{
|
||||
"type": "FeatureCollection",
|
||||
"features": [
|
||||
{
|
||||
"type": "Feature",
|
||||
"geometry": {
|
||||
"type": "Point",
|
||||
"coordinates": [118.429056,35.387537]
|
||||
},
|
||||
"properties": {
|
||||
"name":"沂南县砖埠镇东岳庄村北可见光",
|
||||
"playUrl":"http://221.2.83.254:7012/live/37130100181328000001.m3u8"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
@ -42,10 +42,17 @@ mapContainerName.value = "mapContainer-"+generateUUID();
|
|||
//
|
||||
import { TableOutlined, GlobalOutlined,HomeOutlined} from '@ant-design/icons-vue';
|
||||
|
||||
const emits = defineEmits(["onload","handlerGetDetails"])
|
||||
// 图层控制 历史影像
|
||||
import { message, Modal } from 'ant-design-vue';
|
||||
import U from 'mapbox-gl-utils';
|
||||
import {MP} from "./src/MP";
|
||||
import { GeojsonToWkt } from './src/WktGeojsonTransform';
|
||||
|
||||
const emits = defineEmits(["onload","handlerGetDetails","showMonitor","handlerQueryIntersectTif"])
|
||||
|
||||
|
||||
let map:Map;
|
||||
let mp: any = null;
|
||||
|
||||
|
||||
// init map
|
||||
|
|
@ -841,7 +848,9 @@ onMounted(()=>{
|
|||
mapboxgl.accessToken = MAPBOX_TOKEN;
|
||||
map = initMap();
|
||||
|
||||
|
||||
//挂载mapbox-gl-utils
|
||||
U.init(map);
|
||||
mp = new MP(map);
|
||||
|
||||
map.on("load",()=>{
|
||||
// 添加地形数据
|
||||
|
|
@ -865,6 +874,9 @@ onMounted(()=>{
|
|||
getMaskData();
|
||||
handlerDealStreet();
|
||||
handlerDealCountry();
|
||||
|
||||
// 视频监控
|
||||
addMonitorLayer();
|
||||
})
|
||||
})
|
||||
|
||||
|
|
@ -874,8 +886,170 @@ defineExpose({
|
|||
handlerChangeCounty, // 切换县区
|
||||
handlerChangeLayerVisible, // 控制图层显示隐藏
|
||||
handlerLoadPolygon,
|
||||
handlerDrawPolygon, // 绘制范围
|
||||
handlerDeletePolygon, // 取消绘制
|
||||
handlerChangeTifLayer, // 图层切换
|
||||
});
|
||||
|
||||
|
||||
/* 图层控制 视频监控*/
|
||||
|
||||
import MonitoringData from './MonitoringData.json';
|
||||
|
||||
function addMonitorLayer() {
|
||||
// 加载监控图标
|
||||
map.loadImage('/monitor/monitor.png', function (error, image) {
|
||||
if (error) throw error;
|
||||
if (!map.hasImage('monitorIcon')) {
|
||||
map.addImage('monitorIcon', image);
|
||||
}
|
||||
});
|
||||
|
||||
// 加载监控数据源
|
||||
map.addSource('JianKongSource', {
|
||||
type: 'geojson',
|
||||
data: MonitoringData,
|
||||
});
|
||||
|
||||
// 加载监控图层
|
||||
map.addLayer({
|
||||
id: 'JianKong',
|
||||
type: 'symbol',
|
||||
source: 'JianKongSource',
|
||||
layout: {
|
||||
'icon-image': 'monitorIcon',
|
||||
'icon-size': 0.8,
|
||||
'text-field': ['get', 'name'],
|
||||
'text-size': 12,
|
||||
'text-font': ['Open Sans Semibold', 'Arial Unicode MS Bold'],
|
||||
'text-offset': [0, 1.6],
|
||||
'text-anchor': 'top',
|
||||
'text-allow-overlap': false,
|
||||
visibility: 'none',
|
||||
},
|
||||
paint: {
|
||||
'text-color': '#041B36',
|
||||
'text-halo-color': '#fff',
|
||||
'text-halo-width': 2,
|
||||
},
|
||||
});
|
||||
|
||||
map.on('click', 'JianKong', (e) => {
|
||||
// 显示弹窗
|
||||
emits('showMonitor', e.features[0].properties);
|
||||
});
|
||||
}
|
||||
|
||||
function handlerDeletePolygon(){
|
||||
mp.deleteDraw();
|
||||
}
|
||||
function handlerDrawPolygon (){
|
||||
mp.draw('Polygon');
|
||||
mp.on('Polygon', function (e) {
|
||||
Modal.confirm({
|
||||
title: '是否查询历史影像?',
|
||||
onCancel() {
|
||||
// mp.deleteDraw();
|
||||
},
|
||||
async onOk() {
|
||||
let geojson = {
|
||||
"type": "Feature",
|
||||
"geometry": {
|
||||
"type": "Polygon",
|
||||
"coordinates":[]
|
||||
}
|
||||
}
|
||||
let coordinates = [];
|
||||
e?.forEach((item, index) => {
|
||||
coordinates?.push([item.lng, item.lat]);
|
||||
});
|
||||
coordinates.push(coordinates[0]);
|
||||
geojson.geometry.coordinates[0] = coordinates
|
||||
let wktStr = GeojsonToWkt(geojson.geometry)
|
||||
emits("handlerQueryIntersectTif",wktStr)
|
||||
},
|
||||
});
|
||||
// emit('mapDraw', 'Polygon', e);
|
||||
});
|
||||
};
|
||||
|
||||
const tifLayers = ref([])
|
||||
function handlerChangeTifLayer(item){
|
||||
|
||||
if(item.type == 'historyLayer' || item.type == 'speciaLayer'){
|
||||
if (item.checked) { // 加载
|
||||
if(map.getLayer(item.id)){
|
||||
map.setLayoutProperty(item.id, 'visibility', 'visible');
|
||||
}else{
|
||||
|
||||
map.addSource("source"+item.id,{
|
||||
type: "raster",
|
||||
tiles: [
|
||||
item.url,
|
||||
],
|
||||
tileSize: 256,
|
||||
})
|
||||
map.addLayer({
|
||||
id: item.id,
|
||||
type: "raster",
|
||||
source: "source"+item.id,
|
||||
layout: {
|
||||
visibility: "visible",
|
||||
},
|
||||
paint: {},
|
||||
})
|
||||
tifLayers.value.push(item.id);
|
||||
|
||||
map.moveLayer(item.id,"historyLayerFill");
|
||||
map.moveLayer(item.id,"historyLayerLine");
|
||||
|
||||
}
|
||||
} else {
|
||||
map.setLayoutProperty(item.id, 'visibility', 'none');
|
||||
}
|
||||
}else if(item.type == "dataLayer"){
|
||||
|
||||
if(item.id == "Monitor"){
|
||||
|
||||
if(map.getLayer("JianKong")){
|
||||
if (item.checked) {
|
||||
map.setLayoutProperty("JianKong", 'visibility', 'visible');
|
||||
} else {
|
||||
map.setLayoutProperty("JianKong", 'visibility', 'none');
|
||||
}
|
||||
}
|
||||
}else if(item.id == "Data"){
|
||||
if(map.getLayer("historyLayerLine")){
|
||||
if (item.checked) {
|
||||
map.setLayoutProperty("historyLayerLine", 'visibility', 'visible');
|
||||
map.setLayoutProperty("historyLayerFill", 'visibility', 'visible');
|
||||
} else {
|
||||
map.setLayoutProperty("historyLayerLine", 'visibility', 'none');
|
||||
map.setLayoutProperty("historyLayerFill", 'visibility', 'none');
|
||||
}
|
||||
}
|
||||
}
|
||||
}else if(item.type == "baseLayer"){
|
||||
switch(item.id){
|
||||
case 1:
|
||||
handlerChangeLayerVisible('tdt-img-tiles',false)
|
||||
handlerChangeLayerVisible('tdt-vec-tiles',true)
|
||||
handlerChangeLayerVisible('countyPanelLayer',false)
|
||||
break;
|
||||
case 2:
|
||||
handlerChangeLayerVisible('tdt-img-tiles',true)
|
||||
handlerChangeLayerVisible('tdt-vec-tiles',false)
|
||||
handlerChangeLayerVisible('countyPanelLayer',false)
|
||||
break;
|
||||
case 3:
|
||||
handlerChangeLayerVisible('tdt-img-tiles',false)
|
||||
handlerChangeLayerVisible('tdt-vec-tiles',false)
|
||||
handlerChangeLayerVisible('countyPanelLayer',true)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
</script>
|
||||
<style type="less" scoped>
|
||||
.map-container{
|
||||
|
|
|
|||
|
|
@ -0,0 +1,554 @@
|
|||
import U from 'mapbox-gl-utils';
|
||||
import * as turf from '@turf/turf';
|
||||
|
||||
type EventType = 'Point' | 'LineString' | 'Polygon';
|
||||
interface GenerateGeoJSONDataInterface {
|
||||
lng: number;
|
||||
lat: number;
|
||||
}
|
||||
|
||||
interface FeatureCollection {
|
||||
type: string;
|
||||
features: Array<any>;
|
||||
}
|
||||
|
||||
const CIRCLE_STYLE = {
|
||||
'circle-color': '#6495ED',
|
||||
'circle-radius': 8,
|
||||
'circle-stroke-width': 2,
|
||||
'circle-stroke-color': '#ffffff',
|
||||
};
|
||||
const LINE_STYLE = {
|
||||
'line-color': '#6495ED',
|
||||
'line-width': 3,
|
||||
};
|
||||
const LINE_IS_DRAW_STYLE = {
|
||||
'line-dasharray': [2, 2],
|
||||
'line-color': '#00FA9A',
|
||||
'line-width': 3,
|
||||
};
|
||||
const POLYGON_STYLE = {
|
||||
'fill-color': '#FAFAD2',
|
||||
'fill-opacity': 0.1,
|
||||
};
|
||||
|
||||
function typeOf(obj: any): any {
|
||||
const toString: any = Object.prototype.toString;
|
||||
const map: any = {
|
||||
'[object Boolean]': 'boolean',
|
||||
'[object Number]': 'number',
|
||||
'[object String]': 'string',
|
||||
'[object Function]': 'function',
|
||||
'[object Array]': 'array',
|
||||
'[object Date]': 'date',
|
||||
'[object RegExp]': 'regExp',
|
||||
'[object Undefined]': 'undefined',
|
||||
'[object Null]': 'null',
|
||||
'[object Object]': 'object',
|
||||
};
|
||||
return map[toString.call(obj)];
|
||||
}
|
||||
|
||||
function deepClone(data: any): any {
|
||||
// 获取传入拷贝函数的数据类型
|
||||
const type = typeOf(data);
|
||||
// 定义一个返回any类型的数据
|
||||
let reData: any;
|
||||
// 递归遍历一个array类型数据,
|
||||
if (type === 'array') {
|
||||
reData = [];
|
||||
for (let i = 0; i < data.length; i++) {
|
||||
reData.push(deepClone(data[i]));
|
||||
}
|
||||
} else if (type === 'object') {
|
||||
//递归遍历一个object类型数据
|
||||
reData = {};
|
||||
for (const i in data) {
|
||||
reData[i] = deepClone(data[i]);
|
||||
}
|
||||
} else {
|
||||
// 返回基本数据类型
|
||||
return data;
|
||||
}
|
||||
// 将any类型的数据return出去,作为deepClone的结果
|
||||
return reData;
|
||||
}
|
||||
|
||||
class BaseMP {
|
||||
map: any;
|
||||
listeners: {};
|
||||
constructor(map: any) {
|
||||
this.map = map;
|
||||
// 初始化mapbox工具类
|
||||
U.init(this.map);
|
||||
this.listeners = {};
|
||||
}
|
||||
|
||||
//监听
|
||||
on(event: EventType, callback: void) {
|
||||
console.log('on', event);
|
||||
this.listeners[event] = callback;
|
||||
}
|
||||
|
||||
off(event: EventType) {
|
||||
console.log('off', event);
|
||||
if (this.listeners[event]) {
|
||||
delete this.listeners[event];
|
||||
}
|
||||
}
|
||||
|
||||
emit(event: EventType, data: any) {
|
||||
if (this.listeners[event]) {
|
||||
this.listeners[event](data);
|
||||
}
|
||||
}
|
||||
|
||||
//防抖函数
|
||||
debounce = (func: Function, delay: number) => {
|
||||
let timer: any = null;
|
||||
return (...args: any) => {
|
||||
if (timer) clearTimeout(timer);
|
||||
timer = setTimeout(() => {
|
||||
func.apply(this, args);
|
||||
}, delay);
|
||||
};
|
||||
};
|
||||
|
||||
//切换鼠标样式
|
||||
_changeMouseCursor = (cursor: string = 'pointer') => {
|
||||
this.map.getCanvas().style.cursor = cursor;
|
||||
};
|
||||
|
||||
//生成geoJson
|
||||
_generateGeoJSON(data: GenerateGeoJSONDataInterface[], geometryType: EventType) {
|
||||
/**
|
||||
* // 生成点类型的GeoJSON
|
||||
* var data = [{lng: -122.4194, lat: 37.7749}, {lng: -122.408, lat: 37.791}, {lng: -122.431, lat: 37.769}];
|
||||
* var geoJSON = generateGeoJSON(data, "Point");
|
||||
*
|
||||
* // 生成线类型的GeoJSON
|
||||
* var data = [{lng: -122.4194, lat: 37.7749}, {lng: -122.408, lat: 37.791}, {lng: -122.431, lat: 37.769}];
|
||||
* var geoJSON = generateGeoJSON(data, "LineString");
|
||||
*
|
||||
* // 生成面类型的GeoJSON
|
||||
* var data = [{lng: -122.4194, lat: 37.7749}, {lng: -122.408, lat: 37.791}, {lng: -122.431, lat: 37.769}];
|
||||
* var geoJSON = generateGeoJSON(data, "Polygon");
|
||||
* **/
|
||||
|
||||
const featureCollection: FeatureCollection = {
|
||||
type: 'FeatureCollection',
|
||||
features: [],
|
||||
};
|
||||
switch (geometryType) {
|
||||
case 'Point':
|
||||
for (let i = 0; i < data.length; i++) {
|
||||
const feature = {
|
||||
type: 'Feature',
|
||||
geometry: {
|
||||
type: geometryType,
|
||||
coordinates: [data[i].lng, data[i].lat],
|
||||
},
|
||||
properties: {},
|
||||
};
|
||||
featureCollection.features.push(feature);
|
||||
}
|
||||
break;
|
||||
case 'LineString':
|
||||
const lineFeature = {
|
||||
type: 'Feature',
|
||||
geometry: {
|
||||
type: geometryType,
|
||||
coordinates: [],
|
||||
},
|
||||
properties: {},
|
||||
};
|
||||
for (let i = 0; i < data.length; i++) {
|
||||
lineFeature['geometry']['coordinates'].push([data[i].lng, data[i].lat]);
|
||||
}
|
||||
featureCollection.features.push(lineFeature);
|
||||
break;
|
||||
case 'Polygon':
|
||||
const polygonFeature = {
|
||||
type: 'Feature',
|
||||
geometry: {
|
||||
type: geometryType,
|
||||
coordinates: [[]],
|
||||
},
|
||||
properties: {},
|
||||
};
|
||||
for (let i = 0; i < data.length; i++) {
|
||||
polygonFeature['geometry']['coordinates'][0].push([data[i].lng, data[i].lat]);
|
||||
}
|
||||
featureCollection.features.push(polygonFeature);
|
||||
break;
|
||||
}
|
||||
return featureCollection;
|
||||
}
|
||||
}
|
||||
|
||||
export class MP extends BaseMP {
|
||||
drawModelChoose: { LineString: string; Point: string; Polygon: string; DEFAULT: string };
|
||||
drawModel: string;
|
||||
drawLocal: never[];
|
||||
drawCurrentId: {
|
||||
point: string; //点
|
||||
line: string; //线
|
||||
lastLine: string; //鼠标位置的点
|
||||
polygon: string;
|
||||
};
|
||||
currentMouseLocation: null;
|
||||
correctionMouseLocation: any;
|
||||
clickCount: number;
|
||||
clickTimeout: any;
|
||||
constructor(map) {
|
||||
super(map);
|
||||
this.drawModelChoose = {
|
||||
LineString: 'LineString',
|
||||
Point: 'Point',
|
||||
Polygon: 'Polygon',
|
||||
DEFAULT: 'default',
|
||||
};
|
||||
this.drawModel = this.drawModelChoose.DEFAULT;
|
||||
this.drawLocal = [];
|
||||
this.drawCurrentId = {
|
||||
point: 'current-draw-point', //点
|
||||
line: 'current-draw-line', //线
|
||||
lastLine: 'current-draw-last-line', //鼠标位置的点
|
||||
polygon: 'current-draw-polygon',
|
||||
};
|
||||
this.currentMouseLocation = null; //当前鼠标位置
|
||||
this.correctionMouseLocation = null; //校正后的鼠标位置
|
||||
this.clickCount = 0; // 定义一个计数器
|
||||
this.clickTimeout = null; // 定义一个超时变量
|
||||
}
|
||||
|
||||
//添加或更新source
|
||||
_addOrUpdateSource = (gS, id) => {
|
||||
if (this.map.getSource(id)) {
|
||||
this.map.getSource(id).setData(gS);
|
||||
} else {
|
||||
this.map.U.addGeoJSON(id, gS);
|
||||
}
|
||||
};
|
||||
// 添加layer,有则不操作
|
||||
_addLayer = (layerId, sourceId, type, style) => {
|
||||
// 如果图层不存在,添加图层。如果存在,不做操作
|
||||
if (!this.map.getLayer(sourceId)) {
|
||||
switch (type) {
|
||||
case this.drawModelChoose.Point:
|
||||
//addCircleLayer
|
||||
this.map.U.addCircleLayer(layerId, sourceId, style);
|
||||
break;
|
||||
case this.drawModelChoose.LineString:
|
||||
//addLineLayer
|
||||
this.map.U.addLineLayer(layerId, sourceId, style);
|
||||
break;
|
||||
case this.drawModelChoose.Polygon:
|
||||
//addPolygonLayer
|
||||
this.map.U.addFillLayer(layerId, sourceId, style);
|
||||
break;
|
||||
default:
|
||||
console.log('layer类型错误');
|
||||
}
|
||||
}
|
||||
};
|
||||
_currentDrawSource = () => {
|
||||
// currentGSP 点 currentGSL 线 currentGSPL 面
|
||||
const currentGSP = this._generateGeoJSON(this.drawLocal, 'Point');
|
||||
this._addOrUpdateSource(currentGSP, this.drawCurrentId.point);
|
||||
|
||||
if (
|
||||
this.drawModel === this.drawModelChoose.LineString ||
|
||||
this.drawModel === this.drawModelChoose.Polygon
|
||||
) {
|
||||
const currentGSL = this._generateGeoJSON(this.drawLocal, 'LineString');
|
||||
this._addOrUpdateSource(currentGSL, this.drawCurrentId.line);
|
||||
}
|
||||
if (this.drawModel === this.drawModelChoose.Polygon) {
|
||||
const lastGSPL = this._generateGeoJSON(this.drawLocal, 'Polygon');
|
||||
this._addOrUpdateSource(lastGSPL, this.drawCurrentId.polygon);
|
||||
}
|
||||
};
|
||||
//绘制当前的layer
|
||||
_currentDrawLayer = () => {
|
||||
// 如果是点,直接绘制点
|
||||
this._addLayer(this.drawCurrentId.point, this.drawCurrentId.point, 'Point', CIRCLE_STYLE);
|
||||
// 如果是线,在点的基础上,加上线
|
||||
// 如果是面,在线的基础上,加上面
|
||||
if (
|
||||
this.drawModel === this.drawModelChoose.LineString ||
|
||||
this.drawModel === this.drawModelChoose.Polygon
|
||||
) {
|
||||
this._addLayer(this.drawCurrentId.line, this.drawCurrentId.line, 'LineString', LINE_STYLE);
|
||||
}
|
||||
if (this.drawModel === this.drawModelChoose.Polygon) {
|
||||
this._addLayer(
|
||||
this.drawCurrentId.polygon,
|
||||
this.drawCurrentId.polygon,
|
||||
'Polygon',
|
||||
POLYGON_STYLE,
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
//最后动态的一笔
|
||||
_currentDrawLastLine = () => {
|
||||
if (
|
||||
this.drawModel === this.drawModelChoose.LineString ||
|
||||
this.drawModel === this.drawModelChoose.Polygon
|
||||
) {
|
||||
if (!this.drawLocal.length) {
|
||||
this.map.U.removeLayer(this.drawCurrentId.lastLine);
|
||||
this.map.U.removeSource(this.drawCurrentId.lastLine);
|
||||
return false;
|
||||
}
|
||||
const startPoint = this.drawLocal[this.drawLocal.length - 1];
|
||||
const endPoint = this.getDrawEndPoint();
|
||||
|
||||
// 添加动态线
|
||||
const lastGSL = this._generateGeoJSON([startPoint, endPoint], 'LineString');
|
||||
this.crossesLine(this.drawLocal, [startPoint, endPoint]);
|
||||
this._addOrUpdateSource(lastGSL, this.drawCurrentId.lastLine);
|
||||
this._addLayer(
|
||||
this.drawCurrentId.lastLine,
|
||||
this.drawCurrentId.lastLine,
|
||||
'LineString',
|
||||
LINE_IS_DRAW_STYLE,
|
||||
);
|
||||
}
|
||||
if (this.drawModel === this.drawModelChoose.Polygon) {
|
||||
this._currentDrawLastPolygon();
|
||||
}
|
||||
};
|
||||
//获取矫正的最后点
|
||||
getDrawEndPoint = () => {
|
||||
let endPoint = null;
|
||||
if (this.nearlyClientDistant()) {
|
||||
endPoint = this.correctionMouseLocation;
|
||||
} else {
|
||||
endPoint = this.currentMouseLocation;
|
||||
}
|
||||
return endPoint;
|
||||
};
|
||||
//最后动态的一笔,跟随面生成
|
||||
_currentDrawLastPolygon = () => {
|
||||
// 添加动态面
|
||||
const endPoint = this.getDrawEndPoint();
|
||||
const drawLocalCopy = deepClone(this.drawLocal);
|
||||
drawLocalCopy.push(endPoint);
|
||||
drawLocalCopy.push(drawLocalCopy[0]);
|
||||
const lastGSPL = this._generateGeoJSON(drawLocalCopy, 'Polygon');
|
||||
this._addOrUpdateSource(lastGSPL, this.drawCurrentId.polygon);
|
||||
this._addLayer(
|
||||
this.drawCurrentId.polygon,
|
||||
this.drawCurrentId.polygon,
|
||||
'Polygon',
|
||||
POLYGON_STYLE,
|
||||
);
|
||||
};
|
||||
|
||||
//鼠标点击
|
||||
clickHandler = (e) => {
|
||||
const _this = this;
|
||||
this.clickCount++; // 每次单击事件计数器加1
|
||||
if (this.clickCount === 1) {
|
||||
// 如果是第一次单击
|
||||
this.clickTimeout = setTimeout(function () {
|
||||
// 启动超时变量
|
||||
// 单击事件
|
||||
_this.clickCount = 0; // 计数器清零
|
||||
if (_this.nearlyClientDistant()) {
|
||||
_this.drawLocal.push(_this.correctionMouseLocation);
|
||||
// 如果是第一个点,那么就结束绘制
|
||||
// todo 画面第一点后结束
|
||||
if (
|
||||
_this.drawModel === _this.drawModelChoose.Polygon &&
|
||||
_this.correctionMouseLocation === _this.drawLocal[0]
|
||||
) {
|
||||
_this._currentDrawSource();
|
||||
_this._currentDrawLayer();
|
||||
_this.emit(_this.drawModel, _this.drawLocal);
|
||||
_this.finishDraw();
|
||||
return false;
|
||||
} else {
|
||||
_this.drawLocal.pop();
|
||||
}
|
||||
} else {
|
||||
_this.drawLocal.push(e.lngLat);
|
||||
}
|
||||
_this._currentDrawSource();
|
||||
_this._currentDrawLayer();
|
||||
if (_this.drawModel === _this.drawModelChoose.Point) {
|
||||
_this.drawIsFinish();
|
||||
}
|
||||
}, 200); // 设置超时时间为300毫秒
|
||||
} else {
|
||||
// 如果不是第一次单击
|
||||
clearTimeout(this.clickTimeout); // 清除超时变量
|
||||
this.clickCount = 0; // 计数器清零
|
||||
// 在这里编写双击事件的操作
|
||||
|
||||
// 鼠标双击事件
|
||||
|
||||
if (this.drawModel === this.drawModelChoose.LineString) {
|
||||
_this.drawLocal.push(e.lngLat);
|
||||
_this._currentDrawSource();
|
||||
_this._currentDrawLayer();
|
||||
this.drawIsFinish();
|
||||
}
|
||||
|
||||
if (this.drawModel === this.drawModelChoose.Polygon) {
|
||||
_this.drawLocal.push(e.lngLat);
|
||||
_this._currentDrawSource();
|
||||
_this._currentDrawLayer();
|
||||
this.drawIsFinish();
|
||||
}
|
||||
}
|
||||
};
|
||||
//右键点击
|
||||
contextmenuHandler = (e) => {
|
||||
if (this.drawLocal.length < 1) {
|
||||
return false;
|
||||
}
|
||||
this.drawLocal.pop();
|
||||
this._currentDrawSource();
|
||||
this._currentDrawLayer();
|
||||
this._currentDrawLastLine();
|
||||
};
|
||||
// 鼠标移动
|
||||
mousemoveHandler = this.debounce((e) => {
|
||||
this.currentMouseLocation = e.lngLat;
|
||||
this._currentDrawLastLine();
|
||||
}, 5);
|
||||
// 判断是否吸附,距离12像素
|
||||
nearlyClientDistant = () => {
|
||||
// 判断屏幕距离,鼠标吸附
|
||||
let _this = this;
|
||||
let mousePoint = [this.currentMouseLocation.lng, this.currentMouseLocation.lat];
|
||||
let closestFeature = null;
|
||||
let closestDistance = Infinity;
|
||||
let threshold = 10; // 阈值,单位为像素
|
||||
// 遍历所有特征,找到距离最近的特征
|
||||
let clientPosition = _this.map.project(mousePoint);
|
||||
this.drawLocal.forEach(function (feature) {
|
||||
_this.map.project([feature.lng, feature.lat]);
|
||||
let featurePosition = _this.map.project([feature.lng, feature.lat]);
|
||||
// 计算两个点在屏幕上的像素距离
|
||||
let distance = Math.sqrt(
|
||||
Math.pow(clientPosition.x - featurePosition.x, 2) +
|
||||
Math.pow(clientPosition.y - featurePosition.y, 2),
|
||||
);
|
||||
if (distance < closestDistance && distance < threshold) {
|
||||
closestFeature = feature;
|
||||
closestDistance = distance;
|
||||
}
|
||||
});
|
||||
// 如果距离小于阈值,则将标注吸附到特征上
|
||||
if (closestFeature) {
|
||||
this._changeMouseCursor('pointer');
|
||||
this.correctionMouseLocation = closestFeature;
|
||||
return true;
|
||||
} else {
|
||||
// console.log('范围外')
|
||||
this._changeMouseCursor('crosshair');
|
||||
return false;
|
||||
}
|
||||
};
|
||||
// 判断是否相交 true 相交 false 不相交
|
||||
crossesLine = (line1, line2) => {
|
||||
let _this = this;
|
||||
if (this.drawLocal.length >= 3) {
|
||||
let _line1 = line1.map((e) => {
|
||||
return [e.lng, e.lat];
|
||||
});
|
||||
_line1.pop();
|
||||
let _line2 = line2.map((e) => {
|
||||
return [e.lng, e.lat];
|
||||
});
|
||||
//判断是否有交叉
|
||||
let intersect = turf.lineIntersect(turf.lineString(_line1), turf.lineString(_line2));
|
||||
if (intersect.features.length > 0) {
|
||||
let coordinates = intersect.features[0].geometry.coordinates;
|
||||
//判断是否交叉在点上
|
||||
const isExist = _line1.some(
|
||||
(item) => item[0] === coordinates[0] && item[1] === coordinates[1],
|
||||
);
|
||||
if (isExist) {
|
||||
// console.log('no cross,穿过了交点')
|
||||
_this.map.U.setProperty(this.drawCurrentId.lastLine, 'line-color', '#00FA9A');
|
||||
_this.map.on('click', this.clickHandler);
|
||||
} else {
|
||||
// console.log('cross')
|
||||
_this.map.U.setProperty(this.drawCurrentId.lastLine, 'line-color', '#DC143C');
|
||||
_this._changeMouseCursor('no-drop');
|
||||
_this.map.off('click', this.clickHandler);
|
||||
}
|
||||
} else {
|
||||
// console.log('no cross,不沾边')
|
||||
_this.map.U.setProperty(this.drawCurrentId.lastLine, 'line-color', '#00FA9A');
|
||||
_this.map.on('click', this.clickHandler);
|
||||
}
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
drawStart = () => {
|
||||
//每次绘制都要初始化数据
|
||||
this.drawLocal = [];
|
||||
this.deleteDraw();
|
||||
//禁用鼠标双击放大事件
|
||||
this.map.doubleClickZoom.disable();
|
||||
this._changeMouseCursor('crosshair');
|
||||
this.map.on('click', this.clickHandler);
|
||||
this.map.on('contextmenu', this.contextmenuHandler);
|
||||
this.map.on('mousemove', this.mousemoveHandler);
|
||||
};
|
||||
draw = (shape) => {
|
||||
if(this.drawModelChoose[shape]) {
|
||||
this.drawModel = this.drawModelChoose[shape];
|
||||
this.drawStart();
|
||||
} else {
|
||||
console.log(`暂无${shape}类型`);
|
||||
}
|
||||
};
|
||||
drawIsFinish = () => {
|
||||
let _this = this;
|
||||
this.emit(this.drawModel, this.drawLocal);
|
||||
this.finishDraw();
|
||||
//恢复双击放大功能
|
||||
setTimeout(() => {
|
||||
_this.map.doubleClickZoom.enable();
|
||||
}, 10);
|
||||
};
|
||||
// 结束绘制线和面
|
||||
finishDraw = () => {
|
||||
this.map.U.removeSource(this.drawCurrentId.lastLine);
|
||||
this.map.U.removeLayer(this.drawCurrentId.lastLine);
|
||||
this.drawModel = this.drawModelChoose.DEFAULT;
|
||||
this.unDraw();
|
||||
};
|
||||
unDraw = () => {
|
||||
// console.log('推出绘制模式');
|
||||
this.map.off('click', this.clickHandler);
|
||||
this.map.off('contextmenu', this.contextmenuHandler);
|
||||
this.map.off('mousemove', this.mousemoveHandler);
|
||||
this._changeMouseCursor('pointer');
|
||||
this.drawLocal = [];
|
||||
};
|
||||
//删除绘制的内容
|
||||
deleteDraw = () => {
|
||||
this.map.U.removeSource([
|
||||
this.drawCurrentId.line,
|
||||
this.drawCurrentId.point,
|
||||
this.drawCurrentId.lastLine,
|
||||
this.drawCurrentId.polygon,
|
||||
]);
|
||||
this.map.U.removeLayer([
|
||||
this.drawCurrentId.line,
|
||||
this.drawCurrentId.point,
|
||||
this.drawCurrentId.lastLine,
|
||||
this.drawCurrentId.polygon,
|
||||
]);
|
||||
this.unDraw();
|
||||
};
|
||||
}
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
import WKT from "terraformer-wkt-parser"
|
||||
import { wktToGeoJSON,geojsonToWKT } from "@terraformer/wkt"
|
||||
|
||||
|
||||
|
||||
const WktToGeojson = (wktData)=> {
|
||||
// return WKT.parse(wktData)
|
||||
return wktToGeoJSON(wktData);
|
||||
}
|
||||
|
||||
const GeojsonToWkt = (geojsonData)=> {
|
||||
// return WKT.convert(geojsonData)
|
||||
console.log("geojsonData",geojsonData)
|
||||
return geojsonToWKT(geojsonData)
|
||||
}
|
||||
|
||||
|
||||
export {WktToGeojson,GeojsonToWkt}
|
||||
|
|
@ -0,0 +1,80 @@
|
|||
export enum MapboxConfig {
|
||||
ACCESS_TOKEN = 'pk.eyJ1IjoieHVqaW5nbGlhbmciLCJhIjoiY2w3bzFzZnZqMjdieTN1cG92N2I1d2huOSJ9.aQqMz4S-cTziUYizIH_gNg',
|
||||
// ACCESS_TOKEN = "1234",
|
||||
TDT_TOKEN = 'b6585bc41ee16251dbe6b1af64f375d9',
|
||||
// add more config options here
|
||||
}
|
||||
export const MapboxDefaultStyle = {
|
||||
glyphs: 'mapbox://fonts/mapbox/{fontstack}/{range}.pbf',
|
||||
version: 8,
|
||||
sources: {
|
||||
'dianzi': {
|
||||
type: 'raster',
|
||||
tiles: [
|
||||
`https://t0.tianditu.gov.cn/DataServer?T=cva_w&x={x}&y={y}&l={z}&tk=${MapboxConfig.TDT_TOKEN}`,
|
||||
],
|
||||
tileSize: 256,
|
||||
minzoom:18,
|
||||
maxzoom:24,
|
||||
},
|
||||
'dianzi-biaozhu': {
|
||||
type: 'raster',
|
||||
tiles: [
|
||||
`https://t0.tianditu.gov.cn/DataServer?T=vec_w&x={x}&y={y}&l={z}&tk=${MapboxConfig.TDT_TOKEN}`,
|
||||
],
|
||||
tileSize: 256,
|
||||
},
|
||||
'raster-tiles': {
|
||||
type: 'raster',
|
||||
tiles: [
|
||||
`https://t0.tianditu.gov.cn/DataServer?T=img_w&x={x}&y={y}&l={z}&tk=${MapboxConfig.TDT_TOKEN}`,
|
||||
],
|
||||
tileSize: 256,
|
||||
minzoom:0,
|
||||
maxzoom:18,
|
||||
},
|
||||
},
|
||||
layers: [
|
||||
{
|
||||
id: 'dianzi-biaozhu',
|
||||
type: 'raster',
|
||||
source: 'dianzi-biaozhu',
|
||||
layout: {
|
||||
visibility: 'visible',
|
||||
},
|
||||
},{
|
||||
id: 'tdt-img-tiles',
|
||||
type: 'raster',
|
||||
source: 'raster-tiles',
|
||||
minzoom: 0,
|
||||
maxzoom: 18,
|
||||
},{
|
||||
id: 'dianzi',
|
||||
type: 'raster',
|
||||
source: 'dianzi',
|
||||
layout: {
|
||||
visibility: 'visible',
|
||||
},
|
||||
minzoom: 18,
|
||||
maxzoom: 24,
|
||||
}
|
||||
],
|
||||
};
|
||||
|
||||
export const MapControlConfig = {
|
||||
DrawPoint: {
|
||||
handler: 'handlerDrawPoint',
|
||||
icon: '/point.png',
|
||||
title: '绘制点',
|
||||
},
|
||||
DrawLineString: {
|
||||
handler: 'handlerDrawLineString',
|
||||
icon: '/line.png',
|
||||
title: '绘制线',
|
||||
},
|
||||
DrawPolygon: {
|
||||
handler: 'handlerDrawPolygon',
|
||||
icon: '/polygon.png',
|
||||
title: '绘制面',
|
||||
},
|
||||
};
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
.mapboxgl-ctrl-logo {
|
||||
display: none !important;
|
||||
}
|
||||
.map-container {
|
||||
position: relative;
|
||||
}
|
||||
.map-box,
|
||||
.map-container {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
.map-control {
|
||||
position: absolute;
|
||||
right: 10px;
|
||||
top: 10px;
|
||||
display: flex;
|
||||
}
|
||||
.map-control img {
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
.mapboxgl-ctrl-logo {
|
||||
display: none !important;
|
||||
}
|
||||
.map-container{
|
||||
position: relative;
|
||||
}
|
||||
.map-box,
|
||||
.map-container {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.map-control {
|
||||
position: absolute;
|
||||
right: 10px;
|
||||
top: 10px;
|
||||
display: flex;
|
||||
|
||||
img {
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
cursor: pointer;
|
||||
}
|
||||
img:hover {
|
||||
scale: 1.2;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,62 @@
|
|||
import { ControlOutlined } from '@ant-design/icons-vue';
|
||||
import * as turf from '@turf/turf'
|
||||
|
||||
// js生成UUID
|
||||
const generateUUID = ()=>{
|
||||
|
||||
var d = new Date().getTime(); //Timestamp
|
||||
var d2 = (performance && performance.now && (performance.now()*1000)) || 0;
|
||||
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
|
||||
var r = Math.random() * 16;
|
||||
if(d > 0) {
|
||||
r = (d + r)%16 | 0;
|
||||
d = Math.floor(d/16);
|
||||
} else {
|
||||
r = (d2 + r)%16 | 0;
|
||||
d2 = Math.floor(d2/16);
|
||||
}
|
||||
return (c === 'x' ? r : (r & 0x3 | 0x8)).toString(16);
|
||||
});
|
||||
}
|
||||
|
||||
// js 针对后端post接口参数拼接到url的情况 将json参数转换为 ?key1=value1&key2=value2
|
||||
const ObjectToUrl = (obj)=>{
|
||||
let params = "?";
|
||||
for(let item in obj){
|
||||
params+=item+"="+obj[item]+"&"
|
||||
}
|
||||
return params;
|
||||
}
|
||||
|
||||
|
||||
// turf获取几何图形的中心
|
||||
const getGeometryCenter = (geometry)=>{
|
||||
let coordinates = [];
|
||||
switch(geometry.geometry.type.toUpperCase()){
|
||||
case "POINT":
|
||||
|
||||
break;
|
||||
case "MULTIPOINT":
|
||||
|
||||
break;
|
||||
case "LINESTRING":
|
||||
|
||||
break;
|
||||
case "MULTILINESTRING":
|
||||
|
||||
break;
|
||||
case "POLYGON":
|
||||
coordinates = geometry.geometry.coordinates
|
||||
break;
|
||||
case "MULTIPOLYGON":
|
||||
coordinates = geometry.geometry.coordinates[0]
|
||||
break;
|
||||
}
|
||||
|
||||
// let polygon = turf.polygon(coordinates);
|
||||
// let center = turf.centerOfMass(polygon);
|
||||
return [coordinates[0][0][0],coordinates[0][0][1]];
|
||||
// return [117.732878836452,35.1320944773393]
|
||||
}
|
||||
|
||||
export { generateUUID,ObjectToUrl,getGeometryCenter }
|
||||
|
|
@ -33,7 +33,7 @@
|
|||
<!-- case list -->
|
||||
<CaseList v-show="false" @handlerLayerButtonClick="handlerLayerButtonClick" @toPosition="toPosition"></CaseList>
|
||||
<!-- uav -->
|
||||
<UAV v-show="false" @toPosition="toPosition" @handlerUpdateUavLayerData="handlerUpdateUavLayerData" @handlerLayerButtonClick="handlerLayerButtonClick"></UAV>
|
||||
<!-- <UAV v-show="false" @toPosition="toPosition" @handlerUpdateUavLayerData="handlerUpdateUavLayerData" @handlerLayerButtonClick="handlerLayerButtonClick"></UAV> -->
|
||||
</div>
|
||||
<!-- monitor -->
|
||||
<!-- <Monitor :currentMonitor="monitorInfo" @register="registerModal" /> -->
|
||||
|
|
@ -43,8 +43,17 @@
|
|||
<div class="close-button" @click="showTCLPlayer = false;">
|
||||
<CloseOutlined></CloseOutlined>
|
||||
</div>
|
||||
<TCVideo v-if="showTCLPlayer"></TCVideo>
|
||||
<TCVideo v-if="showTCLPlayer" :play-url="'12334344'"></TCVideo>
|
||||
</div>
|
||||
|
||||
<!-- layer center -->
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
<div class="layer-center-container">
|
||||
<LayerCenter></LayerCenter>
|
||||
</div>
|
||||
|
||||
<a-modal
|
||||
|
|
@ -62,8 +71,11 @@
|
|||
</div>
|
||||
</a-modal>
|
||||
|
||||
|
||||
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
|
||||
import ShowInfoModal from '@/views/demo/tiankongdi/curbspotcity/MapList/ShowInfoModal/index.vue';
|
||||
import SearchComponent from './VideoSupervision/search/index.vue'
|
||||
import Map from './VideoSupervision/map/map.vue';
|
||||
|
|
@ -82,6 +94,10 @@ import {PlayCircleOutlined,EnvironmentOutlined,CloseOutlined} from "@ant-design/
|
|||
import { useMessage } from '@/hooks/web/useMessage';
|
||||
import { useMultipleTabStore } from '@/store/modules/multipleTab';
|
||||
import { getLoadDroneCaseInfoDetail, getCaseInfoById } from '@/api/tiankongdi/index';
|
||||
|
||||
import LayerCenter from './VideoSupervision/layers/index.vue';
|
||||
|
||||
|
||||
const { t } = useI18n();
|
||||
const router = useRouter();
|
||||
const { createConfirm } = useMessage();
|
||||
|
|
@ -367,4 +383,12 @@ onMounted(() => {
|
|||
cursor:pointer;
|
||||
}
|
||||
}
|
||||
|
||||
.layer-center-container{
|
||||
width:208px;
|
||||
position:absolute;
|
||||
bottom:20px;
|
||||
left:20px;
|
||||
z-index:99999;
|
||||
}
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,223 @@
|
|||
<template>
|
||||
<div class="layer-list-container" >
|
||||
<div class="title">
|
||||
图层
|
||||
</div>
|
||||
<p class="cate-name">数据图层</p>
|
||||
<div class="case-list">
|
||||
<div class="case-item" v-for="item in dataLayerList" :key="index" >
|
||||
<img src="/statistical/prove-icon.png" alt="" />
|
||||
<a-checkbox v-model:checked="item.checked" @change="layerChange(item)" >
|
||||
<span style="color:#fff;">{{item.name}}</span>
|
||||
</a-checkbox>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<p class="cate-name">历史影像</p>
|
||||
<div class="case-list">
|
||||
<div class="case-item" v-for="item in historyLayerList" :key="index" >
|
||||
<img src="/statistical/prove-icon.png" alt="" />
|
||||
<a-checkbox v-model:checked="item.checked" @change="layerChange(item)" >
|
||||
<span style="color:#fff;">{{item.name}}</span>
|
||||
</a-checkbox>
|
||||
</div>
|
||||
<a-empty v-if="historyLayerList.length <= 0" />
|
||||
</div>
|
||||
|
||||
<p class="cate-name">专题图层</p>
|
||||
|
||||
<div class="case-list">
|
||||
<div class="case-item" v-for="item in speciaLayerList" :key="index" >
|
||||
<img src="/statistical/prove-icon.png" alt="" />
|
||||
<a-checkbox v-model:checked="item.checked" @change="layerChange(item)" >
|
||||
<span style="color:#fff;">{{item.name}}</span>
|
||||
</a-checkbox>
|
||||
</div>
|
||||
<a-empty v-if="speciaLayerList.length <= 0" />
|
||||
</div>
|
||||
|
||||
|
||||
<p class="cate-name">地图底图</p>
|
||||
<div class="case-list">
|
||||
|
||||
<a-radio-group v-model:value="baseLayer">
|
||||
<div class="case-item" v-for="item in baseLayerList" :key="index" >
|
||||
<img src="/statistical/prove-icon.png" alt="" />
|
||||
<a-radio :value="item.value">
|
||||
<span style="color:#fff;">{{item.name}}</span>
|
||||
</a-radio>
|
||||
</div>
|
||||
</a-radio-group>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import {
|
||||
defineEmits,
|
||||
ref,
|
||||
defineExpose,
|
||||
} from 'vue'
|
||||
|
||||
import {getIntersectTif } from '@/api/tiankongdi';
|
||||
import { useMessage } from '@/hooks/web/useMessage';
|
||||
const { createConfirm, createMessage } = useMessage();
|
||||
|
||||
const dataLayerList = ref([
|
||||
{
|
||||
name:"数据图层",
|
||||
checked:true,
|
||||
},
|
||||
{
|
||||
name:"视频监控",
|
||||
checked:false,
|
||||
value:"JianKong"
|
||||
}
|
||||
])
|
||||
|
||||
const historyLayerList = ref([
|
||||
{
|
||||
name:"费县影像图层",
|
||||
checked:false,
|
||||
}
|
||||
])
|
||||
const speciaLayerList = ref([
|
||||
{
|
||||
name:"地类图层",
|
||||
checked:false,
|
||||
},
|
||||
{
|
||||
name:"三调图层",
|
||||
checked:false,
|
||||
}
|
||||
])
|
||||
|
||||
const baseLayerList = ref([
|
||||
{
|
||||
name:"导航地图",
|
||||
checked:false,
|
||||
value:"daohang",
|
||||
},{
|
||||
name:"卫星地图",
|
||||
checked:false,
|
||||
value:"weixing",
|
||||
},{
|
||||
name:"白板地图",
|
||||
checked:false,
|
||||
value:"baiban",
|
||||
},
|
||||
])
|
||||
|
||||
const baseLayer = ref("weixing")
|
||||
|
||||
const emits = defineEmits(['changeTifLayer'])
|
||||
|
||||
const handlerQueryIntersectTif = (wkt:string)=>{
|
||||
|
||||
let query = {
|
||||
TargetShape:wkt,
|
||||
page:1,
|
||||
limit:10,
|
||||
key:null
|
||||
}
|
||||
|
||||
getIntersectTif(query).then(res=>{
|
||||
if(res.items.length>0){
|
||||
res.items?.forEach((item,index)=>{
|
||||
res.items[index].checked = false;
|
||||
})
|
||||
layerList.value = res.items;
|
||||
}else{
|
||||
createMessage.error("当前范围内暂无查询数据!");
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
const layerChange = (item)=>{
|
||||
emits("changeTifLayer",item);
|
||||
}
|
||||
|
||||
// 抛出函数
|
||||
defineExpose({
|
||||
// handlerQueryIntersectTif
|
||||
});
|
||||
|
||||
</script>
|
||||
<style type="less" scoped>
|
||||
|
||||
.layer-list-container {
|
||||
width: 208px;
|
||||
min-height: 340px;
|
||||
background: #041b36;
|
||||
position: relative;
|
||||
margin-bottom: 20px;
|
||||
&::before {
|
||||
content: '';
|
||||
height: 70%;
|
||||
width: 20px;
|
||||
position: absolute;
|
||||
bottom: 5px;
|
||||
left: 5px;
|
||||
background: url('/videosupervision/main-left.png');
|
||||
background-size: 100% 100%;
|
||||
}
|
||||
&::after {
|
||||
content: '';
|
||||
height: 70%;
|
||||
width: 20px;
|
||||
position: absolute;
|
||||
bottom: 5px;
|
||||
right: 5px;
|
||||
background: url('/videosupervision/main-right.png');
|
||||
background-size: 100% 100%;
|
||||
}
|
||||
.title {
|
||||
width: 100%;
|
||||
height: 40px;
|
||||
background-image: url('/videosupervision/title.png');
|
||||
background-size: 100% 100%;
|
||||
line-height: 40px;
|
||||
text-indent: 18px;
|
||||
font-size: 18px;
|
||||
font-weight: bold;
|
||||
color: #fff;
|
||||
}
|
||||
.switch-button {
|
||||
float: right;
|
||||
margin-right: 20px;
|
||||
}
|
||||
}
|
||||
.case-list {
|
||||
padding: 10px 24px;
|
||||
overflow: auto;
|
||||
.case-item {
|
||||
cursor:pointer;
|
||||
border-bottom: 1px dashed #1d60b4;
|
||||
color:#fff;
|
||||
padding: 5px 0;
|
||||
img {
|
||||
width: 15px;
|
||||
margin-right:12px;
|
||||
}
|
||||
span {
|
||||
color: #7ebbff;
|
||||
margin-left: 10px;
|
||||
}
|
||||
}
|
||||
}
|
||||
::v-deep .ant-empty{
|
||||
margin-top:110px;
|
||||
}
|
||||
::v-deep .ant-empty-description{
|
||||
color:#fff;
|
||||
}
|
||||
|
||||
.cate-name{
|
||||
color:#fff;
|
||||
padding:12px;
|
||||
font-size:14px;
|
||||
margin-bottom:0px;
|
||||
}
|
||||
</style>
|
||||
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
{
|
||||
"type": "FeatureCollection",
|
||||
"features": [
|
||||
{
|
||||
"type": "Feature",
|
||||
"geometry": {
|
||||
"type": "Point",
|
||||
"coordinates": [118.429056,35.387537]
|
||||
},
|
||||
"properties": {
|
||||
"name":"沂南县砖埠镇东岳庄村北可见光",
|
||||
"playUrl":"http://221.2.83.254:7012/live/37130100181328000001.m3u8"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
@ -20,6 +20,8 @@
|
|||
</div>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import MonitoringData from './MonitoringData.json';
|
||||
|
||||
import { TableOutlined, GlobalOutlined,HomeOutlined} from '@ant-design/icons-vue';
|
||||
import { ref, onMounted, defineExpose, defineEmits } from 'vue';
|
||||
import { generateUUID } from '@/components/MapboxMaps/src/tool';
|
||||
|
|
@ -812,18 +814,11 @@ import { TableOutlined, GlobalOutlined,HomeOutlined} from '@ant-design/icons-vue
|
|||
}
|
||||
});
|
||||
|
||||
// // 加载闯
|
||||
// map.loadImage('/images/map/warning-car.png', function (error, image) {
|
||||
// if (error) throw error;
|
||||
// if (!map.hasImage('warningCarIcon')) {
|
||||
// map.addImage('warningCarIcon', image);
|
||||
// }
|
||||
// });
|
||||
|
||||
// 加载监控数据源
|
||||
map.addSource('JianKongSource', {
|
||||
type: 'geojson',
|
||||
data: geojson,
|
||||
data: MonitoringData,
|
||||
});
|
||||
|
||||
// 加载监控图层
|
||||
|
|
@ -1189,7 +1184,6 @@ function handlerChangeTifLayer(item){
|
|||
// 取消绘制
|
||||
const handlerDeletePolygon = ()=>{
|
||||
mp.deleteDraw();
|
||||
|
||||
tifLayers.value?.forEach((item,index)=>{
|
||||
if(map.getLayer(item)){
|
||||
map.removeLayer(item);
|
||||
|
|
|
|||
|
|
@ -5,47 +5,114 @@
|
|||
视频监控
|
||||
</div>
|
||||
<div v-show="isShowPlayer">
|
||||
|
||||
<div class="close-video-button">
|
||||
<CloseOutlined />
|
||||
</div>
|
||||
|
||||
<video
|
||||
class="video-container"
|
||||
class="TCPlayer-video-contaiiner"
|
||||
id="TCPlaeyrContainer"
|
||||
width="235px"
|
||||
height="178px"
|
||||
autoplay
|
||||
preload="auto"
|
||||
playsinline
|
||||
muted
|
||||
webkit-playsinline
|
||||
></video>
|
||||
</div>
|
||||
|
||||
<!-- <video id="flv-player" class="video-js vjs-default-skin" controls preload="auto" width="400" height="250" style="position:relative;left:10px;">
|
||||
</video> -->
|
||||
<!-- <EasyPlayer
|
||||
style="width:900px;height:500px;"
|
||||
:videoUrl="'http://221.2.83.254:7012/live/37130100181328000001.flv'"
|
||||
:aspect="'16:9'"
|
||||
live
|
||||
:fluent="true"
|
||||
:autoplay="true"
|
||||
stretch
|
||||
></EasyPlayer> -->
|
||||
|
||||
<!-- <easy-player
|
||||
video-url="http://221.2.83.254:7012/live/37130100181328000001.m3u8"
|
||||
:live="true"
|
||||
:autoplay="true"
|
||||
style="width:400px;height:250px;"
|
||||
></easy-player> -->
|
||||
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
||||
<script lang="ts" setup>
|
||||
import {ref,onMounted,onBeforeUnmount} from 'vue';
|
||||
|
||||
|
||||
// import EasyPlayer from '@easydarwin/easyplayer'
|
||||
|
||||
const isShowPlayer = ref(false);
|
||||
|
||||
let player = null;
|
||||
|
||||
function handlerPlayVideo(item){
|
||||
|
||||
isShowPlayer.value = true;
|
||||
|
||||
if (player) {
|
||||
player.src("http://221.2.83.254:7012/live/37130100181328000001.flv");
|
||||
player.src("http://221.2.83.254:7012/live/37130100181328000001.m3u8");
|
||||
} else {
|
||||
player = TCPlayer("TCPlaeyrContainer", {});
|
||||
player.src("http://221.2.83.254:7012/live/37130100181328000001.flv");
|
||||
player.src("http://221.2.83.254:7012/live/37130100181328000001.m3u8");
|
||||
}
|
||||
|
||||
|
||||
// player = videojs('flv-player', {
|
||||
// techOrder: ['flvjs', 'html5'], // 使用 flv.js 解码器
|
||||
// autoplay: true,
|
||||
// controls: true,
|
||||
// muted: true,
|
||||
// preload: 'auto',
|
||||
// sources: [
|
||||
// {
|
||||
// // src: 'http://221.2.83.254:7012/live/37130100181328000001.flv', // 替换为你的 FLV 视频流地址
|
||||
// src:"http://60.213.14.14:8080/live/1.flv",
|
||||
// type: 'video/x-flv',
|
||||
// },
|
||||
// ],
|
||||
// });
|
||||
|
||||
// 检查浏览器是否支持 flv.js
|
||||
// if (flvjs.isSupported()) {
|
||||
// alert(123);
|
||||
// const flvPlayer = flvjs.createPlayer({
|
||||
// type: 'flv',
|
||||
// url: 'http://221.2.83.254:7012/live/37130100181328000001.flv', // 替换为你的 FLV 视频流地址
|
||||
// },{
|
||||
// enableStashBuffer: false, // 禁用默认缓冲
|
||||
// isLive: true, // 启用实时流模式
|
||||
// stashInitialSize: ,
|
||||
// });
|
||||
|
||||
// flvPlayer.attachMediaElement(document.getElementById('flv-player'));
|
||||
// flvPlayer.load();
|
||||
// flvPlayer.play();
|
||||
// } else {
|
||||
// console.error('FLV.js is not supported in this browser.');
|
||||
// }
|
||||
|
||||
}
|
||||
|
||||
onMounted(()=>{
|
||||
|
||||
|
||||
// document.getElementById("TCPlaeyrContainer").addEventListener('error', () => {
|
||||
// console.error('Video playback error occurred.1111111111');
|
||||
// player.reload()
|
||||
// // if (retryCount < maxRetries) {
|
||||
// // retryCount++;
|
||||
// // console.log(`Retrying to load video... Attempt ${retryCount}`);
|
||||
// // reloadVideo();
|
||||
// // } else {
|
||||
// // console.error('Max retries reached. Could not recover video playback.');
|
||||
// // alert('视频播放失败,请稍后重试!');
|
||||
// // }
|
||||
// });
|
||||
|
||||
setTimeout(function(){
|
||||
handlerPlayVideo(123);
|
||||
},1000)
|
||||
|
|
@ -54,7 +121,7 @@ onMounted(()=>{
|
|||
|
||||
onBeforeUnmount(()=>{
|
||||
player.dispose();
|
||||
player = null
|
||||
player = null;
|
||||
})
|
||||
|
||||
</script>
|
||||
|
|
@ -66,26 +133,7 @@ onBeforeUnmount(()=>{
|
|||
height: 300px;
|
||||
background:#041B36;
|
||||
position: relative;
|
||||
&::before{
|
||||
content:"";
|
||||
height:70%;
|
||||
width:50px;
|
||||
position:absolute;
|
||||
bottom:10px;
|
||||
left:10px;
|
||||
background:url("/videosupervision/main-left.png");
|
||||
background-size:100% 100%;
|
||||
}
|
||||
&::after{
|
||||
content:"";
|
||||
height:70%;
|
||||
width:50px;
|
||||
position:absolute;
|
||||
bottom:10px;
|
||||
right:10px;
|
||||
background:url("/videosupervision/main-right.png");
|
||||
background-size:100% 100%;
|
||||
}
|
||||
|
||||
.title{
|
||||
width:100%;
|
||||
height:40px;
|
||||
|
|
@ -143,7 +191,7 @@ onBeforeUnmount(()=>{
|
|||
}
|
||||
}
|
||||
|
||||
.video-container{
|
||||
.TCPlayer-video-contaiiner{
|
||||
width: calc( 100% - 30px);
|
||||
height: calc( 100% - 70px);
|
||||
position:absolute;
|
||||
|
|
|
|||
|
|
@ -1,34 +1,27 @@
|
|||
<template>
|
||||
<div class="case-list-container" v-show="tifList.length > 0">
|
||||
<div class="title">
|
||||
查询结果
|
||||
</div>
|
||||
<div class="case-list">
|
||||
<div class="case-item" v-for="item in tifList" :key="index" >
|
||||
<img src="/statistical/prove-icon.png" alt="" />
|
||||
<a-checkbox v-model:checked="item.checked" @change="layerChange(item)" >
|
||||
<span>{{item.tifName}}</span>
|
||||
</a-checkbox>
|
||||
</div>
|
||||
<a-empty v-if="tifList.length <= 0" />
|
||||
</div>
|
||||
<div class="case-list-container" v-show="tifList.length > 0">
|
||||
<div class="title">
|
||||
查询结果
|
||||
</div>
|
||||
<div class="case-list">
|
||||
<div class="case-item" v-for="item in tifList" :key="index" >
|
||||
<img src="/statistical/prove-icon.png" alt="" />
|
||||
<a-checkbox v-model:checked="item.checked" @change="layerChange(item)" >
|
||||
<span>{{item.tifName}}</span>
|
||||
</a-checkbox>
|
||||
</div>
|
||||
<a-empty v-if="tifList.length <= 0" />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import {
|
||||
onMounted,
|
||||
onUnmounted,
|
||||
defineProps,
|
||||
defineEmits,
|
||||
reactive,
|
||||
ref,
|
||||
defineExpose,
|
||||
watch,
|
||||
inject,
|
||||
} from 'vue'
|
||||
|
||||
import {getIntersectTif } from '@/api/tiankongdi';
|
||||
|
||||
import { useMessage } from '@/hooks/web/useMessage';
|
||||
const { createConfirm, createMessage } = useMessage();
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,290 @@
|
|||
<template>
|
||||
<div class="layer-list-container" >
|
||||
<div class="title">
|
||||
图层资源
|
||||
</div>
|
||||
<div class="layers-container">
|
||||
<p class="cate-name">数据图层</p>
|
||||
<div class="case-list">
|
||||
<div class="case-item" v-for="item in dataLayerList" :key="index" >
|
||||
<img src="/statistical/prove-icon.png" alt="" />
|
||||
<a-checkbox v-model:checked="item.checked" @change="layerChange(item,'dataLayer')" >
|
||||
<span style="color:#fff;">{{item.name}}</span>
|
||||
</a-checkbox>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<p class="cate-name">
|
||||
历史影像
|
||||
<div style="float:right;position:relative;top:-4px;">
|
||||
<a-button style="flaot:right;" @click="drawPolygon" v-if="!drawState" size="small" type="primary">查询影像</a-button>
|
||||
<a-button style="flaot:right;" @click="cancleDrawPolygon" v-else size="small" type="primary">取消查询</a-button>
|
||||
</div>
|
||||
</p>
|
||||
|
||||
<div class="case-list">
|
||||
<div class="case-item" v-for="item in historyLayerList" :key="index" >
|
||||
<img src="/statistical/prove-icon.png" alt="" />
|
||||
<a-checkbox v-model:checked="item.checked" @change="layerChange(item,'historyLayer')" >
|
||||
<span style="color:#fff;">{{item.name}}</span>
|
||||
</a-checkbox>
|
||||
</div>
|
||||
<a-empty size="small" :description="'暂无历史影像数据'" v-if="historyLayerList.length <= 0" />
|
||||
</div>
|
||||
|
||||
<p class="cate-name">专题图层</p>
|
||||
|
||||
<div class="case-list">
|
||||
<div class="case-item" v-for="item in speciaLayerList" :key="index" >
|
||||
<img src="/statistical/prove-icon.png" alt="" />
|
||||
<a-checkbox v-model:checked="item.checked" @change="layerChange(item,'speciaLayer')" >
|
||||
<span style="color:#fff;">{{item.name}}</span>
|
||||
</a-checkbox>
|
||||
</div>
|
||||
<a-empty size="small" :description="'暂无专题图层数据'" v-if="speciaLayerList.length <= 0" />
|
||||
|
||||
</div>
|
||||
|
||||
<p class="cate-name">地图底图</p>
|
||||
<div class="case-list">
|
||||
|
||||
<a-radio-group v-model:value="baseLayer">
|
||||
<div class="case-item" v-for="item in baseLayerList" :key="index" >
|
||||
<img src="/statistical/prove-icon.png" alt="" />
|
||||
<a-radio :value="item.value" @change="layerChange(item,'baseLayer')">
|
||||
<span style="color:#fff;">{{item.name}}</span>
|
||||
</a-radio>
|
||||
</div>
|
||||
</a-radio-group>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import {
|
||||
defineEmits,
|
||||
ref,
|
||||
defineExpose,
|
||||
} from 'vue'
|
||||
|
||||
import {getIntersectTif } from '@/api/tiankongdi';
|
||||
import { useMessage } from '@/hooks/web/useMessage';
|
||||
const { createConfirm, createMessage } = useMessage();
|
||||
|
||||
const generateUUID = ()=>{
|
||||
|
||||
var d = new Date().getTime(); //Timestamp
|
||||
var d2 = (performance && performance.now && (performance.now()*1000)) || 0;
|
||||
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
|
||||
var r = Math.random() * 16;
|
||||
if(d > 0) {
|
||||
r = (d + r)%16 | 0;
|
||||
d = Math.floor(d/16);
|
||||
} else {
|
||||
r = (d2 + r)%16 | 0;
|
||||
d2 = Math.floor(d2/16);
|
||||
}
|
||||
return (c === 'x' ? r : (r & 0x3 | 0x8)).toString(16);
|
||||
});
|
||||
}
|
||||
|
||||
const dataLayerList = ref([
|
||||
{
|
||||
id:"Data",
|
||||
name:"数据图层",
|
||||
checked:true,
|
||||
},
|
||||
{
|
||||
id:"Monitor",
|
||||
name:"视频监控",
|
||||
checked:false,
|
||||
}
|
||||
])
|
||||
|
||||
const historyLayerList = ref([
|
||||
// {
|
||||
// id:generateUUID(),
|
||||
// name:"费县高清影像",
|
||||
// url:"http://60.213.14.14:8060/geoserver/feixian/wms?service=WMS&version=1.1.0&request=GetMap&layers=feixian:yingxiang&styles=&bbox={bbox-epsg-3857}&width=256&height=256&srs=EPSG:3857&format=image/png&TRANSPARENT=TRUE",
|
||||
// checked:false,
|
||||
// }
|
||||
])
|
||||
const speciaLayerList = ref([
|
||||
// {
|
||||
// id:generateUUID(),
|
||||
// name:"地类图层",
|
||||
// url:"http://60.213.14.14:8060/geoserver/feixian/wms?service=WMS&version=1.1.0&request=GetMap&layers=feixian:yingxiang&styles=&bbox={bbox-epsg-3857}&width=256&height=256&srs=EPSG:3857&format=image/png&TRANSPARENT=TRUE",
|
||||
// checked:false,
|
||||
// },
|
||||
// {
|
||||
// id:generateUUID(),
|
||||
// name:"三调图层",
|
||||
// url:"http://60.213.14.14:8060/geoserver/feixian/wms?service=WMS&version=1.1.0&request=GetMap&layers=feixian:yingxiang&styles=&bbox={bbox-epsg-3857}&width=256&height=256&srs=EPSG:3857&format=image/png&TRANSPARENT=TRUE",
|
||||
// checked:false,
|
||||
// }
|
||||
])
|
||||
|
||||
const baseLayer = ref("2")
|
||||
|
||||
const baseLayerList = ref([
|
||||
{
|
||||
id:1,
|
||||
name:"导航地图",
|
||||
checked:false,
|
||||
value:"1"
|
||||
},{
|
||||
id:2,
|
||||
name:"卫星地图",
|
||||
checked:false,
|
||||
value:"2"
|
||||
},{
|
||||
id:3,
|
||||
name:"白板地图",
|
||||
checked:false,
|
||||
value:"3",
|
||||
},
|
||||
])
|
||||
|
||||
|
||||
const emits = defineEmits(['changeTifLayer',"drawPolygon","cancleDrawPolygon"])
|
||||
|
||||
const handlerQueryIntersectTif = (wkt:string)=>{
|
||||
|
||||
let query = {
|
||||
TargetShape:wkt,
|
||||
page:1,
|
||||
limit:10,
|
||||
key:null
|
||||
}
|
||||
|
||||
getIntersectTif(query).then(res=>{
|
||||
if(res.items.length>0){
|
||||
res.items?.forEach((item,index)=>{
|
||||
res.items[index].checked = false;
|
||||
res.items[index].id = generateUUID();
|
||||
res.items[index].url = res.items[index].accessUrl;
|
||||
})
|
||||
historyLayerList.value = res.items;
|
||||
}else{
|
||||
createMessage.error("当前范围内暂无查询数据!");
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
const layerChange = (item,type)=>{
|
||||
item.type = type;
|
||||
emits("changeTifLayer",item);
|
||||
}
|
||||
|
||||
const drawState = ref(false);
|
||||
|
||||
const cancleDrawPolygon = ()=>{
|
||||
drawState.value = false;
|
||||
emits("cancleDrawPolygon")
|
||||
}
|
||||
const drawPolygon = (state)=>{
|
||||
drawState.value = true;
|
||||
emits("drawPolygon",state)
|
||||
}
|
||||
|
||||
// 抛出函数
|
||||
defineExpose({
|
||||
handlerQueryIntersectTif
|
||||
});
|
||||
|
||||
|
||||
|
||||
</script>
|
||||
<style type="less" scoped>
|
||||
|
||||
.layer-list-container {
|
||||
width: 208px;
|
||||
height: 600px;
|
||||
background: #041b36;
|
||||
position: relative;
|
||||
margin-bottom: 20px;
|
||||
&::before {
|
||||
content: '';
|
||||
height: 70%;
|
||||
width: 20px;
|
||||
position: absolute;
|
||||
bottom: 5px;
|
||||
left: 5px;
|
||||
background: url('/videosupervision/main-left.png');
|
||||
background-size: 100% 100%;
|
||||
}
|
||||
&::after {
|
||||
content: '';
|
||||
height: 70%;
|
||||
width: 20px;
|
||||
position: absolute;
|
||||
bottom: 5px;
|
||||
right: 5px;
|
||||
background: url('/videosupervision/main-right.png');
|
||||
background-size: 100% 100%;
|
||||
}
|
||||
|
||||
.layers-container{
|
||||
width:100%;
|
||||
height: calc( 100% - 60px);
|
||||
overflow-y:auto;
|
||||
}
|
||||
.title {
|
||||
width: 100%;
|
||||
height: 40px;
|
||||
background-image: url('/videosupervision/title.png');
|
||||
background-size: 100% 100%;
|
||||
line-height: 40px;
|
||||
text-indent: 18px;
|
||||
font-size: 18px;
|
||||
font-weight: bold;
|
||||
color: #fff;
|
||||
}
|
||||
.switch-button {
|
||||
float: right;
|
||||
margin-right: 20px;
|
||||
}
|
||||
}
|
||||
.case-list {
|
||||
padding: 10px 24px;
|
||||
overflow: auto;
|
||||
.case-item {
|
||||
cursor:pointer;
|
||||
border-bottom: 1px dashed #1d60b4;
|
||||
color:#fff;
|
||||
padding: 5px 0;
|
||||
img {
|
||||
width: 15px;
|
||||
margin-right:12px;
|
||||
}
|
||||
span {
|
||||
color: #7ebbff;
|
||||
margin-left: 10px;
|
||||
}
|
||||
}
|
||||
}
|
||||
::v-deep .ant-empty-image{
|
||||
height:50px;
|
||||
position:relative;
|
||||
left:-26px;
|
||||
}
|
||||
::v-deep .ant-empty-description{
|
||||
color:#fff;
|
||||
}
|
||||
|
||||
.cate-name{
|
||||
color:#fff;
|
||||
padding:12px;
|
||||
font-size:14px;
|
||||
margin-bottom:0px;
|
||||
background:rgba(0, 0, 0, 0.2)
|
||||
}
|
||||
|
||||
::v-deeep .ant-empty-image img{
|
||||
width:50px;
|
||||
height:50px;
|
||||
}
|
||||
</style>
|
||||
|
||||
|
|
@ -0,0 +1,156 @@
|
|||
<template>
|
||||
<div class="uav-container">
|
||||
<div class="title">
|
||||
视频监控
|
||||
</div>
|
||||
<div v-show="isShowPlayer">
|
||||
<video
|
||||
class="TCPlayer-video-contaiiner"
|
||||
id="TCPlaeyrContainer"
|
||||
width="235px"
|
||||
height="178px"
|
||||
autoplay
|
||||
preload="auto"
|
||||
playsinline
|
||||
muted
|
||||
webkit-playsinline
|
||||
></video>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
||||
<script lang="ts" setup>
|
||||
|
||||
import {ref,onMounted,defineProps,onBeforeUnmount} from 'vue';
|
||||
|
||||
const props = defineProps(["playUrl"])
|
||||
|
||||
let player = null;
|
||||
|
||||
const isShowPlayer = ref(false);
|
||||
|
||||
|
||||
function handlerPlayVideo(item){
|
||||
|
||||
isShowPlayer.value = true;
|
||||
|
||||
if (player) {
|
||||
player.src(props.playUrl);
|
||||
} else {
|
||||
player = TCPlayer("TCPlaeyrContainer", {});
|
||||
player.src(props.playUrl);
|
||||
}
|
||||
}
|
||||
|
||||
// 初始化视频控件
|
||||
onMounted(()=>{
|
||||
setTimeout(function(){
|
||||
handlerPlayVideo(123);
|
||||
},1000)
|
||||
})
|
||||
|
||||
// 销毁视频控件
|
||||
onBeforeUnmount(()=>{
|
||||
player.dispose();
|
||||
player = null;
|
||||
})
|
||||
|
||||
|
||||
</script>
|
||||
|
||||
<style type="less" scoped>
|
||||
|
||||
.uav-container{
|
||||
width: 418px;
|
||||
height: 300px;
|
||||
background:#041B36;
|
||||
position: relative;
|
||||
|
||||
.title{
|
||||
width:100%;
|
||||
height:40px;
|
||||
background-image:url("/videosupervision/title.png");
|
||||
background-size:100% 100%;
|
||||
line-height:40px;
|
||||
text-indent:18px;
|
||||
font-size:18px;
|
||||
font-weight:bold;
|
||||
color:#fff;
|
||||
}
|
||||
.switch-button{
|
||||
float:right;
|
||||
margin-right:20px;
|
||||
}
|
||||
.uav-list-container{
|
||||
width:100%;
|
||||
height: calc( 100% - 60px);
|
||||
overflow:auto;
|
||||
padding:20px 20px;
|
||||
position:relative;
|
||||
z-index:999;
|
||||
.uav-empty{
|
||||
width:100%;
|
||||
height:100%;
|
||||
text-align:center;
|
||||
color:#999;
|
||||
img{
|
||||
width:120px;
|
||||
margin:40px 0px 18px 0px;
|
||||
}
|
||||
}
|
||||
.uav-item{
|
||||
width:100%;
|
||||
height:40px;
|
||||
padding:0px 15px;
|
||||
line-height:40px;
|
||||
color:#f1f1f1;
|
||||
display:flex;
|
||||
background:rgba(0,0,0,0.2);
|
||||
&:hover{
|
||||
background:rgba(0,0,0,0.4);
|
||||
}
|
||||
div{
|
||||
flex:1;
|
||||
}
|
||||
.position{
|
||||
max-width:30px;
|
||||
cursor:pointer;
|
||||
}
|
||||
.play{
|
||||
max-width:30px;
|
||||
cursor:pointer;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.TCPlayer-video-contaiiner{
|
||||
width: calc( 100% - 30px);
|
||||
height: calc( 100% - 70px);
|
||||
position:absolute;
|
||||
margin:15px;
|
||||
top:40px;
|
||||
right:0px;
|
||||
z-index:1000;
|
||||
background:#041B36;
|
||||
.video-contain {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
}
|
||||
.close-video-button{
|
||||
position:absolute;
|
||||
top:40px;
|
||||
right:10px;
|
||||
background:rgba(0,0,0,0.3);
|
||||
z-index:100100;
|
||||
color:#fff;
|
||||
padding:10px;
|
||||
cursor:pointer;
|
||||
&:hover{
|
||||
color:#408eff;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
Loading…
Reference in New Issue