Skip to content

Commit d5f60d8

Browse files
authored
Merge pull request #1169 from pastleo/feature/slides-spotlight
add spotlight feature
2 parents 2f3f3c5 + f3a3c14 commit d5f60d8

File tree

2 files changed

+291
-2
lines changed

2 files changed

+291
-2
lines changed
Lines changed: 283 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,283 @@
1+
var RevealSpotlight = window.RevealSpotlight || (function () {
2+
3+
//configs
4+
var spotlightSize;
5+
var toggleOnMouseDown;
6+
var spotlightOnKeyPressAndHold;
7+
var presentingCursor;
8+
var spotlightCursor;
9+
var initialPresentationMode;
10+
var disablingUserSelect;
11+
var fadeInAndOut;
12+
var style;
13+
var lockPointerInsideCanvas;
14+
var getMousePos;
15+
16+
var drawBoard;
17+
var isSpotlightOn = true;
18+
var isCursorOn = true;
19+
20+
var lastMouseMoveEvent;
21+
22+
function onRevealJsReady(event) {
23+
configure();
24+
drawBoard = setupCanvas();
25+
26+
addWindowResizeListener();
27+
28+
addMouseMoveListener();
29+
30+
if (toggleOnMouseDown) {
31+
addMouseToggleSpotlightListener();
32+
}
33+
34+
if (spotlightOnKeyPressAndHold) {
35+
addKeyPressAndHoldSpotlightListener(spotlightOnKeyPressAndHold);
36+
}
37+
38+
setCursor(!initialPresentationMode);
39+
setSpotlight(false);
40+
}
41+
42+
function configure() {
43+
var config = Reveal.getConfig().spotlight || {};
44+
spotlightSize = config.size || 60;
45+
presentingCursor = config.presentingCursor || "none";
46+
spotlightCursor = config.spotlightCursor || "none";
47+
var useAsPointer = config.useAsPointer || false;
48+
var pointerColor = config.pointerColor || 'red';
49+
lockPointerInsideCanvas = config.lockPointerInsideCanvas || false;
50+
51+
if(lockPointerInsideCanvas){
52+
getMousePos = getMousePosByMovement;
53+
} else {
54+
getMousePos = getMousePosByBoundingClientRect;
55+
}
56+
57+
// If using as pointer draw a transparent background and
58+
// the mouse pointer in the specified color or default
59+
var pointerStyle = {
60+
backgroundFillStyle : "rgba(0, 0, 0, 0)",
61+
mouseFillStyle : pointerColor
62+
};
63+
64+
var spotlightStyle = {
65+
backgroundFillStyle : "#000000A8",
66+
mouseFillStyle : "#FFFFFFFF"
67+
};
68+
69+
style = useAsPointer ? pointerStyle : spotlightStyle;
70+
71+
if (config.hasOwnProperty("toggleSpotlightOnMouseDown")) {
72+
toggleOnMouseDown = config.toggleSpotlightOnMouseDown;
73+
} else {
74+
toggleOnMouseDown = true;
75+
}
76+
77+
if (config.hasOwnProperty("initialPresentationMode")) {
78+
initialPresentationMode = config.initialPresentationMode;
79+
} else {
80+
initialPresentationMode = toggleOnMouseDown;
81+
}
82+
83+
if (config.hasOwnProperty("spotlightOnKeyPressAndHold")) {
84+
spotlightOnKeyPressAndHold = config.spotlightOnKeyPressAndHold;
85+
} else {
86+
spotlightOnKeyPressAndHold = false;
87+
}
88+
89+
if (config.hasOwnProperty("disablingUserSelect")) {
90+
disablingUserSelect = config.disablingUserSelect;
91+
} else {
92+
disablingUserSelect = true;
93+
}
94+
95+
if (config.hasOwnProperty("fadeInAndOut")) {
96+
fadeInAndOut = config.fadeInAndOut;
97+
} else {
98+
fadeInAndOut = false;
99+
}
100+
}
101+
102+
function setupCanvas() {
103+
var container = document.createElement('div');
104+
container.id = "spotlight";
105+
container.style.cssText = "position:absolute;top:0;left:0;bottom:0;right:0;z-index:99;";
106+
if (fadeInAndOut) {
107+
container.style.cssText += "transition: " + fadeInAndOut + "ms opacity;";
108+
}
109+
110+
var canvas = document.createElement('canvas');
111+
var context = canvas.getContext("2d");
112+
113+
canvas.width = window.innerWidth;
114+
canvas.height = window.innerHeight;
115+
116+
container.appendChild(canvas);
117+
document.body.appendChild(container);
118+
container.style.opacity = 0;
119+
container.style['pointer-events'] = 'none';
120+
return {
121+
container,
122+
canvas,
123+
context
124+
}
125+
}
126+
127+
function addWindowResizeListener() {
128+
window.addEventListener('resize', function (e) {
129+
var canvas = drawBoard.canvas;
130+
canvas.width = window.innerWidth;
131+
canvas.height = window.innerHeight;
132+
}, false);
133+
}
134+
135+
function addMouseMoveListener() {
136+
document.body.addEventListener('mousemove', function (e) {
137+
if(isSpotlightOn) {
138+
showSpotlight(e);
139+
}
140+
lastMouseMoveEvent = e;
141+
}, false);
142+
}
143+
144+
function addMouseToggleSpotlightListener() {
145+
146+
window.addEventListener("mousedown", function (e) {
147+
if (!isCursorOn) {
148+
setSpotlight(true, e);
149+
}
150+
}, false);
151+
152+
window.addEventListener("mouseup", function (e) {
153+
if (!isCursorOn) {
154+
setSpotlight(false, e);
155+
}
156+
}, false);
157+
}
158+
159+
function addKeyPressAndHoldSpotlightListener(keyCode) {
160+
161+
window.addEventListener("keydown", function (e) {
162+
if (!isCursorOn && !isSpotlightOn && e.keyCode === keyCode) {
163+
setSpotlight(true, lastMouseMoveEvent);
164+
}
165+
}, false);
166+
167+
window.addEventListener("keyup", function (e) {
168+
if (!isCursorOn && e.keyCode === keyCode) {
169+
setSpotlight(false);
170+
}
171+
}, false);
172+
}
173+
174+
function toggleSpotlight() {
175+
setSpotlight(!isSpotlightOn, lastMouseMoveEvent);
176+
}
177+
178+
function setSpotlight(isOn, mouseEvt) {
179+
isSpotlightOn = isOn;
180+
var container = drawBoard.container;
181+
if (isOn) {
182+
if (lockPointerInsideCanvas && document.pointerLockElement != drawBoard.canvas) {
183+
drawBoard.canvas.requestPointerLock();
184+
}
185+
container.style.opacity = 1;
186+
container.style['pointer-events'] = null;
187+
document.body.style.cursor = spotlightCursor;
188+
if (mouseEvt) {
189+
showSpotlight(mouseEvt);
190+
}
191+
} else {
192+
container.style.opacity = 0;
193+
container.style['pointer-events'] = 'none';
194+
document.body.style.cursor = presentingCursor;
195+
}
196+
}
197+
198+
function togglePresentationMode() {
199+
setCursor(!isCursorOn);
200+
}
201+
202+
function setCursor(isOn) {
203+
isCursorOn = isOn;
204+
if (isOn) {
205+
if (disablingUserSelect) {
206+
document.body.style.userSelect = null;
207+
}
208+
document.body.style.cursor = null;
209+
} else {
210+
if (disablingUserSelect) {
211+
document.body.style.userSelect = "none";
212+
}
213+
document.body.style.cursor = presentingCursor;
214+
}
215+
}
216+
217+
function showSpotlight(mouseEvt) {
218+
var canvas = drawBoard.canvas;
219+
var context = drawBoard.context;
220+
var mousePos = getMousePos(canvas, mouseEvt);
221+
222+
context.clearRect(0, 0, canvas.width, canvas.height);
223+
224+
// Create a canvas mask
225+
var maskCanvas = document.createElement('canvas');
226+
maskCanvas.width = canvas.width;
227+
maskCanvas.height = canvas.height;
228+
229+
var maskCtx = maskCanvas.getContext('2d');
230+
231+
maskCtx.fillStyle = style.backgroundFillStyle;
232+
maskCtx.fillRect(0, 0, maskCanvas.width, maskCanvas.height);
233+
maskCtx.globalCompositeOperation = 'xor';
234+
235+
maskCtx.fillStyle = style.mouseFillStyle;
236+
maskCtx.arc(mousePos.x, mousePos.y, spotlightSize, 0, 2 * Math.PI);
237+
maskCtx.fill();
238+
239+
context.drawImage(maskCanvas, 0, 0);
240+
}
241+
242+
var mX = 0;
243+
var mY = 0;
244+
245+
function getMousePosByMovement(canvas, evt) {
246+
var movementX = evt.movementX || 0;
247+
var movementY = evt.movementY || 0;
248+
mX += movementX;
249+
mY += movementY;
250+
251+
if (mX > canvas.clientWidth) {
252+
mX = canvas.clientWidth;
253+
}
254+
if (mY > canvas.clientHeight) {
255+
mY = canvas.clientHeight;
256+
}
257+
if (mX < 0) {
258+
mX = 0;
259+
}
260+
if (mY < 0) {
261+
mY = 0;
262+
}
263+
264+
return {
265+
x: mX,
266+
y: mY
267+
};
268+
}
269+
270+
function getMousePosByBoundingClientRect(canvas, evt) {
271+
var rect = canvas.getBoundingClientRect();
272+
return {
273+
x: evt.clientX - rect.left,
274+
y: evt.clientY - rect.top
275+
};
276+
}
277+
278+
Reveal.addEventListener('ready', onRevealJsReady);
279+
280+
this.toggleSpotlight = toggleSpotlight;
281+
this.togglePresentationMode = togglePresentationMode;
282+
return this;
283+
})();

public/js/slide.js

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -74,12 +74,18 @@ const defaultOptions = {
7474
const meta = JSON.parse($('#meta').text())
7575
var options = meta.slideOptions || {}
7676

77+
if (options.hasOwnProperty('spotlight')) {
78+
defaultOptions.dependencies.push({
79+
src: `${serverurl}/build/reveal.js/plugin/spotlight/spotlight.js`
80+
})
81+
}
82+
7783
if (options.hasOwnProperty('allottedTime') || options.hasOwnProperty('allottedMinutes')) {
7884
defaultOptions.dependencies.push({
7985
src: `${serverurl}/build/reveal.js/plugin/elapsed-time-bar/elapsed-time-bar.js`
80-
});
86+
})
8187
if (options.hasOwnProperty('allottedMinutes')) {
82-
options.allottedTime = options.allottedMinutes * 60 * 1000;
88+
options.allottedTime = options.allottedMinutes * 60 * 1000
8389
}
8490
}
8591

0 commit comments

Comments
 (0)