Initial commit
This commit is contained in:
34
static/css/signin.css
Normal file
34
static/css/signin.css
Normal file
@@ -0,0 +1,34 @@
|
||||
.form-signin {
|
||||
max-width: 330px;
|
||||
padding: 15px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
.form-signin .form-signin-heading,
|
||||
.form-signin .checkbox {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
.form-signin .checkbox {
|
||||
font-weight: normal;
|
||||
}
|
||||
.form-signin .form-control {
|
||||
position: relative;
|
||||
height: auto;
|
||||
-webkit-box-sizing: border-box;
|
||||
-moz-box-sizing: border-box;
|
||||
box-sizing: border-box;
|
||||
padding: 10px;
|
||||
font-size: 16px;
|
||||
}
|
||||
.form-signin .form-control:focus {
|
||||
z-index: 2;
|
||||
}
|
||||
.form-signin input[type="email"] {
|
||||
margin-bottom: -1px;
|
||||
border-bottom-right-radius: 0;
|
||||
border-bottom-left-radius: 0;
|
||||
}
|
||||
.form-signin input[type="password"] {
|
||||
margin-bottom: 10px;
|
||||
border-top-left-radius: 0;
|
||||
border-top-right-radius: 0;
|
||||
}
|
||||
8
static/css/speaker.css
Normal file
8
static/css/speaker.css
Normal file
@@ -0,0 +1,8 @@
|
||||
.glyphicon-flip {
|
||||
-moz-transform: scaleX(-1);
|
||||
-o-transform: scaleX(-1);
|
||||
-webkit-transform: scaleX(-1);
|
||||
transform: scaleX(-1);
|
||||
filter: FlipH;
|
||||
-ms-filter: "FlipH";
|
||||
}
|
||||
9
static/css/style.css
Normal file
9
static/css/style.css
Normal file
@@ -0,0 +1,9 @@
|
||||
.noselect {
|
||||
cursor: default;
|
||||
-webkit-touch-callout: none;
|
||||
-webkit-user-select: none;
|
||||
-khtml-user-select: none;
|
||||
-moz-user-select: none;
|
||||
-ms-user-select: none;
|
||||
user-select: none;
|
||||
}
|
||||
10
static/css/viewer.css
Normal file
10
static/css/viewer.css
Normal file
@@ -0,0 +1,10 @@
|
||||
#canvas {
|
||||
margin:auto;
|
||||
position:absolute;
|
||||
top:0;
|
||||
bottom:0;
|
||||
left:0;
|
||||
right:0;
|
||||
max-height:100%;
|
||||
max-width:100%;
|
||||
}
|
||||
10375
static/js/pdf.js
Normal file
10375
static/js/pdf.js
Normal file
File diff suppressed because it is too large
Load Diff
42034
static/js/pdf.worker.js
vendored
Normal file
42034
static/js/pdf.worker.js
vendored
Normal file
File diff suppressed because it is too large
Load Diff
291
static/js/speaker.js
Normal file
291
static/js/speaker.js
Normal file
@@ -0,0 +1,291 @@
|
||||
$(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').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.x - canvasPdfBounding.left) / canvasPdf.width;
|
||||
var y = (event.y - canvasPdfBounding.top) / 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.x - canvasPdfBounding.left) / canvasPdf.width;
|
||||
var y = (event.y - canvasPdfBounding.top) / 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;
|
||||
|
||||
})(); });
|
||||
175
static/js/viewer.js
Normal file
175
static/js/viewer.js
Normal file
@@ -0,0 +1,175 @@
|
||||
$(function() { sio = (function() {
|
||||
|
||||
var sio = {};
|
||||
|
||||
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 pageNumber = 1;
|
||||
|
||||
var pointer = false;
|
||||
var canvasPdfBounding;
|
||||
|
||||
var drawAudienceLaser = false;
|
||||
var lasers = {};
|
||||
|
||||
|
||||
PDFJS.getDocument('/static/uploaded/' + filename + '.pdf').then(function getPdfHelloWorld(_pdf) {
|
||||
|
||||
pdf = _pdf;
|
||||
update();
|
||||
|
||||
});
|
||||
|
||||
var socket = io();
|
||||
|
||||
socket.on('welcome', function() {
|
||||
socket.emit('viewer', filename);
|
||||
});
|
||||
|
||||
socket.on('update', function(newPageNumber) {
|
||||
pageNumber = newPageNumber;
|
||||
update();
|
||||
});
|
||||
|
||||
socket.on('viewer-laser', function(enabled) {
|
||||
drawAudienceLaser = enabled;
|
||||
});
|
||||
|
||||
socket.on('pointer', canvasPointer);
|
||||
|
||||
function update() {
|
||||
|
||||
pdf.getPage(pageNumber).then(function(page) {
|
||||
|
||||
var scale;
|
||||
|
||||
// width / height
|
||||
var ratio = page.pageInfo.view[2] / page.pageInfo.view[3];
|
||||
|
||||
if (window.innerWidth < window.innerHeight) {
|
||||
|
||||
canvasPdf.width = window.innerWidth;
|
||||
canvasPdf.height = canvasPdf.width / ratio;
|
||||
scale = canvasPdf.width / page.getViewport(1.0).width;
|
||||
|
||||
} else {
|
||||
|
||||
canvasPdf.height = window.innerHeight;
|
||||
canvasPdf.width = ratio * canvasPdf.height;
|
||||
scale = canvasPdf.width / page.getViewport(1.0).width;
|
||||
}
|
||||
|
||||
canvasPaint.width = canvasPdf.width;
|
||||
canvasPaint.height = canvasPdf.height;
|
||||
|
||||
$('#canvases').width(canvasPdf.width + 'px');
|
||||
$('#canvases').height(canvasPdf.height + 'px');
|
||||
|
||||
canvasPdfBounding = canvasPdf.getBoundingClientRect();
|
||||
|
||||
var viewport = page.getViewport(scale);
|
||||
|
||||
var renderContext = {
|
||||
canvasContext: contextPdf,
|
||||
viewport: viewport
|
||||
};
|
||||
|
||||
page.render(renderContext);
|
||||
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
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 (drawAudienceLaser === true || laserIndex === 'speaker') {
|
||||
|
||||
contextPaint.fillStyle = laserIndex === 'speaker' ? 'red' : 'green';
|
||||
contextPaint.beginPath();
|
||||
contextPaint.arc(laser.x * canvasPdf.width, laser.y * canvasPdf.height, 10, 0, Math.PI*2, true);
|
||||
contextPaint.closePath();
|
||||
contextPaint.fill();
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
$(window).resize(update);
|
||||
|
||||
sio.onMouseDown = function() {
|
||||
|
||||
var x = (event.x - canvasPdfBounding.left) / canvasPdf.width;
|
||||
var y = (event.y - canvasPdfBounding.top) / 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.x - canvasPdfBounding.left) / canvasPdf.width;
|
||||
var y = (event.y - canvasPdfBounding.top) / 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);
|
||||
|
||||
};
|
||||
|
||||
return sio;
|
||||
|
||||
})(); });
|
||||
BIN
static/uploaded/last_slides.pdf
Normal file
BIN
static/uploaded/last_slides.pdf
Normal file
Binary file not shown.
BIN
static/uploaded/main.pdf
Normal file
BIN
static/uploaded/main.pdf
Normal file
Binary file not shown.
Reference in New Issue
Block a user