ChartJS Data Labels - chart.js

I am using the chartjs-plugin-datalabels library to help configure my datalabels in a chartjs.
The problem is the data labels keep overlapping on a simple line chart where the values between the two data sets for a given X axis are close.
Is there anyway to use the align function to dynamically change whether the data label is on the top or bottom?
Psedocode
if datasetOne of a given X axis item is > datasetTwo of a given X axis item then make the datalabel for dataSetOne[X] === Top else make it bottom
if datasetTwo of a given X axis item is > datasetOne of a given X axis item then make the datalabel for dataSetTwo[X] === Bottom else make it top
Currently I was doing something like this. But the overlapping issue happens again if my second dataset index has lower values than the first data set
align: function ( context: Context) {
if (context.datasetIndex === 0) {
return 'top';
} else {
return 'bottom';
}
}

Related

Rendering n number of grid items based in the dynamic column size

I have a slider that ranges from 1 and up to 3. The slider's on change event sets the value of a CSS variable (e.g. :root { --colNum: 1 } ) so I am able to dynamically change the number of grid columns.
What I am trying to achieve is (let's say I have six images in total):
When I have one column set, I would like to display only the first image, full size and hide the five remaining images.
When I have two columns set, I would like to display the first four images, two in each row and hide the two remaining images.
When I have three columns set, I would like to display all the six images, three per row.
Similar to the following images:
1 column and 1 image (1 row)
2 columns and 4 images (2 rows)
3 columns and 6 images (2 rows)
I have created a sandbox, tried different examples but none of them fit my needs so I have left it in an "initial state".
I am not sure if I am overthinking that but I am open to hear any suggestions or even other approaches in how I could achieve that result.
Thanks in advance.
I have finally achieved what I wanted. Maybe it can help someone else facing similar case as mine.
The solution is going to be in the same sandbox and I will be improving that to completely fit my needs.
Solution
In short, as I previously mentioned I have the CSS var (--colNum) changing its value dynamically based in the slider value.
I have filtered the items from the images array to conditionally render or not the images based in the colNum and image index values.
If I have a condition which renders the images I pass down a style props containing the height and width of the images and in cases it should not render I just return null.
Probably not the best approach but still.
const imagesByColumn = images.map((image, index) => {
// One Image One Column
if (colNum === '1') {
if (index === 0) {
const style = { width: '300px', height: '200px' };
return <Image key={index} url={image.url} style={style} />;
} else {
return null;
}
}
// Two Columns 4 Images
if (colNum === '2') {
if (index >= 0 && index < 4) {
const style = { width: '170px', height: '120px' };
return <Image key={index} url={image.url} style={style} />;
} else {
return null;
}
}
// 3 Columns 6 Images
if (colNum === '3') {
const style = { width: '150px', height: '100px' };
return <Image key={index} url={image.url} style={style} />;
}
return null;
});

How to align ticks label in chartJS 3.x?

is possible with chartJS chenge the align position of tick labels for scaleY and for scaleX?
In the image attached i want 300,150,60, 0 on top of the grid line and 9:56 aligned on the right of the first tick.
I try to modify the code in this answer, but without success.
After some research i adapted the method showned here to works with ChartJS 3.x:
plugins: [{
afterDraw: function (c) {
var yScale = c.scales['y'];
yScale.ticks.forEach(function (o, i) {
// top tick label indent
var yT_O = yScale.getPixelForTick(i) - 9;
// left tick label indent
var xT_O = c.width - 35;
c.ctx.fillStyle = "#707070"
c.ctx.fillText(o.label, xT_O, yT_O);
});
}
}]
Actually i'm not sure this is the best plugin event where do that.
I also had to put "display: false" on the ticks options in order to hide the originals tick labels.

How can create a graphic without any bars with Amchart4

we are using amchart with a project and we need to remove all bars and zoom/resize action
Our final idea is to have exactly the same chart as this
https://mdbootstrap.com/docs/angular/advanced/charts/
with just right-click to save chart as image
is this possible?
I tried to set those variables
chart.seriesContainer.draggable = false;
chart.seriesContainer.resizable = false;
Lets say if you have two axes x and y as below, its is possible to disable the grid for each axis like below
let dateXAxis = chart.xAxes.push(new am4charts.DateAxis());
let valueYAxis = chart.yAxes.push(new am4charts.ValueAxis());
dateXAxis.renderer.grid.template.disabled = true;
valueYAxis.renderer.grid.template.disabled = true;

Draw a pie chart in MFC TeeChart

My English is no very good, so please forgive me. I have added my data successfully in a pie chart, but the pie chart doesn't show with only data shown in the control.
The properties of the control seem like have been configured appropriately. I don't know where is the problem since I have spent whole my night on it.
BOOL CStatInfPieDlg::OnInitDialog()
{
CDialogEx::OnInitDialog();
char temp1[100];
char temp2[100];
CString str;
// TODO: Add extra initialization here
CSeries series = (CSeries)statInfPie.Series(0);
int size = stationInfList.size();
series.put_ColorEachPoint(true);
srand(time(NULL));
for (int i = 0; i < size; i++) {
sprintf(temp1, "%s/%d ", iptostr(stationInfList[i].netaddrA), toCidr(stationInfList[i].netmaskA));
sprintf(temp2, "%s/%d", iptostr(stationInfList[i].netaddrB), toCidr(stationInfList[i].netmaskB));
strcat(temp1, temp2);
str = CString(temp1);
series.Add(stationInfList[i].bcountAToB + stationInfList[i].bcountBToA, str, RGB(rand() % 255, rand() % 255, rand() % 255));
memcpy(temp1, "\0", sizeof(temp1));
memcpy(temp2, "\0", sizeof(temp2));
}
return TRUE; // return TRUE unless you set the focus to a control
// EXCEPTION: OCX Property Pages should return FALSE
}
The code sample above initializes my dialog which contains the TeeChart control. I add data through function Add(). Array temp1 and array temp2 is my description inf. After I compile and run my program, the result shows in the picture blow.
TeeChart tries to make space for the long labels and the Legend, automatically reducing the diameter of the Pie. In this case the result is extreme; the Pie is left with no radius.
That can be resolved in one of several ways:
The latest version of TeeChart (AX) includes a property called InsideSlice for PieMarks.
ie.TChart1.Series(0).asPie.PieMarks.InsideSlice = True
For older versions of TeeChart, where this property is not available you can manually set the Arrowlength (the connector to the Mark) to a negative value:
ie. TChart1.Series(0).Marks.ArrowLength = -20
The Series Marks can be setup to render multiline, taking up less width:
ie. TChart1.Series(0).Marks.MultiLine = True
If the Legend is in the Chart with very long labels that can also be counter productive to chart readability. The Legend can be set to Visible false or told to not resize the Chart Series (the Pie) to fit.
ie. TChart1.Legend.ResizeChart = False
or can be positioned below the Pie
ie. TChart1.Legend.Alignment = laBottom
A thought to design will be required here. Showing long Point Value labels (the Series Marks) and repeating some of the information in the Legend is taking up a great deal of the working space where the Chart could be shown. If the Legend were to be placed below the Chart and the Panel were sized accordingly and perhaps were to use information that doesn't duplicate the Series Marks' information (using a different Legend Text Style) plus setting up the Series Marks with Multiline, with a shorter Arrowlength, then the overall result should be very readable.

Chart.JS spacing and padding

Is it possible to get some more space between the chart and the x-axis?
Is it possible to get some more space between the right side of the chart and the end of the canvas area? I want to add some more elements to the canvas right beside the chart but this is not possible because the chart takes the whole canvas width so it would overlap.
Shifting x axis Labels Vertically
The easiest way to do 1. is by adding spaces to your x labels. You can extend your chart type and override your initialize function to do this (increase 30 to something larger if your labels are long to start with anyway)
initialize: function(data){
data.labels.forEach(function(item, index) {
data.labels[index] += Array(Math.max(30 - item.length, 0)).join(" ");
})
Chart.types.Bar.prototype.initialize.apply(this, arguments);
},
Edit : As pointed out in the comments, this causes a horizontal shift as well and the label ends no longer align with the x axis markers.
Since both the x axis and the x labels are drawn in a single function and you have no other variables you can mess around with (safely) this means you'll have to change the actual scale draw function.
Look for a ctx.translate towards the end of the draw function and change it to
ctx.translate(xPos, (isRotated) ? this.endPoint + 22 : this.endPoint + 18);
You'll also have to adjust the endpoint (which drives the y limits) a bit so that the additional y offset doesn't cause the labels to overflow the chart (look for the line adjusting this in the draw override for 2.).
Leaving a gap on the Right Side
To do 2, you override your draw function (in your extended chart) and change xScalePaddingRight. However since this doesn't affect your horizontal grid lines you have to overlay a filled rectangle once your draw is complete. Your complete draw function would look like this
draw: function(){
// this line is for 1.
if (!this.scale.done) {
this.scale.endPoint -= 20
// we should do this only once
this.scale.done = true;
}
var xScalePaddingRight = 120
this.scale.xScalePaddingRight = xScalePaddingRight
Chart.types.Bar.prototype.draw.apply(this, arguments);
this.chart.ctx.fillStyle="#FFF";
this.chart.ctx.fillRect(this.chart.canvas.width - xScalePaddingRight, 0, xScalePaddingRight, this.chart.canvas.height);
}
Original fiddle - https://jsfiddle.net/gvdmxc5t/
Fiddle with modified Scale draw function - https://jsfiddle.net/xgc6a77a/ (I turned off animation in this one so that the endpoint is shifted only once, but you could just hard code it, or add some extra code so that it's done only once)
The 'tickMarkLength' option extends the grid lines outside the chart and pushes the ticks down.
xAxes: [
{
gridLines: {
tickMarkLength: 15
},
}
]
use this for chartjs 2.0
scales: {
xAxes: [{
barPercentage: 0.9,
categoryPercentage: 0.55
}]
Reference
In chartjs v3, there is an "offset" flag that you can set to true. This will create padding.
scales: {
x: {
offset: true,
}
}
If true, extra space is added to the both edges and the axis is scaled to fit into the chart area. This is set to true for a bar chart by default.
Documentation