Chart.js: Get point index from chart.getPointsAtEvent(e) - javascript

I am looking to make my chart (made with Chart.js) a little more interactive and I would like to get a point's index (of its dataset) with the following code:
canvas.onclick = function(e) {
const points = chart.getPointsAtEvent(e);
// something like `point.getIndex()` would be great so that I know where this point is in the original dataset
};
Anybody have a good solution for this?

You should be able to do an indexOf (instead of a label lookup) because it refers to the exact same object in the points collection
canvas.onclick = function (evt) {
var points = chart.getPointsAtEvent(evt);
alert(chart.datasets[0].points.indexOf(points[0]));
};
Also, for a multi series line chart getPointsAtEvent(evt) returns points from all datasets. So the same code would work irrespective of how many datasets you have or which of the datasets you click on.
Fiddle - http://jsfiddle.net/yxz2sjam/

Related

Is there a way to center label in nested pie chart without using magic numbers as radius for Amchart v4?

My problem: i would like to find an automatic way to center labels in donut chart cells. In my case each cells contains an array of complex objects, what i want is to show the number of those objects.
See:
Playing with radius, allowed me to find those values:
First layer: -28
Second layer: -20
Third layer: -10
Fourth layer: -8
I applied it as a quick fix but i don't like this solution, as it's fixed for 4 layers (what if I need to add an other layer ? etc....) and using "magic numbers" is unmaintenable...
Do you have a better solution ?
You can test it here: https://jsfiddle.net/aliz/gwz7om9e/
Line 40:
pieSeries.labels.template.radius = am4core.percent(positionRadiusInPie);
Note:
Using those attributes didn't work: "horizontalCenter", "VerticalCenter", "textAlign", "align".
EDIT: response to Bhavik Kalariya
This is what I get if I force one radius for all layers.
You can at least get it down to just using one base constant of your choosing by using an adapter approach on the label's radius to calculate the value you want for each series that is added to the chart using whatever formula you choose. Here's a basic formula that gave good results for me with your setup, where BASE_INNER_LABEL_RADIUS is set to -45.
pieSeries.labels.template.adapter.add('radius', function(radius, target) {
var chart = target.baseSprite; //chart stored in baseSprite of the AxisCircularLabel
var index = chart.series.indexOf(target.dataItem.component); //corresponding series stored in the dataItem's component
return am4core.percent(BASE_INNER_LABEL_RADIUS / (index + 2)); //Uses singular constant defined elsewhere, which is used in all series
});
This will adjust itself according to the number of series you add to the chart. You can make this as robust as you want by making further tweaks if you have fewer series and want to make the labels even more centered.
Updated fiddle
Edit
If you want to be even more generic, you can get at the slice sprite directly through the target.dataItem.sprites array (typically the first element, though you can loop through and look for an object whose className is "Slice" if you want to be super safe about it) and calculate your desired radius value using any of the numeric properties it has, such as innerRadius.
pieSeries.labels.template.adapter.add('radius', function(radius, target) {
var chart = target.baseSprite; //chart stored in baseSprite of the AxisCircularLabel
var index = chart.series.indexOf(target.dataItem.component); //corresponding series stored in the dataItem's component
return -(target.dataItem.sprites[0].innerRadius) / (index + 3);
});
You'll want to adjust this accordingly, of course.
Fiddle

Create reversed mxHierarchical layout in mxgraph

Greetings to the community! I am currently creating a custom mxgraph editor and I am converting the graphs using different layouts. I would like to convert my graph layout into an mxHierarchicalLayout but reversed (instead of top-to-down I would like it to be down-to-top). Example of what I do and what I would like to do.
My graph
My graph converted with mxHierarchicalLayout
Code snippet:
let layout = new mxHierarchicalLayout(graph);
layout.execute(graph.getDefaultParent());
How I want to convert the graph
I found in the mxHierarchicalLayout that there is an orientation member variable which is by default 'NORTH'. However when I tried to do the following
let layout = new mxHierarchicalLayout(graph);
layout.orientation=mxConstants.DIRECTION_SOUTH;
layout.execute(graph.getDefaultParent());
The graph went out of my "canvas" and cannot be seen to check if this is the responsible parameter to "reverse" the tree. Could anyone help ? Thanks in advance.
PS
When I use layout.orientation = mxConstants.DIRECTION_SOUTH;
it seems that the layout is converted as I want to but cannot be seen because the coordinates of the svg elements are of type x=-10, y=-5 (negatives), any workaround for this?
SOLVED
I do not know why mxgraph has that buggy behaviour with orientation = south in mxHierarchicalLayout but I managed to create a workaround solution for my problem since I realized that the newly generated layout put my mxCell children objects of the graph to the north ( negative y coordinate). So what I did was after layout.execute(graph.getDefaultParent()); I get each and every child of the graph and retrieve the most negative y coordinate and then move all the cells of the graph from their new coordinates to a new incremented by the absolute value of the most negative y-coordinated element.
Code
function convertGraphToInverseHorizontalTree(){
let layout = new mxHierarchicalLayout(graph);
layout.orientation = mxConstants.DIRECTION_SOUTH;
layout.execute(graph.getDefaultParent());
graph.model.beginUpdate();
//get the most negative y
let mostNegativeY = getMostNegativeCoordinateY(graph);
let children = graph.getChildCells();
graph.moveCells(children, undefined , Math.abs(mostNegativeY));
graph.model.endUpdate();
}
function getMostNegativeCoordinateY(graph){
let children = graph.getChildCells();
let mostNegative = 10000;
for(let i = 0; i < children.length; i++){
if(children[i].geometry != undefined){
if(children[i].geometry.y < mostNegative){
mostNegative = children[i].geometry.y;
}
}
}
return mostNegative;
}
Now the graph is like this

