1

我正在开发一个小地图编辑器,只是为了了解 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;
};

项目对象的样子:

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/

“问题”

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

非常感谢!鲍里斯

4

3 回答 3

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();

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

当您调用rectthen fill,然后rect使用不同的 rect调用fill时,第二个fill命令将填充您定义的两个rect。

这是因为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/

于 2013-08-02T17:30:26.790 回答
2

您可以通过使用简化整个过程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/

于 2013-08-02T17:00:16.983 回答
1

如果您确实想继续使用模式,则需要切换到 usingfillRect而不是创建矩形并 using 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;
};

看到它在行动

.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));

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

或者让您像这样positions对您的项目执行多项操作。你也可以这样做,但模式只需要制作一次。这个jsperf表明使用模式可以更快。.drawImage

于 2013-08-02T17:05:22.180 回答