Canvas WrapText函数与fillText

时间:2014-04-21 16:28:11

标签: javascript jquery html html5 canvas

我正在创建一个多项选择测验,但问题是字符太多而且不会显示在一行上。我知道我必须使用wrapText函数才能将它段落,我只是不确定如何在我的代码中实现它。问题在变量(问题)中设置为字符串,答案是变量中的字符串(选项)。 textpos1,定义我希望我的问题开始的坐标,textpos2 - textpos4定义单独答案开始的坐标。这些坐标位于这些位置以与我的背景图像对齐。

JSFiddle这里有完整的代码,但它似乎不喜欢我的BG图像... http://jsfiddle.net/danielparry8/6U9Rn/

 var canvas = document.getElementById("myCanvas");
            var context = canvas.getContext("2d");
            var quizbg = new Image();
            var Question = new String;
            var Option1 = new String;
            var Option2 = new String;
            var Option3 = new String;
            var mx=0;                                   
            var my=0;
            var CorrectAnswer = 0;
            var qnumber = 0;
            var rightanswers=0;
            var wronganswers=0;
            var QuizFinished = false;
            var lock = false;
            var textpos1=25;
            var textpos2=145;
            var textpos3=230;
            var textpos4=325;
            var Questions = ["Which Manchester United Player won \n the 2008 Golden Boot with 31 Goals?","At which club did Bobby Charlton start his football career?","Which year did Wayne Rooney win the BBC Young Sports Personality of the year award?"];
            var Options = [["Cristiano Ronaldo","Wayne Rooney","Ryan Giggs"],["Manchester United","Manchester City","Chelsea"],["2002","2003","2004"]];

'setQuestions'函数抓取相应的问题和答案,并使用fillText将它们应用到画布,我唯一的问题是问题显示在一个连续行上。

   SetQuestions = function(){

                Question=Questions[qnumber];
                CorrectAnswer=1+Math.floor(Math.random()*3);

                if(CorrectAnswer==1){Option1=Options[qnumber][0];Option2=Options[qnumber][1];Option3=Options[qnumber][2];}
                if(CorrectAnswer==2){Option1=Options[qnumber][2];Option2=Options[qnumber][0];Option3=Options[qnumber][1];}
                if(CorrectAnswer==3){Option1=Options[qnumber][1];Option2=Options[qnumber][2];Option3=Options[qnumber][0];}

                context.textBaseline = "middle";
                context.font = "16pt sans-serif,Arial";
                context.fillText(Question,20,textpos1);
                context.font = "14pt sans-serif,Arial";
                context.fillText(Option1,20,textpos2);
                context.fillText(Option2,20,textpos3);
                context.fillText(Option3,20,textpos4); 
            }

下面是一个wrapText函数,我试图在我的设计中实现无济于事,如果有人可以帮助,非常感谢。谢谢!

    function wrapText(context, text, x, y, maxWidth, fontSize, fontFace){
       var words = text.split(' ');
       var Questions = '';
       var lineHeight=fontSize;

  context.font=fontSize+" "+fontFace;

  for(var n = 0; n < words.length; n++) {
    var testLine = Questions + words[n] + ' ';
    var metrics = context.measureText(testLine);
    var testWidth = metrics.width;
    if(testWidth > maxWidth) {
      context.fillText(Questions, x, y);
      Questions = words[n] + ' ';
      y += lineHeight;
    }
    else {
      Questions = testLine;
    }
  }
  context.fillText(Questions, x, y);
    return(y);
}

2 个答案:

答案 0 :(得分:0)

我试验了你的示例代码。你并没有准确地指出你希望在'wrapText'函数的'fontSize'参数中传递什么,但我认为它会像'16pt'。所以你有这个代码:

var lineHeight=fontSize;

context.font=fontSize+" "+fontFace;

所以现在......

lineHeight === '16pt'
context.font === '16 pt sans-serif,Arial'

然后你的代码说:

y+= lineHeight;

现在你遇到了问题,因为将'16pt'(lineHeight)添加到y没有任何意义。 'y'的值是一个简单的整数值(表示像素)。尝试添加字符串'16pt'会导致奇怪的值和奇怪的结果。

