<template>
  <div class="mark-body">
    <div v-if="markStatus" class="mark-body-status">
      {{ markStatus }}
    </div>
    <div ref="dragContainer" class="mark-body-container">
      <div v-if="!store.currentTask" class="mark-body-none">
        <div>
          <img src="@/assets/image-none-task.png" />
          <p>
            {{ store.message }}
          </p>
        </div>
      </div>
      <div
        v-else-if="store.isScanImage"
        :style="{ width: answerPaperScale }"
        :class="[`rotate-board-${rotateBoard}`]"
      >
        <template
          v-for="(item, index) in sliceImagesWithTrackList"
          :key="index"
        >
          <div class="single-image-container">
            <img
              :src="item.url"
              draggable="false"
              @click="(event) => innerMakeTrack(event, item)"
              @contextmenu="showBigImage"
            />
            <MarkDrawTrack
              :trackList="item.trackList"
              :specialTagList="item.tagList"
              :sliceImageWidth="item.sliceImageWidth"
              :sliceImageHeight="item.sliceImageHeight"
              :dx="item.dx"
              :dy="item.dy"
              @deleteSpecialtag="(tag) => deleteSpecialtag(item, tag)"
            />
          </div>
          <hr class="image-seperator" />
        </template>
      </div>
      <div v-else-if="store.isMultiMedia">
        <MultiMediaMarkBody />
      </div>
      <div v-else>未知数据</div>
    </div>
  </div>
</template>

<script setup lang="ts">
import { onMounted, onUnmounted, reactive, watch, watchEffect } from "vue";
import { store } from "@/store/store";
import MarkDrawTrack from "./MarkDrawTrack.vue";
import type { SliceImage } from "@/types";
import { useTimers } from "@/setups/useTimers";
import {
  getDataUrlForSliceConfig,
  getDataUrlForSplitConfig,
  loadImage,
} from "@/utils/utils";
import { dragImage } from "./use/draggable";
import MultiMediaMarkBody from "./MultiMediaMarkBody.vue";
import "viewerjs/dist/viewer.css";
import Viewer from "viewerjs";
import { message } from "ant-design-vue";
import EventBus from "@/plugins/eventBus";
type MakeTrack = (
  event: MouseEvent,
  item: SliceImage,
  maxSliceWidth: number,
  theFinalHeight: number
) => void | (() => void);

const {
  hasMarkResultToRender = false,
  makeTrack = () => console.debug("非评卷界面makeTrack没有意义"),
} = defineProps<{
  hasMarkResultToRender?: boolean;
  makeTrack?: MakeTrack;
}>();

const emit = defineEmits(["error"]);

//#region : 图片拖动。在轨迹模式下，仅当没有选择分数时可用。
const { dragContainer } = dragImage();
//#endregion : 图片拖动

const { addTimeout } = useTimers();

//#region : 缩略图定位
watch(
  () => [store.minimapScrollToX, store.minimapScrollToY],
  () => {
    const container = document.querySelector<HTMLDivElement>(
      ".mark-body-container"
    );
    addTimeout(() => {
      if (
        container &&
        typeof store.minimapScrollToX === "number" &&
        typeof store.minimapScrollToY === "number"
      ) {
        const { scrollWidth, scrollHeight } = container;
        container.scrollTo({
          top: scrollHeight * store.minimapScrollToY,
          left: scrollWidth * store.minimapScrollToX,
          behavior: "smooth",
        });
      }
    }, 10);
  }
);
//#endregion : 缩略图定位

//#region : 快捷键定位
const scrollContainerByKey = (e: KeyboardEvent) => {
  const container = document.querySelector<HTMLDivElement>(
    ".mark-body-container"
  );
  if (!container) {
    return;
  }
  if (e.key === "w") {
    container.scrollBy({ top: -100, behavior: "smooth" });
  } else if (e.key === "s") {
    container.scrollBy({ top: 100, behavior: "smooth" });
  } else if (e.key === "a") {
    container.scrollBy({ left: -100, behavior: "smooth" });
  } else if (e.key === "d") {
    container.scrollBy({ left: 100, behavior: "smooth" });
  }
};
onMounted(() => {
  document.addEventListener("keypress", scrollContainerByKey);
});
onUnmounted(() => {
  document.removeEventListener("keypress", scrollContainerByKey);
});
//#endregion : 快捷键定位

