teechart.js 4.0.2 → 4.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/Tween.js ADDED
@@ -0,0 +1,13 @@
1
+ // tween.js r5 - http://github.com/sole/tween.js
2
+ var TWEEN=TWEEN||function(){var a,e,c=60,b=false,h=[],i;return{setFPS:function(f){c=f||60},start:function(f){arguments.length!=0&&this.setFPS(f);e=setInterval(this.update,1E3/c)},stop:function(){clearInterval(e)},setAutostart:function(f){(b=f)&&!e&&this.start()},add:function(f){h.push(f);b&&!e&&this.start()},getAll:function(){return h},removeAll:function(){h=[]},remove:function(f){a=h.indexOf(f);a!==-1&&h.splice(a,1)},update:function(f){a=0;i=h.length;for(f=f||Date.now();a<i;)if(h[a].update(f))a++;
3
+ else{h.splice(a,1);i--}i==0&&b==true&&this.stop()}}}();
4
+ TWEEN.Tween=function(a){var e={},c={},b={},h=1E3,i=0,f=null,n=TWEEN.Easing.Linear.EaseNone,k=null,l=null,m=null;this.to=function(d,g){if(g!==null)h=g;for(var j in d)if(a[j]!==null)b[j]=d[j];return this};this.start=function(d){TWEEN.add(this);f=d?d+i:Date.now()+i;for(var g in b)if(a[g]!==null){e[g]=a[g];c[g]=b[g]-a[g]}return this};this.stop=function(){TWEEN.remove(this);return this};this.delay=function(d){i=d;return this};this.easing=function(d){n=d;return this};this.chain=function(d){k=d};this.onUpdate=
5
+ function(d){l=d;return this};this.onComplete=function(d){m=d;return this};this.update=function(d){var g,j;if(d<f)return true;d=(d-f)/h;d=d>1?1:d;j=n(d);for(g in c)a[g]=e[g]+c[g]*j;l!==null&&l.call(a,j);if(d==1){m!==null&&m.call(a);k!==null&&k.start();return false}return true}};TWEEN.Easing={Linear:{},Quadratic:{},Cubic:{},Quartic:{},Quintic:{},Sinusoidal:{},Exponential:{},Circular:{},Elastic:{},Back:{},Bounce:{}};TWEEN.Easing.Linear.EaseNone=function(a){return a};
6
+ TWEEN.Easing.Quadratic.EaseIn=function(a){return a*a};TWEEN.Easing.Quadratic.EaseOut=function(a){return-a*(a-2)};TWEEN.Easing.Quadratic.EaseInOut=function(a){if((a*=2)<1)return 0.5*a*a;return-0.5*(--a*(a-2)-1)};TWEEN.Easing.Cubic.EaseIn=function(a){return a*a*a};TWEEN.Easing.Cubic.EaseOut=function(a){return--a*a*a+1};TWEEN.Easing.Cubic.EaseInOut=function(a){if((a*=2)<1)return 0.5*a*a*a;return 0.5*((a-=2)*a*a+2)};TWEEN.Easing.Quartic.EaseIn=function(a){return a*a*a*a};
7
+ TWEEN.Easing.Quartic.EaseOut=function(a){return-(--a*a*a*a-1)};TWEEN.Easing.Quartic.EaseInOut=function(a){if((a*=2)<1)return 0.5*a*a*a*a;return-0.5*((a-=2)*a*a*a-2)};TWEEN.Easing.Quintic.EaseIn=function(a){return a*a*a*a*a};TWEEN.Easing.Quintic.EaseOut=function(a){return(a-=1)*a*a*a*a+1};TWEEN.Easing.Quintic.EaseInOut=function(a){if((a*=2)<1)return 0.5*a*a*a*a*a;return 0.5*((a-=2)*a*a*a*a+2)};TWEEN.Easing.Sinusoidal.EaseIn=function(a){return-Math.cos(a*Math.PI/2)+1};
8
+ TWEEN.Easing.Sinusoidal.EaseOut=function(a){return Math.sin(a*Math.PI/2)};TWEEN.Easing.Sinusoidal.EaseInOut=function(a){return-0.5*(Math.cos(Math.PI*a)-1)};TWEEN.Easing.Exponential.EaseIn=function(a){return a==0?0:Math.pow(2,10*(a-1))};TWEEN.Easing.Exponential.EaseOut=function(a){return a==1?1:-Math.pow(2,-10*a)+1};TWEEN.Easing.Exponential.EaseInOut=function(a){if(a==0)return 0;if(a==1)return 1;if((a*=2)<1)return 0.5*Math.pow(2,10*(a-1));return 0.5*(-Math.pow(2,-10*(a-1))+2)};
9
+ TWEEN.Easing.Circular.EaseIn=function(a){return-(Math.sqrt(1-a*a)-1)};TWEEN.Easing.Circular.EaseOut=function(a){return Math.sqrt(1- --a*a)};TWEEN.Easing.Circular.EaseInOut=function(a){if((a/=0.5)<1)return-0.5*(Math.sqrt(1-a*a)-1);return 0.5*(Math.sqrt(1-(a-=2)*a)+1)};TWEEN.Easing.Elastic.EaseIn=function(a){var e,c=0.1,b=0.4;if(a==0)return 0;if(a==1)return 1;b||(b=0.3);if(!c||c<1){c=1;e=b/4}else e=b/(2*Math.PI)*Math.asin(1/c);return-(c*Math.pow(2,10*(a-=1))*Math.sin((a-e)*2*Math.PI/b))};
10
+ TWEEN.Easing.Elastic.EaseOut=function(a){var e,c=0.1,b=0.4;if(a==0)return 0;if(a==1)return 1;b||(b=0.3);if(!c||c<1){c=1;e=b/4}else e=b/(2*Math.PI)*Math.asin(1/c);return c*Math.pow(2,-10*a)*Math.sin((a-e)*2*Math.PI/b)+1};
11
+ TWEEN.Easing.Elastic.EaseInOut=function(a){var e,c=0.1,b=0.4;if(a==0)return 0;if(a==1)return 1;b||(b=0.3);if(!c||c<1){c=1;e=b/4}else e=b/(2*Math.PI)*Math.asin(1/c);if((a*=2)<1)return-0.5*c*Math.pow(2,10*(a-=1))*Math.sin((a-e)*2*Math.PI/b);return c*Math.pow(2,-10*(a-=1))*Math.sin((a-e)*2*Math.PI/b)*0.5+1};TWEEN.Easing.Back.EaseIn=function(a){return a*a*(2.70158*a-1.70158)};TWEEN.Easing.Back.EaseOut=function(a){return(a-=1)*a*(2.70158*a+1.70158)+1};
12
+ TWEEN.Easing.Back.EaseInOut=function(a){if((a*=2)<1)return 0.5*a*a*(3.5949095*a-2.5949095);return 0.5*((a-=2)*a*(3.5949095*a+2.5949095)+2)};TWEEN.Easing.Bounce.EaseIn=function(a){return 1-TWEEN.Easing.Bounce.EaseOut(1-a)};TWEEN.Easing.Bounce.EaseOut=function(a){return(a/=1)<1/2.75?7.5625*a*a:a<2/2.75?7.5625*(a-=1.5/2.75)*a+0.75:a<2.5/2.75?7.5625*(a-=2.25/2.75)*a+0.9375:7.5625*(a-=2.625/2.75)*a+0.984375};
13
+ TWEEN.Easing.Bounce.EaseInOut=function(a){if(a<0.5)return TWEEN.Easing.Bounce.EaseIn(a*2)*0.5;return TWEEN.Easing.Bounce.EaseOut(a*2-1)*0.5+0.5};
@@ -0,0 +1,145 @@
1
+ /*
2
+ * Date Format 1.2.3
3
+ * (c) 2007-2009 Steven Levithan <stevenlevithan.com>
4
+ * MIT license
5
+ *
6
+ * Includes enhancements by Scott Trenda <scott.trenda.net>
7
+ * and Kris Kowal <cixar.com/~kris.kowal/>
8
+ *
9
+ * Accepts a date, a mask, or a date and a mask.
10
+ * Returns a formatted version of the given date.
11
+ * The date defaults to the current date/time.
12
+ * The mask defaults to dateFormat.masks.default.
13
+ */
14
+
15
+ /*
16
+ * Additions by Steema Software
17
+ *
18
+ * function Date.msecsRound(min,max)
19
+ * Returns nearest to min logical date in msecs.
20
+ *
21
+ */
22
+
23
+ Date.prototype.msecsRound=function(min,max) {
24
+ var days=Math.round((max-min)/86400000);
25
+
26
+ if (days>60) {
27
+ var d=new Date(min), m=d.getMonth(), y=d.getFullYear();
28
+ if (m<12) m++; else { m=1; y++ }
29
+ return new Date(y,m,1).getTime();
30
+ }
31
+ else
32
+ return min;
33
+ }
34
+
35
+ var dateFormat = function () {
36
+ var token = /d{1,4}|m{1,4}|yy(?:yy)?|([HhMsTt])\1?|[LloSZ]|"[^"]*"|'[^']*'/g,
37
+ timezone = /\b(?:[PMCEA][SDP]T|(?:Pacific|Mountain|Central|Eastern|Atlantic) (?:Standard|Daylight|Prevailing) Time|(?:GMT|UTC)(?:[-+]\d{4})?)\b/g,
38
+ timezoneClip = /[^-+\dA-Z]/g,
39
+ pad = function (val, len) {
40
+ val = String(val);
41
+ len = len || 2;
42
+ while (val.length < len) val = "0" + val;
43
+ return val;
44
+ };
45
+
46
+ // Regexes and supporting functions are cached through closure
47
+ return function (date, mask, utc) {
48
+ var dF = dateFormat;
49
+
50
+ // You can't provide utc if you skip other args (use the "UTC:" mask prefix)
51
+ if (arguments.length == 1 && Object.prototype.toString.call(date) == "[object String]" && !/\d/.test(date)) {
52
+ mask = date;
53
+ date = undefined;
54
+ }
55
+
56
+ // Passing date through Date applies Date.parse, if necessary
57
+ date = date ? new Date(date) : new Date;
58
+ if (isNaN(date)) throw SyntaxError("invalid date");
59
+
60
+ mask = String(dF.masks[mask] || mask || dF.masks["default"]);
61
+
62
+ // Allow setting the utc argument via the mask
63
+ if (mask.slice(0, 4) == "UTC:") {
64
+ mask = mask.slice(4);
65
+ utc = true;
66
+ }
67
+
68
+ var _ = utc ? "getUTC" : "get",
69
+ d = date[_ + "Date"](),
70
+ D = date[_ + "Day"](),
71
+ m = date[_ + "Month"](),
72
+ y = date[_ + "FullYear"](),
73
+ H = date[_ + "Hours"](),
74
+ M = date[_ + "Minutes"](),
75
+ s = date[_ + "Seconds"](),
76
+ L = date[_ + "Milliseconds"](),
77
+ o = utc ? 0 : date.getTimezoneOffset(),
78
+ flags = {
79
+ d: d,
80
+ dd: pad(d),
81
+ ddd: dF.i18n.dayNames[D],
82
+ dddd: dF.i18n.dayNames[D + 7],
83
+ m: m + 1,
84
+ mm: pad(m + 1),
85
+ mmm: dF.i18n.monthNames[m],
86
+ mmmm: dF.i18n.monthNames[m + 12],
87
+ yy: String(y).slice(2),
88
+ yyyy: y,
89
+ h: H % 12 || 12,
90
+ hh: pad(H % 12 || 12),
91
+ H: H,
92
+ HH: pad(H),
93
+ M: M,
94
+ MM: pad(M),
95
+ s: s,
96
+ ss: pad(s),
97
+ l: pad(L, 3),
98
+ L: pad(L > 99 ? Math.round(L / 10) : L),
99
+ t: H < 12 ? "a" : "p",
100
+ tt: H < 12 ? "am" : "pm",
101
+ T: H < 12 ? "A" : "P",
102
+ TT: H < 12 ? "AM" : "PM",
103
+ Z: utc ? "UTC" : (String(date).match(timezone) || [""]).pop().replace(timezoneClip, ""),
104
+ o: (o > 0 ? "-" : "+") + pad(Math.floor(Math.abs(o) / 60) * 100 + Math.abs(o) % 60, 4),
105
+ S: ["th", "st", "nd", "rd"][d % 10 > 3 ? 0 : (d % 100 - d % 10 != 10) * d % 10]
106
+ };
107
+
108
+ return mask.replace(token, function ($0) {
109
+ return $0 in flags ? flags[$0] : $0.slice(1, $0.length - 1);
110
+ });
111
+ };
112
+ }();
113
+
114
+ // Some common format strings
115
+ dateFormat.masks = {
116
+ "default": "ddd mmm dd yyyy HH:MM:ss",
117
+ shortDate: "m/d/yy",
118
+ mediumDate: "mmm d, yyyy",
119
+ longDate: "mmmm d, yyyy",
120
+ fullDate: "dddd, mmmm d, yyyy",
121
+ shortTime: "h:MM TT",
122
+ mediumTime: "h:MM:ss TT",
123
+ longTime: "h:MM:ss TT Z",
124
+ isoDate: "yyyy-mm-dd",
125
+ isoTime: "HH:MM:ss",
126
+ isoDateTime: "yyyy-mm-dd'T'HH:MM:ss",
127
+ isoUtcDateTime: "UTC:yyyy-mm-dd'T'HH:MM:ss'Z'"
128
+ };
129
+
130
+ // Internationalization strings
131
+ dateFormat.i18n = {
132
+ dayNames: [
133
+ "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat",
134
+ "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"
135
+ ],
136
+ monthNames: [
137
+ "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec",
138
+ "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"
139
+ ]
140
+ };
141
+
142
+ // For convenience...
143
+ Date.prototype.format = function (mask, utc) {
144
+ return dateFormat(this, mask, utc);
145
+ };
@@ -0,0 +1,489 @@
1
+ /* $Id$ */
2
+
3
+ /**
4
+ * @projectDescription An cross-browser implementation of the HTML5 <canvas> text methods
5
+ * @author Fabien M�nager
6
+ * @version $Revision$
7
+ * @license MIT License <http://www.opensource.org/licenses/mit-license.php>
8
+ */
9
+
10
+ /**
11
+ * Known issues:
12
+ * - The 'light' font weight is not supported, neither is the 'oblique' font style.
13
+ * - Optimize the different hacks (for Opera9)
14
+ */
15
+
16
+ window.Canvas = window.Canvas || {};
17
+ window.Canvas.Text = {
18
+ // http://mondaybynoon.com/2007/04/02/linux-font-equivalents-to-popular-web-typefaces/
19
+ equivalentFaces: {
20
+ // Web popular fonts
21
+ 'arial': ['liberation sans', 'nimbus sans l', 'freesans', 'optimer', 'dejavu sans'],
22
+ 'times new roman': ['liberation serif', 'helvetiker', 'linux libertine', 'freeserif'],
23
+ 'courier new': ['dejavu sans mono', 'liberation mono', 'nimbus mono l', 'freemono'],
24
+ 'georgia': ['nimbus roman no9 l', 'helvetiker'],
25
+ 'helvetica': ['nimbus sans l', 'helvetiker', 'freesans'],
26
+ 'tahoma': ['dejavu sans', 'optimer', 'bitstream vera sans'],
27
+ 'verdana': ['dejavu sans', 'optimer', 'bitstream vera sans']
28
+ },
29
+ genericFaces: {
30
+ 'serif': ['times new roman', 'georgia', 'garamond', 'bodoni', 'minion web', 'itc stone serif', 'bitstream cyberbit'],
31
+ 'sans-serif': ['arial', 'verdana', 'trebuchet', 'tahoma', 'helvetica', 'itc avant garde gothic', 'univers', 'futura',
32
+ 'gill sans', 'akzidenz grotesk', 'attika', 'typiko new era', 'itc stone sans', 'monotype gill sans 571'],
33
+ 'monospace': ['courier', 'courier new', 'prestige', 'everson mono'],
34
+ 'cursive': ['caflisch script', 'adobe poetica', 'sanvito', 'ex ponto', 'snell roundhand', 'zapf-chancery'],
35
+ 'fantasy': ['alpha geometrique', 'critter', 'cottonwood', 'fb reactor', 'studz']
36
+ },
37
+ faces: {},
38
+ scaling: 0.962,
39
+ _styleCache: {}
40
+ };
41
+
42
+ /** The implementation of the text functions */
43
+ (function(){
44
+ var isOpera9 = (window.opera && /Opera\/9/.test(navigator.userAgent)), // It seems to be faster when the hacked methods are used. But there are artifacts with Opera 10.
45
+ proto = window.CanvasRenderingContext2D ? window.CanvasRenderingContext2D.prototype : document.createElement('canvas').getContext('2d').__proto__,
46
+ ctxt = window.Canvas.Text;
47
+
48
+ // Global options
49
+ ctxt.options = {
50
+ fallbackCharacter: ' ', // The character that will be drawn when not present in the font face file
51
+ dontUseMoz: false, // Don't use the builtin Firefox 3.0 functions (mozDrawText, mozPathText and mozMeasureText)
52
+ reimplement: false, // Don't use the builtin official functions present in Chrome 2, Safari 4, and Firefox 3.1+
53
+ debug: false, // Debug mode, not used yet
54
+ autoload: false // Specify the directory containing the face files or false
55
+ };
56
+
57
+ var scripts = document.getElementsByTagName("script"),
58
+ parts = scripts[scripts.length-1].src.split('?');
59
+
60
+ ctxt.basePath = parts[0].substr(0, parts[0].lastIndexOf("/")+1);
61
+
62
+ if (parts[1]) {
63
+ var options = parts[1].split('&');
64
+ for (var j = options.length-1; j >= 0; --j) {
65
+ var pair = options[j].split('=');
66
+ ctxt.options[pair[0]] = pair[1];
67
+ }
68
+ }
69
+
70
+ // What is the browser's implementation ?
71
+ var moz = !ctxt.options.dontUseMoz && proto.mozDrawText && !proto.fillText;
72
+
73
+ // If the text functions are already here or if on the iPhone (fillText exists) : nothing to do !
74
+ if (proto.fillText && !ctxt.options.reimplement && !/iphone/i.test(navigator.userAgent)) {
75
+ // This property is needed, when including the font face files
76
+ return window._typeface_js = {loadFace: function(){}};
77
+ }
78
+
79
+ function getCSSWeightEquivalent(weight){
80
+ switch(String(weight)) {
81
+ case 'bolder':
82
+ case 'bold':
83
+ case '900':
84
+ case '800':
85
+ case '700': return 'bold';
86
+ case '600':
87
+ case '500':
88
+ case '400':
89
+ default:
90
+ case 'normal': return 'normal';
91
+ //default: return 'light';
92
+ }
93
+ }
94
+
95
+ function getElementStyle(e){
96
+ if (document.defaultView && document.defaultView.getComputedStyle) {
97
+ return document.defaultView.getComputedStyle(e, null);
98
+ }
99
+ return e.currentStyle || e.style;
100
+ }
101
+
102
+ function getXHR(){
103
+ if (!ctxt.xhr) {
104
+ var methods = [
105
+ function(){return new XMLHttpRequest()},
106
+ function(){return new ActiveXObject('Msxml2.XMLHTTP')},
107
+ function(){return new ActiveXObject('Microsoft.XMLHTTP')}
108
+ ];
109
+ for (var i = 0; i < methods.length; i++) {
110
+ try {
111
+ ctxt.xhr = methods[i]();
112
+ break;
113
+ }
114
+ catch (e) {}
115
+ }
116
+ }
117
+ return ctxt.xhr;
118
+ }
119
+
120
+ function arrayContains(a, v){
121
+ var i, l = a.length;
122
+ for (i = l-1; i >= 0; --i) if (a[i] === v) return true;
123
+ return false;
124
+ }
125
+
126
+ ctxt.lookupFamily = function(family){
127
+ var faces = this.faces, face, i, f, list,
128
+ equiv = this.equivalentFaces,
129
+ generic = this.genericFaces;
130
+
131
+ if (faces[family]) return faces[family];
132
+
133
+ if (generic[family]) {
134
+ for (i = 0; i < generic[family].length; i++) {
135
+ if (f = this.lookupFamily(generic[family][i])) return f;
136
+ }
137
+ }
138
+
139
+ if (!(list = equiv[family])) return false;
140
+
141
+ for (i = 0; i < list.length; i++)
142
+ if (face = faces[list[i]]) return face;
143
+ return false;
144
+ }
145
+
146
+ ctxt.getFace = function(family, weight, style){
147
+ var face = this.lookupFamily(family);
148
+ if (!face) return false;
149
+
150
+ if (face &&
151
+ face[weight] &&
152
+ face[weight][style]) return face[weight][style];
153
+
154
+ if (!this.options.autoload) return false;
155
+
156
+ var faceName = (family.replace(/[ -]/g, '_')+'-'+weight+'-'+style),
157
+ xhr = this.xhr,
158
+ url = this.basePath+this.options.autoload+'/'+faceName+'.js';
159
+
160
+ xhr = getXHR();
161
+ xhr.open("get", url, false);
162
+ xhr.send(null);
163
+ if(xhr.status == 200) {
164
+ eval(xhr.responseText);
165
+ return this.faces[family][weight][style];
166
+ }
167
+ else throw 'Unable to load the font ['+family+' '+weight+' '+style+']';
168
+ };
169
+
170
+ ctxt.loadFace = function(data){
171
+ var family = data.familyName.toLowerCase();
172
+
173
+ this.faces[family] = this.faces[family] || {};
174
+
175
+ if (data.strokeFont) {
176
+ this.faces[family].normal = this.faces[family].normal || {};
177
+ this.faces[family].normal.normal = data;
178
+ this.faces[family].normal.italic = data;
179
+
180
+ this.faces[family].bold = this.faces[family].normal || {};
181
+ this.faces[family].bold.normal = data;
182
+ this.faces[family].bold.italic = data;
183
+ }
184
+ else {
185
+ this.faces[family][data.cssFontWeight] = this.faces[family][data.cssFontWeight] || {};
186
+ this.faces[family][data.cssFontWeight][data.cssFontStyle] = data;
187
+ }
188
+ return data;
189
+ };
190
+
191
+ // To use the typeface.js face files
192
+ window._typeface_js = {faces: ctxt.faces, loadFace: ctxt.loadFace};
193
+
194
+ ctxt.getFaceFromStyle = function(style){
195
+ var weight = getCSSWeightEquivalent(style.weight),
196
+ families = style.family, i, face;
197
+
198
+ for (i = 0; i < families.length; i++) {
199
+ // The iPhone adds "-webkit-" at the beginning
200
+ if (face = this.getFace(families[i].toLowerCase().replace(/^-webkit-/, ""), weight, style.style)) {
201
+ return face;
202
+ }
203
+ }
204
+ return false;
205
+ };
206
+
207
+ // Default values
208
+ // Firefox 3.5 throws an error when redefining these properties
209
+ try {
210
+ proto.font = "10px sans-serif";
211
+ proto.textAlign = "start";
212
+ proto.textBaseline = "alphabetic";
213
+ }
214
+ catch(e){}
215
+
216
+ proto.parseStyle = function(styleText){
217
+ if (ctxt._styleCache[styleText]) return this.getComputedStyle(ctxt._styleCache[styleText]);
218
+
219
+ var style = {}, computedStyle, families;
220
+
221
+ if (!this._elt) {
222
+ this._elt = document.createElement('span');
223
+ this.canvas.appendChild(this._elt);
224
+ }
225
+
226
+ // Default style
227
+ this.canvas.font = '10px sans-serif';
228
+ this._elt.style.font = styleText;
229
+
230
+ computedStyle = getElementStyle(this._elt);
231
+ style.size = computedStyle.fontSize;
232
+ style.weight = getCSSWeightEquivalent(computedStyle.fontWeight);
233
+ style.style = computedStyle.fontStyle;
234
+
235
+ families = computedStyle.fontFamily.split(',');
236
+ for(i = 0; i < families.length; i++) {
237
+ families[i] = families[i].replace(/^["'\s]*/, '').replace(/["'\s]*$/, '');
238
+ }
239
+ style.family = families;
240
+ return this.getComputedStyle(ctxt._styleCache[styleText] = style);
241
+ };
242
+
243
+ proto.buildStyle = function (style){
244
+ return style.style+' '+style.weight+' '+style.size+'px "'+style.family+'"';
245
+ };
246
+
247
+ proto.renderText = function(text, style){
248
+ var face = ctxt.getFaceFromStyle(style),
249
+ scale = (style.size / face.resolution) * 0.75,
250
+ offset = 0, i,
251
+ chars = String(text).split(''),
252
+ length = chars.length;
253
+
254
+ if (!isOpera9) {
255
+ this.scale(scale, -scale);
256
+ this.lineWidth /= scale;
257
+ }
258
+
259
+ for (i = 0; i < length; i++) {
260
+ offset += this.renderGlyph(chars[i], face, scale, offset);
261
+ }
262
+ };
263
+
264
+ if (isOpera9) {
265
+ proto.renderGlyph = function(c, face, scale, offset){
266
+ var i, cpx, cpy, outline, action, length,
267
+ glyph = face.glyphs[c] || face.glyphs[ctxt.options.fallbackCharacter];
268
+
269
+ if (!glyph) return;
270
+
271
+ if (glyph.o) {
272
+ outline = glyph._cachedOutline || (glyph._cachedOutline = glyph.o.split(' '));
273
+ length = outline.length;
274
+ for (i = 0; i < length; ) {
275
+ action = outline[i++];
276
+
277
+ switch(action) {
278
+ case 'm':
279
+ this.moveTo(outline[i++]*scale+offset, outline[i++]*-scale);
280
+ break;
281
+ case 'l':
282
+ this.lineTo(outline[i++]*scale+offset, outline[i++]*-scale);
283
+ break;
284
+ case 'q':
285
+ cpx = outline[i++]*scale+offset;
286
+ cpy = outline[i++]*-scale;
287
+ this.quadraticCurveTo(outline[i++]*scale+offset, outline[i++]*-scale, cpx, cpy);
288
+ break;
289
+ case 'b':
290
+ cpx = outline[i++]*scale+offset;
291
+ cpy = outline[i++]*-scale;
292
+ this.bezierCurveTo(outline[i++]*scale+offset, outline[i++]*-scale, outline[i++]*scale+offset, outline[i++]*-scale, cpx, cpy);
293
+ break;
294
+ }
295
+ }
296
+ }
297
+ return glyph.ha*scale;
298
+ };
299
+ }
300
+ else {
301
+ proto.renderGlyph = function(c, face){
302
+ var i, cpx, cpy, outline, action, length,
303
+ glyph = face.glyphs[c] || face.glyphs[ctxt.options.fallbackCharacter];
304
+
305
+ if (!glyph) return;
306
+
307
+ if (glyph.o) {
308
+ outline = glyph._cachedOutline || (glyph._cachedOutline = glyph.o.split(' '));
309
+ length = outline.length;
310
+ for (i = 0; i < length; ) {
311
+ action = outline[i++];
312
+
313
+ switch(action) {
314
+ case 'm':
315
+ this.moveTo(outline[i++], outline[i++]);
316
+ break;
317
+ case 'l':
318
+ this.lineTo(outline[i++], outline[i++]);
319
+ break;
320
+ case 'q':
321
+ cpx = outline[i++];
322
+ cpy = outline[i++];
323
+ this.quadraticCurveTo(outline[i++], outline[i++], cpx, cpy);
324
+ break;
325
+ case 'b':
326
+ cpx = outline[i++];
327
+ cpy = outline[i++];
328
+ this.bezierCurveTo(outline[i++], outline[i++], outline[i++], outline[i++], cpx, cpy);
329
+ break;
330
+ }
331
+ }
332
+ }
333
+ if (glyph.ha) this.translate(glyph.ha, 0);
334
+ };
335
+ }
336
+
337
+ proto.getTextExtents = function(text, style){
338
+ var width = 0, height = 0, ha = 0,
339
+ face = ctxt.getFaceFromStyle(style),
340
+ i, length = text.length, glyph;
341
+
342
+ for (i = 0; i < length; i++) {
343
+ glyph = face.glyphs[text.charAt(i)] || face.glyphs[ctxt.options.fallbackCharacter];
344
+ width += Math.max(glyph.ha, glyph.x_max);
345
+ ha += glyph.ha;
346
+ }
347
+
348
+ return {
349
+ width: width,
350
+ height: face.lineHeight,
351
+ ha: ha
352
+ };
353
+ };
354
+
355
+ proto.getComputedStyle = function(style){
356
+ var p, canvasStyle = getElementStyle(this.canvas),
357
+ computedStyle = {},
358
+ s = style.size,
359
+ canvasFontSize = parseFloat(canvasStyle.fontSize),
360
+ fontSize = parseFloat(s);
361
+
362
+ for (p in style) {
363
+ computedStyle[p] = style[p];
364
+ }
365
+
366
+ // Compute the size
367
+ if (typeof s === 'number' || s.indexOf('px') != -1)
368
+ computedStyle.size = fontSize;
369
+ else if (s.indexOf('em') != -1)
370
+ computedStyle.size = canvasFontSize * fontSize;
371
+ else if (s.indexOf('%') != -1)
372
+ computedStyle.size = (canvasFontSize / 100) * fontSize;
373
+ else if (s.indexOf('pt') != -1)
374
+ computedStyle.size = fontSize / 0.75;
375
+ else
376
+ computedStyle.size = canvasFontSize;
377
+
378
+ return computedStyle;
379
+ };
380
+
381
+ proto.getTextOffset = function(text, style, face){
382
+ var canvasStyle = getElementStyle(this.canvas),
383
+ metrics = this.measureText(text),
384
+ scale = (style.size / face.resolution) * 0.75,
385
+ offset = {x: 0, y: 0, metrics: metrics, scale: scale};
386
+
387
+ switch (this.textAlign) {
388
+ default:
389
+ case null:
390
+ case 'left': break;
391
+ case 'center': offset.x = -metrics.width/2; break;
392
+ case 'right': offset.x = -metrics.width; break;
393
+ case 'start': offset.x = (canvasStyle.direction == 'rtl') ? -metrics.width : 0; break;
394
+ case 'end': offset.x = (canvasStyle.direction == 'ltr') ? -metrics.width : 0; break;
395
+ }
396
+
397
+ switch (this.textBaseline) {
398
+ case 'alphabetic': break;
399
+ default:
400
+ case null:
401
+ case 'ideographic':
402
+ case 'bottom': offset.y = face.descender; break;
403
+ case 'hanging':
404
+ case 'top': offset.y = face.ascender; break;
405
+ case 'middle': offset.y = (face.ascender + face.descender) / 2; break;
406
+ }
407
+ offset.y *= scale;
408
+ return offset;
409
+ };
410
+
411
+ proto.drawText = function(text, x, y, maxWidth, stroke){
412
+ var style = this.parseStyle(this.font),
413
+ face = ctxt.getFaceFromStyle(style),
414
+ offset = this.getTextOffset(text, style, face);
415
+
416
+ this.save();
417
+ this.translate(x + offset.x, y + offset.y);
418
+ if (face.strokeFont && !stroke) {
419
+ this.strokeStyle = this.fillStyle;
420
+ }
421
+ this.lineCap = "round";
422
+ this.beginPath();
423
+
424
+ if (moz) {
425
+ this.mozTextStyle = this.buildStyle(style);
426
+ this[stroke ? 'mozPathText' : 'mozDrawText'](text);
427
+ }
428
+ else {
429
+ this.scale(ctxt.scaling, ctxt.scaling);
430
+ this.renderText(text, style);
431
+ if (face.strokeFont) {
432
+ this.lineWidth = 2 + style.size * (style.weight == 'bold' ? 0.08 : 0.015) / 2;
433
+ }
434
+ }
435
+
436
+ this[(stroke || (face.strokeFont && !moz)) ? 'stroke' : 'fill']();
437
+
438
+ this.closePath();
439
+ this.restore();
440
+
441
+ if (ctxt.options.debug) {
442
+ var left = Math.floor(offset.x + x) + 0.5,
443
+ top = Math.floor(y)+0.5;
444
+
445
+ this.save();
446
+ this.strokeStyle = '#F00';
447
+ this.lineWidth = 0.5;
448
+ this.beginPath();
449
+
450
+ // Text baseline
451
+ this.moveTo(left + offset.metrics.width, top);
452
+ this.lineTo(left, top);
453
+
454
+ // Text align
455
+ this.moveTo(left - offset.x, top + offset.y);
456
+ this.lineTo(left - offset.x, top + offset.y - style.size);
457
+
458
+ this.stroke();
459
+ this.closePath();
460
+ this.restore();
461
+ }
462
+ };
463
+
464
+ proto.fillText = function(text, x, y, maxWidth){
465
+ this.drawText(text, x, y, maxWidth, false);
466
+ };
467
+
468
+ proto.strokeText = function(text, x, y, maxWidth){
469
+ this.drawText(text, x, y, maxWidth, true);
470
+ };
471
+
472
+ proto.measureText = function(text){
473
+ var style = this.parseStyle(this.font),
474
+ dim = {width: 0};
475
+
476
+ if (moz) {
477
+ this.mozTextStyle = this.buildStyle(style);
478
+ dim.width = this.mozMeasureText(text);
479
+ }
480
+ else {
481
+ var face = ctxt.getFaceFromStyle(style),
482
+ scale = (style.size / face.resolution) * 0.75;
483
+
484
+ dim.width = this.getTextExtents(text, style).ha * scale * ctxt.scaling;
485
+ }
486
+
487
+ return dim;
488
+ };
489
+ })();