2011-07-16 20:59:15 +04:00
|
|
|
/**
|
|
|
|
* Creates a render of the element el
|
|
|
|
* @constructor
|
|
|
|
*/
|
|
|
|
|
|
|
|
function html2canvas(el, userOptions) {
|
|
|
|
|
|
|
|
var options = userOptions || {};
|
|
|
|
|
|
|
|
|
|
|
|
this.opts = this.extendObj(options, {
|
|
|
|
logging: false,
|
|
|
|
ready: function (canvas) {
|
|
|
|
document.body.appendChild(canvas);
|
|
|
|
},
|
2011-07-17 03:19:26 +04:00
|
|
|
iframeDefault: "default",
|
2011-07-17 02:34:34 +04:00
|
|
|
flashCanvasPath: "http://html2canvas.hertzen.com/external/flashcanvas/flashcanvas.js",
|
2011-07-18 00:27:45 +04:00
|
|
|
renderViewport: false,
|
|
|
|
reorderZ: true
|
2011-07-16 20:59:15 +04:00
|
|
|
});
|
|
|
|
|
|
|
|
this.element = el;
|
|
|
|
|
|
|
|
var imageLoaded,
|
|
|
|
canvas,
|
|
|
|
ctx,
|
|
|
|
bgx,
|
|
|
|
bgy,
|
|
|
|
image;
|
|
|
|
this.imagesLoaded = 0;
|
|
|
|
this.images = [];
|
2011-07-16 23:35:06 +04:00
|
|
|
this.fontData = [];
|
2011-07-17 03:42:45 +04:00
|
|
|
this.numDraws = 0;
|
2011-07-18 00:27:45 +04:00
|
|
|
this.contextStacks = [];
|
2011-07-16 20:59:15 +04:00
|
|
|
this.ignoreElements = "IFRAME|OBJECT|PARAM";
|
2011-07-18 00:27:45 +04:00
|
|
|
this.needReorder = false;
|
|
|
|
this.blockElements = new RegExp("(BR|PARAM)");
|
2011-07-16 20:59:15 +04:00
|
|
|
|
2011-07-17 03:19:26 +04:00
|
|
|
this.ignoreRe = new RegExp("("+this.ignoreElements+")");
|
2011-07-16 20:59:15 +04:00
|
|
|
|
|
|
|
// test how to measure text bounding boxes
|
|
|
|
this.useRangeBounds = false;
|
2011-07-17 00:56:49 +04:00
|
|
|
|
|
|
|
// Check disabled as Opera doesn't provide bounds.height/bottom even though it supports the method.
|
|
|
|
// TODO take the check back into use, but fix the issue for Opera
|
|
|
|
/*
|
2011-07-16 20:59:15 +04:00
|
|
|
if (document.createRange){
|
|
|
|
var r = document.createRange();
|
|
|
|
this.useRangeBounds = new Boolean(r.getBoundingClientRect);
|
2011-07-17 00:56:49 +04:00
|
|
|
}*/
|
|
|
|
|
2011-07-16 20:59:15 +04:00
|
|
|
// Start script
|
2011-07-17 03:42:45 +04:00
|
|
|
this.init();
|
|
|
|
|
|
|
|
return this;
|
2011-07-16 20:59:15 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
html2canvas.prototype.init = function(){
|
|
|
|
|
|
|
|
var _ = this;
|
|
|
|
|
2011-07-18 00:27:45 +04:00
|
|
|
this.ctx = new this.stackingContext($(document).width(),$(document).height());
|
|
|
|
|
2011-07-16 20:59:15 +04:00
|
|
|
if (!this.ctx){
|
|
|
|
// canvas not initialized, let's kill it here
|
|
|
|
this.log('Canvas not available');
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2011-07-18 00:27:45 +04:00
|
|
|
this.canvas = this.ctx.canvas;
|
2011-07-16 20:59:15 +04:00
|
|
|
|
|
|
|
this.log('Finding background images');
|
|
|
|
|
|
|
|
this.getImages(this.element);
|
|
|
|
|
|
|
|
this.log('Finding images');
|
|
|
|
this.each(document.images,function(i,e){
|
|
|
|
_.preloadImage(_.getAttr(e,'src'));
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
if (this.images.length == 0){
|
|
|
|
this.start();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Check whether all assets have been loaded and start traversing the DOM
|
|
|
|
*/
|
|
|
|
|
|
|
|
html2canvas.prototype.start = function(){
|
|
|
|
|
|
|
|
if (this.images.length == 0 || this.imagesLoaded==this.images.length/2){
|
|
|
|
this.log('Started parsing');
|
2011-07-17 00:56:49 +04:00
|
|
|
this.bodyOverflow = document.getElementsByTagName('body')[0].style.overflow;
|
|
|
|
document.getElementsByTagName('body')[0].style.overflow = "hidden";
|
2011-07-18 00:27:45 +04:00
|
|
|
|
|
|
|
var ctx = this.newElement(this.element, this.ctx) || this.ctx;
|
2011-07-16 20:59:15 +04:00
|
|
|
|
2011-07-18 00:27:45 +04:00
|
|
|
this.parseElement(this.element,ctx);
|
|
|
|
|
2011-07-16 20:59:15 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2011-07-18 00:27:45 +04:00
|
|
|
html2canvas.prototype.stackingContext = function(width,height){
|
|
|
|
this.canvas = document.createElement('canvas');
|
|
|
|
|
|
|
|
// TODO remove jQuery dependency
|
|
|
|
this.canvas.width = $(document).width();
|
|
|
|
this.canvas.height = $(document).height();
|
|
|
|
|
|
|
|
if (!this.canvas.getContext){
|
|
|
|
|
|
|
|
// TODO include Flashcanvas
|
|
|
|
/*
|
|
|
|
var script = document.createElement('script');
|
|
|
|
script.type = "text/javascript";
|
|
|
|
script.src = this.opts.flashCanvasPath;
|
|
|
|
var s = document.getElementsByTagName('script')[0];
|
|
|
|
s.parentNode.insertBefore(script, s);
|
|
|
|
|
|
|
|
if (typeof FlashCanvas != "undefined") {
|
|
|
|
|
|
|
|
FlashCanvas.initElement(this.canvas);
|
|
|
|
this.ctx = this.canvas.getContext('2d');
|
|
|
|
} */
|
|
|
|
|
|
|
|
}else{
|
|
|
|
this.ctx = this.canvas.getContext('2d');
|
|
|
|
}
|
|
|
|
|
|
|
|
// set common settings for canvas
|
|
|
|
this.ctx.textBaseline = "bottom";
|
|
|
|
|
|
|
|
return this.ctx;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
html2canvas.prototype.storageContext = function(width,height){
|
|
|
|
this.storage = [];
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// todo simplify this whole section
|
|
|
|
this.fillRect = function(x, y, w, h){
|
|
|
|
this.storage.push(
|
|
|
|
{
|
|
|
|
type: "function",
|
|
|
|
name:"fillRect",
|
|
|
|
arguments:[x,y,w,h]
|
|
|
|
});
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
this.drawImage = function(image,sx,sy,sw,sh,dx,dy,dw,dh){
|
|
|
|
this.storage.push(
|
|
|
|
{
|
|
|
|
type: "function",
|
|
|
|
name:"drawImage",
|
|
|
|
arguments:[image,sx,sy,sw,sh,dx,dy,dw,dh]
|
|
|
|
});
|
|
|
|
};
|
|
|
|
|
|
|
|
this.fillText = function(currentText,x,y){
|
|
|
|
|
|
|
|
this.storage.push(
|
|
|
|
{
|
|
|
|
type: "function",
|
|
|
|
name:"fillText",
|
|
|
|
arguments:[currentText,x,y]
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
return this;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2011-07-16 20:59:15 +04:00
|
|
|
|
|
|
|
/*
|
2011-07-18 00:27:45 +04:00
|
|
|
* Finished rendering, send callback
|
|
|
|
*/
|
2011-07-16 20:59:15 +04:00
|
|
|
|
|
|
|
html2canvas.prototype.finish = function(){
|
|
|
|
this.log("Finished rendering");
|
2011-07-17 00:56:49 +04:00
|
|
|
document.getElementsByTagName('body')[0].style.overflow = this.bodyOverflow;
|
|
|
|
|
2011-07-16 20:59:15 +04:00
|
|
|
if (this.opts.renderViewport){
|
|
|
|
// let's crop it to viewport only then
|
|
|
|
var newCanvas = document.createElement('canvas');
|
|
|
|
var newctx = newCanvas.getContext('2d');
|
|
|
|
newCanvas.width = window.innerWidth;
|
|
|
|
newCanvas.height = window.innerHeight;
|
|
|
|
|
|
|
|
}
|
2011-07-17 03:42:45 +04:00
|
|
|
this.opts.ready(this);
|
2011-07-16 20:59:15 +04:00
|
|
|
}
|
|
|
|
|