mirror of
https://github.com/niklasvh/html2canvas.git
synced 2023-08-10 21:13:10 +03:00
first implementation for matrix transforms
This commit is contained in:
parent
518dd702a2
commit
10b40821e5
18
src/Core.js
18
src/Core.js
@ -166,6 +166,20 @@ _html2canvas.Util.Bounds = function (element) {
|
|||||||
return bounds;
|
return bounds;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// TODO ideally, we'd want everything to go through this function instead of Util.Bounds,
|
||||||
|
// but would require further work to calculate the correct positions for elements with offsetParents
|
||||||
|
_html2canvas.Util.OffsetBounds = function (element) {
|
||||||
|
var parent = element.offsetParent ? _html2canvas.Util.OffsetBounds(element.offsetParent) : {top: 0, left: 0};
|
||||||
|
|
||||||
|
return {
|
||||||
|
top: element.offsetTop + parent.top,
|
||||||
|
bottom: element.offsetTop + element.offsetHeight + parent.top,
|
||||||
|
left: element.offsetLeft + parent.left,
|
||||||
|
width: element.offsetWidth,
|
||||||
|
height: element.offsetHeight
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
function toPX(element, attribute, value ) {
|
function toPX(element, attribute, value ) {
|
||||||
var rsLeft = element.runtimeStyle && element.runtimeStyle[attribute],
|
var rsLeft = element.runtimeStyle && element.runtimeStyle[attribute],
|
||||||
left,
|
left,
|
||||||
@ -295,14 +309,13 @@ function backgroundBoundsFactory( prop, el, bounds, image, imageIndex, backgroun
|
|||||||
if(prop !== 'backgroundSize') {
|
if(prop !== 'backgroundSize') {
|
||||||
left -= (backgroundSize || image).width*percentage;
|
left -= (backgroundSize || image).width*percentage;
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
if(prop === 'backgroundSize') {
|
if(prop === 'backgroundSize') {
|
||||||
if(bgposition[0] === 'auto') {
|
if(bgposition[0] === 'auto') {
|
||||||
left = image.width;
|
left = image.width;
|
||||||
} else {
|
} else {
|
||||||
if (/contain|cover/.test(bgposition[0])) {
|
if (/contain|cover/.test(bgposition[0])) {
|
||||||
var resized = _html2canvas.Util.resizeBounds( image.width, image.height, bounds.width, bounds.height, bgposition[0] );
|
var resized = _html2canvas.Util.resizeBounds(image.width, image.height, bounds.width, bounds.height, bgposition[0]);
|
||||||
left = resized.width;
|
left = resized.width;
|
||||||
topPos = resized.height;
|
topPos = resized.height;
|
||||||
} else {
|
} else {
|
||||||
@ -335,6 +348,7 @@ _html2canvas.Util.BackgroundPosition = function( el, bounds, image, imageIndex,
|
|||||||
var result = backgroundBoundsFactory( 'backgroundPosition', el, bounds, image, imageIndex, backgroundSize );
|
var result = backgroundBoundsFactory( 'backgroundPosition', el, bounds, image, imageIndex, backgroundSize );
|
||||||
return { left: result[0], top: result[1] };
|
return { left: result[0], top: result[1] };
|
||||||
};
|
};
|
||||||
|
|
||||||
_html2canvas.Util.BackgroundSize = function( el, bounds, image, imageIndex ) {
|
_html2canvas.Util.BackgroundSize = function( el, bounds, image, imageIndex ) {
|
||||||
var result = backgroundBoundsFactory( 'backgroundSize', el, bounds, image, imageIndex );
|
var result = backgroundBoundsFactory( 'backgroundSize', el, bounds, image, imageIndex );
|
||||||
return { width: result[0], height: result[1] };
|
return { width: result[0], height: result[1] };
|
||||||
|
59
src/Parse.js
59
src/Parse.js
@ -48,16 +48,18 @@ _html2canvas.Parse = function (images, options) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function capitalize(m, p1, p2) {
|
||||||
|
if (m.length > 0) {
|
||||||
|
return p1 + p2.toUpperCase();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function textTransform (text, transform) {
|
function textTransform (text, transform) {
|
||||||
switch(transform){
|
switch(transform){
|
||||||
case "lowercase":
|
case "lowercase":
|
||||||
return text.toLowerCase();
|
return text.toLowerCase();
|
||||||
case "capitalize":
|
case "capitalize":
|
||||||
return text.replace( /(^|\s|:|-|\(|\))([a-z])/g , function (m, p1, p2) {
|
return text.replace( /(^|\s|:|-|\(|\))([a-z])/g, capitalize);
|
||||||
if (m.length > 0) {
|
|
||||||
return p1 + p2.toUpperCase();
|
|
||||||
}
|
|
||||||
} );
|
|
||||||
case "uppercase":
|
case "uppercase":
|
||||||
return text.toUpperCase();
|
return text.toUpperCase();
|
||||||
default:
|
default:
|
||||||
@ -127,16 +129,16 @@ _html2canvas.Parse = function (images, options) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function getTextBounds(state, text, textDecoration, isLast) {
|
function getTextBounds(state, text, textDecoration, isLast, transform) {
|
||||||
var bounds;
|
var bounds;
|
||||||
if (support.rangeBounds) {
|
if (support.rangeBounds && !transform) {
|
||||||
if (textDecoration !== "none" || Util.trimText(text).length !== 0) {
|
if (textDecoration !== "none" || Util.trimText(text).length !== 0) {
|
||||||
bounds = textRangeBounds(text, state.node, state.textOffset);
|
bounds = textRangeBounds(text, state.node, state.textOffset);
|
||||||
}
|
}
|
||||||
state.textOffset += text.length;
|
state.textOffset += text.length;
|
||||||
} else if (state.node && typeof state.node.nodeValue === "string" ){
|
} else if (state.node && typeof state.node.nodeValue === "string" ){
|
||||||
var newTextNode = (isLast) ? state.node.splitText(text.length) : null;
|
var newTextNode = (isLast) ? state.node.splitText(text.length) : null;
|
||||||
bounds = textWrapperBounds(state.node);
|
bounds = textWrapperBounds(state.node, transform);
|
||||||
state.node = newTextNode;
|
state.node = newTextNode;
|
||||||
}
|
}
|
||||||
return bounds;
|
return bounds;
|
||||||
@ -149,7 +151,7 @@ _html2canvas.Parse = function (images, options) {
|
|||||||
return range.getBoundingClientRect();
|
return range.getBoundingClientRect();
|
||||||
}
|
}
|
||||||
|
|
||||||
function textWrapperBounds(oldTextNode) {
|
function textWrapperBounds(oldTextNode, transform) {
|
||||||
var parent = oldTextNode.parentNode,
|
var parent = oldTextNode.parentNode,
|
||||||
wrapElement = doc.createElement('wrapper'),
|
wrapElement = doc.createElement('wrapper'),
|
||||||
backupText = oldTextNode.cloneNode(true);
|
backupText = oldTextNode.cloneNode(true);
|
||||||
@ -157,7 +159,7 @@ _html2canvas.Parse = function (images, options) {
|
|||||||
wrapElement.appendChild(oldTextNode.cloneNode(true));
|
wrapElement.appendChild(oldTextNode.cloneNode(true));
|
||||||
parent.replaceChild(wrapElement, oldTextNode);
|
parent.replaceChild(wrapElement, oldTextNode);
|
||||||
|
|
||||||
var bounds = Util.Bounds(wrapElement);
|
var bounds = transform ? Util.OffsetBounds(wrapElement) : Util.Bounds(wrapElement);
|
||||||
parent.replaceChild(backupText, wrapElement);
|
parent.replaceChild(backupText, wrapElement);
|
||||||
return bounds;
|
return bounds;
|
||||||
}
|
}
|
||||||
@ -195,7 +197,7 @@ _html2canvas.Parse = function (images, options) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
textList.forEach(function(text, index) {
|
textList.forEach(function(text, index) {
|
||||||
var bounds = getTextBounds(state, text, textDecoration, (index < textList.length - 1));
|
var bounds = getTextBounds(state, text, textDecoration, (index < textList.length - 1), stack.transform.matrix);
|
||||||
if (bounds) {
|
if (bounds) {
|
||||||
drawText(text, bounds.left, bounds.bottom, ctx);
|
drawText(text, bounds.left, bounds.bottom, ctx);
|
||||||
renderTextDecoration(ctx, textDecoration, bounds, metrics, color);
|
renderTextDecoration(ctx, textDecoration, bounds, metrics, color);
|
||||||
@ -947,14 +949,21 @@ _html2canvas.Parse = function (images, options) {
|
|||||||
return ctx.setVariable("globalAlpha", getCSS(element, "opacity") * ((parentStack) ? parentStack.opacity : 1));
|
return ctx.setVariable("globalAlpha", getCSS(element, "opacity") * ((parentStack) ? parentStack.opacity : 1));
|
||||||
}
|
}
|
||||||
|
|
||||||
function setTransform(ctx, element, parentStack) {
|
function removePx(str) {
|
||||||
|
return str.replace("px", "");
|
||||||
|
}
|
||||||
|
|
||||||
|
var transformRegExp = /(matrix)\((.+)\)/;
|
||||||
|
|
||||||
|
function getTransform(element, parentStack) {
|
||||||
var transform = getCSS(element, "transform") || getCSS(element, "-webkit-transform") || getCSS(element, "-moz-transform") || getCSS(element, "-ms-transform") || getCSS(element, "-o-transform");
|
var transform = getCSS(element, "transform") || getCSS(element, "-webkit-transform") || getCSS(element, "-moz-transform") || getCSS(element, "-ms-transform") || getCSS(element, "-o-transform");
|
||||||
var transformOrigin = getCSS(element, "transform-origin") || getCSS(element, "-webkit-transform-origin") || getCSS(element, "-moz-transform-origin") || getCSS(element, "-ms-transform-origin") || getCSS(element, "-o-transform-origin");
|
var transformOrigin = getCSS(element, "transform-origin") || getCSS(element, "-webkit-transform-origin") || getCSS(element, "-moz-transform-origin") || getCSS(element, "-ms-transform-origin") || getCSS(element, "-o-transform-origin") || "0px 0px";
|
||||||
|
|
||||||
|
transformOrigin = transformOrigin.split(" ").map(removePx).map(Util.asFloat);
|
||||||
|
|
||||||
var matrix;
|
var matrix;
|
||||||
var TRANSFORM_REGEXP = /(matrix)\((.+)\)/;
|
|
||||||
if (transform && transform !== "none") {
|
if (transform && transform !== "none") {
|
||||||
var match = transform.match(TRANSFORM_REGEXP);
|
var match = transform.match(transformRegExp);
|
||||||
if (match) {
|
if (match) {
|
||||||
switch(match[1]) {
|
switch(match[1]) {
|
||||||
case "matrix":
|
case "matrix":
|
||||||
@ -970,14 +979,14 @@ _html2canvas.Parse = function (images, options) {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
function createStack(element, parentStack, bounds) {
|
function createStack(element, parentStack, bounds, transform) {
|
||||||
var ctx = h2cRenderContext((!parentStack) ? documentWidth() : bounds.width , (!parentStack) ? documentHeight() : bounds.height),
|
var ctx = h2cRenderContext((!parentStack) ? documentWidth() : bounds.width , (!parentStack) ? documentHeight() : bounds.height),
|
||||||
stack = {
|
stack = {
|
||||||
ctx: ctx,
|
ctx: ctx,
|
||||||
opacity: setOpacity(ctx, element, parentStack),
|
opacity: setOpacity(ctx, element, parentStack),
|
||||||
cssPosition: getCSS(element, "position"),
|
cssPosition: getCSS(element, "position"),
|
||||||
borders: getBorderData(element),
|
borders: getBorderData(element),
|
||||||
transform: setTransform(ctx, element, parentStack),
|
transform: transform,
|
||||||
clip: (parentStack && parentStack.clip) ? Util.Extend( {}, parentStack.clip ) : null
|
clip: (parentStack && parentStack.clip) ? Util.Extend( {}, parentStack.clip ) : null
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -1006,16 +1015,26 @@ _html2canvas.Parse = function (images, options) {
|
|||||||
return backgroundBounds;
|
return backgroundBounds;
|
||||||
}
|
}
|
||||||
|
|
||||||
function renderElement(element, parentStack, pseudoElement){
|
function getBounds(element, transform) {
|
||||||
var bounds = Util.Bounds(element),
|
var bounds = (transform.matrix) ? Util.OffsetBounds(element) : Util.Bounds(element);
|
||||||
|
transform.origin[0] += bounds.left;
|
||||||
|
transform.origin[1] += bounds.top;
|
||||||
|
return bounds;
|
||||||
|
}
|
||||||
|
|
||||||
|
function renderElement(element, parentStack, pseudoElement) {
|
||||||
|
var transform = getTransform(element, parentStack),
|
||||||
|
bounds = getBounds(element, transform),
|
||||||
image,
|
image,
|
||||||
bgcolor = (ignoreElementsRegExp.test(element.nodeName)) ? "#efefef" : getCSS(element, "backgroundColor"),
|
bgcolor = (ignoreElementsRegExp.test(element.nodeName)) ? "#efefef" : getCSS(element, "backgroundColor"),
|
||||||
stack = createStack(element, parentStack, bounds),
|
stack = createStack(element, parentStack, bounds, transform),
|
||||||
borders = stack.borders,
|
borders = stack.borders,
|
||||||
ctx = stack.ctx,
|
ctx = stack.ctx,
|
||||||
backgroundBounds = getBackgroundBounds(borders, bounds, stack.clip),
|
backgroundBounds = getBackgroundBounds(borders, bounds, stack.clip),
|
||||||
borderData = parseBorders(element, bounds, borders);
|
borderData = parseBorders(element, bounds, borders);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
createShape(ctx, borderData.clip);
|
createShape(ctx, borderData.clip);
|
||||||
|
|
||||||
ctx.save();
|
ctx.save();
|
||||||
|
@ -85,7 +85,9 @@ _html2canvas.Renderer.Canvas = function(options) {
|
|||||||
ctx.save();
|
ctx.save();
|
||||||
|
|
||||||
if (storageContext.transform.matrix) {
|
if (storageContext.transform.matrix) {
|
||||||
|
ctx.translate(storageContext.transform.origin[0], storageContext.transform.origin[1]);
|
||||||
ctx.transform.apply(ctx, storageContext.transform.matrix);
|
ctx.transform.apply(ctx, storageContext.transform.matrix);
|
||||||
|
ctx.translate(-storageContext.transform.origin[0], -storageContext.transform.origin[1]);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (storageContext.clip){
|
if (storageContext.clip){
|
||||||
|
Loading…
Reference in New Issue
Block a user