Highcharts adding url to column chart - javascript

I am new to Highcharts, Sharepoint and JS. What I need to do is make each bar link to a SharePoint view
This code gets the data
IWSChartBuilder.EngagementsSegmentChart = function () {
var load = function () {
var year = new Date().getFullYear();
//Variable to hold counts
var countArray = [];
$.when(
//Consulting Engagements List
IWSChartBuilder.RESTQuery.execute("valid REST query")
).done(
function (engagements1) {
var dataArray = [];
var countArray = [];
//Get data from Consulting Engagements list
var results = engagements1.d.results;
for (var i = 0; i < results.length; i++) {
for (var i = 0; i < results.length; i++) {
dataArray.push(results[i].Segment);
}
}
var baseUrl = "valid url";
countArray = IWSChartBuilder.Utilities.buildCategoryCountsWithLink(countArray, dataArray, baseUrl);
//Put data into format for stacked bar chart
var seriesData = [];
var xCategories = [];
var links = [];
for (var i = 0; i < countArray.length; i++) {
xCategories.push(countArray[i].name);
seriesData.push(countArray[i].y);
links.push(countArray[i].url);
}
//Build Chart
IWSChartBuilder.Utilities.loadColumnChartWithLink(links, xCategories, seriesData, "#engagementSegmentChart", "Engagements by Segment", "Total Projects");
}
).fail(
function (engagements1) {
$("#engagementSegmentChart").html("<strong>An error has occurred.</strong>");
}
);
};
return {
load: load
}
}();
//code to display chart
loadColumnChartWithLink = function (xCategories, seriesData, divId, chartTitle, yAxisTitle) {
//Build Column Chart
$(divId).highcharts({
chart: {
type: 'column'
},
credits: {
enabled: false
},
title: {
text: chartTitle
},
xAxis: {
categories: xCategories,
allowDecimals: false,
labels: {
rotation: -45,
align: 'right'
}
},
yAxis: {
min: 0,
allowDecimals: false,
title: {
text: yAxisTitle
}
},
legend: {
enabled: false
},
plotOptions: {
bar: {
dataLabels: {
enabled: false
}
},
series: {
cursor: 'pointer',
point: {
events: {
click: function() {
location.href = this.options.url;
}
}
}
}
},
series: [{
name: yAxisTitle,
data: seriesData
}]
});
},
Any help is greatly appreciated
Mark

You need to adapt your data to create objects as points, like in the example:
{y:10,url:'http://google.com'}
and then catch click event on serie's point.
http://jsfiddle.net/2tL5T/

Related

how to remove duplicate data set labels in chartjs

