带接口api
This commit is contained in:
parent
b48a792744
commit
6402fbb3ef
BIN
src/assets/images/layer.png
Normal file
BIN
src/assets/images/layer.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 6.3 KiB |
@ -8,6 +8,8 @@
|
|||||||
<OpenLayersZoomControl
|
<OpenLayersZoomControl
|
||||||
:map="map"
|
:map="map"
|
||||||
:resetView="resetView"
|
:resetView="resetView"
|
||||||
|
:routeLayerVisible="routeLayerVisible"
|
||||||
|
@layerToggle="toggleRouteLayer"
|
||||||
@compass="compass"
|
@compass="compass"
|
||||||
@zoomIn="zoomIn"
|
@zoomIn="zoomIn"
|
||||||
@zoomOut="zoomOut"
|
@zoomOut="zoomOut"
|
||||||
@ -29,7 +31,7 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { ref, onMounted, onUnmounted } from "vue";
|
import { ref, onMounted, onUnmounted, watch } from "vue";
|
||||||
import Map from "ol/Map";
|
import Map from "ol/Map";
|
||||||
import View from "ol/View";
|
import View from "ol/View";
|
||||||
import TileLayer from "ol/layer/Tile";
|
import TileLayer from "ol/layer/Tile";
|
||||||
@ -45,6 +47,18 @@ import OpenLayersMapInfo from "./controls/OpenLayersMapInfo.vue";
|
|||||||
import OverviewMap from 'ol/control/OverviewMap';
|
import OverviewMap from 'ol/control/OverviewMap';
|
||||||
import ScaleLine from 'ol/control/ScaleLine';
|
import ScaleLine from 'ol/control/ScaleLine';
|
||||||
import OpenLayersScaleControl from "./controls/OpenLayersScaleControl.vue";
|
import OpenLayersScaleControl from "./controls/OpenLayersScaleControl.vue";
|
||||||
|
import OSM from 'ol/source/OSM';
|
||||||
|
import VectorLayer from 'ol/layer/Vector';
|
||||||
|
import VectorSource from 'ol/source/Vector';
|
||||||
|
import Feature from 'ol/Feature';
|
||||||
|
import Point from 'ol/geom/Point';
|
||||||
|
import LineString from 'ol/geom/LineString';
|
||||||
|
import Polygon from 'ol/geom/Polygon';
|
||||||
|
import Style from 'ol/style/Style';
|
||||||
|
import Icon from 'ol/style/Icon';
|
||||||
|
import Stroke from 'ol/style/Stroke';
|
||||||
|
import Fill from 'ol/style/Fill';
|
||||||
|
import { fromLonLat } from 'ol/proj';
|
||||||
|
|
||||||
// 注册 EPSG:4528 投影
|
// 注册 EPSG:4528 投影
|
||||||
proj4.defs(
|
proj4.defs(
|
||||||
@ -78,6 +92,12 @@ const minZoom = 7; // 最小缩放级别
|
|||||||
const maxZoom = 15; // 最大缩放级别
|
const maxZoom = 15; // 最大缩放级别
|
||||||
const initialZoom = 8; // 设置为7.5,在7和8之间
|
const initialZoom = 8; // 设置为7.5,在7和8之间
|
||||||
|
|
||||||
|
const routeLayerVisible = ref(false); // 默认不显示路线图层
|
||||||
|
|
||||||
|
function toggleRouteLayer() {
|
||||||
|
routeLayerVisible.value = !routeLayerVisible.value;
|
||||||
|
}
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
// 检查是否有保存的默认视图
|
// 检查是否有保存的默认视图
|
||||||
let savedView = null;
|
let savedView = null;
|
||||||
@ -110,6 +130,19 @@ onMounted(() => {
|
|||||||
rotation: savedView ? savedView.rotation : rotation, // 使用保存的旋转角度或默认值
|
rotation: savedView ? savedView.rotation : rotation, // 使用保存的旋转角度或默认值
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// 使用OSM底图
|
||||||
|
const baseLayer = new TileLayer({
|
||||||
|
source: new OSM()
|
||||||
|
});
|
||||||
|
|
||||||
|
// 创建矢量图层
|
||||||
|
const vectorSource = new VectorSource();
|
||||||
|
const vectorLayer = new VectorLayer({
|
||||||
|
source: vectorSource,
|
||||||
|
zIndex: 2,
|
||||||
|
visible: routeLayerVisible.value
|
||||||
|
});
|
||||||
|
|
||||||
// 创建地图,与.ol3页面完全一致
|
// 创建地图,与.ol3页面完全一致
|
||||||
map.value = new Map({
|
map.value = new Map({
|
||||||
target: mapContainer.value,
|
target: mapContainer.value,
|
||||||
@ -124,18 +157,7 @@ onMounted(() => {
|
|||||||
constrainResolution: true,
|
constrainResolution: true,
|
||||||
}),
|
}),
|
||||||
]),
|
]),
|
||||||
layers: [
|
layers: [baseLayer, vectorLayer],
|
||||||
// 使用TileLayer包裹TileSuperMapRest
|
|
||||||
new TileLayer({
|
|
||||||
source: new TileSuperMapRest({
|
|
||||||
url: "http://10.96.3.10:8090/iserver/services/map-QDJC_DT-GX3/rest/maps/QDJC2DZT",
|
|
||||||
projection: "EPSG:4528",
|
|
||||||
tileGrid: tileGrid,
|
|
||||||
wrapX: false,
|
|
||||||
attributions: "", // 空字符串移除属性信息
|
|
||||||
}),
|
|
||||||
}),
|
|
||||||
],
|
|
||||||
view: view,
|
view: view,
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -184,7 +206,73 @@ onMounted(() => {
|
|||||||
}
|
}
|
||||||
}, 500);
|
}, 500);
|
||||||
|
|
||||||
|
// 示例:添加一个点
|
||||||
|
const pointFeature = new Feature({
|
||||||
|
geometry: new Point([13394416, 4136655])
|
||||||
|
});
|
||||||
|
pointFeature.setStyle(new Style({
|
||||||
|
image: new Icon({
|
||||||
|
src: 'https://openlayers.org/en/latest/examples/data/icon.png',
|
||||||
|
scale: 0.7
|
||||||
|
})
|
||||||
|
}));
|
||||||
|
vectorSource.addFeature(pointFeature);
|
||||||
|
|
||||||
|
// 示例:添加一条线
|
||||||
|
const lineFeature = new Feature({
|
||||||
|
geometry: new LineString([
|
||||||
|
[13394416, 4136655],
|
||||||
|
[13395000, 4137000]
|
||||||
|
])
|
||||||
|
});
|
||||||
|
lineFeature.setStyle(new Style({
|
||||||
|
stroke: new Stroke({
|
||||||
|
color: 'blue',
|
||||||
|
width: 2
|
||||||
|
})
|
||||||
|
}));
|
||||||
|
vectorSource.addFeature(lineFeature);
|
||||||
|
|
||||||
|
// 示例:添加一个面
|
||||||
|
const polygonFeature = new Feature({
|
||||||
|
geometry: new Polygon([[
|
||||||
|
[13394416, 4136655],
|
||||||
|
[13395000, 4136655],
|
||||||
|
[13395000, 4137000],
|
||||||
|
[13394416, 4137000],
|
||||||
|
[13394416, 4136655]
|
||||||
|
]])
|
||||||
|
});
|
||||||
|
polygonFeature.setStyle(new Style({
|
||||||
|
stroke: new Stroke({ color: 'red', width: 2 }),
|
||||||
|
fill: new Fill({ color: 'rgba(255,0,0,0.2)' })
|
||||||
|
}));
|
||||||
|
vectorSource.addFeature(polygonFeature);
|
||||||
|
|
||||||
|
// --- 随机生成青岛附近的路线 ---
|
||||||
|
function randomLngLat() {
|
||||||
|
const lng = 120.1 + Math.random() * 0.4;
|
||||||
|
const lat = 35.9 + Math.random() * 0.4;
|
||||||
|
return [lng, lat];
|
||||||
|
}
|
||||||
|
// 生成3条路线,每条5~8个点
|
||||||
|
for (let i = 0; i < 3; i++) {
|
||||||
|
const points = [];
|
||||||
|
const count = 5 + Math.floor(Math.random() * 4);
|
||||||
|
for (let j = 0; j < count; j++) {
|
||||||
|
points.push(fromLonLat(randomLngLat()));
|
||||||
|
}
|
||||||
|
const lineFeature = new Feature({
|
||||||
|
geometry: new LineString(points)
|
||||||
|
});
|
||||||
|
lineFeature.setStyle(new Style({
|
||||||
|
stroke: new Stroke({
|
||||||
|
color: ['red', 'blue', 'green'][i % 3],
|
||||||
|
width: 3
|
||||||
|
})
|
||||||
|
}));
|
||||||
|
vectorSource.addFeature(lineFeature);
|
||||||
|
}
|
||||||
|
|
||||||
// 确保地图完全加载后再次调整视图
|
// 确保地图完全加载后再次调整视图
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
@ -211,6 +299,10 @@ onMounted(() => {
|
|||||||
// 当地图旋转时,不需要额外操作,OpenLayers内部会自动处理拖拽方向
|
// 当地图旋转时,不需要额外操作,OpenLayers内部会自动处理拖拽方向
|
||||||
// 但我们可以在这里做一些自定义处理,比如更新UI等
|
// 但我们可以在这里做一些自定义处理,比如更新UI等
|
||||||
});
|
});
|
||||||
|
|
||||||
|
watch(routeLayerVisible, (val) => {
|
||||||
|
vectorLayer.setVisible(val);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
onUnmounted(() => {
|
onUnmounted(() => {
|
||||||
|
|||||||
@ -39,10 +39,10 @@ function handleMouseMove(event) {
|
|||||||
// 3. 转换为WGS84
|
// 3. 转换为WGS84
|
||||||
try {
|
try {
|
||||||
const [lng, lat] = transform(coordinate, 'EPSG:4528', 'EPSG:4326');
|
const [lng, lat] = transform(coordinate, 'EPSG:4528', 'EPSG:4326');
|
||||||
console.log('WGS84坐标:', lng, lat);
|
//console.log('WGS84坐标:', lng, lat);
|
||||||
wgs84Text.value = `WGS84: 经度=${lng.toFixed(6)}°, 纬度=${lat.toFixed(6)}°`;
|
wgs84Text.value = `WGS84: 经度=${lng.toFixed(6)}°, 纬度=${lat.toFixed(6)}°`;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('坐标转换失败:', error);
|
// console.error('坐标转换失败:', error);
|
||||||
wgs84Text.value = 'WGS84: 转换错误';
|
wgs84Text.value = 'WGS84: 转换错误';
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@ -1,7 +1,25 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="zoom-control">
|
<div class="zoom-control">
|
||||||
<LayerSwitcher class="layer-switcher" :map="map" @layerChange="onLayerChange" ref="layerSwitcherRef" />
|
<el-popover
|
||||||
|
placement="right"
|
||||||
|
width="160"
|
||||||
|
trigger="click"
|
||||||
|
v-model:visible="popoverVisible"
|
||||||
|
popper-class="layer-popover"
|
||||||
|
>
|
||||||
|
<el-checkbox
|
||||||
|
:model-value="props.routeLayerVisible"
|
||||||
|
@change="onLayerToggle"
|
||||||
|
>道路图层</el-checkbox>
|
||||||
|
<template #reference>
|
||||||
|
<div
|
||||||
|
class="layer-toggle"
|
||||||
|
:class="{ active: props.routeLayerVisible }"
|
||||||
|
@click="handleLayerBtnClick"
|
||||||
|
title="图层控制"
|
||||||
|
></div>
|
||||||
|
</template>
|
||||||
|
</el-popover>
|
||||||
<div class="compass" @click="onCompass"></div>
|
<div class="compass" @click="onCompass"></div>
|
||||||
<div class="zoom-in" @click="onZoomIn"></div>
|
<div class="zoom-in" @click="onZoomIn"></div>
|
||||||
<div class="zoom-out" @click="onZoomOut"></div>
|
<div class="zoom-out" @click="onZoomOut"></div>
|
||||||
@ -10,6 +28,7 @@
|
|||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { ref, onMounted } from 'vue';
|
import { ref, onMounted } from 'vue';
|
||||||
|
import { ElPopover, ElCheckbox } from 'element-plus';
|
||||||
// import LayerSwitcher from './LayerSwitcher.vue';
|
// import LayerSwitcher from './LayerSwitcher.vue';
|
||||||
|
|
||||||
// 定义props接受地图实例
|
// 定义props接受地图实例
|
||||||
@ -18,6 +37,10 @@ const props = defineProps({
|
|||||||
resetView: {
|
resetView: {
|
||||||
type: Function,
|
type: Function,
|
||||||
default: null
|
default: null
|
||||||
|
},
|
||||||
|
routeLayerVisible: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -25,7 +48,9 @@ const props = defineProps({
|
|||||||
const layerSwitcherRef = ref(null);
|
const layerSwitcherRef = ref(null);
|
||||||
|
|
||||||
// 向父组件发出事件
|
// 向父组件发出事件
|
||||||
const emit = defineEmits(['compass', 'zoomIn', 'zoomOut', 'layerChange']);
|
const emit = defineEmits(['compass', 'zoomIn', 'zoomOut', 'layerChange', 'layerToggle']);
|
||||||
|
|
||||||
|
const popoverVisible = ref(false);
|
||||||
|
|
||||||
// 指南针/重置视图
|
// 指南针/重置视图
|
||||||
function onCompass() {
|
function onCompass() {
|
||||||
@ -57,6 +82,14 @@ function onLayerChange(layerInfo) {
|
|||||||
emit('layerChange', layerInfo);
|
emit('layerChange', layerInfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function onLayerToggle() {
|
||||||
|
emit('layerToggle');
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleLayerBtnClick() {
|
||||||
|
popoverVisible.value = !popoverVisible.value;
|
||||||
|
}
|
||||||
|
|
||||||
// 导出方法供外部调用
|
// 导出方法供外部调用
|
||||||
defineExpose({
|
defineExpose({
|
||||||
// 设置图层可见性的方法
|
// 设置图层可见性的方法
|
||||||
@ -83,6 +116,22 @@ defineExpose({
|
|||||||
gap: 25px;
|
gap: 25px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.layer-toggle {
|
||||||
|
width: 40px;
|
||||||
|
height: 40px;
|
||||||
|
background: url("../../../assets/images/layer.png") no-repeat;
|
||||||
|
background-size: 100% 100%;
|
||||||
|
cursor: pointer;
|
||||||
|
z-index: 3000;
|
||||||
|
border-radius: 8px;
|
||||||
|
border: 2px solid transparent;
|
||||||
|
box-sizing: border-box;
|
||||||
|
transition: border 0.2s;
|
||||||
|
}
|
||||||
|
.layer-toggle.active {
|
||||||
|
border: 2px solid #409eff;
|
||||||
|
box-shadow: 0 0 8px #409eff44;
|
||||||
|
}
|
||||||
.compass {
|
.compass {
|
||||||
width: 40px;
|
width: 40px;
|
||||||
height: 40px;
|
height: 40px;
|
||||||
@ -91,15 +140,6 @@ defineExpose({
|
|||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
z-index: 3000;
|
z-index: 3000;
|
||||||
}
|
}
|
||||||
.layer-switcher{
|
|
||||||
z-index: 3000;
|
|
||||||
width: 40px;
|
|
||||||
height: 40px;
|
|
||||||
background: url("../../../assets/images/layer.png") no-repeat;
|
|
||||||
background-size: 100% 100%;
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
|
|
||||||
.zoom-in {
|
.zoom-in {
|
||||||
background: url("../../../assets/images/zoomOut.png") no-repeat;
|
background: url("../../../assets/images/zoomOut.png") no-repeat;
|
||||||
background-size: 100% 100%;
|
background-size: 100% 100%;
|
||||||
@ -108,7 +148,6 @@ defineExpose({
|
|||||||
height: 40px;
|
height: 40px;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
.zoom-out {
|
.zoom-out {
|
||||||
background: url("../../../assets/images/zoomIn.png") no-repeat;
|
background: url("../../../assets/images/zoomIn.png") no-repeat;
|
||||||
background-size: 100% 100%;
|
background-size: 100% 100%;
|
||||||
@ -120,7 +159,7 @@ defineExpose({
|
|||||||
|
|
||||||
/* 响应式调整 */
|
/* 响应式调整 */
|
||||||
@media (max-width: 768px) {
|
@media (max-width: 768px) {
|
||||||
.zoom-in, .zoom-out, .compass {
|
.zoom-in, .zoom-out, .compass, .layer-toggle {
|
||||||
width: 28px;
|
width: 28px;
|
||||||
height: 28px;
|
height: 28px;
|
||||||
background-size: 80%;
|
background-size: 80%;
|
||||||
@ -128,4 +167,9 @@ defineExpose({
|
|||||||
background-repeat: no-repeat;
|
background-repeat: no-repeat;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.layer-popover {
|
||||||
|
padding: 12px 16px;
|
||||||
|
min-width: 120px;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="platform-overview">
|
<div class="platform-overview platform-no-padding">
|
||||||
<OpenLayersMap />
|
<OpenLayersMap />
|
||||||
<CarAlarm />
|
<CarAlarm />
|
||||||
<!-- 右侧展开/收起按钮 -->
|
<!-- 右侧展开/收起按钮 -->
|
||||||
@ -15,7 +15,7 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { ref } from 'vue';
|
import { ref, onMounted, onUnmounted } from 'vue';
|
||||||
import OpenLayersMap from '../../components/map/OpenLayersMap.vue';
|
import OpenLayersMap from '../../components/map/OpenLayersMap.vue';
|
||||||
import CarAlarm from '../../components/map/info/carClarm.vue';
|
import CarAlarm from '../../components/map/info/carClarm.vue';
|
||||||
import Eventlist from '../../components/map/info/eventlist.vue';
|
import Eventlist from '../../components/map/info/eventlist.vue';
|
||||||
@ -27,17 +27,24 @@ const showEventList = ref(false);
|
|||||||
function toggleEventList() {
|
function toggleEventList() {
|
||||||
showEventList.value = !showEventList.value;
|
showEventList.value = !showEventList.value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
document.querySelector('.app-main')?.classList.add('platform-no-padding');
|
||||||
|
});
|
||||||
|
onUnmounted(() => {
|
||||||
|
document.querySelector('.app-main')?.classList.remove('platform-no-padding');
|
||||||
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped lang="scss">
|
||||||
.platform-overview {
|
.platform-overview {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height:calc(100vh - 60px);
|
||||||
position: relative;
|
position: relative;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
min-height: 0;
|
z-index:1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 右侧展开/收起按钮样式 */
|
/* 右侧展开/收起按钮样式 */
|
||||||
@ -51,4 +58,17 @@ function toggleEventList() {
|
|||||||
transform: translateY(-50%);
|
transform: translateY(-50%);
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
</style>
|
|
||||||
|
/* 只影响本页,精准去除AppMain的左右padding */
|
||||||
|
:deep(.platform-no-padding) .app-main {
|
||||||
|
padding-left: 0 !important;
|
||||||
|
padding-right: 0 !important;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.app-main.platform-no-padding {
|
||||||
|
padding-left: 0 !important;
|
||||||
|
padding-right: 0 !important;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@ -31,7 +31,7 @@ export default defineConfig(({ mode, command }) => {
|
|||||||
proxy: {
|
proxy: {
|
||||||
// https://cn.vitejs.dev/config/#server-proxy
|
// https://cn.vitejs.dev/config/#server-proxy
|
||||||
'/dev-api': {
|
'/dev-api': {
|
||||||
target: 'http://10.0.0.17:8099',
|
target: 'http://localhost:8099',
|
||||||
changeOrigin: true,
|
changeOrigin: true,
|
||||||
rewrite: (p) => p.replace(/^\/dev-api/, '')
|
rewrite: (p) => p.replace(/^\/dev-api/, '')
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user