【问题标题】:Canvas, Rect: Images for patterns are displayed wrong画布、矩形:图案图像显示错误
【发布时间】:2013-08-03 01:30:26
【问题描述】:

我正在开发一个小地图编辑器,只是为了了解 HTML5 Canvas 和更好的东西。

我想做的事

我正在尝试加载 3 个项目:

  • 2 块岩石
  • 1 个地精

我写了一个函数“drawItem(item)”,它应该在画布上画一个项目:

drawItem = function(item) {
    var imageObj = new Image();
    imageObj.onload = function() {
        var pattern = context.createPattern(imageObj, 'repeat');
        context.rect(gridSize*item.position[0], gridSize*item.position[1], gridSize, gridSize);
        context.fillStyle = pattern;
        context.fill();
    };
    imageObj.src = item.img;
};

item-object 的样子:

itemOne = {
    img : 'https://lh3.googleusercontent.com/ZX4Zl7JT1gkgOVA9FbMFnMAw7TC9bBCVMSGWKFTmOW88vDTgcCOb7tBBo60nxoSdHQ=s190',
    position : [0, 0] //these get multiplied with "gridSize" in the drawItem-function
};

问题来了:

如果我使用项目对象调用此函数,则对象会正确绘制。

如果我使用 3 个不同的项目对象(请参阅 JS-Fiddle)调用此函数 3 次,则 2 个岩石项目顶部似乎有一个妖精。错了。

JS-小提琴

http://jsfiddle.net/rSVkb/1/

“问题”

有人知道这个问题吗?我已经在谷歌上搜索了几个小时,但由于我不确定要搜索什么,所以很难找到。

非常感谢! 鲍里斯

【问题讨论】:

  • 你为什么使用模式?只是好奇,因为你可以使用.drawImage

标签: html canvas


【解决方案1】:

你可以使用drawImage来简化整个过程

drawItem = function(item) {
    var imageObj = new Image();
    imageObj.onload = function() {
        context.drawImage(imageObj, gridSize*item.position[0], gridSize*item.position[1])
    };
    imageObj.src = item.img;
};

http://jsfiddle.net/rSVkb/2/

【讨论】:

    【解决方案2】:

    您可能应该像其他回答者所说的那样使用 drawImage,但为了完整起见,让我告诉您为什么您的原始代码是错误的。

    在这段代码中:

    var pattern = context.createPattern(imageObj, 'repeat');
    context.rect(gridSize*item.position[0], gridSize*item.position[1], gridSize, gridSize);
    context.fillStyle = pattern;
    context.fill();
    

    您正在向当前路径添加rect,然后填充当前路径。

    当您调用rect 然后调用fill,然后使用不同的矩形调用rect,然后再次调用fill,第二个fill 命令正在填充矩形的两个你已经定义了。

    这是因为rect 总是在当前路径中添加一个额外的矩形。

    因此,修复代码的一种方法是添加一行,调用beginPath(),这将重置路径,这样您就不会在每次绘制时都继续添加矩形:

    var pattern = context.createPattern(imageObj, 'repeat');
    context.beginPath();
    context.rect(gridSize*item.position[0], gridSize*item.position[1], gridSize, gridSize);
    context.fillStyle = pattern;
    context.fill();
    

    所以它应该是这样的: http://jsfiddle.net/rSVkb/6/

    【讨论】:

      【解决方案3】:

      如果您确实想继续使用模式,则需要切换到使用fillRect,而不是创建一个矩形并使用fill

      drawItem = function(item) {
          var imageObj = new Image();
          imageObj.onload = function() {
              var pattern = context.createPattern(imageObj, 'repeat');
              context.fillStyle = pattern;
              context.fillRect(gridSize*item.position[0], gridSize*item.position[1], gridSize, gridSize);
          };
          imageObj.src = item.img;
      };
      

      See it in action

      .fill 将当前模式应用于已填充的整个上下文。继续使用模式将允许您连续绘制多个,执行以下操作:

      itemOne = {
          img : 'https://lh3.googleusercontent.com/ZX4Zl7JT1gkgOVA9FbMFnMAw7TC9bBCVMSGWKFTmOW88vDTgcCOb7tBBo60nxoSdHQ=s190',
          position : [0, 0], //these get multiplied with "gridSize" in the drawItem-function
          howManyX: 2,
          howManyY: 1
      };
      
      // And then in drawImage
      context.fillRect(gridSize*item.position[0], gridSize*item.position[1], gridSize*(item.howManyX || 1), gridSize*(item.howManyY || 1));
      

      并将它们用作fillRect 中最后两个参数的修饰符。

      或者让您对 this 等项目执行多个 positions。您也可以使用.drawImage 来做到这一点,但该模式只需要制作一次。而这个jsperf 表明使用模式可以更快。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-08-19
        • 2014-08-16
        • 2014-12-16
        相关资源
        最近更新 更多