//#region : 计算裁切图和裁切图上的分数轨迹和特殊标记轨迹
let rotateBoard = $ref(0);
let sliceImagesWithTrackList: SliceImage[] = reactive([]);
let maxSliceWidth = 0; // 最大的裁切块宽度，图片容器以此为准
let theFinalHeight = 0; // 最终宽度，用来定位轨迹在第几张图片，不包括image-seperator高度

watch(
  () => sliceImagesWithTrackList,
  () => {
    EventBus.emit("draw-change", sliceImagesWithTrackList);
  },
  { deep: true }
);

async function processSliceConfig() {
  if (!store.currentTask) return;
  let markResult = store.currentTask.markResult;
  if (hasMarkResultToRender) {
    // check if have MarkResult for currentTask
    if (!markResult) return;
  }

  const images = [];
  // 必须要先加载一遍，把“选择整图”的宽高重置后，再算总高度
  // 错误的搞法，张莹坚持要用
  const sliceNum = store.currentTask.sliceUrls.length;
  if (store.currentTask.sliceConfig.some((v) => v.i > sliceNum)) {
    console.warn("裁切图设置的数量小于该学生的总图片数量");
  }
  store.currentTask.sliceConfig = store.currentTask.sliceConfig.filter(
    (v) => v.i <= sliceNum
  );
  for (const sliceConfig of store.currentTask.sliceConfig) {
    const url = store.currentTask.sliceUrls[sliceConfig.i - 1];
    const image = await loadImage(url);
    images[sliceConfig.i] = image;
    const { x, y, w, h } = sliceConfig;
    x < 0 && (sliceConfig.x = 0);
    y < 0 && (sliceConfig.y = 0);
    if (sliceConfig.w === 0 && sliceConfig.h === 0) {
      // 选择整图时，w/h 为0
      sliceConfig.w = image.naturalWidth;
      sliceConfig.h = image.naturalHeight;
    }

    if (x <= 1 && y <= 1 && sliceConfig.w <= 1 && sliceConfig.h <= 1) {
      sliceConfig.x = image.naturalWidth * x;
      sliceConfig.y = image.naturalHeight * y;
      sliceConfig.w = image.naturalWidth * w;
      sliceConfig.h = image.naturalHeight * h;
    }
  }

  theFinalHeight = store.currentTask.sliceConfig
    .map((v) => v.h)
    .reduce((acc, v) => (acc += v));
  maxSliceWidth = Math.max(...store.currentTask.sliceConfig.map((v) => v.w));

  // 用来保存sliceImage在整个图片容器中(不包括image-seperator)的高度范围
  let accumTopHeight = 0;
  let accumBottomHeight = 0;
  const trackLists = hasMarkResultToRender
    ? markResult.trackList
    : store.currentTask.questionList.map((q) => q.trackList).flat();

  const tagLists = hasMarkResultToRender
    ? markResult.specialTagList ?? []
    : store.currentTask.specialTagList ?? [];

  const tempSliceImagesWithTrackList: Array<SliceImage> = [];
  for (const sliceConfig of store.currentTask.sliceConfig) {
    accumBottomHeight += sliceConfig.h;
    const url = store.currentTask.sliceUrls[sliceConfig.i - 1];
    const indexInSliceUrls = sliceConfig.i;
    const image = images[sliceConfig.i];

    const dataUrl = await getDataUrlForSliceConfig(
      image,
      sliceConfig,
      maxSliceWidth,
      url
    );

    const thisImageTrackList = trackLists.filter(
      (t) => t.offsetIndex === indexInSliceUrls
    );

    const thisImageTagList = tagLists.filter(
      (t) => t.offsetIndex === indexInSliceUrls
    );

    const sliceImageRendered = await loadImage(dataUrl);
    tempSliceImagesWithTrackList.push({
      url: dataUrl,
      indexInSliceUrls: sliceConfig.i,
      // 通过positionY来定位是第几张slice的还原，并过滤出相应的track
      trackList: thisImageTrackList.filter(
        (t) =>
          t.positionY >= accumTopHeight / theFinalHeight &&
          t.positionY < accumBottomHeight / theFinalHeight
      ),
      tagList: thisImageTagList.filter(
        (t) =>
          t.positionY >= accumTopHeight / theFinalHeight &&
          t.positionY < accumBottomHeight / theFinalHeight
      ),
      // originalImageWidth: image.naturalWidth,
      // originalImageHeight: image.naturalHeight,
      sliceImageWidth: sliceImageRendered.naturalWidth,
      sliceImageHeight: sliceImageRendered.naturalHeight,
      dx: sliceConfig.x,
      dy: sliceConfig.y,
      accumTopHeight,
      effectiveWidth: sliceConfig.w,
    });
    accumTopHeight = accumBottomHeight;
  }

  // 测试是否所有的track和tag都在待渲染的tempSliceImagesWithTrackList中
  const numOfTrackAndTagInData = trackLists.length + tagLists.length;
  const numOfTrackAndTagInTempSlice = tempSliceImagesWithTrackList
    .map((v) => v.trackList.length + v.tagList.length)
    .reduce((p, c) => p + c);
  if (numOfTrackAndTagInData !== numOfTrackAndTagInTempSlice) {
    console.warn({ tagLists, trackLists, tempSliceImagesWithTrackList });
    void message.warn("渲染轨迹数量与实际数量不一致");
  }

  // console.log("render: ", store.currentTask.secretNumber);
  if (sliceImagesWithTrackList.length === 0) {
    // 初次渲染，不做动画
    sliceImagesWithTrackList.push(...tempSliceImagesWithTrackList);
    // 没抽象好，这里不好做校验
    // const renderedTrackAndTagNumber = sliceImagesWithTrackList.map(s => s.trackList.length + s.tagList.length).reduce((p,c) => p+ c);
    // if(renderedTrackAndTagNumber === thisIma)
  } else {
    rotateBoard = 1;
    setTimeout(() => {
      sliceImagesWithTrackList.splice(0);
      sliceImagesWithTrackList.push(...tempSliceImagesWithTrackList);
      setTimeout(() => {
        rotateBoard = 0;
      }, 300);
    }, 300);
  }
}

