3

Hitbox Overlay IIFE Code

//CSS Hitbox Solution 08-26-2015
//StackOverflow - https://stackoverflow.com/questions/32233084/show-an-element-without-hitbox-does-not-take-mouse-touch-input
//Detect MouseOver https://stackoverflow.com/questions/1273566/how-do-i-check-if-the-mouse-is-over-an-element-in-jquery
//Source: https://stackoverflow.com/questions/3942776/using-jquery-to-find-an-element-at-a-particular-position
//https://css-tricks.com/snippets/jquery/get-x-y-mouse-coordinates/
(function($) {
  $.mlp = {
    x: 0,
    y: 0
  }; // Mouse Last Position
  function documentHandler() {
    var $current = this === document ? $(this) : $(this).contents();
    $current.mousemove(function(e) {
      jQuery.mlp = {
        x: e.pageX,
        y: e.pageY
      };
    });
    $current.find("iframe").load(documentHandler);
  }
  $(documentHandler);
  $.fn.ismouseover = function(overThis) {
    var result = false;
    this.eq(0).each(function() {
      var $current = $(this).is("iframe") ? $(this).contents().find("body") : $(this);
      var offset = $current.offset();
      result = offset.left <= $.mlp.x && offset.left + $current.outerWidth() > $.mlp.x && offset.top <= $.mlp.y && offset.top + $current.outerHeight() > $.mlp.y;
    });
    return result;
  };
})(jQuery);
$('.notification-box').on("click", function() {
  $("button").each(function(i) {
    var iteratedButton = $('button:eq(' + i + ')');
    var buttonID = iteratedButton.attr("id");
    if (iteratedButton.ismouseover()) {
      iteratedButton.toggleClass(buttonID);
    }
  });
});

Example 01: Overlay Example for context

Example 02: Concept for auto generating content - Derived from this stackoverflow question.

There is a way by which one can have multiple objects underneath an overlay that masks them. Then, there is a way to have the pointer interact with the elements underneath said overlay if the user clicks at the predetermined point. My question is, may someone please write the code that would, marry the concept of the <map> tag with the IIFE that detects if the point of reference the user clicked is that image and then, act as though it was clicked.

If that did not make sense, simply, I am looking for a process that deviates away from manually setting up coordinates for <area> or having to use tool (which are profound) such as http://www.image-maps.com/. Rather, we would let the pointer do all the work.

We have the following high utility + highly compatible methods: .offset(), .position(), elementFromPoint() and the ability to put elements behind a mask utilizing basic CSS.

So we could combine the IIFE Overlay hitbox method above + ???? = Profit (good bye mapping coordinates via <map>).

I just do not know what the ???? is. I do know that whatever the solution is, I would prefer that it works in all browsers (including IE 5).

Lastly, the process should be fairly automatic in design, setup and implementation.

Whoever creates it, please dub it autoMapperJs (as it would not be limited to images).

Update:
A core feature component of the ???? has been realized as noted by @Alex in the comments. CreateJs notices when the pointer is hovered over a non-transparent area of a image. That is powerful and should be standard in the tool created. It also seems to utilize .mousemove() and z-index. Please keep commenting, as collectively, I feel a solution can be found.

Community
  • 1
  • 1
