1 if(!dojo._hasResource["dojox.charting.Theme"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
2 dojo._hasResource["dojox.charting.Theme"] = true;
3 dojo.provide("dojox.charting.Theme");
4 dojo.require("dojox.charting._color");
7 var dxc=dojox.charting;
8 // TODO: Legend information
10 dxc.Theme = function(/*Object?*/ kwArgs){
12 var def = dxc.Theme._def;
13 dojo.forEach(["chart", "plotarea", "axis", "series", "marker"], function(n){
14 this[n] = dojo.mixin(dojo.clone(def[n]), kwArgs[n]||{});
16 this.markers = dojo.mixin(dojo.clone(dxc.Theme.Markers), kwArgs.markers||{});
18 this.antiAlias = ("antiAlias" in kwArgs)?kwArgs.antiAlias:true;
19 this.assignColors = ("assignColors" in kwArgs)?kwArgs.assignColors:true;
20 this.assignMarkers = ("assignMarkers" in kwArgs)?kwArgs.assignMarkers:true;
21 this._colorCache = null;
23 // push the colors, use _def colors if none passed.
24 kwArgs.colors = kwArgs.colors||def.colors;
25 dojo.forEach(kwArgs.colors, function(item){
26 this.colors.push(item);
29 // private variables for color and marker indexing
30 this._current = { color:0, marker: 0 };
32 this._buildMarkerArray();
37 // A marker is defined by an SVG path segment; it should be defined as
38 // relative motion, and with the assumption that the path segment
39 // will be moved to the value point (i.e prepend Mx,y)
41 CIRCLE: "m-3,0 c0,-4 6,-4 6,0 m-6,0 c0,4 6,4 6,0",
42 SQUARE: "m-3,-3 l0,6 6,0 0,-6 z",
43 DIAMOND: "m0,-3 l3,3 -3,3 -3,-3 z",
44 CROSS: "m0,-3 l0,6 m-3,-3 l6,0",
45 X: "m-3,-3 l6,6 m0,-6 l-6,6",
46 TRIANGLE: "m-3,3 l3,-6 3,6 z",
47 TRIANGLE_INVERTED:"m-3,-3 l3,6 3,-6 z"
50 // all objects are structs used directly in dojox.gfx
59 // TODO: label rotation on axis
61 stroke: { // the axis itself
71 majorTick: { // major ticks on axis
77 minorTick: { // minor ticks on axis
83 font: "normal normal normal 7pt Tahoma", // labels on axis
84 fontColor:"#333" // color of labels
87 outline: {width: 0.1, color: "#ccc"}, // line or outline
88 stroke: {width: 1.5, color: "#333"}, // line or outline
89 fill: "#ccc", // fill, if appropriate
90 font: "normal normal normal 7pt Tahoma", // if there's a label
91 fontColor: "#000" // color of labels
93 marker:{ // any markers on a series.
94 stroke: {width:1}, // stroke or outline
95 fill: "#333", // fill if needed
96 font: "normal normal normal 7pt Tahoma", // label
100 "#000","#111","#222","#333",
101 "#444","#555","#666","#777",
102 "#888","#999","#aaa","#bbb",
108 dojo.extend(dxc.Theme, {
109 defineColors: function(obj){
111 // Generate a set of colors for the theme based on keyword
117 if(kwArgs.cache === undefined){ cache = true; }
118 if(kwArgs.cache == true){ cache = true; }
121 this._colorCache=kwArgs;
123 var mix=this._colorCache||{};
124 kwArgs=dojo.mixin(dojo.clone(mix), kwArgs);
127 var c=[], n=kwArgs.num||32; // the number of colors to generate
129 // we have an array of colors predefined, so fix for the number of series.
130 var l=kwArgs.colors.length;
131 for(var i=0; i<n; i++){
132 c.push(kwArgs.colors[i%l]);
135 }else if(kwArgs.hue){
136 // single hue, generate a set based on brightness
137 var s=kwArgs.saturation||100; // saturation
138 var st=kwArgs.low||30;
139 var end=kwArgs.high||90;
140 var step=(end-st)/n; // brightness steps
141 for(var i=0; i<n; i++){
142 c.push(dxc._color.fromHsb(kwArgs.hue, s, st+(step*i)).toHex());
145 }else if(kwArgs.stops){
146 // create color ranges that are either equally distributed, or
147 // (optionally) based on a passed "offset" property. If you
148 // pass an array of Colors, it will equally distribute, if
149 // you pass an array of structs { color, offset }, it will
150 // use the offset (0.0 - 1.0) to distribute. Note that offset
151 // values should be plotted on a line from 0.0 to 1.0--i.e.
152 // they should be additive. For example:
153 // [ {color, offset:0}, { color, offset:0.2 }, { color, offset:0.5 }, { color, offset:1.0 } ]
155 // If you use stops for colors, you MUST have a color at 0.0 and one
158 // figure out how many stops we have
159 var l=kwArgs.stops.length;
162 "dojox.charting.Theme::defineColors: when using stops to "
163 + "define a color range, you MUST specify at least 2 colors."
167 // figure out if the distribution is equal or not. Note that
168 // colors may not exactly match the stops you define; because
169 // color generation is linear (i.e. evenly divided on a linear
170 // axis), it's very possible that a color will land in between
171 // two stops and not exactly *at* a stop.
173 // The only two colors guaranteed will be the end stops (i.e.
174 // the first and last stop), which will *always* be set as
176 if(typeof(kwArgs.stops[0].offset) == "undefined"){
177 // set up equal offsets
179 for(var i=0; i<l; i++){
181 color:kwArgs.stops[i],
187 kwArgs.stops[0].offset=0;
188 kwArgs.stops[l-1].offset=1;
189 kwArgs.stops.sort(function(a,b){ return a.offset-b.offset; });
191 // create the colors.
193 c.push(kwArgs.stops[0].color.toHex());
195 // TODO: calculate the blend at n/steps and set the color
198 c.push(kwArgs.stops[l-1].color.toHex());
203 _buildMarkerArray: function(){
205 for(var p in this.markers){ this._markers.push(this.markers[p]); }
206 // reset the position
207 this._current.marker=0;
210 addMarker:function(/*String*/ name, /*String*/ segment){
212 // Add a custom marker to this theme.
214 // | myTheme.addMarker("Ellipse", foo);
215 this.markers[name]=segment;
216 this._buildMarkerArray();
218 setMarkers:function(/*Object*/ obj){
220 // Set all the markers of this theme at once. obj should be a
221 // dictionary of keys and path segments.
224 // | myTheme.setMarkers({ "CIRCLE": foo });
226 this._buildMarkerArray();
229 next: function(/*String?*/ type){
231 // get either the next color or the next marker, depending on
232 // what was passed. If type is not passed, it assumes color.
234 // Optional. One of either "color" or "marker". Defaults to
237 // | var color = myTheme.next();
238 // | var color = myTheme.next("color");
239 // | var marker = myTheme.next("marker");
240 if(type == "marker"){
241 return this._markers[ this._current.marker++ % this._markers.length ];
243 return this.colors[ this._current.color++ % this.colors.length ];
248 // resets both marker and color counters back to the start.
249 // Subsequent calls to `next` will retrievie the first value
250 // of each depending on the passed type.
251 this._current = {color: 0, marker: 0};