layui.use(function () { let $ = layui.jquery, layer = layui.layer, laydate = layui.laydate, element = layui.element, laytpl = layui.laytpl; // 左侧宽度 const leftWidth = $('.left-cards').width(); // 地图样式 const BAIDU_MAP_WHITE_STYLE = [ { "featureType": "water", "elementType": "geometry", "stylers": { "visibility": "on", "color": "#ccd6d7ff" } }, { "featureType": "green", "elementType": "geometry", "stylers": { "visibility": "on", "color": "#dee5e5ff" } }, { "featureType": "building", "elementType": "geometry", "stylers": { "visibility": "on" } }, { "featureType": "building", "elementType": "geometry.topfill", "stylers": { "color": "#d1dbdbff" } }, { "featureType": "building", "elementType": "geometry.sidefill", "stylers": { "color": "#d1dbdbff" } }, { "featureType": "building", "elementType": "geometry.stroke", "stylers": { "color": "#aab6b6ff" } }, { "featureType": "subwaystation", "elementType": "geometry", "stylers": { "visibility": "off", "color": "#888fa0ff" } }, { "featureType": "education", "elementType": "geometry", "stylers": { "visibility": "on", "color": "#e1e7e7ff" } }, { "featureType": "medical", "elementType": "geometry", "stylers": { "visibility": "on", "color": "#d1dbdbff" } }, { "featureType": "scenicspots", "elementType": "geometry", "stylers": { "visibility": "on", "color": "#d1dbdbff" } }, { "featureType": "highway", "elementType": "geometry", "stylers": { "visibility": "on", "weight": 4 } }, { "featureType": "highway", "elementType": "geometry.fill", "stylers": { "color": "#ffffffff" } }, { "featureType": "highway", "elementType": "geometry.stroke", "stylers": { "color": "#cacfcfff" } }, { "featureType": "highway", "elementType": "labels", "stylers": { "visibility": "on" } }, { "featureType": "highway", "elementType": "labels.text.fill", "stylers": { "color": "#999999ff" } }, { "featureType": "highway", "elementType": "labels.text.stroke", "stylers": { "color": "#ffffffff" } }, { "featureType": "highway", "elementType": "labels.icon", "stylers": { "visibility": "on" } }, { "featureType": "arterial", "elementType": "geometry", "stylers": { "visibility": "on", "weight": 2 } }, { "featureType": "arterial", "elementType": "geometry.fill", "stylers": { "color": "#fbfffeff" } }, { "featureType": "arterial", "elementType": "geometry.stroke", "stylers": { "color": "#cacfcfff" } }, { "featureType": "arterial", "elementType": "labels", "stylers": { "visibility": "on" } }, { "featureType": "arterial", "elementType": "labels.text.fill", "stylers": { "color": "#999999ff" } }, { "featureType": "arterial", "elementType": "labels.text.stroke", "stylers": { "color": "#ffffffff" } }, { "featureType": "local", "elementType": "geometry", "stylers": { "visibility": "on", "weight": 1 } }, { "featureType": "local", "elementType": "geometry.fill", "stylers": { "color": "#fbfffeff" } }, { "featureType": "local", "elementType": "geometry.stroke", "stylers": { "color": "#cacfcfff" } }, { "featureType": "local", "elementType": "labels", "stylers": { "visibility": "off" } }, { "featureType": "local", "elementType": "labels.text.fill", "stylers": { "color": "#999999ff" } }, { "featureType": "local", "elementType": "labels.text.stroke", "stylers": { "color": "#ffffffff" } }, { "featureType": "railway", "elementType": "geometry", "stylers": { "visibility": "off", "weight": 1 } }, { "featureType": "railway", "elementType": "geometry.fill", "stylers": { "color": "#9494941a" } }, { "featureType": "railway", "elementType": "geometry.stroke", "stylers": { "color": "#ffffff1a" } }, { "featureType": "subway", "elementType": "geometry", "stylers": { "visibility": "off", "weight": 1 } }, { "featureType": "subway", "elementType": "geometry.fill", "stylers": { "color": "#c3bed433" } }, { "featureType": "subway", "elementType": "geometry.stroke", "stylers": { "color": "#ffffff33" } }, { "featureType": "subway", "elementType": "labels", "stylers": { "visibility": "off" } }, { "featureType": "subway", "elementType": "labels.text.fill", "stylers": { "color": "#979c9aff" } }, { "featureType": "subway", "elementType": "labels.text.stroke", "stylers": { "color": "#ffffffff" } }, { "featureType": "continent", "elementType": "labels", "stylers": { "visibility": "on" } }, { "featureType": "continent", "elementType": "labels.icon", "stylers": { "visibility": "on" } }, { "featureType": "continent", "elementType": "labels.text.fill", "stylers": { "color": "#333333ff" } }, { "featureType": "continent", "elementType": "labels.text.stroke", "stylers": { "color": "#ffffffff" } }, { "featureType": "city", "elementType": "labels.icon", "stylers": { "visibility": "on" } }, { "featureType": "city", "elementType": "labels", "stylers": { "visibility": "on" } }, { "featureType": "city", "elementType": "labels.text.fill", "stylers": { "color": "#454d50ff" } }, { "featureType": "city", "elementType": "labels.text.stroke", "stylers": { "color": "#ffffffff" } }, { "featureType": "town", "elementType": "labels.icon", "stylers": { "visibility": "on" } }, { "featureType": "town", "elementType": "labels", "stylers": { "visibility": "off" } }, { "featureType": "town", "elementType": "labels.text.fill", "stylers": { "color": "#454d50ff" } }, { "featureType": "town", "elementType": "labels.text.stroke", "stylers": { "color": "#ffffffff" } }, { "featureType": "road", "elementType": "labels", "stylers": { "visibility": "off" } }, { "featureType": "road", "elementType": "geometry.fill", "stylers": { "color": "#fbfffeff" } }, { "featureType": "poilabel", "elementType": "labels.icon", "stylers": { "visibility": "off" } }, { "featureType": "districtlabel", "elementType": "labels.icon", "stylers": { "visibility": "off" } }, { "featureType": "poilabel", "elementType": "labels.text.fill", "stylers": { "color": "#999999ff" } }, { "featureType": "districtlabel", "elementType": "labels.text.fill", "stylers": { "color": "#888fa0ff" } }, { "featureType": "transportation", "elementType": "geometry", "stylers": { "color": "#d1dbdbff" } }, { "featureType": "companylabel", "elementType": "labels", "stylers": { "visibility": "off" } }, { "featureType": "restaurantlabel", "elementType": "labels", "stylers": { "visibility": "off" } }, { "featureType": "lifeservicelabel", "elementType": "labels", "stylers": { "visibility": "off" } }, { "featureType": "carservicelabel", "elementType": "labels", "stylers": { "visibility": "off" } }, { "featureType": "financelabel", "elementType": "labels", "stylers": { "visibility": "off" } }, { "featureType": "otherlabel", "elementType": "labels", "stylers": { "visibility": "off" } }, { "featureType": "village", "elementType": "labels", "stylers": { "visibility": "off" } }, { "featureType": "district", "elementType": "labels", "stylers": { "visibility": "off" } }, { "featureType": "land", "elementType": "geometry", "stylers": { "color": "#edf3f3ff" } }, { "featureType": "nationalway", "elementType": "geometry.stroke", "stylers": { "color": "#cacfcfff" } }, { "featureType": "provincialway", "elementType": "geometry.stroke", "stylers": { "color": "#cacfcfff" } }, { "featureType": "cityhighway", "elementType": "geometry.stroke", "stylers": { "color": "#cacfcfff" } }, { "featureType": "road", "elementType": "geometry.stroke", "stylers": { "color": "#cacfcfff" } }, { "featureType": "subwaylabel", "elementType": "labels.icon", "stylers": { "visibility": "off" } }, { "featureType": "subwaylabel", "elementType": "labels", "stylers": { "visibility": "off" } }, { "featureType": "tertiarywaysign", "elementType": "labels.icon", "stylers": { "visibility": "off" } }, { "featureType": "tertiarywaysign", "elementType": "labels", "stylers": { "visibility": "off" } }, { "featureType": "provincialwaysign", "elementType": "labels.icon", "stylers": { "visibility": "off" } }, { "featureType": "provincialwaysign", "elementType": "labels", "stylers": { "visibility": "off" } }, { "featureType": "nationalwaysign", "elementType": "labels.icon", "stylers": { "visibility": "off" } }, { "featureType": "nationalwaysign", "elementType": "labels", "stylers": { "visibility": "off" } }, { "featureType": "highwaysign", "elementType": "labels.icon", "stylers": { "visibility": "off" } }, { "featureType": "highwaysign", "elementType": "labels", "stylers": { "visibility": "off" } }, { "featureType": "nationalway", "elementType": "geometry.fill", "stylers": { "color": "#fbfffeff" } }, { "featureType": "nationalway", "elementType": "labels.text.fill", "stylers": { "color": "#999999ff" } }, { "featureType": "provincialway", "elementType": "labels.text.fill", "stylers": { "color": "#999999ff" } }, { "featureType": "cityhighway", "elementType": "labels.text.fill", "stylers": { "color": "#999999ff" } }, { "featureType": "cityhighway", "elementType": "labels.text.stroke", "stylers": { "color": "#ffffffff" } }, { "featureType": "highway", "stylers": { "curZoomRegionId": "0", "curZoomRegion": "6,8", "level": "6" } }, { "featureType": "highway", "stylers": { "curZoomRegionId": "0", "curZoomRegion": "6,8", "level": "7" } }, { "featureType": "highway", "stylers": { "curZoomRegionId": "0", "curZoomRegion": "6,8", "level": "8" } }, { "featureType": "highway", "elementType": "geometry", "stylers": { "visibility": "off", "curZoomRegionId": "0", "curZoomRegion": "6,8", "level": "6" } }, { "featureType": "highway", "elementType": "geometry", "stylers": { "visibility": "off", "curZoomRegionId": "0", "curZoomRegion": "6,8", "level": "7" } }, { "featureType": "highway", "elementType": "geometry", "stylers": { "visibility": "off", "curZoomRegionId": "0", "curZoomRegion": "6,8", "level": "8" } }, { "featureType": "highway", "elementType": "labels", "stylers": { "visibility": "off", "curZoomRegionId": "0", "curZoomRegion": "6,8", "level": "6" } }, { "featureType": "highway", "elementType": "labels", "stylers": { "visibility": "off", "curZoomRegionId": "0", "curZoomRegion": "6,8", "level": "7" } }, { "featureType": "highway", "elementType": "labels", "stylers": { "visibility": "off", "curZoomRegionId": "0", "curZoomRegion": "6,8", "level": "8" } }, { "featureType": "nationalway", "stylers": { "curZoomRegionId": "0", "curZoomRegion": "6,8", "level": "6" } }, { "featureType": "nationalway", "stylers": { "curZoomRegionId": "0", "curZoomRegion": "6,8", "level": "7" } }, { "featureType": "nationalway", "stylers": { "curZoomRegionId": "0", "curZoomRegion": "6,8", "level": "8" } }, { "featureType": "nationalway", "elementType": "geometry", "stylers": { "visibility": "off", "curZoomRegionId": "0", "curZoomRegion": "6,8", "level": "6" } }, { "featureType": "nationalway", "elementType": "geometry", "stylers": { "visibility": "off", "curZoomRegionId": "0", "curZoomRegion": "6,8", "level": "7" } }, { "featureType": "nationalway", "elementType": "geometry", "stylers": { "visibility": "off", "curZoomRegionId": "0", "curZoomRegion": "6,8", "level": "8" } }, { "featureType": "nationalway", "elementType": "labels", "stylers": { "visibility": "off", "curZoomRegionId": "0", "curZoomRegion": "6,8", "level": "6" } }, { "featureType": "nationalway", "elementType": "labels", "stylers": { "visibility": "off", "curZoomRegionId": "0", "curZoomRegion": "6,8", "level": "7" } }, { "featureType": "nationalway", "elementType": "labels", "stylers": { "visibility": "off", "curZoomRegionId": "0", "curZoomRegion": "6,8", "level": "8" } }, { "featureType": "provincialway", "stylers": { "curZoomRegionId": "0", "curZoomRegion": "8,8", "level": "8" } }, { "featureType": "provincialway", "elementType": "geometry", "stylers": { "visibility": "off", "curZoomRegionId": "0", "curZoomRegion": "8,8", "level": "8" } }, { "featureType": "provincialway", "elementType": "labels", "stylers": { "visibility": "off", "curZoomRegionId": "0", "curZoomRegion": "8,8", "level": "8" } }, { "featureType": "cityhighway", "stylers": { "curZoomRegionId": "0", "curZoomRegion": "6,8", "level": "6" } }, { "featureType": "cityhighway", "stylers": { "curZoomRegionId": "0", "curZoomRegion": "6,8", "level": "7" } }, { "featureType": "cityhighway", "stylers": { "curZoomRegionId": "0", "curZoomRegion": "6,8", "level": "8" } }, { "featureType": "cityhighway", "elementType": "geometry", "stylers": { "visibility": "off", "curZoomRegionId": "0", "curZoomRegion": "6,8", "level": "6" } }, { "featureType": "cityhighway", "elementType": "geometry", "stylers": { "visibility": "off", "curZoomRegionId": "0", "curZoomRegion": "6,8", "level": "7" } }, { "featureType": "cityhighway", "elementType": "geometry", "stylers": { "visibility": "off", "curZoomRegionId": "0", "curZoomRegion": "6,8", "level": "8" } }, { "featureType": "cityhighway", "elementType": "labels", "stylers": { "visibility": "off", "curZoomRegionId": "0", "curZoomRegion": "6,8", "level": "6" } }, { "featureType": "cityhighway", "elementType": "labels", "stylers": { "visibility": "off", "curZoomRegionId": "0", "curZoomRegion": "6,8", "level": "7" } }, { "featureType": "cityhighway", "elementType": "labels", "stylers": { "visibility": "off", "curZoomRegionId": "0", "curZoomRegion": "6,8", "level": "8" } }, { "featureType": "cityhighway", "elementType": "geometry.fill", "stylers": { "color": "#fbfffeff" } }, { "featureType": "water", "elementType": "labels.text.fill", "stylers": { "color": "#8f5a33ff" } }, { "featureType": "water", "elementType": "labels.text.stroke", "stylers": { "color": "#ffffffff" } }, { "featureType": "country", "elementType": "labels.text.fill", "stylers": { "color": "#8f5a33ff" } }, { "featureType": "country", "elementType": "labels.text.stroke", "stylers": { "color": "#ffffffff" } }, { "featureType": "country", "elementType": "labels.text", "stylers": { "fontsize": 28 } }, { "featureType": "manmade", "elementType": "geometry", "stylers": { "color": "#dfe7e7ff" } }, { "featureType": "provincialway", "elementType": "geometry.fill", "stylers": { "color": "#fbfffeff" } }, { "featureType": "tertiaryway", "elementType": "geometry.fill", "stylers": { "color": "#fbfffeff" } }, { "featureType": "manmade", "elementType": "labels.text.fill", "stylers": { "color": "#999999ff" } }, { "featureType": "manmade", "elementType": "labels.text.stroke", "stylers": { "color": "#ffffffff" } }, { "featureType": "scenicspots", "elementType": "labels.text.fill", "stylers": { "color": "#999999ff" } }, { "featureType": "scenicspots", "elementType": "labels.text.stroke", "stylers": { "color": "#ffffffff" } }, { "featureType": "airportlabel", "elementType": "labels.text.fill", "stylers": { "color": "#999999ff" } }, { "featureType": "airportlabel", "elementType": "labels.icon", "stylers": { "visibility": "off" } }, { "featureType": "scenicspotslabel", "elementType": "labels.text.fill", "stylers": { "color": "#999999ff" } }, { "featureType": "scenicspotslabel", "elementType": "labels.icon", "stylers": { "visibility": "off" } }, { "featureType": "educationlabel", "elementType": "labels.text.fill", "stylers": { "color": "#999999ff" } }, { "featureType": "educationlabel", "elementType": "labels.icon", "stylers": { "visibility": "off" } }, { "featureType": "medicallabel", "elementType": "labels.text.fill", "stylers": { "color": "#999999ff" } }, { "featureType": "medicallabel", "elementType": "labels.icon", "stylers": { "visibility": "off" } }, { "featureType": "companylabel", "elementType": "labels.icon", "stylers": { "visibility": "off" } }, { "featureType": "restaurantlabel", "elementType": "labels.icon", "stylers": { "visibility": "off" } }, { "featureType": "hotellabel", "elementType": "labels.icon", "stylers": { "visibility": "off" } }, { "featureType": "hotellabel", "elementType": "labels", "stylers": { "visibility": "off" } }, { "featureType": "shoppinglabel", "elementType": "labels.icon", "stylers": { "visibility": "off" } }, { "featureType": "shoppinglabel", "elementType": "labels", "stylers": { "visibility": "off" } }, { "featureType": "lifeservicelabel", "elementType": "labels.icon", "stylers": { "visibility": "off" } }, { "featureType": "carservicelabel", "elementType": "labels.icon", "stylers": { "visibility": "off" } }, { "featureType": "transportationlabel", "elementType": "labels.icon", "stylers": { "visibility": "off" } }, { "featureType": "transportationlabel", "elementType": "labels", "stylers": { "visibility": "off" } }, { "featureType": "financelabel", "elementType": "labels.icon", "stylers": { "visibility": "off" } }, { "featureType": "entertainment", "elementType": "geometry", "stylers": { "color": "#d1dbdbff" } }, { "featureType": "estate", "elementType": "geometry", "stylers": { "color": "#d1dbdbff" } }, { "featureType": "shopping", "elementType": "geometry", "stylers": { "color": "#d1dbdbff" } }, { "featureType": "education", "elementType": "labels.text.fill", "stylers": { "color": "#999999ff" } }, { "featureType": "education", "elementType": "labels.text.stroke", "stylers": { "color": "#ffffffff" } }, { "featureType": "medical", "elementType": "labels.text.fill", "stylers": { "color": "#999999ff" } }, { "featureType": "medical", "elementType": "labels.text.stroke", "stylers": { "color": "#ffffffff" } }, { "featureType": "transportation", "elementType": "labels.text.fill", "stylers": { "color": "#999999ff" } }, { "featureType": "transportation", "elementType": "labels.text.stroke", "stylers": { "color": "#ffffffff" } } ]; // 船只类型图片 const SHIP_IMAGE = { "0": "备用", "20": "地效飞行器", "21": "地效飞行器(危险品A类)", "22": "地效飞行器(危险品B类)", "23": "地效飞行器(危险品C类)", "24": "地效飞行器(危险品D类)", "25": "地效飞行器(保留)", "29": "地效飞行器(无额外信息)", "30": "渔船", "31": "拖轮", "32": "拖轮(拖带长度超过200米)", "33": "挖泥船或水下作业船", "34": "潜水作业船", "35": "军用舰船", "36": "帆船", "37": "游艇", "40": "高速船", "41": "高速船(危险品A类)", "42": "高速船(危险品B类)", "43": "高速船(危险品C类)", "44": "高速船(危险品D类)", "45": "高速船(保留)", "49": "高速船(无额外信息)", "50": "引航船", "51": "搜救船", "52": "拖轮", "53": "港口供应船", "54": "防污染设备船", "55": "执法船", "56": "备用", "58": "医疗运输船", "59": "非战斗舰船", "60": "客船", "61": "客船(危险品A类)", "62": "客船(危险品B类)", "63": "客船(危险品C类)", "64": "客船(危险品D类)", "65": "客船(保留)", "69": "客船(无额外信息)", "70": "货船", "71": "货船(危险品A类)", "72": "货船(危险品B类)", "73": "货船(危险品C类)", "74": "货船(危险品D类)", "75": "货船(保留)", "79": "货船(无额外信息)", "80": "液货船", "81": "液货船(危险品A类)", "82": "液货船(危险品B类)", "83": "液货船(危险品C类)", "84": "液货船(危险品D类)", "85": "液货船(保留)", "89": "液货船(无额外信息)", "90": "其他类型", "91": "其他类型(危险品A类)", "92": "其他类型(危险品B类)", "93": "其他类型(危险品C类)", "94": "其他类型(危险品D类)", "95": "其他类型(保留)", "99": "其他类型(无额外信息)" }; // 航道信息 const SHIP_CHANNEL = { current: 'chengyuan', chengyuan: { id: 1, name: '宬苑', nameEn: 'cy', lng: 121.510884, lat: 31.219752, wgsLng: 121.511941, wgsLat: 31.199828 }, dufeng: { id: 0, name: '杜丰', nameEn: 'df', lng: 121.4780419, lat: 31.078778, wgsLng: 121.47786, wgsLat: 31.061703 } }; // 电子围栏配置项 const FENCE_AREA_OPTIONS = { strokeColor:"red", //边线颜色。 fillColor:"red", //填充颜色。当参数为空时,圆形将没有填充效果。 strokeWeight: 2, //边线的宽度,以像素为单位。 strokeOpacity: 0.5, //边线透明度,取值范围0 - 1。 fillOpacity: 0.03, //填充的透明度,取值范围0 - 1。 strokeStyle: 'solid' //边线的样式,solid或dashed。 }; // mqtt实时船只信息 const ALL_SHIP = deepObserve({}); // 船只选中,水波纹扩散样式 let canvasLayer = null; // 请求后台数据 const REQUEST = { // 封装ajax请求 ajax({ url, type = 'GET', params, success, isLoading = true, isAlert = true }) { let layerIndex = null; let rootPath = document.domain === '10.5.226.53' ? '/tggz' : ''; return $.ajax({ url: `${rootPath}/tg${url}`, type, data: params, timeout: 1000 * 60 * 5, headers: type.toUpperCase() === 'POST' ? { 'Content-Type': 'application/json' } : undefined, beforeSend() { if (isLoading) { layerIndex = showLoading(); } }, complete() { isLoading && closeLoading(layerIndex); }, success(result) { let { code, data } = result; if (code === 0) { success && success(data); } else { isAlert && layer.alert('操作失败...', { icon: 2, anim: 1 }); } }, error() { isAlert && layer.alert('服务器异常,请稍后再试...', { icon: 2, anim: 1 }); } }); } }; // 页面操作事件 const PAGE_EVENT = { shipId: null, map: { // marker移动定时器 moveTimer: {}, // 创建Map实例 init() { let _this = this; let { lng, lat } = SHIP_CHANNEL[SHIP_CHANNEL.current]; window.baiduMap = new BMap.Map('map-container', { minZoom: 12, maxZoom: 20, enableMapClick: false }); baiduMap.centerAndZoom(new BMap.Point(lng, lat), 17); // baiduMap.panBy(leftWidth); baiduMap.enableKeyboard(); baiduMap.enableScrollWheelZoom(); baiduMap.enableInertialDragging(); baiduMap.enableContinuousZoom(); // 设置地图样式` baiduMap.setMapStyle({ styleJson: BAIDU_MAP_WHITE_STYLE }); // 添加缩放控件 let zoomCtrl = new BMap.NavigationControl({ anchor: BMAP_ANCHOR_TOP_RIGHT, type: BMAP_NAVIGATION_CONTROL_SMALL, offset: { width: 25, height: 70 } }); baiduMap.addControl(zoomCtrl); // 监听页面的缩放事件 baiduMap.addEventListener('zoomend', function () { _this.markerSize(); }); // 实例化鼠标绘制工具 let drawingManager = new BMapLib.DrawingManager(baiduMap, { isOpen: false, //是否开启绘制模式 enableDrawingTool: true, //是否显示工具栏 drawingToolOptions: { anchor: BMAP_ANCHOR_TOP_RIGHT, //位置 offset: new BMap.Size(10, 10), //偏离值 }, polygonOptions: FENCE_AREA_OPTIONS, //多边形的样式 rectangleOptions: FENCE_AREA_OPTIONS //矩形的样式 }); // 监听绘画工具事件 drawingManager.addEventListener('overlaycomplete', function (e) { let { overlay } = e; drawingManager.close(); overlay.data = { type: 'fenceArea' }; overlay.addContextMenu(contextMenu(overlay)); }); }, // 添加船只 addShipMarker(data) { let _this = this; let { object_id, bdLng, bdLat, direction, type } = data; let point = new BMap.Point(bdLng, bdLat); // 查询船只信息获取船只类型,根据类型显示相应的图片 // PAGE_EVENT.shipInfo(object_id, d => { // let { shipType } = d || {}; let shipType = type === 'uav' ? '20' : null; _this.imageSize(shipType, ({name, width, height}) => { let icon = new BMap.Icon(`./image/船只/${name}.png`, new BMap.Size(width, height)); icon.imageOriginalSize = { width, height}; // 船 let shipMarker = new BMap.Marker(point, { rotation: direction, icon: icon }); shipMarker.data = data; // 监听点击事件 // 移动的时候点击click事件不触发,改为mouseup shipMarker.addEventListener('mouseup', () => { PAGE_EVENT.shipId = object_id; _this.shipActivate([shipMarker]); PAGE_EVENT.shipInfo(object_id); // 隐藏时间表单 // 清除历史轨迹/轨迹预测 // $('#time-query-form').addClass('layui-hide'); // PAGE_EVENT.map.removeLineLayer(); // 点击船只后继续执行历史轨迹/轨迹预测事件 let activeType = $('.line-info .line-info-item.active').data('type'); if (['history', 'prediction'].includes(activeType)) { PAGE_EVENT[activeType](); } }); // 添加船只时调整图片大小 _this.markerSize(shipMarker) baiduMap.addOverlay(shipMarker); // 首次在地图上添加船只时,获取第一条船的信息 if (!_this.shipId || !ALL_SHIP[_this.shipId]) { _this.shipId = object_id; _this.shipActivate([shipMarker]); PAGE_EVENT.realTimeShipInfo(data); } // 添加船只后调整视角 // let layers = baiduMap.getOverlays(); // let points = []; // layers.forEach(item => { // if (item instanceof BMap.Marker) { // points.push(item.getPosition()); // } // }); // baiduMap.setViewport(points); }); // }); }, // 移除船只 removeShipMarker(id) { let _this = this; // 根据id找到指定的船只marker let shipMarker = _this.getShipMarker(id); if (shipMarker) { // 地图上移除船只 baiduMap.removeOverlay(shipMarker); // 移除船只移动时记录的定时器 delete _this.moveTimer[id]; } // 如果移除是当前选中的船只,重新获取一条船的信息,更新左侧信息 if (id == PAGE_EVENT.shipId || !ALL_SHIP[PAGE_EVENT.shipId]) { baiduMap.removeOverlay(canvasLayer); let newKey = null; // let bounds = baiduMap.getBounds(); for (let key in ALL_SHIP) { let item = ALL_SHIP[key]; // let shipObj = item.find(obj => { // let { object_id, bdLng, bdLat, type } = obj; // let p = new BMap.Point(bdLng, bdLat); // return object_id != id && type !== 'uav' && bounds.containsPoint(p); // }); let shipObj = item.find(obj => obj.object_id != id && obj.type !== 'uav'); if (shipObj) { newKey = key; break; } } if (newKey) { let length = ALL_SHIP[newKey].length; PAGE_EVENT.shipId = newKey; PAGE_EVENT.realTimeShipInfo(ALL_SHIP[newKey][length - 1]); shipMarker = _this.getShipMarker(newKey); _this.shipActivate([shipMarker]); PAGE_EVENT.shipInfo(newKey); } } }, // 移动船只 moveShipMarker(data) { let _this = this; let { object_id: id, bdLng, bdLat, direction } = data; // 根据id找到指定的船只marker let shipMarker = _this.getShipMarker(id); if (!shipMarker) { return; } let length = ALL_SHIP[id].length; if (length > 1) { let lastData = ALL_SHIP[id][length - 1]; let p1 = new BMap.Point(lastData.bdLng, lastData.bdLat); let p2 = new BMap.Point(bdLng, bdLat); shipMarker.data = lastData; shipMarker.setRotation(direction); // 两次经纬度一致,不再移动位置 if (p1.equals(p2)) { return; } _this.move(p1, p2, shipMarker); } // 更新当前船只的移动信息 if (id == PAGE_EVENT.shipId) { let currentShipMarker = _this.getShipMarker(PAGE_EVENT.shipId); if (currentShipMarker) { PAGE_EVENT.realTimeShipInfo(data); // 更新水波纹样式位置 canvasLayer && canvasLayer.draw(); } } }, // 获取指定船只marker getShipMarker(id) { // 获取所有覆盖物 let layers = baiduMap.getOverlays(); // 根据id找到指定的船只marker return layers.find(item => item instanceof BMap.Marker && item.data && item.data.object_id == id); }, // 添加轨迹路线 addLineLayer({data, color = '#00ff00', lineStyle = 'solid', isCircle}) { let _this = this; // 添加路线之前先清除上次添加的路线 _this.removeLineLayer(); if (!data && data.length) { return; } // 根据经纬度去重 let d = uniqueArray(data, ['lng', 'lat']); let points = []; d.forEach(({lng, lat, dateTime}) => { // gps坐标转百度 let bd09 = coordinateUtils.wgs84tobd09(parseFloat(lng), parseFloat(lat)); let p = new BMap.Point(bd09[0], bd09[1]); points.push(p); if (!isCircle) { return; } // 绘制圆点 let marker = new BMap.Marker(p, { icon: new BMap.Symbol(BMap_Symbol_SHAPE_CIRCLE, { fillColor: color, fillOpacity: 1, strokeColor: color, strokeOpacity: 1, scale: 3 }) }); // 文字标注 let label = new BMap.Label(dateTime, { position: p, offset: new BMap.Size(15, -10) }); label.setStyle({ border: 'none', fontSize: '14px', backgroundColor: 'transparent' }); marker.addEventListener('mouseover', () => { baiduMap.addOverlay(label); }); marker.addEventListener('mouseout', () => { baiduMap.removeOverlay(label); }); baiduMap.addOverlay(marker); }); // 绘制连接线 let polyline = new BMap.Polyline(points, { strokeStyle: lineStyle, strokeColor: color, strokeOpacity: 1, strokeWeight: 3 }); baiduMap.addOverlay(polyline); // baiduMap.setViewport(points); }, // 移除轨迹路线 removeLineLayer() { let layers = baiduMap.getOverlays(); layers.forEach(item => { // 移除圆 if (item instanceof BMap.Marker) { let icon = item.getIcon(); if (icon instanceof BMap.Symbol) { baiduMap.removeOverlay(item); } } // 移除线、文字 if (item instanceof BMap.Polyline || item instanceof BMap.Label ) { baiduMap.removeOverlay(item); } }); }, // 动态获取图片原始大小 imageSize(type = '53', callback) { let name = SHIP_IMAGE[type] || '港口供应船'; let div = name && name.includes('飞行器') ? 2 : 4; let img = new Image(); img.src = `./image/船只/${name}.png`; img.onload = () => { let width = (img.naturalWidth / div).toFixed(2); let height = (img.naturalHeight / div).toFixed(2); img = null; callback && callback({name, width, height}); } }, // 根据实际需求调整大小,例如缩放级别越大,图片越大 markerSize(marker) { let setSize = _marker => { if (_marker instanceof BMap.Marker) { let icon = _marker.getIcon(); if (icon instanceof BMap.Symbol) { return; } let zoom = baiduMap.getZoom(); let { width, height } = icon.imageOriginalSize; let scale = (zoom - 12) / (19 - 12); let newWidth = width * scale; let newHeight = height * scale; let size = new BMap.Size(newWidth, newHeight); icon.setSize(size); icon.setImageSize(size); icon.setAnchor({ width: newWidth / 2, height: newHeight / 2 }) _marker.setIcon(icon); } }; if (marker) { setSize(marker); } else { let layers = baiduMap.getOverlays(); layers.forEach(item => setSize(item)); } }, // 船只移动轨迹路线 move(prvePoint, newPoint, marker, polyline) { let _this = this; // 当前帧数 let currentCount = 0 // _当前的坐标,把球面坐标坐标转化为平面坐标 let _prvePoint = baiduMap.getMapType().getProjection().lngLatToPoint(prvePoint) // _终点的坐标,把球面坐标坐标转化为平面坐标 let _newPoint = baiduMap.getMapType().getProjection().lngLatToPoint(newPoint) // 运行的状态 let runTime = 800 // 每隔多长时间执行一次 let intervalTimer = 10 // 两点之间要循环定位的次数 let count = runTime / intervalTimer // 记录每条船的定时器,第二次移动时移除上次未执行完的定时,防止鬼畜 let { object_id } = marker.data; let timer = _this.moveTimer[object_id]; if (timer) { clearInterval(timer); _this.moveTimer[object_id] = null; } //设置定时器 _this.moveTimer[object_id] = setInterval(function () { // 防止便利完后maker不在了 if (currentCount > count) { clearInterval(_this.moveTimer[object_id]) } else { currentCount++ let x = linear(_prvePoint.x, _newPoint.x, currentCount, count), y = linear(_prvePoint.y, _newPoint.y, currentCount, count); let pos = baiduMap.getMapType().getProjection().pointToLngLat(new BMap.Pixel(x, y)); //设置marker角度(两点之间的距离车的角度保持一致) if (currentCount === 1) { //转换角度 // setRotation(prvePoint, newPoint, marker) } //最后一次的pos等于0 marker.setPosition(pos); if (polyline) { // 移动的时候绘制线路 let path = polyline.getPath(); path.push(pos); polyline.setPath(path); } } }, intervalTimer); /* *缓动效果 *初始坐标,目标坐标,当前的步长,总的步长 *@param{BMap.Pixel} initPos 初始平面坐标 *@parm{BMap.Pixel} targetPos 目标平面坐标 *@param{number} 当前帧数 *@param {number} count 总帧数 */ let linear = function (initPos, targetPos, currentCount, count) { let b = initPos, c = targetPos - initPos, t = currentCount, d = count; return c * t / d + b; } /** *在每个点的真实步骤中设置小车转动的角度 */ let setRotation = function(curPos, targetPos, marker) { let deg = 0 curPos = baiduMap.pointToPixel(curPos) targetPos = baiduMap.pointToPixel(targetPos) if (targetPos.x !== curPos.x) { let tan = (targetPos.y - curPos.y) / (targetPos.x - curPos.x), atan = Math.atan(tan); deg = atan * 360 / (2 * Math.PI); if (targetPos.x < curPos.x) { deg = -deg + 90 + 90; } else { deg = -deg; } deg = -90 + deg marker.setRotation(-deg); } else { let disy = targetPos.y - curPos.y; let bias = 0; if (disy > 0) bias = -1 else bias = 1 marker.setRotation(-bias * 90); } } }, // 船只选中效果 shipActivate(markers) { // 存储绘图状态和波纹数据 let drawingState = { ctx: null, canvas: null, pixelPoints: [], // 存储 { x, y, name, radius, alpha } animationFrameId: null, lastTime: 0, maxRadius: 50, // 波纹最大半径 rippleSpeed: 30, // 波纹扩散速度 (像素/秒) startAlpha: 1 // 波纹初始透明度 }; // 创建 CanvasLayer 实例 if (canvasLayer) { baiduMap.removeOverlay(canvasLayer); } canvasLayer = new BMap.CanvasLayer({ paneName: 'vertexPane', update: function () { let canvas = this.canvas; let ctx = canvas.getContext('2d'); drawingState.ctx = ctx; drawingState.canvas = canvas; ctx.clearRect(0, 0, canvas.width, canvas.height); // 获取现有的 radius/alpha 数据,以便在移动时保留状态 const existingState = {}; drawingState.pixelPoints.forEach(p => { existingState[p.id] = { radius: p.radius, alpha: p.alpha }; }); drawingState.pixelPoints = markers.filter(marker => !!marker).map(marker => { let { object_id } = marker.data; let point = marker.getPosition(); let pixel = baiduMap.pointToPixel(point); const oldState = existingState[object_id]; return { x: pixel.x, y: pixel.y, // 保留旧的状态或创建新的,初始半径以错开动画 id: object_id, radius: oldState ? oldState.radius : drawingState.maxRadius, alpha: oldState ? oldState.alpha : drawingState.startAlpha }; }); if (!drawingState.animationFrameId) { startAnimation(); } return true; } }); baiduMap.addOverlay(canvasLayer); // 设置canvasLayer父元素层级,防止阻挡绘制工具 $(canvasLayer.canvas).parent().css('z-index', 100); // 定义并启动动画循环 function animate() { drawingState.animationFrameId = requestAnimationFrame(animate); if (!drawingState.ctx) return; let ctx = drawingState.ctx; let canvas = drawingState.canvas; let now = performance.now(); let deltaTime = (now - drawingState.lastTime) / 1000; drawingState.lastTime = now; // 清空 Canvas ctx.clearRect(0, 0, canvas.width, canvas.height); let maxRadius = drawingState.maxRadius; let speed = drawingState.rippleSpeed; let startAlpha = drawingState.startAlpha; // 绘制每个点及其波纹 drawingState.pixelPoints.forEach(p => { // 更新状态:半径变大 p.radius += speed * deltaTime; // 如果半径超出范围,则重置 if (p.radius >= maxRadius) { p.radius = 0; // 重置半径 p.alpha = startAlpha; // 重置透明度 } else { // 透明度随半径变大而减小 p.alpha = startAlpha * (1 - (p.radius / maxRadius)); } // 绘制扩散的实心圆 ctx.beginPath(); ctx.arc(p.x, p.y, p.radius, 0, Math.PI * 2); ctx.fillStyle = `rgba(0, 255, 0, ${p.alpha})`; // 使用计算出的透明度 ctx.fill(); }); } // 启动动画 function startAnimation() { if (!drawingState.animationFrameId) { drawingState.lastTime = performance.now(); animate(); } } }, // 清除覆盖物 clearOverlays(type) { let overlays = baiduMap.getOverlays(); overlays.forEach(item => { if (item?.data?.type === type) { baiduMap.removeOverlay(item); } }); } }, // mqtt船只实时信息 realTime() { // 根据mqtt订阅更新地图右下角服务器状态 const $status = $('#map-status .layui-badge-dot'); const statusColor = { good: 'layui-bg-green', bad: 'layui-bg-red'}; // mqtt配置信息 const host = 'ws://10.5.226.53:8083/mqtt'; const sendTopic = ['dfAddTrack','dfAddObj','dfRemoveObj','uavAddObj','uavAddTrack','uavRemoveObj']; const qos = 0; const mqttOptions = { keepalive: 60, clean: true, username: 'eadpoint', password: '321123', connectTimeout: 10000, reconnectPeriod: 3000 }; console.log('Connecting mqtt client') const client = mqtt.connect(host, mqttOptions); // 连接异常时触发 client.on('error', (err) => { console.log('Connection error: ', err); $status.removeClass(statusColor.good); $status.addClass(statusColor.bad); // client.end() }); // 重新自动连接时触发 client.on('reconnect', () => { console.log('Reconnecting...'); }); // 连接成功时触发 client.on('connect', () => { $status.addClass(statusColor.good); $status.removeClass(statusColor.bad); client.subscribe(sendTopic, { qos }, (error) => { if (error) { console.log('Subscribe error:', error); } }); }); // 收到发布消息时触发 client.on('message', (topic, payload) => { let resData = JSON.parse(payload.toString()); if ([sendTopic[0], sendTopic[1], sendTopic[3], sendTopic[4]].includes(topic)) { let { object_id, lng, lat } = resData; // gps坐标转百度 let bd09 = coordinateUtils.wgs84tobd09(lng, lat); resData.bdLng = bd09[0]; resData.bdLat = bd09[1]; // 记录数据时间 resData.realTime = Date.now(); // 添加船只路径点 if (!ALL_SHIP[object_id]) { ALL_SHIP[object_id] = []; } ALL_SHIP[object_id].push(resData); if ([sendTopic[3], sendTopic[4]].includes(topic)) { console.log('无人机信息', resData) } } else if ([sendTopic[2], sendTopic[5]].includes(topic)) { // 移除船只 let object_id = typeof resData === 'object' ? resData.object_id : resData; delete ALL_SHIP[object_id]; } checkShip(); }); // mqtt移除事件可能会不及时反馈 // 检测船只是否长时间(30秒)未移动 let checkShip = layui.throttle(function() { let layers = baiduMap.getOverlays(); layers.forEach(item => { if (item instanceof BMap.Marker) { let id = item?.data?.object_id; if (!id) { return; } let data = ALL_SHIP[id]; if (data) { let length = data.length; let { object_id, realTime } = data[length - 1]; let now = Date.now(); if ((now - realTime) > 1000 * 30) { // 超过30秒没添加过数据,则移除该船只 console.log('超时未移动,移除船只:', object_id) delete ALL_SHIP[object_id]; } } else { delete ALL_SHIP[id]; } } }); }, 1000 * 10); }, // 查询船只信息 shipInfo(objectId, callback) { REQUEST.ajax({ url: '/ship/findDtRadarBoatMsg', params: { objectId, stationId: SHIP_CHANNEL[SHIP_CHANNEL.current].id, }, success(data) { let renderHtml = d => { if (d) { let $shipInfo = $('.ship-info-card'); let tpl = shipInfoTpl.innerHTML; laytpl(tpl).render(d, function(html) { $shipInfo.replaceWith(html); }); } } if (callback) { callback(data); } else { renderHtml(data); } }, isLoading: false, isAlert: false }); }, // 船只移动实时信息 realTimeShipInfo: layui.debounce(function(data) { let $locationInfo = $('.location-info-card'); let tpl = locationInfoTpl.innerHTML; laytpl(tpl).render(data, function(html) { $locationInfo.replaceWith(html); }); }, 100), // 实时监控画面 camera() { let name = SHIP_CHANNEL[SHIP_CHANNEL.current].name; this.open({ title: false, content: `../a.html?site=${name}基站` }); }, // 历史轨迹 history(params = {}) { let _this = this; let date = new Date(); let end = layui.util.toDateString(date, 'yyyy-MM-dd HH:mm:ss'); date.setDate(date.getDate() - 1); let start = layui.util.toDateString(date, 'yyyy-MM-dd HH:mm:ss'); $('#start-time').val(start); $('#end-time').val(end); REQUEST.ajax({ url: '/ship/queryRadarBoatHistory', params: { objectId: _this.shipId, stationId: SHIP_CHANNEL[SHIP_CHANNEL.current].id, startTime: $('#start-time').val(), endTime: $('#end-time').val(), ...params }, success(data) { _this.map.addLineLayer({ data, isCircle: true }); } }); }, // 预测 prediction() { let _this = this; REQUEST.ajax({ url: '/ship/trajectoryPrediction', params: { list: _this.shipId, stationId: SHIP_CHANNEL[SHIP_CHANNEL.current].id }, success(data) { _this.map.addLineLayer({ data: data[_this.shipId], color: '#fff', lineStyle: 'dashed' }); } }); }, // 3D全景视角 '3d'() { this.open({ title: '3D全景视角', content: '../index2.html', success(layero, index) { let current = SHIP_CHANNEL['current']; let data = { "lat": SHIP_CHANNEL[current].wgsLat, "lng": SHIP_CHANNEL[current].wgsLng, "alt": 445.6, "heading": 341.8, "pitch": -9.9, "name": SHIP_CHANNEL[current].nameEn, "object_id": PAGE_EVENT.shipId }; console.log(SHIP_CHANNEL['current'], data) let iframe = window[`layui-layer-iframe${index}`]; iframe.postMessage(data, '*'); }, }); }, // 整体三维视角 all3d() { this.open({ title: '三维视角', content: '../index2.html', success(layero, index) { let current = SHIP_CHANNEL['current']; let data = { "lat": SHIP_CHANNEL[current].wgsLat, "lng": SHIP_CHANNEL[current].wgsLng, "alt": 445.6, "heading": 341.8, "pitch": -9.9, "name": SHIP_CHANNEL[current].nameEn }; let iframe = window[`layui-layer-iframe${index}`]; iframe.postMessage(data, '*'); }, end() { $('#map-type .map-type-item').eq(0).click(); } }); }, // 打开弹框 open(options) { layer.open({ type: 2, area: ['1000px', '700px'], ...options }); }, // 查询电子围栏 fenceArea() { let _this = this; REQUEST.ajax({ url: '/fenceArea/findList', params: { stationId: SHIP_CHANNEL[SHIP_CHANNEL.current].id }, success(data) { if (!data?.length) { return; } try { let polygons = []; let polygonType = 'fenceArea'; _this.map.clearOverlays(polygonType); for (let d of data) { let { id, coordinate } = d; coordinate = JSON.parse(coordinate); let points = []; for (let item of coordinate) { let { lng, lat } = item; let bd09 = coordinateUtils.wgs84tobd09(lng, lat); points.push(new BMap.Point(bd09[0], bd09[1])); } let polygon = new BMap.Polygon(points, FENCE_AREA_OPTIONS); polygon.data = { id, type: polygonType }; polygon.addContextMenu(contextMenu(polygon)); baiduMap.addOverlay(polygon); polygons.push(polygon); } SHIP_CHANNEL[SHIP_CHANNEL.current].polygon = polygons; } catch (e) { console.error(e); } } }); }, // 保存电子围栏 saveFenceArea(overlay) { let path = overlay.getPath(); if (!path?.length) { return; } // 清除之前保存的电子围栏 let polygon = SHIP_CHANNEL[SHIP_CHANNEL.current].polygon; if (polygon?.length) { polygon.forEach(item => this.deleteFenceArea(item)); } // 百度经纬度转gps let coordinates = []; for (let i = 0; i < path.length; i++) { let { lng, lat } = path[i]; let wgs = coordinateUtils.bd09towgs84(lng, lat); coordinates[i] = { lng: wgs[0], lat: wgs[1] } } REQUEST.ajax({ url: '/fenceArea/save', type: 'POST', params: JSON.stringify({ coordinates, stationId: SHIP_CHANNEL[SHIP_CHANNEL.current].id }), success(data) { if (data) { showMsg('保存成功'); overlay.data = { id: data, type: 'fenceArea' }; overlay.removeContextMenu(); overlay.addContextMenu(contextMenu(overlay)); if (polygon?.length) { SHIP_CHANNEL[SHIP_CHANNEL.current].polygon.push(overlay); } else { SHIP_CHANNEL[SHIP_CHANNEL.current].polygon = [overlay]; } } } }); }, // 删除电子围栏 deleteFenceArea(overlay) { let { id } = overlay.data; REQUEST.ajax({ url: '/fenceArea/delete', type: 'DELETE', params: { id }, success(data) { console.log(data); let polygon = SHIP_CHANNEL[SHIP_CHANNEL.current].polygon; SHIP_CHANNEL[SHIP_CHANNEL.current].polygon = polygon.filter(item => item.data.id !== id ); baiduMap.removeOverlay(overlay); } }); }, // 无人机信息 uavInfo() { REQUEST.ajax({ url: '/uav/findUav', params: { stationId: SHIP_CHANNEL[SHIP_CHANNEL.current].id }, success(data) { if (!data?.length) { return; } let { uavLng, uavLat } = data[0]; data[0].uavLng = uavLng.substr(0, 12); data[0].uavLat = uavLat.substr(0, 11); let $uavInfo = $('.uav-info-card'); let tpl = uavInfoTpl.innerHTML; laytpl(tpl).render(data[0], function(html) { $uavInfo.replaceWith(html); }); } }); } }; // 历史轨迹时间选择 laydate.render({ elem: '#time-dom', type: 'datetime', rangeLinked: true, range: ['#start-time', '#end-time'], done(value) { let times = value.split(' - '); PAGE_EVENT.history({ startTime: times[0], endTime: times[1] }); } }); // 子页面获取数据 window.addEventListener('message', e => { let channel = e.data; if (typeof channel === 'object') { return; } $('.layui-header .layui-nav .layui-nav-item').each((index, item) => { let text = $(item).text(); if(text.includes(channel)){ $(item).find('.channel').click(); } }); }); // 页面加载完毕后执行 $(function () { // 初始化地图 PAGE_EVENT.map.init(); // mqtt实时信息 PAGE_EVENT.realTime(); // 显示当前航道电子围栏 PAGE_EVENT.fenceArea(); // 显示无人机信息 PAGE_EVENT.uavInfo(); }); // 航道点击事件 element.on('nav(channel-nav)', function(elem){ let value = $(elem).data('value'); SHIP_CHANNEL.current = value; let { lng, lat } = SHIP_CHANNEL[value]; baiduMap.panTo(new BMap.Point(lng, lat)); PAGE_EVENT.fenceArea(); PAGE_EVENT.uavInfo(); }); // 航线信息点击事件 $(document).on('click', '.line-info .line-info-item', function () { let _this = this; let activeClass = 'active'; let type = $(_this).data('type'); $('.line-info-item').removeClass(activeClass); $(_this).addClass(activeClass); if (type === 'history') { $('#time-query-form').removeClass('layui-hide'); } else { $('#time-query-form').addClass('layui-hide'); } PAGE_EVENT.map.removeLineLayer(); PAGE_EVENT[type](); }); // 地图类型切换事件 $(document).on('click', '#map-type .map-type-item', function () { let _this = this; let activeClass = 'active'; let toggleClass = 'toggle-active'; let type = $(_this).data('type'); $('#map-type .map-type-item').removeClass(activeClass); $(_this).addClass(activeClass); if (type === 'map') { $('#map-type .map-type-slider').removeClass(toggleClass); } else { $('#map-type .map-type-slider').addClass(toggleClass); PAGE_EVENT.all3d(); } }); // 使用Proxy监视对象变化 function deepObserve(target) { const handler = { get(target, prop) { const value = target[prop]; if (typeof value === 'object' && value !== null) { return deepObserve(value); } return value; }, set(target, prop, value) { // 过滤掉对象数组 length 属性的设置 if (prop === 'length' && Array.isArray(target)) { return Reflect.set(target, prop, value); } if (Array.isArray(target)) { let length = target.length; if (length === 1) { // 只有一条数据,在地图上创建船只 PAGE_EVENT.map.addShipMarker(value); } else { // 移动船只 PAGE_EVENT.map.moveShipMarker(value); } } return Reflect.set(target, prop, value); }, deleteProperty(target, prop) { // 移除船只 PAGE_EVENT.map.removeShipMarker(prop); return Reflect.deleteProperty(target, prop); } }; return new Proxy(target, handler); } // 根据经纬度去重 function uniqueArray(data, keys) { const map = new Map(); return data.filter(item => { const key = keys.map(k => item[k]).join('|'); if (map.has(key)) { return false; } map.set(key, true); return true; }); } // 绘制电子围栏的右键菜单 function contextMenu(overlay) { let contextMenu = new BMap.ContextMenu(); let id = overlay?.data?.id; if (!id) { contextMenu.addItem(new BMap.MenuItem('保存电子围栏', function () { let polygon = SHIP_CHANNEL[SHIP_CHANNEL.current].polygon; if (polygon?.length) { layer.confirm(`当前航道已存在电子围栏,是否覆盖?`, function(index){ layer.close(index); PAGE_EVENT.saveFenceArea(overlay); }, function () { baiduMap.removeOverlay(overlay); }); } else { PAGE_EVENT.saveFenceArea(overlay); } })); contextMenu.addSeparator(); } contextMenu.addItem(new BMap.MenuItem('删除电子围栏', function () { if (id) { PAGE_EVENT.deleteFenceArea(overlay); } else { baiduMap.removeOverlay(overlay); } })); return contextMenu; } function showMsg(msg, type, callback) { return layer.msg(msg, { anim: type, time: type !== 6 ? 1000 : 3000 }, callback); } function showLoading() { return layer.load(2, { shade: 0.1 }); } function closeLoading(index) { if (index) { layer.close(index); } else { layer.closeAll(); } } })