Open MortenHannemose opened 1 year ago
Thanks! Glad you found it useful.
To have the behaviour you described, use the bookmarklet below. For reference, if others want to make adjust the code to their preferences, the code below is a few lines change from the default behaviour here and here.
javascript:(async () => {
const app = window.PDFViewerApplication;
const anchor = document.getElementById("viewer");
if ("_previewHandler" in app) {
anchor.removeEventListener("mouseover", app._previewHandler);
delete app._previewHandler;
delete app._previewing;
return;
}
const box = anchor.getBoundingClientRect();
const halfWidth = (box.left + box.right) / 2;
const destinations = await app.pdfDocument.getDestinations();
app._previewing = false;
async function mouseoverHandler(event) {
if (event.target.className != "internalLink" || app._previewing) return;
const hash = event.target.hash;
const parent = event.target.parentElement;
const preview = document.createElement("canvas");
const previewStyle = preview.style;
previewStyle.border = "1px solid black";
previewStyle.direction = "ltr";
previewStyle.position = "fixed";
previewStyle.zIndex = "2";
previewStyle.top = `${event.clientY + 4}px`;
previewStyle.boxShadow = "5px 5px 5px black, -5px 5px 5px black";
const namedDest = decodeURIComponent(hash.substring(1));
const explicitDest =
namedDest in destinations
? destinations[namedDest]
: JSON.parse(namedDest);
const pageNumber = app.pdfLinkService._cachedPageNumber(explicitDest[0]);
app.pdfDocument.getPage(pageNumber).then(function (page) {
const tempViewport = page.getViewport({ scale: 1.0 });
const height = tempViewport.height * 1.2 * app.pdfViewer.currentScale;
const width = tempViewport.width * 1.2 * app.pdfViewer.currentScale;
previewStyle.height = `${height}px`;
previewStyle.width = `${width}px`;
previewStyle.left = `${event.clientX - 4}px`;
let offsetX, offsetY;
switch (explicitDest[1].name) {
case "XYZ":
offsetX = -explicitDest[2];
offsetY = explicitDest[3];
break;
case "FitH":
case "FitBH":
case "FitV":
case "FitBV":
offsetY = explicitDest[2];
break;
default:
console.log(`Oops, link ${explicitDest[1].name} is not supported.`);
}
const scale = 4;
const viewport = page.getViewport({
scale: scale,
offsetX: offsetX * scale,
offsetY: (offsetY - tempViewport.height) * scale,
});
preview.height = viewport.height;
preview.width = viewport.width;
const renderContext = {
canvasContext: preview.getContext("2d"),
viewport: viewport,
};
page.render(renderContext);
});
anchor.prepend(preview);
app._previewing = true;
parent.addEventListener("mouseleave", function (event) {
preview.remove();
app._previewing = false;
});
}
anchor.addEventListener("mouseover", mouseoverHandler);
app._previewHandler = mouseoverHandler;
})();
Ah, perfect. Thanks so much for sharing this. It's also much easier to edit the not minified code 😄
I also have a minor comment/something I was wondering. It seems that FitH
and FitBH
are the only modes that can specify a y-offset, and that if FitV
and FitBV
specify an offset, it's an offset in the x-direction. However, I've not encountered them in a real PDF, so this is only based on what I've read in the documentation.
And increasing the zIndex
to a large value such as 99 is necessary for some PDFs
Thank you for writing this code. I was looking for something exactly like this. When I mouse over a reference that's on the right side of the page, it still shows the entire page (unlike in the preview gif you have, where it only shows the right part of the page). If I zoom in and click the link, I'm taken to the correct place in both x and y. For reference the PDF is https://arxiv.org/pdf/1711.07971.pdf and I'm on Firefox 107.0 (latest version as of this post) Another difference to your gif is that the top left corner of the preview does not coincide with the mouse location. In both cases, the gif is the more desirable behavior.