|
@@ -41,7 +41,7 @@
|
|
</div>
|
|
</div>
|
|
<div
|
|
<div
|
|
style="
|
|
style="
|
|
- height: 40px;
|
|
|
|
|
|
+ height: 60px;
|
|
line-height: 40px;
|
|
line-height: 40px;
|
|
font-size: 30px;
|
|
font-size: 30px;
|
|
font-weight: 600;
|
|
font-weight: 600;
|
|
@@ -49,10 +49,27 @@
|
|
color: white;
|
|
color: white;
|
|
display: flex;
|
|
display: flex;
|
|
justify-content: space-between;
|
|
justify-content: space-between;
|
|
|
|
+ align-items: center;
|
|
"
|
|
"
|
|
>
|
|
>
|
|
- <div>共{{ pageLength }}页</div>
|
|
|
|
|
|
+ <div>共 {{ pageLength }} 页</div>
|
|
<div>
|
|
<div>
|
|
|
|
+ 到
|
|
|
|
+ <el-input-number
|
|
|
|
+ @click.stop
|
|
|
|
+ v-model="pageValue"
|
|
|
|
+ :max="pageLength < 1 ? 1 : pageLength"
|
|
|
|
+ :min="1"
|
|
|
|
+ style="background-color: white; border-radius: 5px"
|
|
|
|
+ />
|
|
|
|
+ 页
|
|
|
|
+ <el-button
|
|
|
|
+ type="primary"
|
|
|
|
+ style="font-size: 20px; margin-right: 20px"
|
|
|
|
+ @click="scrollTo(pageValue)"
|
|
|
|
+ link
|
|
|
|
+ >跳转</el-button
|
|
|
|
+ >
|
|
<el-button
|
|
<el-button
|
|
type="primary"
|
|
type="primary"
|
|
style="font-size: 20px; margin-right: 20px"
|
|
style="font-size: 20px; margin-right: 20px"
|
|
@@ -64,7 +81,10 @@
|
|
</div>
|
|
</div>
|
|
<el-scrollbar
|
|
<el-scrollbar
|
|
ref="scrollbar"
|
|
ref="scrollbar"
|
|
- style="height: calc(90vh - 40px); width: 90vw; padding: 0px 20px"
|
|
|
|
|
|
+ @scroll="bigScroll"
|
|
|
|
+ :always="true"
|
|
|
|
+ style="height: calc(90vh - 60px); width: 90vw; padding: 0px 30px"
|
|
|
|
+ :always-show="true"
|
|
>
|
|
>
|
|
<VuePdfEmbed
|
|
<VuePdfEmbed
|
|
v-if="showVisible"
|
|
v-if="showVisible"
|
|
@@ -84,20 +104,29 @@
|
|
/>
|
|
/>
|
|
|
|
|
|
<template v-for="(item, index) in pageLength" :key="index">
|
|
<template v-for="(item, index) in pageLength" :key="index">
|
|
- <el-scrollbar v-if="showELStatus">
|
|
|
|
- <VuePdfEmbed
|
|
|
|
|
|
+ <div :id="'scrollbarId' + (index + 1)">
|
|
|
|
+ <el-scrollbar
|
|
v-if="showELStatus"
|
|
v-if="showELStatus"
|
|
- :source="{
|
|
|
|
- url: pdfSource,
|
|
|
|
- cMapUrl: '/cmaps/',
|
|
|
|
- cMapPacked: true,
|
|
|
|
- }"
|
|
|
|
- :page="index + 1"
|
|
|
|
- @rendered="index + 1 === pageLength ? rendered() : null"
|
|
|
|
- annotation-layer
|
|
|
|
- text-layer
|
|
|
|
- />
|
|
|
|
- </el-scrollbar>
|
|
|
|
|
|
+ @scroll="(e) => scroll(e, index)"
|
|
|
|
+ :ref="(el) => scrollbarRefArray.push(el)"
|
|
|
|
+ style="padding: 20px"
|
|
|
|
+ :always-show="true"
|
|
|
|
+ >
|
|
|
|
+ <VuePdfEmbed
|
|
|
|
+ v-if="showELStatus"
|
|
|
|
+ :source="{
|
|
|
|
+ url: pdfSource,
|
|
|
|
+ cMapUrl: '/cmaps/',
|
|
|
|
+ cMapPacked: true,
|
|
|
|
+ }"
|
|
|
|
+ :page="index + 1"
|
|
|
|
+ @rendered="index + 1 === pageLength ? rendered() : null"
|
|
|
|
+ annotation-layer
|
|
|
|
+ text-layer
|
|
|
|
+ />
|
|
|
|
+ </el-scrollbar>
|
|
|
|
+ </div>
|
|
|
|
+
|
|
<div
|
|
<div
|
|
style="
|
|
style="
|
|
width: 100%;
|
|
width: 100%;
|
|
@@ -118,6 +147,7 @@
|
|
|
|
|
|
<script lang="ts" setup>
|
|
<script lang="ts" setup>
|
|
import VuePdfEmbed from "vue-pdf-embed";
|
|
import VuePdfEmbed from "vue-pdf-embed";
|
|
|
|
+import Hammer from "hammerjs";
|
|
// essential styles
|
|
// essential styles
|
|
import "vue-pdf-embed/dist/style/index.css";
|
|
import "vue-pdf-embed/dist/style/index.css";
|
|
|
|
|
|
@@ -161,7 +191,25 @@ const props = defineProps({
|
|
default: 0,
|
|
default: 0,
|
|
},
|
|
},
|
|
});
|
|
});
|
|
|
|
+const value = ref(0);
|
|
|
|
+const pageValue = ref(1);
|
|
|
|
+const newBigScrollTop = ref(0);
|
|
|
|
+const bigScroll = ({ scrollTop }) => {
|
|
|
|
+ value.value = scrollTop;
|
|
|
|
+};
|
|
|
|
+const scrollTo = (page) => {
|
|
|
|
+ console.log(page);
|
|
|
|
+ const targetElement = document.getElementById(`scrollbarId${page}`);
|
|
|
|
+ console.log(targetElement);
|
|
|
|
+ if (targetElement) {
|
|
|
|
+ const topPos = targetElement.offsetTop;
|
|
|
|
+ console.log(topPos);
|
|
|
|
+ newBigScrollTop.value = topPos;
|
|
|
|
+ scrollbar.value.setScrollTop(topPos);
|
|
|
|
+ }
|
|
|
|
+};
|
|
const scrollbar = ref(null);
|
|
const scrollbar = ref(null);
|
|
|
|
+const scrollbarRefArray = ref([]);
|
|
const reset = () => {
|
|
const reset = () => {
|
|
scrollbar.value.setScrollTop(0);
|
|
scrollbar.value.setScrollTop(0);
|
|
visible.value = false;
|
|
visible.value = false;
|
|
@@ -173,7 +221,6 @@ const pageStatus = ref(true);
|
|
const renderedShow = (pdf: any) => {
|
|
const renderedShow = (pdf: any) => {
|
|
pageLength.value = pdf.numPages;
|
|
pageLength.value = pdf.numPages;
|
|
pageStatus.value = false;
|
|
pageStatus.value = false;
|
|
- console.log(pageLength.value);
|
|
|
|
};
|
|
};
|
|
const visible = ref(false);
|
|
const visible = ref(false);
|
|
const showVisible = ref(false);
|
|
const showVisible = ref(false);
|
|
@@ -182,6 +229,25 @@ const showPdf = () => {
|
|
showVisible.value = true;
|
|
showVisible.value = true;
|
|
};
|
|
};
|
|
const showELStatus = ref(false);
|
|
const showELStatus = ref(false);
|
|
|
|
+const leftArray = ref([]);
|
|
|
|
+const scroll = (e, index) => {
|
|
|
|
+ leftArray.value[index].scrollLeft = e.scrollLeft;
|
|
|
|
+};
|
|
|
|
+const setLeftArray = () => {
|
|
|
|
+ leftArray.value = [];
|
|
|
|
+ for (let i = 0; i < pageLength.value; i++) {
|
|
|
|
+ leftArray.value.push({
|
|
|
|
+ scrollLeft: 0,
|
|
|
|
+ });
|
|
|
|
+ }
|
|
|
|
+};
|
|
|
|
+watch(
|
|
|
|
+ pageLength,
|
|
|
|
+ () => {
|
|
|
|
+ setLeftArray();
|
|
|
|
+ },
|
|
|
|
+ { immediate: true }
|
|
|
|
+);
|
|
const rendered = () => {
|
|
const rendered = () => {
|
|
loading.value = false;
|
|
loading.value = false;
|
|
|
|
|
|
@@ -189,100 +255,153 @@ const rendered = () => {
|
|
const clickableElements = document.querySelectorAll(
|
|
const clickableElements = document.querySelectorAll(
|
|
".vue-pdf-embed .vue-pdf-embed__page"
|
|
".vue-pdf-embed .vue-pdf-embed__page"
|
|
);
|
|
);
|
|
|
|
+
|
|
|
|
+ // 设置所有子元素居中对齐
|
|
clickableElementsA.forEach((element) => {
|
|
clickableElementsA.forEach((element) => {
|
|
element.style.display = "flex";
|
|
element.style.display = "flex";
|
|
element.style.alignItems = "center";
|
|
element.style.alignItems = "center";
|
|
element.style.justifyContent = "center";
|
|
element.style.justifyContent = "center";
|
|
});
|
|
});
|
|
|
|
+
|
|
clickableElements.forEach((element, index) => {
|
|
clickableElements.forEach((element, index) => {
|
|
|
|
+ element.index = index;
|
|
let rotationAngle = 0;
|
|
let rotationAngle = 0;
|
|
- element.addEventListener("click", () => {
|
|
|
|
|
|
+ element.style.touchAction = "auto";
|
|
|
|
+ element.addEventListener("dblclick", () => {
|
|
const currentWidth = element.offsetWidth;
|
|
const currentWidth = element.offsetWidth;
|
|
const currentHeight = element.offsetHeight;
|
|
const currentHeight = element.offsetHeight;
|
|
const parent = element.parentNode;
|
|
const parent = element.parentNode;
|
|
- let distance = 0;
|
|
|
|
-
|
|
|
|
- distance = currentHeight - currentWidth;
|
|
|
|
|
|
+ let distance = currentHeight - currentWidth;
|
|
|
|
|
|
rotationAngle = (rotationAngle + 90) % 360;
|
|
rotationAngle = (rotationAngle + 90) % 360;
|
|
- if (rotationAngle == 0) {
|
|
|
|
- if (distance > 0) {
|
|
|
|
- element.style.transform = `rotate(${rotationAngle}deg) `;
|
|
|
|
- element.firstElementChild.style.transform = `translateY(0px) `;
|
|
|
|
- } else {
|
|
|
|
- element.style.transform = `rotate(${rotationAngle}deg) `;
|
|
|
|
- element.firstElementChild.style.transform = `translateY(0px) `;
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- if (rotationAngle == 90) {
|
|
|
|
|
|
+
|
|
|
|
+ if (rotationAngle === 0 || rotationAngle === 180) {
|
|
|
|
+ element.style.transform = `rotate(${rotationAngle}deg)`;
|
|
|
|
+ element.firstElementChild.style.transform = `translateY(0px)`;
|
|
|
|
+ } else if (rotationAngle === 90) {
|
|
|
|
+ element.style.transform = `rotate(${rotationAngle}deg)`;
|
|
if (distance > 0) {
|
|
if (distance > 0) {
|
|
- element.style.transform = `rotate(${rotationAngle}deg)`;
|
|
|
|
- element.firstElementChild.style.transform = `translateY(-${distance / 2}px) `;
|
|
|
|
|
|
+ element.firstElementChild.style.transform = `translateY(-${distance / 2}px)`;
|
|
} else {
|
|
} else {
|
|
- element.style.transform = `rotate(${rotationAngle}deg)`;
|
|
|
|
element.firstElementChild.style.transform = `translateX(${-distance / 2}px)`;
|
|
element.firstElementChild.style.transform = `translateX(${-distance / 2}px)`;
|
|
}
|
|
}
|
|
- }
|
|
|
|
- if (rotationAngle === 180) {
|
|
|
|
- if (distance > 0) {
|
|
|
|
- element.style.transform = `rotate(${rotationAngle}deg) `;
|
|
|
|
- element.firstElementChild.style.transform = `translateY(0px) `;
|
|
|
|
- } else {
|
|
|
|
- element.style.transform = `rotate(${rotationAngle}deg) `;
|
|
|
|
- element.firstElementChild.style.transform = `translateY(0px) `;
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- if (rotationAngle === 270) {
|
|
|
|
|
|
+ } else if (rotationAngle === 270) {
|
|
|
|
+ element.style.transform = `rotate(${rotationAngle}deg)`;
|
|
if (distance > 0) {
|
|
if (distance > 0) {
|
|
- element.style.transform = `rotate(${rotationAngle}deg) `;
|
|
|
|
- element.firstElementChild.style.transform = `translateY(${distance / 2}px) `;
|
|
|
|
|
|
+ element.firstElementChild.style.transform = `translateY(${distance / 2}px)`;
|
|
} else {
|
|
} else {
|
|
- element.style.transform = `rotate(${rotationAngle}deg) `;
|
|
|
|
element.firstElementChild.style.transform = `translateX(${distance / 2}px)`;
|
|
element.firstElementChild.style.transform = `translateX(${distance / 2}px)`;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
+
|
|
parent.style.width = `${currentWidth}px`;
|
|
parent.style.width = `${currentWidth}px`;
|
|
parent.style.height = `${currentHeight}px`;
|
|
parent.style.height = `${currentHeight}px`;
|
|
});
|
|
});
|
|
|
|
+
|
|
|
|
+ // 🖱️ Ctrl + 鼠标滚轮 缩放
|
|
element.addEventListener("wheel", function (event) {
|
|
element.addEventListener("wheel", function (event) {
|
|
const currentWidth = element.offsetWidth;
|
|
const currentWidth = element.offsetWidth;
|
|
const currentHeight = element.offsetHeight;
|
|
const currentHeight = element.offsetHeight;
|
|
const parent = element.parentNode;
|
|
const parent = element.parentNode;
|
|
|
|
+
|
|
if (event.ctrlKey) {
|
|
if (event.ctrlKey) {
|
|
event.preventDefault();
|
|
event.preventDefault();
|
|
|
|
|
|
- // 获取当前的transform值并解析
|
|
|
|
const transform = getComputedStyle(element).transform;
|
|
const transform = getComputedStyle(element).transform;
|
|
let scale = 1,
|
|
let scale = 1,
|
|
rotate = 0;
|
|
rotate = 0;
|
|
|
|
|
|
if (transform && transform !== "none") {
|
|
if (transform && transform !== "none") {
|
|
- const transformMatrix = new WebKitCSSMatrix(transform);
|
|
|
|
- scale = Math.sqrt(
|
|
|
|
- Math.pow(transformMatrix.a, 2) + Math.pow(transformMatrix.b, 2)
|
|
|
|
- );
|
|
|
|
- rotate =
|
|
|
|
- Math.atan2(transformMatrix.b, transformMatrix.a) * (180 / Math.PI);
|
|
|
|
|
|
+ const matrix = new WebKitCSSMatrix(transform);
|
|
|
|
+ scale = Math.sqrt(matrix.a * matrix.a + matrix.b * matrix.b);
|
|
|
|
+ rotate = Math.atan2(matrix.b, matrix.a) * (180 / Math.PI);
|
|
}
|
|
}
|
|
|
|
|
|
- // 根据滚轮方向调整缩放级别
|
|
|
|
if (event.deltaY < 0) {
|
|
if (event.deltaY < 0) {
|
|
- // 向上滚动,放大
|
|
|
|
- scale += 0.1;
|
|
|
|
|
|
+ scale += 0.1; // 放大
|
|
} else {
|
|
} else {
|
|
- // 向下滚动,缩小
|
|
|
|
- scale -= 0.1;
|
|
|
|
|
|
+ scale -= 0.1; // 缩小
|
|
}
|
|
}
|
|
- // 确保缩放级别不会变成负数或过小
|
|
|
|
scale = Math.max(0.1, Math.min(scale, 5));
|
|
scale = Math.max(0.1, Math.min(scale, 5));
|
|
|
|
|
|
- // 应用新的缩放级别和原有的旋转角度
|
|
|
|
element.style.transform = `scale(${scale}) rotate(${rotate}deg)`;
|
|
element.style.transform = `scale(${scale}) rotate(${rotate}deg)`;
|
|
- //同步放大展示盒子
|
|
|
|
parent.style.width = `${currentWidth * scale}px`;
|
|
parent.style.width = `${currentWidth * scale}px`;
|
|
parent.style.height = `${currentHeight * scale}px`;
|
|
parent.style.height = `${currentHeight * scale}px`;
|
|
}
|
|
}
|
|
});
|
|
});
|
|
|
|
+
|
|
|
|
+ // 🔍 Hammer.js 只用于双指 Pinch(缩放)
|
|
|
|
+ const hammer = new Hammer(element);
|
|
|
|
+ hammer.get("pinch").set({ enable: true });
|
|
|
|
+
|
|
|
|
+ let initialScale = 1;
|
|
|
|
+
|
|
|
|
+ hammer.on("pinchstart", (ev) => {
|
|
|
|
+ const transform = getComputedStyle(element).transform;
|
|
|
|
+ if (transform && transform !== "none") {
|
|
|
|
+ const matrix = new WebKitCSSMatrix(transform);
|
|
|
|
+ initialScale = Math.sqrt(matrix.a * matrix.a + matrix.b * matrix.b);
|
|
|
|
+ }
|
|
|
|
+ });
|
|
|
|
+
|
|
|
|
+ hammer.on("pinch", (ev) => {
|
|
|
|
+ const parent = element.parentNode;
|
|
|
|
+
|
|
|
|
+ let scale = initialScale * ev.scale;
|
|
|
|
+ scale = Math.max(0.5, Math.min(scale, 5));
|
|
|
|
+
|
|
|
|
+ const transform = getComputedStyle(element).transform;
|
|
|
|
+ let rotate = 0;
|
|
|
|
+
|
|
|
|
+ if (transform && transform !== "none") {
|
|
|
|
+ const matrix = new WebKitCSSMatrix(transform);
|
|
|
|
+ rotate = Math.atan2(matrix.b, matrix.a) * (180 / Math.PI);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ element.style.transform = `rotate(${rotate}deg) scale(${scale})`;
|
|
|
|
+ parent.style.width = `${element.offsetWidth * scale}px`;
|
|
|
|
+ parent.style.height = `${element.offsetHeight * scale}px`;
|
|
|
|
+ });
|
|
|
|
+ hammer.on("pinchend", () => {
|
|
|
|
+ console.log("Pinch 操作结束");
|
|
|
|
+ });
|
|
|
|
+ hammer.get("pan").set({
|
|
|
|
+ direction: Hammer.DIRECTION_VERTICAL,
|
|
|
|
+ threshold: 5, // 最小触发距离
|
|
|
|
+ });
|
|
|
|
+ let startX; // 记录开始触摸的位置
|
|
|
|
+ let startScrollLeft = 0; // 记录开始时的滚动位置
|
|
|
|
+ hammer.on("panstart", (ev) => {
|
|
|
|
+ startX = ev.center.x;
|
|
|
|
+ });
|
|
|
|
+
|
|
|
|
+ hammer.on("panmove", (ev) => {
|
|
|
|
+ const deltaX = -ev.deltaX; // 手指水平移动的距离
|
|
|
|
+ const deltaY = -ev.deltaY;
|
|
|
|
+ scrollbarRefArray.value[element.index].setScrollLeft(
|
|
|
|
+ startScrollLeft + deltaX
|
|
|
|
+ );
|
|
|
|
+ scrollbar.value.setScrollTop(newBigScrollTop.value + deltaY);
|
|
|
|
+ ev.preventDefault();
|
|
|
|
+ });
|
|
|
|
+ hammer.on("panend", (ev) => {
|
|
|
|
+ const deltaX = -ev.deltaX; // 手指水平移动的距离
|
|
|
|
+ const deltaY = -ev.deltaY;
|
|
|
|
+ startScrollLeft = startScrollLeft + deltaX;
|
|
|
|
+ if (startScrollLeft < 0) {
|
|
|
|
+ startScrollLeft = 0;
|
|
|
|
+ } else if (startScrollLeft > leftArray.value[element.index].scrollLeft) {
|
|
|
|
+ startScrollLeft = leftArray.value[element.index].scrollLeft;
|
|
|
|
+ }
|
|
|
|
+ newBigScrollTop.value = newBigScrollTop.value + deltaY;
|
|
|
|
+ if (newBigScrollTop.value < 0) {
|
|
|
|
+ newBigScrollTop.value = 0;
|
|
|
|
+ } else if (newBigScrollTop.value > value.value) {
|
|
|
|
+ newBigScrollTop.value = value.value;
|
|
|
|
+ }
|
|
|
|
+ // 阻止默认行为(如页面滚动)
|
|
|
|
+ ev.preventDefault();
|
|
|
|
+ });
|
|
});
|
|
});
|
|
};
|
|
};
|
|
</script>
|
|
</script>
|