Mouseover preview for bar instead of datapoint in StackedColumn chart - javascript

I have a StackedColumn chart which I'd like to add a mouseover preview. Currently I'm looping through the points of a series to add the the functionality to do this.
This makes each series in the column will do a mouseover/mouseout. I'd like it to do a single mouseover/mouseout for the column. Suggestions?

Ok, not a popular question.
I stumbled across the CustomizeMapAreas event. In there I looped through the e.MapAreaItems and adjusted the size of the areas so that there was just one area for the entire column. Then I removed the areas I didn't need anymore. It's probably not the most efficient way to do it, but here it is...
protected void FixStackedColumnAreas(object sender, CustomizeMapAreasEventArgs e)
{
Dictionary<float, MapArea> newAreas = new Dictionary<float, MapArea>();
//loop through all areas and collect the Min and Max Y values for each X
foreach (MapArea area in e.MapAreaItems)
{
if (!newAreas.ContainsKey(area.Coordinates[0]))
{
newAreas.Add(area.Coordinates[0], area);
}
else
{
//get the lowest and highest Y for this X column area
newAreas[area.Coordinates[0]].Coordinates[1] = Math.Min(newAreas[area.Coordinates[0]].Coordinates[1], area.Coordinates[1]);
newAreas[area.Coordinates[0]].Coordinates[3] = Math.Max(newAreas[area.Coordinates[0]].Coordinates[3], area.Coordinates[3]);
}
}
//clear out existing areas
e.MapAreaItems.Clear();
//put in our new areas that define the whole column area instead of the individual pieces of the column
foreach (MapArea area in newAreas.Values)
{
e.MapAreaItems.Add(area);
}
}

Related

How to tell the Highcharts renderer to make the viewport bigger?

In the past I have drawn tables below the chart based on the series. This works because I can tell Highcharts to vertically align the legend, move it to the left, and I can use the legend height and positioning as well as x-axis tick information to figure out where to draw the table lines:
This takes advantage of the fact that once I set the legend vertical, Highcharts is going to internally set the viewport (viewbox?) large enough that the legend is visible, and since my table aligns with the legend, it's also visible.
Now I have a situation where I need to draw a table below the chart that is not based on the series. I actually moved the legend to be floating in the upper right of the chart because there's only one series and it fits nicely there.
I figured out how to position my table lines based on the x-axis label box dimensions (along with tick information), but my table extends out of the viewport (viewbox?) and is not visible:
If I go after the fact and do
myChart.renderer.box.setAttribute("viewBox", "0 0 1200 1200")
to "zoom out", I can see that my whole table did draw, it's in there in the SVG:
So - how do I tell the Highcharts renderer to extend the viewport/viewbox/canvas (whatever the correct term is) down so that when I add my table, it's visible?
I trigger the table drawing from a redraw event handler, and if it's a question of setting some option/parameter I can easily do the calculations I need to figure out how much to extend beforehand and include that in a chart.update({...stuff...}, true) so that it's the right size already when I go to draw my table.
Or I can mess with the chart.renderer directly in code if that's what it will take.
Ok, figured it out.
chart.renderer has a function to setSize, which will set the overall size of the SVG root element itself, however the SVG root is contained within the "highcharts container" div, which has inline CSS styles to set height and width, and importantly, has overflow: hiddden, so you have to also set the height of the container div in order for the increased SVG to be visible. Luckily that is easily accessible at chart.container.
In my case I need to conditionally draw a table after a zoom in or out, so in my function to actually draw the table I also calculate the height it will need and return that so that I can adjust the SVG root and container div after the table is drawn. It looks a little like this:
const drawTable = async (chart, dataForTable) => {
// figure out how much room the table is going to take up
const extraHeight = (rowHeight * dataForTable.length) + littleExtraOffset
// create the SVG container for the table
const group = chart.renderer.g('bottom-table').add();
// draw all the lines for the table etc and add them to the group, then
return {
group,
extraHeight
}
}
const redrawEventHandler = (event) => {
// do stuff to figure out if we need to draw a table or not
let newWidth = baseWidth;
let newHeight = baseHeight;
if (shouldDrawTable) {
const { dataForTable } = this.props;
drawTable(event.target, dataForTable).then(tableResult => {
// save the table SVG group so we can easily destroy it later
this.tableGroup = tableResult.group;
// calculate the new total height
newHeight += tableResult.extraHeight;
this.chart.renderer.setSize(newWidth, newHeight);
this.chart.container.style.height = `${newHeight}px`;
});
} else {
// no table, newWidth and newHeight are still
// the original height and width
this.chart.renderer.setSize(newWidth, newHeight);
this.chart.container.style.height = `${newHeight}px`;
}
}

chartJS: How to return the closest x-axis label on click

I have a chartJS line graph, with x-axes labels being the last 72 hours on each hour mark ( for example: [8:00am, 9:00am, 10:00am,...]). Is there a way I can return the closest xAxis label on click? I have found a way to return the x-y coordinates of the graph, but these coordinates are in pixels, and the graph is able to resize its self based on the size of the browser window. If I were to take into account for the current browser window size, and the number of labels displaying, I could calculate which label would be closest, but I am hoping that there is an easier way to do this.
One Idea I have is to return the label that the "ToolTip" is on, on Click. This would be logically equivalent, as in my options I have the tooltip always display for the closest tick whenever the mouse is on the graph. Would it be possible to return the tooltips label onclick?
My ultimate goal is to have access to the nearest x-axis label (as a string) when I click on the graph. Is this possible?
You can add a custom onclick function to the chart and then ask chartjs for the elements at that location.
See this issue for the complete answer with example: get yLabel value onclick chart js
document.getElementById("myChart").onclick = function (evt) {
var activePoints = myChart.getElementsAtEventForMode(evt, 'point', myChart.options);
var firstPoint = activePoints[0];
var xLabel = myChart.data.labels[firstPoint._index];
// Do things with your x label
};

