@@ -1,4 +1,5 @@ | |||
*.pyc | |||
*.comp.js | |||
*.DS_Store | |||
user_files | |||
defs.py |
@@ -43,7 +43,7 @@ class DocType: | |||
r.save(1) | |||
def on_update(self, from_update=0): | |||
import webnotes.defs | |||
from webnotes import defs | |||
from webnotes.utils.transfer import in_transfer | |||
if (not in_transfer) and getattr(defs,'developer_mode', 0): | |||
@@ -1244,13 +1244,11 @@ ul.box_tabs li.box_tab_selected a { | |||
/* background:url("../images/ui/rc/tab-right-CCC.gif") no-repeat right top; */ | |||
} | |||
/******* jqPlot ***********/ | |||
/*rules for the plot target div. These will be cascaded down to all plot elements according to css rules*/ | |||
.jqplot-target { | |||
position: relative; | |||
color: #666666; | |||
font-family: Arial, Helvetica, sans-serif; | |||
font-family: "Trebuchet MS", Arial, Helvetica, sans-serif; | |||
font-size: 1em; | |||
/* height: 300px; | |||
width: 400px;*/ | |||
@@ -1308,6 +1306,15 @@ ul.box_tabs li.box_tab_selected a { | |||
text-align: right; | |||
} | |||
.jqplot-yaxis-tick.jqplot-breakTick { | |||
right: -20px; | |||
margin-right: 0px; | |||
padding:1px 5px 1px 5px; | |||
/* background-color: white;*/ | |||
z-index: 2; | |||
font-size: 1.5em; | |||
} | |||
.jqplot-y2axis-tick, .jqplot-y3axis-tick, .jqplot-y4axis-tick, .jqplot-y5axis-tick, .jqplot-y6axis-tick, .jqplot-y7axis-tick, .jqplot-y8axis-tick, .jqplot-y9axis-tick { | |||
left: 0px; | |||
/* initial position untill tick is drawn in proper place */ | |||
@@ -1317,6 +1324,15 @@ ul.box_tabs li.box_tab_selected a { | |||
text-align: left; | |||
} | |||
.jqplot-meterGauge-tick { | |||
font-size: 0.75em; | |||
color: #999999; | |||
} | |||
.jqplot-meterGauge-label { | |||
font-size: 1em; | |||
color: #999999; | |||
} | |||
.jqplot-xaxis-label { | |||
margin-top: 10px; | |||
font-size: 11pt; | |||
@@ -1342,6 +1358,13 @@ ul.box_tabs li.box_tab_selected a { | |||
position: absolute; | |||
} | |||
table.jqplot-table-legend { | |||
margin-top: 12px; | |||
margin-bottom: 12px; | |||
margin-left: 12px; | |||
margin-right: 12px; | |||
} | |||
table.jqplot-table-legend, table.jqplot-cursor-legend { | |||
background-color: rgba(255,255,255,0.6); | |||
border: 1px solid #cccccc; | |||
@@ -1353,18 +1376,22 @@ td.jqplot-table-legend { | |||
vertical-align:middle; | |||
} | |||
td.jqplot-seriesToggle:hover, td.jqplot-seriesToggle:active { | |||
cursor: pointer; | |||
} | |||
td.jqplot-table-legend > div { | |||
border:1px solid #cccccc; | |||
padding:0.2em; | |||
border: 1px solid #cccccc; | |||
padding:1px; | |||
} | |||
div.jqplot-table-legend-swatch { | |||
width:0px; | |||
height:0px; | |||
border-top-width: 0.35em; | |||
border-bottom-width: 0.35em; | |||
border-left-width: 0.6em; | |||
border-right-width: 0.6em; | |||
border-top-width: 5px; | |||
border-bottom-width: 5px; | |||
border-left-width: 6px; | |||
border-right-width: 6px; | |||
border-top-style: solid; | |||
border-bottom-style: solid; | |||
border-left-style: solid; | |||
@@ -1402,6 +1429,7 @@ table.jqplot-cursor-tooltip { | |||
.jqplot-point-label { | |||
font-size: 0.75em; | |||
z-index: 2; | |||
} | |||
td.jqplot-cursor-legend-swatch { | |||
@@ -1414,6 +1442,35 @@ width:1.2em; | |||
height:0.7em; | |||
} | |||
.jqplot-error { | |||
/* Styles added to the plot target container when there is an error go here.*/ | |||
text-align: center; | |||
} | |||
.jqplot-error-message { | |||
/* Styling of the custom error message div goes here.*/ | |||
position: relative; | |||
top: 46%; | |||
display: inline-block; | |||
} | |||
div.jqplot-bubble-label { | |||
font-size: 0.8em; | |||
/* background: rgba(90%, 90%, 90%, 0.15);*/ | |||
padding-left: 2px; | |||
padding-right: 2px; | |||
color: rgb(20%, 20%, 20%); | |||
} | |||
div.jqplot-bubble-label.jqplot-bubble-label-highlight { | |||
background: rgba(90%, 90%, 90%, 0.7); | |||
} | |||
div.jqplot-noData-container { | |||
text-align: center; | |||
background-color: rgba(96%, 96%, 96%, 0.3); | |||
} | |||
/** general icons **/ | |||
@@ -1,10 +1,8 @@ | |||
/******* jqPlot ***********/ | |||
/*rules for the plot target div. These will be cascaded down to all plot elements according to css rules*/ | |||
.jqplot-target { | |||
position: relative; | |||
color: #666666; | |||
font-family: Arial, Helvetica, sans-serif; | |||
font-family: "Trebuchet MS", Arial, Helvetica, sans-serif; | |||
font-size: 1em; | |||
/* height: 300px; | |||
width: 400px;*/ | |||
@@ -62,6 +60,15 @@ | |||
text-align: right; | |||
} | |||
.jqplot-yaxis-tick.jqplot-breakTick { | |||
right: -20px; | |||
margin-right: 0px; | |||
padding:1px 5px 1px 5px; | |||
/* background-color: white;*/ | |||
z-index: 2; | |||
font-size: 1.5em; | |||
} | |||
.jqplot-y2axis-tick, .jqplot-y3axis-tick, .jqplot-y4axis-tick, .jqplot-y5axis-tick, .jqplot-y6axis-tick, .jqplot-y7axis-tick, .jqplot-y8axis-tick, .jqplot-y9axis-tick { | |||
left: 0px; | |||
/* initial position untill tick is drawn in proper place */ | |||
@@ -71,6 +78,15 @@ | |||
text-align: left; | |||
} | |||
.jqplot-meterGauge-tick { | |||
font-size: 0.75em; | |||
color: #999999; | |||
} | |||
.jqplot-meterGauge-label { | |||
font-size: 1em; | |||
color: #999999; | |||
} | |||
.jqplot-xaxis-label { | |||
margin-top: 10px; | |||
font-size: 11pt; | |||
@@ -96,6 +112,13 @@ | |||
position: absolute; | |||
} | |||
table.jqplot-table-legend { | |||
margin-top: 12px; | |||
margin-bottom: 12px; | |||
margin-left: 12px; | |||
margin-right: 12px; | |||
} | |||
table.jqplot-table-legend, table.jqplot-cursor-legend { | |||
background-color: rgba(255,255,255,0.6); | |||
border: 1px solid #cccccc; | |||
@@ -107,18 +130,22 @@ td.jqplot-table-legend { | |||
vertical-align:middle; | |||
} | |||
td.jqplot-seriesToggle:hover, td.jqplot-seriesToggle:active { | |||
cursor: pointer; | |||
} | |||
td.jqplot-table-legend > div { | |||
border:1px solid #cccccc; | |||
padding:0.2em; | |||
border: 1px solid #cccccc; | |||
padding:1px; | |||
} | |||
div.jqplot-table-legend-swatch { | |||
width:0px; | |||
height:0px; | |||
border-top-width: 0.35em; | |||
border-bottom-width: 0.35em; | |||
border-left-width: 0.6em; | |||
border-right-width: 0.6em; | |||
border-top-width: 5px; | |||
border-bottom-width: 5px; | |||
border-left-width: 6px; | |||
border-right-width: 6px; | |||
border-top-style: solid; | |||
border-bottom-style: solid; | |||
border-left-style: solid; | |||
@@ -156,6 +183,7 @@ table.jqplot-cursor-tooltip { | |||
.jqplot-point-label { | |||
font-size: 0.75em; | |||
z-index: 2; | |||
} | |||
td.jqplot-cursor-legend-swatch { | |||
@@ -167,3 +195,32 @@ div.jqplot-cursor-legend-swatch { | |||
width:1.2em; | |||
height:0.7em; | |||
} | |||
.jqplot-error { | |||
/* Styles added to the plot target container when there is an error go here.*/ | |||
text-align: center; | |||
} | |||
.jqplot-error-message { | |||
/* Styling of the custom error message div goes here.*/ | |||
position: relative; | |||
top: 46%; | |||
display: inline-block; | |||
} | |||
div.jqplot-bubble-label { | |||
font-size: 0.8em; | |||
/* background: rgba(90%, 90%, 90%, 0.15);*/ | |||
padding-left: 2px; | |||
padding-right: 2px; | |||
color: rgb(20%, 20%, 20%); | |||
} | |||
div.jqplot-bubble-label.jqplot-bubble-label-highlight { | |||
background: rgba(90%, 90%, 90%, 0.7); | |||
} | |||
div.jqplot-noData-container { | |||
text-align: center; | |||
background-color: rgba(96%, 96%, 96%, 0.3); | |||
} |
@@ -0,0 +1,312 @@ | |||
/** | |||
* jqPlot | |||
* Pure JavaScript plotting plugin using jQuery | |||
* | |||
* Version: 1.0.0b2_r792 | |||
* | |||
* Copyright (c) 2009-2011 Chris Leonello | |||
* jqPlot is currently available for use in all personal or commercial projects | |||
* under both the MIT (http://www.opensource.org/licenses/mit-license.php) and GPL | |||
* version 2.0 (http://www.gnu.org/licenses/gpl-2.0.html) licenses. This means that you can | |||
* choose the license that best suits your project and use it accordingly. | |||
* | |||
* Although not required, the author would appreciate an email letting him | |||
* know of any substantial use of jqPlot. You can reach the author at: | |||
* chris at jqplot dot com or see http://www.jqplot.com/info.php . | |||
* | |||
* If you are feeling kind and generous, consider supporting the project by | |||
* making a donation at: http://www.jqplot.com/donate.php . | |||
* | |||
* sprintf functions contained in jqplot.sprintf.js by Ash Searle: | |||
* | |||
* version 2007.04.27 | |||
* author Ash Searle | |||
* http://hexmen.com/blog/2007/03/printf-sprintf/ | |||
* http://hexmen.com/js/sprintf.js | |||
* The author (Ash Searle) has placed this code in the public domain: | |||
* "This code is unrestricted: you are free to use it however you like." | |||
* | |||
*/ | |||
(function($) { | |||
// Class: $.jqplot.BezierCurveRenderer.js | |||
// Renderer which draws lines as stacked bezier curves. | |||
// Data for the line will not be specified as an array of | |||
// [x, y] data point values, but as a an array of [start piont, bezier curve] | |||
// So, the line is specified as: [[xstart, ystart], [cp1x, cp1y, cp2x, cp2y, xend, yend]]. | |||
$.jqplot.BezierCurveRenderer = function(){ | |||
$.jqplot.LineRenderer.call(this); | |||
}; | |||
$.jqplot.BezierCurveRenderer.prototype = new $.jqplot.LineRenderer(); | |||
$.jqplot.BezierCurveRenderer.prototype.constructor = $.jqplot.BezierCurveRenderer; | |||
// Method: setGridData | |||
// converts the user data values to grid coordinates and stores them | |||
// in the gridData array. | |||
// Called with scope of a series. | |||
$.jqplot.BezierCurveRenderer.prototype.setGridData = function(plot) { | |||
// recalculate the grid data | |||
var xp = this._xaxis.series_u2p; | |||
var yp = this._yaxis.series_u2p; | |||
// this._plotData should be same as this.data | |||
var data = this.data; | |||
this.gridData = []; | |||
this._prevGridData = []; | |||
// if seriesIndex = 0, fill to x axis. | |||
// if seriesIndex > 0, fill to previous series data. | |||
var idx = this.index; | |||
if (data.length == 2) { | |||
if (idx == 0) { | |||
this.gridData = [ | |||
[xp.call(this._xaxis, data[0][0]), yp.call(this._yaxis, data[0][1])], | |||
[xp.call(this._xaxis, data[1][0]), yp.call(this._yaxis, data[1][1]), | |||
xp.call(this._xaxis, data[1][2]), yp.call(this._yaxis, data[1][3]), | |||
xp.call(this._xaxis, data[1][4]), yp.call(this._yaxis, data[1][5])], | |||
[xp.call(this._xaxis, data[1][4]), yp.call(this._yaxis, this._yaxis.min)], | |||
[xp.call(this._xaxis, data[0][0]), yp.call(this._yaxis, this._yaxis.min)] | |||
]; | |||
} | |||
else { | |||
var psd = plot.series[idx-1].data; | |||
this.gridData = [ | |||
[xp.call(this._xaxis, data[0][0]), yp.call(this._yaxis, data[0][1])], | |||
[xp.call(this._xaxis, data[1][0]), yp.call(this._yaxis, data[1][1]), | |||
xp.call(this._xaxis, data[1][2]), yp.call(this._yaxis, data[1][3]), | |||
xp.call(this._xaxis, data[1][4]), yp.call(this._yaxis, data[1][5])], | |||
[xp.call(this._xaxis, psd[1][4]), yp.call(this._yaxis, psd[1][5])], | |||
[xp.call(this._xaxis, psd[1][2]), yp.call(this._yaxis, psd[1][3]), | |||
xp.call(this._xaxis, psd[1][0]), yp.call(this._yaxis, psd[1][1]), | |||
xp.call(this._xaxis, psd[0][0]), yp.call(this._yaxis, psd[0][1])] | |||
]; | |||
} | |||
} | |||
else { | |||
if (idx == 0) { | |||
this.gridData = [ | |||
[xp.call(this._xaxis, data[0][0]), yp.call(this._yaxis, data[0][1])], | |||
[xp.call(this._xaxis, data[1][0]), yp.call(this._yaxis, data[1][1]), | |||
xp.call(this._xaxis, data[2][0]), yp.call(this._yaxis, data[2][1]), | |||
xp.call(this._xaxis, data[3][0]), yp.call(this._yaxis, data[3][1])], | |||
[xp.call(this._xaxis, data[3][1]), yp.call(this._yaxis, this._yaxis.min)], | |||
[xp.call(this._xaxis, data[0][0]), yp.call(this._yaxis, this._yaxis.min)] | |||
]; | |||
} | |||
else { | |||
var psd = plot.series[idx-1].data; | |||
this.gridData = [ | |||
[xp.call(this._xaxis, data[0][0]), yp.call(this._yaxis, data[0][1])], | |||
[xp.call(this._xaxis, data[1][0]), yp.call(this._yaxis, data[1][1]), | |||
xp.call(this._xaxis, data[2][0]), yp.call(this._yaxis, data[2][1]), | |||
xp.call(this._xaxis, data[3][0]), yp.call(this._yaxis, data[3][1])], | |||
[xp.call(this._xaxis, psd[3][0]), yp.call(this._yaxis, psd[3][1])], | |||
[xp.call(this._xaxis, psd[2][0]), yp.call(this._yaxis, psd[2][1]), | |||
xp.call(this._xaxis, psd[1][0]), yp.call(this._yaxis, psd[1][1]), | |||
xp.call(this._xaxis, psd[0][0]), yp.call(this._yaxis, psd[0][1])] | |||
]; | |||
} | |||
} | |||
}; | |||
// Method: makeGridData | |||
// converts any arbitrary data values to grid coordinates and | |||
// returns them. This method exists so that plugins can use a series' | |||
// linerenderer to generate grid data points without overwriting the | |||
// grid data associated with that series. | |||
// Called with scope of a series. | |||
$.jqplot.BezierCurveRenderer.prototype.makeGridData = function(data, plot) { | |||
// recalculate the grid data | |||
var xp = this._xaxis.series_u2p; | |||
var yp = this._yaxis.series_u2p; | |||
var gd = []; | |||
var pgd = []; | |||
// if seriesIndex = 0, fill to x axis. | |||
// if seriesIndex > 0, fill to previous series data. | |||
var idx = this.index; | |||
if (data.length == 2) { | |||
if (idx == 0) { | |||
gd = [ | |||
[xp.call(this._xaxis, data[0][0]), yp.call(this._yaxis, data[0][1])], | |||
[xp.call(this._xaxis, data[1][0]), yp.call(this._yaxis, data[1][1]), | |||
xp.call(this._xaxis, data[1][2]), yp.call(this._yaxis, data[1][3]), | |||
xp.call(this._xaxis, data[1][4]), yp.call(this._yaxis, data[1][5])], | |||
[xp.call(this._xaxis, data[1][4]), yp.call(this._yaxis, this._yaxis.min)], | |||
[xp.call(this._xaxis, data[0][0]), yp.call(this._yaxis, this._yaxis.min)] | |||
]; | |||
} | |||
else { | |||
var psd = plot.series[idx-1].data; | |||
gd = [ | |||
[xp.call(this._xaxis, data[0][0]), yp.call(this._yaxis, data[0][1])], | |||
[xp.call(this._xaxis, data[1][0]), yp.call(this._yaxis, data[1][1]), | |||
xp.call(this._xaxis, data[1][2]), yp.call(this._yaxis, data[1][3]), | |||
xp.call(this._xaxis, data[1][4]), yp.call(this._yaxis, data[1][5])], | |||
[xp.call(this._xaxis, psd[1][4]), yp.call(this._yaxis, psd[1][5])], | |||
[xp.call(this._xaxis, psd[1][2]), yp.call(this._yaxis, psd[1][3]), | |||
xp.call(this._xaxis, psd[1][0]), yp.call(this._yaxis, psd[1][1]), | |||
xp.call(this._xaxis, psd[0][0]), yp.call(this._yaxis, psd[0][1])] | |||
]; | |||
} | |||
} | |||
else { | |||
if (idx == 0) { | |||
gd = [ | |||
[xp.call(this._xaxis, data[0][0]), yp.call(this._yaxis, data[0][1])], | |||
[xp.call(this._xaxis, data[1][0]), yp.call(this._yaxis, data[1][1]), | |||
xp.call(this._xaxis, data[2][0]), yp.call(this._yaxis, data[2][1]), | |||
xp.call(this._xaxis, data[3][0]), yp.call(this._yaxis, data[3][1])], | |||
[xp.call(this._xaxis, data[3][1]), yp.call(this._yaxis, this._yaxis.min)], | |||
[xp.call(this._xaxis, data[0][0]), yp.call(this._yaxis, this._yaxis.min)] | |||
]; | |||
} | |||
else { | |||
var psd = plot.series[idx-1].data; | |||
gd = [ | |||
[xp.call(this._xaxis, data[0][0]), yp.call(this._yaxis, data[0][1])], | |||
[xp.call(this._xaxis, data[1][0]), yp.call(this._yaxis, data[1][1]), | |||
xp.call(this._xaxis, data[2][0]), yp.call(this._yaxis, data[2][1]), | |||
xp.call(this._xaxis, data[3][0]), yp.call(this._yaxis, data[3][1])], | |||
[xp.call(this._xaxis, psd[3][0]), yp.call(this._yaxis, psd[3][1])], | |||
[xp.call(this._xaxis, psd[2][0]), yp.call(this._yaxis, psd[2][1]), | |||
xp.call(this._xaxis, psd[1][0]), yp.call(this._yaxis, psd[1][1]), | |||
xp.call(this._xaxis, psd[0][0]), yp.call(this._yaxis, psd[0][1])] | |||
]; | |||
} | |||
} | |||
return gd; | |||
}; | |||
// called within scope of series. | |||
$.jqplot.BezierCurveRenderer.prototype.draw = function(ctx, gd, options) { | |||
var i; | |||
ctx.save(); | |||
if (gd.length) { | |||
if (this.showLine) { | |||
ctx.save(); | |||
var opts = (options != null) ? options : {}; | |||
ctx.fillStyle = opts.fillStyle || this.color; | |||
ctx.beginPath(); | |||
ctx.moveTo(gd[0][0], gd[0][1]); | |||
ctx.bezierCurveTo(gd[1][0], gd[1][1], gd[1][2], gd[1][3], gd[1][4], gd[1][5]); | |||
ctx.lineTo(gd[2][0], gd[2][1]); | |||
if (gd[3].length == 2) { | |||
ctx.lineTo(gd[3][0], gd[3][1]); | |||
} | |||
else { | |||
ctx.bezierCurveTo(gd[3][0], gd[3][1], gd[3][2], gd[3][3], gd[3][4], gd[3][5]); | |||
} | |||
ctx.closePath(); | |||
ctx.fill(); | |||
ctx.restore(); | |||
} | |||
} | |||
ctx.restore(); | |||
}; | |||
$.jqplot.BezierCurveRenderer.prototype.drawShadow = function(ctx, gd, options) { | |||
// This is a no-op, shadows drawn with lines. | |||
}; | |||
$.jqplot.BezierAxisRenderer = function() { | |||
$.jqplot.LinearAxisRenderer.call(this); | |||
}; | |||
$.jqplot.BezierAxisRenderer.prototype = new $.jqplot.LinearAxisRenderer(); | |||
$.jqplot.BezierAxisRenderer.prototype.constructor = $.jqplot.BezierAxisRenderer; | |||
// Axes on a plot with Bezier Curves | |||
$.jqplot.BezierAxisRenderer.prototype.init = function(options){ | |||
$.extend(true, this, options); | |||
var db = this._dataBounds; | |||
// Go through all the series attached to this axis and find | |||
// the min/max bounds for this axis. | |||
for (var i=0; i<this._series.length; i++) { | |||
var s = this._series[i]; | |||
var d = s.data; | |||
if (d.length == 4) { | |||
for (var j=0; j<d.length; j++) { | |||
if (this.name == 'xaxis' || this.name == 'x2axis') { | |||
if (d[j][0] < db.min || db.min == null) { | |||
db.min = d[j][0]; | |||
} | |||
if (d[j][0] > db.max || db.max == null) { | |||
db.max = d[j][0]; | |||
} | |||
} | |||
else { | |||
if (d[j][1] < db.min || db.min == null) { | |||
db.min = d[j][1]; | |||
} | |||
if (d[j][1] > db.max || db.max == null) { | |||
db.max = d[j][1]; | |||
} | |||
} | |||
} | |||
} | |||
else { | |||
if (this.name == 'xaxis' || this.name == 'x2axis') { | |||
if (d[0][0] < db.min || db.min == null) { | |||
db.min = d[0][0]; | |||
} | |||
if (d[0][0] > db.max || db.max == null) { | |||
db.max = d[0][0]; | |||
} | |||
for (var j=0; j<5; j+=2) { | |||
if (d[1][j] < db.min || db.min == null) { | |||
db.min = d[1][j]; | |||
} | |||
if (d[1][j] > db.max || db.max == null) { | |||
db.max = d[1][j]; | |||
} | |||
} | |||
} | |||
else { | |||
if (d[0][1] < db.min || db.min == null) { | |||
db.min = d[0][1]; | |||
} | |||
if (d[0][1] > db.max || db.max == null) { | |||
db.max = d[0][1]; | |||
} | |||
for (var j=1; j<6; j+=2) { | |||
if (d[1][j] < db.min || db.min == null) { | |||
db.min = d[1][j]; | |||
} | |||
if (d[1][j] > db.max || db.max == null) { | |||
db.max = d[1][j]; | |||
} | |||
} | |||
} | |||
} | |||
} | |||
}; | |||
// setup default renderers for axes and legend so user doesn't have to | |||
// called with scope of plot | |||
function preInit(target, data, options) { | |||
options = options || {}; | |||
options.axesDefaults = $.extend(true, {pad:0}, options.axesDefaults); | |||
options.legend = $.extend(true, {placement:'outside'}, options.legend); | |||
// only set these if there is a pie series | |||
var setopts = false; | |||
if (options.seriesDefaults.renderer == $.jqplot.BezierCurveRenderer) { | |||
setopts = true; | |||
} | |||
else if (options.series) { | |||
for (var i=0; i < options.series.length; i++) { | |||
if (options.series[i].renderer == $.jqplot.BezierCurveRenderer) { | |||
setopts = true; | |||
} | |||
} | |||
} | |||
if (setopts) { | |||
options.axesDefaults.renderer = $.jqplot.BezierAxisRenderer; | |||
} | |||
} | |||
$.jqplot.preInitHooks.push(preInit); | |||
})(jQuery); |
@@ -1,18 +1,30 @@ | |||
/** | |||
* Copyright (c) 2009 Chris Leonello | |||
* jqPlot | |||
* Pure JavaScript plotting plugin using jQuery | |||
* | |||
* Version: 1.0.0b2_r792 | |||
* | |||
* Copyright (c) 2009-2011 Chris Leonello | |||
* jqPlot is currently available for use in all personal or commercial projects | |||
* under both the MIT and GPL version 2.0 licenses. This means that you can | |||
* under both the MIT (http://www.opensource.org/licenses/mit-license.php) and GPL | |||
* version 2.0 (http://www.gnu.org/licenses/gpl-2.0.html) licenses. This means that you can | |||
* choose the license that best suits your project and use it accordingly. | |||
* | |||
* The author would appreciate an email letting him know of any substantial | |||
* use of jqPlot. You can reach the author at: chris dot leonello at gmail | |||
* dot com or see http://www.jqplot.com/info.php . This is, of course, | |||
* not required. | |||
* Although not required, the author would appreciate an email letting him | |||
* know of any substantial use of jqPlot. You can reach the author at: | |||
* chris at jqplot dot com or see http://www.jqplot.com/info.php . | |||
* | |||
* If you are feeling kind and generous, consider supporting the project by | |||
* making a donation at: http://www.jqplot.com/donate.php . | |||
* | |||
* Thanks for using jqPlot! | |||
* sprintf functions contained in jqplot.sprintf.js by Ash Searle: | |||
* | |||
* version 2007.04.27 | |||
* author Ash Searle | |||
* http://hexmen.com/blog/2007/03/printf-sprintf/ | |||
* http://hexmen.com/js/sprintf.js | |||
* The author (Ash Searle) has placed this code in the public domain: | |||
* "This code is unrestricted: you are free to use it however you like." | |||
* | |||
*/ | |||
(function($) { | |||
@@ -29,7 +41,7 @@ | |||
$.jqplot.BarRenderer.prototype.constructor = $.jqplot.BarRenderer; | |||
// called with scope of series. | |||
$.jqplot.BarRenderer.prototype.init = function(options) { | |||
$.jqplot.BarRenderer.prototype.init = function(options, plot) { | |||
// Group: Properties | |||
// | |||
// prop: barPadding | |||
@@ -58,9 +70,35 @@ | |||
// prop: waterfall | |||
// true to enable waterfall plot. | |||
this.waterfall = false; | |||
// prop: groups | |||
// group bars into this many groups | |||
this.groups = 1; | |||
// prop: varyBarColor | |||
// true to color each bar separately. | |||
// true to color each bar of a series separately rather than | |||
// have every bar of a given series the same color. | |||
// If used for non-stacked multiple series bar plots, user should | |||
// specify a separate 'seriesColors' array for each series. | |||
// Otherwise, each series will set their bars to the same color array. | |||
// This option has no Effect for stacked bar charts and is disabled. | |||
this.varyBarColor = false; | |||
// prop: highlightMouseOver | |||
// True to highlight slice when moused over. | |||
// This must be false to enable highlightMouseDown to highlight when clicking on a slice. | |||
this.highlightMouseOver = true; | |||
// prop: highlightMouseDown | |||
// True to highlight when a mouse button is pressed over a slice. | |||
// This will be disabled if highlightMouseOver is true. | |||
this.highlightMouseDown = false; | |||
// prop: highlightColors | |||
// an array of colors to use when highlighting a bar. | |||
this.highlightColors = []; | |||
this._type = 'bar'; | |||
// if user has passed in highlightMouseDown option and not set highlightMouseOver, disable highlightMouseOver | |||
if (options.highlightMouseDown && options.highlightMouseOver == null) { | |||
options.highlightMouseOver = false; | |||
} | |||
$.extend(true, this, options); | |||
// fill is still needed to properly draw the legend. | |||
// bars have to be filled. | |||
@@ -81,12 +119,28 @@ | |||
this._stackAxis = 'x'; | |||
this.fillAxis = 'x'; | |||
} | |||
// index of the currenty highlighted point, if any | |||
this._highlightedPoint = null; | |||
// total number of values for all bar series, total number of bar series, and position of this series | |||
this._plotSeriesInfo = null; | |||
// Array of actual data colors used for each data point. | |||
this._dataColors = []; | |||
this._barPoints = []; | |||
// set the shape renderer options | |||
var opts = {lineJoin:'miter', lineCap:'round', fill:true, isarc:false, strokeStyle:this.color, fillStyle:this.color, closePath:this.fill}; | |||
this.renderer.shapeRenderer.init(opts); | |||
// set the shadow renderer options | |||
var sopts = {lineJoin:'miter', lineCap:'round', fill:true, isarc:false, angle:this.shadowAngle, offset:this.shadowOffset, alpha:this.shadowAlpha, depth:this.shadowDepth, closePath:this.fill}; | |||
this.renderer.shadowRenderer.init(sopts); | |||
plot.postInitHooks.addOnce(postInit); | |||
plot.postDrawHooks.addOnce(postPlotDraw); | |||
plot.eventListenerHooks.addOnce('jqplotMouseMove', handleMove); | |||
plot.eventListenerHooks.addOnce('jqplotMouseDown', handleMouseDown); | |||
plot.eventListenerHooks.addOnce('jqplotMouseUp', handleMouseUp); | |||
plot.eventListenerHooks.addOnce('jqplotClick', handleClick); | |||
plot.eventListenerHooks.addOnce('jqplotRightClick', handleRightClick); | |||
}; | |||
// called with scope of series | |||
@@ -108,6 +162,24 @@ | |||
this.data[this.data.length] = (pos == 1) ? [this.data.length+1, sum] : [sum, this.data.length+1]; | |||
this._data[this._data.length] = (pos == 1) ? [this._data.length+1, sum] : [sum, this._data.length+1]; | |||
} | |||
if (this.rendererOptions.groups > 1) { | |||
this.breakOnNull = true; | |||
var l = this.data.length; | |||
var skip = parseInt(l/this.rendererOptions.groups, 10); | |||
var count = 0; | |||
for (var i=skip; i<l; i+=skip) { | |||
this.data.splice(i+count, 0, [null, null]); | |||
count++; | |||
} | |||
for (i=0; i<this.data.length; i++) { | |||
if (this._primaryAxis == '_xaxis') { | |||
this.data[i][0] = i+1; | |||
} | |||
else { | |||
this.data[i][1] = i+1; | |||
} | |||
} | |||
} | |||
} | |||
$.jqplot.preSeriesInitHooks.push(barPreInit); | |||
@@ -131,6 +203,7 @@ | |||
nseries += 1; | |||
} | |||
} | |||
// return total number of values for all bar series, total number of bar series, and position of this series | |||
return [nvals, nseries, pos]; | |||
}; | |||
@@ -141,7 +214,7 @@ | |||
var nseries = 0; | |||
var paxis = this[this._primaryAxis]; | |||
var s, series, pos; | |||
var temp = this.renderer.calcSeriesNumbers.call(this); | |||
var temp = this._plotSeriesInfo = this.renderer.calcSeriesNumbers.call(this); | |||
nvals = temp[0]; | |||
nseries = temp[1]; | |||
var nticks = paxis.numberTicks; | |||
@@ -167,10 +240,27 @@ | |||
} | |||
return [nvals, nseries]; | |||
}; | |||
function computeHighlightColors (colors) { | |||
var ret = []; | |||
for (var i=0; i<colors.length; i++){ | |||
var rgba = $.jqplot.getColorComponents(colors[i]); | |||
var newrgb = [rgba[0], rgba[1], rgba[2]]; | |||
var sum = newrgb[0] + newrgb[1] + newrgb[2]; | |||
for (var j=0; j<3; j++) { | |||
// when darkening, lowest color component can be is 60. | |||
newrgb[j] = (sum > 570) ? newrgb[j] * 0.8 : newrgb[j] + 0.3 * (255 - newrgb[j]); | |||
newrgb[j] = parseInt(newrgb[j], 10); | |||
} | |||
ret.push('rgb('+newrgb[0]+','+newrgb[1]+','+newrgb[2]+')'); | |||
} | |||
return ret; | |||
} | |||
$.jqplot.BarRenderer.prototype.draw = function(ctx, gridData, options) { | |||
var i; | |||
var opts = (options != undefined) ? options : {}; | |||
// Ughhh, have to make a copy of options b/c it may be modified later. | |||
var opts = $.extend({}, options); | |||
var shadow = (opts.shadow != undefined) ? opts.shadow : this.shadow; | |||
var showLine = (opts.showLine != undefined) ? opts.showLine : this.showLine; | |||
var fill = (opts.fill != undefined) ? opts.fill : this.fill; | |||
@@ -178,16 +268,20 @@ | |||
var yaxis = this.yaxis; | |||
var xp = this._xaxis.series_u2p; | |||
var yp = this._yaxis.series_u2p; | |||
var pointx, pointy, nvals, nseries, pos; | |||
var pointx, pointy; | |||
// clear out data colors. | |||
this._dataColors = []; | |||
this._barPoints = []; | |||
if (this.barWidth == null) { | |||
this.renderer.setBarWidth.call(this); | |||
} | |||
var temp = this.renderer.calcSeriesNumbers.call(this); | |||
nvals = temp[0]; | |||
nseries = temp[1]; | |||
pos = temp[2]; | |||
var temp = this._plotSeriesInfo = this.renderer.calcSeriesNumbers.call(this); | |||
var nvals = temp[0]; | |||
var nseries = temp[1]; | |||
var pos = temp[2]; | |||
var points = []; | |||
if (this._stack) { | |||
this._barNudge = 0; | |||
@@ -203,12 +297,18 @@ | |||
negativeColor = opts.fillStyle; | |||
} | |||
var positiveColor = opts.fillStyle; | |||
var base; | |||
var xstart; | |||
var ystart; | |||
if (this.barDirection == 'vertical') { | |||
for (var i=0; i<gridData.length; i++) { | |||
if (this.data[i][1] == null) { | |||
continue; | |||
} | |||
points = []; | |||
var base = gridData[i][0] + this._barNudge; | |||
var ystart; | |||
base = gridData[i][0] + this._barNudge; | |||
ystart; | |||
// stacked | |||
if (this._stack && this._prevGridData.length) { | |||
@@ -222,12 +322,34 @@ | |||
else if (this.waterfall && i > 0 && i < this.gridData.length-1) { | |||
ystart = this.gridData[i-1][1]; | |||
} | |||
else if (this.waterfall && i == 0 && i < this.gridData.length-1) { | |||
if (this._yaxis.min <= 0 && this._yaxis.max >= 0) { | |||
ystart = this._yaxis.series_u2p(0); | |||
} | |||
else if (this._yaxis.min > 0) { | |||
ystart = ctx.canvas.height; | |||
} | |||
else { | |||
ystart = 0; | |||
} | |||
} | |||
else if (this.waterfall && i == this.gridData.length - 1) { | |||
if (this._yaxis.min <= 0 && this._yaxis.max >= 0) { | |||
ystart = this._yaxis.series_u2p(0); | |||
} | |||
else if (this._yaxis.min > 0) { | |||
ystart = ctx.canvas.height; | |||
} | |||
else { | |||
ystart = 0; | |||
} | |||
} | |||
else { | |||
ystart = ctx.canvas.height; | |||
} | |||
} | |||
if ((this.fillToZero && this._plotData[i][1] < 0) || (this.waterfall && this._data[i][1] < 0)) { | |||
if (this.varyBarColor) { | |||
if (this.varyBarColor && !this._stack) { | |||
if (this.useNegativeColors) { | |||
opts.fillStyle = negativeColors.next(); | |||
} | |||
@@ -240,32 +362,50 @@ | |||
} | |||
} | |||
else { | |||
if (this.varyBarColor) { | |||
if (this.varyBarColor && !this._stack) { | |||
opts.fillStyle = positiveColors.next(); | |||
} | |||
else { | |||
opts.fillStyle = positiveColor; | |||
} | |||
} | |||
points.push([base-this.barWidth/2, ystart]); | |||
points.push([base-this.barWidth/2, gridData[i][1]]); | |||
points.push([base+this.barWidth/2, gridData[i][1]]); | |||
points.push([base+this.barWidth/2, ystart]); | |||
if (!this.fillToZero || this._plotData[i][1] >= 0) { | |||
points.push([base-this.barWidth/2, ystart]); | |||
points.push([base-this.barWidth/2, gridData[i][1]]); | |||
points.push([base+this.barWidth/2, gridData[i][1]]); | |||
points.push([base+this.barWidth/2, ystart]); | |||
} | |||
// for negative bars make sure points are always ordered clockwise | |||
else { | |||
points.push([base-this.barWidth/2, gridData[i][1]]); | |||
points.push([base-this.barWidth/2, ystart]); | |||
points.push([base+this.barWidth/2, ystart]); | |||
points.push([base+this.barWidth/2, gridData[i][1]]); | |||
} | |||
this._barPoints.push(points); | |||
// now draw the shadows if not stacked. | |||
// for stacked plots, they are predrawn by drawShadow | |||
if (shadow && !this._stack) { | |||
this.renderer.shadowRenderer.draw(ctx, points, opts); | |||
var sopts = $.extend(true, {}, opts); | |||
// need to get rid of fillStyle on shadow. | |||
delete sopts.fillStyle; | |||
this.renderer.shadowRenderer.draw(ctx, points, sopts); | |||
} | |||
var clr = opts.fillStyle || this.color; | |||
this._dataColors.push(clr); | |||
this.renderer.shapeRenderer.draw(ctx, points, opts); | |||
} | |||
} | |||
else if (this.barDirection == 'horizontal'){ | |||
for (var i=0; i<gridData.length; i++) { | |||
if (this.data[i][0] == null) { | |||
continue; | |||
} | |||
points = []; | |||
var base = gridData[i][1] - this._barNudge; | |||
var xstart; | |||
base = gridData[i][1] - this._barNudge; | |||
xstart; | |||
if (this._stack && this._prevGridData.length) { | |||
xstart = this._prevGridData[i][0]; | |||
@@ -278,12 +418,34 @@ | |||
else if (this.waterfall && i > 0 && i < this.gridData.length-1) { | |||
xstart = this.gridData[i-1][1]; | |||
} | |||
else if (this.waterfall && i == 0 && i < this.gridData.length-1) { | |||
if (this._xaxis.min <= 0 && this._xaxis.max >= 0) { | |||
xstart = this._xaxis.series_u2p(0); | |||
} | |||
else if (this._xaxis.min > 0) { | |||
xstart = 0; | |||
} | |||
else { | |||
xstart = ctx.canvas.width; | |||
} | |||
} | |||
else if (this.waterfall && i == this.gridData.length - 1) { | |||
if (this._xaxis.min <= 0 && this._xaxis.max >= 0) { | |||
xstart = this._xaxis.series_u2p(0); | |||
} | |||
else if (this._xaxis.min > 0) { | |||
xstart = 0; | |||
} | |||
else { | |||
xstart = ctx.canvas.width; | |||
} | |||
} | |||
else { | |||
xstart = 0; | |||
} | |||
} | |||
if ((this.fillToZero && this._plotData[i][1] < 0) || (this.waterfall && this._data[i][1] < 0)) { | |||
if (this.varyBarColor) { | |||
if (this.varyBarColor && !this._stack) { | |||
if (this.useNegativeColors) { | |||
opts.fillStyle = negativeColors.next(); | |||
} | |||
@@ -293,7 +455,7 @@ | |||
} | |||
} | |||
else { | |||
if (this.varyBarColor) { | |||
if (this.varyBarColor && !this._stack) { | |||
opts.fillStyle = positiveColors.next(); | |||
} | |||
else { | |||
@@ -302,19 +464,36 @@ | |||
} | |||
points.push([xstart, base+this.barWidth/2]); | |||
points.push([gridData[i][0], base+this.barWidth/2]); | |||
points.push([gridData[i][0], base-this.barWidth/2]); | |||
points.push([xstart, base-this.barWidth/2]); | |||
points.push([gridData[i][0], base-this.barWidth/2]); | |||
points.push([gridData[i][0], base+this.barWidth/2]); | |||
this._barPoints.push(points); | |||
// now draw the shadows if not stacked. | |||
// for stacked plots, they are predrawn by drawShadow | |||
if (shadow && !this._stack) { | |||
this.renderer.shadowRenderer.draw(ctx, points, opts); | |||
var sopts = $.extend(true, {}, opts); | |||
delete sopts.fillStyle; | |||
this.renderer.shadowRenderer.draw(ctx, points, sopts); | |||
} | |||
var clr = opts.fillStyle || this.color; | |||
this._dataColors.push(clr); | |||
this.renderer.shapeRenderer.draw(ctx, points, opts); | |||
} | |||
} | |||
} | |||
if (this.highlightColors.length == 0) { | |||
this.highlightColors = computeHighlightColors(this._dataColors); | |||
} | |||
else if (typeof(this.highlightColors) == 'string') { | |||
var temp = this.highlightColors; | |||
this.highlightColors = []; | |||
for (var i=0; i<this._dataColors.length; i++) { | |||
this.highlightColors.push(temp); | |||
} | |||
} | |||
}; | |||
@@ -329,14 +508,14 @@ | |||
var yaxis = this.yaxis; | |||
var xp = this._xaxis.series_u2p; | |||
var yp = this._yaxis.series_u2p; | |||
var pointx, pointy, nvals, nseries, pos; | |||
var pointx, points, pointy, nvals, nseries, pos; | |||
if (this._stack && this.shadow) { | |||
if (this.barWidth == null) { | |||
this.renderer.setBarWidth.call(this); | |||
} | |||
var temp = this.renderer.calcSeriesNumbers.call(this); | |||
var temp = this._plotSeriesInfo = this.renderer.calcSeriesNumbers.call(this); | |||
nvals = temp[0]; | |||
nseries = temp[1]; | |||
pos = temp[2]; | |||
@@ -351,6 +530,9 @@ | |||
if (this.barDirection == 'vertical') { | |||
for (var i=0; i<gridData.length; i++) { | |||
if (this.data[i][1] == null) { | |||
continue; | |||
} | |||
points = []; | |||
var base = gridData[i][0] + this._barNudge; | |||
var ystart; | |||
@@ -377,6 +559,9 @@ | |||
else if (this.barDirection == 'horizontal'){ | |||
for (var i=0; i<gridData.length; i++) { | |||
if (this.data[i][0] == null) { | |||
continue; | |||
} | |||
points = []; | |||
var base = gridData[i][1] - this._barNudge; | |||
var xstart; | |||
@@ -398,7 +583,127 @@ | |||
} | |||
} | |||
}; | |||
function postInit(target, data, options) { | |||
for (var i=0; i<this.series.length; i++) { | |||
if (this.series[i].renderer.constructor == $.jqplot.BarRenderer) { | |||
// don't allow mouseover and mousedown at same time. | |||
if (this.series[i].highlightMouseOver) { | |||
this.series[i].highlightMouseDown = false; | |||
} | |||
} | |||
} | |||
this.target.bind('mouseout', {plot:this}, function (ev) { unhighlight(ev.data.plot); }); | |||
} | |||
// called within context of plot | |||
// create a canvas which we can draw on. | |||
// insert it before the eventCanvas, so eventCanvas will still capture events. | |||
function postPlotDraw() { | |||
// Memory Leaks patch | |||
if (this.plugins.barRenderer && this.plugins.barRenderer.highlightCanvas) { | |||
this.plugins.barRenderer.highlightCanvas.resetCanvas(); | |||
this.plugins.barRenderer.highlightCanvas = null; | |||
} | |||
this.plugins.barRenderer = {highlightedSeriesIndex:null}; | |||
this.plugins.barRenderer.highlightCanvas = new $.jqplot.GenericCanvas(); | |||
this.eventCanvas._elem.before(this.plugins.barRenderer.highlightCanvas.createElement(this._gridPadding, 'jqplot-barRenderer-highlight-canvas', this._plotDimensions, this)); | |||
this.plugins.barRenderer.highlightCanvas.setContext(); | |||
} | |||
function highlight (plot, sidx, pidx, points) { | |||
var s = plot.series[sidx]; | |||
var canvas = plot.plugins.barRenderer.highlightCanvas; | |||
canvas._ctx.clearRect(0,0,canvas._ctx.canvas.width, canvas._ctx.canvas.height); | |||
s._highlightedPoint = pidx; | |||
plot.plugins.barRenderer.highlightedSeriesIndex = sidx; | |||
var opts = {fillStyle: s.highlightColors[pidx]}; | |||
s.renderer.shapeRenderer.draw(canvas._ctx, points, opts); | |||
canvas = null; | |||
} | |||
function unhighlight (plot) { | |||
var canvas = plot.plugins.barRenderer.highlightCanvas; | |||
canvas._ctx.clearRect(0,0, canvas._ctx.canvas.width, canvas._ctx.canvas.height); | |||
for (var i=0; i<plot.series.length; i++) { | |||
plot.series[i]._highlightedPoint = null; | |||
} | |||
plot.plugins.barRenderer.highlightedSeriesIndex = null; | |||
plot.target.trigger('jqplotDataUnhighlight'); | |||
canvas = null; | |||
} | |||
function handleMove(ev, gridpos, datapos, neighbor, plot) { | |||
if (neighbor) { | |||
var ins = [neighbor.seriesIndex, neighbor.pointIndex, neighbor.data]; | |||
var evt1 = jQuery.Event('jqplotDataMouseOver'); | |||
evt1.pageX = ev.pageX; | |||
evt1.pageY = ev.pageY; | |||
plot.target.trigger(evt1, ins); | |||
if (plot.series[ins[0]].highlightMouseOver && !(ins[0] == plot.plugins.barRenderer.highlightedSeriesIndex && ins[1] == plot.series[ins[0]]._highlightedPoint)) { | |||
var evt = jQuery.Event('jqplotDataHighlight'); | |||
evt.pageX = ev.pageX; | |||
evt.pageY = ev.pageY; | |||
plot.target.trigger(evt, ins); | |||
highlight (plot, neighbor.seriesIndex, neighbor.pointIndex, neighbor.points); | |||
} | |||
} | |||
else if (neighbor == null) { | |||
unhighlight (plot); | |||
} | |||
} | |||
function handleMouseDown(ev, gridpos, datapos, neighbor, plot) { | |||
if (neighbor) { | |||
var ins = [neighbor.seriesIndex, neighbor.pointIndex, neighbor.data]; | |||
if (plot.series[ins[0]].highlightMouseDown && !(ins[0] == plot.plugins.barRenderer.highlightedSeriesIndex && ins[1] == plot.series[ins[0]]._highlightedPoint)) { | |||
var evt = jQuery.Event('jqplotDataHighlight'); | |||
evt.pageX = ev.pageX; | |||
evt.pageY = ev.pageY; | |||
plot.target.trigger(evt, ins); | |||
highlight (plot, neighbor.seriesIndex, neighbor.pointIndex, neighbor.points); | |||
} | |||
} | |||
else if (neighbor == null) { | |||
unhighlight (plot); | |||
} | |||
} | |||
function handleMouseUp(ev, gridpos, datapos, neighbor, plot) { | |||
var idx = plot.plugins.barRenderer.highlightedSeriesIndex; | |||
if (idx != null && plot.series[idx].highlightMouseDown) { | |||
unhighlight(plot); | |||
} | |||
} | |||
function handleClick(ev, gridpos, datapos, neighbor, plot) { | |||
if (neighbor) { | |||
var ins = [neighbor.seriesIndex, neighbor.pointIndex, neighbor.data]; | |||
var evt = jQuery.Event('jqplotDataClick'); | |||
evt.pageX = ev.pageX; | |||
evt.pageY = ev.pageY; | |||
plot.target.trigger(evt, ins); | |||
} | |||
} | |||
function handleRightClick(ev, gridpos, datapos, neighbor, plot) { | |||
if (neighbor) { | |||
var ins = [neighbor.seriesIndex, neighbor.pointIndex, neighbor.data]; | |||
var idx = plot.plugins.barRenderer.highlightedSeriesIndex; | |||
if (idx != null && plot.series[idx].highlightMouseDown) { | |||
unhighlight(plot); | |||
} | |||
var evt = jQuery.Event('jqplotDataRightClick'); | |||
evt.pageX = ev.pageX; | |||
evt.pageY = ev.pageY; | |||
plot.target.trigger(evt, ins); | |||
} | |||
} | |||
})(jQuery); |
@@ -0,0 +1,234 @@ | |||
/** | |||
* jqPlot | |||
* Pure JavaScript plotting plugin using jQuery | |||
* | |||
* Version: 1.0.0b2_r792 | |||
* | |||
* Copyright (c) 2009-2011 Chris Leonello | |||
* jqPlot is currently available for use in all personal or commercial projects | |||
* under both the MIT (http://www.opensource.org/licenses/mit-license.php) and GPL | |||
* version 2.0 (http://www.gnu.org/licenses/gpl-2.0.html) licenses. This means that you can | |||
* choose the license that best suits your project and use it accordingly. | |||
* | |||
* Although not required, the author would appreciate an email letting him | |||
* know of any substantial use of jqPlot. You can reach the author at: | |||
* chris at jqplot dot com or see http://www.jqplot.com/info.php . | |||
* | |||
* If you are feeling kind and generous, consider supporting the project by | |||
* making a donation at: http://www.jqplot.com/donate.php . | |||
* | |||
* sprintf functions contained in jqplot.sprintf.js by Ash Searle: | |||
* | |||
* version 2007.04.27 | |||
* author Ash Searle | |||
* http://hexmen.com/blog/2007/03/printf-sprintf/ | |||
* http://hexmen.com/js/sprintf.js | |||
* The author (Ash Searle) has placed this code in the public domain: | |||
* "This code is unrestricted: you are free to use it however you like." | |||
* | |||
*/ | |||
(function($) { | |||
/** | |||
* Class: $.jqplot.BlockRenderer | |||
* Plugin renderer to draw a x-y block chart. A Block chart has data points displayed as | |||
* colored squares with a text label inside. Data must be supplied in the form: | |||
* | |||
* > [[x1, y1, "label 1", {css}], [x2, y2, "label 2", {css}], ...] | |||
* | |||
* The label and css object are optional. If the label is ommitted, the | |||
* box will collapse unless a css height and/or width is specified. | |||
* | |||
* The css object is an object specifying css properties | |||
* such as: | |||
* | |||
* > {background:'#4f98a5', border:'3px solid gray', padding:'1px'} | |||
* | |||
* Note that css properties specified with the data point override defaults | |||
* specified with the series. | |||
* | |||
*/ | |||
$.jqplot.BlockRenderer = function(){ | |||
$.jqplot.LineRenderer.call(this); | |||
}; | |||
$.jqplot.BlockRenderer.prototype = new $.jqplot.LineRenderer(); | |||
$.jqplot.BlockRenderer.prototype.constructor = $.jqplot.BlockRenderer; | |||
// called with scope of a series | |||
$.jqplot.BlockRenderer.prototype.init = function(options) { | |||
// Group: Properties | |||
// | |||
// prop: css | |||
// default css styles that will be applied to all data blocks. | |||
// these values will be overridden by css styles supplied with the | |||
// individulal data points. | |||
this.css = {padding:'2px', border:'1px solid #999', textAlign:'center'}; | |||
// prop: escapeHtml | |||
// true to escape html in the box label. | |||
this.escapeHtml = false; | |||
// prop: insertBreaks | |||
// true to turn spaces in data block label into html breaks <br />. | |||
this.insertBreaks = true; | |||
// prop: varyBlockColors | |||
// true to vary the color of each block in this series according to | |||
// the seriesColors array. False to set each block to the color | |||
// specified on this series. This has no effect if a css background color | |||
// option is specified in the renderer css options. | |||
this.varyBlockColors = false; | |||
$.extend(true, this, options); | |||
if (this.css.backgroundColor) { | |||
this.color = this.css.backgroundColor; | |||
} | |||
else if (this.css.background) { | |||
this.color = this.css.background; | |||
} | |||
else if (!this.varyBlockColors) { | |||
this.css.background = this.color; | |||
} | |||
this.canvas = new $.jqplot.BlockCanvas(); | |||
this.shadowCanvas = new $.jqplot.BlockCanvas(); | |||
this.canvas._plotDimensions = this._plotDimensions; | |||
this.shadowCanvas._plotDimensions = this._plotDimensions; | |||
this._type = 'block'; | |||
// group: Methods | |||
// | |||
// Method: moveBlock | |||
// Moves an individual block. More efficient than redrawing | |||
// the whole series by calling plot.drawSeries(). | |||
// Properties: | |||
// idx - the 0 based index of the block or point in this series. | |||
// x - the x coordinate in data units (value on x axis) to move the block to. | |||
// y - the y coordinate in data units (value on the y axis) to move the block to. | |||
// duration - optional parameter to create an animated movement. Can be a | |||
// number (higher is slower animation) or 'fast', 'normal' or 'slow'. If not | |||
// provided, the element is moved without any animation. | |||
this.moveBlock = function (idx, x, y, duration) { | |||
// update plotData, stackData, data and gridData | |||
// x and y are in data coordinates. | |||
var el = this.canvas._elem.children(':eq('+idx+')'); | |||
this.data[idx][0] = x; | |||
this.data[idx][1] = y; | |||
this._plotData[idx][0] = x; | |||
this._plotData[idx][1] = y; | |||
this._stackData[idx][0] = x; | |||
this._stackData[idx][1] = y; | |||
this.gridData[idx][0] = this._xaxis.series_u2p(x); | |||
this.gridData[idx][1] = this._yaxis.series_u2p(y); | |||
var w = el.outerWidth(); | |||
var h = el.outerHeight(); | |||
var left = this.gridData[idx][0] - w/2 + 'px'; | |||
var top = this.gridData[idx][1] - h/2 + 'px'; | |||
if (duration) { | |||
if (parseInt(duration, 10)) { | |||
duration = parseInt(duration, 10); | |||
} | |||
el.animate({left:left, top:top}, duration); | |||
} | |||
else { | |||
el.css({left:left, top:top}); | |||
} | |||
el = null; | |||
}; | |||
}; | |||
// called with scope of series | |||
$.jqplot.BlockRenderer.prototype.draw = function (ctx, gd, options) { | |||
if (this.plugins.pointLabels) { | |||
this.plugins.pointLabels.show = false; | |||
} | |||
var i, el, d, gd, t, css, w, h, left, top; | |||
var opts = (options != undefined) ? options : {}; | |||
var colorGenerator = new $.jqplot.ColorGenerator(this.seriesColors); | |||
this.canvas._elem.empty(); | |||
for (i=0; i<this.gridData.length; i++) { | |||
d = this.data[i]; | |||
gd = this.gridData[i]; | |||
t = ''; | |||
css = {}; | |||
if (typeof d[2] == 'string') { | |||
t = d[2]; | |||
} | |||
else if (typeof d[2] == 'object') { | |||
css = d[2]; | |||
} | |||
if (typeof d[3] == 'object') { | |||
css = d[3]; | |||
} | |||
if (this.insertBreaks){ | |||
t = t.replace(/ /g, '<br />'); | |||
} | |||
css = $.extend(true, {}, this.css, css); | |||
// create a div | |||
el = $('<div style="position:absolute;margin-left:auto;margin-right:auto;"></div>'); | |||
this.canvas._elem.append(el); | |||
// set text | |||
this.escapeHtml ? el.text(t) : el.html(t); | |||
// style it | |||
// remove styles we don't want overridden. | |||
delete css.position; | |||
delete css.marginRight; | |||
delete css.marginLeft; | |||
if (!css.background && !css.backgroundColor && !css.backgroundImage){ | |||
css.background = colorGenerator.next(); | |||
} | |||
el.css(css); | |||
w = el.outerWidth(); | |||
h = el.outerHeight(); | |||
left = gd[0] - w/2 + 'px'; | |||
top = gd[1] - h/2 + 'px'; | |||
el.css({left:left, top:top}); | |||
el = null; | |||
} | |||
}; | |||
$.jqplot.BlockCanvas = function() { | |||
$.jqplot.ElemContainer.call(this); | |||
this._ctx; | |||
}; | |||
$.jqplot.BlockCanvas.prototype = new $.jqplot.ElemContainer(); | |||
$.jqplot.BlockCanvas.prototype.constructor = $.jqplot.BlockCanvas; | |||
$.jqplot.BlockCanvas.prototype.createElement = function(offsets, clss, plotDimensions) { | |||
this._offsets = offsets; | |||
var klass = 'jqplot-blockCanvas'; | |||
if (clss != undefined) { | |||
klass = clss; | |||
} | |||
var elem; | |||
// if this canvas already has a dom element, don't make a new one. | |||
if (this._elem) { | |||
elem = this._elem.get(0); | |||
} | |||
else { | |||
elem = document.createElement('div'); | |||
} | |||
// if new plotDimensions supplied, use them. | |||
if (plotDimensions != undefined) { | |||
this._plotDimensions = plotDimensions; | |||
} | |||
var w = this._plotDimensions.width - this._offsets.left - this._offsets.right + 'px'; | |||
var h = this._plotDimensions.height - this._offsets.top - this._offsets.bottom + 'px'; | |||
this._elem = $(elem); | |||
this._elem.css({ position: 'absolute', width:w, height:h, left: this._offsets.left, top: this._offsets.top }); | |||
this._elem.addClass(klass); | |||
return this._elem; | |||
}; | |||
$.jqplot.BlockCanvas.prototype.setContext = function() { | |||
this._ctx = { | |||
canvas:{ | |||
width:0, | |||
height:0 | |||
}, | |||
clearRect:function(){return null;} | |||
}; | |||
return this._ctx; | |||
}; | |||
})(jQuery); | |||
@@ -0,0 +1,30 @@ | |||
/** | |||
* jqPlot | |||
* Pure JavaScript plotting plugin using jQuery | |||
* | |||
* Version: 1.0.0b2_r792 | |||
* | |||
* Copyright (c) 2009-2011 Chris Leonello | |||
* jqPlot is currently available for use in all personal or commercial projects | |||
* under both the MIT (http://www.opensource.org/licenses/mit-license.php) and GPL | |||
* version 2.0 (http://www.gnu.org/licenses/gpl-2.0.html) licenses. This means that you can | |||
* choose the license that best suits your project and use it accordingly. | |||
* | |||
* Although not required, the author would appreciate an email letting him | |||
* know of any substantial use of jqPlot. You can reach the author at: | |||
* chris at jqplot dot com or see http://www.jqplot.com/info.php . | |||
* | |||
* If you are feeling kind and generous, consider supporting the project by | |||
* making a donation at: http://www.jqplot.com/donate.php . | |||
* | |||
* sprintf functions contained in jqplot.sprintf.js by Ash Searle: | |||
* | |||
* version 2007.04.27 | |||
* author Ash Searle | |||
* http://hexmen.com/blog/2007/03/printf-sprintf/ | |||
* http://hexmen.com/js/sprintf.js | |||
* The author (Ash Searle) has placed this code in the public domain: | |||
* "This code is unrestricted: you are free to use it however you like." | |||
* | |||
*/ | |||
(function(a){a.jqplot.BlockRenderer=function(){a.jqplot.LineRenderer.call(this)};a.jqplot.BlockRenderer.prototype=new a.jqplot.LineRenderer();a.jqplot.BlockRenderer.prototype.constructor=a.jqplot.BlockRenderer;a.jqplot.BlockRenderer.prototype.init=function(b){this.css={padding:"2px",border:"1px solid #999",textAlign:"center"};this.escapeHtml=false;this.insertBreaks=true;this.varyBlockColors=false;a.extend(true,this,b);if(this.css.backgroundColor){this.color=this.css.backgroundColor}else{if(this.css.background){this.color=this.css.background}else{if(!this.varyBlockColors){this.css.background=this.color}}}this.canvas=new a.jqplot.BlockCanvas();this.shadowCanvas=new a.jqplot.BlockCanvas();this.canvas._plotDimensions=this._plotDimensions;this.shadowCanvas._plotDimensions=this._plotDimensions;this._type="block";this.moveBlock=function(l,j,i,e){var c=this.canvas._elem.children(":eq("+l+")");this.data[l][0]=j;this.data[l][1]=i;this._plotData[l][0]=j;this._plotData[l][1]=i;this._stackData[l][0]=j;this._stackData[l][1]=i;this.gridData[l][0]=this._xaxis.series_u2p(j);this.gridData[l][1]=this._yaxis.series_u2p(i);var k=c.outerWidth();var f=c.outerHeight();var d=this.gridData[l][0]-k/2+"px";var g=this.gridData[l][1]-f/2+"px";if(e){if(parseInt(e,10)){e=parseInt(e,10)}c.animate({left:d,top:g},e)}else{c.css({left:d,top:g})}c=null}};a.jqplot.BlockRenderer.prototype.draw=function(q,o,r){if(this.plugins.pointLabels){this.plugins.pointLabels.show=false}var f,c,l,o,p,k,n,g,e,m;var b=(r!=undefined)?r:{};var j=new a.jqplot.ColorGenerator(this.seriesColors);this.canvas._elem.empty();for(f=0;f<this.gridData.length;f++){l=this.data[f];o=this.gridData[f];p="";k={};if(typeof l[2]=="string"){p=l[2]}else{if(typeof l[2]=="object"){k=l[2]}}if(typeof l[3]=="object"){k=l[3]}if(this.insertBreaks){p=p.replace(/ /g,"<br />")}k=a.extend(true,{},this.css,k);c=a('<div style="position:absolute;margin-left:auto;margin-right:auto;"></div>');this.canvas._elem.append(c);this.escapeHtml?c.text(p):c.html(p);delete k.position;delete k.marginRight;delete k.marginLeft;if(!k.background&&!k.backgroundColor&&!k.backgroundImage){k.background=j.next()}c.css(k);n=c.outerWidth();g=c.outerHeight();e=o[0]-n/2+"px";m=o[1]-g/2+"px";c.css({left:e,top:m});c=null}};a.jqplot.BlockCanvas=function(){a.jqplot.ElemContainer.call(this);this._ctx};a.jqplot.BlockCanvas.prototype=new a.jqplot.ElemContainer();a.jqplot.BlockCanvas.prototype.constructor=a.jqplot.BlockCanvas;a.jqplot.BlockCanvas.prototype.createElement=function(i,e,c){this._offsets=i;var b="jqplot-blockCanvas";if(e!=undefined){b=e}var g;if(this._elem){g=this._elem.get(0)}else{g=document.createElement("div")}if(c!=undefined){this._plotDimensions=c}var d=this._plotDimensions.width-this._offsets.left-this._offsets.right+"px";var f=this._plotDimensions.height-this._offsets.top-this._offsets.bottom+"px";this._elem=a(g);this._elem.css({position:"absolute",width:d,height:f,left:this._offsets.left,top:this._offsets.top});this._elem.addClass(b);return this._elem};a.jqplot.BlockCanvas.prototype.setContext=function(){this._ctx={canvas:{width:0,height:0},clearRect:function(){return null}};return this._ctx}})(jQuery); |
@@ -0,0 +1,754 @@ | |||
/** | |||
* jqPlot | |||
* Pure JavaScript plotting plugin using jQuery | |||
* | |||
* Version: 1.0.0b2_r792 | |||
* | |||
* Copyright (c) 2009-2011 Chris Leonello | |||
* jqPlot is currently available for use in all personal or commercial projects | |||
* under both the MIT (http://www.opensource.org/licenses/mit-license.php) and GPL | |||
* version 2.0 (http://www.gnu.org/licenses/gpl-2.0.html) licenses. This means that you can | |||
* choose the license that best suits your project and use it accordingly. | |||
* | |||
* Although not required, the author would appreciate an email letting him | |||
* know of any substantial use of jqPlot. You can reach the author at: | |||
* chris at jqplot dot com or see http://www.jqplot.com/info.php . | |||
* | |||
* If you are feeling kind and generous, consider supporting the project by | |||
* making a donation at: http://www.jqplot.com/donate.php . | |||
* | |||
* sprintf functions contained in jqplot.sprintf.js by Ash Searle: | |||
* | |||
* version 2007.04.27 | |||
* author Ash Searle | |||
* http://hexmen.com/blog/2007/03/printf-sprintf/ | |||
* http://hexmen.com/js/sprintf.js | |||
* The author (Ash Searle) has placed this code in the public domain: | |||
* "This code is unrestricted: you are free to use it however you like." | |||
* | |||
*/ | |||
(function($) { | |||
var arrayMax = function( array ){ | |||
return Math.max.apply( Math, array ); | |||
}; | |||
var arrayMin = function( array ){ | |||
return Math.min.apply( Math, array ); | |||
}; | |||
/** | |||
* Class: $.jqplot.BubbleRenderer | |||
* Plugin renderer to draw a bubble chart. A Bubble chart has data points displayed as | |||
* colored circles with an optional text label inside. To use | |||
* the bubble renderer, you must include the bubble renderer like: | |||
* | |||
* > <script language="javascript" type="text/javascript" src="../src/plugins/jqplot.bubbleRenderer.js"></script> | |||
* | |||
* Data must be supplied in | |||
* the form: | |||
* | |||
* > [[x1, y1, r1, <label or {label:'text', color:color}>], ...] | |||
* | |||
* where the label or options | |||
* object is optional. | |||
* | |||
* Note that all bubble colors will be the same | |||
* unless the "varyBubbleColors" option is set to true. Colors can be specified in the data array | |||
* or in the seriesColors array option on the series. If no colors are defined, the default jqPlot | |||
* series of 16 colors are used. Colors are automatically cycled around again if there are more | |||
* bubbles than colors. | |||
* | |||
* Bubbles are autoscaled by default to fit within the chart area while maintaining | |||
* relative sizes. If the "autoscaleBubbles" option is set to false, the r(adius) values | |||
* in the data array a treated as literal pixel values for the radii of the bubbles. | |||
* | |||
* Properties are passed into the bubble renderer in the rendererOptions object of | |||
* the series options like: | |||
* | |||
* > seriesDefaults: { | |||
* > renderer: $.jqplot.BubbleRenderer, | |||
* > rendererOptions: { | |||
* > bubbleAlpha: 0.7, | |||
* > varyBubbleColors: false | |||
* > } | |||
* > } | |||
* | |||
*/ | |||
$.jqplot.BubbleRenderer = function(){ | |||
$.jqplot.LineRenderer.call(this); | |||
}; | |||
$.jqplot.BubbleRenderer.prototype = new $.jqplot.LineRenderer(); | |||
$.jqplot.BubbleRenderer.prototype.constructor = $.jqplot.BubbleRenderer; | |||
// called with scope of a series | |||
$.jqplot.BubbleRenderer.prototype.init = function(options, plot) { | |||
// Group: Properties | |||
// | |||
// prop: varyBubbleColors | |||
// True to vary the color of each bubble in this series according to | |||
// the seriesColors array. False to set each bubble to the color | |||
// specified on this series. This has no effect if a css background color | |||
// option is specified in the renderer css options. | |||
this.varyBubbleColors = true; | |||
// prop: autoscaleBubbles | |||
// True to scale the bubble radius based on plot size. | |||
// False will use the radius value as provided as a raw pixel value for | |||
// bubble radius. | |||
this.autoscaleBubbles = true; | |||
// prop: autoscaleMultiplier | |||
// Multiplier the bubble size if autoscaleBubbles is true. | |||
this.autoscaleMultiplier = 1.0; | |||
// prop: autoscalePointsFactor | |||
// Factor which decreases bubble size based on how many bubbles on on the chart. | |||
// 0 means no adjustment for number of bubbles. Negative values will decrease | |||
// size of bubbles as more bubbles are added. Values between 0 and -0.2 | |||
// should work well. | |||
this.autoscalePointsFactor = -0.07; | |||
// prop: escapeHtml | |||
// True to escape html in bubble label text. | |||
this.escapeHtml = true; | |||
// prop: highlightMouseOver | |||
// True to highlight bubbles when moused over. | |||
// This must be false to enable highlightMouseDown to highlight when clicking on a slice. | |||
this.highlightMouseOver = true; | |||
// prop: highlightMouseDown | |||
// True to highlight when a mouse button is pressed over a bubble. | |||
// This will be disabled if highlightMouseOver is true. | |||
this.highlightMouseDown = false; | |||
// prop: highlightColors | |||
// An array of colors to use when highlighting a slice. Calculated automatically | |||
// if not supplied. | |||
this.highlightColors = []; | |||
// prop: bubbleAlpha | |||
// Alpha transparency to apply to all bubbles in this series. | |||
this.bubbleAlpha = 1.0; | |||
// prop: highlightAlpha | |||
// Alpha transparency to apply when highlighting bubble. | |||
// Set to value of bubbleAlpha by default. | |||
this.highlightAlpha = null; | |||
// prop: bubbleGradients | |||
// True to color the bubbles with gradient fills instead of flat colors. | |||
// NOT AVAILABLE IN IE due to lack of excanvas support for radial gradient fills. | |||
// will be ignored in IE. | |||
this.bubbleGradients = false; | |||
// prop: showLabels | |||
// True to show labels on bubbles (if any), false to not show. | |||
this.showLabels = true; | |||
// array of [point index, radius] which will be sorted in descending order to plot | |||
// largest points below smaller points. | |||
this.radii = []; | |||
this.maxRadius = 0; | |||
// index of the currenty highlighted point, if any | |||
this._highlightedPoint = null; | |||
// array of jQuery labels. | |||
this.labels = []; | |||
this.bubbleCanvases = []; | |||
this._type = 'bubble'; | |||
// if user has passed in highlightMouseDown option and not set highlightMouseOver, disable highlightMouseOver | |||
if (options.highlightMouseDown && options.highlightMouseOver == null) { | |||
options.highlightMouseOver = false; | |||
} | |||
$.extend(true, this, options); | |||
if (this.highlightAlpha == null) { | |||
this.highlightAlpha = this.bubbleAlpha; | |||
if (this.bubbleGradients) { | |||
this.highlightAlpha = 0.35; | |||
} | |||
} | |||
this.autoscaleMultiplier = this.autoscaleMultiplier * Math.pow(this.data.length, this.autoscalePointsFactor); | |||
// index of the currenty highlighted point, if any | |||
this._highlightedPoint = null; | |||
// adjust the series colors for options colors passed in with data or for alpha. | |||
// note, this can leave undefined holes in the seriesColors array. | |||
var comps; | |||
for (var i=0; i<this.data.length; i++) { | |||
var color = null; | |||
var d = this.data[i]; | |||
this.maxRadius = Math.max(this.maxRadius, d[2]); | |||
if (d[3]) { | |||
if (typeof(d[3]) == 'object') { | |||
color = d[3]['color']; | |||
} | |||
} | |||
if (color == null) { | |||
if (this.seriesColors[i] != null) { | |||
color = this.seriesColors[i]; | |||
} | |||
} | |||
if (color && this.bubbleAlpha < 1.0) { | |||
comps = $.jqplot.getColorComponents(color); | |||
color = 'rgba('+comps[0]+', '+comps[1]+', '+comps[2]+', '+this.bubbleAlpha+')'; | |||
} | |||
if (color) { | |||
this.seriesColors[i] = color; | |||
} | |||
} | |||
if (!this.varyBubbleColors) { | |||
this.seriesColors = [this.color]; | |||
} | |||
this.colorGenerator = new $.jqplot.ColorGenerator(this.seriesColors); | |||
// set highlight colors if none provided | |||
if (this.highlightColors.length == 0) { | |||
for (var i=0; i<this.seriesColors.length; i++){ | |||
var rgba = $.jqplot.getColorComponents(this.seriesColors[i]); | |||
var newrgb = [rgba[0], rgba[1], rgba[2]]; | |||
var sum = newrgb[0] + newrgb[1] + newrgb[2]; | |||
for (var j=0; j<3; j++) { | |||
// when darkening, lowest color component can be is 60. | |||
newrgb[j] = (sum > 570) ? newrgb[j] * 0.8 : newrgb[j] + 0.3 * (255 - newrgb[j]); | |||
newrgb[j] = parseInt(newrgb[j], 10); | |||
} | |||
this.highlightColors.push('rgba('+newrgb[0]+','+newrgb[1]+','+newrgb[2]+', '+this.highlightAlpha+')'); | |||
} | |||
} | |||
this.highlightColorGenerator = new $.jqplot.ColorGenerator(this.highlightColors); | |||
var sopts = {fill:true, isarc:true, angle:this.shadowAngle, alpha:this.shadowAlpha, closePath:true}; | |||
this.renderer.shadowRenderer.init(sopts); | |||
this.canvas = new $.jqplot.DivCanvas(); | |||
this.canvas._plotDimensions = this._plotDimensions; | |||
plot.eventListenerHooks.addOnce('jqplotMouseMove', handleMove); | |||
plot.eventListenerHooks.addOnce('jqplotMouseDown', handleMouseDown); | |||
plot.eventListenerHooks.addOnce('jqplotMouseUp', handleMouseUp); | |||
plot.eventListenerHooks.addOnce('jqplotClick', handleClick); | |||
plot.eventListenerHooks.addOnce('jqplotRightClick', handleRightClick); | |||
plot.postDrawHooks.addOnce(postPlotDraw); | |||
}; | |||
// converts the user data values to grid coordinates and stores them | |||
// in the gridData array. | |||
// Called with scope of a series. | |||
$.jqplot.BubbleRenderer.prototype.setGridData = function(plot) { | |||
// recalculate the grid data | |||
var xp = this._xaxis.series_u2p; | |||
var yp = this._yaxis.series_u2p; | |||
var data = this._plotData; | |||
this.gridData = []; | |||
var radii = []; | |||
this.radii = []; | |||
var dim = Math.min(plot._height, plot._width); | |||
for (var i=0; i<this.data.length; i++) { | |||
if (data[i] != null) { | |||
this.gridData.push([xp.call(this._xaxis, data[i][0]), yp.call(this._yaxis, data[i][1]), data[i][2]]); | |||
this.radii.push([i, data[i][2]]); | |||
radii.push(data[i][2]); | |||
} | |||
} | |||
var r, val, maxr = this.maxRadius = arrayMax(radii); | |||
var l = this.gridData.length; | |||
if (this.autoscaleBubbles) { | |||
for (var i=0; i<l; i++) { | |||
val = radii[i]/maxr; | |||
r = this.autoscaleMultiplier * dim / 6; | |||
this.gridData[i][2] = r * val; | |||
} | |||
} | |||
this.radii.sort(function(a, b) { return b[1] - a[1]; }); | |||
}; | |||
// converts any arbitrary data values to grid coordinates and | |||
// returns them. This method exists so that plugins can use a series' | |||
// linerenderer to generate grid data points without overwriting the | |||
// grid data associated with that series. | |||
// Called with scope of a series. | |||
$.jqplot.BubbleRenderer.prototype.makeGridData = function(data, plot) { | |||
// recalculate the grid data | |||
var xp = this._xaxis.series_u2p; | |||
var yp = this._yaxis.series_u2p; | |||
var gd = []; | |||
var radii = []; | |||
this.radii = []; | |||
var dim = Math.min(plot._height, plot._width); | |||
for (var i=0; i<data.length; i++) { | |||
if (data[i] != null) { | |||
gd.push([xp.call(this._xaxis, data[i][0]), yp.call(this._yaxis, data[i][1]), data[i][2]]); | |||
radii.push(data[i][2]); | |||
this.radii.push([i, data[i][2]]); | |||
} | |||
} | |||
var r, val, maxr = this.maxRadius = arrayMax(radii); | |||
var l = this.gridData.length; | |||
if (this.autoscaleBubbles) { | |||
for (var i=0; i<l; i++) { | |||
val = radii[i]/maxr; | |||
r = this.autoscaleMultiplier * dim / 6; | |||
gd[i][2] = r * val; | |||
} | |||
} | |||
this.radii.sort(function(a, b) { return b[1] - a[1]; }); | |||
return gd; | |||
}; | |||
// called with scope of series | |||
$.jqplot.BubbleRenderer.prototype.draw = function (ctx, gd, options) { | |||
if (this.plugins.pointLabels) { | |||
this.plugins.pointLabels.show = false; | |||
} | |||
var opts = (options != undefined) ? options : {}; | |||
var shadow = (opts.shadow != undefined) ? opts.shadow : this.shadow; | |||
this.canvas._elem.empty(); | |||
for (var i=0; i<this.radii.length; i++) { | |||
var idx = this.radii[i][0]; | |||
var t=null; | |||
var color = null; | |||
var el = null; | |||
var tel = null; | |||
var d = this.data[idx]; | |||
var gd = this.gridData[idx]; | |||
if (d[3]) { | |||
if (typeof(d[3]) == 'object') { | |||
t = d[3]['label']; | |||
} | |||
else if (typeof(d[3]) == 'string') { | |||
t = d[3]; | |||
} | |||
} | |||
// color = (this.varyBubbleColors) ? this.colorGenerator.get(idx) : this.color; | |||
color = this.colorGenerator.get(idx); | |||
// If we're drawing a shadow, expand the canvas dimensions to accomodate. | |||
var canvasRadius = gd[2]; | |||
var offset, depth; | |||
if (this.shadow) { | |||
offset = (0.7 + gd[2]/40).toFixed(1); | |||
depth = 1 + Math.ceil(gd[2]/15); | |||
canvasRadius += offset*depth; | |||
} | |||
this.bubbleCanvases[idx] = new $.jqplot.BubbleCanvas(); | |||
this.canvas._elem.append(this.bubbleCanvases[idx].createElement(gd[0], gd[1], canvasRadius)); | |||
this.bubbleCanvases[idx].setContext(); | |||
var ctx = this.bubbleCanvases[idx]._ctx; | |||
var x = ctx.canvas.width/2; | |||
var y = ctx.canvas.height/2; | |||
if (this.shadow) { | |||
this.renderer.shadowRenderer.draw(ctx, [x, y, gd[2], 0, 2*Math.PI], {offset: offset, depth: depth}); | |||
} | |||
this.bubbleCanvases[idx].draw(gd[2], color, this.bubbleGradients, this.shadowAngle/180*Math.PI); | |||
// now draw label. | |||
if (t && this.showLabels) { | |||
tel = $('<div style="position:absolute;" class="jqplot-bubble-label"></div>'); | |||
if (this.escapeHtml) { | |||
tel.text(t); | |||
} | |||
else { | |||
tel.html(t); | |||
} | |||
this.canvas._elem.append(tel); | |||
var h = $(tel).outerHeight(); | |||
var w = $(tel).outerWidth(); | |||
var top = gd[1] - 0.5*h; | |||
var left = gd[0] - 0.5*w; | |||
tel.css({top: top, left: left}); | |||
this.labels[idx] = $(tel); | |||
} | |||
} | |||
}; | |||
$.jqplot.DivCanvas = function() { | |||
$.jqplot.ElemContainer.call(this); | |||
this._ctx; | |||
}; | |||
$.jqplot.DivCanvas.prototype = new $.jqplot.ElemContainer(); | |||
$.jqplot.DivCanvas.prototype.constructor = $.jqplot.DivCanvas; | |||
$.jqplot.DivCanvas.prototype.createElement = function(offsets, clss, plotDimensions) { | |||
this._offsets = offsets; | |||
var klass = 'jqplot-DivCanvas'; | |||
if (clss != undefined) { | |||
klass = clss; | |||
} | |||
var elem; | |||
// if this canvas already has a dom element, don't make a new one. | |||
if (this._elem) { | |||
elem = this._elem.get(0); | |||
} | |||
else { | |||
elem = document.createElement('div'); | |||
} | |||
// if new plotDimensions supplied, use them. | |||
if (plotDimensions != undefined) { | |||
this._plotDimensions = plotDimensions; | |||
} | |||
var w = this._plotDimensions.width - this._offsets.left - this._offsets.right + 'px'; | |||
var h = this._plotDimensions.height - this._offsets.top - this._offsets.bottom + 'px'; | |||
this._elem = $(elem); | |||
this._elem.css({ position: 'absolute', width:w, height:h, left: this._offsets.left, top: this._offsets.top }); | |||
this._elem.addClass(klass); | |||
return this._elem; | |||
}; | |||
$.jqplot.DivCanvas.prototype.setContext = function() { | |||
this._ctx = { | |||
canvas:{ | |||
width:0, | |||
height:0 | |||
}, | |||
clearRect:function(){return null;} | |||
}; | |||
return this._ctx; | |||
}; | |||
$.jqplot.BubbleCanvas = function() { | |||
$.jqplot.ElemContainer.call(this); | |||
this._ctx; | |||
}; | |||
$.jqplot.BubbleCanvas.prototype = new $.jqplot.ElemContainer(); | |||
$.jqplot.BubbleCanvas.prototype.constructor = $.jqplot.BubbleCanvas; | |||
// initialize with the x,y pont of bubble center and the bubble radius. | |||
$.jqplot.BubbleCanvas.prototype.createElement = function(x, y, r) { | |||
var klass = 'jqplot-bubble-point'; | |||
var elem; | |||
// if this canvas already has a dom element, don't make a new one. | |||
if (this._elem) { | |||
elem = this._elem.get(0); | |||
} | |||
else { | |||
elem = document.createElement('canvas'); | |||
} | |||
elem.width = (r != null) ? 2*r : elem.width; | |||
elem.height = (r != null) ? 2*r : elem.height; | |||
this._elem = $(elem); | |||
var l = (x != null && r != null) ? x - r : this._elem.css('left'); | |||
var t = (y != null && r != null) ? y - r : this._elem.css('top'); | |||
this._elem.css({ position: 'absolute', left: l, top: t }); | |||
this._elem.addClass(klass); | |||
if ($.jqplot.use_excanvas) { | |||
window.G_vmlCanvasManager.init_(document); | |||
elem = window.G_vmlCanvasManager.initElement(elem); | |||
} | |||
return this._elem; | |||
}; | |||
$.jqplot.BubbleCanvas.prototype.draw = function(r, color, gradients, angle) { | |||
var ctx = this._ctx; | |||
// r = Math.floor(r*1.04); | |||
// var x = Math.round(ctx.canvas.width/2); | |||
// var y = Math.round(ctx.canvas.height/2); | |||
var x = ctx.canvas.width/2; | |||
var y = ctx.canvas.height/2; | |||
ctx.save(); | |||
if (gradients && !$.jqplot.use_excanvas) { | |||
r = r*1.04; | |||
var comps = $.jqplot.getColorComponents(color); | |||
var colorinner = 'rgba('+Math.round(comps[0]+0.8*(255-comps[0]))+', '+Math.round(comps[1]+0.8*(255-comps[1]))+', '+Math.round(comps[2]+0.8*(255-comps[2]))+', '+comps[3]+')'; | |||
var colorend = 'rgba('+comps[0]+', '+comps[1]+', '+comps[2]+', 0)'; | |||
// var rinner = Math.round(0.35 * r); | |||
// var xinner = Math.round(x - Math.cos(angle) * 0.33 * r); | |||
// var yinner = Math.round(y - Math.sin(angle) * 0.33 * r); | |||
var rinner = 0.35 * r; | |||
var xinner = x - Math.cos(angle) * 0.33 * r; | |||
var yinner = y - Math.sin(angle) * 0.33 * r; | |||
var radgrad = ctx.createRadialGradient(xinner, yinner, rinner, x, y, r); | |||
radgrad.addColorStop(0, colorinner); | |||
radgrad.addColorStop(0.93, color); | |||
radgrad.addColorStop(0.96, colorend); | |||
radgrad.addColorStop(1, colorend); | |||
// radgrad.addColorStop(.98, colorend); | |||
ctx.fillStyle = radgrad; | |||
ctx.fillRect(0,0, ctx.canvas.width, ctx.canvas.height); | |||
} | |||
else { | |||
ctx.fillStyle = color; | |||
ctx.strokeStyle = color; | |||
ctx.lineWidth = 1; | |||
ctx.beginPath(); | |||
var ang = 2*Math.PI; | |||
ctx.arc(x, y, r, 0, ang, 0); | |||
ctx.closePath(); | |||
ctx.fill(); | |||
} | |||
ctx.restore(); | |||
}; | |||
$.jqplot.BubbleCanvas.prototype.setContext = function() { | |||
this._ctx = this._elem.get(0).getContext("2d"); | |||
return this._ctx; | |||
}; | |||
$.jqplot.BubbleAxisRenderer = function() { | |||
$.jqplot.LinearAxisRenderer.call(this); | |||
}; | |||
$.jqplot.BubbleAxisRenderer.prototype = new $.jqplot.LinearAxisRenderer(); | |||
$.jqplot.BubbleAxisRenderer.prototype.constructor = $.jqplot.BubbleAxisRenderer; | |||
// called with scope of axis object. | |||
$.jqplot.BubbleAxisRenderer.prototype.init = function(options){ | |||
$.extend(true, this, options); | |||
var db = this._dataBounds; | |||
var minsidx = 0, | |||
minpidx = 0, | |||
maxsidx = 0, | |||
maxpidx = 0, | |||
maxr = 0, | |||
minr = 0, | |||
minMaxRadius = 0, | |||
maxMaxRadius = 0, | |||
maxMult = 0, | |||
minMult = 0; | |||
// Go through all the series attached to this axis and find | |||
// the min/max bounds for this axis. | |||
for (var i=0; i<this._series.length; i++) { | |||
var s = this._series[i]; | |||
var d = s._plotData; | |||
for (var j=0; j<d.length; j++) { | |||
if (this.name == 'xaxis' || this.name == 'x2axis') { | |||
if (d[j][0] < db.min || db.min == null) { | |||
db.min = d[j][0]; | |||
minsidx=i; | |||
minpidx=j; | |||
minr = d[j][2]; | |||
minMaxRadius = s.maxRadius; | |||
minMult = s.autoscaleMultiplier; | |||
} | |||
if (d[j][0] > db.max || db.max == null) { | |||
db.max = d[j][0]; | |||
maxsidx=i; | |||
maxpidx=j; | |||
maxr = d[j][2]; | |||
maxMaxRadius = s.maxRadius; | |||
maxMult = s.autoscaleMultiplier; | |||
} | |||
} | |||
else { | |||
if (d[j][1] < db.min || db.min == null) { | |||
db.min = d[j][1]; | |||
minsidx=i; | |||
minpidx=j; | |||
minr = d[j][2]; | |||
minMaxRadius = s.maxRadius; | |||
minMult = s.autoscaleMultiplier; | |||
} | |||
if (d[j][1] > db.max || db.max == null) { | |||
db.max = d[j][1]; | |||
maxsidx=i; | |||
maxpidx=j; | |||
maxr = d[j][2]; | |||
maxMaxRadius = s.maxRadius; | |||
maxMult = s.autoscaleMultiplier; | |||
} | |||
} | |||
} | |||
} | |||
var minRatio = minr/minMaxRadius; | |||
var maxRatio = maxr/maxMaxRadius; | |||
// need to estimate the effect of the radius on total axis span and adjust axis accordingly. | |||
var span = db.max - db.min; | |||
// var dim = (this.name == 'xaxis' || this.name == 'x2axis') ? this._plotDimensions.width : this._plotDimensions.height; | |||
var dim = Math.min(this._plotDimensions.width, this._plotDimensions.height); | |||
var minfact = minRatio * minMult/3 * span; | |||
var maxfact = maxRatio * maxMult/3 * span; | |||
db.max += maxfact; | |||
db.min -= minfact; | |||
}; | |||
function highlight (plot, sidx, pidx) { | |||
plot.plugins.bubbleRenderer.highlightLabelCanvas.empty(); | |||
var s = plot.series[sidx]; | |||
var canvas = plot.plugins.bubbleRenderer.highlightCanvas; | |||
var ctx = canvas._ctx; | |||
ctx.clearRect(0,0,ctx.canvas.width, ctx.canvas.height); | |||
s._highlightedPoint = pidx; | |||
plot.plugins.bubbleRenderer.highlightedSeriesIndex = sidx; | |||
var color = s.highlightColorGenerator.get(pidx); | |||
var x = s.gridData[pidx][0], | |||
y = s.gridData[pidx][1], | |||
r = s.gridData[pidx][2]; | |||
ctx.save(); | |||
ctx.fillStyle = color; | |||
ctx.strokeStyle = color; | |||
ctx.lineWidth = 1; | |||
ctx.beginPath(); | |||
ctx.arc(x, y, r, 0, 2*Math.PI, 0); | |||
ctx.closePath(); | |||
ctx.fill(); | |||
ctx.restore(); | |||
// bring label to front | |||
if (s.labels[pidx]) { | |||
plot.plugins.bubbleRenderer.highlightLabel = s.labels[pidx].clone(); | |||
plot.plugins.bubbleRenderer.highlightLabel.appendTo(plot.plugins.bubbleRenderer.highlightLabelCanvas); | |||
plot.plugins.bubbleRenderer.highlightLabel.addClass('jqplot-bubble-label-highlight'); | |||
} | |||
} | |||
function unhighlight (plot) { | |||
var canvas = plot.plugins.bubbleRenderer.highlightCanvas; | |||
var sidx = plot.plugins.bubbleRenderer.highlightedSeriesIndex; | |||
plot.plugins.bubbleRenderer.highlightLabelCanvas.empty(); | |||
canvas._ctx.clearRect(0,0, canvas._ctx.canvas.width, canvas._ctx.canvas.height); | |||
for (var i=0; i<plot.series.length; i++) { | |||
plot.series[i]._highlightedPoint = null; | |||
} | |||
plot.plugins.bubbleRenderer.highlightedSeriesIndex = null; | |||
plot.target.trigger('jqplotDataUnhighlight'); | |||
} | |||
function handleMove(ev, gridpos, datapos, neighbor, plot) { | |||
if (neighbor) { | |||
var si = neighbor.seriesIndex; | |||
var pi = neighbor.pointIndex; | |||
var ins = [si, pi, neighbor.data, plot.series[si].gridData[pi][2]]; | |||
var evt1 = jQuery.Event('jqplotDataMouseOver'); | |||
evt1.pageX = ev.pageX; | |||
evt1.pageY = ev.pageY; | |||
plot.target.trigger(evt1, ins); | |||
if (plot.series[ins[0]].highlightMouseOver && !(ins[0] == plot.plugins.bubbleRenderer.highlightedSeriesIndex && ins[1] == plot.series[ins[0]]._highlightedPoint)) { | |||
var evt = jQuery.Event('jqplotDataHighlight'); | |||
evt.pageX = ev.pageX; | |||
evt.pageY = ev.pageY; | |||
plot.target.trigger(evt, ins); | |||
highlight (plot, ins[0], ins[1]); | |||
} | |||
} | |||
else if (neighbor == null) { | |||
unhighlight (plot); | |||
} | |||
} | |||
function handleMouseDown(ev, gridpos, datapos, neighbor, plot) { | |||
if (neighbor) { | |||
var si = neighbor.seriesIndex; | |||
var pi = neighbor.pointIndex; | |||
var ins = [si, pi, neighbor.data, plot.series[si].gridData[pi][2]]; | |||
if (plot.series[ins[0]].highlightMouseDown && !(ins[0] == plot.plugins.bubbleRenderer.highlightedSeriesIndex && ins[1] == plot.series[ins[0]]._highlightedPoint)) { | |||
var evt = jQuery.Event('jqplotDataHighlight'); | |||
evt.pageX = ev.pageX; | |||
evt.pageY = ev.pageY; | |||
plot.target.trigger(evt, ins); | |||
highlight (plot, ins[0], ins[1]); | |||
} | |||
} | |||
else if (neighbor == null) { | |||
unhighlight (plot); | |||
} | |||
} | |||
function handleMouseUp(ev, gridpos, datapos, neighbor, plot) { | |||
var idx = plot.plugins.bubbleRenderer.highlightedSeriesIndex; | |||
if (idx != null && plot.series[idx].highlightMouseDown) { | |||
unhighlight(plot); | |||
} | |||
} | |||
function handleClick(ev, gridpos, datapos, neighbor, plot) { | |||
if (neighbor) { | |||
var si = neighbor.seriesIndex; | |||
var pi = neighbor.pointIndex; | |||
var ins = [si, pi, neighbor.data, plot.series[si].gridData[pi][2]]; | |||
var evt = jQuery.Event('jqplotDataClick'); | |||
evt.pageX = ev.pageX; | |||
evt.pageY = ev.pageY; | |||
plot.target.trigger(evt, ins); | |||
} | |||
} | |||
function handleRightClick(ev, gridpos, datapos, neighbor, plot) { | |||
if (neighbor) { | |||
var si = neighbor.seriesIndex; | |||
var pi = neighbor.pointIndex; | |||
var ins = [si, pi, neighbor.data, plot.series[si].gridData[pi][2]]; | |||
var idx = plot.plugins.bubbleRenderer.highlightedSeriesIndex; | |||
if (idx != null && plot.series[idx].highlightMouseDown) { | |||
unhighlight(plot); | |||
} | |||
var evt = jQuery.Event('jqplotDataRightClick'); | |||
evt.pageX = ev.pageX; | |||
evt.pageY = ev.pageY; | |||
plot.target.trigger(evt, ins); | |||
} | |||
} | |||
// called within context of plot | |||
// create a canvas which we can draw on. | |||
// insert it before the eventCanvas, so eventCanvas will still capture events. | |||
function postPlotDraw() { | |||
// Memory Leaks patch | |||
if (this.plugins.bubbleRenderer && this.plugins.bubbleRenderer.highlightCanvas) { | |||
this.plugins.bubbleRenderer.highlightCanvas.resetCanvas(); | |||
this.plugins.bubbleRenderer.highlightCanvas = null; | |||
} | |||
this.plugins.bubbleRenderer = {highlightedSeriesIndex:null}; | |||
this.plugins.bubbleRenderer.highlightCanvas = new $.jqplot.GenericCanvas(); | |||
this.plugins.bubbleRenderer.highlightLabel = null; | |||
this.plugins.bubbleRenderer.highlightLabelCanvas = $('<div style="position:absolute;"></div>'); | |||
var top = this._gridPadding.top; | |||
var left = this._gridPadding.left; | |||
var width = this._plotDimensions.width - this._gridPadding.left - this._gridPadding.right; | |||
var height = this._plotDimensions.height - this._gridPadding.top - this._gridPadding.bottom; | |||
this.plugins.bubbleRenderer.highlightLabelCanvas.css({top:top, left:left, width:width+'px', height:height+'px'}); | |||
this.eventCanvas._elem.before(this.plugins.bubbleRenderer.highlightCanvas.createElement(this._gridPadding, 'jqplot-bubbleRenderer-highlight-canvas', this._plotDimensions, this)); | |||
this.eventCanvas._elem.before(this.plugins.bubbleRenderer.highlightLabelCanvas); | |||
var hctx = this.plugins.bubbleRenderer.highlightCanvas.setContext(); | |||
} | |||
// setup default renderers for axes and legend so user doesn't have to | |||
// called with scope of plot | |||
function preInit(target, data, options) { | |||
options = options || {}; | |||
options.axesDefaults = options.axesDefaults || {}; | |||
options.seriesDefaults = options.seriesDefaults || {}; | |||
// only set these if there is a Bubble series | |||
var setopts = false; | |||
if (options.seriesDefaults.renderer == $.jqplot.BubbleRenderer) { | |||
setopts = true; | |||
} | |||
else if (options.series) { | |||
for (var i=0; i < options.series.length; i++) { | |||
if (options.series[i].renderer == $.jqplot.BubbleRenderer) { | |||
setopts = true; | |||
} | |||
} | |||
} | |||
if (setopts) { | |||
options.axesDefaults.renderer = $.jqplot.BubbleAxisRenderer; | |||
options.sortData = false; | |||
} | |||
} | |||
$.jqplot.preInitHooks.push(preInit); | |||
})(jQuery); | |||
@@ -1,18 +1,30 @@ | |||
/** | |||
* Copyright (c) 2009 Chris Leonello | |||
* jqPlot | |||
* Pure JavaScript plotting plugin using jQuery | |||
* | |||
* Version: 1.0.0b2_r792 | |||
* | |||
* Copyright (c) 2009-2011 Chris Leonello | |||
* jqPlot is currently available for use in all personal or commercial projects | |||
* under both the MIT and GPL version 2.0 licenses. This means that you can | |||
* under both the MIT (http://www.opensource.org/licenses/mit-license.php) and GPL | |||
* version 2.0 (http://www.gnu.org/licenses/gpl-2.0.html) licenses. This means that you can | |||
* choose the license that best suits your project and use it accordingly. | |||
* | |||
* The author would appreciate an email letting him know of any substantial | |||
* use of jqPlot. You can reach the author at: chris dot leonello at gmail | |||
* dot com or see http://www.jqplot.com/info.php . This is, of course, | |||
* not required. | |||
* Although not required, the author would appreciate an email letting him | |||
* know of any substantial use of jqPlot. You can reach the author at: | |||
* chris at jqplot dot com or see http://www.jqplot.com/info.php . | |||
* | |||
* If you are feeling kind and generous, consider supporting the project by | |||
* making a donation at: http://www.jqplot.com/donate.php . | |||
* | |||
* Thanks for using jqPlot! | |||
* sprintf functions contained in jqplot.sprintf.js by Ash Searle: | |||
* | |||
* version 2007.04.27 | |||
* author Ash Searle | |||
* http://hexmen.com/blog/2007/03/printf-sprintf/ | |||
* http://hexmen.com/js/sprintf.js | |||
* The author (Ash Searle) has placed this code in the public domain: | |||
* "This code is unrestricted: you are free to use it however you like." | |||
* | |||
*/ | |||
(function($) { | |||
@@ -69,7 +81,7 @@ | |||
// true to turn on native canvas font support in Mozilla 3.5+ and Safari 4+. | |||
// If true, label will be drawn with canvas tag native support for fonts. | |||
// If false, label will be drawn with Hershey font metrics. | |||
this.enableFontSupport = false; | |||
this.enableFontSupport = true; | |||
// prop: pt2px | |||
// Point to pixel scaling factor, used for computing height of bounding box | |||
// around a label. The labels text renderer has a default setting of 1.4, which | |||
@@ -97,27 +109,14 @@ | |||
} | |||
if (this.enableFontSupport) { | |||
if ($.browser.safari) { | |||
var p = $.browser.version.split('.'); | |||
for (var i=0; i<p.length; i++) { p[i] = Number(p[i]); } | |||
if (p[0] > 528 || (p[0] == 528 && p[1] >= 16)) { | |||
this._textRenderer = new $.jqplot.CanvasFontRenderer(ropts); | |||
} | |||
} | |||
else if ($.browser.mozilla) { | |||
var p = $.browser.version.split("."); | |||
if (p[0] > 1 || (p[0] == 1 && p[1] >= 9 && p[2] > 0) ) { | |||
this._textRenderer = new $.jqplot.CanvasFontRenderer(ropts); | |||
} | |||
else { | |||
this._textRenderer = new $.jqplot.CanvasTextRenderer(ropts); | |||
} | |||
function support_canvas_text() { | |||
return !!(document.createElement('canvas').getContext && typeof document.createElement('canvas').getContext('2d').fillText == 'function'); | |||
} | |||
// TODO: test and enable this | |||
// else if ($.browser.msie) { | |||
// this._textRenderer = new $.jqplot.CanvasFontRenderer(ropts); | |||
// } | |||
if (support_canvas_text()) { | |||
this._textRenderer = new $.jqplot.CanvasFontRenderer(ropts); | |||
} | |||
else { | |||
this._textRenderer = new $.jqplot.CanvasTextRenderer(ropts); | |||
@@ -168,33 +167,41 @@ | |||
return a; | |||
}; | |||
$.jqplot.CanvasAxisLabelRenderer.prototype.draw = function(ctx) { | |||
$.jqplot.CanvasAxisLabelRenderer.prototype.draw = function(ctx, plot) { | |||
// Memory Leaks patch | |||
if (this._elem) { | |||
if ($.jqplot.use_excanvas) { | |||
window.G_vmlCanvasManager.uninitElement(this._elem.get(0)); | |||
} | |||
this._elem.emptyForce(); | |||
this._elem = null; | |||
} | |||
// create a canvas here, but can't draw on it untill it is appended | |||
// to dom for IE compatability. | |||
var domelem = document.createElement('canvas'); | |||
var elem = plot.canvasManager.getCanvas(); | |||
this._textRenderer.setText(this.label, ctx); | |||
var w = this.getWidth(ctx); | |||
var h = this.getHeight(ctx); | |||
domelem.width = w; | |||
domelem.height = h; | |||
domelem.style.width = w; | |||
domelem.style.height = h; | |||
// domelem.style.textAlign = 'center'; | |||
domelem.style.position = 'absolute'; | |||
this._domelem = domelem; | |||
this._elem = $(domelem); | |||
elem.width = w; | |||
elem.height = h; | |||
elem.style.width = w; | |||
elem.style.height = h; | |||
elem = plot.canvasManager.initCanvas(elem); | |||
this._elem = $(elem); | |||
this._elem.css({ position: 'absolute'}); | |||
this._elem.addClass('jqplot-'+this.axis+'-label'); | |||
elem = null; | |||
return this._elem; | |||
}; | |||
$.jqplot.CanvasAxisLabelRenderer.prototype.pack = function() { | |||
if ($.browser.msie) { | |||
window.G_vmlCanvasManager.init_(document); | |||
this._domelem = window.G_vmlCanvasManager.initElement(this._domelem); | |||
} | |||
var ctx = this._elem.get(0).getContext("2d"); | |||
this._textRenderer.draw(ctx, this.label); | |||
this._textRenderer.draw(this._elem.get(0).getContext("2d"), this.label); | |||
}; | |||
})(jQuery); |
@@ -1,14 +1,30 @@ | |||
/** | |||
* Copyright (c) 2009 Chris Leonello | |||
* jqPlot | |||
* Pure JavaScript plotting plugin using jQuery | |||
* | |||
* Version: 1.0.0b2_r792 | |||
* | |||
* Copyright (c) 2009-2011 Chris Leonello | |||
* jqPlot is currently available for use in all personal or commercial projects | |||
* under both the MIT and GPL version 2.0 licenses. This means that you can | |||
* under both the MIT (http://www.opensource.org/licenses/mit-license.php) and GPL | |||
* version 2.0 (http://www.gnu.org/licenses/gpl-2.0.html) licenses. This means that you can | |||
* choose the license that best suits your project and use it accordingly. | |||
* | |||
* Although not required, the author would appreciate an email letting him | |||
* know of any substantial use of jqPlot. You can reach the author at: | |||
* chris dot leonello at gmail dot com or see http://www.jqplot.com/info.php . | |||
* chris at jqplot dot com or see http://www.jqplot.com/info.php . | |||
* | |||
* If you are feeling kind and generous, consider supporting the project by | |||
* making a donation at: http://www.jqplot.com/donate.php . | |||
* | |||
* sprintf functions contained in jqplot.sprintf.js by Ash Searle: | |||
* | |||
* version 2007.04.27 | |||
* author Ash Searle | |||
* http://hexmen.com/blog/2007/03/printf-sprintf/ | |||
* http://hexmen.com/js/sprintf.js | |||
* The author (Ash Searle) has placed this code in the public domain: | |||
* "This code is unrestricted: you are free to use it however you like." | |||
* | |||
*/ | |||
(function(a){a.jqplot.CanvasAxisLabelRenderer=function(b){this.angle=0;this.axis;this.show=true;this.showLabel=true;this.label="";this.fontFamily='"Trebuchet MS", Arial, Helvetica, sans-serif';this.fontSize="11pt";this.fontWeight="normal";this.fontStretch=1;this.textColor="#666666";this.enableFontSupport=false;this.pt2px=null;this._elem;this._ctx;this._plotWidth;this._plotHeight;this._plotDimensions={height:null,width:null};a.extend(true,this,b);if(b.angle==null&&this.axis!="xaxis"&&this.axis!="x2axis"){this.angle=-90}var e={fontSize:this.fontSize,fontWeight:this.fontWeight,fontStretch:this.fontStretch,fillStyle:this.textColor,angle:this.getAngleRad(),fontFamily:this.fontFamily};if(this.pt2px){e.pt2px=this.pt2px}if(this.enableFontSupport){if(a.browser.safari){var d=a.browser.version.split(".");for(var c=0;c<d.length;c++){d[c]=Number(d[c])}if(d[0]>528||(d[0]==528&&d[1]>=16)){this._textRenderer=new a.jqplot.CanvasFontRenderer(e)}}else{if(a.browser.mozilla){var d=a.browser.version.split(".");if(d[0]>1||(d[0]==1&&d[1]>=9&&d[2]>0)){this._textRenderer=new a.jqplot.CanvasFontRenderer(e)}else{this._textRenderer=new a.jqplot.CanvasTextRenderer(e)}}else{this._textRenderer=new a.jqplot.CanvasTextRenderer(e)}}}else{this._textRenderer=new a.jqplot.CanvasTextRenderer(e)}};a.jqplot.CanvasAxisLabelRenderer.prototype.init=function(b){a.extend(true,this,b);this._textRenderer.init({fontSize:this.fontSize,fontWeight:this.fontWeight,fontStretch:this.fontStretch,fillStyle:this.textColor,angle:this.getAngleRad(),fontFamily:this.fontFamily})};a.jqplot.CanvasAxisLabelRenderer.prototype.getWidth=function(d){if(this._elem){return this._elem.outerWidth(true)}else{var f=this._textRenderer;var c=f.getWidth(d);var e=f.getHeight(d);var b=Math.abs(Math.sin(f.angle)*e)+Math.abs(Math.cos(f.angle)*c);return b}};a.jqplot.CanvasAxisLabelRenderer.prototype.getHeight=function(d){if(this._elem){return this._elem.outerHeight(true)}else{var f=this._textRenderer;var c=f.getWidth(d);var e=f.getHeight(d);var b=Math.abs(Math.cos(f.angle)*e)+Math.abs(Math.sin(f.angle)*c);return b}};a.jqplot.CanvasAxisLabelRenderer.prototype.getAngleRad=function(){var b=this.angle*Math.PI/180;return b};a.jqplot.CanvasAxisLabelRenderer.prototype.draw=function(c){var e=document.createElement("canvas");this._textRenderer.setText(this.label,c);var b=this.getWidth(c);var d=this.getHeight(c);e.width=b;e.height=d;e.style.width=b;e.style.height=d;e.style.position="absolute";this._domelem=e;this._elem=a(e);this._elem.addClass("jqplot-"+this.axis+"-label");return this._elem};a.jqplot.CanvasAxisLabelRenderer.prototype.pack=function(){if(a.browser.msie){window.G_vmlCanvasManager.init_(document);this._domelem=window.G_vmlCanvasManager.initElement(this._domelem)}var b=this._elem.get(0).getContext("2d");this._textRenderer.draw(b,this.label)}})(jQuery); | |||
(function(a){a.jqplot.CanvasAxisLabelRenderer=function(b){this.angle=0;this.axis;this.show=true;this.showLabel=true;this.label="";this.fontFamily='"Trebuchet MS", Arial, Helvetica, sans-serif';this.fontSize="11pt";this.fontWeight="normal";this.fontStretch=1;this.textColor="#666666";this.enableFontSupport=true;this.pt2px=null;this._elem;this._ctx;this._plotWidth;this._plotHeight;this._plotDimensions={height:null,width:null};a.extend(true,this,b);if(b.angle==null&&this.axis!="xaxis"&&this.axis!="x2axis"){this.angle=-90}var c={fontSize:this.fontSize,fontWeight:this.fontWeight,fontStretch:this.fontStretch,fillStyle:this.textColor,angle:this.getAngleRad(),fontFamily:this.fontFamily};if(this.pt2px){c.pt2px=this.pt2px}if(this.enableFontSupport){function d(){return !!(document.createElement("canvas").getContext&&typeof document.createElement("canvas").getContext("2d").fillText=="function")}if(d()){this._textRenderer=new a.jqplot.CanvasFontRenderer(c)}else{this._textRenderer=new a.jqplot.CanvasTextRenderer(c)}}else{this._textRenderer=new a.jqplot.CanvasTextRenderer(c)}};a.jqplot.CanvasAxisLabelRenderer.prototype.init=function(b){a.extend(true,this,b);this._textRenderer.init({fontSize:this.fontSize,fontWeight:this.fontWeight,fontStretch:this.fontStretch,fillStyle:this.textColor,angle:this.getAngleRad(),fontFamily:this.fontFamily})};a.jqplot.CanvasAxisLabelRenderer.prototype.getWidth=function(d){if(this._elem){return this._elem.outerWidth(true)}else{var f=this._textRenderer;var c=f.getWidth(d);var e=f.getHeight(d);var b=Math.abs(Math.sin(f.angle)*e)+Math.abs(Math.cos(f.angle)*c);return b}};a.jqplot.CanvasAxisLabelRenderer.prototype.getHeight=function(d){if(this._elem){return this._elem.outerHeight(true)}else{var f=this._textRenderer;var c=f.getWidth(d);var e=f.getHeight(d);var b=Math.abs(Math.cos(f.angle)*e)+Math.abs(Math.sin(f.angle)*c);return b}};a.jqplot.CanvasAxisLabelRenderer.prototype.getAngleRad=function(){var b=this.angle*Math.PI/180;return b};a.jqplot.CanvasAxisLabelRenderer.prototype.draw=function(c,f){if(this._elem){if(a.jqplot.use_excanvas){window.G_vmlCanvasManager.uninitElement(this._elem.get(0))}this._elem.emptyForce();this._elem=null}var e=f.canvasManager.getCanvas();this._textRenderer.setText(this.label,c);var b=this.getWidth(c);var d=this.getHeight(c);e.width=b;e.height=d;e.style.width=b;e.style.height=d;e=f.canvasManager.initCanvas(e);this._elem=a(e);this._elem.css({position:"absolute"});this._elem.addClass("jqplot-"+this.axis+"-label");e=null;return this._elem};a.jqplot.CanvasAxisLabelRenderer.prototype.pack=function(){this._textRenderer.draw(this._elem.get(0).getContext("2d"),this.label)}})(jQuery); |
@@ -1,18 +1,30 @@ | |||
/** | |||
* Copyright (c) 2009 Chris Leonello | |||
* jqPlot | |||
* Pure JavaScript plotting plugin using jQuery | |||
* | |||
* Version: 1.0.0b2_r792 | |||
* | |||
* Copyright (c) 2009-2011 Chris Leonello | |||
* jqPlot is currently available for use in all personal or commercial projects | |||
* under both the MIT and GPL version 2.0 licenses. This means that you can | |||
* under both the MIT (http://www.opensource.org/licenses/mit-license.php) and GPL | |||
* version 2.0 (http://www.gnu.org/licenses/gpl-2.0.html) licenses. This means that you can | |||
* choose the license that best suits your project and use it accordingly. | |||
* | |||
* The author would appreciate an email letting him know of any substantial | |||
* use of jqPlot. You can reach the author at: chris dot leonello at gmail | |||
* dot com or see http://www.jqplot.com/info.php . This is, of course, | |||
* not required. | |||
* Although not required, the author would appreciate an email letting him | |||
* know of any substantial use of jqPlot. You can reach the author at: | |||
* chris at jqplot dot com or see http://www.jqplot.com/info.php . | |||
* | |||
* If you are feeling kind and generous, consider supporting the project by | |||
* making a donation at: http://www.jqplot.com/donate.php . | |||
* | |||
* Thanks for using jqPlot! | |||
* sprintf functions contained in jqplot.sprintf.js by Ash Searle: | |||
* | |||
* version 2007.04.27 | |||
* author Ash Searle | |||
* http://hexmen.com/blog/2007/03/printf-sprintf/ | |||
* http://hexmen.com/js/sprintf.js | |||
* The author (Ash Searle) has placed this code in the public domain: | |||
* "This code is unrestricted: you are free to use it however you like." | |||
* | |||
*/ | |||
(function($) { | |||
@@ -72,12 +84,16 @@ | |||
// prop: formatString | |||
// string passed to the formatter. | |||
this.formatString = ''; | |||
// prop: prefix | |||
// String to prepend to the tick label. | |||
// Prefix is prepended to the formatted tick label. | |||
this.prefix = ''; | |||
// prop: fontFamily | |||
// css spec for the font-family css attribute. | |||
this.fontFamily = '"Trebuchet MS", Arial, Helvetica, sans-serif'; | |||
// prop: fontSize | |||
// CSS spec for font size. | |||
this.fontSize = '11px'; | |||
this.fontSize = '10pt'; | |||
// prop: fontWeight | |||
// CSS spec for fontWeight | |||
this.fontWeight = 'normal'; | |||
@@ -92,7 +108,7 @@ | |||
// true to turn on native canvas font support in Mozilla 3.5+ and Safari 4+. | |||
// If true, tick label will be drawn with canvas tag native support for fonts. | |||
// If false, tick label will be drawn with Hershey font metrics. | |||
this.enableFontSupport = false; | |||
this.enableFontSupport = true; | |||
// prop: pt2px | |||
// Point to pixel scaling factor, used for computing height of bounding box | |||
// around a label. The labels text renderer has a default setting of 1.4, which | |||
@@ -116,27 +132,14 @@ | |||
} | |||
if (this.enableFontSupport) { | |||
if ($.browser.safari) { | |||
var p = $.browser.version.split('.'); | |||
for (var i=0; i<p.length; i++) { p[i] = Number(p[i]); } | |||
if (p[0] > 528 || (p[0] == 528 && p[1] >= 16)) { | |||
this._textRenderer = new $.jqplot.CanvasFontRenderer(ropts); | |||
} | |||
} | |||
else if ($.browser.mozilla) { | |||
var p = $.browser.version.split("."); | |||
if (p[0] > 1 || (p[0] == 1 && p[1] >= 9 && p[2] > 0) ) { | |||
this._textRenderer = new $.jqplot.CanvasFontRenderer(ropts); | |||
} | |||
else { | |||
this._textRenderer = new $.jqplot.CanvasTextRenderer(ropts); | |||
} | |||
function support_canvas_text() { | |||
return !!(document.createElement('canvas').getContext && typeof document.createElement('canvas').getContext('2d').fillText == 'function'); | |||
} | |||
// TODO: test and enable this | |||
// else if ($.browser.msie) { | |||
// this._textRenderer = new $.jqplot.CanvasFontRenderer(ropts); | |||
// } | |||
if (support_canvas_text()) { | |||
this._textRenderer = new $.jqplot.CanvasFontRenderer(ropts); | |||
} | |||
else { | |||
this._textRenderer = new $.jqplot.CanvasTextRenderer(ropts); | |||
@@ -196,37 +199,49 @@ | |||
return this; | |||
}; | |||
$.jqplot.CanvasAxisTickRenderer.prototype.draw = function(ctx) { | |||
$.jqplot.CanvasAxisTickRenderer.prototype.draw = function(ctx, plot) { | |||
if (!this.label) { | |||
this.label = this.formatter(this.formatString, this.value); | |||
this.label = this.prefix + this.formatter(this.formatString, this.value); | |||
} | |||
// Memory Leaks patch | |||
if (this._elem) { | |||
if ($.jqplot.use_excanvas) { | |||
window.G_vmlCanvasManager.uninitElement(this._elem.get(0)); | |||
} | |||
this._elem.emptyForce(); | |||
this._elem = null; | |||
} | |||
// create a canvas here, but can't draw on it untill it is appended | |||
// to dom for IE compatability. | |||
var domelem = document.createElement('canvas'); | |||
var elem = plot.canvasManager.getCanvas(); | |||
this._textRenderer.setText(this.label, ctx); | |||
var w = this.getWidth(ctx); | |||
var h = this.getHeight(ctx); | |||
domelem.width = w; | |||
domelem.height = h; | |||
domelem.style.width = w; | |||
domelem.style.height = h; | |||
domelem.style.textAlign = 'left'; | |||
domelem.style.position = 'absolute'; | |||
this._domelem = domelem; | |||
this._elem = $(domelem); | |||
// canvases seem to need to have width and heigh attributes directly set. | |||
elem.width = w; | |||
elem.height = h; | |||
elem.style.width = w; | |||
elem.style.height = h; | |||
elem.style.textAlign = 'left'; | |||
elem.style.position = 'absolute'; | |||
elem = plot.canvasManager.initCanvas(elem); | |||
this._elem = $(elem); | |||
this._elem.css(this._styles); | |||
this._elem.addClass('jqplot-'+this.axis+'-tick'); | |||
elem = null; | |||
return this._elem; | |||
}; | |||
$.jqplot.CanvasAxisTickRenderer.prototype.pack = function() { | |||
if ($.browser.msie) { | |||
window.G_vmlCanvasManager.init_(document); | |||
this._domelem = window.G_vmlCanvasManager.initElement(this._domelem); | |||
} | |||
var ctx = this._elem.get(0).getContext("2d"); | |||
this._textRenderer.draw(ctx, this.label); | |||
this._textRenderer.draw(this._elem.get(0).getContext("2d"), this.label); | |||
}; | |||
})(jQuery); |
@@ -1,14 +1,30 @@ | |||
/** | |||
* Copyright (c) 2009 Chris Leonello | |||
* jqPlot | |||
* Pure JavaScript plotting plugin using jQuery | |||
* | |||
* Version: 1.0.0b2_r792 | |||
* | |||
* Copyright (c) 2009-2011 Chris Leonello | |||
* jqPlot is currently available for use in all personal or commercial projects | |||
* under both the MIT and GPL version 2.0 licenses. This means that you can | |||
* under both the MIT (http://www.opensource.org/licenses/mit-license.php) and GPL | |||
* version 2.0 (http://www.gnu.org/licenses/gpl-2.0.html) licenses. This means that you can | |||
* choose the license that best suits your project and use it accordingly. | |||
* | |||
* Although not required, the author would appreciate an email letting him | |||
* know of any substantial use of jqPlot. You can reach the author at: | |||
* chris dot leonello at gmail dot com or see http://www.jqplot.com/info.php . | |||
* chris at jqplot dot com or see http://www.jqplot.com/info.php . | |||
* | |||
* If you are feeling kind and generous, consider supporting the project by | |||
* making a donation at: http://www.jqplot.com/donate.php . | |||
* | |||
* sprintf functions contained in jqplot.sprintf.js by Ash Searle: | |||
* | |||
* version 2007.04.27 | |||
* author Ash Searle | |||
* http://hexmen.com/blog/2007/03/printf-sprintf/ | |||
* http://hexmen.com/js/sprintf.js | |||
* The author (Ash Searle) has placed this code in the public domain: | |||
* "This code is unrestricted: you are free to use it however you like." | |||
* | |||
*/ | |||
(function(a){a.jqplot.CanvasAxisTickRenderer=function(b){this.mark="outside";this.showMark=true;this.showGridline=true;this.isMinorTick=false;this.angle=0;this.markSize=4;this.show=true;this.showLabel=true;this.labelPosition="auto";this.label="";this.value=null;this._styles={};this.formatter=a.jqplot.DefaultTickFormatter;this.formatString="";this.fontFamily='"Trebuchet MS", Arial, Helvetica, sans-serif';this.fontSize="11px";this.fontWeight="normal";this.fontStretch=1;this.textColor="#666666";this.enableFontSupport=false;this.pt2px=null;this._elem;this._ctx;this._plotWidth;this._plotHeight;this._plotDimensions={height:null,width:null};a.extend(true,this,b);var e={fontSize:this.fontSize,fontWeight:this.fontWeight,fontStretch:this.fontStretch,fillStyle:this.textColor,angle:this.getAngleRad(),fontFamily:this.fontFamily};if(this.pt2px){e.pt2px=this.pt2px}if(this.enableFontSupport){if(a.browser.safari){var d=a.browser.version.split(".");for(var c=0;c<d.length;c++){d[c]=Number(d[c])}if(d[0]>528||(d[0]==528&&d[1]>=16)){this._textRenderer=new a.jqplot.CanvasFontRenderer(e)}}else{if(a.browser.mozilla){var d=a.browser.version.split(".");if(d[0]>1||(d[0]==1&&d[1]>=9&&d[2]>0)){this._textRenderer=new a.jqplot.CanvasFontRenderer(e)}else{this._textRenderer=new a.jqplot.CanvasTextRenderer(e)}}else{this._textRenderer=new a.jqplot.CanvasTextRenderer(e)}}}else{this._textRenderer=new a.jqplot.CanvasTextRenderer(e)}};a.jqplot.CanvasAxisTickRenderer.prototype.init=function(b){a.extend(true,this,b);this._textRenderer.init({fontSize:this.fontSize,fontWeight:this.fontWeight,fontStretch:this.fontStretch,fillStyle:this.textColor,angle:this.getAngleRad(),fontFamily:this.fontFamily})};a.jqplot.CanvasAxisTickRenderer.prototype.getWidth=function(d){if(this._elem){return this._elem.outerWidth(true)}else{var f=this._textRenderer;var c=f.getWidth(d);var e=f.getHeight(d);var b=Math.abs(Math.sin(f.angle)*e)+Math.abs(Math.cos(f.angle)*c);return b}};a.jqplot.CanvasAxisTickRenderer.prototype.getHeight=function(d){if(this._elem){return this._elem.outerHeight(true)}else{var f=this._textRenderer;var c=f.getWidth(d);var e=f.getHeight(d);var b=Math.abs(Math.cos(f.angle)*e)+Math.abs(Math.sin(f.angle)*c);return b}};a.jqplot.CanvasAxisTickRenderer.prototype.getAngleRad=function(){var b=this.angle*Math.PI/180;return b};a.jqplot.CanvasAxisTickRenderer.prototype.setTick=function(b,d,c){this.value=b;if(c){this.isMinorTick=true}return this};a.jqplot.CanvasAxisTickRenderer.prototype.draw=function(c){if(!this.label){this.label=this.formatter(this.formatString,this.value)}var e=document.createElement("canvas");this._textRenderer.setText(this.label,c);var b=this.getWidth(c);var d=this.getHeight(c);e.width=b;e.height=d;e.style.width=b;e.style.height=d;e.style.textAlign="left";e.style.position="absolute";this._domelem=e;this._elem=a(e);this._elem.css(this._styles);this._elem.addClass("jqplot-"+this.axis+"-tick");return this._elem};a.jqplot.CanvasAxisTickRenderer.prototype.pack=function(){if(a.browser.msie){window.G_vmlCanvasManager.init_(document);this._domelem=window.G_vmlCanvasManager.initElement(this._domelem)}var b=this._elem.get(0).getContext("2d");this._textRenderer.draw(b,this.label)}})(jQuery); | |||
(function(a){a.jqplot.CanvasAxisTickRenderer=function(b){this.mark="outside";this.showMark=true;this.showGridline=true;this.isMinorTick=false;this.angle=0;this.markSize=4;this.show=true;this.showLabel=true;this.labelPosition="auto";this.label="";this.value=null;this._styles={};this.formatter=a.jqplot.DefaultTickFormatter;this.formatString="";this.prefix="";this.fontFamily='"Trebuchet MS", Arial, Helvetica, sans-serif';this.fontSize="10pt";this.fontWeight="normal";this.fontStretch=1;this.textColor="#666666";this.enableFontSupport=true;this.pt2px=null;this._elem;this._ctx;this._plotWidth;this._plotHeight;this._plotDimensions={height:null,width:null};a.extend(true,this,b);var c={fontSize:this.fontSize,fontWeight:this.fontWeight,fontStretch:this.fontStretch,fillStyle:this.textColor,angle:this.getAngleRad(),fontFamily:this.fontFamily};if(this.pt2px){c.pt2px=this.pt2px}if(this.enableFontSupport){function d(){return !!(document.createElement("canvas").getContext&&typeof document.createElement("canvas").getContext("2d").fillText=="function")}if(d()){this._textRenderer=new a.jqplot.CanvasFontRenderer(c)}else{this._textRenderer=new a.jqplot.CanvasTextRenderer(c)}}else{this._textRenderer=new a.jqplot.CanvasTextRenderer(c)}};a.jqplot.CanvasAxisTickRenderer.prototype.init=function(b){a.extend(true,this,b);this._textRenderer.init({fontSize:this.fontSize,fontWeight:this.fontWeight,fontStretch:this.fontStretch,fillStyle:this.textColor,angle:this.getAngleRad(),fontFamily:this.fontFamily})};a.jqplot.CanvasAxisTickRenderer.prototype.getWidth=function(d){if(this._elem){return this._elem.outerWidth(true)}else{var f=this._textRenderer;var c=f.getWidth(d);var e=f.getHeight(d);var b=Math.abs(Math.sin(f.angle)*e)+Math.abs(Math.cos(f.angle)*c);return b}};a.jqplot.CanvasAxisTickRenderer.prototype.getHeight=function(d){if(this._elem){return this._elem.outerHeight(true)}else{var f=this._textRenderer;var c=f.getWidth(d);var e=f.getHeight(d);var b=Math.abs(Math.cos(f.angle)*e)+Math.abs(Math.sin(f.angle)*c);return b}};a.jqplot.CanvasAxisTickRenderer.prototype.getAngleRad=function(){var b=this.angle*Math.PI/180;return b};a.jqplot.CanvasAxisTickRenderer.prototype.setTick=function(b,d,c){this.value=b;if(c){this.isMinorTick=true}return this};a.jqplot.CanvasAxisTickRenderer.prototype.draw=function(c,f){if(!this.label){this.label=this.prefix+this.formatter(this.formatString,this.value)}if(this._elem){if(a.jqplot.use_excanvas){window.G_vmlCanvasManager.uninitElement(this._elem.get(0))}this._elem.emptyForce();this._elem=null}var e=f.canvasManager.getCanvas();this._textRenderer.setText(this.label,c);var b=this.getWidth(c);var d=this.getHeight(c);e.width=b;e.height=d;e.style.width=b;e.style.height=d;e.style.textAlign="left";e.style.position="absolute";e=f.canvasManager.initCanvas(e);this._elem=a(e);this._elem.css(this._styles);this._elem.addClass("jqplot-"+this.axis+"-tick");e=null;return this._elem};a.jqplot.CanvasAxisTickRenderer.prototype.pack=function(){this._textRenderer.draw(this._elem.get(0).getContext("2d"),this.label)}})(jQuery); |
@@ -0,0 +1,705 @@ | |||
/** | |||
* jqPlot | |||
* Pure JavaScript plotting plugin using jQuery | |||
* | |||
* Version: 1.0.0b2_r792 | |||
* | |||
* Copyright (c) 2009-2011 Chris Leonello | |||
* jqPlot is currently available for use in all personal or commercial projects | |||
* under both the MIT (http://www.opensource.org/licenses/mit-license.php) and GPL | |||
* version 2.0 (http://www.gnu.org/licenses/gpl-2.0.html) licenses. This means that you can | |||
* choose the license that best suits your project and use it accordingly. | |||
* | |||
* Although not required, the author would appreciate an email letting him | |||
* know of any substantial use of jqPlot. You can reach the author at: | |||
* chris at jqplot dot com or see http://www.jqplot.com/info.php . | |||
* | |||
* If you are feeling kind and generous, consider supporting the project by | |||
* making a donation at: http://www.jqplot.com/donate.php . | |||
* | |||
* sprintf functions contained in jqplot.sprintf.js by Ash Searle: | |||
* | |||
* version 2007.04.27 | |||
* author Ash Searle | |||
* http://hexmen.com/blog/2007/03/printf-sprintf/ | |||
* http://hexmen.com/js/sprintf.js | |||
* The author (Ash Searle) has placed this code in the public domain: | |||
* "This code is unrestricted: you are free to use it however you like." | |||
* | |||
*/ | |||
(function($) { | |||
// class: $.jqplot.CanvasOverlay | |||
$.jqplot.CanvasOverlay = function(opts){ | |||
var options = opts || {}; | |||
this.options = { | |||
show: $.jqplot.config.enablePlugins, | |||
deferDraw: false | |||
}; | |||
// prop: objects | |||
this.objects = []; | |||
this.objectNames = []; | |||
this.canvas = null; | |||
this.markerRenderer = new $.jqplot.MarkerRenderer({style:'line'}); | |||
this.markerRenderer.init(); | |||
if (options.objects) { | |||
var objs = options.objects, | |||
obj; | |||
for (var i=0; i<objs.length; i++) { | |||
obj = objs[i]; | |||
for (var n in obj) { | |||
switch (n) { | |||
case 'line': | |||
this.addLine(obj[n]); | |||
break; | |||
case 'horizontalLine': | |||
this.addHorizontalLine(obj[n]); | |||
break; | |||
case 'dashedHorizontalLine': | |||
this.addDashedHorizontalLine(obj[n]); | |||
break; | |||
case 'verticalLine': | |||
this.addVerticalLine(obj[n]); | |||
break; | |||
case 'dashedVerticalLine': | |||
this.addDashedVerticalLine(obj[n]); | |||
break; | |||
default: | |||
break; | |||
} | |||
} | |||
} | |||
} | |||
$.extend(true, this.options, options); | |||
}; | |||
// called with scope of a plot object | |||
$.jqplot.CanvasOverlay.postPlotInit = function (target, data, opts) { | |||
var options = opts || {}; | |||
// add a canvasOverlay attribute to the plot | |||
this.plugins.canvasOverlay = new $.jqplot.CanvasOverlay(options.canvasOverlay); | |||
}; | |||
/** | |||
* Class: Line | |||
* A straight line. | |||
*/ | |||
function Line(options) { | |||
this.type = 'line'; | |||
this.options = { | |||
// prop: name | |||
// Optional name for this overlay object. | |||
// Can be later used to retrieve the object by name. | |||
name: null, | |||
// prop: show | |||
// true to show (draw), false to not draw. | |||
show: true, | |||
// prop: lineWidth | |||
// Width of the line. | |||
lineWidth: 2, | |||
// prop: lineCap | |||
// Type of ending placed on the line ['round', 'butt', 'square'] | |||
lineCap: 'round', | |||
// prop: color | |||
// color of the line | |||
color: '#666666', | |||
// prop: shadow | |||
// wether or not to draw a shadow on the line | |||
shadow: true, | |||
// prop: shadowAngle | |||
// Shadow angle in degrees | |||
shadowAngle: 45, | |||
// prop: shadowOffset | |||
// Shadow offset from line in pixels | |||
shadowOffset: 1, | |||
// prop: shadowDepth | |||
// Number of times shadow is stroked, each stroke offset shadowOffset from the last. | |||
shadowDepth: 3, | |||
// prop: shadowAlpha | |||
// Alpha channel transparency of shadow. 0 = transparent. | |||
shadowAlpha: '0.07', | |||
// prop: xaxis | |||
// X axis to use for positioning/scaling the line. | |||
xaxis: 'xaxis', | |||
// prop: yaxis | |||
// Y axis to use for positioning/scaling the line. | |||
yaxis: 'yaxis', | |||
// prop: start | |||
// [x, y] coordinates for the start of the line. | |||
start: [], | |||
// prop: stop | |||
// [x, y] coordinates for the end of the line. | |||
stop: [] | |||
}; | |||
$.extend(true, this.options, options); | |||
} | |||
/** | |||
* Class: HorizontalLine | |||
* A straight horizontal line. | |||
*/ | |||
function HorizontalLine(options) { | |||
this.type = 'horizontalLine'; | |||
this.options = { | |||
// prop: name | |||
// Optional name for this overlay object. | |||
// Can be later used to retrieve the object by name. | |||
name: null, | |||
// prop: show | |||
// true to show (draw), false to not draw. | |||
show: true, | |||
// prop: lineWidth | |||
// Width of the line. | |||
lineWidth: 2, | |||
// prop: lineCap | |||
// Type of ending placed on the line ['round', 'butt', 'square'] | |||
lineCap: 'round', | |||
// prop: color | |||
// color of the line | |||
color: '#666666', | |||
// prop: shadow | |||
// wether or not to draw a shadow on the line | |||
shadow: true, | |||
// prop: shadowAngle | |||
// Shadow angle in degrees | |||
shadowAngle: 45, | |||
// prop: shadowOffset | |||
// Shadow offset from line in pixels | |||
shadowOffset: 1, | |||
// prop: shadowDepth | |||
// Number of times shadow is stroked, each stroke offset shadowOffset from the last. | |||
shadowDepth: 3, | |||
// prop: shadowAlpha | |||
// Alpha channel transparency of shadow. 0 = transparent. | |||
shadowAlpha: '0.07', | |||
// prop: xaxis | |||
// X axis to use for positioning/scaling the line. | |||
xaxis: 'xaxis', | |||
// prop: yaxis | |||
// Y axis to use for positioning/scaling the line. | |||
yaxis: 'yaxis', | |||
// prop: y | |||
// y value to position the line | |||
y: null, | |||
// prop: xmin | |||
// x value for the start of the line, null to scale to axis min. | |||
xmin: null, | |||
// prop: xmax | |||
// x value for the end of the line, null to scale to axis max. | |||
xmax: null, | |||
// prop xOffset | |||
// offset ends of the line inside the grid. Number | |||
xOffset: '6px', // number or string. Number interpreted as units, string as pixels. | |||
xminOffset: null, | |||
xmaxOffset: null | |||
}; | |||
$.extend(true, this.options, options); | |||
} | |||
/** | |||
* Class: DashedHorizontalLine | |||
* A straight dashed horizontal line. | |||
*/ | |||
function DashedHorizontalLine(options) { | |||
this.type = 'dashedHorizontalLine'; | |||
this.options = { | |||
// prop: name | |||
// Optional name for this overlay object. | |||
// Can be later used to retrieve the object by name. | |||
name: null, | |||
// prop: show | |||
// true to show (draw), false to not draw. | |||
show: true, | |||
// prop: lineWidth | |||
// Width of the line. | |||
lineWidth: 2, | |||
// prop: lineCap | |||
// Type of ending placed on the line ['round', 'butt', 'square'] | |||
lineCap: 'butt', | |||
// prop: color | |||
// color of the line | |||
color: '#666666', | |||
// prop: shadow | |||
// wether or not to draw a shadow on the line | |||
shadow: true, | |||
// prop: shadowAngle | |||
// Shadow angle in degrees | |||
shadowAngle: 45, | |||
// prop: shadowOffset | |||
// Shadow offset from line in pixels | |||
shadowOffset: 1, | |||
// prop: shadowDepth | |||
// Number of times shadow is stroked, each stroke offset shadowOffset from the last. | |||
shadowDepth: 3, | |||
// prop: shadowAlpha | |||
// Alpha channel transparency of shadow. 0 = transparent. | |||
shadowAlpha: '0.07', | |||
// prop: xaxis | |||
// X axis to use for positioning/scaling the line. | |||
xaxis: 'xaxis', | |||
// prop: yaxis | |||
// Y axis to use for positioning/scaling the line. | |||
yaxis: 'yaxis', | |||
y: null, | |||
xmin: null, | |||
xmax: null, | |||
xOffset: '6px', // number or string. Number interpreted as units, string as pixels. | |||
xminOffset: null, | |||
xmaxOffset: null, | |||
// prop: dashPattern | |||
// Array of line, space settings in pixels. | |||
// Default is 8 pixel of line, 8 pixel of space. | |||
// Note, limit to a 2 element array b/c of bug with higher order arrays. | |||
dashPattern: [8,8] | |||
}; | |||
$.extend(true, this.options, options); | |||
} | |||
/** | |||
* Class: VerticalLine | |||
* A straight vertical line. | |||
*/ | |||
function VerticalLine(options) { | |||
this.type = 'verticalLine'; | |||
this.options = { | |||
// prop: name | |||
// Optional name for this overlay object. | |||
// Can be later used to retrieve the object by name. | |||
name: null, | |||
// prop: show | |||
// true to show (draw), false to not draw. | |||
show: true, | |||
// prop: lineWidth | |||
// Width of the line. | |||
lineWidth: 2, | |||
// prop: lineCap | |||
// Type of ending placed on the line ['round', 'butt', 'square'] | |||
lineCap: 'round', | |||
// prop: color | |||
// color of the line | |||
color: '#666666', | |||
// prop: shadow | |||
// wether or not to draw a shadow on the line | |||
shadow: true, | |||
// prop: shadowAngle | |||
// Shadow angle in degrees | |||
shadowAngle: 45, | |||
// prop: shadowOffset | |||
// Shadow offset from line in pixels | |||
shadowOffset: 1, | |||
// prop: shadowDepth | |||
// Number of times shadow is stroked, each stroke offset shadowOffset from the last. | |||
shadowDepth: 3, | |||
// prop: shadowAlpha | |||
// Alpha channel transparency of shadow. 0 = transparent. | |||
shadowAlpha: '0.07', | |||
// prop: xaxis | |||
// X axis to use for positioning/scaling the line. | |||
xaxis: 'xaxis', | |||
// prop: yaxis | |||
// Y axis to use for positioning/scaling the line. | |||
yaxis: 'yaxis', | |||
x: null, | |||
ymin: null, | |||
ymax: null, | |||
yOffset: '6px', // number or string. Number interpreted as units, string as pixels. | |||
yminOffset: null, | |||
ymaxOffset: null | |||
}; | |||
$.extend(true, this.options, options); | |||
} | |||
/** | |||
* Class: DashedVerticalLine | |||
* A straight dashed vertical line. | |||
*/ | |||
function DashedVerticalLine(options) { | |||
this.type = 'dashedVerticalLine'; | |||
this.options = { | |||
// prop: name | |||
// Optional name for this overlay object. | |||
// Can be later used to retrieve the object by name. | |||
name: null, | |||
// prop: show | |||
// true to show (draw), false to not draw. | |||
show: true, | |||
// prop: lineWidth | |||
// Width of the line. | |||
lineWidth: 2, | |||
// prop: lineCap | |||
// Type of ending placed on the line ['round', 'butt', 'square'] | |||
lineCap: 'butt', | |||
// prop: color | |||
// color of the line | |||
color: '#666666', | |||
// prop: shadow | |||
// wether or not to draw a shadow on the line | |||
shadow: true, | |||
// prop: shadowAngle | |||
// Shadow angle in degrees | |||
shadowAngle: 45, | |||
// prop: shadowOffset | |||
// Shadow offset from line in pixels | |||
shadowOffset: 1, | |||
// prop: shadowDepth | |||
// Number of times shadow is stroked, each stroke offset shadowOffset from the last. | |||
shadowDepth: 3, | |||
// prop: shadowAlpha | |||
// Alpha channel transparency of shadow. 0 = transparent. | |||
shadowAlpha: '0.07', | |||
// prop: xaxis | |||
// X axis to use for positioning/scaling the line. | |||
xaxis: 'xaxis', | |||
// prop: yaxis | |||
// Y axis to use for positioning/scaling the line. | |||
yaxis: 'yaxis', | |||
x: null, | |||
ymin: null, | |||
ymax: null, | |||
yOffset: '6px', // number or string. Number interpreted as units, string as pixels. | |||
yminOffset: null, | |||
ymaxOffset: null, | |||
// prop: dashPattern | |||
// Array of line, space settings in pixels. | |||
// Default is 8 pixel of line, 8 pixel of space. | |||
// Note, limit to a 2 element array b/c of bug with higher order arrays. | |||
dashPattern: [8,8] | |||
}; | |||
$.extend(true, this.options, options); | |||
} | |||
$.jqplot.CanvasOverlay.prototype.addLine = function(opts) { | |||
var line = new Line(opts); | |||
this.objects.push(line); | |||
this.objectNames.push(line.options.name); | |||
}; | |||
$.jqplot.CanvasOverlay.prototype.addHorizontalLine = function(opts) { | |||
var line = new HorizontalLine(opts); | |||
this.objects.push(line); | |||
this.objectNames.push(line.options.name); | |||
}; | |||
$.jqplot.CanvasOverlay.prototype.addDashedHorizontalLine = function(opts) { | |||
var line = new DashedHorizontalLine(opts); | |||
this.objects.push(line); | |||
this.objectNames.push(line.options.name); | |||
}; | |||
$.jqplot.CanvasOverlay.prototype.addVerticalLine = function(opts) { | |||
var line = new VerticalLine(opts); | |||
this.objects.push(line); | |||
this.objectNames.push(line.options.name); | |||
}; | |||
$.jqplot.CanvasOverlay.prototype.addDashedVerticalLine = function(opts) { | |||
var line = new DashedVerticalLine(opts); | |||
this.objects.push(line); | |||
this.objectNames.push(line.options.name); | |||
}; | |||
$.jqplot.CanvasOverlay.prototype.removeObject = function(idx) { | |||
// check if integer, remove by index | |||
if ($.type(idx) == 'number') { | |||
this.objects.splice(idx, 1); | |||
this.objectNames.splice(idx, 1); | |||
} | |||
// if string, remove by name | |||
else { | |||
var id = $.inArray(idx, this.objectNames); | |||
if (id != -1) { | |||
this.objects.splice(id, 1); | |||
this.objectNames.splice(id, 1); | |||
} | |||
} | |||
}; | |||
$.jqplot.CanvasOverlay.prototype.getObject = function(idx) { | |||
// check if integer, remove by index | |||
if ($.type(idx) == 'number') { | |||
return this.objects[idx]; | |||
} | |||
// if string, remove by name | |||
else { | |||
var id = $.inArray(idx, this.objectNames); | |||
if (id != -1) { | |||
return this.objects[id]; | |||
} | |||
} | |||
}; | |||
// Set get as alias for getObject. | |||
$.jqplot.CanvasOverlay.prototype.get = $.jqplot.CanvasOverlay.prototype.getObject; | |||
$.jqplot.CanvasOverlay.prototype.clear = function(plot) { | |||
this.canvas._ctx.clearRect(0,0,this.canvas.getWidth(), this.canvas.getHeight()); | |||
}; | |||
$.jqplot.CanvasOverlay.prototype.draw = function(plot) { | |||
var obj, | |||
objs = this.objects, | |||
mr = this.markerRenderer, | |||
start, | |||
stop; | |||
if (this.options.show) { | |||
this.canvas._ctx.clearRect(0,0,this.canvas.getWidth(), this.canvas.getHeight()); | |||
for (var k=0; k<objs.length; k++) { | |||
obj = objs[k]; | |||
var opts = $.extend(true, {}, obj.options); | |||
if (obj.options.show) { | |||
// style and shadow properties should be set before | |||
// every draw of marker renderer. | |||
mr.shadow = obj.options.shadow; | |||
switch (obj.type) { | |||
case 'line': | |||
// style and shadow properties should be set before | |||
// every draw of marker renderer. | |||
mr.style = 'line'; | |||
opts.closePath = false; | |||
start = [plot.axes[obj.options.xaxis].series_u2p(obj.options.start[0]), plot.axes[obj.options.yaxis].series_u2p(obj.options.start[1])]; | |||
stop = [plot.axes[obj.options.xaxis].series_u2p(obj.options.stop[0]), plot.axes[obj.options.yaxis].series_u2p(obj.options.stop[1])]; | |||
mr.draw(start, stop, this.canvas._ctx, opts); | |||
break; | |||
case 'horizontalLine': | |||
// style and shadow properties should be set before | |||
// every draw of marker renderer. | |||
if (obj.options.y != null) { | |||
mr.style = 'line'; | |||
opts.closePath = false; | |||
var xaxis = plot.axes[obj.options.xaxis], | |||
xstart, | |||
xstop, | |||
y = plot.axes[obj.options.yaxis].series_u2p(obj.options.y), | |||
xminoff = obj.options.xminOffset || obj.options.xOffset, | |||
xmaxoff = obj.options.xmaxOffset || obj.options.xOffset; | |||
if (obj.options.xmin != null) { | |||
xstart = xaxis.series_u2p(obj.options.xmin); | |||
} | |||
else if (xminoff != null) { | |||
if ($.type(xminoff) == "number") { | |||
xstart = xaxis.series_u2p(xaxis.min + xminoff); | |||
} | |||
else if ($.type(xminoff) == "string") { | |||
xstart = xaxis.series_u2p(xaxis.min) + parseFloat(xminoff); | |||
} | |||
} | |||
if (obj.options.xmax != null) { | |||
xstop = xaxis.series_u2p(obj.options.xmax); | |||
} | |||
else if (xmaxoff != null) { | |||
if ($.type(xmaxoff) == "number") { | |||
xstop = xaxis.series_u2p(xaxis.max - xmaxoff); | |||
} | |||
else if ($.type(xmaxoff) == "string") { | |||
xstop = xaxis.series_u2p(xaxis.max) - parseFloat(xmaxoff); | |||
} | |||
} | |||
if (xstop != null && xstart != null) { | |||
mr.draw([xstart, y], [xstop, y], this.canvas._ctx, opts); | |||
} | |||
} | |||
break; | |||
case 'dashedHorizontalLine': | |||
var dashPat = obj.options.dashPattern; | |||
var dashPatLen = 0; | |||
for (var i=0; i<dashPat.length; i++) { | |||
dashPatLen += dashPat[i]; | |||
} | |||
// style and shadow properties should be set before | |||
// every draw of marker renderer. | |||
if (obj.options.y != null) { | |||
mr.style = 'line'; | |||
opts.closePath = false; | |||
var xaxis = plot.axes[obj.options.xaxis], | |||
xstart, | |||
xstop, | |||
y = plot.axes[obj.options.yaxis].series_u2p(obj.options.y), | |||
xminoff = obj.options.xminOffset || obj.options.xOffset, | |||
xmaxoff = obj.options.xmaxOffset || obj.options.xOffset; | |||
if (obj.options.xmin != null) { | |||
xstart = xaxis.series_u2p(obj.options.xmin); | |||
} | |||
else if (xminoff != null) { | |||
if ($.type(xminoff) == "number") { | |||
xstart = xaxis.series_u2p(xaxis.min + xminoff); | |||
} | |||
else if ($.type(xminoff) == "string") { | |||
xstart = xaxis.series_u2p(xaxis.min) + parseFloat(xminoff); | |||
} | |||
} | |||
if (obj.options.xmax != null) { | |||
xstop = xaxis.series_u2p(obj.options.xmax); | |||
} | |||
else if (xmaxoff != null) { | |||
if ($.type(xmaxoff) == "number") { | |||
xstop = xaxis.series_u2p(xaxis.max - xmaxoff); | |||
} | |||
else if ($.type(xmaxoff) == "string") { | |||
xstop = xaxis.series_u2p(xaxis.max) - parseFloat(xmaxoff); | |||
} | |||
} | |||
if (xstop != null && xstart != null) { | |||
var numDash = Math.ceil((xstop - xstart)/dashPatLen); | |||
var b=xstart, e; | |||
for (var i=0; i<numDash; i++) { | |||
for (var j=0; j<dashPat.length; j+=2) { | |||
e = b+dashPat[j]; | |||
mr.draw([b, y], [e, y], this.canvas._ctx, opts); | |||
b += dashPat[j]; | |||
if (j < dashPat.length-1) { | |||
b += dashPat[j+1]; | |||
} | |||
} | |||
} | |||
} | |||
} | |||
break; | |||
case 'verticalLine': | |||
// style and shadow properties should be set before | |||
// every draw of marker renderer. | |||
if (obj.options.x != null) { | |||
mr.style = 'line'; | |||
opts.closePath = false; | |||
var yaxis = plot.axes[obj.options.yaxis], | |||
ystart, | |||
ystop, | |||
x = plot.axes[obj.options.xaxis].series_u2p(obj.options.x), | |||
yminoff = obj.options.yminOffset || obj.options.yOffset, | |||
ymaxoff = obj.options.ymaxOffset || obj.options.yOffset; | |||
if (obj.options.ymin != null) { | |||
ystart = yaxis.series_u2p(obj.options.ymin); | |||
} | |||
else if (yminoff != null) { | |||
if ($.type(yminoff) == "number") { | |||
ystart = yaxis.series_u2p(yaxis.min - yminoff); | |||
} | |||
else if ($.type(yminoff) == "string") { | |||
ystart = yaxis.series_u2p(yaxis.min) - parseFloat(yminoff); | |||
} | |||
} | |||
if (obj.options.ymax != null) { | |||
ystop = yaxis.series_u2p(obj.options.ymax); | |||
} | |||
else if (ymaxoff != null) { | |||
if ($.type(ymaxoff) == "number") { | |||
ystop = yaxis.series_u2p(yaxis.max + ymaxoff); | |||
} | |||
else if ($.type(ymaxoff) == "string") { | |||
ystop = yaxis.series_u2p(yaxis.max) + parseFloat(ymaxoff); | |||
} | |||
} | |||
if (ystop != null && ystart != null) { | |||
mr.draw([x, ystart], [x, ystop], this.canvas._ctx, opts); | |||
} | |||
} | |||
break; | |||
case 'dashedVerticalLine': | |||
var dashPat = obj.options.dashPattern; | |||
var dashPatLen = 0; | |||
for (var i=0; i<dashPat.length; i++) { | |||
dashPatLen += dashPat[i]; | |||
} | |||
// style and shadow properties should be set before | |||
// every draw of marker renderer. | |||
if (obj.options.x != null) { | |||
mr.style = 'line'; | |||
opts.closePath = false; | |||
var yaxis = plot.axes[obj.options.yaxis], | |||
ystart, | |||
ystop, | |||
x = plot.axes[obj.options.xaxis].series_u2p(obj.options.x), | |||
yminoff = obj.options.yminOffset || obj.options.yOffset, | |||
ymaxoff = obj.options.ymaxOffset || obj.options.yOffset; | |||
if (obj.options.ymin != null) { | |||
ystart = yaxis.series_u2p(obj.options.ymin); | |||
} | |||
else if (yminoff != null) { | |||
if ($.type(yminoff) == "number") { | |||
ystart = yaxis.series_u2p(yaxis.min - yminoff); | |||
} | |||
else if ($.type(yminoff) == "string") { | |||
ystart = yaxis.series_u2p(yaxis.min) - parseFloat(yminoff); | |||
} | |||
} | |||
if (obj.options.ymax != null) { | |||
ystop = yaxis.series_u2p(obj.options.ymax); | |||
} | |||
else if (ymaxoff != null) { | |||
if ($.type(ymaxoff) == "number") { | |||
ystop = yaxis.series_u2p(yaxis.max + ymaxoff); | |||
} | |||
else if ($.type(ymaxoff) == "string") { | |||
ystop = yaxis.series_u2p(yaxis.max) + parseFloat(ymaxoff); | |||
} | |||
} | |||
if (ystop != null && ystart != null) { | |||
var numDash = Math.ceil((ystart - ystop)/dashPatLen); | |||
var firstDashAdjust = ((numDash * dashPatLen) - (ystart - ystop))/2.0; | |||
var b=ystart, e, bs, es; | |||
for (var i=0; i<numDash; i++) { | |||
for (var j=0; j<dashPat.length; j+=2) { | |||
e = b - dashPat[j]; | |||
if (e < ystop) { | |||
e = ystop; | |||
} | |||
if (b < ystop) { | |||
b = ystop; | |||
} | |||
// es = e; | |||
// if (i == 0) { | |||
// es += firstDashAdjust; | |||
// } | |||
mr.draw([x, b], [x, e], this.canvas._ctx, opts); | |||
b -= dashPat[j]; | |||
if (j < dashPat.length-1) { | |||
b -= dashPat[j+1]; | |||
} | |||
} | |||
} | |||
} | |||
} | |||
break; | |||
default: | |||
break; | |||
} | |||
} | |||
} | |||
} | |||
}; | |||
// called within context of plot | |||
// create a canvas which we can draw on. | |||
// insert it before the eventCanvas, so eventCanvas will still capture events. | |||
$.jqplot.CanvasOverlay.postPlotDraw = function() { | |||
// Memory Leaks patch | |||
if (this.plugins.canvasOverlay && this.plugins.canvasOverlay.highlightCanvas) { | |||
this.plugins.canvasOverlay.highlightCanvas.resetCanvas(); | |||
this.plugins.canvasOverlay.highlightCanvas = null; | |||
} | |||
this.plugins.canvasOverlay.canvas = new $.jqplot.GenericCanvas(); | |||
this.eventCanvas._elem.before(this.plugins.canvasOverlay.canvas.createElement(this._gridPadding, 'jqplot-overlayCanvas-canvas', this._plotDimensions, this)); | |||
this.plugins.canvasOverlay.canvas.setContext(); | |||
if (!this.plugins.canvasOverlay.deferDraw) { | |||
this.plugins.canvasOverlay.draw(this); | |||
} | |||
}; | |||
$.jqplot.postInitHooks.push($.jqplot.CanvasOverlay.postPlotInit); | |||
$.jqplot.postDrawHooks.push($.jqplot.CanvasOverlay.postPlotDraw); | |||
})(jQuery); |
@@ -1,18 +1,30 @@ | |||
/** | |||
* Copyright (c) 2009 Chris Leonello | |||
* jqPlot | |||
* Pure JavaScript plotting plugin using jQuery | |||
* | |||
* Version: 1.0.0b2_r792 | |||
* | |||
* Copyright (c) 2009-2011 Chris Leonello | |||
* jqPlot is currently available for use in all personal or commercial projects | |||
* under both the MIT and GPL version 2.0 licenses. This means that you can | |||
* under both the MIT (http://www.opensource.org/licenses/mit-license.php) and GPL | |||
* version 2.0 (http://www.gnu.org/licenses/gpl-2.0.html) licenses. This means that you can | |||
* choose the license that best suits your project and use it accordingly. | |||
* | |||
* The author would appreciate an email letting him know of any substantial | |||
* use of jqPlot. You can reach the author at: chris dot leonello at gmail | |||
* dot com or see http://www.jqplot.com/info.php . This is, of course, | |||
* not required. | |||
* Although not required, the author would appreciate an email letting him | |||
* know of any substantial use of jqPlot. You can reach the author at: | |||
* chris at jqplot dot com or see http://www.jqplot.com/info.php . | |||
* | |||
* If you are feeling kind and generous, consider supporting the project by | |||
* making a donation at: http://www.jqplot.com/donate.php . | |||
* | |||
* Thanks for using jqPlot! | |||
* sprintf functions contained in jqplot.sprintf.js by Ash Searle: | |||
* | |||
* version 2007.04.27 | |||
* author Ash Searle | |||
* http://hexmen.com/blog/2007/03/printf-sprintf/ | |||
* http://hexmen.com/js/sprintf.js | |||
* The author (Ash Searle) has placed this code in the public domain: | |||
* "This code is unrestricted: you are free to use it however you like." | |||
* | |||
*/ | |||
(function($) { | |||
@@ -52,7 +64,7 @@ | |||
// returns float | |||
$.jqplot.CanvasTextRenderer.prototype.normalizeFontSize = function(sz) { | |||
sz = String(sz); | |||
n = parseFloat(sz); | |||
var n = parseFloat(sz); | |||
if (sz.indexOf('px') > -1) { | |||
return n/this.pt2px; | |||
} | |||
@@ -161,7 +173,7 @@ | |||
var total = 0; | |||
var len = str.length; | |||
for ( i = 0; i < len; i++) { | |||
for (var i = 0; i < len; i++) { | |||
var c = this.letter(str.charAt(i)); | |||
if (c) { | |||
total += c.width * this.normalizedFontSize / 25.0 * this.fontStretch; | |||
@@ -1,25 +1,36 @@ | |||
/** | |||
* Copyright (c) 2009 Chris Leonello | |||
* jqPlot | |||
* Pure JavaScript plotting plugin using jQuery | |||
* | |||
* Version: 1.0.0b2_r792 | |||
* | |||
* Copyright (c) 2009-2011 Chris Leonello | |||
* jqPlot is currently available for use in all personal or commercial projects | |||
* under both the MIT and GPL version 2.0 licenses. This means that you can | |||
* under both the MIT (http://www.opensource.org/licenses/mit-license.php) and GPL | |||
* version 2.0 (http://www.gnu.org/licenses/gpl-2.0.html) licenses. This means that you can | |||
* choose the license that best suits your project and use it accordingly. | |||
* | |||
* The author would appreciate an email letting him know of any substantial | |||
* use of jqPlot. You can reach the author at: chris dot leonello at gmail | |||
* dot com or see http://www.jqplot.com/info.php . This is, of course, | |||
* not required. | |||
* Although not required, the author would appreciate an email letting him | |||
* know of any substantial use of jqPlot. You can reach the author at: | |||
* chris at jqplot dot com or see http://www.jqplot.com/info.php . | |||
* | |||
* If you are feeling kind and generous, consider supporting the project by | |||
* making a donation at: http://www.jqplot.com/donate.php . | |||
* | |||
* Thanks for using jqPlot! | |||
* sprintf functions contained in jqplot.sprintf.js by Ash Searle: | |||
* | |||
* version 2007.04.27 | |||
* author Ash Searle | |||
* http://hexmen.com/blog/2007/03/printf-sprintf/ | |||
* http://hexmen.com/js/sprintf.js | |||
* The author (Ash Searle) has placed this code in the public domain: | |||
* "This code is unrestricted: you are free to use it however you like." | |||
* | |||
*/ | |||
(function($) { | |||
/** | |||
* class: $.jqplot.CategoryAxisRenderer | |||
* A plugin for jqPlot to render a category style axis, with equal pixel spacing between y data values of a series. | |||
* This renderer has no options beyond those supplied by the <Axis> class. | |||
* | |||
* To use this renderer, include the plugin in your source | |||
* > <script type="text/javascript" language="javascript" src="plugins/jqplot.categoryAxisRenderer.js"></script> | |||
@@ -28,14 +39,36 @@ | |||
* | |||
* > {axes:{xaxis:{renderer:$.jqplot.CategoryAxisRenderer}}} | |||
**/ | |||
$.jqplot.CategoryAxisRenderer = function() { | |||
$.jqplot.CategoryAxisRenderer = function(options) { | |||
$.jqplot.LinearAxisRenderer.call(this); | |||
// prop: sortMergedLabels | |||
// True to sort tick labels when labels are created by merging | |||
// x axis values from multiple series. That is, say you have | |||
// two series like: | |||
// > line1 = [[2006, 4], [2008, 9], [2009, 16]]; | |||
// > line2 = [[2006, 3], [2007, 7], [2008, 6]]; | |||
// If no label array is specified, tick labels will be collected | |||
// from the x values of the series. With sortMergedLabels | |||
// set to true, tick labels will be: | |||
// > [2006, 2007, 2008, 2009] | |||
// With sortMergedLabels set to false, tick labels will be: | |||
// > [2006, 2008, 2009, 2007] | |||
// | |||
// Note, this property is specified on the renderOptions for the | |||
// axes when creating a plot: | |||
// > axes:{xaxis:{renderer:$.jqplot.CategoryAxisRenderer, rendererOptions:{sortMergedLabels:true}}} | |||
this.sortMergedLabels = false; | |||
}; | |||
$.jqplot.CategoryAxisRenderer.prototype = new $.jqplot.LinearAxisRenderer(); | |||
$.jqplot.CategoryAxisRenderer.prototype.constructor = $.jqplot.CategoryAxisRenderer; | |||
$.jqplot.CategoryAxisRenderer.prototype.init = function(options){ | |||
this.groups = 1; | |||
this.groupLabels = []; | |||
this._groupLabels = []; | |||
this._grouped = false; | |||
this._barsPerGroup = null; | |||
// prop: tickRenderer | |||
// A class of a rendering engine for creating the ticks labels displayed on the plot, | |||
// See <$.jqplot.AxisTickRenderer>. | |||
@@ -47,6 +80,9 @@ | |||
// the min/max bounds for this axis. | |||
for (var i=0; i<this._series.length; i++) { | |||
var s = this._series[i]; | |||
if (s.groups) { | |||
this.groups = s.groups; | |||
} | |||
var d = s.data; | |||
for (var j=0; j<d.length; j++) { | |||
@@ -68,6 +104,10 @@ | |||
} | |||
} | |||
} | |||
if (this.groupLabels.length) { | |||
this.groups = this.groupLabels.length; | |||
} | |||
}; | |||
@@ -85,6 +125,17 @@ | |||
// if we already have ticks, use them. | |||
if (userTicks.length) { | |||
// adjust with blanks if we have groups | |||
if (this.groups > 1 && !this._grouped) { | |||
var l = userTicks.length; | |||
var skip = parseInt(l/this.groups, 10); | |||
var count = 0; | |||
for (var i=skip; i<l; i+=skip) { | |||
userTicks.splice(i+count, 0, ' '); | |||
count++; | |||
} | |||
this._grouped = true; | |||
} | |||
this.min = 0.5; | |||
this.max = userTicks.length + 0.5; | |||
var range = this.max - this.min; | |||
@@ -94,12 +145,12 @@ | |||
// need a marker before and after the tick | |||
var t = new this.tickRenderer(this.tickOptions); | |||
t.showLabel = false; | |||
t.showMark = true; | |||
// t.showMark = true; | |||
t.setTick(tt, this.name); | |||
this._ticks.push(t); | |||
var t = new this.tickRenderer(this.tickOptions); | |||
t.label = userTicks[i]; | |||
t.showLabel = true; | |||
// t.showLabel = true; | |||
t.showMark = false; | |||
t.showGridline = false; | |||
t.setTick(tt+0.5, this.name); | |||
@@ -108,7 +159,7 @@ | |||
// now add the last tick at the end | |||
var t = new this.tickRenderer(this.tickOptions); | |||
t.showLabel = false; | |||
t.showMark = true; | |||
// t.showMark = true; | |||
t.setTick(tt+1, this.name); | |||
this._ticks.push(t); | |||
} | |||
@@ -139,6 +190,7 @@ | |||
var numcats = 0; | |||
var min = 0.5; | |||
var max, val; | |||
var isMerged = false; | |||
for (var i=0; i<this._series.length; i++) { | |||
var s = this._series[i]; | |||
for (var j=0; j<s.data.length; j++) { | |||
@@ -149,12 +201,17 @@ | |||
val = s.data[j][1]; | |||
} | |||
if ($.inArray(val, labels) == -1) { | |||
isMerged = true; | |||
numcats += 1; | |||
labels.push(val); | |||
} | |||
} | |||
} | |||
if (isMerged && this.sortMergedLabels) { | |||
labels.sort(function(a,b) { return a - b; }); | |||
} | |||
// keep a reference to these tick labels to use for redrawing plot (see bug #57) | |||
this.ticks = labels; | |||
@@ -179,6 +236,17 @@ | |||
} | |||
} | |||
} | |||
// adjust with blanks if we have groups | |||
if (this.groups > 1 && !this._grouped) { | |||
var l = labels.length; | |||
var skip = parseInt(l/this.groups, 10); | |||
var count = 0; | |||
for (var i=skip; i<l; i+=skip+1) { | |||
labels[i] = ' '; | |||
} | |||
this._grouped = true; | |||
} | |||
max = numcats + 0.5; | |||
if (this.numberTicks == null) { | |||
@@ -221,18 +289,348 @@ | |||
t.showMark = false; | |||
t.showGridline = false; | |||
} | |||
if (!this.showTicks) { | |||
t.showLabel = false; | |||
t.showMark = false; | |||
} | |||
else if (!this.showTickMarks) { | |||
t.showMark = false; | |||
} | |||
t.setTick(tt, this.name); | |||
this._ticks.push(t); | |||
} | |||
} | |||
}; | |||
// called with scope of axis | |||
$.jqplot.CategoryAxisRenderer.prototype.draw = function(ctx, plot) { | |||
if (this.show) { | |||
// populate the axis label and value properties. | |||
// createTicks is a method on the renderer, but | |||
// call it within the scope of the axis. | |||
this.renderer.createTicks.call(this); | |||
// fill a div with axes labels in the right direction. | |||
// Need to pregenerate each axis to get it's bounds and | |||
// position it and the labels correctly on the plot. | |||
var dim=0; | |||
var temp; | |||
// Added for theming. | |||
if (this._elem) { | |||
// this._elem.empty(); | |||
// Memory Leaks patch | |||
this._elem.emptyForce(); | |||
} | |||
this._elem = this._elem || $('<div class="jqplot-axis jqplot-'+this.name+'" style="position:absolute;"></div>'); | |||
if (this.name == 'xaxis' || this.name == 'x2axis') { | |||
this._elem.width(this._plotDimensions.width); | |||
} | |||
else { | |||
this._elem.height(this._plotDimensions.height); | |||
} | |||
// create a _label object. | |||
this.labelOptions.axis = this.name; | |||
this._label = new this.labelRenderer(this.labelOptions); | |||
if (this._label.show) { | |||
var elem = this._label.draw(ctx, plot); | |||
elem.appendTo(this._elem); | |||
} | |||
var t = this._ticks; | |||
for (var i=0; i<t.length; i++) { | |||
var tick = t[i]; | |||
if (tick.showLabel && (!tick.isMinorTick || this.showMinorTicks)) { | |||
var elem = tick.draw(ctx, plot); | |||
elem.appendTo(this._elem); | |||
} | |||
} | |||
this._groupLabels = []; | |||
// now make group labels | |||
for (var i=0; i<this.groupLabels.length; i++) | |||
{ | |||
var elem = $('<div style="position:absolute;" class="jqplot-'+this.name+'-groupLabel"></div>'); | |||
elem.html(this.groupLabels[i]); | |||
this._groupLabels.push(elem); | |||
elem.appendTo(this._elem); | |||
} | |||
} | |||
return this._elem; | |||
}; | |||
// called with scope of axis | |||
$.jqplot.CategoryAxisRenderer.prototype.set = function() { | |||
var dim = 0; | |||
var temp; | |||
var w = 0; | |||
var h = 0; | |||
var lshow = (this._label == null) ? false : this._label.show; | |||
if (this.show) { | |||
var t = this._ticks; | |||
for (var i=0; i<t.length; i++) { | |||
var tick = t[i]; | |||
if (tick.showLabel && (!tick.isMinorTick || this.showMinorTicks)) { | |||
if (this.name == 'xaxis' || this.name == 'x2axis') { | |||
temp = tick._elem.outerHeight(true); | |||
} | |||
else { | |||
temp = tick._elem.outerWidth(true); | |||
} | |||
if (temp > dim) { | |||
dim = temp; | |||
} | |||
} | |||
} | |||
var dim2 = 0; | |||
for (var i=0; i<this._groupLabels.length; i++) { | |||
var l = this._groupLabels[i]; | |||
if (this.name == 'xaxis' || this.name == 'x2axis') { | |||
temp = l.outerHeight(true); | |||
} | |||
else { | |||
temp = l.outerWidth(true); | |||
} | |||
if (temp > dim2) { | |||
dim2 = temp; | |||
} | |||
} | |||
if (lshow) { | |||
w = this._label._elem.outerWidth(true); | |||
h = this._label._elem.outerHeight(true); | |||
} | |||
if (this.name == 'xaxis') { | |||
dim += dim2 + h; | |||
this._elem.css({'height':dim+'px', left:'0px', bottom:'0px'}); | |||
} | |||
else if (this.name == 'x2axis') { | |||
dim += dim2 + h; | |||
this._elem.css({'height':dim+'px', left:'0px', top:'0px'}); | |||
} | |||
else if (this.name == 'yaxis') { | |||
dim += dim2 + w; | |||
this._elem.css({'width':dim+'px', left:'0px', top:'0px'}); | |||
if (lshow && this._label.constructor == $.jqplot.AxisLabelRenderer) { | |||
this._label._elem.css('width', w+'px'); | |||
} | |||
} | |||
else { | |||
dim += dim2 + w; | |||
this._elem.css({'width':dim+'px', right:'0px', top:'0px'}); | |||
if (lshow && this._label.constructor == $.jqplot.AxisLabelRenderer) { | |||
this._label._elem.css('width', w+'px'); | |||
} | |||
} | |||
} | |||
}; | |||
// called with scope of axis | |||
$.jqplot.CategoryAxisRenderer.prototype.pack = function(pos, offsets) { | |||
var ticks = this._ticks; | |||
var max = this.max; | |||
var min = this.min; | |||
var offmax = offsets.max; | |||
var offmin = offsets.min; | |||
var lshow = (this._label == null) ? false : this._label.show; | |||
var i; | |||
for (var p in pos) { | |||
this._elem.css(p, pos[p]); | |||
} | |||
this._offsets = offsets; | |||
// pixellength will be + for x axes and - for y axes becasue pixels always measured from top left. | |||
var pixellength = offmax - offmin; | |||
var unitlength = max - min; | |||
// point to unit and unit to point conversions references to Plot DOM element top left corner. | |||
this.p2u = function(p){ | |||
return (p - offmin) * unitlength / pixellength + min; | |||
}; | |||
this.u2p = function(u){ | |||
return (u - min) * pixellength / unitlength + offmin; | |||
}; | |||
if (this.name == 'xaxis' || this.name == 'x2axis'){ | |||
this.series_u2p = function(u){ | |||
return (u - min) * pixellength / unitlength; | |||
}; | |||
this.series_p2u = function(p){ | |||
return p * unitlength / pixellength + min; | |||
}; | |||
} | |||
else { | |||
this.series_u2p = function(u){ | |||
return (u - max) * pixellength / unitlength; | |||
}; | |||
this.series_p2u = function(p){ | |||
return p * unitlength / pixellength + max; | |||
}; | |||
} | |||
if (this.show) { | |||
if (this.name == 'xaxis' || this.name == 'x2axis') { | |||
for (i=0; i<ticks.length; i++) { | |||
var t = ticks[i]; | |||
if (t.show && t.showLabel) { | |||
var shim; | |||
if (t.constructor == $.jqplot.CanvasAxisTickRenderer && t.angle) { | |||
// will need to adjust auto positioning based on which axis this is. | |||
var temp = (this.name == 'xaxis') ? 1 : -1; | |||
switch (t.labelPosition) { | |||
case 'auto': | |||
// position at end | |||
if (temp * t.angle < 0) { | |||
shim = -t.getWidth() + t._textRenderer.height * Math.sin(-t._textRenderer.angle) / 2; | |||
} | |||
// position at start | |||
else { | |||
shim = -t._textRenderer.height * Math.sin(t._textRenderer.angle) / 2; | |||
} | |||
break; | |||
case 'end': | |||
shim = -t.getWidth() + t._textRenderer.height * Math.sin(-t._textRenderer.angle) / 2; | |||
break; | |||
case 'start': | |||
shim = -t._textRenderer.height * Math.sin(t._textRenderer.angle) / 2; | |||
break; | |||
case 'middle': | |||
shim = -t.getWidth()/2 + t._textRenderer.height * Math.sin(-t._textRenderer.angle) / 2; | |||
break; | |||
default: | |||
shim = -t.getWidth()/2 + t._textRenderer.height * Math.sin(-t._textRenderer.angle) / 2; | |||
break; | |||
} | |||
} | |||
else { | |||
shim = -t.getWidth()/2; | |||
} | |||
var val = this.u2p(t.value) + shim + 'px'; | |||
t._elem.css('left', val); | |||
t.pack(); | |||
} | |||
} | |||
var labeledge=['bottom', 0]; | |||
if (lshow) { | |||
var w = this._label._elem.outerWidth(true); | |||
this._label._elem.css('left', offmin + pixellength/2 - w/2 + 'px'); | |||
if (this.name == 'xaxis') { | |||
this._label._elem.css('bottom', '0px'); | |||
labeledge = ['bottom', this._label._elem.outerHeight(true)]; | |||
} | |||
else { | |||
this._label._elem.css('top', '0px'); | |||
labeledge = ['top', this._label._elem.outerHeight(true)]; | |||
} | |||
this._label.pack(); | |||
} | |||
// draw the group labels | |||
var step = parseInt(this._ticks.length/this.groups, 10); | |||
for (i=0; i<this._groupLabels.length; i++) { | |||
var mid = 0; | |||
var count = 0; | |||
for (var j=i*step; j<=(i+1)*step; j++) { | |||
if (this._ticks[j]._elem && this._ticks[j].label != " ") { | |||
var t = this._ticks[j]._elem; | |||
var p = t.position(); | |||
mid += p.left + t.outerWidth(true)/2; | |||
count++; | |||
} | |||
} | |||
mid = mid/count; | |||
this._groupLabels[i].css({'left':(mid - this._groupLabels[i].outerWidth(true)/2)}); | |||
this._groupLabels[i].css(labeledge[0], labeledge[1]); | |||
} | |||
} | |||
else { | |||
for (i=0; i<ticks.length; i++) { | |||
var t = ticks[i]; | |||
if (t.show && t.showLabel) { | |||
var shim; | |||
if (t.constructor == $.jqplot.CanvasAxisTickRenderer && t.angle) { | |||
// will need to adjust auto positioning based on which axis this is. | |||
var temp = (this.name == 'yaxis') ? 1 : -1; | |||
switch (t.labelPosition) { | |||
case 'auto': | |||
// position at end | |||
case 'end': | |||
if (temp * t.angle < 0) { | |||
shim = -t._textRenderer.height * Math.cos(-t._textRenderer.angle) / 2; | |||
} | |||
else { | |||
shim = -t.getHeight() + t._textRenderer.height * Math.cos(t._textRenderer.angle) / 2; | |||
} | |||
break; | |||
case 'start': | |||
if (t.angle > 0) { | |||
shim = -t._textRenderer.height * Math.cos(-t._textRenderer.angle) / 2; | |||
} | |||
else { | |||
shim = -t.getHeight() + t._textRenderer.height * Math.cos(t._textRenderer.angle) / 2; | |||
} | |||
break; | |||
case 'middle': | |||
// if (t.angle > 0) { | |||
// shim = -t.getHeight()/2 + t._textRenderer.height * Math.sin(-t._textRenderer.angle) / 2; | |||
// } | |||
// else { | |||
// shim = -t.getHeight()/2 - t._textRenderer.height * Math.sin(t._textRenderer.angle) / 2; | |||
// } | |||
shim = -t.getHeight()/2; | |||
break; | |||
default: | |||
shim = -t.getHeight()/2; | |||
break; | |||
} | |||
} | |||
else { | |||
shim = -t.getHeight()/2; | |||
} | |||
var val = this.u2p(t.value) + shim + 'px'; | |||
t._elem.css('top', val); | |||
t.pack(); | |||
} | |||
} | |||
var labeledge=['left', 0]; | |||
if (lshow) { | |||
var h = this._label._elem.outerHeight(true); | |||
this._label._elem.css('top', offmax - pixellength/2 - h/2 + 'px'); | |||
if (this.name == 'yaxis') { | |||
this._label._elem.css('left', '0px'); | |||
labeledge = ['left', this._label._elem.outerWidth(true)]; | |||
} | |||
else { | |||
this._label._elem.css('right', '0px'); | |||
labeledge = ['right', this._label._elem.outerWidth(true)]; | |||
} | |||
this._label.pack(); | |||
} | |||
// draw the group labels, position top here, do left after label position. | |||
var step = parseInt(this._ticks.length/this.groups, 10); | |||
for (i=0; i<this._groupLabels.length; i++) { | |||
var mid = 0; | |||
var count = 0; | |||
for (var j=i*step; j<=(i+1)*step; j++) { | |||
if (this._ticks[j]._elem && this._ticks[j].label != " ") { | |||
var t = this._ticks[j]._elem; | |||
var p = t.position(); | |||
mid += p.top + t.outerHeight()/2; | |||
count++; | |||
} | |||
} | |||
mid = mid/count; | |||
this._groupLabels[i].css({'top':mid - this._groupLabels[i].outerHeight()/2}); | |||
this._groupLabels[i].css(labeledge[0], labeledge[1]); | |||
} | |||
} | |||
} | |||
}; | |||
})(jQuery); |
@@ -0,0 +1,115 @@ | |||
/** | |||
* jqPlot | |||
* Pure JavaScript plotting plugin using jQuery | |||
* | |||
* Version: 1.0.0b2_r792 | |||
* | |||
* Copyright (c) 2009-2011 Chris Leonello | |||
* jqPlot is currently available for use in all personal or commercial projects | |||
* under both the MIT (http://www.opensource.org/licenses/mit-license.php) and GPL | |||
* version 2.0 (http://www.gnu.org/licenses/gpl-2.0.html) licenses. This means that you can | |||
* choose the license that best suits your project and use it accordingly. | |||
* | |||
* Although not required, the author would appreciate an email letting him | |||
* know of any substantial use of jqPlot. You can reach the author at: | |||
* chris at jqplot dot com or see http://www.jqplot.com/info.php . | |||
* | |||
* If you are feeling kind and generous, consider supporting the project by | |||
* making a donation at: http://www.jqplot.com/donate.php . | |||
* | |||
* sprintf functions contained in jqplot.sprintf.js by Ash Searle: | |||
* | |||
* version 2007.04.27 | |||
* author Ash Searle | |||
* http://hexmen.com/blog/2007/03/printf-sprintf/ | |||
* http://hexmen.com/js/sprintf.js | |||
* The author (Ash Searle) has placed this code in the public domain: | |||
* "This code is unrestricted: you are free to use it however you like." | |||
* | |||
*/ | |||
(function($) { | |||
/** | |||
* Class: $.jqplot.ciParser | |||
* Data Renderer function which converts a custom JSON data object into jqPlot data format. | |||
* Set this as a callable on the jqplot dataRenderer plot option: | |||
* | |||
* > plot = $.jqplot('mychart', [data], { dataRenderer: $.jqplot.ciParser, ... }); | |||
* | |||
* Where data is an object in JSON format or a JSON encoded string conforming to the | |||
* City Index API spec. | |||
* | |||
* Note that calling the renderer function is handled internally by jqPlot. The | |||
* user does not have to call the function. The parameters described below will | |||
* automatically be passed to the ciParser function. | |||
* | |||
* Parameters: | |||
* data - JSON encoded string or object. | |||
* plot - reference to jqPlot Plot object. | |||
* | |||
* Returns: | |||
* data array in jqPlot format. | |||
* | |||
*/ | |||
$.jqplot.ciParser = function (data, plot) { | |||
var ret = [], | |||
line, | |||
temp, | |||
i, j, k, kk; | |||
if (typeof(data) == "string") { | |||
data = $.jqplot.JSON.parse(data, handleStrings); | |||
} | |||
else if (typeof(data) == "object") { | |||
for (k in data) { | |||
for (i=0; i<data[k].length; i++) { | |||
for (kk in data[k][i]) { | |||
data[k][i][kk] = handleStrings(kk, data[k][i][kk]); | |||
} | |||
} | |||
} | |||
} | |||
else { | |||
return null; | |||
} | |||
// function handleStrings | |||
// Checks any JSON encoded strings to see if they are | |||
// encoded dates. If so, pull out the timestamp. | |||
// Expects dates to be represented by js timestamps. | |||
function handleStrings(key, value) { | |||
var a; | |||
if (value != null) { | |||
if (value.toString().indexOf('Date') >= 0) { | |||
//here we will try to extract the ticks from the Date string in the "value" fields of JSON returned data | |||
a = /^\/Date\((-?[0-9]+)\)\/$/.exec(value); | |||
if (a) { | |||
return parseInt(a[1], 10); | |||
} | |||
} | |||
return value; | |||
} | |||
} | |||
for (var prop in data) { | |||
line = []; | |||
temp = data[prop]; | |||
switch (prop) { | |||
case "PriceTicks": | |||
for (i=0; i<temp.length; i++) { | |||
line.push([temp[i]['TickDate'], temp[i]['Price']]); | |||
} | |||
break; | |||
case "PriceBars": | |||
for (i=0; i<temp.length; i++) { | |||
line.push([temp[i]['BarDate'], temp[i]['Open'], temp[i]['High'], temp[i]['Low'], temp[i]['Close']]); | |||
} | |||
break; | |||
} | |||
ret.push(line); | |||
} | |||
return ret; | |||
}; | |||
})(jQuery); |
@@ -0,0 +1,30 @@ | |||
/** | |||
* jqPlot | |||
* Pure JavaScript plotting plugin using jQuery | |||
* | |||
* Version: 1.0.0b2_r792 | |||
* | |||
* Copyright (c) 2009-2011 Chris Leonello | |||
* jqPlot is currently available for use in all personal or commercial projects | |||
* under both the MIT (http://www.opensource.org/licenses/mit-license.php) and GPL | |||
* version 2.0 (http://www.gnu.org/licenses/gpl-2.0.html) licenses. This means that you can | |||
* choose the license that best suits your project and use it accordingly. | |||
* | |||
* Although not required, the author would appreciate an email letting him | |||
* know of any substantial use of jqPlot. You can reach the author at: | |||
* chris at jqplot dot com or see http://www.jqplot.com/info.php . | |||
* | |||
* If you are feeling kind and generous, consider supporting the project by | |||
* making a donation at: http://www.jqplot.com/donate.php . | |||
* | |||
* sprintf functions contained in jqplot.sprintf.js by Ash Searle: | |||
* | |||
* version 2007.04.27 | |||
* author Ash Searle | |||
* http://hexmen.com/blog/2007/03/printf-sprintf/ | |||
* http://hexmen.com/js/sprintf.js | |||
* The author (Ash Searle) has placed this code in the public domain: | |||
* "This code is unrestricted: you are free to use it however you like." | |||
* | |||
*/ | |||
(function(a){a.jqplot.ciParser=function(g,l){var m=[],o,n,h,f,e,c;if(typeof(g)=="string"){g=a.jqplot.JSON.parse(g,d)}else{if(typeof(g)=="object"){for(e in g){for(h=0;h<g[e].length;h++){for(c in g[e][h]){g[e][h][c]=d(c,g[e][h][c])}}}}else{return null}}function d(j,k){var i;if(k!=null){if(k.toString().indexOf("Date")>=0){i=/^\/Date\((-?[0-9]+)\)\/$/.exec(k);if(i){return parseInt(i[1],10)}}return k}}for(var b in g){o=[];n=g[b];switch(b){case"PriceTicks":for(h=0;h<n.length;h++){o.push([n[h]["TickDate"],n[h]["Price"]])}break;case"PriceBars":for(h=0;h<n.length;h++){o.push([n[h]["BarDate"],n[h]["Open"],n[h]["High"],n[h]["Low"],n[h]["Close"]])}break}m.push(o)}return m}})(jQuery); |
@@ -1,18 +1,30 @@ | |||
/** | |||
* Copyright (c) 2009 Chris Leonello | |||
* jqPlot | |||
* Pure JavaScript plotting plugin using jQuery | |||
* | |||
* Version: 1.0.0b2_r792 | |||
* | |||
* Copyright (c) 2009-2011 Chris Leonello | |||
* jqPlot is currently available for use in all personal or commercial projects | |||
* under both the MIT and GPL version 2.0 licenses. This means that you can | |||
* under both the MIT (http://www.opensource.org/licenses/mit-license.php) and GPL | |||
* version 2.0 (http://www.gnu.org/licenses/gpl-2.0.html) licenses. This means that you can | |||
* choose the license that best suits your project and use it accordingly. | |||
* | |||
* The author would appreciate an email letting him know of any substantial | |||
* use of jqPlot. You can reach the author at: chris dot leonello at gmail | |||
* dot com or see http://www.jqplot.com/info.php . This is, of course, | |||
* not required. | |||
* Although not required, the author would appreciate an email letting him | |||
* know of any substantial use of jqPlot. You can reach the author at: | |||
* chris at jqplot dot com or see http://www.jqplot.com/info.php . | |||
* | |||
* If you are feeling kind and generous, consider supporting the project by | |||
* making a donation at: http://www.jqplot.com/donate.php . | |||
* | |||
* Thanks for using jqPlot! | |||
* sprintf functions contained in jqplot.sprintf.js by Ash Searle: | |||
* | |||
* version 2007.04.27 | |||
* author Ash Searle | |||
* http://hexmen.com/blog/2007/03/printf-sprintf/ | |||
* http://hexmen.com/js/sprintf.js | |||
* The author (Ash Searle) has placed this code in the public domain: | |||
* "This code is unrestricted: you are free to use it however you like." | |||
* | |||
*/ | |||
(function($) { | |||
@@ -32,7 +44,8 @@ | |||
// wether to show the cursor or not. | |||
this.show = $.jqplot.config.enablePlugins; | |||
// prop: showTooltip | |||
// show a cursor position tooltip near the cursor | |||
// show a cursor position tooltip. Location of the tooltip | |||
// will be controlled by followMouse and tooltipLocation. | |||
this.showTooltip = true; | |||
// prop: followMouse | |||
// Tooltip follows the mouse, it is not at a fixed location. | |||
@@ -79,6 +92,10 @@ | |||
// They Will be set through call to zoomProxy method. | |||
this.zoomProxy = false; | |||
this.zoomTarget = false; | |||
// prop: looseZoom | |||
// Will expand zoom range to provide more rounded tick values. | |||
// Works only with linear axes and date axes. | |||
this.looseZoom = false; | |||
// prop: clickReset | |||
// Will reset plot zoom if single click on plot without drag. | |||
this.clickReset = false; | |||
@@ -101,7 +118,7 @@ | |||
// // auatoscale the adjacent axis. | |||
// this.autoscaleConstraint = true; | |||
this.shapeRenderer = new $.jqplot.ShapeRenderer(); | |||
this._zoom = {start:[], end:[], started: false, zooming:false, isZoomed:false, axes:{start:{}, end:{}}}; | |||
this._zoom = {start:[], end:[], started: false, zooming:false, isZoomed:false, axes:{start:{}, end:{}}, gridpos:{}, datapos:{}}; | |||
this._tooltipElem; | |||
this.zoomCanvas; | |||
this.cursorCanvas; | |||
@@ -116,6 +133,17 @@ | |||
// Format string used in the cursor legend. If showTooltipDataPosition is true, | |||
// this will also be the default format string used by tooltipFormatString. | |||
this.cursorLegendFormatString = $.jqplot.Cursor.cursorLegendFormatString; | |||
// whether the cursor is over the grid or not. | |||
this._oldHandlers = {onselectstart: null, ondrag: null, onmousedown: null}; | |||
// prop: constrainOutsideZoom | |||
// True to limit actual zoom area to edges of grid, even when zooming | |||
// outside of plot area. That is, can't zoom out by mousing outside plot. | |||
this.constrainOutsideZoom = true; | |||
// prop: showTooltipOutsideZoom | |||
// True will keep updating the tooltip when zooming of the grid. | |||
this.showTooltipOutsideZoom = false; | |||
// true if mouse is over grid, false if not. | |||
this.onGrid = false; | |||
$.extend(true, this, options); | |||
}; | |||
@@ -142,7 +170,6 @@ | |||
if (c.zoom) { | |||
$.jqplot.eventListenerHooks.push(['jqplotMouseDown', handleMouseDown]); | |||
$.jqplot.eventListenerHooks.push(['jqplotMouseUp', handleMouseUp]); | |||
if (c.clickReset) { | |||
$.jqplot.eventListenerHooks.push(['jqplotClick', handleClick]); | |||
@@ -150,7 +177,7 @@ | |||
if (c.dblClickReset) { | |||
$.jqplot.eventListenerHooks.push(['jqplotDblClick', handleDblClick]); | |||
} | |||
} | |||
} | |||
this.resetZoom = function() { | |||
@@ -158,12 +185,17 @@ | |||
if (!c.zoomProxy) { | |||
for (var ax in axes) { | |||
axes[ax].reset(); | |||
axes[ax]._ticks = []; | |||
// fake out tick creation algorithm to make sure original auto | |||
// computed format string is used if _overrideFormatString is true | |||
axes[ax]._autoFormatString = c._zoom.axes[ax].tickFormatString; | |||
} | |||
this.redraw(); | |||
} | |||
else { | |||
var ctx = this.plugins.cursor.zoomCanvas._ctx; | |||
ctx.clearRect(0,0,ctx.canvas.width, ctx.canvas.height); | |||
ctx = null; | |||
} | |||
this.plugins.cursor._zoom.isZoomed = false; | |||
this.target.trigger('jqplotResetZoom', [this, this.plugins.cursor]); | |||
@@ -183,17 +215,49 @@ | |||
// called with context of plot | |||
$.jqplot.Cursor.postDraw = function() { | |||
var c = this.plugins.cursor; | |||
// if (c.zoom) { | |||
c.zoomCanvas = new $.jqplot.GenericCanvas(); | |||
this.eventCanvas._elem.before(c.zoomCanvas.createElement(this._gridPadding, 'jqplot-zoom-canvas', this._plotDimensions)); | |||
var zctx = c.zoomCanvas.setContext(); | |||
// } | |||
c._tooltipElem = $('<div class="jqplot-cursor-tooltip" style="position:absolute;display:none"></div>'); | |||
c.zoomCanvas._elem.before(c._tooltipElem); | |||
// Memory Leaks patch | |||
if (c.zoomCanvas) { | |||
c.zoomCanvas.resetCanvas(); | |||
c.zoomCanvas = null; | |||
} | |||
if (c.cursorCanvas) { | |||
c.cursorCanvas.resetCanvas(); | |||
c.cursorCanvas = null; | |||
} | |||
if (c._tooltipElem) { | |||
c._tooltipElem.emptyForce(); | |||
c._tooltipElem = null; | |||
} | |||
if (c.zoom) { | |||
c.zoomCanvas = new $.jqplot.GenericCanvas(); | |||
this.eventCanvas._elem.before(c.zoomCanvas.createElement(this._gridPadding, 'jqplot-zoom-canvas', this._plotDimensions, this)); | |||
c.zoomCanvas.setContext(); | |||
} | |||
var elem = document.createElement('div'); | |||
c._tooltipElem = $(elem); | |||
elem = null; | |||
c._tooltipElem.addClass('jqplot-cursor-tooltip'); | |||
c._tooltipElem.css({position:'absolute', display:'none'}); | |||
if (c.zoomCanvas) { | |||
c.zoomCanvas._elem.before(c._tooltipElem); | |||
} | |||
else { | |||
this.eventCanvas._elem.before(c._tooltipElem); | |||
} | |||
if (c.showVerticalLine || c.showHorizontalLine) { | |||
c.cursorCanvas = new $.jqplot.GenericCanvas(); | |||
this.eventCanvas._elem.before(c.cursorCanvas.createElement(this._gridPadding, 'jqplot-cursor-canvas', this._plotDimensions)); | |||
var zctx = c.cursorCanvas.setContext(); | |||
this.eventCanvas._elem.before(c.cursorCanvas.createElement(this._gridPadding, 'jqplot-cursor-canvas', this._plotDimensions, this)); | |||
c.cursorCanvas.setContext(); | |||
} | |||
// if we are showing the positions in unit coordinates, and no axes groups | |||
@@ -252,13 +316,18 @@ | |||
var cax = cursor._zoom.axes; | |||
if (!plot.plugins.cursor.zoomProxy && cursor._zoom.isZoomed) { | |||
for (var ax in axes) { | |||
// axes[ax]._ticks = []; | |||
// axes[ax].min = cax[ax].min; | |||
// axes[ax].max = cax[ax].max; | |||
// axes[ax].numberTicks = cax[ax].numberTicks; | |||
// axes[ax].tickInterval = cax[ax].tickInterval; | |||
// // for date axes | |||
// axes[ax].daTickInterval = cax[ax].daTickInterval; | |||
axes[ax].reset(); | |||
axes[ax]._ticks = []; | |||
axes[ax].min = cax[ax].min; | |||
axes[ax].max = cax[ax].max; | |||
axes[ax].numberTicks = cax[ax].numberTicks; | |||
axes[ax].tickInterval = cax[ax].tickInterval; | |||
// for date axes | |||
axes[ax].daTickInterval = cax[ax].daTickInterval; | |||
// fake out tick creation algorithm to make sure original auto | |||
// computed format string is used if _overrideFormatString is true | |||
axes[ax]._autoFormatString = cax[ax].tickFormatString; | |||
} | |||
plot.redraw(); | |||
cursor._zoom.isZoomed = false; | |||
@@ -266,6 +335,7 @@ | |||
else { | |||
var ctx = cursor.zoomCanvas._ctx; | |||
ctx.clearRect(0,0,ctx.canvas.width, ctx.canvas.height); | |||
ctx = null; | |||
} | |||
plot.target.trigger('jqplotResetZoom', [plot, cursor]); | |||
}; | |||
@@ -280,9 +350,9 @@ | |||
var zaxes = c._zoom.axes; | |||
var start = zaxes.start; | |||
var end = zaxes.end; | |||
var min, max; | |||
var min, max, dp, span; | |||
var ctx = plot.plugins.cursor.zoomCanvas._ctx; | |||
// don't zoom is zoom area is too small (in pixels) | |||
// don't zoom if zoom area is too small (in pixels) | |||
if ((c.constrainZoomTo == 'none' && Math.abs(gridpos.x - c._zoom.start[0]) > 6 && Math.abs(gridpos.y - c._zoom.start[1]) > 6) || (c.constrainZoomTo == 'x' && Math.abs(gridpos.x - c._zoom.start[0]) > 6) || (c.constrainZoomTo == 'y' && Math.abs(gridpos.y - c._zoom.start[1]) > 6)) { | |||
if (!plot.plugins.cursor.zoomProxy) { | |||
for (var ax in datapos) { | |||
@@ -295,22 +365,42 @@ | |||
c._zoom.axes[ax].daTickInterval = axes[ax].daTickInterval; | |||
c._zoom.axes[ax].min = axes[ax].min; | |||
c._zoom.axes[ax].max = axes[ax].max; | |||
c._zoom.axes[ax].tickFormatString = (axes[ax].tickOptions != null) ? axes[ax].tickOptions.formatString : ''; | |||
} | |||
if ((c.constrainZoomTo == 'none') || (c.constrainZoomTo == 'x' && ax.charAt(0) == 'x') || (c.constrainZoomTo == 'y' && ax.charAt(0) == 'y')) { | |||
dp = datapos[ax]; | |||
if (dp != null) { | |||
if (dp != null) { | |||
var newmin, newmax; | |||
if (dp > start[ax]) { | |||
axes[ax].min = start[ax]; | |||
axes[ax].max = dp; | |||
newmin = start[ax]; | |||
newmax = dp; | |||
} | |||
else { | |||
span = start[ax] - dp; | |||
axes[ax].max = start[ax]; | |||
axes[ax].min = dp; | |||
newmin = dp; | |||
newmax = start[ax]; | |||
} | |||
axes[ax].tickInterval = null; | |||
// for date axes... | |||
axes[ax].daTickInterval = null; | |||
if (this.looseZoom && (axes[ax].renderer.constructor === $.jqplot.LinearAxisRenderer || axes[ax].renderer.constructor === $.jqplot.DateAxisRenderer)) { | |||
var ret = $.jqplot.LinearTickGenerator(newmin, newmax); | |||
axes[ax].min = ret[0]; | |||
axes[ax].max = ret[1]; | |||
axes[ax]._autoFormatString = ret[3]; | |||
axes[ax].numberTicks = ret[2]; | |||
axes[ax].tickInterval = ret[4]; | |||
// for date axes... | |||
axes[ax].daTickInterval = [ret[4]/1000, 'seconds']; | |||
} | |||
else { | |||
axes[ax].min = newmin; | |||
axes[ax].max = newmax; | |||
axes[ax].tickInterval = null; | |||
// for date axes... | |||
axes[ax].daTickInterval = null; | |||
} | |||
axes[ax]._ticks = []; | |||
} | |||
} | |||
@@ -326,6 +416,7 @@ | |||
ctx.clearRect(0,0,ctx.canvas.width, ctx.canvas.height); | |||
plot.redraw(); | |||
c._zoom.isZoomed = true; | |||
ctx = null; | |||
} | |||
plot.target.trigger('jqplotZoom', [gridpos, datapos, plot, cursor]); | |||
} | |||
@@ -445,11 +536,12 @@ | |||
} | |||
} | |||
} | |||
ctx = null; | |||
} | |||
function getIntersectingPoints(plot, x, y) { | |||
var ret = {indices:[], data:[]}; | |||
var s, i, d0, d, j, r; | |||
var s, i, d0, d, j, r, p; | |||
var threshold; | |||
var c = plot.plugins.cursor; | |||
for (var i=0; i<plot.series.length; i++) { | |||
@@ -517,8 +609,9 @@ | |||
break; | |||
} | |||
c._tooltipElem.css('left', x); | |||
c._tooltipElem.css('top', y); | |||
elem.css('left', x); | |||
elem.css('top', y); | |||
elem = null; | |||
} | |||
function positionTooltip(plot) { | |||
@@ -575,66 +668,83 @@ | |||
elem.css({right:a, bottom:b}); | |||
break; | |||
} | |||
elem = null; | |||
} | |||
function handleClick (ev, gridpos, datapos, neighbor, plot) { | |||
ev.stopPropagation(); | |||
ev.preventDefault(); | |||
ev.stopImmediatePropagation(); | |||
var c = plot.plugins.cursor; | |||
if (c.clickReset) { | |||
c.resetZoom(plot, c); | |||
} | |||
var sel = window.getSelection; | |||
if (document.selection && document.selection.empty) | |||
{ | |||
document.selection.empty(); | |||
} | |||
else if (sel && !sel().isCollapsed) { | |||
sel().collapse(); | |||
} | |||
return false; | |||
} | |||
function handleDblClick (ev, gridpos, datapos, neighbor, plot) { | |||
ev.stopPropagation(); | |||
ev.preventDefault(); | |||
ev.stopImmediatePropagation(); | |||
var c = plot.plugins.cursor; | |||
if (c.dblClickReset) { | |||
c.resetZoom(plot, c); | |||
} | |||
var sel = window.getSelection; | |||
if (document.selection && document.selection.empty) | |||
{ | |||
document.selection.empty(); | |||
} | |||
else if (sel && !sel().isCollapsed) { | |||
sel().collapse(); | |||
} | |||
return false; | |||
} | |||
function handleMouseLeave(ev, gridpos, datapos, neighbor, plot) { | |||
var c = plot.plugins.cursor; | |||
c.onGrid = false; | |||
if (c.show) { | |||
$(ev.target).css('cursor', c.previousCursor); | |||
if (c.showTooltip) { | |||
if (c.showTooltip && !(c._zoom.zooming && c.showTooltipOutsideZoom && !c.constrainOutsideZoom)) { | |||
c._tooltipElem.hide(); | |||
} | |||
if (c.zoom) { | |||
c._zoom.started = false; | |||
c._zoom.zooming = false; | |||
if (!c.zoomProxy) { | |||
var ctx = c.zoomCanvas._ctx; | |||
ctx.clearRect(0,0,ctx.canvas.width, ctx.canvas.height); | |||
} | |||
c._zoom.gridpos = gridpos; | |||
c._zoom.datapos = datapos; | |||
} | |||
if (c.showVerticalLine || c.showHorizontalLine) { | |||
var ctx = c.cursorCanvas._ctx; | |||
ctx.clearRect(0,0,ctx.canvas.width, ctx.canvas.height); | |||
} if (c.showCursorLegend) { | |||
var cells = $(plot.targetId + ' td.jqplot-cursor-legend-label'); | |||
for (var i=0; i<cells.length; i++) { | |||
var idx = $(cells[i]).data('seriesIndex'); | |||
var series = plot.series[idx]; | |||
var label = series.label.toString(); | |||
if (plot.legend.escapeHtml) { | |||
$(cells[i]).text($.jqplot.sprintf(c.cursorLegendFormatString, label, undefined, undefined)); | |||
} | |||
else { | |||
$(cells[i]).html($.jqplot.sprintf(c.cursorLegendFormatString, label, undefined, undefined)); | |||
} | |||
ctx = null; | |||
} | |||
if (c.showCursorLegend) { | |||
var cells = $(plot.targetId + ' td.jqplot-cursor-legend-label'); | |||
for (var i=0; i<cells.length; i++) { | |||
var idx = $(cells[i]).data('seriesIndex'); | |||
var series = plot.series[idx]; | |||
var label = series.label.toString(); | |||
if (plot.legend.escapeHtml) { | |||
$(cells[i]).text($.jqplot.sprintf(c.cursorLegendFormatString, label, undefined, undefined)); | |||
} | |||
else { | |||
$(cells[i]).html($.jqplot.sprintf(c.cursorLegendFormatString, label, undefined, undefined)); | |||
} | |||
} | |||
} | |||
} | |||
} | |||
} | |||
} | |||
function handleMouseEnter(ev, gridpos, datapos, neighbor, plot) { | |||
var c = plot.plugins.cursor; | |||
c.onGrid = true; | |||
if (c.show) { | |||
c.previousCursor = ev.target.style.cursor; | |||
ev.target.style.cursor = c.style; | |||
@@ -652,11 +762,11 @@ | |||
moveLine(gridpos, plot); | |||
} | |||
} | |||
} | |||
} | |||
function handleMouseMove(ev, gridpos, datapos, neighbor, plot) { | |||
var c = plot.plugins.cursor; | |||
var ctx = c.zoomCanvas._ctx; | |||
if (c.show) { | |||
if (c.showTooltip) { | |||
updateTooltip(gridpos, datapos, plot); | |||
@@ -664,32 +774,95 @@ | |||
moveTooltip(gridpos, plot); | |||
} | |||
} | |||
if (c.zoom && c._zoom.started && !c.zoomTarget) { | |||
c._zoom.zooming = true; | |||
if (c.constrainZoomTo == 'x') { | |||
c._zoom.end = [gridpos.x, ctx.canvas.height]; | |||
} | |||
else if (c.constrainZoomTo == 'y') { | |||
c._zoom.end = [ctx.canvas.width, gridpos.y]; | |||
} | |||
else { | |||
c._zoom.end = [gridpos.x, gridpos.y]; | |||
} | |||
drawZoomBox.call(c); | |||
} | |||
if (c.showVerticalLine || c.showHorizontalLine) { | |||
moveLine(gridpos, plot); | |||
} | |||
} | |||
} | |||
function getEventPosition(ev) { | |||
var plot = ev.data.plot; | |||
var go = plot.eventCanvas._elem.offset(); | |||
var gridPos = {x:ev.pageX - go.left, y:ev.pageY - go.top}; | |||
var dataPos = {xaxis:null, yaxis:null, x2axis:null, y2axis:null, y3axis:null, y4axis:null, y5axis:null, y6axis:null, y7axis:null, y8axis:null, y9axis:null}; | |||
var an = ['xaxis', 'yaxis', 'x2axis', 'y2axis', 'y3axis', 'y4axis', 'y5axis', 'y6axis', 'y7axis', 'y8axis', 'y9axis']; | |||
var ax = plot.axes; | |||
var n, axis; | |||
for (n=11; n>0; n--) { | |||
axis = an[n-1]; | |||
if (ax[axis].show) { | |||
dataPos[axis] = ax[axis].series_p2u(gridPos[axis.charAt(0)]); | |||
} | |||
} | |||
return {offsets:go, gridPos:gridPos, dataPos:dataPos}; | |||
} | |||
function handleZoomMove(ev) { | |||
var plot = ev.data.plot; | |||
var c = plot.plugins.cursor; | |||
// don't do anything if not on grid. | |||
if (c.show && c.zoom && c._zoom.started && !c.zoomTarget) { | |||
var ctx = c.zoomCanvas._ctx; | |||
var positions = getEventPosition(ev); | |||
var gridpos = positions.gridPos; | |||
var datapos = positions.dataPos; | |||
c._zoom.gridpos = gridpos; | |||
c._zoom.datapos = datapos; | |||
c._zoom.zooming = true; | |||
var xpos = gridpos.x; | |||
var ypos = gridpos.y; | |||
var height = ctx.canvas.height; | |||
var width = ctx.canvas.width; | |||
if (c.showTooltip && !c.onGrid && c.showTooltipOutsideZoom) { | |||
updateTooltip(gridpos, datapos, plot); | |||
if (c.followMouse) { | |||
moveTooltip(gridpos, plot); | |||
} | |||
} | |||
if (c.constrainZoomTo == 'x') { | |||
c._zoom.end = [xpos, height]; | |||
} | |||
else if (c.constrainZoomTo == 'y') { | |||
c._zoom.end = [width, ypos]; | |||
} | |||
else { | |||
c._zoom.end = [xpos, ypos]; | |||
} | |||
var sel = window.getSelection; | |||
if (document.selection && document.selection.empty) | |||
{ | |||
document.selection.empty(); | |||
} | |||
else if (sel && !sel().isCollapsed) { | |||
sel().collapse(); | |||
} | |||
drawZoomBox.call(c); | |||
ctx = null; | |||
} | |||
} | |||
function handleMouseDown(ev, gridpos, datapos, neighbor, plot) { | |||
var c = plot.plugins.cursor; | |||
$(document).one('mouseup.jqplot_cursor', {plot:plot}, handleMouseUp); | |||
var axes = plot.axes; | |||
if (document.onselectstart != undefined) { | |||
c._oldHandlers.onselectstart = document.onselectstart; | |||
document.onselectstart = function () { return false; }; | |||
} | |||
if (document.ondrag != undefined) { | |||
c._oldHandlers.ondrag = document.ondrag; | |||
document.ondrag = function () { return false; }; | |||
} | |||
if (document.onmousedown != undefined) { | |||
c._oldHandlers.onmousedown = document.onmousedown; | |||
document.onmousedown = function () { return false; }; | |||
} | |||
if (c.zoom) { | |||
if (!c.zoomProxy) { | |||
var ctx = c.zoomCanvas._ctx; | |||
ctx.clearRect(0,0,ctx.canvas.width, ctx.canvas.height); | |||
ctx = null; | |||
} | |||
if (c.constrainZoomTo == 'x') { | |||
c._zoom.start = [gridpos.x, 0]; | |||
@@ -704,17 +877,69 @@ | |||
for (var ax in datapos) { | |||
// get zoom starting position. | |||
c._zoom.axes.start[ax] = datapos[ax]; | |||
} | |||
} | |||
$(document).bind('mousemove.jqplotCursor', {plot:plot}, handleZoomMove); | |||
} | |||
} | |||
function handleMouseUp(ev, gridpos, datapos, neighbor, plot) { | |||
function handleMouseUp(ev) { | |||
var plot = ev.data.plot; | |||
var c = plot.plugins.cursor; | |||
if (c.zoom && c._zoom.zooming && !c.zoomTarget) { | |||
c.doZoom(gridpos, datapos, plot, c); | |||
var xpos = c._zoom.gridpos.x; | |||
var ypos = c._zoom.gridpos.y; | |||
var datapos = c._zoom.datapos; | |||
var height = c.zoomCanvas._ctx.canvas.height; | |||
var width = c.zoomCanvas._ctx.canvas.width; | |||
var axes = plot.axes; | |||
if (c.constrainOutsideZoom && !c.onGrid) { | |||
if (xpos < 0) { xpos = 0; } | |||
else if (xpos > width) { xpos = width; } | |||
if (ypos < 0) { ypos = 0; } | |||
else if (ypos > height) { ypos = height; } | |||
for (var axis in datapos) { | |||
if (datapos[axis]) { | |||
if (axis.charAt(0) == 'x') { | |||
datapos[axis] = axes[axis].series_p2u(xpos); | |||
} | |||
else { | |||
datapos[axis] = axes[axis].series_p2u(ypos); | |||
} | |||
} | |||
} | |||
} | |||
if (c.constrainZoomTo == 'x') { | |||
ypos = height; | |||
} | |||
else if (c.constrainZoomTo == 'y') { | |||
xpos = width; | |||
} | |||
c._zoom.end = [xpos, ypos]; | |||
c._zoom.gridpos = {x:xpos, y:ypos}; | |||
c.doZoom(c._zoom.gridpos, datapos, plot, c); | |||
} | |||
c._zoom.started = false; | |||
c._zoom.zooming = false; | |||
$(document).unbind('mousemove.jqplotCursor', handleZoomMove); | |||
if (document.onselectstart != undefined && c._oldHandlers.onselectstart != null){ | |||
document.onselectstart = c._oldHandlers.onselectstart; | |||
c._oldHandlers.onselectstart = null; | |||
} | |||
if (document.ondrag != undefined && c._oldHandlers.ondrag != null){ | |||
document.ondrag = c._oldHandlers.ondrag; | |||
c._oldHandlers.ondrag = null; | |||
} | |||
if (document.onmousedown != undefined && c._oldHandlers.onmousedown != null){ | |||
document.onmousedown = c._oldHandlers.onmousedown; | |||
c._oldHandlers.onmousedown = null; | |||
} | |||
} | |||
function drawZoomBox() { | |||
@@ -746,6 +971,7 @@ | |||
ctx.clearRect(l, t, w, h); | |||
// IE won't show transparent fill rect, so stroke a rect also. | |||
ctx.strokeRect(l,t,w,h); | |||
ctx = null; | |||
} | |||
$.jqplot.CursorLegendRenderer = function(options) { | |||
@@ -758,15 +984,23 @@ | |||
// called in context of a Legend | |||
$.jqplot.CursorLegendRenderer.prototype.draw = function() { | |||
if (this._elem) { | |||
this._elem.emptyForce(); | |||
this._elem = null; | |||
} | |||
if (this.show) { | |||
var series = this._series; | |||
var series = this._series, s; | |||
// make a table. one line label per row. | |||
this._elem = $('<table class="jqplot-legend jqplot-cursor-legend" style="position:absolute"></table>'); | |||
var elem = document.createElement('div'); | |||
this._elem = $(elem); | |||
elem = null; | |||
this._elem.addClass('jqplot-legend jqplot-cursor-legend'); | |||
this._elem.css('position', 'absolute'); | |||
var pad = false; | |||
for (var i = 0; i< series.length; i++) { | |||
s = series[i]; | |||
if (s.show) { | |||
if (s.show && s.showLabel) { | |||
var lt = $.jqplot.sprintf(this.formatString, s.label.toString()); | |||
if (lt) { | |||
var color = s.color; | |||
@@ -786,6 +1020,9 @@ | |||
} | |||
} | |||
} | |||
series = s = null; | |||
delete series; | |||
delete s; | |||
} | |||
function addrow(label, color, pad, idx) { | |||
@@ -805,6 +1042,8 @@ | |||
else { | |||
td.html(label); | |||
} | |||
tr = null; | |||
td = null; | |||
} | |||
return this._elem; | |||
}; | |||
@@ -1,18 +1,30 @@ | |||
/** | |||
* Copyright (c) 2009 Chris Leonello | |||
* jqPlot | |||
* Pure JavaScript plotting plugin using jQuery | |||
* | |||
* Version: 1.0.0b2_r792 | |||
* | |||
* Copyright (c) 2009-2011 Chris Leonello | |||
* jqPlot is currently available for use in all personal or commercial projects | |||
* under both the MIT and GPL version 2.0 licenses. This means that you can | |||
* under both the MIT (http://www.opensource.org/licenses/mit-license.php) and GPL | |||
* version 2.0 (http://www.gnu.org/licenses/gpl-2.0.html) licenses. This means that you can | |||
* choose the license that best suits your project and use it accordingly. | |||
* | |||
* The author would appreciate an email letting him know of any substantial | |||
* use of jqPlot. You can reach the author at: chris dot leonello at gmail | |||
* dot com or see http://www.jqplot.com/info.php . This is, of course, | |||
* not required. | |||
* Although not required, the author would appreciate an email letting him | |||
* know of any substantial use of jqPlot. You can reach the author at: | |||
* chris at jqplot dot com or see http://www.jqplot.com/info.php . | |||
* | |||
* If you are feeling kind and generous, consider supporting the project by | |||
* making a donation at: http://www.jqplot.com/donate.php . | |||
* | |||
* Thanks for using jqPlot! | |||
* sprintf functions contained in jqplot.sprintf.js by Ash Searle: | |||
* | |||
* version 2007.04.27 | |||
* author Ash Searle | |||
* http://hexmen.com/blog/2007/03/printf-sprintf/ | |||
* http://hexmen.com/js/sprintf.js | |||
* The author (Ash Searle) has placed this code in the public domain: | |||
* "This code is unrestricted: you are free to use it however you like." | |||
* | |||
*/ | |||
(function($) { | |||
@@ -94,6 +106,7 @@ | |||
*/ | |||
$.jqplot.DateAxisRenderer = function() { | |||
$.jqplot.LinearAxisRenderer.call(this); | |||
this.date = new $.jsDate(); | |||
}; | |||
$.jqplot.DateAxisRenderer.prototype = new $.jqplot.LinearAxisRenderer(); | |||
@@ -103,7 +116,7 @@ | |||
if (!format) { | |||
format = '%Y/%m/%d'; | |||
} | |||
return Date.create(val).strftime(format); | |||
return $.jsDate.strftime(val, format); | |||
}; | |||
$.jqplot.DateAxisRenderer.prototype.init = function(options){ | |||
@@ -115,41 +128,94 @@ | |||
this.tickOptions.formatter = $.jqplot.DateTickFormatter; | |||
this.daTickInterval = null; | |||
this._daTickInterval = null; | |||
$.extend(true, this, options); | |||
var db = this._dataBounds; | |||
var db = this._dataBounds, | |||
stats, | |||
sum, | |||
s, | |||
d, | |||
pd, | |||
sd, | |||
intv; | |||
// Go through all the series attached to this axis and find | |||
// the min/max bounds for this axis. | |||
for (var i=0; i<this._series.length; i++) { | |||
var s = this._series[i]; | |||
var d = s.data; | |||
var pd = s._plotData; | |||
var sd = s._stackData; | |||
stats = {intervals:[], frequencies:{}, sortedIntervals:[], min:null, max:null, mean:null}; | |||
sum = 0; | |||
s = this._series[i]; | |||
d = s.data; | |||
pd = s._plotData; | |||
sd = s._stackData; | |||
intv = 0; | |||
for (var j=0; j<d.length; j++) { | |||
if (this.name == 'xaxis' || this.name == 'x2axis') { | |||
d[j][0] = Date.create(d[j][0]).getTime(); | |||
pd[j][0] = Date.create(d[j][0]).getTime(); | |||
sd[j][0] = Date.create(d[j][0]).getTime(); | |||
if (d[j][0] < db.min || db.min == null) { | |||
d[j][0] = new $.jsDate(d[j][0]).getTime(); | |||
pd[j][0] = new $.jsDate(d[j][0]).getTime(); | |||
sd[j][0] = new $.jsDate(d[j][0]).getTime(); | |||
if ((d[j][0] != null && d[j][0] < db.min) || db.min == null) { | |||
db.min = d[j][0]; | |||
} | |||
if (d[j][0] > db.max || db.max == null) { | |||
if ((d[j][0] != null && d[j][0] > db.max) || db.max == null) { | |||
db.max = d[j][0]; | |||
} | |||
if (j>0) { | |||
intv = Math.abs(d[j][0] - d[j-1][0]); | |||
stats.intervals.push(intv); | |||
if (stats.frequencies.hasOwnProperty(intv)) { | |||
stats.frequencies[intv] += 1; | |||
} | |||
else { | |||
stats.frequencies[intv] = 1; | |||
} | |||
} | |||
sum += intv; | |||
} | |||
else { | |||
d[j][1] = Date.create(d[j][1]).getTime(); | |||
pd[j][1] = Date.create(d[j][1]).getTime(); | |||
sd[j][1] = Date.create(d[j][1]).getTime(); | |||
if (d[j][1] < db.min || db.min == null) { | |||
d[j][1] = new $.jsDate(d[j][1]).getTime(); | |||
pd[j][1] = new $.jsDate(d[j][1]).getTime(); | |||
sd[j][1] = new $.jsDate(d[j][1]).getTime(); | |||
if ((d[j][1] != null && d[j][1] < db.min) || db.min == null) { | |||
db.min = d[j][1]; | |||
} | |||
if (d[j][1] > db.max || db.max == null) { | |||
if ((d[j][1] != null && d[j][1] > db.max) || db.max == null) { | |||
db.max = d[j][1]; | |||
} | |||
} | |||
if (j>0) { | |||
intv = Math.abs(d[j][1] - d[j-1][1]); | |||
stats.intervals.push(intv); | |||
if (stats.frequencies.hasOwnProperty(intv)) { | |||
stats.frequencies[intv] += 1; | |||
} | |||
else { | |||
stats.frequencies[intv] = 1; | |||
} | |||
} | |||
} | |||
sum += intv; | |||
} | |||
var tempf = 0, | |||
tempn=0; | |||
for (var n in stats.frequencies) { | |||
stats.sortedIntervals.push({interval:n, frequency:stats.frequencies[n]}); | |||
} | |||
stats.sortedIntervals.sort(function(a, b){ | |||
return b.frequency - a.frequency; | |||
}); | |||
stats.min = $.jqplot.arrayMin(stats.intervals); | |||
stats.max = $.jqplot.arrayMax(stats.intervals); | |||
stats.mean = sum/d.length; | |||
this._intervalStats.push(stats); | |||
stats = sum = s = d = pd = sd = null; | |||
} | |||
db = null; | |||
}; | |||
// called with scope of an axis | |||
@@ -169,6 +235,7 @@ | |||
var name = this.name; | |||
// databounds were set on axis initialization. | |||
var db = this._dataBounds; | |||
var iv = this._intervalStats; | |||
var dim, interval; | |||
var min, max; | |||
var pos1, pos2; | |||
@@ -177,13 +244,18 @@ | |||
// if we already have ticks, use them. | |||
// ticks must be in order of increasing value. | |||
min = ((this.min != null) ? new $.jsDate(this.min).getTime() : db.min); | |||
max = ((this.max != null) ? new $.jsDate(this.max).getTime() : db.max); | |||
var range = max - min; | |||
if (userTicks.length) { | |||
// ticks could be 1D or 2D array of [val, val, ,,,] or [[val, label], [val, label], ...] or mixed | |||
for (i=0; i<userTicks.length; i++){ | |||
var ut = userTicks[i]; | |||
var t = new this.tickRenderer(this.tickOptions); | |||
if (ut.constructor == Array) { | |||
t.value = Date.create(ut[0]).getTime(); | |||
t.value = new $.jsDate(ut[0]).getTime(); | |||
t.label = ut[1]; | |||
if (!this.showTicks) { | |||
t.showLabel = false; | |||
@@ -197,7 +269,7 @@ | |||
} | |||
else { | |||
t.value = Date.create(ut).getTime(); | |||
t.value = new $.jsDate(ut).getTime(); | |||
if (!this.showTicks) { | |||
t.showLabel = false; | |||
t.showMark = false; | |||
@@ -214,16 +286,61 @@ | |||
this.max = this._ticks[this.numberTicks-1].value; | |||
this.daTickInterval = [(this.max - this.min) / (this.numberTicks - 1)/1000, 'seconds']; | |||
} | |||
//////// | |||
// We don't have any ticks yet, let's make some! | |||
// Doing complete autoscaling, no user options specified | |||
//////// | |||
// we don't have any ticks yet, let's make some! | |||
else { | |||
else if (this.tickInterval == null && this.min == null && this.max == null && this.numberTicks == null) { | |||
var ret = $.jqplot.LinearTickGenerator(min, max); | |||
// calculate a padded max and min, points should be less than these | |||
// so that they aren't too close to the edges of the plot. | |||
// User can adjust how much padding is allowed with pad, padMin and PadMax options. | |||
var tumin = min + range*(this.padMin - 1); | |||
var tumax = max - range*(this.padMax - 1); | |||
if (min <=tumin || max >= tumax) { | |||
tumin = min - range*(this.padMin - 1); | |||
tumax = max + range*(this.padMax - 1); | |||
ret = $.jqplot.LinearTickGenerator(tumin, tumax); | |||
} | |||
this.min = ret[0]; | |||
this.max = ret[1]; | |||
this.numberTicks = ret[2]; | |||
this.tickInterval = ret[4]; | |||
this.daTickInterval = [this.tickInterval/1000, 'seconds']; | |||
for (var i=0; i<this.numberTicks; i++){ | |||
var min = new $.jsDate(this.min); | |||
tt = min.add(i*this.daTickInterval[0], this.daTickInterval[1]).getTime(); | |||
var t = new this.tickRenderer(this.tickOptions); | |||
// var t = new $.jqplot.AxisTickRenderer(this.tickOptions); | |||
if (!this.showTicks) { | |||
t.showLabel = false; | |||
t.showMark = false; | |||
} | |||
else if (!this.showTickMarks) { | |||
t.showMark = false; | |||
} | |||
t.setTick(tt, this.name); | |||
this._ticks.push(t); | |||
} | |||
} | |||
//////// | |||
// Some option(s) specified, work around that. | |||
//////// | |||
else { | |||
if (name == 'xaxis' || name == 'x2axis') { | |||
dim = this._plotDimensions.width; | |||
} | |||
else { | |||
dim = this._plotDimensions.height; | |||
} | |||
// if min, max and number of ticks specified, user can't specify interval. | |||
if (this.min != null && this.max != null && this.numberTicks != null) { | |||
this.tickInterval = null; | |||
@@ -248,9 +365,6 @@ | |||
} | |||
} | |||
} | |||
min = ((this.min != null) ? Date.create(this.min).getTime() : db.min); | |||
max = ((this.max != null) ? Date.create(this.max).getTime() : db.max); | |||
// if min and max are same, space them out a bit | |||
if (min == max) { | |||
@@ -259,11 +373,21 @@ | |||
max += adj; | |||
} | |||
var range = max - min; | |||
range = max - min; | |||
var optNumTicks = 2 + parseInt(Math.max(0, dim-100)/100, 10); | |||
// Here try to set ticks based on data spacing. | |||
// if (this.min == null && this.max == null && this.numberTicks == null && this.tickInterval == null) { | |||
// // | |||
// } | |||
var rmin, rmax; | |||
rmin = (this.min != null) ? Date.create(this.min).getTime() : min - range/2*(this.padMin - 1); | |||
rmax = (this.max != null) ? Date.create(this.max).getTime() : max + range/2*(this.padMax - 1); | |||
rmin = (this.min != null) ? new $.jsDate(this.min).getTime() : min - range/2*(this.padMin - 1); | |||
rmax = (this.max != null) ? new $.jsDate(this.max).getTime() : max + range/2*(this.padMax - 1); | |||
this.min = rmin; | |||
this.max = rmax; | |||
range = this.max - this.min; | |||
@@ -272,10 +396,10 @@ | |||
// if tickInterval is specified by user, we will ignore computed maximum. | |||
// max will be equal or greater to fit even # of ticks. | |||
if (this.daTickInterval != null) { | |||
var nc = Date.create(this.max).diff(this.min, this.daTickInterval[1], true); | |||
var nc = new $.jsDate(this.max).diff(this.min, this.daTickInterval[1], true); | |||
this.numberTicks = Math.ceil(nc/this.daTickInterval[0]) +1; | |||
// this.max = Date.create(this.min).add(this.numberTicks-1, this.daTickInterval[1]).getTime(); | |||
this.max = Date.create(this.min).add((this.numberTicks-1) * this.daTickInterval[0], this.daTickInterval[1]).getTime(); | |||
// this.max = new $.jsDate(this.min).add(this.numberTicks-1, this.daTickInterval[1]).getTime(); | |||
this.max = new $.jsDate(this.min).add((this.numberTicks-1) * this.daTickInterval[0], this.daTickInterval[1]).getTime(); | |||
} | |||
else if (dim > 200) { | |||
this.numberTicks = parseInt(3+(dim-200)/100, 10); | |||
@@ -289,7 +413,7 @@ | |||
this.daTickInterval = [range / (this.numberTicks-1)/1000, 'seconds']; | |||
} | |||
for (var i=0; i<this.numberTicks; i++){ | |||
var min = Date.create(this.min); | |||
var min = new $.jsDate(this.min); | |||
tt = min.add(i*this.daTickInterval[0], this.daTickInterval[1]).getTime(); | |||
var t = new this.tickRenderer(this.tickOptions); | |||
// var t = new $.jqplot.AxisTickRenderer(this.tickOptions); | |||
@@ -304,6 +428,8 @@ | |||
this._ticks.push(t); | |||
} | |||
} | |||
if (this._daTickInterval == null) { | |||
this._daTickInterval = this.daTickInterval; | |||
} | |||
@@ -0,0 +1,910 @@ | |||
/** | |||
* jqPlot | |||
* Pure JavaScript plotting plugin using jQuery | |||
* | |||
* Version: 1.0.0b2_r792 | |||
* | |||
* Copyright (c) 2009-2011 Chris Leonello | |||
* jqPlot is currently available for use in all personal or commercial projects | |||
* under both the MIT (http://www.opensource.org/licenses/mit-license.php) and GPL | |||
* version 2.0 (http://www.gnu.org/licenses/gpl-2.0.html) licenses. This means that you can | |||
* choose the license that best suits your project and use it accordingly. | |||
* | |||
* Although not required, the author would appreciate an email letting him | |||
* know of any substantial use of jqPlot. You can reach the author at: | |||
* chris at jqplot dot com or see http://www.jqplot.com/info.php . | |||
* | |||
* If you are feeling kind and generous, consider supporting the project by | |||
* making a donation at: http://www.jqplot.com/donate.php . | |||
* | |||
* sprintf functions contained in jqplot.sprintf.js by Ash Searle: | |||
* | |||
* version 2007.04.27 | |||
* author Ash Searle | |||
* http://hexmen.com/blog/2007/03/printf-sprintf/ | |||
* http://hexmen.com/js/sprintf.js | |||
* The author (Ash Searle) has placed this code in the public domain: | |||
* "This code is unrestricted: you are free to use it however you like." | |||
* | |||
*/ | |||
(function($) { | |||
/** | |||
* Class: $.jqplot.DonutRenderer | |||
* Plugin renderer to draw a donut chart. | |||
* x values, if present, will be used as slice labels. | |||
* y values give slice size. | |||
* | |||
* To use this renderer, you need to include the | |||
* donut renderer plugin, for example: | |||
* | |||
* > <script type="text/javascript" src="plugins/jqplot.donutRenderer.js"></script> | |||
* | |||
* Properties described here are passed into the $.jqplot function | |||
* as options on the series renderer. For example: | |||
* | |||
* > plot2 = $.jqplot('chart2', [s1, s2], { | |||
* > seriesDefaults: { | |||
* > renderer:$.jqplot.DonutRenderer, | |||
* > rendererOptions:{ | |||
* > sliceMargin: 2, | |||
* > innerDiameter: 110, | |||
* > startAngle: -90 | |||
* > } | |||
* > } | |||
* > }); | |||
* | |||
* A donut plot will trigger events on the plot target | |||
* according to user interaction. All events return the event object, | |||
* the series index, the point (slice) index, and the point data for | |||
* the appropriate slice. | |||
* | |||
* 'jqplotDataMouseOver' - triggered when user mouseing over a slice. | |||
* 'jqplotDataHighlight' - triggered the first time user mouses over a slice, | |||
* if highlighting is enabled. | |||
* 'jqplotDataUnhighlight' - triggered when a user moves the mouse out of | |||
* a highlighted slice. | |||
* 'jqplotDataClick' - triggered when the user clicks on a slice. | |||
* 'jqplotDataRightClick' - tiggered when the user right clicks on a slice if | |||
* the "captureRightClick" option is set to true on the plot. | |||
*/ | |||
$.jqplot.DonutRenderer = function(){ | |||
$.jqplot.LineRenderer.call(this); | |||
}; | |||
$.jqplot.DonutRenderer.prototype = new $.jqplot.LineRenderer(); | |||
$.jqplot.DonutRenderer.prototype.constructor = $.jqplot.DonutRenderer; | |||
// called with scope of a series | |||
$.jqplot.DonutRenderer.prototype.init = function(options, plot) { | |||
// Group: Properties | |||
// | |||
// prop: diameter | |||
// Outer diameter of the donut, auto computed by default | |||
this.diameter = null; | |||
// prop: innerDiameter | |||
// Inner diameter of the donut, auto calculated by default. | |||
// If specified will override thickness value. | |||
this.innerDiameter = null; | |||
// prop: thickness | |||
// thickness of the donut, auto computed by default | |||
// Overridden by if innerDiameter is specified. | |||
this.thickness = null; | |||
// prop: padding | |||
// padding between the donut and plot edges, legend, etc. | |||
this.padding = 20; | |||
// prop: sliceMargin | |||
// angular spacing between donut slices in degrees. | |||
this.sliceMargin = 0; | |||
// prop: ringMargin | |||
// pixel distance between rings, or multiple series in a donut plot. | |||
// null will compute ringMargin based on sliceMargin. | |||
this.ringMargin = null; | |||
// prop: fill | |||
// true or false, wether to fil the slices. | |||
this.fill = true; | |||
// prop: shadowOffset | |||
// offset of the shadow from the slice and offset of | |||
// each succesive stroke of the shadow from the last. | |||
this.shadowOffset = 2; | |||
// prop: shadowAlpha | |||
// transparency of the shadow (0 = transparent, 1 = opaque) | |||
this.shadowAlpha = 0.07; | |||
// prop: shadowDepth | |||
// number of strokes to apply to the shadow, | |||
// each stroke offset shadowOffset from the last. | |||
this.shadowDepth = 5; | |||
// prop: highlightMouseOver | |||
// True to highlight slice when moused over. | |||
// This must be false to enable highlightMouseDown to highlight when clicking on a slice. | |||
this.highlightMouseOver = true; | |||
// prop: highlightMouseDown | |||
// True to highlight when a mouse button is pressed over a slice. | |||
// This will be disabled if highlightMouseOver is true. | |||
this.highlightMouseDown = false; | |||
// prop: highlightColors | |||
// an array of colors to use when highlighting a slice. | |||
this.highlightColors = []; | |||
// prop: dataLabels | |||
// Either 'label', 'value', 'percent' or an array of labels to place on the pie slices. | |||
// Defaults to percentage of each pie slice. | |||
this.dataLabels = 'percent'; | |||
// prop: showDataLabels | |||
// true to show data labels on slices. | |||
this.showDataLabels = false; | |||
// prop: dataLabelFormatString | |||
// Format string for data labels. If none, '%s' is used for "label" and for arrays, '%d' for value and '%d%%' for percentage. | |||
this.dataLabelFormatString = null; | |||
// prop: dataLabelThreshold | |||
// Threshhold in percentage (0 - 100) of pie area, below which no label will be displayed. | |||
// This applies to all label types, not just to percentage labels. | |||
this.dataLabelThreshold = 3; | |||
// prop: dataLabelPositionFactor | |||
// A Multiplier (0-1) of the pie radius which controls position of label on slice. | |||
// Increasing will slide label toward edge of pie, decreasing will slide label toward center of pie. | |||
this.dataLabelPositionFactor = 0.4; | |||
// prop: dataLabelNudge | |||
// Number of pixels to slide the label away from (+) or toward (-) the center of the pie. | |||
this.dataLabelNudge = 0; | |||
// prop: startAngle | |||
// Angle to start drawing donut in degrees. | |||
// According to orientation of canvas coordinate system: | |||
// 0 = on the positive x axis | |||
// -90 = on the positive y axis. | |||
// 90 = on the negaive y axis. | |||
// 180 or - 180 = on the negative x axis. | |||
this.startAngle = 0; | |||
this.tickRenderer = $.jqplot.DonutTickRenderer; | |||
// Used as check for conditions where donut shouldn't be drawn. | |||
this._drawData = true; | |||
this._type = 'donut'; | |||
// if user has passed in highlightMouseDown option and not set highlightMouseOver, disable highlightMouseOver | |||
if (options.highlightMouseDown && options.highlightMouseOver == null) { | |||
options.highlightMouseOver = false; | |||
} | |||
$.extend(true, this, options); | |||
if (this.diameter != null) { | |||
this.diameter = this.diameter - this.sliceMargin; | |||
} | |||
this._diameter = null; | |||
this._innerDiameter = null; | |||
this._radius = null; | |||
this._innerRadius = null; | |||
this._thickness = null; | |||
// references to the previous series in the plot to properly calculate diameters | |||
// and thicknesses of nested rings. | |||
this._previousSeries = []; | |||
this._numberSeries = 1; | |||
// array of [start,end] angles arrays, one for each slice. In radians. | |||
this._sliceAngles = []; | |||
// index of the currenty highlighted point, if any | |||
this._highlightedPoint = null; | |||
// set highlight colors if none provided | |||
if (this.highlightColors.length == 0) { | |||
for (var i=0; i<this.seriesColors.length; i++){ | |||
var rgba = $.jqplot.getColorComponents(this.seriesColors[i]); | |||
var newrgb = [rgba[0], rgba[1], rgba[2]]; | |||
var sum = newrgb[0] + newrgb[1] + newrgb[2]; | |||
for (var j=0; j<3; j++) { | |||
// when darkening, lowest color component can be is 60. | |||
newrgb[j] = (sum > 570) ? newrgb[j] * 0.8 : newrgb[j] + 0.3 * (255 - newrgb[j]); | |||
newrgb[j] = parseInt(newrgb[j], 10); | |||
} | |||
this.highlightColors.push('rgb('+newrgb[0]+','+newrgb[1]+','+newrgb[2]+')'); | |||
} | |||
} | |||
plot.postParseOptionsHooks.addOnce(postParseOptions); | |||
plot.postInitHooks.addOnce(postInit); | |||
plot.eventListenerHooks.addOnce('jqplotMouseMove', handleMove); | |||
plot.eventListenerHooks.addOnce('jqplotMouseDown', handleMouseDown); | |||
plot.eventListenerHooks.addOnce('jqplotMouseUp', handleMouseUp); | |||
plot.eventListenerHooks.addOnce('jqplotClick', handleClick); | |||
plot.eventListenerHooks.addOnce('jqplotRightClick', handleRightClick); | |||
plot.postDrawHooks.addOnce(postPlotDraw); | |||
}; | |||
$.jqplot.DonutRenderer.prototype.setGridData = function(plot) { | |||
// set gridData property. This will hold angle in radians of each data point. | |||
var stack = []; | |||
var td = []; | |||
var sa = this.startAngle/180*Math.PI; | |||
var tot = 0; | |||
// don't know if we have any valid data yet, so set plot to not draw. | |||
this._drawData = false; | |||
for (var i=0; i<this.data.length; i++){ | |||
if (this.data[i][1] != 0) { | |||
// we have data, O.K. to draw. | |||
this._drawData = true; | |||
} | |||
stack.push(this.data[i][1]); | |||
td.push([this.data[i][0]]); | |||
if (i>0) { | |||
stack[i] += stack[i-1]; | |||
} | |||
tot += this.data[i][1]; | |||
} | |||
var fact = Math.PI*2/stack[stack.length - 1]; | |||
for (var i=0; i<stack.length; i++) { | |||
td[i][1] = stack[i] * fact; | |||
td[i][2] = this.data[i][1]/tot; | |||
} | |||
this.gridData = td; | |||
}; | |||
$.jqplot.DonutRenderer.prototype.makeGridData = function(data, plot) { | |||
var stack = []; | |||
var td = []; | |||
var tot = 0; | |||
var sa = this.startAngle/180*Math.PI; | |||
// don't know if we have any valid data yet, so set plot to not draw. | |||
this._drawData = false; | |||
for (var i=0; i<data.length; i++){ | |||
if (this.data[i][1] != 0) { | |||
// we have data, O.K. to draw. | |||
this._drawData = true; | |||
} | |||
stack.push(data[i][1]); | |||
td.push([data[i][0]]); | |||
if (i>0) { | |||
stack[i] += stack[i-1]; | |||
} | |||
tot += data[i][1]; | |||
} | |||
var fact = Math.PI*2/stack[stack.length - 1]; | |||
for (var i=0; i<stack.length; i++) { | |||
td[i][1] = stack[i] * fact; | |||
td[i][2] = data[i][1]/tot; | |||
} | |||
return td; | |||
}; | |||
$.jqplot.DonutRenderer.prototype.drawSlice = function (ctx, ang1, ang2, color, isShadow) { | |||
var r = this._diameter / 2; | |||
var ri = r - this._thickness; | |||
var fill = this.fill; | |||
// var lineWidth = this.lineWidth; | |||
ctx.save(); | |||
ctx.translate(this._center[0], this._center[1]); | |||
// ctx.translate(this.sliceMargin*Math.cos((ang1+ang2)/2), this.sliceMargin*Math.sin((ang1+ang2)/2)); | |||
if (isShadow) { | |||
for (var i=0; i<this.shadowDepth; i++) { | |||
ctx.save(); | |||
ctx.translate(this.shadowOffset*Math.cos(this.shadowAngle/180*Math.PI), this.shadowOffset*Math.sin(this.shadowAngle/180*Math.PI)); | |||
doDraw(); | |||
} | |||
} | |||
else { | |||
doDraw(); | |||
} | |||
function doDraw () { | |||
// Fix for IE and Chrome that can't seem to draw circles correctly. | |||
// ang2 should always be <= 2 pi since that is the way the data is converted. | |||
if (ang2 > 6.282 + this.startAngle) { | |||
ang2 = 6.282 + this.startAngle; | |||
if (ang1 > ang2) { | |||
ang1 = 6.281 + this.startAngle; | |||
} | |||
} | |||
// Fix for IE, where it can't seem to handle 0 degree angles. Also avoids | |||
// ugly line on unfilled donuts. | |||
if (ang1 >= ang2) { | |||
return; | |||
} | |||
ctx.beginPath(); | |||
ctx.fillStyle = color; | |||
ctx.strokeStyle = color; | |||
// ctx.lineWidth = lineWidth; | |||
ctx.arc(0, 0, r, ang1, ang2, false); | |||
ctx.lineTo(ri*Math.cos(ang2), ri*Math.sin(ang2)); | |||
ctx.arc(0,0, ri, ang2, ang1, true); | |||
ctx.closePath(); | |||
if (fill) { | |||
ctx.fill(); | |||
} | |||
else { | |||
ctx.stroke(); | |||
} | |||
} | |||
if (isShadow) { | |||
for (var i=0; i<this.shadowDepth; i++) { | |||
ctx.restore(); | |||
} | |||
} | |||
ctx.restore(); | |||
}; | |||
// called with scope of series | |||
$.jqplot.DonutRenderer.prototype.draw = function (ctx, gd, options, plot) { | |||
var i; | |||
var opts = (options != undefined) ? options : {}; | |||
// offset and direction of offset due to legend placement | |||
var offx = 0; | |||
var offy = 0; | |||
var trans = 1; | |||
// var colorGenerator = new this.colorGenerator(this.seriesColors); | |||
if (options.legendInfo && options.legendInfo.placement == 'insideGrid') { | |||
var li = options.legendInfo; | |||
switch (li.location) { | |||
case 'nw': | |||
offx = li.width + li.xoffset; | |||
break; | |||
case 'w': | |||
offx = li.width + li.xoffset; | |||
break; | |||
case 'sw': | |||
offx = li.width + li.xoffset; | |||
break; | |||
case 'ne': | |||
offx = li.width + li.xoffset; | |||
trans = -1; | |||
break; | |||
case 'e': | |||
offx = li.width + li.xoffset; | |||
trans = -1; | |||
break; | |||
case 'se': | |||
offx = li.width + li.xoffset; | |||
trans = -1; | |||
break; | |||
case 'n': | |||
offy = li.height + li.yoffset; | |||
break; | |||
case 's': | |||
offy = li.height + li.yoffset; | |||
trans = -1; | |||
break; | |||
default: | |||
break; | |||
} | |||
} | |||
var shadow = (opts.shadow != undefined) ? opts.shadow : this.shadow; | |||
var showLine = (opts.showLine != undefined) ? opts.showLine : this.showLine; | |||
var fill = (opts.fill != undefined) ? opts.fill : this.fill; | |||
var cw = ctx.canvas.width; | |||
var ch = ctx.canvas.height; | |||
var w = cw - offx - 2 * this.padding; | |||
var h = ch - offy - 2 * this.padding; | |||
var mindim = Math.min(w,h); | |||
var d = mindim; | |||
var ringmargin = (this.ringMargin == null) ? this.sliceMargin * 2.0 : this.ringMargin; | |||
for (var i=0; i<this._previousSeries.length; i++) { | |||
d -= 2.0 * this._previousSeries[i]._thickness + 2.0 * ringmargin; | |||
} | |||
this._diameter = this.diameter || d; | |||
if (this.innerDiameter != null) { | |||
var od = (this._numberSeries > 1 && this.index > 0) ? this._previousSeries[0]._diameter : this._diameter; | |||
this._thickness = this.thickness || (od - this.innerDiameter - 2.0*ringmargin*this._numberSeries) / this._numberSeries/2.0; | |||
} | |||
else { | |||
this._thickness = this.thickness || mindim / 2 / (this._numberSeries + 1) * 0.85; | |||
} | |||
var r = this._radius = this._diameter/2; | |||
this._innerRadius = this._radius - this._thickness; | |||
var sa = this.startAngle / 180 * Math.PI; | |||
this._center = [(cw - trans * offx)/2 + trans * offx, (ch - trans*offy)/2 + trans * offy]; | |||
if (this.shadow) { | |||
var shadowColor = 'rgba(0,0,0,'+this.shadowAlpha+')'; | |||
for (var i=0; i<gd.length; i++) { | |||
var ang1 = (i == 0) ? sa : gd[i-1][1] + sa; | |||
// Adjust ang1 and ang2 for sliceMargin | |||
ang1 += this.sliceMargin/180*Math.PI; | |||
this.renderer.drawSlice.call (this, ctx, ang1, gd[i][1]+sa, shadowColor, true); | |||
} | |||
} | |||
for (var i=0; i<gd.length; i++) { | |||
var ang1 = (i == 0) ? sa : gd[i-1][1] + sa; | |||
// Adjust ang1 and ang2 for sliceMargin | |||
ang1 += this.sliceMargin/180*Math.PI; | |||
var ang2 = gd[i][1] + sa; | |||
this._sliceAngles.push([ang1, ang2]); | |||
this.renderer.drawSlice.call (this, ctx, ang1, ang2, this.seriesColors[i], false); | |||
if (this.showDataLabels && gd[i][2]*100 >= this.dataLabelThreshold) { | |||
var fstr, avgang = (ang1+ang2)/2, label; | |||
if (this.dataLabels == 'label') { | |||
fstr = this.dataLabelFormatString || '%s'; | |||
label = $.jqplot.sprintf(fstr, gd[i][0]); | |||
} | |||
else if (this.dataLabels == 'value') { | |||
fstr = this.dataLabelFormatString || '%d'; | |||
label = $.jqplot.sprintf(fstr, this.data[i][1]); | |||
} | |||
else if (this.dataLabels == 'percent') { | |||
fstr = this.dataLabelFormatString || '%d%%'; | |||
label = $.jqplot.sprintf(fstr, gd[i][2]*100); | |||
} | |||
else if (this.dataLabels.constructor == Array) { | |||
fstr = this.dataLabelFormatString || '%s'; | |||
label = $.jqplot.sprintf(fstr, this.dataLabels[i]); | |||
} | |||
var fact = this._innerRadius + this._thickness * this.dataLabelPositionFactor + this.sliceMargin + this.dataLabelNudge; | |||
var x = this._center[0] + Math.cos(avgang) * fact + this.canvas._offsets.left; | |||
var y = this._center[1] + Math.sin(avgang) * fact + this.canvas._offsets.top; | |||
var labelelem = $('<span class="jqplot-donut-series jqplot-data-label" style="position:absolute;">' + label + '</span>').insertBefore(plot.eventCanvas._elem); | |||
x -= labelelem.width()/2; | |||
y -= labelelem.height()/2; | |||
x = Math.round(x); | |||
y = Math.round(y); | |||
labelelem.css({left: x, top: y}); | |||
} | |||
} | |||
}; | |||
$.jqplot.DonutAxisRenderer = function() { | |||
$.jqplot.LinearAxisRenderer.call(this); | |||
}; | |||
$.jqplot.DonutAxisRenderer.prototype = new $.jqplot.LinearAxisRenderer(); | |||
$.jqplot.DonutAxisRenderer.prototype.constructor = $.jqplot.DonutAxisRenderer; | |||
// There are no traditional axes on a donut chart. We just need to provide | |||
// dummy objects with properties so the plot will render. | |||
// called with scope of axis object. | |||
$.jqplot.DonutAxisRenderer.prototype.init = function(options){ | |||
// | |||
this.tickRenderer = $.jqplot.DonutTickRenderer; | |||
$.extend(true, this, options); | |||
// I don't think I'm going to need _dataBounds here. | |||
// have to go Axis scaling in a way to fit chart onto plot area | |||
// and provide u2p and p2u functionality for mouse cursor, etc. | |||
// for convienence set _dataBounds to 0 and 100 and | |||
// set min/max to 0 and 100. | |||
this._dataBounds = {min:0, max:100}; | |||
this.min = 0; | |||
this.max = 100; | |||
this.showTicks = false; | |||
this.ticks = []; | |||
this.showMark = false; | |||
this.show = false; | |||
}; | |||
$.jqplot.DonutLegendRenderer = function(){ | |||
$.jqplot.TableLegendRenderer.call(this); | |||
}; | |||
$.jqplot.DonutLegendRenderer.prototype = new $.jqplot.TableLegendRenderer(); | |||
$.jqplot.DonutLegendRenderer.prototype.constructor = $.jqplot.DonutLegendRenderer; | |||
/** | |||
* Class: $.jqplot.DonutLegendRenderer | |||
* Legend Renderer specific to donut plots. Set by default | |||
* when user creates a donut plot. | |||
*/ | |||
$.jqplot.DonutLegendRenderer.prototype.init = function(options) { | |||
// Group: Properties | |||
// | |||
// prop: numberRows | |||
// Maximum number of rows in the legend. 0 or null for unlimited. | |||
this.numberRows = null; | |||
// prop: numberColumns | |||
// Maximum number of columns in the legend. 0 or null for unlimited. | |||
this.numberColumns = null; | |||
$.extend(true, this, options); | |||
}; | |||
// called with context of legend | |||
$.jqplot.DonutLegendRenderer.prototype.draw = function() { | |||
var legend = this; | |||
if (this.show) { | |||
var series = this._series; | |||
var ss = 'position:absolute;'; | |||
ss += (this.background) ? 'background:'+this.background+';' : ''; | |||
ss += (this.border) ? 'border:'+this.border+';' : ''; | |||
ss += (this.fontSize) ? 'font-size:'+this.fontSize+';' : ''; | |||
ss += (this.fontFamily) ? 'font-family:'+this.fontFamily+';' : ''; | |||
ss += (this.textColor) ? 'color:'+this.textColor+';' : ''; | |||
ss += (this.marginTop != null) ? 'margin-top:'+this.marginTop+';' : ''; | |||
ss += (this.marginBottom != null) ? 'margin-bottom:'+this.marginBottom+';' : ''; | |||
ss += (this.marginLeft != null) ? 'margin-left:'+this.marginLeft+';' : ''; | |||
ss += (this.marginRight != null) ? 'margin-right:'+this.marginRight+';' : ''; | |||
this._elem = $('<table class="jqplot-table-legend" style="'+ss+'"></table>'); | |||
// Donut charts legends don't go by number of series, but by number of data points | |||
// in the series. Refactor things here for that. | |||
var pad = false, | |||
reverse = false, | |||
nr, nc; | |||
var s = series[0]; | |||
var colorGenerator = new $.jqplot.ColorGenerator(s.seriesColors); | |||
if (s.show) { | |||
var pd = s.data; | |||
if (this.numberRows) { | |||
nr = this.numberRows; | |||
if (!this.numberColumns){ | |||
nc = Math.ceil(pd.length/nr); | |||
} | |||
else{ | |||
nc = this.numberColumns; | |||
} | |||
} | |||
else if (this.numberColumns) { | |||
nc = this.numberColumns; | |||
nr = Math.ceil(pd.length/this.numberColumns); | |||
} | |||
else { | |||
nr = pd.length; | |||
nc = 1; | |||
} | |||
var i, j, tr, td1, td2, lt, rs, color; | |||
var idx = 0; | |||
for (i=0; i<nr; i++) { | |||
if (reverse){ | |||
tr = $('<tr class="jqplot-table-legend"></tr>').prependTo(this._elem); | |||
} | |||
else{ | |||
tr = $('<tr class="jqplot-table-legend"></tr>').appendTo(this._elem); | |||
} | |||
for (j=0; j<nc; j++) { | |||
if (idx < pd.length){ | |||
lt = this.labels[idx] || pd[idx][0].toString(); | |||
color = colorGenerator.next(); | |||
if (!reverse){ | |||
if (i>0){ | |||
pad = true; | |||
} | |||
else{ | |||
pad = false; | |||
} | |||
} | |||
else{ | |||
if (i == nr -1){ | |||
pad = false; | |||
} | |||
else{ | |||
pad = true; | |||
} | |||
} | |||
rs = (pad) ? this.rowSpacing : '0'; | |||
td1 = $('<td class="jqplot-table-legend" style="text-align:center;padding-top:'+rs+';">'+ | |||
'<div><div class="jqplot-table-legend-swatch" style="border-color:'+color+';"></div>'+ | |||
'</div></td>'); | |||
td2 = $('<td class="jqplot-table-legend" style="padding-top:'+rs+';"></td>'); | |||
if (this.escapeHtml){ | |||
td2.text(lt); | |||
} | |||
else { | |||
td2.html(lt); | |||
} | |||
if (reverse) { | |||
td2.prependTo(tr); | |||
td1.prependTo(tr); | |||
} | |||
else { | |||
td1.appendTo(tr); | |||
td2.appendTo(tr); | |||
} | |||
pad = true; | |||
} | |||
idx++; | |||
} | |||
} | |||
} | |||
} | |||
return this._elem; | |||
}; | |||
// $.jqplot.DonutLegendRenderer.prototype.pack = function(offsets) { | |||
// if (this.show) { | |||
// // fake a grid for positioning | |||
// var grid = {_top:offsets.top, _left:offsets.left, _right:offsets.right, _bottom:this._plotDimensions.height - offsets.bottom}; | |||
// if (this.placement == 'insideGrid') { | |||
// switch (this.location) { | |||
// case 'nw': | |||
// var a = grid._left + this.xoffset; | |||
// var b = grid._top + this.yoffset; | |||
// this._elem.css('left', a); | |||
// this._elem.css('top', b); | |||
// break; | |||
// case 'n': | |||
// var a = (offsets.left + (this._plotDimensions.width - offsets.right))/2 - this.getWidth()/2; | |||
// var b = grid._top + this.yoffset; | |||
// this._elem.css('left', a); | |||
// this._elem.css('top', b); | |||
// break; | |||
// case 'ne': | |||
// var a = offsets.right + this.xoffset; | |||
// var b = grid._top + this.yoffset; | |||
// this._elem.css({right:a, top:b}); | |||
// break; | |||
// case 'e': | |||
// var a = offsets.right + this.xoffset; | |||
// var b = (offsets.top + (this._plotDimensions.height - offsets.bottom))/2 - this.getHeight()/2; | |||
// this._elem.css({right:a, top:b}); | |||
// break; | |||
// case 'se': | |||
// var a = offsets.right + this.xoffset; | |||
// var b = offsets.bottom + this.yoffset; | |||
// this._elem.css({right:a, bottom:b}); | |||
// break; | |||
// case 's': | |||
// var a = (offsets.left + (this._plotDimensions.width - offsets.right))/2 - this.getWidth()/2; | |||
// var b = offsets.bottom + this.yoffset; | |||
// this._elem.css({left:a, bottom:b}); | |||
// break; | |||
// case 'sw': | |||
// var a = grid._left + this.xoffset; | |||
// var b = offsets.bottom + this.yoffset; | |||
// this._elem.css({left:a, bottom:b}); | |||
// break; | |||
// case 'w': | |||
// var a = grid._left + this.xoffset; | |||
// var b = (offsets.top + (this._plotDimensions.height - offsets.bottom))/2 - this.getHeight()/2; | |||
// this._elem.css({left:a, top:b}); | |||
// break; | |||
// default: // same as 'se' | |||
// var a = grid._right - this.xoffset; | |||
// var b = grid._bottom + this.yoffset; | |||
// this._elem.css({right:a, bottom:b}); | |||
// break; | |||
// } | |||
// | |||
// } | |||
// else { | |||
// switch (this.location) { | |||
// case 'nw': | |||
// var a = this._plotDimensions.width - grid._left + this.xoffset; | |||
// var b = grid._top + this.yoffset; | |||
// this._elem.css('right', a); | |||
// this._elem.css('top', b); | |||
// break; | |||
// case 'n': | |||
// var a = (offsets.left + (this._plotDimensions.width - offsets.right))/2 - this.getWidth()/2; | |||
// var b = this._plotDimensions.height - grid._top + this.yoffset; | |||
// this._elem.css('left', a); | |||
// this._elem.css('bottom', b); | |||
// break; | |||
// case 'ne': | |||
// var a = this._plotDimensions.width - offsets.right + this.xoffset; | |||
// var b = grid._top + this.yoffset; | |||
// this._elem.css({left:a, top:b}); | |||
// break; | |||
// case 'e': | |||
// var a = this._plotDimensions.width - offsets.right + this.xoffset; | |||
// var b = (offsets.top + (this._plotDimensions.height - offsets.bottom))/2 - this.getHeight()/2; | |||
// this._elem.css({left:a, top:b}); | |||
// break; | |||
// case 'se': | |||
// var a = this._plotDimensions.width - offsets.right + this.xoffset; | |||
// var b = offsets.bottom + this.yoffset; | |||
// this._elem.css({left:a, bottom:b}); | |||
// break; | |||
// case 's': | |||
// var a = (offsets.left + (this._plotDimensions.width - offsets.right))/2 - this.getWidth()/2; | |||
// var b = this._plotDimensions.height - offsets.bottom + this.yoffset; | |||
// this._elem.css({left:a, top:b}); | |||
// break; | |||
// case 'sw': | |||
// var a = this._plotDimensions.width - grid._left + this.xoffset; | |||
// var b = offsets.bottom + this.yoffset; | |||
// this._elem.css({right:a, bottom:b}); | |||
// break; | |||
// case 'w': | |||
// var a = this._plotDimensions.width - grid._left + this.xoffset; | |||
// var b = (offsets.top + (this._plotDimensions.height - offsets.bottom))/2 - this.getHeight()/2; | |||
// this._elem.css({right:a, top:b}); | |||
// break; | |||
// default: // same as 'se' | |||
// var a = grid._right - this.xoffset; | |||
// var b = grid._bottom + this.yoffset; | |||
// this._elem.css({right:a, bottom:b}); | |||
// break; | |||
// } | |||
// } | |||
// } | |||
// }; | |||
// setup default renderers for axes and legend so user doesn't have to | |||
// called with scope of plot | |||
function preInit(target, data, options) { | |||
options = options || {}; | |||
options.axesDefaults = options.axesDefaults || {}; | |||
options.legend = options.legend || {}; | |||
options.seriesDefaults = options.seriesDefaults || {}; | |||
// only set these if there is a donut series | |||
var setopts = false; | |||
if (options.seriesDefaults.renderer == $.jqplot.DonutRenderer) { | |||
setopts = true; | |||
} | |||
else if (options.series) { | |||
for (var i=0; i < options.series.length; i++) { | |||
if (options.series[i].renderer == $.jqplot.DonutRenderer) { | |||
setopts = true; | |||
} | |||
} | |||
} | |||
if (setopts) { | |||
options.axesDefaults.renderer = $.jqplot.DonutAxisRenderer; | |||
options.legend.renderer = $.jqplot.DonutLegendRenderer; | |||
options.legend.preDraw = true; | |||
options.seriesDefaults.pointLabels = {show: false}; | |||
} | |||
} | |||
// called with scope of plot. | |||
function postInit(target, data, options) { | |||
// if multiple series, add a reference to the previous one so that | |||
// donut rings can nest. | |||
for (var i=1; i<this.series.length; i++) { | |||
if (!this.series[i]._previousSeries.length){ | |||
for (var j=0; j<i; j++) { | |||
if (this.series[i].renderer.constructor == $.jqplot.DonutRenderer && this.series[j].renderer.constructor == $.jqplot.DonutRenderer) { | |||
this.series[i]._previousSeries.push(this.series[j]); | |||
} | |||
} | |||
} | |||
} | |||
for (i=0; i<this.series.length; i++) { | |||
if (this.series[i].renderer.constructor == $.jqplot.DonutRenderer) { | |||
this.series[i]._numberSeries = this.series.length; | |||
// don't allow mouseover and mousedown at same time. | |||
if (this.series[i].highlightMouseOver) { | |||
this.series[i].highlightMouseDown = false; | |||
} | |||
} | |||
} | |||
this.target.bind('mouseout', {plot:this}, function (ev) { unhighlight(ev.data.plot); }); | |||
} | |||
var postParseOptionsRun = false; | |||
// called with scope of plot | |||
function postParseOptions(options) { | |||
for (var i=0; i<this.series.length; i++) { | |||
this.series[i].seriesColors = this.seriesColors; | |||
this.series[i].colorGenerator = this.colorGenerator; | |||
} | |||
} | |||
function highlight (plot, sidx, pidx) { | |||
var s = plot.series[sidx]; | |||
var canvas = plot.plugins.donutRenderer.highlightCanvas; | |||
canvas._ctx.clearRect(0,0,canvas._ctx.canvas.width, canvas._ctx.canvas.height); | |||
s._highlightedPoint = pidx; | |||
plot.plugins.donutRenderer.highlightedSeriesIndex = sidx; | |||
s.renderer.drawSlice.call(s, canvas._ctx, s._sliceAngles[pidx][0], s._sliceAngles[pidx][1], s.highlightColors[pidx], false); | |||
} | |||
function unhighlight (plot) { | |||
var canvas = plot.plugins.donutRenderer.highlightCanvas; | |||
canvas._ctx.clearRect(0,0, canvas._ctx.canvas.width, canvas._ctx.canvas.height); | |||
for (var i=0; i<plot.series.length; i++) { | |||
plot.series[i]._highlightedPoint = null; | |||
} | |||
plot.plugins.donutRenderer.highlightedSeriesIndex = null; | |||
plot.target.trigger('jqplotDataUnhighlight'); | |||
} | |||
function handleMove(ev, gridpos, datapos, neighbor, plot) { | |||
if (neighbor) { | |||
var ins = [neighbor.seriesIndex, neighbor.pointIndex, neighbor.data]; | |||
var evt1 = jQuery.Event('jqplotDataMouseOver'); | |||
evt1.pageX = ev.pageX; | |||
evt1.pageY = ev.pageY; | |||
plot.target.trigger(evt1, ins); | |||
if (plot.series[ins[0]].highlightMouseOver && !(ins[0] == plot.plugins.donutRenderer.highlightedSeriesIndex && ins[1] == plot.series[ins[0]]._highlightedPoint)) { | |||
var evt = jQuery.Event('jqplotDataHighlight'); | |||
evt.pageX = ev.pageX; | |||
evt.pageY = ev.pageY; | |||
plot.target.trigger(evt, ins); | |||
highlight (plot, ins[0], ins[1]); | |||
} | |||
} | |||
else if (neighbor == null) { | |||
unhighlight (plot); | |||
} | |||
} | |||
function handleMouseDown(ev, gridpos, datapos, neighbor, plot) { | |||
if (neighbor) { | |||
var ins = [neighbor.seriesIndex, neighbor.pointIndex, neighbor.data]; | |||
if (plot.series[ins[0]].highlightMouseDown && !(ins[0] == plot.plugins.donutRenderer.highlightedSeriesIndex && ins[1] == plot.series[ins[0]]._highlightedPoint)) { | |||
var evt = jQuery.Event('jqplotDataHighlight'); | |||
evt.pageX = ev.pageX; | |||
evt.pageY = ev.pageY; | |||
plot.target.trigger(evt, ins); | |||
highlight (plot, ins[0], ins[1]); | |||
} | |||
} | |||
else if (neighbor == null) { | |||
unhighlight (plot); | |||
} | |||
} | |||
function handleMouseUp(ev, gridpos, datapos, neighbor, plot) { | |||
var idx = plot.plugins.donutRenderer.highlightedSeriesIndex; | |||
if (idx != null && plot.series[idx].highlightMouseDown) { | |||
unhighlight(plot); | |||
} | |||
} | |||
function handleClick(ev, gridpos, datapos, neighbor, plot) { | |||
if (neighbor) { | |||
var ins = [neighbor.seriesIndex, neighbor.pointIndex, neighbor.data]; | |||
var evt = jQuery.Event('jqplotDataClick'); | |||
evt.pageX = ev.pageX; | |||
evt.pageY = ev.pageY; | |||
plot.target.trigger(evt, ins); | |||
} | |||
} | |||
function handleRightClick(ev, gridpos, datapos, neighbor, plot) { | |||
if (neighbor) { | |||
var ins = [neighbor.seriesIndex, neighbor.pointIndex, neighbor.data]; | |||
var idx = plot.plugins.donutRenderer.highlightedSeriesIndex; | |||
if (idx != null && plot.series[idx].highlightMouseDown) { | |||
unhighlight(plot); | |||
} | |||
var evt = jQuery.Event('jqplotDataRightClick'); | |||
evt.pageX = ev.pageX; | |||
evt.pageY = ev.pageY; | |||
plot.target.trigger(evt, ins); | |||
} | |||
} | |||
// called within context of plot | |||
// create a canvas which we can draw on. | |||
// insert it before the eventCanvas, so eventCanvas will still capture events. | |||
function postPlotDraw() { | |||
// Memory Leaks patch | |||
if (this.plugins.donutRenderer && this.plugins.donutRenderer.highlightCanvas) { | |||
this.plugins.donutRenderer.highlightCanvas.resetCanvas(); | |||
this.plugins.donutRenderer.highlightCanvas = null; | |||
} | |||
this.plugins.donutRenderer = {highlightedSeriesIndex:null}; | |||
this.plugins.donutRenderer.highlightCanvas = new $.jqplot.GenericCanvas(); | |||
// do we have any data labels? if so, put highlight canvas before those | |||
// Fix for broken jquery :first selector with canvas (VML) elements. | |||
var labels = $(this.targetId+' .jqplot-data-label'); | |||
if (labels.length) { | |||
$(labels[0]).before(this.plugins.donutRenderer.highlightCanvas.createElement(this._gridPadding, 'jqplot-donutRenderer-highlight-canvas', this._plotDimensions, this)); | |||
} | |||
// else put highlight canvas before event canvas. | |||
else { | |||
this.eventCanvas._elem.before(this.plugins.donutRenderer.highlightCanvas.createElement(this._gridPadding, 'jqplot-donutRenderer-highlight-canvas', this._plotDimensions, this)); | |||
} | |||
var hctx = this.plugins.donutRenderer.highlightCanvas.setContext(); | |||
} | |||
$.jqplot.preInitHooks.push(preInit); | |||
$.jqplot.DonutTickRenderer = function() { | |||
$.jqplot.AxisTickRenderer.call(this); | |||
}; | |||
$.jqplot.DonutTickRenderer.prototype = new $.jqplot.AxisTickRenderer(); | |||
$.jqplot.DonutTickRenderer.prototype.constructor = $.jqplot.DonutTickRenderer; | |||
})(jQuery); | |||
@@ -1,18 +1,30 @@ | |||
/** | |||
* Copyright (c) 2009 Chris Leonello | |||
* jqPlot | |||
* Pure JavaScript plotting plugin using jQuery | |||
* | |||
* Version: 1.0.0b2_r792 | |||
* | |||
* Copyright (c) 2009-2011 Chris Leonello | |||
* jqPlot is currently available for use in all personal or commercial projects | |||
* under both the MIT and GPL version 2.0 licenses. This means that you can | |||
* under both the MIT (http://www.opensource.org/licenses/mit-license.php) and GPL | |||
* version 2.0 (http://www.gnu.org/licenses/gpl-2.0.html) licenses. This means that you can | |||
* choose the license that best suits your project and use it accordingly. | |||
* | |||
* The author would appreciate an email letting him know of any substantial | |||
* use of jqPlot. You can reach the author at: chris dot leonello at gmail | |||
* dot com or see http://www.jqplot.com/info.php . This is, of course, | |||
* not required. | |||
* Although not required, the author would appreciate an email letting him | |||
* know of any substantial use of jqPlot. You can reach the author at: | |||
* chris at jqplot dot com or see http://www.jqplot.com/info.php . | |||
* | |||
* If you are feeling kind and generous, consider supporting the project by | |||
* making a donation at: http://www.jqplot.com/donate.php . | |||
* | |||
* Thanks for using jqPlot! | |||
* sprintf functions contained in jqplot.sprintf.js by Ash Searle: | |||
* | |||
* version 2007.04.27 | |||
* author Ash Searle | |||
* http://hexmen.com/blog/2007/03/printf-sprintf/ | |||
* http://hexmen.com/js/sprintf.js | |||
* The author (Ash Searle) has placed this code in the public domain: | |||
* "This code is unrestricted: you are free to use it however you like." | |||
* | |||
*/ | |||
(function($) { | |||
@@ -67,10 +79,16 @@ | |||
// insert it before the eventCanvas, so eventCanvas will still capture events. | |||
// add a new DragCanvas object to the plot plugins to handle drawing on this new canvas. | |||
$.jqplot.Dragable.postPlotDraw = function() { | |||
// Memory Leaks patch | |||
if (this.plugins.dragable && this.plugins.dragable.highlightCanvas) { | |||
this.plugins.dragable.highlightCanvas.resetCanvas(); | |||
this.plugins.dragable.highlightCanvas = null; | |||
} | |||
this.plugins.dragable = {previousCursor:'auto', isOver:false}; | |||
this.plugins.dragable.dragCanvas = new DragCanvas(); | |||
this.eventCanvas._elem.before(this.plugins.dragable.dragCanvas.createElement(this._gridPadding, 'jqplot-dragable-canvas', this._plotDimensions)); | |||
this.eventCanvas._elem.before(this.plugins.dragable.dragCanvas.createElement(this._gridPadding, 'jqplot-dragable-canvas', this._plotDimensions, this)); | |||
var dctx = this.plugins.dragable.dragCanvas.setContext(); | |||
}; | |||
@@ -168,6 +186,7 @@ | |||
initDragPoint(plot, neighbor); | |||
drag.markerRenderer.draw(s.gridData[neighbor.pointIndex][0], s.gridData[neighbor.pointIndex][1], dc._ctx); | |||
ev.target.style.cursor = "move"; | |||
plot.target.trigger('jqplotDragStart', [neighbor.seriesIndex, neighbor.pointIndex, gridpos, datapos]); | |||
} | |||
} | |||
// Just in case of a hickup, we'll clear the drag canvas and reset. | |||
@@ -194,10 +213,12 @@ | |||
var y = (drag.constrainTo == 'x') ? dp.data[1] : datapos[s.yaxis]; | |||
// var x = datapos[s.xaxis]; | |||
// var y = datapos[s.yaxis]; | |||
s.data[dp.pointIndex] = [x,y]; | |||
s.data[dp.pointIndex][0] = x; | |||
s.data[dp.pointIndex][1] = y; | |||
plot.drawSeries({preventJqPlotSeriesDrawTrigger:true}, dp.seriesIndex); | |||
dc._neighbor = null; | |||
ev.target.style.cursor = dc._cursors.pop(); | |||
plot.target.trigger('jqplotDragStop', [gridpos, datapos]); | |||
} | |||
} | |||
})(jQuery); |
@@ -1,14 +1,30 @@ | |||
/** | |||
* Copyright (c) 2009 Chris Leonello | |||
* jqPlot | |||
* Pure JavaScript plotting plugin using jQuery | |||
* | |||
* Version: 1.0.0b2_r792 | |||
* | |||
* Copyright (c) 2009-2011 Chris Leonello | |||
* jqPlot is currently available for use in all personal or commercial projects | |||
* under both the MIT and GPL version 2.0 licenses. This means that you can | |||
* under both the MIT (http://www.opensource.org/licenses/mit-license.php) and GPL | |||
* version 2.0 (http://www.gnu.org/licenses/gpl-2.0.html) licenses. This means that you can | |||
* choose the license that best suits your project and use it accordingly. | |||
* | |||
* Although not required, the author would appreciate an email letting him | |||
* know of any substantial use of jqPlot. You can reach the author at: | |||
* chris dot leonello at gmail dot com or see http://www.jqplot.com/info.php . | |||
* chris at jqplot dot com or see http://www.jqplot.com/info.php . | |||
* | |||
* If you are feeling kind and generous, consider supporting the project by | |||
* making a donation at: http://www.jqplot.com/donate.php . | |||
* | |||
* sprintf functions contained in jqplot.sprintf.js by Ash Searle: | |||
* | |||
* version 2007.04.27 | |||
* author Ash Searle | |||
* http://hexmen.com/blog/2007/03/printf-sprintf/ | |||
* http://hexmen.com/js/sprintf.js | |||
* The author (Ash Searle) has placed this code in the public domain: | |||
* "This code is unrestricted: you are free to use it however you like." | |||
* | |||
*/ | |||
(function(d){d.jqplot.Dragable=function(g){this.markerRenderer=new d.jqplot.MarkerRenderer({shadow:false});this.shapeRenderer=new d.jqplot.ShapeRenderer();this.isDragging=false;this.isOver=false;this._ctx;this._elem;this._point;this._gridData;this.color;this.constrainTo="none";d.extend(true,this,g)};function b(){d.jqplot.GenericCanvas.call(this);this.isDragging=false;this.isOver=false;this._neighbor;this._cursors=[]}b.prototype=new d.jqplot.GenericCanvas();b.prototype.constructor=b;d.jqplot.Dragable.parseOptions=function(i,h){var g=h||{};this.plugins.dragable=new d.jqplot.Dragable(g.dragable);this.isDragable=d.jqplot.config.enablePlugins};d.jqplot.Dragable.postPlotDraw=function(){this.plugins.dragable={previousCursor:"auto",isOver:false};this.plugins.dragable.dragCanvas=new b();this.eventCanvas._elem.before(this.plugins.dragable.dragCanvas.createElement(this._gridPadding,"jqplot-dragable-canvas",this._plotDimensions));var g=this.plugins.dragable.dragCanvas.setContext()};d.jqplot.preParseSeriesOptionsHooks.push(d.jqplot.Dragable.parseOptions);d.jqplot.postDrawHooks.push(d.jqplot.Dragable.postPlotDraw);d.jqplot.eventListenerHooks.push(["jqplotMouseMove",e]);d.jqplot.eventListenerHooks.push(["jqplotMouseDown",c]);d.jqplot.eventListenerHooks.push(["jqplotMouseUp",a]);function f(n,p){var q=n.series[p.seriesIndex];var m=q.plugins.dragable;var h=q.markerRenderer;var i=m.markerRenderer;i.style=h.style;i.lineWidth=h.lineWidth+2.5;i.size=h.size+5;if(!m.color){var l=d.jqplot.getColorComponents(h.color);var o=[l[0],l[1],l[2]];var k=(l[3]>=0.6)?l[3]*0.6:l[3]*(2-l[3]);m.color="rgba("+o[0]+","+o[1]+","+o[2]+","+k+")"}i.color=m.color;i.init();var g=(p.pointIndex>0)?p.pointIndex-1:0;var j=p.pointIndex+2;m._gridData=q.gridData.slice(g,j)}function e(o,l,h,t,m){if(m.plugins.dragable.dragCanvas.isDragging){var u=m.plugins.dragable.dragCanvas;var i=u._neighbor;var w=m.series[i.seriesIndex];var k=w.plugins.dragable;var r=w.gridData;var p=(k.constrainTo=="y")?i.gridData[0]:l.x;var n=(k.constrainTo=="x")?i.gridData[1]:l.y;var g=w._xaxis.series_p2u(p);var q=w._yaxis.series_p2u(n);var v=u._ctx;v.clearRect(0,0,v.canvas.width,v.canvas.height);if(i.pointIndex>0){k._gridData[1]=[p,n]}else{k._gridData[0]=[p,n]}m.series[i.seriesIndex].draw(u._ctx,{gridData:k._gridData,shadow:false,preventJqPlotSeriesDrawTrigger:true,color:k.color,markerOptions:{color:k.color,shadow:false},trendline:{show:false}});m.target.trigger("jqplotSeriesPointChange",[i.seriesIndex,i.pointIndex,[g,q],[p,n]])}else{if(t!=null){var j=m.series[t.seriesIndex];if(j.isDragable){var u=m.plugins.dragable.dragCanvas;if(!u.isOver){u._cursors.push(o.target.style.cursor);o.target.style.cursor="pointer"}u.isOver=true}}else{if(t==null){var u=m.plugins.dragable.dragCanvas;if(u.isOver){o.target.style.cursor=u._cursors.pop();u.isOver=false}}}}}function c(k,i,g,l,j){var m=j.plugins.dragable.dragCanvas;m._cursors.push(k.target.style.cursor);if(l!=null){var o=j.series[l.seriesIndex];var h=o.plugins.dragable;if(o.isDragable&&!m.isDragging){m._neighbor=l;m.isDragging=true;f(j,l);h.markerRenderer.draw(o.gridData[l.pointIndex][0],o.gridData[l.pointIndex][1],m._ctx);k.target.style.cursor="move"}}else{var n=m._ctx;n.clearRect(0,0,n.canvas.width,n.canvas.height);m.isDragging=false}}function a(m,j,g,o,k){if(k.plugins.dragable.dragCanvas.isDragging){var p=k.plugins.dragable.dragCanvas;var q=p._ctx;q.clearRect(0,0,q.canvas.width,q.canvas.height);p.isDragging=false;var h=p._neighbor;var r=k.series[h.seriesIndex];var i=r.plugins.dragable;var n=(i.constrainTo=="y")?h.data[0]:g[r.xaxis];var l=(i.constrainTo=="x")?h.data[1]:g[r.yaxis];r.data[h.pointIndex]=[n,l];k.drawSeries({preventJqPlotSeriesDrawTrigger:true},h.seriesIndex);p._neighbor=null;m.target.style.cursor=p._cursors.pop()}}})(jQuery); | |||
(function(d){d.jqplot.Dragable=function(g){this.markerRenderer=new d.jqplot.MarkerRenderer({shadow:false});this.shapeRenderer=new d.jqplot.ShapeRenderer();this.isDragging=false;this.isOver=false;this._ctx;this._elem;this._point;this._gridData;this.color;this.constrainTo="none";d.extend(true,this,g)};function b(){d.jqplot.GenericCanvas.call(this);this.isDragging=false;this.isOver=false;this._neighbor;this._cursors=[]}b.prototype=new d.jqplot.GenericCanvas();b.prototype.constructor=b;d.jqplot.Dragable.parseOptions=function(i,h){var g=h||{};this.plugins.dragable=new d.jqplot.Dragable(g.dragable);this.isDragable=d.jqplot.config.enablePlugins};d.jqplot.Dragable.postPlotDraw=function(){if(this.plugins.dragable&&this.plugins.dragable.highlightCanvas){this.plugins.dragable.highlightCanvas.resetCanvas();this.plugins.dragable.highlightCanvas=null}this.plugins.dragable={previousCursor:"auto",isOver:false};this.plugins.dragable.dragCanvas=new b();this.eventCanvas._elem.before(this.plugins.dragable.dragCanvas.createElement(this._gridPadding,"jqplot-dragable-canvas",this._plotDimensions,this));var g=this.plugins.dragable.dragCanvas.setContext()};d.jqplot.preParseSeriesOptionsHooks.push(d.jqplot.Dragable.parseOptions);d.jqplot.postDrawHooks.push(d.jqplot.Dragable.postPlotDraw);d.jqplot.eventListenerHooks.push(["jqplotMouseMove",e]);d.jqplot.eventListenerHooks.push(["jqplotMouseDown",c]);d.jqplot.eventListenerHooks.push(["jqplotMouseUp",a]);function f(n,p){var q=n.series[p.seriesIndex];var m=q.plugins.dragable;var h=q.markerRenderer;var i=m.markerRenderer;i.style=h.style;i.lineWidth=h.lineWidth+2.5;i.size=h.size+5;if(!m.color){var l=d.jqplot.getColorComponents(h.color);var o=[l[0],l[1],l[2]];var k=(l[3]>=0.6)?l[3]*0.6:l[3]*(2-l[3]);m.color="rgba("+o[0]+","+o[1]+","+o[2]+","+k+")"}i.color=m.color;i.init();var g=(p.pointIndex>0)?p.pointIndex-1:0;var j=p.pointIndex+2;m._gridData=q.gridData.slice(g,j)}function e(o,l,h,t,m){if(m.plugins.dragable.dragCanvas.isDragging){var u=m.plugins.dragable.dragCanvas;var i=u._neighbor;var w=m.series[i.seriesIndex];var k=w.plugins.dragable;var r=w.gridData;var p=(k.constrainTo=="y")?i.gridData[0]:l.x;var n=(k.constrainTo=="x")?i.gridData[1]:l.y;var g=w._xaxis.series_p2u(p);var q=w._yaxis.series_p2u(n);var v=u._ctx;v.clearRect(0,0,v.canvas.width,v.canvas.height);if(i.pointIndex>0){k._gridData[1]=[p,n]}else{k._gridData[0]=[p,n]}m.series[i.seriesIndex].draw(u._ctx,{gridData:k._gridData,shadow:false,preventJqPlotSeriesDrawTrigger:true,color:k.color,markerOptions:{color:k.color,shadow:false},trendline:{show:false}});m.target.trigger("jqplotSeriesPointChange",[i.seriesIndex,i.pointIndex,[g,q],[p,n]])}else{if(t!=null){var j=m.series[t.seriesIndex];if(j.isDragable){var u=m.plugins.dragable.dragCanvas;if(!u.isOver){u._cursors.push(o.target.style.cursor);o.target.style.cursor="pointer"}u.isOver=true}}else{if(t==null){var u=m.plugins.dragable.dragCanvas;if(u.isOver){o.target.style.cursor=u._cursors.pop();u.isOver=false}}}}}function c(k,i,g,l,j){var m=j.plugins.dragable.dragCanvas;m._cursors.push(k.target.style.cursor);if(l!=null){var o=j.series[l.seriesIndex];var h=o.plugins.dragable;if(o.isDragable&&!m.isDragging){m._neighbor=l;m.isDragging=true;f(j,l);h.markerRenderer.draw(o.gridData[l.pointIndex][0],o.gridData[l.pointIndex][1],m._ctx);k.target.style.cursor="move";j.target.trigger("jqplotDragStart",[l.seriesIndex,l.pointIndex,i,g])}}else{var n=m._ctx;n.clearRect(0,0,n.canvas.width,n.canvas.height);m.isDragging=false}}function a(m,j,g,o,k){if(k.plugins.dragable.dragCanvas.isDragging){var p=k.plugins.dragable.dragCanvas;var q=p._ctx;q.clearRect(0,0,q.canvas.width,q.canvas.height);p.isDragging=false;var h=p._neighbor;var r=k.series[h.seriesIndex];var i=r.plugins.dragable;var n=(i.constrainTo=="y")?h.data[0]:g[r.xaxis];var l=(i.constrainTo=="x")?h.data[1]:g[r.yaxis];r.data[h.pointIndex][0]=n;r.data[h.pointIndex][1]=l;k.drawSeries({preventJqPlotSeriesDrawTrigger:true},h.seriesIndex);p._neighbor=null;m.target.style.cursor=p._cursors.pop();k.target.trigger("jqplotDragStop",[j,g])}}})(jQuery); |
@@ -0,0 +1,199 @@ | |||
/** | |||
* jqPlot | |||
* Pure JavaScript plotting plugin using jQuery | |||
* | |||
* Version: 1.0.0b2_r792 | |||
* | |||
* Copyright (c) 2009-2011 Chris Leonello | |||
* jqPlot is currently available for use in all personal or commercial projects | |||
* under both the MIT (http://www.opensource.org/licenses/mit-license.php) and GPL | |||
* version 2.0 (http://www.gnu.org/licenses/gpl-2.0.html) licenses. This means that you can | |||
* choose the license that best suits your project and use it accordingly. | |||
* | |||
* Although not required, the author would appreciate an email letting him | |||
* know of any substantial use of jqPlot. You can reach the author at: | |||
* chris at jqplot dot com or see http://www.jqplot.com/info.php . | |||
* | |||
* If you are feeling kind and generous, consider supporting the project by | |||
* making a donation at: http://www.jqplot.com/donate.php . | |||
* | |||
* sprintf functions contained in jqplot.sprintf.js by Ash Searle: | |||
* | |||
* version 2007.04.27 | |||
* author Ash Searle | |||
* http://hexmen.com/blog/2007/03/printf-sprintf/ | |||
* http://hexmen.com/js/sprintf.js | |||
* The author (Ash Searle) has placed this code in the public domain: | |||
* "This code is unrestricted: you are free to use it however you like." | |||
* | |||
*/ | |||
(function($) { | |||
// class $.jqplot.EnhancedLegendRenderer | |||
// Legend renderer which can specify the number of rows and/or columns in the legend. | |||
$.jqplot.EnhancedLegendRenderer = function(){ | |||
$.jqplot.TableLegendRenderer.call(this); | |||
}; | |||
$.jqplot.EnhancedLegendRenderer.prototype = new $.jqplot.TableLegendRenderer(); | |||
$.jqplot.EnhancedLegendRenderer.prototype.constructor = $.jqplot.EnhancedLegendRenderer; | |||
// called with scope of legend. | |||
$.jqplot.EnhancedLegendRenderer.prototype.init = function(options) { | |||
// prop: numberRows | |||
// Maximum number of rows in the legend. 0 or null for unlimited. | |||
this.numberRows = null; | |||
// prop: numberColumns | |||
// Maximum number of columns in the legend. 0 or null for unlimited. | |||
this.numberColumns = null; | |||
// prop: seriesToggle | |||
// false to not enable series on/off toggling on the legend. | |||
// true or a fadein/fadeout speed (number of milliseconds or 'fast', 'normal', 'slow') | |||
// to enable show/hide of series on click of legend item. | |||
this.seriesToggle = 'normal'; | |||
// prop: disableIEFading | |||
// true to toggle series with a show/hide method only and not allow fading in/out. | |||
// This is to overcome poor performance of fade in some versions of IE. | |||
this.disableIEFading = true; | |||
$.extend(true, this, options); | |||
if (this.seriesToggle) { | |||
$.jqplot.postDrawHooks.push(postDraw); | |||
} | |||
}; | |||
// called with scope of legend | |||
$.jqplot.EnhancedLegendRenderer.prototype.draw = function() { | |||
var legend = this; | |||
if (this.show) { | |||
var series = this._series; | |||
var s; | |||
var ss = 'position:absolute;'; | |||
ss += (this.background) ? 'background:'+this.background+';' : ''; | |||
ss += (this.border) ? 'border:'+this.border+';' : ''; | |||
ss += (this.fontSize) ? 'font-size:'+this.fontSize+';' : ''; | |||
ss += (this.fontFamily) ? 'font-family:'+this.fontFamily+';' : ''; | |||
ss += (this.textColor) ? 'color:'+this.textColor+';' : ''; | |||
ss += (this.marginTop != null) ? 'margin-top:'+this.marginTop+';' : ''; | |||
ss += (this.marginBottom != null) ? 'margin-bottom:'+this.marginBottom+';' : ''; | |||
ss += (this.marginLeft != null) ? 'margin-left:'+this.marginLeft+';' : ''; | |||
ss += (this.marginRight != null) ? 'margin-right:'+this.marginRight+';' : ''; | |||
this._elem = $('<table class="jqplot-table-legend" style="'+ss+'"></table>'); | |||
if (this.seriesToggle) { | |||
this._elem.css('z-index', '3'); | |||
} | |||
var pad = false, | |||
reverse = false, | |||
nr, nc; | |||
if (this.numberRows) { | |||
nr = this.numberRows; | |||
if (!this.numberColumns){ | |||
nc = Math.ceil(series.length/nr); | |||
} | |||
else{ | |||
nc = this.numberColumns; | |||
} | |||
} | |||
else if (this.numberColumns) { | |||
nc = this.numberColumns; | |||
nr = Math.ceil(series.length/this.numberColumns); | |||
} | |||
else { | |||
nr = series.length; | |||
nc = 1; | |||
} | |||
var i, j, tr, td1, td2, lt, rs; | |||
var idx = 0; | |||
// check to see if we need to reverse | |||
for (i=series.length-1; i>=0; i--) { | |||
if (series[i]._stack || series[i].renderer.constructor == $.jqplot.BezierCurveRenderer){ | |||
reverse = true; | |||
} | |||
} | |||
for (i=0; i<nr; i++) { | |||
if (reverse){ | |||
tr = $('<tr class="jqplot-table-legend"></tr>').prependTo(this._elem); | |||
} | |||
else{ | |||
tr = $('<tr class="jqplot-table-legend"></tr>').appendTo(this._elem); | |||
} | |||
for (j=0; j<nc; j++) { | |||
if (idx < series.length && series[idx].show && series[idx].showLabel){ | |||
s = series[idx]; | |||
lt = this.labels[idx] || s.label.toString(); | |||
if (lt) { | |||
var color = s.color; | |||
if (!reverse){ | |||
if (i>0){ | |||
pad = true; | |||
} | |||
else{ | |||
pad = false; | |||
} | |||
} | |||
else{ | |||
if (i == nr -1){ | |||
pad = false; | |||
} | |||
else{ | |||
pad = true; | |||
} | |||
} | |||
rs = (pad) ? this.rowSpacing : '0'; | |||
td1 = $('<td class="jqplot-table-legend" style="text-align:center;padding-top:'+rs+';">'+ | |||
'<div><div class="jqplot-table-legend-swatch" style="background-color:'+color+';border-color:'+color+';"></div>'+ | |||
'</div></td>'); | |||
td2 = $('<td class="jqplot-table-legend" style="padding-top:'+rs+';"></td>'); | |||
if (this.escapeHtml){ | |||
td2.text(lt); | |||
} | |||
else { | |||
td2.html(lt); | |||
} | |||
if (reverse) { | |||
if (this.showLabels) {td2.prependTo(tr);} | |||
if (this.showSwatches) {td1.prependTo(tr);} | |||
} | |||
else { | |||
if (this.showSwatches) {td1.appendTo(tr);} | |||
if (this.showLabels) {td2.appendTo(tr);} | |||
} | |||
if (this.seriesToggle) { | |||
var speed; | |||
if (typeof(this.seriesToggle) == 'string' || typeof(this.seriesToggle) == 'number') { | |||
if (!$.jqplot.use_excanvas || !this.disableIEFading) { | |||
speed = this.seriesToggle; | |||
} | |||
} | |||
if (this.showSwatches) { | |||
td1.bind('click', {series:s, speed:speed}, s.toggleDisplay); | |||
td1.addClass('jqplot-seriesToggle'); | |||
} | |||
if (this.showLabels) { | |||
td2.bind('click', {series:s, speed:speed}, s.toggleDisplay); | |||
td2.addClass('jqplot-seriesToggle'); | |||
} | |||
} | |||
pad = true; | |||
} | |||
} | |||
idx++; | |||
} | |||
} | |||
} | |||
return this._elem; | |||
}; | |||
// called with scope of plot. | |||
var postDraw = function () { | |||
if (this.legend.renderer.constructor == $.jqplot.EnhancedLegendRenderer && this.legend.seriesToggle){ | |||
var e = this.legend._elem.detach(); | |||
this.eventCanvas._elem.after(e); | |||
} | |||
}; | |||
})(jQuery); |
@@ -0,0 +1,30 @@ | |||
/** | |||
* jqPlot | |||
* Pure JavaScript plotting plugin using jQuery | |||
* | |||
* Version: 1.0.0b2_r792 | |||
* | |||
* Copyright (c) 2009-2011 Chris Leonello | |||
* jqPlot is currently available for use in all personal or commercial projects | |||
* under both the MIT (http://www.opensource.org/licenses/mit-license.php) and GPL | |||
* version 2.0 (http://www.gnu.org/licenses/gpl-2.0.html) licenses. This means that you can | |||
* choose the license that best suits your project and use it accordingly. | |||
* | |||
* Although not required, the author would appreciate an email letting him | |||
* know of any substantial use of jqPlot. You can reach the author at: | |||
* chris at jqplot dot com or see http://www.jqplot.com/info.php . | |||
* | |||
* If you are feeling kind and generous, consider supporting the project by | |||
* making a donation at: http://www.jqplot.com/donate.php . | |||
* | |||
* sprintf functions contained in jqplot.sprintf.js by Ash Searle: | |||
* | |||
* version 2007.04.27 | |||
* author Ash Searle | |||
* http://hexmen.com/blog/2007/03/printf-sprintf/ | |||
* http://hexmen.com/js/sprintf.js | |||
* The author (Ash Searle) has placed this code in the public domain: | |||
* "This code is unrestricted: you are free to use it however you like." | |||
* | |||
*/ | |||
(function(b){b.jqplot.EnhancedLegendRenderer=function(){b.jqplot.TableLegendRenderer.call(this)};b.jqplot.EnhancedLegendRenderer.prototype=new b.jqplot.TableLegendRenderer();b.jqplot.EnhancedLegendRenderer.prototype.constructor=b.jqplot.EnhancedLegendRenderer;b.jqplot.EnhancedLegendRenderer.prototype.init=function(c){this.numberRows=null;this.numberColumns=null;this.seriesToggle="normal";this.disableIEFading=true;b.extend(true,this,c);if(this.seriesToggle){b.jqplot.postDrawHooks.push(a)}};b.jqplot.EnhancedLegendRenderer.prototype.draw=function(){var e=this;if(this.show){var n=this._series;var o;var q="position:absolute;";q+=(this.background)?"background:"+this.background+";":"";q+=(this.border)?"border:"+this.border+";":"";q+=(this.fontSize)?"font-size:"+this.fontSize+";":"";q+=(this.fontFamily)?"font-family:"+this.fontFamily+";":"";q+=(this.textColor)?"color:"+this.textColor+";":"";q+=(this.marginTop!=null)?"margin-top:"+this.marginTop+";":"";q+=(this.marginBottom!=null)?"margin-bottom:"+this.marginBottom+";":"";q+=(this.marginLeft!=null)?"margin-left:"+this.marginLeft+";":"";q+=(this.marginRight!=null)?"margin-right:"+this.marginRight+";":"";this._elem=b('<table class="jqplot-table-legend" style="'+q+'"></table>');if(this.seriesToggle){this._elem.css("z-index","3")}var w=false,m=false,c,k;if(this.numberRows){c=this.numberRows;if(!this.numberColumns){k=Math.ceil(n.length/c)}else{k=this.numberColumns}}else{if(this.numberColumns){k=this.numberColumns;c=Math.ceil(n.length/this.numberColumns)}else{c=n.length;k=1}}var v,t,d,g,f,h,l;var p=0;for(v=n.length-1;v>=0;v--){if(n[v]._stack||n[v].renderer.constructor==b.jqplot.BezierCurveRenderer){m=true}}for(v=0;v<c;v++){if(m){d=b('<tr class="jqplot-table-legend"></tr>').prependTo(this._elem)}else{d=b('<tr class="jqplot-table-legend"></tr>').appendTo(this._elem)}for(t=0;t<k;t++){if(p<n.length&&n[p].show&&n[p].showLabel){o=n[p];h=this.labels[p]||o.label.toString();if(h){var r=o.color;if(!m){if(v>0){w=true}else{w=false}}else{if(v==c-1){w=false}else{w=true}}l=(w)?this.rowSpacing:"0";g=b('<td class="jqplot-table-legend" style="text-align:center;padding-top:'+l+';"><div><div class="jqplot-table-legend-swatch" style="background-color:'+r+";border-color:"+r+';"></div></div></td>');f=b('<td class="jqplot-table-legend" style="padding-top:'+l+';"></td>');if(this.escapeHtml){f.text(h)}else{f.html(h)}if(m){if(this.showLabels){f.prependTo(d)}if(this.showSwatches){g.prependTo(d)}}else{if(this.showSwatches){g.appendTo(d)}if(this.showLabels){f.appendTo(d)}}if(this.seriesToggle){var u;if(typeof(this.seriesToggle)=="string"||typeof(this.seriesToggle)=="number"){if(!b.jqplot.use_excanvas||!this.disableIEFading){u=this.seriesToggle}}if(this.showSwatches){g.bind("click",{series:o,speed:u},o.toggleDisplay);g.addClass("jqplot-seriesToggle")}if(this.showLabels){f.bind("click",{series:o,speed:u},o.toggleDisplay);f.addClass("jqplot-seriesToggle")}}w=true}}p++}}}return this._elem};var a=function(){if(this.legend.renderer.constructor==b.jqplot.EnhancedLegendRenderer&&this.legend.seriesToggle){var c=this.legend._elem.detach();this.eventCanvas._elem.after(c)}}})(jQuery); |
@@ -0,0 +1,938 @@ | |||
/** | |||
* jqPlot | |||
* Pure JavaScript plotting plugin using jQuery | |||
* | |||
* Version: 1.0.0b2_r792 | |||
* | |||
* Copyright (c) 2009-2011 Chris Leonello | |||
* jqPlot is currently available for use in all personal or commercial projects | |||
* under both the MIT (http://www.opensource.org/licenses/mit-license.php) and GPL | |||
* version 2.0 (http://www.gnu.org/licenses/gpl-2.0.html) licenses. This means that you can | |||
* choose the license that best suits your project and use it accordingly. | |||
* | |||
* Although not required, the author would appreciate an email letting him | |||
* know of any substantial use of jqPlot. You can reach the author at: | |||
* chris at jqplot dot com or see http://www.jqplot.com/info.php . | |||
* | |||
* If you are feeling kind and generous, consider supporting the project by | |||
* making a donation at: http://www.jqplot.com/donate.php . | |||
* | |||
* sprintf functions contained in jqplot.sprintf.js by Ash Searle: | |||
* | |||
* version 2007.04.27 | |||
* author Ash Searle | |||
* http://hexmen.com/blog/2007/03/printf-sprintf/ | |||
* http://hexmen.com/js/sprintf.js | |||
* The author (Ash Searle) has placed this code in the public domain: | |||
* "This code is unrestricted: you are free to use it however you like." | |||
* | |||
*/ | |||
(function($) { | |||
/** | |||
* Class: $.jqplot.FunnelRenderer | |||
* Plugin renderer to draw a funnel chart. | |||
* x values, if present, will be used as labels. | |||
* y values give area size. | |||
* | |||
* Funnel charts will draw a single series | |||
* only. | |||
* | |||
* To use this renderer, you need to include the | |||
* funnel renderer plugin, for example: | |||
* | |||
* > <script type="text/javascript" src="plugins/jqplot.funnelRenderer.js"></script> | |||
* | |||
* Properties described here are passed into the $.jqplot function | |||
* as options on the series renderer. For example: | |||
* | |||
* > plot2 = $.jqplot('chart2', [s1, s2], { | |||
* > seriesDefaults: { | |||
* > renderer:$.jqplot.FunnelRenderer, | |||
* > rendererOptions:{ | |||
* > sectionMargin: 12, | |||
* > widthRatio: 0.3 | |||
* > } | |||
* > } | |||
* > }); | |||
* | |||
* IMPORTANT | |||
* | |||
* *The funnel renderer will reorder data in descending order* so the largest value in | |||
* the data set is first and displayed on top of the funnel. Data will then | |||
* be displayed in descending order down the funnel. The area of each funnel | |||
* section will correspond to the value of each data point relative to the sum | |||
* of all values. That is section area is proportional to section value divided by | |||
* sum of all section values. | |||
* | |||
* If your data is not in descending order when passed into the plot, *it will be | |||
* reordered* when stored in the series.data property. A copy of the unordered | |||
* data is kept in the series._unorderedData property. | |||
* | |||
* A funnel plot will trigger events on the plot target | |||
* according to user interaction. All events return the event object, | |||
* the series index, the point (section) index, and the point data for | |||
* the appropriate section. *Note* the point index will referr to the ordered | |||
* data, not the original unordered data. | |||
* | |||
* 'jqplotDataMouseOver' - triggered when mousing over a section. | |||
* 'jqplotDataHighlight' - triggered the first time user mouses over a section, | |||
* if highlighting is enabled. | |||
* 'jqplotDataUnhighlight' - triggered when a user moves the mouse out of | |||
* a highlighted section. | |||
* 'jqplotDataClick' - triggered when the user clicks on a section. | |||
* 'jqplotDataRightClick' - tiggered when the user right clicks on a section if | |||
* the "captureRightClick" option is set to true on the plot. | |||
*/ | |||
$.jqplot.FunnelRenderer = function(){ | |||
$.jqplot.LineRenderer.call(this); | |||
}; | |||
$.jqplot.FunnelRenderer.prototype = new $.jqplot.LineRenderer(); | |||
$.jqplot.FunnelRenderer.prototype.constructor = $.jqplot.FunnelRenderer; | |||
// called with scope of a series | |||
$.jqplot.FunnelRenderer.prototype.init = function(options, plot) { | |||
// Group: Properties | |||
// | |||
// prop: padding | |||
// padding between the funnel and plot edges, legend, etc. | |||
this.padding = {top: 20, right: 20, bottom: 20, left: 20}; | |||
// prop: sectionMargin | |||
// spacing between funnel sections in pixels. | |||
this.sectionMargin = 6; | |||
// prop: fill | |||
// true or false, wether to fill the areas. | |||
this.fill = true; | |||
// prop: shadowOffset | |||
// offset of the shadow from the area and offset of | |||
// each succesive stroke of the shadow from the last. | |||
this.shadowOffset = 2; | |||
// prop: shadowAlpha | |||
// transparency of the shadow (0 = transparent, 1 = opaque) | |||
this.shadowAlpha = 0.07; | |||
// prop: shadowDepth | |||
// number of strokes to apply to the shadow, | |||
// each stroke offset shadowOffset from the last. | |||
this.shadowDepth = 5; | |||
// prop: highlightMouseOver | |||
// True to highlight area when moused over. | |||
// This must be false to enable highlightMouseDown to highlight when clicking on a area. | |||
this.highlightMouseOver = true; | |||
// prop: highlightMouseDown | |||
// True to highlight when a mouse button is pressed over a area. | |||
// This will be disabled if highlightMouseOver is true. | |||
this.highlightMouseDown = false; | |||
// prop: highlightColors | |||
// array of colors to use when highlighting an area. | |||
this.highlightColors = []; | |||
// prop: widthRatio | |||
// The ratio of the width of the top of the funnel to the bottom. | |||
// a ratio of 0 will make an upside down pyramid. | |||
this.widthRatio = 0.2; | |||
// prop: lineWidth | |||
// width of line if areas are stroked and not filled. | |||
this.lineWidth = 2; | |||
// prop: dataLabels | |||
// Either 'label', 'value', 'percent' or an array of labels to place on the pie slices. | |||
// Defaults to percentage of each pie slice. | |||
this.dataLabels = 'percent'; | |||
// prop: showDataLabels | |||
// true to show data labels on slices. | |||
this.showDataLabels = false; | |||
// prop: dataLabelFormatString | |||
// Format string for data labels. If none, '%s' is used for "label" and for arrays, '%d' for value and '%d%%' for percentage. | |||
this.dataLabelFormatString = null; | |||
// prop: dataLabelThreshold | |||
// Threshhold in percentage (0 - 100) of pie area, below which no label will be displayed. | |||
// This applies to all label types, not just to percentage labels. | |||
this.dataLabelThreshold = 3; | |||
this._type = 'funnel'; | |||
this.tickRenderer = $.jqplot.FunnelTickRenderer; | |||
// if user has passed in highlightMouseDown option and not set highlightMouseOver, disable highlightMouseOver | |||
if (options.highlightMouseDown && options.highlightMouseOver == null) { | |||
options.highlightMouseOver = false; | |||
} | |||
$.extend(true, this, options); | |||
// index of the currenty highlighted point, if any | |||
this._highlightedPoint = null; | |||
// lengths of bases, or horizontal sides of areas of trapezoid. | |||
this._bases = []; | |||
// total area | |||
this._atot; | |||
// areas of segments. | |||
this._areas = []; | |||
// vertical lengths of segments. | |||
this._lengths = []; | |||
// angle of the funnel to vertical. | |||
this._angle; | |||
this._dataIndices = []; | |||
// sort data | |||
this._unorderedData = $.extend(true, [], this.data); | |||
var idxs = $.extend(true, [], this.data); | |||
for (var i=0; i<idxs.length; i++) { | |||
idxs[i].push(i); | |||
} | |||
this.data.sort( function (a, b) { return b[1] - a[1]; } ); | |||
idxs.sort( function (a, b) { return b[1] - a[1]; }); | |||
for (var i=0; i<idxs.length; i++) { | |||
this._dataIndices.push(idxs[i][2]); | |||
} | |||
// set highlight colors if none provided | |||
if (this.highlightColors.length == 0) { | |||
for (var i=0; i<this.seriesColors.length; i++){ | |||
var rgba = $.jqplot.getColorComponents(this.seriesColors[i]); | |||
var newrgb = [rgba[0], rgba[1], rgba[2]]; | |||
var sum = newrgb[0] + newrgb[1] + newrgb[2]; | |||
for (var j=0; j<3; j++) { | |||
// when darkening, lowest color component can be is 60. | |||
newrgb[j] = (sum > 570) ? newrgb[j] * 0.8 : newrgb[j] + 0.4 * (255 - newrgb[j]); | |||
newrgb[j] = parseInt(newrgb[j], 10); | |||
} | |||
this.highlightColors.push('rgb('+newrgb[0]+','+newrgb[1]+','+newrgb[2]+')'); | |||
} | |||
} | |||
plot.postParseOptionsHooks.addOnce(postParseOptions); | |||
plot.postInitHooks.addOnce(postInit); | |||
plot.eventListenerHooks.addOnce('jqplotMouseMove', handleMove); | |||
plot.eventListenerHooks.addOnce('jqplotMouseDown', handleMouseDown); | |||
plot.eventListenerHooks.addOnce('jqplotMouseUp', handleMouseUp); | |||
plot.eventListenerHooks.addOnce('jqplotClick', handleClick); | |||
plot.eventListenerHooks.addOnce('jqplotRightClick', handleRightClick); | |||
plot.postDrawHooks.addOnce(postPlotDraw); | |||
}; | |||
// gridData will be of form [label, percentage of total] | |||
$.jqplot.FunnelRenderer.prototype.setGridData = function(plot) { | |||
// set gridData property. This will hold angle in radians of each data point. | |||
var sum = 0; | |||
var td = []; | |||
for (var i=0; i<this.data.length; i++){ | |||
sum += this.data[i][1]; | |||
td.push([this.data[i][0], this.data[i][1]]); | |||
} | |||
// normalize y values, so areas are proportional. | |||
for (var i=0; i<td.length; i++) { | |||
td[i][1] = td[i][1]/sum; | |||
} | |||
this._bases = new Array(td.length + 1); | |||
this._lengths = new Array(td.length); | |||
this.gridData = td; | |||
}; | |||
$.jqplot.FunnelRenderer.prototype.makeGridData = function(data, plot) { | |||
// set gridData property. This will hold angle in radians of each data point. | |||
var sum = 0; | |||
var td = []; | |||
for (var i=0; i<this.data.length; i++){ | |||
sum += this.data[i][1]; | |||
td.push([this.data[i][0], this.data[i][1]]); | |||
} | |||
// normalize y values, so areas are proportional. | |||
for (var i=0; i<td.length; i++) { | |||
td[i][1] = td[i][1]/sum; | |||
} | |||
this._bases = new Array(td.length + 1); | |||
this._lengths = new Array(td.length); | |||
return td; | |||
}; | |||
$.jqplot.FunnelRenderer.prototype.drawSection = function (ctx, vertices, color, isShadow) { | |||
var fill = this.fill; | |||
var lineWidth = this.lineWidth; | |||
ctx.save(); | |||
if (isShadow) { | |||
for (var i=0; i<this.shadowDepth; i++) { | |||
ctx.save(); | |||
ctx.translate(this.shadowOffset*Math.cos(this.shadowAngle/180*Math.PI), this.shadowOffset*Math.sin(this.shadowAngle/180*Math.PI)); | |||
doDraw(); | |||
} | |||
} | |||
else { | |||
doDraw(); | |||
} | |||
function doDraw () { | |||
ctx.beginPath(); | |||
ctx.fillStyle = color; | |||
ctx.strokeStyle = color; | |||
ctx.lineWidth = lineWidth; | |||
ctx.moveTo(vertices[0][0], vertices[0][1]); | |||
for (var i=1; i<4; i++) { | |||
ctx.lineTo(vertices[i][0], vertices[i][1]); | |||
} | |||
ctx.closePath(); | |||
if (fill) { | |||
ctx.fill(); | |||
} | |||
else { | |||
ctx.stroke(); | |||
} | |||
} | |||
if (isShadow) { | |||
for (var i=0; i<this.shadowDepth; i++) { | |||
ctx.restore(); | |||
} | |||
} | |||
ctx.restore(); | |||
}; | |||
// called with scope of series | |||
$.jqplot.FunnelRenderer.prototype.draw = function (ctx, gd, options, plot) { | |||
var i; | |||
var opts = (options != undefined) ? options : {}; | |||
// offset and direction of offset due to legend placement | |||
var offx = 0; | |||
var offy = 0; | |||
var trans = 1; | |||
this._areas = []; | |||
// var colorGenerator = new this.colorGenerator(this.seriesColors); | |||
if (options.legendInfo && options.legendInfo.placement == 'insideGrid') { | |||
var li = options.legendInfo; | |||
switch (li.location) { | |||
case 'nw': | |||
offx = li.width + li.xoffset; | |||
break; | |||
case 'w': | |||
offx = li.width + li.xoffset; | |||
break; | |||
case 'sw': | |||
offx = li.width + li.xoffset; | |||
break; | |||
case 'ne': | |||
offx = li.width + li.xoffset; | |||
trans = -1; | |||
break; | |||
case 'e': | |||
offx = li.width + li.xoffset; | |||
trans = -1; | |||
break; | |||
case 'se': | |||
offx = li.width + li.xoffset; | |||
trans = -1; | |||
break; | |||
case 'n': | |||
offy = li.height + li.yoffset; | |||
break; | |||
case 's': | |||
offy = li.height + li.yoffset; | |||
trans = -1; | |||
break; | |||
default: | |||
break; | |||
} | |||
} | |||
var loff = (trans==1) ? this.padding.left + offx : this.padding.left; | |||
var toff = (trans==1) ? this.padding.top + offy : this.padding.top; | |||
var roff = (trans==-1) ? this.padding.right + offx : this.padding.right; | |||
var boff = (trans==-1) ? this.padding.bottom + offy : this.padding.bottom; | |||
var shadow = (opts.shadow != undefined) ? opts.shadow : this.shadow; | |||
var showLine = (opts.showLine != undefined) ? opts.showLine : this.showLine; | |||
var fill = (opts.fill != undefined) ? opts.fill : this.fill; | |||
var cw = ctx.canvas.width; | |||
var ch = ctx.canvas.height; | |||
this._bases[0] = cw - loff - roff; | |||
var ltot = this._length = ch - toff - boff; | |||
var hend = this._bases[0]*this.widthRatio; | |||
this._atot = ltot/2 * (this._bases[0] + this._bases[0]*this.widthRatio); | |||
this._angle = Math.atan((this._bases[0] - hend)/2/ltot); | |||
for (i=0; i<gd.length; i++) { | |||
this._areas.push(gd[i][1] * this._atot); | |||
} | |||
var guess, err, count, lsum=0; | |||
var tolerance = 0.0001; | |||
for (i=0; i<this._areas.length; i++) { | |||
guess = this._areas[i]/this._bases[i]; | |||
err = 999999; | |||
this._lengths[i] = guess; | |||
count = 0; | |||
while (err > this._lengths[i]*tolerance && count < 100) { | |||
this._lengths[i] = this._areas[i]/(this._bases[i] - this._lengths[i] * Math.tan(this._angle)); | |||
err = Math.abs(this._lengths[i] - guess); | |||
this._bases[i+1] = this._bases[i] - (2*this._lengths[i]*Math.tan(this._angle)); | |||
guess = this._lengths[i]; | |||
count++; | |||
} | |||
lsum += this._lengths[i]; | |||
} | |||
// figure out vertices of each section | |||
this._vertices = new Array(gd.length); | |||
// these are 4 coners of entire trapezoid | |||
var p0 = [loff, toff], | |||
p1 = [loff+this._bases[0], toff], | |||
p2 = [loff + (this._bases[0] - this._bases[this._bases.length-1])/2, toff + this._length], | |||
p3 = [p2[0] + this._bases[this._bases.length-1], p2[1]]; | |||
// equations of right and left sides, returns x, y values given height of section (y value) | |||
function findleft (l) { | |||
var m = (p0[1] - p2[1])/(p0[0] - p2[0]); | |||
var b = p0[1] - m*p0[0]; | |||
var y = l + p0[1]; | |||
return [(y - b)/m, y]; | |||
} | |||
function findright (l) { | |||
var m = (p1[1] - p3[1])/(p1[0] - p3[0]); | |||
var b = p1[1] - m*p1[0]; | |||
var y = l + p1[1]; | |||
return [(y - b)/m, y]; | |||
} | |||
var x = offx, y = offy; | |||
var h=0, adj=0; | |||
for (i=0; i<gd.length; i++) { | |||
this._vertices[i] = new Array(); | |||
var v = this._vertices[i]; | |||
var sm = this.sectionMargin; | |||
if (i == 0) { | |||
adj = 0; | |||
} | |||
if (i == 1) { | |||
adj = sm/3; | |||
} | |||
else if (i > 0 && i < gd.length-1) { | |||
adj = sm/2; | |||
} | |||
else if (i == gd.length -1) { | |||
adj = 2*sm/3; | |||
} | |||
v.push(findleft(h+adj)); | |||
v.push(findright(h+adj)); | |||
h += this._lengths[i]; | |||
if (i == 0) { | |||
adj = -2*sm/3; | |||
} | |||
else if (i > 0 && i < gd.length-1) { | |||
adj = -sm/2; | |||
} | |||
else if (i == gd.length - 1) { | |||
adj = 0; | |||
} | |||
v.push(findright(h+adj)); | |||
v.push(findleft(h+adj)); | |||
} | |||
if (this.shadow) { | |||
var shadowColor = 'rgba(0,0,0,'+this.shadowAlpha+')'; | |||
for (var i=0; i<gd.length; i++) { | |||
this.renderer.drawSection.call (this, ctx, this._vertices[i], shadowColor, true); | |||
} | |||
} | |||
for (var i=0; i<gd.length; i++) { | |||
var v = this._vertices[i]; | |||
this.renderer.drawSection.call (this, ctx, v, this.seriesColors[i]); | |||
if (this.showDataLabels && gd[i][1]*100 >= this.dataLabelThreshold) { | |||
var fstr, label; | |||
if (this.dataLabels == 'label') { | |||
fstr = this.dataLabelFormatString || '%s'; | |||
label = $.jqplot.sprintf(fstr, gd[i][0]); | |||
} | |||
else if (this.dataLabels == 'value') { | |||
fstr = this.dataLabelFormatString || '%d'; | |||
label = $.jqplot.sprintf(fstr, this.data[i][1]); | |||
} | |||
else if (this.dataLabels == 'percent') { | |||
fstr = this.dataLabelFormatString || '%d%%'; | |||
label = $.jqplot.sprintf(fstr, gd[i][1]*100); | |||
} | |||
else if (this.dataLabels.constructor == Array) { | |||
fstr = this.dataLabelFormatString || '%s'; | |||
label = $.jqplot.sprintf(fstr, this.dataLabels[this._dataIndices[i]]); | |||
} | |||
var fact = (this._radius ) * this.dataLabelPositionFactor + this.sliceMargin + this.dataLabelNudge; | |||
var x = (v[0][0] + v[1][0])/2 + this.canvas._offsets.left; | |||
var y = (v[1][1] + v[2][1])/2 + this.canvas._offsets.top; | |||
var labelelem = $('<span class="jqplot-funnel-series jqplot-data-label" style="position:absolute;">' + label + '</span>').insertBefore(plot.eventCanvas._elem); | |||
x -= labelelem.width()/2; | |||
y -= labelelem.height()/2; | |||
x = Math.round(x); | |||
y = Math.round(y); | |||
labelelem.css({left: x, top: y}); | |||
} | |||
} | |||
}; | |||
$.jqplot.FunnelAxisRenderer = function() { | |||
$.jqplot.LinearAxisRenderer.call(this); | |||
}; | |||
$.jqplot.FunnelAxisRenderer.prototype = new $.jqplot.LinearAxisRenderer(); | |||
$.jqplot.FunnelAxisRenderer.prototype.constructor = $.jqplot.FunnelAxisRenderer; | |||
// There are no traditional axes on a funnel chart. We just need to provide | |||
// dummy objects with properties so the plot will render. | |||
// called with scope of axis object. | |||
$.jqplot.FunnelAxisRenderer.prototype.init = function(options){ | |||
// | |||
this.tickRenderer = $.jqplot.FunnelTickRenderer; | |||
$.extend(true, this, options); | |||
// I don't think I'm going to need _dataBounds here. | |||
// have to go Axis scaling in a way to fit chart onto plot area | |||
// and provide u2p and p2u functionality for mouse cursor, etc. | |||
// for convienence set _dataBounds to 0 and 100 and | |||
// set min/max to 0 and 100. | |||
this._dataBounds = {min:0, max:100}; | |||
this.min = 0; | |||
this.max = 100; | |||
this.showTicks = false; | |||
this.ticks = []; | |||
this.showMark = false; | |||
this.show = false; | |||
}; | |||
/** | |||
* Class: $.jqplot.FunnelLegendRenderer | |||
* Legend Renderer specific to funnel plots. Set by default | |||
* when the user creates a funnel plot. | |||
*/ | |||
$.jqplot.FunnelLegendRenderer = function(){ | |||
$.jqplot.TableLegendRenderer.call(this); | |||
}; | |||
$.jqplot.FunnelLegendRenderer.prototype = new $.jqplot.TableLegendRenderer(); | |||
$.jqplot.FunnelLegendRenderer.prototype.constructor = $.jqplot.FunnelLegendRenderer; | |||
$.jqplot.FunnelLegendRenderer.prototype.init = function(options) { | |||
// Group: Properties | |||
// | |||
// prop: numberRows | |||
// Maximum number of rows in the legend. 0 or null for unlimited. | |||
this.numberRows = null; | |||
// prop: numberColumns | |||
// Maximum number of columns in the legend. 0 or null for unlimited. | |||
this.numberColumns = null; | |||
$.extend(true, this, options); | |||
}; | |||
// called with context of legend | |||
$.jqplot.FunnelLegendRenderer.prototype.draw = function() { | |||
var legend = this; | |||
if (this.show) { | |||
var series = this._series; | |||
var ss = 'position:absolute;'; | |||
ss += (this.background) ? 'background:'+this.background+';' : ''; | |||
ss += (this.border) ? 'border:'+this.border+';' : ''; | |||
ss += (this.fontSize) ? 'font-size:'+this.fontSize+';' : ''; | |||
ss += (this.fontFamily) ? 'font-family:'+this.fontFamily+';' : ''; | |||
ss += (this.textColor) ? 'color:'+this.textColor+';' : ''; | |||
ss += (this.marginTop != null) ? 'margin-top:'+this.marginTop+';' : ''; | |||
ss += (this.marginBottom != null) ? 'margin-bottom:'+this.marginBottom+';' : ''; | |||
ss += (this.marginLeft != null) ? 'margin-left:'+this.marginLeft+';' : ''; | |||
ss += (this.marginRight != null) ? 'margin-right:'+this.marginRight+';' : ''; | |||
this._elem = $('<table class="jqplot-table-legend" style="'+ss+'"></table>'); | |||
// Funnel charts legends don't go by number of series, but by number of data points | |||
// in the series. Refactor things here for that. | |||
var pad = false, | |||
reverse = false, | |||
nr, nc; | |||
var s = series[0]; | |||
var colorGenerator = new $.jqplot.ColorGenerator(s.seriesColors); | |||
if (s.show) { | |||
var pd = s.data; | |||
if (this.numberRows) { | |||
nr = this.numberRows; | |||
if (!this.numberColumns){ | |||
nc = Math.ceil(pd.length/nr); | |||
} | |||
else{ | |||
nc = this.numberColumns; | |||
} | |||
} | |||
else if (this.numberColumns) { | |||
nc = this.numberColumns; | |||
nr = Math.ceil(pd.length/this.numberColumns); | |||
} | |||
else { | |||
nr = pd.length; | |||
nc = 1; | |||
} | |||
var i, j, tr, td1, td2, lt, rs, color; | |||
var idx = 0; | |||
for (i=0; i<nr; i++) { | |||
if (reverse){ | |||
tr = $('<tr class="jqplot-table-legend"></tr>').prependTo(this._elem); | |||
} | |||
else{ | |||
tr = $('<tr class="jqplot-table-legend"></tr>').appendTo(this._elem); | |||
} | |||
for (j=0; j<nc; j++) { | |||
if (idx < pd.length){ | |||
lt = this.labels[idx] || pd[idx][0].toString(); | |||
color = colorGenerator.next(); | |||
if (!reverse){ | |||
if (i>0){ | |||
pad = true; | |||
} | |||
else{ | |||
pad = false; | |||
} | |||
} | |||
else{ | |||
if (i == nr -1){ | |||
pad = false; | |||
} | |||
else{ | |||
pad = true; | |||
} | |||
} | |||
rs = (pad) ? this.rowSpacing : '0'; | |||
td1 = $('<td class="jqplot-table-legend" style="text-align:center;padding-top:'+rs+';">'+ | |||
'<div><div class="jqplot-table-legend-swatch" style="border-color:'+color+';"></div>'+ | |||
'</div></td>'); | |||
td2 = $('<td class="jqplot-table-legend" style="padding-top:'+rs+';"></td>'); | |||
if (this.escapeHtml){ | |||
td2.text(lt); | |||
} | |||
else { | |||
td2.html(lt); | |||
} | |||
if (reverse) { | |||
td2.prependTo(tr); | |||
td1.prependTo(tr); | |||
} | |||
else { | |||
td1.appendTo(tr); | |||
td2.appendTo(tr); | |||
} | |||
pad = true; | |||
} | |||
idx++; | |||
} | |||
} | |||
} | |||
} | |||
return this._elem; | |||
}; | |||
// $.jqplot.FunnelLegendRenderer.prototype.pack = function(offsets) { | |||
// if (this.show) { | |||
// // fake a grid for positioning | |||
// var grid = {_top:offsets.top, _left:offsets.left, _right:offsets.right, _bottom:this._plotDimensions.height - offsets.bottom}; | |||
// if (this.placement == 'insideGrid') { | |||
// switch (this.location) { | |||
// case 'nw': | |||
// var a = grid._left + this.xoffset; | |||
// var b = grid._top + this.yoffset; | |||
// this._elem.css('left', a); | |||
// this._elem.css('top', b); | |||
// break; | |||
// case 'n': | |||
// var a = (offsets.left + (this._plotDimensions.width - offsets.right))/2 - this.getWidth()/2; | |||
// var b = grid._top + this.yoffset; | |||
// this._elem.css('left', a); | |||
// this._elem.css('top', b); | |||
// break; | |||
// case 'ne': | |||
// var a = offsets.right + this.xoffset; | |||
// var b = grid._top + this.yoffset; | |||
// this._elem.css({right:a, top:b}); | |||
// break; | |||
// case 'e': | |||
// var a = offsets.right + this.xoffset; | |||
// var b = (offsets.top + (this._plotDimensions.height - offsets.bottom))/2 - this.getHeight()/2; | |||
// this._elem.css({right:a, top:b}); | |||
// break; | |||
// case 'se': | |||
// var a = offsets.right + this.xoffset; | |||
// var b = offsets.bottom + this.yoffset; | |||
// this._elem.css({right:a, bottom:b}); | |||
// break; | |||
// case 's': | |||
// var a = (offsets.left + (this._plotDimensions.width - offsets.right))/2 - this.getWidth()/2; | |||
// var b = offsets.bottom + this.yoffset; | |||
// this._elem.css({left:a, bottom:b}); | |||
// break; | |||
// case 'sw': | |||
// var a = grid._left + this.xoffset; | |||
// var b = offsets.bottom + this.yoffset; | |||
// this._elem.css({left:a, bottom:b}); | |||
// break; | |||
// case 'w': | |||
// var a = grid._left + this.xoffset; | |||
// var b = (offsets.top + (this._plotDimensions.height - offsets.bottom))/2 - this.getHeight()/2; | |||
// this._elem.css({left:a, top:b}); | |||
// break; | |||
// default: // same as 'se' | |||
// var a = grid._right - this.xoffset; | |||
// var b = grid._bottom + this.yoffset; | |||
// this._elem.css({right:a, bottom:b}); | |||
// break; | |||
// } | |||
// | |||
// } | |||
// else { | |||
// switch (this.location) { | |||
// case 'nw': | |||
// var a = this._plotDimensions.width - grid._left + this.xoffset; | |||
// var b = grid._top + this.yoffset; | |||
// this._elem.css('right', a); | |||
// this._elem.css('top', b); | |||
// break; | |||
// case 'n': | |||
// var a = (offsets.left + (this._plotDimensions.width - offsets.right))/2 - this.getWidth()/2; | |||
// var b = this._plotDimensions.height - grid._top + this.yoffset; | |||
// this._elem.css('left', a); | |||
// this._elem.css('bottom', b); | |||
// break; | |||
// case 'ne': | |||
// var a = this._plotDimensions.width - offsets.right + this.xoffset; | |||
// var b = grid._top + this.yoffset; | |||
// this._elem.css({left:a, top:b}); | |||
// break; | |||
// case 'e': | |||
// var a = this._plotDimensions.width - offsets.right + this.xoffset; | |||
// var b = (offsets.top + (this._plotDimensions.height - offsets.bottom))/2 - this.getHeight()/2; | |||
// this._elem.css({left:a, top:b}); | |||
// break; | |||
// case 'se': | |||
// var a = this._plotDimensions.width - offsets.right + this.xoffset; | |||
// var b = offsets.bottom + this.yoffset; | |||
// this._elem.css({left:a, bottom:b}); | |||
// break; | |||
// case 's': | |||
// var a = (offsets.left + (this._plotDimensions.width - offsets.right))/2 - this.getWidth()/2; | |||
// var b = this._plotDimensions.height - offsets.bottom + this.yoffset; | |||
// this._elem.css({left:a, top:b}); | |||
// break; | |||
// case 'sw': | |||
// var a = this._plotDimensions.width - grid._left + this.xoffset; | |||
// var b = offsets.bottom + this.yoffset; | |||
// this._elem.css({right:a, bottom:b}); | |||
// break; | |||
// case 'w': | |||
// var a = this._plotDimensions.width - grid._left + this.xoffset; | |||
// var b = (offsets.top + (this._plotDimensions.height - offsets.bottom))/2 - this.getHeight()/2; | |||
// this._elem.css({right:a, top:b}); | |||
// break; | |||
// default: // same as 'se' | |||
// var a = grid._right - this.xoffset; | |||
// var b = grid._bottom + this.yoffset; | |||
// this._elem.css({right:a, bottom:b}); | |||
// break; | |||
// } | |||
// } | |||
// } | |||
// }; | |||
// setup default renderers for axes and legend so user doesn't have to | |||
// called with scope of plot | |||
function preInit(target, data, options) { | |||
options = options || {}; | |||
options.axesDefaults = options.axesDefaults || {}; | |||
options.legend = options.legend || {}; | |||
options.seriesDefaults = options.seriesDefaults || {}; | |||
// only set these if there is a funnel series | |||
var setopts = false; | |||
if (options.seriesDefaults.renderer == $.jqplot.FunnelRenderer) { | |||
setopts = true; | |||
} | |||
else if (options.series) { | |||
for (var i=0; i < options.series.length; i++) { | |||
if (options.series[i].renderer == $.jqplot.FunnelRenderer) { | |||
setopts = true; | |||
} | |||
} | |||
} | |||
if (setopts) { | |||
options.axesDefaults.renderer = $.jqplot.FunnelAxisRenderer; | |||
options.legend.renderer = $.jqplot.FunnelLegendRenderer; | |||
options.legend.preDraw = true; | |||
options.sortData = false; | |||
options.seriesDefaults.pointLabels = {show: false}; | |||
} | |||
} | |||
function postInit(target, data, options) { | |||
// if multiple series, add a reference to the previous one so that | |||
// funnel rings can nest. | |||
for (var i=0; i<this.series.length; i++) { | |||
if (this.series[i].renderer.constructor == $.jqplot.FunnelRenderer) { | |||
// don't allow mouseover and mousedown at same time. | |||
if (this.series[i].highlightMouseOver) { | |||
this.series[i].highlightMouseDown = false; | |||
} | |||
} | |||
} | |||
this.target.bind('mouseout', {plot:this}, function (ev) { unhighlight(ev.data.plot); }); | |||
} | |||
// called with scope of plot | |||
function postParseOptions(options) { | |||
for (var i=0; i<this.series.length; i++) { | |||
this.series[i].seriesColors = this.seriesColors; | |||
this.series[i].colorGenerator = this.colorGenerator; | |||
} | |||
} | |||
function highlight (plot, sidx, pidx) { | |||
var s = plot.series[sidx]; | |||
var canvas = plot.plugins.funnelRenderer.highlightCanvas; | |||
canvas._ctx.clearRect(0,0,canvas._ctx.canvas.width, canvas._ctx.canvas.height); | |||
s._highlightedPoint = pidx; | |||
plot.plugins.funnelRenderer.highlightedSeriesIndex = sidx; | |||
s.renderer.drawSection.call(s, canvas._ctx, s._vertices[pidx], s.highlightColors[pidx], false); | |||
} | |||
function unhighlight (plot) { | |||
var canvas = plot.plugins.funnelRenderer.highlightCanvas; | |||
canvas._ctx.clearRect(0,0, canvas._ctx.canvas.width, canvas._ctx.canvas.height); | |||
for (var i=0; i<plot.series.length; i++) { | |||
plot.series[i]._highlightedPoint = null; | |||
} | |||
plot.plugins.funnelRenderer.highlightedSeriesIndex = null; | |||
plot.target.trigger('jqplotDataUnhighlight'); | |||
} | |||
function handleMove(ev, gridpos, datapos, neighbor, plot) { | |||
if (neighbor) { | |||
var ins = [neighbor.seriesIndex, neighbor.pointIndex, neighbor.data]; | |||
var evt1 = jQuery.Event('jqplotDataMouseOver'); | |||
evt1.pageX = ev.pageX; | |||
evt1.pageY = ev.pageY; | |||
plot.target.trigger(evt1, ins); | |||
if (plot.series[ins[0]].highlightMouseOver && !(ins[0] == plot.plugins.funnelRenderer.highlightedSeriesIndex && ins[1] == plot.series[ins[0]]._highlightedPoint)) { | |||
var evt = jQuery.Event('jqplotDataHighlight'); | |||
evt.pageX = ev.pageX; | |||
evt.pageY = ev.pageY; | |||
plot.target.trigger(evt, ins); | |||
highlight (plot, ins[0], ins[1]); | |||
} | |||
} | |||
else if (neighbor == null) { | |||
unhighlight (plot); | |||
} | |||
} | |||
function handleMouseDown(ev, gridpos, datapos, neighbor, plot) { | |||
if (neighbor) { | |||
var ins = [neighbor.seriesIndex, neighbor.pointIndex, neighbor.data]; | |||
if (plot.series[ins[0]].highlightMouseDown && !(ins[0] == plot.plugins.funnelRenderer.highlightedSeriesIndex && ins[1] == plot.series[ins[0]]._highlightedPoint)) { | |||
var evt = jQuery.Event('jqplotDataHighlight'); | |||
evt.pageX = ev.pageX; | |||
evt.pageY = ev.pageY; | |||
plot.target.trigger(evt, ins); | |||
highlight (plot, ins[0], ins[1]); | |||
} | |||
} | |||
else if (neighbor == null) { | |||
unhighlight (plot); | |||
} | |||
} | |||
function handleMouseUp(ev, gridpos, datapos, neighbor, plot) { | |||
var idx = plot.plugins.funnelRenderer.highlightedSeriesIndex; | |||
if (idx != null && plot.series[idx].highlightMouseDown) { | |||
unhighlight(plot); | |||
} | |||
} | |||
function handleClick(ev, gridpos, datapos, neighbor, plot) { | |||
if (neighbor) { | |||
var ins = [neighbor.seriesIndex, neighbor.pointIndex, neighbor.data]; | |||
var evt = jQuery.Event('jqplotDataClick'); | |||
evt.pageX = ev.pageX; | |||
evt.pageY = ev.pageY; | |||
plot.target.trigger(evt, ins); | |||
} | |||
} | |||
function handleRightClick(ev, gridpos, datapos, neighbor, plot) { | |||
if (neighbor) { | |||
var ins = [neighbor.seriesIndex, neighbor.pointIndex, neighbor.data]; | |||
var idx = plot.plugins.funnelRenderer.highlightedSeriesIndex; | |||
if (idx != null && plot.series[idx].highlightMouseDown) { | |||
unhighlight(plot); | |||
} | |||
var evt = jQuery.Event('jqplotDataRightClick'); | |||
evt.pageX = ev.pageX; | |||
evt.pageY = ev.pageY; | |||
plot.target.trigger(evt, ins); | |||
} | |||
} | |||
// called within context of plot | |||
// create a canvas which we can draw on. | |||
// insert it before the eventCanvas, so eventCanvas will still capture events. | |||
function postPlotDraw() { | |||
// Memory Leaks patch | |||
if (this.plugins.funnelRenderer && this.plugins.funnelRenderer.highlightCanvas) { | |||
this.plugins.funnelRenderer.highlightCanvas.resetCanvas(); | |||
this.plugins.funnelRenderer.highlightCanvas = null; | |||
} | |||
this.plugins.funnelRenderer = {}; | |||
this.plugins.funnelRenderer.highlightCanvas = new $.jqplot.GenericCanvas(); | |||
// do we have any data labels? if so, put highlight canvas before those | |||
var labels = $(this.targetId+' .jqplot-data-label'); | |||
if (labels.length) { | |||
$(labels[0]).before(this.plugins.funnelRenderer.highlightCanvas.createElement(this._gridPadding, 'jqplot-funnelRenderer-highlight-canvas', this._plotDimensions, this)); | |||
} | |||
// else put highlight canvas before event canvas. | |||
else { | |||
this.eventCanvas._elem.before(this.plugins.funnelRenderer.highlightCanvas.createElement(this._gridPadding, 'jqplot-funnelRenderer-highlight-canvas', this._plotDimensions, this)); | |||
} | |||
var hctx = this.plugins.funnelRenderer.highlightCanvas.setContext(); | |||
} | |||
$.jqplot.preInitHooks.push(preInit); | |||
$.jqplot.FunnelTickRenderer = function() { | |||
$.jqplot.AxisTickRenderer.call(this); | |||
}; | |||
$.jqplot.FunnelTickRenderer.prototype = new $.jqplot.AxisTickRenderer(); | |||
$.jqplot.FunnelTickRenderer.prototype.constructor = $.jqplot.FunnelTickRenderer; | |||
})(jQuery); | |||
@@ -1,18 +1,30 @@ | |||
/** | |||
* Copyright (c) 2009 Chris Leonello | |||
* jqPlot | |||
* Pure JavaScript plotting plugin using jQuery | |||
* | |||
* Version: 1.0.0b2_r792 | |||
* | |||
* Copyright (c) 2009-2011 Chris Leonello | |||
* jqPlot is currently available for use in all personal or commercial projects | |||
* under both the MIT and GPL version 2.0 licenses. This means that you can | |||
* under both the MIT (http://www.opensource.org/licenses/mit-license.php) and GPL | |||
* version 2.0 (http://www.gnu.org/licenses/gpl-2.0.html) licenses. This means that you can | |||
* choose the license that best suits your project and use it accordingly. | |||
* | |||
* The author would appreciate an email letting him know of any substantial | |||
* use of jqPlot. You can reach the author at: chris dot leonello at gmail | |||
* dot com or see http://www.jqplot.com/info.php . This is, of course, | |||
* not required. | |||
* Although not required, the author would appreciate an email letting him | |||
* know of any substantial use of jqPlot. You can reach the author at: | |||
* chris at jqplot dot com or see http://www.jqplot.com/info.php . | |||
* | |||
* If you are feeling kind and generous, consider supporting the project by | |||
* making a donation at: http://www.jqplot.com/donate.php . | |||
* | |||
* Thanks for using jqPlot! | |||
* sprintf functions contained in jqplot.sprintf.js by Ash Searle: | |||
* | |||
* version 2007.04.27 | |||
* author Ash Searle | |||
* http://hexmen.com/blog/2007/03/printf-sprintf/ | |||
* http://hexmen.com/js/sprintf.js | |||
* The author (Ash Searle) has placed this code in the public domain: | |||
* "This code is unrestricted: you are free to use it however you like." | |||
* | |||
*/ | |||
(function($) { | |||
@@ -86,7 +98,7 @@ | |||
// prop: tooltipLocation | |||
// Where to position tooltip, 'n', 'ne', 'e', 'se', 's', 'sw', 'w', 'nw' | |||
this.tooltipLocation = 'nw'; | |||
// prop: tooltipFade | |||
// prop: fadeTooltip | |||
// true = fade in/out tooltip, flase = show/hide tooltip | |||
this.fadeTooltip = true; | |||
// prop: tooltipFadeSpeed | |||
@@ -102,6 +114,12 @@ | |||
// prop; tooltipSeparator | |||
// String to use to separate x and y axes in tooltip. | |||
this.tooltipSeparator = ', '; | |||
// prop; tooltipContentEditor | |||
// Function used to edit/augment/replace the formatted tooltip contents. | |||
// Called as str = tooltipContentEditor(str, seriesIndex, pointIndex) | |||
// where str is the generated tooltip html and seriesIndex and pointIndex identify | |||
// the data point being highlighted. Should return the html for the tooltip contents. | |||
this.tooltipContentEditor = null; | |||
// prop: useAxesFormatters | |||
// Use the x and y axes formatters to format the text in the tooltip. | |||
this.useAxesFormatters = true; | |||
@@ -126,12 +144,21 @@ | |||
// Typically this is 1. Certain plots, like OHLC, will | |||
// have more y values in each data point array. | |||
this.yvalues = 1; | |||
// prop: bringSeriesToFront | |||
// This option requires jQuery 1.4+ | |||
// True to bring the series of the highlighted point to the front | |||
// of other series. | |||
this.bringSeriesToFront = false; | |||
this._tooltipElem; | |||
this.isHighlighting = false; | |||
$.extend(true, this, options); | |||
}; | |||
var locations = ['nw', 'n', 'ne', 'e', 'se', 's', 'sw', 'w']; | |||
var locationIndicies = {'nw':0, 'n':1, 'ne':2, 'e':3, 'se':4, 's':5, 'sw':6, 'w':7}; | |||
var oppositeLocations = ['se', 's', 'sw', 'w', 'nw', 'n', 'ne', 'e']; | |||
// axis.renderer.tickrenderer.formatter | |||
// called with scope of plot | |||
@@ -143,6 +170,8 @@ | |||
// called within scope of series | |||
$.jqplot.Highlighter.parseOptions = function (defaults, options) { | |||
// Add a showHighlight option to the series | |||
// and set it to true by default. | |||
this.showHighlight = true; | |||
}; | |||
@@ -150,14 +179,29 @@ | |||
// create a canvas which we can draw on. | |||
// insert it before the eventCanvas, so eventCanvas will still capture events. | |||
$.jqplot.Highlighter.postPlotDraw = function() { | |||
// Memory Leaks patch | |||
if (this.plugins.highlighter && this.plugins.highlighter.highlightCanvas) { | |||
this.plugins.highlighter.highlightCanvas.resetCanvas(); | |||
this.plugins.highlighter.highlightCanvas = null; | |||
} | |||
if (this.plugins.highlighter && this.plugins.highlighter._tooltipElem) { | |||
this.plugins.highlighter._tooltipElem.emptyForce(); | |||
this.plugins.highlighter._tooltipElem = null; | |||
} | |||
this.plugins.highlighter.highlightCanvas = new $.jqplot.GenericCanvas(); | |||
this.eventCanvas._elem.before(this.plugins.highlighter.highlightCanvas.createElement(this._gridPadding, 'jqplot-highlight-canvas', this._plotDimensions)); | |||
var hctx = this.plugins.highlighter.highlightCanvas.setContext(); | |||
this.eventCanvas._elem.before(this.plugins.highlighter.highlightCanvas.createElement(this._gridPadding, 'jqplot-highlight-canvas', this._plotDimensions, this)); | |||
this.plugins.highlighter.highlightCanvas.setContext(); | |||
var elem = document.createElement('div'); | |||
this.plugins.highlighter._tooltipElem = $(elem); | |||
elem = null; | |||
this.plugins.highlighter._tooltipElem.addClass('jqplot-highlighter-tooltip'); | |||
this.plugins.highlighter._tooltipElem.css({position:'absolute', display:'none'}); | |||
var p = this.plugins.highlighter; | |||
p._tooltipElem = $('<div class="jqplot-highlighter-tooltip" style="position:absolute;display:none"></div>'); | |||
this.target.append(p._tooltipElem); | |||
this.eventCanvas._elem.before(this.plugins.highlighter._tooltipElem); | |||
}; | |||
$.jqplot.preInitHooks.push($.jqplot.Highlighter.init); | |||
@@ -244,10 +288,7 @@ | |||
str = xstr; | |||
break; | |||
case 'y': | |||
str = ''; | |||
for (var i=0; i<ystrs.length; i++) { | |||
str += ystrs[i] + hl.tooltipSeparator; | |||
} | |||
str = ystrs.join(hl.tooltipSeparator); | |||
break; | |||
default: // same as 'xy' | |||
str = xstr; | |||
@@ -274,6 +315,11 @@ | |||
str = $.jqplot.sprintf(hl.tooltipFormatString, neighbor.data[1]); | |||
} | |||
} | |||
if ($.isFunction(hl.tooltipContentEditor)) { | |||
// args str, seriesIndex, pointIndex are essential so the hook can look up | |||
// extra data for the point. | |||
str = hl.tooltipContentEditor(str, neighbor.seriesIndex, neighbor.pointIndex, plot); | |||
} | |||
elem.html(str); | |||
var gridpos = {x:neighbor.gridData[0], y:neighbor.gridData[1]}; | |||
var ms = 0; | |||
@@ -281,7 +327,13 @@ | |||
if (series.markerRenderer.show == true) { | |||
ms = (series.markerRenderer.size + hl.sizeAdjust)/2; | |||
} | |||
switch (hl.tooltipLocation) { | |||
var loc = locations; | |||
if (series.fillToZero && series.fill && neighbor.data[1] < 0) { | |||
loc = oppositeLocations; | |||
} | |||
switch (loc[locationIndicies[hl.tooltipLocation]]) { | |||
case 'nw': | |||
var x = gridpos.x + plot._gridPadding.left - elem.outerWidth(true) - hl.tooltipOffset - fact * ms; | |||
var y = gridpos.y + plot._gridPadding.top - hl.tooltipOffset - elem.outerHeight(true) - fact * ms; | |||
@@ -322,16 +374,19 @@ | |||
elem.css('left', x); | |||
elem.css('top', y); | |||
if (hl.fadeTooltip) { | |||
elem.fadeIn(hl.tooltipFadeSpeed); | |||
// Fix for stacked up animations. Thnanks Trevor! | |||
elem.stop(true,true).fadeIn(hl.tooltipFadeSpeed); | |||
} | |||
else { | |||
elem.show(); | |||
} | |||
elem = null; | |||
} | |||
function handleMove(ev, gridpos, datapos, neighbor, plot) { | |||
var hl = plot.plugins.highlighter; | |||
var c = plot.plugins.cursor; | |||
if (hl.show) { | |||
if (neighbor == null && hl.isHighlighting) { | |||
var ctx = hl.highlightCanvas._ctx; | |||
@@ -342,17 +397,24 @@ | |||
else { | |||
hl._tooltipElem.hide(); | |||
} | |||
if (hl.bringSeriesToFront) { | |||
plot.restorePreviousSeriesOrder(); | |||
} | |||
hl.isHighlighting = false; | |||
ctx = null; | |||
} | |||
if (neighbor != null && plot.series[neighbor.seriesIndex].showHighlight && !hl.isHighlighting) { | |||
else if (neighbor != null && plot.series[neighbor.seriesIndex].showHighlight && !hl.isHighlighting) { | |||
hl.isHighlighting = true; | |||
if (hl.showMarker) { | |||
draw(plot, neighbor); | |||
} | |||
if (hl.showTooltip) { | |||
if (hl.showTooltip && (!c || !c._zoom.started)) { | |||
showTooltip(plot, plot.series[neighbor.seriesIndex], neighbor); | |||
} | |||
if (hl.bringSeriesToFront) { | |||
plot.moveSeriesToFront(neighbor.seriesIndex); | |||
} | |||
} | |||
} | |||
} |
@@ -0,0 +1,475 @@ | |||
/* | |||
2010-11-01 Chris Leonello | |||
Slightly modified version of the original json2.js to put JSON | |||
functions under the $.jqplot namespace. | |||
licensing and orignal comments follow: | |||
http://www.JSON.org/json2.js | |||
2010-08-25 | |||
Public Domain. | |||
NO WARRANTY EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK. | |||
See http://www.JSON.org/js.html | |||
This code should be minified before deployment. | |||
See http://javascript.crockford.com/jsmin.html | |||
USE YOUR OWN COPY. IT IS EXTREMELY UNWISE TO LOAD CODE FROM SERVERS YOU DO | |||
NOT CONTROL. | |||
This file creates a global JSON object containing two methods: stringify | |||
and parse. | |||
$.jqplot.JSON.stringify(value, replacer, space) | |||
value any JavaScript value, usually an object or array. | |||
replacer an optional parameter that determines how object | |||
values are stringified for objects. It can be a | |||
function or an array of strings. | |||
space an optional parameter that specifies the indentation | |||
of nested structures. If it is omitted, the text will | |||
be packed without extra whitespace. If it is a number, | |||
it will specify the number of spaces to indent at each | |||
level. If it is a string (such as '\t' or ' '), | |||
it contains the characters used to indent at each level. | |||
This method produces a JSON text from a JavaScript value. | |||
When an object value is found, if the object contains a toJSON | |||
method, its toJSON method will be called and the result will be | |||
stringified. A toJSON method does not serialize: it returns the | |||
value represented by the name/value pair that should be serialized, | |||
or undefined if nothing should be serialized. The toJSON method | |||
will be passed the key associated with the value, and this will be | |||
bound to the value | |||
For example, this would serialize Dates as ISO strings. | |||
Date.prototype.toJSON = function (key) { | |||
function f(n) { | |||
// Format integers to have at least two digits. | |||
return n < 10 ? '0' + n : n; | |||
} | |||
return this.getUTCFullYear() + '-' + | |||
f(this.getUTCMonth() + 1) + '-' + | |||
f(this.getUTCDate()) + 'T' + | |||
f(this.getUTCHours()) + ':' + | |||
f(this.getUTCMinutes()) + ':' + | |||
f(this.getUTCSeconds()) + 'Z'; | |||
}; | |||
You can provide an optional replacer method. It will be passed the | |||
key and value of each member, with this bound to the containing | |||
object. The value that is returned from your method will be | |||
serialized. If your method returns undefined, then the member will | |||
be excluded from the serialization. | |||
If the replacer parameter is an array of strings, then it will be | |||
used to select the members to be serialized. It filters the results | |||
such that only members with keys listed in the replacer array are | |||
stringified. | |||
Values that do not have JSON representations, such as undefined or | |||
functions, will not be serialized. Such values in objects will be | |||
dropped; in arrays they will be replaced with null. You can use | |||
a replacer function to replace those with JSON values. | |||
$.jqplot.JSON.stringify(undefined) returns undefined. | |||
The optional space parameter produces a stringification of the | |||
value that is filled with line breaks and indentation to make it | |||
easier to read. | |||
If the space parameter is a non-empty string, then that string will | |||
be used for indentation. If the space parameter is a number, then | |||
the indentation will be that many spaces. | |||
Example: | |||
text = $.jqplot.JSON.stringify(['e', {pluribus: 'unum'}]); | |||
// text is '["e",{"pluribus":"unum"}]' | |||
text = $.jqplot.JSON.stringify(['e', {pluribus: 'unum'}], null, '\t'); | |||
// text is '[\n\t"e",\n\t{\n\t\t"pluribus": "unum"\n\t}\n]' | |||
text = $.jqplot.JSON.stringify([new Date()], function (key, value) { | |||
return this[key] instanceof Date ? | |||
'Date(' + this[key] + ')' : value; | |||
}); | |||
// text is '["Date(---current time---)"]' | |||
$.jqplot.JSON.parse(text, reviver) | |||
This method parses a JSON text to produce an object or array. | |||
It can throw a SyntaxError exception. | |||
The optional reviver parameter is a function that can filter and | |||
transform the results. It receives each of the keys and values, | |||
and its return value is used instead of the original value. | |||
If it returns what it received, then the structure is not modified. | |||
If it returns undefined then the member is deleted. | |||
Example: | |||
// Parse the text. Values that look like ISO date strings will | |||
// be converted to Date objects. | |||
myData = $.jqplot.JSON.parse(text, function (key, value) { | |||
var a; | |||
if (typeof value === 'string') { | |||
a = | |||
/^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2}(?:\.\d*)?)Z$/.exec(value); | |||
if (a) { | |||
return new Date(Date.UTC(+a[1], +a[2] - 1, +a[3], +a[4], | |||
+a[5], +a[6])); | |||
} | |||
} | |||
return value; | |||
}); | |||
myData = $.jqplot.JSON.parse('["Date(09/09/2001)"]', function (key, value) { | |||
var d; | |||
if (typeof value === 'string' && | |||
value.slice(0, 5) === 'Date(' && | |||
value.slice(-1) === ')') { | |||
d = new Date(value.slice(5, -1)); | |||
if (d) { | |||
return d; | |||
} | |||
} | |||
return value; | |||
}); | |||
This is a reference implementation. You are free to copy, modify, or | |||
redistribute. | |||
*/ | |||
(function($) { | |||
$.jqplot.JSON = window.JSON; | |||
if (!window.JSON) { | |||
$.jqplot.JSON = {}; | |||
} | |||
function f(n) { | |||
// Format integers to have at least two digits. | |||
return n < 10 ? '0' + n : n; | |||
} | |||
if (typeof Date.prototype.toJSON !== 'function') { | |||
Date.prototype.toJSON = function (key) { | |||
return isFinite(this.valueOf()) ? | |||
this.getUTCFullYear() + '-' + | |||
f(this.getUTCMonth() + 1) + '-' + | |||
f(this.getUTCDate()) + 'T' + | |||
f(this.getUTCHours()) + ':' + | |||
f(this.getUTCMinutes()) + ':' + | |||
f(this.getUTCSeconds()) + 'Z' : null; | |||
}; | |||
String.prototype.toJSON = | |||
Number.prototype.toJSON = | |||
Boolean.prototype.toJSON = function (key) { | |||
return this.valueOf(); | |||
}; | |||
} | |||
var cx = /[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g, | |||
escapable = /[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g, | |||
gap, | |||
indent, | |||
meta = { // table of character substitutions | |||
'\b': '\\b', | |||
'\t': '\\t', | |||
'\n': '\\n', | |||
'\f': '\\f', | |||
'\r': '\\r', | |||
'"' : '\\"', | |||
'\\': '\\\\' | |||
}, | |||
rep; | |||
function quote(string) { | |||
// If the string contains no control characters, no quote characters, and no | |||
// backslash characters, then we can safely slap some quotes around it. | |||
// Otherwise we must also replace the offending characters with safe escape | |||
// sequences. | |||
escapable.lastIndex = 0; | |||
return escapable.test(string) ? | |||
'"' + string.replace(escapable, function (a) { | |||
var c = meta[a]; | |||
return typeof c === 'string' ? c : | |||
'\\u' + ('0000' + a.charCodeAt(0).toString(16)).slice(-4); | |||
}) + '"' : | |||
'"' + string + '"'; | |||
} | |||
function str(key, holder) { | |||
// Produce a string from holder[key]. | |||
var i, // The loop counter. | |||
k, // The member key. | |||
v, // The member value. | |||
length, | |||
mind = gap, | |||
partial, | |||
value = holder[key]; | |||
// If the value has a toJSON method, call it to obtain a replacement value. | |||
if (value && typeof value === 'object' && | |||
typeof value.toJSON === 'function') { | |||
value = value.toJSON(key); | |||
} | |||
// If we were called with a replacer function, then call the replacer to | |||
// obtain a replacement value. | |||
if (typeof rep === 'function') { | |||
value = rep.call(holder, key, value); | |||
} | |||
// What happens next depends on the value's type. | |||
switch (typeof value) { | |||
case 'string': | |||
return quote(value); | |||
case 'number': | |||
// JSON numbers must be finite. Encode non-finite numbers as null. | |||
return isFinite(value) ? String(value) : 'null'; | |||
case 'boolean': | |||
case 'null': | |||
// If the value is a boolean or null, convert it to a string. Note: | |||
// typeof null does not produce 'null'. The case is included here in | |||
// the remote chance that this gets fixed someday. | |||
return String(value); | |||
// If the type is 'object', we might be dealing with an object or an array or | |||
// null. | |||
case 'object': | |||
// Due to a specification blunder in ECMAScript, typeof null is 'object', | |||
// so watch out for that case. | |||
if (!value) { | |||
return 'null'; | |||
} | |||
// Make an array to hold the partial results of stringifying this object value. | |||
gap += indent; | |||
partial = []; | |||
// Is the value an array? | |||
if (Object.prototype.toString.apply(value) === '[object Array]') { | |||
// The value is an array. Stringify every element. Use null as a placeholder | |||
// for non-JSON values. | |||
length = value.length; | |||
for (i = 0; i < length; i += 1) { | |||
partial[i] = str(i, value) || 'null'; | |||
} | |||
// Join all of the elements together, separated with commas, and wrap them in | |||
// brackets. | |||
v = partial.length === 0 ? '[]' : | |||
gap ? '[\n' + gap + | |||
partial.join(',\n' + gap) + '\n' + | |||
mind + ']' : | |||
'[' + partial.join(',') + ']'; | |||
gap = mind; | |||
return v; | |||
} | |||
// If the replacer is an array, use it to select the members to be stringified. | |||
if (rep && typeof rep === 'object') { | |||
length = rep.length; | |||
for (i = 0; i < length; i += 1) { | |||
k = rep[i]; | |||
if (typeof k === 'string') { | |||
v = str(k, value); | |||
if (v) { | |||
partial.push(quote(k) + (gap ? ': ' : ':') + v); | |||
} | |||
} | |||
} | |||
} else { | |||
// Otherwise, iterate through all of the keys in the object. | |||
for (k in value) { | |||
if (Object.hasOwnProperty.call(value, k)) { | |||
v = str(k, value); | |||
if (v) { | |||
partial.push(quote(k) + (gap ? ': ' : ':') + v); | |||
} | |||
} | |||
} | |||
} | |||
// Join all of the member texts together, separated with commas, | |||
// and wrap them in braces. | |||
v = partial.length === 0 ? '{}' : | |||
gap ? '{\n' + gap + partial.join(',\n' + gap) + '\n' + | |||
mind + '}' : '{' + partial.join(',') + '}'; | |||
gap = mind; | |||
return v; | |||
} | |||
} | |||
// If the JSON object does not yet have a stringify method, give it one. | |||
if (typeof $.jqplot.JSON.stringify !== 'function') { | |||
$.jqplot.JSON.stringify = function (value, replacer, space) { | |||
// The stringify method takes a value and an optional replacer, and an optional | |||
// space parameter, and returns a JSON text. The replacer can be a function | |||
// that can replace values, or an array of strings that will select the keys. | |||
// A default replacer method can be provided. Use of the space parameter can | |||
// produce text that is more easily readable. | |||
var i; | |||
gap = ''; | |||
indent = ''; | |||
// If the space parameter is a number, make an indent string containing that | |||
// many spaces. | |||
if (typeof space === 'number') { | |||
for (i = 0; i < space; i += 1) { | |||
indent += ' '; | |||
} | |||
// If the space parameter is a string, it will be used as the indent string. | |||
} else if (typeof space === 'string') { | |||
indent = space; | |||
} | |||
// If there is a replacer, it must be a function or an array. | |||
// Otherwise, throw an error. | |||
rep = replacer; | |||
if (replacer && typeof replacer !== 'function' && | |||
(typeof replacer !== 'object' || | |||
typeof replacer.length !== 'number')) { | |||
throw new Error('$.jqplot.JSON.stringify'); | |||
} | |||
// Make a fake root object containing our value under the key of ''. | |||
// Return the result of stringifying the value. | |||
return str('', {'': value}); | |||
}; | |||
} | |||
// If the JSON object does not yet have a parse method, give it one. | |||
if (typeof $.jqplot.JSON.parse !== 'function') { | |||
$.jqplot.JSON.parse = function (text, reviver) { | |||
// The parse method takes a text and an optional reviver function, and returns | |||
// a JavaScript value if the text is a valid JSON text. | |||
var j; | |||
function walk(holder, key) { | |||
// The walk method is used to recursively walk the resulting structure so | |||
// that modifications can be made. | |||
var k, v, value = holder[key]; | |||
if (value && typeof value === 'object') { | |||
for (k in value) { | |||
if (Object.hasOwnProperty.call(value, k)) { | |||
v = walk(value, k); | |||
if (v !== undefined) { | |||
value[k] = v; | |||
} else { | |||
delete value[k]; | |||
} | |||
} | |||
} | |||
} | |||
return reviver.call(holder, key, value); | |||
} | |||
// Parsing happens in four stages. In the first stage, we replace certain | |||
// Unicode characters with escape sequences. JavaScript handles many characters | |||
// incorrectly, either silently deleting them, or treating them as line endings. | |||
text = String(text); | |||
cx.lastIndex = 0; | |||
if (cx.test(text)) { | |||
text = text.replace(cx, function (a) { | |||
return '\\u' + | |||
('0000' + a.charCodeAt(0).toString(16)).slice(-4); | |||
}); | |||
} | |||
// In the second stage, we run the text against regular expressions that look | |||
// for non-JSON patterns. We are especially concerned with '()' and 'new' | |||
// because they can cause invocation, and '=' because it can cause mutation. | |||
// But just to be safe, we want to reject all unexpected forms. | |||
// We split the second stage into 4 regexp operations in order to work around | |||
// crippling inefficiencies in IE's and Safari's regexp engines. First we | |||
// replace the JSON backslash pairs with '@' (a non-JSON character). Second, we | |||
// replace all simple value tokens with ']' characters. Third, we delete all | |||
// open brackets that follow a colon or comma or that begin the text. Finally, | |||
// we look to see that the remaining characters are only whitespace or ']' or | |||
// ',' or ':' or '{' or '}'. If that is so, then the text is safe for eval. | |||
if (/^[\],:{}\s]*$/.test(text.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g, '@').replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, ']').replace(/(?:^|:|,)(?:\s*\[)+/g, ''))) { | |||
// In the third stage we use the eval function to compile the text into a | |||
// JavaScript structure. The '{' operator is subject to a syntactic ambiguity | |||
// in JavaScript: it can begin a block or an object literal. We wrap the text | |||
// in parens to eliminate the ambiguity. | |||
j = eval('(' + text + ')'); | |||
// In the optional fourth stage, we recursively walk the new structure, passing | |||
// each name/value pair to a reviver function for possible transformation. | |||
return typeof reviver === 'function' ? | |||
walk({'': j}, '') : j; | |||
} | |||
// If the text is not JSON parseable, then a SyntaxError is thrown. | |||
throw new SyntaxError('$.jqplot.JSON.parse'); | |||
}; | |||
} | |||
})(jQuery); |
@@ -0,0 +1,30 @@ | |||
/** | |||
* jqPlot | |||
* Pure JavaScript plotting plugin using jQuery | |||
* | |||
* Version: 1.0.0b2_r792 | |||
* | |||
* Copyright (c) 2009-2011 Chris Leonello | |||
* jqPlot is currently available for use in all personal or commercial projects | |||
* under both the MIT (http://www.opensource.org/licenses/mit-license.php) and GPL | |||
* version 2.0 (http://www.gnu.org/licenses/gpl-2.0.html) licenses. This means that you can | |||
* choose the license that best suits your project and use it accordingly. | |||
* | |||
* Although not required, the author would appreciate an email letting him | |||
* know of any substantial use of jqPlot. You can reach the author at: | |||
* chris at jqplot dot com or see http://www.jqplot.com/info.php . | |||
* | |||
* If you are feeling kind and generous, consider supporting the project by | |||
* making a donation at: http://www.jqplot.com/donate.php . | |||
* | |||
* sprintf functions contained in jqplot.sprintf.js by Ash Searle: | |||
* | |||
* version 2007.04.27 | |||
* author Ash Searle | |||
* http://hexmen.com/blog/2007/03/printf-sprintf/ | |||
* http://hexmen.com/js/sprintf.js | |||
* The author (Ash Searle) has placed this code in the public domain: | |||
* "This code is unrestricted: you are free to use it however you like." | |||
* | |||
*/ | |||
(function($){$.jqplot.JSON=window.JSON;if(!window.JSON){$.jqplot.JSON={}}function f(n){return n<10?"0"+n:n}if(typeof Date.prototype.toJSON!=="function"){Date.prototype.toJSON=function(key){return isFinite(this.valueOf())?this.getUTCFullYear()+"-"+f(this.getUTCMonth()+1)+"-"+f(this.getUTCDate())+"T"+f(this.getUTCHours())+":"+f(this.getUTCMinutes())+":"+f(this.getUTCSeconds())+"Z":null};String.prototype.toJSON=Number.prototype.toJSON=Boolean.prototype.toJSON=function(key){return this.valueOf()}}var cx=/[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,escapable=/[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,gap,indent,meta={"\b":"\\b","\t":"\\t","\n":"\\n","\f":"\\f","\r":"\\r",'"':'\\"',"\\":"\\\\"},rep;function quote(string){escapable.lastIndex=0;return escapable.test(string)?'"'+string.replace(escapable,function(a){var c=meta[a];return typeof c==="string"?c:"\\u"+("0000"+a.charCodeAt(0).toString(16)).slice(-4)})+'"':'"'+string+'"'}function str(key,holder){var i,k,v,length,mind=gap,partial,value=holder[key];if(value&&typeof value==="object"&&typeof value.toJSON==="function"){value=value.toJSON(key)}if(typeof rep==="function"){value=rep.call(holder,key,value)}switch(typeof value){case"string":return quote(value);case"number":return isFinite(value)?String(value):"null";case"boolean":case"null":return String(value);case"object":if(!value){return"null"}gap+=indent;partial=[];if(Object.prototype.toString.apply(value)==="[object Array]"){length=value.length;for(i=0;i<length;i+=1){partial[i]=str(i,value)||"null"}v=partial.length===0?"[]":gap?"[\n"+gap+partial.join(",\n"+gap)+"\n"+mind+"]":"["+partial.join(",")+"]";gap=mind;return v}if(rep&&typeof rep==="object"){length=rep.length;for(i=0;i<length;i+=1){k=rep[i];if(typeof k==="string"){v=str(k,value);if(v){partial.push(quote(k)+(gap?": ":":")+v)}}}}else{for(k in value){if(Object.hasOwnProperty.call(value,k)){v=str(k,value);if(v){partial.push(quote(k)+(gap?": ":":")+v)}}}}v=partial.length===0?"{}":gap?"{\n"+gap+partial.join(",\n"+gap)+"\n"+mind+"}":"{"+partial.join(",")+"}";gap=mind;return v}}if(typeof $.jqplot.JSON.stringify!=="function"){$.jqplot.JSON.stringify=function(value,replacer,space){var i;gap="";indent="";if(typeof space==="number"){for(i=0;i<space;i+=1){indent+=" "}}else{if(typeof space==="string"){indent=space}}rep=replacer;if(replacer&&typeof replacer!=="function"&&(typeof replacer!=="object"||typeof replacer.length!=="number")){throw new Error("$.jqplot.JSON.stringify")}return str("",{"":value})}}if(typeof $.jqplot.JSON.parse!=="function"){$.jqplot.JSON.parse=function(text,reviver){var j;function walk(holder,key){var k,v,value=holder[key];if(value&&typeof value==="object"){for(k in value){if(Object.hasOwnProperty.call(value,k)){v=walk(value,k);if(v!==undefined){value[k]=v}else{delete value[k]}}}}return reviver.call(holder,key,value)}text=String(text);cx.lastIndex=0;if(cx.test(text)){text=text.replace(cx,function(a){return"\\u"+("0000"+a.charCodeAt(0).toString(16)).slice(-4)})}if(/^[\],:{}\s]*$/.test(text.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g,"@").replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,"]").replace(/(?:^|:|,)(?:\s*\[)+/g,""))){j=eval("("+text+")");return typeof reviver==="function"?walk({"":j},""):j}throw new SyntaxError("$.jqplot.JSON.parse")}}})(jQuery); |
@@ -1,20 +1,32 @@ | |||
/** | |||
* Copyright (c) 2009 Chris Leonello | |||
* jqPlot | |||
* Pure JavaScript plotting plugin using jQuery | |||
* | |||
* Version: 1.0.0b2_r792 | |||
* | |||
* Copyright (c) 2009-2011 Chris Leonello | |||
* jqPlot is currently available for use in all personal or commercial projects | |||
* under both the MIT and GPL version 2.0 licenses. This means that you can | |||
* under both the MIT (http://www.opensource.org/licenses/mit-license.php) and GPL | |||
* version 2.0 (http://www.gnu.org/licenses/gpl-2.0.html) licenses. This means that you can | |||
* choose the license that best suits your project and use it accordingly. | |||
* | |||
* The author would appreciate an email letting him know of any substantial | |||
* use of jqPlot. You can reach the author at: chris dot leonello at gmail | |||
* dot com or see http://www.jqplot.com/info.php . This is, of course, | |||
* not required. | |||
* Although not required, the author would appreciate an email letting him | |||
* know of any substantial use of jqPlot. You can reach the author at: | |||
* chris at jqplot dot com or see http://www.jqplot.com/info.php . | |||
* | |||
* If you are feeling kind and generous, consider supporting the project by | |||
* making a donation at: http://www.jqplot.com/donate.php . | |||
* | |||
* Thanks for using jqPlot! | |||
* sprintf functions contained in jqplot.sprintf.js by Ash Searle: | |||
* | |||
* version 2007.04.27 | |||
* author Ash Searle | |||
* http://hexmen.com/blog/2007/03/printf-sprintf/ | |||
* http://hexmen.com/js/sprintf.js | |||
* The author (Ash Searle) has placed this code in the public domain: | |||
* "This code is unrestricted: you are free to use it however you like." | |||
* | |||
*/ | |||
*/ | |||
(function($) { | |||
/** | |||
* class: $.jqplot.LogAxisRenderer | |||
@@ -70,21 +82,21 @@ | |||
for (var j=0; j<d.length; j++) { | |||
if (this.name == 'xaxis' || this.name == 'x2axis') { | |||
if (d[j][0] > db.max || db.max == null) { | |||
db.max = d[j][0]; | |||
if ((d[j][0] != null && d[j][0] < db.min) || db.min == null) { | |||
db.min = d[j][0]; | |||
} | |||
if (d[j][0] > db.max || db.max == null) { | |||
if ((d[j][0] != null && d[j][0] > db.max) || db.max == null) { | |||
db.max = d[j][0]; | |||
} | |||
} | |||
else { | |||
if (d[j][1] < db.min || db.min == null) { | |||
if ((d[j][1] != null && d[j][1] < db.min) || db.min == null) { | |||
db.min = d[j][1]; | |||
} | |||
if (d[j][1] > db.max || db.max == null) { | |||
if ((d[j][1] != null && d[j][1] > db.max) || db.max == null) { | |||
db.max = d[j][1]; | |||
} | |||
} | |||
} | |||
} | |||
} | |||
}; | |||
@@ -273,8 +285,8 @@ | |||
var ticks = this._ticks; | |||
var trans = function (v) { return Math.log(v)/Math.log(lb); }; | |||
var invtrans = function (v) { return Math.pow(Math.E, (Math.log(lb)*v)); }; | |||
max = trans(this.max); | |||
min = trans(this.min); | |||
var max = trans(this.max); | |||
var min = trans(this.min); | |||
var offmax = offsets.max; | |||
var offmin = offsets.min; | |||
var lshow = (this._label == null) ? false : this._label.show; | |||
@@ -317,7 +329,7 @@ | |||
if (this.show) { | |||
if (this.name == 'xaxis' || this.name == 'x2axis') { | |||
for (i=0; i<ticks.length; i++) { | |||
for (var i=0; i<ticks.length; i++) { | |||
var t = ticks[i]; | |||
if (t.show && t.showLabel) { | |||
var shim; | |||
@@ -370,7 +382,7 @@ | |||
} | |||
} | |||
else { | |||
for (i=0; i<ticks.length; i++) { | |||
for (var i=0; i<ticks.length; i++) { | |||
var t = ticks[i]; | |||
if (t.show && t.showLabel) { | |||
var shim; | |||
@@ -1,18 +1,30 @@ | |||
/** | |||
* Copyright (c) 2009 Chris Leonello | |||
* jqPlot | |||
* Pure JavaScript plotting plugin using jQuery | |||
* | |||
* Version: 1.0.0b2_r792 | |||
* | |||
* Copyright (c) 2009-2011 Chris Leonello | |||
* jqPlot is currently available for use in all personal or commercial projects | |||
* under both the MIT and GPL version 2.0 licenses. This means that you can | |||
* under both the MIT (http://www.opensource.org/licenses/mit-license.php) and GPL | |||
* version 2.0 (http://www.gnu.org/licenses/gpl-2.0.html) licenses. This means that you can | |||
* choose the license that best suits your project and use it accordingly. | |||
* | |||
* The author would appreciate an email letting him know of any substantial | |||
* use of jqPlot. You can reach the author at: chris dot leonello at gmail | |||
* dot com or see http://www.jqplot.com/info.php . This is, of course, | |||
* not required. | |||
* Although not required, the author would appreciate an email letting him | |||
* know of any substantial use of jqPlot. You can reach the author at: | |||
* chris at jqplot dot com or see http://www.jqplot.com/info.php . | |||
* | |||
* If you are feeling kind and generous, consider supporting the project by | |||
* making a donation at: http://www.jqplot.com/donate.php . | |||
* | |||
* Thanks for using jqPlot! | |||
* sprintf functions contained in jqplot.sprintf.js by Ash Searle: | |||
* | |||
* version 2007.04.27 | |||
* author Ash Searle | |||
* http://hexmen.com/blog/2007/03/printf-sprintf/ | |||
* http://hexmen.com/js/sprintf.js | |||
* The author (Ash Searle) has placed this code in the public domain: | |||
* "This code is unrestricted: you are free to use it however you like." | |||
* | |||
*/ | |||
(function($) { | |||
@@ -83,7 +95,11 @@ | |||
var dim=0; | |||
var temp; | |||
this._elem = $('<div class="jqplot-axis jqplot-'+this.name+'" style="position:absolute;"></div>'); | |||
var elem = document.createElement('div'); | |||
this._elem = $(elem); | |||
this._elem.addClass('jqplot-axis jqplot-'+this.name); | |||
this._elem.css('position', 'absolute'); | |||
elem = null; | |||
if (this.name == 'xaxis' || this.name == 'x2axis') { | |||
this._elem.width(this._plotDimensions.width); | |||
@@ -97,8 +113,7 @@ | |||
this.labelOptions.axis = this.name; | |||
this._label = new this.labelRenderer(this.labelOptions); | |||
if (this._label.show) { | |||
var elem = this._label.draw(ctx); | |||
elem.appendTo(this._elem); | |||
this._elem.append(this._label.draw(ctx)); | |||
} | |||
var t, tick, elem; | |||
@@ -107,8 +122,7 @@ | |||
for (var i=0; i<t.length; i++) { | |||
tick = t[i]; | |||
if (tick.showLabel && (!tick.isMinorTick || this.showMinorTicks)) { | |||
elem = tick.draw(ctx); | |||
elem.appendTo(this._elem); | |||
this._elem.append(tick.draw(ctx)); | |||
} | |||
} | |||
} | |||
@@ -127,6 +141,7 @@ | |||
elem.addClass('jqplot-'+this.name+'-tick'); | |||
elem.addClass('jqplot-mekko-barLabel'); | |||
elem.appendTo(this._elem); | |||
elem = null; | |||
} | |||
} | |||
@@ -467,7 +482,7 @@ | |||
if (this.show) { | |||
if (this.name == 'xaxis' || this.name == 'x2axis') { | |||
for (i=0; i<ticks.length; i++) { | |||
for (var i=0; i<ticks.length; i++) { | |||
var t = ticks[i]; | |||
if (t.show && t.showLabel) { | |||
var shim; | |||
@@ -522,7 +537,7 @@ | |||
} | |||
// now show the labels under the bars. | |||
var b, l, r; | |||
for (i=0; i<this.barLabels.length; i++) { | |||
for (var i=0; i<this.barLabels.length; i++) { | |||
b = this._barLabels[i]; | |||
if (b.show) { | |||
w = b.getWidth(); | |||
@@ -535,7 +550,7 @@ | |||
} | |||
} | |||
else { | |||
for (i=0; i<ticks.length; i++) { | |||
for (var i=0; i<ticks.length; i++) { | |||
var t = ticks[i]; | |||
if (t.show && t.showLabel) { | |||
var shim; | |||
@@ -1,24 +1,66 @@ | |||
/** | |||
* Copyright (c) 2009 Chris Leonello | |||
* jqPlot | |||
* Pure JavaScript plotting plugin using jQuery | |||
* | |||
* Version: 1.0.0b2_r792 | |||
* | |||
* Copyright (c) 2009-2011 Chris Leonello | |||
* jqPlot is currently available for use in all personal or commercial projects | |||
* under both the MIT and GPL version 2.0 licenses. This means that you can | |||
* under both the MIT (http://www.opensource.org/licenses/mit-license.php) and GPL | |||
* version 2.0 (http://www.gnu.org/licenses/gpl-2.0.html) licenses. This means that you can | |||
* choose the license that best suits your project and use it accordingly. | |||
* | |||
* The author would appreciate an email letting him know of any substantial | |||
* use of jqPlot. You can reach the author at: chris dot leonello at gmail | |||
* dot com or see http://www.jqplot.com/info.php . This is, of course, | |||
* not required. | |||
* Although not required, the author would appreciate an email letting him | |||
* know of any substantial use of jqPlot. You can reach the author at: | |||
* chris at jqplot dot com or see http://www.jqplot.com/info.php . | |||
* | |||
* If you are feeling kind and generous, consider supporting the project by | |||
* making a donation at: http://www.jqplot.com/donate.php . | |||
* | |||
* Thanks for using jqPlot! | |||
* sprintf functions contained in jqplot.sprintf.js by Ash Searle: | |||
* | |||
* version 2007.04.27 | |||
* author Ash Searle | |||
* http://hexmen.com/blog/2007/03/printf-sprintf/ | |||
* http://hexmen.com/js/sprintf.js | |||
* The author (Ash Searle) has placed this code in the public domain: | |||
* "This code is unrestricted: you are free to use it however you like." | |||
* | |||
*/ | |||
(function($) { | |||
// Class: $.jqplot.MekkoRenderer | |||
/** | |||
* Class: $.jqplot.MekkoRenderer | |||
* Draws a Mekko style chart which shows 3 dimensional data on a 2 dimensional graph. | |||
* the <$.jqplot.MekkoAxisRenderer> should be used with mekko charts. The mekko renderer | |||
* overrides the default legend renderer with it's own $.jqplot.MekkoLegendRenderer | |||
* which allows more flexibility to specify number of rows and columns in the legend. | |||
* | |||
* Data is specified per bar in the chart. You can specify data as an array of y values, or as | |||
* an array of [label, value] pairs. Note that labels are used only on the first series. | |||
* Labels on subsequent series are ignored: | |||
* | |||
* > bar1 = [['shirts', 8],['hats', 14],['shoes', 6],['gloves', 16],['dolls', 12]]; | |||
* > bar2 = [15,6,9,13,6]; | |||
* > bar3 = [['grumpy',4],['sneezy',2],['happy',7],['sleepy',9],['doc',7]]; | |||
* | |||
* If you want to place labels for each bar under the axis, you use the barLabels option on | |||
* the axes. The bar labels can be styled with the ".jqplot-mekko-barLabel" css class. | |||
* | |||
* > barLabels = ['Mickey Mouse', 'Donald Duck', 'Goofy']; | |||
* > axes:{xaxis:{barLabels:barLabels}} | |||
* | |||
*/ | |||
$.jqplot.MekkoRenderer = function(){ | |||
this.shapeRenderer = new $.jqplot.ShapeRenderer(); | |||
// prop: borderColor | |||
// color of the borders between areas on the chart | |||
this.borderColor = null; | |||
// prop: showBorders | |||
// True to draw borders lines between areas on the chart. | |||
// False will draw borders lines with the same color as the area. | |||
this.showBorders = true; | |||
}; | |||
// called with scope of series. | |||
@@ -35,6 +77,7 @@ | |||
var opts = {lineJoin:'miter', lineCap:'butt', isarc:false, fillRect:this.fillRect, strokeRect:this.strokeRect}; | |||
this.renderer.shapeRenderer.init(opts); | |||
plot.axes.x2axis._series.push(this); | |||
this._type = 'mekko'; | |||
}; | |||
// Method: setGridData | |||
@@ -106,6 +149,12 @@ | |||
if (showLine) { | |||
for (i=0; i<gd.length; i++){ | |||
opts.fillStyle = colorGenerator.next(); | |||
if (this.renderer.showBorders) { | |||
opts.strokeStyle = this.renderer.borderColor; | |||
} | |||
else { | |||
opts.strokeStyle = opts.fillStyle; | |||
} | |||
this.renderer.shapeRenderer.draw(ctx, gd[i], opts); | |||
} | |||
} | |||
@@ -118,60 +167,139 @@ | |||
// This is a no-op, no shadows on mekko charts. | |||
}; | |||
// called with scope of legend renderer. | |||
$.jqplot.MekkoLegendRenderer = function() { | |||
$.jqplot.TableLegendRenderer.call(this); | |||
/** | |||
* Class: $.jqplot.MekkoLegendRenderer | |||
* Legend renderer used by mekko charts with options for | |||
* controlling number or rows and columns as well as placement | |||
* outside of plot area. | |||
* | |||
*/ | |||
$.jqplot.MekkoLegendRenderer = function(){ | |||
// | |||
}; | |||
$.jqplot.MekkoLegendRenderer.prototype = new $.jqplot.TableLegendRenderer(); | |||
$.jqplot.MekkoLegendRenderer.prototype.constructor = $.jqplot.MekkoLegendRenderer; | |||
// called with scope of legend | |||
$.jqplot.MekkoLegendRenderer.prototype.init = function(options) { | |||
this.labels = []; | |||
// prop: numberRows | |||
// Maximum number of rows in the legend. 0 or null for unlimited. | |||
this.numberRows = null; | |||
// prop: numberColumns | |||
// Maximum number of columns in the legend. 0 or null for unlimited. | |||
this.numberColumns = null; | |||
// this will override the placement option on the Legend object | |||
this.placement = "outside"; | |||
$.extend(true, this, options); | |||
}; | |||
// called with context of legend | |||
// called with scope of legend | |||
$.jqplot.MekkoLegendRenderer.prototype.draw = function() { | |||
var legend = this; | |||
if (this.show) { | |||
var series = this._series; | |||
// make a table. one line label per row. | |||
var ss = 'position:absolute;'; | |||
ss += (this.background) ? 'background:'+this.background+';' : ''; | |||
ss += (this.border) ? 'border:'+this.border+';' : ''; | |||
ss += (this.fontSize) ? 'font-size:'+this.fontSize+';' : ''; | |||
ss += (this.fontFamily) ? 'font-family:'+this.fontFamily+';' : ''; | |||
ss += (this.textColor) ? 'color:'+this.textColor+';' : ''; | |||
this._elem = $('<table class="jqplot-table-legend jqplot-mekko-legend" style="'+ss+'"></table>'); | |||
var pad = false, i, labels = [], colors = []; | |||
this._elem = $('<table class="jqplot-table-legend" style="'+ss+'"></table>'); | |||
// Mekko charts legends don't go by number of series, but by number of data points | |||
// in the series. Refactor things here for that. | |||
var pad = false, | |||
reverse = true, // mekko charts are always stacked, so reverse | |||
nr, nc; | |||
var s = series[0]; | |||
var colorGenerator = new $.jqplot.ColorGenerator(s.seriesColors); | |||
if (s.show) { | |||
var pd = s.data; | |||
for (i=0; i<pd.length; i++){ | |||
labels.push(this.labels[i] || pd[i][0].toString()); | |||
colors.push(colorGenerator.next()); | |||
if (this.numberRows) { | |||
nr = this.numberRows; | |||
if (!this.numberColumns){ | |||
nc = Math.ceil(pd.length/nr); | |||
} | |||
else{ | |||
nc = this.numberColumns; | |||
} | |||
} | |||
else if (this.numberColumns) { | |||
nc = this.numberColumns; | |||
nr = Math.ceil(pd.length/this.numberColumns); | |||
} | |||
for (i=pd.length-1; i>-1; i--) { | |||
if (labels[i]) { | |||
this.renderer.addrow.call(this, labels[i], colors[i], pad); | |||
pad = true; | |||
else { | |||
nr = pd.length; | |||
nc = 1; | |||
} | |||
var i, j, tr, td1, td2, lt, rs, color; | |||
var idx = 0; | |||
for (i=0; i<nr; i++) { | |||
if (reverse){ | |||
tr = $('<tr class="jqplot-table-legend"></tr>').prependTo(this._elem); | |||
} | |||
else{ | |||
tr = $('<tr class="jqplot-table-legend"></tr>').appendTo(this._elem); | |||
} | |||
for (j=0; j<nc; j++) { | |||
if (idx < pd.length) { | |||
lt = this.labels[idx] || pd[idx][0].toString(); | |||
color = colorGenerator.next(); | |||
if (!reverse){ | |||
if (i>0){ | |||
pad = true; | |||
} | |||
else{ | |||
pad = false; | |||
} | |||
} | |||
else{ | |||
if (i == nr -1){ | |||
pad = false; | |||
} | |||
else{ | |||
pad = true; | |||
} | |||
} | |||
rs = (pad) ? this.rowSpacing : '0'; | |||
td1 = $('<td class="jqplot-table-legend" style="text-align:center;padding-top:'+rs+';">'+ | |||
'<div><div class="jqplot-table-legend-swatch" style="border-color:'+color+';"></div>'+ | |||
'</div></td>'); | |||
td2 = $('<td class="jqplot-table-legend" style="padding-top:'+rs+';"></td>'); | |||
if (this.escapeHtml){ | |||
td2.text(lt); | |||
} | |||
else { | |||
td2.html(lt); | |||
} | |||
if (reverse) { | |||
td2.prependTo(tr); | |||
td1.prependTo(tr); | |||
} | |||
else { | |||
td1.appendTo(tr); | |||
td2.appendTo(tr); | |||
} | |||
pad = true; | |||
} | |||
idx++; | |||
} | |||
} | |||
tr = null; | |||
td1 = null; | |||
td2 = null; | |||
} | |||
} | |||
} | |||
return this._elem; | |||
}; | |||
$.jqplot.MekkoLegendRenderer.prototype.pack = function(offsets) { | |||
if (this.show) { | |||
// fake a grid for positioning | |||
var grid = {_top:offsets.top, _left:offsets.left, _right:offsets.right, _bottom:this._plotDimensions.height - offsets.bottom}; | |||
if (this.placement == 'inside') { | |||
var grid = {_top:offsets.top, _left:offsets.left, _right:offsets.right, _bottom:this._plotDimensions.height - offsets.bottom}; | |||
if (this.placement == 'insideGrid') { | |||
switch (this.location) { | |||
case 'nw': | |||
var a = grid._left + this.xoffset; | |||
@@ -1,18 +1,30 @@ | |||
/** | |||
* Copyright (c) 2009 Chris Leonello | |||
* jqPlot | |||
* Pure JavaScript plotting plugin using jQuery | |||
* | |||
* Version: 1.0.0b2_r792 | |||
* | |||
* Copyright (c) 2009-2011 Chris Leonello | |||
* jqPlot is currently available for use in all personal or commercial projects | |||
* under both the MIT and GPL version 2.0 licenses. This means that you can | |||
* under both the MIT (http://www.opensource.org/licenses/mit-license.php) and GPL | |||
* version 2.0 (http://www.gnu.org/licenses/gpl-2.0.html) licenses. This means that you can | |||
* choose the license that best suits your project and use it accordingly. | |||
* | |||
* The author would appreciate an email letting him know of any substantial | |||
* use of jqPlot. You can reach the author at: chris dot leonello at gmail | |||
* dot com or see http://www.jqplot.com/info.php . This is, of course, | |||
* not required. | |||
* Although not required, the author would appreciate an email letting him | |||
* know of any substantial use of jqPlot. You can reach the author at: | |||
* chris at jqplot dot com or see http://www.jqplot.com/info.php . | |||
* | |||
* If you are feeling kind and generous, consider supporting the project by | |||
* making a donation at: http://www.jqplot.com/donate.php . | |||
* | |||
* Thanks for using jqPlot! | |||
* sprintf functions contained in jqplot.sprintf.js by Ash Searle: | |||
* | |||
* version 2007.04.27 | |||
* author Ash Searle | |||
* http://hexmen.com/blog/2007/03/printf-sprintf/ | |||
* http://hexmen.com/js/sprintf.js | |||
* The author (Ash Searle) has placed this code in the public domain: | |||
* "This code is unrestricted: you are free to use it however you like." | |||
* | |||
*/ | |||
(function($) { | |||
@@ -95,6 +107,10 @@ | |||
// true if is a hi-low-close chart (no open price). | |||
// This is determined automatically from the series data. | |||
this.hlc = false; | |||
// prop: lineWidth | |||
// Width of the hi-low line and open/close ticks. | |||
// Must be set in the rendererOptions for the series. | |||
this.lineWidth = 1.5; | |||
this._tickLength; | |||
this._bodyWidth; | |||
}; | |||
@@ -104,10 +120,13 @@ | |||
// called with scope of series. | |||
$.jqplot.OHLCRenderer.prototype.init = function(options) { | |||
// prop: lineWidth | |||
// Width of the hi-low line and open/close ticks. | |||
this.lineWidth = 1.5; | |||
options = options || {}; | |||
// lineWidth has to be set on the series, changes in renderer | |||
// constructor have no effect. set the default here | |||
// if no renderer option for lineWidth is specified. | |||
this.lineWidth = options.lineWidth || 1.5; | |||
$.jqplot.LineRenderer.prototype.init.call(this, options); | |||
this._type = 'ohlc'; | |||
// set the yaxis data bounds here to account for hi and low values | |||
var db = this._yaxis._dataBounds; | |||
var d = this._plotData; | |||
@@ -171,13 +190,23 @@ | |||
xmaxidx = i+1; | |||
} | |||
} | |||
var dwidth = this.gridData[xmaxidx-1][0] - this.gridData[xminidx][0]; | |||
var nvisiblePoints = xmaxidx - xminidx; | |||
try { | |||
var dinterval = Math.abs(this._xaxis.series_u2p(parseInt(this._xaxis._intervalStats[0].sortedIntervals[0].interval)) - this._xaxis.series_u2p(0)); | |||
} | |||
catch (e) { | |||
var dinterval = dwidth / nvisiblePoints; | |||
} | |||
if (r.candleStick) { | |||
if (typeof(r.bodyWidth) == 'number') { | |||
r._bodyWidth = r.bodyWidth; | |||
} | |||
else { | |||
r._bodyWidth = Math.min(20, ctx.canvas.width/(xmaxidx - xminidx)/2); | |||
r._bodyWidth = Math.min(20, dinterval/1.75); | |||
} | |||
} | |||
else { | |||
@@ -185,7 +214,7 @@ | |||
r._tickLength = r.tickLength; | |||
} | |||
else { | |||
r._tickLength = Math.min(10, ctx.canvas.width/(xmaxidx - xminidx)/4); | |||
r._tickLength = Math.min(10, dinterval/3.5); | |||
} | |||
} | |||
@@ -1,14 +1,30 @@ | |||
/** | |||
* Copyright (c) 2009 Chris Leonello | |||
* jqPlot | |||
* Pure JavaScript plotting plugin using jQuery | |||
* | |||
* Version: 1.0.0b2_r792 | |||
* | |||
* Copyright (c) 2009-2011 Chris Leonello | |||
* jqPlot is currently available for use in all personal or commercial projects | |||
* under both the MIT and GPL version 2.0 licenses. This means that you can | |||
* under both the MIT (http://www.opensource.org/licenses/mit-license.php) and GPL | |||
* version 2.0 (http://www.gnu.org/licenses/gpl-2.0.html) licenses. This means that you can | |||
* choose the license that best suits your project and use it accordingly. | |||
* | |||
* Although not required, the author would appreciate an email letting him | |||
* know of any substantial use of jqPlot. You can reach the author at: | |||
* chris dot leonello at gmail dot com or see http://www.jqplot.com/info.php . | |||
* chris at jqplot dot com or see http://www.jqplot.com/info.php . | |||
* | |||
* If you are feeling kind and generous, consider supporting the project by | |||
* making a donation at: http://www.jqplot.com/donate.php . | |||
* | |||
* sprintf functions contained in jqplot.sprintf.js by Ash Searle: | |||
* | |||
* version 2007.04.27 | |||
* author Ash Searle | |||
* http://hexmen.com/blog/2007/03/printf-sprintf/ | |||
* http://hexmen.com/js/sprintf.js | |||
* The author (Ash Searle) has placed this code in the public domain: | |||
* "This code is unrestricted: you are free to use it however you like." | |||
* | |||
*/ | |||
(function(a){a.jqplot.OHLCRenderer=function(){a.jqplot.LineRenderer.call(this);this.candleStick=false;this.tickLength="auto";this.bodyWidth="auto";this.openColor=null;this.closeColor=null;this.wickColor=null;this.fillUpBody=false;this.fillDownBody=true;this.upBodyColor=null;this.downBodyColor=null;this.hlc=false;this._tickLength;this._bodyWidth};a.jqplot.OHLCRenderer.prototype=new a.jqplot.LineRenderer();a.jqplot.OHLCRenderer.prototype.constructor=a.jqplot.OHLCRenderer;a.jqplot.OHLCRenderer.prototype.init=function(e){this.lineWidth=1.5;a.jqplot.LineRenderer.prototype.init.call(this,e);var b=this._yaxis._dataBounds;var f=this._plotData;if(f[0].length<5){this.renderer.hlc=true;for(var c=0;c<f.length;c++){if(f[c][2]<b.min||b.min==null){b.min=f[c][2]}if(f[c][1]>b.max||b.max==null){b.max=f[c][1]}}}else{for(var c=0;c<f.length;c++){if(f[c][3]<b.min||b.min==null){b.min=f[c][3]}if(f[c][2]>b.max||b.max==null){b.max=f[c][2]}}}};a.jqplot.OHLCRenderer.prototype.draw=function(z,J,g){var G=this.data;var u=this._xaxis.min;var y=this._xaxis.max;var k=0;var H=G.length;var n=this._xaxis.series_u2p;var F=this._yaxis.series_u2p;var C,D,e,I,E,m,K,B;var v;var t=this.renderer;var q=(g!=undefined)?g:{};var j=(q.shadow!=undefined)?q.shadow:this.shadow;var A=(q.fill!=undefined)?q.fill:this.fill;var c=(q.fillAndStroke!=undefined)?q.fillAndStroke:this.fillAndStroke;t.bodyWidth=(q.bodyWidth!=undefined)?q.bodyWidth:t.bodyWidth;t.tickLength=(q.tickLength!=undefined)?q.tickLength:t.tickLength;z.save();if(this.show){var l,p,f,L,s;for(var C=0;C<G.length;C++){if(G[C][0]<u){k=C}else{if(G[C][0]<y){H=C+1}}}if(t.candleStick){if(typeof(t.bodyWidth)=="number"){t._bodyWidth=t.bodyWidth}else{t._bodyWidth=Math.min(20,z.canvas.width/(H-k)/2)}}else{if(typeof(t.tickLength)=="number"){t._tickLength=t.tickLength}else{t._tickLength=Math.min(10,z.canvas.width/(H-k)/4)}}for(var C=k;C<H;C++){l=n(G[C][0]);if(t.hlc){p=null;f=F(G[C][1]);L=F(G[C][2]);s=F(G[C][3])}else{p=F(G[C][1]);f=F(G[C][2]);L=F(G[C][3]);s=F(G[C][4])}v={};if(t.candleStick&&!t.hlc){m=t._bodyWidth;K=l-m/2;if(s<p){if(t.wickColor){v.color=t.wickColor}else{if(t.downBodyColor){v.color=t.upBodyColor}}e=a.extend(true,{},q,v);t.shapeRenderer.draw(z,[[l,f],[l,s]],e);t.shapeRenderer.draw(z,[[l,p],[l,L]],e);v={};I=s;E=p-s;if(t.fillUpBody){v.fillRect=true}else{v.strokeRect=true;m=m-this.lineWidth;K=l-m/2}if(t.upBodyColor){v.color=t.upBodyColor;v.fillStyle=t.upBodyColor}B=[K,I,m,E]}else{if(s>p){if(t.wickColor){v.color=t.wickColor}else{if(t.downBodyColor){v.color=t.downBodyColor}}e=a.extend(true,{},q,v);t.shapeRenderer.draw(z,[[l,f],[l,p]],e);t.shapeRenderer.draw(z,[[l,s],[l,L]],e);v={};I=p;E=s-p;if(t.fillDownBody){v.fillRect=true}else{v.strokeRect=true;m=m-this.lineWidth;K=l-m/2}if(t.downBodyColor){v.color=t.downBodyColor;v.fillStyle=t.downBodyColor}B=[K,I,m,E]}else{if(t.wickColor){v.color=t.wickColor}e=a.extend(true,{},q,v);t.shapeRenderer.draw(z,[[l,f],[l,L]],e);v={};v.fillRect=false;v.strokeRect=false;K=[l-m/2,p];I=[l+m/2,s];m=null;E=null;B=[K,I]}}e=a.extend(true,{},q,v);t.shapeRenderer.draw(z,B,e)}else{D=q.color;if(t.openColor){q.color=t.openColor}if(!t.hlc){t.shapeRenderer.draw(z,[[l-t._tickLength,p],[l,p]],q)}q.color=D;if(t.wickColor){q.color=t.wickColor}t.shapeRenderer.draw(z,[[l,f],[l,L]],q);q.color=D;if(t.closeColor){q.color=t.closeColor}t.shapeRenderer.draw(z,[[l,s],[l+t._tickLength,s]],q);q.color=D}}}z.restore()};a.jqplot.OHLCRenderer.prototype.drawShadow=function(b,d,c){};a.jqplot.OHLCRenderer.checkOptions=function(d,c,b){if(!b.highlighter){b.highlighter={showMarker:false,tooltipAxes:"y",yvalues:4,formatString:'<table class="jqplot-highlighter"><tr><td>date:</td><td>%s</td></tr><tr><td>open:</td><td>%s</td></tr><tr><td>hi:</td><td>%s</td></tr><tr><td>low:</td><td>%s</td></tr><tr><td>close:</td><td>%s</td></tr></table>'}}}})(jQuery); | |||
(function(a){a.jqplot.OHLCRenderer=function(){a.jqplot.LineRenderer.call(this);this.candleStick=false;this.tickLength="auto";this.bodyWidth="auto";this.openColor=null;this.closeColor=null;this.wickColor=null;this.fillUpBody=false;this.fillDownBody=true;this.upBodyColor=null;this.downBodyColor=null;this.hlc=false;this.lineWidth=1.5;this._tickLength;this._bodyWidth};a.jqplot.OHLCRenderer.prototype=new a.jqplot.LineRenderer();a.jqplot.OHLCRenderer.prototype.constructor=a.jqplot.OHLCRenderer;a.jqplot.OHLCRenderer.prototype.init=function(e){e=e||{};this.lineWidth=e.lineWidth||1.5;a.jqplot.LineRenderer.prototype.init.call(this,e);this._type="ohlc";var b=this._yaxis._dataBounds;var f=this._plotData;if(f[0].length<5){this.renderer.hlc=true;for(var c=0;c<f.length;c++){if(f[c][2]<b.min||b.min==null){b.min=f[c][2]}if(f[c][1]>b.max||b.max==null){b.max=f[c][1]}}}else{for(var c=0;c<f.length;c++){if(f[c][3]<b.min||b.min==null){b.min=f[c][3]}if(f[c][2]>b.max||b.max==null){b.max=f[c][2]}}}};a.jqplot.OHLCRenderer.prototype.draw=function(A,N,j){var J=this.data;var v=this._xaxis.min;var z=this._xaxis.max;var l=0;var K=J.length;var p=this._xaxis.series_u2p;var G=this._yaxis.series_u2p;var D,E,f,M,F,n,O,C;var y;var u=this.renderer;var s=(j!=undefined)?j:{};var k=(s.shadow!=undefined)?s.shadow:this.shadow;var B=(s.fill!=undefined)?s.fill:this.fill;var c=(s.fillAndStroke!=undefined)?s.fillAndStroke:this.fillAndStroke;u.bodyWidth=(s.bodyWidth!=undefined)?s.bodyWidth:u.bodyWidth;u.tickLength=(s.tickLength!=undefined)?s.tickLength:u.tickLength;A.save();if(this.show){var m,q,g,Q,t;for(var D=0;D<J.length;D++){if(J[D][0]<v){l=D}else{if(J[D][0]<z){K=D+1}}}var I=this.gridData[K-1][0]-this.gridData[l][0];var L=K-l;try{var P=Math.abs(this._xaxis.series_u2p(parseInt(this._xaxis._intervalStats[0].sortedIntervals[0].interval))-this._xaxis.series_u2p(0))}catch(H){var P=I/L}if(u.candleStick){if(typeof(u.bodyWidth)=="number"){u._bodyWidth=u.bodyWidth}else{u._bodyWidth=Math.min(20,P/1.75)}}else{if(typeof(u.tickLength)=="number"){u._tickLength=u.tickLength}else{u._tickLength=Math.min(10,P/3.5)}}for(var D=l;D<K;D++){m=p(J[D][0]);if(u.hlc){q=null;g=G(J[D][1]);Q=G(J[D][2]);t=G(J[D][3])}else{q=G(J[D][1]);g=G(J[D][2]);Q=G(J[D][3]);t=G(J[D][4])}y={};if(u.candleStick&&!u.hlc){n=u._bodyWidth;O=m-n/2;if(t<q){if(u.wickColor){y.color=u.wickColor}else{if(u.downBodyColor){y.color=u.upBodyColor}}f=a.extend(true,{},s,y);u.shapeRenderer.draw(A,[[m,g],[m,t]],f);u.shapeRenderer.draw(A,[[m,q],[m,Q]],f);y={};M=t;F=q-t;if(u.fillUpBody){y.fillRect=true}else{y.strokeRect=true;n=n-this.lineWidth;O=m-n/2}if(u.upBodyColor){y.color=u.upBodyColor;y.fillStyle=u.upBodyColor}C=[O,M,n,F]}else{if(t>q){if(u.wickColor){y.color=u.wickColor}else{if(u.downBodyColor){y.color=u.downBodyColor}}f=a.extend(true,{},s,y);u.shapeRenderer.draw(A,[[m,g],[m,q]],f);u.shapeRenderer.draw(A,[[m,t],[m,Q]],f);y={};M=q;F=t-q;if(u.fillDownBody){y.fillRect=true}else{y.strokeRect=true;n=n-this.lineWidth;O=m-n/2}if(u.downBodyColor){y.color=u.downBodyColor;y.fillStyle=u.downBodyColor}C=[O,M,n,F]}else{if(u.wickColor){y.color=u.wickColor}f=a.extend(true,{},s,y);u.shapeRenderer.draw(A,[[m,g],[m,Q]],f);y={};y.fillRect=false;y.strokeRect=false;O=[m-n/2,q];M=[m+n/2,t];n=null;F=null;C=[O,M]}}f=a.extend(true,{},s,y);u.shapeRenderer.draw(A,C,f)}else{E=s.color;if(u.openColor){s.color=u.openColor}if(!u.hlc){u.shapeRenderer.draw(A,[[m-u._tickLength,q],[m,q]],s)}s.color=E;if(u.wickColor){s.color=u.wickColor}u.shapeRenderer.draw(A,[[m,g],[m,Q]],s);s.color=E;if(u.closeColor){s.color=u.closeColor}u.shapeRenderer.draw(A,[[m,t],[m+u._tickLength,t]],s);s.color=E}}}A.restore()};a.jqplot.OHLCRenderer.prototype.drawShadow=function(b,d,c){};a.jqplot.OHLCRenderer.checkOptions=function(d,c,b){if(!b.highlighter){b.highlighter={showMarker:false,tooltipAxes:"y",yvalues:4,formatString:'<table class="jqplot-highlighter"><tr><td>date:</td><td>%s</td></tr><tr><td>open:</td><td>%s</td></tr><tr><td>hi:</td><td>%s</td></tr><tr><td>low:</td><td>%s</td></tr><tr><td>close:</td><td>%s</td></tr></table>'}}}})(jQuery); |
@@ -1,27 +1,70 @@ | |||
/** | |||
* Copyright (c) 2009 Chris Leonello | |||
* jqPlot | |||
* Pure JavaScript plotting plugin using jQuery | |||
* | |||
* Version: 1.0.0b2_r792 | |||
* | |||
* Copyright (c) 2009-2011 Chris Leonello | |||
* jqPlot is currently available for use in all personal or commercial projects | |||
* under both the MIT and GPL version 2.0 licenses. This means that you can | |||
* under both the MIT (http://www.opensource.org/licenses/mit-license.php) and GPL | |||
* version 2.0 (http://www.gnu.org/licenses/gpl-2.0.html) licenses. This means that you can | |||
* choose the license that best suits your project and use it accordingly. | |||
* | |||
* The author would appreciate an email letting him know of any substantial | |||
* use of jqPlot. You can reach the author at: chris dot leonello at gmail | |||
* dot com or see http://www.jqplot.com/info.php . This is, of course, | |||
* not required. | |||
* Although not required, the author would appreciate an email letting him | |||
* know of any substantial use of jqPlot. You can reach the author at: | |||
* chris at jqplot dot com or see http://www.jqplot.com/info.php . | |||
* | |||
* If you are feeling kind and generous, consider supporting the project by | |||
* making a donation at: http://www.jqplot.com/donate.php . | |||
* | |||
* Thanks for using jqPlot! | |||
* sprintf functions contained in jqplot.sprintf.js by Ash Searle: | |||
* | |||
* version 2007.04.27 | |||
* author Ash Searle | |||
* http://hexmen.com/blog/2007/03/printf-sprintf/ | |||
* http://hexmen.com/js/sprintf.js | |||
* The author (Ash Searle) has placed this code in the public domain: | |||
* "This code is unrestricted: you are free to use it however you like." | |||
* | |||
*/ | |||
(function($) { | |||
/** | |||
* Class: $.jqplot.PieRenderer | |||
* Plugin renderer to draw a pie chart. | |||
* Pie charts will draw only the first series. Other series are ignored. | |||
* x values, if present, will be used as slice labels. | |||
* y values give slice size. | |||
* | |||
* To use this renderer, you need to include the | |||
* pie renderer plugin, for example: | |||
* | |||
* > <script type="text/javascript" src="plugins/jqplot.pieRenderer.js"></script> | |||
* | |||
* Properties described here are passed into the $.jqplot function | |||
* as options on the series renderer. For example: | |||
* | |||
* > plot2 = $.jqplot('chart2', [s1, s2], { | |||
* > seriesDefaults: { | |||
* > renderer:$.jqplot.PieRenderer, | |||
* > rendererOptions:{ | |||
* > sliceMargin: 2, | |||
* > startAngle: -90 | |||
* > } | |||
* > } | |||
* > }); | |||
* | |||
* A pie plot will trigger events on the plot target | |||
* according to user interaction. All events return the event object, | |||
* the series index, the point (slice) index, and the point data for | |||
* the appropriate slice. | |||
* | |||
* 'jqplotDataMouseOver' - triggered when user mouseing over a slice. | |||
* 'jqplotDataHighlight' - triggered the first time user mouses over a slice, | |||
* if highlighting is enabled. | |||
* 'jqplotDataUnhighlight' - triggered when a user moves the mouse out of | |||
* a highlighted slice. | |||
* 'jqplotDataClick' - triggered when the user clicks on a slice. | |||
* 'jqplotDataRightClick' - tiggered when the user right clicks on a slice if | |||
* the "captureRightClick" option is set to true on the plot. | |||
*/ | |||
$.jqplot.PieRenderer = function(){ | |||
$.jqplot.LineRenderer.call(this); | |||
@@ -31,17 +74,17 @@ | |||
$.jqplot.PieRenderer.prototype.constructor = $.jqplot.PieRenderer; | |||
// called with scope of a series | |||
$.jqplot.PieRenderer.prototype.init = function(options) { | |||
$.jqplot.PieRenderer.prototype.init = function(options, plot) { | |||
// Group: Properties | |||
// | |||
// prop: diameter | |||
// diameter of the pie, auto computed by default | |||
// Outer diameter of the pie, auto computed by default | |||
this.diameter = null; | |||
// prop: padding | |||
// padding between the pie and plot edges, legend, etc. | |||
this.padding = 20; | |||
// prop: sliceMargin | |||
// pixels spacing between pie slices. | |||
// angular spacing between pie slices in degrees. | |||
this.sliceMargin = 0; | |||
// prop: fill | |||
// true or false, wether to fil the slices. | |||
@@ -57,71 +100,244 @@ | |||
// number of strokes to apply to the shadow, | |||
// each stroke offset shadowOffset from the last. | |||
this.shadowDepth = 5; | |||
// prop: highlightMouseOver | |||
// True to highlight slice when moused over. | |||
// This must be false to enable highlightMouseDown to highlight when clicking on a slice. | |||
this.highlightMouseOver = true; | |||
// prop: highlightMouseDown | |||
// True to highlight when a mouse button is pressed over a slice. | |||
// This will be disabled if highlightMouseOver is true. | |||
this.highlightMouseDown = false; | |||
// prop: highlightColors | |||
// an array of colors to use when highlighting a slice. | |||
this.highlightColors = []; | |||
// prop: dataLabels | |||
// Either 'label', 'value', 'percent' or an array of labels to place on the pie slices. | |||
// Defaults to percentage of each pie slice. | |||
this.dataLabels = 'percent'; | |||
// prop: showDataLabels | |||
// true to show data labels on slices. | |||
this.showDataLabels = false; | |||
// prop: dataLabelFormatString | |||
// Format string for data labels. If none, '%s' is used for "label" and for arrays, '%d' for value and '%d%%' for percentage. | |||
this.dataLabelFormatString = null; | |||
// prop: dataLabelThreshold | |||
// Threshhold in percentage (0-100) of pie area, below which no label will be displayed. | |||
// This applies to all label types, not just to percentage labels. | |||
this.dataLabelThreshold = 3; | |||
// prop: dataLabelPositionFactor | |||
// A Multiplier (0-1) of the pie radius which controls position of label on slice. | |||
// Increasing will slide label toward edge of pie, decreasing will slide label toward center of pie. | |||
this.dataLabelPositionFactor = 0.52; | |||
// prop: dataLabelNudge | |||
// Number of pixels to slide the label away from (+) or toward (-) the center of the pie. | |||
this.dataLabelNudge = 2; | |||
// prop: dataLabelCenterOn | |||
// True to center the data label at its position. | |||
// False to set the inside facing edge of the label at its position. | |||
this.dataLabelCenterOn = true; | |||
// prop: startAngle | |||
// Angle to start drawing pie in degrees. | |||
// According to orientation of canvas coordinate system: | |||
// 0 = on the positive x axis | |||
// -90 = on the positive y axis. | |||
// 90 = on the negaive y axis. | |||
// 180 or - 180 = on the negative x axis. | |||
this.startAngle = 0; | |||
this.tickRenderer = $.jqplot.PieTickRenderer; | |||
// Used as check for conditions where pie shouldn't be drawn. | |||
this._drawData = true; | |||
this._type = 'pie'; | |||
// if user has passed in highlightMouseDown option and not set highlightMouseOver, disable highlightMouseOver | |||
if (options.highlightMouseDown && options.highlightMouseOver == null) { | |||
options.highlightMouseOver = false; | |||
} | |||
$.extend(true, this, options); | |||
if (this.diameter != null) { | |||
this.diameter = this.diameter - this.sliceMargin; | |||
if (this.sliceMargin < 0) { | |||
this.sliceMargin = 0; | |||
} | |||
this._diameter = null; | |||
this._radius = null; | |||
// array of [start,end] angles arrays, one for each slice. In radians. | |||
this._sliceAngles = []; | |||
// index of the currenty highlighted point, if any | |||
this._highlightedPoint = null; | |||
// set highlight colors if none provided | |||
if (this.highlightColors.length == 0) { | |||
for (var i=0; i<this.seriesColors.length; i++){ | |||
var rgba = $.jqplot.getColorComponents(this.seriesColors[i]); | |||
var newrgb = [rgba[0], rgba[1], rgba[2]]; | |||
var sum = newrgb[0] + newrgb[1] + newrgb[2]; | |||
for (var j=0; j<3; j++) { | |||
// when darkening, lowest color component can be is 60. | |||
newrgb[j] = (sum > 570) ? newrgb[j] * 0.8 : newrgb[j] + 0.3 * (255 - newrgb[j]); | |||
newrgb[j] = parseInt(newrgb[j], 10); | |||
} | |||
this.highlightColors.push('rgb('+newrgb[0]+','+newrgb[1]+','+newrgb[2]+')'); | |||
} | |||
} | |||
this.highlightColorGenerator = new $.jqplot.ColorGenerator(this.highlightColors); | |||
plot.postParseOptionsHooks.addOnce(postParseOptions); | |||
plot.postInitHooks.addOnce(postInit); | |||
plot.eventListenerHooks.addOnce('jqplotMouseMove', handleMove); | |||
plot.eventListenerHooks.addOnce('jqplotMouseDown', handleMouseDown); | |||
plot.eventListenerHooks.addOnce('jqplotMouseUp', handleMouseUp); | |||
plot.eventListenerHooks.addOnce('jqplotClick', handleClick); | |||
plot.eventListenerHooks.addOnce('jqplotRightClick', handleRightClick); | |||
plot.postDrawHooks.addOnce(postPlotDraw); | |||
}; | |||
$.jqplot.PieRenderer.prototype.setGridData = function(plot) { | |||
// this is a no-op | |||
// set gridData property. This will hold angle in radians of each data point. | |||
var stack = []; | |||
var td = []; | |||
var sa = this.startAngle/180*Math.PI; | |||
var tot = 0; | |||
// don't know if we have any valid data yet, so set plot to not draw. | |||
this._drawData = false; | |||
for (var i=0; i<this.data.length; i++){ | |||
if (this.data[i][1] != 0) { | |||
// we have data, O.K. to draw. | |||
this._drawData = true; | |||
} | |||
stack.push(this.data[i][1]); | |||
td.push([this.data[i][0]]); | |||
if (i>0) { | |||
stack[i] += stack[i-1]; | |||
} | |||
tot += this.data[i][1]; | |||
} | |||
var fact = Math.PI*2/stack[stack.length - 1]; | |||
for (var i=0; i<stack.length; i++) { | |||
td[i][1] = stack[i] * fact; | |||
td[i][2] = this.data[i][1]/tot; | |||
} | |||
this.gridData = td; | |||
}; | |||
$.jqplot.PieRenderer.prototype.makeGridData = function(data, plot) { | |||
var stack = []; | |||
var td = []; | |||
var tot = 0; | |||
var sa = this.startAngle/180*Math.PI; | |||
// don't know if we have any valid data yet, so set plot to not draw. | |||
this._drawData = false; | |||
for (var i=0; i<data.length; i++){ | |||
if (this.data[i][1] != 0) { | |||
// we have data, O.K. to draw. | |||
this._drawData = true; | |||
} | |||
stack.push(data[i][1]); | |||
td.push([data[i][0]]); | |||
if (i>0) { | |||
stack[i] += stack[i-1]; | |||
} | |||
tot += data[i][1]; | |||
} | |||
var fact = Math.PI*2/stack[stack.length - 1]; | |||
for (var i=0; i<stack.length; i++) { | |||
td[i][1] = stack[i] * fact; | |||
td[i][2] = data[i][1]/tot; | |||
} | |||
return td; | |||
}; | |||
function calcRadiusAdjustment(ang) { | |||
return Math.sin((ang - (ang-Math.PI) / 8 / Math.PI )/2.0); | |||
} | |||
function calcRPrime(ang1, ang2, sliceMargin, fill, lineWidth) { | |||
var rprime = 0; | |||
var ang = ang2 - ang1; | |||
var absang = Math.abs(ang); | |||
var sm = sliceMargin; | |||
if (fill == false) { | |||
sm += lineWidth; | |||
} | |||
if (sm > 0 && absang > 0.01 && absang < 6.282) { | |||
rprime = parseFloat(sm) / 2.0 / calcRadiusAdjustment(ang); | |||
} | |||
return rprime; | |||
} | |||
$.jqplot.PieRenderer.prototype.drawSlice = function (ctx, ang1, ang2, color, isShadow) { | |||
var r = this._diameter / 2; | |||
var fill = this.fill; | |||
var lineWidth = this.lineWidth; | |||
ctx.save(); | |||
ctx.translate(this.sliceMargin*Math.cos((ang1+ang2)/2), this.sliceMargin*Math.sin((ang1+ang2)/2)); | |||
if (isShadow) { | |||
for (var i=0; i<this.shadowDepth; i++) { | |||
ctx.save(); | |||
ctx.translate(this.shadowOffset*Math.cos(this.shadowAngle/180*Math.PI), this.shadowOffset*Math.sin(this.shadowAngle/180*Math.PI)); | |||
doDraw(); | |||
if (this._drawData) { | |||
var r = this._radius; | |||
var fill = this.fill; | |||
var lineWidth = this.lineWidth; | |||
var sm = this.sliceMargin; | |||
if (this.fill == false) { | |||
sm += this.lineWidth; | |||
} | |||
ctx.save(); | |||
ctx.translate(this._center[0], this._center[1]); | |||
var rprime = calcRPrime(ang1, ang2, this.sliceMargin, this.fill, this.lineWidth); | |||
var transx = rprime * Math.cos((ang1 + ang2) / 2.0); | |||
var transy = rprime * Math.sin((ang1 + ang2) / 2.0); | |||
if ((ang2 - ang1) <= Math.PI) { | |||
r -= rprime; | |||
} | |||
else { | |||
r += rprime; | |||
} | |||
ctx.translate(transx, transy); | |||
if (isShadow) { | |||
for (var i=0, l=this.shadowDepth; i<l; i++) { | |||
ctx.save(); | |||
ctx.translate(this.shadowOffset*Math.cos(this.shadowAngle/180*Math.PI), this.shadowOffset*Math.sin(this.shadowAngle/180*Math.PI)); | |||
doDraw(r); | |||
} | |||
for (var i=0, l=this.shadowDepth; i<l; i++) { | |||
ctx.restore(); | |||
} | |||
} | |||
else { | |||
doDraw(r); | |||
} | |||
ctx.restore(); | |||
} | |||
else { | |||
doDraw(); | |||
} | |||
function doDraw () { | |||
function doDraw (rad) { | |||
// Fix for IE and Chrome that can't seem to draw circles correctly. | |||
// ang2 should always be <= 2 pi since that is the way the data is converted. | |||
if (ang2 > 6.282) { | |||
ang2 = 6.282; | |||
// 2Pi = 6.2831853, Pi = 3.1415927 | |||
if (ang2 > 6.282 + this.startAngle) { | |||
ang2 = 6.282 + this.startAngle; | |||
if (ang1 > ang2) { | |||
ang1 = 6.281; | |||
ang1 = 6.281 + this.startAngle; | |||
} | |||
} | |||
// Fix for IE, where it can't seem to handle 0 degree angles. Also avoids | |||
// ugly line on unfilled pies. | |||
if (ang1 >= ang2) { | |||
return; | |||
} | |||
ctx.beginPath(); | |||
ctx.moveTo(0, 0); | |||
ctx.fillStyle = color; | |||
ctx.strokeStyle = color; | |||
ctx.lineWidth = lineWidth; | |||
ctx.arc(0, 0, r, ang1, ang2, false); | |||
ctx.arc(0, 0, rad, ang1, ang2, false); | |||
ctx.lineTo(0,0); | |||
ctx.closePath(); | |||
if (fill) { | |||
ctx.fill(); | |||
} | |||
@@ -129,26 +345,18 @@ | |||
ctx.stroke(); | |||
} | |||
} | |||
if (isShadow) { | |||
for (var i=0; i<this.shadowDepth; i++) { | |||
ctx.restore(); | |||
} | |||
} | |||
ctx.restore(); | |||
}; | |||
// called with scope of series | |||
$.jqplot.PieRenderer.prototype.draw = function (ctx, gd, options) { | |||
$.jqplot.PieRenderer.prototype.draw = function (ctx, gd, options, plot) { | |||
var i; | |||
var opts = (options != undefined) ? options : {}; | |||
// offset and direction of offset due to legend placement | |||
var offx = 0; | |||
var offy = 0; | |||
var trans = 1; | |||
var colorGenerator = new this.colorGenerator(this.seriesColors); | |||
if (options.legendInfo) { | |||
var colorGenerator = new $.jqplot.ColorGenerator(this.seriesColors); | |||
if (options.legendInfo && options.legendInfo.placement == 'insideGrid') { | |||
var li = options.legendInfo; | |||
switch (li.location) { | |||
case 'nw': | |||
@@ -185,33 +393,111 @@ | |||
} | |||
var shadow = (opts.shadow != undefined) ? opts.shadow : this.shadow; | |||
var showLine = (opts.showLine != undefined) ? opts.showLine : this.showLine; | |||
var fill = (opts.fill != undefined) ? opts.fill : this.fill; | |||
var cw = ctx.canvas.width; | |||
var ch = ctx.canvas.height; | |||
var w = cw - offx - 2 * this.padding; | |||
var h = ch - offy - 2 * this.padding; | |||
var d = Math.min(w,h); | |||
this._diameter = this.diameter || d - this.sliceMargin; | |||
// this.diameter -= this.sliceMargin; | |||
var r = this._diameter/2; | |||
ctx.save(); | |||
ctx.translate((cw - trans * offx)/2 + trans * offx, (ch - trans*offy)/2 + trans * offy); | |||
var mindim = Math.min(w,h); | |||
var d = mindim; | |||
// Fixes issue #272. Thanks hugwijst! | |||
// reset slice angles array. | |||
this._sliceAngles = []; | |||
var sm = this.sliceMargin; | |||
if (this.fill == false) { | |||
sm += this.lineWidth; | |||
} | |||
var rprime; | |||
var maxrprime = 0; | |||
var ang, ang1, ang2, shadowColor; | |||
var sa = this.startAngle / 180 * Math.PI; | |||
// have to pre-draw shadows, so loop throgh here and calculate some values also. | |||
for (var i=0, l=gd.length; i<l; i++) { | |||
ang1 = (i == 0) ? sa : gd[i-1][1] + sa; | |||
ang2 = gd[i][1] + sa; | |||
this._sliceAngles.push([ang1, ang2]); | |||
rprime = calcRPrime(ang1, ang2, this.sliceMargin, this.fill, this.lineWidth); | |||
if (Math.abs(ang2-ang1) > Math.PI) { | |||
maxrprime = Math.max(rprime, maxrprime); | |||
} | |||
} | |||
if (this.diameter != null && this.diameter > 0) { | |||
this._diameter = this.diameter - 2*maxrprime; | |||
} | |||
else { | |||
this._diameter = d - 2*maxrprime; | |||
} | |||
// Need to check for undersized pie. This can happen if | |||
// plot area too small and legend is too big. | |||
if (this._diameter < 6) { | |||
$.jqplot.log('Diameter of pie too small, not rendering.'); | |||
return; | |||
} | |||
var r = this._radius = this._diameter/2; | |||
this._center = [(cw - trans * offx)/2 + trans * offx + maxrprime * Math.cos(sa), (ch - trans*offy)/2 + trans * offy + maxrprime * Math.sin(sa)]; | |||
if (this.shadow) { | |||
var shadowColor = 'rgba(0,0,0,'+this.shadowAlpha+')'; | |||
for (var i=0; i<gd.length; i++) { | |||
var ang1 = (i == 0) ? 0 : gd[i-1][1]; | |||
this.renderer.drawSlice.call (this, ctx, ang1, gd[i][1], shadowColor, true); | |||
for (var i=0, l=gd.length; i<l; i++) { | |||
shadowColor = 'rgba(0,0,0,'+this.shadowAlpha+')'; | |||
this.renderer.drawSlice.call (this, ctx, this._sliceAngles[i][0], this._sliceAngles[i][1], shadowColor, true); | |||
} | |||
} | |||
for (var i=0; i<gd.length; i++) { | |||
var ang1 = (i == 0) ? 0 : gd[i-1][1]; | |||
this.renderer.drawSlice.call (this, ctx, ang1, gd[i][1], colorGenerator.next()); | |||
} | |||
this.renderer.drawSlice.call (this, ctx, this._sliceAngles[i][0], this._sliceAngles[i][1], colorGenerator.next(), false); | |||
ctx.restore(); | |||
if (this.showDataLabels && gd[i][2]*100 >= this.dataLabelThreshold) { | |||
var fstr, avgang = (this._sliceAngles[i][0] + this._sliceAngles[i][1])/2, label; | |||
if (this.dataLabels == 'label') { | |||
fstr = this.dataLabelFormatString || '%s'; | |||
label = $.jqplot.sprintf(fstr, gd[i][0]); | |||
} | |||
else if (this.dataLabels == 'value') { | |||
fstr = this.dataLabelFormatString || '%d'; | |||
label = $.jqplot.sprintf(fstr, this.data[i][1]); | |||
} | |||
else if (this.dataLabels == 'percent') { | |||
fstr = this.dataLabelFormatString || '%d%%'; | |||
label = $.jqplot.sprintf(fstr, gd[i][2]*100); | |||
} | |||
else if (this.dataLabels.constructor == Array) { | |||
fstr = this.dataLabelFormatString || '%s'; | |||
label = $.jqplot.sprintf(fstr, this.dataLabels[i]); | |||
} | |||
var fact = (this._radius ) * this.dataLabelPositionFactor + this.sliceMargin + this.dataLabelNudge; | |||
var x = this._center[0] + Math.cos(avgang) * fact + this.canvas._offsets.left; | |||
var y = this._center[1] + Math.sin(avgang) * fact + this.canvas._offsets.top; | |||
var labelelem = $('<div class="jqplot-pie-series jqplot-data-label" style="position:absolute;">' + label + '</div>').insertBefore(plot.eventCanvas._elem); | |||
if (this.dataLabelCenterOn) { | |||
x -= labelelem.width()/2; | |||
y -= labelelem.height()/2; | |||
} | |||
else { | |||
x -= labelelem.width() * Math.sin(avgang/2); | |||
y -= labelelem.height()/2; | |||
} | |||
x = Math.round(x); | |||
y = Math.round(y); | |||
labelelem.css({left: x, top: y}); | |||
} | |||
} | |||
}; | |||
$.jqplot.PieAxisRenderer = function() { | |||
@@ -243,44 +529,201 @@ | |||
this.show = false; | |||
}; | |||
$.jqplot.PieLegendRenderer = function() { | |||
$.jqplot.PieLegendRenderer = function(){ | |||
$.jqplot.TableLegendRenderer.call(this); | |||
}; | |||
$.jqplot.PieLegendRenderer.prototype = new $.jqplot.TableLegendRenderer(); | |||
$.jqplot.PieLegendRenderer.prototype.constructor = $.jqplot.PieLegendRenderer; | |||
/** | |||
* Class: $.jqplot.PieLegendRenderer | |||
* Legend Renderer specific to pie plots. Set by default | |||
* when user creates a pie plot. | |||
*/ | |||
$.jqplot.PieLegendRenderer.prototype.init = function(options) { | |||
// Group: Properties | |||
// | |||
// prop: numberRows | |||
// Maximum number of rows in the legend. 0 or null for unlimited. | |||
this.numberRows = null; | |||
// prop: numberColumns | |||
// Maximum number of columns in the legend. 0 or null for unlimited. | |||
this.numberColumns = null; | |||
$.extend(true, this, options); | |||
}; | |||
// called with context of legend | |||
$.jqplot.PieLegendRenderer.prototype.draw = function() { | |||
var legend = this; | |||
if (this.show) { | |||
var series = this._series; | |||
// make a table. one line label per row. | |||
var ss = 'position:absolute;'; | |||
ss += (this.background) ? 'background:'+this.background+';' : ''; | |||
ss += (this.border) ? 'border:'+this.border+';' : ''; | |||
ss += (this.fontSize) ? 'font-size:'+this.fontSize+';' : ''; | |||
ss += (this.fontFamily) ? 'font-family:'+this.fontFamily+';' : ''; | |||
ss += (this.textColor) ? 'color:'+this.textColor+';' : ''; | |||
this._elem = $('<table class="jqplot-table-legend" style="'+ss+'"></table>'); | |||
var pad = false; | |||
this._elem = $(document.createElement('table')); | |||
this._elem.addClass('jqplot-table-legend'); | |||
var ss = {position:'absolute'}; | |||
if (this.background) { | |||
ss['background'] = this.background; | |||
} | |||
if (this.border) { | |||
ss['border'] = this.border; | |||
} | |||
if (this.fontSize) { | |||
ss['fontSize'] = this.fontSize; | |||
} | |||
if (this.fontFamily) { | |||
ss['fontFamily'] = this.fontFamily; | |||
} | |||
if (this.textColor) { | |||
ss['textColor'] = this.textColor; | |||
} | |||
if (this.marginTop != null) { | |||
ss['marginTop'] = this.marginTop; | |||
} | |||
if (this.marginBottom != null) { | |||
ss['marginBottom'] = this.marginBottom; | |||
} | |||
if (this.marginLeft != null) { | |||
ss['marginLeft'] = this.marginLeft; | |||
} | |||
if (this.marginRight != null) { | |||
ss['marginRight'] = this.marginRight; | |||
} | |||
this._elem.css(ss); | |||
// Pie charts legends don't go by number of series, but by number of data points | |||
// in the series. Refactor things here for that. | |||
var pad = false, | |||
reverse = false, | |||
nr, | |||
nc; | |||
var s = series[0]; | |||
var colorGenerator = new s.colorGenerator(s.seriesColors); | |||
var colorGenerator = new $.jqplot.ColorGenerator(s.seriesColors); | |||
if (s.show) { | |||
var pd = s.data; | |||
for (var i=0; i<pd.length; i++){ | |||
var lt = pd[i][0].toString(); | |||
if (lt) { | |||
this.renderer.addrow.call(this, lt, colorGenerator.next(), pad); | |||
pad = true; | |||
} | |||
if (this.numberRows) { | |||
nr = this.numberRows; | |||
if (!this.numberColumns){ | |||
nc = Math.ceil(pd.length/nr); | |||
} | |||
else{ | |||
nc = this.numberColumns; | |||
} | |||
} | |||
else if (this.numberColumns) { | |||
nc = this.numberColumns; | |||
nr = Math.ceil(pd.length/this.numberColumns); | |||
} | |||
else { | |||
nr = pd.length; | |||
nc = 1; | |||
} | |||
var i, j; | |||
var tr, td1, td2; | |||
var lt, rs, color; | |||
var idx = 0; | |||
var div0, div1; | |||
for (i=0; i<nr; i++) { | |||
tr = $(document.createElement('tr')); | |||
tr.addClass('jqplot-table-legend'); | |||
if (reverse){ | |||
tr.prependTo(this._elem); | |||
} | |||
else{ | |||
tr.appendTo(this._elem); | |||
} | |||
for (j=0; j<nc; j++) { | |||
if (idx < pd.length){ | |||
lt = this.labels[idx] || pd[idx][0].toString(); | |||
color = colorGenerator.next(); | |||
if (!reverse){ | |||
if (i>0){ | |||
pad = true; | |||
} | |||
else{ | |||
pad = false; | |||
} | |||
} | |||
else{ | |||
if (i == nr -1){ | |||
pad = false; | |||
} | |||
else{ | |||
pad = true; | |||
} | |||
} | |||
rs = (pad) ? this.rowSpacing : '0'; | |||
td1 = $(document.createElement('td')); | |||
td1.addClass('jqplot-table-legend'); | |||
td1.css({textAlign: 'center', paddingTop: rs}); | |||
div0 = $(document.createElement('div')); | |||
div1 = $(document.createElement('div')); | |||
div1.addClass('jqplot-table-legend-swatch'); | |||
div1.css({backgroundColor: color, borderColor: color}); | |||
td1.append(div0.append(div1)); | |||
td2 = $(document.createElement('td')); | |||
td2.addClass('jqplot-table-legend'); | |||
td2.css('paddingTop', rs); | |||
if (this.escapeHtml){ | |||
td2.text(lt); | |||
} | |||
else { | |||
td2.html(lt); | |||
} | |||
if (reverse) { | |||
td2.prependTo(tr); | |||
td1.prependTo(tr); | |||
} | |||
else { | |||
td1.appendTo(tr); | |||
td2.appendTo(tr); | |||
} | |||
pad = true; | |||
} | |||
idx++; | |||
} | |||
} | |||
} | |||
} | |||
return this._elem; | |||
} | |||
return this._elem; | |||
}; | |||
$.jqplot.PieRenderer.prototype.handleMove = function(ev, gridpos, datapos, neighbor, plot) { | |||
if (neighbor) { | |||
var ins = [neighbor.seriesIndex, neighbor.pointIndex, neighbor.data]; | |||
plot.target.trigger('jqplotDataMouseOver', ins); | |||
if (plot.series[ins[0]].highlightMouseOver && !(ins[0] == plot.plugins.pieRenderer.highlightedSeriesIndex && ins[1] == plot.series[ins[0]]._highlightedPoint)) { | |||
plot.target.trigger('jqplotDataHighlight', ins); | |||
highlight (plot, ins[0], ins[1]); | |||
} | |||
} | |||
else if (neighbor == null) { | |||
unhighlight (plot); | |||
} | |||
}; | |||
// this.eventCanvas._elem.bind($.jqplot.eventListenerHooks[i][0], {plot:this}, $.jqplot.eventListenerHooks[i][1]); | |||
// setup default renderers for axes and legend so user doesn't have to | |||
// called with scope of plot | |||
function preInit(target, data, options) { | |||
@@ -305,11 +748,22 @@ | |||
options.axesDefaults.renderer = $.jqplot.PieAxisRenderer; | |||
options.legend.renderer = $.jqplot.PieLegendRenderer; | |||
options.legend.preDraw = true; | |||
// options.seriesDefaults.colorGenerator = this.colorGenerator; | |||
// options.seriesDefaults.seriesColors = this.seriesColors; | |||
options.seriesDefaults.pointLabels = {show: false}; | |||
} | |||
} | |||
function postInit(target, data, options) { | |||
for (var i=0; i<this.series.length; i++) { | |||
if (this.series[i].renderer.constructor == $.jqplot.PieRenderer) { | |||
// don't allow mouseover and mousedown at same time. | |||
if (this.series[i].highlightMouseOver) { | |||
this.series[i].highlightMouseDown = false; | |||
} | |||
} | |||
} | |||
this.target.bind('mouseout', {plot:this}, function (ev) { unhighlight(ev.data.plot); }); | |||
} | |||
// called with scope of plot | |||
function postParseOptions(options) { | |||
for (var i=0; i<this.series.length; i++) { | |||
@@ -318,8 +772,119 @@ | |||
} | |||
} | |||
function highlight (plot, sidx, pidx) { | |||
var s = plot.series[sidx]; | |||
var canvas = plot.plugins.pieRenderer.highlightCanvas; | |||
canvas._ctx.clearRect(0,0,canvas._ctx.canvas.width, canvas._ctx.canvas.height); | |||
s._highlightedPoint = pidx; | |||
plot.plugins.pieRenderer.highlightedSeriesIndex = sidx; | |||
s.renderer.drawSlice.call(s, canvas._ctx, s._sliceAngles[pidx][0], s._sliceAngles[pidx][1], s.highlightColorGenerator.get(pidx), false); | |||
} | |||
function unhighlight (plot) { | |||
var canvas = plot.plugins.pieRenderer.highlightCanvas; | |||
canvas._ctx.clearRect(0,0, canvas._ctx.canvas.width, canvas._ctx.canvas.height); | |||
for (var i=0; i<plot.series.length; i++) { | |||
plot.series[i]._highlightedPoint = null; | |||
} | |||
plot.plugins.pieRenderer.highlightedSeriesIndex = null; | |||
plot.target.trigger('jqplotDataUnhighlight'); | |||
} | |||
function handleMove(ev, gridpos, datapos, neighbor, plot) { | |||
if (neighbor) { | |||
var ins = [neighbor.seriesIndex, neighbor.pointIndex, neighbor.data]; | |||
var evt1 = jQuery.Event('jqplotDataMouseOver'); | |||
evt1.pageX = ev.pageX; | |||
evt1.pageY = ev.pageY; | |||
plot.target.trigger(evt1, ins); | |||
if (plot.series[ins[0]].highlightMouseOver && !(ins[0] == plot.plugins.pieRenderer.highlightedSeriesIndex && ins[1] == plot.series[ins[0]]._highlightedPoint)) { | |||
var evt = jQuery.Event('jqplotDataHighlight'); | |||
evt.pageX = ev.pageX; | |||
evt.pageY = ev.pageY; | |||
plot.target.trigger(evt, ins); | |||
highlight (plot, ins[0], ins[1]); | |||
} | |||
} | |||
else if (neighbor == null) { | |||
unhighlight (plot); | |||
} | |||
} | |||
function handleMouseDown(ev, gridpos, datapos, neighbor, plot) { | |||
if (neighbor) { | |||
var ins = [neighbor.seriesIndex, neighbor.pointIndex, neighbor.data]; | |||
if (plot.series[ins[0]].highlightMouseDown && !(ins[0] == plot.plugins.pieRenderer.highlightedSeriesIndex && ins[1] == plot.series[ins[0]]._highlightedPoint)) { | |||
var evt = jQuery.Event('jqplotDataHighlight'); | |||
evt.pageX = ev.pageX; | |||
evt.pageY = ev.pageY; | |||
plot.target.trigger(evt, ins); | |||
highlight (plot, ins[0], ins[1]); | |||
} | |||
} | |||
else if (neighbor == null) { | |||
unhighlight (plot); | |||
} | |||
} | |||
function handleMouseUp(ev, gridpos, datapos, neighbor, plot) { | |||
var idx = plot.plugins.pieRenderer.highlightedSeriesIndex; | |||
if (idx != null && plot.series[idx].highlightMouseDown) { | |||
unhighlight(plot); | |||
} | |||
} | |||
function handleClick(ev, gridpos, datapos, neighbor, plot) { | |||
if (neighbor) { | |||
var ins = [neighbor.seriesIndex, neighbor.pointIndex, neighbor.data]; | |||
var evt = jQuery.Event('jqplotDataClick'); | |||
evt.pageX = ev.pageX; | |||
evt.pageY = ev.pageY; | |||
plot.target.trigger(evt, ins); | |||
} | |||
} | |||
function handleRightClick(ev, gridpos, datapos, neighbor, plot) { | |||
if (neighbor) { | |||
var ins = [neighbor.seriesIndex, neighbor.pointIndex, neighbor.data]; | |||
var idx = plot.plugins.pieRenderer.highlightedSeriesIndex; | |||
if (idx != null && plot.series[idx].highlightMouseDown) { | |||
unhighlight(plot); | |||
} | |||
var evt = jQuery.Event('jqplotDataRightClick'); | |||
evt.pageX = ev.pageX; | |||
evt.pageY = ev.pageY; | |||
plot.target.trigger(evt, ins); | |||
} | |||
} | |||
// called within context of plot | |||
// create a canvas which we can draw on. | |||
// insert it before the eventCanvas, so eventCanvas will still capture events. | |||
function postPlotDraw() { | |||
// Memory Leaks patch | |||
if (this.plugins.pieRenderer && this.plugins.pieRenderer.highlightCanvas) { | |||
this.plugins.pieRenderer.highlightCanvas.resetCanvas(); | |||
this.plugins.pieRenderer.highlightCanvas = null; | |||
} | |||
this.plugins.pieRenderer = {highlightedSeriesIndex:null}; | |||
this.plugins.pieRenderer.highlightCanvas = new $.jqplot.GenericCanvas(); | |||
// do we have any data labels? if so, put highlight canvas before those | |||
var labels = $(this.targetId+' .jqplot-data-label'); | |||
if (labels.length) { | |||
$(labels[0]).before(this.plugins.pieRenderer.highlightCanvas.createElement(this._gridPadding, 'jqplot-pieRenderer-highlight-canvas', this._plotDimensions, this)); | |||
} | |||
// else put highlight canvas before event canvas. | |||
else { | |||
this.eventCanvas._elem.before(this.plugins.pieRenderer.highlightCanvas.createElement(this._gridPadding, 'jqplot-pieRenderer-highlight-canvas', this._plotDimensions, this)); | |||
} | |||
var hctx = this.plugins.pieRenderer.highlightCanvas.setContext(); | |||
} | |||
$.jqplot.preInitHooks.push(preInit); | |||
$.jqplot.postParseOptionsHooks.push(postParseOptions); | |||
$.jqplot.PieTickRenderer = function() { | |||
$.jqplot.AxisTickRenderer.call(this); | |||
@@ -1,18 +1,30 @@ | |||
/** | |||
* Copyright (c) 2009 Chris Leonello | |||
* jqPlot | |||
* Pure JavaScript plotting plugin using jQuery | |||
* | |||
* Version: 1.0.0b2_r792 | |||
* | |||
* Copyright (c) 2009-2011 Chris Leonello | |||
* jqPlot is currently available for use in all personal or commercial projects | |||
* under both the MIT and GPL version 2.0 licenses. This means that you can | |||
* under both the MIT (http://www.opensource.org/licenses/mit-license.php) and GPL | |||
* version 2.0 (http://www.gnu.org/licenses/gpl-2.0.html) licenses. This means that you can | |||
* choose the license that best suits your project and use it accordingly. | |||
* | |||
* The author would appreciate an email letting him know of any substantial | |||
* use of jqPlot. You can reach the author at: chris dot leonello at gmail | |||
* dot com or see http://www.jqplot.com/info.php . This is, of course, | |||
* not required. | |||
* Although not required, the author would appreciate an email letting him | |||
* know of any substantial use of jqPlot. You can reach the author at: | |||
* chris at jqplot dot com or see http://www.jqplot.com/info.php . | |||
* | |||
* If you are feeling kind and generous, consider supporting the project by | |||
* making a donation at: http://www.jqplot.com/donate.php . | |||
* | |||
* Thanks for using jqPlot! | |||
* sprintf functions contained in jqplot.sprintf.js by Ash Searle: | |||
* | |||
* version 2007.04.27 | |||
* author Ash Searle | |||
* http://hexmen.com/blog/2007/03/printf-sprintf/ | |||
* http://hexmen.com/js/sprintf.js | |||
* The author (Ash Searle) has placed this code in the public domain: | |||
* "This code is unrestricted: you are free to use it however you like." | |||
* | |||
*/ | |||
(function($) { | |||
@@ -77,11 +89,14 @@ | |||
this.labelsFromSeries = false; | |||
// prop: seriesLabelIndex | |||
// array index for location of labels within data point arrays. | |||
// if null, will use the last element of teh data point array. | |||
// if null, will use the last element of the data point array. | |||
this.seriesLabelIndex = null; | |||
// prop: labels | |||
// array of arrays of labels, one array for each series. | |||
this.labels = []; | |||
// actual labels that will get displayed. | |||
// needed to preserve user specified labels in labels array. | |||
this._labels = []; | |||
// prop: stackedValue | |||
// true to display value as stacked in a stacked plot. | |||
// no effect if labels is specified. | |||
@@ -100,10 +115,17 @@ | |||
// Number of pixels that the label must be away from an axis | |||
// boundary in order to be drawn. Negative values will allow overlap | |||
// with the grid boundaries. | |||
this.edgeTolerance = 0; | |||
this.edgeTolerance = -5; | |||
// prop: formatter | |||
// A class of a formatter for the tick text. sprintf by default. | |||
this.formatter = $.jqplot.DefaultTickFormatter; | |||
// prop: formatString | |||
// string passed to the formatter. | |||
this.formatString = ''; | |||
// prop: hideZeros | |||
// true to not show a label for a value which is 0. | |||
this.hideZeros = false; | |||
this._elems = []; | |||
$.extend(true, this, options); | |||
}; | |||
@@ -115,31 +137,55 @@ | |||
// called with scope of a series | |||
$.jqplot.PointLabels.init = function (target, data, seriesDefaults, opts){ | |||
var options = $.extend(true, {}, seriesDefaults, opts); | |||
options.pointLabels = options.pointLabels || {}; | |||
if (this.renderer.constructor == $.jqplot.BarRenderer && this.barDirection == 'horizontal' && !options.pointLabels.location) { | |||
options.pointLabels.location = 'e'; | |||
} | |||
// add a pointLabels attribute to the series plugins | |||
this.plugins.pointLabels = new $.jqplot.PointLabels(options.pointLabels); | |||
var p = this.plugins.pointLabels; | |||
if (p.labels.length == 0 || p.labelsFromSeries) { | |||
this.plugins.pointLabels.setLabels.call(this); | |||
}; | |||
// called with scope of series | |||
$.jqplot.PointLabels.prototype.setLabels = function() { | |||
var p = this.plugins.pointLabels; | |||
var labelIdx; | |||
if (p.seriesLabelIndex != null) { | |||
labelIdx = p.seriesLabelIndex; | |||
} | |||
else if (this.renderer.constructor == $.jqplot.BarRenderer && this.barDirection == 'horizontal') { | |||
labelIdx = 0; | |||
} | |||
else { | |||
labelIdx = this._plotData[0].length -1; | |||
} | |||
p._labels = []; | |||
if (p.labels.length == 0 || p.labelsFromSeries) { | |||
if (p.stackedValue) { | |||
if (this._plotData.length && this._plotData[0].length){ | |||
var idx = p.seriesLabelIndex || this._plotData[0].length -1; | |||
// var idx = p.seriesLabelIndex || this._plotData[0].length -1; | |||
for (var i=0; i<this._plotData.length; i++) { | |||
p.labels.push(this._plotData[i][idx]); | |||
p._labels.push(this._plotData[i][labelIdx]); | |||
} | |||
} | |||
} | |||
else { | |||
var d = this.data; | |||
var d = this._plotData; | |||
if (this.renderer.constructor == $.jqplot.BarRenderer && this.waterfall) { | |||
d = this._data; | |||
} | |||
if (d.length && d[0].length) { | |||
var idx = p.seriesLabelIndex || d[0].length -1; | |||
// var idx = p.seriesLabelIndex || d[0].length -1; | |||
for (var i=0; i<d.length; i++) { | |||
p.labels.push(d[i][idx]); | |||
p._labels.push(d[i][labelIdx]); | |||
} | |||
} | |||
d = null; | |||
} | |||
} | |||
else if (p.labels.length){ | |||
p._labels = p.labels; | |||
} | |||
}; | |||
$.jqplot.PointLabels.prototype.xOffset = function(elem, location, padding) { | |||
@@ -219,60 +265,50 @@ | |||
// called with scope of series | |||
$.jqplot.PointLabels.draw = function (sctx, options) { | |||
var p = this.plugins.pointLabels; | |||
// set labels again in case they have changed. | |||
p.setLabels.call(this); | |||
// remove any previous labels | |||
for (var i=0; i<p._elems.length; i++) { | |||
// Memory Leaks patch | |||
// p._elems[i].remove(); | |||
p._elems[i].emptyForce(); | |||
} | |||
p._elems.splice(0, p._elems.length); | |||
if (p.show) { | |||
// var xoffset, yoffset; | |||
// | |||
// switch (p.location) { | |||
// case 'nw': | |||
// xoffset = function(elem) { return -elem.outerWidth(true) - p.xpadding; }; | |||
// yoffset = function(elem) { return -elem.outerHeight(true) - p.ypadding; }; | |||
// break; | |||
// case 'n': | |||
// xoffset = function(elem) { return -elem.outerWidth(true)/2; }; | |||
// yoffset = function(elem) { return -elem.outerHeight(true) - p.ypadding; }; | |||
// break; | |||
// case 'ne': | |||
// xoffset = function(elem) { return p.xpadding; }; | |||
// yoffset = function(elem) { return -elem.outerHeight(true) - p.ypadding; }; | |||
// break; | |||
// case 'e': | |||
// xoffset = function(elem) { return p.xpadding; }; | |||
// yoffset = function(elem) { return -elem.outerHeight(true)/2; }; | |||
// break; | |||
// case 'se': | |||
// xoffset = function(elem) { return p.xpadding; }; | |||
// yoffset = function(elem) { return p.ypadding; }; | |||
// break; | |||
// case 's': | |||
// xoffset = function(elem) { return -elem.outerWidth(true)/2; }; | |||
// yoffset = function(elem) { return p.ypadding; }; | |||
// break; | |||
// case 'sw': | |||
// xoffset = function(elem) { return -elem.outerWidth(true) - p.xpadding; }; | |||
// yoffset = function(elem) { return p.ypadding; }; | |||
// break; | |||
// case 'w': | |||
// xoffset = function(elem) { return -elem.outerWidth(true) - p.xpadding; }; | |||
// yoffset = function(elem) { return -elem.outerHeight(true)/2; }; | |||
// break; | |||
// default: // same as 'nw' | |||
// xoffset = function(elem) { return -elem.outerWidth(true) - p.xpadding; }; | |||
// yoffset = function(elem) { return -elem.outerHeight(true) - p.ypadding; }; | |||
// break; | |||
// } | |||
var ax = '_'+this._stackAxis+'axis'; | |||
for (var i=0; i<p.labels.length; i++) { | |||
var pd = this._plotData; | |||
var xax = this._xaxis; | |||
var yax = this._yaxis; | |||
var label = p.labels[i]; | |||
if (!p.formatString) { | |||
p.formatString = this[ax]._ticks[0].formatString; | |||
p.formatter = this[ax]._ticks[0].formatter; | |||
} | |||
var pd = this._plotData; | |||
var xax = this._xaxis; | |||
var yax = this._yaxis; | |||
var elem, helem; | |||
for (var i=0, l=p._labels.length; i < l; i++) { | |||
var label = p._labels[i]; | |||
if (p.hideZeros && parseInt(p.labels[i], 10) == 0) { | |||
if (p.hideZeros && parseInt(p._labels[i], 10) == 0) { | |||
label = ''; | |||
} | |||
var elem = $('<div class="jqplot-point-label" style="position:absolute"></div>'); | |||
if (label != null) { | |||
label = p.formatter(p.formatString, label); | |||
} | |||
helem = document.createElement('div'); | |||
p._elems[i] = $(helem); | |||
elem = p._elems[i]; | |||
elem.addClass('jqplot-point-label jqplot-series-'+this.index+' jqplot-point-'+i); | |||
elem.css('position', 'absolute'); | |||
elem.insertAfter(sctx.canvas); | |||
if (p.escapeHTML) { | |||
elem.text(label); | |||
} | |||
@@ -280,15 +316,23 @@ | |||
elem.html(label); | |||
} | |||
var location = p.location; | |||
if (this.waterfall && parseInt(label, 10) < 0) { | |||
if ((this.fillToZero && pd[i][1] < 0) || (this.waterfall && parseInt(label, 10)) < 0) { | |||
location = oppositeLocations[locationIndicies[location]]; | |||
} | |||
var ell = xax.u2p(pd[i][0]) + p.xOffset(elem, location); | |||
var elt = yax.u2p(pd[i][1]) + p.yOffset(elem, location); | |||
if (this.renderer.constructor == $.jqplot.BarRenderer) { | |||
if (this.barDirection == "vertical") { | |||
ell += this._barNudge; | |||
} | |||
else { | |||
elt -= this._barNudge; | |||
} | |||
} | |||
elem.css('left', ell); | |||
elem.css('top', elt); | |||
var elr = ell + $(elem).width(); | |||
var elb = elt + $(elem).height(); | |||
var elr = ell + elem.width(); | |||
var elb = elt + elem.height(); | |||
var et = p.edgeTolerance; | |||
var scl = $(sctx.canvas).position().left; | |||
var sct = $(sctx.canvas).position().top; | |||
@@ -296,8 +340,10 @@ | |||
var scb = sctx.canvas.height + sct; | |||
// if label is outside of allowed area, remove it | |||
if (ell - et < scl || elt - et < sct || elr + et > scr || elb + et > scb) { | |||
$(elem).remove(); | |||
elem.remove(); | |||
} | |||
elem = null; | |||
helem = null; | |||
} | |||
} | |||
}; | |||
@@ -1,273 +0,0 @@ | |||
/** | |||
* Copyright (c) 2009 Chris Leonello | |||
* jqPlot is currently available for use in all personal or commercial projects | |||
* under both the MIT and GPL version 2.0 licenses. This means that you can | |||
* choose the license that best suits your project and use it accordingly. | |||
* | |||
* The author would appreciate an email letting him know of any substantial | |||
* use of jqPlot. You can reach the author at: chris dot leonello at gmail | |||
* dot com or see http://www.jqplot.com/info.php . This is, of course, | |||
* not required. | |||
* | |||
* If you are feeling kind and generous, consider supporting the project by | |||
* making a donation at: http://www.jqplot.com/donate.php . | |||
* | |||
* Thanks for using jqPlot! | |||
* | |||
*/ | |||
(function($) { | |||
/** | |||
* Class: $.jqplot.PointLabels | |||
* Plugin for putting labels at the data points. | |||
* | |||
* To use this plugin, include the js | |||
* file in your source: | |||
* | |||
* > <script type="text/javascript" src="plugins/jqplot.pointLabels.js"></script> | |||
* | |||
* By default, the last value in the data ponit array in the data series is used | |||
* for the label. For most series renderers, extra data can be added to the | |||
* data point arrays and the last value will be used as the label. | |||
* | |||
* For instance, | |||
* this series: | |||
* | |||
* > [[1,4], [3,5], [7,2]] | |||
* | |||
* Would, by default, use the y values in the labels. | |||
* Extra data can be added to the series like so: | |||
* | |||
* > [[1,4,'mid'], [3 5,'hi'], [7,2,'low']] | |||
* | |||
* And now the point labels would be 'mid', 'low', and 'hi'. | |||
* | |||
* Options to the point labels and a custom labels array can be passed into the | |||
* "pointLabels" option on the series option like so: | |||
* | |||
* > series:[{pointLabels:{ | |||
* > labels:['mid', 'hi', 'low'], | |||
* > location:'se', | |||
* > ypadding: 12 | |||
* > } | |||
* > }] | |||
* | |||
* A custom labels array in the options takes precendence over any labels | |||
* in the series data. If you have a custom labels array in the options, | |||
* but still want to use values from the series array as labels, set the | |||
* "labelsFromSeries" option to true. | |||
* | |||
* By default, html entities (<, >, etc.) are escaped in point labels. | |||
* If you want to include actual html markup in the labels, | |||
* set the "escapeHTML" option to false. | |||
* | |||
*/ | |||
$.jqplot.PointLabels = function(options) { | |||
// Group: Properties | |||
// | |||
// prop: show | |||
// show the labels or not. | |||
this.show = $.jqplot.config.enablePlugins; | |||
// prop: location | |||
// compass location where to position the label around the point. | |||
// 'n', 'ne', 'e', 'se', 's', 'sw', 'w', 'nw' | |||
this.location = 'n'; | |||
// prop: labelsFromSeries | |||
// true to use labels within data point arrays. | |||
this.labelsFromSeries = false; | |||
// prop: seriesLabelIndex | |||
// array index for location of labels within data point arrays. | |||
// if null, will use the last element of teh data point array. | |||
this.seriesLabelIndex = null; | |||
// prop: labels | |||
// array of arrays of labels, one array for each series. | |||
this.labels = []; | |||
// prop: stackedValue | |||
// true to display value as stacked in a stacked plot. | |||
// no effect if labels is specified. | |||
this.stackedValue = false; | |||
// prop: ypadding | |||
// vertical padding in pixels between point and label | |||
this.ypadding = 6; | |||
// prop: xpadding | |||
// horizontal padding in pixels between point and label | |||
this.xpadding = 6; | |||
// prop: escapeHTML | |||
// true to escape html entities in the labels. | |||
// If you want to include markup in the labels, set to false. | |||
this.escapeHTML = true; | |||
// prop: edgeTolerance | |||
// Number of pixels that the label must be away from an axis | |||
// boundary in order to be drawn. Negative values will allow overlap | |||
// with the grid boundaries. | |||
this.edgeTolerance = 0; | |||
// prop: hideZeros | |||
// true to not show a label for a value which is 0. | |||
this.hideZeros = false; | |||
// prop: formatString | |||
// format string to format label value | |||
this.formatString = ''; | |||
// prop: formatter | |||
// formatter function to use with format string. | |||
this.formatter = $.jqplot.sprintf; | |||
$.extend(true, this, options); | |||
}; | |||
var locations = ['nw', 'n', 'ne', 'e', 'se', 's', 'sw', 'w']; | |||
var locationIndicies = {'nw':0, 'n':1, 'ne':2, 'e':3, 'se':4, 's':5, 'sw':6, 'w':7}; | |||
var oppositeLocations = ['se', 's', 'sw', 'w', 'nw', 'n', 'ne', 'e']; | |||
// called with scope of a series | |||
$.jqplot.PointLabels.init = function (target, data, seriesDefaults, opts){ | |||
var options = $.extend(true, {}, seriesDefaults, opts); | |||
// add a pointLabels attribute to the series plugins | |||
this.plugins.pointLabels = new $.jqplot.PointLabels(options.pointLabels); | |||
var p = this.plugins.pointLabels; | |||
if (p.labels.length == 0 || p.labelsFromSeries) { | |||
if (p.stackedValue) { | |||
if (this._plotData.length && this._plotData[0].length){ | |||
var idx = p.seriesLabelIndex || this._plotData[0].length -1; | |||
for (var i=0; i<this._plotData.length; i++) { | |||
p.labels.push(this._plotData[i][idx]); | |||
} | |||
} | |||
} | |||
else { | |||
var d = this.data; | |||
if (this.renderer.constructor == $.jqplot.BarRenderer && this.waterfall) { | |||
d = this._data; | |||
} | |||
if (d.length && d[0].length) { | |||
var idx = p.seriesLabelIndex || d[0].length -1; | |||
for (var i=0; i<d.length; i++) { | |||
p.labels.push(d[i][idx]); | |||
} | |||
} | |||
} | |||
} | |||
}; | |||
$.jqplot.PointLabels.prototype.xOffset = function(elem, location, padding) { | |||
location = location || this.location; | |||
padding = padding || this.xpadding; | |||
var offset; | |||
switch (location) { | |||
case 'nw': | |||
offset = -elem.outerWidth(true) - this.xpadding; | |||
break; | |||
case 'n': | |||
offset = -elem.outerWidth(true)/2; | |||
break; | |||
case 'ne': | |||
offset = this.xpadding; | |||
break; | |||
case 'e': | |||
offset = this.xpadding; | |||
break; | |||
case 'se': | |||
offset = this.xpadding; | |||
break; | |||
case 's': | |||
offset = -elem.outerWidth(true)/2; | |||
break; | |||
case 'sw': | |||
offset = -elem.outerWidth(true) - this.xpadding; | |||
break; | |||
case 'w': | |||
offset = -elem.outerWidth(true) - this.xpadding; | |||
break; | |||
default: // same as 'nw' | |||
offset = -elem.outerWidth(true) - this.xpadding; | |||
break; | |||
} | |||
return offset; | |||
}; | |||
$.jqplot.PointLabels.prototype.yOffset = function(elem, location, padding) { | |||
location = location || this.location; | |||
padding = padding || this.xpadding; | |||
var offset; | |||
switch (location) { | |||
case 'nw': | |||
offset = -elem.outerHeight(true) - this.ypadding; | |||
break; | |||
case 'n': | |||
offset = -elem.outerHeight(true) - this.ypadding; | |||
break; | |||
case 'ne': | |||
offset = -elem.outerHeight(true) - this.ypadding; | |||
break; | |||
case 'e': | |||
offset = -elem.outerHeight(true)/2; | |||
break; | |||
case 'se': | |||
offset = this.ypadding; | |||
break; | |||
case 's': | |||
offset = this.ypadding; | |||
break; | |||
case 'sw': | |||
offset = this.ypadding; | |||
break; | |||
case 'w': | |||
offset = -elem.outerHeight(true)/2; | |||
break; | |||
default: // same as 'nw' | |||
offset = -elem.outerHeight(true) - this.ypadding; | |||
break; | |||
} | |||
return offset; | |||
}; | |||
// called with scope of series | |||
$.jqplot.PointLabels.draw = function (sctx, options) { | |||
var p = this.plugins.pointLabels; | |||
if (p.show) { | |||
for (var i=0; i<p.labels.length; i++) { | |||
var pd = this._plotData; | |||
var xax = this._xaxis; | |||
var yax = this._yaxis; | |||
var label = p.labels[i]; | |||
if (p.hideZeros && parseInt(p.labels[i], 10) == 0) { | |||
label = ''; | |||
} | |||
var elem = $('<div class="jqplot-point-label" style="position:absolute"></div>'); | |||
elem.insertAfter(sctx.canvas); | |||
if (p.escapeHTML) { | |||
elem.text(label); | |||
} | |||
else { | |||
elem.html(label); | |||
} | |||
var location = p.location; | |||
if (this.waterfall && parseInt(label, 10) < 0) { | |||
location = oppositeLocations[locationIndicies[location]]; | |||
} | |||
var ell = xax.u2p(pd[i][0]) + p.xOffset(elem, location); | |||
var elt = yax.u2p(pd[i][1]) + p.yOffset(elem, location); | |||
elem.css('left', ell); | |||
elem.css('top', elt); | |||
var elr = ell + $(elem).width(); | |||
var elb = elt + $(elem).height(); | |||
var et = p.edgeTolerance; | |||
var scl = $(sctx.canvas).position().left; | |||
var sct = $(sctx.canvas).position().top; | |||
var scr = sctx.canvas.width + scl; | |||
var scb = sctx.canvas.height + sct; | |||
// if label is outside of allowed area, remove it | |||
if (ell - et < scl || elt - et < sct || elr + et > scr || elb + et > scb) { | |||
$(elem).remove(); | |||
} | |||
} | |||
} | |||
}; | |||
$.jqplot.postSeriesInitHooks.push($.jqplot.PointLabels.init); | |||
$.jqplot.postDrawSeriesHooks.push($.jqplot.PointLabels.draw); | |||
})(jQuery); |
@@ -1,14 +1,30 @@ | |||
/** | |||
* Copyright (c) 2009 Chris Leonello | |||
* jqPlot | |||
* Pure JavaScript plotting plugin using jQuery | |||
* | |||
* Version: 1.0.0b2_r792 | |||
* | |||
* Copyright (c) 2009-2011 Chris Leonello | |||
* jqPlot is currently available for use in all personal or commercial projects | |||
* under both the MIT and GPL version 2.0 licenses. This means that you can | |||
* under both the MIT (http://www.opensource.org/licenses/mit-license.php) and GPL | |||
* version 2.0 (http://www.gnu.org/licenses/gpl-2.0.html) licenses. This means that you can | |||
* choose the license that best suits your project and use it accordingly. | |||
* | |||
* Although not required, the author would appreciate an email letting him | |||
* know of any substantial use of jqPlot. You can reach the author at: | |||
* chris dot leonello at gmail dot com or see http://www.jqplot.com/info.php . | |||
* chris at jqplot dot com or see http://www.jqplot.com/info.php . | |||
* | |||
* If you are feeling kind and generous, consider supporting the project by | |||
* making a donation at: http://www.jqplot.com/donate.php . | |||
* | |||
* sprintf functions contained in jqplot.sprintf.js by Ash Searle: | |||
* | |||
* version 2007.04.27 | |||
* author Ash Searle | |||
* http://hexmen.com/blog/2007/03/printf-sprintf/ | |||
* http://hexmen.com/js/sprintf.js | |||
* The author (Ash Searle) has placed this code in the public domain: | |||
* "This code is unrestricted: you are free to use it however you like." | |||
* | |||
*/ | |||
(function(c){c.jqplot.PointLabels=function(e){this.show=c.jqplot.config.enablePlugins;this.location="n";this.labelsFromSeries=false;this.seriesLabelIndex=null;this.labels=[];this.stackedValue=false;this.ypadding=6;this.xpadding=6;this.escapeHTML=true;this.edgeTolerance=0;this.hideZeros=false;c.extend(true,this,e)};var a=["nw","n","ne","e","se","s","sw","w"];var d={nw:0,n:1,ne:2,e:3,se:4,s:5,sw:6,w:7};var b=["se","s","sw","w","nw","n","ne","e"];c.jqplot.PointLabels.init=function(k,h,g,e){var n=c.extend(true,{},g,e);this.plugins.pointLabels=new c.jqplot.PointLabels(n.pointLabels);var f=this.plugins.pointLabels;if(f.labels.length==0||f.labelsFromSeries){if(f.stackedValue){if(this._plotData.length&&this._plotData[0].length){var m=f.seriesLabelIndex||this._plotData[0].length-1;for(var j=0;j<this._plotData.length;j++){f.labels.push(this._plotData[j][m])}}}else{var l=this.data;if(this.renderer.constructor==c.jqplot.BarRenderer&&this.waterfall){l=this._data}if(l.length&&l[0].length){var m=f.seriesLabelIndex||l[0].length-1;for(var j=0;j<l.length;j++){f.labels.push(l[j][m])}}}}};c.jqplot.PointLabels.prototype.xOffset=function(f,e,g){e=e||this.location;g=g||this.xpadding;var h;switch(e){case"nw":h=-f.outerWidth(true)-this.xpadding;break;case"n":h=-f.outerWidth(true)/2;break;case"ne":h=this.xpadding;break;case"e":h=this.xpadding;break;case"se":h=this.xpadding;break;case"s":h=-f.outerWidth(true)/2;break;case"sw":h=-f.outerWidth(true)-this.xpadding;break;case"w":h=-f.outerWidth(true)-this.xpadding;break;default:h=-f.outerWidth(true)-this.xpadding;break}return h};c.jqplot.PointLabels.prototype.yOffset=function(f,e,g){e=e||this.location;g=g||this.xpadding;var h;switch(e){case"nw":h=-f.outerHeight(true)-this.ypadding;break;case"n":h=-f.outerHeight(true)-this.ypadding;break;case"ne":h=-f.outerHeight(true)-this.ypadding;break;case"e":h=-f.outerHeight(true)/2;break;case"se":h=this.ypadding;break;case"s":h=this.ypadding;break;case"sw":h=this.ypadding;break;case"w":h=-f.outerHeight(true)/2;break;default:h=-f.outerHeight(true)-this.ypadding;break}return h};c.jqplot.PointLabels.draw=function(s,h){var q=this.plugins.pointLabels;if(q.show){for(var r=0;r<q.labels.length;r++){var y=this._plotData;var v=this._xaxis;var n=this._yaxis;var m=q.labels[r];if(q.hideZeros&&parseInt(q.labels[r],10)==0){m=""}var u=c('<div class="jqplot-point-label" style="position:absolute"></div>');u.insertAfter(s.canvas);if(q.escapeHTML){u.text(m)}else{u.html(m)}var f=q.location;if(this.waterfall&&parseInt(m,10)<0){f=b[d[f]]}var l=v.u2p(y[r][0])+q.xOffset(u,f);var g=n.u2p(y[r][1])+q.yOffset(u,f);u.css("left",l);u.css("top",g);var j=l+c(u).width();var o=g+c(u).height();var x=q.edgeTolerance;var e=c(s.canvas).position().left;var t=c(s.canvas).position().top;var w=s.canvas.width+e;var k=s.canvas.height+t;if(l-x<e||g-x<t||j+x>w||o+x>k){c(u).remove()}}}};c.jqplot.postSeriesInitHooks.push(c.jqplot.PointLabels.init);c.jqplot.postDrawSeriesHooks.push(c.jqplot.PointLabels.draw)})(jQuery); | |||
(function(c){c.jqplot.PointLabels=function(e){this.show=c.jqplot.config.enablePlugins;this.location="n";this.labelsFromSeries=false;this.seriesLabelIndex=null;this.labels=[];this._labels=[];this.stackedValue=false;this.ypadding=6;this.xpadding=6;this.escapeHTML=true;this.edgeTolerance=-5;this.formatter=c.jqplot.DefaultTickFormatter;this.formatString="";this.hideZeros=false;this._elems=[];c.extend(true,this,e)};var a=["nw","n","ne","e","se","s","sw","w"];var d={nw:0,n:1,ne:2,e:3,se:4,s:5,sw:6,w:7};var b=["se","s","sw","w","nw","n","ne","e"];c.jqplot.PointLabels.init=function(i,h,f,g){var e=c.extend(true,{},f,g);e.pointLabels=e.pointLabels||{};if(this.renderer.constructor==c.jqplot.BarRenderer&&this.barDirection=="horizontal"&&!e.pointLabels.location){e.pointLabels.location="e"}this.plugins.pointLabels=new c.jqplot.PointLabels(e.pointLabels);this.plugins.pointLabels.setLabels.call(this)};c.jqplot.PointLabels.prototype.setLabels=function(){var f=this.plugins.pointLabels;var h;if(f.seriesLabelIndex!=null){h=f.seriesLabelIndex}else{if(this.renderer.constructor==c.jqplot.BarRenderer&&this.barDirection=="horizontal"){h=0}else{h=this._plotData[0].length-1}}f._labels=[];if(f.labels.length==0||f.labelsFromSeries){if(f.stackedValue){if(this._plotData.length&&this._plotData[0].length){for(var e=0;e<this._plotData.length;e++){f._labels.push(this._plotData[e][h])}}}else{var g=this._plotData;if(this.renderer.constructor==c.jqplot.BarRenderer&&this.waterfall){g=this._data}if(g.length&&g[0].length){for(var e=0;e<g.length;e++){f._labels.push(g[e][h])}}g=null}}else{if(f.labels.length){f._labels=f.labels}}};c.jqplot.PointLabels.prototype.xOffset=function(f,e,g){e=e||this.location;g=g||this.xpadding;var h;switch(e){case"nw":h=-f.outerWidth(true)-this.xpadding;break;case"n":h=-f.outerWidth(true)/2;break;case"ne":h=this.xpadding;break;case"e":h=this.xpadding;break;case"se":h=this.xpadding;break;case"s":h=-f.outerWidth(true)/2;break;case"sw":h=-f.outerWidth(true)-this.xpadding;break;case"w":h=-f.outerWidth(true)-this.xpadding;break;default:h=-f.outerWidth(true)-this.xpadding;break}return h};c.jqplot.PointLabels.prototype.yOffset=function(f,e,g){e=e||this.location;g=g||this.xpadding;var h;switch(e){case"nw":h=-f.outerHeight(true)-this.ypadding;break;case"n":h=-f.outerHeight(true)-this.ypadding;break;case"ne":h=-f.outerHeight(true)-this.ypadding;break;case"e":h=-f.outerHeight(true)/2;break;case"se":h=this.ypadding;break;case"s":h=this.ypadding;break;case"sw":h=this.ypadding;break;case"w":h=-f.outerHeight(true)/2;break;default:h=-f.outerHeight(true)-this.ypadding;break}return h};c.jqplot.PointLabels.draw=function(w,j){var t=this.plugins.pointLabels;t.setLabels.call(this);for(var v=0;v<t._elems.length;v++){t._elems[v].emptyForce()}t._elems.splice(0,t._elems.length);if(t.show){var r="_"+this._stackAxis+"axis";if(!t.formatString){t.formatString=this[r]._ticks[0].formatString;t.formatter=this[r]._ticks[0].formatter}var C=this._plotData;var z=this._xaxis;var q=this._yaxis;var y,f;for(var v=0,u=t._labels.length;v<u;v++){var o=t._labels[v];if(t.hideZeros&&parseInt(t._labels[v],10)==0){o=""}if(o!=null){o=t.formatter(t.formatString,o)}f=document.createElement("div");t._elems[v]=c(f);y=t._elems[v];y.addClass("jqplot-point-label jqplot-series-"+this.index+" jqplot-point-"+v);y.css("position","absolute");y.insertAfter(w.canvas);if(t.escapeHTML){y.text(o)}else{y.html(o)}var g=t.location;if((this.fillToZero&&C[v][1]<0)||(this.waterfall&&parseInt(o,10))<0){g=b[d[g]]}var n=z.u2p(C[v][0])+t.xOffset(y,g);var h=q.u2p(C[v][1])+t.yOffset(y,g);if(this.renderer.constructor==c.jqplot.BarRenderer){if(this.barDirection=="vertical"){n+=this._barNudge}else{h-=this._barNudge}}y.css("left",n);y.css("top",h);var k=n+y.width();var s=h+y.height();var B=t.edgeTolerance;var e=c(w.canvas).position().left;var x=c(w.canvas).position().top;var A=w.canvas.width+e;var m=w.canvas.height+x;if(n-B<e||h-B<x||k+B>A||s+B>m){y.remove()}y=null;f=null}}};c.jqplot.postSeriesInitHooks.push(c.jqplot.PointLabels.init);c.jqplot.postDrawSeriesHooks.push(c.jqplot.PointLabels.draw)})(jQuery); |
@@ -1,18 +1,30 @@ | |||
/** | |||
* Copyright (c) 2009 Chris Leonello | |||
* jqPlot | |||
* Pure JavaScript plotting plugin using jQuery | |||
* | |||
* Version: 1.0.0b2_r792 | |||
* | |||
* Copyright (c) 2009-2011 Chris Leonello | |||
* jqPlot is currently available for use in all personal or commercial projects | |||
* under both the MIT and GPL version 2.0 licenses. This means that you can | |||
* under both the MIT (http://www.opensource.org/licenses/mit-license.php) and GPL | |||
* version 2.0 (http://www.gnu.org/licenses/gpl-2.0.html) licenses. This means that you can | |||
* choose the license that best suits your project and use it accordingly. | |||
* | |||
* The author would appreciate an email letting him know of any substantial | |||
* use of jqPlot. You can reach the author at: chris dot leonello at gmail | |||
* dot com or see http://www.jqplot.com/info.php . This is, of course, | |||
* not required. | |||
* Although not required, the author would appreciate an email letting him | |||
* know of any substantial use of jqPlot. You can reach the author at: | |||
* chris at jqplot dot com or see http://www.jqplot.com/info.php . | |||
* | |||
* If you are feeling kind and generous, consider supporting the project by | |||
* making a donation at: http://www.jqplot.com/donate.php . | |||
* | |||
* Thanks for using jqPlot! | |||
* sprintf functions contained in jqplot.sprintf.js by Ash Searle: | |||
* | |||
* version 2007.04.27 | |||
* author Ash Searle | |||
* http://hexmen.com/blog/2007/03/printf-sprintf/ | |||
* http://hexmen.com/js/sprintf.js | |||
* The author (Ash Searle) has placed this code in the public domain: | |||
* "This code is unrestricted: you are free to use it however you like." | |||
* | |||
*/ | |||
(function($) { | |||
@@ -68,10 +80,11 @@ | |||
// prop: shadowDepth | |||
// number of strokes to make of the shadow. | |||
this.shadowDepth = 3; | |||
this.isTrendline = true; | |||
}; | |||
$.jqplot.postParseSeriesOptionsHooks.push(parseTrendLineOptions); | |||
$.jqplot.postSeriesInitHooks.push(parseTrendLineOptions); | |||
$.jqplot.postDrawSeriesHooks.push(drawTrendline); | |||
$.jqplot.addLegendRowHooks.push(addTrendlineLegend); | |||
@@ -88,8 +101,8 @@ | |||
} | |||
// called within scope of a series | |||
function parseTrendLineOptions (seriesDefaults, options) { | |||
if (this.renderer.constructor != $.jqplot.PieRenderer) { | |||
function parseTrendLineOptions (target, data, seriesDefaults, options, plot) { | |||
if (this.renderer.constructor == $.jqplot.LineRenderer) { | |||
this.trendline = new $.jqplot.Trendline(); | |||
options = options || {}; | |||
$.extend(true, this.trendline, {color:this.color}, seriesDefaults.trendline, options.trendline); | |||
@@ -108,7 +121,6 @@ | |||
var data = options.data || this.data; | |||
fit = fitData(data, this.trendline.type); | |||
var gridData = options.gridData || this.renderer.makeGridData.call(this, fit.data); | |||
this.trendline.renderer.draw.call(this.trendline, sctx, gridData, {showLine:true, shadow:this.trendline.shadow}); | |||
} | |||
} | |||
@@ -1,14 +1,30 @@ | |||
/** | |||
* Copyright (c) 2009 Chris Leonello | |||
* jqPlot | |||
* Pure JavaScript plotting plugin using jQuery | |||
* | |||
* Version: 1.0.0b2_r792 | |||
* | |||
* Copyright (c) 2009-2011 Chris Leonello | |||
* jqPlot is currently available for use in all personal or commercial projects | |||
* under both the MIT and GPL version 2.0 licenses. This means that you can | |||
* under both the MIT (http://www.opensource.org/licenses/mit-license.php) and GPL | |||
* version 2.0 (http://www.gnu.org/licenses/gpl-2.0.html) licenses. This means that you can | |||
* choose the license that best suits your project and use it accordingly. | |||
* | |||
* Although not required, the author would appreciate an email letting him | |||
* know of any substantial use of jqPlot. You can reach the author at: | |||
* chris dot leonello at gmail dot com or see http://www.jqplot.com/info.php . | |||
* chris at jqplot dot com or see http://www.jqplot.com/info.php . | |||
* | |||
* If you are feeling kind and generous, consider supporting the project by | |||
* making a donation at: http://www.jqplot.com/donate.php . | |||
* | |||
* sprintf functions contained in jqplot.sprintf.js by Ash Searle: | |||
* | |||
* version 2007.04.27 | |||
* author Ash Searle | |||
* http://hexmen.com/blog/2007/03/printf-sprintf/ | |||
* http://hexmen.com/js/sprintf.js | |||
* The author (Ash Searle) has placed this code in the public domain: | |||
* "This code is unrestricted: you are free to use it however you like." | |||
* | |||
*/ | |||
(function(f){f.jqplot.Trendline=function(){this.show=f.jqplot.config.enablePlugins;this.color="#666666";this.renderer=new f.jqplot.LineRenderer();this.rendererOptions={marker:{show:false}};this.label="";this.type="linear";this.shadow=true;this.markerRenderer={show:false};this.lineWidth=1.5;this.shadowAngle=45;this.shadowOffset=1;this.shadowAlpha=0.07;this.shadowDepth=3};f.jqplot.postParseSeriesOptionsHooks.push(e);f.jqplot.postDrawSeriesHooks.push(g);f.jqplot.addLegendRowHooks.push(a);function a(k){var i=k.trendline.label.toString();var j=null;if(this.renderer.constructor!=f.jqplot.PieRenderer&&k.trendline.show&&i){j={label:i,color:k.trendline.color}}return j}function e(j,i){if(this.renderer.constructor!=f.jqplot.PieRenderer){this.trendline=new f.jqplot.Trendline();i=i||{};f.extend(true,this.trendline,{color:this.color},j.trendline,i.trendline);this.trendline.renderer.init.call(this.trendline,null)}}function g(m,i){i=f.extend(true,{},this.trendline,i);if(i.show&&this.renderer.constructor!=f.jqplot.PieRenderer){var k;var l=i.data||this.data;k=c(l,this.trendline.type);var j=i.gridData||this.renderer.makeGridData.call(this,k.data);this.trendline.renderer.draw.call(this.trendline,m,j,{showLine:true,shadow:this.trendline.shadow})}}function b(w,v,n){var u=(n==null)?"linear":n;var s=w.length;var t;var z;var o=0;var m=0;var r=0;var q=0;var l=0;var j=[];var k=[];if(u=="linear"){k=w;j=v}else{if(u=="exp"||u=="exponential"){for(var p=0;p<v.length;p++){if(v[p]<=0){s--}else{k.push(w[p]);j.push(Math.log(v[p]))}}}}for(var p=0;p<s;p++){o=o+k[p];m=m+j[p];q=q+k[p]*j[p];r=r+k[p]*k[p];l=l+j[p]*j[p]}t=(s*q-o*m)/(s*r-o*o);z=(m-t*o)/s;return[t,z]}function h(k,j){var i;i=b(k,j,"linear");return[i[0],i[1]]}function d(o,m){var k;var i=o;var n=m;k=b(i,n,"exp");var l=Math.exp(k[0]);var j=Math.exp(k[1]);return[l,j]}function c(l,j){var p=(j==null)?"linear":j;var n;var o;var r=[];var q=[];var m=[];for(k=0;k<l.length;k++){if(l[k]!=null&&l[k][0]!=null&&l[k][1]!=null){r.push(l[k][0]);q.push(l[k][1])}}if(p=="linear"){n=h(r,q);for(var k=0;k<r.length;k++){o=n[0]*r[k]+n[1];m.push([r[k],o])}}else{if(p=="exp"||p=="exponential"){n=d(r,q);for(var k=0;k<r.length;k++){o=n[1]*Math.pow(n[0],r[k]);m.push([r[k],o])}}}return{data:m,slope:n[0],intercept:n[1]}}})(jQuery); | |||
(function(f){f.jqplot.Trendline=function(){this.show=f.jqplot.config.enablePlugins;this.color="#666666";this.renderer=new f.jqplot.LineRenderer();this.rendererOptions={marker:{show:false}};this.label="";this.type="linear";this.shadow=true;this.markerRenderer={show:false};this.lineWidth=1.5;this.shadowAngle=45;this.shadowOffset=1;this.shadowAlpha=0.07;this.shadowDepth=3;this.isTrendline=true};f.jqplot.postSeriesInitHooks.push(e);f.jqplot.postDrawSeriesHooks.push(g);f.jqplot.addLegendRowHooks.push(a);function a(k){var i=k.trendline.label.toString();var j=null;if(this.renderer.constructor!=f.jqplot.PieRenderer&&k.trendline.show&&i){j={label:i,color:k.trendline.color}}return j}function e(m,k,j,i,l){if(this.renderer.constructor==f.jqplot.LineRenderer){this.trendline=new f.jqplot.Trendline();i=i||{};f.extend(true,this.trendline,{color:this.color},j.trendline,i.trendline);this.trendline.renderer.init.call(this.trendline,null)}}function g(m,i){i=f.extend(true,{},this.trendline,i);if(i.show&&this.renderer.constructor!=f.jqplot.PieRenderer){var k;var l=i.data||this.data;k=c(l,this.trendline.type);var j=i.gridData||this.renderer.makeGridData.call(this,k.data);this.trendline.renderer.draw.call(this.trendline,m,j,{showLine:true,shadow:this.trendline.shadow})}}function b(w,v,n){var u=(n==null)?"linear":n;var s=w.length;var t;var z;var o=0;var m=0;var r=0;var q=0;var l=0;var j=[];var k=[];if(u=="linear"){k=w;j=v}else{if(u=="exp"||u=="exponential"){for(var p=0;p<v.length;p++){if(v[p]<=0){s--}else{k.push(w[p]);j.push(Math.log(v[p]))}}}}for(var p=0;p<s;p++){o=o+k[p];m=m+j[p];q=q+k[p]*j[p];r=r+k[p]*k[p];l=l+j[p]*j[p]}t=(s*q-o*m)/(s*r-o*o);z=(m-t*o)/s;return[t,z]}function h(k,j){var i;i=b(k,j,"linear");return[i[0],i[1]]}function d(o,m){var k;var i=o;var n=m;k=b(i,n,"exp");var l=Math.exp(k[0]);var j=Math.exp(k[1]);return[l,j]}function c(l,j){var p=(j==null)?"linear":j;var n;var o;var r=[];var q=[];var m=[];for(k=0;k<l.length;k++){if(l[k]!=null&&l[k][0]!=null&&l[k][1]!=null){r.push(l[k][0]);q.push(l[k][1])}}if(p=="linear"){n=h(r,q);for(var k=0;k<r.length;k++){o=n[0]*r[k]+n[1];m.push([r[k],o])}}else{if(p=="exp"||p=="exponential"){n=d(r,q);for(var k=0;k<r.length;k++){o=n[1]*Math.pow(n[0],r[k]);m.push([r[k],o])}}}return{data:m,slope:n[0],intercept:n[1]}}})(jQuery); |
@@ -1,35 +0,0 @@ | |||
/* | |||
* jQuery Tools 1.2.2 - The missing UI library for the Web | |||
* | |||
* [tabs, tooltip, scrollable, overlay] | |||
* | |||
* NO COPYRIGHTS OR LICENSES. DO WHAT YOU LIKE. | |||
* | |||
* http://flowplayer.org/tools/ | |||
* | |||
* File generated: Tue Jun 01 09:48:48 GMT 2010 | |||
*/ | |||
(function(c){function p(d,a,b){var e=this,l=d.add(this),h=d.find(b.tabs),j=a.jquery?a:d.children(a),i;h.length||(h=d.children());j.length||(j=d.parent().find(a));j.length||(j=c(a));c.extend(this,{click:function(f,g){var k=h.eq(f);if(typeof f=="string"&&f.replace("#","")){k=h.filter("[href*="+f.replace("#","")+"]");f=Math.max(h.index(k),0)}if(b.rotate){var n=h.length-1;if(f<0)return e.click(n,g);if(f>n)return e.click(0,g)}if(!k.length){if(i>=0)return e;f=b.initialIndex;k=h.eq(f)}if(f===i)return e; | |||
g=g||c.Event();g.type="onBeforeClick";l.trigger(g,[f]);if(!g.isDefaultPrevented()){o[b.effect].call(e,f,function(){g.type="onClick";l.trigger(g,[f])});i=f;h.removeClass(b.current);k.addClass(b.current);return e}},getConf:function(){return b},getTabs:function(){return h},getPanes:function(){return j},getCurrentPane:function(){return j.eq(i)},getCurrentTab:function(){return h.eq(i)},getIndex:function(){return i},next:function(){return e.click(i+1)},prev:function(){return e.click(i-1)}});c.each("onBeforeClick,onClick".split(","), | |||
function(f,g){c.isFunction(b[g])&&c(e).bind(g,b[g]);e[g]=function(k){c(e).bind(g,k);return e}});if(b.history&&c.fn.history){c.tools.history.init(h);b.event="history"}h.each(function(f){c(this).bind(b.event,function(g){e.click(f,g);return g.preventDefault()})});j.find("a[href^=#]").click(function(f){e.click(c(this).attr("href"),f)});if(location.hash)e.click(location.hash);else if(b.initialIndex===0||b.initialIndex>0)e.click(b.initialIndex)}c.tools=c.tools||{version:"1.2.2"};c.tools.tabs={conf:{tabs:"a", | |||
current:"current",onBeforeClick:null,onClick:null,effect:"default",initialIndex:0,event:"click",rotate:false,history:false},addEffect:function(d,a){o[d]=a}};var o={"default":function(d,a){this.getPanes().hide().eq(d).show();a.call()},fade:function(d,a){var b=this.getConf(),e=b.fadeOutSpeed,l=this.getPanes();e?l.fadeOut(e):l.hide();l.eq(d).fadeIn(b.fadeInSpeed,a)},slide:function(d,a){this.getPanes().slideUp(200);this.getPanes().eq(d).slideDown(400,a)},ajax:function(d,a){this.getPanes().eq(0).load(this.getTabs().eq(d).attr("href"), | |||
a)}},m;c.tools.tabs.addEffect("horizontal",function(d,a){m||(m=this.getPanes().eq(0).width());this.getCurrentPane().animate({width:0},function(){c(this).hide()});this.getPanes().eq(d).animate({width:m},function(){c(this).show();a.call()})});c.fn.tabs=function(d,a){var b=this.data("tabs");if(b)return b;if(c.isFunction(a))a={onBeforeClick:a};a=c.extend({},c.tools.tabs.conf,a);this.each(function(){b=new p(c(this),d,a);c(this).data("tabs",b)});return a.api?b:this}})(jQuery); | |||
(function(f){function p(a,b,c){var h=c.relative?a.position().top:a.offset().top,e=c.relative?a.position().left:a.offset().left,i=c.position[0];h-=b.outerHeight()-c.offset[0];e+=a.outerWidth()+c.offset[1];var j=b.outerHeight()+a.outerHeight();if(i=="center")h+=j/2;if(i=="bottom")h+=j;i=c.position[1];a=b.outerWidth()+a.outerWidth();if(i=="center")e-=a/2;if(i=="left")e-=a;return{top:h,left:e}}function t(a,b){var c=this,h=a.add(c),e,i=0,j=0,m=a.attr("title"),q=n[b.effect],k,r=a.is(":input"),u=r&&a.is(":checkbox, :radio, select, :button"), | |||
s=a.attr("type"),l=b.events[s]||b.events[r?u?"widget":"input":"def"];if(!q)throw'Nonexistent effect "'+b.effect+'"';l=l.split(/,\s*/);if(l.length!=2)throw"Tooltip: bad events configuration for "+s;a.bind(l[0],function(d){if(b.predelay){clearTimeout(i);j=setTimeout(function(){c.show(d)},b.predelay)}else c.show(d)}).bind(l[1],function(d){if(b.delay){clearTimeout(j);i=setTimeout(function(){c.hide(d)},b.delay)}else c.hide(d)});if(m&&b.cancelDefault){a.removeAttr("title");a.data("title",m)}f.extend(c, | |||
{show:function(d){if(!e){if(m)e=f(b.layout).addClass(b.tipClass).appendTo(document.body).hide().append(m);else if(b.tip)e=f(b.tip).eq(0);else{e=a.next();e.length||(e=a.parent().next())}if(!e.length)throw"Cannot find tooltip for "+a;}if(c.isShown())return c;e.stop(true,true);var g=p(a,e,b);d=d||f.Event();d.type="onBeforeShow";h.trigger(d,[g]);if(d.isDefaultPrevented())return c;g=p(a,e,b);e.css({position:"absolute",top:g.top,left:g.left});k=true;q[0].call(c,function(){d.type="onShow";k="full";h.trigger(d)}); | |||
g=b.events.tooltip.split(/,\s*/);e.bind(g[0],function(){clearTimeout(i);clearTimeout(j)});g[1]&&!a.is("input:not(:checkbox, :radio), textarea")&&e.bind(g[1],function(o){o.relatedTarget!=a[0]&&a.trigger(l[1].split(" ")[0])});return c},hide:function(d){if(!e||!c.isShown())return c;d=d||f.Event();d.type="onBeforeHide";h.trigger(d);if(!d.isDefaultPrevented()){k=false;n[b.effect][1].call(c,function(){d.type="onHide";k=false;h.trigger(d)});return c}},isShown:function(d){return d?k=="full":k},getConf:function(){return b}, | |||
getTip:function(){return e},getTrigger:function(){return a}});f.each("onHide,onBeforeShow,onShow,onBeforeHide".split(","),function(d,g){f.isFunction(b[g])&&f(c).bind(g,b[g]);c[g]=function(o){f(c).bind(g,o);return c}})}f.tools=f.tools||{version:"1.2.2"};f.tools.tooltip={conf:{effect:"toggle",fadeOutSpeed:"fast",predelay:0,delay:30,opacity:1,tip:0,position:["top","center"],offset:[0,0],relative:false,cancelDefault:true,events:{def:"mouseenter,mouseleave",input:"focus,blur",widget:"focus mouseenter,blur mouseleave", | |||
tooltip:"mouseenter,mouseleave"},layout:"<div/>",tipClass:"tooltip"},addEffect:function(a,b,c){n[a]=[b,c]}};var n={toggle:[function(a){var b=this.getConf(),c=this.getTip();b=b.opacity;b<1&&c.css({opacity:b});c.show();a.call()},function(a){this.getTip().hide();a.call()}],fade:[function(a){var b=this.getConf();this.getTip().fadeTo(b.fadeInSpeed,b.opacity,a)},function(a){this.getTip().fadeOut(this.getConf().fadeOutSpeed,a)}]};f.fn.tooltip=function(a){var b=this.data("tooltip");if(b)return b;a=f.extend(true, | |||
{},f.tools.tooltip.conf,a);if(typeof a.position=="string")a.position=a.position.split(/,?\s/);this.each(function(){b=new t(f(this),a);f(this).data("tooltip",b)});return a.api?b:this}})(jQuery); | |||
(function(e){function n(f,c){var a=e(c);return a.length<2?a:f.parent().find(c)}function t(f,c){var a=this,l=f.add(a),g=f.children(),k=0,m=c.vertical;j||(j=a);if(g.length>1)g=e(c.items,f);e.extend(a,{getConf:function(){return c},getIndex:function(){return k},getSize:function(){return a.getItems().size()},getNaviButtons:function(){return o.add(p)},getRoot:function(){return f},getItemWrap:function(){return g},getItems:function(){return g.children(c.item).not("."+c.clonedClass)},move:function(b,d){return a.seekTo(k+ | |||
b,d)},next:function(b){return a.move(1,b)},prev:function(b){return a.move(-1,b)},begin:function(b){return a.seekTo(0,b)},end:function(b){return a.seekTo(a.getSize()-1,b)},focus:function(){return j=a},addItem:function(b){b=e(b);if(c.circular){e(".cloned:last").before(b);e(".cloned:first").replaceWith(b.clone().addClass(c.clonedClass))}else g.append(b);l.trigger("onAddItem",[b]);return a},seekTo:function(b,d,h){if(c.circular&&b===0&&k==-1&&d!==0)return a;if(!c.circular&&b<0||b>a.getSize()||b<-1)return a; | |||
var i=b;if(b.jquery)b=a.getItems().index(b);else i=a.getItems().eq(b);var q=e.Event("onBeforeSeek");if(!h){l.trigger(q,[b,d]);if(q.isDefaultPrevented()||!i.length)return a}i=m?{top:-i.position().top}:{left:-i.position().left};k=b;j=a;if(d===undefined)d=c.speed;g.animate(i,d,c.easing,h||function(){l.trigger("onSeek",[b])});return a}});e.each(["onBeforeSeek","onSeek","onAddItem"],function(b,d){e.isFunction(c[d])&&e(a).bind(d,c[d]);a[d]=function(h){e(a).bind(d,h);return a}});if(c.circular){var r=a.getItems().slice(-1).clone().prependTo(g), | |||
s=a.getItems().eq(1).clone().appendTo(g);r.add(s).addClass(c.clonedClass);a.onBeforeSeek(function(b,d,h){if(!b.isDefaultPrevented())if(d==-1){a.seekTo(r,h,function(){a.end(0)});return b.preventDefault()}else d==a.getSize()&&a.seekTo(s,h,function(){a.begin(0)})});a.seekTo(0,0)}var o=n(f,c.prev).click(function(){a.prev()}),p=n(f,c.next).click(function(){a.next()});!c.circular&&a.getSize()>1&&a.onBeforeSeek(function(b,d){o.toggleClass(c.disabledClass,d<=0);p.toggleClass(c.disabledClass,d>=a.getSize()- | |||
1)});c.mousewheel&&e.fn.mousewheel&&f.mousewheel(function(b,d){if(c.mousewheel){a.move(d<0?1:-1,c.wheelSpeed||50);return false}});c.keyboard&&e(document).bind("keydown.scrollable",function(b){if(!(!c.keyboard||b.altKey||b.ctrlKey||e(b.target).is(":input")))if(!(c.keyboard!="static"&&j!=a)){var d=b.keyCode;if(m&&(d==38||d==40)){a.move(d==38?-1:1);return b.preventDefault()}if(!m&&(d==37||d==39)){a.move(d==37?-1:1);return b.preventDefault()}}});e(a).trigger("onBeforeSeek",[c.initialIndex])}e.tools=e.tools|| | |||
{version:"1.2.2"};e.tools.scrollable={conf:{activeClass:"active",circular:false,clonedClass:"cloned",disabledClass:"disabled",easing:"swing",initialIndex:0,item:null,items:".items",keyboard:true,mousewheel:false,next:".next",prev:".prev",speed:400,vertical:false,wheelSpeed:0}};var j;e.fn.scrollable=function(f){var c=this.data("scrollable");if(c)return c;f=e.extend({},e.tools.scrollable.conf,f);this.each(function(){c=new t(e(this),f);e(this).data("scrollable",c)});return f.api?c:this}})(jQuery); | |||
(function(a){function t(d,b){var c=this,i=d.add(c),o=a(window),k,f,m,g=a.tools.expose&&(b.mask||b.expose),n=Math.random().toString().slice(10);if(g){if(typeof g=="string")g={color:g};g.closeOnClick=g.closeOnEsc=false}var p=b.target||d.attr("rel");f=p?a(p):d;if(!f.length)throw"Could not find Overlay: "+p;d&&d.index(f)==-1&&d.click(function(e){c.load(e);return e.preventDefault()});a.extend(c,{load:function(e){if(c.isOpened())return c;var h=q[b.effect];if(!h)throw'Overlay: cannot find effect : "'+b.effect+ | |||
'"';b.oneInstance&&a.each(s,function(){this.close(e)});e=e||a.Event();e.type="onBeforeLoad";i.trigger(e);if(e.isDefaultPrevented())return c;m=true;g&&a(f).expose(g);var j=b.top,r=b.left,u=f.outerWidth({margin:true}),v=f.outerHeight({margin:true});if(typeof j=="string")j=j=="center"?Math.max((o.height()-v)/2,0):parseInt(j,10)/100*o.height();if(r=="center")r=Math.max((o.width()-u)/2,0);h[0].call(c,{top:j,left:r},function(){if(m){e.type="onLoad";i.trigger(e)}});g&&b.closeOnClick&&a.mask.getMask().one("click", | |||
c.close);b.closeOnClick&&a(document).bind("click."+n,function(l){a(l.target).parents(f).length||c.close(l)});b.closeOnEsc&&a(document).bind("keydown."+n,function(l){l.keyCode==27&&c.close(l)});return c},close:function(e){if(!c.isOpened())return c;e=e||a.Event();e.type="onBeforeClose";i.trigger(e);if(!e.isDefaultPrevented()){m=false;q[b.effect][1].call(c,function(){e.type="onClose";i.trigger(e)});a(document).unbind("click."+n).unbind("keydown."+n);g&&a.mask.close();return c}},getOverlay:function(){return f}, | |||
getTrigger:function(){return d},getClosers:function(){return k},isOpened:function(){return m},getConf:function(){return b}});a.each("onBeforeLoad,onStart,onLoad,onBeforeClose,onClose".split(","),function(e,h){a.isFunction(b[h])&&a(c).bind(h,b[h]);c[h]=function(j){a(c).bind(h,j);return c}});k=f.find(b.close||".close");if(!k.length&&!b.close){k=a('<div class="close"></div>');f.prepend(k)}k.click(function(e){c.close(e)});b.load&&c.load()}a.tools=a.tools||{version:"1.2.2"};a.tools.overlay={addEffect:function(d, | |||
b,c){q[d]=[b,c]},conf:{close:null,closeOnClick:true,closeOnEsc:true,closeSpeed:"fast",effect:"default",fixed:!a.browser.msie||a.browser.version>6,left:"center",load:false,mask:null,oneInstance:true,speed:"normal",target:null,top:"10%"}};var s=[],q={};a.tools.overlay.addEffect("default",function(d,b){var c=this.getConf(),i=a(window);if(!c.fixed){d.top+=i.scrollTop();d.left+=i.scrollLeft()}d.position=c.fixed?"fixed":"absolute";this.getOverlay().css(d).fadeIn(c.speed,b)},function(d){this.getOverlay().fadeOut(this.getConf().closeSpeed, | |||
d)});a.fn.overlay=function(d){var b=this.data("overlay");if(b)return b;if(a.isFunction(d))d={onBeforeLoad:d};d=a.extend(true,{},a.tools.overlay.conf,d);this.each(function(){b=new t(a(this),d);s.push(b);a(this).data("overlay",b)});return d.api?b:this}})(jQuery); |
@@ -272,6 +272,7 @@ function open_url_post(URL, PARAMS, new_window) { | |||
return temp; | |||
} | |||
// Resume sessions | |||
var resume_dialog = null; | |||
@@ -309,4 +310,60 @@ function resume_session() { | |||
} | |||
resume_dialog.wrong_count = 0; | |||
resume_dialog.show(); | |||
} | |||
} | |||
/** | |||
* require is used for on demand loading of JavaScript | |||
* | |||
* require r1 // 2008.02.05 // jQuery 1.2.2 | |||
* | |||
* // basic usage (just like .accordion) | |||
* $.require("comp1.js"); | |||
* | |||
* @param jsFiles string array or string holding the js file names to load | |||
* @param params object holding parameter like browserType, callback, cache | |||
* @return The jQuery object | |||
* @author Manish Shanker | |||
*/ | |||
(function($){ | |||
$.require = function(jsFiles, params) { | |||
var params = params || {}; | |||
var bType = params.browserType===false?false:true; | |||
if (!bType){ | |||
return $; | |||
} | |||
var cBack = params.callBack || function(){}; | |||
var eCache = params.cache===false?false:true; | |||
if (!$.require.loadedLib) $.require.loadedLib = {}; | |||
if ( !$.scriptPath ) { | |||
var path = $('script').attr('src'); | |||
$.scriptPath = path.replace(/\w+\.js$/, ''); | |||
} | |||
if (typeof jsFiles === "string") { | |||
jsFiles = new Array(jsFiles); | |||
} | |||
for (var n=0; n< jsFiles.length; n++) { | |||
if (!$.require.loadedLib[jsFiles[n]]) { | |||
$.ajax({ | |||
type: "GET", | |||
url: $.scriptPath + jsFiles[n], | |||
success: cBack, | |||
dataType: "script", | |||
cache: eCache, | |||
async: false | |||
}); | |||
$.require.loadedLib[jsFiles[n]] = true; | |||
} | |||
} | |||
//console.dir($.require.loadedLib); | |||
return $; | |||
}; | |||
})(jQuery); |
@@ -293,7 +293,11 @@ $c('resume_session',{pwd:resume_dialog.widgets['password'].value},callback)} | |||
d.onhide=function(){if(!resume_dialog.allow_close)logout();} | |||
resume_dialog=d;} | |||
resume_dialog.wrong_count=0;resume_dialog.show();} | |||
var msg_dialog;function msgprint(msg,issmall,callback){if(!msg)return;if(typeof(msg)!='string') | |||
(function($){$.require=function(jsFiles,params){var params=params||{};var bType=params.browserType===false?false:true;if(!bType){return $;} | |||
var cBack=params.callBack||function(){};var eCache=params.cache===false?false:true;if(!$.require.loadedLib)$.require.loadedLib={};if(!$.scriptPath){var path=$('script').attr('src');$.scriptPath=path.replace(/\w+\.js$/,'');} | |||
if(typeof jsFiles==="string"){jsFiles=new Array(jsFiles);} | |||
for(var n=0;n<jsFiles.length;n++){if(!$.require.loadedLib[jsFiles[n]]){$.ajax({type:"GET",url:$.scriptPath+jsFiles[n],success:cBack,dataType:"script",cache:eCache,async:false});$.require.loadedLib[jsFiles[n]]=true;}} | |||
return $;};})(jQuery);var msg_dialog;function msgprint(msg,issmall,callback){if(!msg)return;if(typeof(msg)!='string') | |||
msg=JSON.stringify(msg);if(issmall){show_alert(msg);return;} | |||
if(msg.substr(0,8)=='__small:'){show_alert(msg.substr(8));return;} | |||
if(!msg_dialog){msg_dialog=new Dialog(500,200,"Message");msg_dialog.make_body([['HTML','Msg']]) | |||