amCharts 5: CategoryAxis.height() after first datavalidated event - amcharts

Context
I am trying to replicate amCharts 4 Auto-adjusting chart height based on a number of data items with amCharts 5 instead.
Code pens with console logs:
amCharts 4: https://codepen.io/jackfoo/pen/XWeoNdW
amCharts 5: https://codepen.io/jackfoo/pen/MWEZKbX
The very first time the callback for the datavalidated event of a CategoryAxis is executed, CategoryAxis.height() returns a value that seems wrong. I don't know if the axis was actually rendered before the first datavalidated event. If it was not, then I guess it does not make sense to call CategoryAxis.height().
For information, the very first time the callback is executed, the property inited is false.
Question
The very first time the callback for the datavalidated event of a CategoryAxis is executed, what is CategoryAxis.height() supposed to return?

amCharts have updated their tutorial now for version 5.
amCharts 5: Auto-adjusting chart height based on a number of data items
Now the height is set using
chart.root.dom.style.height = chartHeight + "px";
Some points to note is
amCharts 5 uses "root element" approach - you create a root element,
then add actual chart or series objects to it.
...
amCharts 4 did not
have a root element, so chart instance was the top element in the
tree.
...
amCharts 5 uses Canvas API as its method of rendering, whereas
amCharts 4 used SVG.
~ AmCharts 4 and 5
The full code is in their codepen... now the datavalidated event is on the series.
var cellSize = 30;
series.events.on("datavalidated", function(ev) {
var series = ev.target;
var chart = series.chart;
var xAxis = chart.xAxes.getIndex(0);
// Calculate how we need to adjust chart height
var chartHeight = series.data.length * cellSize + xAxis.height() +
chart.get("paddingTop", 0) + chart.get("paddingBottom", 0);
// Set it on chart's container
chart.root.dom.style.height = chartHeight + "px";
});

Related

Label auto resizing for the bar charts dc.js

