vue3 mars3d 天地图

2 篇文章 0 订阅
1 篇文章 0 订阅

准备工作:

        安装mars3d依赖:

                npm i mars3d 

                npm i mars3d-heatmap (热力图,需要的话安装)

                npm i -D copy-webpack-plugin

                增加mars3d目录配置,修改vue.config.js中configureWebpack里的内容如下:

const CopyWebpackPlugin = require("copy-webpack-plugin");
const cesiumSourcePath = "node_modules/mars3d-cesium/Build/Cesium/"; // cesium库安装目录
const cesiumRunPath = "./mars3d-cesium/"; // cesium运行时路径
const timeStamp = Date.now()
module.exports = {
    configureWebpack: (config) => {
    const plugins = [
      // 标识cesium资源所在的主目录,cesium内部资源加载、多线程等处理时需要用到
      new webpack.DefinePlugin({
        CESIUM_BASE_URL: JSON.stringify(path.join(config.output.publicPath, cesiumRunPath))
      }),
      // Cesium相关资源目录需要拷贝到系统目录下面(部分CopyWebpackPlugin版本的语法可能没有patterns)
      new CopyWebpackPlugin([
          { from: path.join(cesiumSourcePath, 'Workers'), to: path.join(config.output.path, cesiumRunPath, 'Workers') },
          { from: path.join(cesiumSourcePath, 'Assets'), to: path.join(config.output.path, cesiumRunPath, 'Assets') },
          { from: path.join(cesiumSourcePath, 'ThirdParty'), to: path.join(config.output.path, cesiumRunPath, 'ThirdParty') },
          { from: path.join(cesiumSourcePath, 'Widgets'), to: path.join(config.output.path, cesiumRunPath, 'Widgets') }
      ])
    ]

    if (process.env.NODE_ENV === "production") {
      plugins.push(
        new UglifyJSPlugin({
          uglifyOptions: {
            //删除注释
            output: {comments: false},
            warnings: false,
            //删除console 和 debugger  删除警告
            compress: {
              drop_debugger: true,
              drop_console: true
            }
          },
          cache: true, // 启用文件缓存
          sourceMap: false,//不生成调试文件
          parallel: true // 使用多进程并行运行来提高构建速度
        })
      );
    }
    config.plugins = [...config.plugins, ...plugins]
    //给打包的文件名加上时间戳,防止浏览器缓存

    config.output.filename = `js/[name].${timeStamp}.js`
    config.output.chunkFilename = `js/[name].${timeStamp}.js`

    return {
      module: { unknownContextCritical: false }, // 配置加载的模块类型,cesium时必须配置
      plugins: plugins
    }
  },
  //...其它配置
}

组件页:

<template>
  <div class="r-map-3d">
    <div class="map-box" :id="mapId"></div>
  </div>
</template>
<script setup>
import {defineEmits, defineProps, onMounted, reactive, ref} from 'vue'
import mars3D from '@/plugins/mars3d/mapController'

const props = defineProps({
  //中心点
  center: {
    type: Array,
    default: () => [0, 0]
  }
})
const emit = defineEmits(['onLoad']);
const mapId = ref(`map_${Date.now()}`)

const data = reactive({
  map: null,
})

onMounted(() => {
  data.map = new mars3D(mapId.value, props.center)
  emit('onLoad', data.map)
})
</script>
<style scoped lang="scss">
.r-map-3d {
  width: 100%;
  height: 100%;

  .map-box {
    height: 100%;
    width: 100%;
  }
}
</style>

mapController.js:(地图操作类)

import {mapUrl, mapAk} from "@/config/baseURL";
//引入cesium基础库
import "mars3d-cesium/Build/Cesium/Widgets/widgets.css";
import * as Cesium from "mars3d-cesium";
//导入mars3d主库
import "mars3d/dist/mars3d.css";
import * as mars3d from "mars3d";
import "mars3d-heatmap"

export default class MapController {
    constructor(mapId) {
        this.ak = mapAk
        this.mapId = mapId

        /** 地图实例 */
        this.instance = null

        this.initMap()
    }

