How can I add an onmouseover event to a line? - c3.js

Using c3.js, I have a line graph with many lines. The tooltip properly appears at individual data points, and I can use the mouseover property to fire on data point hover.
I need to change the color of a line on the graph on mouseover at any position of the line. It appears as though lines are obscured from hover events by other shapes as I can't even get pain JS or CSS to fire events. Is there any way to get c3.js to fire an event when the mouse moves over and out of a line?

It's a default js function method calling:
onmouseover: function () { ... }

Related

How to prevent d3 brush events from firing after calling brush.move

I am displaying several identical charts (showing different datasets) side-by-side. Upon brushing on one chart, the brush should be replicated on all others.
Currently, I do this by calling brush.move on a selection of all charts excluding the currently brushed chart, as soon as someone brushes on a chart. This happens in a brush-type eventListener.
However, this brush.move triggers the brush-type event attached to the brush, leading to an error (or, more generally, an infinite loop).
How can I prevent this?
You can use the d3.event object to check what caused the update of the brush. From the API docs on brush events:
Brush Events
When a brush event listener is invoked, d3.event is set to the current brush event. The event object exposes several fields:
…
sourceEvent - the underlying input event, such as mousemove or touchmove.
If your brush is modified programtically, i.e. by calling brush.move(), the d3.event.sourceEvent property will be null, because no input event caused this update. In your event handler you can check this property to skip execution for programmatic changes:
if (!d3.event.sourceEvent) return;
The same technique is employed by Mike Bostock in his Brush Snapping Block. While handling the actual input event the brush is modified again to snap to the nearest value, which, obviously, should not trigger another run of the event handler.

Can not capture mouseover event while dragging on an svg

What I need is to highlight one circle when Im dragging an arrow over it.
While dragging this are the color of the circles:
circles now
What I need is stg like this:
Target Node highlighted
I tried with d3js mouseover event on the circle, but is not being fired while dragging, and also tried with css rule ( :hover) over the circle with the same results.
Any ideas?
Thanks
Check this out:
https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/pointer-events
If you set the pointer-events parameter of your element you drag to none, then the other elements you hover onto, will trigger the mouseover event.
And when you finish the drag, set the parameter to auto.

NVD3 Charts not rendering correctly in hidden tab

I am building a page which contains many charts, which are displayed one at a time depending on which tab you are looking at.
The chart in the initially active tab renders correctly. However when I click to another tab, the chart is not rendered properly.
Presumably this is because the hidden field does not have dimensions until it is made visible. In fact if I resize the window the chart will correct it's proportions, and render so that it fills the available width.
I can fix this problem by explicitly defining the chart size via css, but this defeats the responsive aspect of the charts.
Can anyone tell me how to trigger the same NVD3 event which gets activated when the window resizes? That way I can bind it to the selection of a new tab, and hopefully remedy the rendering issue.
I had the same issue (charts on multiple tabs), and this is the only thing that I could get to work.
$(function () {
$(document).on('shown.bs.tab', 'a[data-toggle="tab"]', function (e) {
window.dispatchEvent(new Event('resize'));
});
});
I have a feeling, however, that all of the charts are being re-rendered, regardless of whether they are on the active tab (visible) or in the non-selected tabs (hidden).
Does anyone know how to ensure ONLY the active chart gets resized / redrawn?
I figured out how to trigger the resize event I needed. In my case the tabs are driven by bootstrap. So I simply modified my bootstrap show tab event to trigger a page resize event as well. It's a little indirect, but it gets the job done:
jQuery('#myTab a').click(function (e) {
e.preventDefault()
jQuery(this).tab('show')
jQuery(window).trigger('resize'); // Added this line to force NVD3 to redraw the chart
})
Just add this JavaScript:
$('a[data-toggle="tab"]').on('shown.bs.tab', function (e) {
window.dispatchEvent(new Event('resize'));
})
hidden.bs.tab is the event that fires after a new tab is shown as per the Bootstrap docs. This code fires a resize event after each tab change.
Reason For New Answer
Vanilla Javascript is necessary for a lot of people in 2018. As a lot of frameworks and Javascript libraries that exist today do not play well with jQuery. Once upon a time answering all Javascript problems with a jQuery solution was acceptable but it is no longer feasible.
Problem
When loading C3.js or D3.js graphs, if the viewport is not actively in site during page load the graphs do not render correctly.
Example
If you type in the URL then open a new tab and then go back after your page loads.
If you refresh the page that has your graphs on it then minimize the browser and open it back up after the page has loaded.
If you refresh or go to the page with the graphs then swipe away to a new window on your computer. Then go back to the page with the graphs after they have loaded.
In all these cases your C3.js / D3.js graphs will not render correctly. Typically you will see a blank canvas. So if you were expecting a bar chart, you would see a canvas without the bars being drawn.
Background
Although I have seen this question answered I needed an answer that did NOT use jQuery. Now that we have reached the days of everything can not be fixed with jQuery I thought it seemed fit to provide a vanilla Javascript answer to this question.
My team faced the issue that the C3.js / D3.js graphs would not load if you refreshed the page and swiped away or minimized. Basically if you did not stay on the page and keep it in site till it was done loading you would not see the graphs till you resized the page again. I know this is a problem that happens to everyone using C3.js / D3.js but we are specifically using Lightning in Salesforce.
Answer
Our fix was to add this in the controller function that initializes the charts. Anyone can use this in any function they write to initialize their C3.js / D3.js graphs regardless of their stack. This is not Salesforce dependent but it does indeed work if you are facing this issue in Salesforce.
document.addEventListener('visibilitychange', () => {
console.log(document.visibilityState);
window.dispatchEvent(new Event('resize'));
});
I was facing same issue. I was using ng-show to make div hidden . Once I replaced ng-show with ng-if I am able to see graph drawn in expected behavior. Explanation:
When we use ng-show or ng-hide to make div hidden it only changes it display property but div will be in dom.
When we use ng-if div is removed from dom and again added to dom so internally it performs redraw operation on nvd3 graph too. Hence we see correct graph instead of squished one.
The event that usually triggers a redraw is the window resize event -- NVD3 doesn't use a custom event for this. You can control this yourself though; the usual definition is
nv.utils.windowResize(function() { d3.select('#chart svg').call(chart); });
(where "#chart" is the element that contains the graph). There's nothing stopping you triggering the code on another event or even just running the redraw code explicitly when you change the tab.
a more efficient approach would be to use the chart.update() method
var chart_x = nv.models.somechart()
var chart_y = nv.models.somechart()
..... show charts
jQuery('#myTab a').click(function (e) {
e.preventDefault()
jQuery(this).tab('show')
if(jQuery(this)...something === '..x..')
chart_x.update(); //CALL THE UPDATE
else ...
})

