added presentation viewers #9
@@ -1,4 +1,159 @@
|
||||
.md-nav__source{display: none;}
|
||||
.md-nav--primary > .md-nav__list > .md-nav__item > .md-nav__link {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
/* PDF Viewer Styles */
|
||||
.pdf-viewer-container {
|
||||
border: 1px solid #ccc;
|
||||
border-radius: 6px;
|
||||
overflow: hidden;
|
||||
font-family: sans-serif;
|
||||
margin-bottom: 20px;
|
||||
background-color: #f5f5f5;
|
||||
}
|
||||
|
||||
.pdf-viewer-header {
|
||||
background-color: #333;
|
||||
color: white;
|
||||
padding: 10px 15px;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.pdf-viewer-header .document-label {
|
||||
font-weight: bold;
|
||||
font-size: 0.9em;
|
||||
}
|
||||
|
||||
.pdf-viewer-header .download-btn {
|
||||
text-decoration: none;
|
||||
background-color: #e74c3c;
|
||||
color: white !important;
|
||||
padding: 6px 12px;
|
||||
border-radius: 4px;
|
||||
font-size: 0.85em;
|
||||
transition: background 0.2s;
|
||||
}
|
||||
|
||||
.pdf-viewer-header .download-btn:hover {
|
||||
background-color: #c0392b;
|
||||
}
|
||||
|
||||
.pdf-viewer-content {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
min-height: 200px;
|
||||
background-color: #525659;
|
||||
}
|
||||
|
||||
.pdf-viewer-content canvas {
|
||||
display: block;
|
||||
width: 100%;
|
||||
height: auto;
|
||||
}
|
||||
|
||||
.pdf-viewer-loading {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
color: white;
|
||||
}
|
||||
|
||||
.pdf-viewer-controls {
|
||||
background-color: #ddd;
|
||||
padding: 10px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
gap: 15px;
|
||||
}
|
||||
|
||||
.pdf-viewer-controls button {
|
||||
cursor: pointer;
|
||||
padding: 5px 15px;
|
||||
border: 1px solid #999;
|
||||
background: #eee;
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
.pdf-viewer-controls button:hover {
|
||||
background: #fff;
|
||||
}
|
||||
|
||||
.pdf-viewer-controls .page-info {
|
||||
font-size: 0.9em;
|
||||
}
|
||||
|
||||
/* HTML Viewer Styles */
|
||||
.html-viewer-container {
|
||||
border: 1px solid #ccc;
|
||||
border-radius: 6px;
|
||||
overflow: hidden;
|
||||
font-family: sans-serif;
|
||||
margin-bottom: 20px;
|
||||
background-color: #f5f5f5;
|
||||
}
|
||||
|
||||
.html-viewer-header {
|
||||
background-color: #333;
|
||||
color: white;
|
||||
padding: 10px 15px;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.html-viewer-header .document-label {
|
||||
font-weight: bold;
|
||||
font-size: 0.9em;
|
||||
}
|
||||
|
||||
.html-viewer-header .open-btn {
|
||||
text-decoration: none;
|
||||
background-color: #3498db;
|
||||
color: white !important;
|
||||
padding: 6px 12px;
|
||||
border-radius: 4px;
|
||||
font-size: 0.85em;
|
||||
transition: background 0.2s;
|
||||
}
|
||||
|
||||
.html-viewer-header .open-btn:hover {
|
||||
background-color: #2980b9;
|
||||
}
|
||||
|
||||
.html-viewer-content {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
aspect-ratio: 16 / 9;
|
||||
}
|
||||
|
||||
.html-viewer-content iframe {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
border: none;
|
||||
}
|
||||
|
||||
.html-viewer-controls {
|
||||
background-color: #ddd;
|
||||
padding: 10px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
gap: 15px;
|
||||
}
|
||||
|
||||
.html-viewer-controls button {
|
||||
cursor: pointer;
|
||||
padding: 5px 15px;
|
||||
border: 1px solid #999;
|
||||
background: #eee;
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
.html-viewer-controls button:hover {
|
||||
background: #fff;
|
||||
}
|
||||
66
docs/_javascripts/html-viewer.js
Normal file
66
docs/_javascripts/html-viewer.js
Normal file
@@ -0,0 +1,66 @@
|
||||
/**
|
||||
* Navigation controller for Remark.js presentations in iframes.
|
||||
*
|
||||
* Looks for elements with class 'html-viewer-container'.
|
||||
*/
|
||||
|
||||
document$.subscribe(({ body }) => {
|
||||
const containers = body.querySelectorAll('.html-viewer-container');
|
||||
|
||||
containers.forEach(container => {
|
||||
const iframe = container.querySelector('iframe');
|
||||
const prevBtn = container.querySelector('.prev-btn');
|
||||
const nextBtn = container.querySelector('.next-btn');
|
||||
const pageNumDisplay = container.querySelector('.page-num');
|
||||
const pageCountDisplay = container.querySelector('.page-count');
|
||||
|
||||
if (!iframe || !prevBtn || !nextBtn) return;
|
||||
|
||||
function updatePageInfo() {
|
||||
try {
|
||||
if (iframe.contentWindow && iframe.contentWindow.slideshow) {
|
||||
const slideshow = iframe.contentWindow.slideshow;
|
||||
const currentIndex = slideshow.getCurrentSlideIndex() + 1;
|
||||
const totalSlides = slideshow.getSlides().length;
|
||||
|
||||
if (pageNumDisplay) pageNumDisplay.textContent = currentIndex;
|
||||
if (pageCountDisplay) pageCountDisplay.textContent = totalSlides;
|
||||
}
|
||||
} catch (e) {
|
||||
// Silently fail if cross-origin or slideshow not yet loaded
|
||||
}
|
||||
}
|
||||
|
||||
prevBtn.addEventListener('click', () => {
|
||||
try {
|
||||
if (iframe.contentWindow && iframe.contentWindow.slideshow) {
|
||||
iframe.contentWindow.slideshow.gotoPreviousSlide();
|
||||
updatePageInfo();
|
||||
} else {
|
||||
iframe.contentWindow.dispatchEvent(new KeyboardEvent('keydown', { 'keyCode': 37 }));
|
||||
}
|
||||
} catch (e) {
|
||||
console.error("Could not navigate slideshow:", e);
|
||||
}
|
||||
});
|
||||
|
||||
nextBtn.addEventListener('click', () => {
|
||||
try {
|
||||
if (iframe.contentWindow && iframe.contentWindow.slideshow) {
|
||||
iframe.contentWindow.slideshow.gotoNextSlide();
|
||||
updatePageInfo();
|
||||
} else {
|
||||
iframe.contentWindow.dispatchEvent(new KeyboardEvent('keydown', { 'keyCode': 39 }));
|
||||
}
|
||||
} catch (e) {
|
||||
console.error("Could not navigate slideshow:", e);
|
||||
}
|
||||
});
|
||||
|
||||
// Update info when iframe loads
|
||||
iframe.addEventListener('load', updatePageInfo);
|
||||
|
||||
// Periodically update in case the user navigates using the keyboard inside the iframe
|
||||
setInterval(updatePageInfo, 500);
|
||||
});
|
||||
});
|
||||
108
docs/_javascripts/pdf-viewer.js
Normal file
108
docs/_javascripts/pdf-viewer.js
Normal file
@@ -0,0 +1,108 @@
|
||||
/**
|
||||
* Reusable PDF Viewer for MkDocs Material
|
||||
*
|
||||
* Uses PDF.js to render PDF files in a canvas.
|
||||
* Looks for elements with class 'pdf-viewer-container' and a 'data-url' attribute.
|
||||
*/
|
||||
|
||||
document$.subscribe(({ body }) => {
|
||||
const containers = body.querySelectorAll('.pdf-viewer-container[data-url]');
|
||||
|
||||
if (containers.length === 0) return;
|
||||
|
||||
// Load PDF.js worker if not already loaded
|
||||
if (window['pdfjs-dist/build/pdf'] && !window['pdfjs-dist/build/pdf'].GlobalWorkerOptions.workerSrc) {
|
||||
window['pdfjs-dist/build/pdf'].GlobalWorkerOptions.workerSrc = 'https://cdnjs.cloudflare.com/ajax/libs/pdf.js/2.16.105/pdf.worker.min.js';
|
||||
}
|
||||
|
||||
containers.forEach(container => {
|
||||
initPDFViewer(container);
|
||||
});
|
||||
});
|
||||
|
||||
function initPDFViewer(container) {
|
||||
const url = container.getAttribute('data-url');
|
||||
const canvas = container.querySelector('canvas');
|
||||
const pageNumDisplay = container.querySelector('.page-num');
|
||||
const pageCountDisplay = container.querySelector('.page-count');
|
||||
const prevBtn = container.querySelector('.prev-btn');
|
||||
const nextBtn = container.querySelector('.next-btn');
|
||||
const loadingMsg = container.querySelector('.pdf-viewer-loading');
|
||||
|
||||
if (!canvas || !url) return;
|
||||
|
||||
let pdfDoc = null;
|
||||
let pageNum = 1;
|
||||
let pageRendering = false;
|
||||
let pageNumPending = null;
|
||||
const scale = 2.0;
|
||||
const ctx = canvas.getContext('2d');
|
||||
|
||||
function renderPage(num) {
|
||||
pageRendering = true;
|
||||
|
||||
pdfDoc.getPage(num).then(page => {
|
||||
if (loadingMsg) loadingMsg.style.display = 'none';
|
||||
|
||||
const viewport = page.getViewport({ scale: scale });
|
||||
canvas.height = viewport.height;
|
||||
canvas.width = viewport.width;
|
||||
|
||||
const renderContext = {
|
||||
canvasContext: ctx,
|
||||
viewport: viewport
|
||||
};
|
||||
const renderTask = page.render(renderContext);
|
||||
|
||||
renderTask.promise.then(() => {
|
||||
pageRendering = false;
|
||||
if (pageNumPending !== null) {
|
||||
renderPage(pageNumPending);
|
||||
pageNumPending = null;
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
if (pageNumDisplay) pageNumDisplay.textContent = num;
|
||||
}
|
||||
|
||||
function queueRenderPage(num) {
|
||||
if (pageRendering) {
|
||||
pageNumPending = num;
|
||||
} else {
|
||||
renderPage(num);
|
||||
}
|
||||
}
|
||||
|
||||
if (prevBtn) {
|
||||
prevBtn.addEventListener('click', () => {
|
||||
if (pageNum <= 1) return;
|
||||
pageNum--;
|
||||
queueRenderPage(pageNum);
|
||||
});
|
||||
}
|
||||
|
||||
if (nextBtn) {
|
||||
nextBtn.addEventListener('click', () => {
|
||||
if (pageNum >= pdfDoc.numPages) return;
|
||||
pageNum++;
|
||||
queueRenderPage(pageNum);
|
||||
});
|
||||
}
|
||||
|
||||
// Load the document
|
||||
const pdfjsLib = window['pdfjs-dist/build/pdf'];
|
||||
if (!pdfjsLib) {
|
||||
console.error('PDF.js library not found');
|
||||
return;
|
||||
}
|
||||
|
||||
pdfjsLib.getDocument(url).promise.then(pdfDoc_ => {
|
||||
pdfDoc = pdfDoc_;
|
||||
if (pageCountDisplay) pageCountDisplay.textContent = pdfDoc.numPages;
|
||||
renderPage(pageNum);
|
||||
}).catch(err => {
|
||||
console.error('Error loading PDF:', err);
|
||||
if (loadingMsg) loadingMsg.textContent = "Error loading PDF.";
|
||||
});
|
||||
}
|
||||
@@ -12,7 +12,7 @@
|
||||
|
||||
| Date | Time | Event | Location | Link | Calendar |
|
||||
| ---- | ---- | ----- | -------- | ---- | -------- |
|
||||
| 03. Mar 2026 | 11:00-11:45 | [Elisabet Capón:<br>An Introduction to Renku](events/2026-03-03_capon.md) | [OHSA/E13](https://pocket.psi.ch/psimap) | N/A |
|
||||
|
||||
|
||||
<!--
|
||||
<div class="grid cards" markdown>
|
||||
@@ -28,7 +28,8 @@
|
||||
|
||||
| Date | Time | Event | Location | Link | Calendar |
|
||||
| ---- | ---- | ----- | -------- | ---- | -------- |
|
||||
| 03. Feb 2026 | 11:00-11:45 | [Achim Gsell:<br>Coding Styles](events/2026-02-03/Coding_Styles.md) | [OHSA/E13](https://pocket.psi.ch/psimap) | N/A |
|
||||
| 03. Mar 2026 | 11:00-11:45 | [Elisabet Capón:<br>An Introduction to Renku](events/2026-03-03/2026-03-03_capon.md) | [OHSA/E13](https://pocket.psi.ch/psimap) | N/A |
|
||||
| 03. Feb 2026 | 11:00-11:45 | [Achim Gsell:<br>Coding Styles](events/2026-02-03/2026-02-03_gsell.md) | [OHSA/E13](https://pocket.psi.ch/psimap) | N/A |
|
||||
| 02. Dec 2025 | 11:00-11:45 | [Michael Weinold: Serverless and decentralised](events/2025-12-02_weinold.md) | [OHSA/E13](https://pocket.psi.ch/psimap) | N/A | N/A |
|
||||
| 04. Nov 2025 | 11:00-11:45 | [Romain Sacchi: From scientific software to public tools](events/2025-11-04_sacchi.md) | [OHSA/E13](https://pocket.psi.ch/psimap) | N/A | N/A |
|
||||
| 23. Oct 2025 | 10:00-11:00 | Technical Documentation with `mkdocs` and WASM | Zoom | [Recording of the Talk](https://rse.swiss/events/2025_10_23_technical_documentation_with_mkdocs_and_webassembly/) | N/A |
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# Romain Sacchi: From scientific software to public tools
|
||||
# Romain Sacchi: From Scientific Software to Public Tools
|
||||
|
||||
**Presenter:** Romain Sacchi
|
||||
**When:** 4. November 2025; 11:00-11:45am
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# Serverless and decentralized
|
||||
# Serverless and Decentralized
|
||||
|
||||
**Presenter:** Michael Weinold
|
||||
**When:** 2. December 2025; 11:00-11:45
|
||||
|
||||
29
docs/events/2026-02-03/2026-02-03_gsell.md
Normal file
29
docs/events/2026-02-03/2026-02-03_gsell.md
Normal file
@@ -0,0 +1,29 @@
|
||||
# Achim Gsell: Coding Styles
|
||||
|
||||
**Presenter:** Achim Gsell
|
||||
**When:** 3. February 2026; 11:00-11:45am
|
||||
**Where:** PSI OHSA/E13
|
||||
|
||||
Coding style matters in software development because most code is read far
|
||||
more often than it is written—and usually by someone other than the original
|
||||
author. A consistent style makes intent obvious and helps the developers in
|
||||
writing better code.
|
||||
|
||||
<div class="html-viewer-container">
|
||||
<div class="html-viewer-header">
|
||||
<span class="document-label">Presentation Viewer</span>
|
||||
<a href="../index.html" target="_blank" class="open-btn">
|
||||
↗ Open in New Tab
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<div class="html-viewer-content">
|
||||
<iframe src="../index.html"></iframe>
|
||||
</div>
|
||||
|
||||
<div class="html-viewer-controls">
|
||||
<button class="prev-btn">Previous</button>
|
||||
<span class="page-info">Slide <span class="page-num">--</span> of <span class="page-count">--</span></span>
|
||||
<button class="next-btn">Next</button>
|
||||
</div>
|
||||
</div>
|
||||
@@ -1,12 +0,0 @@
|
||||
# Achim Gsell: Coding Styles
|
||||
|
||||
**Presenter:** Achim Gsell
|
||||
**When:** 3. February 2026; 11:00-11:45am
|
||||
**Where:** PSI OHSA/E13
|
||||
|
||||
Coding style matters in software development because most code is read far
|
||||
more often than it is written—and usually by someone other than the original
|
||||
author. A consistent style makes intent obvious and helps the developers in
|
||||
writing better code.
|
||||
|
||||
[Link to slides](index.html)
|
||||
@@ -1,9 +0,0 @@
|
||||
# Elisabet Capón: Introduction to Renku
|
||||
|
||||
**Presenter:** Elisabet Capón
|
||||
**When:** 3. March 2026; 11:00-11:45am
|
||||
**Where:** PSI OHSA/E13
|
||||
|
||||
In this talk, Dr. Elisabet Capón will introduce Renku, a novel open-source platform designed to connect the ecosystem of data, code, and compute to empower researchers and collaborative communities. The platform mission is to enable the Swiss National Open Research Data (ORD) Strategy by supporting the accessibility and reuse of research data across Switzerland.
|
||||
|
||||
Renku connectes external Git repositories, data stores, and containerized compute environments to allow users to mix and match resources to suit their project setups. The talk outlines how Renku reduces technical friction for three key groups: researchers seeking unified workflows, educators managing computing courses, and organizers running seamless events.
|
||||
27
docs/events/2026-03-03/2026-03-03_capon.md
Normal file
27
docs/events/2026-03-03/2026-03-03_capon.md
Normal file
@@ -0,0 +1,27 @@
|
||||
# An Introduction to Renko
|
||||
|
||||
**Presenter:** Elisabet Capón García
|
||||
**When:** 3. March 2026; 11:00-11:45
|
||||
**Where:** PSI OHSA/E13
|
||||
|
||||
[Elisabet Capón](https://www.datascience.ch/people/elisabet-capon-garcia) is a community manager at the Swiss Data Science Center (SDSC), where she focuses on fostering open research practices and supporting the [Renku open-source project](https://renkulab.io). Renku is a platform that enables researchers to create, share, and reproduce data science projects with ease, promoting collaboration and transparency in scientific research. She will provide an introduction to Renku, highlighting its features and benefits for research software engineering.
|
||||
|
||||
<div class="pdf-viewer-container" data-url="../2026-03-03_slides.pdf">
|
||||
<div class="pdf-viewer-header">
|
||||
<span class="document-label">Document Viewer</span>
|
||||
<a href="../2026-03-03_slides.pdf" download target="_blank" class="download-btn">
|
||||
⬇ Download PDF
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<div class="pdf-viewer-content">
|
||||
<canvas></canvas>
|
||||
<div class="pdf-viewer-loading">Loading...</div>
|
||||
</div>
|
||||
|
||||
<div class="pdf-viewer-controls">
|
||||
<button class="prev-btn">Previous</button>
|
||||
<span class="page-info">Page <span class="page-num">--</span> of <span class="page-count">--</span></span>
|
||||
<button class="next-btn">Next</button>
|
||||
</div>
|
||||
</div>
|
||||
BIN
docs/events/2026-03-03/2026-03-03_slides.pdf
Normal file
BIN
docs/events/2026-03-03/2026-03-03_slides.pdf
Normal file
Binary file not shown.
@@ -1,7 +0,0 @@
|
||||
# An Introduction to Renko
|
||||
|
||||
**Presenter:** Elisabet Capón García
|
||||
**When:** 3. March 2026; 11:00-11:45
|
||||
**Where:** PSI OHSA/E13
|
||||
|
||||
[Elisabet Capón](https://www.datascience.ch/people/elisabet-capon-garcia) is a community manager at the Swiss Data Science Center (SDSC), where she focuses on fostering open research practices and supporting the [Renku open-source project](https://renkulab.io). Renku is a platform that enables researchers to create, share, and reproduce data science projects with ease, promoting collaboration and transparency in scientific research. She will provide an introduction to Renku, highlighting its features and benefits for research software engineering.
|
||||
@@ -6,7 +6,6 @@ Software is ubiquitous in modern research and its quality has a direct impact on
|
||||
|
||||
| Date | Time | Event | Location | Link | Calendar |
|
||||
| ---- | ---- | ----- | -------- | ---- | -------- |
|
||||
| 03. Mar 2026 | 11:00-11:45 | [Elisabet Capón:<br>An Introduction to Renku](events/2026-03-03_capon.md) | OHSA/E13 | [Map](https://pocket.psi.ch/psimap) | N/A |
|
||||
|
||||
## Staying Informed
|
||||
|
||||
|
||||
110
docs/surveys.md
110
docs/surveys.md
@@ -4,110 +4,22 @@
|
||||
|
||||
In 2025, we conducted a staff survey on the state of research software engineering at Paul Scherrer Institut (PSI). The survey was open in September and October 2025, and we received responses from over 50 research software engineers (RSEs) across all centers at PSI. On average, every respondent spent over half an hour on the survey. The results [are available through the ETH Research Collection](https://doi.org/10.3929/ethz-c-000790389) and can be downloaded below:
|
||||
|
||||
<div class="pdf-component" style="border: 1px solid #ccc; border-radius: 6px; overflow: hidden; font-family: sans-serif; margin-bottom: 20px; background-color: #f5f5f5;">
|
||||
|
||||
<div style="background-color: #333; color: white; padding: 10px 15px; display: flex; justify-content: space-between; align-items: center;">
|
||||
<span style="font-weight: bold; font-size: 0.9em;">Document Viewer</span>
|
||||
<a href="../_static/media/survey2025.pdf" download target="_blank" style="text-decoration: none; background-color: #e74c3c; color: white; padding: 6px 12px; border-radius: 4px; font-size: 0.85em; transition: background 0.2s;">
|
||||
<div class="pdf-viewer-container" data-url="../_static/media/survey2025.pdf">
|
||||
<div class="pdf-viewer-header">
|
||||
<span class="document-label">Document Viewer</span>
|
||||
<a href="../_static/media/survey2025.pdf" download target="_blank" class="download-btn">
|
||||
⬇ Download PDF
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<div id="pdf-wrapper" style="position: relative; width: 100%; min-height: 200px; background-color: #525659;">
|
||||
|
||||
<canvas id="the-canvas" style="display: block; width: 100%; height: auto;"></canvas>
|
||||
|
||||
<div id="pdf-loading" style="position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); color: white;">Loading...</div>
|
||||
|
||||
<div class="pdf-viewer-content">
|
||||
<canvas></canvas>
|
||||
<div class="pdf-viewer-loading">Loading...</div>
|
||||
</div>
|
||||
|
||||
<div style="background-color: #ddd; padding: 10px; display: flex; justify-content: center; align-items: center; gap: 15px;">
|
||||
<button id="prev" style="cursor: pointer; padding: 5px 15px;">Previous</button>
|
||||
<span style="font-size: 0.9em;">Page <span id="page_num">--</span> of <span id="page_count">--</span></span>
|
||||
<button id="next" style="cursor: pointer; padding: 5px 15px;">Next</button>
|
||||
<div class="pdf-viewer-controls">
|
||||
<button class="prev-btn">Previous</button>
|
||||
<span class="page-info">Page <span class="page-num">--</span> of <span class="page-count">--</span></span>
|
||||
<button class="next-btn">Next</button>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/pdf.js/2.16.105/pdf.min.js"></script>
|
||||
<script>
|
||||
(function() {
|
||||
var url = '../_static/media/survey2025.pdf'; // <--- CHECK PATH
|
||||
|
||||
var pdfjsLib = window['pdfjs-dist/build/pdf'];
|
||||
pdfjsLib.GlobalWorkerOptions.workerSrc = 'https://cdnjs.cloudflare.com/ajax/libs/pdf.js/2.16.105/pdf.worker.min.js';
|
||||
|
||||
var pdfDoc = null,
|
||||
pageNum = 1,
|
||||
pageRendering = false,
|
||||
pageNumPending = null,
|
||||
scale = 2.0, // High res render, scaled down by CSS
|
||||
canvas = document.getElementById('the-canvas'),
|
||||
ctx = canvas.getContext('2d'),
|
||||
loading = document.getElementById('pdf-loading');
|
||||
|
||||
function renderPage(num) {
|
||||
pageRendering = true;
|
||||
|
||||
// Fetch page
|
||||
pdfDoc.getPage(num).then(function(page) {
|
||||
loading.style.display = 'none';
|
||||
|
||||
var viewport = page.getViewport({scale: scale});
|
||||
canvas.height = viewport.height;
|
||||
canvas.width = viewport.width;
|
||||
|
||||
// Render
|
||||
var renderContext = {
|
||||
canvasContext: ctx,
|
||||
viewport: viewport
|
||||
};
|
||||
var renderTask = page.render(renderContext);
|
||||
|
||||
// Wait for render to finish
|
||||
renderTask.promise.then(function() {
|
||||
pageRendering = false;
|
||||
if (pageNumPending !== null) {
|
||||
renderPage(pageNumPending);
|
||||
pageNumPending = null;
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// Update page counters
|
||||
document.getElementById('page_num').textContent = num;
|
||||
}
|
||||
|
||||
function queueRenderPage(num) {
|
||||
if (pageRendering) {
|
||||
pageNumPending = num;
|
||||
} else {
|
||||
renderPage(num);
|
||||
}
|
||||
}
|
||||
|
||||
function onPrevPage() {
|
||||
if (pageNum <= 1) { return; }
|
||||
pageNum--;
|
||||
queueRenderPage(pageNum);
|
||||
}
|
||||
document.getElementById('prev').addEventListener('click', onPrevPage);
|
||||
|
||||
function onNextPage() {
|
||||
if (pageNum >= pdfDoc.numPages) { return; }
|
||||
pageNum++;
|
||||
queueRenderPage(pageNum);
|
||||
}
|
||||
document.getElementById('next').addEventListener('click', onNextPage);
|
||||
|
||||
// Initial Load
|
||||
pdfjsLib.getDocument(url).promise.then(function(pdfDoc_) {
|
||||
pdfDoc = pdfDoc_;
|
||||
document.getElementById('page_count').textContent = pdfDoc.numPages;
|
||||
renderPage(pageNum);
|
||||
}).catch(function(err) {
|
||||
console.error(err);
|
||||
loading.textContent = "Error loading PDF.";
|
||||
});
|
||||
})();
|
||||
</script>
|
||||
@@ -71,6 +71,9 @@ extra_javascript:
|
||||
# unpkg is incredibly slow (17s to load the css file)
|
||||
- https://cdnjs.cloudflare.com/ajax/libs/KaTeX/0.16.9/katex.min.js
|
||||
- https://cdnjs.cloudflare.com/ajax/libs/KaTeX/0.16.9/contrib/auto-render.min.js
|
||||
- https://cdnjs.cloudflare.com/ajax/libs/pdf.js/2.16.105/pdf.min.js
|
||||
- _javascripts/pdf-viewer.js
|
||||
- _javascripts/html-viewer.js
|
||||
extra_css:
|
||||
# https://cdnjs.com/libraries/KaTeX
|
||||
# unpkg is incredibly slow (17s to load the css file)
|
||||
|
||||
Reference in New Issue
Block a user