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?
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>
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>
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>
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>
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With