d3 pie chart with link in tooltip

I have a d3 pie chart that displays a tooltip on hover. I need to have a link in the tooltip box, but the box disappears once the cursor leaves the pie chart. How can i modify the mouseover/mouseout function to stay open when the cursor is inside?
.on('mouseover', function (d) {
$("#tooltip")
.html(d.data.label)
.stop(true).fadeTo(800, 1);
})
.on('mouseout', function (d) {
$("#tooltip").fadeOut(900, 0);
});
here is my fiddle
That's tricky. Normally, you just set pointer-events:none; on the tooltip in CSS, so that it doesn't block the mouse events from getting to the element below. But if you do that, then your link won't work!
I'm assuming that your eventual intention is to have the tooltip display over top of or immediately adjacent to the pie chart. If so, this answer is relevant for getting your positioning right.
One option would be to the add mouseover/mouseout functions to the tooltip as well, so that a mouseover on the tooltip triggers it's own visibility, and mouseout starts the transitions for it to fade away -- but only if that mouse doesn't immediately trigger a mouseover fading it back in again!
I'm not an expert on JQuery, but if their transitions work the same as D3 transitions, then the "fade in" transition as you move from SVG to tooltip should cancel out the just-started "fade out" transition so the user doesn't notice. Just make sure the transition or delay on the fade out is reasonably long for the user to move from one element to the other.
If you want the pop-up to be in the corner, I don't see how you can do that and also have it fade out after the mouse moves off the pie chart. Not without driving your users crazy, anyway.

Mouse events stop working after d3 graph, zoom loads

On my page, I have some events defined using Spine's controller events. They are assigned to selectors using jQuery's delegate, and they work fine:
events:
'click #zoom a': 'zoom'
'mouseenter #zoom a': -> $("#yZoom_help").show()
'mouseleave #zoom a': -> $("#yZoom_help").delay(1600).fadeOut 1600
Asynchronously at some point later in time, I set up some things with d3. Specifically, I am setting up zoom behavior on a canvas, a bunch of axes, etc.
#x_scale = d3.scale.linear()
.domain([#lcData.start, #lcData.end])
.range([0, #width])
#y_scale = d3.scale.linear()
.domain([#lcData.ymin, #lcData.ymax])
.range([#h_graph, 0])
#zoom_graph = d3.behavior.zoom()
.x(#x_scale)
.scaleExtent([1, #max_zoom])
.on("zoom", #graph_zoom)
#canvas = d3.select("#graph_canvas")
.attr("width", #width)
.attr("height", #h_graph)
.call(#zoom_graph)
.node().getContext("2d")
# ... some other things left out
The problem is that after I go through this d3 setup stuff, the mouse events on the non-d3 elements stop working. They just don't work at all. The elements have the highest z-index and are not obscured by any canvas or svg elements, but they stop detecting any mouse events.
d3 should only be activating mouse events on the canvas, right? Is there some d3 magic going on that is taking over the mouse on the entire page? For example, d3 inserts this div in the body:
EDIT: If you want to see what I mean, go to this link:
http://korhal.andrewmao.net:9294/#/sources/APH10154043
There is a little icon in the top left that changes color when you hover. This is the one with the mouse events; it is supposed to display a message. Once the page loads, it stops working. If you want to see it work, just reload the page and disable the JSONP call in your debugger, which prevents the function that sets up d3 from executing.
What happened here actually had nothing to do with d3. It seems that I was inadvertently calling #render twice during the loading of my Spine app, making all the elements get unbound from their events, when a view was appended.
Rebinding could be done with a call to #delegateEvents(#events) followed by #refreshElements, but in this case it was simply better to fix the superfluous #render call.
Related question with backbone: Why Backbone events on replacing html does not work?

Resources