效果图:
代码实现:
1.通过dataV获取GeoJSON数据
网址:datav.aliyun.com/portal/scho… 通过左侧地图选择范围,在复制右侧JSON AIP地址
// 1.获取geojson数据
// const geojsonDataUrl = "https://geo.datav.aliyun.com/areas_v3/bound/100000_full_city.json" //全国
// const geojsonDataUrl = "https://geo.datav.aliyun.com/areas_v3/bound/440000_full.json" //广州
const geojsonDataUrl = "https://geo.datav.aliyun.com/areas_v3/bound/440300_full.json" //深圳市
2.创建图层并且添加到地图上
// 2.创建矢量数据源
const vectorSource = new VectorSource({
url: geojsonDataUrl,
format: new GeoJSON(),
});
// 创建图层
// 定义矢量图层样式
geoLayer.value = new VectorLayer({
source: vectorSource,// 数据源
style: new Style({
fill: new Fill({
color: 'rgba(0, 0, 255, 0.1)', // 区域填充颜色
}),
stroke: new Stroke({
color: '#319FD3', // 边界线颜色
width: 1, // 边界线宽度
lineDash: [5, 5], // 虚线设置,[实线长度, 空白长度]
}),
}),
});
// 将图层添加到地图上
map.value.addLayer(geoLayer.value);
3.效果
整体代码
/**
* 绘画出行政边界
* 1.通过dataV获取geoJSON数据
*/
// 是否显示geojson数据
const showGeoJSOM = ref(false)
watch(showGeoJSOM, (newVal) => {
if (newVal) {
loadGeoJSON()
} else {
// 清除图层
map.value.removeLayer(geoLayer.value)
}
})
// 创建行政区域边界图层
const geoLayer = ref(null)
function loadGeoJSON() {
// 1.获取geojson数据
// const geojsonDataUrl = "https://geo.datav.aliyun.com/areas_v3/bound/100000_full_city.json" //全国
// const geojsonDataUrl = "https://geo.datav.aliyun.com/areas_v3/bound/440000_full.json" //广州
const geojsonDataUrl = "https://geo.datav.aliyun.com/areas_v3/bound/440300_full.json" //深圳市
// 2.创建矢量数据源
const vectorSource = new VectorSource({
url: geojsonDataUrl,
format: new GeoJSON(),
});
// 创建图层
// 定义矢量图层样式
geoLayer.value = new VectorLayer({
source: vectorSource,// 数据源
style: new Style({
fill: new Fill({
color: 'rgba(0, 0, 255, 0.1)', // 区域填充颜色
}),
stroke: new Stroke({
color: '#319FD3', // 边界线颜色
width: 1, // 边界线宽度
lineDash: [5, 5], // 虚线设置,[实线长度, 空白长度]
}),
}),
});
// 将图层添加到地图上
map.value.addLayer(geoLayer.value);
}
4.高亮选中的区域
1.封装一下高亮与默认的区域样式
// 默认样式
function defaultStyle() {
return new Style({
fill: new Fill({
color: "rgba(0, 0, 255, 0.1)", // 区域填充颜色
}),
stroke: new Stroke({
color: "#319FD3", // 边界线颜色
width: 1, // 边界线宽度
lineDash: [5, 5], // 虚线设置,[实线长度, 空白长度]
}),
});
}
// 凸显样式
function highlightStyle() {
return new Style({
fill: new Fill({
color: "rgba(255, 0, 0, 0.3)", // 区域填充颜色,红色凸显
}),
stroke: new Stroke({
color: "#FF0000", // 边界线颜色
width: 2, // 边界线宽度
}),
});
}
2.侦听地图的点击事件 --在初始化地图的时候添加进去
// 监听地图点击事件
map.value.on("singleclick", watchMapClick);
3.处理事件
// 存储当前选中的区域
const selectedFeature = ref(null);
function watchMapClick(event) {
// 使用 forEachFeatureAtPixel 方法,检查点击的像素位置上是否有对应的 feature(地理对象)
// 该方法会遍历点击像素处的所有 feature,并对每个 feature 执行回调函数
map.value.forEachFeatureAtPixel(event.pixel, function (feature) {
// 如果当前点击的 feature 不等于之前选中的 feature,才进行处理
// selectedFeature.value 用来保存上一次被选中的 feature
if (selectedFeature.value !== feature) {
// 检查之前是否已经有一个选中的 feature
// 如果有,需要将其样式恢复为默认样式(defaultStyle)
if (selectedFeature.value) {
selectedFeature.value.setStyle(defaultStyle); // 恢复上一次选中的 feature 的默认样式
}
// 将当前点击的 feature 的样式设置为高亮样式(highlightStyle)
feature.setStyle(highlightStyle);
// 将当前选中的 feature 赋值给 selectedFeature.value,记录当前的选中状态
selectedFeature.value = feature;
}
// 输出当前点击的 feature 信息到控制台,便于调试和查看具体的 feature 对象
console.log("当前点击的feature", feature);
});
}
完整代码
<template>
<div class="openlayers-map">
<div id="map"></div>
<!-- 工具栏 -->
<div class="but_box">
<button @click="showGeoJSOM = !showGeoJSOM">
{{ showGeoJSOM ? "隐藏" : "显示" }}行政区域
</button>
</div>
</div>
</template>
<script setup name="openlayersMap">
import { ref, onMounted, watch } 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 GeoJSON from "ol/format/GeoJSON";
import { Point } from "ol/geom"; // 引入几何点
import XYZ from "ol/source/XYZ"; // 引入XYZ瓦片源
const key = ref("3f0514d9051775ff8b59cfb08d4bb86f");
/**
* 获取天地图图层
*
* @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}`,
}),
className: layerName, //
});
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 layer2 = await getLayer("vec_w", "vec"); // 影像底图 - 经纬度投影
const layer3 = await getLayer("cva_w", "cva"); // 矢量注记 - 球面墨卡托投影
// 渲染地图视图
map.value = new Map({
target: "map", // 地图将绑定到 HTML 元素 id 为 'map' 的 DOM 元素
layers: [layer2, layer3], // 添加三层异步获取的图层到地图上
view: new View({
center: fromLonLat(mapCenter.value), // 将经纬度转换为地图投影坐标系,设置地图中心点
zoom: mapZoom.value, // 设置初始缩放等级,
maxZoom: 18, // 设置地图最大缩放等级为 18,防止缩放过大 天地图最大就是18再大就不会显示地图
projection: "EPSG:3857", // 地图的投影坐标系,
}),
});
// 给地图添加点击事件
map.value.on("click", clickMap);
// 监听地图点击事件
map.value.on("singleclick", watchMapClick);
// 监听地图的渲染完成事件 整个图层
map.value.once("rendercomplete", () => {
console.log("地图渲染完成");
// 添加滤镜到背景图层
document.querySelector(".vec_w canvas").style.filter =
"brightness(0.88) contrast(1.22) grayscale(0) hue-rotate(380deg) opacity(1) saturate(1.1) sepia(0.94) invert(0.9)";
document.querySelector(".cva_w canvas").style.filter =
"brightness(0.7) contrast(2) grayscale(5) hue-rotate(360deg) opacity(1) saturate(1.8) sepia(0.94) invert(1)";
});
// loadGeoJSON()
}
// 组件挂载完成后初始化地图
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);
}
/**
* 绘画出行政边界
* 1.通过dataV获取geoJSON数据
*/
// 是否显示geojson数据
const showGeoJSOM = ref(false);
watch(showGeoJSOM, (newVal) => {
if (newVal) {
loadGeoJSON();
} else {
map.value.removeLayer(geoLayer.value);
}
});
// 创建行政区域边界图层
const geoLayer = ref(null);
function loadGeoJSON() {
// 1.获取geojson数据
// const geojsonDataUrl = "https://geo.datav.aliyun.com/areas_v3/bound/100000_full_city.json" //全国
// const geojsonDataUrl = "https://geo.datav.aliyun.com/areas_v3/bound/440000_full.json" //广州
const geojsonDataUrl =
"https://geo.datav.aliyun.com/areas_v3/bound/440300_full.json"; //深圳市
// 2.创建矢量数据源
const vectorSource = new VectorSource({
url: geojsonDataUrl,
format: new GeoJSON(),
});
// 创建图层
// 定义矢量图层样式 --默认样式
geoLayer.value = new VectorLayer({
source: vectorSource, // 数据源
style: defaultStyle(),
id: "loadGeoJSON",
});
// 将图层添加到地图上
map.value.addLayer(geoLayer.value);
}
/**
* 侦听地图点击事件
*/
// 默认样式
function defaultStyle() {
return new Style({
fill: new Fill({
color: "rgba(0, 0, 255, 0.1)", // 区域填充颜色
}),
stroke: new Stroke({
color: "#319FD3", // 边界线颜色
width: 1, // 边界线宽度
lineDash: [5, 5], // 虚线设置,[实线长度, 空白长度]
}),
});
}
// 凸显样式
function highlightStyle() {
return new Style({
fill: new Fill({
color: "rgba(255, 0, 0, 0.3)", // 区域填充颜色,红色凸显
}),
stroke: new Stroke({
color: "#FF0000", // 边界线颜色
width: 2, // 边界线宽度
}),
});
}
// 存储当前选中的区域
const selectedFeature = ref(null);
function watchMapClick(event) {
// 使用 forEachFeatureAtPixel 方法,检查点击的像素位置上是否有对应的 feature(地理对象)
// 该方法会遍历点击像素处的所有 feature,并对每个 feature 执行回调函数
map.value.forEachFeatureAtPixel(event.pixel, function (feature) {
// 如果当前点击的 feature 不等于之前选中的 feature,才进行处理
// selectedFeature.value 用来保存上一次被选中的 feature
if (selectedFeature.value !== feature) {
// 检查之前是否已经有一个选中的 feature
// 如果有,需要将其样式恢复为默认样式(defaultStyle)
if (selectedFeature.value) {
selectedFeature.value.setStyle(defaultStyle); // 恢复上一次选中的 feature 的默认样式
}
// 将当前点击的 feature 的样式设置为高亮样式(highlightStyle)
feature.setStyle(highlightStyle);
// 将当前选中的 feature 赋值给 selectedFeature.value,记录当前的选中状态
selectedFeature.value = feature;
}
// 输出当前点击的 feature 信息到控制台,便于调试和查看具体的 feature 对象
console.log("当前点击的feature", feature);
});
}
</script>
<style scoped lang="scss">
.openlayers-map {
width: 100vw;
height: 100vh;
background-color: #191936;
position: relative;
.but_box {
position: absolute;
top: 0;
left: 0;
}
#map {
width: 100%;
height: 100%;
::v-deep {
.ol-overlaycontainer-stopevent {
display: none;
}
}
}
}
</style>