HTML5 Canvas 设置 z-index

Posted

技术标签:

【中文标题】HTML5 Canvas 设置 z-index【英文标题】:HTML5 Canvas set z-index 【发布时间】:2012-02-28 06:16:54 【问题描述】:

是否可以在 html5 画布中设置绘制对象的 z-index?

我正在尝试获取它,以便一个对象可以在“玩家”之前,而另一个对象可以在“玩家”之后

【问题讨论】:

有几种解决方案:使用多个画布元素或选择正确在画布上绘制对象的顺序。请参阅以下问题:* implementing-layers-in-html5-canvas * html5-canvas-element-multiple-layers 这绝对是可能的,唯一的事情是你必须自己管理要绘制的对象数组。 【参考方案1】:

抱歉,不,canvas 元素将有它的 z-index 并且在其上绘制的任何内容都将在该层上。

如果您指的是画布上的不同事物,那么是的,任何被绘制的东西都会被绘制在之前的任何东西之上。

【讨论】:

【参考方案2】:

只需先画它后面的东西,然后是东西,然后是其他对象。

要进行命中测试,您可能需要在显示列表上向后迭代,测试每个对象。如果您非常了解对象边界,这将起作用。

或者您可能想尝试一些标准的图形技巧,例如将相同的对象绘制到另一个内存画布上,并为每个绘制的对象使用独特的颜色:要进行测试,只需检查内存画布上的像素颜色。整洁;-)

【讨论】:

【参考方案3】:

我发现一个对我有用的解决方案(并且摆脱了闪烁,欢呼!)是使用两个画布。 (或更多)

我假设您正在制作某种游戏(因为您提到了玩家)并以此为例。

您可以从 windows 的工作方式中获取一个页面,然后将一个画布作为背景,然后在其上放置另一个画布作为您的播放器画布。您可以将播放器画布标记为“脏”或在更改时更改,并且仅在需要时重绘更改的图层。这意味着您仅在玩家移动或采取行动时更新第二个画布。

这个方法可以走得更远,你可以为 HUD 添加第三个画布,上面有游戏统计数据,只有当玩家的统计数据改变时才会改变。

html 可能看起来像这样:

<canvas id="background-canvas"   style="border:1px solid #000000;"></canvas>
<canvas id="player-canvas"   style="border:1px solid #000000;"></canvas>
<canvas id="hud-canvas"   style="border:1px solid #000000;"></canvas>

【讨论】:

【参考方案4】:

是的..有点是的。您可以使用globalCompositeOperation“绘制”现有像素。

ctx.globalCompositeOperation='destination-over';

这是一个例子和一个演示:

var canvas=document.getElementById("canvas");
var ctx=canvas.getContext("2d");

var cx=100;

drawCircle()
cx+=20;

ctx.globalCompositeOperation='destination-over';

$("#test").click(function()
  drawCircle();
  cx+=20;
);

function drawCircle()
  ctx.beginPath();
  ctx.arc(cx,150,20,0,Math.PI*2);
  ctx.closePath();
  ctx.fillStyle=randomColor();
  ctx.fill();


function randomColor() 
  return('#'+Math.floor(Math.random()*16777215).toString(16));
body background-color: ivory; 
canvasborder:1px solid red;
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<button id="test">Draw new circle behind.</button><br>
<canvas id="canvas" width=300 height=300></canvas>

【讨论】:

你为什么说“有点”?对我来说,这似乎是这里唯一真正的解决方案。 我说“有点”是因为合成不如重构图纸以首先显示正确的 z 分层那样灵活。合成只涉及 2 个“层”。一层是画布上的现有像素,第二层是新绘制的像素。重构以绘制适当分层的图形会产生所需的层数。 *** 很棒! 喜欢使用toString(16) - 你教会了我一个新技巧:) @conor909 它将数字转换为十六进制格式,然后返回为字符串,因此基本上它允许您轻松地将数字 rgb 值转换为其十六进制字符串等价物。尝试在控制台中运行上面显示的 randomColor() 函数以查看它的实际效果【参考方案5】:

或者您可以简单地使用包含要绘制的对象的数组,然后使用每个子对象的zIndex 属性对该数组进行排序。然后你 jist 迭代那个数组并绘制。

var canvas = document.querySelector('#game-canvas');
var ctx = canvas.getContext('2d');

// Define our shape "class".
var Shape = function (x, y, z, width, height) 
  this.x = x;
  this.y = y;
  this.zIndex = z;
  this.width = width;
  this.height = height;
;
// Define the shape draw function.
Shape.prototype.draw = function () 
  ctx.fillStyle = 'lime';
  ctx.fillRect(this.x, this.y, this.width, this.height);
;

// let's store the objects to be drawn.
var objects = [
  new Shape(10, 10, 0, 30, 30), // should be drawn first.
  new Shape(50, 10, 2, 30, 30), // should be drawn third.
  new Shape(90, 10, 1, 30, 30)  // should be drawn second.
];

// For performance reasons, we will first map to a temp array, sort and map the temp array to the objects array.
var map = objects.map(function (el, index) 
  return  index : index, value : el.zIndex ;
);

// Now we need to sort the array by z index.
map.sort(function (a, b) 
  return a.value - b.value;
);

// We finaly rebuilt our sorted objects array.
var objectsSorted = map.map(function (el) 
  return objects[el.index];
);

// Now that objects are sorted, we can iterate to draw them.
for (var i = 0; i < objectsSorted.length; i++) 
  objectsSorted[i].draw();


// Enjoy !

请注意,我没有测试该代码并将其写在我的手机上,因此可能会有拼写错误,但我希望这应该可以理解其中的原理。

【讨论】:

我认为map.sort(function (a, b) return a - b; ); 应该是map.sort(function (a, b) return a.value - b.value; );,我认为你不能只减去两个对象。

以上是关于HTML5 Canvas 设置 z-index的主要内容,如果未能解决你的问题,请参考以下文章

设置 HTML5 Canvas 的背景填充、描边和不透明度

HTML5中的Canvas

HTML5 is Canvas

我应该使用 HTML5 Canvas 还是 CSS3 Sprites 来为游戏对象设置动画?

kineticjs (HTML5 Canvas) - 缩小时平滑图像

html5 canvas 画圆弧有锯齿怎么解决