    /**
     * 创建天地图层
     * @param name 描述
     * @auth Roffer
     * @date 2022/9/29 15:50
     *
     */
    initMap() {
        // 需要覆盖config.json中地图属性参数(当前示例框架中自动处理合并)
        //option相关设置:http://mars3d.cn/apidoc.html#Map
        const mapOptions = {
            //scene相关设置:http://mars3d.cn/api/Map.html#.sceneOptions
            scene: {
                center: {lat: 29.068075, lng: 103.966252, alt: 82849.5, heading: 358.9, pitch: -28.4},
                showSkyAtmosphere: false,
                backgroundColor: '#000',
                contextOptions: {
                    webgl: {
                        //通过canvas.toDataURL()实现截图需要将该项设置为true
                        preserveDrawingBuffer: true
                    }
                },
                cameraController: {
                    //相机最近视距,变焦时相机位置的最小量级(以米为单位),默认为1。该值是相机与地表(含地形)的相对距离。默认1.0
                    minimumZoomDistance: 1,
                    //相机最远视距,变焦时相机位置的最大值(以米为单位)。该值是相机与地表(含地形)的相对距离。默认50000000.0
                    maximumZoomDistance: 200000
                },
                globe: {
                    show: true,//是否显示地球
                }
            },
            // control: {
            //     locationBar: {
            //         fps: true,//是否显示实时FPS帧率
            //         navigationHelpButton: true
            //     }
            // },
        }

        this.instance = new mars3d.Map(this.mapId, mapOptions); //支持的参数请看API文档:http://mars3d.cn/api/Map.html
        this.instance.basemap = 2017 // 蓝色底图
        const mapLayer = mars3d.LayerUtil.create({
            type: "wmts",
            url: mapUrl,
            //wmts服务元数据中指定的layer值
            format: "image/png",
            layer: "defaultLayer",
            style: "default",
            //跨域支持,在使用html2canvas截屏的时候,如果不设置该属性,会截不到地图内容
            crossOrigin: 'Anonymous',
            tileMatrixSetID: "GetTileMatrix",
            minimumLevel: 3,
            maximumLevel: 17,
            minimumTerrainLevel: 1,
            maximumTerrainLevel: 25,
            zIndex: 2,
            crs: "EPSG4490",
            chinaCRS: "WGS84",
            tileWidth: 256,
            tileHeight: 256,
            name: "影像",
            extent: {
                xmin: 96.8064823,
                ymin: 25.68096106,
                xmax: 109.1252279,
                ymax: 34.75215408
            }
        })

        this.instance.addLayer(mapLayer)

        //获取右键菜单绘制完成数据
        this.instance.on(mars3d.EventType.drawCreated, (e) => {
            console.log(JSON.stringify(e.graphic));
        })
    }

    /**
     * 区域标记
     * @param areaCode 区域编码
     * @param filter 透明度,默认不透明,值范围:0~1
     * @param popupState 点击地图popup显隐
     * @auth Roffer
     * @date 2022/11/10 19:03
     *
     */
    addAreaLayer(areaCode = '510100000000', filter = 1, styleCback,popupState=true) {
        const geoJsonLayer = new mars3d.layer.GeoJsonLayer({
            name: "成都市",
            url: `/json/5101/${areaCode}.json`,
            allowDrillPick: true,
            symbol: {
                type: "polygon",
                styleOptions: {
                    materialType: mars3d.MaterialType.PolyGradient, // 重要参数,指定材质
                    // materialType: mars3d.MaterialType.Stripe, // 重要参数,指定材质
                    materialOptions: {
                        color: "#3388cc",
                        opacity: 0.7,
                        alphaPower: 1.3
                    },
                    // 面中心点,显示文字的配置
                    label: {
                        text: "{name}", // 对应的属性名称
                        opacity: 1,
                        font_size: 18,
                        color: "#fff",
                        font_family: "宋体",
                        outline: false,
                        scaleByDistance: true,
                        scaleByDistance_far: 20000000,
                        scaleByDistance_farValue: 0.1,
                        scaleByDistance_near: 1000,
                        scaleByDistance_nearValue: 1
                    }
                },
                callback: styleCback ? styleCback : function (attr, styleOpt) {
                    const randomHeight = (attr.childrenNum || 1) * 600 // 测试的高度
                    return {
                        materialOptions: {
                            color: attr.fill,
                            alphaPower: filter
                            // color: getColor()
                        },
                        height: 20,
                        diffHeight: randomHeight
                    }
                }
            },
            popup:popupState ? "{name}" : false
        })
        this.instance.addLayer(geoJsonLayer)

        const arrColor = ["rgb(15,176,255)", "rgb(18,76,154)", "#40C4E4", "#42B2BE", "rgb(51,176,204)", "#8CB7E5", "rgb(0,244,188)", "#139FF0"]

        let index = 0

        function getColor() {
            return arrColor[++index % arrColor.length]
        }

        return geoJsonLayer
    }

