Uncaught ReferenceError: indicatorStyle is not defined
at updateIndicatorPosition (live-map.vue:85:3)
at initMiniMap (live-map.vue:161:3)
at live-map.vue:276:5 如上所示报错,鹰眼地图还是只有那个株洲影像其他都没有,为全蓝色,修改以下代码:<template>
<div id="cesiumContainer"></div>
<div ref="miniMapContainer" class="mini-map" @click="handleMiniMapClick">
<div class="location-indicator" :style="indicatorStyle"></div>
<!-- 四个角折角 -->
<div class="corner corner-top-left"></div>
<div class="corner corner-top-right"></div>
<div class="corner corner-bottom-left"></div>
<div class="corner corner-bottom-right"></div>
<!-- <div class="camera-icon">📷</div> -->
<div class="focus-effect"></div>
<div class="pulse"></div>
</div>
<Search @location-selected="handleLocationSelected" />
<LocationBar
v-if="loaded"
:update-interval="100"
:use-dms-format="useDmsFormat"
/>
</template>
<style>
/* @import "/temp/css/divGraphic.css"; */
</style>
<script setup lang="ts">
import { computed, onUnmounted, onMounted, reactive } from "vue";
import LocationBar from "./location-bar.vue";
import Search from "./search.vue";
import initMap from "./init";
import { ref } from "vue";
import { throttle } from 'lodash';
import { loadRipplePoints, createMultipleRippleCircles } from './circle.js';
import { $prototype } from "../../main.ts";
const miniMapContainer = ref<HTMLElement>();
let viewIndicator: Rectangle;
// 视图指示器样式
const currentPosition = reactive({
longitude: 113.361538,
latitude: 27.339318,
});
// 株洲市范围常量
const ZHUZHOU_EXTENT = {
west: 112.5, // 株洲市西边界
east: 114.5, // 株洲市东边界
south: 26.0, // 株洲市南边界
north: 28.0 // 株洲市北边界
};
const rippleEntities = ref<any[]>([]); // 存储波纹圆实体
const heightThreshold = 80000; // 高度阈值(米),高于此值隐藏波纹圆
const updateRippleVisibility = throttle(() => {
if (!$prototype.$map || rippleEntities.value.length === 0) return;
// 添加缺失的相机高度计算和显示判断
const cameraHeight = $prototype.$map.camera.positionCartographic.height;
const shouldShow = cameraHeight > heightThreshold;
rippleEntities.value.forEach(entity => {
entity.show = shouldShow;
});
}, 200);
// 更新指示器位置
const updateIndicatorPosition = () => {
if (!$prototype.$map) return;
const camera = $prototype.$map.camera;
const rect = camera.computeViewRectangle();
if (!rect) return;
// 计算在株洲市范围内的相对位置
const center = Cesium.Rectangle.center(rect);
const lon = Cesium.Math.toDegrees(center.longitude);
const lat = Cesium.Math.toDegrees(center.latitude);
const lonPercent = ((lon - ZHUZHOU_EXTENT.west) /
(ZHUZHOU_EXTENT.east - ZHUZHOU_EXTENT.west)) * 100;
const latPercent = 100 - ((lat - ZHUZHOU_EXTENT.south) /
(ZHUZHOU_EXTENT.north - ZHUZHOU_EXTENT.south)) * 100;
// 更新CSS指示器
indicatorStyle.value = {
left: `${lonPercent}%`,
top: `${latPercent}%`,
display: "block"
};
};
// 更新鹰眼地图 - 只更新指示器位置
const updateOverview = () => {
if (!$prototype.$map || !overviewViewer.value) return;
// 获取主地图的当前视图中心
const rectangle = $prototype.$map.camera.computeViewRectangle();
if (!rectangle) return;
const center = Cesium.Rectangle.center(rectangle);
currentPosition.longitude = Cesium.Math.toDegrees(center.longitude);
currentPosition.latitude = Cesium.Math.toDegrees(center.latitude);
// 更新指示器位置
updateIndicatorPosition();
};
const overviewViewer = ref(null);
// 初始化鹰眼地图 - 使用株洲市影像
const initMiniMap = () => {
Cesium.Ion.defaultAccessToken = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJqdGkiOiIxMDhlNDdmYy03NzFhLTQ1ZTQtOWQ3NS1lZDAzNDc3YjE4NDYiLCJpZCI6MzAxNzQyLCJpYXQiOjE3NDcwNTMyMDN9.eaez8rQxVbPv2LKEU0sMDclPWyHKhh1tR27Vg-_rQSM";
if (!miniMapContainer.value) return;
// 创建株洲市专用影像提供器
const zhuzhouProvider = new Cesium.UrlTemplateImageryProvider({
url: "http://124.232.190.30:9000/proxy/pk1725866655224/map/zzzsyx_18/{z}/{x}/{y}.png",
minimumLevel: 1,
maximumLevel: 17,
crs: "EPSG:3857",
tilingScheme: new Cesium.WebMercatorTilingScheme(), // 修复2:明确使用墨卡托投影
});
// 鹰眼地图初始化 - 使用株洲市影像
overviewViewer.value = new Cesium.Viewer(miniMapContainer.value, {
sceneMode: Cesium.SceneMode.SCENE2D,
baseLayerPicker: false,
homeButton: false,
timeline: false,
navigationHelpButton: false,
animation: false,
scene3DOnly: true,
selectionIndicator: false,
infoBox: false,
imageryProvider: zhuzhouProvider,
// 修复3:移除地形服务,避免蓝色背景
terrainProvider: undefined,
// 修复4:设置正确的投影
mapProjection: new Cesium.WebMercatorProjection(),
});
// 设置固定视野为株洲市范围
overviewViewer.value.camera.setView({
destination: Cesium.Rectangle.fromDegrees(
ZHUZHOU_EXTENT.west,
ZHUZHOU_EXTENT.south,
ZHUZHOU_EXTENT.east,
ZHUZHOU_EXTENT.north
)
});
// 隐藏控件
const toolbar = overviewViewer.value.container.getElementsByClassName("cesium-viewer-toolbar")[0];
if (toolbar) toolbar.style.display = "none";
overviewViewer.value.cesiumWidget.creditContainer.style.display = "none";
// 修复5:初始化视图指示器
initRectangle();
// 修复6:初始更新指示器位置
updateIndicatorPosition();
};
// 初始化视图指示器
function initRectangle() {
// 创建视图指示器(株洲市范围框)
viewIndicator = overviewViewer.value.entities.add({
rectangle: {
coordinates: Cesium.Rectangle.fromDegrees(
ZHUZHOU_EXTENT.west,
ZHUZHOU_EXTENT.south,
ZHUZHOU_EXTENT.east,
ZHUZHOU_EXTENT.north
),
material: Cesium.Color.RED.withAlpha(0.3),
outline: true,
outlineColor: Cesium.Color.RED,
outlineWidth: 2,
},
});
}
const loaded = ref(false);
const useDmsFormat = ref(false);
function addDemoGraphics() {
const chinaBoundary = $prototype.$map.dataSources.add(
Cesium.GeoJsonDataSource.load("/shp_zz.geojson", {
stroke: Cesium.Color.WHITE,
fill: false,
clampToGround: true,
describe: null,
})
);
chinaBoundary.then((dataSource) => {
const entities = dataSource.entities.values;
for (let entity of entities) {
if (entity.polyline) {
entity.polyline.fill = false;
}
}
});
}
function flyToDes() {
const center = Cesium.Cartesian3.fromDegrees(-98.0, 40.0);
$prototype.$map.camera.flyTo({
destination: new Cesium.Cartesian3(
-2432812.6687511606,
5559483.804371395,
2832009.419525571
),
orientation: {
heading: 6.283185307179421,
pitch: -1.0472145569408116,
roll: 6.2831853071795205,
},
complete: function () {},
});
}
// 监听主地图相机变化
const setupCameraListener = () => {
$prototype.$map.camera.changed.addEventListener(updateOverview);
};
// 鹰眼地图点击处理
const handleMiniMapClick = (event: MouseEvent) => {
if (!miniMapContainer.value || !overviewViewer.value) return;
const rect = miniMapContainer.value.getBoundingClientRect();
const x = event.clientX - rect.left;
const y = event.clientY - rect.top;
// 计算在固定范围内的相对位置
const xPercent = (x / rect.width) * 100;
const yPercent = (y / rect.height) * 100;
// 转换为株洲市范围内的经纬度
const lon = ZHUZHOU_EXTENT.west +
(xPercent / 100) * (ZHUZHOU_EXTENT.east - ZHUZHOU_EXTENT.west);
const lat = ZHUZHOU_EXTENT.north -
(yPercent / 100) * (ZHUZHOU_EXTENT.north - ZHUZHOU_EXTENT.south);
// 主地图飞向点击位置
$prototype.$map.camera.flyTo({
destination: Cesium.Cartesian3.fromDegrees(lon, lat, 1000000),
});
};
function addImage() {
var rightImageProvider = new Cesium.UrlTemplateImageryProvider({
name: "影像图",
type: "xyz",
layer: "vec_d",
url: "http://124.232.190.30:9000/proxy/pk1725866655224/map/zzzsyx_18/{z}/{x}/{y}.png",
minimumLevel: 1,
maximumLevel: 17,
crs: "EPSG:3857",
});
$prototype.$map.imageryLayers.addImageryProvider(rightImageProvider);
rightImageProvider.splitDirection = Cesium.SplitDirection.right;
}
onMounted(() => {
initMap();
addImage();
loaded.value = true;
addDemoGraphics();
flyToDes();
// 修复7:确保鹰眼地图完全初始化后再设置相机监听
setTimeout(() => {
initMiniMap();
setupCameraListener();
// 初始更新
updateOverview();
}, 1000);
(async () => {
try {
const ripplePoints = await loadRipplePoints();
rippleEntities.value = createMultipleRippleCircles(
$prototype.$map,
ripplePoints
);
$prototype.$map.camera.changed.addEventListener(updateRippleVisibility);
updateRippleVisibility();
} catch (error) {
console.error('加载波纹圆失败:', error);
}
})();
});
let currentMarker: any = null;
const createMarker = (location: { lng: number; lat: number; name: string }) => {
if (currentMarker) {
$prototype.$map.entities.remove(currentMarker);
}
currentMarker = $prototype.$map.entities.add({
position: Cesium.Cartesian3.fromDegrees(
location.lng,
location.lat,
50
),
point: {
pixelSize: 200,
color: Cesium.Color.RED,
outlineColor: Cesium.Color.WHITE,
outlineWidth: 2,
heightReference: Cesium.HeightReference.RELATIVE_TO_GROUND,
},
label: {
text: location.name,
font: "40px sans-serif",
fillColor: Cesium.Color.WHITE,
outlineColor: Cesium.Color.BLACK,
outlineWidth: 1,
verticalOrigin: Cesium.VerticalOrigin.BOTTOM,
pixelOffset: new Cesium.Cartesian2(0, -20),
heightReference: Cesium.HeightReference.RELATIVE_TO_GROUND,
distanceDisplayCondition: new Cesium.DistanceDisplayCondition(0, 10000),
},
description: `<div style="padding: 10px;">
<h3 style="margin: 0 0 5px 0;">${location.name}</h3>
<p>经度:${location.lng.toFixed(6)}</p>
<p>纬度:${location.lat.toFixed(6)}</p>
</div>`,
});
return currentMarker;
};
const handleLocationSelected = (location: { lng: number; lat: number; name: string; }) => {
if (!$prototype.$map) return;
const destination = Cesium.Cartesian3.fromDegrees(
location.lng,
location.lat,
200
);
$prototype.$map.camera.flyTo({
destination,
orientation: {
heading: Cesium.Math.toRadians(0),
pitch: Cesium.Math.toRadians(-45),
roll: 0,
},
duration: 2,
complete: () => {
createMarker(location);
},
});
};
onUnmounted(() => {
if ($prototype.$map) {
$prototype.$map.destroy();
$prototype.$map = null;
}
if ($prototype.$map) {
$prototype.$map.camera.changed.removeEventListener(updateRippleVisibility);
}
console.log("组件销毁");
});
const emit = defineEmits(["onload", "onclick"]);
const initMars3d = async (option: any) => {
emit("onclick", true);
emit("onload", $prototype.$map);
};
</script>
<style lang="less">
/**cesium 工具按钮栏*/
.cesium-viewer-toolbar {
top: auto !important;
bottom: 35px !important;
left: 12px !important;
right: auto !important;
}
.cesium-toolbar-button img {
height: 100%;
}
.cesium-viewer-toolbar > .cesium-toolbar-button,
.cesium-navigationHelpButton-wrapper,
.cesium-viewer-geocoderContainer {
margin-bottom: 5px;
float: left;
clear: both;
text-align: center;
}
.cesium-button {
background-color: rgba(23, 49, 71, 0.8);
color: #e6e6e6;
fill: #e6e6e6;
box-shadow: 0 1px 4px rgba(0, 0, 0, 0.3);
line-height: 32px;
}
.cesium-button:hover {
background: #3ea6ff;
}
/**cesium 底图切换面板*/
.cesium-baseLayerPicker-dropDown {
bottom: 0;
left: 40px;
max-height: 700px;
margin-bottom: 5px;
background-color: rgba(23, 49, 71, 0.8);
}
/**cesium 帮助面板*/
.cesium-navigation-help {
top: auto;
bottom: 0;
left: 40px;
transform-origin: left bottom;
background: none;
background-color: rgba(23, 49, 71, 0.8);
.cesium-navigation-help-instructions {
background: none;
}
.cesium-navigation-button {
background: none;
}
.cesium-navigation-button-selected,
.cesium-navigation-button-unselected:hover {
background: rgba(0, 138, 255, 0.2);
}
}
/**cesium 二维三维切换*/
.cesium-sceneModePicker-wrapper {
width: auto;
}
.cesium-sceneModePicker-wrapper .cesium-sceneModePicker-dropDown-icon {
float: right;
margin: 0 3px;
}
/**cesium POI查询输入框*/
.cesium-viewer-geocoderContainer .search-results {
left: 0;
right: 40px;
width: auto;
z-index: 9999;
}
.cesium-geocoder-searchButton {
background-color: rgba(23, 49, 71, 0.8);
}
.cesium-viewer-geocoderContainer .cesium-geocoder-input {
background-color: rgba(63, 72, 84, 0.7);
}
.cesium-viewer-geocoderContainer .cesium-geocoder-input:focus {
background-color: rgba(63, 72, 84, 0.9);
}
.cesium-viewer-geocoderContainer .search-results {
background-color: rgba(23, 49, 71, 0.8);
}
/**cesium info信息框*/
.cesium-infoBox {
top: 50px;
background-color: rgba(23, 49, 71, 0.8);
}
.cesium-infoBox-title {
background-color: rgba(23, 49, 71, 0.8);
}
/**cesium 任务栏的FPS信息*/
.cesium-performanceDisplay-defaultContainer {
top: auto;
bottom: 35px;
right: 50px;
}
.cesium-performanceDisplay-ms,
.cesium-performanceDisplay-fps {
color: #fff;
}
/**cesium tileset调试信息面板*/
.cesium-viewer-cesiumInspectorContainer {
top: 10px;
left: 10px;
right: auto;
}
.cesium-cesiumInspector {
background-color: rgba(23, 49, 71, 0.8);
}
/**覆盖mars3d内部控件的颜色等样式*/
.mars3d-compass .mars3d-compass-outer {
fill: rgba(23, 49, 71, 0.8);
}
.mars3d-contextmenu-ul,
.mars3d-sub-menu {
background-color: rgba(23, 49, 71, 0.8);
> li > a:hover,
> li > a:focus,
> li > .active {
background-color: #3ea6ff;
}
> .active > a,
> .active > a:hover,
> .active > a:focus {
background-color: #3ea6ff;
}
}
/* Popup样式*/
.mars3d-popup-color {
color: #ffffff;
}
.mars3d-popup-background {
background: rgba(23, 49, 71, 0.8);
}
.mars3d-popup-content {
margin: 15px;
}
.mars3d-template-content label {
padding-right: 6px;
}
.mars3d-template-titile {
border-bottom: 1px solid #3ea6ff;
}
.mars3d-template-titile a {
font-size: 16px;
}
.mars3d-tooltip {
background: rgba(23, 49, 71, 0.8);
border: 1px solid rgba(23, 49, 71, 0.8);
}
.mars3d-popup-btn-custom {
padding: 3px 10px;
border: 1px solid #209ffd;
background: #209ffd1c;
}
.mars-dialog .mars-dialog__content {
height: 100%;
width: 100%;
overflow: auto;
padding: 5px;
}
.image {
border: solid 2px #fff;
}
.content {
height: 90%;
padding-top: 10px;
overflow-x: auto;
overflow-y: auto;
}
.content-text {
padding: 0 10px;
text-indent: 30px;
font-size: 17px;
}
.details-video {
width: 100%;
height: 760px;
background-color: #000;
}
:where(.css-lt97qq9).ant-space {
display: inline-flex;
}
:where(.css-lt97qq9).ant-space-align-center {
align-items: center;
}
:where(.css-lt97qq9).ant-image .ant-image-mask {
position: absolute;
inset: 0;
display: flex;
align-items: center;
justify-content: center;
color: #fff;
background: rgba(0, 0, 0, 0.5);
cursor: pointer;
opacity: 0;
transition: opacity 0.3s;
}
:where(.css-lt97qq9).ant-image .ant-image-mask .ant-image-mask-info {
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
padding: 0 4px;
}
:where(.css-1t97qq9)[class^="ant-image"] [class^="ant-image"],
:where(.css-1t97qq9)[class*=" ant-image"] [class^="ant-image"],
:where(.css-1t97qq9)[class^="ant-image"] [class*=" ant-image"],
:where(.css-1t97qq9)[class*=" ant-image"] [class*=" ant-image"] {
box-sizing: border-box;
}
:where(.css-lt97qq9).ant-image .ant-image-img {
width: 100%;
height: auto;
vertical-align: middle;
}
</style>
<style scoped>
.mini-map-container {
position: relative;
width: 100%;
height: 100%;
}
.main-viewer {
width: 100%;
height: 100%;
}
.mini-map {
position: absolute;
right: 3vw;
bottom: 6vh;
width: 12vw;
height: 17vh;
border: 2px solid #fff;
box-shadow: 0 0 10px rgba(0, 0, 0, 0.5);
z-index: 999;
cursor: pointer;
overflow: hidden;
}
.location-indicator {
position: absolute;
width: 14px;
height: 14px;
background: #ff3e3e;
border: 2px solid white;
border-radius: 50%;
transform: translate(-50%, -50%);
box-shadow: 0 0 15px rgba(255, 62, 62, 1);
z-index: 100;
}
.view-rectangle {
position: absolute;
border: 2px solid #00f2fe;
z-index: 99;
pointer-events: none;
box-shadow: 0 0 20px rgba(0, 242, 254, 0.7);
}
/* 相机聚焦样式 - 四个角折角 */
.corner {
position: absolute;
width: 25px;
height: 25px;
z-index: 100;
pointer-events: none;
}
.corner::before,
.corner::after {
content: "";
position: absolute;
background: #00f2fe;
box-shadow: 0 0 10px rgba(0, 242, 254, 0.8);
}
.corner-top-left {
top: -2px;
left: -2px;
}
.corner-top-left::before {
top: 0;
left: 0;
width: 15px;
height: 3px;
}
.corner-top-left::after {
top: 0;
left: 0;
width: 3px;
height: 15px;
}
.corner-top-right {
top: -2px;
right: -2px;
}
.corner-top-right::before {
top: 0;
right: 0;
width: 15px;
height: 3px;
}
.corner-top-right::after {
top: 0;
right: 0;
width: 3px;
height: 15px;
}
.corner-bottom-left {
bottom: -2px;
left: -2px;
}
.corner-bottom-left::before {
bottom: 0;
left: 0;
width: 15px;
height: 3px;
}
.corner-bottom-left::after {
bottom: 0;
left: 0;
width: 3px;
height: 15px;
}
.corner-bottom-right {
bottom: -2px;
right: -2px;
}
.corner-bottom-right::before {
bottom: 0;
right: 0;
width: 15px;
height: 3px;
}
.corner-bottom-right::after {
bottom: 0;
right: 0;
width: 3px;
height: 15px;
}
.camera-icon {
position: absolute;
top: 10px;
right: 10px;
color: #00f2fe;
font-size: 24px;
z-index: 100;
text-shadow: 0 0 10px rgba(0, 242, 254, 0.8);
}
.focus-effect {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
pointer-events: none;
z-index: 98;
border: 2px solid rgba(0, 242, 254, 0.2);
border-radius: 5px;
box-shadow: inset 0 0 30px rgba(0, 242, 254, 0.1);
}
.pulse {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
width: 10px;
height: 10px;
border-radius: 50%;
background: rgba(0, 242, 254, 0.7);
box-shadow: 0 0 0 0 rgba(0, 242, 254, 0.7);
animation: pulse 2s infinite;
}
::v-deep.cesium-viewer-toolbar {
display: none;
}
</style>
最新发布