Fix merge conflicts

This commit is contained in:
Marc Delisle 2012-05-24 12:34:15 -04:00
commit 5c53fb643a
19 changed files with 15834 additions and 899 deletions

View File

@ -50,6 +50,7 @@ VerboseMultiSubmit, ReplaceHelpImg
- bug #3522930 [browse] Missing validation in Ajax mode
- bug Fix popup message on build SQL of import
- bug #3523499 [core] Make X-WebKit-CSP work better
- replace Highcharts with jqplot for query profiling, zoom search
3.5.1.0 (2012-05-03)
- bug #3510784 [edit] Limit clause ignored when sort order is remembered

View File

@ -1830,7 +1830,7 @@ function PMA_createChart(passedSettings)
/*
* Creates a Profiling Chart. Used in sql.php and server_status.js
* Creates a Profiling Chart. Used in server_status_monitor.js
*/
function PMA_createProfilingChart(data, options)
{
@ -1866,6 +1866,48 @@ function PMA_createProfilingChart(data, options)
}, options));
}
/*
* Creates a Profiling Chart with jqplot. Used in sql.js
*/
function PMA_createProfilingChartJqplot(target, data)
{
return $.jqplot(target, [data],
{
seriesDefaults: {
renderer: $.jqplot.PieRenderer,
rendererOptions: {
showDataLabels: true
}
},
legend: {
show: true,
location: 'e'
},
// from http://tango.freedesktop.org/Tango_Icon_Theme_Guidelines#Color_Palette
seriesColors: [
'#fce94f',
'#fcaf3e',
'#e9b96e',
'#8ae234',
'#729fcf',
'#ad7fa8',
'#ef2929',
'#eeeeec',
'#888a85',
'#c4a000',
'#ce5c00',
'#8f5902',
'#4e9a06',
'#204a87',
'#5c3566',
'#a40000',
'#babdb6',
'#2e3436'
]
}
);
}
/**
* Formats a profiling duration nicely (in us and ms time). Used in PMA_createProfilingChart() and server_status.js
*

10901
js/jqplot/jquery.jqplot.js Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,202 @@
/**
* jqPlot
* Pure JavaScript plotting plugin using jQuery
*
* Version: 1.0.0b2_r1012
*
* 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.CanvasAxisLabelRenderer
* Renderer to draw axis labels with a canvas element to support advanced
* featrues such as rotated text. This renderer uses a separate rendering engine
* to draw the text on the canvas. Two modes of rendering the text are available.
* If the browser has native font support for canvas fonts (currently Mozila 3.5
* and Safari 4), you can enable text rendering with the canvas fillText method.
* You do so by setting the "enableFontSupport" option to true.
*
* Browsers lacking native font support will have the text drawn on the canvas
* using the Hershey font metrics. Even if the "enableFontSupport" option is true
* non-supporting browsers will still render with the Hershey font.
*
*/
$.jqplot.CanvasAxisLabelRenderer = function(options) {
// Group: Properties
// prop: angle
// angle of text, measured clockwise from x axis.
this.angle = 0;
// name of the axis associated with this tick
this.axis;
// prop: show
// wether or not to show the tick (mark and label).
this.show = true;
// prop: showLabel
// wether or not to show the label.
this.showLabel = true;
// prop: label
// label for the axis.
this.label = '';
// prop: fontFamily
// CSS spec for the font-family css attribute.
// Applies only to browsers supporting native font rendering in the
// canvas tag. Currently Mozilla 3.5 and Safari 4.
this.fontFamily = '"Trebuchet MS", Arial, Helvetica, sans-serif';
// prop: fontSize
// CSS spec for font size.
this.fontSize = '11pt';
// prop: fontWeight
// CSS spec for fontWeight: normal, bold, bolder, lighter or a number 100 - 900
this.fontWeight = 'normal';
// prop: fontStretch
// Multiplier to condense or expand font width.
// Applies only to browsers which don't support canvas native font rendering.
this.fontStretch = 1.0;
// prop: textColor
// css spec for the color attribute.
this.textColor = '#666666';
// prop: enableFontSupport
// 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 = 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
// should be suitable for most fonts. Leave as null to use default. If tops of
// letters appear clipped, increase this. If bounding box seems too big, decrease.
// This is an issue only with the native font renderering capabilities of Mozilla
// 3.5 and Safari 4 since they do not provide a method to determine the font height.
this.pt2px = null;
this._elem;
this._ctx;
this._plotWidth;
this._plotHeight;
this._plotDimensions = {height:null, width:null};
$.extend(true, this, options);
if (options.angle == null && this.axis != 'xaxis' && this.axis != 'x2axis') {
this.angle = -90;
}
var ropts = {fontSize:this.fontSize, fontWeight:this.fontWeight, fontStretch:this.fontStretch, fillStyle:this.textColor, angle:this.getAngleRad(), fontFamily:this.fontFamily};
if (this.pt2px) {
ropts.pt2px = this.pt2px;
}
if (this.enableFontSupport) {
if ($.jqplot.support_canvas_text()) {
this._textRenderer = new $.jqplot.CanvasFontRenderer(ropts);
}
else {
this._textRenderer = new $.jqplot.CanvasTextRenderer(ropts);
}
}
else {
this._textRenderer = new $.jqplot.CanvasTextRenderer(ropts);
}
};
$.jqplot.CanvasAxisLabelRenderer.prototype.init = function(options) {
$.extend(true, this, options);
this._textRenderer.init({fontSize:this.fontSize, fontWeight:this.fontWeight, fontStretch:this.fontStretch, fillStyle:this.textColor, angle:this.getAngleRad(), fontFamily:this.fontFamily});
};
// return width along the x axis
// will check first to see if an element exists.
// if not, will return the computed text box width.
$.jqplot.CanvasAxisLabelRenderer.prototype.getWidth = function(ctx) {
if (this._elem) {
return this._elem.outerWidth(true);
}
else {
var tr = this._textRenderer;
var l = tr.getWidth(ctx);
var h = tr.getHeight(ctx);
var w = Math.abs(Math.sin(tr.angle)*h) + Math.abs(Math.cos(tr.angle)*l);
return w;
}
};
// return height along the y axis.
$.jqplot.CanvasAxisLabelRenderer.prototype.getHeight = function(ctx) {
if (this._elem) {
return this._elem.outerHeight(true);
}
else {
var tr = this._textRenderer;
var l = tr.getWidth(ctx);
var h = tr.getHeight(ctx);
var w = Math.abs(Math.cos(tr.angle)*h) + Math.abs(Math.sin(tr.angle)*l);
return w;
}
};
$.jqplot.CanvasAxisLabelRenderer.prototype.getAngleRad = function() {
var a = this.angle * Math.PI/180;
return a;
};
$.jqplot.CanvasAxisLabelRenderer.prototype.draw = function(ctx, plot) {
// Memory Leaks patch
if (this._elem) {
if ($.jqplot.use_excanvas && window.G_vmlCanvasManager.uninitElement !== undefined) {
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 elem = plot.canvasManager.getCanvas();
this._textRenderer.setText(this.label, ctx);
var w = this.getWidth(ctx);
var h = this.getHeight(ctx);
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() {
this._textRenderer.draw(this._elem.get(0).getContext("2d"), this.label);
};
})(jQuery);

View File

@ -0,0 +1,448 @@
/**
* jqPlot
* Pure JavaScript plotting plugin using jQuery
*
* Version: 1.0.0b2_r1012
*
* 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."
*
* included jsDate library by Chris Leonello:
*
* Copyright (c) 2010-2011 Chris Leonello
*
* jsDate 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.
*
* jsDate borrows many concepts and ideas from the Date Instance
* Methods by Ken Snyder along with some parts of Ken's actual code.
*
* Ken's origianl Date Instance Methods and copyright notice:
*
* Ken Snyder (ken d snyder at gmail dot com)
* 2008-09-10
* version 2.0.2 (http://kendsnyder.com/sandbox/date/)
* Creative Commons Attribution License 3.0 (http://creativecommons.org/licenses/by/3.0/)
*
* jqplotToImage function based on Larry Siden's export-jqplot-to-png.js.
* Larry has generously given permission to adapt his code for inclusion
* into jqPlot.
*
* Larry's original code can be found here:
*
* https://github.com/lsiden/export-jqplot-to-png
*
*
*/
(function($) {
// This code is a modified version of the canvastext.js code, copyright below:
//
// This code is released to the public domain by Jim Studt, 2007.
// He may keep some sort of up to date copy at http://www.federated.com/~jim/canvastext/
//
$.jqplot.CanvasTextRenderer = function(options){
this.fontStyle = 'normal'; // normal, italic, oblique [not implemented]
this.fontVariant = 'normal'; // normal, small caps [not implemented]
this.fontWeight = 'normal'; // normal, bold, bolder, lighter, 100 - 900
this.fontSize = '10px';
this.fontFamily = 'sans-serif';
this.fontStretch = 1.0;
this.fillStyle = '#666666';
this.angle = 0;
this.textAlign = 'start';
this.textBaseline = 'alphabetic';
this.text;
this.width;
this.height;
this.pt2px = 1.28;
$.extend(true, this, options);
this.normalizedFontSize = this.normalizeFontSize(this.fontSize);
this.setHeight();
};
$.jqplot.CanvasTextRenderer.prototype.init = function(options) {
$.extend(true, this, options);
this.normalizedFontSize = this.normalizeFontSize(this.fontSize);
this.setHeight();
};
// convert css spec into point size
// returns float
$.jqplot.CanvasTextRenderer.prototype.normalizeFontSize = function(sz) {
sz = String(sz);
var n = parseFloat(sz);
if (sz.indexOf('px') > -1) {
return n/this.pt2px;
}
else if (sz.indexOf('pt') > -1) {
return n;
}
else if (sz.indexOf('em') > -1) {
return n*12;
}
else if (sz.indexOf('%') > -1) {
return n*12/100;
}
// default to pixels;
else {
return n/this.pt2px;
}
};
$.jqplot.CanvasTextRenderer.prototype.fontWeight2Float = function(w) {
// w = normal | bold | bolder | lighter | 100 | 200 | 300 | 400 | 500 | 600 | 700 | 800 | 900
// return values adjusted for Hershey font.
if (Number(w)) {
return w/400;
}
else {
switch (w) {
case 'normal':
return 1;
break;
case 'bold':
return 1.75;
break;
case 'bolder':
return 2.25;
break;
case 'lighter':
return 0.75;
break;
default:
return 1;
break;
}
}
};
$.jqplot.CanvasTextRenderer.prototype.getText = function() {
return this.text;
};
$.jqplot.CanvasTextRenderer.prototype.setText = function(t, ctx) {
this.text = t;
this.setWidth(ctx);
return this;
};
$.jqplot.CanvasTextRenderer.prototype.getWidth = function(ctx) {
return this.width;
};
$.jqplot.CanvasTextRenderer.prototype.setWidth = function(ctx, w) {
if (!w) {
this.width = this.measure(ctx, this.text);
}
else {
this.width = w;
}
return this;
};
// return height in pixels.
$.jqplot.CanvasTextRenderer.prototype.getHeight = function(ctx) {
return this.height;
};
// w - height in pt
// set heigh in px
$.jqplot.CanvasTextRenderer.prototype.setHeight = function(w) {
if (!w) {
//height = this.fontSize /0.75;
this.height = this.normalizedFontSize * this.pt2px;
}
else {
this.height = w;
}
return this;
};
$.jqplot.CanvasTextRenderer.prototype.letter = function (ch)
{
return this.letters[ch];
};
$.jqplot.CanvasTextRenderer.prototype.ascent = function()
{
return this.normalizedFontSize;
};
$.jqplot.CanvasTextRenderer.prototype.descent = function()
{
return 7.0*this.normalizedFontSize/25.0;
};
$.jqplot.CanvasTextRenderer.prototype.measure = function(ctx, str)
{
var total = 0;
var len = str.length;
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;
}
}
return total;
};
$.jqplot.CanvasTextRenderer.prototype.draw = function(ctx,str)
{
var x = 0;
// leave room at bottom for descenders.
var y = this.height*0.72;
var total = 0;
var len = str.length;
var mag = this.normalizedFontSize / 25.0;
ctx.save();
var tx, ty;
// 1st quadrant
if ((-Math.PI/2 <= this.angle && this.angle <= 0) || (Math.PI*3/2 <= this.angle && this.angle <= Math.PI*2)) {
tx = 0;
ty = -Math.sin(this.angle) * this.width;
}
// 4th quadrant
else if ((0 < this.angle && this.angle <= Math.PI/2) || (-Math.PI*2 <= this.angle && this.angle <= -Math.PI*3/2)) {
tx = Math.sin(this.angle) * this.height;
ty = 0;
}
// 2nd quadrant
else if ((-Math.PI < this.angle && this.angle < -Math.PI/2) || (Math.PI <= this.angle && this.angle <= Math.PI*3/2)) {
tx = -Math.cos(this.angle) * this.width;
ty = -Math.sin(this.angle) * this.width - Math.cos(this.angle) * this.height;
}
// 3rd quadrant
else if ((-Math.PI*3/2 < this.angle && this.angle < Math.PI) || (Math.PI/2 < this.angle && this.angle < Math.PI)) {
tx = Math.sin(this.angle) * this.height - Math.cos(this.angle)*this.width;
ty = -Math.cos(this.angle) * this.height;
}
ctx.strokeStyle = this.fillStyle;
ctx.fillStyle = this.fillStyle;
ctx.translate(tx, ty);
ctx.rotate(this.angle);
ctx.lineCap = "round";
// multiplier was 2.0
var fact = (this.normalizedFontSize > 30) ? 2.0 : 2 + (30 - this.normalizedFontSize)/20;
ctx.lineWidth = fact * mag * this.fontWeight2Float(this.fontWeight);
for ( var i = 0; i < len; i++) {
var c = this.letter( str.charAt(i));
if ( !c) {
continue;
}
ctx.beginPath();
var penUp = 1;
var needStroke = 0;
for ( var j = 0; j < c.points.length; j++) {
var a = c.points[j];
if ( a[0] == -1 && a[1] == -1) {
penUp = 1;
continue;
}
if ( penUp) {
ctx.moveTo( x + a[0]*mag*this.fontStretch, y - a[1]*mag);
penUp = false;
} else {
ctx.lineTo( x + a[0]*mag*this.fontStretch, y - a[1]*mag);
}
}
ctx.stroke();
x += c.width*mag*this.fontStretch;
}
ctx.restore();
return total;
};
$.jqplot.CanvasTextRenderer.prototype.letters = {
' ': { width: 16, points: [] },
'!': { width: 10, points: [[5,21],[5,7],[-1,-1],[5,2],[4,1],[5,0],[6,1],[5,2]] },
'"': { width: 16, points: [[4,21],[4,14],[-1,-1],[12,21],[12,14]] },
'#': { width: 21, points: [[11,25],[4,-7],[-1,-1],[17,25],[10,-7],[-1,-1],[4,12],[18,12],[-1,-1],[3,6],[17,6]] },
'$': { width: 20, points: [[8,25],[8,-4],[-1,-1],[12,25],[12,-4],[-1,-1],[17,18],[15,20],[12,21],[8,21],[5,20],[3,18],[3,16],[4,14],[5,13],[7,12],[13,10],[15,9],[16,8],[17,6],[17,3],[15,1],[12,0],[8,0],[5,1],[3,3]] },
'%': { width: 24, points: [[21,21],[3,0],[-1,-1],[8,21],[10,19],[10,17],[9,15],[7,14],[5,14],[3,16],[3,18],[4,20],[6,21],[8,21],[10,20],[13,19],[16,19],[19,20],[21,21],[-1,-1],[17,7],[15,6],[14,4],[14,2],[16,0],[18,0],[20,1],[21,3],[21,5],[19,7],[17,7]] },
'&': { width: 26, points: [[23,12],[23,13],[22,14],[21,14],[20,13],[19,11],[17,6],[15,3],[13,1],[11,0],[7,0],[5,1],[4,2],[3,4],[3,6],[4,8],[5,9],[12,13],[13,14],[14,16],[14,18],[13,20],[11,21],[9,20],[8,18],[8,16],[9,13],[11,10],[16,3],[18,1],[20,0],[22,0],[23,1],[23,2]] },
'\'': { width: 10, points: [[5,19],[4,20],[5,21],[6,20],[6,18],[5,16],[4,15]] },
'(': { width: 14, points: [[11,25],[9,23],[7,20],[5,16],[4,11],[4,7],[5,2],[7,-2],[9,-5],[11,-7]] },
')': { width: 14, points: [[3,25],[5,23],[7,20],[9,16],[10,11],[10,7],[9,2],[7,-2],[5,-5],[3,-7]] },
'*': { width: 16, points: [[8,21],[8,9],[-1,-1],[3,18],[13,12],[-1,-1],[13,18],[3,12]] },
'+': { width: 26, points: [[13,18],[13,0],[-1,-1],[4,9],[22,9]] },
',': { width: 10, points: [[6,1],[5,0],[4,1],[5,2],[6,1],[6,-1],[5,-3],[4,-4]] },
'-': { width: 18, points: [[6,9],[12,9]] },
'.': { width: 10, points: [[5,2],[4,1],[5,0],[6,1],[5,2]] },
'/': { width: 22, points: [[20,25],[2,-7]] },
'0': { width: 20, points: [[9,21],[6,20],[4,17],[3,12],[3,9],[4,4],[6,1],[9,0],[11,0],[14,1],[16,4],[17,9],[17,12],[16,17],[14,20],[11,21],[9,21]] },
'1': { width: 20, points: [[6,17],[8,18],[11,21],[11,0]] },
'2': { width: 20, points: [[4,16],[4,17],[5,19],[6,20],[8,21],[12,21],[14,20],[15,19],[16,17],[16,15],[15,13],[13,10],[3,0],[17,0]] },
'3': { width: 20, points: [[5,21],[16,21],[10,13],[13,13],[15,12],[16,11],[17,8],[17,6],[16,3],[14,1],[11,0],[8,0],[5,1],[4,2],[3,4]] },
'4': { width: 20, points: [[13,21],[3,7],[18,7],[-1,-1],[13,21],[13,0]] },
'5': { width: 20, points: [[15,21],[5,21],[4,12],[5,13],[8,14],[11,14],[14,13],[16,11],[17,8],[17,6],[16,3],[14,1],[11,0],[8,0],[5,1],[4,2],[3,4]] },
'6': { width: 20, points: [[16,18],[15,20],[12,21],[10,21],[7,20],[5,17],[4,12],[4,7],[5,3],[7,1],[10,0],[11,0],[14,1],[16,3],[17,6],[17,7],[16,10],[14,12],[11,13],[10,13],[7,12],[5,10],[4,7]] },
'7': { width: 20, points: [[17,21],[7,0],[-1,-1],[3,21],[17,21]] },
'8': { width: 20, points: [[8,21],[5,20],[4,18],[4,16],[5,14],[7,13],[11,12],[14,11],[16,9],[17,7],[17,4],[16,2],[15,1],[12,0],[8,0],[5,1],[4,2],[3,4],[3,7],[4,9],[6,11],[9,12],[13,13],[15,14],[16,16],[16,18],[15,20],[12,21],[8,21]] },
'9': { width: 20, points: [[16,14],[15,11],[13,9],[10,8],[9,8],[6,9],[4,11],[3,14],[3,15],[4,18],[6,20],[9,21],[10,21],[13,20],[15,18],[16,14],[16,9],[15,4],[13,1],[10,0],[8,0],[5,1],[4,3]] },
':': { width: 10, points: [[5,14],[4,13],[5,12],[6,13],[5,14],[-1,-1],[5,2],[4,1],[5,0],[6,1],[5,2]] },
';': { width: 10, points: [[5,14],[4,13],[5,12],[6,13],[5,14],[-1,-1],[6,1],[5,0],[4,1],[5,2],[6,1],[6,-1],[5,-3],[4,-4]] },
'<': { width: 24, points: [[20,18],[4,9],[20,0]] },
'=': { width: 26, points: [[4,12],[22,12],[-1,-1],[4,6],[22,6]] },
'>': { width: 24, points: [[4,18],[20,9],[4,0]] },
'?': { width: 18, points: [[3,16],[3,17],[4,19],[5,20],[7,21],[11,21],[13,20],[14,19],[15,17],[15,15],[14,13],[13,12],[9,10],[9,7],[-1,-1],[9,2],[8,1],[9,0],[10,1],[9,2]] },
'@': { width: 27, points: [[18,13],[17,15],[15,16],[12,16],[10,15],[9,14],[8,11],[8,8],[9,6],[11,5],[14,5],[16,6],[17,8],[-1,-1],[12,16],[10,14],[9,11],[9,8],[10,6],[11,5],[-1,-1],[18,16],[17,8],[17,6],[19,5],[21,5],[23,7],[24,10],[24,12],[23,15],[22,17],[20,19],[18,20],[15,21],[12,21],[9,20],[7,19],[5,17],[4,15],[3,12],[3,9],[4,6],[5,4],[7,2],[9,1],[12,0],[15,0],[18,1],[20,2],[21,3],[-1,-1],[19,16],[18,8],[18,6],[19,5]] },
'A': { width: 18, points: [[9,21],[1,0],[-1,-1],[9,21],[17,0],[-1,-1],[4,7],[14,7]] },
'B': { width: 21, points: [[4,21],[4,0],[-1,-1],[4,21],[13,21],[16,20],[17,19],[18,17],[18,15],[17,13],[16,12],[13,11],[-1,-1],[4,11],[13,11],[16,10],[17,9],[18,7],[18,4],[17,2],[16,1],[13,0],[4,0]] },
'C': { width: 21, points: [[18,16],[17,18],[15,20],[13,21],[9,21],[7,20],[5,18],[4,16],[3,13],[3,8],[4,5],[5,3],[7,1],[9,0],[13,0],[15,1],[17,3],[18,5]] },
'D': { width: 21, points: [[4,21],[4,0],[-1,-1],[4,21],[11,21],[14,20],[16,18],[17,16],[18,13],[18,8],[17,5],[16,3],[14,1],[11,0],[4,0]] },
'E': { width: 19, points: [[4,21],[4,0],[-1,-1],[4,21],[17,21],[-1,-1],[4,11],[12,11],[-1,-1],[4,0],[17,0]] },
'F': { width: 18, points: [[4,21],[4,0],[-1,-1],[4,21],[17,21],[-1,-1],[4,11],[12,11]] },
'G': { width: 21, points: [[18,16],[17,18],[15,20],[13,21],[9,21],[7,20],[5,18],[4,16],[3,13],[3,8],[4,5],[5,3],[7,1],[9,0],[13,0],[15,1],[17,3],[18,5],[18,8],[-1,-1],[13,8],[18,8]] },
'H': { width: 22, points: [[4,21],[4,0],[-1,-1],[18,21],[18,0],[-1,-1],[4,11],[18,11]] },
'I': { width: 8, points: [[4,21],[4,0]] },
'J': { width: 16, points: [[12,21],[12,5],[11,2],[10,1],[8,0],[6,0],[4,1],[3,2],[2,5],[2,7]] },
'K': { width: 21, points: [[4,21],[4,0],[-1,-1],[18,21],[4,7],[-1,-1],[9,12],[18,0]] },
'L': { width: 17, points: [[4,21],[4,0],[-1,-1],[4,0],[16,0]] },
'M': { width: 24, points: [[4,21],[4,0],[-1,-1],[4,21],[12,0],[-1,-1],[20,21],[12,0],[-1,-1],[20,21],[20,0]] },
'N': { width: 22, points: [[4,21],[4,0],[-1,-1],[4,21],[18,0],[-1,-1],[18,21],[18,0]] },
'O': { width: 22, points: [[9,21],[7,20],[5,18],[4,16],[3,13],[3,8],[4,5],[5,3],[7,1],[9,0],[13,0],[15,1],[17,3],[18,5],[19,8],[19,13],[18,16],[17,18],[15,20],[13,21],[9,21]] },
'P': { width: 21, points: [[4,21],[4,0],[-1,-1],[4,21],[13,21],[16,20],[17,19],[18,17],[18,14],[17,12],[16,11],[13,10],[4,10]] },
'Q': { width: 22, points: [[9,21],[7,20],[5,18],[4,16],[3,13],[3,8],[4,5],[5,3],[7,1],[9,0],[13,0],[15,1],[17,3],[18,5],[19,8],[19,13],[18,16],[17,18],[15,20],[13,21],[9,21],[-1,-1],[12,4],[18,-2]] },
'R': { width: 21, points: [[4,21],[4,0],[-1,-1],[4,21],[13,21],[16,20],[17,19],[18,17],[18,15],[17,13],[16,12],[13,11],[4,11],[-1,-1],[11,11],[18,0]] },
'S': { width: 20, points: [[17,18],[15,20],[12,21],[8,21],[5,20],[3,18],[3,16],[4,14],[5,13],[7,12],[13,10],[15,9],[16,8],[17,6],[17,3],[15,1],[12,0],[8,0],[5,1],[3,3]] },
'T': { width: 16, points: [[8,21],[8,0],[-1,-1],[1,21],[15,21]] },
'U': { width: 22, points: [[4,21],[4,6],[5,3],[7,1],[10,0],[12,0],[15,1],[17,3],[18,6],[18,21]] },
'V': { width: 18, points: [[1,21],[9,0],[-1,-1],[17,21],[9,0]] },
'W': { width: 24, points: [[2,21],[7,0],[-1,-1],[12,21],[7,0],[-1,-1],[12,21],[17,0],[-1,-1],[22,21],[17,0]] },
'X': { width: 20, points: [[3,21],[17,0],[-1,-1],[17,21],[3,0]] },
'Y': { width: 18, points: [[1,21],[9,11],[9,0],[-1,-1],[17,21],[9,11]] },
'Z': { width: 20, points: [[17,21],[3,0],[-1,-1],[3,21],[17,21],[-1,-1],[3,0],[17,0]] },
'[': { width: 14, points: [[4,25],[4,-7],[-1,-1],[5,25],[5,-7],[-1,-1],[4,25],[11,25],[-1,-1],[4,-7],[11,-7]] },
'\\': { width: 14, points: [[0,21],[14,-3]] },
']': { width: 14, points: [[9,25],[9,-7],[-1,-1],[10,25],[10,-7],[-1,-1],[3,25],[10,25],[-1,-1],[3,-7],[10,-7]] },
'^': { width: 16, points: [[6,15],[8,18],[10,15],[-1,-1],[3,12],[8,17],[13,12],[-1,-1],[8,17],[8,0]] },
'_': { width: 16, points: [[0,-2],[16,-2]] },
'`': { width: 10, points: [[6,21],[5,20],[4,18],[4,16],[5,15],[6,16],[5,17]] },
'a': { width: 19, points: [[15,14],[15,0],[-1,-1],[15,11],[13,13],[11,14],[8,14],[6,13],[4,11],[3,8],[3,6],[4,3],[6,1],[8,0],[11,0],[13,1],[15,3]] },
'b': { width: 19, points: [[4,21],[4,0],[-1,-1],[4,11],[6,13],[8,14],[11,14],[13,13],[15,11],[16,8],[16,6],[15,3],[13,1],[11,0],[8,0],[6,1],[4,3]] },
'c': { width: 18, points: [[15,11],[13,13],[11,14],[8,14],[6,13],[4,11],[3,8],[3,6],[4,3],[6,1],[8,0],[11,0],[13,1],[15,3]] },
'd': { width: 19, points: [[15,21],[15,0],[-1,-1],[15,11],[13,13],[11,14],[8,14],[6,13],[4,11],[3,8],[3,6],[4,3],[6,1],[8,0],[11,0],[13,1],[15,3]] },
'e': { width: 18, points: [[3,8],[15,8],[15,10],[14,12],[13,13],[11,14],[8,14],[6,13],[4,11],[3,8],[3,6],[4,3],[6,1],[8,0],[11,0],[13,1],[15,3]] },
'f': { width: 12, points: [[10,21],[8,21],[6,20],[5,17],[5,0],[-1,-1],[2,14],[9,14]] },
'g': { width: 19, points: [[15,14],[15,-2],[14,-5],[13,-6],[11,-7],[8,-7],[6,-6],[-1,-1],[15,11],[13,13],[11,14],[8,14],[6,13],[4,11],[3,8],[3,6],[4,3],[6,1],[8,0],[11,0],[13,1],[15,3]] },
'h': { width: 19, points: [[4,21],[4,0],[-1,-1],[4,10],[7,13],[9,14],[12,14],[14,13],[15,10],[15,0]] },
'i': { width: 8, points: [[3,21],[4,20],[5,21],[4,22],[3,21],[-1,-1],[4,14],[4,0]] },
'j': { width: 10, points: [[5,21],[6,20],[7,21],[6,22],[5,21],[-1,-1],[6,14],[6,-3],[5,-6],[3,-7],[1,-7]] },
'k': { width: 17, points: [[4,21],[4,0],[-1,-1],[14,14],[4,4],[-1,-1],[8,8],[15,0]] },
'l': { width: 8, points: [[4,21],[4,0]] },
'm': { width: 30, points: [[4,14],[4,0],[-1,-1],[4,10],[7,13],[9,14],[12,14],[14,13],[15,10],[15,0],[-1,-1],[15,10],[18,13],[20,14],[23,14],[25,13],[26,10],[26,0]] },
'n': { width: 19, points: [[4,14],[4,0],[-1,-1],[4,10],[7,13],[9,14],[12,14],[14,13],[15,10],[15,0]] },
'o': { width: 19, points: [[8,14],[6,13],[4,11],[3,8],[3,6],[4,3],[6,1],[8,0],[11,0],[13,1],[15,3],[16,6],[16,8],[15,11],[13,13],[11,14],[8,14]] },
'p': { width: 19, points: [[4,14],[4,-7],[-1,-1],[4,11],[6,13],[8,14],[11,14],[13,13],[15,11],[16,8],[16,6],[15,3],[13,1],[11,0],[8,0],[6,1],[4,3]] },
'q': { width: 19, points: [[15,14],[15,-7],[-1,-1],[15,11],[13,13],[11,14],[8,14],[6,13],[4,11],[3,8],[3,6],[4,3],[6,1],[8,0],[11,0],[13,1],[15,3]] },
'r': { width: 13, points: [[4,14],[4,0],[-1,-1],[4,8],[5,11],[7,13],[9,14],[12,14]] },
's': { width: 17, points: [[14,11],[13,13],[10,14],[7,14],[4,13],[3,11],[4,9],[6,8],[11,7],[13,6],[14,4],[14,3],[13,1],[10,0],[7,0],[4,1],[3,3]] },
't': { width: 12, points: [[5,21],[5,4],[6,1],[8,0],[10,0],[-1,-1],[2,14],[9,14]] },
'u': { width: 19, points: [[4,14],[4,4],[5,1],[7,0],[10,0],[12,1],[15,4],[-1,-1],[15,14],[15,0]] },
'v': { width: 16, points: [[2,14],[8,0],[-1,-1],[14,14],[8,0]] },
'w': { width: 22, points: [[3,14],[7,0],[-1,-1],[11,14],[7,0],[-1,-1],[11,14],[15,0],[-1,-1],[19,14],[15,0]] },
'x': { width: 17, points: [[3,14],[14,0],[-1,-1],[14,14],[3,0]] },
'y': { width: 16, points: [[2,14],[8,0],[-1,-1],[14,14],[8,0],[6,-4],[4,-6],[2,-7],[1,-7]] },
'z': { width: 17, points: [[14,14],[3,0],[-1,-1],[3,14],[14,14],[-1,-1],[3,0],[14,0]] },
'{': { width: 14, points: [[9,25],[7,24],[6,23],[5,21],[5,19],[6,17],[7,16],[8,14],[8,12],[6,10],[-1,-1],[7,24],[6,22],[6,20],[7,18],[8,17],[9,15],[9,13],[8,11],[4,9],[8,7],[9,5],[9,3],[8,1],[7,0],[6,-2],[6,-4],[7,-6],[-1,-1],[6,8],[8,6],[8,4],[7,2],[6,1],[5,-1],[5,-3],[6,-5],[7,-6],[9,-7]] },
'|': { width: 8, points: [[4,25],[4,-7]] },
'}': { width: 14, points: [[5,25],[7,24],[8,23],[9,21],[9,19],[8,17],[7,16],[6,14],[6,12],[8,10],[-1,-1],[7,24],[8,22],[8,20],[7,18],[6,17],[5,15],[5,13],[6,11],[10,9],[6,7],[5,5],[5,3],[6,1],[7,0],[8,-2],[8,-4],[7,-6],[-1,-1],[8,8],[6,6],[6,4],[7,2],[8,1],[9,-1],[9,-3],[8,-5],[7,-6],[5,-7]] },
'~': { width: 24, points: [[3,6],[3,8],[4,11],[6,12],[8,12],[10,11],[14,8],[16,7],[18,7],[20,8],[21,10],[-1,-1],[3,8],[4,10],[6,11],[8,11],[10,10],[14,7],[16,6],[18,6],[20,7],[21,10],[21,12]] }
};
$.jqplot.CanvasFontRenderer = function(options) {
options = options || {};
if (!options.pt2px) {
options.pt2px = 1.5;
}
$.jqplot.CanvasTextRenderer.call(this, options);
};
$.jqplot.CanvasFontRenderer.prototype = new $.jqplot.CanvasTextRenderer({});
$.jqplot.CanvasFontRenderer.prototype.constructor = $.jqplot.CanvasFontRenderer;
$.jqplot.CanvasFontRenderer.prototype.measure = function(ctx, str)
{
// var fstyle = this.fontStyle+' '+this.fontVariant+' '+this.fontWeight+' '+this.fontSize+' '+this.fontFamily;
var fstyle = this.fontSize+' '+this.fontFamily;
ctx.save();
ctx.font = fstyle;
var w = ctx.measureText(str).width;
ctx.restore();
return w;
};
$.jqplot.CanvasFontRenderer.prototype.draw = function(ctx, str)
{
var x = 0;
// leave room at bottom for descenders.
var y = this.height*0.72;
//var y = 12;
ctx.save();
var tx, ty;
// 1st quadrant
if ((-Math.PI/2 <= this.angle && this.angle <= 0) || (Math.PI*3/2 <= this.angle && this.angle <= Math.PI*2)) {
tx = 0;
ty = -Math.sin(this.angle) * this.width;
}
// 4th quadrant
else if ((0 < this.angle && this.angle <= Math.PI/2) || (-Math.PI*2 <= this.angle && this.angle <= -Math.PI*3/2)) {
tx = Math.sin(this.angle) * this.height;
ty = 0;
}
// 2nd quadrant
else if ((-Math.PI < this.angle && this.angle < -Math.PI/2) || (Math.PI <= this.angle && this.angle <= Math.PI*3/2)) {
tx = -Math.cos(this.angle) * this.width;
ty = -Math.sin(this.angle) * this.width - Math.cos(this.angle) * this.height;
}
// 3rd quadrant
else if ((-Math.PI*3/2 < this.angle && this.angle < Math.PI) || (Math.PI/2 < this.angle && this.angle < Math.PI)) {
tx = Math.sin(this.angle) * this.height - Math.cos(this.angle)*this.width;
ty = -Math.cos(this.angle) * this.height;
}
ctx.strokeStyle = this.fillStyle;
ctx.fillStyle = this.fillStyle;
// var fstyle = this.fontStyle+' '+this.fontVariant+' '+this.fontWeight+' '+this.fontSize+' '+this.fontFamily;
var fstyle = this.fontSize+' '+this.fontFamily;
ctx.font = fstyle;
ctx.translate(tx, ty);
ctx.rotate(this.angle);
ctx.fillText(str, x, y);
// ctx.strokeText(str, x, y);
ctx.restore();
};
})(jQuery);

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,702 @@
/**
* jqPlot
* Pure JavaScript plotting plugin using jQuery
*
* Version: 1.0.0b2_r1012
*
* 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.DateAxisRenderer
* A plugin for a jqPlot to render an axis as a series of date values.
* This renderer has no options beyond those supplied by the <Axis> class.
* It supplies it's own tick formatter, so the tickOptions.formatter option
* should not be overridden.
*
* Thanks to Ken Synder for his enhanced Date instance methods which are
* included with this code <http://kendsnyder.com/sandbox/date/>.
*
* To use this renderer, include the plugin in your source
* > <script type="text/javascript" language="javascript" src="plugins/jqplot.dateAxisRenderer.js"></script>
*
* and supply the appropriate options to your plot
*
* > {axes:{xaxis:{renderer:$.jqplot.DateAxisRenderer}}}
*
* Dates can be passed into the axis in almost any recognizable value and
* will be parsed. They will be rendered on the axis in the format
* specified by tickOptions.formatString. e.g. tickOptions.formatString = '%Y-%m-%d'.
*
* Accecptable format codes
* are:
*
* > Code Result Description
* > == Years ==
* > %Y 2008 Four-digit year
* > %y 08 Two-digit year
* > == Months ==
* > %m 09 Two-digit month
* > %#m 9 One or two-digit month
* > %B September Full month name
* > %b Sep Abbreviated month name
* > == Days ==
* > %d 05 Two-digit day of month
* > %#d 5 One or two-digit day of month
* > %e 5 One or two-digit day of month
* > %A Sunday Full name of the day of the week
* > %a Sun Abbreviated name of the day of the week
* > %w 0 Number of the day of the week (0 = Sunday, 6 = Saturday)
* > %o th The ordinal suffix string following the day of the month
* > == Hours ==
* > %H 23 Hours in 24-hour format (two digits)
* > %#H 3 Hours in 24-hour integer format (one or two digits)
* > %I 11 Hours in 12-hour format (two digits)
* > %#I 3 Hours in 12-hour integer format (one or two digits)
* > %p PM AM or PM
* > == Minutes ==
* > %M 09 Minutes (two digits)
* > %#M 9 Minutes (one or two digits)
* > == Seconds ==
* > %S 02 Seconds (two digits)
* > %#S 2 Seconds (one or two digits)
* > %s 1206567625723 Unix timestamp (Seconds past 1970-01-01 00:00:00)
* > == Milliseconds ==
* > %N 008 Milliseconds (three digits)
* > %#N 8 Milliseconds (one to three digits)
* > == Timezone ==
* > %O 360 difference in minutes between local time and GMT
* > %Z Mountain Standard Time Name of timezone as reported by browser
* > %G -06:00 Hours and minutes between GMT
* > == Shortcuts ==
* > %F 2008-03-26 %Y-%m-%d
* > %T 05:06:30 %H:%M:%S
* > %X 05:06:30 %H:%M:%S
* > %x 03/26/08 %m/%d/%y
* > %D 03/26/08 %m/%d/%y
* > %#c Wed Mar 26 15:31:00 2008 %a %b %e %H:%M:%S %Y
* > %v 3-Sep-2008 %e-%b-%Y
* > %R 15:31 %H:%M
* > %r 3:31:00 PM %I:%M:%S %p
* > == Characters ==
* > %n \n Newline
* > %t \t Tab
* > %% % Percent Symbol
*/
$.jqplot.DateAxisRenderer = function() {
$.jqplot.LinearAxisRenderer.call(this);
this.date = new $.jsDate();
};
var second = 1000;
var minute = 60 * second;
var hour = 60 * minute;
var day = 24 * hour;
var week = 7 * day;
// these are less definitive
var month = 30.4368499 * day;
var year = 365.242199 * day;
var daysInMonths = [31,28,31,30,31,30,31,30,31,30,31,30];
// array of consistent nice intervals. Longer intervals
// will depend on days in month, days in year, etc.
var niceFormatStrings = ['%M:%S.%#N', '%M:%S.%#N', '%M:%S.%#N', '%M:%S', '%M:%S', '%M:%S', '%M:%S', '%H:%M:%S', '%H:%M:%S', '%H:%M', '%H:%M', '%H:%M', '%H:%M', '%H:%M', '%H:%M', '%a %H:%M', '%a %H:%M', '%b %e %H:%M', '%b %e %H:%M', '%b %e %H:%M', '%b %e %H:%M', '%v', '%v', '%v', '%v', '%v', '%v', '%v'];
var niceIntervals = [0.1*second, 0.2*second, 0.5*second, second, 2*second, 5*second, 10*second, 15*second, 30*second, minute, 2*minute, 5*minute, 10*minute, 15*minute, 30*minute, hour, 2*hour, 4*hour, 6*hour, 8*hour, 12*hour, day, 2*day, 3*day, 4*day, 5*day, week, 2*week];
var niceMonthlyIntervals = [];
function bestDateInterval(min, max, titarget) {
// iterate through niceIntervals to find one closest to titarget
var badness = Number.MAX_VALUE;
var temp, bestTi, bestfmt;
for (var i=0, l=niceIntervals.length; i < l; i++) {
temp = Math.abs(titarget - niceIntervals[i]);
if (temp < badness) {
badness = temp;
bestTi = niceIntervals[i];
bestfmt = niceFormatStrings[i];
}
}
return [bestTi, bestfmt];
}
$.jqplot.DateAxisRenderer.prototype = new $.jqplot.LinearAxisRenderer();
$.jqplot.DateAxisRenderer.prototype.constructor = $.jqplot.DateAxisRenderer;
$.jqplot.DateTickFormatter = function(format, val) {
if (!format) {
format = '%Y/%m/%d';
}
return $.jsDate.strftime(val, format);
};
$.jqplot.DateAxisRenderer.prototype.init = function(options){
// prop: tickRenderer
// A class of a rendering engine for creating the ticks labels displayed on the plot,
// See <$.jqplot.AxisTickRenderer>.
// this.tickRenderer = $.jqplot.AxisTickRenderer;
// this.labelRenderer = $.jqplot.AxisLabelRenderer;
this.tickOptions.formatter = $.jqplot.DateTickFormatter;
// prop: tickInset
// Controls the amount to inset the first and last ticks from
// the edges of the grid, in multiples of the tick interval.
// 0 is no inset, 0.5 is one half a tick interval, 1 is a full
// tick interval, etc.
this.tickInset = 0;
// prop: drawBaseline
// True to draw the axis baseline.
this.drawBaseline = true;
// prop: baselineWidth
// width of the baseline in pixels.
this.baselineWidth = null;
// prop: baselineColor
// CSS color spec for the baseline.
this.baselineColor = null;
this.daTickInterval = null;
this._daTickInterval = null;
$.extend(true, this, options);
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++) {
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] = 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] != 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] = 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] != 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;
}
if (s.renderer.bands) {
if (s.renderer.bands.hiData.length) {
var bd = s.renderer.bands.hiData;
for (var j=0, l=bd.length; j < l; j++) {
if (this.name === 'xaxis' || this.name === 'x2axis') {
bd[j][0] = new $.jsDate(bd[j][0]).getTime();
if ((bd[j][0] != null && bd[j][0] > db.max) || db.max == null) {
db.max = bd[j][0];
}
}
else {
bd[j][1] = new $.jsDate(bd[j][1]).getTime();
if ((bd[j][1] != null && bd[j][1] > db.max) || db.max == null) {
db.max = bd[j][1];
}
}
}
}
if (s.renderer.bands.lowData.length) {
var bd = s.renderer.bands.lowData;
for (var j=0, l=bd.length; j < l; j++) {
if (this.name === 'xaxis' || this.name === 'x2axis') {
bd[j][0] = new $.jsDate(bd[j][0]).getTime();
if ((bd[j][0] != null && bd[j][0] < db.min) || db.min == null) {
db.min = bd[j][0];
}
}
else {
bd[j][1] = new $.jsDate(bd[j][1]).getTime();
if ((bd[j][1] != null && bd[j][1] < db.min) || db.min == null) {
db.min = bd[j][1];
}
}
}
}
}
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
$.jqplot.DateAxisRenderer.prototype.reset = function() {
this.min = this._options.min;
this.max = this._options.max;
this.tickInterval = this._options.tickInterval;
this.numberTicks = this._options.numberTicks;
this._autoFormatString = '';
if (this._overrideFormatString && this.tickOptions && this.tickOptions.formatString) {
this.tickOptions.formatString = '';
}
this.daTickInterval = this._daTickInterval;
// this._ticks = this.__ticks;
};
$.jqplot.DateAxisRenderer.prototype.createTicks = function(plot) {
// we're are operating on an axis here
var ticks = this._ticks;
var userTicks = this.ticks;
var name = this.name;
// databounds were set on axis initialization.
var db = this._dataBounds;
var iv = this._intervalStats;
var dim = (this.name.charAt(0) === 'x') ? this._plotDimensions.width : this._plotDimensions.height;
var interval;
var min, max;
var pos1, pos2;
var tt, i;
var threshold = 30;
var insetMult = 1;
var tickInterval = this.tickInterval;
// 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);
// see if we're zooming. if we are, don't use the min and max we're given,
// but compute some nice ones. They will be reset later.
var cursor = plot.plugins.cursor;
if (cursor && cursor._zoom && cursor._zoom.zooming) {
this.min = null;
this.max = null;
}
var range = max - min;
if (this.tickOptions == null || !this.tickOptions.formatString) {
this._overrideFormatString = true;
}
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 = new $.jsDate(ut[0]).getTime();
t.label = ut[1];
if (!this.showTicks) {
t.showLabel = false;
t.showMark = false;
}
else if (!this.showTickMarks) {
t.showMark = false;
}
t.setTick(t.value, this.name);
this._ticks.push(t);
}
else {
t.value = new $.jsDate(ut).getTime();
if (!this.showTicks) {
t.showLabel = false;
t.showMark = false;
}
else if (!this.showTickMarks) {
t.showMark = false;
}
t.setTick(t.value, this.name);
this._ticks.push(t);
}
}
this.numberTicks = userTicks.length;
this.min = this._ticks[0].value;
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!
////////
// if user specified min and max are null, we set those to make best ticks.
else if (this.min == null && this.max == null) {
var opts = $.extend(true, {}, this.tickOptions, {name: this.name, value: null});
// want to find a nice interval
var nttarget,
titarget;
// if no tickInterval or numberTicks options specified, make a good guess.
if (!this.tickInterval && !this.numberTicks) {
var tdim = Math.max(dim, threshold+1);
// how many ticks to put on the axis?
// date labels tend to be long. If ticks not rotated,
// don't use too many and have a high spacing factor.
// If we are rotating ticks, use a lower factor.
var spacingFactor = 115;
if (this.tickRenderer === $.jqplot.CanvasAxisTickRenderer && this.tickOptions.angle) {
spacingFactor = 115 - 40 * Math.abs(Math.sin(this.tickOptions.angle/180*Math.PI));
}
nttarget = Math.ceil((tdim-threshold)/spacingFactor + 1);
titarget = (max - min) / (nttarget - 1);
}
// If tickInterval is specified, we'll try to honor it.
// Not gauranteed to get this interval, but we'll get as close as
// we can.
// tickInterval will be used before numberTicks, that is if
// both are specified, numberTicks will be ignored.
else if (this.tickInterval) {
titarget = this.tickInterval;
}
// if numberTicks specified, try to honor it.
// Not gauranteed, but will try to get close.
else if (this.numberTicks) {
nttarget = this.numberTicks;
titarget = (max - min) / (nttarget - 1);
}
// If we can use an interval of 2 weeks or less, pick best one
if (titarget <= 19*day) {
var ret = bestDateInterval(min, max, titarget);
var tempti = ret[0];
this._autoFormatString = ret[1];
min = Math.floor(min/tempti) * tempti;
min = new $.jsDate(min);
min = min.getTime() + min.getUtcOffset();
nttarget = Math.ceil((max - min) / tempti) + 1;
this.min = min;
this.max = min + (nttarget - 1) * tempti;
// if max is less than max, add an interval
if (this.max < max) {
this.max += tempti;
nttarget += 1;
}
this.tickInterval = tempti;
this.numberTicks = nttarget;
for (var i=0; i<nttarget; i++) {
opts.value = this.min + i * tempti;
t = new this.tickRenderer(opts);
if (this._overrideFormatString && this._autoFormatString != '') {
t.formatString = this._autoFormatString;
}
if (!this.showTicks) {
t.showLabel = false;
t.showMark = false;
}
else if (!this.showTickMarks) {
t.showMark = false;
}
this._ticks.push(t);
}
insetMult = this.tickInterval;
}
// should we use a monthly interval?
else if (titarget <= 9 * month) {
this._autoFormatString = '%v';
// how many months in an interval?
var intv = Math.round(titarget/month);
if (intv < 1) {
intv = 1;
}
else if (intv > 6) {
intv = 6;
}
// figure out the starting month and ending month.
var mstart = new $.jsDate(min).setDate(1).setHours(0,0,0,0);
// See if max ends exactly on a month
var tempmend = new $.jsDate(max);
var mend = new $.jsDate(max).setDate(1).setHours(0,0,0,0);
if (tempmend.getTime() !== mend.getTime()) {
mend = mend.add(1, 'month');
}
var nmonths = mend.diff(mstart, 'month');
nttarget = Math.ceil(nmonths/intv) + 1;
this.min = mstart.getTime();
this.max = mstart.clone().add((nttarget - 1) * intv, 'month').getTime();
this.numberTicks = nttarget;
for (var i=0; i<nttarget; i++) {
if (i === 0) {
opts.value = mstart.getTime();
}
else {
opts.value = mstart.add(intv, 'month').getTime();
}
t = new this.tickRenderer(opts);
if (this._overrideFormatString && this._autoFormatString != '') {
t.formatString = this._autoFormatString;
}
if (!this.showTicks) {
t.showLabel = false;
t.showMark = false;
}
else if (!this.showTickMarks) {
t.showMark = false;
}
this._ticks.push(t);
}
insetMult = intv * month;
}
// use yearly intervals
else {
this._autoFormatString = '%v';
// how many years in an interval?
var intv = Math.round(titarget/year);
if (intv < 1) {
intv = 1;
}
// figure out the starting and ending years.
var mstart = new $.jsDate(min).setMonth(0, 1).setHours(0,0,0,0);
var mend = new $.jsDate(max).add(1, 'year').setMonth(0, 1).setHours(0,0,0,0);
var nyears = mend.diff(mstart, 'year');
nttarget = Math.ceil(nyears/intv) + 1;
this.min = mstart.getTime();
this.max = mstart.clone().add((nttarget - 1) * intv, 'year').getTime();
this.numberTicks = nttarget;
for (var i=0; i<nttarget; i++) {
if (i === 0) {
opts.value = mstart.getTime();
}
else {
opts.value = mstart.add(intv, 'year').getTime();
}
t = new this.tickRenderer(opts);
if (this._overrideFormatString && this._autoFormatString != '') {
t.formatString = this._autoFormatString;
}
if (!this.showTicks) {
t.showLabel = false;
t.showMark = false;
}
else if (!this.showTickMarks) {
t.showMark = false;
}
this._ticks.push(t);
}
insetMult = intv * year;
}
}
////////
// 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;
}
// if user specified a tick interval, convert to usable.
if (this.tickInterval != null)
{
// if interval is a number or can be converted to one, use it.
// Assume it is in SECONDS!!!
if (Number(this.tickInterval)) {
this.daTickInterval = [Number(this.tickInterval), 'seconds'];
}
// else, parse out something we can build from.
else if (typeof this.tickInterval == "string") {
var parts = this.tickInterval.split(' ');
if (parts.length == 1) {
this.daTickInterval = [1, parts[0]];
}
else if (parts.length == 2) {
this.daTickInterval = [parts[0], parts[1]];
}
}
}
// if min and max are same, space them out a bit
if (min == max) {
var adj = 24*60*60*500; // 1/2 day
min -= adj;
max += adj;
}
range = max - min;
var optNumTicks = 2 + parseInt(Math.max(0, dim-100)/100, 10);
var rmin, rmax;
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;
if (this.numberTicks == null){
// 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 = new $.jsDate(this.max).diff(this.min, this.daTickInterval[1], true);
this.numberTicks = Math.ceil(nc/this.daTickInterval[0]) +1;
// 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);
}
else {
this.numberTicks = 2;
}
}
insetMult = range / (this.numberTicks-1)/1000;
if (this.daTickInterval == null) {
this.daTickInterval = [insetMult, '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);
}
}
if (this.tickInset) {
this.min = this.min - this.tickInset * insetMult;
this.max = this.max + this.tickInset * insetMult;
}
if (this._daTickInterval == null) {
this._daTickInterval = this.daTickInterval;
}
ticks = null;
};
})(jQuery);