async function processSplitConfig() {
  if (!store.currentTask) return;
  let markResult = store.currentTask.markResult;
  if (hasMarkResultToRender) {
    // check if have MarkResult for currentTask
    if (!markResult) return;
  }

  const images = [];
  for (const url of store.currentTask.sliceUrls) {
    const image = await loadImage(url);
    images.push(image);
  }

  // 如果拒绝裁切，则保持整卷
  if (!store.setting.enableSplit) {
    store.setting.splitConfig = [0, 1];
  }
  // 裁切块，可能是一块，两块，三块... [start, width ...] => [0, 0.3] | [0, 0.55, 0.45, 0.55] | [0, 0.35, 0.33, 0.35, 0.66, 0.35]
  // 要转变为 [[0, 0.3]] | [[0, 0.55], [0.45, 0.55]] | [[0, 0.35], [0.33, 0.35], [0.66, 0.35]]
  const splitConfigPairs = store.setting.splitConfig.reduce<[number, number][]>(
    (a, v, index) => {
      // 偶数位组成数组的第一位，奇数位组成数组的第二位
      index % 2 === 0 ? a.push([v, -1]) : (a.at(-1)![1] = v);
      return a;
    },
    []
  );

  // 最大的 splitConfig 的宽度
  const maxSplitConfig = Math.max(
    ...store.setting.splitConfig.filter((v, i) => i % 2)
  );
  maxSliceWidth =
    Math.max(...images.map((v) => v.naturalWidth)) * maxSplitConfig;

  theFinalHeight =
    splitConfigPairs.length *
    images.reduce((acc, v) => (acc += v.naturalHeight), 0);

  // 高度比宽度大的图片不裁切
  const imagesOfBiggerHeight = images.filter(
    (v) => v.naturalHeight > v.naturalWidth
  );
  if (imagesOfBiggerHeight.length > 0) {
    maxSliceWidth = Math.max(
      maxSliceWidth,
      ...imagesOfBiggerHeight.map((v) => v.naturalWidth)
    );
    // 不裁切的图剪切多加的高度
    theFinalHeight -=
      imagesOfBiggerHeight.map((v) => v.naturalHeight).reduce((p, c) => p + c) *
      (splitConfigPairs.length - 1);
  }

  let accumTopHeight = 0;
  let accumBottomHeight = 0;
  const tempSliceImagesWithTrackList: SliceImage[] = [];
  const trackLists = hasMarkResultToRender
    ? markResult.trackList
    : (store.currentTask.questionList || []).map((q) => q.trackList).flat();
  const tagLists = hasMarkResultToRender
    ? markResult.specialTagList ?? []
    : store.currentTask.specialTagList ?? [];
  for (const url of store.currentTask.sliceUrls) {
    for (const config of splitConfigPairs) {
      const indexInSliceUrls = store.currentTask.sliceUrls.indexOf(url) + 1;
      const image = images[indexInSliceUrls - 1];
      let shouldBreak = false;
      let [splitConfigStart, splitConfigEnd] = config;
      if (image.naturalHeight > image.naturalWidth) {
        splitConfigStart = 0;
        splitConfigEnd = 1;
        shouldBreak = true;
      }

      accumBottomHeight += image.naturalHeight;

      const dataUrl = await getDataUrlForSplitConfig(
        image,
        [splitConfigStart, splitConfigEnd],
        maxSliceWidth,
        url
      );

      const thisImageTrackList = trackLists.filter(
        (t) => t.offsetIndex === indexInSliceUrls
      );

      const thisImageTagList = tagLists.filter(
        (t) => t.offsetIndex === indexInSliceUrls
      );
      const sliceImageRendered = await loadImage(dataUrl);
      tempSliceImagesWithTrackList.push({
        url: dataUrl,
        indexInSliceUrls: store.currentTask.sliceUrls.indexOf(url) + 1,
        trackList: thisImageTrackList.filter(
          (t) =>
            t.positionY >= accumTopHeight / theFinalHeight &&
            t.positionY < accumBottomHeight / theFinalHeight
        ),
        tagList: thisImageTagList.filter(
          (t) =>
            t.positionY >= accumTopHeight / theFinalHeight &&
            t.positionY < accumBottomHeight / theFinalHeight
        ),
        // originalImageWidth: image.naturalWidth,
        // originalImageHeight: image.naturalHeight,
        sliceImageWidth: sliceImageRendered.naturalWidth,
        sliceImageHeight: sliceImageRendered.naturalHeight,
        dx: image.naturalWidth * splitConfigStart,
        dy: 0,
        accumTopHeight,
        effectiveWidth: image.naturalWidth * splitConfigEnd,
      });
      accumTopHeight = accumBottomHeight;

      // 如果本图高比宽大，不该裁切，则跳过多次裁切
      if (shouldBreak) {
        break;
      }
    }
  }

  // 测试是否所有的track和tag都在待渲染的tempSliceImagesWithTrackList中
  const numOfTrackAndTagInData = trackLists.length + tagLists.length;
  const numOfTrackAndTagInTempSlice = tempSliceImagesWithTrackList
    .map((v) => v.trackList.length + v.tagList.length)
    .reduce((p, c) => p + c);
  if (numOfTrackAndTagInData !== numOfTrackAndTagInTempSlice) {
    console.warn({ tagLists, trackLists, tempSliceImagesWithTrackList });
    void message.warn("渲染轨迹数量与实际数量不一致");
  }

  rotateBoard = 1;
  addTimeout(() => {
    sliceImagesWithTrackList.splice(0);
    sliceImagesWithTrackList.push(...tempSliceImagesWithTrackList);
    addTimeout(() => {
      rotateBoard = 0;
    }, 300);
  }, 300);
}

