Search code examples
javascriptd3.jsmouseoversvg-path

d3 trigger mouseover on path underlying other path?


I have this chart.

As you can see i inserted two paths.

There is am mouseover listener on the circles.

Now the problem is, that one path is overlaying the other and the circles belonging to it, and the event is not triggered when hovering an underlying circle.

Here the circle I mean:

enter image description here

I draw the lines and circles like this:

//draw line
let valueline = d3.line()
  .x(function(d) { return x(d.date); })
  .y(function(d) { return ys[count](d.val); });

let chart = chartBody.append("g")
  .attr("class", `charts chart-${count}`)
  .append("path")
    .attr("class", `line-${count} line`)
    .attr("d", valueline(data.samples));

//get dots for circle values
let node = chartBody.selectAll("dot")
                .data(data.samples)
                .enter()
                .append("g");

//add circle
node.append("circle")
  .attr("class", `circle-${count}`)
  .attr("cx", function(d) {return x(d.date); })
  .attr("cy", function(d) { return ys[count](d.val); })
  .attr("r", 8)
  .on("mouseover", showHideDetails)
  .on("mouseout", showHideDetails);

Is there a way to trigger the event on the underlying circle or do i have to use something else than the path tag?

Help would be greatly appreciated.


Solution

  • One way to do this is to group the path and circles element separately.

    let chartBody = svg.append("g")
      .attr("class", "chart-body")
      .attr("clip-path", "url(#clip)")
      //.call(zoom)
    
    let rect = chartBody.append('svg:rect')
      .attr('id', 'rect')
      .attr('width', width)
      .attr('height', height)
      .attr('fill', 'white');
    
    // create group for path
    let chartPathContainer = chartBody.append('g')
        .attr('class', 'chart-path-container');
    
    // create group for circles after path so all circles are not covered by path
    let chartCircleContainer = chartBody.append('g')
        .attr('class', 'chart-circle-container');
    

    Then when drawing the path and dots, use their respective group as the container, instead of appending them into chartBody.

      let chart = chartPathContainer.append("g")
        .attr("class", `charts chart-${count}`)
        .attr("data-axis", count)
        .append("path")
        .attr("class", `line-${count} line`)
        .attr("d", valueline(data.samples))
        .attr("data-axis", count)
        .attr("data-inactive", false);
      //.on("mouseover", showDetails)
      //.on("mouseout", hideDetails);
    
      //get dots for circle values
      let node = chartCircleContainer.selectAll("dot")
        .data(data.samples)
        .enter()
        .append("g");
    

    Just make sure there's no circles/dots that overlap each other.