Sai Rajesh
Sai Rajesh

Reputation: 1982

line chart with mouseover tooltip is not working in d3.js

I've created a line chart using this http://bl.ocks.org/d3noob/6eb506b129f585ce5c8a code example. I've managed to recreate it.

that code is

<!DOCTYPE html>
<meta charset="utf-8">
<style> /* set the CSS */

body { font: 12px Arial;}

path { 
    stroke: steelblue;
    stroke-width: 2;
    fill: none;
}

.axis path,
.axis line {
    fill: none;
    stroke: grey;
    stroke-width: 1;
    shape-rendering: crispEdges;
}

</style>
<body>

<!-- load the d3.js library -->    
<script src="http://d3js.org/d3.v3.min.js"></script>

<script>

// Set the dimensions of the canvas / graph
var margin = {top: 30, right: 20, bottom: 30, left: 50},
    width = 600 - margin.left - margin.right,
    height = 270 - margin.top - margin.bottom;

// Parse the date / time
var parseDate = d3.time.format("%d-%b-%y").parse,
    formatDate = d3.time.format("%d-%b"),
    bisectDate = d3.bisector(function(d) { return d.date; }).left;

// Set the ranges
// var x = d3.time.scale().range([0, width]);
var x = d3.scale.ordinal().rangePoints([0, width]);
var y = d3.scale.linear().range([height, 0]);

// Define the axes
var xAxis = d3.svg.axis().scale(x)
    .orient("bottom").ticks(5);

var yAxis = d3.svg.axis().scale(y)
    .orient("left").ticks(5);

// Define the line
var valueline = d3.svg.line()
    .interpolate('basis')
    .x(function(d) { return x(d.date); })
    .y(function(d) { return y(d.close); });
    
// Adds the svg canvas
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 lineSvg = svg.append("g"); 

var focus = svg.append("g") 
    .style("display", "none");

// Get the data
var data = [
  {
    "date": "w1",
    "close": 629.32
  },
  {
    "date": "w2",
    "close": 124.31
  },
  {
    "date": "w3",
    "close": 333.68
  },
  {
    "date": "w4",
    "close": 236.23
  }
]
    // data.forEach(function(d) {
    //     // d.date = parseDate(d.date);
    //     d.date = +d.date;
    //     d.close = +d.close;
    // });

    // Scale the range of the data
    x.domain(data.map(function(d) { return d.date; }));
    y.domain([0, d3.max(data, function(d) { return d.close; })]);

    // Add the valueline path.
    lineSvg.append("path")
        .attr("class", "line")
        .attr("d", valueline(data));

    // Add the X Axis
    svg.append("g")
        .attr("class", "x axis")
        .attr("transform", "translate(0," + height + ")")
        .call(xAxis);

    // Add the Y Axis
    svg.append("g")
        .attr("class", "y axis")
        .call(yAxis);

   // append the x line
    focus.append("line")
        .attr("class", "x")
        .style("stroke", "blue")
        .style("stroke-dasharray", "3,3")
        .style("opacity", 0.5)
        .attr("y1", 0)
        .attr("y2", height);

    // append the y line
    focus.append("line")
        .attr("class", "y")
        .style("stroke", "blue")
        .style("stroke-dasharray", "3,3")
        .style("opacity", 0.5)
        .attr("x1", width)
        .attr("x2", width);

    // append the circle at the intersection
    focus.append("circle")
        .attr("class", "y")
        .style("fill", "none")
        .style("stroke", "blue")
        .attr("r", 4);

    // place the value at the intersection
    focus.append("text")
        .attr("class", "y1")
        .style("stroke", "white")
        .style("stroke-width", "3.5px")
        .style("opacity", 0.8)
        .attr("dx", 8)
        .attr("dy", "-.3em");
    focus.append("text")
        .attr("class", "y2")
        .attr("dx", 8)
        .attr("dy", "-.3em");

    // place the date at the intersection
    focus.append("text")
        .attr("class", "y3")
        .style("stroke", "white")
        .style("stroke-width", "3.5px")
        .style("opacity", 0.8)
        .attr("dx", 8)
        .attr("dy", "1em");
    focus.append("text")
        .attr("class", "y4")
        .attr("dx", 8)
        .attr("dy", "1em");
    
    // append the rectangle to capture mouse
    svg.append("rect")
        .attr("width", width)
        .attr("height", height)
        .style("fill", "none")
        .style("pointer-events", "all")
        .on("mouseover", function() { focus.style("display", null); })
        .on("mouseout", function() { focus.style("display", "none"); })
        .on("mousemove", mousemove);

    function mousemove() {
        var x0 = x.invert(d3.mouse(this)[0]),
            i = bisectDate(data, x0, 1),
            d0 = data[i - 1],
            d1 = data[i],
            d = x0 - d0.date > d1.date - x0 ? d1 : d0;

        focus.select("circle.y")
            .attr("transform",
                  "translate(" + x(d.date) + "," +
                                 y(d.close) + ")");

        focus.select("text.y1")
            .attr("transform",
                  "translate(" + x(d.date) + "," +
                                 y(d.close) + ")")
            .text(d.close);

        focus.select("text.y2")
            .attr("transform",
                  "translate(" + x(d.date) + "," +
                                 y(d.close) + ")")
            .text(d.close);

        focus.select("text.y3")
            .attr("transform",
                  "translate(" + x(d.date) + "," +
                                 y(d.close) + ")")
            .text(formatDate(d.date));

        focus.select("text.y4")
            .attr("transform",
                  "translate(" + x(d.date) + "," +
                                 y(d.close) + ")")
            .text(formatDate(d.date));

        focus.select(".x")
            .attr("transform",
                  "translate(" + x(d.date) + "," +
                                 y(d.close) + ")")
                       .attr("y2", height - y(d.close));

        focus.select(".y")
            .attr("transform",
                  "translate(" + width * -1 + "," +
                                 y(d.close) + ")")
                       .attr("x2", width + width);
    }
</script>
</body>

line is coming correctly but i m not able to set mouseover tooltip like above example.. I m facing error like invert fuction is not defined...

Upvotes: 0

Views: 882

Answers (1)

Cleared
Cleared

Reputation: 2580

In the chart you linked to, he is using a time-scale for the x-axis (which has an invert-function). You are using an ordinal-scale (which do not have an invert-function).The invert-function is used to calculate the value on the x-axis for a given mouse-position.

A time-scale always has a corresponding x-value for each mouse-position (since it is continous, so no matter where your mouse is, you have a date-time for that position) while an ordinal scale does not have a corresponding x-value for all mouse-positions since it is discrete, i.e. what is the x-value when you have the mouse in-beteen for example w1 and w2?

So your solution would be to change to a time-scale (in which case you have to convert w1,w2,w3 e.t.c. to a date-time object).

Or, if you want to stick with your ordinal-scale, you have to remove the invert function. Since the invert-function is used to calculate the x-value for a given mouse-position, you have to create this logic by your self. Inspiration can be found in Inversion with ordinal scale. So replace var x0 = x.invert(d3.mouse(this)[0]) with

    var xPos = d3.mouse(this)[0];
    console.log("hovering at " + xPos);
    var leftEdges = x.range();
    var width = x.rangeBand();
    var j;
    for(j=0; xPos > (leftEdges[j] + width); j++) {}
        //do nothing, just increment j until case fails
    console.log("Clicked on " + x.domain()[j]);
    var x0 = x.domain()[j];

Upvotes: 1

Related Questions