( ′∀`)σ≡σ☆))Д′)レ(゚∀゚;)ヘ=З=З=Зε≡(ノ´_ゝ`)ノ
# Presentation Mode in Fabric.js (Canva‑Style)
This document describes how to implement a **Canva‑like Presentation Mode** using **Fabric.js**. Presentation Mode is a *viewer state* of your editor where slides are rendered full‑screen, scaled correctly, and navigated sequentially.
---
## 1. Conceptual Overview
Presentation Mode is **not** a different canvas.
It is:
- A locked, non‑interactive Fabric canvas
- Rendering **one page (slide) at a time**
- Scaled to fit the screen while preserving aspect ratio
- Controlled via keyboard / click navigation
> **Editor Mode** = interactive Fabric canvas
> **Presentation Mode** = static renderer + navigation
---
## 2. Data Model (Slides / Pages)
Each slide is stored as Fabric JSON.
```js
const pages = [
{
id: "slide-1",
width: 1920,
height: 1080,
json: canvas.toJSON()
},
{
id: "slide-2",
width: 1920,
height: 1080,
json: canvas.toJSON()
}
];
```
---
## 3. Entering Presentation Mode
### 3.1 Save Editor State
```js
const editorState = canvas.toJSON();
```
---
### 3.2 Disable Interactions
```js
canvas.discardActiveObject();
canvas.selection = false;
canvas.forEachObject(obj => {
obj.selectable = false;
obj.evented = false;
});
```
---
### 3.3 Fullscreen Container
```js
document.getElementById('canvas-wrap').requestFullscreen();
```
Fallback can be handled using CSS (`position: fixed`).
---
## 4. Scaling Canvas to Screen
Preserve aspect ratio at all times.
```js
function fitCanvasToScreen(canvas, slideW, slideH) {
const scale = Math.min(
window.innerWidth / slideW,
window.innerHeight / slideH
);
canvas.setWidth(slideW * scale);
canvas.setHeight(slideH * scale);
canvas.setZoom(scale);
canvas.renderAll();
}
```
---
## 5. Loading a Slide
Use **one Fabric canvas**, load JSON per slide.
```js
function loadSlide(slide) {
canvas.clear();
canvas.loadFromJSON(slide.json, () => {
fitCanvasToScreen(canvas, slide.width, slide.height);
canvas.renderAll();
});
}
```
---
## 6. Slide Navigation
### 6.1 State
```js
let currentIndex = 0;
```
---
### 6.2 Controls
```js
function nextSlide() {
if (currentIndex < pages.length - 1) {
currentIndex++;
loadSlide(pages[currentIndex]);
}
}
function prevSlide() {
if (currentIndex > 0) {
currentIndex--;
loadSlide(pages[currentIndex]);
}
}
```
---
### 6.3 Keyboard Events
```js
document.addEventListener('keydown', e => {
if (e.key === 'ArrowRight' || e.key === ' ') nextSlide();
if (e.key === 'ArrowLeft') prevSlide();
if (e.key === 'Escape') exitPresentation();
});
```
---
## 7. Performance Optimizations
Disable unnecessary rendering overhead.
```js
canvas.enableRetinaScaling = false;
canvas.renderOnAddRemove = false;
```
Render **once** after JSON load.
---
## 8. Slide Transitions
Fabric does not animate canvas state; transitions are done via DOM.
### Fade Transition Example
```js
const el = canvas.getElement();
el.style.transition = 'opacity 0.4s ease';
el.style.opacity = 0;
setTimeout(() => {
loadSlide(slide);
el.style.opacity = 1;
}, 300);
```
Advanced effects:
- Dual canvas cross‑fade
- Web Animations API
---
## 9. Exiting Presentation Mode
Restore editor state and interactions.
```js
function exitPresentation() {
document.exitFullscreen();
canvas.clear();
canvas.loadFromJSON(editorState, () => {
canvas.selection = true;
canvas.forEachObject(obj => {
obj.selectable = true;
obj.evented = true;
});
canvas.renderAll();
});
}
```
---
## 10. Optional Enhancements (Canva‑Grade)
### Presenter View
- Second window via `window.open()`
- Speaker notes
- Next slide preview
### Preloading Slides
```js
pages.forEach(p => fabric.util.enlivenObjects(p.json.objects));
```
### Export
- Slides → images
- Slides → video
- Slides → PDF / PPT
---
## 11. Mental Model
> **Fabric.js renders.**
> **Your app orchestrates.**
Presentation Mode is a **state machine** layered on top of Fabric — not a Fabric feature itself.
---
**End of Document**