0

I am working on a model of a human body, which has specific organs that need to highlight and come to the top on hover and be clickable. The hard part, ex: The lungs overlap the heart, how can I make the heart clickable without putting it on top of the lungs?

I tried using transparent SVGs, but haven't been able to get them to work either.

Thanks!

user1547761
  • 71
  • 1
  • 5
  • If its svg, couldn't you just put css pointer-events: none on the bits you don't want to be clickable ? – Ian Dec 26 '14 at 09:40

2 Answers2

3

You need a "hit-test" mechanism. It works like this:

  1. keep contours of your shapes in a JS structure
  2. have a single surface on your graphics receive all mouse click events
  3. when the surface is clicked, use the passed coords to find which shape got hit in (1)

Alternatively, switching your graphics into vectors will provide this functionality out of the box, but the added advantage of scalable graphics. The downsides to this are: old browsers and increased processing to generate the vectors.

Community
  • 1
  • 1
Christian
  • 27,509
  • 17
  • 111
  • 155
3

Do you have the outline paths of the heart, lungs, etc?

If yes, you just use context.isPointInPath to hit-test each of your organs.

If no, you can draw each organ onto its own canvas and then use context.getImageData to hit-test whether the pixel under the mouse is opaque for any particular organ-canvas.

Here's an example of hit-testing with the pixel data:

enter image description here

Highlighting the organ the mouse is hovering:

enter image description hereenter image description here

var canvas=document.getElementById("canvas");
var ctx=canvas.getContext("2d");
var cw=canvas.width;
var ch=canvas.height;
var $canvas=$("#canvas");
var canvasOffset=$canvas.offset();
var offsetX=canvasOffset.left;
var offsetY=canvasOffset.top;


var heartCanvas=document.createElement('canvas');
var heartCtx=heartCanvas.getContext('2d');
var lungsCanvas=document.createElement('canvas');
var lungsCtx=lungsCanvas.getContext('2d');
heartCanvas.width=lungsCanvas.width=canvas.width;
heartCanvas.height=lungsCanvas.height=canvas.height;
var heart={canvas:heartCanvas,x:100,y:125,alpha:0.25};
var lungs={canvas:lungsCanvas,x:65,y:105,alpha:0.25};

var imgCount=3;
var bodyImg=new Image();bodyImg.onload=start;bodyImg.src="https://dl.dropboxusercontent.com/u/139992952/multple/humanOutline.png";
var heartImg=new Image();heartImg.crossOrigin='anonymous';heartImg.onload=start;heartImg.src="https://dl.dropboxusercontent.com/u/139992952/multple/heart.png";
var lungsImg=new Image();lungsImg.crossOrigin='anonymous';lungsImg.onload=start;lungsImg.src="https://dl.dropboxusercontent.com/u/139992952/multple/lungs.png";
function start(){
  if(--imgCount>0){return;}   
  var data;
  heartCtx.drawImage(heartImg,heart.x,heart.y);
  data=heartCtx.getImageData(0,0,cw,ch).data;
  heart.pixels=[];
  for(var i=0;i<data.length;i+=4){heart.pixels.push(data[i+3]);}
  lungsCtx.drawImage(lungsImg,lungs.x,lungs.y);
  data=lungsCtx.getImageData(0,0,cw,ch).data;
  lungs.pixels=[];
  for(var i=0;i<data.length;i+=4){lungs.pixels.push(data[i+3]);}
  $("#canvas").mousemove(function(e){handleMouseMove(e);});
  draw();
}

function draw(){
  ctx.clearRect(0,0,cw,ch);
  ctx.globalAlpha=0.25;
  ctx.drawImage(bodyImg,0,0);
  ctx.globalAlpha=heart.alpha;
  ctx.drawImage(heartCanvas,0,0);
  ctx.globalAlpha=lungs.alpha;
  ctx.drawImage(lungsCanvas,0,0);
  ctx.globalAlpha=1.00;
}

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

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

  var heartPixelAlpha=heart.pixels[mouseY*cw+mouseX];
  heart.alpha=(heartPixelAlpha>0)?1.00:0.25;
  var lungsPixelAlpha=lungs.pixels[mouseY*cw+mouseX];
  lungs.alpha=(lungsPixelAlpha>0)?1.00:0.25;

  draw();
}
body{ background-color: ivory; }
#canvas{border:1px solid red;}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<h4>Hover mouse over 1+ organs to highlight them</h4>
<canvas id="canvas" width=300 height=330></canvas>
markE
  • 102,905
  • 11
  • 164
  • 176
  • It almost works perfectly... moving over the part of the lungs which cover the heart triggers the event for both organs. – Christian Dec 26 '14 at 14:15
  • Yes, you'll have to make the design decision about what happens when hovering over multiple organs--my example highlights both. If you want to highlight just a single organ you could order your hit tests in your desired z-index order and then stop testing after reaching your first hit. – markE Dec 26 '14 at 23:51