Tool tips not displaying when the mouse is moved or hovered over

I have customized the code below to create a multi-line chart with tooltips and make the x-axis ordinal. However, the tooltips are not displaying when I hover over the data points, and I want to show the tooltips only for the data in the variable.

https://bl.ocks.org/larsenmtl/e3b8b7c2ca4787f77d78f58d41c3da91

Here is my modified code:

    <head>
    <script data-require="<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="bbdf88fb88958e9588">[email protected]</a>" data-semver="3.5.3" src="//cdnjs.cloudflare.com/ajax/libs/d3/3.5.3/d3.js"></script> 
      <style>
        body {
          font: 10px sans-serif;
        }
        
        .axis path,
        .axis line {
          fill: none;
          stroke: #000;
          shape-rendering: crispEdges;
        }
        
        .line {
          fill: none;
          stroke: steelblue;
          stroke-width: 1.5px;
        }
      </style>
    </head>
    
    <body>
      <script>
    
        var margin = {
            top: 20,
            right: 80,
            bottom: 30,
            left: 50
          },
          width = 900 - margin.left - margin.right,
          height = 500 - margin.top - margin.bottom;
    
    //    var parseDate = d3.time.format("%Y%m%d").parse;
    
    //    var x = d3.scale.linear()
    //      .range([0, width]);
        var x  = d3.scale.ordinal()
        .domain(["20170101","20170108","20170115","20170122","20170128"])
        .rangePoints([0, width],0.5);
    
        var y = d3.scale.linear()
          .range([height, 0]);
    
        var color = d3.scale.category10();
    
        var xAxis = d3.svg.axis()
          .scale(x)
    //      .ticks(5)
          .orient("bottom")
    //      .tickValues(["2017-01-01", "2017-01-08", "2017-01-15", "2017-01-22", "2017-01-28"]);
    
        var yAxis = d3.svg.axis()
          .scale(y)
          .orient("left");
    
        var line = d3.svg.line()
          .interpolate("linear")
          .x(function(d) {
            return x(d.week);
          })
          .y(function(d) {
            return y(d.avg_test_drives);
          });
    
        var svg = d3.select("body").append("svg")
          .attr("width", width + margin.left + margin.right)
          .attr("height", height + margin.top + margin.bottom)
          .append("g")
          .attr("transform", "translate(" + margin.left + "," + margin.top + ")");
    
    //    var data = d3.tsv.parse(myData);
    //      console.log(data[0]);
    //      alert (JSON.stringify(data));
          
        var data =  [{"week": "20170101", "dealer": "68", "peers": "73","all dealers":"123"},
                     {"week": "20170108", "dealer": "121","peers":"112","all dealers":"131"},
                     {"week": "20170115", "dealer": "104","peers":"101","all dealers":"106"},
                     {"week": "20170122", "dealer": "123","peers":"131","all dealers":"122"},
                     {"week": "20170128", "dealer": "106","peers":"107","all dealers":"122"}]
    //    alert (JSON.stringify(data));
    
        color.domain(d3.keys(data[0]).filter(function(key) {
          return key !== "week";
        }));
        
    
        data.forEach(function(d) {
          d.week = d.week;
        });
            
    
        var testdrives = color.domain().map(function(name) {
          return {
            name: name,
            values: data.map(function(d) {
              return {
                week: d.week,
                avg_test_drives: +d[name]
              };
            })
          };
        });
     
       
    //    x.domain(d3.extent(data, function(d) {
    //      return d.week;
    //    }));
          
         
    
        y.domain([
          d3.min(testdrives, function(c) {
            return d3.min(c.values, function(v) {
              return v.avg_test_drives;
            });
          }),
          d3.max(testdrives, function(c) {
            return d3.max(c.values, function(v) {
              return v.avg_test_drives;
            });
          })
        ]);
          
        
    
        var legend = svg.selectAll('g')
          .data(testdrives)
          .enter()
          .append('g')
          .attr('class', 'legend');
    
        legend.append('rect')
          .attr('x', width - 20)
          .attr('y', function(d, i) {
            return i * 20;
          })
          .attr('width', 10)
          .attr('height', 10)
          .style('fill', function(d) {
            return color(d.name);
          });
    
        legend.append('text')
          .attr('x', width - 8)
          .attr('y', function(d, i) {
            return (i * 20) + 9;
          })
          .text(function(d) {
            return d.name;
          });
          
        
    
        svg.append("g")
          .attr("class", "x axis")
          .attr("transform", "translate(0," + height + ")")
          .call(xAxis)
    //      .ticks(5);
    
        svg.append("g")
          .attr("class", "y axis")
          .call(yAxis)
          .append("text")
          .attr("transform", "rotate(-90)")
          .attr("y", 6)
          .attr("dy", ".71em")
          .style("text-anchor", "end")
          .text("Test Drives");
    
        var entity = svg.selectAll(".entity")
          .data(testdrives)
          .enter().append("g")
          .attr("class", "entity");
    //    alert (JSON.stringify(entity));   
       
        entity.append("path")
          .attr("class", "line")
          .attr("d", function(d) {
            return line(d.values);
          })
          .style("stroke", function(d) {
            return color(d.name);
          });
    
        entity.append("text")
          .datum(function(d) {
            return {
              name: d.week,
              value: d.values[d.values.length - 1]
            };
          })
          .attr("transform", function(d) {
            return "translate(" + x(d.value.week) + "," + y(d.value.avg_test_drives) + ")";
          })
          .attr("x", 3)
          .attr("dy", ".35em")
          .text(function(d) {
            return d.week;
          });
          
    
    
        var mouseG = svg.append("g")
          .attr("class", "mouse-over-effects");
    
        mouseG.append("path") // this is the black vertical line to follow mouse
          .attr("class", "mouse-line")
          .style("stroke", "black")
          .style("stroke-width", "1px")
          .style("opacity", "0");
          
        var lines = document.getElementsByClassName('line');
          
         
    
        var mousePerLine = mouseG.selectAll('.mouse-per-line')
          .data(testdrives)
          .enter()
          .append("g")
          .attr("class", "mouse-per-line");
          
       
        mousePerLine.append("circle")
          .attr("r", 7)
          .style("stroke", function(d) {
            return color(d.week);
          })
          .style("fill", "none")
          .style("stroke-width", "1px")
          .style("opacity", "0");
    
        mousePerLine.append("text")
          .attr("transform", "translate(10,3)");
          
    
        mouseG.append('svg:rect') // append a rect to catch mouse movements on canvas
          .attr('width', width) // can't catch mouse events on a g element
          .attr('height', height)
          .attr('fill', 'none')
          .attr('pointer-events', 'all')
          .on('mouseout', function() { // on mouse out hide line, circles and text
            d3.select(".mouse-line")
              .style("opacity", "0");
            d3.selectAll(".mouse-per-line circle")
              .style("opacity", "0");
            d3.selectAll(".mouse-per-line text")
              .style("opacity", "0");
          })
                
          .on('mouseover', function() { // on mouse in show line, circles and text
            d3.select(".mouse-line")
              .style("opacity", "1");
            d3.selectAll(".mouse-per-line circle")
              .style("opacity", "1");
            d3.selectAll(".mouse-per-line text")
              .style("opacity", "1");
          })
          
          .on('mousemove', function() { // mouse moving over canvas
            var mouse = d3.mouse(this);
            d3.select(".mouse-line")
              .attr("d", function() {
                var d = "M" + mouse[0] + "," + height;
                d += " " + mouse[0] + "," + 0;
                return d;
            
              });
            
          
         
           d3.selectAll(".mouse-per-line")
              .attr("transform", function(d, i) {
                console.log(width/mouse[0])
                var xDate = x.invert(mouse[0]),
                    bisect = d3.bisector(function(d) { return d.week; }).right;
                    idx = bisect(d.values, xDate);
                
                var beginning = 0,
                    end = lines[i].getTotalLength(),
                    target = null;
    
                while (true){
                  target = Math.floor((beginning + end) / 2);
                  pos = lines[i].getPointAtLength(target);
                  if ((target === end || target === beginning) && pos.x !== mouse[0]) {
                      break;
                  }
                  if (pos.x > mouse[0])      end = target;
                  else if (pos.x < mouse[0]) beginning = target;
                  else break; //position found
                }
                
                d3.select(this).select('text')
                  .text(y.invert(pos.y).toFixed(2));
                  
                return "translate(" + mouse[0] + "," + pos.y +")";
              });
          });
          
      </script>
    </body>

