创建地图
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",
})
);
};
默认图片以及点击图标后,图标更换的图片 、坐标点(图片是百度上随意找的图,坐标点数据可以通过百度地图坐标拾取器找)
const imgSrc = "https://unpkg.com/leaflet@1.7.1/dist/images/marker-icon.png";
const imgSrc2 =
"https://img0.baidu.com/it/u=1011815455,1718073395&fm=253&fmt=auto&app=138&f=PNG?w=256&h=256";
//坐标点
const infoList = ref([
{
lng: "115.428784",
lat: "23.088291",
},
{
lng: "115.428784",
lat: "24.088291",
},
]);
添加地图标记点
//添加地图标记
const showMarkets = () => {
const layers = map.value?.getAllLayers();
//判断地图是否有该图层,我是为了后面图层控制,移出之后再添加时避免重复添加使用的
const addLayers = layers?.find(
(item: any) => item?.getProperties().name == "infoList"
);
if (map.value && !addLayers) {
addMarkers(
map.value,
infoList.value,
imgSrc,
{ name: "infoList" },
{ scale: 1 }
);
}
};
添加地图点击事件
let selectMarker: VectorSource<Geometry>;
const markerClick = function () {
setTimeout(() => {
if (map.value) {
map.value.on("click", function (e) {
if (!map.value) return;
// 获取当前点击 如果点击到了marker feature有值
const feature = map.value!.forEachFeatureAtPixel(
e.pixel,
(feature) => feature
);
if (!feature || !feature.get("features")) {
//点击地图无图标处,图标恢复默认样式
selectMarker?.clear();
} else {
let info: any = ref([]);
info.value.push(feature.get("features")[0].values_);
selectMarker?.clear();
selectMarker = addMarkers(
map.value,
info.value,
imgSrc2,
{ name: "peopleList" },
{ scale: 0.15 }
);
//将点击的图标 坐标作为中心点
const { lng, lat } = info.value[0];
const lag = map.value.getView().animate({
center: [lng, lat],
});
}
});
}
}, 100);
};
效果图
创建地图,添加标记点
点击图标,中心点改变
点击地图空白或点击另一个图标,第一次点击的图标 样式恢复初始值
完整代码
map.vue
<template>
<div ref="mapContainer" class="mapContainer"></div>
</template>
<script lang="ts" setup>
import { ref } from "vue";
import { computed, onMounted, shallowRef } from "vue";
import { createMap, setLayer, addMarkers } from "./map";
import type { Map as olMapType } from "ol";
import { ScaleLine } from "ol/control";
import VectorSource from "ol/source/Vector";
import Geometry from "ol/geom/Geometry";
onMounted(function () {
initMap();
showMarkets();
markerClick();
});
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",
})
);
};
const imgSrc = "https://unpkg.com/leaflet@1.7.1/dist/images/marker-icon.png";
const imgSrc2 =
"https://img0.baidu.com/it/u=1011815455,1718073395&fm=253&fmt=auto&app=138&f=PNG?w=256&h=256";
//坐标点
const infoList = ref([
{
lng: "115.428784",
lat: "23.088291",
},
{
lng: "115.428784",
lat: "24.088291",
},
]);
//添加地图标记
const showMarkets = () => {
const layers = map.value?.getAllLayers();
//判断地图是否有该图层,我是为了后面图层控制,移出之后再添加时避免重复添加使用的
const addLayers = layers?.find(
(item: any) => item?.getProperties().name == "infoList"
);
if (map.value && !addLayers) {
addMarkers(
map.value,
infoList.value,
imgSrc,
{ name: "infoList" },
{ scale: 1 }
);
}
};
let selectMarker: VectorSource<Geometry>;
const markerClick = function () {
setTimeout(() => {
if (map.value) {
map.value.on("click", function (e) {
if (!map.value) return;
// 获取当前点击 如果点击到了marker feature有值
const feature = map.value!.forEachFeatureAtPixel(
e.pixel,
(feature) => feature
);
if (!feature || !feature.get("features")) {
//点击地图无图标处,图标恢复默认样式
selectMarker?.clear();
} else {
let info: any = ref([]);
info.value.push(feature.get("features")[0].values_);
selectMarker?.clear();
selectMarker = addMarkers(
map.value,
info.value,
imgSrc2,
{ name: "peopleList" },
{ scale: 0.15 }
);
//将点击的图标 坐标作为中心点
const { lng, lat } = info.value[0];
const lag = map.value.getView().animate({
center: [lng, lat],
});
}
});
}
}, 100);
};
</script>
<style>
.mapContainer {
width: 100%;
height: 800px;
}
</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";
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";
/**
* @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,
}),
});
};