Blame | Letzte Änderung | Log anzeigen | RSS feed
/*** jqPlot* Pure JavaScript plotting plugin using jQuery** Version: 1.0.8* Revision: 1250** Copyright (c) 2009-2013 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.MekkoAxisRenderer// An axis renderer for a Mekko chart.// Should be used with a Mekko chart where the mekkoRenderer is used on the series.// Displays the Y axis as a range from 0 to 1 (0 to 100%) and the x axis with a tick// for each series scaled to the sum of all the y values.$.jqplot.MekkoAxisRenderer = function() {};// called with scope of axis object.$.jqplot.MekkoAxisRenderer.prototype.init = function(options){// prop: tickMode// How to space the ticks on the axis.// 'bar' will place a tick at the width of each bar.// This is the default for the x axis.// 'even' will place ticks at even intervals. This is// the default for x2 axis and y axis. y axis cannot be changed.this.tickMode;// prop: barLabelRenderer// renderer to use to draw labels under each bar.this.barLabelRenderer = $.jqplot.AxisLabelRenderer;// prop: barLabels// array of labels to put under each bar.this.barLabels = this.barLabels || [];// prop: barLabelOptions// options object to pass to the bar label renderer.this.barLabelOptions = {};this.tickOptions = $.extend(true, {showGridline:false}, this.tickOptions);this._barLabels = [];$.extend(true, this, options);if (this.name == 'yaxis') {this.tickOptions.formatString = this.tickOptions.formatString || "%d\%";}var db = this._dataBounds;db.min = 0;// for y axes, scale always go from 0 to 1 (0 to 100%)if (this.name == 'yaxis' || this.name == 'y2axis') {db.max = 100;this.tickMode = 'even';}// For x axes, scale goes from 0 to sum of all y values.else if (this.name == 'xaxis'){this.tickMode = (this.tickMode == null) ? 'bar' : this.tickMode;for (var i=0; i<this._series.length; i++) {db.max += this._series[i]._sumy;}}else if (this.name == 'x2axis'){this.tickMode = (this.tickMode == null) ? 'even' : this.tickMode;for (var i=0; i<this._series.length; i++) {db.max += this._series[i]._sumy;}}};// called with scope of axis$.jqplot.MekkoAxisRenderer.prototype.draw = function(ctx, plot) {if (this.show) {// populate the axis label and value properties.// createTicks is a method on the renderer, but// call it within the scope of the axis.this.renderer.createTicks.call(this);// fill a div with axes labels in the right direction.// Need to pregenerate each axis to get its bounds and// position it and the labels correctly on the plot.var dim=0;var temp;var elem = document.createElement('div');this._elem = $(elem);this._elem.addClass('jqplot-axis jqplot-'+this.name);this._elem.css('position', 'absolute');elem = null;if (this.name == 'xaxis' || this.name == 'x2axis') {this._elem.width(this._plotDimensions.width);}else {this._elem.height(this._plotDimensions.height);}// draw the axis label// create a _label object.this.labelOptions.axis = this.name;this._label = new this.labelRenderer(this.labelOptions);if (this._label.show) {this._elem.append(this._label.draw(ctx));}var t, tick, elem;if (this.showTicks) {t = this._ticks;for (var i=0; i<t.length; i++) {tick = t[i];if (tick.showLabel && (!tick.isMinorTick || this.showMinorTicks)) {this._elem.append(tick.draw(ctx));}}}// draw the series labelsfor (i=0; i<this.barLabels.length; i++) {this.barLabelOptions.axis = this.name;this.barLabelOptions.label = this.barLabels[i];this._barLabels.push(new this.barLabelRenderer(this.barLabelOptions));if (this.tickMode != 'bar') {this._barLabels[i].show = false;}if (this._barLabels[i].show) {var elem = this._barLabels[i].draw(ctx, plot);elem.removeClass('jqplot-'+this.name+'-label');elem.addClass('jqplot-'+this.name+'-tick');elem.addClass('jqplot-mekko-barLabel');elem.appendTo(this._elem);elem = null;}}}return this._elem;};// called with scope of an axis$.jqplot.MekkoAxisRenderer.prototype.reset = function() {this.min = this._min;this.max = this._max;this.tickInterval = this._tickInterval;this.numberTicks = this._numberTicks;// this._ticks = this.__ticks;};// called with scope of axis$.jqplot.MekkoAxisRenderer.prototype.set = function() {var dim = 0;var temp;var w = 0;var h = 0;var lshow = (this._label == null) ? false : this._label.show;if (this.show && this.showTicks) {var t = this._ticks;for (var i=0; i<t.length; i++) {var tick = t[i];if (tick.showLabel && (!tick.isMinorTick || this.showMinorTicks)) {if (this.name == 'xaxis' || this.name == 'x2axis') {temp = tick._elem.outerHeight(true);}else {temp = tick._elem.outerWidth(true);}if (temp > dim) {dim = temp;}}}if (lshow) {w = this._label._elem.outerWidth(true);h = this._label._elem.outerHeight(true);}if (this.name == 'xaxis') {dim = dim + h;this._elem.css({'height':dim+'px', left:'0px', bottom:'0px'});}else if (this.name == 'x2axis') {dim = dim + h;this._elem.css({'height':dim+'px', left:'0px', top:'0px'});}else if (this.name == 'yaxis') {dim = dim + w;this._elem.css({'width':dim+'px', left:'0px', top:'0px'});if (lshow && this._label.constructor == $.jqplot.AxisLabelRenderer) {this._label._elem.css('width', w+'px');}}else {dim = dim + w;this._elem.css({'width':dim+'px', right:'0px', top:'0px'});if (lshow && this._label.constructor == $.jqplot.AxisLabelRenderer) {this._label._elem.css('width', w+'px');}}}};// called with scope of axis$.jqplot.MekkoAxisRenderer.prototype.createTicks = function() {// we're are operating on an axis herevar ticks = this._ticks;var userTicks = this.ticks;var name = this.name;// databounds were set on axis initialization.var db = this._dataBounds;var dim, interval;var min, max;var pos1, pos2;var t, tt, i, j;// if we already have ticks, use them.// ticks must be in order of increasing value.if (userTicks.length) {// ticks could be 1D or 2D array of [val, val, ,,,] or [[val, label], [val, label], ...] or mixedfor (i=0; i<userTicks.length; i++){var ut = userTicks[i];var t = new this.tickRenderer(this.tickOptions);if (ut.constructor == Array) {t.value = ut[0];t.label = ut[1];if (!this.showTicks) {t.showLabel = false;t.showMark = false;}else if (!this.showTickMarks) {t.showMark = false;}t.setTick(ut[0], this.name);this._ticks.push(t);}else {t.value = ut;if (!this.showTicks) {t.showLabel = false;t.showMark = false;}else if (!this.showTickMarks) {t.showMark = false;}t.setTick(ut, 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.tickInterval = (this.max - this.min) / (this.numberTicks - 1);}// we don't have any ticks yet, let's make some!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;}min = (this.min != null) ? this.min : db.min;max = (this.max != null) ? this.max : db.max;// if min and max are same, space them out a bit.+if (min == max) {var adj = 0.05;if (min > 0) {adj = Math.max(Math.log(min)/Math.LN10, 0.05);}min -= adj;max += adj;}var range = max - min;var rmin, rmax;var temp, prev, curr;var ynumticks = [3,5,6,11,21];// yaxis divide ticks in nice intervals from 0 to 1.if (this.name == 'yaxis' || this.name == 'y2axis') {this.min = 0;this.max = 100;// user didn't specify number of ticks.if (!this.numberTicks){if (this.tickInterval) {this.numberTicks = 3 + Math.ceil(range / this.tickInterval);}else {temp = 2 + Math.ceil((dim-(this.tickSpacing-1))/this.tickSpacing);for (i=0; i<ynumticks.length; i++) {curr = temp/ynumticks[i];if (curr == 1) {this.numberTicks = ynumticks[i];break;}else if (curr > 1) {prev = curr;continue;}else if (curr < 1) {// was prev or is curr closer to one?if (Math.abs(prev - 1) < Math.abs(curr - 1)) {this.numberTicks = ynumticks[i-1];break;}else {this.numberTicks = ynumticks[i];break;}}else if (i == ynumticks.length -1) {this.numberTicks = ynumticks[i];}}this.tickInterval = range / (this.numberTicks - 1);}}// user did specify number of ticks.else {this.tickInterval = range / (this.numberTicks - 1);}for (var i=0; i<this.numberTicks; i++){tt = this.min + i * this.tickInterval;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);}}// for x axes, have number ot ticks equal to number of series and ticks placed// at sum of y values for each series.else if (this.tickMode == 'bar') {this.min = 0;this.numberTicks = this._series.length + 1;t = new this.tickRenderer(this.tickOptions);if (!this.showTicks) {t.showLabel = false;t.showMark = false;}else if (!this.showTickMarks) {t.showMark = false;}t.setTick(0, this.name);this._ticks.push(t);temp = 0;for (i=1; i<this.numberTicks; i++){temp += this._series[i-1]._sumy;t = new this.tickRenderer(this.tickOptions);if (!this.showTicks) {t.showLabel = false;t.showMark = false;}else if (!this.showTickMarks) {t.showMark = false;}t.setTick(temp, this.name);this._ticks.push(t);}this.max = this.max || temp;// if user specified a max and it is greater than sum, add a tickif (this.max > temp) {t = new this.tickRenderer(this.tickOptions);if (!this.showTicks) {t.showLabel = false;t.showMark = false;}else if (!this.showTickMarks) {t.showMark = false;}t.setTick(this.max, this.name);this._ticks.push(t);}}else if (this.tickMode == 'even') {this.min = 0;this.max = this.max || db.max;// get a desired number of ticksvar nt = 2 + Math.ceil((dim-(this.tickSpacing-1))/this.tickSpacing);range = this.max - this.min;this.numberTicks = nt;this.tickInterval = range / (this.numberTicks - 1);for (i=0; i<this.numberTicks; i++){tt = this.min + i * this.tickInterval;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);}}}};// called with scope of axis$.jqplot.MekkoAxisRenderer.prototype.pack = function(pos, offsets) {var ticks = this._ticks;var max = this.max;var min = this.min;var offmax = offsets.max;var offmin = offsets.min;var lshow = (this._label == null) ? false : this._label.show;for (var p in pos) {this._elem.css(p, pos[p]);}this._offsets = offsets;// pixellength will be + for x axes and - for y axes becasue pixels always measured from top left.var pixellength = offmax - offmin;var unitlength = max - min;// point to unit and unit to point conversions references to Plot DOM element top left corner.this.p2u = function(p){return (p - offmin) * unitlength / pixellength + min;};this.u2p = function(u){return (u - min) * pixellength / unitlength + offmin;};if (this.name == 'xaxis' || this.name == 'x2axis'){this.series_u2p = function(u){return (u - min) * pixellength / unitlength;};this.series_p2u = function(p){return p * unitlength / pixellength + min;};}else {this.series_u2p = function(u){return (u - max) * pixellength / unitlength;};this.series_p2u = function(p){return p * unitlength / pixellength + max;};}if (this.show) {if (this.name == 'xaxis' || this.name == 'x2axis') {for (var i=0; i<ticks.length; i++) {var t = ticks[i];if (t.show && t.showLabel) {var shim;if (t.constructor == $.jqplot.CanvasAxisTickRenderer && t.angle) {// will need to adjust auto positioning based on which axis this is.var temp = (this.name == 'xaxis') ? 1 : -1;switch (t.labelPosition) {case 'auto':// position at endif (temp * t.angle < 0) {shim = -t.getWidth() + t._textRenderer.height * Math.sin(-t._textRenderer.angle) / 2;}// position at startelse {shim = -t._textRenderer.height * Math.sin(t._textRenderer.angle) / 2;}break;case 'end':shim = -t.getWidth() + t._textRenderer.height * Math.sin(-t._textRenderer.angle) / 2;break;case 'start':shim = -t._textRenderer.height * Math.sin(t._textRenderer.angle) / 2;break;case 'middle':shim = -t.getWidth()/2 + t._textRenderer.height * Math.sin(-t._textRenderer.angle) / 2;break;default:shim = -t.getWidth()/2 + t._textRenderer.height * Math.sin(-t._textRenderer.angle) / 2;break;}}else {shim = -t.getWidth()/2;}var val = this.u2p(t.value) + shim + 'px';t._elem.css('left', val);t.pack();}}var w;if (lshow) {w = this._label._elem.outerWidth(true);this._label._elem.css('left', offmin + pixellength/2 - w/2 + 'px');if (this.name == 'xaxis') {this._label._elem.css('bottom', '0px');}else {this._label._elem.css('top', '0px');}this._label.pack();}// now show the labels under the bars.var b, l, r;for (var i=0; i<this.barLabels.length; i++) {b = this._barLabels[i];if (b.show) {w = b.getWidth();l = this._ticks[i].getLeft() + this._ticks[i].getWidth();r = this._ticks[i+1].getLeft();b._elem.css('left', (r+l-w)/2+'px');b._elem.css('top', this._ticks[i]._elem.css('top'));b.pack();}}}else {for (var i=0; i<ticks.length; i++) {var t = ticks[i];if (t.show && t.showLabel) {var shim;if (t.constructor == $.jqplot.CanvasAxisTickRenderer && t.angle) {// will need to adjust auto positioning based on which axis this is.var temp = (this.name == 'yaxis') ? 1 : -1;switch (t.labelPosition) {case 'auto':// position at endcase 'end':if (temp * t.angle < 0) {shim = -t._textRenderer.height * Math.cos(-t._textRenderer.angle) / 2;}else {shim = -t.getHeight() + t._textRenderer.height * Math.cos(t._textRenderer.angle) / 2;}break;case 'start':if (t.angle > 0) {shim = -t._textRenderer.height * Math.cos(-t._textRenderer.angle) / 2;}else {shim = -t.getHeight() + t._textRenderer.height * Math.cos(t._textRenderer.angle) / 2;}break;case 'middle':shim = -t.getHeight()/2;break;default:shim = -t.getHeight()/2;break;}}else {shim = -t.getHeight()/2;}var val = this.u2p(t.value) + shim + 'px';t._elem.css('top', val);t.pack();}}if (lshow) {var h = this._label._elem.outerHeight(true);this._label._elem.css('top', offmax - pixellength/2 - h/2 + 'px');if (this.name == 'yaxis') {this._label._elem.css('left', '0px');}else {this._label._elem.css('right', '0px');}this._label.pack();}}}};})(jQuery);