diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..b96b18b --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +slides/* diff --git a/Readme.md b/Readme.md index 4cb4725..401120b 100644 --- a/Readme.md +++ b/Readme.md @@ -50,6 +50,14 @@ dictumst. Fusce faucibus sagittis sapien vel posuere. ```ruby ['a', 'b'].map(&:uppercase) ```` + +## Exporting -# GistDeck by noah and todd +You can export your deck as a stack of PNGs or as a single PDF using our +phantomjs plugin + +1. `sudo npm install -g phantomjs` +2. `phantomjs rasterize.js [directory] [width] [height]` +3. `convert slides/* -compress jpeg -resize 1024x768 -units PixelsPerInch -density 150x150 output.pdf # requires ImageMagick` +# GistDeck by noah and todd diff --git a/gist.html b/gist.html index b0448ca..44b0bda 100644 --- a/gist.html +++ b/gist.html @@ -12,8 +12,8 @@ - - + + @@ -25,13 +25,12 @@ + diff --git a/gistdeck.js b/gistdeck.js index 5c54a17..e1f8b93 100644 --- a/gistdeck.js +++ b/gistdeck.js @@ -1,4 +1,4 @@ -(function() { +function gistdeck() { // Cache window and slides jQuery selectors var $window = $(window); @@ -11,6 +11,20 @@ .addClass('gistdeck-css') .appendTo('head'); + $('[id$=-css]').each(function() { + // Using ajax to grab contents of CSS file because gist doesn't + // provide the right content-type to make it a style link + // No problems with same-origin policy when script is run from gist.github.com + $.ajax({ + url: $(this).find('.file-actions a:last').attr('href'), + success: function(data) { + $( '' ) + .addClass('gistdeck-css') + .appendTo('head'); + } + }); + }); + // Set gap before all slides but first, and after slides container, equal to the window height $slides.not($slides.first()).css('margin-top', $window.height()); $('.markdown-body').css('margin-bottom', $window.height()); @@ -90,4 +104,6 @@ initialize(); } -})(); +}; + +module.exports = gistdeck; diff --git a/rasterize.js b/rasterize.js new file mode 100644 index 0000000..470adeb --- /dev/null +++ b/rasterize.js @@ -0,0 +1,92 @@ +var gistdeck = require( './gistdeck' ), + page = require( 'webpage' ).create(), + system = require( 'system' ), + address, outputDir, + viewportWidth = 1024, + viewportHeight = 768; + +if ( system.args.length < 2 || system.args.length > 5 ) { + console.log( 'Usage: rasterize.js URL [directory width height]' ); + phantom.exit( 1 ); +} else { + address = system.args[1]; + outputDir = system.args[2]; + viewportWidth = system.args[3] || viewportWidth; + viewportHeight = system.args[4] || viewportHeight; + page.viewportSize = { width: viewportWidth, height: viewportHeight }; + + function pad(n, width, z) { + z = z || '0'; + n = n + ''; + return n.length >= width ? n : new Array(width - n.length + 1).join(z) + n; + } + + page.open( address, function (status) { + if ( status !== 'success' ) { + console.log( 'Unable to load that gist!' ); + phantom.exit(); + } else { + + // Set timeout for page/images to load + window.setTimeout( function() { + console.log( 'Generating Images...' ); + page.evaluate( function( gistdeck, viewportHeight ) { + document.height = viewportHeight; + + gistdeck(); + }, gistdeck, viewportHeight ); + + // Set timeout again to let gistdeck styles load + setTimeout( function() { + var i = 0, + scroll, + totalHeight, + roughCount, + numLen, + data = page.evaluate( function() { + return { + scroll: $(document).scrollTop(), + winHeight: $('.markdown-body').height() + }; + }); + + scroll = data.scroll; + totalHeight = data.winHeight; + roughCount = Math.round( totalHeight / viewportHeight ); + numLen = ( roughCount + '' ).length + 1; + + // Keep advancing and taking screen shots until we reach the last slide + while( totalHeight - scroll > viewportHeight ) { + + var data = page.evaluate( function(i) { + var e = $.Event( 'keydown.gistdeck', {which: 39 } ), + $doc = $(document); + + // Programmatically hit the right arrow key + // to navigate slides + // We have to hit it i times because phantomJS doesn't save + // our scrollTop + for( var j = 0; j < i; j++ ) { + $doc.trigger(e); + } + + return { + scroll: $(document).scrollTop(), + winHeight: $('.markdown-body').height() + }; + }, i); + + scroll = data.scroll; + totalHeight = data.winHeight; + + // Take snapshot relative to scroll position + page.clipRect = { top: scroll, left: 0, width: viewportWidth, height: viewportHeight }; + page.render( ( outputDir ? outputDir : 'slides' ) + '/slide-' + pad(i+1, numLen) + '.png' ); + i++; + } + phantom.exit(); + }, 2000 ); + }, 2000); + } + }); +}