|
@@ -0,0 +1,289 @@
|
|
|
+<template>
|
|
|
+ <div class="scaleplate">
|
|
|
+ <!-- 显示/隐藏参考线 -->
|
|
|
+ <div class="refer-line-img" @click="showReferLine = !showReferLine">
|
|
|
+ <EyeFilled v-if="showReferLine" />
|
|
|
+ <EyeInvisibleFilled v-else />
|
|
|
+ </div>
|
|
|
+ <!-- 标尺 -->
|
|
|
+ <div
|
|
|
+ class="scaleplate-horizontal"
|
|
|
+ ref="horizontalRef"
|
|
|
+ @mousemove="handleMouseMoveHScaleplate($event, 'horizontal')"
|
|
|
+ @mouseenter="virtualReferLine.type = 'horizontal'"
|
|
|
+ @mouseleave="virtualReferLine.type = null"
|
|
|
+ @click="handleAddReferLine"
|
|
|
+ >
|
|
|
+ <canvas
|
|
|
+ id="scaleplateHorizontal"
|
|
|
+ :style="{ width: windowSize.width + 'px', height: '20px' }"
|
|
|
+ />
|
|
|
+ </div>
|
|
|
+ <div
|
|
|
+ class="scaleplate-vertical"
|
|
|
+ ref="verticalRef"
|
|
|
+ @mousemove="handleMouseMoveHScaleplate($event, 'vertical')"
|
|
|
+ @mouseenter="virtualReferLine.type = 'vertical'"
|
|
|
+ @mouseleave="virtualReferLine.type = null"
|
|
|
+ @click="handleAddReferLine"
|
|
|
+ >
|
|
|
+ <canvas
|
|
|
+ id="scaleplateVertical"
|
|
|
+ :style="{ width: '20px', height: windowSize.height + 'px' }"
|
|
|
+ />
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <!-- 参考线 -->
|
|
|
+ <div
|
|
|
+ class="refer-line"
|
|
|
+ v-for="item in stageStore.getReferLines"
|
|
|
+ v-show="showReferLine"
|
|
|
+ :key="item.key"
|
|
|
+ :style="{left: item.x + 'px', top: item.y + 'px'}"
|
|
|
+ :class="item.type === 'horizontal' ? 'refer-line-h' : 'refer-line-v'"
|
|
|
+ @dblclick="projectStore.removeReferLine(item.key)"
|
|
|
+ >
|
|
|
+ <UseDraggable @move="(position, event) => handleDragReferLine(position, event, item.key)">
|
|
|
+ <span class="refer-line__txt">{{ item.value }}px</span>
|
|
|
+ <span class="refer-line__line"></span>
|
|
|
+ </UseDraggable>
|
|
|
+ </div>
|
|
|
+ <!-- 临时参考线 -->
|
|
|
+ <div
|
|
|
+ class="refer-line virtual-refer-line"
|
|
|
+ :class="
|
|
|
+ virtualReferLine.type === 'horizontal' ? 'refer-line-h' : 'refer-line-v'
|
|
|
+ "
|
|
|
+ :style="{left: virtualReferLine.x + 'px', top: virtualReferLine.y + 'px'}"
|
|
|
+ v-show="virtualReferLine.type"
|
|
|
+ >
|
|
|
+ <span class="refer-line__txt">{{ virtualReferLine.value }}px</span>
|
|
|
+ <span class="refer-line__line refer-line__dashed"></span>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+</template>
|
|
|
+
|
|
|
+<script setup lang="ts">
|
|
|
+import {
|
|
|
+ onMounted,
|
|
|
+ ref,
|
|
|
+ onBeforeUnmount,
|
|
|
+ nextTick,
|
|
|
+ watch,
|
|
|
+} from "vue";
|
|
|
+import type { Ref } from "vue";
|
|
|
+import { EyeFilled, EyeInvisibleFilled } from "@ant-design/icons-vue";
|
|
|
+import { UseDraggable } from "@vueuse/components";
|
|
|
+import { drawScaleplate } from "@/utils";
|
|
|
+import { useStageStore } from "@/store/modules/stage";
|
|
|
+import { useProjectStore } from "@/store/modules/project";
|
|
|
+import type { ReferLine } from "#/project";
|
|
|
+
|
|
|
+const stageStore = useStageStore();
|
|
|
+const projectStore = useProjectStore();
|
|
|
+const horizontalRef = ref<HTMLElement | null>(null);
|
|
|
+const verticalRef = ref<HTMLElement | null>(null);
|
|
|
+const showReferLine: Ref<boolean> = ref(true);
|
|
|
+const windowSize: Ref<{ width: number; height: number }> = ref({
|
|
|
+ width: 0,
|
|
|
+ height: 0,
|
|
|
+});
|
|
|
+
|
|
|
+/* 绘制标尺刻度 */
|
|
|
+const handleDrawScaleplate = () => {
|
|
|
+ // 水平轴
|
|
|
+ const { scale, scrollX, scrollY, originX, originY } = stageStore;
|
|
|
+ drawScaleplate({
|
|
|
+ canvas: document.getElementById(
|
|
|
+ "scaleplateHorizontal"
|
|
|
+ ) as HTMLCanvasElement,
|
|
|
+ canvasStyleWidth: windowSize.value.width,
|
|
|
+ canvasStyleHeight: 20,
|
|
|
+ direcotion: "horizontal",
|
|
|
+ scale,
|
|
|
+ scrollX,
|
|
|
+ scrollY,
|
|
|
+ originX,
|
|
|
+ originY,
|
|
|
+ });
|
|
|
+ // 垂直轴
|
|
|
+ drawScaleplate({
|
|
|
+ canvas: document.getElementById("scaleplateVertical") as HTMLCanvasElement,
|
|
|
+ canvasStyleWidth: 20,
|
|
|
+ canvasStyleHeight: windowSize.value.height,
|
|
|
+ direcotion: "vertical",
|
|
|
+ scale,
|
|
|
+ scrollX,
|
|
|
+ scrollY,
|
|
|
+ originX,
|
|
|
+ originY,
|
|
|
+ });
|
|
|
+};
|
|
|
+
|
|
|
+/* =============================== 参考线 ================================= */
|
|
|
+const virtualReferLine: Ref<ReferLine> = ref({
|
|
|
+ key: 0,
|
|
|
+ x: 0,
|
|
|
+ y: 0,
|
|
|
+ value: 0,
|
|
|
+ type: null,
|
|
|
+});
|
|
|
+/* 临时参考线位置 */
|
|
|
+const handleMouseMoveHScaleplate = (e: MouseEvent, type: "horizontal" | "vertical") => {
|
|
|
+ const { offsetX, offsetY } = e;
|
|
|
+ const { scale, originX, originY, scrollX, scrollY } = stageStore;
|
|
|
+
|
|
|
+ virtualReferLine.value.x = type === "horizontal" ? offsetX + 20 : 0;
|
|
|
+ virtualReferLine.value.y = type === "vertical" ? offsetY + 20 : 0;
|
|
|
+ // 计算当前位置数值
|
|
|
+ if(type === "horizontal") {
|
|
|
+ const offset = scrollX - originX;
|
|
|
+ virtualReferLine.value.value = Math.round((offset + offsetX) / scale);
|
|
|
+ } else {
|
|
|
+ const offset = scrollY - originY;
|
|
|
+ virtualReferLine.value.value = Math.round((offset + offsetY) / scale);
|
|
|
+ }
|
|
|
+};
|
|
|
+/* 添加参考线 */
|
|
|
+const handleAddReferLine = () => {
|
|
|
+ if(!virtualReferLine.value.type) return;
|
|
|
+
|
|
|
+ projectStore.addReferLine({
|
|
|
+ ...virtualReferLine.value,
|
|
|
+ key: Date.now(),
|
|
|
+ });
|
|
|
+};
|
|
|
+/* 拖拽参考线 */
|
|
|
+const handleDragReferLine = ({x, y}: {x: number, y: number}, e: PointerEvent, key: number) => {
|
|
|
+ const referLine = projectStore.referLines.find((item) => item.key === key);
|
|
|
+ if(!referLine) return;
|
|
|
+
|
|
|
+ const { scale, originX, originY, scrollX, scrollY } = stageStore;
|
|
|
+ const {left, top} = horizontalRef.value!.getBoundingClientRect();
|
|
|
+
|
|
|
+ if(referLine.type === "horizontal") {
|
|
|
+ const lineX = x - left + 20;
|
|
|
+ const offsetX = scrollX - originX;
|
|
|
+
|
|
|
+ referLine.value = Math.round((lineX + offsetX - 20) / scale);
|
|
|
+ referLine.x = lineX;
|
|
|
+ } else {
|
|
|
+ const lineY = y - top;
|
|
|
+ const offsetY = scrollY - originY;
|
|
|
+
|
|
|
+ referLine.value = Math.round((lineY + offsetY - 20) / scale);
|
|
|
+ referLine.y = lineY;
|
|
|
+ }
|
|
|
+
|
|
|
+ projectStore.updateReferLine(referLine);
|
|
|
+};
|
|
|
+/* ===============================参考线结束================================= */
|
|
|
+
|
|
|
+
|
|
|
+/* 设置刻度宽高 */
|
|
|
+const setWindowSize = async () => {
|
|
|
+ windowSize.value = {
|
|
|
+ width: horizontalRef.value!.clientWidth,
|
|
|
+ height: verticalRef.value!.clientHeight,
|
|
|
+ };
|
|
|
+ await nextTick();
|
|
|
+ handleDrawScaleplate();
|
|
|
+};
|
|
|
+
|
|
|
+watch(
|
|
|
+ () => [stageStore.scrollX, stageStore.scrollY, stageStore.scale],
|
|
|
+ () => {
|
|
|
+ handleDrawScaleplate();
|
|
|
+ },
|
|
|
+ { immediate: false }
|
|
|
+);
|
|
|
+
|
|
|
+onMounted(() => {
|
|
|
+ setWindowSize();
|
|
|
+ addEventListener("resize", setWindowSize);
|
|
|
+});
|
|
|
+onBeforeUnmount(() => {
|
|
|
+ removeEventListener("resize", setWindowSize);
|
|
|
+});
|
|
|
+</script>
|
|
|
+
|
|
|
+<style lang="less" scoped>
|
|
|
+.refer-line-img {
|
|
|
+ width: 20px;
|
|
|
+ height: 20px;
|
|
|
+ background: #fff;
|
|
|
+ text-align: center;
|
|
|
+ font-size: 12px;
|
|
|
+ line-height: 20px;
|
|
|
+ border-bottom: solid 1px #eee;
|
|
|
+ border-right: solid 1px #eee;
|
|
|
+ cursor: pointer;
|
|
|
+}
|
|
|
+.scaleplate-horizontal {
|
|
|
+ position: absolute;
|
|
|
+ left: 20px;
|
|
|
+ top: 0;
|
|
|
+ width: calc(100% - 20px);
|
|
|
+ height: 20px;
|
|
|
+ background: #fff;
|
|
|
+ border-bottom: solid 1px #eee;
|
|
|
+}
|
|
|
+.scaleplate-vertical {
|
|
|
+ position: absolute;
|
|
|
+ top: 20px;
|
|
|
+ left: 0;
|
|
|
+ height: calc(100% - 20px);
|
|
|
+ width: 20px;
|
|
|
+ background: #fff;
|
|
|
+ border-right: solid 1px #eee;
|
|
|
+}
|
|
|
+
|
|
|
+.refer-line {
|
|
|
+ position: absolute;
|
|
|
+ font-size: 12px;
|
|
|
+ color: red;
|
|
|
+ &-h {
|
|
|
+ width: 5px;
|
|
|
+ height: 100%;
|
|
|
+ .refer-line__line {
|
|
|
+ border-left: solid 1px red;
|
|
|
+ cursor: e-resize;
|
|
|
+ }
|
|
|
+ .refer-line__dashed {
|
|
|
+ border-left: dashed 1px red;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ &-v {
|
|
|
+ width: 100%;
|
|
|
+ height: 5px;
|
|
|
+ .refer-line__line {
|
|
|
+ border-top: solid 1px red;
|
|
|
+ cursor: n-resize;
|
|
|
+ }
|
|
|
+ .refer-line__dashed {
|
|
|
+ border-top: dashed 1px red;
|
|
|
+ }
|
|
|
+ .refer-line__txt {
|
|
|
+ transform: rotate(-90deg);
|
|
|
+ transform-origin: -4px 2px;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ &__line {
|
|
|
+ position: absolute;
|
|
|
+ width: 100%;
|
|
|
+ height: 100%;
|
|
|
+ top: 0;
|
|
|
+ left: 0;
|
|
|
+ }
|
|
|
+ &__txt {
|
|
|
+ font-size: 12px;
|
|
|
+ position: absolute;
|
|
|
+ top: 0px;
|
|
|
+ left: 4px;
|
|
|
+ pointer-events: none;
|
|
|
+ }
|
|
|
+}
|
|
|
+.virtual-refer-line {
|
|
|
+ pointer-events: none;
|
|
|
+}
|
|
|
+</style>
|