Subversion-Projekte lars-tiefland.cienc

Revision

Details | Letzte Änderung | Log anzeigen | RSS feed

Revision Autor Zeilennr. Zeile
9 lars 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);