const deleteSpecialtag = (item, tag) => {
  const findInd = (tagList, curTag) => {
    return tagList.findIndex(
      (itemTag) =>
        itemTag.tagName === curTag.tagName &&
        itemTag.offsetX === curTag.offsetX &&
        itemTag.offsetY === curTag.offsetY
    );
  };

  const tagIndex = findInd(item.tagList, tag);
  if (tagIndex === -1) return;
  item.tagList.splice(tagIndex, 1);

  const stagIndex = findInd(
    store.currentTaskEnsured.markResult.specialTagList,
    tag
  );
  if (stagIndex === -1) return;
  store.currentTaskEnsured.markResult.specialTagList.splice(tagIndex, 1);
};

// should not render twice at the same time
let renderLock = false;
const renderPaperAndMark = async () => {
  // console.log("renderPagerAndMark=>store.curTask:", store.currentTask);

  if (!store.currentTask) return;
  if (!store.isScanImage) return;
  if (renderLock) {
    console.log("上个任务还未渲染完毕，稍等一秒再尝试渲染");
    await new Promise((res) => setTimeout(res, 1000));
    await renderPaperAndMark();
    return;
  }
  // check if have MarkResult for currentTask
  let markResult = store.currentTask.markResult;
  if (hasMarkResultToRender && !markResult) {
    return;
  }

  renderLock = true;
  try {
    store.globalMask = true;

    const hasSliceConfig = store.currentTask.sliceConfig?.length;

    if (hasSliceConfig) {
      await processSliceConfig();
    } else {
      await processSplitConfig();
    }
    // 研究生考试需要停留在上次阅卷的位置，所以注释掉下面的代码
    // await new Promise((res) => setTimeout(res, 700));
    // const container = <HTMLDivElement>(
    //   document.querySelector(".mark-body-container")
    // );
    // addTimeout(() => {
    //   container?.scrollTo({
    //     top: 0,
    //     left: 0,
    //     behavior: "smooth",
    //   });
    // }, 10);
  } catch (error) {
    sliceImagesWithTrackList.splice(0);
    console.trace("render error ", error);
    // 图片加载出错，自动加载下一个任务
    emit("error");
  } finally {
    renderLock = false;
    store.globalMask = false;
  }
};