View File

@ -0,0 +1,454 @@
/**
* jqPlot
* Pure JavaScript plotting plugin using jQuery
*
* Version: 1.0.0b2_r1012
*
* 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.eventListenerHooks.push(['jqplotMouseMove', handleMove]);
/**
* Class: $.jqplot.Highlighter
* Plugin which will highlight data points when they are moused over.
*
* To use this plugin, include the js
* file in your source:
*
* > <script type="text/javascript" src="plugins/jqplot.highlighter.js"></script>
*
* A tooltip providing information about the data point is enabled by default.
* To disable the tooltip, set "showTooltip" to false.
*
* You can control what data is displayed in the tooltip with various
* options. The "tooltipAxes" option controls wether the x, y or both
* data values are displayed.
*
* Some chart types (e.g. hi-low-close) have more than one y value per
* data point. To display the additional values in the tooltip, set the
* "yvalues" option to the desired number of y values present (3 for a hlc chart).
*
* By default, data values will be formatted with the same formatting
* specifiers as used to format the axis ticks. A custom format code
* can be supplied with the tooltipFormatString option. This will apply
* to all values in the tooltip.
*
* For more complete control, the "formatString" option can be set. This
* Allows conplete control over tooltip formatting. Values are passed to
* the format string in an order determined by the "tooltipAxes" and "yvalues"
* options. So, if you have a hi-low-close chart and you just want to display
* the hi-low-close values in the tooltip, you could set a formatString like:
*
* > highlighter: {
* > tooltipAxes: 'y',
* > yvalues: 3,
* > formatString:'<table class="jqplot-highlighter">
* > <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>'
* > }
*
*/
$.jqplot.Highlighter = function(options) {
// Group: Properties
//
//prop: show
// true to show the highlight.
this.show = $.jqplot.config.enablePlugins;
// prop: markerRenderer
// Renderer used to draw the marker of the highlighted point.
// Renderer will assimilate attributes from the data point being highlighted,
// so no attributes need set on the renderer directly.
// Default is to turn off shadow drawing on the highlighted point.
this.markerRenderer = new $.jqplot.MarkerRenderer({shadow:false});
// prop: showMarker
// true to show the marker
this.showMarker = true;
// prop: lineWidthAdjust
// Pixels to add to the lineWidth of the highlight.
this.lineWidthAdjust = 2.5;
// prop: sizeAdjust
// Pixels to add to the overall size of the highlight.
this.sizeAdjust = 5;
// prop: showTooltip
// Show a tooltip with data point values.
this.showTooltip = true;
// prop: tooltipLocation
// Where to position tooltip, 'n', 'ne', 'e', 'se', 's', 'sw', 'w', 'nw'
this.tooltipLocation = 'nw';
// prop: fadeTooltip
// true = fade in/out tooltip, flase = show/hide tooltip
this.fadeTooltip = true;
// prop: tooltipFadeSpeed
// 'slow', 'def', 'fast', or number of milliseconds.
this.tooltipFadeSpeed = "fast";
// prop: tooltipOffset
// Pixel offset of tooltip from the highlight.
this.tooltipOffset = 2;
// prop: tooltipAxes
// Which axes to display in tooltip, 'x', 'y' or 'both', 'xy' or 'yx'
// 'both' and 'xy' are equivalent, 'yx' reverses order of labels.
this.tooltipAxes = 'both';
// 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;
// prop: tooltipFormatString
// sprintf format string for the tooltip.
// Uses Ash Searle's javascript sprintf implementation
// found here: http://hexmen.com/blog/2007/03/printf-sprintf/
// See http://perldoc.perl.org/functions/sprintf.html for reference.
// Additional "p" and "P" format specifiers added by Chris Leonello.
this.tooltipFormatString = '%.5P';
// prop: formatString
// alternative to tooltipFormatString
// will format the whole tooltip text, populating with x, y values as
// indicated by tooltipAxes option. So, you could have a tooltip like:
// 'Date: %s, number of cats: %d' to format the whole tooltip at one go.
// If useAxesFormatters is true, values will be formatted according to
// Axes formatters and you can populate your tooltip string with
// %s placeholders.
this.formatString = null;
// prop: yvalues
// Number of y values to expect in the data point array.
// 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;
this.currentNeighbor = null;
$.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
$.jqplot.Highlighter.init = function (target, data, opts){
var options = opts || {};
// add a highlighter attribute to the plot
this.plugins.highlighter = new $.jqplot.Highlighter(options.highlighter);
};
// 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;
};
// 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.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, 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'});
this.eventCanvas._elem.before(this.plugins.highlighter._tooltipElem);
};
$.jqplot.preInitHooks.push($.jqplot.Highlighter.init);
$.jqplot.preParseSeriesOptionsHooks.push($.jqplot.Highlighter.parseOptions);
$.jqplot.postDrawHooks.push($.jqplot.Highlighter.postPlotDraw);
function draw(plot, neighbor) {
var hl = plot.plugins.highlighter;
var s = plot.series[neighbor.seriesIndex];
var smr = s.markerRenderer;
var mr = hl.markerRenderer;
mr.style = smr.style;
mr.lineWidth = smr.lineWidth + hl.lineWidthAdjust;
mr.size = smr.size + hl.sizeAdjust;
var rgba = $.jqplot.getColorComponents(smr.color);
var newrgb = [rgba[0], rgba[1], rgba[2]];
var alpha = (rgba[3] >= 0.6) ? rgba[3]*0.6 : rgba[3]*(2-rgba[3]);
mr.color = 'rgba('+newrgb[0]+','+newrgb[1]+','+newrgb[2]+','+alpha+')';
mr.init();
mr.draw(s.gridData[neighbor.pointIndex][0], s.gridData[neighbor.pointIndex][1], hl.highlightCanvas._ctx);
}
function showTooltip(plot, series, neighbor) {
// neighbor looks like: {seriesIndex: i, pointIndex:j, gridData:p, data:s.data[j]}
// gridData should be x,y pixel coords on the grid.
// add the plot._gridPadding to that to get x,y in the target.
var hl = plot.plugins.highlighter;
var elem = hl._tooltipElem;
var serieshl = series.highlighter || {};
var opts = $.extend(true, {}, hl, serieshl);
if (opts.useAxesFormatters) {
var xf = series._xaxis._ticks[0].formatter;
var yf = series._yaxis._ticks[0].formatter;
var xfstr = series._xaxis._ticks[0].formatString;
var yfstr = series._yaxis._ticks[0].formatString;
var str;
var xstr = xf(xfstr, neighbor.data[0]);
var ystrs = [];
for (var i=1; i<opts.yvalues+1; i++) {
ystrs.push(yf(yfstr, neighbor.data[i]));
}
if (typeof opts.formatString === 'string') {
switch (opts.tooltipAxes) {
case 'both':
case 'xy':
ystrs.unshift(xstr);
ystrs.unshift(opts.formatString);
str = $.jqplot.sprintf.apply($.jqplot.sprintf, ystrs);
break;
case 'yx':
ystrs.push(xstr);
ystrs.unshift(opts.formatString);
str = $.jqplot.sprintf.apply($.jqplot.sprintf, ystrs);
break;
case 'x':
str = $.jqplot.sprintf.apply($.jqplot.sprintf, [opts.formatString, xstr]);
break;
case 'y':
ystrs.unshift(opts.formatString);
str = $.jqplot.sprintf.apply($.jqplot.sprintf, ystrs);
break;
default: // same as xy
ystrs.unshift(xstr);
ystrs.unshift(opts.formatString);
str = $.jqplot.sprintf.apply($.jqplot.sprintf, ystrs);
break;
}
}
else {
switch (opts.tooltipAxes) {
case 'both':
case 'xy':
str = xstr;
for (var i=0; i<ystrs.length; i++) {
str += opts.tooltipSeparator + ystrs[i];
}
break;
case 'yx':
str = '';
for (var i=0; i<ystrs.length; i++) {
str += ystrs[i] + opts.tooltipSeparator;
}
str += xstr;
break;
case 'x':
str = xstr;
break;
case 'y':
str = ystrs.join(opts.tooltipSeparator);
break;
default: // same as 'xy'
str = xstr;
for (var i=0; i<ystrs.length; i++) {
str += opts.tooltipSeparator + ystrs[i];
}
break;
}
}
}
else {
var str;
if (typeof opts.formatString === 'string') {
str = $.jqplot.sprintf.apply($.jqplot.sprintf, [opts.formatString].concat(neighbor.data));
}
else {
if (opts.tooltipAxes == 'both' || opts.tooltipAxes == 'xy') {
str = $.jqplot.sprintf(opts.tooltipFormatString, neighbor.data[0]) + opts.tooltipSeparator + $.jqplot.sprintf(opts.tooltipFormatString, neighbor.data[1]);
}
else if (opts.tooltipAxes == 'yx') {
str = $.jqplot.sprintf(opts.tooltipFormatString, neighbor.data[1]) + opts.tooltipSeparator + $.jqplot.sprintf(opts.tooltipFormatString, neighbor.data[0]);
}
else if (opts.tooltipAxes == 'x') {
str = $.jqplot.sprintf(opts.tooltipFormatString, neighbor.data[0]);
}
else if (opts.tooltipAxes == 'y') {
str = $.jqplot.sprintf(opts.tooltipFormatString, neighbor.data[1]);
}
}
}
if ($.isFunction(opts.tooltipContentEditor)) {
// args str, seriesIndex, pointIndex are essential so the hook can look up
// extra data for the point.
str = opts.tooltipContentEditor(str, neighbor.seriesIndex, neighbor.pointIndex, plot);
}
elem.html(str);
var gridpos = {x:neighbor.gridData[0], y:neighbor.gridData[1]};
var ms = 0;
var fact = 0.707;
if (series.markerRenderer.show == true) {
ms = (series.markerRenderer.size + opts.sizeAdjust)/2;
}
var loc = locations;
if (series.fillToZero && series.fill && neighbor.data[1] < 0) {
loc = oppositeLocations;
}
switch (loc[locationIndicies[opts.tooltipLocation]]) {
case 'nw':
var x = gridpos.x + plot._gridPadding.left - elem.outerWidth(true) - opts.tooltipOffset - fact * ms;
var y = gridpos.y + plot._gridPadding.top - opts.tooltipOffset - elem.outerHeight(true) - fact * ms;
break;
case 'n':
var x = gridpos.x + plot._gridPadding.left - elem.outerWidth(true)/2;
var y = gridpos.y + plot._gridPadding.top - opts.tooltipOffset - elem.outerHeight(true) - ms;
break;
case 'ne':
var x = gridpos.x + plot._gridPadding.left + opts.tooltipOffset + fact * ms;
var y = gridpos.y + plot._gridPadding.top - opts.tooltipOffset - elem.outerHeight(true) - fact * ms;
break;
case 'e':
var x = gridpos.x + plot._gridPadding.left + opts.tooltipOffset + ms;
var y = gridpos.y + plot._gridPadding.top - elem.outerHeight(true)/2;
break;
case 'se':
var x = gridpos.x + plot._gridPadding.left + opts.tooltipOffset + fact * ms;
var y = gridpos.y + plot._gridPadding.top + opts.tooltipOffset + fact * ms;
break;
case 's':
var x = gridpos.x + plot._gridPadding.left - elem.outerWidth(true)/2;
var y = gridpos.y + plot._gridPadding.top + opts.tooltipOffset + ms;
break;
case 'sw':
var x = gridpos.x + plot._gridPadding.left - elem.outerWidth(true) - opts.tooltipOffset - fact * ms;
var y = gridpos.y + plot._gridPadding.top + opts.tooltipOffset + fact * ms;
break;
case 'w':
var x = gridpos.x + plot._gridPadding.left - elem.outerWidth(true) - opts.tooltipOffset - ms;
var y = gridpos.y + plot._gridPadding.top - elem.outerHeight(true)/2;
break;
default: // same as 'nw'
var x = gridpos.x + plot._gridPadding.left - elem.outerWidth(true) - opts.tooltipOffset - fact * ms;
var y = gridpos.y + plot._gridPadding.top - opts.tooltipOffset - elem.outerHeight(true) - fact * ms;
break;
}
elem.css('left', x);
elem.css('top', y);
if (opts.fadeTooltip) {
// Fix for stacked up animations. Thnanks Trevor!
elem.stop(true,true).fadeIn(opts.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;
ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);
if (hl.fadeTooltip) {
hl._tooltipElem.fadeOut(hl.tooltipFadeSpeed);
}
else {
hl._tooltipElem.hide();
}
if (hl.bringSeriesToFront) {
plot.restorePreviousSeriesOrder();
}
hl.isHighlighting = false;
hl.currentNeighbor = null;
ctx = null;
}
else if (neighbor != null && plot.series[neighbor.seriesIndex].showHighlight && !hl.isHighlighting) {
hl.isHighlighting = true;
hl.currentNeighbor = neighbor;
if (hl.showMarker) {
draw(plot, neighbor);
}
if (hl.showTooltip && (!c || !c._zoom.started)) {
showTooltip(plot, plot.series[neighbor.seriesIndex], neighbor);
}
if (hl.bringSeriesToFront) {
plot.moveSeriesToFront(neighbor.seriesIndex);
}
}
// check to see if we're highlighting the wrong point.
else if (neighbor != null && hl.isHighlighting && hl.currentNeighbor != neighbor) {
// highlighting the wrong point.
// if new series allows highlighting, highlight new point.
if (plot.series[neighbor.seriesIndex].showHighlight) {
var ctx = hl.highlightCanvas._ctx;
ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);
hl.isHighlighting = true;
hl.currentNeighbor = neighbor;
if (hl.showMarker) {
draw(plot, neighbor);
}
if (hl.showTooltip && (!c || !c._zoom.started)) {
showTooltip(plot, plot.series[neighbor.seriesIndex], neighbor);
}
if (hl.bringSeriesToFront) {
plot.moveSeriesToFront(neighbor.seriesIndex);
}
}
}
}
}
})(jQuery);

