----------------------------------------------------------
My Favorite tooltip method for a line graph.
Purpose
Tooltips are a fabulous way to include an interactive element on a graph and a great mechanism for including additional, focused information to the user.
There are quite a number of different ways to implement tooltips (one of which you can find in the ‘Adding tooltips’ section of the ‘Assorted Tips and Tricks’ chapter of D3 Tips and Tricks) and I would be very hesitant about proclaiming any one better than another. However, the one we will work through here is my favorite when using a line graph as I think it brings a ‘fuzzier’ mechanism for deciding when a tooltip is highlighted (you don’t have to be over an object to get information on it) which I like.
I believe that the original example for this was shown by Mike Bostock here, but I first came across the technique in an example by ‘gniemetz’. I liked ‘gniemetz’s example enough to adapt a similar example which I will explain below.
The idea with this technique is to set an area the size of the graph that will be used to determine when a tooltip will be displayed. So that when the mouse enters that area, the
display
style that allows elements to be shown or hidden. This then tells the script to show the tooltip and the location of the mouse determines which point will have the tooltip. In the example below we can see that the mouse cursor is some distance away from the point that is being highlighted, but it is in line (in the vertical axis) with the highlighted point (in fact we will use some clever maths to determine which date point (or point on the x axis) is the one that will be used to generate the tooltip.More complicated favorite tooltip example |
To begin this explanation we’ll start with a simple example that will just project a circle on the point where the tooltip will appear. Once we’ve worked out how that works we can add whatever we want and I will explain what is going on in the more complex example.
As mentioned, we will start with a simple example that adds a circle on the point where we will place our tooltip. It will look a bit like this;
Simple version of the favorite tooltip example |
The Code
The full code for this simple example is available online at bl.ocks.org or GitHub. It is also available as the files ‘best-tooltip-simple.html’ and ‘atad.csv’ as a download with the book D3 Tips and Tricks (in a zip file) when you download the book from Leanpub.
I have placed commented out asterisks besides the lines that have been added or altered from the simple graph example that we started out with at the beginning of the book so that it’s easy to see what has changed.
<!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
;
bisectDate
=
d3
.
bisector
(
function
(
d
)
{
return
d
.
date
;
}).
left
;
// **
// Set the ranges
var
x
=
d3
.
time
.
scale
().
range
([
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
()
.
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
d3
.
csv
(
"atad.csv"
,
function
(
error
,
data
)
{
// **********
data
.
forEach
(
function
(
d
)
{
d
.
date
=
parseDate
(
d
.
date
);
d
.
close
=
+
d
.
close
;
});
// Scale the range of the data
x
.
domain
(
d3
.
extent
(
data
,
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 circle at the intersection // **********
focus
.
append
(
"circle"
)
// **********
.
attr
(
"class"
,
"y"
)
// **********
.
style
(
"fill"
,
"none"
)
// **********
.
style
(
"stroke"
,
"blue"
)
// **********
.
attr
(
"r"
,
4
);
// **********
// 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
)
+
")"
);
// **********
}
// **********
});
</script>
</body>
Description
You should be able to tell from the asterisks in the code above that there aren’t too many changes and appart from a few at the start and middle, the majority are contained in a large block towards the end.
Starting with our first change
bisectDate
=
d3
.
bisector
(
function
(
d
)
{
return
d
.
date
;
}).
left
;
This is our function that will be called later in the code that returns a value in our array of data that corresponds to the horizontal position of the mouse pointer. Specifically it returns the date that falls to the left of the mouse cursor.
The
d3.bisector
is an ‘array method’ that can use an accessor or comparator function to divide an array of objects. In this case our array of date values. In the code I have used the d3.bisector
as an accessor, because I believe that it’s simpler to do so for the point of explanation, but the downside is that I had to have my dates ordered in ascending order which is why I load a slightly different csv file later (atad.csv
).
If your eyes glazed over slightly reading the previous paragraph, don’t let that put you off. Like with so many things, just relax and let d3.js do the magic and remember that
d3.bisector
can find a value in an ordered array.
The next block of changes declares a couple of functions that we will use to add our elements to our graph;
var
lineSvg
=
svg
.
append
(
"g"
);
var
focus
=
svg
.
append
(
"g"
)
.
style
(
"display"
,
"none"
);
We will use
lineSvg
to add our line for the line graph and focus
will add our tooltip elements. it is possible to avoid using lineSvg, but this way of declaring the functions means that we can control which elements are on top of which on the screen. For instance, it would be a pretty sad affair if our tooltip was appearing under the line of the line graph (hard to read).
As we saw earlier, our data is being sourced from a different csv file (
atad.csv
).d3
.
csv
(
"atad.csv"
,
function
(
error
,
data
)
{
This is because we need to have it in a compatible order (ascending) to allow our bisector function to operate correctly. So while the line may look the same as the simple graph version, the data is ordered in reverse (some may say that this is the way the original data should have been presented all along, but I suppose we can’t always second guess the data we get).
We then make a small change to the script that appended the line to the graph and instead of using
svg.append
… we use our newly declared lineSvg
. lineSvg
.
append
(
"path"
)
.
attr
(
"class"
,
"line"
)
.
attr
(
"d"
,
valueline
(
data
));
The final, larger block of code can be broken into 4 logical sections;
- Adding the circle to the graph
- Set the area that we use to capture our mouse movements
- The clever maths that determines which date will be highlighted
- Move the circle to the appropriate position
The last two points actually occur within a separate function, but for the purposes of explanation I’m happy that this is a logical division of labour for the script.
|
ADDING THE CIRCLE TO THE GRAPH
Adding the circle to the graph is actually fairly simple;
focus
.
append
(
"circle"
)
.
attr
(
"class"
,
"y"
)
.
style
(
"fill"
,
"none"
)
.
style
(
"stroke"
,
"blue"
)
.
attr
(
"r"
,
4
);
If you’ve followed any of the other examples in D3 Tips and Tricks there shouldn’t be any surprises here (well, perhaps assigning a class to the circle (
y
) could count as mildly unusual).
Except for one small thing….
We don’t place it anywhere on the graph! There is no x y coordinates and no translation of position. Nothing! Never fear. All we want to do at this stage is to create the element. In a few blocks of code time we will move the circle.
SET THE AREA TO CAPTURE THE MOUSE MOVEMENTS
As we briefly covered earlier, the thing that makes this particular tooltip technique different is that we don’t hover over an element to highlight the tooltip. Instead we move the mouse into an area which is relevant to the tooltip and it appears.
And its all thanks to the following code;
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
);
Here we’re adding a rectangle to the graph (
svg.append("rect")
) with the same height and width as our graph area (.attr("width", width)
and .attr("height", height)
) and we’re making sure that there’s no colour (fill) in it (.style("fill", "none")
). Nothing too weird about all that.
Then we make sure that if any mouse events occur within the area that we capture them (
.style("pointer-events", "all")
). This is when things start to get interesting.
The first pointer event that we want to work with is
mouseover
; .
on
(
"mouseover"
,
function
()
{
focus
.
style
(
"display"
,
null
);
})
This line of code tells the script that when the mouse moves over the area of the rectangle of the area of the graph the display properties of the
focus
elements (remember that we appended our circle to focus
earlier) are set to null
. This might sound like a bit of a strange thing to do, since what we want to do is to make sure that when the mouse moves over the graph we want the focus
elements to be displayed. but by setting the display
style to null
the default value for display
is enacted and this is inline
which allows the elements to be rendered as normal. So why not use inline
instead of null
? Good question. I’ve tried it and it works without problem, but the original example that Mike Bostock used had the setting at null
and I’ll make the assumption that Mike knows something that I don’t know about when to use null
and when to use inline
for a display style (maybe some browser incompatibility issues?).
The reverse of making our
focus
element display display everything is being able to make it stop displaying everything. This is what happens in the next line; .
on
(
"mouseout"
,
function
()
{
focus
.
style
(
"display"
,
"none"
);
})
Here, where the mouse moves off the area, the display properties for the
focus
element are turned off.
Lastly for this block, we need to capture the actions of the mouse as it moves on the graph area and move our tooltips as required. This is accomplished with the final line in the block…
.
on
(
"mousemove"
,
mousemove
);
… where if the mouse moves we call the
mousemove
function.DETERMINING WHICH DATE WILL BE HIGHLIGHTED
Once the
mousemove
function is called is carries out the last two steps in our code. The first of which is the clever maths that determines which point in our graph has the tooltip applied to it. 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
;
The first line of this block is a dozy;
var
x0
=
x
.
invert
(
d3
.
mouse
(
this
)[
0
]),
If we break it down the
d3.mouse(this)[0]
portion returns the x position on the screen of the mouse (d3.mouse(this)[1]
would return the y position). Then the x.invert
function is reversing the process that we use to map the domain (date) to range (position on screen). So it takes the position on the screen and converts it into an equivalent date!
for the adventurous amongst you, throw a
console.log(x0); line into the mousemove function and check out the changing date/time as the cursor moves pixel by pixel (This will work for Google Chrome). Very cool. |
Then we use our
bisectDate
function that we declared earlier to find the index of our data
array that is close to the mouse cursor. i
=
bisectDate
(
data
,
x0
,
1
),
It takes our data array and the date corresponding to the position of or mouse cursor and returns the index number of the data array which has a date that is higher than the cursor position.
Then we declare arrays that are subsets of our data array;
d0
=
data
[
i
-
1
],
d1
=
data
[
i
],
d0
is the combination of date
and close
that is in the data array at the index to the left of the cursor and d1
is the combination of date
and close
that is in the data array at the index to the right of the cursor. In other words we now have two variables that know the value and date above and below the date that corresponds to the position of the cursor.
The final line in this segment declares a new array
d
that is represents the date
and close
combination that is closest to the cursor. d
=
x0
-
d0
.
date
>
d1
.
date
-
x0
?
d1
:
d0
;
It is using the magic JavaScript short hand for an
if
statement that is essentially saying if the distance between the mouse cursor and the date
and close
combination on the left is greater than the distance between the mouse cursor and the date
and close
combination on the right then d
is an array of the date
and close
on the right of the cursor (d1
). Otherwise d
is an array of the date
and close
on the left of the cursor (d0
).
This could be regarded as a fairly complicated little piece of code, but if you take the time to understand it, you will be surprised how elegant it appears. As we’ve seen before though, if you just want to believe that the d3.js magic is happening, that’s fine.
MOVE THE CIRCLE TO THE APPROPRIATE POSITION
The final block of code that we’ll check out takes the closest
date
/ close
combination that we’ve just worked out and moves the circle to that position; focus
.
select
(
"circle.y"
)
.
attr
(
"transform"
,
"translate("
+
x
(
d
.
date
)
+
","
+
y
(
d
.
close
)
+
")"
);
This is a pretty easy bit of code to follow. We select the circle (using the class
y
that we assigned to it earlier) and then move it using translate
to the date
/ close
position that we had just worked out was the closest.
Of course this is provision of the coordinates to the circle that we noticed was missing earlier in the code when we were appending it to the graph.
And there we have it. A simple circle positioned at the closest point to the mouse cursor when the cursor hovers over the graph.
Simple version of the favorite tooltip example |
If we hadn’t mentioned it earlier you might be thinking that this could possibly be the most complicated method for making most basic (read lame) tooltip ever. But you know there’s more right? Right….? Read on.
Complex version
You’ve read to this point, so that’s a sign that you’re still interested. In that case, I recommend that you take a moment to check out the live example of the graph that I’m going to describe.
More complicated favorite tooltip example |
Here’s a graph that when you move your mouse over it shows the closest intersection point on the graph with lines that extend the full width of the graph (great for comparing the level across the graph) and down to the x axis (to get a rough feel for the date). As well as this there is a subtle circle around the data point in question (as already explained in the previous section) and the actual date and value represented at the intersection point. As if that wasn’t enough there is a nice little drop shadow effect under the text so that no matter what the background is you can read it. Nice.
The full code for this example is available online at bl.ocks.org or GitHub. It is also available as the files ‘best-tooltip-coolio.html’ and ‘atad.csv’ as a download with the book D3 Tips and Tricks (in a zip file) when you download the book from Leanpub.
CODE / EXPLANATION
Because the date at the tooltip needs to be formatted in a particular way we need to declare this appropriately;
formatDate
=
d3
.
time
.
format
(
"%d-%b"
),
Other than that everything is pretty normal until we get to the part where we start adding elements to our
focus
group (you remember we had the circle before? Now we’re adding additional elements.). // 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"
);
Here you can see we’re adding the x (horizontal) line and the y (vertical) line as well as the date and text values. Notice on the text values, there is a white drop shadow added first and then the text over the top. Another thing to note is that just like the position information, we don’t actually put the text in here, this is simple a ‘placeholder’ for the element.
Then all we need to do is move all the new elements to the correct position and add the changing text where appropriate;
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
);
There’s no big surprises here. Just an extension of what we accomplished with the circle earlier. The only part that looks semi-interesting is some of the application of the positioning of the x and y lines and this is more because of the points at which the lines start and finish.
Now this is unlikely to be the end solution for most people, but at least there are plenty of examples of different elements in there to play with and experiment on.
Enjoy!
The description above (and heaps of other stuff) is in the D3 Tips and Tricks book that can be downloaded for free (or donate if you really want to :-)).
If you look at Mike's first example that you linked to you'll see that he only applies the translation to the overall focus element.
ReplyDeleteFor your complex mouse over example this reduces the amount of code you need to write as you add extra sub-elements to the focus element, which means less bugs :)
It does mean that the co-ordinates for all the sub-elements are relative to the focus element position.
Fantastic. Thanks for that. So much to learn :-).
DeleteHow to change date and month to only integer value?
ReplyDeleteSorry for the late reply. In the more complex version, the 'formatDate' declaration formats the date to show the day of the month (as an integer) and the shortened name of the month. To convert this to an integer for the month, all we need to do is to change the '%b' (abbreviated month name) for '%m' (month as a decimal number [01,12]).
DeleteIn your example the tooltip is appearing on top of the line. I followed the example and my tooltip is behind the line even though I am appending it after the line in the code.
ReplyDeleteSorry for the really late reply. That is extremely odd. I'm note entirely sure why it would be doing this, but you could stand up an example on bl.ocks.org for demonstration purposes which might make resolving the issue easier. Conversly, I think that it might be possible if the data set you are producing is significant. In which case a queue might be in order (that is a pretty random guess, but it might be the cause) https://gist.github.com/mbostock/1696080
DeleteHiya. Thank you so much for this site. It has become an invaluable tool in trying to get my head around d3. Quick question on this tooltip method and apologies if its me showing my inexperience but how would you go about updating the tooltips if the underlying data changes. I can't seem to work it out at all. Any help would be much appreciated. Thank you again for the amazingly helpful site
ReplyDeleteApologies for the really late reply. It's not you or the question. It's just that I neglect lagge blocks of questions for long periods of time and then only return to them when shame eventually kicks in :-(. Anywho... You're actually asking a question to which the answer is slightly complex. The main component to this is the dynamic changing of the data that makes up the page. to do this you will need to connect the page to the data source via a socket (http://stackoverflow.com/questions/12764813/producing-a-live-graph-with-d3) or via a regularly refreshing data set (using an update pattern (https://bl.ocks.org/mbostock/3808218) and once you have that in place, if you have your tool tip set up the data in the tool tips should update automatically.
DeleteThanks a lot for a very comprehensive guide, learned a lot reading this.
ReplyDeletenice
ReplyDeleteExcellent! I search it for a while.
ReplyDeleteI don't know how to give to keyword to search the feature of the complex version (dot-line).
Does it have any name or somebody could give it a name?
Anyway, thanks for this tutorial!
I don't know either. If you like we could call it the Hsiao effect?
DeleteAwesome tutorial again sir. I left a comment on the Update viz with button click, but this tutorial is related to that question. I'm curious on how you implement this tooltip along with the update chart example found here: http://www.d3noob.org/2013/02/update-d3js-data-dynamically-button.html
ReplyDeleteYou should be able to start with this example and add the button from the other example in. I think that they have enough common code in them to be fairly interchangeable. If it doesn't work, keep experimenting by starting with the simplest example that you have that does work and then keep adding parts and experimenting as you go.
DeleteHow would the code be for multi-line chart?
ReplyDeleteGood news, this method was developed from a multi-line example here http://bl.ocks.org/gniemetz/4618602
DeleteThanks a ton!!
DeleteHey.....if we want to have ordinal scale on x-axis then it says that x.invert() is not a function...could you please help?
ReplyDeleteCrikey. That's a tricky one. obviously the function of converting the position of the cursor to a date is (as I mentioned above) a 'doozy'. I suspect that your problem might be coming about in your equivalent of the 'bisectDate' part. You are sailing into waters that I have not seen before, so you are going to be discovering new issues that I won't have an answer to I'm afraid. All I can do is wish you luck and give the advice to make small changes often and test each one to learn. Good luck
DeleteHey....is there any way we can fix hoverline to last value when the graph page opens?
ReplyDeleteHmm.... Interesting question. I don't think it could be done easily with the current code. Mainly because it relies on the mouse position to set the hover line. Hmm... On second thought you could have the last value as the default value that would be displayed if the mouse *wasn't* hovered over the graph. This would be a bit ugly when the mouse exited on the opposite side IMHO, so it would be better to have a default starting position that immediately updates as soon as the mouse comes into the frame. Doing that would be a block of work that I would be loathe to start myself, so I would have to leave it to you I'm afraid :-).
Deletemulti-line example here http://bl.ocks.org/gniemetz/4618602 is not displayed
ReplyDeleteYou are correct. It looks like the page is refusing to load the 'data.txt' file associated with the html file because it associates the call with a cross origin request (this does seem weird). The script still works (and would work in the block) if the 'd3.csv' call is made directly to 'data.txt' instead of 'https://gist.githubusercontent.com/gniemetz/4618602/raw/74eee5aff836de54d83715336b3bfd76dd8fb579/data.txt'.
DeleteHi I'm trying to incorporate your tooltip code into the "d3.js Multi-series line chart interactive" (http://bl.ocks.org/DStruths/9c042e3a6b66048b5bd4 code). Can anyone provide some insight on how to achieve that.
ReplyDeleteThanks!
Wow. That is a great bl.ock. I've never seen that one before. While I can't provide an answer, What I reccomend is to reduce the example down to its simplest core and try adding the required code from there. If it still eludes you ask a question on StackOverflow. Best of luck.
Delete