记录 在vue3中openLayers加载地图 -使用天地图的瓦片数据

693 阅读5分钟

前置条件

安装openlayers库

官网地址:openlayers.org/

npm install ol

1. 获取天地图的瓦片数据

天地图瓦片数据: lbs.tianditu.gov.cn/server/MapS…

import TileLayer from 'ol/layer/Tile'; // 引入瓦片图层
import XYZ from 'ol/source/XYZ'; // 引入XYZ瓦片源
const key = ref(" 天地图的key")
/**
 * 获取天地图图层
 * 
 * @param {string} layerName - 图层名称,例如 'cva_c' 表示矢量注记图层
 * @param {string} layerType - 图层类型,例如 'cva' 表示矢量注记
 * @returns {Promise<TileLayer>} 返回一个 Promise,该 Promise 解析为一个 TileLayer 对象
 */
function getLayer(layerName, layerType) {
    return new Promise((resolve, reject) => {
        try {
            // 创建 TileLayer 图层实例
            const layer = new TileLayer({
                source: new XYZ({
                    // 天地图 WMTS 服务的 URL
                    url: `http://t0.tianditu.gov.cn/${layerName}/wmts?SERVICE=WMTS&REQUEST=GetTile&VERSION=1.0.0&LAYER=${layerType}&STYLE=default&TILEMATRIXSET=w&FORMAT=tiles&TILEMATRIX={z}&TILEROW={y}&TILECOL={x}&tk=${key.value}`,
                }),
            });
            if (layer) {
                resolve(layer);
            } else {
                reject(new Error('获取图层失败'));
            }
        } catch (error) {
            // 捕获任何异常并拒绝 Promise,返回错误信息
            reject(new Error(`创建图层时发生错误: ${error.message}`));
        }
    });
}

2. 初始化地图

import { Map, View, Feature } from 'ol';
const map = ref(null)
const mapCenter = ref([114.42742665908969, 23.127858267967294])
const mapZoom = ref(15) // 默认缩放级别
async function initMap() {
    // 判断是否已经存在地图实例,如果存在则销毁
    if (map.value) {
        map.value.setTarget(undefined); // 解除当前地图实例的 target,确保 DOM 元素不会被重复使用
        map.value = null; // 将 map 实例置为空,以便后续创建新地图实例
    }
    //根据给定的图层名称和类型,获取相应的图层
    const layer1 = await getLayer('img_w', 'img');
    const layer2 = await getLayer('cia_w', 'cia');
    const layer3 = await getLayer('cva_w', 'cva');

    // 渲染地图视图
    map.value = new Map({
        target: 'map', // 地图将绑定到 HTML 元素 id 为 'map' 的 DOM 元素
        layers: [layer1, layer2, layer3], // 添加三层异步获取的图层到地图上
        view: new View({
            center: fromLonLat(mapCenter.value), // 将经纬度转换为地图投影坐标系,设置地图中心点
            zoom: mapZoom.value, // 设置初始缩放等级,
            maxZoom: 18, // 设置地图最大缩放等级为 18,防止缩放过大 天地图最大就是18再大就不会显示地图
            projection: 'EPSG:3857' // 地图的投影坐标系,
        })
    });
}

// 组件挂载完成后初始化地图
onMounted(() => {
    initMap();
});
效果图:

微信图片_20240913161404.png

3.给地图绑定点击事件

async function initMap() {
    // 判断是否已经存在地图实例,如果存在则销毁
    if (map.value) {
        map.value.setTarget(undefined); // 解除当前地图实例的 target,确保 DOM 元素不会被重复使用
        map.value = null; // 将 map 实例置为空,以便后续创建新地图实例
    }
    //根据给定的图层名称和类型,获取相应的图层
    const layer1 = await getLayer('img_w', 'img');
    const layer3 = await getLayer('cva_w', 'cva');

    // 渲染地图视图
    map.value = new Map({
        target: 'map', // 地图将绑定到 HTML 元素 id 为 'map' 的 DOM 元素
        layers: [layer1, layer3], // 添加三层异步获取的图层到地图上
        view: new View({
            center: fromLonLat(mapCenter.value), // 将经纬度转换为地图投影坐标系,设置地图中心点
            zoom: mapZoom.value, // 设置初始缩放等级,
            maxZoom: 18, // 设置地图最大缩放等级为 18,防止缩放过大 天地图最大就是18再大就不会显示地图
            projection: 'EPSG:3857' // 地图的投影坐标系,
        })
    });
    // 给地图添加点击事件
    map.value.on('click', clickMap);
}

// 地图点击事件
function clickMap(e) {
    // 获取点击坐标
    console.log(e.coordinate);
}

3.给点击的位置添加一个图标

/**
 * 创建userlayer图层
 */
const userLayer = ref(null)
import location from "@/assets/images/location.png" // 本地图片
function createdUserLaer(coordinate) {
    // 1.创建图层
    userLayer.value = new VectorLayer({
        source: new VectorSource() // 创建矢量数据源
    })
    // 2.创建要素
    const feature = new Feature({
        geometry: new Point(coordinate),
    });
    // 3.设置样式要素
    feature.setStyle(new Style({
        image: new Icon({
            src: location,
            scale: 0.1
        })
    }));
    // 3.将要素添加到矢量数据源中
    userLayer.value.getSource().addFeature(feature);
    // 4.将图层添加到地图上
    map.value.addLayer(userLayer.value);
}
效果图