    /**
     * 添加自定义多边形
     * @param geoJson geoJson数据
     * @param color 多边形颜色
     * @auth Roffer
     * @date 2022/12/8 11:01
     *
     */
    addCustomLayer({pointList, color, text, popup, popupOptions, tooltip, tooltipOptions}) {
        const graphicLayer = this.genGraphicLayer()
        const graphic = new mars3d.graphic.PolygonEntity({
            positions: pointList,
            style: {
                color,
                opacity: 0.5,
                outline: false,
                outlineWidth: 3,
                outlineColor: "#ffffff",
                highlight: {
                    opacity: 0.8
                },
                label: {
                    show: false,
                    text,
                    font_size: 12,
                    color: "#ffffff",
                    distanceDisplayCondition: true,
                    distanceDisplayCondition_far: 500000,
                    distanceDisplayCondition_near: 0
                }
            },
            popup,
            popupOptions,
            tooltip,
            tooltipOptions
        })

        graphicLayer.addGraphic(graphic)
        this.instance.addLayer(graphicLayer)

        return graphicLayer
    }

    /**
     * 添加一个自定义标注层
     * @auth Roffer
     * @date 2022/11/11 14:19
     *
     */
    genGraphicLayer() {
        let graphicLayer = new mars3d.layer.GraphicLayer()
        this.instance.addLayer(graphicLayer)
        return graphicLayer
    }

    /**
     * 添加自定义html标记点,适用于小于100条数据
     * @param point 经纬度,示例:[123.1,22.444]
     * @param html 要显示的html内容
     * @param popup 自定义详细信息(String,Array,function)
     * @param popupOptions 自定义详细信息参数设置(Object)详情:http://mars3d.cn/api/Popup.html#.StyleOptions
     * @param tooltip 自定义鼠标悬浮提示信息(String,Array,function)
     * @param tooltipOptions 自定义鼠标悬浮提示信息参数设置(Object)详情:http://mars3d.cn/api/Tooltip.html#.StyleOptions
     * @param attr 附加自定义属性(可在点击时,通过e.target.attr获取)
     * @param click 点击回调函数(返回点击的对象)
     * @param style Object,覆盖style对象中的属性值
     * @auth Roffer
     * @date 2022/10/22 14:55
     *
     */
    addDivLayer({point, html, popup, popupOptions, tooltip, tooltipOptions, attr, click, style}, graphicLayer) {
        const graphic = new mars3d.graphic.DivGraphic({
            position: new mars3d.LngLatPoint(point[0], point[1], 915),
            style: {
                html,
                horizontalOrigin: Cesium.HorizontalOrigin.LEFT,
                verticalOrigin: Cesium.VerticalOrigin.BOTTOM,
                clampToGround: true,
                offsetX: -20,
                offsetY: -30,
                ...style
            },
            attr,
            popup,
            popupOptions,
            tooltip,
            tooltipOptions,
            eventParent: false,//不冒泡事件
        })
        graphicLayer.addGraphic(graphic)

        click && graphic.on(mars3d.EventType.click, click)

        return graphicLayer
    }

    /**
     * 批量添加html标标注
     * @param list 数据,
     *         格式为:
     *              [{
     *                  point:[103.111,30.123],html:'<div>xxx</div>',attr:{},click:()=>{}
     *              },...]
     * @auth Roffer
     * @date 2022/11/11 14:00
     *
     */
    batchAddDivLayer(list = []) {
        // 创建矢量数据图层
        let graphicLayer = this.genGraphicLayer()

        list.forEach(item => {
            this.addDivLayer(item, graphicLayer)
        })

        return graphicLayer
    }

    /**
     * 获取当前屏幕边界坐标
     * @auth Roffer
     * @date 2022/11/21 15:37
     *
     */
    getScreenXY() {
        //屏幕边界坐标
        let info = this.instance.viewer.camera.computeViewRectangle()
        info.east = Cesium.Math.toDegrees(info.east)
        info.north = Cesium.Math.toDegrees(info.north)
        info.south = Cesium.Math.toDegrees(info.south)
        info.west = Cesium.Math.toDegrees(info.west)
        // east 104.58916517174933
        // north 30.8081617249502
        // south 30.48271217718593
        // west 103.95342383654778
        return info
    }

