Hi guys quit knew in the JS world so I have a question,
Anoyone knows how I can get the variable ' Totaal_dataset' only in the label of the chart and not as a 3rd bar in the chart?
Below the code and the ability to play with it. It's a compound interest calculator.
https://codepen.io/sietssoo/pen/oNqGpXq
(function () {
var initial_deposit = document.querySelector('#initial_deposit'),
contribution_amount = document.querySelector('#contribution_amount'),
investment_timespan = document.querySelector('#investment_timespan'),
investment_timespan_text = document.querySelector('#investment_timespan_text'),
estimated_return = document.querySelector('#estimated_return'),
future_balance = document.querySelector('#future_balance');
function updateValue(element, action) {
var min = parseFloat(element.getAttribute('min')),
max = parseFloat(element.getAttribute('max')),
step = parseFloat(element.getAttribute('step')) || 1,
oldValue = element.dataset.value || element.defaultValue || 0,
newValue = parseFloat(element.value.replace(/\€/, ''));
if (isNaN(parseFloat(newValue))) {
newValue = oldValue;
} else {
if (action == 'add') {
newValue += step;
} else if (action == 'sub') {
newValue -= step;
}
newValue = newValue < min ? min : newValue > max ? max : newValue;
}
element.dataset.value = newValue;
element.value = (element.dataset.prepend || '') + newValue + (element.dataset.append || '');
updateChart();
}
function getChartData() {
var P = parseFloat(initial_deposit.dataset.value), // Principal
r = parseFloat(estimated_return.dataset.value / 100), // Annual Interest Rate
c = parseFloat(contribution_amount.dataset.value), // Contribution Amount
n = parseInt(document.querySelector('[name="compound_period"]:checked').value), // Compound Period
n2 = parseInt(document.querySelector('[name="contribution_period"]:checked').value), // Contribution Period
t = parseInt(investment_timespan.value), // Investment Time Span
currentYear = (new Date()).getFullYear()
;
var labels = [];
for (var year = currentYear; year < currentYear + t; year++) {
labels.push(year);
}
var balance_dataset = {
label: 'Totaal:',
grouped: false,
data: []
};
var principal_dataset = {
label: 'Totaal geïnvesteerd:',
backgroundColor: 'rgb(240, 202, 98)',
data: []
};
var interest_dataset = {
label: "+ Totale winst: ",
backgroundColor: 'rgb(14, 93, 51)',
data: []
};
for (var i = 1; i <= t; i++) {
var principal = P + ( c * n2 * i ),
interest = 0,
balance = principal;
if (r) {
var x = Math.pow(1 + r / n, n * i),
compound_interest = P * x,
contribution_interest = c * (x - 1) / (r / n2);
interest = (compound_interest + contribution_interest - principal).toFixed(0)
balance = (compound_interest + contribution_interest).toFixed(0);
}
future_balance.innerHTML = '€' + balance;
principal_dataset.data.push(principal);
interest_dataset.data.push(interest);
balance_dataset.data.push(balance);
}
return {
labels: labels,
datasets: [principal_dataset, interest_dataset]
}
}
function updateChart() {
var data = getChartData();
chart.data.labels = data.labels;
chart.data.datasets[0].data = data.datasets[0].data;
chart.data.datasets[1].data = data.datasets[1].data;
chart.update();
}
initial_deposit.addEventListener('change', function () {
updateValue(this);
});
contribution_amount.addEventListener('change', function () {
updateValue(this);
});
estimated_return.addEventListener('change', function () {
updateValue(this);
});
investment_timespan.addEventListener('change', function () {
investment_timespan_text.innerHTML = this.value + ' years';
updateChart();
});
investment_timespan.addEventListener('input', function () {
investment_timespan_text.innerHTML = this.value + ' years';
});
var radios = document.querySelectorAll('[name="contribution_period"], [name="compound_period"]');
for (var j = 0; j < radios.length; j++) {
radios[j].addEventListener('change', updateChart);
}
var buttons = document.querySelectorAll('[data-counter]');
for (var i = 0; i < buttons.length; i++) {
var button = buttons[i];
button.addEventListener('click', function () {
var field = document.querySelector('[name="' + this.dataset.field + '"]'),
action = this.dataset.counter;
if (field) {
updateValue(field, action);
}
});
}
var ctx = document.getElementById('myChart').getContext('2d'),
chart = new Chart(ctx, {
type: 'bar',
data: getChartData(),
options: {
legend: {
display: false
},
tooltips: {
mode: 'index',
intersect: false,
callbacks: {
label: function (tooltipItem, data) {
return data.datasets[tooltipItem.datasetIndex].label + '€ ' + tooltipItem.yLabel;
}
}
},
responsive: true,
scales: {
xAxes: [{
stacked: true,
scaleLabel: {
display: true,
labelString: 'Jaar'
}
}],
yAxes: [{
stacked: true,
ticks: {
callback: function (value) {
return '€' + value;
}
},
scaleLabel: {
display: true
}
}]
}
}
});
})();`
Related
The Chart.js plugin is super, excellent, beautiful and easily customizable.
But even all this did not help me solve a few problems.
I have to create pixel perfect chart according to design shown on picture 1
I hope for your help!!
How to make those lines that without signatures be longer than those with signatures
I did the indentation from the scales to the graphs using the tickMarkLength parameter, but maybe it’s possible somehow under another, because you can see the overlap of one scale on another.
How to make the grid lines of the left and right scales coincide?
I set beforeUpdate .stepSize, but in spite of the fact that I specify that there should be 8 intervals, sometimes 8, then 9.
There is a link to my current code:
function data_generation(values_obj) {
let max_val=-900;
let min_val=0;
Object.keys(values_obj).forEach(function(key) {
chart_object={};
chart_object.label= values_obj[key].name;
chart_object.data= Object.values(values_obj[key].data);
chart_object.backgroundColor= values_obj[key].color;
if(key == 'TempOutdoor') {
chart_object.yAxisID = 'right-y-axis';
chart_object.backgroundColor= "transparent";
chart_object.pointRadius= 4;
chart_object.lineTension= 0;
chart_object.pointBackgroundColor="#FFF";
chart_object.pointBorderColor= "#60AD5E";
chart_object.borderColor= "#60AD5E";
chart_object.pointBorderWidth= 2;
chart_object.type= 'line';
} else {
chart_object.yAxisID = 'left-y-axis';
chart_object.lineTension= 0;
}
config.data.datasets.push(chart_object);
//find common min and max values
//min
if(min_val>parseFloat(values_obj[key].min)) {
min_val = parseFloat(values_obj[key].min);
}
//max
if(max_val < parseFloat(values_obj[key].max)) {
max_val = parseFloat(values_obj[key].max);
}
});
}
var config = {
drawTicks:false,
type: 'bar',
data: {
datasets: [ ],
labels: ''
},
options: {
animation: {
duration: 0
},
'legend':false,
responsive:true,
maintainAspectRatio: false,
scales: {
xAxes: [{
stacked: true,
barThickness: ($(window).width()<991.99)?14:24,
ticks: {
fontSize: ($(window).width()<991.99)?10:14,
},
gridLines : {
display : false
}
}],
yAxes: [
{
beforeUpdate: function(scale) {
//1 find max and min through all leftlabels
var left_side_list = config.data.datasets.filter(obj => {return obj.yAxisID == "left-y-axis"});
var left_side_list_data = [].concat(...Object.keys(left_side_list).map(e => left_side_list[e].data));
let max_val = Math.max.apply(Math,left_side_list_data);
let min_val = Math.min.apply(Math,left_side_list_data);
// 8 intervals - 9 lines
let left_iterval = (max_val - min_val) / 8;
//set stepsize
scale.chart.options.scales.yAxes[0].ticks.stepSize = left_iterval;
return;
},
id: 'left-y-axis',
type: 'linear',
position: 'left',
ticks: {
beginAtZero: false,
fontSize: ($(window).width()<991.99)?10:14,
callback: function(value, index, values) {
if(index % 2 == 0 || index==0) {
return ' ';
} else {
return " "+value.toFixed(0)+" ";
}
}
},
gridLines: {
drawBorder: false,
tickMarkLength: ($(window).width()<991.99)?34:84,
}
},
{
beforeUpdate: function(scale) {
//var nMaxRev = Math.max.apply(Math,scale.chart.config.data.datasets[1].data);
//get right object data
var temp_list = config.data.datasets.filter(obj => {return obj.yAxisID == "right-y-axis"});
//var temp_list = scale.chart.config.data.datasets.filter(obj => {return obj.yAxisID == "right-y-axis"});
//console.log(temp_list);
if(temp_list[0].data !== undefined || temp_list[0].data != []) {
var nMaxRev = Math.max.apply(Math, temp_list[0].data);
var nMinRev = Math.min.apply(Math, temp_list[0].data);
var nLeftTickCount = 8;
if(nMinRev<0) {
nLeftTickCount = 7;
}
var nTickInterval = (nMaxRev - nMinRev) / nLeftTickCount;
scale.chart.options.scales.yAxes[1].ticks.stepSize = nTickInterval;
}
return;
},
id: 'right-y-axis',
type: 'linear',
position: 'right',
ticks: {
beginAtZero: false,
fontSize: ($(window).width()<991.99)?10:14,
callback: function(value, index, values) {
if(index % 2 == 0 || index==0) {
return '';
} else {
return " "+value.toFixed(0);
}
}
},
gridLines: {
drawBorder: false,
tickMarkLength: ($(window).width()<991.99)?34:84,
}
}
]
}
}
};
window.onload = function() {
var data_string='{"success":true,"axis":["Пн","Вт","Ср","Чт","Пт","Сб","Вс"],"data":{"TempOutdoor":{"period_start":"2021-05-10 00:00:00","period_end":"2021-05-16 23:59:59","data":{"Пн":-4.9787234042553195,"Вт":-2.9166666666666665,"Ср":-3.3125,"Чт":2.5208333333333335,"Пт":6.84375,"Сб":0,"Вс":0},"min":"-4.98","max":"6.84","avg":"-0.26","sum":"-1.84","name":"Температура на улице","color":"#60AD5E","value_type":"instant"},"MotoHW":{"period_start":"2021-05-10 00:00:00","period_end":"2021-05-16 23:59:59","data":{"Пн":11,"Вт":15,"Ср":13,"Чт":12,"Пт":9,"Сб":0,"Вс":0},"min":"0.00","max":"15.00","avg":"8.57","sum":"60.00","name":"Мотогодини: Гаряча вода","color":"#29819D","value_type":"counter"}},"closestPeriods":{"previous":{"2021-05-03 00:00:00":"03.05 - 09.05"},"current":{"2021-05-10 00:00:00":"10.05 - 16.05"},"next":null}}';
var data = JSON.parse(data_string);
config.data.labels = data.axis;
var values_obj = data.data;
data_generation(values_obj);
//console.log(JSON.stringify(config));
var ctx = document.getElementById('StatisticsChartCanvas').getContext('2d');
window.StatisticsChart = new Chart(ctx,config);
};
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.9.3/Chart.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="chart-wrapper" style="width:548px; height:265px;">
<canvas id="StatisticsChartCanvas"></canvas>
</div>
After a huge amount of ideas, attempts and errors, I found a solution for the full customization of the scale.
For this I
Disabled the display of gridlines and ticks using property
display:false,
Wrote a plugin that draw gridlines and ticks in accordance with the design.
That's what happened
var AikGridLinePlugin = {
beforeDraw: function(chartInstance) {
var yScaleLeft = chartInstance.scales["left-y-axis"];
var yScaleRight = chartInstance.scales["right-y-axis"];
var canvas = chartInstance.chart;
var ctx = canvas.ctx;
//left axis
var left_side_list = chartInstance.data.datasets.filter(obj => {return obj.yAxisID == "left-y-axis"});
var left_side_list_data = [].concat(...Object.keys(left_side_list).map(e => left_side_list[e].data));
let left_side_list_max = Math.max.apply(Math,left_side_list_data);
let left_side_list_min = Math.min.apply(Math,left_side_list_data);
let left_iterval = (left_side_list_max - left_side_list_min) / 8;
// right axis
var right_side_list = chartInstance.data.datasets.filter(obj => {return obj.yAxisID == "right-y-axis"});
var right_side_list_data = [].concat(...Object.keys(right_side_list).map(e => right_side_list[e].data));
let right_side_list_max = Math.max.apply(Math,right_side_list_data);
let right_side_list_min = Math.min.apply(Math,right_side_list_data);
let right_iterval = (right_side_list_max - right_side_list_min) / 8;
var current_value_left = left_side_list_min,
current_value_right = right_side_list_min,
current_value_right_text=0;
for(var i=1;i<10;i++) {
ctx.lineWidth = 1;
ctx.font = "13px Roboto";
ctx.fillStyle = "#666666";
ctx.beginPath();
if(i%2==0) {
ctx.moveTo(47, yScaleLeft.getPixelForValue(current_value_left));
ctx.lineTo((canvas.width-47), yScaleLeft.getPixelForValue(current_value_left));
ctx.fillText((current_value_left>1)?current_value_left.toFixed(0):current_value_left.toFixed(1), 5, yScaleLeft.getPixelForValue(current_value_left)+5);
current_value_right_text=(current_value_right>1 || current_value_right<-1)?current_value_right.toFixed(0):current_value_right.toFixed(1);
ctx.fillText(current_value_right_text, (canvas.width-5-ctx.measureText(current_value_right_text).width), yScaleLeft.getPixelForValue(current_value_left)+5);
} else {
ctx.moveTo(15, yScaleLeft.getPixelForValue(current_value_left));
ctx.lineTo((canvas.width-15), yScaleLeft.getPixelForValue(current_value_left));
}
ctx.strokeStyle = "#91979F";
ctx.stroke();
current_value_left = current_value_left+left_iterval;
current_value_right = current_value_right+right_iterval;
}
return;
}
};
Chart.pluginService.register(AikGridLinePlugin);
function data_generation(values_obj) {
let max_val=-900;
let min_val=0;
Object.keys(values_obj).forEach(function(key) {
chart_object={};
chart_object.label= values_obj[key].name;
chart_object.data= Object.values(values_obj[key].data);
chart_object.backgroundColor= values_obj[key].color;
if(key == 'TempOutdoor') {
chart_object.yAxisID = 'right-y-axis';
chart_object.backgroundColor= "transparent";
chart_object.pointRadius= 4;
chart_object.lineTension= 0;
chart_object.pointBackgroundColor="#FFF";
chart_object.pointBorderColor= "#60AD5E";
chart_object.borderColor= "#60AD5E";
chart_object.pointBorderWidth= 2;
chart_object.type= 'line';
} else {
chart_object.yAxisID = 'left-y-axis';
chart_object.lineTension= 0;
}
config.data.datasets.push(chart_object);
//find common min and max values
//min
if(min_val>parseFloat(values_obj[key].min)) {
min_val = parseFloat(values_obj[key].min);
}
//max
if(max_val < parseFloat(values_obj[key].max)) {
max_val = parseFloat(values_obj[key].max);
}
});
}
var config = {
drawTicks:false,
type: 'bar',
data: {
datasets: [ ],
labels: ''
},
options: {
animation: {
duration: 0
},
'legend':false,
responsive:true,
maintainAspectRatio: false,
scales: {
xAxes: [{
id: 'x-axis',
stacked: true,
barThickness: ($(window).width()<991.99)?14:24,
ticks: {
fontSize: ($(window).width()<991.99)?10:14,
},
gridLines : {
display : false
}
}],
yAxes: [
{
id: 'left-y-axis',
type: 'linear',
position: 'left',
ticks: {
display:false,
},
gridLines: {
display : false,
drawBorder: false,
tickMarkLength: ($(window).width()<991.99)?34:84,
}
},
{
id: 'right-y-axis',
type: 'linear',
position: 'right',
ticks: {
display : false,
beginAtZero: false,
fontSize: ($(window).width()<991.99)?10:14,
},
gridLines: {
display : false,
drawBorder: false,
tickMarkLength: ($(window).width()<991.99)?34:84,
}
}
]
}
}
};
window.onload = function() {
var data_string='{"success":true,"axis":["Пн","Вт","Ср","Чт","Пт","Сб","Вс"],"data":{"TempOutdoor":{"period_start":"2021-05-10 00:00:00","period_end":"2021-05-16 23:59:59","data":{"Пн":-4.9787234042553195,"Вт":-2.9166666666666665,"Ср":-3.3125,"Чт":2.5208333333333335,"Пт":6.84375,"Сб":0,"Вс":0},"min":"-4.98","max":"6.84","avg":"-0.26","sum":"-1.84","name":"Температура на улице","color":"#60AD5E","value_type":"instant"},"MotoHW":{"period_start":"2021-05-10 00:00:00","period_end":"2021-05-16 23:59:59","data":{"Пн":11,"Вт":15,"Ср":13,"Чт":12,"Пт":9,"Сб":0,"Вс":0},"min":"0.00","max":"15.00","avg":"8.57","sum":"60.00","name":"Мотогодини: Гаряча вода","color":"#29819D","value_type":"counter"}},"closestPeriods":{"previous":{"2021-05-03 00:00:00":"03.05 - 09.05"},"current":{"2021-05-10 00:00:00":"10.05 - 16.05"},"next":null}}';
var data = JSON.parse(data_string);
config.data.labels = data.axis;
var values_obj = data.data;
data_generation(values_obj);
//console.log(JSON.stringify(config));
var ctx = document.getElementById('StatisticsChartCanvas').getContext('2d');
window.StatisticsChart = new Chart(ctx,config);
};
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.9.3/Chart.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="chart-wrapper" style="width:548px; height:265px;">
<canvas id="StatisticsChartCanvas"></canvas>
</div>
Trying to show two pie charts in the same page but it doesn't work. This is the code:
<html>
<head>
</head>
<body>
<canvas id="tests-summary" height="50px"></canvas>
<canvas id="exceptions-summary" height="50px"></canvas>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.4.0/Chart.min.js"></script>
<script>
// Tests pie chart
var testSummaryData = {
datasets: [{
data: [
55,
114,
152
],
backgroundColor: [
"#82bc41",
"#bbbbbb",
"#c8102e"
],
label: 'My dataset' // for legend
}],
labels: [
"Passed",
"Skipped",
"Failed"
]
};
var testSummaryOptions = {
events: false,
animation: {
duration: 500,
easing: "easeOutQuart",
onComplete: function () {
var ctx = this.chart.ctx;
ctx.font = "bold 16px Arial";
ctx.textAlign = 'center';
ctx.textBaseline = 'bottom';
this.data.datasets.forEach(function (dataset) {
for (var i = 0; i < dataset.data.length; i++) {
var model = dataset._meta[Object.keys(dataset._meta)[0]].data[i]._model,
total = dataset._meta[Object.keys(dataset._meta)[0]].total,
mid_radius = model.innerRadius + (model.outerRadius - model.innerRadius)/2,
start_angle = model.startAngle,
end_angle = model.endAngle,
mid_angle = start_angle + (end_angle - start_angle)/2;
var x = mid_radius * Math.cos(mid_angle);
var y = mid_radius * Math.sin(mid_angle);
ctx.fillStyle = '#fff';
if (i == 1){ // Darker text color for lighter background
ctx.fillStyle = '#444';
}
var percent = String(Math.round(dataset.data[i]/total*100)) + "%";
//Don't Display If Legend is hide or value is 0
if(dataset.data[i] != 0 && dataset._meta[0].data[i].hidden != true) {
ctx.fillText(dataset.data[i], model.x + x, model.y + y);
// Display percent in another line, line break doesn't work for fillText
ctx.fillText(percent, model.x + x, model.y + y + 15);
}
}
});
}
}
};
var testSummaryCanvas = $("#tests-summary");
var testSummaryPieChart = new Chart(testSummaryCanvas, {
type: 'pie',
data: testSummaryData,
options: testSummaryOptions
});
var exceptionsSummaryData = {
datasets: [{
data: [
55,
114
],
backgroundColor: [
"#82bc41",
"#bbbbbb"
],
label: 'My dataset' // for legend
}],
labels: [
"Passed",
"Skipped"
]
};
var exceptionsSummaryOptions = {
events: false,
animation: {
duration: 500,
easing: "easeOutQuart",
onComplete: function () {
var ctx = this.chart.ctx;
ctx.font = "bold 16px Arial";
ctx.textAlign = 'center';
ctx.textBaseline = 'bottom';
this.data.datasets.forEach(function (dataset) {
for (var i = 0; i < dataset.data.length; i++) {
var model = dataset._meta[Object.keys(dataset._meta)[0]].data[i]._model,
total = dataset._meta[Object.keys(dataset._meta)[0]].total,
mid_radius = model.innerRadius + (model.outerRadius - model.innerRadius)/2,
start_angle = model.startAngle,
end_angle = model.endAngle,
mid_angle = start_angle + (end_angle - start_angle)/2;
var x = mid_radius * Math.cos(mid_angle);
var y = mid_radius * Math.sin(mid_angle);
ctx.fillStyle = '#fff';
if (i == 1){ // Darker text color for lighter background
ctx.fillStyle = '#444';
}
var percent = String(Math.round(dataset.data[i]/total*100)) + "%";
//Don't Display If Legend is hide or value is 0
if(dataset.data[i] != 0 && dataset._meta[0].data[i].hidden != true) {
ctx.fillText(dataset.data[i], model.x + x, model.y + y);
// Display percent in another line, line break doesn't work for fillText
ctx.fillText(percent, model.x + x, model.y + y + 15);
}
}
});
}
}
};
var exceptionsCanvas = $("#exceptions-summary");
var exceptionsPieChart = new Chart(exceptionsCanvas, {
type: 'pie',
data: exceptionsSummaryData,
options: exceptionsSummaryOptions
});
</script>
</body>
</html>
The existing Logarithmic Axis defaults to the base of 10. Is there a way to change the scale to a logarithm of a different base?
You can implement a custom scale to change the base of the the log scale like so:
class Log2Axis extends Chart.Scale {
constructor(cfg) {
super(cfg);
this._startValue = undefined;
this._valueRange = 0;
}
parse(raw, index) {
const value = Chart.LinearScale.prototype.parse.apply(this, [raw, index]);
return isFinite(value) && value > 0 ? value : null;
}
determineDataLimits() {
const {
min,
max
} = this.getMinMax(true);
this.min = isFinite(min) ? Math.max(0, min) : null;
this.max = isFinite(max) ? Math.max(0, max) : null;
}
buildTicks() {
const ticks = [];
let power = Math.floor(Math.log2(this.min || 1));
let maxPower = Math.ceil(Math.log2(this.max || 2));
while (power <= maxPower) {
ticks.push({
value: Math.pow(2, power)
});
power += 1;
}
this.min = ticks[0].value;
this.max = ticks[ticks.length - 1].value;
return ticks;
}
/**
* #protected
*/
configure() {
const start = this.min;
super.configure();
this._startValue = Math.log2(start);
this._valueRange = Math.log2(this.max) - Math.log2(start);
}
getPixelForValue(value) {
if (value === undefined || value === 0) {
value = this.min;
}
return this.getPixelForDecimal(value === this.min ? 0 :
(Math.log2(value) - this._startValue) / this._valueRange);
}
getValueForPixel(pixel) {
const decimal = this.getDecimalForPixel(pixel);
return Math.pow(2, this._startValue + decimal * this._valueRange);
}
}
Log2Axis.id = 'log2';
Log2Axis.defaults = {};
Chart.register(Log2Axis);
var options = {
type: 'line',
data: {
labels: ["Red", "Blue", "Yellow", "Green", "Purple", "Orange", "Black", "White"],
datasets: [{
label: '# of Votes',
data: [8, 3, 60, 20, 130, 80, 1030, 250],
backgroundColor: 'pink',
borderColor: 'pink'
}]
},
options: {
scales: {
x: {
display: true
},
y: {
display: true,
type: 'log2',
}
}
}
}
var ctx = document.getElementById('chartJSContainer').getContext('2d');
new Chart(ctx, options);
<body>
<canvas id="chartJSContainer" width="600" height="400"></canvas>
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/3.4.0/chart.js"></script>
</body>
Fiddle link: https://jsfiddle.net/Leelenaleee/oyLf0wed/6/
Credit to chart.js team who made a sample for this: https://www.chartjs.org/docs/master/samples/advanced/derived-axis-type.html
I have web monitoring data and I want to graph with chart js library in javascript.
Multiple data are at the same moment. However, 'tooltip' displays only one piece of data. Why is this?
Please help me :(
I (A) Login-swlee.zabbix.dev selected and time is 06/25 02:23:21
I (B) First page-swlee.zabbix.dev selected and time is 06/25 02:23:21
I (A) and (B) both selected but tooltip is only one.
```
var colors = ["#FEB500", "#5F8CFC", "#ADC803", "#F0605D"]
var list = data.list;
var list2 = data.list2;
var list3 = data.list3;
var datasets = [];
var labels = [];
for (i = 0; i < list3.length; i++) {
var date = new Date(list3[i].clock * 1000).getTime();
if (labels.indexOf(date) < 0) {
labels.push(date);
}
}
labels.sort();
var tbody = document.getElementById('webTable').children[1];
for (var i = 0; i < list.length; i++) {
var item = list[i];
var td_name = [];
for (var j = 0; j < list2.length; j++) {
var item2 = list2[j];
if (item.hosts[0].hostid == item2.hostid && item2.key_.indexOf('web.test.rspcode') > -1) {
var label = item2.name.replace('$1', item2.key_.substring(17, item2.key_.length - 1).split(',')[0]).replace('$2', item2.key_.substring(17, item2.key_.length - 1).split(',')[1]);
//line chart
var dataset = {
data: [],
label: label,
fill: false,
spanGaps: true,
borderColor: colors[i]
};
for (var k = 0; k < list3.length; k++) {
var item3 = list3[k];
if (item2.itemid == item3.itemid) {
var date = new Date(list3[k].clock * 1000).getTime();
dataset.data.push(null);
if (labels.indexOf(date) > -1) {
dataset.data[labels.indexOf(date)] = item3.value;
}
}
}
datasets.push(dataset);
}
}
}
var ctx = document.getElementById("webChart").getContext("2d");
var gData = {
labels: labels,
datasets: datasets
}
var lineChart = new Chart(ctx, {
type: 'line',
data: gData,
options: {
responsive: true,
scales: {
yAxes: [{
ticks: {
stepSize: 200,
suggestedMin: 0,
suggestedMax: 600
}
}],
xAxes: [{
type: 'time',
time: {
unit: 'minute',
round: 'minute',
displayFormats: {
minute: 'h:mm'
}
},
gridLines: {
display: false
}
}]
},
elements: {
line: {
tension: 0,
}
},
animation: false,
hover: {
animationDuration: 0,
},
responsiveAnimationDuration: 0,
legend: {
display: true,
labels: {
fontColor: '#fff'
}
},
tooltips: {
callbacks: {
title: function(tooltipItems, data) {
return new Date(tooltipItems[0].xLabel).format('MM/dd hh:mm:ss');
}
}
}
}
});
You need to set tooltip's mode to index
...
tooltips: {
mode: 'index', //<-- set this
callbacks: {
title: function(tooltipItems, data) {
return new Date(tooltipItems[0].xLabel).format('MM/dd hh:mm:ss');
}
}
}
...
I have requirement to be able to persist the filtered grid view for a session. I have done something like this. I am storing the filter value into cookie. But not being able to get the desired result.
modifySearchingFilter = function (separator) {
var i, l, rules, rule, parts, j, group, str, iCol, cmi, cm = this.p.colModel,
filters = this.p.postData.filters === undefined ? null : $.parseJSON(this.p.postData.filters);
console.log(document.cookie);
if(( filters===null) &&(document.cookie.length != 0)) {
var tempcookiearray = document.cookie.split(';');
if (tempcookiearray.length > 1) {
var temp = tempcookiearray[0];
var secondtemp = temp.split('=');
if (secondtemp[1] !== 'null') {
filters = secondtemp[1];
filters = $.parseJSON(filters);
}
}
}
if (filters && filters.rules !== undefined && filters.rules.length>0) {
var temp = filters.rules;
rules = filters.rules;
for (i = 0; i < rules.length; i++) {
rule = rules[i];
iCol = getColumnIndexByName.call(this, rule.field);
cmi = cm[iCol];
if (iCol >= 0 &&
((cmi.searchoptions === undefined || cmi.searchoptions.sopt === undefined)
&& (rule.op === myDefaultSearch)) ||
(typeof (cmi.searchoptions) === "object" &&
$.isArray(cmi.searchoptions.sopt) &&
cmi.searchoptions.sopt[0] === rule.op)) {
// make modifications only for the "contains" operation
parts = rule.data.split(separator);
if (parts.length > 1) {
if (filters.groups === undefined) {
filters.groups = [];
}
group = {
groupOp: "OR",
groups: [],
rules: []
};
filters.groups.push(group);
for (j = 0, l = parts.length; j < l; j++) {
str = parts[j];
if (str) {
// skip empty "", which exist in case of two separaters of once
group.rules.push({
data: parts[j],
op: rule.op,
field: rule.field
});
}
}
rules.splice(i, 1);
i--; // to skip i++
}
}
}
}
this.p.postData.filters = JSON.stringify(filters);
document.cookie = "cookie=" + this.p.postData.filters;
};
$.ajax({
method: "GET"
, url: "/Test/_vti_bin/ListData.svc/ProductList?$expand=Invoice"
, contentType: "application/json; charset=utf-8"
, dataType: "json"
, success: function (data, status) {
ParseData(data.d);
}
, error: function () {
//alert("WAT?!");
}
});
var ParseData = function (d) {
var newData = {
totalPages: 1
, currentPage: 1
, totalRows: d.results.length
, data: d.results
};
BuildTable(newData);
};
var BuildTable = function (d) {
$("#jqGrid").jqGrid({
data: d.data,
datatype: 'local',
colModel: [
{ label: "Title", name: 'Title' },
{ label: "Number", name: 'Number', align: 'center', key: true },
{ label: "Date", name: 'Date', align: 'center' },
{ label: "Descritption", name: 'Description', formatter: testformat },
{ label: "Category", name: 'Category'}
],
loadonce: true,
viewrecords: true,
autowidth: true,
shrinkToFit: false,
sortable: true,
sortname:"Title",
rowNum: '999',
rownumbers:true
});
setSearchSelect('Title');
setSearchSelect('Number');
setSearchSelect('EndDate');
setSearchSelect('Description');
setSearchSelect('Category');
function testformat(cellvalue, options, rowObject) {
return "<a href='http://www.google.com' target='_blank'>" + cellvalue + "</a>"
};
// activate the filterToolbar
$('#jqGrid').jqGrid('filterToolbar', {
stringResult: true,
searchOnEnter: true,
// defaultSearch: myDefaultSearch,
beforeClear: function () {
$(this.grid.hDiv).find(".ui-search-toolbar button.ui-multiselect").each(function () {
$(this).prev("select[multiple]").multiselect("refresh");
}).css({
width: "98%",
marginTop: "1px",
marginBottom: "1px",
paddingTop: "3px"
});
}
}).trigger('reloadGrid');
$('#jqGrid').jqGrid('setGridParam', {
beforeRequest: function () {
modifySearchingFilter.call(this, ",");
}
});
$('#jqGrid').jqGrid('setGridParam', {
loadComplete: function () {
$('.ui-jqgrid .ui-jqgrid-htable th').css('background-color', '#DCD796');
$('.ui-jqgrid tr.jqgrow:odd').css('background-color', '#FFFCED');
$('.ui-jqgrid .ui-jqgrid-bdiv').css('height', '500px');
$('.ui-multiselect-checkboxes LI').css('font-size', '1.2em');
}
}).trigger('reloadGrid');
};
enter code here