Custom Hover Legend for Morris.js Bar Chart - javascript

I am looking to customize the hover legend on my stacked bar chart so it won't show labels that don't have values in a specific bar, but show up in other bars. Hopefully the picture in the link below will help clear things up. The label for march in the picture has values for only a few labels, but displays all of them. I know I have to use the hoverCallback function, but I am not sure how to only return content for labels with data. The following is a link the morris.js webpage on bar charts: morris.js. Any suggestions on how to read the row data or possible solutions would be very helpful. Thanks for the help in advance!
Morris Graph

Try this:
new Morris.Bar({
element: 'bar-example',
data: [
{ t: "a", a: 2, b: 5, c: 2 },
{ t: "b", a: 3, b: null, c: null },
{ t: "c", a: 4, b: 8, c: 12 },
{ t: "d", a: null, b: 9, c: 15 }
],
xkey: 't',
ykeys: ['a', 'b', 'c'],
labels: ['Spotify', 'Apple', 'Uber'],
stacked: true,
hoverCallback: function (index, options, content, row) {
var finalContent = $(content);
var cpt = 0;
$.each(row, function (n, v) {
if (v == null) {
$(finalContent).eq(cpt).empty();
}
cpt++;
});
return finalContent;
}
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/raphael/2.1.0/raphael-min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/morris.js/0.5.1/morris.min.js"></script>
<link href="//cdnjs.cloudflare.com/ajax/libs/morris.js/0.5.1/morris.css" rel="stylesheet"/>
<div id="bar-example"></div>

Related

Keep selection in highcharts even on page refresh

I am using highcharts for generating/showcasing graph on UI(HTML with JavaScript Page)
There are multiple elements in series section that one can select or unselect to display on graph.
But after every refresh, user selected elements gets unselected and only the default selections appear. And user has to select the elements again.
Any solution to it?
One can relate the question from the picture:
In this, By default A is selected.
If user selects Ball or C then the point graph will appear for Ball and C as well but as soon as graph refreshes, graph will have point graph with A only.
You can store your visible series states in local storage. Example:
const savedStates = localStorage.getItem('seriesStates');
const seriesStates = savedStates ?
JSON.parse(savedStates) : {
A: true,
Ball: false,
C: false,
D: false
};
Highcharts.chart('container', {
series: [{
name: 'A',
data: [1, 2, 3],
visible: seriesStates.A
}, {
name: 'Ball',
data: [2, 2, 2],
visible: seriesStates.Ball
}, {
name: 'C',
data: [3, 3, 3],
visible: seriesStates.C
}, {
name: 'D',
data: [4, 4, 4],
visible: seriesStates.D
}],
plotOptions: {
series: {
events: {
legendItemClick: function() {
seriesStates[this.name] = !this.visible;
localStorage.setItem(
'seriesStates',
JSON.stringify(seriesStates)
);
}
}
}
}
});
Live demo: http://jsfiddle.net/BlackLabel/jkuc50Lf/
Docs: https://developer.mozilla.org/en-US/docs/Web/API/Window/localStorage

Live chart updating by rest api using javascript

I’m looking for a chart libraly javascript. It can draw line chart and call to rest api every few seconds (5s or 3s) then update the line chart. I searched its calling live chart updating by json but it draw only data in my json api i want it continue drawing. Can you help me. Many many thanks.
If you want to have Charts in your project then you may want to take a look at Chartjs. It's a great library providing all the charts one may need, such as Line, Bar, Pie, and many others.
Creating a chart is easy, e.g:
var ctx = document.getElementById('myChart').getContext('2d');
var myChart = new Chart(ctx, {
type: 'line',
data: {
labels: ['M', 'T', 'W', 'T', 'F', 'S', 'S'],
datasets: [{
label: 'apples',
data: [12, 19, 3, 17, 6, 3, 7],
backgroundColor: "rgba(153,255,51,0.4)"
}, {
label: 'oranges',
data: [2, 29, 5, 5, 2, 3, 10],
backgroundColor: "rgba(255,153,0,0.4)"
}]
}
});
For additional example you may want to see this introduction to Chart.js.
For dynamically updating your Charts check directly the Updating Charts Docu. An example from the link:
function addData(chart, label, data) {
chart.data.labels.push(label);
chart.data.datasets.forEach((dataset) => {
dataset.data.push(data);
});
chart.update();
}
function removeData(chart) {
chart.data.labels.pop();
chart.data.datasets.forEach((dataset) => {
dataset.data.pop();
});
chart.update();
}

Number of xLabel is greater than the length of data

I used Morris.js to build the following chart:
http://jsbin.com/uqawig/441/embed?js,output
The xLabel have problems when I reduce the length down to 2 as:
Morris.Line({
element: 'line-example',
data: [
{ y: '2006', a: 100, b: 90 },
{ y: '2007', a: 75, b: 65 }
],
xkey: 'y',
ykeys: ['a', 'b'],
labels: ['Series A', 'Series B']
});
xLabel show as 2006-03 2006-05 2006-07 2006-09 2006-11 2007-01
I want xLabel to show only the years like 2006 2007.
I searched a lot but didn't found any solutions.
Any ideas?
Set the parseTime parameter to false in your Morris configuration:
parseTime: false
Reference: Morris Line & Area Charts
parseTime: Set to false to skip time/date parsing for X values, instead treating them as an equally-spaced series.

Morris.js shown not correctly

I have created a graph with morris.js but it isn't shown correctly.
Here is my code
initChart: function(){
console.log('go! ');
var graphchart = document.createElement('div');
graphchart.setAttribute('id','graphchart');
graphchart.style.height = '200px';
graphchart.style.width = '500px';
new Morris.Line({
element: graphchart,
data: [
{ y: '2006', a: 100, b: 90 ,c:50},
{ y: '2007', a: 75, b: 65 ,c:50},
{ y: '2008', a: 50, b: 40 ,c:50},
{ y: '2012', a: 100, b: 90 ,c:50}
],
xkey: 'y',
ykeys: ['a', 'b','c'],
labels: ['Value1','Value2','Value3']
});
this.fire('my-devicelist-chart-created',{graph: graphchart});
}
So what is the problem that i got an wrong graph?
My HTML implementation:
<style>
</style>
<div y-scroll fit id="myfirstchart">
<paper-button on-tap="{{initStart}}">
<core-icon icon="chevron-right" class="icon"></core-icon>
<span>{{language.test}}</span>
</paper-button>
</div>
</div>
For all people with the same problem.
resize: true
Helped me out. Set it to true (default: false) when you create your Morris graph.

Morris Chart is Missing Half Part

I used morris chart in my application project to show some details about quantity of sales.
After executing the AJAX request, the chart is only showing half part. Here's the syntax:
var chartBahan = Morris.Bar ({
element: 'morris-analytics-bahan',
xkey: '2',
ykeys: ['3'],
labels: ['Quantity Bahan'],
resize: false,
gridEnabled: true
});
//getting the morris chart over bahan and karakteristik
function getBahanPotensial(kode){
//ajax call
$.ajax({
type:"POST",
async: false,
url:"<%= request.getContextPath()%>/GenerateListBahanPotensial",
data:{
kode:kode
},
success: function(data){
chartBahan.setData($.parseJSON(data));
chartBahan.redraw();
},
error:function(msg){
alert("Data Failed to Analyze" + msg);
}
});
}
var chartKarakter = new Morris.Bar ({
element: 'morris-analytics-karakter',
xkey: '2',
ykeys: ['3'],
labels: ['Karakter Quantity'],
resize: true
});
function getKarakterPotensial(kode){
//ajax call
$.ajax({
type:"POST",
async: false,
url:"<%= request.getContextPath()%>/GenerateListKarakterPotensial",
data:{
kode:kode
},
success:function(data){
chartKarakter.setData($.parseJSON(data));
chartKarakter.redraw();
},
error:function(msg){
alert("Data Failed to Analyze" + msg);
}
});
}
I execute the above function from another function let say doProcess()
function sendRequest(thecode){
if(thecode === ""){ alert("Tolong Input Kode Produk");}
else {
var kodebarang = thecode;
}
//executing AJAX call.
$.ajax({
type:"POST",
async: false,
url:"<%= request.getContextPath()%>/GenerateAnalytics",
data:{
kodebarang:kodebarang
},
success:function(msg){
$('#result_analysis').show();
$('#navigation_button').show();
new Morris.Bar ({
element: 'morris-analytics-bar',
data: $.parseJSON(msg),
xkey: '1',
ykeys: ['2', '3'],
labels: ['Sales Area', 'Tingkat Penjualan'],
barRatio: 0.4,
xLabelAngle: 0,
hideHover: 'auto'
});
//execute the morris chart others !! PENTING
var kodeb = $('#bahan_id').val();
var kodek = $('#karakteristik_id').val();
getBahanPotensial(kodeb);
getKarakterPotensial(kodek);
},
error:function(msg){
alert("Data Failed to Analyze" + msg);
}
});
}
but the problem is, when i create Morris Chart in Success Callback
success:function(msg){
$('#result_analysis').show();
$('#navigation_button').show();
new Morris.Bar ({
element: 'morris-analytics-bar',
data: $.parseJSON(msg),
xkey: '1',
ykeys: ['2', '3'],
labels: ['Sales Area', 'Tingkat Penjualan'],
barRatio: 0.4,
xLabelAngle: 0,
hideHover: 'auto'
});
The chart is properly showing. Here's the screen shot:
But the other chart when i use template for charting (outside the success callback) the chart is BROKEN
here's the screenshot
then, i have dropdown list to regenerate the chart based on specific parameter, the chart is properly showing (all data show) BUT the chart is only half PAGE. here's the screenshot:
Is there any ideas what going on?
UPDATE
What I mean template is code like this:
var chartBahan = Morris.Bar ({
element: 'morris-analytics-bahan',
xkey: '2',
ykeys: ['3'],
labels: ['Quantity Bahan'],
resize: false,
gridEnabled: true
});
and the method to call the template is
success:function(data){
chartBahan.setData($.parseJSON(data));
chartBahan.redraw();
},
The RIGHT chart is the FIRST Screenshot. It's wider than the other two.
UPDATED 2
still getting error on charts created by Morris :(
here's the screenshot.
I solved that issue by setting the width of the svg element to 100% in css
svg{
width: 100% !important
}
Two last charts from your example threw lots of errors in the console of Google Chrome (you can open it by pressing F12).
The reason is that the data property is required when you call Morris.Bar({ data: ... }), but in you example you didn't have this property. So you should completely remove your declarations like var chartBahan = Morris.Bar (... and replace the success callback with this code:
function getBahanPotensial(kode){
$.ajax({
...
success: function(data){
if (window.chartBahan) {
chartBahan.setData($.parseJSON(data));
// chartBahan.redraw(); // useless call, it can be removed
} else {
window.chartBahan = Morris.Bar ({
element: 'morris-analytics-bahan',
data: $.parseJSON(data),
xkey: '2',
ykeys: ['3'],
labels: ['Quantity Bahan'],
resize: false,
gridEnabled: true
});
}
}
...
});
}
In my code I check whether the global variable window.chartBahan exists and if it doesn't - I create a new chart; otherwise I call setData and the chart updates itself automatically.
Also you haven't posted your HTML mark-up, it may have issues as well. I used this HTML code and it worked fine:
<body>
<div id="morris-analytics-bar" style="height: 250px;"></div>
<div id="morris-analytics-bahan" style="height: 250px;"></div>
<div id="morris-analytics-karakter" style="height: 250px;"></div>
</body>
//Java script code
Morris.Line({
element: 'hero-area',
data: getdata("<?php echo base_url('user/getYearlPremiumuser');?>") ,
xkey: 'Year',
parseTime: false,
ykeys: ['Teacher', 'Student'],
labels: ['Teacher', 'Student'],
hideHover: 'false',
lineWidth: 1,
pointSize: 5,
lineColors: ['#4a8bc2', '#ff6c60'],
fillOpacity:7,
smooth: true
});
********//php code ( code codeigniter)********
public function getYearlPremiumuser()
{
$teacherArray={ y: '2014', a: 50, b: 90},
{ y: '2015', a: 65, b: 75},
{ y: '2016', a: 50, b: 50},
{ y: '2017', a: 75, b: 60},
{ y: '2018', a: 80, b: 65},
{ y: '2019', a: 90, b: 70},
{ y: '2020', a: 100, b: 75},
{ y: '2021', a: 115, b: 75},
{ y: '2022', a: 120, b: 85},
{ y: '2023', a: 145, b: 85},
{ y: '2024', a: 160, b: 95}
for($i=0;$i<count($teacherArray);$i++)
{
$temp=array();
$temp= array_merge($teacherArray[$i],$studentarray[$i]);
$finalResultArray[]=$temp;
}
echo json_encode($finalResultArray);
}
click here to know more
I have similar issue using Morris.js and Angular2 - the problem in my case was that I use in DIV with chart the *ngIf='showChart' (or [hidden]='!showChart') - and when I set up chart, the showChar=false so the div doesn't exist. In my case I read date periodic in every 1min so at first dataLoad i see nothing, after second dataLoad i see half/part of chart). So I fix this by (typescript):
showchart = true;
setTimeout( () => { this.setUpChart() }, 1 );
And it works :)

Categories

Resources