View File

@ -0,0 +1,899 @@
/**
* jqPlot
* Pure JavaScript plotting plugin using jQuery
*
* Version: 1.0.0b2_r1012
*
* 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.PieRenderer
* Plugin renderer to draw a pie 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
* 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);
};
$.jqplot.PieRenderer.prototype = new $.jqplot.LineRenderer();
$.jqplot.PieRenderer.prototype.constructor = $.jqplot.PieRenderer;
// called with scope of a series
$.jqplot.PieRenderer.prototype.init = function(options, plot) {
// Group: Properties
//
// prop: diameter
// 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
// angular spacing between pie slices in degrees.
this.sliceMargin = 0;
// 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.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.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) {
// 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) {
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();
}
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.
// 2Pi = 6.2831853, Pi = 3.1415927
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 pies.
if (ang1 >= ang2) {
return;
}
ctx.beginPath();
ctx.fillStyle = color;
ctx.strokeStyle = color;
ctx.lineWidth = lineWidth;
ctx.arc(0, 0, rad, ang1, ang2, false);
ctx.lineTo(0,0);
ctx.closePath();
if (fill) {
ctx.fill();
}
else {
ctx.stroke();
}
}
};
// called with scope of series
$.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 $.jqplot.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 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;
// 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) {
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++) {
this.renderer.drawSlice.call (this, ctx, this._sliceAngles[i][0], this._sliceAngles[i][1], colorGenerator.next(), false);
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() {
$.jqplot.LinearAxisRenderer.call(this);
};
$.jqplot.PieAxisRenderer.prototype = new $.jqplot.LinearAxisRenderer();
$.jqplot.PieAxisRenderer.prototype.constructor = $.jqplot.PieAxisRenderer;
// There are no traditional axes on a pie chart. We just need to provide
// dummy objects with properties so the plot will render.
// called with scope of axis object.
$.jqplot.PieAxisRenderer.prototype.init = function(options){
//
this.tickRenderer = $.jqplot.PieTickRenderer;
$.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.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;
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 $.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;
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 jqplot-table-legend-swatch');
td1.css({textAlign: 'center', paddingTop: rs});
div0 = $(document.createElement('div'));
div0.addClass('jqplot-table-legend-swatch-outline');
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 jqplot-table-legend-label');
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;
};
$.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) {
options = options || {};
options.axesDefaults = options.axesDefaults || {};
options.legend = options.legend || {};
options.seriesDefaults = options.seriesDefaults || {};
// only set these if there is a pie series
var setopts = false;
if (options.seriesDefaults.renderer == $.jqplot.PieRenderer) {
setopts = true;
}
else if (options.series) {
for (var i=0; i < options.series.length; i++) {
if (options.series[i].renderer == $.jqplot.PieRenderer) {
setopts = true;
}
}
}
if (setopts) {
options.axesDefaults.renderer = $.jqplot.PieAxisRenderer;
options.legend.renderer = $.jqplot.PieLegendRenderer;
options.legend.preDraw = true;
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;
}
}
}
}
// 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 = $.jqplot.colorGenerator;
}
}
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();
this.eventCanvas._elem.bind('mouseleave', {plot:this}, function (ev) { unhighlight(ev.data.plot); });
}
$.jqplot.preInitHooks.push(preInit);
$.jqplot.PieTickRenderer = function() {
$.jqplot.AxisTickRenderer.call(this);
};
$.jqplot.PieTickRenderer.prototype = new $.jqplot.AxisTickRenderer();
$.jqplot.PieTickRenderer.prototype.constructor = $.jqplot.PieTickRenderer;
})(jQuery);

View File

@ -294,24 +294,20 @@ $js_messages['strSave'] = __('Save');
$js_messages['strHideSearchCriteria'] = __('Hide search criteria');
$js_messages['strShowSearchCriteria'] = __('Show search criteria');
/* For tbl_zoom_plot.js */
/* For tbl_zoom_plot_jqplot.js */
$js_messages['strZoomSearch'] = __('Zoom Search');
$js_messages['strDisplayHelp'] = '<ul><li>'
. __('Each point represents a data row.')
. '</li><li>'
. __('Hovering over a point will show its label.')
. '</li><li>'
. __('Use mousewheel to zoom in or out of the plot.')
. '</li><li>'
. __('Click and drag the mouse to navigate the plot.')
. __('To zoom in, select a section of the plot with the mouse.')
. '</li><li>'
. __('Click reset zoom link to come back to original state.')
. '</li><li>'
. __('Click a data point to view and possibly edit the data row.')
. '</li><li>'
. __('The plot can be resized by dragging it along the bottom right corner.')
. '</li><li>'
. __('Strings are converted into integer for plotting')
. '</li></ul>';
$js_messages['strInputNull'] = '<strong>' . __('Select two columns') . '</strong>';
$js_messages['strSameInputs'] = '<strong>' . __('Select two different columns') . '</strong>';

