[9062] | 1 | /** |
---|
| 2 | * jqPlot |
---|
| 3 | * Pure JavaScript plotting plugin using jQuery |
---|
| 4 | * |
---|
| 5 | * Version: @VERSION |
---|
| 6 | * |
---|
| 7 | * Copyright (c) 2009-2011 Chris Leonello |
---|
| 8 | * jqPlot is currently available for use in all personal or commercial projects |
---|
| 9 | * under both the MIT (http://www.opensource.org/licenses/mit-license.php) and GPL |
---|
| 10 | * version 2.0 (http://www.gnu.org/licenses/gpl-2.0.html) licenses. This means that you can |
---|
| 11 | * choose the license that best suits your project and use it accordingly. |
---|
| 12 | * |
---|
| 13 | * Although not required, the author would appreciate an email letting him |
---|
| 14 | * know of any substantial use of jqPlot. You can reach the author at: |
---|
| 15 | * chris at jqplot dot com or see http://www.jqplot.com/info.php . |
---|
| 16 | * |
---|
| 17 | * If you are feeling kind and generous, consider supporting the project by |
---|
| 18 | * making a donation at: http://www.jqplot.com/donate.php . |
---|
| 19 | * |
---|
| 20 | * sprintf functions contained in jqplot.sprintf.js by Ash Searle: |
---|
| 21 | * |
---|
| 22 | * version 2007.04.27 |
---|
| 23 | * author Ash Searle |
---|
| 24 | * http://hexmen.com/blog/2007/03/printf-sprintf/ |
---|
| 25 | * http://hexmen.com/js/sprintf.js |
---|
| 26 | * The author (Ash Searle) has placed this code in the public domain: |
---|
| 27 | * "This code is unrestricted: you are free to use it however you like." |
---|
| 28 | * |
---|
| 29 | */ |
---|
| 30 | (function($) { |
---|
| 31 | /** |
---|
| 32 | * JavaScript printf/sprintf functions. |
---|
| 33 | * |
---|
| 34 | * This code has been adapted from the publicly available sprintf methods |
---|
| 35 | * by Ash Searle. His original header follows: |
---|
| 36 | * |
---|
| 37 | * This code is unrestricted: you are free to use it however you like. |
---|
| 38 | * |
---|
| 39 | * The functions should work as expected, performing left or right alignment, |
---|
| 40 | * truncating strings, outputting numbers with a required precision etc. |
---|
| 41 | * |
---|
| 42 | * For complex cases, these functions follow the Perl implementations of |
---|
| 43 | * (s)printf, allowing arguments to be passed out-of-order, and to set the |
---|
| 44 | * precision or length of the output based on arguments instead of fixed |
---|
| 45 | * numbers. |
---|
| 46 | * |
---|
| 47 | * See http://perldoc.perl.org/functions/sprintf.html for more information. |
---|
| 48 | * |
---|
| 49 | * Implemented: |
---|
| 50 | * - zero and space-padding |
---|
| 51 | * - right and left-alignment, |
---|
| 52 | * - base X prefix (binary, octal and hex) |
---|
| 53 | * - positive number prefix |
---|
| 54 | * - (minimum) width |
---|
| 55 | * - precision / truncation / maximum width |
---|
| 56 | * - out of order arguments |
---|
| 57 | * |
---|
| 58 | * Not implemented (yet): |
---|
| 59 | * - vector flag |
---|
| 60 | * - size (bytes, words, long-words etc.) |
---|
| 61 | * |
---|
| 62 | * Will not implement: |
---|
| 63 | * - %n or %p (no pass-by-reference in JavaScript) |
---|
| 64 | * |
---|
| 65 | * @version 2007.04.27 |
---|
| 66 | * @author Ash Searle |
---|
| 67 | * |
---|
| 68 | * You can see the original work and comments on his blog: |
---|
| 69 | * http://hexmen.com/blog/2007/03/printf-sprintf/ |
---|
| 70 | * http://hexmen.com/js/sprintf.js |
---|
| 71 | */ |
---|
| 72 | |
---|
| 73 | /** |
---|
| 74 | * @Modifications 2009.05.26 |
---|
| 75 | * @author Chris Leonello |
---|
| 76 | * |
---|
| 77 | * Added %p %P specifier |
---|
| 78 | * Acts like %g or %G but will not add more significant digits to the output than present in the input. |
---|
| 79 | * Example: |
---|
| 80 | * Format: '%.3p', Input: 0.012, Output: 0.012 |
---|
| 81 | * Format: '%.3g', Input: 0.012, Output: 0.0120 |
---|
| 82 | * Format: '%.4p', Input: 12.0, Output: 12.0 |
---|
| 83 | * Format: '%.4g', Input: 12.0, Output: 12.00 |
---|
| 84 | * Format: '%.4p', Input: 4.321e-5, Output: 4.321e-5 |
---|
| 85 | * Format: '%.4g', Input: 4.321e-5, Output: 4.3210e-5 |
---|
| 86 | */ |
---|
| 87 | $.jqplot.sprintf = function() { |
---|
| 88 | function pad(str, len, chr, leftJustify) { |
---|
| 89 | var padding = (str.length >= len) ? '' : Array(1 + len - str.length >>> 0).join(chr); |
---|
| 90 | return leftJustify ? str + padding : padding + str; |
---|
| 91 | |
---|
| 92 | } |
---|
| 93 | |
---|
| 94 | function thousand_separate(value) { |
---|
| 95 | var value_str = new String(value); |
---|
| 96 | for (var i=10; i>0; i--) { |
---|
| 97 | if (value_str == (value_str = value_str.replace(/^(\d+)(\d{3})/, "$1"+$.jqplot.sprintf.thousandsSeparator+"$2"))) break; |
---|
| 98 | } |
---|
| 99 | return value_str; |
---|
| 100 | } |
---|
| 101 | |
---|
| 102 | function justify(value, prefix, leftJustify, minWidth, zeroPad, htmlSpace) { |
---|
| 103 | var diff = minWidth - value.length; |
---|
| 104 | if (diff > 0) { |
---|
| 105 | var spchar = ' '; |
---|
| 106 | if (htmlSpace) { spchar = ' '; } |
---|
| 107 | if (leftJustify || !zeroPad) { |
---|
| 108 | value = pad(value, minWidth, spchar, leftJustify); |
---|
| 109 | } else { |
---|
| 110 | value = value.slice(0, prefix.length) + pad('', diff, '0', true) + value.slice(prefix.length); |
---|
| 111 | } |
---|
| 112 | } |
---|
| 113 | return value; |
---|
| 114 | } |
---|
| 115 | |
---|
| 116 | function formatBaseX(value, base, prefix, leftJustify, minWidth, precision, zeroPad, htmlSpace) { |
---|
| 117 | // Note: casts negative numbers to positive ones |
---|
| 118 | var number = value >>> 0; |
---|
| 119 | prefix = prefix && number && {'2': '0b', '8': '0', '16': '0x'}[base] || ''; |
---|
| 120 | value = prefix + pad(number.toString(base), precision || 0, '0', false); |
---|
| 121 | return justify(value, prefix, leftJustify, minWidth, zeroPad, htmlSpace); |
---|
| 122 | } |
---|
| 123 | |
---|
| 124 | function formatString(value, leftJustify, minWidth, precision, zeroPad, htmlSpace) { |
---|
| 125 | if (precision != null) { |
---|
| 126 | value = value.slice(0, precision); |
---|
| 127 | } |
---|
| 128 | return justify(value, '', leftJustify, minWidth, zeroPad, htmlSpace); |
---|
| 129 | } |
---|
| 130 | |
---|
| 131 | var a = arguments, i = 0, format = a[i++]; |
---|
| 132 | |
---|
| 133 | return format.replace($.jqplot.sprintf.regex, function(substring, valueIndex, flags, minWidth, _, precision, type) { |
---|
| 134 | if (substring == '%%') { return '%'; } |
---|
| 135 | |
---|
| 136 | // parse flags |
---|
| 137 | var leftJustify = false, positivePrefix = '', zeroPad = false, prefixBaseX = false, htmlSpace = false, thousandSeparation = false; |
---|
| 138 | for (var j = 0; flags && j < flags.length; j++) switch (flags.charAt(j)) { |
---|
| 139 | case ' ': positivePrefix = ' '; break; |
---|
| 140 | case '+': positivePrefix = '+'; break; |
---|
| 141 | case '-': leftJustify = true; break; |
---|
| 142 | case '0': zeroPad = true; break; |
---|
| 143 | case '#': prefixBaseX = true; break; |
---|
| 144 | case '&': htmlSpace = true; break; |
---|
| 145 | case '\'': thousandSeparation = true; break; |
---|
| 146 | } |
---|
| 147 | |
---|
| 148 | // parameters may be null, undefined, empty-string or real valued |
---|
| 149 | // we want to ignore null, undefined and empty-string values |
---|
| 150 | |
---|
| 151 | if (!minWidth) { |
---|
| 152 | minWidth = 0; |
---|
| 153 | } |
---|
| 154 | else if (minWidth == '*') { |
---|
| 155 | minWidth = +a[i++]; |
---|
| 156 | } |
---|
| 157 | else if (minWidth.charAt(0) == '*') { |
---|
| 158 | minWidth = +a[minWidth.slice(1, -1)]; |
---|
| 159 | } |
---|
| 160 | else { |
---|
| 161 | minWidth = +minWidth; |
---|
| 162 | } |
---|
| 163 | |
---|
| 164 | // Note: undocumented perl feature: |
---|
| 165 | if (minWidth < 0) { |
---|
| 166 | minWidth = -minWidth; |
---|
| 167 | leftJustify = true; |
---|
| 168 | } |
---|
| 169 | |
---|
| 170 | if (!isFinite(minWidth)) { |
---|
| 171 | throw new Error('$.jqplot.sprintf: (minimum-)width must be finite'); |
---|
| 172 | } |
---|
| 173 | |
---|
| 174 | if (!precision) { |
---|
| 175 | precision = 'fFeE'.indexOf(type) > -1 ? 6 : (type == 'd') ? 0 : void(0); |
---|
| 176 | } |
---|
| 177 | else if (precision == '*') { |
---|
| 178 | precision = +a[i++]; |
---|
| 179 | } |
---|
| 180 | else if (precision.charAt(0) == '*') { |
---|
| 181 | precision = +a[precision.slice(1, -1)]; |
---|
| 182 | } |
---|
| 183 | else { |
---|
| 184 | precision = +precision; |
---|
| 185 | } |
---|
| 186 | |
---|
| 187 | // grab value using valueIndex if required? |
---|
| 188 | var value = valueIndex ? a[valueIndex.slice(0, -1)] : a[i++]; |
---|
| 189 | |
---|
| 190 | switch (type) { |
---|
| 191 | case 's': { |
---|
| 192 | if (value == null) { |
---|
| 193 | return ''; |
---|
| 194 | } |
---|
| 195 | return formatString(String(value), leftJustify, minWidth, precision, zeroPad, htmlSpace); |
---|
| 196 | } |
---|
| 197 | case 'c': return formatString(String.fromCharCode(+value), leftJustify, minWidth, precision, zeroPad, htmlSpace); |
---|
| 198 | case 'b': return formatBaseX(value, 2, prefixBaseX, leftJustify, minWidth, precision, zeroPad,htmlSpace); |
---|
| 199 | case 'o': return formatBaseX(value, 8, prefixBaseX, leftJustify, minWidth, precision, zeroPad, htmlSpace); |
---|
| 200 | case 'x': return formatBaseX(value, 16, prefixBaseX, leftJustify, minWidth, precision, zeroPad, htmlSpace); |
---|
| 201 | case 'X': return formatBaseX(value, 16, prefixBaseX, leftJustify, minWidth, precision, zeroPad, htmlSpace).toUpperCase(); |
---|
| 202 | case 'u': return formatBaseX(value, 10, prefixBaseX, leftJustify, minWidth, precision, zeroPad, htmlSpace); |
---|
| 203 | case 'i': { |
---|
| 204 | var number = parseInt(+value, 10); |
---|
| 205 | if (isNaN(number)) { |
---|
| 206 | return ''; |
---|
| 207 | } |
---|
| 208 | var prefix = number < 0 ? '-' : positivePrefix; |
---|
| 209 | var number_str = thousandSeparation ? thousand_separate(String(Math.abs(number))): String(Math.abs(number)); |
---|
| 210 | value = prefix + pad(number_str, precision, '0', false); |
---|
| 211 | //value = prefix + pad(String(Math.abs(number)), precision, '0', false); |
---|
| 212 | return justify(value, prefix, leftJustify, minWidth, zeroPad, htmlSpace); |
---|
| 213 | } |
---|
| 214 | case 'd': { |
---|
| 215 | var number = Math.round(+value); |
---|
| 216 | if (isNaN(number)) { |
---|
| 217 | return ''; |
---|
| 218 | } |
---|
| 219 | var prefix = number < 0 ? '-' : positivePrefix; |
---|
| 220 | var number_str = thousandSeparation ? thousand_separate(String(Math.abs(number))): String(Math.abs(number)); |
---|
| 221 | value = prefix + pad(number_str, precision, '0', false); |
---|
| 222 | return justify(value, prefix, leftJustify, minWidth, zeroPad, htmlSpace); |
---|
| 223 | } |
---|
| 224 | case 'e': |
---|
| 225 | case 'E': |
---|
| 226 | case 'f': |
---|
| 227 | case 'F': |
---|
| 228 | case 'g': |
---|
| 229 | case 'G': |
---|
| 230 | { |
---|
| 231 | var number = +value; |
---|
| 232 | if (isNaN(number)) { |
---|
| 233 | return ''; |
---|
| 234 | } |
---|
| 235 | var prefix = number < 0 ? '-' : positivePrefix; |
---|
| 236 | var method = ['toExponential', 'toFixed', 'toPrecision']['efg'.indexOf(type.toLowerCase())]; |
---|
| 237 | var textTransform = ['toString', 'toUpperCase']['eEfFgG'.indexOf(type) % 2]; |
---|
| 238 | var number_str = Math.abs(number)[method](precision); |
---|
| 239 | number_str = thousandSeparation ? thousand_separate(number_str): number_str; |
---|
| 240 | value = prefix + number_str; |
---|
| 241 | return justify(value, prefix, leftJustify, minWidth, zeroPad, htmlSpace)[textTransform](); |
---|
| 242 | } |
---|
| 243 | case 'p': |
---|
| 244 | case 'P': |
---|
| 245 | { |
---|
| 246 | // make sure number is a number |
---|
| 247 | var number = +value; |
---|
| 248 | if (isNaN(number)) { |
---|
| 249 | return ''; |
---|
| 250 | } |
---|
| 251 | var prefix = number < 0 ? '-' : positivePrefix; |
---|
| 252 | |
---|
| 253 | var parts = String(Number(Math.abs(number)).toExponential()).split(/e|E/); |
---|
| 254 | var sd = (parts[0].indexOf('.') != -1) ? parts[0].length - 1 : parts[0].length; |
---|
| 255 | var zeros = (parts[1] < 0) ? -parts[1] - 1 : 0; |
---|
| 256 | |
---|
| 257 | if (Math.abs(number) < 1) { |
---|
| 258 | if (sd + zeros <= precision) { |
---|
| 259 | value = prefix + Math.abs(number).toPrecision(sd); |
---|
| 260 | } |
---|
| 261 | else { |
---|
| 262 | if (sd <= precision - 1) { |
---|
| 263 | value = prefix + Math.abs(number).toExponential(sd-1); |
---|
| 264 | } |
---|
| 265 | else { |
---|
| 266 | value = prefix + Math.abs(number).toExponential(precision-1); |
---|
| 267 | } |
---|
| 268 | } |
---|
| 269 | } |
---|
| 270 | else { |
---|
| 271 | var prec = (sd <= precision) ? sd : precision; |
---|
| 272 | value = prefix + Math.abs(number).toPrecision(prec); |
---|
| 273 | } |
---|
| 274 | var textTransform = ['toString', 'toUpperCase']['pP'.indexOf(type) % 2]; |
---|
| 275 | return justify(value, prefix, leftJustify, minWidth, zeroPad, htmlSpace)[textTransform](); |
---|
| 276 | } |
---|
| 277 | case 'n': return ''; |
---|
| 278 | default: return substring; |
---|
| 279 | } |
---|
| 280 | }); |
---|
| 281 | }; |
---|
| 282 | |
---|
| 283 | $.jqplot.sprintf.thousandsSeparator = ','; |
---|
| 284 | |
---|
| 285 | $.jqplot.sprintf.regex = /%%|%(\d+\$)?([-+#0&\' ]*)(\*\d+\$|\*|\d+)?(\.(\*\d+\$|\*|\d+))?([nAscboxXuidfegpEGP])/g; |
---|
| 286 | |
---|
| 287 | })(jQuery); |
---|