Skip to content

Commit 29b580d

Browse files
committed
added support for form element text value rendering
1 parent 8082865 commit 29b580d

8 files changed

Lines changed: 344 additions & 186 deletions

File tree

build.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
<fileset dir="${src.dir}" includes="Background.js"/>
2222
<fileset dir="${src.dir}" includes="Border.js"/>
2323
<fileset dir="${src.dir}" includes="Draw.js"/>
24+
<fileset dir="${src.dir}" includes="Forms.js"/>
2425
<fileset dir="${src.dir}" includes="Images.js"/>
2526
<fileset dir="${src.dir}" includes="Renderer.js"/>
2627
<fileset dir="${src.dir}" includes="Text.js"/>

build/html2canvas.js

Lines changed: 167 additions & 90 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* html2canvas v0.26 <http://html2canvas.hertzen.com>
2+
* html2canvas v0.27 <http://html2canvas.hertzen.com>
33
* Copyright (c) 2011 Niklas von Hertzen. All rights reserved.
44
* http://www.twitter.com/niklasvh
55
*
@@ -737,7 +737,7 @@ html2canvas.prototype.newElement = function(el,parentStack){
737737
stack.clip.width = stack.clip.width-(borders[1].width);
738738
stack.clip.height = stack.clip.height-(borders[2].width);
739739
}
740-
*/
740+
*/
741741
if (this.ignoreRe.test(el.nodeName) && this.opts.iframeDefault != "transparent"){
742742
if (this.opts.iframeDefault=="default"){
743743
bgcolor = "#efefef";
@@ -780,26 +780,59 @@ html2canvas.prototype.newElement = function(el,parentStack){
780780
this.drawBackground(el,bgbounds,ctx);
781781
}
782782

783-
if (el.nodeName=="IMG"){
784-
image = _.loadImage(_.getAttr(el,'src'));
785-
if (image){
786-
// console.log(image.width);
787-
this.drawImage(
788-
ctx,
789-
image,
790-
0, //sx
791-
0, //sy
792-
image.width, //sw
793-
image.height, //sh
794-
x+parseInt(_.getCSS(el,'padding-left'),10) + borders[3].width, //dx
795-
y+parseInt(_.getCSS(el,'padding-top'),10) + borders[0].width, // dy
796-
bounds.width - (borders[1].width + borders[3].width + parseInt(_.getCSS(el,'padding-left'),10) + parseInt(_.getCSS(el,'padding-right'),10)), //dw
797-
bounds.height - (borders[0].width + borders[2].width + parseInt(_.getCSS(el,'padding-top'),10) + parseInt(_.getCSS(el,'padding-bottom'),10)) //dh
798-
);
783+
switch(el.nodeName){
784+
case "IMG":
785+
image = _.loadImage(_.getAttr(el,'src'));
786+
if (image){
787+
// console.log(image.width);
788+
this.drawImage(
789+
ctx,
790+
image,
791+
0, //sx
792+
0, //sy
793+
image.width, //sw
794+
image.height, //sh
795+
x+parseInt(_.getCSS(el,'padding-left'),10) + borders[3].width, //dx
796+
y+parseInt(_.getCSS(el,'padding-top'),10) + borders[0].width, // dy
797+
bounds.width - (borders[1].width + borders[3].width + parseInt(_.getCSS(el,'padding-left'),10) + parseInt(_.getCSS(el,'padding-right'),10)), //dw
798+
bounds.height - (borders[0].width + borders[2].width + parseInt(_.getCSS(el,'padding-top'),10) + parseInt(_.getCSS(el,'padding-bottom'),10)) //dh
799+
);
799800

800-
}else {
801-
this.log("Error loading <img>:" + _.getAttr(el,'src'));
802-
}
801+
}else {
802+
this.log("Error loading <img>:" + _.getAttr(el,'src'));
803+
}
804+
break;
805+
case "INPUT":
806+
// TODO add all relevant type's, i.e. HTML5 new stuff
807+
// todo add support for placeholder attribute for browsers which support it
808+
if (/^(text|url|email|submit|button|reset)$/.test(el.type) && el.value.length > 0){
809+
810+
this.renderFormValue(el,bounds,stack);
811+
812+
813+
/*
814+
this just doesn't work well enough
815+
816+
this.newText(el,{
817+
nodeValue:el.value,
818+
splitText: function(){
819+
return this;
820+
},
821+
formValue:true
822+
},stack);
823+
*/
824+
}
825+
break;
826+
case "TEXTAREA":
827+
if (el.value.length > 0){
828+
this.renderFormValue(el,bounds,stack);
829+
}
830+
break;
831+
case "SELECT":
832+
if (el.options.length > 0){
833+
this.renderFormValue(el,bounds,stack);
834+
}
835+
break;
803836
}
804837

805838

@@ -816,8 +849,8 @@ html2canvas.prototype.newElement = function(el,parentStack){
816849

817850

818851
/*
819-
* Function to draw the text on the canvas
820-
*/
852+
* Function to draw the text on the canvas
853+
*/
821854

822855
html2canvas.prototype.printText = function(currentText,x,y,ctx){
823856
if (this.trim(currentText).length>0){
@@ -852,6 +885,44 @@ html2canvas.prototype.drawImage = function(ctx,image,sx,sy,sw,sh,dx,dy,dw,dh){
852885
);
853886
this.numDraws++;
854887

888+
}
889+
html2canvas.prototype.renderFormValue = function(el,bounds,stack){
890+
891+
var valueWrap = document.createElement('valuewrap'),
892+
_ = this;
893+
894+
this.each(['lineHeight','textAlign','fontFamily','color','fontSize','paddingLeft','paddingTop','width','height','border','borderLeftWidth','borderTopWidth'],function(i,style){
895+
valueWrap.style[style] = _.getCSS(el,style);
896+
});
897+
898+
valueWrap.style.borderColor = "black";
899+
valueWrap.style.borderStyle = "solid";
900+
valueWrap.style.display = "block";
901+
valueWrap.style.position = "absolute";
902+
if (/^(submit|reset|button|text|password)$/.test(el.type) || el.nodeName == "SELECT"){
903+
valueWrap.style.lineHeight = _.getCSS(el,"height");
904+
}
905+
906+
907+
valueWrap.style.top = bounds.top+"px";
908+
valueWrap.style.left = bounds.left+"px";
909+
if (el.nodeName == "SELECT"){
910+
// TODO increase accuracy of text position
911+
var textValue = el.options[el.selectedIndex].text;
912+
} else{
913+
var textValue = el.value;
914+
915+
}
916+
var textNode = document.createTextNode(textValue);
917+
918+
valueWrap.appendChild(textNode);
919+
$('body').append(valueWrap);
920+
921+
this.newText(el,textNode,stack);
922+
923+
$(valueWrap).remove();
924+
925+
855926
}
856927
/*
857928
* Function to find all images from <img> and background-image
@@ -1331,7 +1402,7 @@ html2canvas.prototype.setContextVariable = function(ctx,variable,value){
13311402

13321403
}
13331404

1334-
html2canvas.prototype.newText = function(el,textNode,stack){
1405+
html2canvas.prototype.newText = function(el,textNode,stack,form){
13351406
var ctx = stack.ctx;
13361407
var family = this.getCSS(el,"font-family");
13371408
var size = this.getCSS(el,"font-size");
@@ -1346,7 +1417,7 @@ html2canvas.prototype.newText = function(el,textNode,stack){
13461417

13471418

13481419
var letter_spacing = this.getCSS(el,"letter-spacing");
1349-
1420+
13501421
// apply text-transform:ation to the text
13511422
textNode.nodeValue = this.textTransform(textNode.nodeValue,this.getCSS(el,"text-transform"));
13521423
var text = this.trim(textNode.nodeValue);
@@ -1400,79 +1471,81 @@ html2canvas.prototype.newText = function(el,textNode,stack){
14001471
}
14011472
*/
14021473

1403-
14041474

1405-
1406-
var oldTextNode = textNode;
1407-
for(var c=0;c<renderList.length;c++){
14081475

1409-
// TODO only do the splitting for non-range prints
1410-
var newTextNode = oldTextNode.splitText(renderList[c].length);
1476+
1477+
var oldTextNode = textNode;
1478+
for(var c=0;c<renderList.length;c++){
1479+
1480+
// TODO only do the splitting for non-range prints
1481+
1482+
var newTextNode = oldTextNode.splitText(renderList[c].length);
14111483

1412-
if (text_decoration!="none" || this.trim(oldTextNode.nodeValue).length != 0){
1484+
if (text_decoration!="none" || this.trim(oldTextNode.nodeValue).length != 0){
14131485

14141486

14151487

14161488

1417-
if (this.support.rangeBounds){
1418-
// getBoundingClientRect is supported for ranges
1419-
if (document.createRange){
1420-
var range = document.createRange();
1421-
range.selectNode(oldTextNode);
1422-
}else{
1423-
// TODO add IE support
1424-
var range = document.body.createTextRange();
1425-
}
1426-
if (range.getBoundingClientRect()){
1427-
var bounds = range.getBoundingClientRect();
1489+
if (this.support.rangeBounds){
1490+
// getBoundingClientRect is supported for ranges
1491+
if (document.createRange){
1492+
var range = document.createRange();
1493+
range.selectNode(oldTextNode);
1494+
}else{
1495+
// TODO add IE support
1496+
var range = document.body.createTextRange();
1497+
}
1498+
if (range.getBoundingClientRect()){
1499+
var bounds = range.getBoundingClientRect();
1500+
}else{
1501+
var bounds = {};
1502+
}
14281503
}else{
1429-
var bounds = {};
1430-
}
1431-
}else{
1432-
// it isn't supported, so let's wrap it inside an element instead and the bounds there
1504+
// it isn't supported, so let's wrap it inside an element instead and the bounds there
14331505

1434-
var parent = oldTextNode.parentNode;
1435-
var wrapElement = document.createElement('wrapper');
1436-
var backupText = oldTextNode.cloneNode(true);
1437-
wrapElement.appendChild(oldTextNode.cloneNode(true));
1438-
parent.replaceChild(wrapElement,oldTextNode);
1506+
var parent = oldTextNode.parentNode;
1507+
var wrapElement = document.createElement('wrapper');
1508+
var backupText = oldTextNode.cloneNode(true);
1509+
wrapElement.appendChild(oldTextNode.cloneNode(true));
1510+
parent.replaceChild(wrapElement,oldTextNode);
14391511

1440-
var bounds = this.getBounds(wrapElement);
1512+
var bounds = this.getBounds(wrapElement);
14411513

14421514

1443-
parent.replaceChild(backupText,wrapElement);
1444-
}
1515+
parent.replaceChild(backupText,wrapElement);
1516+
}
14451517

14461518

14471519

14481520

1449-
// console.log(range);
1450-
// console.log("'"+oldTextNode.nodeValue+"'"+bounds.left)
1451-
this.printText(oldTextNode.nodeValue,bounds.left,bounds.bottom,ctx);
1521+
// console.log(range);
1522+
// console.log("'"+oldTextNode.nodeValue+"'"+bounds.left)
1523+
this.printText(oldTextNode.nodeValue,bounds.left,bounds.bottom,ctx);
14521524

1453-
switch(text_decoration) {
1454-
case "underline":
1455-
// Draws a line at the baseline of the font
1456-
// TODO As some browsers display the line as more than 1px if the font-size is big, need to take that into account both in position and size
1457-
this.newRect(ctx,bounds.left,Math.round(bounds.top+metrics.baseline+metrics.lineWidth),bounds.width,1,color);
1458-
break;
1459-
case "overline":
1460-
this.newRect(ctx,bounds.left,bounds.top,bounds.width,1,color);
1461-
break;
1462-
case "line-through":
1463-
// TODO try and find exact position for line-through
1464-
this.newRect(ctx,bounds.left,Math.ceil(bounds.top+metrics.middle+metrics.lineWidth),bounds.width,1,color);
1465-
break;
1525+
switch(text_decoration) {
1526+
case "underline":
1527+
// Draws a line at the baseline of the font
1528+
// TODO As some browsers display the line as more than 1px if the font-size is big, need to take that into account both in position and size
1529+
this.newRect(ctx,bounds.left,Math.round(bounds.top+metrics.baseline+metrics.lineWidth),bounds.width,1,color);
1530+
break;
1531+
case "overline":
1532+
this.newRect(ctx,bounds.left,bounds.top,bounds.width,1,color);
1533+
break;
1534+
case "line-through":
1535+
// TODO try and find exact position for line-through
1536+
this.newRect(ctx,bounds.left,Math.ceil(bounds.top+metrics.middle+metrics.lineWidth),bounds.width,1,color);
1537+
break;
14661538

1467-
}
1539+
}
14681540

1469-
}
1541+
}
14701542

1471-
oldTextNode = newTextNode;
1543+
oldTextNode = newTextNode;
14721544

14731545

14741546

1475-
}
1547+
}
1548+
14761549

14771550

14781551
}
@@ -1663,18 +1736,18 @@ html2canvas.prototype.withinBounds = function(src,dst){
16631736

16641737
html2canvas.prototype.clipBounds = function(src,dst){
16651738

1666-
var x = Math.max(src.left,dst.left);
1667-
var y = Math.max(src.top,dst.top);
1739+
var x = Math.max(src.left,dst.left);
1740+
var y = Math.max(src.top,dst.top);
16681741

1669-
var x2 = Math.min((src.left+src.width),(dst.left+dst.width));
1670-
var y2 = Math.min((src.top+src.height),(dst.top+dst.height));
1742+
var x2 = Math.min((src.left+src.width),(dst.left+dst.width));
1743+
var y2 = Math.min((src.top+src.height),(dst.top+dst.height));
16711744

1672-
return {
1673-
left:x,
1674-
top:y,
1675-
width:x2-x,
1676-
height:y2-y
1677-
};
1745+
return {
1746+
left:x,
1747+
top:y,
1748+
width:x2-x,
1749+
height:y2-y
1750+
};
16781751

16791752
}
16801753

@@ -1706,8 +1779,8 @@ html2canvas.prototype.getBounds = function(el){
17061779
var p = $(el).offset();
17071780

17081781
return {
1709-
left: p.left + parseInt(this.getCSS(el,"border-left-width"),10),
1710-
top: p.top + parseInt(this.getCSS(el,"border-top-width"),10),
1782+
left: p.left + this.getCSS(el,"border-left-width",true),
1783+
top: p.top + this.getCSS(el,"border-top-width",true),
17111784
width:$(el).innerWidth(),
17121785
height:$(el).innerHeight()
17131786
}
@@ -1786,7 +1859,7 @@ html2canvas.prototype.formatZ = function(zindex,position,parentZ,parentNode){
17861859
if (parentPosition!="static" && typeof parentPosition != "undefined"){
17871860
zindex = 0;
17881861
}
1789-
/*else{
1862+
/*else{
17901863
return parentZ;
17911864
}*/
17921865
}
@@ -1818,8 +1891,12 @@ html2canvas.prototype.getContents = function(el){
18181891
* Function for fetching the css attribute
18191892
* TODO remove jQuery dependancy
18201893
*/
1821-
html2canvas.prototype.getCSS = function(el,attribute){
1822-
return $(el).css(attribute);
1894+
html2canvas.prototype.getCSS = function(el,attribute,intOnly){
1895+
if (intOnly){
1896+
return parseInt($(el).css(attribute),10);
1897+
}else{
1898+
return $(el).css(attribute);
1899+
}
18231900
}
18241901

18251902

0 commit comments

Comments
 (0)