View File

@ -609,7 +609,7 @@ function makeProfilingChart()
// Prevent the user from seeing the JSON code
$('div#profilingchart').html('').show();
PMA_createProfilingChart(data);
PMA_createProfilingChartJqplot('profilingchart', data);
}

View File

@ -1,878 +0,0 @@
/* vim: set expandtab sw=4 ts=4 sts=4: */
/**
** @fileoverview JavaScript functions used on tbl_select.php
**
** @requires jQuery
** @requires js/functions.js
**/
/**
** Display Help/Info
**/
function displayHelp() {
var msgbox = PMA_ajaxShowMessage(PMA_messages['strDisplayHelp'], 10000);
msgbox.click(function() {
PMA_ajaxRemoveMessage(msgbox);
});
}
/**
** Extend the array object for max function
** @param array
**/
Array.max = function (array) {
return Math.max.apply( Math, array );
};
/**
** Extend the array object for min function
** @param array
**/
Array.min = function (array) {
return Math.min.apply( Math, array );
};
/**
** Checks if a string contains only numeric value
** @param n: String (to be checked)
**/
function isNumeric(n) {
return !isNaN(parseFloat(n)) && isFinite(n);
}
/**
** Checks if an object is empty
** @param n: Object (to be checked)
**/
function isEmpty(obj) {
var name;
for (name in obj) {
return false;
}
return true;
}
/**
** Converts a timestamp into the format of its field type
** @param val Integer Timestamp
** @param type String Field type(datetime/timestamp/time/date)
**/
function getDate(val, type) {
if (type.toString().search(/datetime/i) != -1 || type.toString().search(/timestamp/i) != -1) {
return Highcharts.dateFormat('%Y-%m-%e %H:%M:%S', val);
}
else if (type.toString().search(/time/i) != -1) {
return Highcharts.dateFormat('%H:%M:%S', val);
}
else if (type.toString().search(/date/i) != -1) {
return Highcharts.dateFormat('%Y-%m-%e', val);
}
}
/**
** Converts a date/time into timestamp
** @param val String Date
** @param type Sring Field type(datetime/timestamp/time/date)
**/
function getTimeStamp(val, type) {
if (type.toString().search(/datetime/i) != -1 || type.toString().search(/timestamp/i) != -1) {
return getDateFromFormat(val, 'yyyy-MM-dd HH:mm:ss', val);
}
else if (type.toString().search(/time/i) != -1) {
return getDateFromFormat('1970-01-01 ' + val, 'yyyy-MM-dd HH:mm:ss');
}
else if (type.toString().search(/date/i) != -1) {
return getDateFromFormat(val, 'yyyy-MM-dd');
}
}
/**
** Classifies the field type into numeric,timeseries or text
** @param field: field type (as in database structure)
**/
function getType(field) {
if (field.toString().search(/int/i) != -1 || field.toString().search(/decimal/i) != -1
|| field.toString().search(/year/i) != -1) {
return 'numeric';
} else if (field.toString().search(/time/i) != -1 || field.toString().search(/date/i) != -1) {
return 'time';
} else {
return 'text';
}
}
/**
** Converts a categorical array into numeric array
** @param array categorical values array
**/
function getCord(arr) {
var newCord = new Array();
var original = $.extend(true, [], arr);
var arr = jQuery.unique(arr).sort();
$.each(original, function(index, value) {
newCord.push(jQuery.inArray(value, arr));
});
return [newCord, arr, original];
}
/**
** Scrolls the view to the display section
**/
function scrollToChart() {
var x = $('#dataDisplay').offset().top - 100; // 100 provides buffer in viewport
$('html,body').animate({scrollTop: x}, 500);
}
/**
** Handlers for panning feature
**/
function includePan(currentChart) {
var mouseDown;
var lastX;
var lastY;
var chartWidth = $('#resizer').width() - 3;
var chartHeight = $('#resizer').height() - 20;
$('#querychart').mousedown(function() {
mouseDown = 1;
});
$('#querychart').mouseup(function() {
mouseDown = 0;
});
$('#querychart').mousemove(function(e) {
if (mouseDown == 1) {
if (e.pageX > lastX) {
var xExtremes = currentChart.xAxis[0].getExtremes();
var diff = (e.pageX - lastX) * (xExtremes.max - xExtremes.min) / chartWidth;
currentChart.xAxis[0].setExtremes(xExtremes.min - diff, xExtremes.max - diff);
} else if (e.pageX < lastX) {
var xExtremes = currentChart.xAxis[0].getExtremes();
var diff = (lastX - e.pageX) * (xExtremes.max - xExtremes.min) / chartWidth;
currentChart.xAxis[0].setExtremes(xExtremes.min + diff, xExtremes.max + diff);
}
if (e.pageY > lastY) {
var yExtremes = currentChart.yAxis[0].getExtremes();
var ydiff = 1.0 * (e.pageY - lastY) * (yExtremes.max - yExtremes.min) / chartHeight;
currentChart.yAxis[0].setExtremes(yExtremes.min + ydiff, yExtremes.max + ydiff);
} else if (e.pageY < lastY) {
var yExtremes = currentChart.yAxis[0].getExtremes();
var ydiff = 1.0 * (lastY - e.pageY) * (yExtremes.max - yExtremes.min) / chartHeight;
currentChart.yAxis[0].setExtremes(yExtremes.min - ydiff, yExtremes.max - ydiff);
}
}
lastX = e.pageX;
lastY = e.pageY;
});
}
$(function() {
var cursorMode = ($("input[name='mode']:checked").val() == 'edit') ? 'crosshair' : 'pointer';
var currentChart = null;
var currentData = null;
var xLabel = $('#tableid_0').val();
var yLabel = $('#tableid_1').val();
var xType = $('#types_0').val();
var yType = $('#types_1').val();
var dataLabel = $('#dataLabel').val();
var zoomRatio = 1;
// Get query result
var data = jQuery.parseJSON($('#querydata').html());
/**
** Input form submit on field change
**/
$('#tableid_0').change(function() {
//AJAX request for field type, collation, operators, and value field
$.post('tbl_zoom_select.php',{
'ajax_request' : true,
'change_tbl_info' : true,
'db' : window.parent.db,
'table' : window.parent.table,
'field' : $('#tableid_0').val(),
'it' : 0,
'token' : window.parent.token
},function(data) {
$('#tableFieldsId tr:eq(1) td:eq(0)').html(data.field_type);
$('#tableFieldsId tr:eq(1) td:eq(1)').html(data.field_collation);
$('#tableFieldsId tr:eq(1) td:eq(2)').html(data.field_operators);
$('#tableFieldsId tr:eq(1) td:eq(3)').html(data.field_value);
xLabel = $('#tableid_0').val();
$('#types_0').val(data.field_type);
$('#collations_0').val(data.field_collations);
});
});
$('#tableid_1').change(function() {
//AJAX request for field type, collation, operators, and value field
$.post('tbl_zoom_select.php',{
'ajax_request' : true,
'change_tbl_info' : true,
'db' : window.parent.db,
'table' : window.parent.table,
'field' : $('#tableid_1').val(),
'it' : 1,
'token' : window.parent.token
},function(data) {
$('#tableFieldsId tr:eq(3) td:eq(0)').html(data.field_type);
$('#tableFieldsId tr:eq(3) td:eq(1)').html(data.field_collation);
$('#tableFieldsId tr:eq(3) td:eq(2)').html(data.field_operators);
$('#tableFieldsId tr:eq(3) td:eq(3)').html(data.field_value);
yLabel = $('#tableid_1').val();
$('#types_1').val(data.field_type);
$('#collations_1').val(data.field_collations);
});
});
$('#tableid_2').change(function() {
//AJAX request for field type, collation, operators, and value field
$.post('tbl_zoom_select.php',{
'ajax_request' : true,
'change_tbl_info' : true,
'db' : window.parent.db,
'table' : window.parent.table,
'field' : $('#tableid_2').val(),
'it' : 2,
'token' : window.parent.token
},function(data) {
$('#tableFieldsId tr:eq(6) td:eq(0)').html(data.field_type);
$('#tableFieldsId tr:eq(6) td:eq(1)').html(data.field_collation);
$('#tableFieldsId tr:eq(6) td:eq(2)').html(data.field_operators);
$('#tableFieldsId tr:eq(6) td:eq(3)').html(data.field_value);
$('#types_2').val(data.field_type);
$('#collations_2').val(data.field_collations);
});
});
$('#tableid_3').change(function() {
//AJAX request for field type, collation, operators, and value field
$.post('tbl_zoom_select.php',{
'ajax_request' : true,
'change_tbl_info' : true,
'db' : window.parent.db,
'table' : window.parent.table,
'field' : $('#tableid_3').val(),
'it' : 3,
'token' : window.parent.token
},function(data) {
$('#tableFieldsId tr:eq(8) td:eq(0)').html(data.field_type);
$('#tableFieldsId tr:eq(8) td:eq(1)').html(data.field_collation);
$('#tableFieldsId tr:eq(8) td:eq(2)').html(data.field_operators);
$('#tableFieldsId tr:eq(8) td:eq(3)').html(data.field_value);
$('#types_3').val(data.field_type);
$('#collations_3').val(data.field_collations);
});
});
/**
* Input form validation
**/
$('#inputFormSubmitId').click(function() {
if ($('#tableid_0').get(0).selectedIndex == 0 || $('#tableid_1').get(0).selectedIndex == 0) {
PMA_ajaxShowMessage(PMA_messages['strInputNull']);
} else if (xLabel == yLabel) {
PMA_ajaxShowMessage(PMA_messages['strSameInputs']);
}
});
/**
** Prepare a div containing a link, otherwise it's incorrectly displayed
** after a couple of clicks
**/
$('<div id="togglesearchformdiv"><a id="togglesearchformlink"></a></div>')
.insertAfter('#zoom_search_form')
// don't show it until we have results on-screen
.hide();
$('#togglesearchformlink')
.html(PMA_messages['strShowSearchCriteria'])
.bind('click', function() {
var $link = $(this);
$('#zoom_search_form').slideToggle();
if ($link.text() == PMA_messages['strHideSearchCriteria']) {
$link.text(PMA_messages['strShowSearchCriteria']);
} else {
$link.text(PMA_messages['strHideSearchCriteria']);
}
// avoid default click action
return false;
});
/**
** Set dialog properties for the data display form
**/
var buttonOptions = {};
/*
* Handle saving of a row in the editor
*/
buttonOptions[PMA_messages['strSave']] = function () {
//Find changed values by comparing form values with selectedRow Object
var newValues = new Object();//Stores the values changed from original
var sqlTypes = new Object();
var it = 4;
var xChange = false;
var yChange = false;
var key;
for (key in selectedRow) {
var oldVal = selectedRow[key];
var newVal = ($('#fields_null_id_' + it).prop('checked')) ? null : $('#fieldID_' + it).val();
if (newVal instanceof Array) { // when the column is of type SET
newVal = $('#fieldID_' + it).map(function(){
return $(this).val();
}).get().join(",");
}
if (oldVal != newVal) {
selectedRow[key] = newVal;
newValues[key] = newVal;
if (key == xLabel) {
xChange = true;
data[currentData][xLabel] = newVal;
} else if (key == yLabel) {
yChange = true;
data[currentData][yLabel] = newVal;
}
}
var $input = $('#fieldID_' + it);
if ($input.hasClass('bit')) {
sqlTypes[key] = 'bit';
}
it++;
} //End data update
//Update the chart series and replot
if (xChange || yChange) {
var newSeries = new Array();
newSeries[0] = new Object();
newSeries[0].marker = {
symbol: 'circle'
};
//Logic similar to plot generation, replot only if xAxis changes or yAxis changes.
//Code includes a lot of checks so as to replot only when necessary
if (xChange) {
xCord[currentData] = selectedRow[xLabel];
if (xType == 'numeric') {
currentChart.series[0].data[currentData].update({ x : selectedRow[xLabel] });
currentChart.xAxis[0].setExtremes(Array.min(xCord) - 6, Array.max(xCord) + 6);
} else if (xType == 'time') {
currentChart.series[0].data[currentData].update({
x : getTimeStamp(selectedRow[xLabel], $('#types_0').val())
});
} else {
var tempX = getCord(xCord);
var tempY = getCord(yCord);
var i = 0;
newSeries[0].data = new Array();
xCord = tempX[2];
yCord = tempY[2];
$.each(data, function(key, value) {
if (yType != 'text') {
newSeries[0].data.push({
name: value[dataLabel],
x: tempX[0][i],
y: value[yLabel],
marker: {fillColor: colorCodes[i % 8]},
id: i
});
} else {
newSeries[0].data.push({
name: value[dataLabel],
x: tempX[0][i],
y: tempY[0][i],
marker: {fillColor: colorCodes[i % 8]},
id: i
});
}
i++;
});
currentSettings.xAxis.labels = {
formatter : function() {
if (tempX[1][this.value] && tempX[1][this.value].length > 10) {
return tempX[1][this.value].substring(0, 10);
} else {
return tempX[1][this.value];
}
}
};
currentSettings.series = newSeries;
currentChart = PMA_createChart(currentSettings);
}
}
if (yChange) {
yCord[currentData] = selectedRow[yLabel];
if (yType == 'numeric') {
currentChart.series[0].data[currentData].update({ y : selectedRow[yLabel] });
currentChart.yAxis[0].setExtremes(Array.min(yCord) - 6, Array.max(yCord) + 6);
} else if (yType == 'time') {
currentChart.series[0].data[currentData].update({
y : getTimeStamp(selectedRow[yLabel], $('#types_1').val())
});
} else {
var tempX = getCord(xCord);
var tempY = getCord(yCord);
var i = 0;
newSeries[0].data = new Array();
xCord = tempX[2];
yCord = tempY[2];
$.each(data, function(key, value) {
if (xType != 'text' ) {
newSeries[0].data.push({
name: value[dataLabel],
x: value[xLabel],
y: tempY[0][i],
marker: {fillColor: colorCodes[i % 8]},
id: i
});
} else {
newSeries[0].data.push({
name: value[dataLabel],
x: tempX[0][i],
y: tempY[0][i],
marker: {fillColor: colorCodes[i % 8]},
id: i
});
}
i++;
});
currentSettings.yAxis.labels = {
formatter : function() {
if (tempY[1][this.value] && tempY[1][this.value].length > 10) {
return tempY[1][this.value].substring(0, 10);
} else {
return tempY[1][this.value];
}
}
};
currentSettings.series = newSeries;
currentChart = PMA_createChart(currentSettings);
}
}
currentChart.series[0].data[currentData].select();
} //End plot update
//Generate SQL query for update
if (!isEmpty(newValues)) {
var sql_query = 'UPDATE `' + window.parent.table + '` SET ';
for (key in newValues) {
sql_query += '`' + key + '`=' ;
var value = newValues[key];
// null
if (value == null) {
sql_query += 'NULL, ';
// empty
} else if ($.trim(value) == '') {
sql_query += "'', ";
// other
} else {
// type explicitly identified
if (sqlTypes[key] != null) {
if (sqlTypes[key] == 'bit') {
sql_query += "b'" + value + "', ";
}
// type not explicitly identified
} else {
if (!isNumeric(value)) {
sql_query += "'" + value + "', ";
} else {
sql_query += value + ', ';
}
}
}
}
sql_query = sql_query.substring(0, sql_query.length - 2);
sql_query += ' WHERE ' + PMA_urldecode(data[currentData]['where_clause']);
//Post SQL query to sql.php
$.post('sql.php', {
'token' : window.parent.token,
'db' : window.parent.db,
'ajax_request' : true,
'sql_query' : sql_query,
'inline_edit' : false
}, function(data) {
if (data.success == true) {
$('#sqlqueryresults').html(data.sql_query);
$("#sqlqueryresults").trigger('appendAnchor');
} else {
PMA_ajaxShowMessage(data.error, false);
}
}); //End $.post
}//End database update
$("#dataDisplay").dialog('close');
};
buttonOptions[PMA_messages['strCancel']] = function () {
$(this).dialog('close');
};
$("#dataDisplay").dialog({
autoOpen: false,
title: PMA_messages['strDataPointContent'],
modal: true,
buttons: buttonOptions,
width: $('#dataDisplay').width() + 80,
open: function () {
$(this).find('input[type=checkbox]').css('margin', '0.5em');
}
});
/**
* Attach Ajax event handlers for input fields
* in the dialog. Used to submit the Ajax
* request when the ENTER key is pressed.
*/
$("#dataDisplay").find(':input').live('keydown', function (e) {
if (e.which === 13) { // 13 is the ENTER key
e.preventDefault();
if (typeof buttonOptions[PMA_messages['strSave']] === 'function') {
buttonOptions[PMA_messages['strSave']].call();
}
}
});
/*
* Generate plot using Highcharts
*/
if (data != null) {
$('#zoom_search_form')
.slideToggle()
.hide();
$('#togglesearchformlink')
.text(PMA_messages['strShowSearchCriteria']);
$('#togglesearchformdiv').show();
var selectedRow;
var colorCodes = ['#FF0000', '#00FFFF', '#0000FF', '#0000A0', '#FF0080', '#800080', '#FFFF00', '#00FF00', '#FF00FF'];
var series = new Array();
var xCord = new Array();
var yCord = new Array();
var tempX, tempY;
var it = 0;
var xMax; // xAxis extreme max
var xMin; // xAxis extreme min
var yMax; // yAxis extreme max
var yMin; // yAxis extreme min
// Set the basic plot settings
var currentSettings = {
chart: {
renderTo: 'querychart',
type: 'scatter',
//zoomType: 'xy',
width:$('#resizer').width() - 3,
height:$('#resizer').height() - 20
},
credits: {
enabled: false
},
exporting: { enabled: false },
label: { text: $('#dataLabel').val() },
plotOptions: {
series: {
allowPointSelect: true,
cursor: 'pointer',
showInLegend: false,
dataLabels: {
enabled: false
},
point: {
events: {
click: function() {
var id = this.id;
var fid = 4;
currentData = id;
// Make AJAX request to tbl_zoom_select.php for getting the complete row info
var post_params = {
'ajax_request' : true,
'get_data_row' : true,
'db' : window.parent.db,
'table' : window.parent.table,
'where_clause' : data[id]['where_clause'],
'token' : window.parent.token
};
$.post('tbl_zoom_select.php', post_params, function(data) {
// Row is contained in data.row_info, now fill the displayResultForm with row values
for (var key in data.row_info) {
$field = $('#fieldID_' + fid);
$field_null = $('#fields_null_id_' + fid);
if (data.row_info[key] == null) {
$field_null.prop('checked', true);
$field.val('');
} else {
$field_null.prop('checked', false);
if ($field.prop('multiple')) { // when the column is of type SET
$field.val(data.row_info[key].split(','));
} else {
$field.val(data.row_info[key]);
}
}
fid++;
}
selectedRow = new Object();
selectedRow = data.row_info;
});
$("#dataDisplay").dialog("open");
}
}
}
}
},
tooltip: {
formatter: function() {
return this.point.name;
}
},
title: { text: PMA_messages['strQueryResults'] },
xAxis: {
title: { text: $('#tableid_0').val() },
events: {
setExtremes: function(e) {
this.resetZoom.show();
}
}
},
yAxis: {
min: null,
title: { text: $('#tableid_1').val() },
endOnTick: false,
startOnTick: false,
events: {
setExtremes: function(e) {
this.resetZoom.show();
}
}
}
};
// If data label is not set, do not show tooltips
if (dataLabel == '') {
currentSettings.tooltip.enabled = false;
}
$('#resizer').resizable({
resize: function() {
currentChart.setSize(
this.offsetWidth - 3,
this.offsetHeight - 20,
false
);
}
});
// Classify types as either numeric,time,text
xType = getType(xType);
yType = getType(yType);
//Set the axis type based on the field
currentSettings.xAxis.type = (xType == 'time') ? 'datetime' : 'linear';
currentSettings.yAxis.type = (yType == 'time') ? 'datetime' : 'linear';
// Formulate series data for plot
series[0] = new Object();
series[0].data = new Array();
series[0].marker = {
symbol: 'circle'
};
if (xType != 'text' && yType != 'text') {
$.each(data, function(key, value) {
var xVal = (xType == 'numeric') ? value[xLabel] : getTimeStamp(value[xLabel], $('#types_0').val());
var yVal = (yType == 'numeric') ? value[yLabel] : getTimeStamp(value[yLabel], $('#types_1').val());
series[0].data.push({
name: value[dataLabel],
x: xVal,
y: yVal,
marker: {fillColor: colorCodes[it % 8]},
id: it
});
xCord.push(value[xLabel]);
yCord.push(value[yLabel]);
it++;
});
if (xType == 'numeric') {
currentSettings.xAxis.max = Array.max(xCord) + 6;
currentSettings.xAxis.min = Array.min(xCord) - 6;
} else {
currentSettings.xAxis.labels = { formatter : function() {
return getDate(this.value, $('#types_0').val());
}};
}
if (yType == 'numeric') {
currentSettings.yAxis.max = Array.max(yCord) + 6;
currentSettings.yAxis.min = Array.min(yCord) - 6;
} else {
currentSettings.yAxis.labels = { formatter : function() {
return getDate(this.value, $('#types_1').val());
}};
}
} else if (xType == 'text' && yType != 'text') {
$.each(data, function(key, value) {
xCord.push(value[xLabel]);
yCord.push(value[yLabel]);
});
tempX = getCord(xCord);
$.each(data, function(key, value) {
var yVal = (yType == 'numeric') ? value[yLabel] : getTimeStamp(value[yLabel], $('#types_1').val());
series[0].data.push({
name: value[dataLabel],
x: tempX[0][it],
y: yVal,
marker: {fillColor: colorCodes[it % 8]},
id: it
});
it++;
});
currentSettings.xAxis.labels = {
formatter : function() {
if (tempX[1][this.value] && tempX[1][this.value].length > 10) {
return tempX[1][this.value].substring(0, 10);
} else {
return tempX[1][this.value];
}
}
};
if (yType == 'numeric') {
currentSettings.yAxis.max = Array.max(yCord) + 6;
currentSettings.yAxis.min = Array.min(yCord) - 6;
} else {
currentSettings.yAxis.labels = {
formatter : function() {
return getDate(this.value, $('#types_1').val());
}
};
}
xCord = tempX[2];
} else if (xType != 'text' && yType == 'text') {
$.each(data, function(key, value) {
xCord.push(value[xLabel]);
yCord.push(value[yLabel]);
});
tempY = getCord(yCord);
$.each(data, function(key, value) {
var xVal = (xType == 'numeric') ? value[xLabel] : getTimeStamp(value[xLabel], $('#types_0').val());
series[0].data.push({
name: value[dataLabel],
y: tempY[0][it],
x: xVal,
marker: {fillColor: colorCodes[it % 8]},
id: it
});
it++;
});
if (xType == 'numeric') {
currentSettings.xAxis.max = Array.max(xCord) + 6;
currentSettings.xAxis.min = Array.min(xCord) - 6;
} else {
currentSettings.xAxis.labels = {
formatter : function() {
return getDate(this.value, $('#types_0').val());
}
};
}
currentSettings.yAxis.labels = {
formatter : function() {
if (tempY[1][this.value] && tempY[1][this.value].length > 10) {
return tempY[1][this.value].substring(0, 10);
} else {
return tempY[1][this.value];
}
}
};
yCord = tempY[2];
} else if (xType == 'text' && yType == 'text') {
$.each(data, function(key, value) {
xCord.push(value[xLabel]);
yCord.push(value[yLabel]);
});
tempX = getCord(xCord);
tempY = getCord(yCord);
$.each(data, function(key, value) {
series[0].data.push({
name: value[dataLabel],
x: tempX[0][it],
y: tempY[0][it],
marker: {fillColor: colorCodes[it % 8]},
id: it
});
it++;
});
currentSettings.xAxis.labels = {
formatter : function() {
if (tempX[1][this.value] && tempX[1][this.value].length > 10) {
return tempX[1][this.value].substring(0, 10);
} else {
return tempX[1][this.value];
}
}
};
currentSettings.yAxis.labels = {
formatter : function() {
if (tempY[1][this.value] && tempY[1][this.value].length > 10) {
return tempY[1][this.value].substring(0, 10);
} else {
return tempY[1][this.value];
}
}
};
xCord = tempX[2];
yCord = tempY[2];
}
currentSettings.series = series;
currentChart = PMA_createChart(currentSettings);
xMin = currentChart.xAxis[0].getExtremes().min;
xMax = currentChart.xAxis[0].getExtremes().max;
yMin = currentChart.yAxis[0].getExtremes().min;
yMax = currentChart.yAxis[0].getExtremes().max;
includePan(currentChart); //Enable panning feature
var setZoom = function() {
var newxm = xMin + (xMax - xMin) * (1 - zoomRatio) / 2;
var newxM = xMax - (xMax - xMin) * (1 - zoomRatio) / 2;
var newym = yMin + (yMax - yMin) * (1 - zoomRatio) / 2;
var newyM = yMax - (yMax - yMin) * (1 - zoomRatio) / 2;
currentChart.xAxis[0].setExtremes(newxm, newxM);
currentChart.yAxis[0].setExtremes(newym, newyM);
};
//Enable zoom feature
$("#querychart").mousewheel(function(objEvent, intDelta) {
if (intDelta > 0) {
if (zoomRatio > 0.1) {
zoomRatio = zoomRatio - 0.1;
setZoom();
}
} else if (intDelta < 0) {
zoomRatio = zoomRatio + 0.1;
setZoom();
}
});
//Add reset zoom feature
currentChart.yAxis[0].resetZoom = currentChart.xAxis[0].resetZoom = $('<a href="#">Reset zoom</a>')
.appendTo(currentChart.container)
.css({
position: 'absolute',
top: 10,
right: 20,
display: 'none'
})
.click(function() {
currentChart.xAxis[0].setExtremes(null, null);
currentChart.yAxis[0].setExtremes(null, null);
this.style.display = 'none';
});
scrollToChart();
}
});