Answer №1

During your attempt to access the `invert()` function of `x`, it was discovered that `x` is no longer `linear()`, but rather `ordinal()`. This change rendered it impossible to invert, resulting in a missing `invert()` function for `x = d3.scale.ordinal()`. Consequently, calling this function triggered an error and obstructed the execution of subsequent lines of code. In order to rectify this issue, simply comment out:

 var xDate = x.invert(mouse[0]),
                    bisect = d3.bisector(function(d) { return d.week; }).right;
                    idx = bisect(d.values, xDate);

within d3.selectAll(".mouse-per-line"). By making this adjustment, the tooltip functionality will be restored:

    <head>
    <script data-require="<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="ff9bccbfccd1cad1cc">[email protected]</a>" data-semver="3.5.3" src="//cdnjs.cloudflare.com/ajax/libs/d3/3.5.3/d3.js"></script> 


      <style>
        body {
          font: 10px sans-serif;
        }
        
        .axis path,
        .axis line {
          fill: none;
          stroke: #000;
          shape-rendering: crispEdges;
        }
        
        .line {
          fill: none;
          stroke: steelblue;
          stroke-width: 1.5px;
        }
      </style>
    </head>
    
    <body>
      <script>
    
        var margin = {
            top: 20,
            right: 80,
            bottom: 30,
            left: 50
          },
          width = 900 - margin.left - margin.right,
          height = 500 - margin.top - margin.bottom;
    
    //    var parseDate = d3.time.format("%Y%m%d").parse;
    
    //    var x = d3.scale.linear()
    //      .range([0, width]);
        var x  = d3.scale.ordinal()
        .domain(["20170101","20170108","20170115","20170122","20170128"])
        .rangePoints([0, width],0.5);
    
        var y = d3.scale.linear()
          .range([height, 0]);
    
        var color = d3.scale.category10();
    
        var xAxis = d3.svg.axis()
          .scale(x)
    //      .ticks(5)
          .orient("bottom")
    //      .tickValues(["2017-01-01", "2017-01-08", "2017-01-15", "2017-01-22", "2017-01-28"]);
    
        var yAxis = d3.svg.axis()
          .scale(y)
          .orient("left");
    
        var line = d3.svg.line()
          .interpolate("linear")
          .x(function(d) {
            return x(d.week);
          })
          .y(function(d) {
            return y(d.avg_test_drives);
          });
    
        var svg = d3.select("body").append("svg")
          .attr("width", width + margin.left + margin.right)
          .attr("height", height + margin.top + margin.bottom)
          .append("g")
          .attr("transform", "translate(" + margin.left + "," + margin.top + ")");
    
    //    var data = d3.tsv.parse(myData);
    //      console.log(data[0]);
    //      alert (JSON.stringify(data));
          
        var data =  [{"week": "20170101", "dealer": "68", "peers": "73","all dealers":"123"},
                     {"week": "20170108", "dealer": "121","peers":"112","all dealers":"131"},
                     {"week": "20170115", "dealer": "104","peers":"101","all dealers":"106"},
                     {"week": "20170122", "dealer": "123","peers":"131","all dealers":"122"},
                     {"week": "20170128", "dealer": "106","peers":"107","all dealers":"122"}]
    //    alert (JSON.stringify(data));
    
        color.domain(d3.keys(data[0]).filter(function(key) {
          return key !== "week";
        }));
        
    
        data.forEach(function(d) {
          d.week = d.week;
        });
            
    
        var testdrives = color.domain().map(function(name) {
          return {
            name: name,
            values: data.map(function(d) {
              return {
                week: d.week,
                avg_test_drives: +d[name]
              };
            })
          };
        });
     
       
    //    x.domain(d3.extent(data, function(d) {
    //      return d.week;
    //    }));
          
         
    
        y.domain([
          d3.min(testdrives, function(c) {
            return d3.min(c.values, function(v) {
              return v.avg_test_drives;
            });
          }),
          d3.max(testdrives, function(c) {
            return d3.max(c.values, function(v) {
              return v.avg_test_drives;
            });
          })
        ]);
          
        
    
        var legend = svg.selectAll('g')
          .data(testdrives)
          .enter()
          .append('g')
          .attr('class', 'legend');
    
        legend.append('rect')
          .attr('x', width - 20)
          .attr('y', function(d, i) {
            return i * 20;
          })
          .attr('width', 10)
          .attr('height', 10)
          .style('fill', function(d) {
            return color(d.name);
          });
    
        legend.append('text')
          .attr('x', width - 8)
          .attr('y', function(d, i) {
            return (i * 20) + 9;
          })
          .text(function(d) {
            return d.name;
          });
          
        
    
        svg.append("g")
          .attr("class", "x axis")
          .attr("transform", "translate(0," + height + ")")
          .call(xAxis)
    //      .ticks(5);
    
        svg.append("g")
          .attr("class", "y axis")
          .call(yAxis)
          .append("text")
          .attr("transform", "rotate(-90)")
          .attr("y", 6)
          .attr("dy", ".71em")
          .style("text-anchor", "end")
          .text("Test Drives");
    
        var entity = svg.selectAll(".entity")
          .data(testdrives)
          .enter().append("g")
          .attr("class", "entity");
    //    alert (JSON.stringify(entity));   
       
        entity.append("path")
          .attr("class", "line")
          .attr("d", function(d) {
            return line(d.values);
          })
          .style("stroke", function(d) {
            return color(d.name);
          });
    
        entity.append("text")
          .datum(function(d) {
            return {
              name: d.week,
              value: d.values[d.values.length - 1]
            };
          })
          .attr("transform", function(d) {
            return "translate(" + x(d.value.week) + "," + y(d.value.avg_test_drives) + ")";
          })
          .attr("x", 3)
          .attr("dy", ".35em")
          .text(function(d) {
            return d.week;
          });
          
    
    
        var mouseG = svg.append("g")
          .attr("class", "mouse-over-effects");
    
        mouseG.append("path") 
          .attr("class", "mouse-line")
          .style("stroke", "black")
          .style("stroke-width", "1px")
          .style("opacity", "0");
          
        var lines = document.getElementsByClassName('line');
          
         
    
        var mousePerLine = mouseG.selectAll('.mouse-per-line')
          .data(testdrives)
          .enter()
          .append("g")
          .attr("class", "mouse-per-line");
          
       
        mousePerLine.append("circle")
          .attr("r", 7)
          .style("stroke", function(d) {
            return color(d.week);
          })
          .style("fill", "none")
          .style("stroke-width", "1px")
          .style("opacity", "0");
    
        mousePerLine.append("text")
          .attr("transform", "translate(10,3)");
          
    
        mouseG.append('svg:rect') 
          .attr('width', width) 
          .attr('height', height)
          .attr('fill', 'none')
          .attr('pointer-events', 'all')
          .on('mouseout', function() {
            d3.select(".mouse-line")
              .style("opacity", "0");
            d3.selectAll(".mouse-per-line circle")
              .style("opacity", "0");
            d3.selectAll(".mouse-per-line text")
              .style("opacity", "0");
          })
                
          .on('mouseover', function() {
            d3.select(".mouse-line")
              .style("opacity", "1");
            d3.selectAll(".mouse-per-line circle")
              .style("opacity", "1");
            d3.selectAll(".mouse-per-line text")
              .style("opacity", "1");
          })
          
          .on('mousemove', function() {
            var mouse = d3.mouse(this);
            d3.select(".mouse-line")
              .attr("d", function() {
                var d = "M" + mouse[0] + "," + height;
                d += " " + mouse[0] + "," + 0;
                return d;
            
              });
            
          
         
           d3.selectAll(".mouse-per-line")
              .attr("transform", function(d, i) {
                console.log(width/mouse[0])
               /* var xDate = x.invert(mouse[0]),
                    bisect = d3.bisector(function(d) { return d.week; }).right;
                    idx = bisect(d.values, xDate);
                */
                var beginning = 0,
                    end = lines[i].getTotalLength(),
                    target = null;
    
                while (true){
                  target = Math.floor((beginning + end) / 2);
                  pos = lines[i].getPointAtLength(target);
                  if ((target === end || target === beginning) && pos.x !== mouse[0]) {
                      break;
                  }
                  if (pos.x > mouse[0])      end = target;
                  else if (pos.x < mouse[0]) beginning = target;
                  else break; //position found
                }
                
                d3.select(this).select('text')
                  .text(y.invert(pos.y).toFixed(2));
                  
                return "translate(" + mouse[0] + "," + pos.y +")";
              });
          });
          
      </script>
    </body>

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

