使png可拖动忽略透明区域的最佳方法

时间:2015-06-12 10:33:02

标签: jquery css html5 canvas

我有' png'文件有一些不规则的形状。我需要使它们可拖动,但只有非透明区域才能作为鼠标事件的处理程序。请告诉我实现相同的最佳方法。

我已经尝试过使用' map'但是draggable不适用于map。

2 个答案:

答案 0 :(得分:2)

如果在画布上绘制了png图像,则可以检查单击的像素。

假设你点击了(x,y)

var currentCanvas = ctx.getImageData(x, y, 1, 1);
var pix = currentCanvas.data;

if (pix[3] > 0) { //0 is transparent, 255 is fully visible
    //clicked a non-transparent area and thus it is draggable
}

此解决方案假设背景也是透明的,因此您无法在其后面绘制任何其他内容。

答案 1 :(得分:1)

以下是仅当鼠标开始在图像的非透明部分中拖动时才开始拖动图像的方法:

  • 使用context.getImageData获取有关图片的像素信息。
  • 创建一个包含图像的alpha信息的数组
  • 要开始拖动事件,请侦听mousedown事件并检查alpha数组以查看是否在图像中按下了鼠标。如果是,请开始拖动。

这是带注释的示例代码和演示:

var canvas=document.getElementById("canvas");
var ctx=canvas.getContext("2d");
var cw=canvas.width;
var ch=canvas.height;
function reOffset(){
  var BB=canvas.getBoundingClientRect();
  offsetX=BB.left;
  offsetY=BB.top;        
}
var offsetX,offsetY;
reOffset();
window.onscroll=function(e){ reOffset(); }
window.onresize=function(e){ reOffset(); }

var isDown=false;
var startX,startY;

var hitArray
var draggables=[];

var testImg=new Image();
testImg.crossOrigin='anonymous';
testImg.onload=start;
testImg.src="https://dl.dropboxusercontent.com/u/139992952/multple/pikachu.png";
function start(){

  draggables.push({
    img:testImg,
    x:50,
    y:50,
    width:testImg.width,
    height:testImg.height,
    hitarray:makeHitArray(testImg),
    isDragging:false,
  });

  draggables.push({
    img:testImg,
    x:150,
    y:50,
    width:testImg.width,
    height:testImg.height,
    hitarray:makeHitArray(testImg),
    isDragging:false,
  });

  // listen for mouse events
  $("#canvas").mousedown(function(e){handleMouseDown(e);});
  $("#canvas").mousemove(function(e){handleMouseMove(e);});
  $("#canvas").mouseup(function(e){handleMouseUp(e);});
  $("#canvas").mouseout(function(e){handleMouseOut(e);});

  drawAll();

}

function drawAll(){
  ctx.clearRect(0,0,cw,ch);
  for(var i=0;i<draggables.length;i++){
    var d=draggables[i];
    ctx.drawImage(d.img,d.x,d.y);
  }
}

// Draw a target image on a canvas
// Get the imageData of that canvas
// Make an array containing the opacity of each pixel on the canvas
// ( 0==pixel is not part of the object, 1==pixel is part of the object)
function makeHitArray(img){
  var a=[];
  canvas.width=img.width;
  canvas.height=img.height;
  ctx.drawImage(img,0,0);
  var data=ctx.getImageData(0,0,canvas.width,canvas.height).data;
  for(var i=0;i<data.length;i+=4){
    // if this pixel is mostly opaque push 1 else push 0
    a.push(data[i+3]>250?1:0);
  }
  canvas.width=cw;
  canvas.height=ch;
  return(a);
}

function hitTest(mx,my,d){
  // return if the mouse is not inside the image bounds
  if(mx<d.x || mx>d.x+d.width || my<d.y || my>d.y+d.height){return;}
  // undo the effects of the image not being at [0,0]
  x=mx-d.x;
  y=my-d.y;
  // calculate which index in the hitarray to test
  index=(y*d.width)+x;
  // test the hitarray
  if(d.hitarray[index]>0){
    // the mouse is over an opaque part of the image
    return(true);
  }else{
    // the mouse is not over an opaque part of the image
    return(false);
  }
}

function handleMouseDown(e){
  // tell the browser we're handling this event
  e.preventDefault();
  e.stopPropagation();

  // get the mouse position
  startX=parseInt(e.clientX-offsetX);
  startY=parseInt(e.clientY-offsetY);

  // Set the dragging flags if the mouse was down over 
  // an opaque part of the draggable image
  isDown=false;
  for(var i=0;i<draggables.length;i++){
    var d=draggables[i];
    d.isDragging=hitTest(startX,startY,d);
    if(d.isDragging){
      isDown=true;
    }
  }         
}

function handleMouseUp(e){
  // tell the browser we're handling this event
  e.preventDefault();
  e.stopPropagation();

  mouseX=parseInt(e.clientX-offsetX);
  mouseY=parseInt(e.clientY-offsetY);

  // Put your mouseup stuff here
  isDown=false;
}

function handleMouseOut(e){
  // tell the browser we're handling this event
  e.preventDefault();
  e.stopPropagation();

  mouseX=parseInt(e.clientX-offsetX);
  mouseY=parseInt(e.clientY-offsetY);

  // Put your mouseOut stuff here
  isDown=false;
}

function handleMouseMove(e){
  if(!isDown){return;}
  // tell the browser we're handling this event
  e.preventDefault();
  e.stopPropagation();

  // get the mouse position
  mouseX=parseInt(e.clientX-offsetX);
  mouseY=parseInt(e.clientY-offsetY);

  // calculate how far the mouse has moved since the last move event
  var dx=mouseX-startX;
  var dy=mouseY-startY;
  startX=mouseX;
  startY=mouseY;

  // iterate draggables and move any that are being dragged
  for(var i=0;i<draggables.length;i++){
    var d=draggables[i];
    if(d.isDragging){
      d.x+=dx;
      d.y+=dy;
    }
  }

  drawAll();

}
body{ background-color: ivory; }
#canvas{border:1px solid red; margin:0 auto; }
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<canvas id="canvas" width=300 height=300></canvas>