515
js/tbl_zoom_plot_jqplot.js Normal file
View File

@ -0,0 +1,515 @@
// todo: change the axis
/* vim: set expandtab sw=4 ts=4 sts=4: */
/**
** @fileoverview JavaScript functions used on tbl_select.php
**
** @requires jQuery
** @requires js/functions.js
**/
/**
** Display Help/Info
**/
function displayHelp() {
var msgbox = PMA_ajaxShowMessage(PMA_messages['strDisplayHelp'], 10000);
msgbox.click(function() {
PMA_ajaxRemoveMessage(msgbox);
});
}
/**
** Extend the array object for max function
** @param array
**/
Array.max = function (array) {
return Math.max.apply( Math, array );
};
/**
** Extend the array object for min function
** @param array
**/
Array.min = function (array) {
return Math.min.apply( Math, array );
};
/**
** Checks if a string contains only numeric value
** @param n: String (to be checked)
**/
function isNumeric(n) {
return !isNaN(parseFloat(n)) && isFinite(n);
}
/**
** Checks if an object is empty
** @param n: Object (to be checked)
**/
function isEmpty(obj) {
var name;
for (name in obj) {
return false;
}
return true;
}
/**
** Converts a date/time into timestamp
** @param val String Date
** @param type Sring Field type(datetime/timestamp/time/date)
**/
function getTimeStamp(val, type) {
if (type.toString().search(/datetime/i) != -1 || type.toString().search(/timestamp/i) != -1) {
return getDateFromFormat(val, 'yyyy-MM-dd HH:mm:ss', val);
}
else if (type.toString().search(/time/i) != -1) {
return getDateFromFormat('1970-01-01 ' + val, 'yyyy-MM-dd HH:mm:ss');
}
else if (type.toString().search(/date/i) != -1) {
return getDateFromFormat(val, 'yyyy-MM-dd');
}
}
/**
** Classifies the field type into numeric,timeseries or text
** @param field: field type (as in database structure)
**/
function getType(field) {
if (field.toString().search(/int/i) != -1 || field.toString().search(/decimal/i) != -1
|| field.toString().search(/year/i) != -1) {
return 'numeric';
} else if (field.toString().search(/time/i) != -1 || field.toString().search(/date/i) != -1) {
return 'time';
} else {
return 'text';
}
}
/**
** Converts a categorical array into numeric array
** @param array categorical values array
**/
function getCord(arr) {
var newCord = new Array();
var original = $.extend(true, [], arr);
var arr = jQuery.unique(arr).sort();
$.each(original, function(index, value) {
newCord.push(jQuery.inArray(value, arr));
});
return [newCord, arr, original];
}
/**
** Scrolls the view to the display section
**/
function scrollToChart() {
var x = $('#dataDisplay').offset().top - 100; // 100 provides buffer in viewport
$('html,body').animate({scrollTop: x}, 500);
}
$(document).ready(function() {
var cursorMode = ($("input[name='mode']:checked").val() == 'edit') ? 'crosshair' : 'pointer';
var currentChart = null;
var searchedDataKey = null;
var xLabel = $('#tableid_0').val();
var yLabel = $('#tableid_1').val();
var xType = $('#types_0').val();
var yType = $('#types_1').val();
var dataLabel = $('#dataLabel').val();
var lastX;
var lastY;
var zoomRatio = 1;
// Get query result
var searchedData = jQuery.parseJSON($('#querydata').html());
/**
** Input form submit on field change
**/
$('#tableid_0').change(function() {
$('#zoom_search_form').submit();
});
$('#tableid_1').change(function() {
$('#zoom_search_form').submit();
});
$('#tableid_2').change(function() {
$('#zoom_search_form').submit();
});
$('#tableid_3').change(function() {
$('#zoom_search_form').submit();
});
/**
* Input form validation
**/
$('#inputFormSubmitId').click(function() {
if ($('#tableid_0').get(0).selectedIndex == 0 || $('#tableid_1').get(0).selectedIndex == 0) {
PMA_ajaxShowMessage(PMA_messages['strInputNull']);
} else if (xLabel == yLabel) {
PMA_ajaxShowMessage(PMA_messages['strSameInputs']);
}
});
/**
** Prepare a div containing a link, otherwise it's incorrectly displayed
** after a couple of clicks
**/
$('<div id="togglesearchformdiv"><a id="togglesearchformlink"></a></div>')
.insertAfter('#zoom_search_form')
// don't show it until we have results on-screen
.hide();
$('#togglesearchformlink')
.html(PMA_messages['strShowSearchCriteria'])
.bind('click', function() {
var $link = $(this);
$('#zoom_search_form').slideToggle();
if ($link.text() == PMA_messages['strHideSearchCriteria']) {
$link.text(PMA_messages['strShowSearchCriteria']);
} else {
$link.text(PMA_messages['strHideSearchCriteria']);
}
// avoid default click action
return false;
});
/**
** Set dialog properties for the data display form
**/
var buttonOptions = {};
/*
* Handle saving of a row in the editor
*/
buttonOptions[PMA_messages['strSave']] = function () {
//Find changed values by comparing form values with selectedRow Object
var newValues = new Object();//Stores the values changed from original
var sqlTypes = new Object();
var it = 4;
var xChange = false;
var yChange = false;
for (key in selectedRow) {
var oldVal = selectedRow[key];
var newVal = ($('#fields_null_id_' + it).attr('checked')) ? null : $('#fieldID_' + it).val();
if (newVal instanceof Array) { // when the column is of type SET
newVal = $('#fieldID_' + it).map(function(){
return $(this).val();
}).get().join(",");
}
if (oldVal != newVal) {
selectedRow[key] = newVal;
newValues[key] = newVal;
if (key == xLabel) {
xChange = true;
searchedData[searchedDataKey][xLabel] = newVal;
} else if (key == yLabel) {
yChange = true;
searchedData[searchedDataKey][yLabel] = newVal;
}
}
var $input = $('#fieldID_' + it);
if ($input.hasClass('bit')) {
sqlTypes[key] = 'bit';
}
it++;
} //End data update
//Update the chart series and replot
if (xChange || yChange) {
//Logic similar to plot generation, replot only if xAxis changes or yAxis changes.
//Code includes a lot of checks so as to replot only when necessary
if (xChange) {
xCord[searchedDataKey] = selectedRow[xLabel];
// [searchedDataKey][0] contains the x value
if (xType == 'numeric') {
series[0][searchedDataKey][0] = selectedRow[xLabel];
} else if (xType == 'time') {
series[0][searchedDataKey][0] =
getTimeStamp(selectedRow[xLabel], $('#types_0').val());
} else {
// todo: text values
}
currentChart.series[0].data = series[0];
// todo: axis changing
currentChart.replot();
}
if (yChange) {
yCord[searchedDataKey] = selectedRow[yLabel];
// [searchedDataKey][1] contains the y value
if (yType == 'numeric') {
series[0][searchedDataKey][1] = selectedRow[yLabel];
} else if (yType == 'time') {
series[0][searchedDataKey][1] =
getTimeStamp(selectedRow[yLabel], $('#types_1').val());
} else {
// todo: text values
}
currentChart.series[0].data = series[0];
// todo: axis changing
currentChart.replot();
}
} //End plot update
//Generate SQL query for update
if (!isEmpty(newValues)) {
var sql_query = 'UPDATE `' + window.parent.table + '` SET ';
for (key in newValues) {
sql_query += '`' + key + '`=' ;
var value = newValues[key];
// null
if (value == null) {
sql_query += 'NULL, ';
// empty
} else if ($.trim(value) == '') {
sql_query += "'', ";
// other
} else {
// type explicitly identified
if (sqlTypes[key] != null) {
if (sqlTypes[key] == 'bit') {
sql_query += "b'" + value + "', ";
}
// type not explicitly identified
} else {
if (!isNumeric(value)) {
sql_query += "'" + value + "', ";
} else {
sql_query += value + ', ';
}
}
}
}
sql_query = sql_query.substring(0, sql_query.length - 2);
sql_query += ' WHERE ' + PMA_urldecode(searchedData[searchedDataKey]['where_clause']);
//Post SQL query to sql.php
$.post('sql.php', {
'token' : window.parent.token,
'db' : window.parent.db,
'ajax_request' : true,
'sql_query' : sql_query,
'inline_edit' : false
}, function(data) {
if (data.success == true) {
$('#sqlqueryresults').html(data.sql_query);
$("#sqlqueryresults").trigger('appendAnchor');
} else {
PMA_ajaxShowMessage(data.error, false);
}
}); //End $.post
}//End database update
$("#dataDisplay").dialog('close');
};
buttonOptions[PMA_messages['strCancel']] = function () {
$(this).dialog('close');
};
$("#dataDisplay").dialog({
autoOpen: false,
title: PMA_messages['strDataPointContent'],
modal: true,
buttons: buttonOptions,
width: $('#dataDisplay').width() + 80,
open: function () {
$(this).find('input[type=checkbox]').css('margin', '0.5em');
}
});
/**
* Attach Ajax event handlers for input fields
* in the dialog. Used to submit the Ajax
* request when the ENTER key is pressed.
*/
$("#dataDisplay").find(':input').live('keydown', function (e) {
if (e.which === 13) { // 13 is the ENTER key
e.preventDefault();
if (typeof buttonOptions[PMA_messages['strSave']] === 'function') {
buttonOptions[PMA_messages['strSave']].call();
}
}
});
/*
* Generate plot using jqplot
*/
if (searchedData != null) {
$('#zoom_search_form')
.slideToggle()
.hide();
$('#togglesearchformlink')
.text(PMA_messages['strShowSearchCriteria']);
$('#togglesearchformdiv').show();
var selectedRow;
var colorCodes = ['#FF0000', '#00FFFF', '#0000FF', '#0000A0', '#FF0080', '#800080', '#FFFF00', '#00FF00', '#FF00FF'];
var series = new Array();
var xCord = new Array();
var yCord = new Array();
var tempX, tempY;
var it = 0;
var xMax; // xAxis extreme max
var xMin; // xAxis extreme min
var yMax; // yAxis extreme max
var yMin; // yAxis extreme min
var options = {
series: [
// for a scatter plot
{ showLine: false }
],
axes: {
xaxis: {
label: $('#tableid_0').val(),
labelRenderer: $.jqplot.CanvasAxisLabelRenderer
},
yaxis: {
label: $('#tableid_1').val(),
labelRenderer: $.jqplot.CanvasAxisLabelRenderer
}
},
highlighter: {
show: true,
tooltipAxes: 'y',
yvalues: 2,
// hide the first y value
formatString: '<span class="hide">%s</span>%s'
},
cursor: {
show: true,
zoom: true,
showTooltip: false
}
}
// If data label is not set, do not show tooltips
if (dataLabel == '') {
options.highlighter.show = false;
}
// Classify types as either numeric,time,text
xType = getType(xType);
yType = getType(yType);
// could have multiple series but we'll have just one
series[0] = new Array();
if (xType == 'time') {
originalXType = $('#types_0').val();
if (originalXType == 'date') {
format = '%Y-%m-%d';
}
// todo: does not seem to work
//else if (originalXType == 'time') {
// format = '%H:%M';
//} else {
// format = '%Y-%m-%d %H:%M';
//}
$.extend(options.axes.xaxis, {
renderer:$.jqplot.DateAxisRenderer,
tickOptions: {
formatString: format
}
});
}
if (yType == 'time') {
originalYType = $('#types_1').val();
if (originalYType == 'date') {
format = '%Y-%m-%d';
}
$.extend(options.axes.yaxis, {
renderer:$.jqplot.DateAxisRenderer,
tickOptions: {
formatString: format
}
});
}
$.each(searchedData, function(key, value) {
if (xType == 'numeric') {
var xVal = parseFloat(value[xLabel]);
}
if (xType == 'time') {
var xVal = getTimeStamp(value[xLabel], originalXType);
}
if (yType == 'numeric') {
var yVal = parseFloat(value[yLabel]);
}
if (yType == 'time') {
var yVal = getTimeStamp(value[yLabel], originalYType);
}
series[0].push([
xVal,
yVal,
// extra Y values
value[dataLabel], // for highlighter
// (may set an undefined value)
value['where_clause'], // for click on point
key // key from searchedData
]);
});
// under IE 8, the initial display is mangled; after a manual
// resizing, it's ok
// under IE 9, everything is fine
currentChart = $.jqplot('querychart', series, options);
$('button.button-reset').click(function(event) {
event.preventDefault();
currentChart.resetZoom();
});
$('div#resizer').resizable();
$('div#resizer').bind('resizestop', function(event, ui) {
// make room so that the handle will still appear
$('div#querychart').height($('div#resizer').height() * 0.96);
$('div#querychart').width($('div#resizer').width() * 0.96);
currentChart.replot( {resetAxes: true})
});
$('div#querychart').bind('jqplotDataClick',
function(event, seriesIndex, pointIndex, data) {
searchedDataKey = data[4]; // key from searchedData (global)
var field_id = 4;
var post_params = {
'ajax_request' : true,
'get_data_row' : true,
'db' : window.parent.db,
'table' : window.parent.table,
'where_clause' : data[3],
'token' : window.parent.token
};
$.post('tbl_zoom_select.php', post_params, function(data) {
// Row is contained in data.row_info,
// now fill the displayResultForm with row values
for (key in data.row_info) {
$field = $('#fieldID_' + field_id);
$field_null = $('#fields_null_id_' + field_id);
if (data.row_info[key] == null) {
$field_null.attr('checked', true);
$field.val('');
} else {
$field_null.attr('checked', false);
if ($field.attr('multiple')) { // when the column is of type SET
$field.val(data.row_info[key].split(','));
} else {
$field.val(data.row_info[key]);
}
}
field_id++;
}
selectedRow = new Object();
selectedRow = data.row_info;
});
$("#dataDisplay").dialog("open");
}
);
}
});