The significance of Token Details in Tokbox

I'm currently working on developing a video chat platform that caters to various user roles - some may just observe while others actively participate in calls. I've been exploring the capabilities of the Tokbox Api () which allows metadata to be ...

TabContainer - streamline your selection process with inline tabs

I am currently working on a GUI that includes a TabContainer with two tabs, each containing a different datagrid. I initially created the tabcontainer divs and datagrids declaratively in HTML for simplicity, but I am open to changing this approach if it wo ...

Gulp is failing to convert SCSS files into CSS

I'm having trouble getting gulp to compile my SASS code into CSS automatically. What could be the issue? file structure: public -css --styles.css -index.html sass -styles.scss gulpfile.js package.json Gulpfile: var gulp = require('gulp') ...

The inheritance caused this scope to be lost

Here is an illustration of code with two files and "classes". In the CRUD class, there is a problem with this.modelName when setting routes as it changes the context. The question arises on how to maintain the same scope within the CRUD where modelName is ...

Issue with the alphabetical ordering of subpages

My PageSidebar.js component lists child pages alphabetically. https://i.sstatic.net/DZro1.png However, when I navigate to a child page, the alphabetical order is not maintained. https://i.sstatic.net/fRVgO.png I've tried multiple solutions but hav ...

What are the best ways to improve ajax response in jQuery?

