Merge branch 'feature/print' into dev
This commit is contained in:
commit
b019604531
4 changed files with 137 additions and 75 deletions
|
@ -585,7 +585,7 @@ Limitations:
|
||||||
Presentations can be exported to PDF via a special print stylesheet. This feature requires that you use [Google Chrome](http://google.com/chrome).
|
Presentations can be exported to PDF via a special print stylesheet. This feature requires that you use [Google Chrome](http://google.com/chrome).
|
||||||
Here's an example of an exported presentation that's been uploaded to SlideShare: http://www.slideshare.net/hakimel/revealjs-13872948.
|
Here's an example of an exported presentation that's been uploaded to SlideShare: http://www.slideshare.net/hakimel/revealjs-13872948.
|
||||||
|
|
||||||
1. Open your presentation with [css/print/pdf.css](https://github.com/hakimel/reveal.js/blob/master/css/print/pdf.css) included on the page. The default index HTML lets you add *print-pdf* anywhere in the query to include the stylesheet, for example: [lab.hakim.se/reveal-js?print-pdf](http://lab.hakim.se/reveal-js?print-pdf).
|
1. Open your presentation with `print-pdf` included anywhere in the query string. This triggers the default index HTML to load the PDF print stylesheet ([css/print/pdf.css](https://github.com/hakimel/reveal.js/blob/master/css/print/pdf.css)). You can test this with [lab.hakim.se/reveal-js?print-pdf](http://lab.hakim.se/reveal-js?print-pdf).
|
||||||
2. Open the in-browser print dialog (CMD+P).
|
2. Open the in-browser print dialog (CMD+P).
|
||||||
3. Change the **Destination** setting to **Save as PDF**.
|
3. Change the **Destination** setting to **Save as PDF**.
|
||||||
4. Change the **Layout** to **Landscape**.
|
4. Change the **Layout** to **Landscape**.
|
||||||
|
|
|
@ -17,8 +17,6 @@
|
||||||
|
|
||||||
body {
|
body {
|
||||||
font-size: 18pt;
|
font-size: 18pt;
|
||||||
width: 297mm;
|
|
||||||
height: 229mm;
|
|
||||||
margin: 0 auto !important;
|
margin: 0 auto !important;
|
||||||
border: 0;
|
border: 0;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
|
@ -105,8 +103,6 @@ ul, ol, div, p {
|
||||||
overflow: visible;
|
overflow: visible;
|
||||||
display: block;
|
display: block;
|
||||||
|
|
||||||
text-align: center;
|
|
||||||
|
|
||||||
-webkit-perspective: none;
|
-webkit-perspective: none;
|
||||||
-moz-perspective: none;
|
-moz-perspective: none;
|
||||||
-ms-perspective: none;
|
-ms-perspective: none;
|
||||||
|
@ -118,21 +114,15 @@ ul, ol, div, p {
|
||||||
perspective-origin: 50% 50%;
|
perspective-origin: 50% 50%;
|
||||||
}
|
}
|
||||||
.reveal .slides section {
|
.reveal .slides section {
|
||||||
|
|
||||||
page-break-after: always !important;
|
page-break-after: always !important;
|
||||||
|
|
||||||
visibility: visible !important;
|
visibility: visible !important;
|
||||||
position: relative !important;
|
position: relative !important;
|
||||||
width: 100% !important;
|
|
||||||
height: 229mm !important;
|
|
||||||
min-height: 229mm !important;
|
|
||||||
display: block !important;
|
display: block !important;
|
||||||
overflow: hidden !important;
|
position: relative !important;
|
||||||
|
|
||||||
left: 0 !important;
|
|
||||||
top: 0 !important;
|
|
||||||
margin: 0 !important;
|
margin: 0 !important;
|
||||||
padding: 2cm 2cm 0 2cm !important;
|
padding: 0 !important;
|
||||||
box-sizing: border-box !important;
|
box-sizing: border-box !important;
|
||||||
|
|
||||||
opacity: 1 !important;
|
opacity: 1 !important;
|
||||||
|
@ -154,30 +144,6 @@ ul, ol, div, p {
|
||||||
height: auto !important;
|
height: auto !important;
|
||||||
min-height: auto !important;
|
min-height: auto !important;
|
||||||
}
|
}
|
||||||
.reveal .absolute-element {
|
|
||||||
margin-left: 2.2cm;
|
|
||||||
margin-top: 1.8cm;
|
|
||||||
}
|
|
||||||
.reveal section .fragment {
|
|
||||||
opacity: 1 !important;
|
|
||||||
visibility: visible !important;
|
|
||||||
|
|
||||||
-webkit-transform: none !important;
|
|
||||||
-moz-transform: none !important;
|
|
||||||
-ms-transform: none !important;
|
|
||||||
transform: none !important;
|
|
||||||
}
|
|
||||||
.reveal section .slide-background {
|
|
||||||
position: absolute;
|
|
||||||
top: 0;
|
|
||||||
left: 0;
|
|
||||||
width: 100%;
|
|
||||||
z-index: 0;
|
|
||||||
}
|
|
||||||
.reveal section>* {
|
|
||||||
position: relative;
|
|
||||||
z-index: 1;
|
|
||||||
}
|
|
||||||
.reveal img {
|
.reveal img {
|
||||||
box-shadow: none;
|
box-shadow: none;
|
||||||
}
|
}
|
||||||
|
@ -189,11 +155,17 @@ ul, ol, div, p {
|
||||||
font-size: 16pt !important;
|
font-size: 16pt !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.reveal.center .slides section:not(.stack) {
|
/* Slide backgrounds are placed inside of their slide when exporting to PDF */
|
||||||
display: flex !important;
|
.reveal section .slide-background {
|
||||||
flex-direction: column;
|
position: absolute;
|
||||||
align-items: center;
|
top: 0;
|
||||||
justify-content: center;
|
left: 0;
|
||||||
padding-top: 2em !important;
|
width: 100%;
|
||||||
padding-bottom: 2em !important;
|
z-index: 0;
|
||||||
}
|
}
|
||||||
|
/* All elements should be above the slide-background */
|
||||||
|
.reveal section>* {
|
||||||
|
position: relative;
|
||||||
|
z-index: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -1328,6 +1328,8 @@ body {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
|
||||||
-webkit-perspective: 600px;
|
-webkit-perspective: 600px;
|
||||||
-moz-perspective: 600px;
|
-moz-perspective: 600px;
|
||||||
|
|
150
js/reveal.js
150
js/reveal.js
|
@ -333,6 +333,12 @@ var Reveal = (function(){
|
||||||
// Update all backgrounds
|
// Update all backgrounds
|
||||||
updateBackground( true );
|
updateBackground( true );
|
||||||
|
|
||||||
|
// Special setup and config is required when printing to PDF
|
||||||
|
if( isPrintingPDF() ) {
|
||||||
|
removeEventListeners();
|
||||||
|
setupPDF();
|
||||||
|
}
|
||||||
|
|
||||||
// Notify listeners that the presentation is ready but use a 1ms
|
// Notify listeners that the presentation is ready but use a 1ms
|
||||||
// timeout to ensure it's not fired synchronously after #initialize()
|
// timeout to ensure it's not fired synchronously after #initialize()
|
||||||
setTimeout( function() {
|
setTimeout( function() {
|
||||||
|
@ -401,6 +407,74 @@ var Reveal = (function(){
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Configures the presentation for printing to a static
|
||||||
|
* PDF.
|
||||||
|
*/
|
||||||
|
function setupPDF() {
|
||||||
|
|
||||||
|
// The aspect ratio of pages when saving to PDF in Chrome,
|
||||||
|
// we need to abide by this ratio when determining the pixel
|
||||||
|
// size of our pages
|
||||||
|
var pageAspectRatio = 1.295;
|
||||||
|
|
||||||
|
var slideSize = getComputedSlideSize( window.innerWidth, window.innerHeight );
|
||||||
|
|
||||||
|
// Dimensions of the PDF pages
|
||||||
|
var pageWidth = Math.round( slideSize.width * ( 1 + config.margin ) ),
|
||||||
|
pageHeight = Math.round( pageWidth / pageAspectRatio );
|
||||||
|
|
||||||
|
// Dimensions of slides within the pages
|
||||||
|
var slideWidth = slideSize.width,
|
||||||
|
slideHeight = slideSize.height;
|
||||||
|
|
||||||
|
document.body.classList.add( 'print-pdf' );
|
||||||
|
document.body.style.width = pageWidth + 'px';
|
||||||
|
document.body.style.height = pageHeight + 'px';
|
||||||
|
|
||||||
|
// Slide and slide background layout
|
||||||
|
toArray( document.querySelectorAll( SLIDES_SELECTOR ) ).forEach( function( slide ) {
|
||||||
|
|
||||||
|
// Vertical stacks are not centred since their section
|
||||||
|
// children will be
|
||||||
|
if( slide.classList.contains( 'stack' ) === false ) {
|
||||||
|
// Center the slide inside of the page, giving the slide some margin
|
||||||
|
var left = ( pageWidth - slideWidth ) / 2,
|
||||||
|
top = ( pageHeight - slideHeight ) / 2;
|
||||||
|
|
||||||
|
var contentHeight = getAbsoluteHeight( slide );
|
||||||
|
var numberOfPages = Math.ceil( contentHeight / pageHeight );
|
||||||
|
|
||||||
|
// Center slides vertically
|
||||||
|
if( numberOfPages === 1 && config.center || slide.classList.contains( 'center' ) ) {
|
||||||
|
top = Math.max( ( pageHeight - contentHeight ) / 2, 0 );
|
||||||
|
}
|
||||||
|
|
||||||
|
// Position the slide inside of the page
|
||||||
|
slide.style.left = left + 'px';
|
||||||
|
slide.style.top = top + 'px';
|
||||||
|
slide.style.width = slideWidth + 'px';
|
||||||
|
|
||||||
|
// TODO Backgrounds need to be multiplied when the slide
|
||||||
|
// stretches over multiple pages
|
||||||
|
var background = slide.querySelector( '.slide-background' );
|
||||||
|
if( background ) {
|
||||||
|
background.style.width = pageWidth + 'px';
|
||||||
|
background.style.height = ( pageHeight * numberOfPages ) + 'px';
|
||||||
|
background.style.top = -top + 'px';
|
||||||
|
background.style.left = -left + 'px';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} );
|
||||||
|
|
||||||
|
// Show all fragments
|
||||||
|
toArray( document.querySelectorAll( SLIDES_SELECTOR + ' .fragment' ) ).forEach( function( fragment ) {
|
||||||
|
fragment.classList.add( 'visible' );
|
||||||
|
} );
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates an HTML element and returns a reference to it.
|
* Creates an HTML element and returns a reference to it.
|
||||||
* If the element already exists the existing instance will
|
* If the element already exists the existing instance will
|
||||||
|
@ -428,9 +502,7 @@ var Reveal = (function(){
|
||||||
*/
|
*/
|
||||||
function createBackgrounds() {
|
function createBackgrounds() {
|
||||||
|
|
||||||
if( isPrintingPDF() ) {
|
var printMode = isPrintingPDF();
|
||||||
document.body.classList.add( 'print-pdf' );
|
|
||||||
}
|
|
||||||
|
|
||||||
// Clear prior backgrounds
|
// Clear prior backgrounds
|
||||||
dom.background.innerHTML = '';
|
dom.background.innerHTML = '';
|
||||||
|
@ -441,7 +513,7 @@ var Reveal = (function(){
|
||||||
|
|
||||||
var backgroundStack;
|
var backgroundStack;
|
||||||
|
|
||||||
if( isPrintingPDF() ) {
|
if( printMode ) {
|
||||||
backgroundStack = createBackground( slideh, slideh );
|
backgroundStack = createBackground( slideh, slideh );
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
@ -451,7 +523,7 @@ var Reveal = (function(){
|
||||||
// Iterate over all vertical slides
|
// Iterate over all vertical slides
|
||||||
toArray( slideh.querySelectorAll( 'section' ) ).forEach( function( slidev ) {
|
toArray( slideh.querySelectorAll( 'section' ) ).forEach( function( slidev ) {
|
||||||
|
|
||||||
if( isPrintingPDF() ) {
|
if( printMode ) {
|
||||||
createBackground( slidev, slidev );
|
createBackground( slidev, slidev );
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
@ -887,7 +959,7 @@ var Reveal = (function(){
|
||||||
|
|
||||||
if( typeof child.offsetTop === 'number' && child.style ) {
|
if( typeof child.offsetTop === 'number' && child.style ) {
|
||||||
// Count # of abs children
|
// Count # of abs children
|
||||||
if( child.style.position === 'absolute' ) {
|
if( window.getComputedStyle( child ).position === 'absolute' ) {
|
||||||
absoluteChildren += 1;
|
absoluteChildren += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1124,37 +1196,18 @@ var Reveal = (function(){
|
||||||
|
|
||||||
if( dom.wrapper && !isPrintingPDF() ) {
|
if( dom.wrapper && !isPrintingPDF() ) {
|
||||||
|
|
||||||
// Available space to scale within
|
var size = getComputedSlideSize();
|
||||||
var availableWidth = dom.wrapper.offsetWidth,
|
|
||||||
availableHeight = dom.wrapper.offsetHeight;
|
|
||||||
|
|
||||||
// Reduce available space by margin
|
var slidePadding = 20; // TODO Dig this out of DOM
|
||||||
availableWidth -= ( availableHeight * config.margin );
|
|
||||||
availableHeight -= ( availableHeight * config.margin );
|
|
||||||
|
|
||||||
// Dimensions of the content
|
|
||||||
var slideWidth = config.width,
|
|
||||||
slideHeight = config.height,
|
|
||||||
slidePadding = 20; // TODO Dig this out of DOM
|
|
||||||
|
|
||||||
// Layout the contents of the slides
|
// Layout the contents of the slides
|
||||||
layoutSlideContents( config.width, config.height, slidePadding );
|
layoutSlideContents( config.width, config.height, slidePadding );
|
||||||
|
|
||||||
// Slide width may be a percentage of available width
|
dom.slides.style.width = size.width + 'px';
|
||||||
if( typeof slideWidth === 'string' && /%$/.test( slideWidth ) ) {
|
dom.slides.style.height = size.height + 'px';
|
||||||
slideWidth = parseInt( slideWidth, 10 ) / 100 * availableWidth;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Slide height may be a percentage of available height
|
|
||||||
if( typeof slideHeight === 'string' && /%$/.test( slideHeight ) ) {
|
|
||||||
slideHeight = parseInt( slideHeight, 10 ) / 100 * availableHeight;
|
|
||||||
}
|
|
||||||
|
|
||||||
dom.slides.style.width = slideWidth + 'px';
|
|
||||||
dom.slides.style.height = slideHeight + 'px';
|
|
||||||
|
|
||||||
// Determine scale of content to fit within available space
|
// Determine scale of content to fit within available space
|
||||||
scale = Math.min( availableWidth / slideWidth, availableHeight / slideHeight );
|
scale = Math.min( size.presentationWidth / size.width, size.presentationHeight / size.height );
|
||||||
|
|
||||||
// Respect max/min scale settings
|
// Respect max/min scale settings
|
||||||
scale = Math.max( scale, config.minScale );
|
scale = Math.max( scale, config.minScale );
|
||||||
|
@ -1191,7 +1244,7 @@ var Reveal = (function(){
|
||||||
slide.style.top = 0;
|
slide.style.top = 0;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
slide.style.top = Math.max( ( ( slideHeight - getAbsoluteHeight( slide ) ) / 2 ) - slidePadding, 0 ) + 'px';
|
slide.style.top = Math.max( ( ( size.height - getAbsoluteHeight( slide ) ) / 2 ) - slidePadding, 0 ) + 'px';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
@ -1239,6 +1292,41 @@ var Reveal = (function(){
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calculates the computed pixel size of our slides. These
|
||||||
|
* values are based on the width and height configuration
|
||||||
|
* options.
|
||||||
|
*/
|
||||||
|
function getComputedSlideSize( presentationWidth, presentationHeight ) {
|
||||||
|
|
||||||
|
var size = {
|
||||||
|
// Slide size
|
||||||
|
width: config.width,
|
||||||
|
height: config.height,
|
||||||
|
|
||||||
|
// Presentation size
|
||||||
|
presentationWidth: presentationWidth || dom.wrapper.offsetWidth,
|
||||||
|
presentationHeight: presentationHeight || dom.wrapper.offsetHeight
|
||||||
|
};
|
||||||
|
|
||||||
|
// Reduce available space by margin
|
||||||
|
size.presentationWidth -= ( size.presentationHeight * config.margin );
|
||||||
|
size.presentationHeight -= ( size.presentationHeight * config.margin );
|
||||||
|
|
||||||
|
// Slide width may be a percentage of available width
|
||||||
|
if( typeof size.width === 'string' && /%$/.test( size.width ) ) {
|
||||||
|
size.width = parseInt( size.width, 10 ) / 100 * size.presentationWidth;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Slide height may be a percentage of available height
|
||||||
|
if( typeof size.height === 'string' && /%$/.test( size.height ) ) {
|
||||||
|
size.height = parseInt( size.height, 10 ) / 100 * size.presentationHeight;
|
||||||
|
}
|
||||||
|
|
||||||
|
return size;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Stores the vertical index of a stack so that the same
|
* Stores the vertical index of a stack so that the same
|
||||||
* vertical slide can be selected when navigating to and
|
* vertical slide can be selected when navigating to and
|
||||||
|
|
Loading…
Reference in a new issue