    /**
     * 添加自定义标记点
     * @param data 参数对象,包含以下:
     *              url 请求数据的接口地址(url、data二选一)
     *              dataColumn data字段key(url时指定)
     *              data 请求数据的接口地址(url、data二选一)
     *              lngColumn 经纬字段key
     *              latColumn 纬纬字段key
     *              altColumn 高度字段key
     *              positionIconImg 显示的图标图片
     *              showGroup 是否显示聚合分组数据,默认true显示
     *              text 显示的名称字段key
     * @param popup 详细信息对象
     *          key:对象中的key值
     *          item[key]:显示的名称 eg:{name:'名称'}
     * @auth Roffer
     * @date 2022/10/22 14:55
     *
     */
    addBusineDataLayer(data, popup) {
        let option = {
            showGroup: true,
            ...data
        }
        // 创建矢量数据图层(业务数据图层)
        let busineDataLayer = new mars3d.layer.BusineDataLayer({
            ...option,
            symbol: {
                type: "billboard", // 对应是 mars3d.graphic.BillboardEntity
                styleOptions: {
                    image: option.positionIconImg,
                    horizontalOrigin: Cesium.HorizontalOrigin.CENTER,
                    verticalOrigin: Cesium.VerticalOrigin.BOTTOM,
                    scaleByDistance: new Cesium.NearFarScalar(1000, 0.7, 5000000, 0.3),
                    visibleDepth: false,
                    // label: {
                    //     text: `{${data.text || 'text'}}`,
                    //     font_size: 13,
                    //     color: Cesium.Color.AZURE,
                    //     outline: true,
                    //     outlineColor: Cesium.Color.BLACK,
                    //     outlineWidth: 2,
                    //     horizontalOrigin: Cesium.HorizontalOrigin.LEFT,
                    //     verticalOrigin: Cesium.VerticalOrigin.BOTTOM,
                    //     pixelOffset: new Cesium.Cartesian2(10, 0), // 偏移量
                    //     distanceDisplayCondition: new Cesium.DistanceDisplayCondition(0.0, 80000)
                    // }
                }
            },
            // 点的聚合配置
            clustering: {
                enabled: option.showGroup,
                pixelRange: 20,
                clampToGround: false,
                opacity: 1,
                // getImage: function (count) {   //getImage是完全自定义方式
                //   let colorIn
                //   if (count < 10) {
                //     colorIn = 'rgba(110, 204, 57, 0.6)'
                //   } else if (count < 100) {
                //     colorIn = 'rgba(240, 194, 12,  0.6)'
                //   } else {
                //     colorIn = 'rgba(241, 128, 23,  0.6)'
                //   }
                //   return mars3d.Util.getCircleImage(count, {
                //     color: colorIn,
                //     radius: 30,
                //   })
                // },
            }
        })

        this.instance.addLayer(busineDataLayer)

        //包含详情
        if (popup) {
            //详细信息弹窗
            busineDataLayer.bindPopup(function (event) {
                const item = event.graphic?.attr
                if (!item) {
                    return false
                }
                const tabData = [
                    `<table style="width: auto;">
                    <tr><th scope="col" colspan="2" style="text-align:center;font-size:15px;">${item[option.text]}</th></tr>`
                ]
                for (let key in popup) {
                    tabData.push(`<tr>`)
                    tabData.push(`<td>${popup[key]}</td><td>${item[key]}</td>`)
                    tabData.push(`</tr>`)
                }
                tabData.push('</table>')
                return tabData.join('')
            })

            busineDataLayer.bindTooltip(function (event) {
                const item = event.graphic?.attr
                if (!item) {
                    return false
                }
                const tabData = [
                    `<table style="width: auto;">
                    <tr><th scope="col" colspan="2" style="text-align:center;font-size:15px;">${item[option.text]}</th></tr>`
                ]
                for (let key in popup) {
                    tabData.push(`<tr>`)
                    tabData.push(`<td>${popup[key]}</td><td>${item[key]}</td>`)
                    tabData.push(`</tr>`)
                }
                tabData.push('</table>')
                return tabData.join('')
            })
        }

        // 单击事件
        busineDataLayer.on(mars3d.EventType.click, (event) => {
            if (this.instance.camera.positionCartographic.height > 1000) {
                const graphic = event.graphic
                if (graphic) {
                    // 单击了具体的点对象
                    // graphic.closePopup()

                    const position = graphic.positionShow
                    this.instance.flyToPoint(position, {
                        radius: 1000, // 距离目标点的距离
                        duration: 3,
                        complete: function (e) {
                            // 飞行完成回调方法
                            // graphic.openPopup()
                        }
                    })
                } else {
                    // 单击了聚合的点
                    const arrEntity = event.pickedObject.id
                    this.instance.flyTo(arrEntity)
                }
            }
        })

        return busineDataLayer
    }