My database query is fetching around 5000 rows of data along with data from 5 relational tables, leading to performance issues. The network tab shows the size of the request resource as 9.1 mb. After that, I am dynamically adding this data to a table using ...

HTML5 Audio using AudioJS may not function reliably when loaded remotely

I have been encountering frustrating issues with loading audio tags for a while now. Despite spending nearly two weeks trying to solve the problems, every fix seems to create another one. My webpage includes an < audio > tag that utilizes audio.js t ...

The Discord.js bot is unable to send messages in embedded format

I created a Discord bot using discord.js with multiple commands, including three commands with embed forms. One command, "help", works perfectly fine, but the other two are not functioning properly. All of them have the same main code structure, specifical ...

Implementing the if/shim binding in Knockout.js

In my project, I am looking to develop a unique custom binding that functions similarly to the if binding. However, instead of completely removing the element from view, I want it to be replaced with another element of equal height whenever it needs to be ...

Identify the page search function to reveal hidden content in a collapsible section

Our team has implemented an expandable box feature on our wiki (in Confluence) to condense information, using the standard display:none/block method. However, I am looking for a way to make this work seamlessly with the browser's find functionality. S ...

Exploring complex nested data structures

I've been tackling a component that manages labels and their child labels. The data structure and rendering process are sorted out, as shown in this example. However, I'm at a roadblock when it comes to manipulating the data effectively. Specif ...