View File

@ -74,7 +74,8 @@ class PMA_Theme
'gis',
'navigation',
'pmd',
'rte'
'rte',
'jqplot'
);
/**

View File

@ -443,6 +443,9 @@ if (PMA_USR_BROWSER_AGENT == 'IE' && PMA_USR_BROWSER_VER < 9) {
$GLOBALS['js_include'][] = 'canvg/flashcanvas.js';
}
$GLOBALS['js_include'][] = 'canvg/canvg.js';
// for profiling chart
$GLOBALS['js_include'][] = 'jqplot/jquery.jqplot.js';
$GLOBALS['js_include'][] = 'jqplot/plugins/jqplot.pieRenderer.js';
/**
* flush status variables if requested

View File

@ -55,14 +55,12 @@ if (isset($_REQUEST['printview'])) {
}
if (isset($_SESSION['profiling'])) {
$GLOBALS['js_include'][] = 'highcharts/highcharts.js';
/* Files required for chart exporting */
$GLOBALS['js_include'][] = 'highcharts/exporting.js';
/* < IE 9 doesn't support canvas natively */
if (PMA_USR_BROWSER_AGENT == 'IE' && PMA_USR_BROWSER_VER < 9) {
$GLOBALS['js_include'][] = 'canvg/flashcanvas.js';
}
$GLOBALS['js_include'][] = 'canvg/canvg.js';
$GLOBALS['js_include'][] = 'jqplot/jquery.jqplot.js';
$GLOBALS['js_include'][] = 'jqplot/plugins/jqplot.pieRenderer.js';
}
/**
@ -1023,7 +1021,6 @@ $(makeProfilingChart);
echo '</div>';
//require_once 'libraries/chart.lib.php';
echo '<div id="profilingchart" style="display:none;">';
//PMA_chart_profiling($profiling_results);
echo json_encode($chart_json);
echo '</div>';
echo '</fieldset>' . "\n";

View File

@ -20,14 +20,21 @@ require_once './libraries/tbl_info.inc.php';
$GLOBALS['js_include'][] = 'makegrid.js';
$GLOBALS['js_include'][] = 'sql.js';
$GLOBALS['js_include'][] = 'functions.js';
$GLOBALS['js_include'][] = 'tbl_zoom_plot.js';
$GLOBALS['js_include'][] = 'date.js';
$GLOBALS['js_include'][] = 'jquery/jquery.mousewheel.js';
$GLOBALS['js_include'][] = 'highcharts/highcharts.js';
/* Files required for chart exporting */
$GLOBALS['js_include'][] = 'highcharts/exporting.js';
/* < IE 9 doesn't support canvas natively */
if (PMA_USR_BROWSER_AGENT == 'IE' && PMA_USR_BROWSER_VER < 9) {
$GLOBALS['js_include'][] = 'canvg/flashcanvas.js';
}
$GLOBALS['js_include'][] = 'jqplot/jquery.jqplot.js';
$GLOBALS['js_include'][] = 'jqplot/plugins/jqplot.canvasTextRenderer.js';
$GLOBALS['js_include'][] = 'jqplot/plugins/jqplot.canvasAxisLabelRenderer.js';
$GLOBALS['js_include'][] = 'jqplot/plugins/jqplot.dateAxisRenderer.js';
$GLOBALS['js_include'][] = 'jqplot/plugins/jqplot.highlighter.js';
$GLOBALS['js_include'][] = 'jqplot/plugins/jqplot.cursor.js';
$GLOBALS['js_include'][] = 'canvg/canvg.js';
$GLOBALS['js_include'][] = 'jquery/timepicker.js';
$GLOBALS['js_include'][] = 'tbl_zoom_plot_jqplot.js';
/**
* Sets globals from $_POST
@ -409,14 +416,15 @@ if (isset($zoom_submit)
//JSON encode the data(query result)
if (isset($zoom_submit) && ! empty($data)) {
?>
<div id='resizer' style="width:600px;height:400px">
<div id="resizer">
<center><a href="#" onclick="displayHelp();"><?php echo __('How to use'); ?></a></center>
<div id="querydata" style="display:none">
<?php
echo json_encode($data);
?>
</div>
<div id="querychart" style="float:right"></div>
<div id="querychart"></div>
<button class="button-reset"><?php echo __('Reset zoom'); ?></button>
</div>
<?php
}

View File

@ -627,6 +627,18 @@ td.disabled {
white-space: nowrap;
}
/**
* zoom search
*/
div#resizer {
width: 600px;
height: 400px;
}
div#querychart {
float: left;
width: 600px;
}
/**
* login form
*/
@ -2379,3 +2391,265 @@ body .ui-widget {
.ui-dialog fieldset legend a {
color: #0000FF;
}
/* 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: #222222;
font-family: "Trebuchet MS", Arial, Helvetica, sans-serif;
font-size: 1em;
/* height: 300px;
width: 400px;*/
}
/*rules applied to all axes*/
.jqplot-axis {
font-size: 0.75em;
}
.jqplot-xaxis {
margin-top: 10px;
}
.jqplot-x2axis {
margin-bottom: 10px;
}
.jqplot-yaxis {
margin-right: 10px;
}
.jqplot-y2axis, .jqplot-y3axis, .jqplot-y4axis, .jqplot-y5axis, .jqplot-y6axis, .jqplot-y7axis, .jqplot-y8axis, .jqplot-y9axis, .jqplot-yMidAxis {
margin-left: 10px;
margin-right: 10px;
}
/*rules applied to all axis tick divs*/
.jqplot-axis-tick, .jqplot-xaxis-tick, .jqplot-yaxis-tick, .jqplot-x2axis-tick, .jqplot-y2axis-tick, .jqplot-y3axis-tick, .jqplot-y4axis-tick, .jqplot-y5axis-tick, .jqplot-y6axis-tick, .jqplot-y7axis-tick, .jqplot-y8axis-tick, .jqplot-y9axis-tick, .jqplot-yMidAxis-tick {
position: absolute;
white-space: pre;
}
.jqplot-xaxis-tick {
top: 0px;
/* initial position untill tick is drawn in proper place */
left: 15px;
/* padding-top: 10px;*/
vertical-align: top;
}
.jqplot-x2axis-tick {
bottom: 0px;
/* initial position untill tick is drawn in proper place */
left: 15px;
/* padding-bottom: 10px;*/
vertical-align: bottom;
}
.jqplot-yaxis-tick {
right: 0px;
/* initial position untill tick is drawn in proper place */
top: 15px;
/* padding-right: 10px;*/
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 */
top: 15px;
/* padding-left: 10px;*/
/* padding-right: 15px;*/
text-align: left;
}
.jqplot-yMidAxis-tick {
text-align: center;
white-space: nowrap;
}
.jqplot-xaxis-label {
margin-top: 10px;
font-size: 11pt;
position: absolute;
}
.jqplot-x2axis-label {
margin-bottom: 10px;
font-size: 11pt;
position: absolute;
}
.jqplot-yaxis-label {
margin-right: 10px;
/* text-align: center;*/
font-size: 11pt;
position: absolute;
}
.jqplot-yMidAxis-label {
font-size: 11pt;
position: absolute;
}
.jqplot-y2axis-label, .jqplot-y3axis-label, .jqplot-y4axis-label, .jqplot-y5axis-label, .jqplot-y6axis-label, .jqplot-y7axis-label, .jqplot-y8axis-label, .jqplot-y9axis-label {
/* text-align: center;*/
font-size: 11pt;
margin-left: 10px;
position: absolute;
}
.jqplot-meterGauge-tick {
font-size: 0.75em;
color: #999999;
}
.jqplot-meterGauge-label {
font-size: 1em;
color: #999999;
}
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;
position: absolute;
font-size: 0.75em;
}
td.jqplot-table-legend {
vertical-align:middle;
}
/*
These rules could be used instead of assigning
element styles and relying on js object properties.
*/
/*
td.jqplot-table-legend-swatch {
padding-top: 0.5em;
text-align: center;
}
tr.jqplot-table-legend:first td.jqplot-table-legend-swatch {
padding-top: 0px;
}
*/
td.jqplot-seriesToggle:hover, td.jqplot-seriesToggle:active {
cursor: pointer;
}
.jqplot-table-legend .jqplot-series-hidden {
text-decoration: line-through;
}
div.jqplot-table-legend-swatch-outline {
border: 1px solid #cccccc;
padding:1px;
}
div.jqplot-table-legend-swatch {
width:0px;
height:0px;
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;
border-right-style: solid;
}
.jqplot-title {
top: 0px;
left: 0px;
padding-bottom: 0.5em;
font-size: 1.2em;
}
table.jqplot-cursor-tooltip {
border: 1px solid #cccccc;
font-size: 0.75em;
}
.jqplot-cursor-tooltip {
border: 1px solid #cccccc;
font-size: 0.75em;
white-space: nowrap;
background: rgba(208,208,208,0.5);
padding: 1px;
}
.jqplot-highlighter-tooltip, .jqplot-canvasOverlay-tooltip {
border: 1px solid #cccccc;
font-size: 0.75em;
white-space: nowrap;
background: rgba(208,208,208,0.5);
padding: 1px;
}
.jqplot-point-label {
font-size: 0.75em;
z-index: 2;
}
td.jqplot-cursor-legend-swatch {
vertical-align: middle;
text-align: center;
}
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);
}

