如何分割画布对角或非方块

时间:2015-03-02 19:15:55

标签: javascript canvas html5-canvas

假设我的画布是一个矩形。我想把那个画布对角分开,然后能够操纵那些碎片来做我想做的事。

我的最终目标是将一个矩形对角分割,然后两个动画以相反的方向在屏幕上显示动画。我想在动画循环中完全在画布中完成这项工作,或者将每个片段转换为图像元素,并使用CSS3动画来移动这些片段。我只想弄清楚这样做的最好方法。

下面的代码,代码链接和图片只是为了说明我希望我的画布分割的位置。你会发现它并不是一个具有相同侧面的精确分裂。

http://codepen.io/FranciscoG/pen/YPjzbQ

<div id="container">
  <img id="dog" src="http://i.imgur.com/1GUzYh9.jpg" width="375"
  height="667">
</div>

<script>
var container = document.getElementById('container');
var dogImg = document.getElementById('dog');

function convertImageToCanvas(image) {
    var canvas = document.createElement("canvas");
    canvas.width = image.width;
    canvas.height = image.height;
    canvas.getContext("2d").drawImage(image, 0, 0);
    return canvas;
}

function drawLine(canvas) {
  var context = canvas.getContext('2d');
  context.beginPath();
  context.moveTo(0,0);
  context.lineTo(345, 0);
  context.lineTo(0, 567);
  context.lineTo(0,0);
  context.stroke();
  context.closePath();
  return canvas;
};

var newDog = convertImageToCanvas(dogImg);
var divided = drawLine(newDog);
container.innerHTML = "";
container.appendChild(divided)
</script>

enter image description here

2 个答案:

答案 0 :(得分:3)

你总是可以使用剪辑,但请注意,这将涉及保存/恢复调用,这是一个相对较慢的业务。有人建议在规范中包含resetClip(),但似乎很难将消息传递到组为什么需要它。

无论如何,我建议采用以下方法:

  • 创建一个对象或函数,可以重现图像半边之一的单个蒙版(路径)(即带有包含框的对角线)。
  • 左半部分:绘制图像,将复合模式设置为destination-in,绘制蒙版,将画布提取为图像
  • 对于右半部分:绘制图像,将复合模式设置为destination-out,绘制蒙版,将画布提取为图像

现在将容器内的图像(直接使用canvas元素)放在容器中,使它们堆叠在一起。

使用过渡或动画类进行动画处理。

&#13;
&#13;
var img = new Image(375, 667);
img.onload = setup;
img.src = "http://i.imgur.com/1GUzYh9.jpg";

function setup() {

  var path = [0,0, 345,0, 0, 567];   // last point not needed..
  var left = createCanvas(this, path, "destination-in");
  var right = createCanvas(this, path, "destination-out");
  var cont = document.getElementById("cont");
  
  cont.appendChild(left);
  cont.appendChild(right);
  
  // animate here by setting animation/transition class or using JS:
  var x = 0;
  (function loop() {
    left.style.left = x + "px";   // translate is smoother, but need
    right.style.left = -x + "px"; // prefix in some browser. Update as needed..
    x-=5; if (x < -400) x = 0;
    requestAnimationFrame(loop);
  })();
  
  function createCanvas(img, path, mode) {
    var canvas = document.createElement("canvas"),
        ctx = canvas.getContext("2d");
    canvas.width = img.width;
    canvas.height = img.height;
    
    // draw image
    ctx.drawImage(img, 0, 0);
    
    // create mask
    ctx.moveTo(path[0], path[1]);
    for(var i = 2; i < path.length; i += 2) ctx.lineTo(path[i], path[i+1]);
    ctx.closePath();
    
    // composite mode and create half
    ctx.globalCompositeOperation = mode;
    ctx.fill();
    
    return canvas
  }
}
&#13;
#cont {
  position:relative;width:375px;height:667px;overflow:hidden;
  }
#cont>canvas {position:absolute;left:0;right:0;}
&#13;
<div id="cont"></div>
&#13;
&#13;
&#13;

答案 1 :(得分:1)

您可以使用context.clip来实现图像分割效果

context.clip限制使用指定路径绘制图像。

您可以定义其中几个剪裁区域,将图像分成几个部分(路径)。

然后在动画循环中,您可以清除画布并使用更改的偏移重绘每个剪裁区域。左剪辑区域将在每个循环中向左移动(偏移)。右侧裁剪区域将在每个循环中向右移动(偏移)。

以下是示例代码和演示:

&#13;
&#13;
var canvas=document.getElementById("canvas");
var ctx=canvas.getContext("2d");
var cw=canvas.width;
var ch=canvas.height;


var nextTime=0;
var duration=1000/60*3;

var offset=0;
var paths=[];

var img=new Image();
img.onload=start;
img.src="https://dl.dropboxusercontent.com/u/139992952/multple/Dog-With-Cute-Cat.jpg";
function start(){
  cw=canvas.width=img.width;
  ch=canvas.height=img.height;

  paths.push({path:[{x:0,y:0},{x:150,y:0},{x:0,y:ch}],direction:-1});
  paths.push({path:[{x:150,y:0},{x:0,y:ch},{x:cw,y:ch},{x:cw,y:0}],direction:1});

  requestAnimationFrame(animate);
}

function draw(){
  ctx.clearRect(0,0,cw,ch);
  for(var i=0;i<paths.length;i++){
    var path=paths[i].path;
    var offX=offset*paths[i].direction;
    ctx.save();
    ctx.beginPath();
    var pt=path[0];
    ctx.moveTo(pt.x+offX,pt.y);
    for(var j=1;j<path.length;j++){
      var pt=path[j];
      ctx.lineTo(pt.x+offX,pt.y);
    }
    ctx.closePath();
    ctx.stroke();
    ctx.clip();
    ctx.drawImage(img,offX,0);
    ctx.restore();
  }
}

function animate(time){
  if(offset<cw){requestAnimationFrame(animate);}else{log('done');}
  if(time<nextTime){return;}
  nextTime=time+duration;
  draw();
  offset++;
}
&#13;
body{ background-color: ivory; padding:10px; }
#canvas{border:1px solid red;}
&#13;
<canvas id="canvas" width=300 height=300></canvas>
&#13;
&#13;
&#13;