Exploring the power of Selenium Webdriver in combination with JavaScript

Can someone help me figure out why I'm getting this error message: "Exception in thread "main" java.lang.ClassCastException: java.lang.Long cannot be cast to org.openqa.selenium.WebElement at canvasdrag.Canvas.main(Canvas.java:57)" WebElement elemen ...

When attempting to reference a custom module within a React application, the error message "moment is not a function" may appear

I am facing an issue while trying to integrate a custom module I developed into a basic React application using react-boilerplate. Upon importing the module, I encountered an error stating that the moment function within the module is undefined. Here is t ...

Guide: Implementing Vuex store within a plugin

I recently developed a custom Vue plugin which includes a customized instance method import Echo from 'laravel-echo'; import Vue from 'vue'; import config from '@/config'; const echor = { install(Vue){ Vue.prototy ...

The typography text exceeds the boundaries of the Material-UI CardContent

In the React Material-UI framework, I am working with a CardContent component that looks like this: <CardContent className={classes.cardContent}> <Typography component="p" className={classes.title} variant="title"> {this.props.post.title ...

Trouble with displaying events on Angular UI-Calendar

I've been working with Angular UI Calendar and following the steps outlined on their website: http://angular-ui.github.io/ui-calendar/ Despite implementing everything correctly, I'm facing an issue where the events fetched from my API are not s ...

Displaying PHP output within a JavaScript expression

Let's dive into a scenario involving a basic HTML document and some JavaScript that's loaded within it: <!-- doc.html --> <!doctype html> <html lang="en"> <head> <script type="text/javascript" src=" ...

Crafting Effective AngularJS Directives

Recently, I've been delving into AngularJS and have grasped the core concepts quite well. As I embark on building my own application, I find myself struggling with laying out the blueprint, particularly in terms of directive design. Are there any not ...

What are the drawbacks of utilizing the onClick function in JavaScript?

What is the rationale behind programmers opting not to use onClick function in Javascript? ...

Insert a JavaScript object into the rendered HTML using the componentDidMount lifecycle method

I'm trying to incorporate a JavaScript object into the template once the component has mounted for tracking purposes. Here is how I want the object to be rendered: var tracking = { pagename: 'page name', channel: 'lp&ap ...