I have a bar chart with in dc.js. The x axis is dimension and y is the measure ranging from 1 - 10k. I want to show all the bars and their labels not overlapping each other. Chart looks fine when there are few bars when the number of bars starts to increase they look not okay. I am looking to auto resize the labels for the bar-chart.
Sample Chart
I tried this method of renderlet to change the fontsize automatically
stackedBarChart.on('renderlet', function(chart) {
chart.selectAll('text.barLabel')
.attr('transform', function(d) {
//How do i get/set the width of the label here ?
});
I tried the below and I am able to do dynamic label sizing. I used pretransistion and inside that fetched all bar lables and altered their font-size. The font sizing is altered according to Gordon's Idea, Getting each bar's size and and assigning the font size dynamically. For testing I have used .2 as a factor to reduce the font size.
.on('pretransition', function(chart) {
var chart_width = chart.width();
chart.selectAll("text.barLabel").attr('font-size', function(data) {
let total_bars = chart.group().all().length;
let sing_bar_width = Math.floor(chart_width / total_bars);
return (sing_bar_width * .2) + "px";
});
});

dc.js Can a Pie Legend be recentered after filtering

I would like to be able to recenter a Pie charts legend after it has been filtered. Slices/Legends will removed when filtering because we remove empty bins. I added a pretransition listener to chart2, but that seems to be to late because the legend y value is the previous value and not current.
.on('pretransition', chart => buildLegend (chart))
If Male is selected on the Gender Pie chart I want the 4 legend items on the Job Pie chart to be re-centered. Any suggestions?
You can see a jsFiddle example.
A little more digging around showed me how to reference and update SVG elements.
function recenterLegend(chart) {
chart.selectAll('g.dc-legend')
.attr('transform', function(d) {
let legendY = (300 - (chart.group().all().length * 16)) / 2;
let translate = 'translate(220,' + legendY + ')';
return translate ;
});
}
Here is the updated jsfiddle.

In AmCharts, how can I pull the visible coordinates of the categoryAxis based on the scrollbar?

I have a an AmChart, JavaScript chart, column chart with scroll.
I'd like to be able to pull the category axis data for the min and the max values that are currently being displayed in the chart.
Example:
If I have 0-10 on the x-axis and I zoom to 4-6, I want to be able to reference the data on point 4 and point 6.
I am new to AmCharts so hopefully I am just missing something simple but I can't seem to figure this out.
Here is a link to a chart I made:
https://live.amcharts.com/U4YmV/
You can use the zoomed event to capture the startIndex and endIndex from its event object.
In the example below, zoomedData is the zoom selection.
chart.addListener("zoomed", zoomed);
function zoomed (e) {
var chart = e.chart,
data = chart.dataProvider,
zoomedData = data.slice(e.startIndex, e.endIndex + 1);
}
Please check the example here: https://codepen.io/team/amcharts/pen/246e8f826610e848b7389fb85657348a

d3.js custom colors weird behavior - gradient problems

I have a question about the strange behavior of d3.js coloring. I want to create gradient in a pie chart and I used 2 solutions:
var data =
[1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1];
var length = 100;
var color = d3.scale.linear().domain([1,length])
.interpolate(d3.interpolateHcl)
.range([d3.rgb("#5C97C1"), d3.rgb('#FFC357')]);
// var color = d3.scale.ordinal()
// .domain(data)
// .range(
// ["#5C97C1", "#6199BE", "#639ABC", "#689CB9", "#6C9EB6", "#6F9FB4", "#73A1B1", "#78A3AD", "#7BA5AA", "#81A7A6",
// "#84A8A4", "#88AAA1", "#8BAC9F", "#8FAD9C", "#93AF99", "#97B196", "#9BB393", "#9FB491", "#A2B68E", "#A8B88A",
// "#ABBA88", "#AFBC85", "#B2BD82", "#B7BF7F", "#BAC07D", "#BFC379", "#C3C476", "#C7C674", "#CAC871", "#CEC96E",
// "#D3CB6B", "#D1CB6C", "#D7CD68", "#DBCF65", "#DDCE64", "#DECE64", "#DFCE63", "#E0CD63", "#E1CD62", "#E3CC62",
// "#E3CC61", "#E5CC61", "#E6CB60", "#E7CB60", "#E8CB5F", "#E9CA5F", "#EACA5F", "#EBCA5E", "#ECC95E", "#EEC95D",
// "#EFC85D", "#F0C85C", "#F1C85C", "#F2C75B", "#F3C75B", "#F4C75A", "#F5C65A", "#F6C65A", "#F8C559", "#F9C559",
// "#FAC558", "#FBC458", "#FCC457", "#FDC457", "#FEC356", "#FEC256", "#FDBF57", "#FBBC58", "#FAB959", "#F9B759",
// "#F8B45A", "#F6B05C", "#F5AD5C", "#F3AA5D", "#F2A85E", "#F0A55F", "#EFA260", "#ED9E61", "#EC9C61", "#EB9962",
// "#EA9763", "#E79264", "#E69065", "#E58D66", "#E48B66", "#E38867", "#E18568", "#DF8169", "#DE7E6A", "#DC7B6B",
// "#DD7C6B", "#DB796C", "#D9756D", "#D8736D", "#D7706E", "#D56D6F", "#D46B70", "#D36871", "#D06272", "#CF6173"]);
Or full version here http://codepen.io/Balzzac/pen/EZGwGy?editors=1000
And I get weird behavior in the first slice and the 50th of 100 in both cases. I want to understand why and how to fix it?
After a bit of digging, here's what I've found.
The issue is primarily to do with the fact that the call to pie(data) does not return data in order of ascending angle. This is not an issue when you want to have your bar chart ordered largest-smallest, but in your case this is causing problems.
You can see this for yourself when you call d3.layout.pie()(data) in the console - the values are almost sorted, but with a few exceptions.
In D3 v3.0, the solution is to call .sort(null) when setting up your pie chart:
var pie = d3.layout.pie().sort(null);
If you are using D3 v4.0 (which you should!), the solution is to call .sortValue(null):
var pie = d3.pie().sortValues(null);
As an aside, the relevant changes to convert to D3 4.0 are:
<script src="https://d3js.org/d3.v4.min.js"></script>
....
var color = d3.scaleLinear().domain([1,length])
.interpolate(d3.interpolateHcl)
.range([d3.rgb("#5C97C1"), d3.rgb('#FFC357')]);
var arc = d3.arc()
.outerRadius(radius)
.innerRadius(0);
var pie = d3.pie().sortValues(null);
....
In relation to the difference between browsers, I have a suspicion it is related to different sort implementations between browsers, but not 100% sure on this.

How to draw Yaxis label in highcharts

Is there any way to draw Yaxis lable using highcharts/highstock api? The value of the label will be the end value of the series. The color will be the same color of the series.
I found there is a renderer api, but is seems it is difficult to know the exact position of the point.
Here's an older example that uses the renderer function:
http://jsfiddle.net/jlbriggs/4FrGG/4/
function(chart){
$(chart.series).each(function(i, serie){
//to get the appropraite 'y' position
var point = serie.data[serie.data.length-1];
chart.renderer.text(
//the text to render
'<span style="font-weight:bold;color:' + serie.color + ';">' + serie.name + '</span>',
//the 'x' position
chart.plotLeft+chart.plotWidth+5,
//the 'y' position
chart.plotTop + point.plotY+3).add()
});
});
You could also do it by using data labels, enabled for only the last data point:
http://jsfiddle.net/jlbriggs/zXLZA/0/
You could also do it now by using the 'tickPositions' property, and then the formatter function on the axis labels
http://api.highcharts.com/highcharts#yAxis.tickPositions
http://api.highcharts.com/highcharts#yAxis.labels.formatter

Resources