Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to trigger click of both elements, when clicking overlapping area

I have two elements overlapping each other, Both has click events. Clicking on each element works fine.

If I click on an overlapping area as shown below, can I trigger the click of both?
enter image description here

Below is my code

$("#circle1").click(function(d) {
  alert("circle1");
});
$("#circle2").click(function(d) {
  alert("circle2");
});
.path {
  fill: red;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<svg width="525" height="226">
   <circle id="circle1" cx="50" cy="50" r="40" stroke="black" stroke-width="3" fill="red" />
   <circle id="circle2" cx="80" cy="50" r="40" stroke="black" stroke-width="3" fill="transparent" />
</svg>
like image 892
ozil Avatar asked Dec 19 '19 08:12

ozil


3 Answers

I would use clip-path to get the intersection of the 2 circles. Then I would attach the event to intersection.

intersection.addEventListener("click",()=>{
  console.log("intersection")
})
circle{stroke-width:3;stroke:black;}
svg{border:1px solid}
<svg id="svg" viewBox="0 0 525 226">
  <defs>
   <circle id="circle1" cx="50" cy="50" r="40" />
   <circle id="circle2" cx="80" cy="50" r="40"  />
   <clipPath id="clip"><use xlink:href="#circle2"  />
</clipPath>  
  </defs>
  <use xlink:href="#circle1" class="circle"  fill="red" /> 
  <use xlink:href="#circle2" class="circle"  fill="transparent" />

  <use xlink:href="#circle1" id="intersection" clip-path="url(#clip)"  fill="gold" />
</svg>
like image 135
enxaneta Avatar answered Oct 18 '22 02:10

enxaneta


You should not rely on any approach that calculates the position of the intersection or that creates another element just to compute the intersection. Such approaches will eventually fail or simply become too complicated and cumbersome.

Instead of that, use the event itself and a method like document.elementFromPoint to get all elements under the click. For instance, you can use document.elementFromPoint “recursively”, as described here. Then, using selection.dispatch, you dispatch the click event to all elements under the click.

Here is a very basic demo (click on the blue circle, the red circle or the intersection):

let clicked;
d3.select(".blue").on("click", function() {
  if (!clicked) return;
  console.log("blue circle were clicked")
});
d3.select(".red").on("click", function() {
  if (!clicked) return;
  console.log("red circle were clicked")
});
d3.select("svg").on("click", function() {
  clicked = true;
  getAllElements(...d3.mouse(this));
  clicked = false;

  function getAllElements(x, y) {
    const elements = [];
    let thisElement = document.elementFromPoint(x, y);
    while (thisElement && thisElement.nearestViewportElement) {
      elements.push(thisElement);
      d3.select(thisElement).style("display", "none");
      thisElement = document.elementFromPoint(x, y);
    }
    elements.forEach(function(elm) {
      d3.select(elm).style("display", null)
        .dispatch("click");
    });
  };
})
.as-console-wrapper {
  max-height: 30% !important;
}
<script src="https://d3js.org/d3.v5.min.js"></script>
<svg>
  <circle cx="100" cy="75" r="60" fill="powderblue" stroke="gray" stroke-width="2" opacity="0.75" class="blue"></circle>
  <circle cx="170" cy="75" r="60" fill="tomato" stroke="gray" stroke-width="2" opacity="0.75" class="red"></circle>
</svg>
like image 36
Gerardo Furtado Avatar answered Oct 18 '22 00:10

Gerardo Furtado


Here is how you can calculate the overlap area calculate clientX for each click event and make sure it is overlap area as you have already provide X and Y for your circles. Here is example. In example, I have provided a rough idea you can calculate according to your actual dimesions.

$(".circle").click(function(e) {
    if((event.clientX>50  && event.clientX<80) && (event.clientY>25 && event.clientY<85)){
    alert('overlaper area');
    }
});
.path {
  fill: red;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.2.0/jquery.min.js"></script>
<svg width="525" height="226">
   <circle class="circle" id="circle1" cx="50" cy="50" r="40" stroke="black" stroke-width="3" fill="red" />
   <circle class="circle" id="circle2" cx="80" cy="50" r="40" stroke="black" stroke-width="3" fill="transparent" />
</svg>
like image 2
manikant gautam Avatar answered Oct 18 '22 01:10

manikant gautam