I have the following bar chart that I loop through an array to add in new datasets as follows:
for (var i = 0; i < this.Chart.length; i++) {
barChartData.datasets.push({
label: this.Chart[i].name,
backgroundColor: this.chart[i].color
data: [{
x: //set details
y: //set details
}],
});
}
this.data = {
labels: moment.months(),
datasets: barChartData.datasets
};
this.config = {
type: 'bar',
data: this.data,
options: {
scales: {
x: {
stacked: true,
grid: {
display: false
}
},
y: {
stacked: true,
grid: {
display: false
}
}
},
datasets: {
bar: {
barThickness: 30
}
}
},
responsive: true,
maintainAspectRatio: true,
};
Everything works as expected the only issue is with this line:
label: this.Chart[i].name,
where I loop through the name of the label, I have duplicates because one label name can have multiple data associated to it for different months, which is correct behavior.
This is how it looks:
Is there a way on the chart that I could remove the duplicate label just for display purposes so it looks as:
You could remove duplicates from your list using this function
function remove_duplicates_safe(arr) {
var seen = {};
var ret_arr = [];
for (var i = 0; i < arr.length; i++) {
if (!(arr[i] in seen)) {
ret_arr.push(arr[i]);
seen[arr[i]] = true;
}
}
return ret_arr;
}
You can then do something like this or make any logic you need
var listNoDuplicates = remove_duplicates_safe(this.Chart);
replace this line
for (var i = 0; i < this.Chart.length; i++) {
with this line
for (var i = 0; i < listNoDuplicates.length; i++) {

Chart.js - how to have statis lables and populate with dynamic data?

I am working on chart.js and I have data coming from JSON via ajax. See the example below:
[{"timestamp":"06:00:00.000000","true_count":2},{"timestamp":"07:00:00.000000","true_count":5},{"timestamp":"08:00:00.000000","true_count":7},{"timestamp":"09:00:00.000000","true_count":8},{"timestamp":"10:00:00.000000","true_count":12},{"timestamp":"11:00:00.000000","true_count":15},{"timestamp":"12:00:00.000000","true_count":20},{"timestamp":"13:00:00.000000","true_count":17},{"timestamp":"14:00:00.000000","true_count":14},{"timestamp":"16:00:00.000000","true_count":11},{"timestamp":"17:00:00.000000","true_count":19},{"timestamp":"18:00:00.000000","true_count":22},{"timestamp":"19:00:00.000000","true_count":16},{"timestamp":"20:00:00.000000","true_count":14},{"timestamp":"22:00:00.000000","true_count":7}]
The JS code i am using for my chart is below:
// create initial empty chart
var ctx_live = document.getElementById("chLine");
var myChart = new Chart(ctx_live, {
type: 'bar',
data: {
labels: [],
datasets: [{
data: [],
borderWidth: 1,
borderColor:'#00c0ef',
label: 'liveCount',
}]
},
options: {
responsive: true,
title: {
display: true,
text: "Count Per Hour",
},
legend: {
display: false
},
scales: {
yAxes: [{
ticks: {
beginAtZero: true,
}
}]
}
}
});
// logic to get new data
var getData = function() {
var _data =[];
var _labels = [];
$.ajax({
url: 'chart_data',
type: "get",
success: function(data) {
full_data = JSON.parse(data);
full_data.forEach(function(key,index) {
_data.push(key.true_count);
_labels.push(key.hour);
});
myChart.data.labels = _labels;
myChart.data.datasets[0].data = _data;
myChart.update();
}
});
};
// get new data every 3 seconds
setInterval(getData, 3000);
Now, this is working fine and shows the true_count over time which is a one-hour basis. Now, the chart is showing only hours with count but what I would like to do is to set the static hours from 12 AM to 11 PM, and for hours for which I don't have data the true_count will be zero, and for those that I have data for, the true count will be assigned to that hour and show on the chart.
Any ideas on how do I do that?
Here is an example:
// create initial empty chart
var ctx_live = document.getElementById("chLine");
var myChart = new Chart(ctx_live, {
type: 'bar',
data: {
labels: [],
datasets: [{
data: [],
borderWidth: 1,
borderColor: '#00c0ef',
label: 'liveCount',
}]
},
options: {
responsive: true,
title: {
display: true,
text: "Count Per Hour",
},
legend: {
display: false
},
scales: {
yAxes: [{
ticks: {
beginAtZero: true,
}
}]
}
}
});
// Some constants to be changed later:
const HOUR_TO_START = 0;
const HOUR_TO_END = 23;
// helper:
const intToAmPm = (i) =>
i==0 ? '12 AM' :
i==12 ? '12 PM' :
i < 12 ? i + ' AM' :
(i-12) + ' PM';
// logic to get new data
var getData = function() {
var _data = [];
var _labels = [];
$ajax({
url: 'chart_data',
type: "get",
success: function(data) {
full_data = JSON.parse(data);
let preparedData = {};
full_data.forEach(function(key, index) {
let hour = parseInt(String(key.timestamp).substring(0, 2));
preparedData[hour] = key.true_count;
});
for (let i = HOUR_TO_START; i <= HOUR_TO_END; i++) {
_data.push(preparedData[i] === undefined ? 0 : preparedData[i]);
_labels.push(intToAmPm(i));
}
myChart.data.labels = _labels;
myChart.data.datasets[0].data = _data;
myChart.update();
}
});
};
// get new data every 3 seconds
//setInterval(getData, 3000);
getData();
// THIS IS FOR TESTING. IMITATE BACKEND
function $ajax(param) {
param.success('[{"timestamp":"06:00:00.000000","true_count":2},{"timestamp":"07:00:00.000000","true_count":5},{"timestamp":"08:00:00.000000","true_count":7},{"timestamp":"09:00:00.000000","true_count":8},{"timestamp":"10:00:00.000000","true_count":12},{"timestamp":"11:00:00.000000","true_count":15},{"timestamp":"12:00:00.000000","true_count":20},{"timestamp":"13:00:00.000000","true_count":17},{"timestamp":"14:00:00.000000","true_count":14},{"timestamp":"16:00:00.000000","true_count":11},{"timestamp":"17:00:00.000000","true_count":19},{"timestamp":"18:00:00.000000","true_count":22},{"timestamp":"19:00:00.000000","true_count":16},{"timestamp":"20:00:00.000000","true_count":14},{"timestamp":"22:00:00.000000","true_count":7}]');
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.9.3/Chart.min.js"></script>
<canvas id="chLine"></canvas>

Chart.js showing old chart on hover

I am having 3 different charts on my web page for which I am using Chartjs. The problem occurs when I hover over one of the charts it starts showing old data. I am creating chart on a HTML button click. I checked few answers on stackoverflow (for eg. destroy()) but that is not working for me. Below is the function for chart. please guide me regarding this.
<script>
function dailyPrd1() {
var pl_type1 = "";
var pl_sl1 = "";
var date1="";
pl_type1 = plant_type1.options[plant_type1.selectedIndex].innerHTML;
//alert(pl_type1);
pl_sl1 = plant_select1.options[plant_select1.selectedIndex].innerHTML;
//alert(pl_sl1);
date1 = document.getElementById('date2').value;
//alert(date1);
var pl2 = "";
pl2 = pl_type1 + '-' + pl_sl1;
var obj2 = "";
var hrs1 = [];
var prod1 = [];
var colr1 = [];
var req2 = new XMLHttpRequest();
var config_string2 = '<%=ConfigurationManager.AppSettings["serverip11"].ToString() %>' + pl_sl1 + "/" + pl_type1 + "/" + date1;
req2.open("GET", config_string2, true);
req2.send();
req2.overrideMimeType("application/json");
req2.onload = function () {
obj2 = JSON.parse(this.response);
obj2 = JSON.parse(obj2);
var len12 = 0;
len12 = obj2.day_list.length;
for (i = 0; i < len12; i++) {
hrs1.push(obj2.day_list[i].day);
}
var speedCanvas2 = document.getElementById("myChart3");
Chart.defaults.global.defaultFontFamily = "Lato";
Chart.defaults.global.defaultFontSize = 16;
var chartOptions2 = {
responsive: true,
scales: {
xAxes: [{
display: true,
scaleLabel: {
display: true,
labelString: 'Days'
}
}],
yAxes: [{
display: true,
scaleLabel: {
display: true,
labelString: 'Value in cu.m'
}
}]
},
legend: {
display: true,
position: 'top',
labels: {
boxWidth: 80,
fontColor: 'black'
}
}
};
var speedData2 = {
labels: hrs1,
// datasets: [dataFirst, dataSecond]
};
var lineChart2 = new Chart(speedCanvas2, {
type: 'bar',
data: speedData2,
options: chartOptions2
});
var iti1 = 0;
iti1 = obj2.prod_qty.length;
var aaa = 'Pl 1'
for (j = 0; j < iti1; j++) {
prod1.push(obj2.prod_qty[j].tot_prod);
}
addData(lineChart2, pl2, getRandomColor(), prod1);
}
}
</script>
After you change your data you should update your chart with chartVariable.update().
I made a JSBin which explains you how to use it.
The important function for you is the last in the code, addDataButton() which gets triggered by a button click. In this function I add new data and update my chart after that.
Instead of chartVariable and chart you should use lineChart2 in your case.
Complete code:
let numberOfDataCounter = 0 // Current data counter
const numberOfDataAtBeginning = 4 // data number to start with
const weekdays = ["Su", "Mo", "Du", "We", "Th", "Fr", "Sa"]
function randomNumber(){
let randomNumber = Math.floor(Math.random()*100)
return randomNumber
}
let chartData = {
label: [],
data: []
}
function addData (){
chartData.label.push(weekdays[numberOfDataCounter % 7])
chartData.data.push(randomNumber())
numberOfDataCounter++
}
// Fill chart with data at beginning
while (numberOfDataAtBeginning>numberOfDataCounter) {
addData()
}
let data = {
labels: chartData.label,
datasets: [{
label: "Label",
data: chartData.data
}]
}
let chart = new Chart(document.getElementById("chart"), {
type: 'line',
data: data,
options: {
scales: {
yAxes: [{
ticks: {
min: 0,
max: 100
}
}]
}
}
});
function addDataButton(){
addData()
chart.update()
}

put your own series in highcharts sereis

I am trying to pass in my_series to series in highcharts to graph stacked bars. From my php, I get hash, which is like this:
{"Oat":{"10":"AA","11":"H"},"Brown Rice":{"10":"AA","11":"BB"}}
I actually dont know what is wrong with my code. I think it should work, but when I run it, I do not see anything on the screen. I checked that sample_name has "Oat" and "Brown Rice", which is what I want.
What I eventually want is a color-coded stacked bar graph that has samples on the yAxis and position on the xAxis. I think I almost got to what I want, it's just a problem with making an actual graph.
Thank you!
$(function() {
var allele_str = [];
var sample_name = [];
var hash = {};
var my_series = {
data: []
};
var position = [];
var options = {
chart: {
renderTo: 'container',
defaultSeriesType: 'bar',
zoomType: 'xy',
inverted: true
},
title: {
text: 'Gene'
},
xAxis: {
categories: [],
},
legend: {
enabled: false
},
yAxis: {
title: {
text: 'Position'
},
labels: {
enabled: false
}
}
plotOptions: {
series: {
stacking: 'normal'
}
}
series: []
};
$.getJSON('6K_load.php', function(data) {
sample_name = Object.keys(data);
options.xAxis.categories.push(sample_name);
for (var x in sample_name) { // sample Oat, BR
for (var k in data[sample_name[x]]) { // pos
series.name = k;
var z = data[sample_name[x]][k];
hash[z] = 1;
allele_str.y = hash[z];
if (z === 'AA') {
allele_str.color = 'grey';
}
if (z === 'BB') {
allele_str.color = 'blue';
}
if (z === '--') {
allele_str.color = 'white';
}
if (z === 'H') {
allele_str.color = 'red';
}
my_series.data.push(allele_str);
}
options.series.push(my_series);
}
var chart = new Highcharts.Chart(options);
});
});
The problem is that you not parse your data to number value, you need to use parseFloat() in this line
my_series.data.push(parseFloat(allele_str));

Adding series dynamically in highcharts

(function($){
$(function () {
$(document).ready(function() {
Highcharts.setOptions({
global: {
useUTC: false
}
});
var i=0;
var chart = new Highcharts.Chart({
chart: {
type: 'spline',
renderTo: 'container',
animation: Highcharts.svg, // don't animate in old IE
marginRight: 10,
events: {
load: function() {
// set up the updating of the chart each second
var series = this.series[0];
setInterval(function() {
var Name = new Array();
Name[0] = "Random data";
Name[1] = "Volvo";
var length=chart.series.length;
var flag=0;
var index=0;
var x = (new Date()).getTime(), // current time
y = Math.random();
for (var k=0;k<Name.length;k++) {
for(var j=0;j<chart.series.length;j++) {
if(chart.series[j].name==Name[k]) {
flag=1;
index=j;
x = (new Date()).getTime();
y = Math.random();
break;
}
}
if(flag==1) {
chart.series[index].addPoint([x, y], true, true);
flag=0;
} else {
chart.addSeries({name: '' + Name[k] + '', data: [] });
chart.series[length].addPoint([x, y+1], true);
length=length+1;
}
}
}, 1000);
}
}
},
title: {
text: 'Live random data'
},
xAxis: {
type: 'datetime',
tickPixelInterval: 150
},
yAxis: {
title: {
text: 'Value'
},
plotLines: [{
value: 0,
width: 1,
color: '#808080'
}]
},
tooltip: {
formatter: function() {
return '<b>'+ this.series.name +'</b><br/>'+
Highcharts.dateFormat('%Y-%m-%d %H:%M:%S', this.x) +'<br/>'+
Highcharts.numberFormat(this.y, 2);
}
},
legend: {
enabled: false
},
exporting: {
enabled: false
},
series: [{
name: 'Random data',
data: (function() {
// generate an array of random data
var data = [],
time = (new Date()).getTime(),
i;
for (i = -19; i <= 0; i++) {
data.push({
x: time + i * 1000,
y: Math.random()
});
}
return data;
})()
}]
});
});
});
})(jQuery);
I am able to add series and add point in charts but the series that I add after initialization, which is "volvo", is not drawing lines between its points. What might be the problem?
And is there any other way of comparing arrays and adding points without a for-loop? Because I can get millions of series at times and I don't want to be looping over arrays to check if it exists or not. So is there any efficient way of finding wheteher a list already exists, and if it does what is its index?
here is its fiddle: www.jsfiddle.net/2jYLz/
It is related with fact that you have enabled shifting in addPoint() when you add new serie. In other words, shifting remove first point and add new in the end of serie. So when you have one point it caused your scenario. So you need to disable shipfing, and when lenght of series.data achieve i.e 10 points, shifting should be enabled.

Categories