D3 Brush Event Not Working Correctly - d3.js

In D3 I am working on customizing and adding to #Rengel's timeline (link shown in JS Fiddle.
I've successfully created a similar timeline based on tracks, and it also allows users to filter project data based on checkbox values. Each piece of data now has a tooltip, and there are letters from another dataset populating underneath the projects in the same svg container. Now finally I want to add a brush like this one - wrobstory's from the blocks website.
I have only recently started to work on brush events so I am very much a noob, which is why I am unsure how I am going wrong. There is a JS Fiddle I created at: https://jsfiddle.net/rootseire/2vq8028o/2/ which shows everything working before the brush gets called. When I select a section of the timeline, the brush appears, it calculates indexes and extent. But it changes the y state of the year and the year text then transitions down the page.
I have been trying to see why this is happening, but I think I need to step back from the code as it might be just that I am not referencing the correct element. Here is the code for when the mouse pointer drags over the interface:
vis.on('mousedown', function(){
brush_elm = vis.select(".brush").node();
new_click_event = new Event('mousedown');
new_click_event.pageX = d3.event.pageX;
new_click_event.clientX = d3.event.clientX;
new_click_event.pageY = d3.event.pageY;
new_click_event.clientY = d3.event.clientY;
brush_elm.dispatchEvent(new_click_event);
});
But I think it might have something to do with the .points selector. How can I make the brush target the x-axis, the project rectangles and the letters together?
Thanks in advance,
P

Related

How to remove a series from XYChartScrollbar in amCharts v4?

How can a series be removed from the XYChartScrollbar in amCharts v4?
It was added in much the same way as series are added to the chart:
chart.scrollbarX = new am4charts.XYChartScrollbar();
chart.scrollbarX.series.push(series);
Removing it seems to remove it from the List (chart.scrollbarX.series.length goes from 1 to 0) but it remains on the scrollbar display. I've also tried removeIndex, but no luck there either.
// removes from List, but still displayed
var scrollbarIndex = chart.scrollbarX.series.indexOf(series);
chart.scrollbarX.series.removeIndex(scrollbarIndex);
// same result, removed from List but still displayed
chart.scrollbarX.series.removeValue(series);
I have also tried calling invalidate() and even deepInvalidate() to try to get the scrollbar to refresh but no success.
An example pen is at https://codepen.io/anon/pen/OrQvbw?editors=0011. Clicking on a toggle button adds the series to the chart and scrollbar, but only removes it from the chart.
Removing a series from the scrollbar itself does not seem to remove the series from the scrollbar's chart which itself is a whole other chart with distinct series. Going to look into this more and get back to you.
In the meantime, we can piggy back off of the scrollbar's removeValue method via the series' List's "removed" event, to do the same thing on scrollbarChart. The scrollbarChart's series are all clones of the original chart's series, presuming a series only ever has 1 clone and that that clone is within scrollbarChart, this code seems to do the trick (removed.oldValue is the series we just removed from scrollbarX.series):
chart.scrollbarX.series.events.on("removed", function(removed){
chart.scrollbarX.scrollbarChart.series.removeValue(removed.oldValue.clones.getIndex(0));
});
Here's a fork of your demo with that addition:
https://codepen.io/team/amcharts/pen/1b623a1b4ddf6a198bc80bdf5f5e1514

dc.js animated selection along x-axis

