138 lines
5.2 KiB
JavaScript
138 lines
5.2 KiB
JavaScript
/**
|
|
* papar_dokumen.js
|
|
* Handles document list -> preview rendering (PDF + images) on canvas
|
|
* Requires: jQuery, pdfjsLib (global), Bootstrap
|
|
*
|
|
* Note: Ensure pdfjsLib global is available (use non-module CDN).
|
|
*/
|
|
|
|
(function ($, window, document, undefined) {
|
|
'use strict';
|
|
|
|
$(function () {
|
|
|
|
const $canvas = $('#pdf-canvas');
|
|
const canvas = $canvas.length ? $canvas[0] : null;
|
|
const ctx = canvas ? canvas.getContext('2d') : null;
|
|
const $container = $('#preview-container');
|
|
let currentUrl = null;
|
|
let zoom = 1.0;
|
|
|
|
if (!canvas || !ctx) {
|
|
console.warn('Canvas not found for dokumen preview.');
|
|
return;
|
|
}
|
|
|
|
// init event bindings
|
|
$(document).on('click', '.dokumen-item', function () {
|
|
const url = $(this).data('url');
|
|
if (!url) return;
|
|
currentUrl = url;
|
|
loadFile(url);
|
|
});
|
|
|
|
$('#btn-zoom-in').on('click', function (e) {
|
|
e.preventDefault();
|
|
zoom = Math.min(3, zoom + 0.2);
|
|
if (currentUrl) loadFile(currentUrl);
|
|
});
|
|
|
|
$('#btn-zoom-out').on('click', function (e) {
|
|
e.preventDefault();
|
|
zoom = Math.max(0.2, zoom - 0.2);
|
|
if (currentUrl) loadFile(currentUrl);
|
|
});
|
|
|
|
function loadFile(url) {
|
|
const ext = (url.split('.').pop() || '').toLowerCase();
|
|
if (['pdf'].includes(ext)) {
|
|
renderPDF(url);
|
|
} else if (['jpg','jpeg','png','gif','webp'].includes(ext)) {
|
|
renderImage(url);
|
|
} else {
|
|
toast('Format tidak disokong untuk preview', 'error');
|
|
}
|
|
}
|
|
|
|
// Render first page of PDF
|
|
function renderPDF(url) {
|
|
// ensure pdfjsLib exists
|
|
if (typeof pdfjsLib === 'undefined') {
|
|
console.error('pdfjsLib not found. Include PDF.js (non-module) before papar_dokumen.js');
|
|
return;
|
|
}
|
|
|
|
// disable workers to avoid CORS/worker issues, or set workerSrc if available
|
|
if (pdfjsLib.GlobalWorkerOptions && !pdfjsLib.GlobalWorkerOptions.workerSrc) {
|
|
// try use CDN worker (same version assumed)
|
|
pdfjsLib.GlobalWorkerOptions.workerSrc = 'https://cdnjs.cloudflare.com/ajax/libs/pdf.js/2.16.105/pdf.worker.min.js';
|
|
}
|
|
|
|
pdfjsLib.getDocument(url).promise.then(function (pdf) {
|
|
return pdf.getPage(1).then(function (page) {
|
|
const containerWidth = $container.width();
|
|
const viewport = page.getViewport({ scale: 1 });
|
|
const scale = (containerWidth / viewport.width) * zoom;
|
|
const scaledViewport = page.getViewport({ scale: scale });
|
|
const outputScale = window.devicePixelRatio || 1;
|
|
|
|
canvas.width = Math.floor(scaledViewport.width * outputScale);
|
|
canvas.height = Math.floor(scaledViewport.height * outputScale);
|
|
canvas.style.width = Math.floor(scaledViewport.width) + "px";
|
|
canvas.style.height = Math.floor(scaledViewport.height) + "px";
|
|
|
|
const renderContext = {
|
|
canvasContext: ctx,
|
|
viewport: scaledViewport,
|
|
transform: [outputScale, 0, 0, outputScale, 0, 0],
|
|
};
|
|
|
|
ctx.clearRect(0, 0, canvas.width, canvas.height);
|
|
page.render(renderContext);
|
|
});
|
|
}).catch(function (err) {
|
|
console.error('Error rendering PDF', err);
|
|
toast('Gagal memaparkan PDF.');
|
|
});
|
|
}
|
|
|
|
// Render image to canvas, fit to container and support zoom
|
|
function renderImage(url) {
|
|
const img = new Image();
|
|
img.crossOrigin = 'anonymous';
|
|
img.onload = function () {
|
|
const containerW = $container.width();
|
|
const containerH = $container.height();
|
|
|
|
const fitScale = Math.min(containerW / img.width, containerH / img.height);
|
|
const finalW = Math.max(1, Math.floor(img.width * fitScale * zoom));
|
|
const finalH = Math.max(1, Math.floor(img.height * fitScale * zoom));
|
|
|
|
canvas.width = finalW;
|
|
canvas.height = finalH;
|
|
canvas.style.width = finalW + 'px';
|
|
canvas.style.height = finalH + 'px';
|
|
|
|
ctx.clearRect(0, 0, canvas.width, canvas.height);
|
|
ctx.drawImage(img, 0, 0, finalW, finalH);
|
|
};
|
|
img.onerror = function () {
|
|
console.error('Error loading image', url);
|
|
toast('Imej gagal dimuatkan.');
|
|
};
|
|
img.src = url;
|
|
}
|
|
|
|
function toast(msg, lvl = 'info') {
|
|
if ($('#globalToast').length) {
|
|
$('#globalToast .toast-body').text(msg);
|
|
new bootstrap.Toast($('#globalToast')[0]).show();
|
|
} else {
|
|
console[lvl === 'error' ? 'error' : 'log'](msg);
|
|
}
|
|
}
|
|
|
|
});
|
|
|
|
})(jQuery, window, document);
|