I will like to override the style for charts in dc.js
I want to change, fonts, colors, font-weights, for axes, legends, and similar.
What is the best way to make this changes, without modifying the lib?
Styles/elements that are not driven by data
Anything that is not driven by data is best modified by using CSS. I usually just use the browser's inspector/developer tools to determine the correct selectors to use, but you can also get some clues by looking at the sass source for dc.css.
All of the visual attributes you list above fall in this category. Generally anything that is outside of the plot area is not data-driven.
Many of the visual attributes for things inside the chart are also not data-driven. For example, if you wanted to change the text labels inside the plot area, those styles all come from dc.css and are best modified with CSS.
Styles/elements that are driven by data
For changing anything that is data-driven, using a pretransition hook is going to be the best way - this fires after a render or redraw when all elements have been added or removed (but before they transition from old values to new values).
The form for this is
chart.on('pretransition', function(chart) {
chart.select('something').attr(...);
});
where something is a selector like rect.bar - in-chart selectors are starting to be documented in the Wiki.
Related
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/
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.
I am planing use d3.js to display a network diagram. But while going through the documentation I am feeling we cannot customise the nodes using custom html template as it is SVG. am I correct?. But still my question is d3.js tells D3 helps you bring data to life using HTML, SVG and CSS, means html also used for rendering the networks. So can I use my custom html for nodes if it uses html to render?
Because I needed a network diagram that required some multiline text, it was much easier (and more supported by browsers) to use absolute-positioned DIV elements for the nodes, and then use a background SVG layer to draw the edges between them.
I haven't had a lot of luck getting foreign object to work properly across all browsers.
D3 does not constrain your rendering technology at all. You can certainly use SVG, HTML, or both. I'm not sure how you're planning to create your network diagram, but presumably it will be using SVG at the overall diagram level. (I can't think of a decent way to show connections in pure HTML.) If that is the case, you'll have to embed HTML within the overall SVG. That's possible, see here, and D3 fully supports it.
How can I apply slide methods of jQuery to a non-SVG DOM element in d3.js?
Is there something I can use out of the box?
No, there's nothing out of the box, but you can do this by simply animating the relevant dimensional attributes, e.g. slide down would be something like
d3.select("#element").attr("height", 0)
.transition().duration(500).attr("height", realheight);
Depending on what you want to animate, you might have to work with clip paths to hide part of the element as it is being slid in.
You can of course simply use the JQuery methods. There should be no problem with that unless you want to run D3 transitions on the same object at the same time.
I am using jQPlot to draw a pie chart.
How can I change the color of the text that appears on each pie slice? There does not appear to be an option to do this.
It is not really a good idea to modify the distributed jqplot CSS file, because that makes for poor maintainability (you have to re-apply your changes if you, or anyone else, ever upgrades).
Instead, I recommend overriding the CSS using CSS Specificity Rules (see the Star Wars Version).
For example, given
<div id='myChart'; style="width:400px;height:300px;background-color:#eedd33">
</div>
You could define a CSS rule
#myChart
{
color: Teal;
}
You don't want to modify the given CSS file as it will modify all uses of the library.
You don't want to create a CSS rule for the entire chart container, as it will also apply the color to any legend or other text that will inherit it.
Instead, just modify the class jqplot uses for its data labels: .jqplot-data-label
Use this:
$('.jqplot-data-label').css("color","white");
This way, only the data labels will change color. All other text such as legend labels will not be changed.
In the end I just modified the top-level jqplot css that affects all text (as I wanted it all the same colour anyway).