检测图像的透明部分上的敲击 [英] Detecting taps on transparent section of images

查看:51
本文介绍了检测图像的透明部分上的敲击的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我目前正在从事一个项目,在该项目中,用户点击不规则形状的图像以放置一个点(例如,用飞镖或将尾巴钉在驴上)。我将点放在画布上没有问题,但是遇到了人们在图像外部点击(但仍在图像边界框上)的问题。有谁知道如何过滤掉图像的透明部分上的水龙头?
这是我的代码:

I am currently working on a project where users tap on an irregularly shaped image in order to place a dot (Think of a dartboard or pin the tail on the donkey). I have no problems placing the dot on the canvas, however I run into problems where people tap outside the image (but still on the bounding-box of the image). Does anyone know how to filter out taps on the transparent part of an image? Here is my code:

<style>

#bodyImageFront {
    display:block;
    max-height: 75vh;
    max-width: 90%;
    height:auto;
    width: auto;
    margin-bottom: 10px;
    z-index:1;
    position:absolute;
}

canvas {
    z-index:20;
}

</style>

<script>

var pointMap = [];

$(document).ready(function () {
    drawCanvas();
});

$(window).resize(function () {
    console.log("resize");
    drawCanvas();
    var tempArray = pointMap;
    pointMap = [];
    for (var i = 0; i < tempArray.length; i++) {
        addPointToMap(tempArray[i]);
    }
});

function drawCanvas() {
    if (document.getElementById("bodyMapFrontCanvas")) {
           document.getElementById("bodyMapFrontContainer").removeChild(document.getElementById("bodyMapFrontCanvas"));
    }
    var frontCanvas = document.createElement("canvas");
    frontCanvas.setAttribute("id", "bodyMapFrontCanvas");
    frontCanvas.setAttribute("width", document.getElementById("bodyImageFront").width);
    frontCanvas.setAttribute("height", document.getElementById("bodyImageFront").height);
    frontCanvas.setAttribute("style", "position:relative;");
    frontCanvas.setAttribute("onclick", "addPointToMap(event, 'bodyMapFrontCanvas');");
    document.getElementById('bodyMapFrontContainer').appendChild(frontCanvas);
}

function addPointToMap(point, canvasId) {
    x = point.offsetX ? (point.offsetX) : event.pageX - document.getElementById(canvasId).offsetLeft;
    y = point.offsetY ? (point.offsetY) : event.pageY - document.getElementById(canvasId).offsetTop;
    var context = document.getElementById(canvasId).getContext("2d");
    context.fillRect(x, y, 10, 10);
    pointMap.
}
</script>
<html>
<form id="mainForm">
    <div id="canvasContainer"></div>
    <div class="col-xs-12 col-md-6" id="bodyMapFrontContainer">
        <img src="~/Content/body.png" class="questionInputMethod" id="bodyImageFront" />
    </div>
</form>
</html>

我为缩进较差的
表示歉意

I apologize for the poor indentation Thanks in advance

