$(function() { sio = (function() { var sio = {}; var counter = $('#counter'); var canvasPdf = $('#canvas-pdf').get(0); var contextPdf = canvasPdf.getContext('2d'); var canvasPaint = $('#canvas-paint').get(0); var contextPaint = canvasPaint.getContext('2d'); var pdf; var currentPage = 1; var startTime = 0; var startSlide = 0; var refreshIntervalId = 0; var pointer = false; var shouldUpdatePointer = false; var canvasPdfBounding; var lasers = {}; var drawAudienceLasers = false; PDFJS.getDocument('/static/uploaded/' + filename + '.pdf?' + (Math.floor(Math.random() * 10000))).then(function getPdf(_pdf) { pdf = _pdf; updateUI(); }); var socket = io(); socket.on('welcome', function() { socket.emit('speaker', filename, socket.id); }); socket.on('pointer', canvasPointer); function filterInt(value) { if(/^(\-|\+)?([0-9]+|Infinity)$/.test(value)) return Number(value); return NaN; } var updateUI = function() { counter.val(currentPage + '/' + pdf.pdfInfo.numPages); $('#previous,#first').prop('disabled', currentPage === 1); $('#next,#last').prop('disabled', currentPage === pdf.pdfInfo.numPages); pdf.getPage(currentPage).then(function(page) { previousPage = currentPage; var viewport = page.getViewport(2.0); canvasPdf.width = viewport.width; canvasPdf.height = viewport.height; canvasPaint.width = viewport.width; canvasPaint.height = viewport.height; $('#canvases').width(canvasPdf.width + 'px'); $('#canvases').height(canvasPdf.height + 'px'); canvasPdfBounding = canvasPdf.getBoundingClientRect(); var renderContext = { canvasContext: contextPdf, viewport: viewport }; page.render(renderContext); }); }; function updateAudience() { socket.emit('change-slide', filename, currentPage); } function formatTime(ms) { var sec = padToTwo(Math.floor((ms / 1000) % 60)); var min = padToTwo(Math.floor(((ms / 1000 - sec) % 3600) / 60)); return min + ':' + sec; } function updateTimers() { if (refreshIntervalId !== 0) { $('#totalTime').html(formatTime(Date.now() - startTime)); $('#slideTime').html(formatTime(Date.now() - startSlide)); } } function padToTwo(number) { if (number<=99) { number = ("0"+number).slice(-2); } return number; } function resetTimeSlide() { startSlide = Date.now(); updateTimers(); } // Check if number is valid, and updates // number undefined means sync all clients function changeSlide(number) { if (isNaN(number) || number < 1 || number > pdf.pdfInfo.numPages) { return false; } if (currentPage === undefined || currentPage === number) { updateAudience(); return true; } currentPage = number; updateUI(); updateAudience(); resetTimeSlide(); return true; } function canvasPointer(id,x,y) { // Clear canvas canvasPaint.width = canvasPaint.width; if (id != undefined) { if (x != undefined && y != undefined) { lasers[id] = {x:x, y:y}; } else { delete lasers[id]; } } for (var laserIndex in lasers) { var laser = lasers[laserIndex]; if (drawAudienceLasers === true || laserIndex === socket.id) { contextPaint.fillStyle = laserIndex === socket.id ? 'red' : 'green'; contextPaint.beginPath(); contextPaint.arc(laser.x * canvasPdf.width, laser.y * canvasPdf.height, 10, 0, Math.PI*2, true); contextPaint.closePath(); contextPaint.fill(); } } } sio.onMouseDown = function(event) { var x = event.offsetX / canvasPdf.width; var y = event.offsetY / canvasPdf.height; socket.emit('pointer', filename, socket.id, x, y); pointer = true; shouldUpdatePointer = true; canvasPointer(socket.id, x, y); }; sio.onMouseMove = function(event) { if (pointer) { var x = event.offsetX / canvasPdf.width; var y = event.offsetY / canvasPdf.height; if (shouldUpdatePointer) { // Update socket.emit('pointer', filename, socket.id, x, y); shouldUpdatePointer = false; setTimeout(function() { shouldUpdatePointer = true; }, 20); } canvasPointer(socket.id, x, y); } }; sio.onMouseUp = function(event) { socket.emit('pointer', filename, socket.id); pointer = false; shouldUpdatePointer = false; canvasPointer(socket.id); }; sio.startPresentation = function() { startTime = startSlide = Date.now(); refreshIntervalId = setInterval(updateTimers, 1000); updateTimers(); $('#start').prop('disabled', true); $('#stop').prop('disabled', false); }; sio.stopPresentation = function() { clearInterval(refreshIntervalId); refreshIntervalId = 0; $('#start').prop('disabled', false); $('#stop').prop('disabled', true); }; sio.changeSlideFromCounter = function() { var slideNumber = filterInt($('#counter').val()); changeSlide(slideNumber); // lose focus $(':focus').blur(); }; sio.switchAudienceLaser = function() { var laser = $('#viewer-laser'); if (drawAudienceLasers === false) { // Laser is disabled, will be enabled laser.text('Audience laser is enabled'); laser.removeClass('btn-default').addClass('btn-primary'); drawAudienceLasers = true; } else { laser.text('Audience laser is disabled'); laser.removeClass('btn-primary').addClass('btn-default'); drawAudienceLasers = false; } socket.emit('viewer-laser', filename, drawAudienceLasers); }; sio.clearCounter = function() { $('#counter').val(''); }; sio.nextSlide = function() { changeSlide(currentPage + 1); }; sio.previousSlide = function() { changeSlide(currentPage - 1); }; sio.firstSlide = function() { changeSlide(1); }; sio.lastSlide = function() { changeSlide(pdf.pdfInfo.numPages); }; sio.syncAudience = updateAudience; sio.update = updateUI; $(window).resize(updateUI); return sio; })(); });