vue3+openlayers5实现地图的展示与图片渲染拖拽等
·
前言:
vue3+openlayers5实现地图的展示与图片渲染拖拽等,之前写过vue2版本的,这里说下vue3版本的
实现效果:

实现代码:
1、安装插件
pnpm i ol ol-ext
推荐版本
"ol": "^6.15.1",
"ol-ext": "^4.0.36",
2、不同地图瓦片地址
https://wprd0{1-4}.is.autonavi.com/appmaptile?lang=zh_cn&size=1&style=7&x={x}&y={y}&z={z}
https://wprd0{1-4}.is.autonavi.com/appmaptile?lang=zh_cn&size=1&style=8&x={x}&y={y}&z={z}
3、主要代码
<template>
<div id="map" class="map" ref="mapDom"></div>
</template>
<script setup>
import "ol/ol.css";
import View from "ol/View";
import Map from "ol/Map";
import TileLayer from "ol/layer/Tile";
import XYZ from "ol/source/XYZ";
import { Vector as VectorSource } from "ol/source";
import { Feature } from "ol";
import { Vector as VectorLayer } from "ol/layer";
import { Polygon } from "ol/geom";
import ExtTransform from 'ol-ext/interaction/Transform';
import ImageLayer from 'ol/layer/Image';
import Static from 'ol/source/ImageStatic';
import Projection from 'ol/proj/Projection';
import { Style, Fill, Stroke } from "ol/style";
import { ref, onMounted, onUnmounted } from 'vue';
// 使用 ref 定义响应式变量
const map = ref(null);
const switchVal = ref(false);
const center = ref([116.39702518856394, 39.918590567855425]);
const centerSize = ref(11.5);
const projection = ref('EPSG:4326');
const polygon_vectorSource = ref(new VectorSource());
const pointCenter = ref([116.2925480012459, 39.87353495433062]);
const Coordinate_arr = ref([
[116.33272829555995, 39.893308222194946], // 右上
[116.33272829555995, 39.85376168646629], // 右下
[116.25236770693185, 39.85376168646629], // 左下
[116.25236770693185, 39.893308222194946], // 左上
]);
const Pixel_arr = ref([]);
const imgStatic = ref(null);
const mapDom = ref(null); // 修正引用名称
// 初始化地图
const initMap = () => {
if (!mapDom.value) return;
// 渲染地图
const layers = [
new TileLayer({
source: new XYZ({
url: "https://wprd0{1-4}.is.autonavi.com/appmaptile?lang=zh_cn&size=1&style=7&x={x}&y={y}&z={z}",
}),
}),
];
map.value = new Map({
layers: layers,
target: mapDom.value, // 使用 ref 而不是字符串 ID
view: new View({
center: center.value,
projection: projection.value,
zoom: centerSize.value,
maxZoom: 17,
minZoom: 8,
}),
});
map.value.on("moveend", function(evt) {
const zoom = map.value.getView().getZoom();
console.log("zoom = " + zoom);
if (Pixel_arr.value.length > 0 && !switchVal.value) {
let arr = changeGetCoordinateFromPixel(Pixel_arr.value);
let left_lon = arr[2][0];
let bottom_lat = arr[2][1];
let right_lon = arr[0][0];
let top_lat = arr[0][1];
createImg(left_lon, bottom_lat, right_lon, top_lat);
createPolygon();
}
});
// 图片值
setTimeout(() => {
changeGetPixelFromCoordinate(Coordinate_arr.value);
}, 800);
};
// 创建多边形
const createPolygon = () => {
// 清除现有的
polygon_vectorSource.value.clear();
let polygon = new Feature({
geometry: new Polygon([Coordinate_arr.value]),
});
polygon.setStyle(new Style({
fill: new Fill({
color: 'rgba(255, 255, 255, 0.2)'
}),
stroke: new Stroke({
width: 4,
color: [255, 0, 0, 1],
}),
}));
polygon_vectorSource.value.addFeature(polygon);
// 检查是否已经添加了图层,避免重复添加
let vectorLayer = map.value.getLayers().getArray().find(layer =>
layer instanceof VectorLayer && layer.getSource() === polygon_vectorSource.value
);
if (!vectorLayer) {
map.value.addLayer(new VectorLayer({
source: polygon_vectorSource.value,
}));
}
};
// 切换坐标,实际坐标 -> 界面坐标
const changeGetPixelFromCoordinate = (Coordinate_arr) => {
let Pixel_arr = [];
Pixel_arr.push(map.value.getPixelFromCoordinate(Coordinate_arr[0]));
Pixel_arr.push(map.value.getPixelFromCoordinate(Coordinate_arr[1]));
Pixel_arr.push(map.value.getPixelFromCoordinate(Coordinate_arr[2]));
Pixel_arr.push(map.value.getPixelFromCoordinate(Coordinate_arr[3]));
Pixel_arr.value = Pixel_arr;
return Pixel_arr;
};
// 切换坐标,界面坐标 -> 实际坐标
const changeGetCoordinateFromPixel = (Pixel_arr) => {
let Coordinate_arr = [];
Coordinate_arr.push(map.value.getCoordinateFromPixel(Pixel_arr[0]));
Coordinate_arr.push(map.value.getCoordinateFromPixel(Pixel_arr[1]));
Coordinate_arr.push(map.value.getCoordinateFromPixel(Pixel_arr[2]));
Coordinate_arr.push(map.value.getCoordinateFromPixel(Pixel_arr[3]));
Coordinate_arr.value = Coordinate_arr;
return Coordinate_arr;
};
// 创建图片图层
const createImg = (left_lon, bottom_lat, right_lon, top_lat, arr) => {
if (!left_lon || !bottom_lat || !right_lon || !top_lat) {
return;
}
if (arr) {
let Coordinate_arr = [];
Coordinate_arr[0] = [arr[0], arr[1]];
Coordinate_arr[1] = [arr[2], arr[3]];
Coordinate_arr[2] = [arr[4], arr[5]];
Coordinate_arr[3] = [arr[6], arr[7]];
let newArr = changeGetPixelFromCoordinate(Coordinate_arr);
console.log(newArr);
}
var extent = [left_lon, bottom_lat, right_lon, top_lat];
console.log('图片范围:', extent);
var customProjection = new Projection({
code: 'xkcd-image',
units: 'degrees', // 使用 degrees 而不是 pixels
extent: extent,
});
// 移除现有图片图层
if (imgStatic.value) {
map.value.removeLayer(imgStatic.value);
imgStatic.value = null;
}
// 创建新的图片图层
imgStatic.value = new ImageLayer({
source: new Static({
url: 'https://imgs.xkcd.com/comics/online_communities.png',
projection: customProjection,
imageExtent: extent,
}),
});
map.value.addLayer(imgStatic.value);
};
// 操作事件
const onEdit = () => {
const transform = new ExtTransform({
enableRotatedTransform: false,
hitTolerance: 2,
translate: true, // 拖拽
stretch: false, // 拉伸
scale: true, // 缩放
rotate: true, // 旋转
translateFeature: false,
noFlip: true,
});
map.value.addInteraction(transform);
// 开始事件
transform.on(['rotatestart', 'translatestart'], function(e) {
console.log('开始变换', e);
});
// 旋转
transform.on('rotating', (e) => {
const angle = ((e.angle * 180 / Math.PI - 180) % 360 + 180).toFixed(2);
console.log("旋转角度: " + angle);
updateImageFromFeature(e.feature);
});
// 移动
transform.on('translating', (e) => {
console.log('移动中');
updateImageFromFeature(e.feature);
});
// 缩放
transform.on('scaling', (e) => {
console.log('缩放中');
updateImageFromFeature(e.feature);
});
// 事件结束
transform.on(['rotateend', 'translateend', 'scaleend'], (e) => {
console.log('变换结束', e);
pointCenter.value = e.target.center_;
createImg();
});
};
// 从要素更新图片(提取公共逻辑)
const updateImageFromFeature = (feature) => {
const geometry = feature.getGeometry();
if (geometry instanceof Polygon) {
const coordinates = geometry.getCoordinates()[0]; // 获取多边形坐标
const extent = calculateExtentFromPolygon(coordinates);
createImg(extent[0], extent[1], extent[2], extent[3], coordinates.flat());
}
};
// 从多边形坐标计算范围
const calculateExtentFromPolygon = (coordinates) => {
let minX = Infinity, minY = Infinity, maxX = -Infinity, maxY = -Infinity;
coordinates.forEach(coord => {
minX = Math.min(minX, coord[0]);
minY = Math.min(minY, coord[1]);
maxX = Math.max(maxX, coord[0]);
maxY = Math.max(maxY, coord[1]);
});
return [minX, minY, maxX, maxY];
};
// 清理资源
const cleanup = () => {
if (map.value) {
map.value.setTarget(null);
map.value = null;
}
};
onMounted(() => {
initMap();
createPolygon();
let left_lon = 116.25236770693185;
let bottom_lat = 39.85376168646629;
let right_lon = 116.33272829555995;
let top_lat = 39.893308222194946;
createImg(left_lon, bottom_lat, right_lon, top_lat);
onEdit();
});
onUnmounted(() => {
cleanup();
});
</script>
<style scoped lang="scss">
.map {
width: 100%;
height: 400px;
border: 1px solid #ccc;
}
</style>
更多推荐



所有评论(0)