推荐答案


  • 解决方案1:您的图像复杂且边框透明,不需要透明部分是可单击的:

    • Solution 1 : You have a complicated image with transparent border and don't want the transparent part to be clickable :

      将图像绘制到画布中,并使用 getImageData(x,y,width,height) 检查点击像素是否是透明的。

      Draw the image into the canvas and use getImageData(x,y,width,height) to check if the pixel under the click is transparent.

      var pointMap = [], canvas, ctx, img;
      
      $(document).ready(function () {
        img = $('#bodyImageFront');
        img[0].onload = init;
      });
      
      
      $(window).resize(function () {
          canvas.width = img[0].width;
          canvas.height = img[0].height;
          drawCanvas();
          var tempArray = pointMap;
          pointMap = [];
          for (var i = 0; i < tempArray.length; i++) {
              addPointToMap(tempArray[i]);
          }
      });
      
      function init(){
         canvas = document.createElement("canvas");
         canvas.id="bodyMapFrontCanvas";
         canvas.width = img[0].width;
         canvas.height = img[0].height;
         $(canvas).css('position:relative');
         $(canvas).click(addPointToMap);
         ctx = canvas.getContext('2d');
         img.parent().append(canvas);
         img.css('opacity:0');
         drawCanvas();
        }
      function drawCanvas() {
        if(!canvas) return;
        ctx.drawImage(img[0], 0,0,canvas.width,canvas.height);
      }
      
      function addPointToMap(evt) {
          var target = evt.target,
          x = evt.offsetX ? evt.offsetX : evt.pageX - target.offsetLeft,
          y = evt.offsetY ? evt.offsetY : evt.pageY - target.offsetTop;
          // get the image data of our clicked point  
          var pointData = ctx.getImageData(x,y,1,1).data;
          // if its alpha channel is 0, don't go farther
          if(pointData[3]===0) return;
      
          ctx.fillRect(x-5, y-5, 10, 10);
          if(evt.type){
            pointMap.push({target: target, offsetX: x, offsetY: y});
            }
      }

      #bodyImageFront {
          display:block;
          max-height: 75vh;
          max-width: 90%;
          height:auto;
          width: auto;
          margin-bottom: 10px;
          z-index:-1;
          position:absolute;
      }
      
      canvas {
          z-index:20;
          background:#AAFFAA;
      }

      <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
      
      <form id="mainForm">
          <div id="canvasContainer"></div>
          <div id="bodyMapFrontContainer">
              <img src="https://dl.dropboxusercontent.com/s/nqtih1j7vj850ff/c6RvK.png" id="bodyImageFront" crossorigin="Anonymous" />
          </div>
      </form>


      • 解决方案2:您真的只想绘制一个简单的形状,如您给出的示例:

      • Solution 2 : You really only want to draw a simple shape like in the example you gave :

      绘制此形状直接在画布上绘制形状,并使用 isPointInPath( ) 来检测是否应激活点击。

      Draw this shape directly onto the canvas and use isPointInPath() to detect whether it should activate the click or not.

      var canvas = document.querySelector('canvas'),
          ctx = canvas.getContext('2d');
      function draw(){
        
        var w = canvas.width, h = canvas.height;
        ctx.fillStyle = "#5b9bd5";
        ctx.beginPath();
        var radius = w/3,
            x= canvas.width/2,
            y = radius, a= 11;
        for ( var i = 0; i <= 4 * Math.PI; i += ( 4 * Math.PI ) / 5 ) {
          ctx.lineTo( x + radius * Math.cos(i + a), y + radius * Math.sin(i + a));
        }
        ctx.closePath();
        ctx.fill();
        }
      
      function clickHandler(e){
        var target = e.target,
          x = e.clientX,
          y = e.clientY;
         if(ctx.isPointInPath(e.clientX, e.clientY)){
           ctx.fillStyle="#000";
           ctx.fillRect(x-5,y-5,10,10);
           }
        }
      canvas.addEventListener('click', clickHandler, false);
      draw();

      canvas{background:#AAFFAA;}
      *{margin:0; overflow: hidden;}

      <canvas height=500 width=500/>


      • 解决方案3:再次,您只需要一个简单的形状,而您实际上并不需要< canvas>

      • Solution 3: Once again you only want a simple shape, and you don't really need <canvas>:

      svg 绘制,并将事件侦听器仅添加到您要收听的svg元素中。

      Draw it with svg and add the event listener only to the svg element you want to listen to.

      document.getElementById('star').addEventListener('click', clickHandler, false);
      var svg = document.querySelector('svg');
      
      function clickHandler(e){
         var vB = svg.getBBox(),
             bB = svg.getBoundingClientRect(),
             ratio = {w:(vB.width/bB.width), h:(vB.height/bB.height)};
      
         var x = e.clientX*ratio.w,
             y = e.clientY*ratio.h;
        
          var rect = document.createElementNS('http://www.w3.org/2000/svg', 'rect');
          rect.setAttribute('x', x);
          rect.setAttribute('y', y);
          rect.setAttribute('width', 10*ratio.w);
          rect.setAttribute('height', 10*ratio.w);
          rect.setAttribute('fill', "#000");
          var parent = e.target.parentNode;
          parent.appendChild(rect);
          
        }

      *{margin: 0; overflow: hidden;}
      svg{
        height: 100vh;
      }

      <svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" x="0px" y="0px"
      	 viewBox="0 0 100 100" enable-background="new 0 0 100 100" xml:space="preserve">
      <rect fill="#AAFFAA" width="100" height="100"/>
      <polygon id="star" fill="#29ABE2" points="50,16.5 60.9,40.6 85.2,42.1 65.6,59.3 71.8,83.5 50,70.1 28.2,83.5 34.4,59.3 14.8,42.1 39.1,41.6 
      	"/>
      </svg>

      这篇关于检测图像的透明部分上的敲击的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