nvd3 + lineAndFocus + BrushExtent(access focus part that is clicked) - nvd3.js

I'm using the lineWithFocusChart.js model shown in the nvd3 examples shown here: http://nvd3.org/examples/lineWithFocus.html
I want to be able to get access to the values that the user selects in the brushExtent (slightly related see here) and then apply the focus to all other lineAndFocus charts.
I can do so for the line-chart part with this:
chart.lines.dispatch.on('elementClick.customNameSpace', function(e) {
console.log('click', e);
});
Is there something similar for the brushExtent?
EDIT1: I can control where it focuses using this code. Editing this example here
chart.brushExtent([10,20])
chart.update()
EDIT2: This is what I am looking for, now I just need to put it all together,(i.e. draw the graph,listen for changes, then draw the graph with the changes...)
chart.dispatch.on('brush.update', function(b) {
console.log(b.extent[0], b.extent[1]);
});

Just do:
chart.focus.dispatch.on('onBrush', function brushChanged(brushExtent) {
otherCharts.forEach((chart) => chart.brushExtent(brushExtent));
});
I used a similar approach in my lineWithFocusPlusSecondaryChart model.

Related

Unable to reset the focus ordinal bar chart

I am trying to reset after choosing some of the individual's bar.
index.html: (line no. 62)
<span>
reset
</span>
This seems not to work. I was able to reset all the graphs pie chart, line chart, etc but not this one.
Those two ordinal graphs are created in index.js like this:
var focus = new dc.barChart('#focus');
var range = new dc.barChart('#range');
https://blockbuilder.org/ninjakx/483fd69328694c6b6125bb43b9f7f8a7
Update:
It looks weird now Coz it's showing a single bar and all the bar have got invisible but I want them to be visible (in gray colour) but not clickable.
This example replaces the built-in filtering functionality of the bar chart with its own implementation of ordinal selection, because the chart has a linear scale.
The example uses a global variable focusFilter to store the current selection. We need to empty this out and we also need to update the dimension filter as the original filterAll would do, pulling that code out of the click handler:
focus.applyFilter = function() { // non-standard method
if(focusFilter.length)
this.dimension().filterFunction(function(k) {
return focusFilter.includes(k);
});
else this.dimension().filter(null);
};
focus.filterAll = function() {
focusFilter = [];
this.applyFilter();
};
This will also allow dc.filterAll() to work, for a "reset all" link.
Fork of your block.
For some reason, I could not get the original
reset
links to work at all in this block, so I replaced them with the equivalent D3 click handlers:
d3.select('#reset-focus').on('click', () => {
focus.filterAll();
dc.redrawAll();
})
d3.select('#reset-all').on('click', () => {
dc.filterAll();
dc.redrawAll();
})
I also updated the focus ordinal bar example. Note that automatic hiding/showing of the reset link doesn't work because the chart still has an irrelevant range filter inside of it.

How can I programatically clear the search fields in smart-table?