I'd like to have dc.js chart which slides along a selection, e.g. in the Nasdaq example https://dc-js.github.io/dc.js/ you would select a sub-selection of time then click "animate" button and the selection filter would slide along the x-axis at a pre-determined step size.
I'm a bit lost as to where one would start...does anyone have any ideas?
Most of what you need to do is set the current filter on the relevant chart based on a timer, instead of based on user interaction.
I've copied the relevant parts of the Nasdaq example into a fiddle to illustrate this: https://jsfiddle.net/0zkbyyqu/9/
Once the charts are in place, the animation is just a matter of changing the filter based on a setInterval. For obscure reasons, we want to use the focus method of the moveChart, not the filter method, but it's essentially doing the same thing, with a little more code to reflect the changes in the range chart:
var beginYear = 1985;
window.setInterval(function() {
moveChart.focus([
new Date(beginYear, 0,0,0,0,0,0),
new Date(beginYear+3, 0,0,0,0,0,0)]);
if(++beginYear > 2009)
beginYear = 1985;
}, 1000);
(If you were using the filter method, you'd have to construct a dc.filters.RangedFilter, as detailed here: Initial Range selection in DC.js chart)
I have left off your idea about the initial selection of the range coming from the user, and just gone with a range of 3 years. This example just starts animating as soon as it is loaded. You can fetch the current filter using chart.filter(); the result will be a RangedFilter, which is an array of two dates. Hopefully it is clear how to add start/stop buttons to the animation.
A couple of things are tricky about this approach:
It's tricky using a chart with transitions when you also have a timer or streaming data. In this case, I had to reduce the transitionDuration to 500ms for it to make any sense, but the cause-and-effect is still a little confusing. Not sure what to do about this.
The area chart transitions are incorrect so you get some weird artifacts.

d3-tip on dc-js chart disappears upon filtering over 0-valued group

I have a number of graphs, for simplicity take this example on jsfiddle, where there is a brush-on graph, a bar chart keyed on time and a row chart keyed on some categories. In addition, I use the d3-tip library for the tooltips (in the link above a very simplified version of my tip).
In order to avoid the creation of a bar-row in a rowChart, I used the fake-group as outlined in the FAQ of dc-js (and here as well).
The fake group works well, not displaying the C category on the row chart.
However, if I brush on some months with 0 data, when I reset the filter (just click anywhere but the filtered region on the brushon chart), the d3-tip on the row chart disappears.
Notice the if the group is created without the fake-grouping-function, this problem does not arise.
Any explanation why this happens?
How to avoid this (without loosing the remove_empty_bins)?
Although you can use dc.js and d3.js interchangeably, and dc.js is intentionally a "leaky abstraction", some things will go better if you do them the idiomatic dc.js way.
I have two suggestions:
Apply your tooltips in response to dc.js events so that they will get reapplied when new graphical objects are created (or re-created).
Use chart.selectAll instead of d3.selectAll when modifying the charts.
Okay, #2 actually has no bearing on this question, but it does help scope the selects better so that it's harder for them to miss the chart or accidentally modify stuff elsewhere in the page.
Implementing #1 looks something like this:
month_chart.on('pretransition', function(chart) {
chart.selectAll('rect.bar').call(month_tip)
.on('mouseover', month_tip.show).on('mouseout', month_tip.hide);
});
loc_chart1.on('pretransition', function(chart) {
chart.selectAll('g.row').call(loc_tip)
.on('mouseover', loc_tip.show).on('mouseout', loc_tip.hide);
});
The pretransition event fires right after a render or redraw, so it's usually the best moment to manipulate dc's elements. Much better than just running the code globally. I like to set everything up, then call dc.renderAll(), then allow the renders and redraws to take care of themselves later on.
In particular, when those bars get added back in when remove_empty_bins stops removing them, these events will pick them up and re-tip them.
Fork of your fiddle: https://jsfiddle.net/gordonwoodhull/5feL3gko/4/

how to make chart column with drill down with D3 Js

Could some one please suggest how to do column-drilldown with D3 JS library,
below example is from Hightchart,
http://www.highcharts.com/demo/column-drilldown
A complete code example for this problem is probably quite extensive, so I'll mostly keep to how you would approach it and assume you know enough of D3 to turn the concept into code.
Lets assume you have the functionality for drawing a general bar chart.
Part of that functionality would priobably be things like
Setting up your svg element and containers
Setting up your scales (one for x and one for y)
Adding axes based on the scales you have created
Adding your bars to the svg container
4.1 Make sure you have your data set available as an array
4.2 Create an enter selection for the available data and append rectelements
4.3 Update attributes like x, y for all your available bar nodes
4.4 Remove any nodes on your exit selection
Voila you have a simple bar chart. Nothing new in that and you can have a look at the code details here -> https://bl.ocks.org/mbostock/3885304
Now in order to do the drill down:
In order to avoid lots of code repetition it probably makes sense to separate the above steps into functions. So for example a setup function that just creates your svg and containers as well as your scales.
Important about the setup function is that you do not need to rerun it on drill through.
Second you will want an update function. This contains steps 3+, which you will need to rerun in order to update your charts on drill through.
One addition here would be adding functionality for updating your scale domain in the beginning (as your data changes on drill through and you want to reflect that in your scales).
Now that you have those two functions all you really need to do is:
Add a click handler to your axis labels or your bars (click on bars might be easier for now). You cans use d3's .on() function for that.
In that event you will want to subset your data by the value of the clicked bar (or get a new data set for the bar value depending on how your data is structured) and then run the update function we created above with the new data.
It could look something like this:
d3.selectAll('.bar-nodes')
.on('click', function(d) {
var updatedData = updateData(d);
updateChart(updatedData);
});
If anything is unclear some more specific questions would be good.
Hope that helps.

Google Visualization - Annotated timeline legend

I have an annotated timeline chart that gets new data over ajax. It's working fine, new points come in and I redraw the graph. My graph has two lines, so there are two labels in the legend on top. For whatever stupid reason, every single time the graph is redrawn, the legend labels swap places! So it will say
• Foo 5.2 • Bar 3.6
And then I'll refresh (and there will be no new data, so the call to redraw is 100% identical to the previous one) and now it says
• Bar 3.6 • Foo 5.2
In the respective red and blue, of course. What on earth would possess the applet to do this? Is there any way I can control the order of legend labels? I couldn't find anything about it in the official documentation.
Try using google.visualization.DataTable. For example:
dataTable = new google.visualization.DataTable({cols:graphColumns, rows:graphRows});
chart = new google.visualization.AnnotatedTimeLine($('#chart_div')[0]);
chart.draw(dataTable)
I use it this way and don't have any problems with my legend values.

Resources