Search for and zoom in to a scatter plot point (Highcharts, react.js)

I'm using the highcharts library in react.js and it's working great. However, I'm plotting ~15,000 scattered points and it's a bit tricky finding the one I want among all that. I'd like to be able to search for a specific point, since each point has its own unique name property along with its x and y coordinates (not id, but I could put the name as id if that made the solution easier). When the point is found, the graph should zoom in a bit, since at default zoom level there's quite a few overlaps of points so just making it blink/bigger/something wouldn't help much. I've looked through the Highcharts API docs but I can't find anything that will do a manual zoom into specified coordinates.
I found the mapZoom function, but that's only for maps, and... well, this isn't a map. It's a scatter plot.
Also, since this is react, it's a bit tricky to see how I can access the chart object to do stuff with it, since the only time it exists is when it's being returned to be rendered:
var CosinePlot = React.createClass({
componentDidMount: function() {
let chart = this.refs.chart.getChart();
},
render: function() {
return <ReactHighcharts config={plotConfig} isPureConfig={true}/>;
}
});
If you know exact point you want to zoom in, simply get it's x and y. Then zoom into that point using chart.xAxis[0].setExtremes(min, max) and chart.yAxis[0].setExtremes(min, max).
And regarding accessing the chart object, I guess you are using this this wrapper. There is an explanation how to retrieve that chart object here.

HighCharts: How to draw a straight line in multiple axes like plotLines with fixed X-axis with different values

I'm using highcharts for my project. I've used multiple axes for drawing the chart. What I want is there should be a straight line on fixed x-axis even though with different values.
I want to have something like plotLines which will be straight and fixed on the x-axis but still shows different values I put it.
I would create separate series to achieve that. I think it's simpler solution than playing around with renderer. Demo: http://jsfiddle.net/6wo5mzo4/
(function(H) {
var seriesTypes = H.seriesTypes;
seriesTypes.fakeLine = Highcharts.extendClass(seriesTypes.line);
seriesTypes.fakeLine.prototype.translate = function() {
var s = this;
seriesTypes.line.prototype.translate.call(s);
H.each(s.points, function(point) {
point.plotY = s.chart.plotWidth / 2; // display in the middle - note: plotWidth, not plotHeight, because chart is inverted
});
}
})(Highcharts);
However, I still have doubts how useful such chart will be. I would also suggest to review the requirements.

flot: zoom, hover and series selection in the same plot

I am trying to plot 3 different series on the same plot. I want to do the following in the plot:
allow the user to select which series are plotted ("Turning series on/off" example on the flot website),
allow the user to zoom in and zoom out ("Rectangular selection with zooming" example),
show the values of the curves when the user hovers the mouse ("Tracking curves" example).
I have been trying to make it work for a long time now, and I can't get everything to work. My current attempt fails to properly turn series on/off. As soon as I check a box, the graph becomes blank. The javascript file which defines all the plotting functions etc., is plot_displacement.js.
The relevant part of the code is:
var choice_container = jQuery("#choices");
choice_container.find("input").change(do_plot);
The HTML is:
<p id="choices">Show:</p>
<div id="plotdiv" style="width:600px;height:300px;position:static;"></div>
I am using change and not click because of this question's answer. If I use click, then selecting/unselecting the checkboxes doesn't seem to have any effect.
I am sure I am overlooking something simple, but I can't figure out what. I would love to be able to do all the 3 things that I am trying to do in flot.
Thanks!
Your problem is simply that do_plot is being called from your change event with xmin being a jQuery Event object. You expect it to be undefined and then set to 0, but instead you're passing xmin: jQuery.Event to flot, which doesn't know what to do with it.
Edit: Since someone asked, the actual code you might want to put in there, when checking if xmin is undefined, additionally check whether it is an object (jQuery.Event has a typeof object):
if (typeof(xmin) == 'undefined' || typeof(xmin) == 'object') xmin = 0;
Click does work for me.
I use the code from the Flot example:
$("#checkboxes").find("input").click(plotAccordingToChoices);
Clicking the checkboxes calls:
function plotAccordingToChoices() {
var data = [];
$("#checkboxes").find("input:checked").each(function () {
var key = $(this).attr("name");
if (key && datasets[key])
data.push(datasets[key]);
});
if (data.length > 0){
plot = $.plot($("#chart1"), data, options);
}
}
datasets is a global array keyed by the set name and was created at initialization.

Categories

Resources