I am working with chart.js and am trying to add 2 plugins to the same chart, but when applied, both of the plugins disappear and there is no direct error in the console.
Does anyone know how to implement two plugins to the same graph?
First pulgin
Second plugin referance
Basically, the graph has to show data labels on a line chart and at the same time, draw yAxis lines, but only starting from the points on the line chart.
For some reason, the chart will not show either of them when both are applied.
Chart.helpers.merge(Chart.defaults.global.plugins.datalabels, {
color : '#ffffff'
})
// Chart.plugins.unregister(ChartDataLabels);
// var chart = new Chart(ctx, {
// / plugins: [ChartDataLabels],
// options: {
// // ...
// }
// })
var ctx = document.getElementById('myChart').getContext('2d');
var chart = new Chart(ctx, {
// The type of chart we want to create
type : 'line',
// The data for our dataset
data : {
labels : [ '', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun', '' ],
datasets : [ {
label : 'My first dataset',
borderWidth : 3,
borderColor : 'rgb(255,0, 0)',
data : data1,
} ]
},
// Configuration options go here
options : {
elements : {
point : {
radius : 3
}
},
legend : {
display : false,
labels : {
fontColor : "white",
fontSize : 18
}
},
scales : {
yAxes : [ {
ticks : {
fontSize : 0,
beginAtZero : false,
max : 40,
},
gridLines : {
display : false,
drawBorder : false,
}
} ],
xAxes : [ {
ticks : {
fontColor : "white",
fontSize : 14,
beginAtZero : 0,
},
gridLines : {
display : false,
}
} ]
},
plugins : [ { // this is the magical bit :)
afterRender : function(c, options) {
let
meta = c.getDatasetMeta(0), max;
c.ctx.save();
c.ctx.strokeStyle = c.config.options.scales.xAxes[0].gridLines.color;
c.ctx.lineWidth = c.config.options.scales.xAxes[0].gridLines.lineWidth;
c.ctx.beginPath();
meta.data
.forEach(function(e) {
if (max == undefined
|| c.config.data.datasets[0].data[e._index] > max) {
max = c.config.data.datasets[0].data[e._index];
}
c.ctx.moveTo(e._model.x,
meta.dataset._scale.bottom);
c.ctx
.lineTo(e._model.x,
e._model.y);
});
c.ctx.textBaseline = 'top';
c.ctx.textAlign = 'right';
c.ctx.fillStyle = 'black';
c.ctx.fillText('Max value: ' + max,
c.width - 10, 10);
c.ctx.stroke();
c.ctx.restore();
}
} ],
tooltips : {
callbacks : {
label : function(tooltipItem) {
console.log(tooltipItem)
return tooltipItem.yLabel;
}
}
}
}
});
var data1 = [ 1, 9, 12, 3, 15, 8, 2, -5, 3, 4, 5, 7 ];
myChart(data1);
HTML .js code
<script src="js/chart.js"></script>
<!-- data label .js -->
<script
src="https://cdn.jsdelivr.net/npm/chartjs-plugin-datalabels#0.5.0"></script>
<!-- yAxis lines .js -->
<script
src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.7.3/Chart.min.js"></script>
<canvas id="myChart"></canvas>
var chart = new Chart(document.getElementById('chart'), {
type : 'line',
data : {
labels : [ '', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun', '' ],
datasets : [ {
label : 'My first dataset',
borderWidth : 1,
borderColor : 'rgb(255,0, 0)',
data : [ 1, 9, 12, 3, 15, 8, 2, -5, 3, 4, 5, 7 ],
datalabels: {
align: 'end',
anchor: 'end',
backgroundColor: 'rgb(255, 120, 12, .2)',
borderRadius: 20
}
}]
},
options : {
scales : {
xAxes : [ {
gridLines : {
display : false,
color: 'rgba(255, 120, 12, .2)',
lineWidth: 5
}
} ],
yAxes : [{
gridLines : {
display : false,
color: 'rgba(255, 120, 12, .2)',
lineWidth: 5
},
ticks : {
beginAtZero: true
}
}]
},
},
plugins : [{ // this is the magical bit :)
afterRender : function(c, options) {
let meta = c.getDatasetMeta(0), max;
c.ctx.save();
c.ctx.strokeStyle = c.config.options.scales.xAxes[0].gridLines.color;
c.ctx.lineWidth = c.config.options.scales.xAxes[0].gridLines.lineWidth;
c.ctx.beginPath();
meta.data.forEach(function(e)
{
if (max == undefined || c.config.data.datasets[0].data[e._index] > max) {
max = c.config.data.datasets[0].data[e._index];
}
c.ctx.moveTo(e._model.x,meta.dataset._scale.bottom);
c.ctx.lineTo(e._model.x,e._model.y);
});
c.ctx.textBaseline = 'top';
c.ctx.textAlign = 'right';
c.ctx.fillStyle = 'black';
c.ctx.fillText('Max value: ' + max, c.width - 10, 10);
c.ctx.stroke();
c.ctx.restore();
}
}],
tooltips : {
callbacks : {
label : function(tooltipItem) {
console.log(tooltipItem)
return tooltipItem.yLabel;
}
}
}
});
>
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.7.3/Chart.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/chartjs-plugin-datalabels#0.6.0/dist/chartjs-plugin-datalabels.min.js"></script>
<canvas id="chart"></canvas>
Related
I'm currently creating a chart whose data is dynamically fetch from a database. Based on this data, I want to create a Horizontal Stacked Bar Chart that has only one series. Would that be possible in AmCharts? Or do I need a different approach?
Here's what I'd like as final result:
Here's a sample of what I'm currently doing: Chart Sample
I'm also aware that using series.stacked = true; would make a column chart stacked but I think this needs to have multiple series which I want to avoid for now.
<html>
<head></head>
<style></style>
<!-- Resources -->
<script src="https://cdn.amcharts.com/lib/5/index.js"></script>
<script src="https://cdn.amcharts.com/lib/5/xy.js"></script>
<script src="https://cdn.amcharts.com/lib/5/themes/Animated.js"></script>
<body>
<div id="chartdiv" style="width: 600px;height: 200px;background:#c7cacb;margin: 0 auto;"></div>
<script>
am5.ready(function () {
var root = am5.Root.new("chartdiv");
root._logo.dispose();
root.setThemes([
am5themes_Animated.new(root)
]);
var chart = root.container.children.push(am5xy.XYChart.new(root, {
panX: false,
panY: false,
wheelX: false,
wheelY: false,
layout: root.verticalLayout
}));
var data = [{
"year": "Payments",
"europe": 50,
"namerica": 0,
"asia": 0,
}, {
"year": "Invoiced",
"europe": 30,
"namerica": 0,
"asia": 0,
}, {
"year": "Other Adjustment Sum",
"europe": 40,
"namerica": 20,
"asia": 39,
}]
var yAxis = chart.yAxes.push(am5xy.CategoryAxis.new(root, {
categoryField: "year",
renderer: am5xy.AxisRendererY.new(root, {}),
tooltip: am5.Tooltip.new(root, {})
}));
yAxis.data.setAll(data);
var xAxis = chart.xAxes.push(am5xy.ValueAxis.new(root, {
min: 0,
renderer: am5xy.AxisRendererX.new(root, {})
}));
xAxis = chart.xAxes.push(
am5xy.ValueAxis.new(root, {
min: 0,
numberFormat: "''",
renderer: am5xy.AxisRendererX.new(root, {
strokeOpacity: 1,
strokeWidth: 1,
minGridDistance: 60
}),
})
);
let myRange = [
{
x: 20,
},
{
x: 40,
},
{
x: 60,
},
{
x: 80,
},
{
x: 100,
},
];
for (var i = 0; i < data.length + 2; i++) {
let value = myRange[i].x;
let rangeDataItem = xAxis.makeDataItem({
value: value,
});
let range = xAxis.createAxisRange(rangeDataItem);
rangeDataItem.get('label').setAll({
forceHidden: false,
text: value,
});
}
var legend = chart.children.push(am5.Legend.new(root, {
centerX: am5.p50,
x: am5.p50
}));
function makeSeries(name, fieldName, color) {
var series = chart.series.push(am5xy.ColumnSeries.new(root, {
name: name,
stacked: true,
xAxis: xAxis,
yAxis: yAxis,
baseAxis: yAxis,
fill: color,
valueXField: fieldName,
categoryYField: "year"
}));
series.columns.template.setAll({
tooltipText: "{name}, {categoryY}: {valueX}",
tooltipY: am5.percent(90)
});
series.data.setAll(data);
series.appear();
}
makeSeries("Europe", "europe", "#83cdf4");
makeSeries("North America", "namerica","#caa3ed");
makeSeries("Asia", "asia","#eec48b");
chart.appear(1000, 100);
});
</script>
</body>
</html>
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 3 years ago.
Improve this question
I want to show only the last point. Can somebody help with this?
Expected
Actual
Well, hello!
You can set the pointRadius to zero, eg:
var myChart = new Chart(
ctx, {
type: 'line',
data: {
labels: [...]
datasets: [
{
data: [...],
pointRadius: 0, # <<< Here.
}
]
},
options: {}
})
For many points (like your question) change pointRadius to array:
pointRadius: [0, 0, 0, 0, 0, 0, 5]
Follow my full example in Fiddle
If this helped you, check it out
Update
I just saw Edi's answer as I submitted mine and he mentioned the pointRadius. I noticed this too messing around and as he stated, you can pass in an array to simplify this.
I wrote a method below to "grow" the array (scaling with the data) in order to ensure that the last data point has a radius > 0.
The custom Line chart appears to render much smoother because the native draw function has been modified.
Chart.js 2.0 introduces the concept of controllers for each dataset. Like scales, new controllers can be written as needed.
I copied the source for controller.line.js and modified the loop for the draw() method to only draw the last point. This is the easiest solution without having to figure out how to set an array of radius values.
/** Initialize array with radius of n and queue values ahead of it */
function pointRadiusLast(radius, length, initialArray) {
var result = initialArray || [ radius ];
while (result.length < length) result.unshift(0); // Place zeros in front
return result;
}
// https://www.chartjs.org/docs/latest/developers/charts.html
var valueOrDefault = Chart.helpers.valueOrDefault;
const lineEnabled = (dataset, options) => valueOrDefault(dataset.showLine, options.showLines)
Chart.defaults.derivedLine = Chart.defaults.line;
var customController = Chart.controllers.line.extend({
/** If you want to EXTEND the draw function.
draw: function(ease) {
Chart.controllers.line.prototype.draw.call(this, ease); // Override the super method
var meta = this.getMeta();
var pt0 = meta.data[0];
var radius = pt0._view.radius;
var ctx = this.chart.chart.ctx;
ctx.save();
// Custom drawing...
ctx.restore();
}
If you want to OVERRIDE the draw function...
*/
draw: function(ease) {
var me = this;
var chart = me.chart;
var meta = me.getMeta();
var points = meta.data || [];
var area = chart.chartArea;
var ilen = points.length;
var halfBorderWidth;
var i = 0;
if (lineEnabled(me.getDataset(), chart.options)) {
halfBorderWidth = (meta.dataset._model.borderWidth || 0) / 2;
Chart.helpers.canvas.clipArea(chart.ctx, {
left: area.left,
right: area.right,
top: area.top - halfBorderWidth,
bottom: area.bottom + halfBorderWidth
});
meta.dataset.draw();
Chart.helpers.canvas.unclipArea(chart.ctx);
}
// Draw the points
for (; i < ilen; ++i) {
if (i === ilen - 1) { // Only the last or simply... points[ilen - 1].draw(area)
points[i].draw(area);
}
}
}
});
Chart.controllers.derivedLine = customController; // Specify type on chart below
var data = [
{ month : 'January' , low : 25, high : 43 },
{ month : 'February' , low : 27, high : 47 },
{ month : 'March' , low : 35, high : 56 },
{ month : 'April' , low : 44, high : 67 },
{ month : 'May' , low : 54, high : 76 },
{ month : 'June' , low : 63, high : 85 }
];
var additionalData = [
{ month : 'July' , low : 68, high : 89 },
{ month : 'August' , low : 66, high : 87 },
{ month : 'September' , low : 59, high : 81 },
{ month : 'October' , low : 46, high : 69 },
{ month : 'November' , low : 37, high : 59 },
{ month : 'December' , low : 30, high : 48 }
];
var defaults = {
fill: false,
lineTension: 0.1,
borderCapStyle: 'butt',
borderDash: [],
borderDashOffset: 0.0,
borderJoinStyle: 'miter',
pointBackgroundColor: "#fff",
pointBorderWidth: 1,
pointHoverRadius: 5,
pointHoverBorderWidth: 2,
//pointRadius: 0, <-- Do not specify this, we will supply it below
pointHitRadius: 10
};
/** Initialize array with radius of n and queue values ahead of it */
function pointRadiusLast(radius, length, initialArray) {
var result = initialArray || [ radius ];
while (result.length < length) result.unshift(0);
return result;
}
var dataSets = [
Object.assign({
label: "Low",
backgroundColor: "rgba(75,192,192,0.4)",
borderColor: "rgba(75,192,192,1)",
pointBorderColor: "rgba(75,192,192,1)",
pointHoverBackgroundColor: "rgba(75,192,192,1)",
pointHoverBorderColor: "rgba(220,220,220,1)",
data: data.map(item => item.low)
}, defaults),
Object.assign({
label: "High",
backgroundColor: "rgba(192,75,75,0.4)",
borderColor: "rgba(192,75,75,1)",
pointBorderColor: "rgba(192,75,75,1)",
pointHoverBackgroundColor: "rgba(192,75,75,1)",
pointHoverBorderColor: "rgba(192,75,75,1)",
data: data.map(item => item.high)
}, defaults)
];
var chartOptions = {
title : {
text : 'Weather Averages for Washington, DC',
display : true
},
showLines: true
};
var defaultChart = Chart.Line(document.getElementById('default-line-chart'), {
data: {
labels: data.map(item => item.month),
datasets: dataSets.map(dataset => $.extend(true, {}, dataset, {
pointRadius : pointRadiusLast(5, data.length)
}))
},
options : $.extend(true, {}, chartOptions, {
title : {
text : chartOptions.title.text + ' (Default)'
}
})
});
var customChart = new Chart(document.getElementById('custom-line-chart'), {
type: 'derivedLine',
data: {
labels: data.map(item => item.month),
datasets: dataSets.map(dataset => $.extend(true, {}, dataset, {
pointRadius : 5
}))
},
options : $.extend(true, {}, chartOptions, {
title : {
text : chartOptions.title.text + ' (Custom)'
}
})
});
setTimeout(function() {
var category = 'month', fields = [ 'low', 'high' ];
var counter = additionalData.length;
var intervalId = setInterval(function() {
if (counter --> 0) {
var record = additionalData[additionalData.length - counter - 1];
addData(defaultChart, record, category, fields);
addData(customChart, record, category, fields);
} else {
clearInterval(intervalId);
}
}, 1000); // Update every second
}, 1000); // 1 second delay
function addData(chart, data, xField, yFields) {
chart.data.labels.push(data[xField]);
chart.data.datasets.forEach((dataset, i) => {
dataset.data.push(data[yFields[i]]);
if (chart.config.type === 'line') { // Only the normal Line chart
dataset.pointRadius = pointRadiusLast(5, dataset.data.length);
}
});
chart.update();
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.7.3/Chart.min.js"></script>
<canvas id="default-line-chart" width="400" height="120"></canvas>
<canvas id="custom-line-chart" width="400" height="120"></canvas>
Right now the callbacks (on hover) show the data from data set. I want to change each of that point with a different value. For that I have a same size array as the original data array.
I tried this
tooltips: {
callbacks: {
label: function(tooltipItem, data) {
return measures;
}
}
},
but it returned the whole array for every point.
The chart can have more then 1 datasets. They are created dynamically in a for loop. I tried creating the callbacks dynamically as well
call[r] = {
abel: function(tooltipItem, data) {
return measures;
}
};
tooltips: {
callbacks: call
},
But that just threw TypeErrors
TypeError: c.callbacks.labelColor is undefined
TypeError: e.title is undefined
How can i get each array element on a different point? And in case of multiple datasets show the values from the same position array as dataset?
Sorry if im not clear enough. Just cant quite wrap my head around this.
Thanks!
I have implemented graph in one of my project for Power On Time duration. I have refered you with my code. Please see if it can help.
Labels Array:
Array(9)
0
:
"2018-09-17"
1
:
"2018-09-17"
2
:
"2018-09-17"
3
:
"2018-09-17"
4
:
"2018-09-17"
5
:
"2018-09-17"
6
:
"2018-09-17"
7
:
"2018-09-17"
8
:
"2018-09-18"
Data Array:
Array(9)
0
:
"200"
1
:
"211"
2
:
"234"
3
:
"255"
4
:
"300"
5
:
"321"
6
:
"400"
7
:
"421"
8
:
"00421"
<script>
var powerontimedata_chart_labels=[];
var powerontimedata_chart_data=[];
function initiateChart(labels, data){
chart_labels=JSON.parse(labels);
chart_data=JSON.parse(data);
console.log(powerontimedata_chart_labels);
console.log(powerontimedata_chart_data);
plotDataLineChart();
}
function plotDataLineChart(){
var lineChartOptions = {
maintainAspectRatio: false,
steppedLine : 'after',
responsive : true,
showTooltips : false,
showInlineValues : true,
centeredInllineValues : true,
tooltipCaretSize : 0,
tooltipTemplate : "<%= value %>",
scales: {
xAxes: [{
position: "right",
scaleLabel: {
display: true,
stepSize : 1,
autoSkip: false,
labelString: "Date",
fontFamily: "Montserrat",
fontColor: "black",
},
ticks:{
stepSize : 2,
autoSkip: true
}
}],
yAxes: [{
position: "left",
scaleLabel: {
display: true,
stepSize : 1,
autoSkip: false,
labelString: "Time in Hour",
fontFamily: "Montserrat",
fontColor: "black",
},
ticks: {
beginAtZero:true,
autoSkip: true
}
}]
},
"animation": {
"duration": 1,
"onComplete": function() {
var chartInstance = this.chart,
ctx = chartInstance.ctx;
ctx.font = Chart.helpers.fontString(Chart.defaults.global.defaultFontSize, Chart.defaults.global.defaultFontStyle, Chart.defaults.global.defaultFontFamily);
console.log(ctx);
ctx.textAlign = 'center';
ctx.textBaseline = 'bottom';
ctx.fillStyle = '#ff0000';
this.data.datasets.forEach(function(dataset, i) {
var meta = chartInstance.controller.getDatasetMeta(i);
meta.data.forEach(function(bar, index) {
var data = dataset.data[index];
ctx.fillText(data, bar._model.x, bar._model.y - 5);
});
});
}
},
//multiTooltipTemplate: "<%= datasetLabel %> - <%= value %>"
};
var lineChartCanvas = $('#weekbarChart').get(0).getContext('2d')
var ontime = {
labels : chart_labels,
datasets : [
{
label : 'Power Ontime',
fill : true,
borderColor : "#FF0000",
backgroundColor : "#F5B7B1",
data : powerontimedata_chart_data,
steppedLine: false,
pointStyle: 'clearInterval',
pointBorderColor : "#FF0000",
}
]
}
realTimeChart = new Chart(lineChartCanvas, {
type: 'line',
data: ontime,
options: lineChartOptions
});
}
initiateChart('<?= json_encode($chart["labels"])?>','<?= json_encode($chart["data"])?>');
</script>
And my graph comes out to be :
Referring this example to create scatter graph using echarts library:
Basic Scattergraph
My code for this is as follows:
option ={
xAxis : [
{
type : 'value',
scale:true
}
],
yAxis : [
{
type : 'value',
scale:true
}
],
series : [
{
symbolSize: 40,
itemStyle: {
normal: {
color: 'lightblue',
borderWidth: 4,
label : {
show: true,
position: 'inside',
formatter: function(v)
{
if (v==[161.2, 51.6])
return 'a'
else
return v
}
}
}
},
type:'scatter',
data: [
[161.2, 51.6],[167.5, 59.0],[157.0, 63.0],[155.8, 53.6],
[170.0, 59.0], [166.0, 69.8], [176.2, 66.8]
],
}
]
};
In the formatter function inside series I am trying to match my variable 'v' with a coordinate point from data. But that condition is not satisfied. Where am I going wrong? I only see [object Object] in all the bubbles. Please help.
If you are using the Echarts2.x version, code is as follow:
option ={
xAxis : [
{
type : 'value',
scale:true
}
],
yAxis : [
{
type : 'value',
scale:true
}
],
series : [
{
symbolSize: 40,
itemStyle: {
normal: {
color: 'lightblue',
borderWidth: 4,
label : {
show: true,
position: 'inside',
formatter: function(data){
var v = data.value;
if (v[0]==161.2 && v[1]==51.6)
return 'a'
else
return v
}
}
}
},
type:'scatter',
data: [
[161.2, 51.6],[167.5, 59.0],[157.0, 63.0],[155.8, 53.6],
[170.0, 59.0], [166.0, 69.8], [176.2, 66.8]
],
}
]
};
the parameter of formatter function is an object which is a point object on the scatter, Its structure is as follow:
$vars:Array[3]
color:"lightblue"
componentSubType:"scatter"
componentType:"series"
data:Array[2]
dataIndex:0
dataType:undefined
name:""
seriesIndex:0
seriesName:"-"
seriesType:"scatter"
status:"normal"
value:Array[2]
So the parameter isn't the array you wanted.
The itemStyle attribute is used to set the graphic style, The label attribute is used to set the text label on the graph, which can be used to explain some data information of the graph. Such as value, name, etc. In Echarts3.x in order to make the structure of entire configuration more flat and reasonable, label was taken out with itemStyle at the same level. like itemStyle have two states of normal and emphasis. if you are using Echarts3.x version, code is like as follow:
option ={
xAxis : [
{
type : 'value',
scale:true
}
],
yAxis : [
{
type : 'value',
scale:true
}
],
series : [
{
symbolSize: 40,
itemStyle: {
normal: {
color: 'lightblue',
borderWidth: 4,
}
},
label : {
normal: {
show: true,
position: 'inside',
formatter: function(data){
var v = data.value;
if (v[0]==161.2 && v[1]==51.6)
return 'a'
else
return v
}
}
},
type:'scatter',
data: [
[161.2, 51.6],[167.5, 59.0],[157.0, 63.0],[155.8, 53.6],
[170.0, 59.0], [166.0, 69.8], [176.2, 66.8]
],
}
]
};
In my code, I want to set y-axis '0' when i didn't put the value in var line1.
Now I didn't put information about ['2013-01-25 11:23am'].
In this case, I want to set y-asix value to 0. No, it didn't work like that.
How can I do?
function Drawchart() {
this.showChart = function() {
$(document).ready(
function() {
var line1 = [ [ '2013-01-25 11:20am', 20 ],
[ '2013-01-25 11:35AM', 30 ],
[ '2013-01-25 11:36AM', 7 ],
[ '2013-01-25 11:37AM', 3 ],
[ '2013-01-25 11:38AM', 1 ],
[ '2013-01-25 11:39AM', 2 ] ];
var plot2 = $.jqplot('chart', [ line1 ], {
title : 'Customized Date Axis',
gridPadding : {
right : 35
},
axes : {
xaxis : {
renderer : $.jqplot.DateAxisRenderer,
pad : 0,
tickOptions : {
angle : -90,
fontSize : "5pt",
formatString : '%I:%M%p '
},
min : '11:00 AM',
tickInterval : '1 minute'
},
yaxis : {
min : 0
}
},
series : [ {
lineWidth : 4,
color : '#000000',
markerOptions : {
style : 'square'
}
} ]
});
});
}
}
You can't because JQPlot need to know which points must be drawn in the serie.
You need to set your 0 points manualy like this : ['2013-01-25 11:23am',0] and include them into the array.
var line1=[['2013-01-25 11:20am',20],['2013-01-25 11:23am',0],['2013-01-25 11:35AM',30],['2013-01-25 11:36AM',7],['2013-01-25 11:37AM',3],['2013-01-25 11:38AM',1],['2013-01-25 11:39AM',2]];
Are those 0s actual data points? if so then you should build your line1 with that data or augment it outside of jqplot.
Perhaps also what might help you is a canvas overlay
$.jqplot('chart', [ line1 ], {
...
canvasOverlay: {
show: true,
objects: [
{horizontalLine: {
name: '',
y: 0,
lineWidth: 3,
xOffset: 0,
color: 'rgb(89, 198, 154)',
shadow: false
}}
]
} // end canvasOverlay
}); // end jqplot