检测图像的透明部分上的敲击 [英] Detecting taps on transparent section of images
问题描述
我目前正在从事一个项目,在该项目中,用户点击不规则形状的图像以放置一个点(例如,用飞镖或将尾巴钉在驴上)。我将点放在画布上没有问题,但是遇到了人们在图像外部点击(但仍在图像边界框上)的问题。有谁知道如何过滤掉图像的透明部分上的水龙头?
这是我的代码:
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屋!
-