Sure there is a way to count all of points that shown after zooming or any changing view and do reaction for that.
My target is in Highchart 7.2.0 stockChart, IF "viewed points" x "radius of circles", gone more than (>) "view-port pixels", i just hide them, or doing something special with points, because some of them are Special and still should be shown.
so i need :
HOW GET : Count of points that JUST viewed now (WITHOUT PUTTING A "FOR" TO ALL OF DATA's)
(I just think if there is no true way for it, it is better to i count svg objects instead of : counting all of my data and using isInside with min and max)
The Best Events for : "afterSetExtremes" and "events:{redraw:" [Solved i think]
events: {
afterSetExtremes: function(event) {
console.log(event.min);
console.log(event.max);
}
}
How i turn them off [Solved i think]
if (chart.userOptions.plotOptions.line.marker.enabled) {
chart.userOptions.plotOptions.line.marker.enabled=false;
chart.update({
plotOptions: {
marker: {
enabled:false
}
}
});
}
If there is automatic way like "amchart" options that i just ask "marker: { enabled: true" (when no problem) and "marker: { enabled: false" when it is tight. [Solved i think]
Solved by this:
plotOptions: {
series: {
marker: {
enabled:undefined,
enabledThreshold: 4,
symbol: 'circle',
radius: 4,
},
}
}
It was like this :
marker: {enabled:true,
enabledThreshold: 0, (By Default)
Should be :
marker: {enabled:undefined,
enabledThreshold: 4, (More than Zero)
Got help from here : https://stackoverflow.com/a/54417034/7514010
The easiest way is to loop through the data and check isInside point property or point position. As an alternative you can overwrite translate method and count the number of visible points in the existing loop:
var counter;
(function(H) {
H.Series.prototype.translate = function() {
...
counter = 0;
// Translate each point
for (i = 0; i < dataLength; i++) {
...
point.isInside =
plotY !== undefined &&
plotY >= 0 &&
plotY <= yAxis.len && // #3519
plotX >= 0 &&
plotX <= xAxis.len;
// CHANGE
if (point.isInside) {
counter++;
}
// CHANGE
...
}
series.closestPointRangePx = closestPointRangePx;
H.fireEvent(this, 'afterTranslate');
}
})(Highcharts)
Live demo: http://jsfiddle.net/BlackLabel/yx1cj0at/
Docs: https://www.highcharts.com/docs/extending-highcharts
It answered by #ppotaczek here in the third comment by this link jsfiddle.net/BlackLabel/j1tLfaxu and also in GitHub issues : https://github.com/highcharts/highcharts/issues/12017
If need to get count of points that just viewed now (by using afterSetExtremes or redraw or render events) :
chart: {
events: {
render: function() {
console.log(this.series[0].points.length)
}
}
},
processedXData can be used too instead of points
points object have enough options like isInside :
this.series[0].points[0].isInsdie.
Because it is possible the first or last point be not shown and just affect the lines in line chart or in other type of chart be not shown because zooming in Y too.
and for just calculation where the extreme started you may need :
this.series[0].cropStart
and comparing that with your main data.
In the highcharts example above suppose I have 100 series in Bananas which is 1 right now and just one series in Apples ,and if there is a lot of empty space between Bananas and Oranges can we reduce the spacing between them ?
The reason is if there are 100 series in Bananas due to space constraint every line gets overlapped even though there is extra space available between Bananas and Apples . Also is it possible to remove "Oranges" if it doesnt have any series at all and accomodate only series from "Bananas"?
Categories functionality works only for constant tick interval equaled to 1. What you're trying to achieve is having a different space reserved for every category. That means that tick interval has to be irregular.
Unfortunately Highcharts doesn't provide a property to do that automatically - some coding and restructuring the data is required:
All the points have specified x position (integer value)
xAxis.grouping is disabled and xAxis.pointRangeis 1
Following code is used to define and position the labels:
events: {
render: function() {
var xAxis = this.xAxis[0];
for (var i = 0; i < xAxis.tickPositions.length; i++) {
var tickPosition = xAxis.tickPositions[i],
tick = xAxis.ticks[tickPosition],
nextTickPosition,
nextTick;
if (!tick.isLast) {
nextTickPosition = xAxis.tickPositions[i + 1];
nextTick = xAxis.ticks[nextTickPosition];
tick.label.attr({
y: (new Number(tick.mark.d.split(' ')[2]) + new Number(nextTick.mark.d.split(' ')[2])) / 2 + 3
});
}
}
}
}
(...)
xAxis: {
tickPositions: [-0.5, 6.5, 7.5],
showLastLabel: false,
labels: {
formatter: function() {
switch (this.pos) {
case -0.5:
return 'Bananas';
case 6.5:
return 'Apples';
}
}
}
}
Live demo: http://jsfiddle.net/BlackLabel/2Lcs5up5/
I'm using Chart.js 2.6. I have a chart to which I've added custom pagination to step through the dataset, as it is quite large. My pagination and everything works great, I simply grab the next chunk of data in my set and update the chart.config.data with the new data object, and then call .update() on the chart. However, in order to make the chart make sense, I needed to keep the left (Y-axis) scale the same when the user is paginating through. Normally Chart.js would rebuild it based on the data in the chart, but I want it to always reflect the same values.
I've set the max value on the yAxes object of the chart to the maximum value in my data set. I've also set the beginAtZero option to true, and the maxTicksLimit to 10. However, even though my Yaxis does stay the same, it doesn't always look that great (see below screenshot). In this example, my max is set to 21,000 in the chart. Does anyone have any suggestions as to how I can either provide a better max (rounding up to next 5,000, 500, 100, etc based on the value) or some way to get it to create the Y axis without crunching the top number the way it does now?
Here is the function I currently use to determining the max data value to set as the max value in the Yaxes object in the chart. the plugin.settings.chartData variable represents an array of the data values used in the chart. I am trying to get it to increment correctly to the next 1000, 500, etc based on what the maxValue is, but as you can see my math is not correct. In the screenshot example, the maxValue is coming back as 20,750 and my function is rounding it up to 21,000. In this example it SHOULD round it up to the next increment which would be 25,000.
var determineMaxDataValue = function() {
var maxValue = Math.max.apply(Math, plugin.settings.chartData);
var step = maxValue > 1000 ? 1000 : 500;
plugin.settings.maxDataValue = (Math.ceil(maxValue / step) * step);
};
I too had the same problem. You needn't write any special function for determining the max value in the Yaxes. Use 'suggestedMax' setting. Instead for setting 'max' as maximum value in your graph, set suggestMax as the maximum value in your graph. This never works if you have set 'stepsize'.
options: {
scales: {
yAxes: [{
ticks: {
suggestedMax: maxvalue+20
}
}]
}
}
20 is added, so that the tooltip on max value will be clearly visible.
For more info, refer http://www.chartjs.org/docs/latest/axes/cartesian/linear.html#axis-range-settings
Figured it out. Instead of supplying the max value on the Y Axis as I have been, I instead implemented the afterBuildTicks callback and updated the ticks to have the correct increments.
yAxes: [{
afterBuildTicks: function(scale) {
scale.ticks = updateChartTicks(scale);
return;
},
beforeUpdate: function(oScale) {
return;
},
ticks: {
beginAtZero:true,
// max:plugin.settings.maxDataValue,
maxTicksLimit: 10
}
}]
my updateChartTicks function loops over the existing ticks and determines the correct increment amount between the ticks. Then I use that value to add my final "tick" which will always be greater than the largest data in the dataset.
var updateChartTicks = function(scale) {
var incrementAmount = 0;
var previousAmount = 0;
var newTicks = [];
newTicks = scale.ticks;
for (x=0;x<newTicks.length;x++) {
incrementAmount = (previousAmount - newTicks[x]);
previousAmount = newTicks[x];
}
if (newTicks.length > 2) {
if (newTicks[0] - newTicks[1] != incrementAmount) {
newTicks[0] = newTicks[1] + incrementAmount;
}
}
return newTicks;
};
I'm trying to modify the behavior of a vertical C3.js Spine chart so that the mousewheel scrolls the range of the data instead of zooming. I created an event listener using Prototype to change the range of the chart when someone scrolls inside its parent div like so:
$("chartDiv").observe("mousewheel", function(e, charts) {
if (charts.get("splineChart") != null) {
var cht = charts.get("splineChart");
var range = cht.axis.range();
if (e.wheelDelta > 0) {
cht.axis.range({
min: {
y: range.min.y - 10
},
max: {
y: range.max.y - 10
},
});
}
else {
cht.axis.range({
min: {
y: range.min.y + 10
},
max: {
y: range.max.y + 10
},
});
}
}
}.bindAsEventListener(this, chartList));
When testing in Chrome, the event is handled corrently and I have access to the chart object that I want to work with, but the max and min objects returned by range() have undefined values for x, y, and y2.
I've read through the API listed on http://c3js.org/reference.html#api-axis-range and it says is that calling range() with no argument should return the current min and max values for each axis.
What am I doing wrong here? I need to get and update the current displayed range for data in the chart.
I want to display all of the points on my chart from the data I get, but I don't want to display all the labels for them, because then the chart is not very readable. I was looking for it in the docs, but couldn't find any parameter that would limit this.
I don't want to take only three labels for example, because then the chart is also limited to three points. Is it possible?
I have something like that right now:
If I could just leave every third-fourth label, it would be great. But I found absolutely nothing about labels options.
Try adding the options.scales.xAxes.ticks.maxTicksLimit option:
xAxes: [{
type: 'time',
ticks: {
autoSkip: true,
maxTicksLimit: 20
}
}]
For concreteness, let's say your original list of labels looks like:
["0", "1", "2", "3", "4", "5", "6", "7", "8"]
If you only want to display every 4th label, filter your list of labels so that every 4th label is filled in, and all others are the empty string (e.g. ["0", "", "", "", "4", "", "", "", "8"]).
For anyone looking to achieve this on Chart JS V2 the following will work:
var options = {
scales: {
xAxes: [{
afterTickToLabelConversion: function(data){
var xLabels = data.ticks;
xLabels.forEach(function (labels, i) {
if (i % 2 == 1){
xLabels[i] = '';
}
});
}
}]
}
}
Then pass the options variable as usual into a:
myLineChart = new Chart(ctx, {
type: 'line',
data: data,
options: options
});`
UPDATE:
I'v updated my fork with the latest pull (as of Jan 27, 2014) from NNick's Chart.js master branch.
https://github.com/hay-wire/Chart.js/tree/showXLabels
ORIGINAL ANSWER:
For those still facing this issue, I forked Chart.js a while back to solve the same problem. You can check it out on:
https://github.com/hay-wire/Chart.js/tree/skip-xlabels => Older branch! Check showXLabels branch for latest pull.
How to use:
Applicable to bar chart and line chart.
User can now pass a { showXLabels: 10 } to display only 10 labels (actual displayed labels count might be a bit different depending on the number of total labels present on x axis, but it will still remain close to 10 however)
Helps a lot when there is a very large amount of data. Earlier, the graph used to look devastated due to x axis labels drawn over each other in the cramped space. With showXLabels, user now has the control to reduce the number of labels to whatever number of labels fit good into the space available to him.
See the attached images for a comparison.
Without showXLabels option:
With { showXLabels: 10 } passed into option:
Here's some discussion on it:
https://github.com/nnnick/Chart.js/pull/521#issuecomment-60469304
For Chart.js 3.3.2, you can use #Nikita Ag's approach with a few changes. You can check the documentation. Put ticks in xAxis in scales. Example:
...
options: {
scales: {
xAxis: {
ticks: {
maxTicksLimit: 10
}
}
}
}
...
for axis rotation
use this:
scales: {
xAxes: [
{
// aqui controlas la cantidad de elementos en el eje horizontal con autoSkip
ticks: {
autoSkip: true,
maxRotation: 0,
minRotation: 0
}
}
]
}
In Chart.js 3.2.0:
options: {
scales: {
x: {
ticks: {
maxTicksLimit: 10
}
}
}
}
According to the chart.js github issue #12. Current solutions include:
Use 2.0 alpha (not production)
Hide x-axis at all when it becames too crowd (cannot accept at all)
manually control label skip of x-axis (not in responsive page)
However, after a few minutes, I thinks there's a better solution.
The following snippet will hide labels automatically. By modify xLabels with empty string before invoke draw() and restore them after then. Even more, re-rotating x labels can be applied as there's more space after hiding.
var axisFixedDrawFn = function() {
var self = this
var widthPerXLabel = (self.width - self.xScalePaddingLeft - self.xScalePaddingRight) / self.xLabels.length
var xLabelPerFontSize = self.fontSize / widthPerXLabel
var xLabelStep = Math.ceil(xLabelPerFontSize)
var xLabelRotationOld = null
var xLabelsOld = null
if (xLabelStep > 1) {
var widthPerSkipedXLabel = (self.width - self.xScalePaddingLeft - self.xScalePaddingRight) / (self.xLabels.length / xLabelStep)
xLabelRotationOld = self.xLabelRotation
xLabelsOld = clone(self.xLabels)
self.xLabelRotation = Math.asin(self.fontSize / widthPerSkipedXLabel) / Math.PI * 180
for (var i = 0; i < self.xLabels.length; ++i) {
if (i % xLabelStep != 0) {
self.xLabels[i] = ''
}
}
}
Chart.Scale.prototype.draw.apply(self, arguments);
if (xLabelRotationOld != null) {
self.xLabelRotation = xLabelRotationOld
}
if (xLabelsOld != null) {
self.xLabels = xLabelsOld
}
};
Chart.types.Bar.extend({
name : "AxisFixedBar",
initialize : function(data) {
Chart.types.Bar.prototype.initialize.apply(this, arguments);
this.scale.draw = axisFixedDrawFn;
}
});
Chart.types.Line.extend({
name : "AxisFixedLine",
initialize : function(data) {
Chart.types.Line.prototype.initialize.apply(this, arguments);
this.scale.draw = axisFixedDrawFn;
}
});
Please notice that clone is an external dependency.
i had a similar type of issue, and was given a nice solution to my specific issue show label in tooltip but not in x axis for chartjs line chart. See if this helps you
you can limit at as
scales: {
x: {
ticks: {
// For a category axis, the val is the index so the lookup via getLabelForValue is needed
callback: function(val, index) {
// Hide the label of every 2nd dataset
return index % 5 === 0 ? this.getLabelForValue(val) : '';
},
}
}
}
this will skip 4 labels and set the 5th one only.
you can use the following code:
xAxes: [{
ticks: {
autoSkip: true,
maxRotation: 90
}
}]
You may well not need anything with this new built-in feature.
A built-in label auto-skip feature detects would-be overlapping ticks and labels and removes every nth label to keep things displaying normally. https://www.chartjs.org/docs/latest/axes/
To set a custom number of ticks regardless of your chartsjs version:
yAxes: [{
ticks: {
stepSize: Math.round((Math.max.apply(Math, myListOfyValues) / 10)/5)*5,
beginAtZero: true,
precision: 0
}
}]
10 = the number of ticks
5 = rounds tick values to the nearest 5. All your y values will have the same step size.
Similar will work for xAxes too.
This answer works like a charm.
If you are wondering about the clone function, try this one:
var clone = function(el){ return el.slice(0); }
In the Chart.js file, you should find (on line 884 for me)
var Line = function(...
...
function drawScale(){
...
ctx.fillText(data.labels[i], 0,0);
...
If you just wrap that one line call to fillText with if ( i % config.xFreq === 0){ ... }
and then in chart.Line.defaults add something line xFreq : 1 you should be able to start using xFreq in your options when you call new Chart(ctx).Line(data, options).
Mind you this is pretty hacky.