View File

@ -0,0 +1,277 @@
<?php
/* vim: set expandtab sw=4 ts=4 sts=4: */
/**
* Styles for jqplot
* for the pmahomme theme
*
* @package PhpMyAdmin-theme
* @subpackage PMAHomme
*/
// unplanned execution path
if (! defined('PMA_MINIMUM_COMMON') && ! defined('TESTSUITE')) {
exit();
}
?>
/* 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: #222222;
font-family: "Trebuchet MS", Arial, Helvetica, sans-serif;
font-size: 1em;
/* height: 300px;
width: 590px;*/
}
/*rules applied to all axes*/
.jqplot-axis {
font-size: 0.75em;
}
.jqplot-xaxis {
margin-top: 10px;
}
.jqplot-x2axis {
margin-bottom: 10px;
}
.jqplot-yaxis {
margin-right: 10px;
}
.jqplot-y2axis, .jqplot-y3axis, .jqplot-y4axis, .jqplot-y5axis, .jqplot-y6axis, .jqplot-y7axis, .jqplot-y8axis, .jqplot-y9axis, .jqplot-yMidAxis {
margin-left: 10px;
margin-right: 10px;
}
/*rules applied to all axis tick divs*/
.jqplot-axis-tick, .jqplot-xaxis-tick, .jqplot-yaxis-tick, .jqplot-x2axis-tick, .jqplot-y2axis-tick, .jqplot-y3axis-tick, .jqplot-y4axis-tick, .jqplot-y5axis-tick, .jqplot-y6axis-tick, .jqplot-y7axis-tick, .jqplot-y8axis-tick, .jqplot-y9axis-tick, .jqplot-yMidAxis-tick {
position: absolute;
white-space: pre;
}
.jqplot-xaxis-tick {
top: 0px;
/* initial position untill tick is drawn in proper place */
left: 15px;
/* padding-top: 10px;*/
vertical-align: top;
}
.jqplot-x2axis-tick {
bottom: 0px;
/* initial position untill tick is drawn in proper place */
left: 15px;
/* padding-bottom: 10px;*/
vertical-align: bottom;
}
.jqplot-yaxis-tick {
right: 0px;
/* initial position untill tick is drawn in proper place */
top: 15px;
/* padding-right: 10px;*/
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 */
top: 15px;
/* padding-left: 10px;*/
/* padding-right: 15px;*/
text-align: left;
}
.jqplot-yMidAxis-tick {
text-align: center;
white-space: nowrap;
}
.jqplot-xaxis-label {
margin-top: 10px;
font-size: 11pt;
position: absolute;
}
.jqplot-x2axis-label {
margin-bottom: 10px;
font-size: 11pt;
position: absolute;
}
.jqplot-yaxis-label {
margin-right: 10px;
/* text-align: center;*/
font-size: 11pt;
position: absolute;
}
.jqplot-yMidAxis-label {
font-size: 11pt;
position: absolute;
}
.jqplot-y2axis-label, .jqplot-y3axis-label, .jqplot-y4axis-label, .jqplot-y5axis-label, .jqplot-y6axis-label, .jqplot-y7axis-label, .jqplot-y8axis-label, .jqplot-y9axis-label {
/* text-align: center;*/
font-size: 11pt;
margin-left: 10px;
position: absolute;
}
.jqplot-meterGauge-tick {
font-size: 0.75em;
color: #999999;
}
.jqplot-meterGauge-label {
font-size: 1em;
color: #999999;
}
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;
position: absolute;
font-size: 0.75em;
}
td.jqplot-table-legend {
vertical-align:middle;
}
/*
These rules could be used instead of assigning
element styles and relying on js object properties.
*/
/*
td.jqplot-table-legend-swatch {
padding-top: 0.5em;
text-align: center;
}
tr.jqplot-table-legend:first td.jqplot-table-legend-swatch {
padding-top: 0px;
}
*/
td.jqplot-seriesToggle:hover, td.jqplot-seriesToggle:active {
cursor: pointer;
}
.jqplot-table-legend .jqplot-series-hidden {
text-decoration: line-through;
}
div.jqplot-table-legend-swatch-outline {
border: 1px solid #cccccc;
padding:1px;
}
div.jqplot-table-legend-swatch {
width:0px;
height:0px;
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;
border-right-style: solid;
}
.jqplot-title {
top: 0px;
left: 0px;
padding-bottom: 0.5em;
font-size: 1.2em;
}
table.jqplot-cursor-tooltip {
border: 1px solid #cccccc;
font-size: 0.75em;
}
.jqplot-cursor-tooltip {
border: 1px solid #cccccc;
font-size: 0.75em;
white-space: nowrap;
background: rgba(208,208,208,0.5);
padding: 1px;
}
.jqplot-highlighter-tooltip, .jqplot-canvasOverlay-tooltip {
border: 1px solid #cccccc;
font-size: 0.75em;
white-space: nowrap;
background: rgba(208,208,208,0.5);
padding: 1px;
}
.jqplot-point-label {
font-size: 0.75em;
z-index: 2;
}
td.jqplot-cursor-legend-swatch {
vertical-align: middle;
text-align: center;
}
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);
}