Custom gridLines and Axes Chartjs

I am trying to design a CDF Chart using chartjs to show probabilities in a graph. Basically, I will always have 100 points starting at 0 to some max number which I calculate beforehand and I want to generate the charts as I attached. Smooth and not many gridLines. I tried using chart type "line", yet it is far off.
Could you please help me out to configure the chart correctly.
Examples of what I am looking for:
This is a solution without autoSkip, using gridline colour options to hide unwanted x axis gridlines. (sorry about my British spelling of 'colour'!)
I can't use autoSkip since my time/x axis labels show new Year, Month, Date only once and I couldn't work out how to not skip the particular labels which indicate a new month, for instance. I finally found that you can define gridline colours in an array, so my solution is to create a gridline colour array, setting the chart background colour to the gridlines I want to hide. In my case, I already send a list of labels with empty values for when I don't want a label and gridline, just a datapoint.
var labels = data3json['labels'].split(',');
//set gridline colour to background when label is empty:
var xaxis_gridline_colours = [];
for (var i = 0; i < labels.length; i++) {
if (labels[i].length > 0) {
if (i == 0) {
xaxis_gridline_colours.push("#cccccc"); //x and y axis!
} else {
xaxis_gridline_colours.push("#dddddd"); //visible gridline
}
} else {
xaxis_gridline_colours.push("#ffffff"); //invisible gridline
//or call a chart background colour variable like:
//xaxis_gridline_colours.push(chart_bkg_colour);
}
}
Later in the code:
chart = new Chart(ctx24, {
options: {
scales: {
xAxes: [{
gridLines: {
display: true, //default true
color: xaxis_gridline_colours,
etc
First about the gridLines, you can in your chart options change the stepSize of your xAxes (put it to 10 for instance) so you will have 10 times less vertical grid Lines (since your xAxes stepSize seems to be 1 by default).
If the big points are bothering you, when you create your datasets you can change their pointRadius to 0; this way no points displayed just a smoothline.
Finally you can change the color of the line of each dataset by setting the property borderColor.
Take a look at this page for more customization : http://www.chartjs.org/docs/latest/charts/line.html
Hope this helps.
I have noticed that most of you add the line styles only via code. I just spend 1h looking for the settings, as I change it once, but then I couldn't change it again.
How to do it. Post on Stackoverflow pointed me in the right direction.
Charts grid lines style
Line: this.chart1.ChartAreas[0].AxisX.LineDashStyle.Dot
Go to Properties->Chart->Chart Areas and click on 3 dots (...) next collection.
Properties
In Collection, go to Axes and again click on 3 dots (...) next collection.
Axes Collection
You will have 2 Axis: X and Y. Select each Axis and go to the required section to change properties. Be careful. They are well hidden, but I tried to highlight all the options. Of course, to perform the custom modification, you will have to code it.
Axis Collection Editor

Hide x-axis labels but show tooltips in chart.js

I found many answers how to hide every nth label and yet still be able to show it in the tooltip. But there's a catch. If the label is very long, then the chart would be drawn somehow squished to the top of the canvas. It's logical. But is there any way to hide the labels, still show them in the tooltips and yet ignore them while calculating the y-values? So that the line can be drawn from top to bottom of the canvas?
Thank you for any advice!!
You can extend the line chart to do this. Adapted from Hide labels on x-axis ChartJS (which was for bar charts) with some unneeded code removed.
What we do is pretty simple, we first set the labels array to blanks, allow the initialization to happen and finally loop through the points for the (first) dataset and set the labels to the original labels.
Chart.types.Line.extend({
name: "LineAlt",
initialize: function(data){
var originalLabels = data.labels;
data.labels = data.labels.map(function() { return '' });
Chart.types.Line.prototype.initialize.apply(this, arguments);
this.datasets[0].points.forEach(function(bar, i) {
bar.label = originalLabels[i];
});
}
});
It's enough that you set the labels for the first dataset even if you have multiple datasets - when building a multiTooltip, the label is picked from the first dataset.
Fiddle - http://jsfiddle.net/xjchy2dn/

How do I make the closest four points on a graph glow?

As my cursor moves, I grab the two closest points IF it is not already on a plotted point.
I want to be able to make these two closest points light up (i.e. change colour to something orange or something), and then go back to normal once the cursor leaves the scope of the graph. How do I go about implementing this?
placeholder.bind("plothover", function (event, pos, item) {
if (item){
local_x = item.datapoint[0].toFixed(2);
local_y = item.datapoint[1].toFixed(2);
if (!updateLegendTimeout){
updateLegendTimeout = setTimeout(updateLegend(local_x,local_y), 1000);
updateLegendTimeout = null;
}
}
else{
var closest_points_container = interpolate(plot,pos.x,pos.y);
//Code to make points glow goes here, they are contained in closest_points[0]
and closest_points[1].
}
Flot provides highlight and unhighlight methods on the plot object, as described in the Plot Methods section of the docs. Unfortunately that has the restriction that only one point may be highlighted at a time. That is baked-in; you can't change it without altering the source.
The work-around I would use is to add a second series showing only points, no lines, and set the point style to appear as a highlight, i.e. with translucency. This highlight series will start out empty; then when you want to highlight a point on your main series you can copy it to the highlight series and redraw.

Categories