I'm using smart-table at the moment, and I have input text boxes up the top of each column and I am using st-search. The point of what I am making is something is selected from the table, and then the results in the table are changed.
I am trying to clear the search boxes when the row is clicked. At the moment other business logic is implemented on click, so it's at this point that I am looking to clear these text boxes.
I have tried to associate an ng-model to these text boxes, and to clear them when the row is clicked but the text boxes don't change. I have also googled this issue and I have only found solutions on how to make this work for when you click on a button (by a directive) to clear the predicates. I haven't been able to make these solutions work programatically however.
To resolve this I did the following:
Monkey-patched smarttable.js with the code in this github issue (https://github.com/lorenzofox3/Smart-Table/issues/164). For me this occured at around line 574.
// added from https://github.com/lorenzofox3/Smart-Table/issues/164
ng.module("smart-table").directive("stResetSearch",
function() {
return {
restrict: 'EA',
require: '^stTable',
link: function(scope, element, attrs, ctrl) {
return element.bind('click',
function() {
return scope.$apply(function() {
var tableState;
tableState = ctrl.tableState();
tableState.search.predicateObject = {};
tableState.pagination.start = 0;
return ctrl.pipe();
});
});
}
};
});
Added 'st-research-search' to the element that was calling the function in angularjs. For me, that was the "tr" element. Like below.
<tr ng-repeat="medicine in medicines" ng-click="medicationMatched(medicine)" ng-class="heatmapClass(medicine)" st-reset-search>
This worked fine. Unfortunately, I wasn't able to programatically clear the predicates from the code. But this works well enough for me.

How would you go about having a dc.js bar-chart not be clickable but be hoverable?

I have a top 10 chart that works (using a fake group) how all other bar-charts work with cross-filter. If I select one of the things on the top 10 chart it filters all the other charts which is not what I want to have happen. I just want the chart display the chart.title text (the hover-text) while disabling its ability to be clickable.
So far I've looked into dc.js itself to see if there was a configuration for the bar-chart to get what I need and I couldn't find anything.
I've tried using this
ng-click="stopClick($event)"
$scope.stopClick = function (event) {
event.preventDefault();
event.stopPropagation();
};
That didnt do anything to the chart.
I've tried using inline css for the chart
style="pointer-events: none;"
But that disables the hover-text completely.
Any help would be greatly appreciated.
Huh, you would expect .brushOn(false) to do this, but I guess it has no effect for bar charts with ordinal x scale.
Instead, you can disable the event handler manually:
chart.on('pretransition', function(chart) {
chart.selectAll('rect.bar').on('click', null);
});
I wasn't having luck with the chosen answer but Gordon's answer to a different question did work https://stackoverflow.com/a/50702979
chart.onClick = function() {}

dc.js - dynamically change valueAccessor of a stacked layer in a lineChart and redraw it

I am trying to realize a dashboard to display basic data.
I am actually completely stuck on an issue. Strangely enough, I couldn't find anything even similar to it online, so I don't have many leads on how to move forward.
I have mainly two charts:
a lineChart called "stackChart" that
displays consumption as a base layer with its valueAccessor function
dispalys production as a stacked layer with its value Accessor function
a barChart called "volumeChart" that is simply the rangeChart for the lineChart
I use radio buttons to select whether to aggregate the grouped data by sum or by average (using the same approach as this example) and then I just use:
stackChart.valueAccessor(/*function with new value (avg or sum)*/);
dc.redrawAll();
to refresh the base layer (consumption).
What I don't manage to do is to refresh the "stacked layer" by updating its valueAccessor! I can't find any way to access its valueAccessor (or, worst case, just completely remove the stacked layer and then add a new refreshed stacked layer using just ".stack(...)").
Here is the respective part of my code where the chart is built:
// Charts customization #js
stackChart
.renderArea(true)
.height(350)
.transitionDuration(1500)
.dimension(dateDim)
.group(powByTime, "Consumption")
// BASE LAYER valueAccessor HERE
.valueAccessor(function(d) { return d.value.conSum; })
.x(d3.time.scale().domain([minDate, maxDate]))
.xUnits(d3.time.days)
.elasticY(true)
.renderHorizontalGridLines(true)
.legend(dc.legend().x(80).y(0).itemHeight(13).gap(5))
.brushOn(false)
// STACKED LAYER HERE
.stack(powByTime, "Production", function(d) { return d.value.prodSum; })
.rangeChart(volumeChart)
.controlsUseVisibility(true)
;
And here is where I look for changes in the radio buttons and re-draw the layers:
// Listen for changes
d3.selectAll('#select-operation input')
.on('click', function() {
var aggrMode = this.value; // fetch "avg" or "sum" from buttons
// UPDATE BASE LAYER HERE:
stackChart.valueAccessor(function(d) { var sel = accessors[aggrMode]['consPow']; return d.value[sel]; });
// ???HOW TO UPDATE STACKED LAYER valueAccessor function???
//stackChart.stack.valueAccessor(function(d) { var sel = accessors[aggrMode]['prodPow']; return d.value[sel]; });
dc.redrawAll();
});
If you need more details on what I am trying to do and full code you can check here.
As a reference, here is what it looks like:
I don't really know dc.js, but it may be possible that you can't change an accessor once it's been set. Try writing a single function for your accessor that will return either the sum or the average, depending on the state of some variable that you can set.
#Ryan's solution will probably work fine (and may be a better design), but here's the lowdown on the dc.js API with respect to stacking, in case you need it.
As described in this issue the group and stack API is pretty weird. It grew organically, in a backward-compatible way, so both the stacks and the value accessors on top of the stacks sort of branch out in a beautiful fractal of... well, no it's pretty messy.
But the issue also suggests the solution for your problem. Since chart.group() resets the set of stacks, just go ahead and build them all from scratch in your event handler:
stackChart.group(powByTime, "Consumption") // this resets the stacks
.valueAccessor(function(d) { var sel = accessors[aggrMode]['consPow']; return d.value[sel]; })
.stack(powByTime, "Production", function(d) { var sel = accessors[aggrMode]['prodPow']; return d.value[sel]; });
Internally it's just emptying an array of layers/stacks and then populating it with some references.
This is quite efficient since dc.js doesn't store your data except where it is bound to the DOM elements. So it is the same amount of work to redraw using the old group and value accessor as it is to redraw using new ones.

Get id of dragged element in d3.js

I am probably having some kind of brain damage atm because something like this should be trivial.
I got a bunch of SVG circles rendered manually (via React). I am then attaching d3 drag behavior to all of them. The drag behavior is applied, and the drag function is being executed, but when I drag one of these circles I am not able to respond accordingly because I do not know which one of them was moved. Where can I get the ID of dragged element?
I have checked a few other questions and found just some crazy filter solution... that cannot be it.
I have also peeked at docs and found the subject property.. however that one is null everywhere I tried it.
My code:
componentWillUpdate() {
let nodes = d3.selectAll("circle");
const dragFn = (d,i) => {
d3.event.sourceEvent.stopPropagation();
this.props.onNodeDrag(I_NEED_AN_ID_HERE);
}
const dragBehavior = d3.behavior.drag();
dragBehavior.on('drag', dragFn);
dragBehavior.on('dragstart', () => {
d3.event.sourceEvent.stopPropagation();
});
nodes.call(dragBehavior);
}
I don't know what your "this" is inside the function but in plain js you can get any attribute of the html element with:
d3.select(this).attr("id"); //or class etc.
or if it's wrapped
d3.select(this).select("circle").attr("id");
Here's an example: http://jsfiddle.net/a2QpA/343/

Resources