2

Like the title suggests, I'd like to know if a user is clicking on the non-transparent part of a png.

Further - imagine there are several layers of pngs that are layered ontop of each other. Same size, but for each layer, the non-transparent part gets smaller and smaller. I'd like to be able to identify which of the pngs are being clicked by identifying which non-transparent part the user clicks on.

Cookie
  • 364
  • 1
  • 2
  • 12
  • Are the dimensions and positions of each transparent section known? – notepadNinja Sep 20 '22 at 18:03
  • Not really no, the user uploads x number of layers that are stacked ontop of each other. Generally, *smaller* items are placed higher up in the stack. – Cookie Sep 20 '22 at 18:11
  • You might be able to do this by adding the overlapping images to a [canvas element](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/canvas). On mouse click the code would need to drill down through the images to find the first non-transparent pixel. Yet, this is way beyond the scope of an SO question. There is enough information in this other question to get you started: [How can I read a pixel of an image when user clicks it?](https://stackoverflow.com/a/1041492/943435) – Yogi Sep 20 '22 at 18:30

2 Answers2

3

Let's try using a canvas. Thanks to @Yogi from the comments.

var url = "https://upload.wikimedia.org/wikipedia/commons/thumb/4/47/PNG_transparency_demonstration_1.png/420px-PNG_transparency_demonstration_1.png";

var image = new Image();
image.onload = function() {
  var canvas = document.createElement("canvas");
  document.body.appendChild(canvas);
  canvas.width = image.width;
  canvas.height = image.height;
  var context = canvas.getContext("2d");
  context.drawImage(image, 0, 0);

  canvas.addEventListener('mousedown', function(ev) {
    var cx = ev.offsetX
    var cy = ev.offsetY
    var data = context.getImageData(cx, cy, 1, 1).data;
    console.log(""+data)

  })
}
image.crossOrigin = "anonymous"
image.src = url;
<body>
  click and get color in console.<br>

</body>
IT goldman
  • 14,885
  • 2
  • 14
  • 28
1

Mixing and matching the answers and comments above:

Attach a click handler for each png you've rendered. On click, the event will propagate from the top-most png of the stack (the first png the click "meets"), all the way to the bottom-most (the first one rendered).

The handler will execute the same logic for each png (you may reuse the same function):

  1. Get the relative coordinates of the click (relative to each image).
  2. Determine if the pixel is transparent or not (this is the key the answer).
  3. If it meets your criteria, record which png was clicked using event.currentTarget. Then, stop propagating the event, to prevent deeper pngs from recording an event as well.

If the png didn't meet your criteria, allow the event to keep propagating.

notepadNinja
  • 409
  • 1
  • 6
  • 13