    /**
     * 两点连线(弧线)
     * @param startPoint 起始经纬度
     * @param endPoint 结束经纬度
     * @param attr 显示的信息对象(object,key、value格式)
     * @param popup 点击时显示的信息
     * @param popupOptions 点击时显示的信息参数设置对象,如可以设置偏移量{offsetX:-10,offsetY:-10},更多参数:http://mars3d.cn/api/Popup.html#.StyleOptions
     * @param tooltip hover时显示的信息
     * @param tooltipOptions hover时显示的信息参数设置对象,如可以设置偏移量{offsetX:-10,offsetY:-10},更多参数:http://mars3d.cn/api/Tooltip.html#.StyleOptions
     * @param lineColor 线条的颜色(默认:#1a9850)
     * @auth Roffer
     * @date 2022/12/3 11:04
     *
     */
    addArc({startPoint, endPoint, attr, popup, popupOptions, tooltip, tooltipOptions, lineColor}, graphicLayer) {
        graphicLayer = graphicLayer || this.genGraphicLayer()
        const start = Cesium.Cartesian3.fromDegrees(...startPoint, 42.31)
        const end = Cesium.Cartesian3.fromDegrees(...endPoint, 37.53)
        const positions = mars3d.PolyUtil.getLinkedPointList(start, end, 20000, 50) // 计算曲线点

        const graphic = new mars3d.graphic.PolylineEntity({
            positions: positions,
            style: {
                width: 10,
                // 动画线材质
                materialType: mars3d.MaterialType.LineFlow,
                materialOptions: {
                    image: require('@/assets/img/map_icon/line-arrow-blue.png'),
                    color: lineColor || '#1a9850',
                    mixt: false,
                    speed: 20,
                    repeat: new Cesium.Cartesian2(5, 1)
                }
            },
            attr,
            popup,
            popupOptions,
            tooltip,
            tooltipOptions
        })
        graphicLayer.addGraphic(graphic)

        return graphicLayer
    }

    /**
     * 热力图
     * @param pointData 经纬度数组 [{lng:123,lat:456},...]
     * @auth Roffer
     * @date 2022/11/11 14:58
     *
     */
    addHeatLayer(pointData) {
        // 热力图 图层
        let heatLayer = new mars3d.layer.HeatLayer({
            positions: pointData,
            // rectangle: rectangle,
            // 以下为热力图本身的样式参数,可参阅api:https://www.patrick-wied.at/static/heatmapjs/docs.html
            heatStyle: {
                radius: 40,
                blur: 0.85
            },
            // 以下为矩形矢量对象的样式参数
            style: {
                arc: true, // 是否为曲面
                height: 100.0,
                opacity: 0.6,
                // classificationType: Cesium.ClassificationType.CESIUM_3D_TILE,
                // clampToGround: true
            }
        })

        this.instance.addLayer(heatLayer)

        return heatLayer
    }

    /**
     * 删除layer
     * @param layer layer对象
     * @auth Roffer
     * @date 2022/11/11 14:26
     *
     */
    removeLayer(layer) {
        this.instance.removeLayer(layer)
    }
}

 使用:

<r-map-3d @onLoad="mapLoad"/>

<script setup>
let map = null//地图实例
let areaLayer = null//图层的操作最好不要定义在vue3的响应式对象中,否则会引起页面卡顿
/** 地图加载完成 */
const mapLoad = (instance) => {
  map = instance
  areaLayer = map.addAreaLayer('510100000000')
}
</script>

最后附上天地图mapUrl地址:

export const mapAk = 'xxxx'//请自行去官方申请
//浅色底图
// export const mapUrl = `http://www.scgis.net/services/newtianditudlg/WMTS?ak=${mapAk}`
//暗色底图
export const mapUrl = `http://www.scgis.net/services/tdtdarkmap/WMTS?ak=${mapAk}`

 省市区地图json数据,请移步到https://geojson.cn/ 根据业务需求下载对应的json数据

mars3d官网 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

roffer

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值