|
@@ -1,251 +1,276 @@
|
|
-<template>
|
|
|
|
- <div
|
|
|
|
- ref="dragContainer"
|
|
|
|
- class="mark-body-container tw-flex-auto tw-p-2 tw-pt-0"
|
|
|
|
- >
|
|
|
|
- <div v-if="!store.currentTask" class="tw-text-center">
|
|
|
|
- {{ store.message }}
|
|
|
|
- </div>
|
|
|
|
- <div v-else :style="{ width: answerPaperScale }" class="tw-pt-2">
|
|
|
|
- <div
|
|
|
|
- v-for="(item, index) in sliceImagesWithTrackList"
|
|
|
|
- :key="index"
|
|
|
|
- class="single-image-container"
|
|
|
|
- :style="{
|
|
|
|
- width: item.width,
|
|
|
|
- }"
|
|
|
|
- >
|
|
|
|
- <img :src="item.url" draggable="false" />
|
|
|
|
- <MarkDrawTrack
|
|
|
|
- :trackList="item.trackList"
|
|
|
|
- :specialTagList="item.tagList"
|
|
|
|
- :sliceImageHeight="item.originalImageHeight"
|
|
|
|
- :sliceImageWidth="item.originalImageWidth"
|
|
|
|
- :dx="0"
|
|
|
|
- :dy="0"
|
|
|
|
- />
|
|
|
|
- <hr class="image-seperator" />
|
|
|
|
- </div>
|
|
|
|
- </div>
|
|
|
|
- <ZoomPaper v-if="store.isScanImage && sliceImagesWithTrackList.length" />
|
|
|
|
- </div>
|
|
|
|
-</template>
|
|
|
|
-
|
|
|
|
-<script setup lang="ts">
|
|
|
|
-import { reactive, watch } from "vue";
|
|
|
|
-import { store } from "@/store/store";
|
|
|
|
-import MarkDrawTrack from "@/features/mark/MarkDrawTrack.vue";
|
|
|
|
-import type { SpecialTag, Track, ColorMap } from "@/types";
|
|
|
|
-import { useTimers } from "@/setups/useTimers";
|
|
|
|
-import { loadImage } from "@/utils/utils";
|
|
|
|
-import { dragImage } from "@/features/mark/use/draggable";
|
|
|
|
-import ZoomPaper from "@/components/ZoomPaper.vue";
|
|
|
|
-
|
|
|
|
-interface SliceImage {
|
|
|
|
- url: string;
|
|
|
|
- trackList: Array<Track | SpecialTag>;
|
|
|
|
- tagList: Array<Track | SpecialTag>;
|
|
|
|
- originalImageWidth: number;
|
|
|
|
- originalImageHeight: number;
|
|
|
|
- width: string; // 图片在整个图片列表里面的宽度比例
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-const { origImageUrls = "sliceUrls" } = defineProps<{
|
|
|
|
- origImageUrls?: "sheetUrls" | "sliceUrls";
|
|
|
|
-}>();
|
|
|
|
-const emit = defineEmits(["error", "getIsMultComments"]);
|
|
|
|
-
|
|
|
|
-const { dragContainer } = dragImage();
|
|
|
|
-
|
|
|
|
-const { addTimeout } = useTimers();
|
|
|
|
-
|
|
|
|
-let sliceImagesWithTrackList: SliceImage[] = reactive([]);
|
|
|
|
-let maxImageWidth = 0;
|
|
|
|
-
|
|
|
|
-function addColorAttr(
|
|
|
|
- tList: (Track | SpecialTag)[],
|
|
|
|
- isTrack?: boolean
|
|
|
|
-): (Track | SpecialTag)[] {
|
|
|
|
- let markerIds: (number | undefined)[] = tList
|
|
|
|
- .map((v) => v.markerId)
|
|
|
|
- .filter((x) => !!x);
|
|
|
|
- markerIds = Array.from(new Set(markerIds));
|
|
|
|
- markerIds.sort();
|
|
|
|
- let colorMap: ColorMap = {};
|
|
|
|
- for (let i = 0; i < markerIds.length; i++) {
|
|
|
|
- const mId: any = markerIds[i];
|
|
|
|
- if (i == 0) {
|
|
|
|
- colorMap[mId + ""] = "red";
|
|
|
|
- } else if (i == 1) {
|
|
|
|
- colorMap[mId + ""] = "blue";
|
|
|
|
- } else if (i > 1) {
|
|
|
|
- colorMap[mId + ""] = "green";
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- if (Object.keys(colorMap).length > 1) {
|
|
|
|
- emit("getIsMultComments", true);
|
|
|
|
- }
|
|
|
|
- tList = tList.map((item: Track | SpecialTag) => {
|
|
|
|
- item.color = colorMap[item.markerId + ""] || "red";
|
|
|
|
- return item;
|
|
|
|
- });
|
|
|
|
- return tList;
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-async function processImage() {
|
|
|
|
- if (!store.currentTask) return;
|
|
|
|
-
|
|
|
|
- const images = [];
|
|
|
|
- const urls = store.currentTask[origImageUrls] || [];
|
|
|
|
- for (const url of urls) {
|
|
|
|
- const image = await loadImage(url);
|
|
|
|
- images.push(image);
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- maxImageWidth = Math.max(...images.map((i) => i.naturalWidth));
|
|
|
|
-
|
|
|
|
- for (const url of urls) {
|
|
|
|
- const indexInSliceUrls = urls.indexOf(url) + 1;
|
|
|
|
- const image = images[indexInSliceUrls - 1];
|
|
|
|
-
|
|
|
|
- const trackLists = (store.currentTask.questionList || [])
|
|
|
|
- // .map((q) => q.trackList)
|
|
|
|
- .map((q) => {
|
|
|
|
- let tList = q.trackList;
|
|
|
|
-
|
|
|
|
- return addColorAttr(tList, true);
|
|
|
|
- })
|
|
|
|
- .flat();
|
|
|
|
- const thisImageTrackList = trackLists.filter(
|
|
|
|
- (t) => t.offsetIndex === indexInSliceUrls
|
|
|
|
- );
|
|
|
|
- const thisImageTagList = addColorAttr(
|
|
|
|
- (store.currentTask.specialTagList || []).filter(
|
|
|
|
- (t) => t.offsetIndex === indexInSliceUrls
|
|
|
|
- )
|
|
|
|
- );
|
|
|
|
-
|
|
|
|
- sliceImagesWithTrackList.push({
|
|
|
|
- url,
|
|
|
|
- trackList: thisImageTrackList,
|
|
|
|
- tagList: thisImageTagList,
|
|
|
|
- originalImageWidth: image.naturalWidth,
|
|
|
|
- originalImageHeight: image.naturalHeight,
|
|
|
|
- width: (image.naturalWidth / maxImageWidth) * 100 + "%",
|
|
|
|
- });
|
|
|
|
- }
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-// should not render twice at the same time
|
|
|
|
-let renderLock = false;
|
|
|
|
-const renderPaperAndMark = async () => {
|
|
|
|
- if (renderLock) {
|
|
|
|
- console.log("上个任务还未渲染完毕,稍等一秒再尝试渲染");
|
|
|
|
- await new Promise((res) => setTimeout(res, 1000));
|
|
|
|
- await renderPaperAndMark();
|
|
|
|
- return;
|
|
|
|
- }
|
|
|
|
- renderLock = true;
|
|
|
|
- sliceImagesWithTrackList.splice(0);
|
|
|
|
-
|
|
|
|
- if (!store.currentTask) {
|
|
|
|
- renderLock = false;
|
|
|
|
- return;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- try {
|
|
|
|
- store.globalMask = true;
|
|
|
|
- await processImage();
|
|
|
|
- } catch (error) {
|
|
|
|
- sliceImagesWithTrackList.splice(0);
|
|
|
|
- console.log("render error ", error);
|
|
|
|
- // 图片加载出错,自动加载下一个任务
|
|
|
|
- emit("error");
|
|
|
|
- } finally {
|
|
|
|
- await new Promise((res) => setTimeout(res, 500));
|
|
|
|
- store.globalMask = false;
|
|
|
|
- renderLock = false;
|
|
|
|
- }
|
|
|
|
-};
|
|
|
|
-
|
|
|
|
-watch(() => store.currentTask, renderPaperAndMark);
|
|
|
|
-
|
|
|
|
-watch(
|
|
|
|
- (): (number | undefined)[] => [
|
|
|
|
- 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);
|
|
|
|
- }
|
|
|
|
-);
|
|
|
|
-
|
|
|
|
-const answerPaperScale = $computed(() => {
|
|
|
|
- // 放大、缩小不影响页面之前的滚动条定位
|
|
|
|
- let percentWidth = 0;
|
|
|
|
- let percentTop = 0;
|
|
|
|
- const container = document.querySelector(
|
|
|
|
- ".mark-body-container"
|
|
|
|
- ) as HTMLDivElement;
|
|
|
|
- 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 + "%";
|
|
|
|
-});
|
|
|
|
-</script>
|
|
|
|
-
|
|
|
|
-<style scoped>
|
|
|
|
-.mark-body-container {
|
|
|
|
- height: calc(100vh - 56px);
|
|
|
|
- overflow: auto;
|
|
|
|
- background-color: var(--app-container-bg-color);
|
|
|
|
- background-image: linear-gradient(45deg, #e0e0e0 25%, transparent 25%),
|
|
|
|
- linear-gradient(-45deg, #e0e0e0 25%, transparent 25%),
|
|
|
|
- linear-gradient(45deg, transparent 75%, #e0e0e0 75%),
|
|
|
|
- linear-gradient(-45deg, transparent 75%, #e0e0e0 75%);
|
|
|
|
- background-size: 20px 20px;
|
|
|
|
- background-position: 0 0, 0 10px, 10px -10px, -10px 0px;
|
|
|
|
- transform: inherit;
|
|
|
|
-
|
|
|
|
- cursor: grab;
|
|
|
|
- user-select: none;
|
|
|
|
-}
|
|
|
|
-.mark-body-container img {
|
|
|
|
- width: 100%;
|
|
|
|
-}
|
|
|
|
-.single-image-container {
|
|
|
|
- position: relative;
|
|
|
|
-}
|
|
|
|
-.image-seperator {
|
|
|
|
- border: 2px solid rgba(120, 120, 120, 0.1);
|
|
|
|
-}
|
|
|
|
-</style>
|
|
|
|
|
|
+<template>
|
|
|
|
+ <div
|
|
|
|
+ ref="dragContainer"
|
|
|
|
+ class="mark-body-container tw-flex-auto tw-p-2 tw-pt-0"
|
|
|
|
+ >
|
|
|
|
+ <div v-if="!store.currentTask" class="tw-text-center">
|
|
|
|
+ {{ store.message }}
|
|
|
|
+ </div>
|
|
|
|
+ <div v-else :style="{ width: answerPaperScale }" class="tw-pt-2">
|
|
|
|
+ <div
|
|
|
|
+ v-for="(item, index) in sliceImagesWithTrackList"
|
|
|
|
+ :key="index"
|
|
|
|
+ class="single-image-container"
|
|
|
|
+ :style="{
|
|
|
|
+ width: item.width,
|
|
|
|
+ }"
|
|
|
|
+ >
|
|
|
|
+ <img :src="item.url" draggable="false" />
|
|
|
|
+ <MarkDrawTrack
|
|
|
|
+ :trackList="item.trackList"
|
|
|
|
+ :specialTagList="item.tagList"
|
|
|
|
+ :sliceImageHeight="item.originalImageHeight"
|
|
|
|
+ :sliceImageWidth="item.originalImageWidth"
|
|
|
|
+ :dx="0"
|
|
|
|
+ :dy="0"
|
|
|
|
+ />
|
|
|
|
+ <hr class="image-seperator" />
|
|
|
|
+ </div>
|
|
|
|
+ </div>
|
|
|
|
+ <ZoomPaper v-if="store.isScanImage && sliceImagesWithTrackList.length" />
|
|
|
|
+ </div>
|
|
|
|
+</template>
|
|
|
|
+
|
|
|
|
+<script setup lang="ts">
|
|
|
|
+import { reactive, watch } from "vue";
|
|
|
|
+import { store } from "@/store/store";
|
|
|
|
+import MarkDrawTrack from "@/features/mark/MarkDrawTrack.vue";
|
|
|
|
+import type { SpecialTag, Track, ColorMap } from "@/types";
|
|
|
|
+import { useTimers } from "@/setups/useTimers";
|
|
|
|
+import { loadImage } from "@/utils/utils";
|
|
|
|
+import { dragImage } from "@/features/mark/use/draggable";
|
|
|
|
+import ZoomPaper from "@/components/ZoomPaper.vue";
|
|
|
|
+
|
|
|
|
+interface SliceImage {
|
|
|
|
+ url: string;
|
|
|
|
+ trackList: Array<Track>;
|
|
|
|
+ tagList: Array<SpecialTag>;
|
|
|
|
+ originalImageWidth: number;
|
|
|
|
+ originalImageHeight: number;
|
|
|
|
+ width: string; // 图片在整个图片列表里面的宽度比例
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+const { origImageUrls = "sliceUrls" } = defineProps<{
|
|
|
|
+ origImageUrls?: "sheetUrls" | "sliceUrls";
|
|
|
|
+}>();
|
|
|
|
+const emit = defineEmits(["error", "getIsMultComments"]);
|
|
|
|
+
|
|
|
|
+const { dragContainer } = dragImage();
|
|
|
|
+
|
|
|
|
+const { addTimeout } = useTimers();
|
|
|
|
+
|
|
|
|
+let sliceImagesWithTrackList: SliceImage[] = reactive([]);
|
|
|
|
+let maxImageWidth = 0;
|
|
|
|
+
|
|
|
|
+function addTrackColorAttr(
|
|
|
|
+ tList: Track[]
|
|
|
|
+): Track[] {
|
|
|
|
+ let markerIds: (number | undefined)[] = tList
|
|
|
|
+ .map((v) => v.markerId)
|
|
|
|
+ .filter((x) => !!x);
|
|
|
|
+ markerIds = Array.from(new Set(markerIds));
|
|
|
|
+ markerIds.sort();
|
|
|
|
+ let colorMap: ColorMap = {};
|
|
|
|
+ for (let i = 0; i < markerIds.length; i++) {
|
|
|
|
+ const mId: any = markerIds[i];
|
|
|
|
+ if (i == 0) {
|
|
|
|
+ colorMap[mId + ""] = "red";
|
|
|
|
+ } else if (i == 1) {
|
|
|
|
+ colorMap[mId + ""] = "blue";
|
|
|
|
+ } else if (i > 1) {
|
|
|
|
+ colorMap[mId + ""] = "green";
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ if (Object.keys(colorMap).length > 1) {
|
|
|
|
+ emit("getIsMultComments", true);
|
|
|
|
+ }
|
|
|
|
+ tList = tList.map((item: Track) => {
|
|
|
|
+ item.color = colorMap[item.markerId + ""] || "red";
|
|
|
|
+ return item;
|
|
|
|
+ });
|
|
|
|
+ return tList;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+function addTagColorAttr(
|
|
|
|
+ tList: SpecialTag[]
|
|
|
|
+): SpecialTag[] {
|
|
|
|
+ let markerIds: (number | undefined)[] = tList
|
|
|
|
+ .map((v) => v.markerId)
|
|
|
|
+ .filter((x) => !!x);
|
|
|
|
+ markerIds = Array.from(new Set(markerIds));
|
|
|
|
+ markerIds.sort();
|
|
|
|
+ let colorMap: ColorMap = {};
|
|
|
|
+ for (let i = 0; i < markerIds.length; i++) {
|
|
|
|
+ const mId: any = markerIds[i];
|
|
|
|
+ if (i == 0) {
|
|
|
|
+ colorMap[mId + ""] = "red";
|
|
|
|
+ } else if (i == 1) {
|
|
|
|
+ colorMap[mId + ""] = "blue";
|
|
|
|
+ } else if (i > 1) {
|
|
|
|
+ colorMap[mId + ""] = "green";
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ tList = tList.map((item: SpecialTag) => {
|
|
|
|
+ item.color = colorMap[item.markerId + ""] || "red";
|
|
|
|
+ return item;
|
|
|
|
+ });
|
|
|
|
+ return tList;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+async function processImage() {
|
|
|
|
+ if (!store.currentTask) return;
|
|
|
|
+
|
|
|
|
+ const images = [];
|
|
|
|
+ const urls = store.currentTask[origImageUrls] || [];
|
|
|
|
+ for (const url of urls) {
|
|
|
|
+ const image = await loadImage(url);
|
|
|
|
+ images.push(image);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ maxImageWidth = Math.max(...images.map((i) => i.naturalWidth));
|
|
|
|
+
|
|
|
|
+ for (const url of urls) {
|
|
|
|
+ const indexInSliceUrls = urls.indexOf(url) + 1;
|
|
|
|
+ const image = images[indexInSliceUrls - 1];
|
|
|
|
+
|
|
|
|
+ const trackLists = (store.currentTask.questionList || [])
|
|
|
|
+ // .map((q) => q.trackList)
|
|
|
|
+ .map((q) => {
|
|
|
|
+ let tList = q.trackList;
|
|
|
|
+
|
|
|
|
+ return addTrackColorAttr(tList);
|
|
|
|
+ })
|
|
|
|
+ .flat();
|
|
|
|
+ const thisImageTrackList = trackLists.filter(
|
|
|
|
+ (t) => t.offsetIndex === indexInSliceUrls
|
|
|
|
+ );
|
|
|
|
+ const thisImageTagList = addTagColorAttr(
|
|
|
|
+ (store.currentTask.specialTagList || []).filter(
|
|
|
|
+ (t) => t.offsetIndex === indexInSliceUrls
|
|
|
|
+ )
|
|
|
|
+ );
|
|
|
|
+
|
|
|
|
+ sliceImagesWithTrackList.push({
|
|
|
|
+ url,
|
|
|
|
+ trackList: thisImageTrackList,
|
|
|
|
+ tagList: thisImageTagList,
|
|
|
|
+ originalImageWidth: image.naturalWidth,
|
|
|
|
+ originalImageHeight: image.naturalHeight,
|
|
|
|
+ width: (image.naturalWidth / maxImageWidth) * 100 + "%",
|
|
|
|
+ });
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+// should not render twice at the same time
|
|
|
|
+let renderLock = false;
|
|
|
|
+const renderPaperAndMark = async () => {
|
|
|
|
+ if (renderLock) {
|
|
|
|
+ console.log("上个任务还未渲染完毕,稍等一秒再尝试渲染");
|
|
|
|
+ await new Promise((res) => setTimeout(res, 1000));
|
|
|
|
+ await renderPaperAndMark();
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
+ renderLock = true;
|
|
|
|
+ sliceImagesWithTrackList.splice(0);
|
|
|
|
+
|
|
|
|
+ if (!store.currentTask) {
|
|
|
|
+ renderLock = false;
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ try {
|
|
|
|
+ store.globalMask = true;
|
|
|
|
+ await processImage();
|
|
|
|
+ } catch (error) {
|
|
|
|
+ sliceImagesWithTrackList.splice(0);
|
|
|
|
+ console.log("render error ", error);
|
|
|
|
+ // 图片加载出错,自动加载下一个任务
|
|
|
|
+ emit("error");
|
|
|
|
+ } finally {
|
|
|
|
+ await new Promise((res) => setTimeout(res, 500));
|
|
|
|
+ store.globalMask = false;
|
|
|
|
+ renderLock = false;
|
|
|
|
+ }
|
|
|
|
+};
|
|
|
|
+
|
|
|
|
+watch(() => store.currentTask, renderPaperAndMark);
|
|
|
|
+
|
|
|
|
+watch(
|
|
|
|
+ (): (number | undefined)[] => [
|
|
|
|
+ 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);
|
|
|
|
+ }
|
|
|
|
+);
|
|
|
|
+
|
|
|
|
+const answerPaperScale = $computed(() => {
|
|
|
|
+ // 放大、缩小不影响页面之前的滚动条定位
|
|
|
|
+ let percentWidth = 0;
|
|
|
|
+ let percentTop = 0;
|
|
|
|
+ const container = document.querySelector(
|
|
|
|
+ ".mark-body-container"
|
|
|
|
+ ) as HTMLDivElement;
|
|
|
|
+ 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 + "%";
|
|
|
|
+});
|
|
|
|
+</script>
|
|
|
|
+
|
|
|
|
+<style scoped>
|
|
|
|
+.mark-body-container {
|
|
|
|
+ height: calc(100vh - 56px);
|
|
|
|
+ overflow: auto;
|
|
|
|
+ background-color: var(--app-container-bg-color);
|
|
|
|
+ background-image: linear-gradient(45deg, #e0e0e0 25%, transparent 25%),
|
|
|
|
+ linear-gradient(-45deg, #e0e0e0 25%, transparent 25%),
|
|
|
|
+ linear-gradient(45deg, transparent 75%, #e0e0e0 75%),
|
|
|
|
+ linear-gradient(-45deg, transparent 75%, #e0e0e0 75%);
|
|
|
|
+ background-size: 20px 20px;
|
|
|
|
+ background-position: 0 0, 0 10px, 10px -10px, -10px 0px;
|
|
|
|
+ transform: inherit;
|
|
|
|
+
|
|
|
|
+ cursor: grab;
|
|
|
|
+ user-select: none;
|
|
|
|
+}
|
|
|
|
+.mark-body-container img {
|
|
|
|
+ width: 100%;
|
|
|
|
+}
|
|
|
|
+.single-image-container {
|
|
|
|
+ position: relative;
|
|
|
|
+}
|
|
|
|
+.image-seperator {
|
|
|
|
+ border: 2px solid rgba(120, 120, 120, 0.1);
|
|
|
|
+}
|
|
|
|
+</style>
|