如何使用 PDF.js 和 jQuery 在 PDF 顶部创建可拖动元素
How to create a draggable element on top of a PDF using PDF.js and jQuery
我正在创建一项服务,使用 PDF.js 和 jQuery 用图像标记 pdf。我设法使用 PDF.js 创建了一个可拖动对象,但该对象在被拖动时留下了过去对象的痕迹。
我使用 context.clearRect(0, 0, canvas.width, canvas.height);
清除了过去的对象,但它也清除了 canvas 中的基础 PDF。
如何在不影响底层 PDF 的情况下拖动此对象?
这是我到目前为止所做的。
我正在使用以下代码将 PDF 加载到 canvas。
function loadPdfPreview(base64pdf){
pdfjsLib.GlobalWorkerOptions.workerSrc = 'https://cdnjs.cloudflare.com/ajax/libs/pdf.js/2.0.943/pdf.worker.min.js';
var loadingTask = pdfjsLib.getDocument({data: base64pdf});
loadingTask.promise.then(function (pdf) {
// Fetch the first page
pdf.getPage(1).then(function (page) {
var scale = 1.0;
var viewport = page.getViewport(scale);
// Prepare canvas using PDF page dimensions
canvas = document.getElementById('pdf-canvas');
context = canvas.getContext('2d');
canvas.height = viewport.height;
canvas.width = viewport.width;
canvasOffset = $("#pdf-canvas").offset();
offsetX = canvasOffset.left;
offsetY = canvasOffset.top;
// Render PDF page into canvas context
var renderContext = {
canvasContext: context,
viewport: viewport
};
page.render(renderContext).then(function () {
// creating the dummy object on success
drawObjectFromBlueprint(blueprint);
}, function (e) {
console.log(e);
});
});
});
}
pdf 加载到 canvas 后,我使用以下函数在 canvas 顶部绘制对象。
function drawObjectFromBlueprint(blueprint) {
// drawing a draggable element inside the canvas
context.strokeStyle = "lightgray";
// Clearing the previous dummy objects
context.clearRect(0, 0, canvas.width, canvas.height);
// drawing the dummy object
context.beginPath();
context.moveTo(blueprint.x, blueprint.y);
context.lineTo(blueprint.right, blueprint.y);
context.lineTo(blueprint.right, blueprint.bottom);
context.lineTo(blueprint.x, blueprint.bottom);
context.closePath();
context.fillStyle = blueprint.fill;
context.fill();
context.stroke();
}
我使用以下代码处理鼠标移动事件。
function handleMouseMove(e) {
var mouseX = parseInt(e.clientX - offsetX1);
var mouseY = parseInt(e.clientY - offsetY1);
// always update the global blueprint
blueprint.x += (mouseX - lastX);
blueprint.y += (mouseY - lastY);
blueprint.right = blueprint.x + blueprint.width;
blueprint.bottom = blueprint.y + blueprint.height;
lastX = mouseX;
lastY = mouseY;
drawObjectFromBlueprint(blueprint);
}
然后我使用以下代码监听鼠标移动事件。
$("#drawable-canvas").mousemove(function (e) {
handleMouseMove(e);
});
我想在不影响底层 PDF 的情况下重新绘制对象。尝试通过清除整个 canvas 来加载 PDF 并重新绘制对象,但它没有按预期工作。
在page.render
方法的回调中,pdf页面会绘制在canvas上。画出来的图要单独保存,这样原图才不会拖动消失
// maybe globalScope...?
const tempCanvas = document.createElement('canvas');
const tempCtx = tempCanvas.getContext('2d');
// your code
page.render(renderContext).then(function () {
// Save the original page image.
tempCanvas.width = canvas.width;
tempCanvas.height = canvas.height;
tempCtx.drawImage(canvas, 0, 0);
// creating the dummy object on success
drawObjectFromBlueprint(blueprint);
}, ...
接下来请修改为使用drawObjectFromBlueprint
中的原页面图片绘制。
function drawObjectFromBlueprint(blueprint) {
// draw original page image
context.drawImage(tempCanvas, 0, 0);
// drawing a draggable element inside the canvas
context.strokeStyle = "lightgray";
...
}
经过两个小时的尝试,找出了执行此操作的方法。正如@Nikolaus 建议的那样,我使用了两个 canvases,并使用底部 canvas 加载 PDF,顶部 canvas 用于绘图。
以下是我的HTML:
<div class="col-md-12" id="pdfDisplay" style="display: none;">
<div id="pageContainer" class="pdfViewer nopadding" style="background-color:transparent">
<canvas id="pdf-canvas" style="border:1px solid black"></canvas>
<canvas id="drawable-canvas" style="border:1px solid black"></canvas>
</div>
</div>
以下是我 CSS 将两个 canvas 放在彼此之上的方法。
#pageContainer { position: relative; }
#drawable-canvas { position: absolute; top: 0; left: 0; }
以下是我的全局 Javascript 变量:
var isUploading = false;
var base64pdf = "";
var initX = 50;
var initY = 50;
var initWidth = 200;
var initHeight = 150;
// blueprint options are in pixels
// this blueprint holds the latest values for the draggable object
// always update this global blueprint when making a change so it holds the latest values
var blueprint = {
x: initX,
y: initY,
width: initWidth,
height: initHeight,
right: (initX+initWidth), // x + width
bottom: (initY+initHeight), // y + height
fill: "skyblue"
};
var context = null;
var canvas = null;
var drawableContext = null;
var drawableCanvas = null;
var canvasOffset = null;
var offsetX = 0;
var offsetY = 0;
var canvasOffset1 = null;
var offsetX1 = 0;
var offsetY1 = 0;
var lastX = 0;
var lastY = 0;
var mouseIsDown = false;
Javascript 监听鼠标向上、向下和移动的函数,因为我只需要在使用鼠标拖动对象时跟踪鼠标移动。
$("#drawable-canvas").mousedown(function (e) {
var mouseX = parseInt(e.clientX - offsetX);
var mouseY = parseInt(e.clientY - offsetY);
lastX = mouseX;
lastY = mouseY;
mouseIsDown = true;
});
$("#drawable-canvas").mousemove(function (e) {
handleMouseMove(e);
});
$("#drawable-canvas").mouseup(function (e) {
mouseIsDown = false;
});
Javascript函数加载PDF到底部canvas.
function loadPdfPreview(base64pdf){
pdfjsLib.GlobalWorkerOptions.workerSrc = 'https://cdnjs.cloudflare.com/ajax/libs/pdf.js/2.0.943/pdf.worker.min.js';
var loadingTask = pdfjsLib.getDocument({data: base64pdf});
loadingTask.promise.then(function (pdf) {
// Fetch the first page
pdf.getPage(1).then(function (page) {
var scale = 1.0;
var viewport = page.getViewport(scale);
// Prepare canvas using PDF page dimensions
canvas = document.getElementById('pdf-canvas');
context = canvas.getContext('2d');
canvas.height = viewport.height;
canvas.width = viewport.width;
canvasOffset = $("#pdf-canvas").offset();
offsetX = canvasOffset.left;
offsetY = canvasOffset.top;
canvasOffset1 = $("#drawable-canvas").offset();
offsetX1 = canvasOffset1.left;
offsetY1 = canvasOffset1.top;
// creating the drawable-canvas canvas for drawing purposes without affecting the pdf-canvas
// it has identical width and height and X and Y values
drawableCanvas = document.getElementById('drawable-canvas');;
drawableCanvas.height = viewport.height;
//bringing the drawable canvas up using z-index
drawableCanvas.style.zIndex = 1;
drawableCanvas.width = viewport.width;
drawableContext = drawableCanvas.getContext('2d');
// Render PDF page into canvas context
var renderContext = {
canvasContext: context,
viewport: viewport
};
page.render(renderContext).then(function () {
// creating the dummy object on success
drawObjectFromBlueprint(blueprint);
}, function (e) {
console.log(e);
});
});
});
}
处理鼠标移动(拖动对象):
function handleMouseMove(e) {
if (!mouseIsDown) {
return;
}
var mouseX = parseInt(e.clientX - offsetX1);
var mouseY = parseInt(e.clientY - offsetY1);
// always update the global blueprint
blueprint.x += (mouseX - lastX);
blueprint.y += (mouseY - lastY);
blueprint.right = blueprint.x + blueprint.width;
blueprint.bottom = blueprint.y + blueprint.height;
lastX = mouseX;
lastY = mouseY;
drawObjectFromBlueprint(blueprint);
console.log(blueprint);
}
Javascript函数在drawablecanvas上绘制对象,完全独立于pdf-canvas.
function drawObjectFromBlueprint(blueprint) {
// drawing a draggable element inside the canvas
drawableContext.strokeStyle = "lightgray";
// Clearing the previous dummy objects
drawableContext.clearRect(0, 0, drawableCanvas.width, drawableCanvas.height);
// drawing the dummy object
drawableContext.beginPath();
drawableContext.moveTo(blueprint.x, blueprint.y);
drawableContext.lineTo(blueprint.right, blueprint.y);
drawableContext.lineTo(blueprint.right, blueprint.bottom);
drawableContext.lineTo(blueprint.x, blueprint.bottom);
drawableContext.closePath();
drawableContext.fillStyle = blueprint.fill;
drawableContext.fill();
drawableContext.stroke();
}
我正在创建一项服务,使用 PDF.js 和 jQuery 用图像标记 pdf。我设法使用 PDF.js 创建了一个可拖动对象,但该对象在被拖动时留下了过去对象的痕迹。
我使用 context.clearRect(0, 0, canvas.width, canvas.height);
清除了过去的对象,但它也清除了 canvas 中的基础 PDF。
如何在不影响底层 PDF 的情况下拖动此对象?
这是我到目前为止所做的。
我正在使用以下代码将 PDF 加载到 canvas。
function loadPdfPreview(base64pdf){
pdfjsLib.GlobalWorkerOptions.workerSrc = 'https://cdnjs.cloudflare.com/ajax/libs/pdf.js/2.0.943/pdf.worker.min.js';
var loadingTask = pdfjsLib.getDocument({data: base64pdf});
loadingTask.promise.then(function (pdf) {
// Fetch the first page
pdf.getPage(1).then(function (page) {
var scale = 1.0;
var viewport = page.getViewport(scale);
// Prepare canvas using PDF page dimensions
canvas = document.getElementById('pdf-canvas');
context = canvas.getContext('2d');
canvas.height = viewport.height;
canvas.width = viewport.width;
canvasOffset = $("#pdf-canvas").offset();
offsetX = canvasOffset.left;
offsetY = canvasOffset.top;
// Render PDF page into canvas context
var renderContext = {
canvasContext: context,
viewport: viewport
};
page.render(renderContext).then(function () {
// creating the dummy object on success
drawObjectFromBlueprint(blueprint);
}, function (e) {
console.log(e);
});
});
});
}
pdf 加载到 canvas 后,我使用以下函数在 canvas 顶部绘制对象。
function drawObjectFromBlueprint(blueprint) {
// drawing a draggable element inside the canvas
context.strokeStyle = "lightgray";
// Clearing the previous dummy objects
context.clearRect(0, 0, canvas.width, canvas.height);
// drawing the dummy object
context.beginPath();
context.moveTo(blueprint.x, blueprint.y);
context.lineTo(blueprint.right, blueprint.y);
context.lineTo(blueprint.right, blueprint.bottom);
context.lineTo(blueprint.x, blueprint.bottom);
context.closePath();
context.fillStyle = blueprint.fill;
context.fill();
context.stroke();
}
我使用以下代码处理鼠标移动事件。
function handleMouseMove(e) {
var mouseX = parseInt(e.clientX - offsetX1);
var mouseY = parseInt(e.clientY - offsetY1);
// always update the global blueprint
blueprint.x += (mouseX - lastX);
blueprint.y += (mouseY - lastY);
blueprint.right = blueprint.x + blueprint.width;
blueprint.bottom = blueprint.y + blueprint.height;
lastX = mouseX;
lastY = mouseY;
drawObjectFromBlueprint(blueprint);
}
然后我使用以下代码监听鼠标移动事件。
$("#drawable-canvas").mousemove(function (e) {
handleMouseMove(e);
});
我想在不影响底层 PDF 的情况下重新绘制对象。尝试通过清除整个 canvas 来加载 PDF 并重新绘制对象,但它没有按预期工作。
在page.render
方法的回调中,pdf页面会绘制在canvas上。画出来的图要单独保存,这样原图才不会拖动消失
// maybe globalScope...?
const tempCanvas = document.createElement('canvas');
const tempCtx = tempCanvas.getContext('2d');
// your code
page.render(renderContext).then(function () {
// Save the original page image.
tempCanvas.width = canvas.width;
tempCanvas.height = canvas.height;
tempCtx.drawImage(canvas, 0, 0);
// creating the dummy object on success
drawObjectFromBlueprint(blueprint);
}, ...
接下来请修改为使用drawObjectFromBlueprint
中的原页面图片绘制。
function drawObjectFromBlueprint(blueprint) {
// draw original page image
context.drawImage(tempCanvas, 0, 0);
// drawing a draggable element inside the canvas
context.strokeStyle = "lightgray";
...
}
经过两个小时的尝试,找出了执行此操作的方法。正如@Nikolaus 建议的那样,我使用了两个 canvases,并使用底部 canvas 加载 PDF,顶部 canvas 用于绘图。
以下是我的HTML:
<div class="col-md-12" id="pdfDisplay" style="display: none;">
<div id="pageContainer" class="pdfViewer nopadding" style="background-color:transparent">
<canvas id="pdf-canvas" style="border:1px solid black"></canvas>
<canvas id="drawable-canvas" style="border:1px solid black"></canvas>
</div>
</div>
以下是我 CSS 将两个 canvas 放在彼此之上的方法。
#pageContainer { position: relative; }
#drawable-canvas { position: absolute; top: 0; left: 0; }
以下是我的全局 Javascript 变量:
var isUploading = false;
var base64pdf = "";
var initX = 50;
var initY = 50;
var initWidth = 200;
var initHeight = 150;
// blueprint options are in pixels
// this blueprint holds the latest values for the draggable object
// always update this global blueprint when making a change so it holds the latest values
var blueprint = {
x: initX,
y: initY,
width: initWidth,
height: initHeight,
right: (initX+initWidth), // x + width
bottom: (initY+initHeight), // y + height
fill: "skyblue"
};
var context = null;
var canvas = null;
var drawableContext = null;
var drawableCanvas = null;
var canvasOffset = null;
var offsetX = 0;
var offsetY = 0;
var canvasOffset1 = null;
var offsetX1 = 0;
var offsetY1 = 0;
var lastX = 0;
var lastY = 0;
var mouseIsDown = false;
Javascript 监听鼠标向上、向下和移动的函数,因为我只需要在使用鼠标拖动对象时跟踪鼠标移动。
$("#drawable-canvas").mousedown(function (e) {
var mouseX = parseInt(e.clientX - offsetX);
var mouseY = parseInt(e.clientY - offsetY);
lastX = mouseX;
lastY = mouseY;
mouseIsDown = true;
});
$("#drawable-canvas").mousemove(function (e) {
handleMouseMove(e);
});
$("#drawable-canvas").mouseup(function (e) {
mouseIsDown = false;
});
Javascript函数加载PDF到底部canvas.
function loadPdfPreview(base64pdf){
pdfjsLib.GlobalWorkerOptions.workerSrc = 'https://cdnjs.cloudflare.com/ajax/libs/pdf.js/2.0.943/pdf.worker.min.js';
var loadingTask = pdfjsLib.getDocument({data: base64pdf});
loadingTask.promise.then(function (pdf) {
// Fetch the first page
pdf.getPage(1).then(function (page) {
var scale = 1.0;
var viewport = page.getViewport(scale);
// Prepare canvas using PDF page dimensions
canvas = document.getElementById('pdf-canvas');
context = canvas.getContext('2d');
canvas.height = viewport.height;
canvas.width = viewport.width;
canvasOffset = $("#pdf-canvas").offset();
offsetX = canvasOffset.left;
offsetY = canvasOffset.top;
canvasOffset1 = $("#drawable-canvas").offset();
offsetX1 = canvasOffset1.left;
offsetY1 = canvasOffset1.top;
// creating the drawable-canvas canvas for drawing purposes without affecting the pdf-canvas
// it has identical width and height and X and Y values
drawableCanvas = document.getElementById('drawable-canvas');;
drawableCanvas.height = viewport.height;
//bringing the drawable canvas up using z-index
drawableCanvas.style.zIndex = 1;
drawableCanvas.width = viewport.width;
drawableContext = drawableCanvas.getContext('2d');
// Render PDF page into canvas context
var renderContext = {
canvasContext: context,
viewport: viewport
};
page.render(renderContext).then(function () {
// creating the dummy object on success
drawObjectFromBlueprint(blueprint);
}, function (e) {
console.log(e);
});
});
});
}
处理鼠标移动(拖动对象):
function handleMouseMove(e) {
if (!mouseIsDown) {
return;
}
var mouseX = parseInt(e.clientX - offsetX1);
var mouseY = parseInt(e.clientY - offsetY1);
// always update the global blueprint
blueprint.x += (mouseX - lastX);
blueprint.y += (mouseY - lastY);
blueprint.right = blueprint.x + blueprint.width;
blueprint.bottom = blueprint.y + blueprint.height;
lastX = mouseX;
lastY = mouseY;
drawObjectFromBlueprint(blueprint);
console.log(blueprint);
}
Javascript函数在drawablecanvas上绘制对象,完全独立于pdf-canvas.
function drawObjectFromBlueprint(blueprint) {
// drawing a draggable element inside the canvas
drawableContext.strokeStyle = "lightgray";
// Clearing the previous dummy objects
drawableContext.clearRect(0, 0, drawableCanvas.width, drawableCanvas.height);
// drawing the dummy object
drawableContext.beginPath();
drawableContext.moveTo(blueprint.x, blueprint.y);
drawableContext.lineTo(blueprint.right, blueprint.y);
drawableContext.lineTo(blueprint.right, blueprint.bottom);
drawableContext.lineTo(blueprint.x, blueprint.bottom);
drawableContext.closePath();
drawableContext.fillStyle = blueprint.fill;
drawableContext.fill();
drawableContext.stroke();
}