【问题标题】:Trying to draw a bookshelf (Khan Academy exercise)试着画一个书架(可汗学院练习)
【发布时间】:2015-09-20 22:22:36
【问题描述】:

我正在做一个练习,该练习涉及基于一系列书籍对象在画布上绘制书架。具体说明如下:

现在添加更多书籍,并使用循环在画布下方绘制更多书架。想想如何使用条件和/或 % 运算符来做到这一点。

我的代码在循环中包含一个条件,但我似乎无法让它工作。条件在下面代码的最后。

//book array
var books = [{
    title: "The Giver",
    author: "Lois Lowry",
    coverColor: color(214, 255, 219),
    stars: 3
}, {
    title: "The Outsiders",
    author: "S. E. Hinton",
    coverColor: color(255, 127, 127),
    stars: 5
}, {
    title: "Harry Potter",
    author: "J. K. Rowling",
    coverColor: color(135, 193, 255),
    stars: 4
}, {
    title: "Harry Potter",
    author: "J. K. Rowling",
    coverColor: color(135, 193, 255),
    stars: 4
}];

// draw shelf
background(230, 187, 122);
fill(173, 117, 33);
rect(0, 120, width, 10);

// book loop
for (var i = 0; i < books.length; i++) {
    var book = books[i]; //setting book variable
    var xPos = i * 100;
    var yPos = 20;
    fill(book.coverColor);
    rect(xPos + 10, yPos, 90, 100);
    fill(0, 0, 0);
    textSize(11); //general book drawings
    text(book.title, xPos + 15, yPos + 5, 70, 100);
    textSize(9);
    text(book.author, xPos + 20, yPos * 2, 70, 100);

    //Seal of approval
    if (book.stars > 3) {
        var approvalSeal = getImage("cute/Star");
        image(approvalSeal, xPos + 10, yPos * 4, 30, 40);
        text("Seal of approval!", xPos + 45, yPos * 4 + 15, 50, 40);
    }

    //conditional wrap-around
    if (xPos > 350) {
        xPos = i * 100;
        yPos += 120;
    }
}