// watchEffect(renderPaperAndMark);
// 在阻止渲染的情况下，watchEffect收集不到 store.currentTask 的依赖，会导致本组件不再更新
watch(
  () => store.currentTask,
  () => {
    setTimeout(renderPaperAndMark, 50);
  }
);
//#endregion : 计算裁切图和裁切图上的分数轨迹和特殊标记轨迹

//#region : 放大缩小和之后的滚动
const answerPaperScale = $computed(() => {
  // 放大、缩小不影响页面之前的滚动条定位
  let percentWidth = 0;
  let percentTop = 0;
  const container = document.querySelector(".mark-body-container");
  if (container) {
    const { scrollLeft, scrollTop, scrollWidth, scrollHeight } = container;
    percentWidth = scrollLeft / scrollWidth;
    percentTop = scrollTop / scrollHeight;
  }

  addTimeout(() => {
    if (container) {
      const { scrollWidth, scrollHeight } = container;
      container.scrollTo({
        left: scrollWidth * percentWidth,
        top: scrollHeight * percentTop,
      });
    }
  }, 10);
  const scale = store.setting.uiSetting["answer.paper.scale"];
  return scale * 100 + "%";
});
//#endregion : 放大缩小和之后的滚动

//#region : 显示评分状态和清除轨迹
let markStatus = $ref("");
if (hasMarkResultToRender) {
  watch(
    () => store.currentTask,
    () => {
      markStatus = store.getMarkStatus;
    }
  );

  // 清除分数轨迹
  watchEffect(() => {
    for (const track of store.removeScoreTracks) {
      for (const sliceImage of sliceImagesWithTrackList) {
        sliceImage.trackList = sliceImage.trackList.filter(
          (t) =>
            !(
              t.mainNumber === track.mainNumber &&
              t.subNumber === track.subNumber &&
              t.number === track.number
            )
        );
      }
    }
    // 清除后，删除，否则会影响下次切换
    store.removeScoreTracks.splice(0);
  });

  // 清除特殊标记轨迹
  watchEffect(() => {
    if (!store.currentTask) return;
    for (const sliceImage of sliceImagesWithTrackList) {
      sliceImage.tagList = sliceImage.tagList.filter((t) =>
        store.currentTaskEnsured.markResult?.specialTagList.find(
          (st) =>
            st.offsetIndex === t.offsetIndex &&
            st.offsetX === t.offsetX &&
            st.offsetY === t.offsetY
        )
      );
    }
    if (store.currentTaskEnsured.markResult?.specialTagList.length === 0) {
      for (const sliceImage of sliceImagesWithTrackList) {
        sliceImage.tagList = [];
      }
    }
  });
}
//#endregion : 显示评分状态和清除轨迹

//#region : 评分
const innerMakeTrack = (event: MouseEvent, item: SliceImage) => {
  makeTrack(event, item, maxSliceWidth, theFinalHeight);
};
//#endregion : 评分

//#region : 显示大图，供查看和翻转
const showBigImage = (event: MouseEvent) => {
  event.preventDefault();
  // console.log(event);
  let viewer: Viewer = null as unknown as Viewer;
  viewer && viewer.destroy();
  viewer = new Viewer(event.target as HTMLElement, {
    // inline: true,
    viewed() {
      viewer.zoomTo(1);
    },
    hidden() {
      viewer.destroy();
    },
    zIndex: 1000000,
  });
  viewer.show();
};
//#endregion : 显示大图，供查看和翻转

