gpt4 book ai didi

javascript - 使用网格中的多个不同图像填充 Canvas 形状

转载 作者:行者123 更新时间:2023-11-28 15:08:26 25 4
gpt4 key购买 nike

我正在使用 Canvas 创建一个六边形网格,并且尝试使用图像中的特定图案填充每个图 block 。以下代码是我正在使用的代码。

最终结果是一个六边形网格,其中的瓷砖图案全部具有相同的图像......但它不应该是这样。我认为正在发生的事情是它为每个图 block 的图案创建了一个覆盖层,但该图像基本上覆盖了所有图 block ......而我最终只看到了最后一个被调用的图像。

我的印象是我的 fill() 只是填充了那个小六边形形状......而不是全部。我怎样才能做到这一点,以便每个单独的六 Angular 形都可以有自己的图像?

此代码在 for 循环中运行以创建网格。这是我的drawHex()方法。我无法想象我需要为每个图 block 使用全新的 Canvas 才能实现这一点。

var numberOfSides = 6,
size = hex.properties.radius,
Xcenter = hexObj.x + (hex.properties.width / 2),
Ycenter = hexObj.y + (hex.properties.height / 2);

var img = new Image();
if (hexObj.t == "grassland"){
img.src = "/static/grass.jpg";
}else{
img.src = "/static/mountain.jpg";
}

var pattern = context.createPattern(img, "repeat");
context.fillStyle = pattern;
context.beginPath();
context.moveTo (Xcenter + size * Math.cos(0), Ycenter + size * Math.sin(0));
for (var i = 1; i <= numberOfSides;i += 1) {
context.lineTo (Xcenter + size * Math.cos(i * 2 * Math.PI / numberOfSides), Ycenter + size * Math.sin(i * 2 * Math.PI / numberOfSides));
}
context.fill();
context.closePath();
context.stroke();

最佳答案

首先重要的是了解图像加载的工作原理。这是一个异步操作,这意味着您必须等待图像加载才能继续。

这种类型将决定策略,因为每次您想要更改图像时设置图像源也会迫使您处理它的异步方面,即延迟等。此外,如果在创建图案时尚未加载图像,则样式将无法渲染。

因此,更好的方法是预加载您将使用的所有图像(或单个 Sprite 表)。然后将它们保留在内存中(如果图像不是很大,这通常不是问题)。

捆绑图 block

然后,您可以存储引用每个图像的多个 CanvasPattern 对象。一种方法是构建一个图 block 对象,其中包含有关该图 block 的所有信息,包括。它的模式。

例如:

function Tile(ctx, x, y, radius, img) {
this.pattern = ctx.createPattern(img, "repeat");
// store other properties here like x, y, radius etc.
}
Tile.prototype.render = function(ctx) {
ctx.beginPath();
// create hex shape here
ctx.fillStyle = this.pattern;
ctx.fill();
}

现在您可以创建一个 Tile 对象并将其保存在数组(或母对象)中:

var tiles = [];
tiles.push(new Tile(ctx, x1, y1, radius, img1); // img1 has loaded (onload)
tiles.push(new Tile(ctx, x2, y2, radius, img2); // img2 has also loaded (onload)
// etc.

然后简单地立即渲染它们,例如:

tiles.forEach(function(tile) { tile.render(ctx) });

加载图像

您将需要一个图像加载器来加载所有图像。缺点是用户必须等待图像加载,除非你有一个前台可以占据用户,同时图像在后台加载。

加载程序不必很复杂,但对于生产,您可能需要处理错误(onerror/onabort)。此示例将在所有图像加载后调用函数 start():

var images = [];
var urls = ["//image1.jpg", "//image2.jpg", ...];
var count = urls.length;

function handler() {
if (!--count) start();
}

urls.forEach(function(url) {
var img = new Image;
images.push(img);
img.onload = handler;
//img.onerror = ... // handler for error and abort here
//img.onabort = ...
img.src = url;
})

一个小演示

var images = [], urls = ["//i.imgur.com/DAg71N5.jpg?1", "//i.imgur.com/ZO3XQpj.jpg?1"],
tiles = [], count = urls.length, ctx = c.getContext("2d");

function handler() {if (!--count) start()}

function Tile(ctx, x, y, radius, img) {
this.pattern = ctx.createPattern(img, "repeat");
this.x = x;
this.y = y;
this.radius = radius;
}
Tile.prototype.render = function(ctx) {
ctx.beginPath();
for(var i = 0; i < Math.PI*2; i += Math.PI/3)
ctx.lineTo(this.x + Math.cos(i) * this.radius, this.y + Math.sin(i) * this.radius);
ctx.fillStyle = this.pattern;
ctx.fill();
}

urls.forEach(function(url) {
var img = new Image;
images.push(img);
img.onload = handler;
img.src = url;
});

function start() {
tiles.push(new Tile(ctx, 50, 50, 50, images[0]));
tiles.push(new Tile(ctx, 130, 95, 50, images[1]));
tiles.forEach(function(tile) { tile.render(ctx) });
}
<canvas id=c></canvas>

提示

六 Angular 形可以这样绘制:

for(var i = 0; i < Math.PI*2; i += Math.PI/3)
ctx.lineTo(this.x + Math.cos(i) * this.radius, this.y + Math.sin(i) * this.radius);

请注意,这需要 beginPath()。这允许我们传递 moveTo() 作为新路径上的第一个 lineTo() 会将路径光标移动到其起点。

要保持图案相对于形状,您可以在相对于 (0,0) 绘制它们之前在上下文中使用 translate() ,这也简化了十六进制绘制:

ctx.translate(this.x, this.y);
ctx.moveTo(this.radius, 0);
for(var i = 0; i < Math.PI*2; i += Math.PI/3)
ctx.lineTo(Math.cos(i) * this.radius, Math.sin(i) * this.radius);
// cancel transforms here if needed

在较新的浏览器中,您可以对模式本身使用setTransform()。并非所有浏览器都支持此功能,因此请小心..

小型更新出于重用目的,您可以考虑在对象外部创建一个模式作为加载过程的一部分,以便您仅使用对该模式的引用每个瓷砖。

specs are a little unclear关于图案在复制方面对图像的作用。唯一的要求是对图像源的更改不得影响创建后的图案,这可能意味着也可能不意味着始终或仅在其条件需要时在内部复制图像:

Modifying the image used when creating a CanvasPattern object after calling the createPattern() method must not affect the pattern(s) rendered by the CanvasPattern object.

无论如何,上面的示例应该有足够的内容,以便为您提供解决问题的基础和理解。根据需要修改!

关于javascript - 使用网格中的多个不同图像填充 Canvas 形状,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37838676/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com