【问题讨论】:

    标签: javascript canvas processing


    【解决方案1】:

    你应该把它放在循环之外:

    var yPos = 20;
    

    目前您在每次迭代时重置yPos,因此环绕代码永远不会生效。

    xPos 也有问题。您在每次迭代时将其设置为 i * 100,这使它超出了货架的尽头。制作新书架时必须重置xPos

    正确的方法是初始化xPosyPos,绘制第一个书架,然后开始遍历书籍。增加书本位置并在必要时环绕:

    function drawShelf(yPos) {
      var saved = context.fillStyle;
      fill(color(173, 117, 33));
      rect(0, yPos + 120, width, 10);
      context.fillStyle = saved;
    }
    
    var xPos = 0,
        yPos = 0;
    
    drawShelf(yPos);
    
    for (var i = 0; i < books.length; i++) {
      var book = books[i];
      fill(book.coverColor);
      rect(xPos + 10, yPos + 20, 90, 100);
      xPos += 100;
      if (xPos > 350) {
        xPos = 0;
        yPos += 130;
        drawShelf(yPos);
      }
    }
    

    您可以在下面的 sn-p 中看到此代码运行。我已经添加了代码来模拟来自处理环境的绘图命令,并且我已经制作了十几个具有随机颜色的书籍对象。其他书籍属性被省略。

    var canvas = document.getElementsByTagName('canvas')[0],
        width = 410,
        height = 400,
        context = canvas.getContext('2d');
    canvas.width = width;
    canvas.height = height;
    function background(r, g, b) {
      var saved = context.fillStyle;
      fill(color(r, g, b));
      rect(0, 0, width, height);
      context.fillStyle = saved;
    }
    function color(r, g, b) {
      return 'rgb(' + r + ', ' + g + ', ' + b + ')';
    }
    function fill(style) {
      context.fillStyle = style;
    }
    function rect(x, y, w, h) {
      context.fillRect(x, y, w, h);
    }
    
    var books = new Array(12);
    for (var i = 0; i < books.length; ++i) {
      books[i] = {
        coverColor: color(
          Math.floor(Math.random() * 256),
          Math.floor(Math.random() * 256),
          Math.floor(Math.random() * 256)
        )
      };
    }
    
    background(230, 187, 122);
    
    function drawShelf(yPos) {
      var saved = context.fillStyle;
      fill(color(173, 117, 33));
      rect(0, yPos + 120, width, 10);
      context.fillStyle = saved;
    }
    
    var xPos = 0,
        yPos = 0;
    
    drawShelf(yPos);
    
    for (var i = 0; i < books.length; i++) {
      var book = books[i];
      fill(book.coverColor);
      rect(xPos + 10, yPos + 20, 90, 100);
      xPos += 100;
      if (xPos > 350) {
        xPos = 0;
        yPos += 130;
        drawShelf(yPos);
      }
    }
    &lt;canvas&gt;&lt;/canvas&gt;

    【讨论】:

    • 您的代码运行得非常好!可汗学院有一个有趣的 API,所以我不得不稍微玩一下代码才能让它工作,但一旦它开始运行,它就像一个魅力!很棒的工作,感谢您的帮助!
    【解决方案2】:

    您的条件不执行任何操作的原因是因为它位于 for 循环迭代的末尾。没有对分配的新值进行任何操作,并且随着下一次迭代的滚动,坐标恢复为“第一行书”坐标。您需要在使用它们之前分配这些坐标。

    我画我的(丑陋的)书架的方式是只对 x 坐标使用 % 运算符,对行使用地板除法。对我来说,这似乎比使用条件更容易。书架可以看成一个格子,排列起来像

    0 1 2 
    3 4 5 
    6 7 8 ... etc
    

    由于您将350 作为限制,我假设您希望每行显示 3 本书。请注意,x 坐标会重复自己,就像这样

    0 100 200
    0 100 200
    0 100 200
    

    % 运算符与正参数一起使用时,返回第一个参数除以第二个参数的余数。使用 300 作为第二个参数,我得到 x 坐标的重复序列 0、100 和 200。

    现在,行 y 坐标仅增加,每 3 本书。因此,我使用 Math.floor 向下舍入到要跳转到的确切行数,并使用这些值确定在哪里画这本书。

    在我的快速演示中,我只能依赖原始画布操作。我不熟悉提供的可汗学院工具。

    另外我不认为你的意思是使用 yPos * 2 或 * 4,因为当你向下移动几行时,这些偏移量会成倍增加,而不仅仅是向下移动。

         var ctx = document.getElementById("canvas").getContext("2d");
    
         function color() {}
    
         function fill(r, g, b) {
    
         }
    
         function rect(x, y, w, h) {
           ctx.rect(x, y, w, h);
           ctx.stroke();
         }
    
         function text(s, x, y, w, h) {
           ctx.beginPath();
           ctx.moveTo(x, y);
           ctx.font = "9px serif";
           ctx.fillText(s, x, y + 15);
           ctx.stroke();
         }
    
         var books = [{
           title: "The Giver (0)",
           author: "Lois Lowry (0)",
           coverColor: color(214, 255, 219),
           stars: 3
         }, {
           title: "The Outsiders (1)",
           author: "S. E. Hinton (1)",
           coverColor: color(255, 127, 127),
           stars: 5
         }, {
           title: "Harry Potter (2)",
           author: "J. K. Rowling (2)",
           coverColor: color(135, 193, 255),
           stars: 4
         }, {
           title: "Mary Scooter (3)",
           author: "G. Q. Bowling (3)",
           coverColor: color(135, 193, 255),
           stars: 4
         }, {
           title: "The Brothers Karmazoov (4)",
           author: "F. Downstoveeski (4)",
           coverColor: color(214, 255, 219),
           stars: 3
         }, {
           title: "The Unbearable Brightness of Skiing (5)",
           author: "Milano Counter (5)",
           coverColor: color(255, 127, 127),
           stars: 5
         }, {
           title: "The Uber Gatsby (6)",
           author: "Scot-Free Fitzgee (6)",
           coverColor: color(135, 193, 255),
           stars: 4
         }, {
           title: "Catch-42 (7)",
           author: "Joe Keller (7)",
           coverColor: color(135, 193, 255),
           stars: 4
         }, {
           title: "Focker's Pendulum (8)",
           author: "Umbrella Ekoh (8)",
           coverColor: color(214, 255, 219),
           stars: 3
         }, {
           title: "The Tiny Princess (9)",
           author: "Anthony St. Expert (9)",
           coverColor: color(255, 127, 127),
           stars: 5
         }, {
           title: "Of Fire and Ice (10)",
           author: "George Martinelli (10)",
           coverColor: color(135, 193, 255),
           stars: 4
         }];
    
          // draw shelf
          // background(230, 187, 122);
          // fill(173, 117, 33);
          // rect(0, 120, width, 10);
    
          // book loop
         for (var i = 0; i < books.length; i++) {
           var book = books[i]; //setting book variable
    
           // DETERMINE WHERE TO PLACE TOP-LEFT BOOK CORNER 
           var xPos = (i * 100 % 300);
           var yPos = 20 + 120 * Math.floor(i / 3);
    
           // var xPos = i*100;
           // var yPos = 20;
    
           // fill(book.coverColor);
           rect(xPos + 10, yPos, 90, 100);
           // fill(0, 0, 0);
           // textSize(11);//general book drawings
           text(book.title, xPos + 15, yPos + 5, 70, 100);
           // textSize(9);
           text(book.author, xPos + 20, yPos + 25, 70, 100);
    
           //Seal of approval
           if (book.stars > 3) {
             // var approvalSeal = getImage("cute/Star");
             // image(approvalSeal,xPos+10, yPos*4, 30, 40);
             text("Seal of approval!", xPos + 45, yPos + 40 + 15, 50, 40);
           }
    
           //conditional wrap-around
           // if(xPos > 350) {
           //   xPos = i*100;
           // yPos += 120;
           // }
         }
    <canvas id="canvas" width="450" height="600">
    </canvas>

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2012-07-31
      • 2014-03-30
      • 2015-12-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多