HTML5 canvas createPattern API

时间:2015-03-27 16:15:21

标签: javascript html5 canvas

我的代码如下:

<body>
    <canvas id="main" width=400 height=300></canvas>
<script>
var windowToCanvas = function(canvas, x, y) {
    var bbox = canvas.getBoundingClientRect();
    return {
        x: (x - bbox.left) * (canvas.width  / bbox.width),
        y: (y - bbox.top)  * (canvas.height / bbox.height)
    };
};

image = new Image();
image.src = "redball.png";
image.onload = function (e) {
    var canvas = document.getElementById('main'),
        context = canvas.getContext('2d');

    var pattern = context.createPattern(image, "repeat");

    function draw(loc) {
        context.clearRect(0, 0, canvas.width, canvas.height);
        context.fillStyle = pattern;
        context.beginPath();
        context.moveTo(loc.x, loc.y);
        context.lineTo(loc.x + 300, loc.y + 60);
        context.lineTo(loc.x + 70, loc.y + 200);
        context.closePath();
        context.fill();
    }

    canvas.onmousemove = function(e) {
        var event = e || window.event,
            x = event.x || event.clientX,
            y = event.y || event.clientY,
            loc = windowToCanvas(canvas, x, y);

        draw(loc);
    };
}
</script>
</body>

我调用createPattern API,使用背景图像填充三角形,但是当鼠标移动时,背景图像也会移动,我只想将背景图像固定在位,我该如何解决这个问题?

1 个答案:

答案 0 :(得分:0)

将上下文模式视为画布上的背景图像。

模式始终从画布原点[0,0]开始。如果图案重复,则图案会在向右和向下重复的图块中填充画布。

因此,如果在画布周围移动三角形,则三角形将始终显示图案的不同部分。

有三种方法可以使三角形始终显示图案图像的相同部分。

选项#1 - context.translate

将画布原点从其默认[0,0]位置移动到三角形位置[loc.x,loc.y]。您可以使用画布转换执行此操作。特别是,translate命令将移动原点。移动原点也会移动图案的左上角起始位置,使图案始终以相对于移动三角形的相同方式对齐:

var pattern = context.createPattern(image, "repeat");
context.fillStyle=pattern;

function draw(loc) {
    context.clearRect(0, 0, canvas.width, canvas.height);
    // the origin [0,0] is now [loc.x,loc.y]
    context.translate(loc.x,loc.y);
    context.beginPath();
    // you are already located at [loc.x,loc.y] so
    // you don't need to add loc.x & loc.y to
    // your drawing coordinates
    context.moveTo(0,0);
    context.lineTo(300,60);
    context.lineTo(70,200);
    context.closePath();
    context.fill();
    // always clean up! Move the origina back to [0,0]
    context.translate(-loc.x,-loc.y);
}

使用翻译进行演示:

var windowToCanvas = function(canvas, x, y) {
  var bbox = canvas.getBoundingClientRect();
  return {
    x: (x - bbox.left) * (canvas.width  / bbox.width),
    y: (y - bbox.top)  * (canvas.height / bbox.height)
  };
};

image = new Image();
image.src = "https://dl.dropboxusercontent.com/u/139992952/multple/jellybeans.jpg";
image.onload = function (e) {
  var canvas = document.getElementById('main'),
      context = canvas.getContext('2d');

  var pattern = context.createPattern(image, "repeat");
  context.fillStyle=pattern;

  draw({x:0,y:0});

  function draw(loc) {
    context.clearRect(0, 0, canvas.width, canvas.height);
    // the origin [0,0] is now [loc.x,loc.y]
    context.translate(loc.x,loc.y);
    context.beginPath();
    // you are already located at [loc.x,loc.y] so
    // you don't need to add loc.x & loc.y to
    // your drawing coordinates
    context.moveTo(0,0);
    context.lineTo(300,60);
    context.lineTo(70,200);
    context.closePath();
    context.fill();
    // always clean up! Move the origina back to [0,0]
    context.translate(-loc.x,-loc.y);
  }


  canvas.onmousemove = function(e) {
    var event = e || window.event,
        x = event.x || event.clientX,
        y = event.y || event.clientY,
        loc = windowToCanvas(canvas, x, y);

    draw(loc);
  };
}
body{ background-color: ivory; }
#canvas{border:1px solid red;}
<h4>Move the mouse to move the triangle<br>The image is large, so be patient while it loads</h4>
<canvas id="main" width=600 height=600></canvas>

选项#2 - 合成

使用合成而不是图案在三角形上方绘制图像。合成是一种控制在画布上绘制新像素将如何与现有画布像素交互的方法。特别是,source-atop合成将导致仅在新像素与现有非透明像素重叠的地方绘制任何新像素。您要做的是以纯色绘制三角形,然后使用source-atop合成仅在实心三角形像素的位置绘制图像:

function draw(loc) {
    context.clearRect(0, 0, canvas.width, canvas.height);
    context.beginPath();
    context.moveTo(loc.x, loc.y);
    context.lineTo(loc.x + 300, loc.y + 60);
    context.lineTo(loc.x + 70, loc.y + 200);
    context.closePath();
    // fill the triangle with a solid color
    context.fill();
    // set compositing to 'source-atop' so
    // new drawings will only be visible if
    // they overlap a solid color pixel
    context.globalCompositeOperation='source-atop';
    context.drawImage(image,loc.x,loc.y);
    // always clean up! Set compositing back to its default value
    context.globalCompositeOperation='source-over';
}

使用合成的演示:

var windowToCanvas = function(canvas, x, y) {
  var bbox = canvas.getBoundingClientRect();
  return {
    x: (x - bbox.left) * (canvas.width  / bbox.width),
    y: (y - bbox.top)  * (canvas.height / bbox.height)
  };
};

image = new Image();
image.src = "https://dl.dropboxusercontent.com/u/139992952/multple/jellybeans.jpg";
image.onload = function (e) {
  var canvas = document.getElementById('main'),
      context = canvas.getContext('2d');

  var pattern = context.createPattern(image, "repeat");
  context.fillStyle=pattern;

  draw({x:0,y:0});

  function draw(loc) {
    context.clearRect(0, 0, canvas.width, canvas.height);
    context.beginPath();
    context.moveTo(loc.x, loc.y);
    context.lineTo(loc.x + 300, loc.y + 60);
    context.lineTo(loc.x + 70, loc.y + 200);
    context.closePath();
    // fill the triangle with a solid color
    context.fill();
    // set compositing to 'source-atop' so
    // new drawings will only be visible if
    // they overlap a solid color pixel
    context.globalCompositeOperation='source-atop';
    context.drawImage(image,loc.x,loc.y);
    // always clean up! Set compositing back to its default value
    context.globalCompositeOperation='source-over';
  }

  canvas.onmousemove = function(e) {
    var event = e || window.event,
        x = event.x || event.clientX,
        y = event.y || event.clientY,
        loc = windowToCanvas(canvas, x, y);

    draw(loc);
  };
}
body{ background-color: ivory; }
#canvas{border:1px solid red;}
<h4>Move the mouse to move the triangle<br>The image is large, so be patient while it loads</h4>
<canvas id="main" width=600 height=600></canvas>

更多选项......

还有更多可能的选择。我会在不提供代码示例的情况下提及其中一些:

  • 创建填充三角形的img元素,并使用drawImage(img,loc.x,loc.y)在画布周围移动该三角形图像

  • 从三角形创建剪裁区域。剪切区域导致新图形仅显示在定义的剪切区域中。在这种情况下,新的drawImage只能在三角形内部显示,并且在三角形外部不可见。

  • 更多传统选项......