我使用了JSFiddle中的代码,将其复制到我自己的沙盒中。然后我从上面剪切/粘贴了wrapText的代码。 我替换了:

context.fillText(Question,20,textpos1);

使用:

wrapText(上下文中,提问,20%,textpos1,500, '16PT', '无衬线,Arial字体');

里面的wrapText

y = lineHeight;

改为使用:

y = 16;

你应该看到你的包裹线。 y = 16只是我选择的任意数字。它代表像素......它与16pt不同。

答案 1 :(得分:0)

以下是一个示例和一个演示:http://jsfiddle.net/m1erickson/QGz2R/

如果你创建一个&#34;类&#34;那么你可以重用那个&#34; class&#34;根据需要存储和绘制尽可能多的问题。

首先,创建一个问题&amp;答案类:

  • 问题文本
  • 每个答案文字
  • 在画布上绘制的每个答案的边界框
  • 正确答案

示例代码:

    // a Question & Answer "class" 

    function QA(question,options,correctOption){
        this.QBB=null;  // the bounding box for the wrapped question text
        this.Q=question;
        this.A=[];
        this.correct=correctOption;
        for(var i=0;i<options.length;i++){
            this.A.push({text:options[i],BB:null});
        }
    }

    // Draw the question and possible answers on the canvas
    // At the same time calculate the bounding boxes(BB)
    // of each answer so that the BB can be used to test
    // if the user clicked in the correct answer

    QA.prototype.draw=function(x,y,maxWidth){
        var BB=this.QBB=wrapText(this.Q,x,y,maxWidth,14,"verdana");
        for(var i=0;i<this.A.length;i++){
            y+=BB.height;
            BB=this.A[i].BB=wrapText(i+". "+this.A[i].text,x,y,maxWidth,14,"verdana");
            ctx.strokeRect(BB.x,BB.y,BB.width,BB.height);
        }
        return({x:x,y:y});
    }

    // test if the supplied mouseX/mouseY is inside any answer

    QA.prototype.hitAnswer=function(x,y){
        for(var i=0;i<this.A.length;i++){
            var bb=this.A[i].BB;
            if(x>bb.x && x<bb.x+bb.width && y>bb.y && y<bb.y+bb.height){
                return(i);
            }
        }
        return(-1);
    }

接下来,

  • 聆听mousedown事件
  • 测试用户是否点击了任何答案。您可以通过测试是否在任何答案的边界框内单击鼠标来执行此操作。
  • 如果用户点击了回答提醒,他们是否选择了正确答案。

示例代码:

    // Listen for mousedown and check if the user has
    // clicked in an answer to the question

    function handleMouseDown(e){
      e.preventDefault();
      e.stopPropagation();

      mouseX=parseInt(e.clientX-offsetX);
      mouseY=parseInt(e.clientY-offsetY);

      var answer=q.hitAnswer(mouseX,mouseY);
      if(answer==q.correct){
        $results.text("Correct! #"+q.correct+" is the answer");
      }else{
        $results.text("Sorry! #"+answer+" is not the answer");
      }

    }

这是稍微修改过的wrapText代码,它现在返回它刚刚包装在画布上的文本的边界框:

    // wrap the specified text and draw it to the canvas
    // and return the bounding box of that wrapped text

    function wrapText(text, x, y, maxWidth, fontSize, fontFace){
      var startY=y;
      var words = text.split(' ');
      var line = '';
      var lineHeight=fontSize+2;

      ctx.font=fontSize+" "+fontFace;

      y+=fontSize;

      for(var n = 0; n < words.length; n++) {
        var testLine = line + words[n] + ' ';
        var metrics = ctx.measureText(testLine);
        var testWidth = metrics.width;
        if(testWidth > maxWidth) {
          ctx.fillText(line, x, y);
          line = words[n] + ' ';
          y += lineHeight;
        }
        else {
          line = testLine;
        }
      }
      ctx.fillText(line, x, y);
      return({x:x,y:startY,width:maxWidth,height:y-startY+4});
    }