123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308 |
- <template>
- <div class="map-layout" @click="activeId = null">
- <div
- id="map"
- class="map-container"
- ref="container"
- :class="{ active: !!activeId }"
- @click.stop
- @mousedown="activeId = null"
- @wheel="activeId = null"
- >
- <div class="map-component">
- <el-tooltip
- class="tooltip"
- :visible="!!activeId"
- :content="active?.name"
- effect="light"
- placement="top"
- virtual-triggering
- :virtual-ref="triggerRef"
- />
- <el-select
- v-model="tileType"
- placeholder="选择底图"
- style="width: 120px"
- class="tile-type-select"
- >
- <el-option
- v-for="item in tileOptions"
- :key="item"
- :label="item"
- :value="item"
- />
- </el-select>
- </div>
- </div>
- <div class="right-control">
- <MapRight
- @fly-point="flyScenePoint"
- @fly-scene="flyScene"
- @goto-point="gotoPoint"
- />
- </div>
- </div>
- </template>
- <script setup lang="ts">
- import MapRight from "./map-right.vue";
- import { router, setDocTitle } from "@/router";
- import { TileType, createMap } from "./";
- import { ScenePoint, Scene, scenePoints, scenes } from "@/store/scene";
- import { initRelics, initSelfRelics, relics } from "@/store/relics";
- import { computed, onMounted, ref, watchEffect, watch } from "vue";
- import { Manage } from "./manage";
- import ScaleLine from "ol/control/ScaleLine";
- const activeId = ref<ScenePoint["id"] | null>();
- const active = computed(() =>
- scenePoints.value.find((point) => point.id === activeId.value)
- );
- const activePixel = ref<number[] | null>();
- const triggerRef = ref({
- getBoundingClientRect() {
- return DOMRect.fromRect({
- x: activePixel.value![0],
- y: activePixel.value![1],
- width: 0,
- height: 0,
- });
- },
- });
- const tileOptions: TileType[] = ["影像底图", "矢量底图"];
- const tileType = ref<TileType>(tileOptions[0]);
- const points = computed(() =>
- scenePoints.value
- .filter((point) => point.pos)
- .map((point) => ({
- data: point.pos,
- id: point.id,
- label: point.name,
- }))
- );
- const gotoPoint = (point: ScenePoint) => {
- router.push({
- name: router.currentRoute.value.name === "map" ? "pano" : "query-pano",
- params: { pid: point.id },
- });
- };
- const flyUserCenter = () => {
- navigator.geolocation.getCurrentPosition(
- (pos) => {
- mapManage.setCenter([pos.coords.longitude, pos.coords.latitude]);
- },
- () => console.error("获取中心位置失败"),
- {
- enableHighAccuracy: true,
- timeout: 5000,
- maximumAge: 0,
- }
- );
- };
- const center = [109.47293862712675, 30.26530938156551];
- const container = ref<HTMLDivElement>();
- let mapManage: Manage;
- onMounted(async () => {
- mapManage = createMap(container.value!);
- mapManage.setCenter(center);
- mapManage.hotsBus.on("active", (id) => {
- if (id) {
- activeId.value = id;
- active.value && activeScenePoint(active.value!);
- } else {
- activeId.value = null;
- activePixel.value = null;
- }
- });
- mapManage.hotsBus.on("click", (id) => {
- const point = id && scenePoints.value.find((point) => point.id === id);
- point && gotoPoint(point);
- });
- refreshHots();
- refreshTileType();
- const scaleLine = new ScaleLine({
- className: "scale-view",
- maxWidth: 150,
- minWidth: 100,
- units: "metric",
- });
- // 加载比例尺
- mapManage.map.addControl(scaleLine);
- watch(
- tileType,
- (type) => {
- const el = (scaleLine as any).element as HTMLDivElement;
- el.classList.add(type === "影像底图" ? "light" : "dark");
- el.classList.remove(type === "影像底图" ? "dark" : "light");
- console.log(el, type);
- },
- { flush: "post", immediate: true }
- );
- });
- const activeScenePoint = (point: ScenePoint) => {
- activePixel.value = mapManage.map.getPixelFromCoordinate(point.pos);
- activeId.value = point.id;
- };
- const flyPos = (pos: number[]) => mapManage.map.getView().setCenter(pos);
- const flyScenePoint = (point: ScenePoint) => {
- flyPos(point.pos);
- setTimeout(() => {
- activeScenePoint(point);
- }, 16);
- };
- const flyScene = (scene: Scene) => {
- const totalPos = [0, 0];
- let numCalc = 0;
- for (let i = 0; i < scene.scenePos.length; i++) {
- totalPos[0] += scene.scenePos[i].pos[0];
- totalPos[1] += scene.scenePos[i].pos[1];
- numCalc++;
- }
- totalPos[0] /= numCalc;
- totalPos[1] /= numCalc;
- flyPos(totalPos);
- };
- const refreshHots = () => {
- if (!mapManage) return;
- mapManage.clearHots();
- mapManage.addHots(points.value);
- };
- const refreshTileType = () => {
- if (!mapManage) return;
- mapManage.setTileType(tileType.value);
- };
- watch(points, refreshHots, { immediate: true });
- watch(tileType, refreshTileType, { immediate: true });
- watch(
- () => [router.currentRoute.value.name, router.currentRoute.value.params?.relicsId],
- ([name, rid]) => {
- if (["map", "query-map"].includes(name as string)) {
- relics.value = undefined;
- const fn = name === "map" ? initSelfRelics : initRelics;
- fn(Number(rid)).finally(() => {
- if (!relics.value) {
- router.replace({ name: "relics" });
- }
- const scene = scenes.value.find(
- (scene) => !scene.scenePos.every((pos) => !pos.pos || pos.pos.length === 0)
- );
- if (scene) {
- flyScene(scene);
- } else {
- flyUserCenter();
- }
- });
- }
- },
- { immediate: true }
- );
- watchEffect(() => {
- if (
- ["map", "query-map"].includes(router.currentRoute.value.name as string) &&
- relics.value
- ) {
- setDocTitle(relics.value.name);
- }
- });
- </script>
- <style lang="scss">
- .tooltip {
- pointer-events: none;
- }
- .map-layout {
- display: flex;
- flex-direction: row;
- height: 100%;
- }
- .map-container {
- flex: 1;
- position: relative;
- }
- .right-control {
- flex: none;
- width: 300px;
- padding: 15px;
- border-left: 1px solid var(--border-color);
- }
- .map-component {
- width: 100%;
- height: 100%;
- position: relative;
- }
- .active {
- cursor: pointer;
- }
- .active-point {
- position: absolute;
- pointer-events: none;
- }
- .map-component {
- pointer-events: none;
- position: absolute;
- width: 100%;
- height: 100%;
- left: 0;
- top: 0;
- z-index: 9;
- }
- .env {
- width: 100%;
- height: 100%;
- }
- .tile-type-select {
- pointer-events: all;
- position: absolute;
- right: 10px;
- top: 10px;
- }
- .scale-view {
- --color: #fff;
- position: absolute;
- left: 20px;
- bottom: 20px;
- height: 8px;
- color: var(--color);
- text-align: center;
- border: 1px solid var(--color);
- border-top: none;
- z-index: 1;
- font-size: 14px;
- display: flex;
- align-items: end;
- &.light {
- --color: #fff;
- > div {
- text-shadow: 0 0 2px #000;
- }
- }
- &.dark {
- --color: #000;
- > div {
- text-shadow: 0 0 2px #fff;
- }
- }
- }
- </style>
|