Added support for some list-style-type's with list-style-position: inside

This commit is contained in:
MoyuScript
2011-08-11 22:43:42 +03:00
parent 7880e62056
commit 5ade2c104c
7 changed files with 545 additions and 167 deletions

View File

@ -168,6 +168,9 @@ html2canvas.prototype.newElement = function(el,parentStack){
this.renderFormValue(el,bounds,stack);
}
break;
case "LI":
this.drawListItem(el,stack,bgbounds);
break;
}

121
src/Lists.js Normal file
View File

@ -0,0 +1,121 @@
html2canvas.prototype.drawListItem = function(element,stack,elBounds){
var position = this.getCSS(element,"list-style-position",false);
var item = this.getListItem(element),
x,
y;
var type = this.getCSS(element,"list-style-type",false);
if (/^(decimal|decimal-leading-zero|upper-alpha|upper-latin|upper-roman|lower-alpha|lower-greek|lower-latin|lower-roman)$/i.test(type)){
// TODO remove jQuery dependency
var currentIndex = $(element).index()+1,
text;
if (type == "decimal"){
text = currentIndex;
}else if (type == "decimal-leading-zero"){
if (currentIndex.toString().length == 1){
text = currentIndex = "0" + currentIndex.toString();
}else{
text = currentIndex.toString();
}
}else if (type == "upper-roman"){
text = this.getListRoman(currentIndex);
}else if (type == "lower-roman"){
text = this.getListRoman(currentIndex).toLowerCase();
}else if (type == "lower-alpha"){
text = this.getListAlpha(currentIndex).toLowerCase();
}else if (type == "upper-alpha"){
text = this.getListAlpha(currentIndex);
}
text += ". ";
var listBounds = this.getListPosition(element,text);
if (position == "inside"){
this.setFont(stack.ctx,element,false);
x = elBounds.left;
}else{
return; /* TODO really need to figure out some more accurate way to try and find the position.
as defined in http://www.w3.org/TR/CSS21/generate.html#propdef-list-style-position, it does not even have a specified "correct" position, so each browser
may display it whatever way it feels like.
"The position of the list-item marker adjacent to floats is undefined in CSS 2.1. CSS 2.1 does not specify the precise location of the marker box or its position in the painting order"
*/
this.setFont(stack.ctx,element,true);
x = elBounds.left-10;
}
y = listBounds.bottom;
this.printText(text, x, y, stack.ctx);
}
}
html2canvas.prototype.getListPosition = function(element,val){
var boundElement = document.createElement("boundelement");
boundElement.style.display = "inline";
//boundElement.style.width = "1px";
//boundElement.style.height = "1px";
var type = element.style.listStyleType;
element.style.listStyleType = "none";
boundElement.appendChild(document.createTextNode(val));
element.insertBefore(boundElement,element.firstChild);
var bounds = this.getBounds(boundElement);
element.removeChild(boundElement);
element.style.listStyleType = type;
return bounds;
}
html2canvas.prototype.getListItem = function(element){
}
html2canvas.prototype.getListAlpha = function(number){
var tmp = "";
do{
var modulus = number % 26;
tmp = String.fromCharCode((modulus) + 64) + tmp;
number = number / 26;
}while((number*26) > 26);
return tmp;
}
html2canvas.prototype.getListRoman = function(number){
var romanArray = ["M","CM","D","CD","C","XC","L","XL","X","IX","V","IV","I"],
decimal = [1000,900,500,400,100,90,50,40,10,9,5,4,1],
roman = "";
if (number <= 0 || number >= 4000) return;
for (var v=0; v<romanArray.length; v++) {
while (number >= decimal[v]) {
number -= decimal[v];
roman += romanArray[v];
}
}
return roman;
}

View File

