vue3+openlayes实现离线地图加载

概述
OpenLayers 使在任何网页中放置动态地图变得容易。它可以显示从任何来源加载的地图图块、矢量数据和标记。OpenLayers 的开发旨在进一步使用各种地理信息。它是完全免费的开源 JavaScript
官网

https://openlayers.org/

1、下载依赖

npm i ol -S

 

2、下载瓦片
这里使用 全能地图下载工具 也可使用别的下载工具,可以将瓦片下下来就行

https://pan.baidu.com/s/1LzFMrxHpdQpGp1W5JZiU6Ad7tg

 

由于瓦片太大,放在项目里不合适,这里将瓦片放在 nginx 里了,也可放在项目里测,不建议,加载会很慢

vue代码

<template>
    <div id="map" />
    <div id="popup" ref="mapContent" v-html="mapText"></div>
</template>

<script setup>
    import 'ol/ol.css'
    import TileLayer from 'ol/layer/Tile'
    import XYZ from 'ol/source/XYZ'
    import VectorLayer from 'ol/layer/Vector'
    import VectorSource from 'ol/source/Vector'
    import { Map, View, Feature, Overlay } from 'ol'
    import { Point as olPoint } from 'ol/geom'
    import { fromLonLat, transform } from 'ol/proj'
    import { Style, Fill, Icon, Text } from 'ol/style'
    import { onMounted, reactive, ref } from 'vue'

    const mapView = reactive({
        center: fromLonLat([119.02888, 33.54414]), // 地图中心点
        zoom: 11, // 初始缩放级别
        minZoom: 8, // 最小缩放级别
        maxZoom: 16 // 最大缩放级别
    })
    let map = ref(null)
    // 弹框
    const overlay = ref(null)
    const mapContent = ref(null)
    const mapText = ref(null)

    // 初始化地图
    const init = () => {
        const mapUrl = ref(
            import.meta.env.VITE_MAP_URL + '/{z}/{x}/{y}.png')
        console.log(mapUrl.value)
        const tileLayer = new TileLayer({
            source: new XYZ({ url: mapUrl.value })
        })
        map.value = new Map({
            layers: [tileLayer],
            view: new View(mapView),
            target: 'map'
        })

        // 创建点位数组
        const peoples = [{
                name: '张三',
                title: '化工大院',
                long: [119.01819, 33.55102]
            },
            {
                name: '李四',
                title: '东仪小区',
                long: [119.04211, 33.53684]
            },
            {
                name: '王五',
                title: '紫郡长安',
                long: [119.01738, 33.58877]
            }
        ]
        // 循环将每个人都添加在地图上
        peoples.forEach((v) => {
            addLayer(v)
        })

        // 初始化地图之后就将弹框挂载好,后续只是修改显示的位置
        createOverlay()
        // 地图点击
        map.value.on('click', (e) => mapClick(e))
    }

    // 添加点位
    const addLayer = (v) => {
        const layer = new VectorLayer({
            source: new VectorSource()
        })
        // 添加图层
        map.value.addLayer(layer)
        // 创建 feature 坐标信息
        const feature = new Feature({
            // 经纬度转换成坐标信息
            geometry: new olPoint(fromLonLat(v.long)),
            // 可以带别的参数,key 可以随便写,不冲突就行,这里将所有的参数都放进来,供后续使用
            ...v
        })
        feature.setStyle(
            new Style({
                // 标点的图片,如果要标不同类型的点,这个图片可以判断加
                image: new Icon({
                    crossOrigin: 'anonymous',
                    src: new URL('../assets/img/people_mark1.png',
                        import.meta.url).href
                }),
                // 标点的文字
                text: new Text({
                    // 文字
                    text: v.name,
                    // 文字样式
                    fill: new Fill({
                        color: 'red'
                    }),
                    font: '20px Calibri',
                    // 偏移量
                    offsetY: 20
                })
            })
        )
        // 将 feature 坐标信息添加在地图上
        layer.getSource().addFeatures([feature])
    }

    // 创建弹框
    const createOverlay = () => {
        overlay.value = new Overlay({
            element: mapContent.value, // 将弹框挂载在 dom 上
            autoPan: true, // 如果弹框显示不全则自动归位
            positioning: 'bottom-center', // 相对于其位置属性的实际位置
            stopEvent: true, // 事件冒泡
            autoPanAnimation: {
                duration: 300 // 地图移动速度
            }
        })

        map.value.addOverlay(overlay.value) // 将弹框添加到地图上
    }
    // 关闭弹框
    const closeMapPopup = () => {
        overlay.value.setPosition(undefined)
    }
    // 地图点击
    const mapClick = (e) => {
        const lonlat = transform(e.coordinate, 'EPSG:3857', 'EPSG:4326')
        // 判断当前点击是否点击在图标上
        const feature = map.value.forEachFeatureAtPixel(e.pixel, (feature) => feature)
        if (feature) {
            // 弹框内容
            mapText.value = `<p>${feature.values_.title}<p>`
            // 把 overlay 显示到指定的坐标位置
            overlay.value.setPosition(fromLonLat(feature.values_.long))
        } else {
            // 弹框关闭
            closeMapPopup()
        }
    }

    onMounted(() => {
        init()
    })
</script>

<style scoped>
    @media (min-width: 1024px) {
        #map {
            width: 100%;
            min-height: calc(100vh);
            display: flex;
            align-items: center;
        }
    }

    @media (max-width: 1024px) {
        #map {
            width: 100%;
            height: 500px;
            margin-top: 20px;
        }
    }

    #popup {
        background-color: #fff;
        filter: drop-shadow(0 1px 4px rgba(0, 0, 0, 0.2));
        padding: 15px;
        border-radius: 10px;
        border: 1px solid #cccccc;
        top: 0;
        left: 0;
    }
</style>

 

posted @ 2023-02-28 15:09  HelpYourself!  阅读(809)  评论(0编辑  收藏  举报