pdf的展示 翻页 及数据回显

This commit is contained in:
zhangxuelin 2024-07-26 10:26:34 +08:00
parent fd7686af9a
commit 4e2ac7c92e
4 changed files with 418 additions and 156 deletions

View File

@ -1,97 +1,213 @@
<template> <template>
<div class="canvasitem"> <div class="canvasitem">
<canvas v-for="(item,index) in pdfObj.numberOfPdf" :key="index" :id="'pdf-canvas'+(index+1)" :ref="'canvasPdf'+(index+1)" class="pdf-canvas" style="height:100vh;padding-right:10px"></canvas> <div class="pdfAdnFabric">
<canvas id="pdf-fabric"></canvas>
<canvas id="pdf-fabric1" v-if="props.pdfObj.numberOfPdf == 2"></canvas>
</div>
</div> </div>
</template> </template>
<script setup > <script setup >
import { ref, onMounted, watch, reactive,defineProps ,defineExpose,nextTick,defineEmits } from 'vue'; import {
ref,
onMounted,
watch,
reactive,
defineProps,
defineExpose,
nextTick,
defineEmits
} from 'vue'
import { fabric } from 'fabric'
import { ElMessage } from 'element-plus'
import { handleevent, savecanvsStore, initcanvasdata, displayData } from '@/utils/pdfAndFabric'
const props = defineProps({ const props = defineProps({
pdfObj: { pdfObj: {
type: Object, type: Object,
default: { default: {
numberOfPdf:2, //pdf 1 2 numberOfPdf: 2, //pdf 1 2
pdfUrl:null, pdfUrl: null,
numPages:1 numPages: 1
} }
} }
}) })
const numPages=ref(0) // canvas
const canvsStore = reactive({
id: 'xxxx',
pageArr: []
})
const fabriccanvas = ref(null)
const fabriccanvas1 = ref(null)
//
const numPagesTotal = ref(0)
const imgarr = ref([])
// pdf // pdf
const canvasNumbsValue = ref([]); const canvasNumbsValue = ref([])
const emit = defineEmits(['update:numPages']) const emit = defineEmits(['update:numPagesTotal'])
const renderPage = async (canvasobj) => { const renderPage = async (canvasobj) => {
if(canvasobj.page>numPages.value) return if (canvasobj.page > numPagesTotal.value) return
const pdf = await pdfjsLib.getDocument(props.pdfObj.pdfUrl).promise; const pdf = await pdfjsLib.getDocument(props.pdfObj.pdfUrl).promise
// //
const page1 = await pdf.getPage(canvasobj.page); const page = await pdf.getPage(canvasobj.page)
const viewport1 = page1.getViewport({ scale: 1 }); const viewport = page.getViewport({ scale: 1 })
const canvasElement1 = canvasobj.canvas;
canvasElement1.width = viewport1.width;
canvasElement1.height = viewport1.height;
const renderContext1 = { const canvasElement = canvasobj.canvas
canvasContext:canvasobj.context, canvasElement.width = viewport.width
viewport: viewport1, canvasElement.height = viewport.height
}; const renderContext = {
await page1.render(renderContext1).promise; canvasContext: canvasobj.context,
viewport: viewport
}; }
page.render(renderContext).promise.then((res) => {
const img = document.createElement('img')
img.src = canvasobj.canvas.toDataURL('image/png')
canvasobj.canvas.remove()
imgarr.value.push({ src: img.src, page: canvasobj.page, JSONdata: {}, index: canvasobj.index })
img.onload = () => {
//
// pdf fabric
if (props.pdfObj.numberOfPdf == 2) {
if (canvasobj.index == 0) {
fabriccanvas.value.setWidth(img.width)
fabriccanvas.value.setHeight(img.height)
displayData(fabriccanvas, canvsStore, canvasobj, fabric, img)
} else {
fabriccanvas1.value.setWidth(img.width)
fabriccanvas1.value.setHeight(img.height)
displayData(fabriccanvas1, canvsStore, canvasobj, fabric, img)
}
} else {
fabriccanvas.value.setWidth(img.width)
fabriccanvas.value.setHeight(img.height)
displayData(fabriccanvas, canvsStore, canvasobj, fabric, img)
}
// console.log(imgarr.value)
img.remove()
}
// imgarrJSONdatacanvsStore.pageArr
canvsStore.pageArr.forEach((item) => {
if (item.page == canvasobj.page) {
imgarr.value.forEach((img) => {
if (img.page == canvasobj.page) {
img.JSONdata = item.JSONdata
}
})
}
})
})
}
const updatePage = (canvasobj) => { const updatePage = (canvasobj) => {
renderPage(canvasobj); renderPage(canvasobj)
}; }
const loadPdf = async (canvasobj) => { const loadPdf = async (canvasobj) => {
updatePage(canvasobj)
}
updatePage(canvasobj); const initPdf = async (type = 'default') => {
//
}; savecanvsStore(imgarr, canvsStore)
const initPdf = async() => { // initcanvasdata(fabriccanvas)
// initcanvasdata(fabriccanvas1)
//
if (type == 'restone') {
// canvas
fabriccanvas1.value.clear()
// canvas
fabriccanvas1.value.dispose()
}
// canvas // canvas
canvasNumbsValue.value.forEach((canvasObj) => { canvasNumbsValue.value.forEach((canvasObj) => {
const context = canvasObj.context; const context = canvasObj.context
context.clearRect(0, 0, canvasObj.canvas.width, canvasObj.canvas.height); context.clearRect(0, 0, canvasObj.canvas.width, canvasObj.canvas.height)
}); })
canvasNumbsValue.value=[] //
if(props.pdfObj.pdfUrl){ imgarr.value = []
await nextTick(); // DOM canvasNumbsValue.value = []
if(props.pdfObj.numberOfPdf==1){ if (props.pdfObj.pdfUrl) {
canvasNumbsValue.value=[{}] await nextTick() // DOM
canvasNumbsValue.value[0].canvas = document.getElementById('pdf-canvas1'); if (props.pdfObj.numberOfPdf == 1) {
canvasNumbsValue.value[0].context = canvasNumbsValue.value[0].canvas.getContext('2d'); canvasNumbsValue.value = [{}]
canvasNumbsValue.value[0].page =Number(props.pdfObj.numPages)*props.pdfObj.numberOfPdf const canvasElement = document.createElement('canvas')
await loadPdf(canvasNumbsValue.value[0]); canvasNumbsValue.value[0].canvas = canvasElement
}else{ canvasNumbsValue.value[0].context = canvasNumbsValue.value[0].canvas.getContext('2d')
for(var i=0;i<props.pdfObj.numberOfPdf;i++){ canvasNumbsValue.value[0].page = props.pdfObj.numPages
canvasNumbsValue.value[i] = {}; canvasNumbsValue.value[0].index = 0
canvasNumbsValue.value[i].canvas = document.getElementById('pdf-canvas'+(i+1)); await loadPdf(canvasNumbsValue.value[0])
canvasNumbsValue.value[i].context = canvasNumbsValue.value[i].canvas.getContext('2d'); } else {
if(i==0){ for (var i = 0; i < props.pdfObj.numberOfPdf; i++) {
canvasNumbsValue.value[i].page =Number(props.pdfObj.numPages)*props.pdfObj.numberOfPdf-1 canvasNumbsValue.value[i] = {}
}else{ const canvasElement = document.createElement('canvas')
canvasNumbsValue.value[i].page =Number(props.pdfObj.numPages)*props.pdfObj.numberOfPdf canvasNumbsValue.value[i].canvas = canvasElement
} canvasNumbsValue.value[i].context = canvasNumbsValue.value[i].canvas.getContext('2d')
await loadPdf(canvasNumbsValue.value[i]); //
} if (i == 0) {
canvasNumbsValue.value[i].page = props.pdfObj.numPages
} else {
canvasNumbsValue.value[i].page = props.pdfObj.numPages + 1
} }
canvasNumbsValue.value[i].index = i
// FabricVue
await loadPdf(canvasNumbsValue.value[i])
}
}
} }
} }
onMounted( async() => { const initPdfone = async () => {
const pdf = await pdfjsLib.getDocument(props.pdfObj.pdfUrl).promise; setTimeout(() => {
numPages.value = pdf.numPages; fabriccanvas1.value = new fabric.Canvas('pdf-fabric1')
emit('update:numPages', pdf.numPages); fabriccanvas1.value.isDrawingMode = true
fabriccanvas1.value.freeDrawingBrush.color = 'red'
fabriccanvas1.value.setWidth(595)
}, 0)
initPdf('addOnePage')
}
onMounted(async () => {
try {
const pdf = await pdfjsLib.getDocument(props.pdfObj.pdfUrl).promise
numPagesTotal.value = pdf.numPages
// console.log(pdf)
// fabriccanvas
fabriccanvas.value = new fabric.Canvas('pdf-fabric')
fabriccanvas.value.setWidth(595)
fabriccanvas.value.isDrawingMode = true
fabriccanvas.value.freeDrawingBrush.color = 'red'
fabriccanvas1.value = new fabric.Canvas('pdf-fabric1')
fabriccanvas1.value.isDrawingMode = true
fabriccanvas1.value.freeDrawingBrush.color = 'red'
fabriccanvas1.value.setWidth(595)
emit('update:numPagesTotal', pdf.numPages)
initPdf() initPdf()
}); } catch (error) {
console.log(error)
ElMessage.error('pdf文件错误')
}
// 2canvas
handleevent(fabriccanvas.value, imgarr)
handleevent(fabriccanvas1.value, imgarr, 'two')
})
defineExpose({ defineExpose({
initPdf initPdf,
}); initPdfone
})
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
.canvasitem{ .canvasitem {
display: flex; display: flex;
flex-wrap: wrap; flex-wrap: wrap;
width: 100%; width: 100%;
justify-content: center justify-content: center;
}
.pdfAdnFabric {
position: relative;
display: flex;
height: 100vh;
align-items: center;
:deep(> div:nth-of-type(1)) {
margin-right: 10px;
}
} }
</style> </style>