image.png

整体代码

<template>
    <div class="openlayers-map">
        <div id="map"> </div>
    </div>
</template>

<script setup name="openlayersMap">
import { ref, onMounted } from 'vue'
import { Map, View, Feature } from 'ol'; // 引入OpenLayers中的Map、View、Feature
import { Vector as VectorSource } from 'ol/source'; // 引入矢量数据源
import { Vector as VectorLayer } from 'ol/layer'; // 引入矢量图层
import { fromLonLat, toLonLat } from 'ol/proj'; // 引入坐标转换方法
import { Fill, Stroke, Style, Text, Icon } from 'ol/style'; // 引入样式和图标模块
import TileLayer from 'ol/layer/Tile'; // 引入瓦片图层
import { easeOut } from 'ol/easing'; // 引入缓动动画效果
import Overlay from 'ol/Overlay'; // 引入覆盖层用于工具提示
import { Point } from 'ol/geom'; // 引入几何点
import XYZ from 'ol/source/XYZ'; // 引入XYZ瓦片源
const key = ref("天地图的key")
/**
 * 获取天地图图层
 * 
 * @param {string} layerName - 图层名称,例如 'cva_c' 表示矢量注记图层
 * @param {string} layerType - 图层类型,例如 'cva' 表示矢量注记
 * @returns {Promise<TileLayer>} 返回一个 Promise,该 Promise 解析为一个 TileLayer 对象
 */
function getLayer(layerName, layerType) {
    return new Promise((resolve, reject) => {
        try {
            // 创建 TileLayer 图层实例
            const layer = new TileLayer({
                source: new XYZ({
                    // 天地图 WMTS 服务的 URL
                    url: `http://t0.tianditu.gov.cn/${layerName}/wmts?SERVICE=WMTS&REQUEST=GetTile&VERSION=1.0.0&LAYER=${layerType}&STYLE=default&TILEMATRIXSET=w&FORMAT=tiles&TILEMATRIX={z}&TILEROW={y}&TILECOL={x}&tk=${key.value}`,
                }),
            });
            if (layer) {
                resolve(layer);
            } else {
                reject(new Error('获取图层失败'));
            }
        } catch (error) {
            // 捕获任何异常并拒绝 Promise,返回错误信息
            reject(new Error(`创建图层时发生错误: ${error.message}`));
        }
    });
}

const map = ref(null)
const mapCenter = ref([114.42742665908969, 23.127858267967294])
const mapZoom = ref(15) // 默认缩放级别
async function initMap() {
    // 判断是否已经存在地图实例,如果存在则销毁
    if (map.value) {
        map.value.setTarget(undefined); // 解除当前地图实例的 target,确保 DOM 元素不会被重复使用
        map.value = null; // 将 map 实例置为空,以便后续创建新地图实例
    }
    //根据给定的图层名称和类型,获取相应的图层
    const layer1 = await getLayer('img_w', 'img');
    const layer3 = await getLayer('cva_w', 'cva');

    // 渲染地图视图
    map.value = new Map({
        target: 'map', // 地图将绑定到 HTML 元素 id 为 'map' 的 DOM 元素
        layers: [layer1, layer3], // 添加三层异步获取的图层到地图上
        view: new View({
            center: fromLonLat(mapCenter.value), // 将经纬度转换为地图投影坐标系,设置地图中心点
            zoom: mapZoom.value, // 设置初始缩放等级,
            maxZoom: 18, // 设置地图最大缩放等级为 18,防止缩放过大 天地图最大就是18再大就不会显示地图
            projection: 'EPSG:3857' // 地图的投影坐标系,
        })
    });
    // 给地图添加点击事件
    map.value.on('click', clickMap);
}

// 组件挂载完成后初始化地图
onMounted(() => {
    initMap();
});

// 地图点击事件
function clickMap(e) {
    // 获取点击坐标 获取到的是地图坐标不是经纬度
    createdUserLaer(e.coordinate)
}
/**
 * 创建userlayer图层
 */
const userLayer = ref(null)
import location from "@/assets/images/location.png" // 本地图片
function createdUserLaer(coordinate) {
    // 1.创建图层
    userLayer.value = new VectorLayer({
        source: new VectorSource() // 创建矢量数据源
    })
    // 2.创建要素
    const feature = new Feature({
        geometry: new Point(coordinate),
    });
    // 3.设置样式要素
    feature.setStyle(new Style({
        image: new Icon({
            src: location,
            scale: 0.2
        })
    }));
    // 3.将要素添加到矢量数据源中
    userLayer.value.getSource().addFeature(feature);
    // 4.将图层添加到地图上
    map.value.addLayer(userLayer.value);
}

</script>

<style scoped lang="scss">
.openlayers-map {
    width: 100vw;
    height: 100vh;
    background: aquamarine;

    #map {
        width: 100%;
        height: 100%;
    }
}
</style>