airport-qingdao-vue3/src/components/map/controls/OpenLayersZoomControl.vue
2025-07-08 10:50:41 +08:00

353 lines
7.5 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<div class="zoom-control">
<LayerSwitcher
class="layer-switcher"
:map="map"
@layerChange="onLayerChange"
ref="layerSwitcherRef"
/>
<div
class="compass-container"
:style="{ transform: `rotate(${-rotation}deg)` }"
>
<div class="rotate-left" @click="rotateLeft" title="向右旋转90°"></div>
<div class="rotate-right" @click="rotateRight" title="向左旋转90°"></div>
</div>
<div class="zoom-in" @click="onZoomIn"></div>
<div class="zoom-out" @click="onZoomOut"></div>
</div>
</template>
<script setup>
import { ref, onMounted, onUnmounted, watch } from "vue";
import LayerSwitcher from "./LayerSwitcher.vue";
// 导入图片资源
import znzBgImg from "../../../assets/images/znzBg.png";
import needleImg from "../../../assets/images/znz.png";
import leftArrowImg from "../../../assets/images/left_arrow.png";
import rightArrowImg from "../../../assets/images/right_arrow.png";
// 定义props接受地图实例
const props = defineProps({
map: Object, // 地图实例
resetView: {
type: Function,
default: null,
},
});
// 组件引用
const layerSwitcherRef = ref(null);
// 地图旋转角度 (弧度转换为度)
const rotation = ref(0);
// 向父组件发出事件
const emit = defineEmits([
"compass",
"zoomIn",
"zoomOut",
"layerChange",
"rotate",
]);
// 监听地图视图变化,更新旋转角度
function updateRotation() {
if (props.map && props.map.getView()) {
// OpenLayers中旋转角度是弧度转换为度
rotation.value = (props.map.getView().getRotation() * 180) / Math.PI;
}
}
// 重置地图旋转
function resetRotation() {
if (props.map) {
// 重置旋转为0
props.map.getView().animate({
rotation: 0,
duration: 300,
});
emit("rotate", 0);
}
}
// 向左旋转地图(逆时针)
function rotateLeft() {
if (props.map) {
const currentRotation = props.map.getView().getRotation();
const newRotation = currentRotation - Math.PI / 2; // 旋转90度逆时针
props.map.getView().animate({
rotation: newRotation,
duration: 300,
});
emit("rotate", (newRotation * 180) / Math.PI);
}
}
// 向右旋转地图(顺时针)
function rotateRight() {
if (props.map) {
const currentRotation = props.map.getView().getRotation();
const newRotation = currentRotation + Math.PI / 2; // 旋转90度顺时针
props.map.getView().animate({
rotation: newRotation,
duration: 300,
});
emit("rotate", (newRotation * 180) / Math.PI);
}
}
// 指南针/重置视图
function onCompass() {
emit("compass");
if (props.resetView) {
props.resetView();
} else if (props.map) {
// 如果没有提供重置函数,尝试使用地图的初始视图
const initialCenter = props.map.options.center;
const initialZoom = props.map.options.zoom || 7;
props.map.setView(initialCenter, initialZoom, { animate: true });
}
}
// 放大地图
function onZoomIn() {
emit("zoomIn");
if (props.map) {
const currentZoom = props.map.getView().getZoom();
props.map.getView().animate({
zoom: currentZoom + 1,
duration: 250,
});
}
}
// 缩小地图
function onZoomOut() {
emit("zoomOut");
if (props.map) {
const currentZoom = props.map.getView().getZoom();
props.map.getView().animate({
zoom: currentZoom - 1,
duration: 250,
});
}
}
// 图层变化处理
function onLayerChange(layerInfo) {
console.log("ZoomControl收到图层变化:", layerInfo);
// 将图层信息传递给父组件
emit("layerChange", layerInfo);
}
// 监听地图旋转事件
let rotationListener = null;
onMounted(() => {
if (props.map) {
// 初始化旋转角度
updateRotation();
// 添加视图变化监听器
rotationListener = props.map
.getView()
.on("change:rotation", updateRotation);
}
});
onUnmounted(() => {
// 移除监听器
if (rotationListener) {
rotationListener.dispose();
}
});
// 监听地图实例变化
watch(
() => props.map,
(newMap) => {
if (newMap) {
// 初始化旋转角度
updateRotation();
// 移除旧的监听器
if (rotationListener) {
rotationListener.dispose();
}
// 添加新的视图变化监听器
rotationListener = newMap.getView().on("change:rotation", updateRotation);
}
}
);
// 导出方法供外部调用
defineExpose({
// 设置图层可见性的方法
setLayerVisibility(layerName, visible) {
if (layerSwitcherRef.value) {
return layerSwitcherRef.value.setLayerVisibility(layerName, visible);
}
return false;
},
// 重置旋转
resetRotation,
// 获取当前旋转角度
getRotation() {
return rotation.value;
},
});
</script>
<style scoped>
.zoom-control {
position: absolute;
bottom: 250px;
left: 20px;
z-index: 3000;
width: 40px;
height: auto;
display: flex;
flex-direction: column;
justify-content: space-between;
gap: 25px;
}
.compass-container {
position: relative;
width: 40px;
height: 40px;
cursor: pointer;
background: url("../../../assets/images/znzBg.png") no-repeat;
background-size: 100% 100%;
}
.rotation-controls {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
display: flex;
justify-content: space-between;
align-items: center;
z-index: 3002;
}
.rotate-left,
.rotate-right {
width: 24px;
height: 24px;
position: absolute;
top: 50%;
transform: translateY(-50%);
cursor: pointer;
}
.rotate-left {
left: -3px;
background: url("../../../assets/images/left_arrow.png") no-repeat;
background-size: 100% 100%;
z-index: 5000;
}
.rotate-right {
right: -3px;
background: url("../../../assets/images/right_arrow.png") no-repeat;
background-size: 100% 100%;
}
.rotate-left:hover,
.rotate-left:active {
left: -3px;
background: url("../../../assets/images/left_arrow_active.png") no-repeat;
background-size: 100% 100%;
}
.rotate-right:hover,
.rotate-right:active {
right: -3px;
background: url("../../../assets/images/right_arrow_active.png") no-repeat;
background-size: 100% 100%;
}
.layer-switcher {
z-index: 3000;
width: 40px;
height: 40px;
background: url("../../../assets/images/layer.png") no-repeat;
background-size: 100% 100%;
cursor: pointer;
}
.layer-switcher:hover,
.layer-switcher:active {
background: url("../../../assets/images/layerActive.png") no-repeat;
background-size: 100% 100%;
}
.zoom-in {
background: url("../../../assets/images/zoomOut.png") no-repeat;
background-size: 100% 100%;
z-index: 3000;
width: 40px;
height: 40px;
cursor: pointer;
}
.zoom-in:hover,
.zoom-in:active {
background: url("../../../assets/images/zoomOutActive.png") no-repeat;
background-size: 100% 100%;
}
.zoom-out {
background: url("../../../assets/images/zoomIn.png") no-repeat;
background-size: 100% 100%;
z-index: 3000;
width: 40px;
height: 40px;
cursor: pointer;
}
.zoom-out:hover,
.zoom-out:active {
background: url("../../../assets/images/zoomInActive.png") no-repeat;
background-size: 100% 100%;
}
/* 响应式调整 */
@media (max-width: 768px) {
.zoom-in,
.zoom-out,
.compass-container,
.compass-bg,
.compass-needle {
width: 28px;
height: 28px;
}
.zoom-in,
.zoom-out {
background-size: 80%;
background-position: center center;
background-repeat: no-repeat;
}
.rotate-left,
.rotate-right {
width: 18px;
height: 18px;
}
.rotate-left {
left: -18px;
}
.rotate-right {
right: -18px;
}
}
</style>