import request from 'axios'; // wms 通用参数 const WMS_PARAMS = { SERVICE: 'WMS', VERSION: '1.3.0', REQUEST: 'GetMap', FORMAT: 'image/png', TRANSPARENT: true, srs: 'EPSG:3857', width: 256, height: 256, bbox: 'bboxx', }; const WFS_PARAMS = { SERVICE: 'WFS', request: 'GetFeature', typeName: 'typename', VERSION: '1.1.0', outputFormat: 'application/json', bbox: '', }; const VECTOR_TYPE = { POINT: 'POINT', LINESTRING: 'LINESTRING', POLYGON: 'POLYGON', }; const mapConfig = { NAN_PING: { center: [118.09335687862085, 27.36991075178898], }, WU_HU: { center: [118.43303301141083, 31.350763350582454], }, XIAO_GAN: { center: [113.899, 30.915], }, }[import.meta.env.VITE_PROJECT_NAME]; export default class NewFiberMapUtils { //地图实例 map = null; //三维场景对象 virtualSpaceObj = null; //搜索对象 search = null; features = []; //相机动画对象 animation = null; //点聚合对象 markerCluster = null; callbacks = { mapClick: undefined, featureClick: undefined, }; imageLayers = []; canvasLayers = []; timer = null; static defaultParams = { keys: { temporary: 'temporary', primaryKey: 'primary_key' }, url: { icon: 'https://lkimgyt.luokuang.com/1592966522911.png' }, size: { icon: [32, 32] }, flyTo: { duration: 3000, zoom: 15, center: mapConfig.center }, }; static mapConfig = { adcode: 411600, container: 'map', zoom: 11.6, pitch: 0, bearing: 0, fog: false, antialias: true, // 是否开启抗锯齿 cursor: 'default', center: new LKMap.LngLat(...mapConfig.center), minZoom: 3, maxZoom: 22, isHotspot: false, isHotspotActive: false, }; static _layers = { terrain: { url: 'https://api.luokuang.com/data3d/terrain_png/440100/20220901/{z}/{x}/{y}.png', }, baseMap: [ { id: 'baseMap_vector', name: '矢量图', icon: import.meta.env.VITE_APP_MAP_SRC + 'static/images/ylz/dengjired.png', type: 0, url: import.meta.env.VITE_APP_MAP_SRC + 'static/libs/map/nightblue.json', check: true, }, { id: 'baseMap_imagery', name: '影像图', icon: import.meta.env.VITE_APP_MAP_SRC + 'static/images/ylz/dengjigreen.png', type: 1, url: 'https://gac-geo.googlecnapps.cn/maps/vt?lyrs=s&hl=zh-CN&gl=CN&x={x}&y={y}&z={z}&src=app&scale=2', }, ], wms: {}, features: [], }; constructor(container, options) { this.initMap(container, options); } initMap(container, options) { let self = this; let config = Object.assign(NewFiberMapUtils.mapConfig, options); config.container = container || config.container; if (import.meta.env.VITE_PROJECT_ISERVER_URL && import.meta.env.VITE_PROJECT_NAME == 'NAN_PING') config.style = { version: 8, sources: { 'raster-tiles': { type: 'raster', tiles: ['/OfflineMap/mapabc/satellite/{z}/{x}/{y}.jpg'], tileSize: 256, }, }, // "sources": {"raster-tiles": {"type": "raster", "tiles": ['http://map.geoq.cn/ArcGIS/rest/services/ChinaOnlineStreetPurplishBlue/MapServer/tile/{z}/{y}/{x}'], "tileSize": 256}}, layers: [{ id: 'simple-tiles', type: 'raster', source: 'raster-tiles', minzoom: 0, maxzoom: 22 }], }; self.callbacks = { mapClick: options.mapClick, featureClick: options.featureClick, }; this.map = new LKMap.Map(config.container, config); this.map.on('load', () => { // this.addTerrain(); // this.addControl(); self.updateSky(); self.addBaseMapImagery(); //self.mapZoomEndEvt(); //地图点击回调 if (self.callbacks.mapClick) this.mapClick(self.callbacks); self.animation = new LKMap.CameraAnimation({ map: this.map }); /* this.map.plugin(["MarkerClusterer", "AnalysisSearch"], function () { //查询对象 self.search = new LKMap.AnalysisSearch({ size: 10, adcode: NewFiberMapUtils.mapConfig.adcode, regionLimit: true }) //聚合对象 self.markerCluster = new LKMap.MarkerClusterer({ map: self.map }); });*/ if (import.meta.env.VITE_PROJECT_ISERVER_URL && import.meta.env.VITE_PROJECT_NAME == 'NAN_PING') { let configs = [ // {id:'tdt_vec',url:'http://t{s}.tianditu.com/DataServer?T=vec_w&X={x}&Y={y}&L={z}&tk=dee46731f7a87187c6507ff35aa9f2ef',params:{subdomains: ['0', '1', '2', '3', '4', '5', '6', '7'], minZoom: 1, maxZoom: 19, tileType: 'xyz'}}, { id: 'iserver_basemap_vec', url: import.meta.env.VITE_PROJECT_ISERVER_URL + '/iserver/services/map-arcgis-50/wmts100?layer=图层&style=default&tilematrixset=GlobalCRS84Scale_图层&Service=WMTS&Request=GetTile&Version=1.0.0&TileMatrix={z}&TileCol={x}&TileRow={y}&Format=image/png', params: { subdomains: [], minZoom: 1, maxZoom: 19, tileType: 'xyz' }, }, { id: 'iserver_basemap_annotation', url: import.meta.env.VITE_PROJECT_ISERVER_URL + '/iserver/services/map-arcgis-51/wmts100?layer=图层&style=default&tilematrixset=GlobalCRS84Scale_图层&Service=WMTS&Request=GetTile&Version=1.0.0&TileMatrix={z}&TileCol={x}&TileRow={y}&Format=image/png', params: { subdomains: [], minZoom: 1, maxZoom: 19, tileType: 'xyz' }, }, // {id:'iserver_china_4490',url:'https://iserver.supermap.io/iserver/services/map-china400/rest/maps/China_4490/zxyTileImage.png?z={z}&x={x}&y={y}',params:{subdomains: [], minZoom: 1, maxZoom: 19, tileType: 'xyz'}}, ]; configs.forEach(config => { new WMTSLayer({ url: config.url }).addTo(self.map); }); // configs.forEach(config => self.map.addLayer(new customTileLayer(config.id, config.url,config.params))) } self.loadVectorWall(); }); if (!(import.meta.env.VITE_PROJECT_ISERVER_URL) || !!!(import.meta.env.VITE_PROJECT_NAME == 'NAN_PING')) self.map.setStyle(NewFiberMapUtils._layers.baseMap[0].url); } async loadVectorWall() { let { data } = await request( import.meta.env.VITE_APP_MAP_SRC + 'static/json/' + import.meta.env.VITE_PROJECT_NAME + '_' + 'boundary.json' ); let effectLayer = new this.virtualSpaceObj.DynamicEffect({ VirtualSpace: this.virtualSpaceObj }); effectLayer.createTextureWall({ id: 5, url: 'https://lkimgyt.luokuang.com/1655804893047.png', path: turf.getCoords(data.features[0])[0][0], direction: 3, height: 3000, base: 18, isGradient: true, repeatY: 4, }); } searchByKeyWord(keyword, callback) { let self = this; self.search.search(keyword, callback); } featureClick(feature, callback) { feature.on('click', e => callback(e)); } mapZoomEndEvt() { let self = this; self.map.on('zoomend', e => { markerScopeEvt(); }); function markerScopeEvt() { let zoom = self.map.getZoom(); self.features .filter(i => !!i.getIcon) .forEach(i => { let iconScope = i.getIcon().options.scope; let labelScope = (i.getLabel() || {}).scope || [0, 25]; i[['hide', 'show'][Number(zoom > iconScope[0] && zoom < iconScope[1])]](); if (!!i.getLabel()) i.setLabelStyle(Object.assign(i.getLabel().style, { opacity: Number(zoom > labelScope[0] && zoom < labelScope[1]) })); }); } } mapClick(callback) { let self = this; this.map.on('click', e => { const zoom = self.map.getZoom(); const value = Math.pow(2, 22 - zoom); let { lng, lat } = e.lngLat; let val = 0.0005; let bbox = turf.bbox(turf.buffer(turf.point([lng, lat]), val)); // let bbox = turf.bbox(turf.buffer(turf.point(CoordTransform.gcj02towgs84(lng,lat)),val)); const center = wgs84ToMercator(lng, lat); // const [] // const min = [center.x - value, center.y - value]; // const max = [center.x + value, center.y + value]; let params = Object.assign(WFS_PARAMS, {}); // delete params.bbox; // params.bbox = bbox.join(',') // params.filter = `<Filter xmlns="http://www.opengis.net/ogc" xmlns:gml="http://www.opengis.net/gml"><Intersects><PropertyName>geometrys</PropertyName><gml:Point srsName="http://www.opengis.net/gml/srs/epsg.xml#4326"><gml:coordinates>${CoordTransform.gcj02towgs84(lng,lat).join(',')}</gml:coordinates></gml:Point></Intersects></Filter>` // params.bbox = `${lng - val},${lat - val},${lng + val},${lat + val}` // params.bbox = [min,max].flat().join(','); bbox.push('EPSG:4326'); params.bbox = bbox.join(','); if (!!!Object.keys(NewFiberMapUtils._layers.wms).length) return; let { linestring, point } = NewFiberMapUtils._layers.wms; let lineStringChecks = linestring.children.filter(i => i.check); let pointChecks = point.children.filter(i => i.check); let urls = []; urls.push(!!lineStringChecks.length && linestring); urls.push(!!pointChecks.length && point); urls = urls.filter(Boolean).map(item => { let url = item.url; params.typeName = item.layers; url = url + '?' + Object.keys(params) .map(key => `${key}=${params[key]}`) .join('&'); return request({ url: url.toString() }); }); if (!!!urls.length) return Promise.resolve(); Promise.all(urls).then(results => callback(results)); }); function wgs84ToMercator(lng, lat) { lng = parseFloat(lng); lat = parseFloat(lat); let d = Math.PI / 180, max = 90, sin = Math.sin(lat * d); lat = Math.max(Math.min(max, lat), -max); let x = 6378137 * lng * d; let y = (6378137 * Math.log((1 + sin) / (1 - sin))) / 2; return { x, y, }; } } addBaseMapImagery() { NewFiberMapUtils._layers.baseMap[1].instance = new LKMap.TileLayer({ getTileUrl: NewFiberMapUtils._layers.baseMap[1].url, opacity: 1, }); NewFiberMapUtils._layers.baseMap[1].instance.setMap(this.map); NewFiberMapUtils._layers.baseMap[1].instance.hide(); } wmsLayerChange(cItem, cIndex, item) { console.log(cItem, cIndex, item); console.log(item.url); let self = this; cItem.instance ? (cItem.check ? cItem.instance.show() : cItem.instance.hide()) : loadWms(); function loadWms() { let bboxKey = WMS_PARAMS.bbox; let url = item.url; let params = Object.assign(WMS_PARAMS, { LAYERS: item.layers, cql_filter: `${item.filterField}='${cItem.id}'` }); url = url + '?' + Object.keys(params) .map(key => `${key}=${params[key]}`) .join('&'); console.log(url); cItem.instance = new LKMap.TileLayer.WMS({ getTileUrl: bbox => url.replaceAll(bboxKey, bbox) }); cItem.instance.setMap(self.map); } } baseMapChange(item) { item.instance ? item.check ? item.instance.show() : item.instance.hide() : NewFiberMapUtils._layers.baseMap[1].instance.hide(); } updateSky() { let self = this; // 实例化三维场景类 self.virtualSpaceObj = new LKMap.VirtualSpace({ map: self.map, /*** * 天空盒类型: * 1. hdr_morning 早上 * 2. hdr_daylight 白天 * 3. hdr_sunset 日落 * 4. hdr_night 晚上 */ skyType: 'hdr_daylight', // 设置天空盒类型 }); } addTerrain() { this.map.addTerrain({ url: NewFiberMapUtils._layers.terrain.url, exaggeration: 1, maxDrapeOverZoom: 5, }); this.map.addHillshading({ illuminationAnchor: 'map', exaggeration: 0.5, }); } // 添加地图控件 addControl(params) { let self = this; // 缩放控件 this.map.plugin(['ToolBar', 'Scale', 'ControlBar'], function () { [ new LKMap.ToolBar({ position: 'bottom-right', showZoom: true, liteStyle: true }), new LKMap.Scale({ position: 'bottom-left' }), new LKMap.ControlBar({ position: 'bottom-right' }), ].forEach(control => self.map.addControl(control)); }); } static throttle(fn, delay = 300) { let timer = null; return function (...args) { if (timer == null) { timer = setTimeout(() => { fn.call(this, ...args); clearTimeout(timer); timer = null; }, delay); } }; } addMarkers(lngLats, properties, labelScope = [15, 25], iconScope = [0, 25]) { let self = this; return lngLats.map((lngLat, index) => { let id = properties[index].mapParams.id ?? NewFiberMapUtils.defaultParams.keys.temporary; let icon = properties[index].mapParams.icon ?? NewFiberMapUtils.defaultParams.url.icon; let size = properties[index].mapParams.size ?? NewFiberMapUtils.defaultParams.size.icon; let visible = properties[index].mapParams.visible ?? true; let marker = new LKMap.Marker({ map: self.map, position: new LKMap.LngLat(...lngLat), anchor: 'bottom', extData: properties[index] ?? {}, visible: visible, icon: new LKMap.Icon({ size: new LKMap.Size(...size), image: icon, scope: iconScope, anchor: 'top-center', }), label: { scope: labelScope, content: properties[index].mapParams.name ?? '', direction: 'top', offset: new LKMap.Pixel(0, -5), style: { 'background-color': 'rgba(255,255,255,1)', padding: '5px 10px', 'border-radius': '4px', color: 'black', 'box-shadow': '0 2px 4px rgba(0, 0, 0, .12), 0 0 6px rgba(0, 0, 0, .04)', }, }, }); marker.newfiberId = id; return marker; // this.features.push(marker); }); } addPolygon(lngLats, properties, labelScope = [15, 25], iconScope = [0, 25]) { let self = this; return lngLats.map((lngLat, index) => { let id = properties[index].mapParams.id ?? NewFiberMapUtils.defaultParams.keys.temporary; let color = properties[index].mapParams.color; let visible = properties[index].mapParams.visible ?? true; let polygon = new LKMap.Polygon({ path: lngLat, strokeWeight: 2, strokeOpacity: 0.8, strokeColor: color, fillColor: color, extData: properties[index], visible: visible, }); polygon.newfiberId = id; polygon.setMap(self.map); return polygon; // this.features.push(marker); }); } addPolyline(lngLats, properties) { let self = this; return lngLats.map((lngLat, index) => { let id = properties[index].mapParams.id ?? NewFiberMapUtils.defaultParams.keys.temporary; let visible = properties[index].mapParams.visible ?? true; let color = properties[index].mapParams.color; let polyline = new LKMap.Polyline({ map: self.map, path: lngLat, strokeWeight: 1, showBorder: true, // 是否显示描边 borderWeight: 1, // 描边宽度 borderColor: color, extData: properties[index], visible: visible, }); polyline.newfiberId = id; return polyline; // this.features.push(marker); }); } addGeojsonPolyline(geojsonData, option) { let self = this; let id = option.id ?? NewFiberMapUtils.defaultParams.keys.temporary; let geojson = null; geojson && geojson.remove(); geojson = new LKMap.GeoJSON({ geoJSON: geojsonData, // GeoJSON对象 getPolyline: function (geojson, lnglats) { //还可以自定义getMarker和getPolyline let Polyline = new LKMap.Polyline({ path: lnglats, strokeWeight: option.width || 2, strokeOpacity: option.opacity || 0.8, strokeColor: option.color || '#DD3737', extData: geojson.properties, visible: false, }); Polyline.newfiberId = id; Polyline.setMap(self.map); self.features.push(Polyline); }, }); } addGeojson(geoJSON) { let self = this; let features = []; /* let features = geoJSON.features.map(feature => { let type = feature.geometry.type.toLocaleUpperCase(); let coordinates = feature.geometry.coordinates; let properties = feature.properties; let lkFeature = []; if(type.includes(VECTOR_TYPE.POINT)) lkFeature = self.addMarkers(coordinates,[properties]) if(type.includes(VECTOR_TYPE.LINESTRING)) lkFeature = self.addPolyline([coordinates],[properties]) if(type.includes(VECTOR_TYPE.POLYGON)) lkFeature = self.addPolygon([coordinates],[properties]) return lkFeature[0]; }).filter(Boolean);*/ let geojson = new LKMap.GeoJSON({ geoJSON, // GeoJSON对象 getMarker: function (feature, lnglats) { //还可以自定义getMarker和getPolyline features.push(self.addMarkers([lnglats], [feature.properties])); }, getPolygon: (feature, lnglats) => { let polygon = self.addPolygon([lnglats], [feature.properties]); features.push(polygon); }, getPolyline: (feature, lnglats) => { features.push(self.addPolyline([lnglats], [feature.properties])); }, }); if (self.callbacks.featureClick) features.flat(Infinity).forEach(i => self.featureClick(i, self.callbacks.featureClick)); self.features = self.features.concat(features).flat(Infinity); } beansToGeojson( beans, fields = { id: 'id', color: 'color', geometry: 'geometry', name: 'name', icon: 'icon_url', visible: false } ) { return turf.featureCollection( beans .filter(bean => bean[fields.geometry]) .map(bean => { let mapParams = { id: bean[fields.id] || NewFiberMapUtils.defaultParams.keys.temporary, color: bean[fields.color] || NewFiberMapUtils.randomRgb(), icon: bean[fields.icon] || NewFiberMapUtils.defaultParams.url.icon, name: bean[fields.name] || '', visible: [false, true][Number(fields.visible == true)], }; bean = Object.assign({ mapParams }, bean); let feature = turf.feature(Terraformer.WKT.parse(bean[fields.geometry]), bean); gcoord.transform(feature, gcoord.WGS84, gcoord.GCJ02); let point = turf.center(feature.geometry); point.properties = bean; return [feature, point]; }) .flat(Infinity) ); } flyTo(params, callback) { let defaultFlyParams = NewFiberMapUtils.defaultParams.flyTo; defaultFlyParams = Object.assign(defaultFlyParams, params); this.animation.flyTo(defaultFlyParams, () => callback); } removeByIds(ids = []) { if (!!!ids.length) { this.features.forEach(i => i.remove()); this.features = []; } this.getFeaturesByIds(ids).forEach(i => i.remove()); // return this.getFeaturesByIds(ids).forEach(feature => feature.remove()) } getFeaturesByIds(ids) { return this.features.filter(feature => ids.includes(feature.newfiberId)); } setFeaturesVisibleByIds(ids, visible = true) { this.getFeaturesByIds(ids).forEach(feature => feature[['hide', 'show'][Number(visible)]]()); } setAllFeaturesVisible(visible = true) { this.features.forEach(feature => feature[['hide', 'show'][Number(visible)]]()); } setFitViewByFeatures(feature = null, options = null) { // this.map.flyTo(feature); this.map.setFitView(feature, options); } dynamicLine(geojson) { this.runLineLayer = new this.virtualSpaceObj.RunLine({ VirtualSpace: this.virtualSpaceObj }); this.runLineLayer.addLine( geojson.features.map((feature, index) => { let lngLats = turf.coordAll(feature); return { id: index, image: import.meta.env.VITE_APP_MAP_SRC + 'static/line.png', height: 0, from: gcoord.transform(lngLats[0], gcoord.WGS1984, gcoord.AMap), to: gcoord.transform(lngLats[1], gcoord.WGS1984, gcoord.AMap), speed: 2, width: 10, }; }), e => { console.log('飞线添加完成', e); } ); } initImageLayers(urls, bounds) { let self = this; if (!!!self.imageLayers.length) self.imageLayers.forEach(layer => layer.remove()); self.imageLayers.length = 0; self.imageLayers = urls.map(url => { let imageLayer = new LKMap.ImageLayer({ url, bounds: new LKMap.Bounds(...bounds), // 设置图片覆盖的范围 opacity: 1, // 设置图层透明度 }); imageLayer.setMap(self.map); return imageLayer; }); } startPlayImageLayers() { let self = this; let step = 0; const alphaStep = 0.01; let arrTileLayer = self.imageLayers; function changeRadarAlpha(time) { if (step > arrTileLayer.length - 1) { step = 0; arrTileLayer[arrTileLayer.length - 1].setOptions({ opacity: 0 }); // arrTileLayer[arrTileLayer.length - 1].alpha = 0 } const layer1 = arrTileLayer[step]; const layer2 = arrTileLayer[step + 1]; if (!layer1 || !layer2) return; layer1.setOptions({ opacity: 1 }); layer2.setOptions({ opacity: 0 }); clearInterval(self.timer); self.timer = window.setInterval(function () { let opacity1 = layer1.getOptions().opacity; let opacity2 = layer2.getOptions().opacity; opacity1 -= alphaStep; opacity2 += alphaStep; layer2.setOptions({ opacity: opacity1 }); layer2.setOptions({ opacity: opacity2 }); if (opacity1 < alphaStep) { layer1.alpha = 0; layer2.setOptions({ opacity: 0 }); step++; changeRadarAlpha(time); } }, time * 1000 * alphaStep); } changeRadarAlpha(1); } initCanvasLayer(id, bounds) { if (!!this.canvasLayers.length) this.canvasLayers.forEach(i => i.remove()); this.canvasLayers.length = 0; let canvasLayerObj = new LKMap.CanvasLayer({ canvasId: id, bounds: new LKMap.Bounds(...bounds), }); canvasLayerObj.setMap(this.map); this.canvasLayers.push(canvasLayerObj); } static randomRgb() { //rgb颜色随机 const r = Math.floor(Math.random() * 256); const g = Math.floor(Math.random() * 256); const b = Math.floor(Math.random() * 256); return `rgba(${r},${g},${b},0.5)`; } static loadAllImages(imgUrls) { var _load = function (imgUrl) { //创建img标签 var img = new Image(); img.src = imgUrl; //跨域选项 img.setAttribute('crossOrigin', 'Anonymous'); return new Promise((resolve, reject) => { //文件加载完毕 img.onload = function () { resolve(img); }; }); }; var _loadAll = function (imgUrls) { var loadedImageUrls = []; for (var i = 0, len = imgUrls.length; i < len; i++) { loadedImageUrls.push(_load(imgUrls[i])); } return loadedImageUrls; }; return Promise.all(_loadAll(imgUrls)); } canvasImageToMap(data) { let images = []; Object.keys(data).forEach(key => { let canvasLayerObj = new LKMap.CanvasLayer({ canvasId: `${key}_canvas`, bounds: new LKMap.Bounds(...data[key].bounds), }); canvasLayerObj.setMap(AllData.maps[key].map); images = images.concat(data[key].urls); AllData.maps[key].map.setBounds(new LKMap.Bounds(...data[key].bounds)); }); let index = 0; NewFiberMapUtils.loadAllImages(images).then(res => { let imagess = _.chunk(res, res.length / 2); let keys = Object.keys(AllData.remouldData); let canvass = keys.map((key, index) => { let canvas = document.getElementById(`${key}_canvas`); canvas.width = data[key].wh[0]; canvas.height = data[key].wh[1]; return canvas; }); let contexts = canvass.map(canvas => canvas.getContext('2d')); if (AllData.interval) clearInterval(AllData.interval); AllData.interval = setInterval(() => { index++; if (index == imagess[0].length) index = 0; contexts.forEach((context, idx) => { let w = canvass[idx].width; let h = canvass[idx].height; canvass[idx].width = w; canvass[idx].height = h; context.drawImage(imagess[idx][index], 0, 0, data[keys[idx]].wh[0], data[keys[idx]].wh[1]); }); }, 1000); }); } }