添加画布接口

This commit is contained in:
zhangxuelin 2024-08-06 14:07:02 +08:00
parent 1d4cad94c1
commit 2a670c1447
6 changed files with 279 additions and 82 deletions

View File

@ -0,0 +1,35 @@
import request from '@/utils/request'
// 新增pdf圈点勾画
export const addsmartBookMark = (params) => {
return request({
url: '/smarttalk/bookMark/addSmartBookMark',
method: 'post',
data:params
})
}
// 修改pdf圈点勾画
export const updateSmartBookMarkContent = (params) => {
return request({
url: '/smarttalk/bookMark/updateSmartBookMarkContent',
method: 'post',
data:params
})
}
// 根据书id获取pdf圈点勾画
export const getBookMarkById = (bookId) => {
return request({
url: '/smarttalk/bookMark/' + bookId,
method: 'get'
})
}
//根据id删除对应页数
export function deleteBookMark(ids) {
return request({
url: '/smarttalk/bookMark/' + ids,
method: 'delete'
})
}

View File

@ -1,16 +1,17 @@
<template> pdfAdnFabric<template>
<div class="canvasitem"> <div class="canvasitem">
<div class="pdfAdnFabric" id="pdfAdnFabric" @touchstart="handleTouchStart"> <div class="pdfAdnFabric" id="pdfAdnFabric" @touchstart="handleTouchStart">
<!-- @touchmove="handleTouchMove" <!-- @touchmove="handleTouchMove"
@touchend="handleTouchEnd" @touchend="handleTouchEnd"
@mousedown="handleMouseDown" @mousedown="handleMouseDown"
@mousemove="handleMouseMove" @mousemove="handleMouseMove"
@mouseup="handleMouseUp" --> @mouseup="handleMouseUp" -->
<div > <div :class="ispointer ? 'ispointer' : ''">
<canvas ref="fabriccanvas" style="pointer-events: none;" /> <canvas ref="fabriccanvas" />
</div> </div>
<div v-if="props.pdfObj.numberOfPdf === 2" style="pointer-events: none;" > <!-- style="pointer-events: none;" -->
<canvas ref="fabriccanvas1" /> <div v-if="props.pdfObj.numberOfPdf === 2" :class="ispointer ? 'ispointer' : ''">
<canvas ref="fabriccanvas1" />
</div> </div>
</div> </div>
</div> </div>
@ -30,8 +31,8 @@ import {
// import { fabric } from 'fabric' // import { fabric } from 'fabric'
import { ElMessage } from 'element-plus' import { ElMessage } from 'element-plus'
import { handleevent, savecanvsStore, initcanvasdata, displayData } from '@/utils/pdfAndFabric' import { handleevent, savecanvsStore, initcanvasdata, displayData } from '@/utils/pdfAndFabric'
import {fabricVue, TYPES} from '@/plugins/fabric' import { fabricVue, TYPES } from '@/plugins/fabric'
import { updateSmartBookMarkContent, addsmartBookMark,getBookMarkById } from '@/api/eTextbook/index'
const props = defineProps({ const props = defineProps({
pdfObj: { pdfObj: {
type: Object, type: Object,
@ -42,9 +43,9 @@ const props = defineProps({
} }
} }
}) })
const ispointer = ref(false) //
// canvas // canvas
const canvsStore = reactive({ const canvsStore = reactive({
id: 'xxxx',
pageArr: [] pageArr: []
}) })
const fabriccanvas = ref(null) const fabriccanvas = ref(null)
@ -63,10 +64,10 @@ const renderPage = async (canvasobj) => {
const pdf = await pdfjsLib.getDocument(props.pdfObj.pdfUrl).promise const pdf = await pdfjsLib.getDocument(props.pdfObj.pdfUrl).promise
// //
const page = await pdf.getPage(canvasobj.page) const page = await pdf.getPage(canvasobj.page)
var screenWidth = window.innerWidth/2-100; var screenWidth = window.innerWidth / 2 - 100
var screenHeight = window.innerHeight; var screenHeight = window.innerHeight
const viewport = page.getViewport({ scale:2}) const viewport = page.getViewport({ scale: 2 })
const canvasElement = canvasobj.canvas const canvasElement = canvasobj.canvas
canvasElement.width = viewport.width canvasElement.width = viewport.width
canvasElement.height = viewport.height canvasElement.height = viewport.height
@ -74,7 +75,7 @@ const renderPage = async (canvasobj) => {
canvasContext: canvasobj.context, canvasContext: canvasobj.context,
viewport: viewport viewport: viewport
} }
console.log(renderContext,22222222222222222222) // console.log(renderContext,22222222222222222222)
page.render(renderContext).promise.then((res) => { page.render(renderContext).promise.then((res) => {
const img = document.createElement('img') const img = document.createElement('img')
@ -94,7 +95,6 @@ const renderPage = async (canvasobj) => {
canvas1FabricVue.value.canvas.setWidth(screenWidth) canvas1FabricVue.value.canvas.setWidth(screenWidth)
canvas1FabricVue.value.canvas.setHeight(screenHeight) canvas1FabricVue.value.canvas.setHeight(screenHeight)
displayData(canvas1FabricVue, canvsStore, canvasobj, fabric, img) displayData(canvas1FabricVue, canvsStore, canvasobj, fabric, img)
} }
} else { } else {
canvasFabricVue.value.canvas.setHeight(screenHeight) canvasFabricVue.value.canvas.setHeight(screenHeight)
@ -102,7 +102,7 @@ const renderPage = async (canvasobj) => {
} }
img.remove() img.remove()
} }
// imgarrJSONdatacanvsStore.pageArr // imgarrJSONdatacanvsStore.pageArr
// canvsStore.pageArr.forEach((item) => { // canvsStore.pageArr.forEach((item) => {
// if (item.page == canvasobj.page) { // if (item.page == canvasobj.page) {
// imgarr.value.forEach((img) => { // imgarr.value.forEach((img) => {
@ -123,22 +123,52 @@ const loadPdf = async (canvasobj) => {
} }
const initPdf = async (type = 'default') => { const initPdf = async (type = 'default') => {
if(imgarr.value?.length){ imgarr.value.forEach((a) => {
if (a.index == 0) {
} a.JSONdata = canvasFabricVue.value.canvas.toJSON()
imgarr.value.forEach(a=>{ } else {
if(a.index==0){ a.JSONdata = canvas1FabricVue.value.canvas.toJSON()
a.JSONdata=canvasFabricVue.value.canvas.toJSON()
}else{
a.JSONdata=canvas1FabricVue.value.canvas.toJSON()
} }
}) })
if (type != 'default') {
const nameMap = new Map(canvsStore.pageArr.map((item) => [item.page, item.id]))
//
let promises = []
imgarr.value.forEach((item) => {
if (nameMap.has(item.page)) {
const params = {
id: nameMap.get(item.page),
contentData: JSON.stringify(item.JSONdata.objects)
}
promises.push(updateSmartBookMarkContent([params]))
} else {
promises.push(addsmartBookMark({
pageNum: item.page,
contentData: JSON.stringify(item.JSONdata.objects),
bookId: props.pdfObj.bookId,
type: '教材',
source: 'smarttalk'
}))
}
})
Promise.all(promises).then(res=>{
getBookMarkById(props.pdfObj.bookId).then(res=>{
const pageArr=getUniqueArrayByLastOccurrence(res.data)
canvsStore.pageArr=[]
pageArr.forEach((a) => {
canvsStore.pageArr.push({ page: a.pageNum, id: a.id, JSONdata: a.contentData })
})
})
})
}
// //
savecanvsStore(imgarr, canvsStore) // savecanvsStore(imgarr, canvsStore)
if(props.pdfObj.numberOfPdf == 1){ if (props.pdfObj.numberOfPdf == 1) {
// imgarr.value[0]
canvasFabricVue.value.history.clean() canvasFabricVue.value.history.clean()
}else{ } else {
canvasFabricVue.value.history.clean() canvasFabricVue.value.history.clean()
canvas1FabricVue.value.history.clean() canvas1FabricVue.value.history.clean()
} }
@ -179,77 +209,91 @@ const initPdf = async (type = 'default') => {
} }
} }
} }
//page
const getUniqueArrayByLastOccurrence=(array)=> {
const uniqueItems = array.reduce((acc, current) => {
// 使 Map pageNum
acc.set(current.pageNum, current);
return acc;
}, new Map());
// Map
const resultArray = Array.from(uniqueItems.values());
return resultArray;
}
const initPdfone = async () => { const initPdfone = async () => {
setTimeout( async() => { setTimeout(async () => {
const option = { freeDrawingCursor: 'default' } const option = { freeDrawingCursor: 'default' }
const canvas2 = new fabricVue() const canvas2 = new fabricVue()
await canvas2.initCanvas(fabriccanvas1.value, option) await canvas2.initCanvas(fabriccanvas1.value, option)
canvas2.canvas.setWidth(window.innerWidth/2-100) canvas2.canvas.setWidth(window.innerWidth / 2 - 100)
canvas1FabricVue.value=canvas2 canvas1FabricVue.value = canvas2
await initPdf('addOnePage') await initPdf('addOnePage')
}, 0) }, 0)
} }
onMounted(async () => { onMounted(async () => {
try { try {
const pdf = await pdfjsLib.getDocument(props.pdfObj.pdfUrl).promise const pdf = await pdfjsLib.getDocument(props.pdfObj.pdfUrl).promise
numPagesTotal.value = pdf.numPages numPagesTotal.value = pdf.numPages
// fabriccanvas // fabriccanvas
const option = { freeDrawingCursor: 'default'} const option = { freeDrawingCursor: 'default' }
const canvas1 = new fabricVue() const canvas1 = new fabricVue()
// canvas1.boardConfig.mode= TYPES.ActionMode.OTHER
// canvas1.boardConfig.mode= TYPES.ActionMode.ERASE
await canvas1.initCanvas(fabriccanvas.value, option) await canvas1.initCanvas(fabriccanvas.value, option)
canvas1.canvas.setWidth(window.innerWidth/2-100) canvas1.canvas.setWidth(window.innerWidth / 2 - 100)
// canvas1.canvas.isDrawingMode=false // canvas1.canvas.isDrawingMode=false
canvas1.canvas.selectable = false; canvasFabricVue.value = canvas1
canvas1.canvas.evented = false;
canvasFabricVue.value=canvas1
const canvas2 = new fabricVue() const canvas2 = new fabricVue()
canvas2.boardConfig.mode = TYPES.ActionMode.DRAW
await canvas2.initCanvas(fabriccanvas1.value, option) await canvas2.initCanvas(fabriccanvas1.value, option)
canvas2.canvas.setWidth(window.innerWidth/2-100) canvas2.canvas.setWidth(window.innerWidth / 2 - 100)
canvas2.canvas.isDrawingMode=false // canvas2.canvas.isDrawingMode=false
canvas1FabricVue.value=canvas2 canvas1FabricVue.value = canvas2
window.test={canvas1,canvas2} window.test = { canvas1, canvas2 }
emit('update:numPagesTotal', pdf.numPages) emit('update:numPagesTotal', pdf.numPages)
initPdf() if (props.pdfObj.allPageData.length) {
}catch (error) { props.pdfObj.allPageData.forEach((a) => {
if (a.pageNum == 1 || a.pageNum == 2) {
canvsStore.pageArr.push({ page: a.pageNum, id: a.id, JSONdata: a.contentData })
}
})
}
await initPdf()
} catch (error) {
console.log(error) console.log(error)
ElMessage.error('pdf文件错误') ElMessage.error('pdf文件错误')
} }
// 2canvas // 2canvas
// handleevent(fabriccanvas.value, imgarr) // handleevent(fabriccanvas.value, imgarr)
// handleevent(fabriccanvas1.value, imgarr, 'two') // handleevent(fabriccanvas1.value, imgarr, 'two')
}) })
const handleTouchStart = (e) => { const handleTouchStart = (e) => {
console.log(e) console.log(e)
}
};
const handleTouchMove = (e) => { const handleTouchMove = (e) => {
console.log(e) console.log(e)
}; }
const handleTouchEnd = (e) => { const handleTouchEnd = (e) => {
console.log(e) console.log(e)
}
};
const handleMouseDown = (e) => { const handleMouseDown = (e) => {
// console.log(e) // console.log(e)
}; }
const handleMouseMove = (e) => { const handleMouseMove = (e) => {
// console.log(e) // console.log(e)
}
};
const handleMouseUp = (e) => { const handleMouseUp = (e) => {
// console.log(e) // console.log(e)
}
};
defineExpose({ defineExpose({
initPdf, initPdf,
@ -273,4 +317,7 @@ defineExpose({
margin-right: 10px; margin-right: 10px;
} }
} }
.ispointer {
pointer-events: none;
}
</style> </style>

View File

@ -1615,6 +1615,7 @@ export class fabricVue {
break break
case TYPES.ActionMode.OTHER: // 其他(工具选择) case TYPES.ActionMode.OTHER: // 其他(工具选择)
this.canvas.isDrawingMode = false this.canvas.isDrawingMode = false
objectSet.selectable = false
this.canvas.freeDrawingCursor = 'default' this.canvas.freeDrawingCursor = 'default'
break break
default: default:

View File

@ -1,3 +1,4 @@
// 所有事件 // 所有事件
export function handleevent(canvas, imgarr, type = 'defalut') { export function handleevent(canvas, imgarr, type = 'defalut') {
// // 鼠标按下 // // 鼠标按下
@ -35,12 +36,12 @@ export function savecanvsStore(imgarr, canvsStore) {
} }
// 重显数据 // 重显数据
export function displayData(FabricVue, canvsStore, canvasobj, fabric, img) { export function displayData(FabricVue, canvsStore, canvasobj, fabric, img) {
// 初始化 // 初始化
const canvas = FabricVue.value.canvas const canvas = FabricVue.value.canvas
if (!canvas) { if (!canvas) {
return return
} }
if (!canvsStore.pageArr.length) { if (!canvsStore.pageArr.length) {
fabric.Image.fromURL( fabric.Image.fromURL(
img.src, img.src,
@ -49,11 +50,15 @@ export function displayData(FabricVue, canvsStore, canvasobj, fabric, img) {
left: 0, left: 0,
top: 0, top: 0,
scaleX: canvas.width / img.width, scaleX: canvas.width / img.width,
scaleY: canvas.height / img.height scaleY: canvas.height / img.height,
erasable: false // 不允许擦拭
}) })
// FabricVue.setBackgroundImage(image, FabricVue.renderAll.bind(FabricVue)) // FabricVue.setBackgroundImage(image, FabricVue.renderAll.bind(FabricVue))
// setBackgroundImage(image,FabricVue) // setBackgroundImage(image,FabricVue)
// canvas.setBackgroundImage(image, canvas.renderAll.bind(canvas));
canvas.setBackgroundImage(image, () => { canvas.setBackgroundImage(image, () => {
canvas.renderAll.bind(canvas)
FabricVue.value.render() FabricVue.value.render()
}) })
}, },
@ -61,16 +66,44 @@ export function displayData(FabricVue, canvsStore, canvasobj, fabric, img) {
) )
return return
} }
canvsStore.pageArr.forEach((item) => {
//初始化 const isfind=findObjectByPage(canvsStore.pageArr,canvasobj.page)
if (item.page == canvasobj.page) { if(isfind){
canvas.loadFromJSON(item.JSONdata, () => { const canvdata={
// 在所有对象加载完成后重新渲染画布 objects:JSON.parse(isfind.JSONdata),
// Utils.handleCanvasJSONLoaded(canvas) version: "5.3.0"
canvas.requestRenderAll() // 批量重绘 }
}) requestAnimationFrame(function () {
} else { canvas.loadFromJSON(canvdata, () => {
// 使用 requestAnimationFrame 来更新画布,确保在下一帧进行重绘 // 在所有对象加载完成后重新渲染画布
// Utils.handleCanvasJSONLoaded(canvas)
canvas.requestRenderAll() // 批量重绘
})
fabric.Image.fromURL(
img.src,
(image) => {
image.set({
left: 0,
top: 0,
scaleX: canvas.width / img.width,
scaleY: canvas.height / img.height,
selectable: false,
evented: false,
erasable: false // 不允许擦拭
})
// canvas.setBackgroundImage(image, canvas.renderAll.bind(canvas));
canvas.setBackgroundImage(image, () => {
canvas.renderAll.bind(canvas)
FabricVue.value.render()
})
},
{crossOrigin: 'anonymous'}
)
// 渲染所有对象
canvas.requestRenderAll() // 批量重绘
})
}else{
// 使用 requestAnimationFrame 来更新画布,确保在下一帧进行重绘
// // 清除 Canvas // // 清除 Canvas
// canvas.clear() // canvas.clear()
requestAnimationFrame(function () { requestAnimationFrame(function () {
@ -81,9 +114,14 @@ export function displayData(FabricVue, canvsStore, canvasobj, fabric, img) {
left: 0, left: 0,
top: 0, top: 0,
scaleX: canvas.width / img.width, scaleX: canvas.width / img.width,
scaleY: canvas.height / img.height scaleY: canvas.height / img.height,
selectable: false,
evented: false,
erasable: false // 不允许擦拭
}) })
// canvas.setBackgroundImage(image, canvas.renderAll.bind(canvas));
canvas.setBackgroundImage(image, () => { canvas.setBackgroundImage(image, () => {
canvas.renderAll.bind(canvas)
FabricVue.value.render() FabricVue.value.render()
}) })
}, },
@ -92,8 +130,53 @@ export function displayData(FabricVue, canvsStore, canvasobj, fabric, img) {
// 渲染所有对象 // 渲染所有对象
canvas.requestRenderAll() // 批量重绘 canvas.requestRenderAll() // 批量重绘
}) })
} }
})
// canvsStore.pageArr.forEach((item) => {
// //初始化
// if (item.page == canvasobj.page) {
// // item.JSONdata
// canvas.loadFromJSON(JSON.parse(item.JSONdata), () => {
// // 在所有对象加载完成后重新渲染画布
// // Utils.handleCanvasJSONLoaded(canvas)
// canvas.requestRenderAll() // 批量重绘
// })
// } else {
// // 使用 requestAnimationFrame 来更新画布,确保在下一帧进行重绘
// // // 清除 Canvas
// // canvas.clear()
// requestAnimationFrame(function () {
// fabric.Image.fromURL(
// img.src,
// (image) => {
// image.set({
// left: 0,
// top: 0,
// scaleX: canvas.width / img.width,
// scaleY: canvas.height / img.height,
// selectable: false,
// evented: false,
// erasable: false // 不允许擦拭
// })
// // canvas.setBackgroundImage(image, canvas.renderAll.bind(canvas));
// canvas.setBackgroundImage(image, () => {
// canvas.renderAll.bind(canvas)
// FabricVue.value.render()
// })
// },
// {crossOrigin: 'anonymous'}
// )
// // 渲染所有对象
// canvas.requestRenderAll() // 批量重绘
// })
// }
// })
}
// 找到page一样的
const findObjectByPage=(array, page)=> {
const foundObject = array.find(obj => obj.page === page);
return foundObject || false;
} }
//page 一样替换 //page 一样替换

