Show live data on Highcharts without default series - javascript

I found this code from Highchart website: https://jsfiddle.net/gh/get/library/pure/highcharts/highcharts/tree/master/samples/highcharts/demo/dynamic-update/
I want to show data on a chart with empty default series and put dateTime as xAxis. I don't want to use jQuery and do not want to add point on load event in chart. I just want to add point when page is loaded completely. I used this
const chart = new Highcharts.chart('container', {
...
...
...
}
document.addEventListener('DOMContentLoaded', function() {
var i = 0;
console.log(chart)
setInterval(function() {
console.log(values[i])
chart.series[0].addPoint(values[i], true, true);
i++;
}, 1000);
})
I used the chart structure like the link above. values[i] is a point which is [dateTime, Number] that I get it from my an API. I found some solutions that uses category for xAxis but I need to use dateTime and show the dateTime there not category.

You can not add a point with shift to a series without data. Add first point without shift or do not use shift: http://jsfiddle.net/BlackLabel/0h9jz3t1/
const chart = new Highcharts.chart('container', {
series: [{}]
});
const values = [[100, 20], [200, 20], [300, 20], [400, 20], [500, 20]];
document.addEventListener('DOMContentLoaded', function() {
var i = 0;
chart.series[0].addPoint(values[i], true, false);
i++;
setInterval(function() {
chart.series[0].addPoint(values[i], true, true);
i++;
}, 1000);
});
Live demo: http://jsfiddle.net/BlackLabel/oqp30tna/
API: https://api.highcharts.com/class-reference/Highcharts.Series#addPoint

Related

Make events run multiple times, Highcharts

I have a Highchart in which under the options object I have events object as ashown below.
var options = {
chart: {
renderTo: 'container',
type: 'line',
animation: Highcharts.svg, // don't animate in old IE
marginRight: 10,
events: {
load: function() {
var series = this.series[0],
chart = this;
...// Some Code
}
}
So what I want is that I need events data to update dynamically and load the Highcharts only once.
How can I make the Following section dynamic so that the values in it change dynamically. Keeping in mind that Highcharts container have to be defined and load only once.
events: {
load: function() {
var series = this.series[0],
chart = this;
...// Some Code
}
}
One of the official Highcharts demos shows how to achieve it. Take a look at it:
setInterval(function () {
var x = (new Date()).getTime(), // current time
y = Math.random();
series.addPoint([x, y], true, true);
}, 1000);
https://jsfiddle.net/gh/get/library/pure/highcharts/highcharts/tree/master/samples/highcharts/demo/dynamic-update/
Highcharts also offers other options to update the chart with new data, API:
https://api.highcharts.com/class-reference/Highcharts.Chart#addSeries
https://api.highcharts.com/class-reference/Highcharts.Series#update
https://api.highcharts.com/class-reference/Highcharts.Series#setData

How to create custom legend in ChartJS

I need to create custom legend for my donut chart using ChartJS library.
I have created donut with default legend provided by ChartJS but I need some modification.
I would like to have value above the car name. Also I don't like sticky legend I want to have it separate from donut so I can change the style for fonts, boxes (next to the text "Audi" for example)
I know there is some Legend generator but I'm not sure how to use it with VueJS - because I'm using VueJS as a framework
This is how my legend looks like now - http://imgur.com/a/NPUoi
My code:
From Vue component where I import a donut component:
<div class="col-md-6">
<div class="chart-box">
<p class="chart-title">Cars</p>
<donut-message id="chart-parent"></donut-message>
</div>
</div>
Javascript:
import { Doughnut } from 'vue-chartjs'
export default Doughnut.extend({
ready () {
Chart.defaults.global.tooltips.enabled = false;
Chart.defaults.global.legend.display = false;
this.render({
labels: ['Audi','BMW','Ford','Opel'],
datasets: [
{
label: 'Cars',
backgroundColor: ['#35d89b','#4676ea','#fba545','#e6ebfd'],
data: [40, 30, 20, 10]
}
]
},
{
responsive: true,
cutoutPercentage: 75,
legend: {
display: true,
position: "right",
fullWidth: true,
labels: {
boxWidth: 10,
fontSize: 14
}
},
animation: {
animateScale: true
}
})
}
});
I'm having the same problem trying to understand the documentation and this link might clarify the process of customize the legends:
https://codepen.io/michiel-nuovo/pen/RRaRRv
The trick is to track a callback to build your own HTML structure and return this new structure to ChartJS.
Inside the options object:
legendCallback: function(chart) {
var text = [];
text.push('<ul class="' + chart.id + '-legend">');
for (var i = 0; i < chart.data.datasets[0].data.length; i++) {
text.push('<li><span style="background-color:' +
chart.data.datasets[0].backgroundColor[i] + '">');
if (chart.data.labels[i]) {
text.push(chart.data.labels[i]);
}
text.push('</span></li>');
}
text.push('</ul>');
return text.join("");
}
Second, you need a container to insert the new html and using the method myChart.generateLegend() to get the customized html:
$("#your-legend-container").html(myChart.generateLegend());
After that, if you need, track down the events:
$("#your-legend-container").on('click', "li", function() {
myChart.data.datasets[0].data[$(this).index()] += 50;
myChart.update();
console.log('legend: ' + data.datasets[0].data[$(this).index()]);
});
$('#myChart').on('click', function(evt) {
var activePoints = myChart.getElementsAtEvent(evt);
var firstPoint = activePoints[0];
if (firstPoint !== undefined) {
console.log('canvas: ' +
data.datasets[firstPoint._datasetIndex].data[firstPoint._index]);
}
else {
myChart.data.labels.push("New");
myChart.data.datasets[0].data.push(100);
myChart.data.datasets[0].backgroundColor.push("red");
myChart.options.animation.animateRotate = false;
myChart.options.animation.animateScale = false;
myChart.update();
$("#your-legend-container").html(myChart.generateLegend());
}
}
Another solution that I found, if you don't need to change the HTMl structure inside the legend, you can just insert the same HTML in your legend container and customize it by CSS, check this another link:
http://jsfiddle.net/vrwjfg9z/
Hope it works for you.
You can extract the legend markup.
data () {
return {
legendMarkup: ''
}
},
ready () {
this.legendMarkup = this._chart.generateLegend()
}
And in your template you can output it.
<div class="legend" ref="legend" v-html="legendMarkup"></div>
this._chart is the internal chartjs instance in vue-chartjs. So you can call all chartjs methods which are not exposed by vue-chartjs api over it.
However you can also use the legend generator. The usage is the same in vue. You can pass in the options, use callbacks etc.
please check this documentation
.
Legend Configuration
The chart legend displays data about the datasets that area appearing on the chart.
Configuration options
Position of the legend. Options are:
'top'
'left'
'bottom'
'right'
Legend Item Interface
Items passed to the legend onClick function are the ones returned from labels.generateLabels. These items must implement the following interface.
{
// Label that will be displayed
text: String,
// Fill style of the legend box
fillStyle: Color,
// If true, this item represents a hidden dataset. Label will be rendered with a strike-through effect
hidden: Boolean,
// For box border. See https://developer.mozilla.org/en/docs/Web/API/CanvasRenderingContext2D/lineCap
lineCap: String,
// For box border. See https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/setLineDash
lineDash: Array[Number],
// For box border. See https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/lineDashOffset
lineDashOffset: Number,
// For box border. See https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/lineJoin
lineJoin: String,
// Width of box border
lineWidth: Number,
// Stroke style of the legend box
strokeStyle: Color
// Point style of the legend box (only used if usePointStyle is true)
pointStyle: String
}
Example
The following example will create a chart with the legend enabled and turn all of the text red in color.
var chart = new Chart(ctx, {
type: 'bar',
data: data,
options: {
legend: {
display: true,
labels: {
fontColor: 'rgb(255, 99, 132)'
}
}
}
});
Custom On Click Actions
It can be common to want to trigger different behaviour when clicking an item in the legend. This can be easily achieved using a callback in the config object.
The default legend click handler is:
function(e, legendItem) {
var index = legendItem.datasetIndex;
var ci = this.chart;
var meta = ci.getDatasetMeta(index);
// See controller.isDatasetVisible comment
meta.hidden = meta.hidden === null? !ci.data.datasets[index].hidden : null;
// We hid a dataset ... rerender the chart
ci.update();
}
Lets say we wanted instead to link the display of the first two datasets. We could change the click handler accordingly.
var defaultLegendClickHandler = Chart.defaults.global.legend.onClick;
var newLegendClickHandler = function (e, legendItem) {
var index = legendItem.datasetIndex;
if (index > 1) {
// Do the original logic
defaultLegendClickHandler(e, legendItem);
} else {
let ci = this.chart;
[ci.getDatasetMeta(0),
ci.getDatasetMeta(1)].forEach(function(meta) {
meta.hidden = meta.hidden === null? !ci.data.datasets[index].hidden : null;
});
ci.update();
}
};
var chart = new Chart(ctx, {
type: 'line',
data: data,
options: {
legend: {
}
}
});
Now when you click the legend in this chart, the visibility of the first two datasets will be linked together.
HTML Legends
Sometimes you need a very complex legend. In these cases, it makes sense to generate an HTML legend. Charts provide a generateLegend() method on their prototype that returns an HTML string for the legend.
To configure how this legend is generated, you can change the legendCallback config property.
var chart = new Chart(ctx, {
type: 'line',
data: data,
options: {
legendCallback: function(chart) {
// Return the HTML string here.
}
}
});

c3.js tooltip - make static and style

I have a c3.js stacked barchart that updates when you hover over a Leaflet map, and I need the tooltip to be static as otherwise the user will hover over other areas of the map and change the data in the barchart, before actually reaching it. However, I'm new to coding and especially new to C3 and I can't get around how to make the tooltip static. Also, does anyone know how to style the tooltip later? I have only found very complex examples online, but it feels like I should be able to do it somewhere after I generate the chart.
Any help would be much appreciated!
Here is my code:
function getMiniChartData(properties) {
var values = [
['rape', rape[properties['gss_code']]],
['other sexual', other_sexual[properties['gss_code']]]];
console.log(values);
return values;
}
var chart;
function drawMiniChart(properties) {
console.log('drawing mini chart');
var data = getMiniChartData(properties);
chart = c3.generate({
bindto: '#minichart',
color: {
pattern: ['#E31A1C', '#BD0026']
},
point: {
show: false
},
tooltip: {
show: true
},
data: {
columns: data,
type: 'bar',
groups: [
['rape', 'other sexual']
]
},
axis: {
y: {
max:60,
min:0
}
},
grid: {
y: {
lines: [{
value: 0
}]
}
}
});
}
function updateMiniChartData(properties) {
console.log('updating mini chart');
var data = getMiniChartData(properties);
chart.load({
columns: data
});
}
Just edit the position in the tooltip :
position: function () {
var position = c3.chart.internal.fn.tooltipPosition.apply(this, arguments);
position.top = 0;
return position;
}
This will set the tooltip to always be at the top of the point. So it stays at the same y coordinate (top:0) but follows the points x value. You could go further and set it to stay at one position on the page.
Check this fiddle I have put together : http://jsfiddle.net/thatOneGuy/owhxgaqm/185/
This question will help you out : C3 charts - contents of tooltip clickable
If you want it visible all the time just add this code :
var originalHideTooltip = chart.internal.hideTooltip
chart.internal.hideTooltip = function () {
setTimeout(originalHideTooltip, 100)
};

Add Region URL to Geochart

I am creating a map using Google Geochart and need a listener so that when the user clicks on a region it loads a given URL.
My code is:
google.load('visualization', '1.1', {packages: ['geochart'], callback: drawVisualization});
function drawVisualization() {
var data = google.visualization.arrayToDataTable([
['Country', 'Value', {role: 'tooltip', p:{html:true}}],
['US', 20, 'Test'],
['Canada', 20, 'http://www.ipfa.org/council/branches/106/ipfa-canada/'],
['GB', 20, 'http://www.ipfa.org/council/branches/52/ipfa-uk/'],
]);
var chart = new google.visualization.GeoChart(document.getElementById('visualization'));
google.visualization.events.addListener(chart, 'select', function () {
var selection = chart.getSelection();
var row = selection[0].row;
var url = data.getValue(row, 3);
window.open(url);
});
chart.draw(data, {
width: 800,
height: 600,
tooltip: {
isHtml: true
}
}
);
}
The URL listener works on another map I use, what am I doing wrong to not work on this one?
There are two issues. First, you are using the wrong index to reference your URLs; they are in column 2, not column 3 (which doesn't exist):
var url = data.getValue(row, 3);
Second, one of your URL's (for the US) is an anchor tag, which won't work if passed to the window.open call. If you want anchor tags in the tooltips, set the value of the cell to the URL and formatted value of the URL column to the anchor tag:
['US', 20, {v: 'http://www.ipfa.org/council/branches/39/ipfa-americas/', f: 'Test'}]
I would also suggest testing for the length of the selection array, because it is possible for the selection array to be empty if the user clicks a region twice in a row (the second click deselects the region), which would cause this line to throw an error:
var row = selection[0].row;
I suggest using this instead:
var selection = chart.getSelection();
if (selection.length) {
var url = data.getValue(selection[0].row, 2);
window.open(url);
}

Add Unique Links to all d3.js Data Points in Graph

I'm using nvd3.js to create a line graph that displays ratings that I have calculated over time. I have more information for each individual data point (rating) and would like to have each data point on the graph link to a unique page with more information about that specific data point.
For example: I would like to be able to hover over the first data point on the graph (x: 1345457533, y: -0.0126262626263) and click on it to go to a specific page (http://www.example.com/info?id=1) that provides more information about that rating or data point. Each data point has a unique id and unique url that I would like to link to.
Here is the code that I am using to generate the graph:
nv.addGraph(function() {
var chart = nv.models.lineChart();
chart.xAxis
.axisLabel('Time')
.tickFormat(d3.format('r'));
chart.yAxis
.axisLabel('Rating')
.tickFormat(d3.format('.2f'));
d3.select('#chart svg')
.datum(data())
.transition().duration(500)
.call(chart);
nv.utils.windowResize(chart.update);
return chart;
});
function data() {
var data = [ { x: 1345457533, y: -0.0126262626263 },
{ x: 1345457409, y: 0.0224089635854 },
{ x: 1345457288, y: 0.0270935960591 },
{ x: 1345457168, y: -0.0378151260504 },
{ x: 1345457046, y: -0.115789473684 } ]
return [
{
values: data,
key: "Sample1",
color: "#232066"
}
];
}
The HTML:
<div id="chart">
<svg></svg>
</div>
And here is a working example.
Here is an working solution http://jsfiddle.net/66hAj/7/
$('#chart svg').on('click', function(e){
var elem = $(e.target),
currentItem, currentUrl;
if(elem.parent('.nv-point-paths').length) {
currentItem = e.target.getAttribute('class').match(/\d+/)[0];
currentUrl = _data[0].urls[ currentItem ];
$('#log').text(currentUrl);
//window.location = currentUrl
}
})
I've used jQuery to bind a click handler on the canvas and then get the data based on the element clicked on the graph.
currentItem gives you the id of the current item that you clicked on
currentUrl gives the url related to the currently clicked item.
You can see the url change in the div below the chart as you click on each point over the graph.

Categories

Resources