Detecting taps on transparent section of images

后端 未结 1 724
隐瞒了意图╮
隐瞒了意图╮ 2021-01-28 15:15

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 proble

相关标签:
1条回答
  • 2021-01-28 15:56
    • Solution 1 : You have a complicated image with transparent border and don't want the transparent part to be clickable :

      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>

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

      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/>

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

      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>

    0 讨论(0)
提交回复
热议问题