mirror of
https://github.com/niklasvh/html2canvas.git
synced 2023-08-10 21:13:10 +03:00
initial border-radius rendering
This commit is contained in:
parent
42abcfe5fc
commit
bb73d3c15e
345
src/Parse.js
345
src/Parse.js
@ -330,105 +330,293 @@ _html2canvas.Parse = function (images, options) {
|
||||
);
|
||||
}
|
||||
|
||||
function renderBorders(el, ctx, bounds, clip){
|
||||
function getBorderData(element) {
|
||||
return ["Top", "Right", "Bottom", "Left"].map(function(side) {
|
||||
return {
|
||||
width: getCSSInt(element, 'border' + side + 'Width'),
|
||||
color: getCSS(element, 'border' + side + 'Color')
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
function getBorderRadiusData(element) {
|
||||
return ["TopLeft", "TopRight", "BottomRight", "BottomLeft"].map(function(side) {
|
||||
return getCSS(element, 'border' + side + 'Radius');
|
||||
});
|
||||
}
|
||||
|
||||
function pathArc(x, y, cornerX, cornerY, radius) {
|
||||
return ["arc", cornerX, cornerY, x, y, radius];
|
||||
}
|
||||
|
||||
var getCurvePoints = (function(kappa) {
|
||||
|
||||
return function(x, y, r1, r2) {
|
||||
var ox = (r1) * kappa, // control point offset horizontal
|
||||
oy = (r2) * kappa, // control point offset vertical
|
||||
xm = x + r1, // x-middle
|
||||
ym = y + r2; // y-middle
|
||||
return {
|
||||
topLeft: bezierCurve({
|
||||
x:x,
|
||||
y:ym
|
||||
}, {
|
||||
x:x,
|
||||
y:ym - oy
|
||||
}, {
|
||||
x:xm - ox,
|
||||
y:y
|
||||
}, {
|
||||
x:xm,
|
||||
y:y
|
||||
}),
|
||||
topRight: bezierCurve({
|
||||
x:x,
|
||||
y:y
|
||||
}, {
|
||||
x:x + ox,
|
||||
y:y
|
||||
}, {
|
||||
x:xm,
|
||||
y:ym - oy
|
||||
}, {
|
||||
x:xm,
|
||||
y:ym
|
||||
}),
|
||||
bottomRight: bezierCurve({
|
||||
x:xm,
|
||||
y:y
|
||||
}, {
|
||||
x:xm,
|
||||
y:y + oy
|
||||
}, {
|
||||
x:x + ox,
|
||||
y:ym
|
||||
}, {
|
||||
x:x,
|
||||
y:ym
|
||||
}),
|
||||
bottomLeft: bezierCurve({
|
||||
x:xm,
|
||||
y:ym
|
||||
}, {
|
||||
x:xm - ox,
|
||||
y:ym
|
||||
}, {
|
||||
x:x,
|
||||
y:y + oy
|
||||
}, {
|
||||
x:x,
|
||||
y:y
|
||||
})
|
||||
};
|
||||
};
|
||||
})(4 * ((Math.sqrt(2) - 1) / 3));
|
||||
|
||||
function bezierCurve(start, startControl, endControl, end) {
|
||||
|
||||
var lerp = function (a, b, t) {
|
||||
return {
|
||||
x:a.x + (b.x - a.x) * t,
|
||||
y:a.y + (b.y - a.y) * t
|
||||
};
|
||||
};
|
||||
|
||||
return {
|
||||
start: start,
|
||||
startControl: startControl,
|
||||
endControl: endControl,
|
||||
end: end,
|
||||
subdivide: function(t) {
|
||||
var ab = lerp(start, startControl, t),
|
||||
bc = lerp(startControl, endControl, t),
|
||||
cd = lerp(endControl, end, t),
|
||||
abbc = lerp(ab, bc, t),
|
||||
bccd = lerp(bc, cd, t),
|
||||
dest = lerp(abbc, bccd, t);
|
||||
return [bezierCurve(start, ab, abbc, dest), bezierCurve(dest, bccd, cd, end)];
|
||||
},
|
||||
curveTo: function(borderArgs) {
|
||||
borderArgs.push(["bezierCurve", startControl.x, startControl.y, endControl.x, endControl.y, end.x, end.y]);
|
||||
},
|
||||
curveToReversed: function(borderArgs) {
|
||||
borderArgs.push(["bezierCurve", endControl.x, endControl.y, startControl.x, startControl.y, start.x, start.y]);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
function drawSide(borderData, radius1, radius2, outer1, inner1, outer2, inner2) {
|
||||
var borderArgs = [];
|
||||
|
||||
if (radius1[0] > 0 || radius1[1] > 0) {
|
||||
borderArgs.push(["line", outer1[1].start.x, outer1[1].start.y]);
|
||||
outer1[1].curveTo(borderArgs);
|
||||
} else {
|
||||
borderArgs.push([ "line", borderData.c1[0], borderData.c1[1]]);
|
||||
}
|
||||
|
||||
if (radius2[0] > 0 || radius2[1] > 0) {
|
||||
borderArgs.push(["line", outer2[0].start.x, outer2[0].start.y]);
|
||||
outer2[0].curveTo(borderArgs);
|
||||
borderArgs.push(["line", inner2[0].end.x, inner2[0].end.y]);
|
||||
inner2[0].curveToReversed(borderArgs);
|
||||
} else {
|
||||
borderArgs.push([ "line", borderData.c2[0], borderData.c2[1]]);
|
||||
borderArgs.push([ "line", borderData.c3[0], borderData.c3[1]]);
|
||||
}
|
||||
|
||||
if (radius1[0] > 0 || radius1[1] > 0) {
|
||||
borderArgs.push(["line", inner1[1].end.x, inner1[1].end.y]);
|
||||
inner1[1].curveToReversed(borderArgs);
|
||||
} else {
|
||||
borderArgs.push([ "line", borderData.c4[0], borderData.c4[1]]);
|
||||
}
|
||||
|
||||
return borderArgs;
|
||||
}
|
||||
|
||||
function parseBorders(element, ctx, bounds, clip, borders){
|
||||
var x = bounds.left,
|
||||
y = bounds.top,
|
||||
w = bounds.width,
|
||||
h = bounds.height,
|
||||
width = bounds.width,
|
||||
height = bounds.height,
|
||||
borderSide,
|
||||
borderData,
|
||||
bx,
|
||||
by,
|
||||
bw,
|
||||
bh,
|
||||
i,
|
||||
borderArgs,
|
||||
borderBounds,
|
||||
borders = (function(el){
|
||||
var borders = [],
|
||||
sides = ["Top","Right","Bottom","Left"],
|
||||
s;
|
||||
|
||||
for (s = 0; s < 4; s+=1){
|
||||
borders.push({
|
||||
width: getCSSInt(el, 'border' + sides[s] + 'Width'),
|
||||
color: getCSS(el, 'border' + sides[s] + 'Color')
|
||||
});
|
||||
}
|
||||
|
||||
return borders;
|
||||
|
||||
}(el)),
|
||||
// http://www.w3.org/TR/css3-background/#the-border-radius
|
||||
borderRadius = (function( el ) {
|
||||
var borders = [],
|
||||
sides = ["TopLeft","TopRight","BottomRight","BottomLeft"],
|
||||
s;
|
||||
|
||||
for (s = 0; s < 4; s+=1){
|
||||
borders.push( getCSS(el, 'border' + sides[s] + 'Radius') );
|
||||
}
|
||||
|
||||
return borders;
|
||||
})( el );
|
||||
borderRadius = getBorderRadiusData(element);
|
||||
|
||||
|
||||
var tlh = borderRadius[0][0];
|
||||
var tlv = borderRadius[0][1];
|
||||
var trh = borderRadius[1][0];
|
||||
var trv = borderRadius[1][1];
|
||||
var brv = borderRadius[2][0];
|
||||
var brh = borderRadius[2][1];
|
||||
var blh = borderRadius[3][0];
|
||||
var blv = borderRadius[3][1];
|
||||
|
||||
for ( borderSide = 0; borderSide < 4; borderSide+=1 ) {
|
||||
borderData = borders[ borderSide ];
|
||||
|
||||
var topWidth = width - trh;
|
||||
var rightHeight = height - brv;
|
||||
var bottomWidth = width - brh;
|
||||
var leftHeight = height - blv;
|
||||
|
||||
var topLeftOuter = getCurvePoints(
|
||||
x,
|
||||
y,
|
||||
tlh,
|
||||
tlv
|
||||
).topLeft.subdivide(0.5);
|
||||
|
||||
var topLeftInner = getCurvePoints(
|
||||
x + borders[3].width,
|
||||
y + borders[0].width,
|
||||
Math.max(0, tlh - borders[3].width),
|
||||
Math.max(0, tlv - borders[0].width)
|
||||
).topLeft.subdivide(0.5);
|
||||
|
||||
var topRightOuter = getCurvePoints(
|
||||
x + topWidth,
|
||||
y,
|
||||
trh,
|
||||
trv
|
||||
).topRight.subdivide(0.5);
|
||||
|
||||
var topRightInner = getCurvePoints(
|
||||
x + Math.min(topWidth, width + borders[3].width),
|
||||
y + borders[0].width,
|
||||
(topWidth > width + borders[3].width) ? 0 :trh - borders[3].width,
|
||||
trv - borders[0].width
|
||||
).topRight.subdivide(0.5);
|
||||
|
||||
var bottomRightOuter = getCurvePoints(
|
||||
x + bottomWidth,
|
||||
y + rightHeight,
|
||||
brh,
|
||||
brv
|
||||
).bottomRight.subdivide(0.5);
|
||||
var bottomRightInner = getCurvePoints(
|
||||
x + Math.min(bottomWidth, width + borders[3].width),
|
||||
y + Math.min(rightHeight, height + borders[0].width),
|
||||
Math.max(0, brh - borders[1].width),
|
||||
Math.max(0, brv - borders[2].width)
|
||||
).bottomRight.subdivide(0.5);
|
||||
|
||||
var bottomLeftOuter = getCurvePoints(
|
||||
x,
|
||||
y + leftHeight,
|
||||
blh,
|
||||
blv
|
||||
).bottomLeft.subdivide(0.5);
|
||||
|
||||
var bottomLeftInner = getCurvePoints(
|
||||
x + borders[3].width,
|
||||
y + leftHeight,
|
||||
Math.max(0, blh - borders[3].width),
|
||||
Math.max(0, blv - borders[2].width)
|
||||
).bottomLeft.subdivide(0.5);
|
||||
|
||||
for (borderSide = 0; borderSide < 4; borderSide++) {
|
||||
borderData = borders[borderSide];
|
||||
borderArgs = [];
|
||||
if (borderData.width>0){
|
||||
bx = x;
|
||||
by = y;
|
||||
bw = w;
|
||||
bh = h - (borders[2].width);
|
||||
bw = width;
|
||||
bh = height - (borders[2].width);
|
||||
|
||||
switch(borderSide){
|
||||
case 0:
|
||||
// top border
|
||||
bh = borders[0].width;
|
||||
|
||||
i = 0;
|
||||
borderArgs[ i++ ] = [ "line", bx, by ]; // top left
|
||||
borderArgs[ i++ ] = [ "line", bx + bw, by ]; // top right
|
||||
borderArgs[ i++ ] = [ "line", bx + bw - borders[ 1 ].width, by + bh ]; // bottom right
|
||||
borderArgs[ i++ ] = [ "line", bx + borders[ 3 ].width, by + bh ]; // bottom left
|
||||
|
||||
borderArgs = drawSide({
|
||||
c1: [bx, by],
|
||||
c2: [bx + bw, by],
|
||||
c3: [bx + bw - borders[1].width, by + bh],
|
||||
c4: [bx + borders[3].width, by + bh]
|
||||
}, borderRadius[0], borderRadius[1], topLeftOuter, topLeftInner, topRightOuter, topRightInner);
|
||||
break;
|
||||
case 1:
|
||||
// right border
|
||||
bx = x + w - (borders[1].width);
|
||||
bx = x + width - (borders[1].width);
|
||||
bw = borders[1].width;
|
||||
|
||||
i = 0;
|
||||
borderArgs[ i++ ] = [ "line", bx, by + borders[ 0 ].width]; // top left
|
||||
borderArgs[ i++ ] = [ "line", bx + bw, by ]; // top right
|
||||
borderArgs[ i++ ] = [ "line", bx + bw, by + bh + borders[ 2 ].width ]; // bottom right
|
||||
borderArgs[ i++ ] = [ "line", bx, by + bh ]; // bottom left
|
||||
|
||||
borderArgs = drawSide({
|
||||
c1: [bx + bw, by],
|
||||
c2: [bx + bw, by + bh + borders[2].width],
|
||||
c3: [bx, by + bh],
|
||||
c4: [bx, by + borders[0].width]
|
||||
}, borderRadius[1], borderRadius[2], topRightOuter, topRightInner, bottomRightOuter, bottomRightInner);
|
||||
break;
|
||||
case 2:
|
||||
// bottom border
|
||||
by = (by + h) - (borders[2].width);
|
||||
by = (by + height) - (borders[2].width);
|
||||
bh = borders[2].width;
|
||||
|
||||
i = 0;
|
||||
borderArgs[ i++ ] = [ "line", bx + borders[ 3 ].width, by ]; // top left
|
||||
borderArgs[ i++ ] = [ "line", bx + bw - borders[ 2 ].width, by ]; // top right
|
||||
borderArgs[ i++ ] = [ "line", bx + bw, by + bh ]; // bottom right
|
||||
borderArgs[ i++ ] = [ "line", bx, by + bh ]; // bottom left
|
||||
|
||||
borderArgs = drawSide({
|
||||
c1: [bx + bw, by + bh],
|
||||
c2: [bx, by + bh],
|
||||
c3: [bx + borders[3].width, by],
|
||||
c4: [bx + bw - borders[2].width, by]
|
||||
}, borderRadius[2], borderRadius[3], bottomRightOuter, bottomRightInner, bottomLeftOuter, bottomLeftInner);
|
||||
break;
|
||||
case 3:
|
||||
// left border
|
||||
bw = borders[3].width;
|
||||
|
||||
i = 0;
|
||||
borderArgs[ i++ ] = [ "line", bx, by ]; // top left
|
||||
borderArgs[ i++ ] = [ "line", bx + bw, by + borders[ 0 ].width ]; // top right
|
||||
borderArgs[ i++ ] = [ "line", bx + bw, by + bh ]; // bottom right
|
||||
borderArgs[ i++ ] = [ "line", bx, by + bh + borders[ 2 ].width ]; // bottom left
|
||||
|
||||
borderArgs = drawSide({
|
||||
c1: [bx, by + bh + borders[2].width],
|
||||
c2: [bx, by],
|
||||
c3: [bx + bw, by + borders[0].width],
|
||||
c4: [bx + bw, by + bh]
|
||||
}, borderRadius[3], borderRadius[0], bottomLeftOuter, bottomLeftInner, topLeftOuter, topLeftInner);
|
||||
break;
|
||||
}
|
||||
|
||||
@ -442,32 +630,25 @@ _html2canvas.Parse = function (images, options) {
|
||||
if (clip){
|
||||
borderBounds = clipBounds(borderBounds, clip);
|
||||
}
|
||||
|
||||
|
||||
if ( borderBounds.width > 0 && borderBounds.height > 0 ) {
|
||||
|
||||
if ( borderData.color !== "transparent" ){
|
||||
ctx.setVariable( "fillStyle", borderData.color );
|
||||
|
||||
var shape = ctx.drawShape(),
|
||||
numBorderArgs = borderArgs.length;
|
||||
|
||||
for ( i = 0; i < numBorderArgs; i++ ) {
|
||||
shape[( i === 0) ? "moveTo" : borderArgs[ i ][ 0 ] + "To" ].apply( null, borderArgs[ i ].slice(1) );
|
||||
}
|
||||
|
||||
numDraws+=1;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
renderBorders(ctx, borderArgs, borderBounds, borderData.color);
|
||||
}
|
||||
}
|
||||
|
||||
return borders;
|
||||
}
|
||||
|
||||
function renderBorders(ctx, borderArgs, borderBounds, color) {
|
||||
if (borderBounds.width > 0 && borderBounds.height > 0) {
|
||||
if (color !== "transparent") {
|
||||
ctx.setVariable( "fillStyle", color);
|
||||
var shape = ctx.drawShape();
|
||||
borderArgs.forEach(function(border, index) {
|
||||
shape[(index === 0) ? "moveTo" : border[0] + "To" ].apply(null, border.slice(1));
|
||||
});
|
||||
numDraws+=1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function renderFormValue (el, bounds, stack){
|
||||
|
||||
@ -695,7 +876,7 @@ _html2canvas.Parse = function (images, options) {
|
||||
zIndex: setZ(getCSS(element, "zIndex"), (parentStack) ? parentStack.zIndex : null),
|
||||
opacity: setOpacity(ctx, element, parentStack),
|
||||
cssPosition: getCSS(element, "position"),
|
||||
borders: renderBorders(element, ctx, bounds, false),
|
||||
borders: getBorderData(element),
|
||||
clip: (parentStack && parentStack.clip) ? _html2canvas.Util.Extend( {}, parentStack.clip ) : null
|
||||
};
|
||||
|
||||
@ -738,6 +919,8 @@ _html2canvas.Parse = function (images, options) {
|
||||
renderBackgroundImage(element, backgroundBounds, ctx);
|
||||
}
|
||||
|
||||
parseBorders(element, ctx, bounds, stack.clip, borders);
|
||||
|
||||
switch(element.nodeName){
|
||||
case "IMG":
|
||||
if ((image = loadImage(element.getAttribute('src')))) {
|
||||
|
@ -34,6 +34,12 @@ function h2cRenderContext(width, height) {
|
||||
'arguments': arguments
|
||||
});
|
||||
},
|
||||
arcTo: function() {
|
||||
shape.push({
|
||||
name: "arcTo",
|
||||
'arguments': arguments
|
||||
});
|
||||
},
|
||||
bezierCurveTo: function() {
|
||||
shape.push({
|
||||
name: "bezierCurveTo",
|
||||
|
@ -31,7 +31,7 @@
|
||||
|
||||
.box3 {
|
||||
border-width: 10px;
|
||||
border-left-color: #00b5e2;
|
||||
border-left-color: transparent;
|
||||
border-top-color: red;
|
||||
border-right-color: green;
|
||||
}
|
||||
@ -40,7 +40,9 @@
|
||||
border-width: 50px;
|
||||
border-left-color: #00b5e2;
|
||||
border-top-color: red;
|
||||
border-top-width: 10px;
|
||||
border-right-color: green;
|
||||
border-bottom-right-radius: 190px;
|
||||
}
|
||||
|
||||
html {
|
||||
|
Loading…
Reference in New Issue
Block a user