|
@@ -6,7 +6,7 @@
|
|
:key="index"
|
|
:key="index"
|
|
class="single-image-container"
|
|
class="single-image-container"
|
|
>
|
|
>
|
|
- <img :src="item.url" @click="makeMark" />
|
|
|
|
|
|
+ <img :src="item.url" @click="(event) => makeMark(event, item)" />
|
|
<MarkDrawTrack
|
|
<MarkDrawTrack
|
|
:track-list="item.trackList"
|
|
:track-list="item.trackList"
|
|
:original-image="item.originalImage"
|
|
:original-image="item.originalImage"
|
|
@@ -24,10 +24,10 @@
|
|
|
|
|
|
<script lang="ts">
|
|
<script lang="ts">
|
|
import { computed, defineComponent, reactive, ref, watchEffect } from "vue";
|
|
import { computed, defineComponent, reactive, ref, watchEffect } from "vue";
|
|
-import { store } from "./store";
|
|
|
|
|
|
+import { findCurrentTaskMarkResult, store } from "./store";
|
|
import filters from "@/filters";
|
|
import filters from "@/filters";
|
|
import MarkDrawTrack from "./MarkDrawTrack.vue";
|
|
import MarkDrawTrack from "./MarkDrawTrack.vue";
|
|
-import { Track } from "@/types";
|
|
|
|
|
|
+import { MarkResult, Track } from "@/types";
|
|
|
|
|
|
interface SliceImage {
|
|
interface SliceImage {
|
|
url: string;
|
|
url: string;
|
|
@@ -37,6 +37,7 @@ interface SliceImage {
|
|
sliceImage: HTMLImageElement;
|
|
sliceImage: HTMLImageElement;
|
|
dx: number;
|
|
dx: number;
|
|
dy: number;
|
|
dy: number;
|
|
|
|
+ accumTopHeight: number;
|
|
}
|
|
}
|
|
export default defineComponent({
|
|
export default defineComponent({
|
|
name: "MarkBody",
|
|
name: "MarkBody",
|
|
@@ -44,7 +45,10 @@ export default defineComponent({
|
|
setup(props, context) {
|
|
setup(props, context) {
|
|
const container = ref(null);
|
|
const container = ref(null);
|
|
let sliceImagesWithTrackList: Array<SliceImage> = reactive([]);
|
|
let sliceImagesWithTrackList: Array<SliceImage> = reactive([]);
|
|
- watchEffect(async () => {
|
|
|
|
|
|
+ let maxSliceWidth = 0;
|
|
|
|
+ let theFinalHeight = 0;
|
|
|
|
+
|
|
|
|
+ const renderPaperAndMark = async () => {
|
|
async function loadImage(url: string): Promise<HTMLImageElement> {
|
|
async function loadImage(url: string): Promise<HTMLImageElement> {
|
|
return new Promise((resolve, reject) => {
|
|
return new Promise((resolve, reject) => {
|
|
const image = new Image();
|
|
const image = new Image();
|
|
@@ -56,18 +60,41 @@ export default defineComponent({
|
|
}
|
|
}
|
|
if (!store.currentTask?.libraryId) return;
|
|
if (!store.currentTask?.libraryId) return;
|
|
|
|
|
|
|
|
+ // check if have MarkResult for currentTask
|
|
|
|
+ let markResult = findCurrentTaskMarkResult();
|
|
|
|
+ // console.log("watcheffect markResult 1", markResult, store.markResults);
|
|
|
|
+
|
|
|
|
+ if (!markResult) {
|
|
|
|
+ const { libraryId, studentId } = store.currentTask;
|
|
|
|
+ const statusValue = store.setting.statusValue;
|
|
|
|
+ markResult = {} as MarkResult;
|
|
|
|
+ markResult.libraryId = libraryId;
|
|
|
|
+ markResult.studentId = studentId;
|
|
|
|
+ markResult.statusValue = statusValue;
|
|
|
|
+ markResult.spent = Date.now();
|
|
|
|
+
|
|
|
|
+ markResult.trackList = store.currentTask.questionList.reduce(
|
|
|
|
+ (all, c) => all.concat(c.trackList),
|
|
|
|
+ [] as Array<Track>
|
|
|
|
+ );
|
|
|
|
+ store.markResults = [...store.markResults, markResult];
|
|
|
|
+ // console.log("watcheffect markResult 2", markResult, store.markResults);
|
|
|
|
+ }
|
|
|
|
+ // store.markResults.splice(store.markResults.indexOf(markResult), 1);
|
|
|
|
+ // store.markResults.push(markResult);
|
|
|
|
+ // console.log("watcheffect markResult 3", markResult, store.markResults);
|
|
|
|
+ // const allTrackList = findCurrentTaskMarkResult().trackList;
|
|
|
|
+ // console.log(allTrackList);
|
|
|
|
+ // console.log(store.markResults);
|
|
|
|
+
|
|
// reset sliceImagesWithTrackList
|
|
// reset sliceImagesWithTrackList
|
|
sliceImagesWithTrackList.splice(0);
|
|
sliceImagesWithTrackList.splice(0);
|
|
- const allTrackList = store.currentTask.questionList.reduce(
|
|
|
|
- (all, c) => all.concat(c.trackList),
|
|
|
|
- [] as Array<Track>
|
|
|
|
- );
|
|
|
|
|
|
|
|
if (store.currentTask.sliceConfig?.length) {
|
|
if (store.currentTask.sliceConfig?.length) {
|
|
for (const url of store.currentTask.sliceUrls) {
|
|
for (const url of store.currentTask.sliceUrls) {
|
|
await loadImage(filters.toCompleteUrl(url));
|
|
await loadImage(filters.toCompleteUrl(url));
|
|
}
|
|
}
|
|
- const theFinalheight = store.currentTask.sliceConfig
|
|
|
|
|
|
+ theFinalHeight = store.currentTask.sliceConfig
|
|
.map((v) => v.h)
|
|
.map((v) => v.h)
|
|
.reduce((acc, v) => (acc += v));
|
|
.reduce((acc, v) => (acc += v));
|
|
let accumTopHeight = 0;
|
|
let accumTopHeight = 0;
|
|
@@ -80,7 +107,7 @@ export default defineComponent({
|
|
const image = await loadImage(url);
|
|
const image = await loadImage(url);
|
|
|
|
|
|
const div = (container.value as unknown) as HTMLDivElement;
|
|
const div = (container.value as unknown) as HTMLDivElement;
|
|
- const maxSliceWidth = Math.max(
|
|
|
|
|
|
+ maxSliceWidth = Math.max(
|
|
...store.currentTask.sliceConfig.map((v) => v.w)
|
|
...store.currentTask.sliceConfig.map((v) => v.w)
|
|
);
|
|
);
|
|
|
|
|
|
@@ -103,7 +130,7 @@ export default defineComponent({
|
|
);
|
|
);
|
|
// console.log(image, canvas.height, sliceConfig, ctx);
|
|
// console.log(image, canvas.height, sliceConfig, ctx);
|
|
// console.log(canvas.toDataURL());
|
|
// console.log(canvas.toDataURL());
|
|
- const thisImageTrackList = allTrackList.filter(
|
|
|
|
|
|
+ const thisImageTrackList = markResult.trackList.filter(
|
|
(v) => v.offsetIndex === sliceConfig.i
|
|
(v) => v.offsetIndex === sliceConfig.i
|
|
);
|
|
);
|
|
|
|
|
|
@@ -117,13 +144,14 @@ export default defineComponent({
|
|
// 通过positionY来定位是第几张slice的还原,并过滤出相应的track
|
|
// 通过positionY来定位是第几张slice的还原,并过滤出相应的track
|
|
trackList: thisImageTrackList.filter(
|
|
trackList: thisImageTrackList.filter(
|
|
(t) =>
|
|
(t) =>
|
|
- t.positionY >= accumTopHeight / theFinalheight &&
|
|
|
|
- t.positionY < accumBottomHeight / theFinalheight
|
|
|
|
|
|
+ t.positionY >= accumTopHeight / theFinalHeight &&
|
|
|
|
+ t.positionY < accumBottomHeight / theFinalHeight
|
|
),
|
|
),
|
|
originalImage: image,
|
|
originalImage: image,
|
|
sliceImage,
|
|
sliceImage,
|
|
dx: sliceConfig.x,
|
|
dx: sliceConfig.x,
|
|
dy: sliceConfig.y,
|
|
dy: sliceConfig.y,
|
|
|
|
+ accumTopHeight,
|
|
});
|
|
});
|
|
accumTopHeight = accumBottomHeight;
|
|
accumTopHeight = accumBottomHeight;
|
|
}
|
|
}
|
|
@@ -142,10 +170,10 @@ export default defineComponent({
|
|
.filter((v) => v) as unknown) as Array<[number, number]>;
|
|
.filter((v) => v) as unknown) as Array<[number, number]>;
|
|
|
|
|
|
const maxSplitConfig = Math.max(...store.setting.splitConfig);
|
|
const maxSplitConfig = Math.max(...store.setting.splitConfig);
|
|
- const maxSliceWidth =
|
|
|
|
|
|
+ maxSliceWidth =
|
|
Math.max(...images.map((v) => v.naturalWidth)) * maxSplitConfig;
|
|
Math.max(...images.map((v) => v.naturalWidth)) * maxSplitConfig;
|
|
|
|
|
|
- const theFinalheight =
|
|
|
|
|
|
+ theFinalHeight =
|
|
newConfig.length *
|
|
newConfig.length *
|
|
images.reduce((acc, v) => (acc += v.naturalHeight), 0);
|
|
images.reduce((acc, v) => (acc += v.naturalHeight), 0);
|
|
|
|
|
|
@@ -180,7 +208,7 @@ export default defineComponent({
|
|
// console.log(image, canvas.height, sliceConfig, ctx);
|
|
// console.log(image, canvas.height, sliceConfig, ctx);
|
|
// console.log(canvas.toDataURL());
|
|
// console.log(canvas.toDataURL());
|
|
|
|
|
|
- const thisImageTrackList = allTrackList.filter(
|
|
|
|
|
|
+ const thisImageTrackList = markResult.trackList.filter(
|
|
(t) =>
|
|
(t) =>
|
|
t.offsetIndex === store.currentTask.sliceUrls.indexOf(url) + 1
|
|
t.offsetIndex === store.currentTask.sliceUrls.indexOf(url) + 1
|
|
);
|
|
);
|
|
@@ -190,22 +218,34 @@ export default defineComponent({
|
|
sliceImage.src = dataUrl;
|
|
sliceImage.src = dataUrl;
|
|
sliceImagesWithTrackList.push({
|
|
sliceImagesWithTrackList.push({
|
|
url: canvas.toDataURL(),
|
|
url: canvas.toDataURL(),
|
|
- indexInSliceUrls: store.currentTask.sliceUrls.indexOf(url),
|
|
|
|
|
|
+ indexInSliceUrls: store.currentTask.sliceUrls.indexOf(url) + 1,
|
|
trackList: thisImageTrackList.filter(
|
|
trackList: thisImageTrackList.filter(
|
|
(t) =>
|
|
(t) =>
|
|
- t.positionY >= accumTopHeight / theFinalheight &&
|
|
|
|
- t.positionY < accumBottomHeight / theFinalheight
|
|
|
|
|
|
+ t.positionY >= accumTopHeight / theFinalHeight &&
|
|
|
|
+ t.positionY < accumBottomHeight / theFinalHeight
|
|
),
|
|
),
|
|
originalImage: image,
|
|
originalImage: image,
|
|
sliceImage,
|
|
sliceImage,
|
|
dx: image.naturalWidth * config[0],
|
|
dx: image.naturalWidth * config[0],
|
|
dy: 0,
|
|
dy: 0,
|
|
|
|
+ accumTopHeight,
|
|
});
|
|
});
|
|
accumTopHeight = accumBottomHeight;
|
|
accumTopHeight = accumBottomHeight;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
- });
|
|
|
|
|
|
+ };
|
|
|
|
+
|
|
|
|
+ watchEffect(renderPaperAndMark);
|
|
|
|
+
|
|
|
|
+ // const reRenderPaperAndMark = () => {
|
|
|
|
+ // // const markResult = findCurrentTaskMarkResult();
|
|
|
|
+ // // const thisImageTrackList = markResult.trackList.filter(
|
|
|
|
+ // // (v) => v.offsetIndex === sliceConfig.i
|
|
|
|
+ // // );
|
|
|
|
+ // sliceImagesWithTrackList;
|
|
|
|
+ // };
|
|
|
|
+ // watch(() => store.markResults, reRenderPaperAndMark, { deep: true });
|
|
|
|
|
|
const answerPaperScale = computed(() => {
|
|
const answerPaperScale = computed(() => {
|
|
// 放大、缩小不影响页面之前的滚动条定位
|
|
// 放大、缩小不影响页面之前的滚动条定位
|
|
@@ -240,8 +280,31 @@ export default defineComponent({
|
|
return scale * 100 + "%";
|
|
return scale * 100 + "%";
|
|
});
|
|
});
|
|
|
|
|
|
- const makeMark = (event: Event) => {
|
|
|
|
|
|
+ const makeMark = (event: MouseEvent, item: SliceImage) => {
|
|
console.log(event);
|
|
console.log(event);
|
|
|
|
+ console.log(item);
|
|
|
|
+ const target = event.target as HTMLImageElement;
|
|
|
|
+ const track = {} as Track;
|
|
|
|
+ // TODO: choose question first
|
|
|
|
+ track.mainNumber = 4;
|
|
|
|
+ track.subNumber = "1";
|
|
|
|
+ track.score = 9;
|
|
|
|
+ track.offsetIndex = item.indexInSliceUrls;
|
|
|
|
+ track.offsetX =
|
|
|
|
+ event.offsetX * (target.naturalWidth / target.width) + item.dx;
|
|
|
|
+ track.offsetY =
|
|
|
|
+ event.offsetY * (target.naturalHeight / target.height) + item.dy;
|
|
|
|
+ track.positionX = (track.offsetX - item.dx) / maxSliceWidth;
|
|
|
|
+ track.positionY =
|
|
|
|
+ (track.offsetY - item.dy + item.accumTopHeight) / theFinalHeight;
|
|
|
|
+ // console.log(track);
|
|
|
|
+ const markResult = findCurrentTaskMarkResult();
|
|
|
|
+ // console.log("makemark markresult", markResult);
|
|
|
|
+ if (markResult) {
|
|
|
|
+ markResult.trackList = [...markResult.trackList, track];
|
|
|
|
+ }
|
|
|
|
+ // sliceImagesWithTrackList.find(s => s.indexInSliceUrls === item.indexInSliceUrls)
|
|
|
|
+ item.trackList.push(track);
|
|
};
|
|
};
|
|
return {
|
|
return {
|
|
container,
|
|
container,
|