<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, Manage } from "./openlayer";
import { ScenePoint, Scene, scenePoints, scenes } from "@/store/scene";
import { initRelics, initSelfRelics, relics } from "@/store/relics";
import { computed, onMounted, ref, watchEffect, watch, onUnmounted } from "vue";
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 = () => {
  mapManage.setCenter([116.412611, 39.908866]);
  navigator.geolocation.getCurrentPosition(
    (pos) => {
      console.log("获取中心位置成功", pos);
      mapManage.setCenter([pos.coords.longitude, pos.coords.latitude]);
    },
    (e) => {
      console.error(e);
      console.error("获取中心位置失败");
    },
    {
      enableHighAccuracy: false,
      timeout: 50000,
      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++) {
    const coord = scene.scenePos[i].pos as number[];
    if (coord && coord.length > 0) {
      totalPos[0] += coord[0];
      totalPos[1] += coord[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], old) => {
    if (["map", "query-map"].includes(name as string) && (!old || old[1] !== rid)) {
      relics.value = undefined;
      const fn = name === "map" ? initSelfRelics : initRelics;
      fn(Number(rid)).finally(() => {
        if (!relics.value) {
          router.replace({ name: "relics" });
        }
        if (!autoInitPos()) {
          flyUserCenter();
        }
      });
    }
  },
  { immediate: true }
);

const autoInitPos = () => {
  const scene = scenes.value.find(
    (scene) => !scene.scenePos.every((pos) => !pos.pos || pos.pos.length === 0)
  );
  if (scene) {
    flyScene(scene);
    return true;
  } else {
    return false;
  }
};

watch(
  () => {
    const scene = scenes.value.find(
      (scene) => !scene.scenePos.every((pos) => !pos.pos || pos.pos.length === 0)
    );
    return scene?.sceneCode;
  },
  (firstCode) => {
    if (firstCode) {
      autoInitPos();
    }
  }
);

watchEffect(() => {
  if (
    ["map", "query-map"].includes(router.currentRoute.value.name as string) &&
    relics.value
  ) {
    setDocTitle(relics.value.name);
  }
});

onUnmounted(() => mapManage.map.dispose());
</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: 320px;
  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>
./openlayer./openlayer/manage
