import { LineLayer, PointLayer, PolygonLayer, Popup, RasterLayer, Scene } from '@antv/l7' import type { ICameraOptions, ISourceCFG, Point } from '@antv/l7-core' import { Mapbox } from '@antv/l7-maps' import { formatStringByTemplate } from '@/utils/string' import bus from '@/utils/bus' import boundary from '@/assets/json/zmw.json' import boundaryTri from '@/assets/json/tri.json' import thData from '@/assets/json/thly-all.json' import lakeData from '@/assets/json/lake.json' import thly from '@/assets/images/thly-all.png' export let scene: Scene // 加载状态 export let loadedStatus = false export let imageMap = new Map() function loadImage(images: any[]) { images.forEach((item: any) => { if (!imageMap.has(item.name)) { imageMap.set(item.name, item.src) scene.addImage(item.name, item.src) } }) } /** * 初始化地图 */ export function init(config: any) { loadedStatus = false imageMap = new Map() scene = new Scene({ id: 'mapDiv', map: new Mapbox({ center: [120.83, 31.05], zoom: 9, maxZoom: 10, minZoom: 5, pitch: 90, // 地图倾斜度 style: 'blank' }) }) scene.on('loaded', () => { loadedStatus = true loadBaseLayer() // 加载图片 if (config && config.images && config.images.length > 0) { loadImage(config.images) } setTimeout(function() { const map = scene.map const startZoom = 6.5 const endZoom = 9 const duration = 6000 // 动画持续时间,单位毫秒 const interval = 100 // 每次更新间隔,单位毫秒 const step = (endZoom - startZoom) * (interval / duration) const zoomAnimation = setInterval(() => { const currentZoom = map.getZoom() if (currentZoom <= startZoom) { clearInterval(zoomAnimation) map.setZoom(startZoom) } else { const newZoom = currentZoom - step map.setZoom(newZoom) } }, interval) }, 9000) }) // 地图平移时触发事件 scene.on('mapmove', () => { console.log('中心点:', scene.getCenter().lng, scene.getCenter().lat, scene.getZoom(), scene.getPitch()) }) } /** * 加载底图 */ function loadBaseLayer() { // //添加太湖流域地图 const thMap = new PolygonLayer({}) .source(thData) //使用的数据为下载到本地的json数据 .shape('extrude') //用于绘制几何体 .size(30000) .active({ color: 'rgba(0, 0, 0, .1)' }) .style({ mapTexture: thly, heightfixed: true, //抬升高度是否随 zoom 变化 raisingHeight: 1000, //抬升高度 sourceColor: '#67bdec', //抬高高度的颜色 targetColor: '#67bdec', opacity: 0.5 }) const triLayer = new LineLayer({ zIndex: 2 }) .source(boundaryTri) .color('rgb(241,152,49)') .size(2) .style({ raisingHeight: 50000 }) scene.addLayer(triLayer) const layerBoundary = new LineLayer({ zIndex: 2 }) .source(boundary) .size(50) .shape('wall') .style({ opacity: 1, sourceColor: '#0DCCFF', targetColor: 'rbga(255,255,255, 0)', raisingHeight: 50000 }) scene.addLayer(layerBoundary) scene.addLayer(thMap) setMark(lakeData) } /** * 设置地图视角 * @param center 中心点 * @param zoom 层级 * @param pitch 倾斜角度 * @param padding */ export function setCenter(center: Point, zoom: number, pitch = 0, padding = {}) { if (center && zoom) { scene.setZoomAndCenter(zoom, center) } else if (center) { scene.setCenter(center, padding as ICameraOptions) } else if (zoom) { scene.setZoom(zoom) } scene.setPitch(pitch) } export function loadMap(option: any) { const loadMapFun = (option: any) => { if (option.view) { setCenter(option.view.center, option.view.zoom) } if (option.layers) { // 清空图层 scene.removeAllLayer() // 加载地图 loadBaseLayer() option.layers.forEach((layer: any) => { switch (layer.type) { case 'point': createPointByCongfig(layer) break // case 'line': // createLineByCongfig(layer, mapJson) // break // case 'polygon': // createPolygonByCongfig(layer, mapJson) // break // case 'mark': // setMark(config) // break } }) } } function checkStatus(option: any) { if (loadedStatus) { loadMapFun(option) } else { setTimeout(() => checkStatus(option), 1000) } } checkStatus(option) } function createPointByCongfig(config: any) { console.log('config', config, imageMap) const layer = new PointLayer({}) .source(config.data, config.dataOptions) .size(config.size) .active(config.emphasis.show).shape('triangleColumn') .color('#3ae33d') // setLayerShape(layer, config.shape) // 颜色配置 // setLayerColor(layer, config.color); scene.addLayer(layer) setMark(config) // setPopup(layer, config); // 点击事件 layer.on('click', (e: any) => { let row = e.feature.properties || e.feature bus.emit('point_click', { data: row, e }) }) } function createLakePoint(config: any) { const layer = new PointLayer({}) .source(config.data, config.dataOptions) .size(config.size) .active(config.emphasis.show) setLayerShape(layer, config.shape) // 颜色配置 // setLayerColor(layer, config.color); scene.addLayer(layer) setMark(config) // setPopup(layer, config); // 点击事件 layer.on('click', (e: any) => { let row = e.feature.properties || e.feature bus.emit('point_click', { data: row, e }) }) } function getValueByConditions(data: any, conditions: any, field: any) { let condition for (const item of conditions) { if (compareByConditions(data, item)) { condition = item break } } if (!condition) { return null } if (field === 'color') { return condition[field] } if (condition[field] !== 'image') { return condition[field] } if (condition[field] === 'image') { return condition.imageName } return null } function compareByConditions(data: any, condition: any) { switch (condition.cond) { case 'lt': if (data < condition.value) { return true } break case 'lte': if (data <= condition.value) { return true } break case 'eq': if (data == condition.value) { return true } break case 'gt': if (data > condition.value) { return true } break case 'gte': if (data >= condition.value) { return true } break case 'ne': if (data != condition.value) { return true } break } return false } /** * 图层数据配置 * @param dataType * @returns {{parser: {x: string, y: string, type: string}}|null} */ function getSourceOptions(dataType: any) { switch (dataType) { case 'geojson': return null case 'list': return { parser: { type: 'json', x: '经度', y: '纬度' } } default: } } /** * 图层形状配置 * @param layer * @param config */ function setLayerShape(layer: any, config: any) { if (config.isConstant) { layer.shape(config.value) } else { layer.shape(config.field, config.value) } } /** * 图层颜色配置 * @param layer * @param config */ function setLayerColor(layer: any, config: any) { if (config.isConstant) { layer.color(config.value) } else { const field = config.field const conditions = config.conditions layer.color(field, (field: any) => { return getValueByConditions(field, conditions, 'color') }) } } export function setMark(config: any) { if (!config.label.show) { return } // 标注 const markLayer = new PointLayer({}) .source(config.data, config.dataOptions) .shape(config.label.field, 'text') .size(16) .color(config.label.color || '#000') .style({ textAnchor: config.label.position || 'center', // 文本相对锚点的位置 center|left|right|top|bottom|top-left textOffset: [0, 40], // 文本相对锚点的偏移量 [水平, 垂直] spacing: 2, // 字符间距 padding: [1, 1], // 文本包围盒 padding [水平,垂直],影响碰撞检测结果,避免相邻文本靠的太近 stroke: config.label.stroke || '#ffffff', // 描边颜色 strokeWidth: 2, // 描边宽度 strokeOpacity: 1.0 }) scene.addLayer(markLayer) } function setPopup(layer: any, config: any) { if (!config.enabled) { return } layer.on(config.trigger, (e: any) => { let properties = e.feature.properties || e.feature const content = formatStringByTemplate(properties, config.content) // offsets: [0, 0], closeButton: false, const popup = new Popup({}) .setLnglat(e.lngLat) .setHTML(content) scene.addPopup(popup) }) } /** * 创建线图层 * @param config 配置 * @param dataType 图层数据类型 * @param mapData 图层数据 */ function createLineByCongfig(config: any, dataType: any, mapData: any) { const sourceOptions = getSourceOptions(dataType) as ISourceCFG const layer = new LineLayer({}) .source(mapData, sourceOptions) .size(1) .style({ lineType: 'dash', dashArray: [2, 2] }) .active(config.active) scene.addLayer(layer) setMark(config) setPopup(layer, config.popup) } /** * 创建面图层 * @param config 配置 * @param dataType 图层数据类型 * @param mapData 图层数据 */ function createPolygonByCongfig(config: any, dataType: any, mapData: any) { const sourceOptions = getSourceOptions(dataType) as ISourceCFG const layer = new PolygonLayer({}) .source(mapData, sourceOptions) .shape('fill') .active(config.active) // 颜色配置 setLayerColor(layer, config.color) scene.addLayer(layer) setMark(config) setPopup(layer, config.popup) } export function getLegendData(config: any) { const layers = config.layers const layerLegend = layers.reduce((acc: any, item: any) => { if (item.legend && item.legend.data) { return acc.concat(item.legend.data) } else { return acc } }, []) // return layerLegend.map((item: any) => { // const data = {label: item.text} // if (item.shape === 'image') { // data.imgType = 'img' // data.src = item.imgSrc // } else { // data.imgType = 'svg' // data.src = item.shape // data.imgStyle = {fill: item.color} // } // return data // }) return null }