2150 |
mathias |
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");
|
|
|
5 |
|
|
|
6 |
(function(){
|
|
|
7 |
var dxc=dojox.charting;
|
|
|
8 |
// TODO: Legend information
|
|
|
9 |
dxc.Theme=function(/*object?*/kwArgs){
|
|
|
10 |
kwArgs=kwArgs||{};
|
|
|
11 |
this.chart=dojo.mixin(dojo.clone(dxc.Theme._def.chart), kwArgs.chart||{});
|
|
|
12 |
this.plotarea=dojo.mixin(dojo.clone(dxc.Theme._def.plotarea), kwArgs.plotarea||{});
|
|
|
13 |
this.axis=dojo.mixin(dojo.clone(dxc.Theme._def.axis), kwArgs.axis||{});
|
|
|
14 |
this.series=dojo.mixin(dojo.clone(dxc.Theme._def.series), kwArgs.series||{});
|
|
|
15 |
this.marker=dojo.mixin(dojo.clone(dxc.Theme._def.marker), kwArgs.marker||{});
|
|
|
16 |
this.markers=dojo.mixin(dojo.clone(dxc.Theme.Markers), kwArgs.markers||{});
|
|
|
17 |
this.colors=[];
|
|
|
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;
|
|
|
22 |
|
|
|
23 |
// push the colors, use _def colors if none passed.
|
|
|
24 |
kwArgs.colors=kwArgs.colors||dxc.Theme._def.colors;
|
|
|
25 |
dojo.forEach(kwArgs.colors, function(item){
|
|
|
26 |
this.colors.push(item);
|
|
|
27 |
}, this);
|
|
|
28 |
|
|
|
29 |
// private variables for color and marker indexing
|
|
|
30 |
this._current={ color:0, marker: 0 };
|
|
|
31 |
this._markers=[];
|
|
|
32 |
this._buildMarkerArray();
|
|
|
33 |
};
|
|
|
34 |
|
|
|
35 |
// "static" fields
|
|
|
36 |
// default markers.
|
|
|
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)
|
|
|
40 |
dxc.Theme.Markers={
|
|
|
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"
|
|
|
48 |
};
|
|
|
49 |
dxc.Theme._def={
|
|
|
50 |
// all objects are structs used directly in dojox.gfx
|
|
|
51 |
chart:{
|
|
|
52 |
stroke:null,
|
|
|
53 |
fill: "white"
|
|
|
54 |
},
|
|
|
55 |
plotarea:{
|
|
|
56 |
stroke:null,
|
|
|
57 |
fill: "white"
|
|
|
58 |
},
|
|
|
59 |
// TODO: label rotation on axis
|
|
|
60 |
axis:{
|
|
|
61 |
stroke:{ color:"#333",width:1 }, // the axis itself
|
|
|
62 |
line:{ color:"#ccc",width:1,style:"Dot",cap:"round" }, // gridlines
|
|
|
63 |
majorTick:{ color:"#666", width:1, length:6, position:"center" }, // major ticks on axis
|
|
|
64 |
minorTick:{ color:"#666", width:0.8, length:3, position:"center" }, // minor ticks on axis
|
|
|
65 |
font:"normal normal normal 7pt Tahoma", // labels on axis
|
|
|
66 |
fontColor:"#333" // color of labels
|
|
|
67 |
},
|
|
|
68 |
series:{
|
|
|
69 |
outline: {width: 2, color: "#ccc"}, // line or outline
|
|
|
70 |
stroke: {width: 2, color: "#333"}, // line or outline
|
|
|
71 |
fill: "#ccc", // fill, if appropriate
|
|
|
72 |
font: "normal normal normal 7pt Tahoma", // if there's a label
|
|
|
73 |
fontColor: "#000" // color of labels
|
|
|
74 |
},
|
|
|
75 |
marker:{ // any markers on a series.
|
|
|
76 |
stroke: {width:1}, // stroke or outline
|
|
|
77 |
fill: "#333", // fill if needed
|
|
|
78 |
font: "normal normal normal 7pt Tahoma", // label
|
|
|
79 |
fontColor: "#000"
|
|
|
80 |
},
|
|
|
81 |
colors:[
|
|
|
82 |
"#000","#111","#222","#333",
|
|
|
83 |
"#444","#555","#666","#777",
|
|
|
84 |
"#888","#999","#aaa","#bbb",
|
|
|
85 |
"#ccc"
|
|
|
86 |
]
|
|
|
87 |
};
|
|
|
88 |
|
|
|
89 |
// prototype methods
|
|
|
90 |
dojo.extend(dxc.Theme, {
|
|
|
91 |
defineColors: function(obj){
|
|
|
92 |
// we can generate a set of colors based on keyword arguments
|
|
|
93 |
var kwArgs=obj||{};
|
|
|
94 |
|
|
|
95 |
// deal with caching
|
|
|
96 |
var cache=false;
|
|
|
97 |
if(kwArgs.cache===undefined){ cache=true; }
|
|
|
98 |
if(kwArgs.cache==true){ cache=true; }
|
|
|
99 |
|
|
|
100 |
if(cache){
|
|
|
101 |
this._colorCache=kwArgs;
|
|
|
102 |
} else {
|
|
|
103 |
var mix=this._colorCache||{};
|
|
|
104 |
kwArgs=dojo.mixin(dojo.clone(mix), kwArgs);
|
|
|
105 |
}
|
|
|
106 |
|
|
|
107 |
var c=[], n=kwArgs.num||32; // the number of colors to generate
|
|
|
108 |
if(kwArgs.colors){
|
|
|
109 |
// we have an array of colors predefined, so fix for the number of series.
|
|
|
110 |
var l=kwArgs.colors.length;
|
|
|
111 |
for(var i=0; i<n; i++){
|
|
|
112 |
c.push(kwArgs.colors[i%l]);
|
|
|
113 |
}
|
|
|
114 |
this.colors=c;
|
|
|
115 |
}
|
|
|
116 |
else if(kwArgs.hue){
|
|
|
117 |
// single hue, generate a set based on brightness
|
|
|
118 |
var s=kwArgs.saturation||100; // saturation
|
|
|
119 |
var st=kwArgs.low||30;
|
|
|
120 |
var end=kwArgs.high||90;
|
|
|
121 |
var step=(end-st)/n; // brightness steps
|
|
|
122 |
for(var i=0; i<n; i++){
|
|
|
123 |
c.push(dxc._color.fromHsb(kwArgs.hue, s, st+(step*i)).toHex());
|
|
|
124 |
}
|
|
|
125 |
this.colors=c;
|
|
|
126 |
}
|
|
|
127 |
else if(kwArgs.stops){
|
|
|
128 |
// create color ranges that are either equally distributed, or
|
|
|
129 |
// (optionally) based on a passed "offset" property. If you
|
|
|
130 |
// pass an array of Colors, it will equally distribute, if
|
|
|
131 |
// you pass an array of structs { color, offset }, it will
|
|
|
132 |
// use the offset (0.0 - 1.0) to distribute. Note that offset
|
|
|
133 |
// values should be plotted on a line from 0.0 to 1.0--i.e.
|
|
|
134 |
// they should be additive. For example:
|
|
|
135 |
// [ {color, offset:0}, { color, offset:0.2 }, { color, offset:0.5 }, { color, offset:1.0 } ]
|
|
|
136 |
//
|
|
|
137 |
// If you use stops for colors, you MUST have a color at 0.0 and one
|
|
|
138 |
// at 1.0.
|
|
|
139 |
|
|
|
140 |
// figure out how many stops we have
|
|
|
141 |
var l=kwArgs.stops.length;
|
|
|
142 |
if(l<2){
|
|
|
143 |
throw new Error(
|
|
|
144 |
"dojox.charting.Theme::defineColors: when using stops to "
|
|
|
145 |
+ "define a color range, you MUST specify at least 2 colors."
|
|
|
146 |
);
|
|
|
147 |
}
|
|
|
148 |
|
|
|
149 |
// figure out if the distribution is equal or not. Note that
|
|
|
150 |
// colors may not exactly match the stops you define; because
|
|
|
151 |
// color generation is linear (i.e. evenly divided on a linear
|
|
|
152 |
// axis), it's very possible that a color will land in between
|
|
|
153 |
// two stops and not exactly *at* a stop.
|
|
|
154 |
//
|
|
|
155 |
// The only two colors guaranteed will be the end stops (i.e.
|
|
|
156 |
// the first and last stop), which will *always* be set as
|
|
|
157 |
// the end stops.
|
|
|
158 |
if(typeof(kwArgs.stops[0].offset)=="undefined"){
|
|
|
159 |
// set up equal offsets
|
|
|
160 |
var off=1/(l-1);
|
|
|
161 |
for(var i=0; i<l; i++){
|
|
|
162 |
kwArgs.stops[i]={
|
|
|
163 |
color:kwArgs.stops[i],
|
|
|
164 |
offset:off*i
|
|
|
165 |
};
|
|
|
166 |
}
|
|
|
167 |
}
|
|
|
168 |
// ensure the ends.
|
|
|
169 |
kwArgs.stops[0].offset=0;
|
|
|
170 |
kwArgs.stops[l-1].offset=1;
|
|
|
171 |
kwArgs.stops.sort(function(a,b){ return a.offset-b.offset; });
|
|
|
172 |
|
|
|
173 |
// create the colors.
|
|
|
174 |
// first stop.
|
|
|
175 |
c.push(kwArgs.stops[0].color.toHex());
|
|
|
176 |
|
|
|
177 |
// TODO: calculate the blend at n/steps and set the color
|
|
|
178 |
|
|
|
179 |
// last stop
|
|
|
180 |
c.push(kwArgs.stops[l-1].color.toHex());
|
|
|
181 |
this.colors=c;
|
|
|
182 |
}
|
|
|
183 |
},
|
|
|
184 |
|
|
|
185 |
_buildMarkerArray: function(){
|
|
|
186 |
this._markers=[];
|
|
|
187 |
for(var p in this.markers){ this._markers.push(this.markers[p]); }
|
|
|
188 |
// reset the position
|
|
|
189 |
this._current.marker=0;
|
|
|
190 |
},
|
|
|
191 |
|
|
|
192 |
addMarker:function(/* string */name, /*string*/segment){
|
|
|
193 |
// summary
|
|
|
194 |
// Add a custom marker to this theme.
|
|
|
195 |
//
|
|
|
196 |
// example
|
|
|
197 |
// myTheme.addMarker("Ellipse", foo);
|
|
|
198 |
this.markers[name]=segment;
|
|
|
199 |
this._buildMarkerArray();
|
|
|
200 |
},
|
|
|
201 |
setMarkers:function(/* object */obj){
|
|
|
202 |
// summary
|
|
|
203 |
// Set all the markers of this theme at once. obj should be
|
|
|
204 |
// a dictionary of keys and path segments.
|
|
|
205 |
//
|
|
|
206 |
// example
|
|
|
207 |
// myTheme.setMarkers({ "CIRCLE": foo });
|
|
|
208 |
this.markers=obj;
|
|
|
209 |
this._buildMarkerArray();
|
|
|
210 |
},
|
|
|
211 |
|
|
|
212 |
next: function(/* string? */type){
|
|
|
213 |
// summary
|
|
|
214 |
// get either the next color or the next marker, depending on what was
|
|
|
215 |
// passed. If type is not passed, it assumes color.
|
|
|
216 |
//
|
|
|
217 |
// example
|
|
|
218 |
// var color=myTheme.next();
|
|
|
219 |
// var color=myTheme.next("color");
|
|
|
220 |
// var marker=myTheme.next("marker");
|
|
|
221 |
if(!type) type="color";
|
|
|
222 |
if(type=="color"){
|
|
|
223 |
return this.colors[this._current.color++%this.colors.length];
|
|
|
224 |
}
|
|
|
225 |
else if(type=="marker"){
|
|
|
226 |
return this._markers[this._current.marker++%this._markers.length];
|
|
|
227 |
}
|
|
|
228 |
},
|
|
|
229 |
clear: function(){
|
|
|
230 |
this._current = {color: 0, marker: 0};
|
|
|
231 |
}
|
|
|
232 |
});
|
|
|
233 |
})();
|
|
|
234 |
|
|
|
235 |
}
|