Upgrade to ExtJS 4.0.2 - Released 06/09/2011
[extjs.git] / src / chart / theme / Theme.js
1 /*
2
3 This file is part of Ext JS 4
4
5 Copyright (c) 2011 Sencha Inc
6
7 Contact:  http://www.sencha.com/contact
8
9 GNU General Public License Usage
10 This file may be used under the terms of the GNU General Public License version 3.0 as published by the Free Software Foundation and appearing in the file LICENSE included in the packaging of this file.  Please review the following information to ensure the GNU General Public License version 3.0 requirements will be met: http://www.gnu.org/copyleft/gpl.html.
11
12 If you are unsure which license is appropriate for your use, please contact the sales department at http://www.sencha.com/contact.
13
14 */
15 /**
16  * @class Ext.chart.theme.Theme
17  * 
18  * Provides chart theming.
19  * 
20  * Used as mixins by Ext.chart.Chart.
21  */
22 Ext.define('Ext.chart.theme.Theme', {
23
24     /* Begin Definitions */
25
26     requires: ['Ext.draw.Color'],
27
28     /* End Definitions */
29
30     theme: 'Base',
31     themeAttrs: false,
32     
33     initTheme: function(theme) {
34         var me = this,
35             themes = Ext.chart.theme,
36             key, gradients;
37         if (theme) {
38             theme = theme.split(':');
39             for (key in themes) {
40                 if (key == theme[0]) {
41                     gradients = theme[1] == 'gradients';
42                     me.themeAttrs = new themes[key]({
43                         useGradients: gradients
44                     });
45                     if (gradients) {
46                         me.gradients = me.themeAttrs.gradients;
47                     }
48                     if (me.themeAttrs.background) {
49                         me.background = me.themeAttrs.background;
50                     }
51                     return;
52                 }
53             }
54             //<debug>
55             Ext.Error.raise('No theme found named "' + theme + '"');
56             //</debug>
57         }
58     }
59 }, 
60 // This callback is executed right after when the class is created. This scope refers to the newly created class itself
61 function() {
62    /* Theme constructor: takes either a complex object with styles like:
63   
64    {
65         axis: {
66             fill: '#000',
67             'stroke-width': 1
68         },
69         axisLabelTop: {
70             fill: '#000',
71             font: '11px Arial'
72         },
73         axisLabelLeft: {
74             fill: '#000',
75             font: '11px Arial'
76         },
77         axisLabelRight: {
78             fill: '#000',
79             font: '11px Arial'
80         },
81         axisLabelBottom: {
82             fill: '#000',
83             font: '11px Arial'
84         },
85         axisTitleTop: {
86             fill: '#000',
87             font: '11px Arial'
88         },
89         axisTitleLeft: {
90             fill: '#000',
91             font: '11px Arial'
92         },
93         axisTitleRight: {
94             fill: '#000',
95             font: '11px Arial'
96         },
97         axisTitleBottom: {
98             fill: '#000',
99             font: '11px Arial'
100         },
101         series: {
102             'stroke-width': 1
103         },
104         seriesLabel: {
105             font: '12px Arial',
106             fill: '#333'
107         },
108         marker: {
109             stroke: '#555',
110             fill: '#000',
111             radius: 3,
112             size: 3
113         },
114         seriesThemes: [{
115             fill: '#C6DBEF'
116         }, {
117             fill: '#9ECAE1'
118         }, {
119             fill: '#6BAED6'
120         }, {
121             fill: '#4292C6'
122         }, {
123             fill: '#2171B5'
124         }, {
125             fill: '#084594'
126         }],
127         markerThemes: [{
128             fill: '#084594',
129             type: 'circle' 
130         }, {
131             fill: '#2171B5',
132             type: 'cross'
133         }, {
134             fill: '#4292C6',
135             type: 'plus'
136         }]
137     }
138   
139   ...or also takes just an array of colors and creates the complex object:
140   
141   {
142       colors: ['#aaa', '#bcd', '#eee']
143   }
144   
145   ...or takes just a base color and makes a theme from it
146   
147   {
148       baseColor: '#bce'
149   }
150   
151   To create a new theme you may add it to the Themes object:
152   
153   Ext.chart.theme.MyNewTheme = Ext.extend(Object, {
154       constructor: function(config) {
155           Ext.chart.theme.call(this, config, {
156               baseColor: '#mybasecolor'
157           });
158       }
159   });
160   
161   //Proposal:
162   Ext.chart.theme.MyNewTheme = Ext.chart.createTheme('#basecolor');
163   
164   ...and then to use it provide the name of the theme (as a lower case string) in the chart config.
165   
166   {
167       theme: 'mynewtheme'
168   }
169  */
170
171 (function() {
172     Ext.chart.theme = function(config, base) {
173         config = config || {};
174         var i = 0, l, colors, color,
175             seriesThemes, markerThemes,
176             seriesTheme, markerTheme, 
177             key, gradients = [],
178             midColor, midL;
179         
180         if (config.baseColor) {
181             midColor = Ext.draw.Color.fromString(config.baseColor);
182             midL = midColor.getHSL()[2];
183             if (midL < 0.15) {
184                 midColor = midColor.getLighter(0.3);
185             } else if (midL < 0.3) {
186                 midColor = midColor.getLighter(0.15);
187             } else if (midL > 0.85) {
188                 midColor = midColor.getDarker(0.3);
189             } else if (midL > 0.7) {
190                 midColor = midColor.getDarker(0.15);
191             }
192             config.colors = [ midColor.getDarker(0.3).toString(),
193                               midColor.getDarker(0.15).toString(),
194                               midColor.toString(),
195                               midColor.getLighter(0.15).toString(),
196                               midColor.getLighter(0.3).toString()];
197
198             delete config.baseColor;
199         }
200         if (config.colors) {
201             colors = config.colors.slice();
202             markerThemes = base.markerThemes;
203             seriesThemes = base.seriesThemes;
204             l = colors.length;
205             base.colors = colors;
206             for (; i < l; i++) {
207                 color = colors[i];
208                 markerTheme = markerThemes[i] || {};
209                 seriesTheme = seriesThemes[i] || {};
210                 markerTheme.fill = seriesTheme.fill = markerTheme.stroke = seriesTheme.stroke = color;
211                 markerThemes[i] = markerTheme;
212                 seriesThemes[i] = seriesTheme;
213             }
214             base.markerThemes = markerThemes.slice(0, l);
215             base.seriesThemes = seriesThemes.slice(0, l);
216         //the user is configuring something in particular (either markers, series or pie slices)
217         }
218         for (key in base) {
219             if (key in config) {
220                 if (Ext.isObject(config[key]) && Ext.isObject(base[key])) {
221                     Ext.apply(base[key], config[key]);
222                 } else {
223                     base[key] = config[key];
224                 }
225             }
226         }
227         if (config.useGradients) {
228             colors = base.colors || (function () {
229                 var ans = [];
230                 for (i = 0, seriesThemes = base.seriesThemes, l = seriesThemes.length; i < l; i++) {
231                     ans.push(seriesThemes[i].fill || seriesThemes[i].stroke);
232                 }
233                 return ans;
234             })();
235             for (i = 0, l = colors.length; i < l; i++) {
236                 midColor = Ext.draw.Color.fromString(colors[i]);
237                 if (midColor) {
238                     color = midColor.getDarker(0.1).toString();
239                     midColor = midColor.toString();
240                     key = 'theme-' + midColor.substr(1) + '-' + color.substr(1);
241                     gradients.push({
242                         id: key,
243                         angle: 45,
244                         stops: {
245                             0: {
246                                 color: midColor.toString()
247                             },
248                             100: {
249                                 color: color.toString()
250                             }
251                         }
252                     });
253                     colors[i] = 'url(#' + key + ')'; 
254                 }
255             }
256             base.gradients = gradients;
257             base.colors = colors;
258         }
259         /*
260         base.axis = Ext.apply(base.axis || {}, config.axis || {});
261         base.axisLabel = Ext.apply(base.axisLabel || {}, config.axisLabel || {});
262         base.axisTitle = Ext.apply(base.axisTitle || {}, config.axisTitle || {});
263         */
264         Ext.apply(this, base);
265     };
266 })();
267 });
268