Alexander Dixon
  • 837
  • 1
  • 9
  • 24
  • 2
    _(including IE 5)._ :-o – hjpotter92 Aug 28 '15 at 20:11
  • 4
    IE5 compatibility means its very hard.. :( – Pankaj Parkar Aug 31 '15 at 16:48
  • 1
    IE 5 can be built upon later perhaps. At least to get the concept realized so we have a working template to build upon and refine. – Alexander Dixon Aug 31 '15 at 16:50
  • 2
    http://www.createjs.com/easeljs has a nice feature. you can put images on a canvas and the pointer notices when youre actually hovering over a non-transparent pixel, as seen here: http://www.createjs.com/demos/easeljs/draganddrop. I highly doubt that IE 5 is even an internet browser. – Alex Sep 03 '15 at 13:36
  • 1
    You may consider to use SVG instead of Canvas for better element base manipulation and event handling. Btw neither SVG nor Canvas have native support in IE8 and below. – Can Guney Aksakalli Sep 07 '15 at 14:48
  • As Can Guney Aksakalli mentioned, SVG would be perfect for this. Just replace the image map area elements with clear svg elements, and you have an interactive image map. And for IE8 and below, VML is available. RaphaelJS combines both of these, so I would recommend that. From your post though, it doesn't seem clear to me that this is what you need. Are you needing an image map polyfill, or dynamic detection? – iautomation Sep 08 '15 at 06:28
  • Here's a working example of a pseudo image map with RaphaelJS http://jsfiddle.net/iausallc/msc4sew7/ – iautomation Sep 08 '15 at 06:34

1 Answers1

5

Here's a start. Put images into an array of layers and placements on canvas then run through them on mouse over for hit. Also put over images in layers array to draw that image when hit.

var can = document.getElementById('image-map');
var W = can.width;
var H = can.height;
var ctx = can.getContext('2d');
var layers = [];
var mouse = {x:0,y:0};

can.addEventListener('mousemove', function(evt) {
  mouse = getMousePos(can, evt);
  drawCanvas();
}, false);

function getMousePos(canvas, evt) {
  var rect = canvas.getBoundingClientRect();
  return {
    x: evt.clientX - rect.left,
    y: evt.clientY - rect.top
  };
}

main();

function main() {

  initLayers();
  drawCanvas();
}

function drawCanvas() {
  ctx.clearRect(0, 0, W, H);
  var hit = -1;
  for (var i =layers.length; i--;) {
    var c = layers[i];
    if(maskHit(c.img, c.x, c.y)) {
      hit = i;
      break;
    }
  }
  
  for (var i =0; i < layers.length; i++) {
    var c = layers[i];
    var img = hit === i ? c.hov : c.img;
    ctx.drawImage(img, c.x, c.y);
  }
  ctx.drawImage(circ(10,"rgba(255,200,0,.75)"), mouse.x-10/2,mouse.y-10/2);
}

// UTILITY TO DRAW SAMPLE IMAGES
function circ(size, color) {
  var can = document.createElement('canvas');
  can.width = can.height = size;
  var to_rad = Math.PI / 180;
  var ctx = can.getContext('2d');
  ctx.beginPath();
  ctx.moveTo(size, size / 2);
  ctx.arc(size / 2, size / 2, size / 2, 0, 360 * to_rad);
  ctx.fillStyle = color;
  ctx.fill();
  return can;
}

function initLayers() {
  var s = 75; // size

  // PUT YOUR IMAGES IN A LAYERS ARRAY WITH X,Y COORDS FOR CANVAS
  // PLACEMENT. X AND Y ARE TOP LEFT CORNDER OF IMAGE. STORE HOVER
  // IMAGE FOR MOUSE HIT.
  layers = [{
    img: circ(s, "#090"),
    hov: circ(s, "#C0C"),
    x: 123,
    y: 12
  }, {
    img: circ(s, "#F00"),
    hov: circ(s, "#C0C"),
    x: 63,
    y: 12
  }, {
    img: circ(s, "#00F"),
    hov: circ(s, "#C0C"),
    x: 3,
    y: 12
  }];

}

var maskCan = document.createElement("canvas");
maskCan.width=maskCan.height=1;
var maskCtx = maskCan.getContext('2d');

function maskHit(img, x, y) {
    
  // get relative coords to image upper left corner
  
  x = mouse.x - x;
  y = mouse.y - y;
  
  if (x < 0 || y < 0 || x > img.width || y > img.height) return false;

  //return 1; // square hit, no alpha check
  
  // ALPHA CHECK - draw one pixel, get and check alpha.
  //                    sx sy sw sh dx dy dw dh
  maskCtx.clearRect(0,0,1,1);
  maskCtx.drawImage(img, x, y, 1, 1, 0, 0, 1, 1);
  var imageData = maskCtx.getImageData(0,0,1,1);
  //console.log(imageData.data[3])
  return imageData.data[3] === 255;
}
#image-map {
  border: 1px solid #ACE;
}
<canvas id="image-map" width="200" height="100"></canvas>
wolfhammer
  • 2,641
  • 1
  • 12
  • 11
  • great work and thank you for taking the initiative to spearhead this effort. This canvas approach works. Could you please create a fiddle of this using real images. Also, for anyone else reading, code an SVG alternative be created as well? – Alexander Dixon Sep 08 '15 at 15:42
  • 1
    Although the approach did not entirely get me there, I feel that I have a good framework to ask a more precise follow-up question now that I have more knowledge of what I am trying to ask. I will study up on RapahelJS + CreateJS and form a more robust question, so please stay tuned. Thanks again! – Alexander Dixon Sep 08 '15 at 16:42
  • @AlexanderDixon The real image usage is hard to show in an example because of cross origin issues. Current browsers will see inspecting pixel data of a foreign URL as a security risk and won't allow it. I haven't gotten into graphic libraries and use native methods when they exist. For legacy browsers I would look at modernizer or some library that would give them features of a new browser. The older browser solution in my mind is a patch unless that's a primary focus. – wolfhammer Sep 09 '15 at 17:56