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