OSDN Git Service

jqplotをバージョンアップ(v1.0.8)。
[magic3/magic3.git] / scripts / jquery / jqplot1.0.8 / plugins / jqplot.logAxisRenderer.js
1 /**
2  * jqPlot
3  * Pure JavaScript plotting plugin using jQuery
4  *
5  * Version: 1.0.8
6  * Revision: 1250
7  *
8  * Copyright (c) 2009-2013 Chris Leonello
9  * jqPlot is currently available for use in all personal or commercial projects 
10  * under both the MIT (http://www.opensource.org/licenses/mit-license.php) and GPL 
11  * version 2.0 (http://www.gnu.org/licenses/gpl-2.0.html) licenses. This means that you can 
12  * choose the license that best suits your project and use it accordingly. 
13  *
14  * Although not required, the author would appreciate an email letting him 
15  * know of any substantial use of jqPlot.  You can reach the author at: 
16  * chris at jqplot dot com or see http://www.jqplot.com/info.php .
17  *
18  * If you are feeling kind and generous, consider supporting the project by
19  * making a donation at: http://www.jqplot.com/donate.php .
20  *
21  * sprintf functions contained in jqplot.sprintf.js by Ash Searle:
22  *
23  *     version 2007.04.27
24  *     author Ash Searle
25  *     http://hexmen.com/blog/2007/03/printf-sprintf/
26  *     http://hexmen.com/js/sprintf.js
27  *     The author (Ash Searle) has placed this code in the public domain:
28  *     "This code is unrestricted: you are free to use it however you like."
29  * 
30  */
31 (function($) {
32     /**
33     *  class: $.jqplot.LogAxisRenderer
34     *  A plugin for a jqPlot to render a logarithmic axis.
35     * 
36     *  To use this renderer, include the plugin in your source
37     *  > <script type="text/javascript" language="javascript" src="plugins/jqplot.logAxisRenderer.js"></script>
38     *  
39     *  and supply the appropriate options to your plot
40     *  
41     *  > {axes:{xaxis:{renderer:$.jqplot.LogAxisRenderer}}}
42     **/ 
43     $.jqplot.LogAxisRenderer = function() {
44         $.jqplot.LinearAxisRenderer.call(this);
45         // prop: axisDefaults
46         // Default properties which will be applied directly to the series.
47         //
48         // Group: Properties
49         //
50         // Properties
51         //
52         // base - the logarithmic base, commonly 2, 10 or Math.E
53         // tickDistribution - Deprecated.  "power" distribution of ticks
54         // always used.  Option has no effect.
55         this.axisDefaults = {
56             base : 10,
57             tickDistribution :'power'
58         };
59     };
60     
61     $.jqplot.LogAxisRenderer.prototype = new $.jqplot.LinearAxisRenderer();
62     $.jqplot.LogAxisRenderer.prototype.constructor = $.jqplot.LogAxisRenderer;
63     
64     $.jqplot.LogAxisRenderer.prototype.init = function(options) {
65         // prop: drawBaseline
66         // True to draw the axis baseline.
67         this.drawBaseline = true;
68         // prop: minorTicks
69         // Number of ticks to add between "major" ticks.
70         // Major ticks are ticks supplied by user or auto computed.
71         // Minor ticks cannot be created by user.
72         this.minorTicks = 'auto';
73         this._scalefact = 1.0;
74
75         $.extend(true, this, options);
76
77         this._autoFormatString = '%d';
78         this._overrideFormatString = false;
79
80         for (var d in this.renderer.axisDefaults) {
81             if (this[d] == null) {
82                 this[d] = this.renderer.axisDefaults[d];
83             }
84         }
85
86         this.resetDataBounds();
87     };
88     
89     $.jqplot.LogAxisRenderer.prototype.createTicks = function(plot) {
90         // we're are operating on an axis here
91         var ticks = this._ticks;
92         var userTicks = this.ticks;
93         var name = this.name;
94         var db = this._dataBounds;
95         var dim = (this.name.charAt(0) === 'x') ? this._plotDimensions.width : this._plotDimensions.height;
96         var interval;
97         var min, max;
98         var pos1, pos2;
99         var tt, i;
100
101         var threshold = 30;
102         // For some reason scalefactor is screwing up ticks.
103         this._scalefact =  (Math.max(dim, threshold+1) - threshold)/300;
104
105         // if we already have ticks, use them.
106         // ticks must be in order of increasing value.
107         if (userTicks.length) {
108             // ticks could be 1D or 2D array of [val, val, ,,,] or [[val, label], [val, label], ...] or mixed
109             for (i=0; i<userTicks.length; i++){
110                 var ut = userTicks[i];
111                 var t = new this.tickRenderer(this.tickOptions);
112                 if (ut.constructor == Array) {
113                     t.value = ut[0];
114                     t.label = ut[1];
115                     if (!this.showTicks) {
116                         t.showLabel = false;
117                         t.showMark = false;
118                     }
119                     else if (!this.showTickMarks) {
120                         t.showMark = false;
121                     }
122                     t.setTick(ut[0], this.name);
123                     this._ticks.push(t);
124                 }
125
126                 else if ($.isPlainObject(ut)) {
127                     $.extend(true, t, ut);
128                     t.axis = this.name;
129                     this._ticks.push(t);
130                 }
131                 
132                 else {
133                     t.value = ut;
134                     if (!this.showTicks) {
135                         t.showLabel = false;
136                         t.showMark = false;
137                     }
138                     else if (!this.showTickMarks) {
139                         t.showMark = false;
140                     }
141                     t.setTick(ut, this.name);
142                     this._ticks.push(t);
143                 }
144             }
145             this.numberTicks = userTicks.length;
146             this.min = this._ticks[0].value;
147             this.max = this._ticks[this.numberTicks-1].value;
148         }
149         
150         // we don't have any ticks yet, let's make some!
151         else if (this.min == null && this.max == null) {
152             min = db.min * (2 - this.padMin);
153             max = db.max * this.padMax;
154             
155             // if min and max are same, space them out a bit
156             if (min == max) {
157                 var adj = 0.05;
158                 min = min*(1-adj);
159                 max = max*(1+adj);
160             }
161             
162             // perform some checks
163             if (this.min != null && this.min <= 0) {
164                 throw new Error("Log axis minimum must be greater than 0");
165             }
166             if (this.max != null && this.max <= 0) {
167                 throw new Error("Log axis maximum must be greater than 0");
168             }
169
170             function findCeil (val) {
171                 var order = Math.pow(10, Math.floor(Math.log(val)/Math.LN10));
172                 return Math.ceil(val/order) * order;
173             }
174
175             function findFloor(val) {
176                 var order = Math.pow(10, Math.floor(Math.log(val)/Math.LN10));
177                 return Math.floor(val/order) * order;
178             }
179
180             // var range = max - min;
181             var rmin, rmax;
182
183             // for power distribution, open up range to get a nice power of axis.renderer.base.
184             // power distribution won't respect the user's min/max settings.
185             rmin = Math.pow(this.base, Math.floor(Math.log(min)/Math.log(this.base)));
186             rmax = Math.pow(this.base, Math.ceil(Math.log(max)/Math.log(this.base)));
187
188             // // if min and max are same, space them out a bit
189             // if (rmin === rmax) {
190             //     var adj = 0.05;
191             //     rmin = rmin*(1-adj);
192             //     rmax = rmax*(1+adj);
193             // }
194
195             // Handle case where a data value was zero
196             if (rmin === 0) {
197               rmin = 1;
198             }
199
200             var order = Math.round(Math.log(rmin)/Math.LN10);
201
202             if (this.tickOptions == null || !this.tickOptions.formatString) {
203                 this._overrideFormatString = true;
204             }
205
206             this.min = rmin;
207             this.max = rmax;
208             var range = this.max - this.min;            
209
210             var minorTicks = (this.minorTicks === 'auto') ? 0 : this.minorTicks;
211             var numberTicks;
212             if (this.numberTicks == null){
213                 if (dim > 140) {
214                     numberTicks = Math.round(Math.log(this.max/this.min)/Math.log(this.base) + 1);
215                     if (numberTicks < 2) {
216                         numberTicks = 2;
217                     }
218                     if (minorTicks === 0) {
219                         var temp = dim/(numberTicks - 1);
220                         if (temp < 100) {
221                             minorTicks = 0;
222                         }
223                         else if (temp < 190) {
224                             minorTicks = 1;
225                         }
226                         else if (temp < 250) {
227                             minorTicks = 3;
228                         }
229                         else if (temp < 600) {
230                             minorTicks = 4;
231                         }
232                         else {
233                             minorTicks = 9;
234                         }
235                     }
236                 }
237                 else {
238                     numberTicks = 2;
239                     if (minorTicks === 0) {
240                         minorTicks = 1;
241                     }
242                     minorTicks = 0;
243                 }
244             }
245             else {
246                 numberTicks = this.numberTicks;
247             }
248
249             if (order >= 0 && minorTicks !== 3) {
250                 this._autoFormatString = '%d';
251             }
252             // Adjust format string for case with 3 ticks where we'll have like 1, 2.5, 5, 7.5, 10
253             else if (order <= 0 && minorTicks === 3) {
254                 var temp = -(order - 1);
255                 this._autoFormatString = '%.'+ Math.abs(order-1) + 'f';
256             }
257
258             // Adjust format string for values less than 1.
259             else if (order < 0) {
260                 var temp = -order;
261                 this._autoFormatString = '%.'+ Math.abs(order) + 'f';
262             }
263
264             else {
265                 this._autoFormatString = '%d';
266             }
267
268             var to, t, val, tt1, spread, interval;
269             for (var i=0; i<numberTicks; i++){
270                 tt = Math.pow(this.base, i - numberTicks + 1) * this.max;
271
272                 t = new this.tickRenderer(this.tickOptions);
273             
274                 if (this._overrideFormatString) {
275                     t.formatString = this._autoFormatString;
276                 }
277                 
278                 if (!this.showTicks) {
279                     t.showLabel = false;
280                     t.showMark = false;
281                 }
282                 else if (!this.showTickMarks) {
283                     t.showMark = false;
284                 }
285                 t.setTick(tt, this.name);
286                 this._ticks.push(t);
287
288                 if (minorTicks && i<numberTicks-1) {
289                     tt1 = Math.pow(this.base, i - numberTicks + 2) * this.max;
290                     spread = tt1 - tt;
291                     interval = tt1 / (minorTicks+1);
292                     for (var j=minorTicks-1; j>=0; j--) {
293                         val = tt1-interval*(j+1);
294                         t = new this.tickRenderer(this.tickOptions);
295             
296                         if (this._overrideFormatString && this._autoFormatString != '') {
297                             t.formatString = this._autoFormatString;
298                         }
299                         if (!this.showTicks) {
300                             t.showLabel = false;
301                             t.showMark = false;
302                         }
303                         else if (!this.showTickMarks) {
304                             t.showMark = false;
305                         }
306                         t.setTick(val, this.name);
307                         this._ticks.push(t);
308                     }
309                 }       
310             }     
311         }
312
313         // min and max are set as would be the case with zooming
314         else if (this.min != null && this.max != null) {
315             var opts = $.extend(true, {}, this.tickOptions, {name: this.name, value: null});
316             var nt, ti;
317             // don't have an interval yet, pick one that gives the most
318             // "round" ticks we can get.
319             if (this.numberTicks == null && this.tickInterval == null) {
320                 // var threshold = 30;
321                 var tdim = Math.max(dim, threshold+1);
322                 var nttarget =  Math.ceil((tdim-threshold)/35 + 1);
323
324                 var ret = $.jqplot.LinearTickGenerator.bestConstrainedInterval(this.min, this.max, nttarget);
325
326                 this._autoFormatString = ret[3];
327                 nt = ret[2];
328                 ti = ret[4];
329
330                 for (var i=0; i<nt; i++) {
331                     opts.value = this.min + i * ti;
332                     t = new this.tickRenderer(opts);
333                     
334                     if (this._overrideFormatString && this._autoFormatString != '') {
335                         t.formatString = this._autoFormatString;
336                     }
337                     if (!this.showTicks) {
338                         t.showLabel = false;
339                         t.showMark = false;
340                     }
341                     else if (!this.showTickMarks) {
342                         t.showMark = false;
343                     }
344                     this._ticks.push(t);
345                 }
346             }
347
348             // for loose zoom, number ticks and interval are also set.
349             else if (this.numberTicks != null && this.tickInterval != null) {
350                 nt = this.numberTicks;
351                 for (var i=0; i<nt; i++) {
352                     opts.value = this.min + i * this.tickInterval;
353                     t = new this.tickRenderer(opts);
354                     
355                     if (this._overrideFormatString && this._autoFormatString != '') {
356                         t.formatString = this._autoFormatString;
357                     }
358                     if (!this.showTicks) {
359                         t.showLabel = false;
360                         t.showMark = false;
361                     }
362                     else if (!this.showTickMarks) {
363                         t.showMark = false;
364                     }
365                     this._ticks.push(t);
366                 }
367             }
368         }
369     };
370     
371     $.jqplot.LogAxisRenderer.prototype.pack = function(pos, offsets) {
372         var lb = parseInt(this.base, 10);
373         var ticks = this._ticks;
374         var trans = function (v) { return Math.log(v)/Math.log(lb); };
375         var invtrans = function (v) { return Math.pow(Math.E, (Math.log(lb)*v)); };
376         var max = trans(this.max);
377         var min = trans(this.min);
378         var offmax = offsets.max;
379         var offmin = offsets.min;
380         var lshow = (this._label == null) ? false : this._label.show;
381         
382         for (var p in pos) {
383             this._elem.css(p, pos[p]);
384         }
385         
386         this._offsets = offsets;
387         // pixellength will be + for x axes and - for y axes becasue pixels always measured from top left.
388         var pixellength = offmax - offmin;
389         var unitlength = max - min;
390         
391         // point to unit and unit to point conversions references to Plot DOM element top left corner.
392         this.p2u = function(p){
393             return invtrans((p - offmin) * unitlength / pixellength + min);
394         };
395         
396         this.u2p = function(u){
397             return (trans(u) - min) * pixellength / unitlength + offmin;
398         };
399         
400         if (this.name == 'xaxis' || this.name == 'x2axis'){
401             this.series_u2p = function(u){
402                 return (trans(u) - min) * pixellength / unitlength;
403             };
404             this.series_p2u = function(p){
405                 return invtrans(p * unitlength / pixellength + min);
406             };
407         }
408         // yaxis is max at top of canvas.
409         else {
410             this.series_u2p = function(u){
411                 return (trans(u) - max) * pixellength / unitlength;
412             };
413             this.series_p2u = function(p){
414                 return invtrans(p * unitlength / pixellength + max);
415             };
416         }
417         
418         if (this.show) {
419             if (this.name == 'xaxis' || this.name == 'x2axis') {
420                 for (var i=0; i<ticks.length; i++) {
421                     var t = ticks[i];
422                     if (t.show && t.showLabel) {
423                         var shim;
424                         
425                         if (t.constructor == $.jqplot.CanvasAxisTickRenderer && t.angle) {
426                             switch (t.labelPosition) {
427                                 case 'auto':
428                                     // position at end
429                                     if (t.angle < 0) {
430                                         shim = -t.getWidth() + t._textRenderer.height * Math.sin(-t._textRenderer.angle) / 2;
431                                     }
432                                     // position at start
433                                     else {
434                                         shim = -t._textRenderer.height * Math.sin(t._textRenderer.angle) / 2;
435                                     }
436                                     break;
437                                 case 'end':
438                                     shim = -t.getWidth() + t._textRenderer.height * Math.sin(-t._textRenderer.angle) / 2;
439                                     break;
440                                 case 'start':
441                                     shim = -t._textRenderer.height * Math.sin(t._textRenderer.angle) / 2;
442                                     break;
443                                 case 'middle':
444                                     shim = -t.getWidth()/2 + t._textRenderer.height * Math.sin(-t._textRenderer.angle) / 2;
445                                     break;
446                                 default:
447                                     shim = -t.getWidth()/2 + t._textRenderer.height * Math.sin(-t._textRenderer.angle) / 2;
448                                     break;
449                             }
450                         }
451                         else {
452                             shim = -t.getWidth()/2;
453                         }
454                         // var shim = t.getWidth()/2;
455                         var val = this.u2p(t.value) + shim + 'px';
456                         t._elem.css('left', val);
457                         t.pack();
458                     }
459                 }
460                 if (lshow) {
461                     var w = this._label._elem.outerWidth(true);
462                     this._label._elem.css('left', offmin + pixellength/2 - w/2 + 'px');
463                     if (this.name == 'xaxis') {
464                         this._label._elem.css('bottom', '0px');
465                     }
466                     else {
467                         this._label._elem.css('top', '0px');
468                     }
469                     this._label.pack();
470                 }
471             }
472             else {
473                 for (var i=0; i<ticks.length; i++) {
474                     var t = ticks[i];
475                     if (t.show && t.showLabel) {                        
476                         var shim;
477                         if (t.constructor == $.jqplot.CanvasAxisTickRenderer && t.angle) {
478                             switch (t.labelPosition) {
479                                 case 'auto':
480                                     // position at end
481                                 case 'end':
482                                     if (t.angle < 0) {
483                                         shim = -t._textRenderer.height * Math.cos(-t._textRenderer.angle) / 2;
484                                     }
485                                     else {
486                                         shim = -t.getHeight() + t._textRenderer.height * Math.cos(t._textRenderer.angle) / 2;
487                                     }
488                                     break;
489                                 case 'start':
490                                     if (t.angle > 0) {
491                                         shim = -t._textRenderer.height * Math.cos(-t._textRenderer.angle) / 2;
492                                     }
493                                     else {
494                                         shim = -t.getHeight() + t._textRenderer.height * Math.cos(t._textRenderer.angle) / 2;
495                                     }
496                                     break;
497                                 case 'middle':
498                                     // if (t.angle > 0) {
499                                     //     shim = -t.getHeight()/2 + t._textRenderer.height * Math.sin(-t._textRenderer.angle) / 2;
500                                     // }
501                                     // else {
502                                     //     shim = -t.getHeight()/2 - t._textRenderer.height * Math.sin(t._textRenderer.angle) / 2;
503                                     // }
504                                     shim = -t.getHeight()/2;
505                                     break;
506                                 default:
507                                     shim = -t.getHeight()/2;
508                                     break;
509                             }
510                         }
511                         else {
512                             shim = -t.getHeight()/2;
513                         }
514                         
515                         var val = this.u2p(t.value) + shim + 'px';
516                         t._elem.css('top', val);
517                         t.pack();
518                     }
519                 }
520                 if (lshow) {
521                     var h = this._label._elem.outerHeight(true);
522                     this._label._elem.css('top', offmax - pixellength/2 - h/2 + 'px');
523                     if (this.name == 'yaxis') {
524                         this._label._elem.css('left', '0px');
525                     }
526                     else {
527                         this._label._elem.css('right', '0px');
528                     }   
529                     this._label.pack();
530                 }
531             }
532         }        
533     };
534 })(jQuery);