View File

@ -28,6 +28,8 @@ export class CanvasClickEvent {
// 事件:按下鼠标 // 事件:按下鼠标
canvas?.on('mouse:down', (e) => { canvas?.on('mouse:down', (e) => {
console.log(222222222222222222222222222)
this.isMouseDown = true this.isMouseDown = true
if (this.isSpaceKeyDown) { if (this.isSpaceKeyDown) {
return return
@ -148,6 +150,8 @@ export class CanvasClickEvent {
// 事件:移动鼠标 // 事件:移动鼠标
canvas?.on('mouse:move', (e) => { canvas?.on('mouse:move', (e) => {
console.log(222222222222222222222222222)
if (this.isMouseDown) { if (this.isMouseDown) {
// Press space, drag the canvas, stop drawing. // Press space, drag the canvas, stop drawing.
if (this.isSpaceKeyDown) { if (this.isSpaceKeyDown) {
@ -180,6 +184,8 @@ export class CanvasClickEvent {
// 事件:松开鼠标 // 事件:松开鼠标
canvas?.on('mouse:up', (e) => { canvas?.on('mouse:up', (e) => {
console.log(222222222222222222222222222)
this.isMouseDown = false this.isMouseDown = false
if (this.autoDrawInk?.[0]?.length > 3) { if (this.autoDrawInk?.[0]?.length > 3) {
autoDrawData.addInk([...this.autoDrawInk]) autoDrawData.addInk([...this.autoDrawInk])

View File

@ -0,0 +1,129 @@
// 所有事件
export function handleevent(canvas, imgarr, type = 'defalut') {
// 鼠标按下
canvas.on('mouse:down', function (e) {})
// // 监听鼠标移动事件
// canvas.on('mouse:move', (options) => {
// console.log('Mouse move event:', options);
// });
// 监听鼠标释放事件
canvas.on('mouse:up', (options) => {
//判断是点击的哪一个
if (type == 'defalut') {
if (imgarr.value[0].index == 0) {
imgarr.value[0].JSONdata = canvas.toJSON()
}
if (imgarr.value[1].index == 0) {
imgarr.value[1].JSONdata = canvas.toJSON()
}
} else {
if (imgarr.value[0].index == 1) {
imgarr.value[0].JSONdata = canvas.toJSON()
}
if (imgarr.value[1].index == 1) {
imgarr.value[1].JSONdata = canvas.toJSON()
}
}
})
}
// 保存数据
export function savecanvsStore(imgarr, canvsStore) {
canvsStore.pageArr = mergeAndReplace(canvsStore.pageArr, imgarr.value)
// console.log(canvsStore.pageArr,22222222222222222222+'存入')
}
// 重显数据
export function displayData(canvas, canvsStore, canvasobj, fabric, img) {
// 初始化
if (!canvsStore.pageArr.length) {
fabric.Image.fromURL(img.src, (img) => {
img.set({
left: 0,
top: 0,
scaleX: canvas.value.width / img.width,
scaleY: canvas.value.height / img.height
})
canvas.value.setBackgroundImage(img, canvas.value.renderAll.bind(canvas.value))
})
return
}
canvsStore.pageArr.forEach((item) => {
//初始化
if (item.page == canvasobj.page) {
canvas.value.clear() // 清除 Canvas
// console.log(item.JSONdata, '找到一样的数据')
canvas.value.loadFromJSON(item.JSONdata, () => {
// 在所有对象加载完成后重新渲染画布
requestAnimationFrame(() => {
// 渲染所有对象
canvas.value.renderAll.bind(canvas.value)
canvas.value.renderAll()
})
})
} else {
// 使用 requestAnimationFrame 来更新画布,确保在下一帧进行重绘
canvas.value.clear() // 清除 Canvas
requestAnimationFrame(function () {
fabric.Image.fromURL(img.src, (img) => {
img.set({
left: 0,
top: 0,
scaleX: canvas.value.width / img.width,
scaleY: canvas.value.height / img.height
})
canvas.value.setBackgroundImage(img, canvas.value.renderAll.bind(canvas.value))
})
// 渲染所有对象
canvas.value.renderAll.bind(canvas.value)
})
}
})
}
//page 一样替换
const mergeAndReplace = (arr1, arr2) => {
// // 用于存储替换后的数组
// const resultArray = array1.map(item1 => {
// // 在 array2 中查找 page 相同的对象
// const replacement = array2.find(item2 => item2.page == item1.page);
// // 如果找到替换对象,则返回替换对象,否则返回原对象
// return replacement ? replacement : item1;
// });
// // 将 array2 中 page 不在 array1 中的对象追加到结果数组中
// array2.forEach(item2 => {
// const existsInArray1 = array1.some(item1 => item1.page == item2.page);
// if (!existsInArray1) {
// resultArray.push(item2);
// }
// });
// return resultArray;
// 创建一个映射,将 arr2 中的对象按 page 属性存储
let map = new Map(arr2.map((item) => [item.page, item]))
// 使用 map 替换 arr1 中相应 page 的对象,并添加 arr2 中的对象
arr1 = arr1.map((item) => (map.has(item.page) ? map.get(item.page) : item))
// 将 map 中存在但 arr1 中不存在的对象添加到 arr1
for (let [page, obj] of map) {
if (!arr1.some((item) => item.page === page)) {
arr1.push(obj)
}
}
return arr1
}
// 初始化数据
export function initcanvasdata(canvas) {
canvas.value.clear() // 清除 Canvas
// 设置画布的背景色或其他属性
canvas.value.backgroundColor = 'rgba(255, 255, 255, 1)' // 白色背景
// 使用 requestAnimationFrame 来更新画布,确保在下一帧进行重绘
requestAnimationFrame(function () {
// 渲染所有对象
canvas.value.renderAll.bind(canvas.value)
})
}

View File

@ -1,17 +1,28 @@
<template> <template>
<div class="pdfbox" ref="pdfbox"> <div class="pdfbox" ref="pdfbox">
<pdfCanvas :pdfObj="pdfObj" ref="pdfCanvaslist" @update:numPages="handleUpdate" /> <pdfCanvas :pdfObj="pdfObj" ref="pdfCanvaslist" @update:numPagesTotal="handleUpdate" />
<div class="pdf-btn"> <div class="pdf-btn">
<el-button style=" border-top-left-radius: 8px;" @click="switchPageMode"> <el-button
<i class="iconfont icon-danyemoban" v-if="pdfObj.numberOfPdf==2"></i> style="border-top-left-radius: 8px"
<i class="iconfont icon-shuangye" v-if="pdfObj.numberOfPdf==1"></i> @click="switchPageMode"
<span class="texts">{{ pdfObj.numberOfPdf==1?'双页':'单页' }}</span> :disabled="numPagesTotal == 1"
>
<i class="iconfont icon-danyemoban" v-if="pdfObj.numberOfPdf == 2"></i>
<i class="iconfont icon-shuangye" v-if="pdfObj.numberOfPdf == 1"></i>
<span class="texts">{{ pdfObj.numberOfPdf == 1 ? '双页' : '单页' }}</span>
</el-button> </el-button>
<el-button @click="navtopage('up')" :disabled="pdfObj.numPages==1"> <el-button @click="navtopage('up')" :disabled="pdfObj.numPages == 1 || numPagesTotal == 1">
<i class="iconfont icon-shangyiye"></i> <i class="iconfont icon-shangyiye"></i>
<span class="texts">上一页</span> <span class="texts">上一页</span>
</el-button> </el-button>
<el-button @click="navtopage('lower')" :disabled="pdfObj.numPages >= numPages/pdfObj.numberOfPdf" > <el-button
@click="navtopage('lower')"
:disabled="
pdfObj.numberOfPdf == 1
? pdfObj.numPages >= numPagesTotal
: pdfObj.numPages >= numPagesTotal - 1 || numPagesTotal == 1
"
>
<i class="iconfont icon-xiayiye"></i> <i class="iconfont icon-xiayiye"></i>
<span class="texts">下一页</span> <span class="texts">下一页</span>
</el-button> </el-button>
@ -20,59 +31,59 @@
</template> </template>
<script setup> <script setup>
import { ref, onMounted, watch, reactive } from 'vue'; import { ref, onMounted, watch, reactive } from 'vue'
import * as pdfjsLib from 'pdfjs-dist/legacy/build/pdf'; import * as pdfjsLib from 'pdfjs-dist/legacy/build/pdf'
pdfjsLib.GlobalWorkerOptions.workerSrc = '/lib/build/pdf.worker.mjs'; pdfjsLib.GlobalWorkerOptions.workerSrc = '/lib/build/pdf.worker.mjs'
import pdfCanvas from '@/components/pdf/index.vue'; import pdfCanvas from '@/components/pdf/index.vue'
// //
const pdfObj = reactive({ const pdfObj = reactive({
numberOfPdf:2, // numberOfPdf: 2, //
pdfUrl:'/aaa.pdf', //url pdfUrl: '/aaa.pdf', //url
numPages:1// numPages: 1 //
}); })
const numPages=ref(0) //
const numPagesTotal = ref(0)
const pdfCanvaslist=ref(null); const pdfCanvaslist = ref(null)
const navtopage=(type)=>{ const navtopage = (type) => {
const maxpage=numPages.value/pdfObj.numberOfPdf let num = 1
if(type=='up'){ if (pdfObj.numberOfPdf == 2) {
pdfObj.numPages--; num = 2
}else{
pdfObj.numPages++;
} }
if(pdfObj.numPages>maxpage) return if (type == 'up') {
pdfObj.numPages -= num
} else {
pdfObj.numPages += num
}
if (pdfObj.numPages > numPagesTotal.value) return
pdfCanvaslist.value.initPdf() pdfCanvaslist.value.initPdf()
} }
const handleUpdate=(data)=>{ const handleUpdate = (data) => {
numPages.value=data numPagesTotal.value = data
} if (numPagesTotal.value == 1) {
const divideWithRemainder=(num1, num2)=> { pdfObj.numberOfPdf = 1
// pdfCanvaslist.value.initPdf('restone')
const quotient = Math.floor(num1 / num2); }
const remainder = num1 % num2;
// 1
return remainder === 0 ? quotient : quotient + 1;
} }
// //
const switchPageMode=()=>{ const switchPageMode = () => {
// //
if(pdfObj.numberOfPdf==1){ if (pdfObj.numberOfPdf == 1) {
pdfObj.numberOfPdf=2; // 1
pdfObj.numPages= divideWithRemainder(pdfObj.numPages,pdfObj.numberOfPdf) if (pdfObj.numPages == numPagesTotal.value) {
}else{ pdfObj.numPages = pdfObj.numPages - 1
// }
pdfObj.numberOfPdf=1; pdfObj.numberOfPdf = 2
pdfObj.numPages=pdfObj.numPages*2-1 // pdf canvas
pdfCanvaslist.value.initPdfone()
} else {
//
pdfObj.numberOfPdf = 1
pdfCanvaslist.value.initPdf('restone')
} }
pdfCanvaslist.value.initPdf()
} }
onMounted(async () => { onMounted(async () => {})
});
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
@ -82,17 +93,17 @@ onMounted(async () => {
justify-content: center; justify-content: center;
background: #f0f0f0; background: #f0f0f0;
flex-wrap: wrap; flex-wrap: wrap;
.pdf-btn{ .pdf-btn {
position: absolute; position: absolute;
right: 0; right: 0;
bottom: 0; bottom: 0;
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.5); box-shadow: 0 4px 6px rgba(0, 0, 0, 0.5);
border-radius: 5px 0 0 0; border-radius: 5px 0 0 0;
.texts{ .texts {
display: block !important; display: block !important;
margin-top: 10px; margin-top: 10px;
} }
button{ button {
margin-left: 0; margin-left: 0;
border: none; border: none;
font-size: 16px; font-size: 16px;
@ -100,10 +111,10 @@ onMounted(async () => {
border-radius: 0; border-radius: 0;
width: 80px; width: 80px;
height: 70px; height: 70px;
:deep(>span) { :deep(> span) {
display: block !important; display: block !important;
} }
.iconfont{ .iconfont {
font-size: 26px; font-size: 26px;
margin-bottom: 10px; margin-bottom: 10px;
} }