openlayers官网:
OpenLayers - Welcomehttps://openlayers.org/
1、创建地图
获取页面节点放置地图的节点元素,设置地图中心点,创建地图
const mapContainer = shallowRef<HTMLDivElement | null>(null);
const map = shallowRef<olMapType | null>(null);
const center = [115.428784, 23.088291];
const initMap = () => {
const target = mapContainer.value;
const _map = createMap(target!, center); //创建地图
map.value = _map;
// 当鼠标移入到marker上时 鼠标显示手的样式
_map.on("pointermove", (e) => {
const pixel = _map.getEventPixel(e.originalEvent);
const hit = _map.hasFeatureAtPixel(pixel);
(_map.getTarget() as HTMLElement).style.cursor = hit ? "pointer" : "";
});
_map.addControl(
new ScaleLine({
units: "metric",
className: "ol-scale-line",
})
);
};
2、地图图标以及坐标数据(坐标点数据可以通过百度地图坐标拾取器获取)
//图层1
const imgSrc1 =
"https://img1.baidu.com/it/u=2973931732,461284785&fm=253&fmt=auto&app=138&f=PNG?w=200&h=200";
//坐标点
const infoList1 = [
{
lng: "105.428784",
lat: "23.088291",
},
{
lng: "135.428784",
lat: "24.088291",
},
];
//图层2
const imgSrc2 =
"https://img0.baidu.com/it/u=1011815455,1718073395&fm=253&fmt=auto&app=138&f=PNG?w=256&h=256";
const infoList2 = [
{ lng: "107.927905", lat: "33.378945" },
{ lng: "128.227905", lat: "44.478945" },
{ lng: "139.327905", lat: " 34.578945" },
{ lng: "124.227905", lat: "35.578945" },
];
const imgSrc3 =
"https://img2.baidu.com/it/u=552603751,2471267685&fm=253&fmt=auto&app=120&f=PNG?w=220&h=150";
const infoList3 = [
{ lng: "101.927905", lat: "32.378945" },
{ lng: "92.227905", lat: "22.478945" },
{ lng: "113.327905", lat: "23.578945" },
{ lng: "72.227905", lat: "25.578945" },
];
3、添加地图标记markers图层
//添加地图标记
const showMarkets = (
infoList: any,
imgSrc: string,
name: string,
scale: number
) => {
//判断地图是否有该图层,图层控制,移出之后再添加时避免重复添加使用的
const addLayers = getLayerInfo(name);
if (map.value && !addLayers) {
addMarkers(map.value, infoList, imgSrc, { name: name }, { scale: scale });
}
};
const addMarkersLayers = () => {
showMarkets(infoList1, imgSrc1, "infoList1", 0.2); //蓝色
showMarkets(infoList2, imgSrc2, "infoList2", 0.2); //红色
showMarkets(infoList3, imgSrc3, "infoList3", 0.4); //绿色
};
4、判断地图图层是否包含某一个图层的方法
const getLayerInfo = (name: string) => {
const layers = map.value?.getAllLayers();
if (layers) {
return layers.find((item: any) => item?.getProperties().name == name);
}
};
5、地图图标图层控制,勾选显示,取消则移除图层
首先要判断地图是否已经存在了该图层,存在时勾选不添加,不存在时则添加图层;取消勾选移除图层
const checkList = ref(["红色图层", "蓝色图层", "绿色图层"]);
const checkboxGroup1 = ref(["红色图层", "蓝色图层", "绿色图层"]);
//该部分可以优化,这里不是简写
const handleChange = function (value: any) {
const redLayer = getLayerInfo("infoList2");
if (value.includes("红色图层")) {
if (redLayer) {
//已存在
} else {
//添加
showMarkets(infoList2, imgSrc2, "infoList2", 0.2);
}
} else {
//@ts-ignore
map.value?.removeLayer(redLayer);
}
const blueLayer = getLayerInfo("infoList1");
if (value.includes("蓝色图层")) {
if (blueLayer) {
//已存在
} else {
//添加
showMarkets(infoList1, imgSrc1, "infoList1", 0.2);
}
} else {
//@ts-ignore
map.value?.removeLayer(blueLayer);
}
const greenLayer = getLayerInfo("infoList3");
if (value.includes("绿色图层")) {
if (greenLayer) {
//已存在
} else {
//添加
showMarkets(infoList3, imgSrc3, "infoList3", 0.4);
}
} else {
//@ts-ignore
map.value?.removeLayer(greenLayer);
}
};
6、切换地图底图
const changeLayer = (type: "street" | "satellite" | "dark") => {
let layerUrl = "";
switch (type) {
case "street":
layerUrl = streetUrl;
break;
case "satellite":
layerUrl = satelliteUrl;
break;
case "dark":
layerUrl = darkUrl;
break;
default:
return;
}
if (map.value) setLayer(layerUrl, map.value as olMapType);
};
7、页面效果图
取消勾选
切换底图
8、完整代码
map.vue
<template>
<button @click="changeLayer('dark')">切换暗色底图</button>
<button @click="changeLayer('street')">切换街道底图</button>
<button @click="changeLayer('satellite')">切换卫星底图</button>
<div ref="mapContainer" class="mapContainer">
<div class="content">
<el-checkbox-group
v-model="checkboxGroup1"
size="large"
@change="handleChange"
>
<el-checkbox
v-for="(item, index) in checkList"
:key="index"
:label="item"
border
/>
</el-checkbox-group>
</div>
</div>
</template>
<script lang="ts" setup>
import { ref } from "vue";
import { onMounted, shallowRef } from "vue";
import { createMap, setLayer, addMarkers } from "./map";
import type { Map as olMapType } from "ol";
import { ScaleLine } from "ol/control";
import { streetUrl, satelliteUrl, darkUrl } from "@/config";
onMounted(function () {
initMap();
addMarkersLayers();
});
const mapContainer = shallowRef<HTMLDivElement | null>(null);
const map = shallowRef<olMapType | null>(null);
const center = [115.428784, 23.088291];
const initMap = () => {
const target = mapContainer.value;
const _map = createMap(target!, center); //创建地图
map.value = _map;
// 当鼠标移入到marker上时 鼠标显示手的样式
_map.on("pointermove", (e) => {
const pixel = _map.getEventPixel(e.originalEvent);
const hit = _map.hasFeatureAtPixel(pixel);
(_map.getTarget() as HTMLElement).style.cursor = hit ? "pointer" : "";
});
_map.addControl(
new ScaleLine({
units: "metric",
className: "ol-scale-line",
})
);
};
//图层1
const imgSrc1 =
"https://img1.baidu.com/it/u=2973931732,461284785&fm=253&fmt=auto&app=138&f=PNG?w=200&h=200";
//坐标点
const infoList1 = [
{
lng: "105.428784",
lat: "23.088291",
},
{
lng: "135.428784",
lat: "24.088291",
},
];
//图层2
const imgSrc2 =
"https://img0.baidu.com/it/u=1011815455,1718073395&fm=253&fmt=auto&app=138&f=PNG?w=256&h=256";
const infoList2 = [
{ lng: "107.927905", lat: "33.378945" },
{ lng: "128.227905", lat: "44.478945" },
{ lng: "139.327905", lat: " 34.578945" },
{ lng: "124.227905", lat: "35.578945" },
];
const imgSrc3 =
"https://img2.baidu.com/it/u=552603751,2471267685&fm=253&fmt=auto&app=120&f=PNG?w=220&h=150";
const infoList3 = [
{ lng: "101.927905", lat: "32.378945" },
{ lng: "92.227905", lat: "22.478945" },
{ lng: "113.327905", lat: "23.578945" },
{ lng: "72.227905", lat: "25.578945" },
];
//添加地图标记
const showMarkets = (
infoList: any,
imgSrc: string,
name: string,
scale: number
) => {
//判断地图是否有该图层,图层控制,移出之后再添加时避免重复添加使用的
const addLayers = getLayerInfo(name);
if (map.value && !addLayers) {
addMarkers(map.value, infoList, imgSrc, { name: name }, { scale: scale });
}
};
const addMarkersLayers = () => {
showMarkets(infoList1, imgSrc1, "infoList1", 0.2); //蓝色
showMarkets(infoList2, imgSrc2, "infoList2", 0.2); //红色
showMarkets(infoList3, imgSrc3, "infoList3", 0.4); //绿色
};
const getLayerInfo = (name: string) => {
const layers = map.value?.getAllLayers();
if (layers) {
return layers.find((item: any) => item?.getProperties().name == name);
}
};
const checkList = ref(["红色图层", "蓝色图层", "绿色图层"]);
const checkboxGroup1 = ref(["红色图层", "蓝色图层", "绿色图层"]);
//该部分可以优化,这里不是简写
const handleChange = function (value: any) {
const redLayer = getLayerInfo("infoList2");
if (value.includes("红色图层")) {
if (redLayer) {
//已存在
} else {
//添加
showMarkets(infoList2, imgSrc2, "infoList2", 0.2);
}
} else {
//@ts-ignore
map.value?.removeLayer(redLayer);
}
const blueLayer = getLayerInfo("infoList1");
if (value.includes("蓝色图层")) {
if (blueLayer) {
//已存在
} else {
//添加
showMarkets(infoList1, imgSrc1, "infoList1", 0.2);
}
} else {
//@ts-ignore
map.value?.removeLayer(blueLayer);
}
const greenLayer = getLayerInfo("infoList3");
if (value.includes("绿色图层")) {
if (greenLayer) {
//已存在
} else {
//添加
showMarkets(infoList3, imgSrc3, "infoList3", 0.4);
}
} else {
//@ts-ignore
map.value?.removeLayer(greenLayer);
}
};
const changeLayer = (type: "street" | "satellite" | "dark") => {
let layerUrl = "";
switch (type) {
case "street":
layerUrl = streetUrl;
break;
case "satellite":
layerUrl = satelliteUrl;
break;
case "dark":
layerUrl = darkUrl;
break;
default:
return;
}
if (map.value) setLayer(layerUrl, map.value as olMapType);
};
</script>
<style lang="scss" scoped>
.content {
background-color: white;
border-radius: 0.25rem;
padding: 1rem;
position: absolute;
left: 1.5rem;
top: 1rem;
z-index: 9999;
width: 150px;
min-width: 150px;
.el-checkbox {
width: 100%;
margin-bottom: 10px;
}
}
.mapContainer {
width: 100%;
height: 800px;
position: relative;
}
</style>
map.ts
import { Feature, Map, View } from "ol";
import { defaults as defaultControls } from "ol/control";
import { Point } from "ol/geom";
import TileLayer from "ol/layer/Tile";
import VectorLayer from "ol/layer/Vector";
import { Cluster, Vector as VectorSource, XYZ } from "ol/source";
import OSM from "ol/source/OSM";
import { Icon, Style } from "ol/style";
import { MapOptions } from "ol/PluggableMap";
import { satelliteUrl } from "@/config";
/**
* @description 创建一个地图实例
* @param {Document | DocumentId} target 地图挂载到的容器
* @param {Array} center 地图中心点
* @param {Object} config 其他配置项
* @returns 地图对象
*/
export const createMap = function (
target: HTMLElement | string,
center: number[],
config: MapOptions = {}
): Map {
const view = new View({
projection: "EPSG:4326",
center: center, // 需要
zoom: 14,
maxZoom: 18,
// minZoom: 16,
constrainResolution: true, //自动缩放到距离最近的一个整数级别,因为当缩放在非整数级别时地图会糊
});
// 创建地图对象
const map = new Map({
target,
layers: [
new TileLayer({
source: new OSM(),
}),
],
controls: defaultControls({
zoom: false, //不显示放大放小按钮;
rotate: false, //不显示指北针控件;
attribution: false, //不显示右下角的地图信息控件;
}).extend([]),
view,
...config,
});
setLayer(satelliteUrl, map);
return map;
};
/**
* @description 设置地图的地图
* @param {String} layerUrl 地图地址
* @param {Objcet} map 当前的地图实例
*/
export const setLayer = function (layerUrl: string, map: Map) {
const satelliteE = new XYZ({
crossOrigin: "anonymous",
url: layerUrl,
});
const baseLayer2 = map.getLayers().item(0);
// FIXME
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
baseLayer2.setSource(satelliteE);
};
/**
* @description 循环创建marker
* @param {Object} map 绑定的地图对象
* @param {Array} el 含有经纬度的数组
*/
export function addMarkers(
map: Map,
lnglats: any,
imgSrc: string,
options = {},
styleConfig = {}
) {
// 创建Feature对象集合
const features1 = [];
for (let i = 0; i < lnglats.length; i++) {
const numAry = new Feature({
geometry: new Point([Number(lnglats[i].lng), Number(lnglats[i].lat)]),
...lnglats[i],
});
features1.push(numAry);
}
// 矢量要素数据源
const source1 = new VectorSource({
features: features1,
});
const clusterSource = new Cluster({
distance: 5, //标注之间
source: source1,
});
const iconStyle = markerStyle(imgSrc, styleConfig);
const clusters = new VectorLayer({
source: clusterSource,
style: iconStyle,
zIndex: 999,
...options,
});
map.addLayer(clusters);
return source1;
}
const markerStyle = (imgSrc: any, styleConfig: {}) => {
const img = imgSrc ? imgSrc : ``;
return new Style({
image: new Icon({
opacity: 1,
src: img,
anchor: [0.5, 3], // 偏移位置
anchorOrigin: "bottom-left",
anchorXUnits: "fraction",
anchorYUnits: "pixels",
offsetOrigin: "top-right",
offset: [0, 1], //偏移量设置
scale: 1, //图标缩放比例
...styleConfig,
}),
});
};
config/index.ts
// 街景地图地址
export const streetUrl =
"https://webrd01.is.autonavi.com/appmaptile?lang=zh_cn&size=1&scale=1&style=8&x={x}&y={y}&z={z}";
// 卫星图地址
export const satelliteUrl =
"http://wprd0{1-4}.is.autonavi.com/appmaptile?x={x}&y={y}&z={z}&lang=zh_cn&size=1&scl=1&style=6";
//暗色地图
export const darkUrl =
"http://map.geoq.cn/ArcGIS/rest/services/ChinaOnlineStreetPurplishBlue/MapServer/tile/{z}/{y}/{x}";