View File

@ -33,19 +33,26 @@
<script setup> <script setup>
import { ref, onMounted, watch, reactive } from 'vue' import { ref, onMounted, watch, reactive } from 'vue'
import { useRoute } from 'vue-router';
import * as pdfjsLib from 'pdfjs-dist/legacy/build/pdf' import * as pdfjsLib from 'pdfjs-dist/legacy/build/pdf'
import pdfCanvas from '@/components/pdf/index.vue' import pdfCanvas from '@/components/pdf/index.vue'
import { getStaticUrl } from '@/utils/tool' import { getStaticUrl } from '@/utils/tool'
const { ipcRenderer } = require('electron') const { ipcRenderer } = require('electron')
import { getBookMarkById } from '@/api/eTextbook/index'
// const getStaticUrl=(url)=>{
// return url
// }
pdfjsLib.GlobalWorkerOptions.workerSrc = getStaticUrl('/lib/build/pdf.worker.mjs') pdfjsLib.GlobalWorkerOptions.workerSrc = getStaticUrl('/lib/build/pdf.worker.mjs')
// //
const pdfObj = reactive({ const pdfObj = reactive({
numberOfPdf: 2, // numberOfPdf: 2, //
pdfUrl: getStaticUrl('aaa.pdf', 'user', 'selfFile', true), pdfUrl: getStaticUrl('aaa.pdf', 'user', 'selfFile', true),
allPageData:[],
bookId:null,
numPages: 1 // numPages: 1 //
}) })
const textbookId=ref(null)
// //
const numPagesTotal = ref(0) const numPagesTotal = ref(0)
const pdfCanvaslist = ref(null) const pdfCanvaslist = ref(null)
@ -60,7 +67,7 @@ const navtopage = (type) => {
pdfObj.numPages += num pdfObj.numPages += num
} }
if (pdfObj.numPages > numPagesTotal.value) return if (pdfObj.numPages > numPagesTotal.value) return
pdfCanvaslist.value.initPdf() pdfCanvaslist.value.initPdf('rest')
} }
// //
const minimize = () => { const minimize = () => {
@ -70,7 +77,7 @@ const handleUpdate = (data) => {
numPagesTotal.value = data numPagesTotal.value = data
if (numPagesTotal.value == 1) { if (numPagesTotal.value == 1) {
pdfObj.numberOfPdf = 1 pdfObj.numberOfPdf = 1
pdfCanvaslist.value.initPdf('restone') pdfCanvaslist.value.initPdf('rest')
} }
} }
// //
@ -87,10 +94,33 @@ const switchPageMode = () => {
} else { } else {
// //
pdfObj.numberOfPdf = 1 pdfObj.numberOfPdf = 1
pdfCanvaslist.value.initPdf('restone') pdfCanvaslist.value.initPdf('rest')
} }
} }
onMounted(async () => {}) onMounted(async () => {
const route = useRoute();
textbookId.value = route.query.textbookId
pdfObj.bookId=textbookId.value
getBookMarkById(textbookId.value).then(res=>{
pdfObj.allPageData=getUniqueArrayByLastOccurrence(res.data)
console.log(pdfObj.allPageData)
})
})
//page
const getUniqueArrayByLastOccurrence=(array)=> {
const uniqueItems = array.reduce((acc, current) => {
// 使 Map pageNum
acc.set(current.pageNum, current);
return acc;
}, new Map());
// Map
const resultArray = Array.from(uniqueItems.values());
return resultArray;
}
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>

View File

@ -437,7 +437,8 @@ export default {
}, },
// PDF- // PDF-
navtoPdf() { navtoPdf() {
createWindow('open-PDF', { url: '/classBegins/index' }) console.log(this.uploadData.textbookId)
createWindow('open-PDF', { url: '/classBegins/index?textbookId='+this.uploadData.textbookId })
}, },
// - // -
openLesson() { openLesson() {