Blame | Last modification | View Log | RSS feed
if(!dojo._hasResource["dojox.charting.Theme"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource["dojox.charting.Theme"] = true;
dojo.provide("dojox.charting.Theme");
dojo.require("dojox.charting._color");
(function(){
var dxc=dojox.charting;
// TODO: Legend information
dxc.Theme=function(/*object?*/kwArgs){
kwArgs=kwArgs||{};
this.chart=dojo.mixin(dojo.clone(dxc.Theme._def.chart), kwArgs.chart||{});
this.plotarea=dojo.mixin(dojo.clone(dxc.Theme._def.plotarea), kwArgs.plotarea||{});
this.axis=dojo.mixin(dojo.clone(dxc.Theme._def.axis), kwArgs.axis||{});
this.series=dojo.mixin(dojo.clone(dxc.Theme._def.series), kwArgs.series||{});
this.marker=dojo.mixin(dojo.clone(dxc.Theme._def.marker), kwArgs.marker||{});
this.markers=dojo.mixin(dojo.clone(dxc.Theme.Markers), kwArgs.markers||{});
this.colors=[];
this.antiAlias=("antiAlias" in kwArgs)?kwArgs.antiAlias:true;
this.assignColors=("assignColors" in kwArgs)?kwArgs.assignColors:true;
this.assignMarkers=("assignMarkers" in kwArgs)?kwArgs.assignMarkers:true;
this._colorCache=null;
// push the colors, use _def colors if none passed.
kwArgs.colors=kwArgs.colors||dxc.Theme._def.colors;
dojo.forEach(kwArgs.colors, function(item){
this.colors.push(item);
}, this);
// private variables for color and marker indexing
this._current={ color:0, marker: 0 };
this._markers=[];
this._buildMarkerArray();
};
// "static" fields
// default markers.
// A marker is defined by an SVG path segment; it should be defined as
// relative motion, and with the assumption that the path segment
// will be moved to the value point (i.e prepend Mx,y)
dxc.Theme.Markers={
CIRCLE:"m-3,0 c0,-4 6,-4 6,0 m-6,0 c0,4 6,4 6,0",
SQUARE:"m-3,-3 l0,6 6,0 0,-6 z",
DIAMOND:"m0,-3 l3,3 -3,3 -3,-3 z",
CROSS:"m0,-3 l0,6 m-3,-3 l6,0",
X:"m-3,-3 l6,6 m0,-6 l-6,6",
TRIANGLE:"m-3,3 l3,-6 3,6 z",
TRIANGLE_INVERTED:"m-3,-3 l3,6 3,-6 z"
};
dxc.Theme._def={
// all objects are structs used directly in dojox.gfx
chart:{
stroke:null,
fill: "white"
},
plotarea:{
stroke:null,
fill: "white"
},
// TODO: label rotation on axis
axis:{
stroke:{ color:"#333",width:1 }, // the axis itself
line:{ color:"#ccc",width:1,style:"Dot",cap:"round" }, // gridlines
majorTick:{ color:"#666", width:1, length:6, position:"center" }, // major ticks on axis
minorTick:{ color:"#666", width:0.8, length:3, position:"center" }, // minor ticks on axis
font:"normal normal normal 7pt Tahoma", // labels on axis
fontColor:"#333" // color of labels
},
series:{
outline: {width: 2, color: "#ccc"}, // line or outline
stroke: {width: 2, color: "#333"}, // line or outline
fill: "#ccc", // fill, if appropriate
font: "normal normal normal 7pt Tahoma", // if there's a label
fontColor: "#000" // color of labels
},
marker:{ // any markers on a series.
stroke: {width:1}, // stroke or outline
fill: "#333", // fill if needed
font: "normal normal normal 7pt Tahoma", // label
fontColor: "#000"
},
colors:[
"#000","#111","#222","#333",
"#444","#555","#666","#777",
"#888","#999","#aaa","#bbb",
"#ccc"
]
};
// prototype methods
dojo.extend(dxc.Theme, {
defineColors: function(obj){
// we can generate a set of colors based on keyword arguments
var kwArgs=obj||{};
// deal with caching
var cache=false;
if(kwArgs.cache===undefined){ cache=true; }
if(kwArgs.cache==true){ cache=true; }
if(cache){
this._colorCache=kwArgs;
} else {
var mix=this._colorCache||{};
kwArgs=dojo.mixin(dojo.clone(mix), kwArgs);
}
var c=[], n=kwArgs.num||32; // the number of colors to generate
if(kwArgs.colors){
// we have an array of colors predefined, so fix for the number of series.
var l=kwArgs.colors.length;
for(var i=0; i<n; i++){
c.push(kwArgs.colors[i%l]);
}
this.colors=c;
}
else if(kwArgs.hue){
// single hue, generate a set based on brightness
var s=kwArgs.saturation||100; // saturation
var st=kwArgs.low||30;
var end=kwArgs.high||90;
var step=(end-st)/n; // brightness steps
for(var i=0; i<n; i++){
c.push(dxc._color.fromHsb(kwArgs.hue, s, st+(step*i)).toHex());
}
this.colors=c;
}
else if(kwArgs.stops){
// create color ranges that are either equally distributed, or
// (optionally) based on a passed "offset" property. If you
// pass an array of Colors, it will equally distribute, if
// you pass an array of structs { color, offset }, it will
// use the offset (0.0 - 1.0) to distribute. Note that offset
// values should be plotted on a line from 0.0 to 1.0--i.e.
// they should be additive. For example:
// [ {color, offset:0}, { color, offset:0.2 }, { color, offset:0.5 }, { color, offset:1.0 } ]
//
// If you use stops for colors, you MUST have a color at 0.0 and one
// at 1.0.
// figure out how many stops we have
var l=kwArgs.stops.length;
if(l<2){
throw new Error(
"dojox.charting.Theme::defineColors: when using stops to "
+ "define a color range, you MUST specify at least 2 colors."
);
}
// figure out if the distribution is equal or not. Note that
// colors may not exactly match the stops you define; because
// color generation is linear (i.e. evenly divided on a linear
// axis), it's very possible that a color will land in between
// two stops and not exactly *at* a stop.
//
// The only two colors guaranteed will be the end stops (i.e.
// the first and last stop), which will *always* be set as
// the end stops.
if(typeof(kwArgs.stops[0].offset)=="undefined"){
// set up equal offsets
var off=1/(l-1);
for(var i=0; i<l; i++){
kwArgs.stops[i]={
color:kwArgs.stops[i],
offset:off*i
};
}
}
// ensure the ends.
kwArgs.stops[0].offset=0;
kwArgs.stops[l-1].offset=1;
kwArgs.stops.sort(function(a,b){ return a.offset-b.offset; });
// create the colors.
// first stop.
c.push(kwArgs.stops[0].color.toHex());
// TODO: calculate the blend at n/steps and set the color
// last stop
c.push(kwArgs.stops[l-1].color.toHex());
this.colors=c;
}
},
_buildMarkerArray: function(){
this._markers=[];
for(var p in this.markers){ this._markers.push(this.markers[p]); }
// reset the position
this._current.marker=0;
},
addMarker:function(/* string */name, /*string*/segment){
// summary
// Add a custom marker to this theme.
//
// example
// myTheme.addMarker("Ellipse", foo);
this.markers[name]=segment;
this._buildMarkerArray();
},
setMarkers:function(/* object */obj){
// summary
// Set all the markers of this theme at once. obj should be
// a dictionary of keys and path segments.
//
// example
// myTheme.setMarkers({ "CIRCLE": foo });
this.markers=obj;
this._buildMarkerArray();
},
next: function(/* string? */type){
// summary
// get either the next color or the next marker, depending on what was
// passed. If type is not passed, it assumes color.
//
// example
// var color=myTheme.next();
// var color=myTheme.next("color");
// var marker=myTheme.next("marker");
if(!type) type="color";
if(type=="color"){
return this.colors[this._current.color++%this.colors.length];
}
else if(type=="marker"){
return this._markers[this._current.marker++%this._markers.length];
}
},
clear: function(){
this._current = {color: 0, marker: 0};
}
});
})();
}