// onRenderTriggered(({ key, target, type }) => {
//   console.log({ key, target, type });
// });
let topKB = $ref(10);
const topKBStyle = $computed(() => topKB + "%");
let leftKB = $ref(10);
const leftKBStyle = $computed(() => leftKB + "%");
function moveCicle(event: KeyboardEvent) {
  // query mark-body-container and body to calc max/min topKB and max leftKB
  if (event.key === "k") {
    if (topKB > 1) topKB--;
  }
  if (event.key === "j") {
    if (topKB < 99) topKB++;
  }
  if (event.key === "h") {
    if (leftKB > 1) leftKB--;
  }
  if (event.key === "l") {
    if (leftKB < 99) leftKB++;
  }
  if (event.key === "c") {
    topKB = 50;
    leftKB = 50;
  }
}
function giveScoreCicle(event: KeyboardEvent) {
  // console.log(event.key);
  event.preventDefault();
  // console.log(store.currentScore);
  // 接收currentScore间隔时间外才会进入此事件
  if (event.key === " " && typeof store.currentScore === "number") {
    // topKB--;
    const circleElement = document.querySelector(".kb-circle");
    let { top, left } = circleElement.getBoundingClientRect();
    top = top + 45;
    left = left + 45;
    // console.log(top, left);
    // getBoundingClientRect().top left
    // capture => to the specific image
    const me = new MouseEvent("click", {
      bubbles: true,
      cancelable: true,
      view: window,
      clientY: top,
      clientX: left,
    });
    const eles = document.elementsFromPoint(left, top);
    // console.log(eles);
    let ele: Element;
    // if (eles[0].className === "kb-circle") {
    //   if (eles[1].tagName == "IMG") {
    //     ele = eles[1];
    //   }
    // } else
    if (eles[0].tagName == "IMG") {
      ele = eles[0];
    }
    if (ele) {
      ele.dispatchEvent(me);
    }
  }
}
onMounted(() => {
  document.addEventListener("keypress", moveCicle);
  document.addEventListener("keypress", giveScoreCicle);
});
onUnmounted(() => {
  document.removeEventListener("keypress", moveCicle);
  document.removeEventListener("keypress", giveScoreCicle);
});
// setInterval(() => {
//   _topKB++;
//   console.log(topKB);
// }, 1000);

//#region autoScroll自动跳转
let oldFirstScoreContainer: HTMLDivElement | null;
watch(
  () => store.currentTask,
  () => {
    if (store.setting.autoScroll) {
      // 给任务清理和动画留一点时间
      oldFirstScoreContainer =
        document.querySelector<HTMLDivElement>(".score-container");
      oldFirstScoreContainer?.scrollIntoView({ behavior: "smooth" });
      addTimeout(scrollToFirstScore, 1000);
    } else {
      const container = document.querySelector<HTMLDivElement>(
        ".mark-body-container"
      );
      container?.scrollTo({ top: 0, left: 0, behavior: "smooth" });
    }
  }
);
function scrollToFirstScore() {
  if (renderLock) {
    window.requestAnimationFrame(scrollToFirstScore);
  }
  addTimeout(() => {
    const firstScore =
      document.querySelector<HTMLDivElement>(".score-container");
    firstScore?.scrollIntoView({ behavior: "smooth" });
  }, 1000);
}
//#endregion
</script>

<style scoped>
.double-triangle {
  background-color: #ef7c78;
  width: 30px;
  height: 6px;
  clip-path: polygon(0 0, 0 6px, 50% 0, 100% 0, 100% 6px, 50% 0);

  position: absolute;
  bottom: -5px;
}

@keyframes rotate {
  0% {
    transform: rotateY(0deg);
    opacity: 1;
  }
  50% {
    transform: rotateY(90deg);
  }

  100% {
    transform: rotateY(0deg);
    opacity: 0;
  }
}

.kb-circle {
  position: fixed;
  width: 90px;
  height: 90px;
  border: 1px solid #ff5050;
  border-radius: 50%;
  /* margin-left: -45px;
  margin-top: -45px; */
  /* transform: translate(-50%, -50%); */
  /* margin-left: 50%;
  margin-top: 10%; */
  top: v-bind(topKBStyle);
  left: v-bind(leftKBStyle);
  /* c to center circle
  jikl
  斜线移动
  space上分，方便连续给分
  shift加速？
  */
  /*
  getBoundingClientRect().top left
  capture => to the specific image
  new MouseEvent("click", {
    bubbles: true,
    cancelable: true,
    view: window,
    clientX
    clientY
  });
  */
  /* to click through div */
  pointer-events: none;

  /* display: grid; */
}

.kb-circle .text {
  font-size: 2rem;
  color: #ff5050;
  margin-top: 10px;
  display: block;
  text-align: center;
  width: 100%;
  line-height: 90px;
}
</style>
