Currently I have a request to have a Bullet Chart with two targets (min and max).
To do it I am simply using a normal Bullet Chart with a Scatter series to draw the other target. I would like to wrap this behavior inside the bullet chart, so it would have something like the following options:
series: [{
data: [{
y: 275,
target: 250,
minTarget: 100
}]
},
And then, on the wrap, I would get this minTarget and make a scatter plot automatically. How can I do it?
Here's the fiddle I have so far: http://jsfiddle.net/gwkxd02p/
I do not think that render is a good method to add another series - anyway, you can try to do it like this:
Highcharts.wrap(Highcharts.seriesTypes.bullet.prototype, 'render', function(p) {
if (!this.hasRendered) {
const scatterData = this.points
.map(({ x, y, options }) => ({
x,
y: options.minTarget !== undefined ? options.minTarget : null
}))
if (scatterData.length) {
const scatter = this.chart.addSeries({
type: 'scatter',
data: scatterData,
marker: {
symbol: 'line',
lineWidth: 3,
radius: 8,
lineColor: '#000'
}
}, false)
scatter.translate()
scatter.render()
}
}
p.call(this)
})
And data for bullet:
series: [{
data: [{
y: 275,
target: 250,
minTarget: 100
}, {
y: 100,
target: 50
}, {
y: 500,
target: 600,
minTarget: 20
}]
live example: http://jsfiddle.net/n4p0ezzw/
I think that the better place is bullet's init method but in that method the points do not exist yet - so you would have to match the x values (if it is needed) on your own.
My suggestion is - do not wrap Highcharts if you don't have to. A better (simpler, safer, cleaner, easier to debug, it does not change Highcharts internal code) practice would be to wrap the Highcharts constructor in a function and parse the options inside it and then call the chart constructor with new options, like this:
function customBullet(container, options) {
const newOptions = {} // parse options, check for minTarget, etc. and create new options
return Highcharts.chart(container, newOptions)
}
Related
I'm making a website with one graph that use ChartJS library. This chart display, on the website, all of the data available as default.
My goal is to let the visitors to choose a different number of data of the graph. So, I did one button at the top of the chart which, when a visitor click on it, must change the number of data displayed.
The problem is that ChartJS use a JSON object and I not succeed configure different behaviors in it.
...
datasets: [
{
label: "Exemple",
data: [
{ x: "Day1", y: 0 },
{ x: "Day2", y: 1 },
{ x: "Day3", y: 2 },
{ x: "Day4", y: 3 },
{ x: "Day5", y: 4 },
....
],
...
I tried to put an event on it, like :
data: mybutton.addEventListener("click", () => {
[{x: "Day1", y: 0}]
},
A function, like :
data: myFunction(),
Even a variable with function into, like :
const myData = () => {
// function
}
data: myData,
Or an If else.
Nothing worked... Do you any idea ?
I found the solution by myself.
I put the JSON object in a function, put an AddEventListener("click", function()), targeted the part of the JSON to modify and added an update() at the end.
function chartFunction() {
....
// data before
datasets: [
{
label: "Exemple",
data: [
{ x: "Day1", y: 0 },
.....
button.addEventListener("click", () => {
(myChart.data.datasets[0].data = [...]).myChart.update();
});
};
chartFunction();
I have a simple Highchart with a dataset of up to 1000 datas. There are only y values the x values are generated automatically. Also, the values come from my nodejs server so please don't be surprised about the notation.
Now I want 3 special values whose x and y values are known to be highlighted. In which way doesn't matter for now.
One possibility would be to show the point at the location, otherwise they are not displayed. The problem I have is that I don't know how to control a specific point.
var chart1 = new Highcharts.Chart({
chart: {
renderTo: 'chart-emg1',
type: 'line'
},
title: {
text: 'EMG 1'
},
xAxis: {
tickInterval: 1
},
yAxis: {
title: { text: 'Voltage'}
},
series: [{
data: [<%-data1 %>]
}]
});
You can use the load event and update specific points. For example:
events: {
load: function() {
this.series[0].points.forEach(point => {
const isPointToHighlight = pointsToHighlight.some(
p => p.x === point.x && p.y === point.y
);
if (isPointToHighlight) {
point.update({
color: 'red',
marker: {
enabled: true
}
}, false);
}
});
this.redraw();
}
}
Live demo: http://jsfiddle.net/BlackLabel/tLd3j78f/
API Reference:
https://api.highcharts.com/highcharts/chart.events.load
https://api.highcharts.com/class-reference/Highcharts.Point#update
I have a bubble chart with multiple datasets. Two points of two different datasets may have the same coordinates (x and y-value) and lay on the same place in the chart. Because the display order of the points is determined according the order of the datasets, the smaller point could be completely covered by the bigger point in front of it.
Is there a option or a way, to display the points in order of their bubble size?
Simplified example of four points. The solution must also work for multiple datasets with each 30+ points.
I am searching a solution to draw the blue point in front of the red point, for the left pair and let the right pair as it is. This order must be independent of the order of the datasets, as it is per point and not per dataset.
Sorting the datasets seems to be no option for me, as the order cannot be determined per dataset, but instead must be determined for every coordinate/point. When drawing a point, it must be checked for this particular coordinate, if any other point with the same coordinates exists and if this point is greater than the current point (if true, the greater point must be drawn before, to not cover up the current point).
const config = {
type: 'bubble',
data: {
datasets: [{
label: 'Dataset 1',
data: [{
x: 1,
y: 1,
r: 20
},
{
x: 2,
y: 1,
r: 15
}
],
borderColor: 'red',
backgroundColor: 'red'
},
{
label: 'Dataset 2',
data: [{
x: 1,
y: 1,
r: 15
},
{
x: 2,
y: 1,
r: 20
}
],
borderColor: 'blue',
backgroundColor: 'blue'
}
]
},
options: {
responsive: true,
scales: {
x: {
suggestedMin: 0,
suggestedMax: 3
}
},
plugins: {
legend: {
position: 'top',
}
}
}
};
var ctx = document.getElementById('chartJSCanvas').getContext('2d');
const chart = new Chart(ctx, config);
<body>
<canvas id="chartJSCanvas" width="300" height="100"></canvas>
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/3.1.0/chart.js" integrity="sha512-LlFvdZpYhQdASf4aZfSpmyHD6+waYVfJRwfJrBgki7/Uh+TXMLFYcKMRim65+o3lFsfk20vrK9sJDute7BUAUw==" crossorigin="anonymous"></script>
</body>
The easiest way would be to just sort the data in the datasets and then the datasets themselves before drawing them.
An easy way to do this is provided by Array.prototype.forEach and Array.prototype.sort
First sort the data within each dataset like this:
config.data.datasets.forEach(function(element){
element.data.sort(function (a, b) {
return a.r - b.r;
});
});
Then you can sort the data sets by their smallest element like this:
config.data.datasets.sort(function (a, b) {
return a.data[0].r - b.data[0].r;
});
After that, you can regularly pass your config object with ordered datasets to your library call just the way you do it above:
const chart = new Chart(ctx, config);
I want to dynamically change the startAngle value on my polar chart from JSON 'Wind_direction' value.
The code is below:
$(function() {
$.getJSON('wind_graph.php?callback=?', function(dataWind) {
var direction = Wind_direction;
var polarOptions = {
chart: {
polar: true,
events : {
load : function () {
setInterval(function(){
RefreshDataWind();
}, 1000);
}
}
},
title: {
text: 'Wind Direction'
},
pane: {
startAngle: direction,
},
xAxis: {
tickInterval: 15,
min: 0,
max: 360
},
plotOptions: {
series: {
pointStart: 0,
pointInterval: 30,
},
}
};
// The polar chart
$('#graph-1').highcharts(Highcharts.merge(polarOptions, {
yAxis: {
tickInterval: 5,
min: 0,
max: 25,
visible: false
},
series: [{
type: 'line',
name: 'Direction',
data: [
[0, 0],
[direction, 20]
],
}
]
}));
function RefreshDataWind()
{
var chart = $('#graph-1').highcharts();
$.getJSON('wind_graph.php?callback=?', function(dataWind)
{
var direction = Wind_direction;
chart.series[0].setData([[0,0],[direction, 20]]);
});
}
});
});
In the last function, below 'chart.series[0].setData... I was trying to add something like this:
chart.pane.setStartAngle(direction);
but this throws the error: "Cannot read property 'startAngle' of undefined"
Also was trying another one idea:
polarOptions.pane({ startAngle: direction });
but here is error: "polarOptions.pane is not a function".
So I'm stack. Please for help.
You should be able to update all chart options with Chart.update(). Unfortunately, it looks that it does not have any effect on pane - I reported the issue here.
Now you can update the pane in old-fashioned way - by destroying and creating a new chart - http://jsfiddle.net/highcharts/qhY8C/
The other possibility is trying the workaround - set options for pane, remove the pane and update the axis - it should create a new pane with new options.
const xAxis = chart.xAxis[0];
chart.options.pane.startAngle = 45;
Highcharts.erase(chart.panes, xAxis.pane);
chart.yAxis[0].update(null, false);
xAxis.update();
example: http://jsfiddle.net/v8L381Lj/
Working with tooltips in Highcharts I can see that not all type of series are included in the same tooltip. In the definition of my Highcharts object the property of tooltip look like:
tooltip: {
positioner : function (boxWidth, boxHeight, point) {
return {
x : point.plotX - 100,
y : point.plotY
};
},
shared : true
}
And how I am setting the tooltip property for each series is:
public getDefaultTooltip() {
return {
pointFormat : '<span style="font-weight: bold; color: {series.color}">{series.name}</span>: <b>{point.y} </b><br/>'
};
}
After read the documentation of tooltip I can see that shared property is not valid for series of type 'scatter', what is exactly the type of series that is not working for me. So, is there some workaround in order to make available all the data in the same shared tooltip?
in the example bellow I want to show all the series data in the same tooltip but the scatter serie is using a different popover. http://jsfiddle.net/rolandomartinezg/a6c4c4tv/1/
The ScatterSeries is defined in highcharts with noSharedTooltip = true. I think this is because the scatter series show both the x and y in their tooltips.
var ScatterSeries = extendClass(Series, {
type: 'scatter',
sorted: false,
requireSorting: false,
noSharedTooltip: true,
trackerGroups: ['group', 'markerGroup', 'dataLabelsGroup'],
takeOrdinalPosition: false, // #2342
kdDimensions: 2,
kdComparer: 'distR',
drawGraph: function () {
if (this.options.lineWidth) {
Series.prototype.drawGraph.call(this);
}
}
});
To get around this, you can use a line series instead of the scatter series with the lineWidth = 0. You also need to turn off the hover state for the series to avoid the line showing up on hover.
, {
type: 'line',
name: 'Average',
lineWidth: 0,
states: {
hover: {
enabled: false
}
},
data: [3, 2.67, 3, 6.33, 3.33],
marker: {
lineWidth: 2,
lineColor: Highcharts.getOptions().colors[3],
fillColor: 'white'
}
}
http://jsfiddle.net/a6c4c4tv/2/