@ -5,9 +5,7 @@ html2canvas.prototype.newText = function(el,textNode,stack,form){
var size = this.getCSS(el,"font-size");
var color = this.getCSS(el,"color");
var bold = this.getCSS(el,"font-weight");
var font_style = this.getCSS(el,"font-style");
var font_variant = this.getCSS(el,"font-variant");
var text_decoration = this.getCSS(el,"text-decoration");
var text_align = this.getCSS(el,"text-align");
@ -21,14 +19,7 @@ html2canvas.prototype.newText = function(el,textNode,stack,form){
//text = $.trim(text);
if (text.length>0){
switch(bold){
case 401:
bold = "bold";
break;
case 400:
bold = "normal";
break;
}
if (text_decoration!="none"){
@ -36,8 +27,7 @@ html2canvas.prototype.newText = function(el,textNode,stack,form){
}
var font = font_variant+" "+bold+" "+font_style+" "+size+" "+family,
renderList,
var renderList,
renderWords = false;
@ -54,12 +44,8 @@ html2canvas.prototype.newText = function(el,textNode,stack,form){
renderList = textNode.nodeValue.split("");
}
this.setContextVariable(ctx,"fillStyle",color);
this.setContextVariable(ctx,"font",font);
this.setFont(ctx,el,false);
/*
if (stack.clip){
@ -71,81 +57,81 @@ html2canvas.prototype.newText = function(el,textNode,stack,form){
var oldTextNode = textNode;
for(var c=0;c<renderList.length;c++){
var oldTextNode = textNode;
for(var c=0;c<renderList.length;c++){
// IE 9 bug
if (typeof oldTextNode.nodeValue != "string"){
continue;
}
// IE 9 bug
if (typeof oldTextNode.nodeValue != "string"){
continue;
}
// TODO only do the splitting for non-range prints
var newTextNode = oldTextNode.splitText(renderList[c].length);
// TODO only do the splitting for non-range prints
var newTextNode = oldTextNode.splitText(renderList[c].length);
if (text_decoration!="none" || this.trim(oldTextNode.nodeValue).length != 0){
if (text_decoration!="none" || this.trim(oldTextNode.nodeValue).length != 0){
if (this.support.rangeBounds){
// getBoundingClientRect is supported for ranges
if (document.createRange){
var range = document.createRange();
range.selectNode(oldTextNode);
}else{
// TODO add IE support
var range = document.body.createTextRange();
}
if (range.getBoundingClientRect()){
var bounds = range.getBoundingClientRect();
}else{
var bounds = {};
}
if (this.support.rangeBounds){
// getBoundingClientRect is supported for ranges
if (document.createRange){
var range = document.createRange();
range.selectNode(oldTextNode);
}else{
// it isn't supported, so let's wrap it inside an element instead and the bounds there
var parent = oldTextNode.parentNode;
var wrapElement = document.createElement('wrapper');
var backupText = oldTextNode.cloneNode(true);
wrapElement.appendChild(oldTextNode.cloneNode(true));
parent.replaceChild(wrapElement,oldTextNode);
var bounds = this.getBounds(wrapElement);
parent.replaceChild(backupText,wrapElement);
// TODO add IE support
var range = document.body.createTextRange();
}
if (range.getBoundingClientRect()){
var bounds = range.getBoundingClientRect();
}else{
var bounds = {};
}
}else{
// it isn't supported, so let's wrap it inside an element instead and the bounds there
var parent = oldTextNode.parentNode;
var wrapElement = document.createElement('wrapper');
var backupText = oldTextNode.cloneNode(true);
wrapElement.appendChild(oldTextNode.cloneNode(true));
parent.replaceChild(wrapElement,oldTextNode);
var bounds = this.getBounds(wrapElement);
parent.replaceChild(backupText,wrapElement);
}
// console.log(range);
// console.log("'"+oldTextNode.nodeValue+"'"+bounds.left)
this.printText(oldTextNode.nodeValue,bounds.left,bounds.bottom,ctx);
// console.log(range);
// console.log("'"+oldTextNode.nodeValue+"'"+bounds.left)
this.printText(oldTextNode.nodeValue,bounds.left,bounds.bottom,ctx);
switch(text_decoration) {
case "underline":
// Draws a line at the baseline of the font
// 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
this.newRect(ctx,bounds.left,Math.round(bounds.top+metrics.baseline+metrics.lineWidth),bounds.width,1,color);
break;
case "overline":
this.newRect(ctx,bounds.left,bounds.top,bounds.width,1,color);
break;
case "line-through":
// TODO try and find exact position for line-through
this.newRect(ctx,bounds.left,Math.ceil(bounds.top+metrics.middle+metrics.lineWidth),bounds.width,1,color);
break;
switch(text_decoration) {
case "underline":
// Draws a line at the baseline of the font
// 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
this.newRect(ctx,bounds.left,Math.round(bounds.top+metrics.baseline+metrics.lineWidth),bounds.width,1,color);
break;
case "overline":
this.newRect(ctx,bounds.left,bounds.top,bounds.width,1,color);
break;
case "line-through":
// TODO try and find exact position for line-through
this.newRect(ctx,bounds.left,Math.ceil(bounds.top+metrics.middle+metrics.lineWidth),bounds.width,1,color);
break;
}
}
}
oldTextNode = newTextNode;
}
oldTextNode = newTextNode;
}
@ -153,6 +139,39 @@ html2canvas.prototype.newText = function(el,textNode,stack,form){
}
html2canvas.prototype.setFont = function(ctx,el,align){
var family = this.getCSS(el,"font-family");
var size = this.getCSS(el,"font-size");
var color = this.getCSS(el,"color");
var bold = this.getCSS(el,"font-weight");
var font_style = this.getCSS(el,"font-style");
var font_variant = this.getCSS(el,"font-variant");
switch(bold){
case 401:
bold = "bold";
break;
case 400:
bold = "normal";
break;
}
var font = font_variant+" "+bold+" "+font_style+" "+size+" "+family;
this.setContextVariable(ctx,"fillStyle",color);
this.setContextVariable(ctx,"font",font);
if (align){
this.setContextVariable(ctx,"textAlign","right");
}else{
this.setContextVariable(ctx,"textAlign","left");
}
}
/*
* Function to find baseline for font with a specicic size
*/