html2canvas/src/index.js

108 lines
3.4 KiB
JavaScript
Raw Normal View History

2017-07-29 05:07:42 +03:00
/* @flow */
'use strict';
import {NodeParser} from './NodeParser';
import CanvasRenderer from './CanvasRenderer';
import Logger from './Logger';
import ImageLoader from './ImageLoader';
import {Bounds, parseDocumentSize} from './Bounds';
2017-08-01 15:54:18 +03:00
import {cloneWindow} from './Clone';
2017-07-29 05:07:42 +03:00
import Color from './Color';
import {FontMetrics} from './Font';
2017-07-29 05:07:42 +03:00
export type Options = {
2017-08-01 17:36:51 +03:00
async: ?boolean,
allowTaint: ?boolean,
canvas: ?HTMLCanvasElement,
imageTimeout: ?number,
proxy: ?string,
removeContainer: ?boolean,
type: ?string
2017-07-29 05:07:42 +03:00
};
const html2canvas = (element: HTMLElement, config: Options): Promise<HTMLCanvasElement> => {
2017-07-29 05:07:42 +03:00
const logger = new Logger();
2017-08-01 15:54:18 +03:00
const ownerDocument = element.ownerDocument;
const defaultView = ownerDocument.defaultView;
const windowBounds = new Bounds(
defaultView.pageXOffset,
defaultView.pageYOffset,
defaultView.innerWidth,
defaultView.innerHeight
);
2017-08-01 17:36:51 +03:00
const defaultOptions = {
async: true,
allowTaint: false,
canvas: ownerDocument.createElement('canvas'),
imageTimeout: 10000,
proxy: null,
removeContainer: true,
scale: defaultView.devicePixelRatio,
type: null
};
const options = {...defaultOptions, ...config};
const canvas = options.canvas;
if (!(canvas instanceof HTMLCanvasElement)) {
return Promise.reject(__DEV__ ? `Invalid canvas element provided in options` : '');
}
2017-08-01 15:54:18 +03:00
return cloneWindow(
ownerDocument,
ownerDocument,
windowBounds,
element,
options
).then(([container, clonedElement]) => {
if (__DEV__) {
logger.log(`Document cloned`);
}
const imageLoader = new ImageLoader(options, logger);
const stack = NodeParser(clonedElement, imageLoader, logger);
const clonedDocument = clonedElement.ownerDocument;
const size = options.type === 'view' ? windowBounds : parseDocumentSize(clonedDocument);
const width = size.width;
const height = size.height;
2017-08-01 17:36:51 +03:00
canvas.width = Math.floor(width * options.scale);
canvas.height = Math.floor(height * options.scale);
2017-08-01 15:54:18 +03:00
canvas.style.width = `${width}px`;
canvas.style.height = `${height}px`;
// http://www.w3.org/TR/css3-background/#special-backgrounds
const backgroundColor =
clonedElement === clonedDocument.documentElement
2017-08-01 15:54:18 +03:00
? stack.container.style.background.backgroundColor.isTransparent()
? clonedDocument.body
? new Color(getComputedStyle(clonedDocument.body).backgroundColor)
2017-08-01 15:54:18 +03:00
: null
: stack.container.style.background.backgroundColor
: null;
return imageLoader.ready().then(imageStore => {
2017-08-01 17:36:51 +03:00
if (options.removeContainer === true) {
if (container.parentNode) {
container.parentNode.removeChild(container);
} else if (__DEV__) {
logger.log(`Cannot detach cloned iframe as it is not in the DOM anymore`);
}
2017-08-01 15:54:18 +03:00
}
const fontMetrics = new FontMetrics(clonedDocument);
const renderer = new CanvasRenderer(canvas, {
scale: options.scale,
backgroundColor,
imageStore,
fontMetrics
});
2017-08-01 15:54:18 +03:00
return renderer.render(stack);
});
2017-07-29 05:07:42 +03:00
});
};
module.exports = html2canvas;