Accepted answer

for a quick fix, you can move the range above the overlay and manually call the overlay event handlers from the range.

      .attr("class", "overlay")
      .attr("width", width)
      .attr("height", height)
      .on("mouseover", function() {"display", null); })
      .on("mouseout", function() {"display", "none"); })
      .on("mousemove", mousemove);

  // move range above overlay and call the overlay event handlers from there
      .attr("id", "range")
      .attr("class", "range")
      .attr("x", left)
      .attr("width", wid)
      .attr("height", height)
      .on("mousemove", mousemove)
      .on("mouseout", function() {"display", "none"); })
      .on("mouseover", function() {
"display", null);
          // event handling for range mouseover (alert broke mouse move)
          console.log("i can see you!");

bubbling acts at the dom level, and since there is no way to have a rect be a child of another rect, bubbling will not take care of this for you. grouping the elements together and placing a handler that checks the event target on the group will keep you from registering the event handler twice, but suffers from the same basic problem: when elements overlap, whichever element is declared last in the source order will get the event.


all above answers are right but i wanted to give another example:

    let log = console.log
let data = []
let pointstart = document.queryselector("svg").createsvgpoint()
let pointstop = document.queryselector("svg").createsvgpoint()
let divlog ="#log")
var svg ="svg")

var linearfn = d3.line()
  .x(d => d.x)
  .y(d => d.y)

function logtagname(eventname, tagname) {
  divlog.html(divlog.html() + eventname + " : " + tagname + "<br/>")

svg.on("click", function() {
    log("tagname: ",
    logtagname("svg click",
    pointstart.x = event.x - 8
    pointstart.y = event.y - 8

      x: pointstart.x,
      y: pointstart.y

    svg.selectall("path") // svg içinde tanımlı path elemanlarını bul
      .data([1]).enter() // 1 elemanlı dizinin eleman sayısı kadarı için enter()
      .append('path') // dizi elemanı kadar path oluştur
      .attr("fill", "none")
      .attr("stroke", "black")
      .attr("stroke-width", 8)
      .attr("d", linearfn(data))
      .on("click", function() {
        log("tagname: ",
        logtagname("path click",
        /* click event will start from path and pass to the svg element */
        // event.stoppropagation(); // letting pass event bubbling 

      .attr("cx", d => d.x + .5)
      .attr("cy", d => d.y + .5)
      .attr("r", 20)
      .attr("stroke-width", 3)
      .attr("stroke", "red")
      .attr("cursor", "move")
      .style("fill", "transparent")
      .attr("pointer-events", "all") // when clicked in/outside of circle, it'll handle events
      .on("mouseover", function() {
        log("over oldu")"stroke", "blue");
      .on("mouseout", function() {
        log("out oldu")"stroke", "red");
      .on("click", function() {
        event.stoppropagation(); // not letting pass event bubbling
        log("click oldu")"stroke", "black");
  .on("mousemove", function() {
    // fare hareketinde de çizdireceğiz ama x,y noktasını 
    // tıklanıncaya kadar diziye eklemeyeceğiz
    pointstop.x = event.x - 8
    pointstop.y = event.y - 8"path")
      .attr("d", linearfn(data.concat({
        x: pointstop.x,
        y: pointstop.y


you can also use the following style, to "hide" certain svg elements for mouse events. in my case, it was the mouseover event, that i wanted to bubble through:

pointer-events: none;

Related Query

More Query from same tag