Calculate correct bounds for text/elements under nested transforms

This commit is contained in:
Niklas von Hertzen 2017-08-01 23:27:12 +08:00
parent c5135f4839
commit aafb0cfb9c
5 changed files with 38 additions and 30 deletions

View File

@ -44,20 +44,8 @@ export class Bounds {
}
}
export const parseBounds = (node: HTMLElement, isTransformed: boolean): Bounds => {
return isTransformed ? offsetBounds(node) : Bounds.fromClientRect(node.getBoundingClientRect());
};
const offsetBounds = (node: HTMLElement): Bounds => {
// //$FlowFixMe
const parent = node.offsetParent ? offsetBounds(node.offsetParent) : {top: 0, left: 0};
return new Bounds(
node.offsetLeft + parent.left,
node.offsetTop + parent.top,
node.offsetWidth,
node.offsetHeight
);
export const parseBounds = (node: HTMLElement): Bounds => {
return Bounds.fromClientRect(node.getBoundingClientRect());
};
export const calculatePaddingBox = (bounds: Bounds, borders: Array<Border>): Bounds => {

View File

@ -88,10 +88,15 @@ export default class NodeContainer {
zIndex: parseZIndex(style.zIndex)
};
if (this.isTransformed()) {
// getBoundingClientRect provides values post-transform, we want them without the transformation
node.style.transform = 'matrix(1,0,0,1,0,0)';
}
this.image =
// $FlowFixMe
node.tagName === 'IMG' ? imageLoader.loadImage(node.currentSrc || node.src) : null;
this.bounds = parseBounds(node, this.isTransformed());
this.bounds = parseBounds(node);
if (__DEV__) {
this.name = `${node.tagName.toLowerCase()}${node.id
? `#${node.id}`

View File

@ -35,7 +35,8 @@ const parseNodeTree = (
stack: StackingContext,
imageLoader: ImageLoader
): void => {
node.childNodes.forEach((childNode: Node) => {
for (let childNode = node.firstChild, nextNode; childNode; childNode = nextNode) {
nextNode = childNode.nextSibling;
if (childNode.nodeType === Node.TEXT_NODE) {
//$FlowFixMe
if (childNode.data.trim().length > 0) {
@ -72,7 +73,7 @@ const parseNodeTree = (
}
}
}
});
}
};
const createsRealStackingContext = (container: NodeContainer, node: HTMLElement): boolean => {

View File

@ -3,7 +3,7 @@
import {ucs2} from 'punycode';
import type TextContainer from './TextContainer';
import {Bounds} from './Bounds';
import {Bounds, parseBounds} from './Bounds';
import {TEXT_DECORATION} from './parsing/textDecoration';
import FEATURES from './Feature';
@ -40,19 +40,32 @@ export const parseTextBounds = (textContainer: TextContainer, node: Text): Array
) {
if (FEATURES.SUPPORT_RANGE_BOUNDS) {
textBounds.push(new TextBounds(text, getRangeBounds(node, offset, text.length)));
} else {
const replacementNode = node.splitText(text.length);
textBounds.push(new TextBounds(text, getWrapperBounds(node)));
node = replacementNode;
}
} else if (!FEATURES.SUPPORT_RANGE_BOUNDS) {
node = node.splitText(text.length);
}
offset += text.length;
}
return textBounds;
};
/*
else if (container.node && typeof container.node.data === 'string') {
var replacementNode = container.node.splitText(text.length);
var bounds = this.getWrapperBounds(container.node, container.parent.hasTransform());
container.node = replacementNode;
return bounds;
}*/
const getWrapperBounds = (node: Text): Bounds => {
const wrapper = node.ownerDocument.createElement('html2canvaswrapper');
wrapper.appendChild(node.cloneNode(true));
const parentNode = node.parentNode;
if (parentNode) {
parentNode.replaceChild(wrapper, node);
const bounds = parseBounds(wrapper);
if (wrapper.firstChild) {
parentNode.replaceChild(wrapper.firstChild, wrapper);
}
return bounds;
}
return new Bounds(0, 0, 0, 0);
};
const getRangeBounds = (node: Text, offset: number, length: number): Bounds => {

View File

@ -19,10 +19,7 @@ export type Options = {
type: ?string
};
const html2canvas = (
element: HTMLElement,
config: Options
): Promise<HTMLCanvasElement> => {
const html2canvas = (element: HTMLElement, config: Options): Promise<HTMLCanvasElement> => {
const logger = new Logger();
const ownerDocument = element.ownerDocument;
@ -91,7 +88,11 @@ const html2canvas = (
}
}
const renderer = new CanvasRenderer(canvas, {scale: options.scale, backgroundColor, imageStore});
const renderer = new CanvasRenderer(canvas, {
scale: options.scale,
backgroundColor,
imageStore
});
return renderer.render(stack);
});
});