Theme.js 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633
  1. /*
  2. Copyright (c) 2004-2012, The Dojo Foundation All Rights Reserved.
  3. Available via Academic Free License >= 2.1 OR the modified BSD license.
  4. see: http://dojotoolkit.org/license for details
  5. */
  6. if(!dojo._hasResource["dojox.charting.Theme"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
  7. dojo._hasResource["dojox.charting.Theme"] = true;
  8. dojo.provide("dojox.charting.Theme");
  9. dojo.require("dojox.color");
  10. dojo.require("dojox.color.Palette");
  11. dojo.require("dojox.lang.utils");
  12. dojo.require("dojox.gfx.gradutils");
  13. dojo.declare("dojox.charting.Theme", null, {
  14. // summary:
  15. // A Theme is a pre-defined object, primarily JSON-based, that makes up the definitions to
  16. // style a chart.
  17. //
  18. // description:
  19. // While you can set up style definitions on a chart directly (usually through the various add methods
  20. // on a dojox.charting.Chart2D object), a Theme simplifies this manual setup by allowing you to
  21. // pre-define all of the various visual parameters of each element in a chart.
  22. //
  23. // Most of the properties of a Theme are straight-forward; if something is line-based (such as
  24. // an axis or the ticks on an axis), they will be defined using basic stroke parameters. Likewise,
  25. // if an element is primarily block-based (such as the background of a chart), it will be primarily
  26. // fill-based.
  27. //
  28. // In addition (for convenience), a Theme definition does not have to contain the entire JSON-based
  29. // structure. Each theme is built on top of a default theme (which serves as the basis for the theme
  30. // "GreySkies"), and is mixed into the default theme object. This allows you to create a theme based,
  31. // say, solely on colors for data series.
  32. //
  33. // Defining a new theme is relatively easy; see any of the themes in dojox.charting.themes for examples
  34. // on how to define your own.
  35. //
  36. // When you set a theme on a chart, the theme itself is deep-cloned. This means that you cannot alter
  37. // the theme itself after setting the theme value on a chart, and expect it to change your chart. If you
  38. // are looking to make alterations to a theme for a chart, the suggestion would be to create your own
  39. // theme, based on the one you want to use, that makes those alterations before it is applied to a chart.
  40. //
  41. // Finally, a Theme contains a number of functions to facilitate rendering operations on a chart--the main
  42. // helper of which is the ~next~ method, in which a chart asks for the information for the next data series
  43. // to be rendered.
  44. //
  45. // A note on colors:
  46. // The Theme constructor was on the use of dojox.color.Palette (in general) for creating a visually distinct
  47. // set of colors for usage in a chart. A palette is usually comprised of 5 different color definitions, and
  48. // no more. If you have a need to render a chart with more than 5 data elements, you can simply "push"
  49. // new color definitions into the theme's .color array. Make sure that you do that with the actual
  50. // theme object from a Chart, and not in the theme itself (i.e. either do that before using .setTheme
  51. // on a chart).
  52. //
  53. // example:
  54. // The default theme (and structure) looks like so:
  55. // | // all objects are structs used directly in dojox.gfx
  56. // | chart:{
  57. // | stroke: null,
  58. // | fill: "white",
  59. // | pageStyle: null // suggested page style as an object suitable for dojo.style()
  60. // | },
  61. // | plotarea:{
  62. // | stroke: null,
  63. // | fill: "white"
  64. // | },
  65. // | axis:{
  66. // | stroke: { // the axis itself
  67. // | color: "#333",
  68. // | width: 1
  69. // | },
  70. // | tick: { // used as a foundation for all ticks
  71. // | color: "#666",
  72. // | position: "center",
  73. // | font: "normal normal normal 7pt Tahoma", // labels on axis
  74. // | fontColor: "#333" // color of labels
  75. // | },
  76. // | majorTick: { // major ticks on axis, and used for major gridlines
  77. // | width: 1,
  78. // | length: 6
  79. // | },
  80. // | minorTick: { // minor ticks on axis, and used for minor gridlines
  81. // | width: 0.8,
  82. // | length: 3
  83. // | },
  84. // | microTick: { // minor ticks on axis, and used for minor gridlines
  85. // | width: 0.5,
  86. // | length: 1
  87. // | }
  88. // | },
  89. // | series: {
  90. // | stroke: {width: 1.5, color: "#333"}, // line
  91. // | outline: {width: 0.1, color: "#ccc"}, // outline
  92. // | //shadow: {dx: 1, dy: 1, width: 2, color: [0, 0, 0, 0.3]},
  93. // | shadow: null, // no shadow
  94. // | fill: "#ccc", // fill, if appropriate
  95. // | font: "normal normal normal 8pt Tahoma", // if there's a label
  96. // | fontColor: "#000" // color of labels
  97. // | labelWiring: {width: 1, color: "#ccc"}, // connect marker and target data item(slice, column, bar...)
  98. // | },
  99. // | marker: { // any markers on a series
  100. // | symbol: "m-3,3 l3,-6 3,6 z", // symbol
  101. // | stroke: {width: 1.5, color: "#333"}, // stroke
  102. // | outline: {width: 0.1, color: "#ccc"}, // outline
  103. // | shadow: null, // no shadow
  104. // | fill: "#ccc", // fill if needed
  105. // | font: "normal normal normal 8pt Tahoma", // label
  106. // | fontColor: "#000"
  107. // | }
  108. //
  109. // example:
  110. // Defining a new theme is pretty simple:
  111. // | dojox.charting.themes.Grasslands = new dojox.charting.Theme({
  112. // | colors: [ "#70803a", "#dde574", "#788062", "#b1cc5d", "#eff2c2" ]
  113. // | });
  114. // |
  115. // | myChart.setTheme(dojox.charting.themes.Grasslands);
  116. shapeSpaces: {shape: 1, shapeX: 1, shapeY: 1},
  117. constructor: function(kwArgs){
  118. // summary:
  119. // Initialize a theme using the keyword arguments. Note that the arguments
  120. // look like the example (above), and may include a few more parameters.
  121. kwArgs = kwArgs || {};
  122. // populate theme with defaults updating them if needed
  123. var def = dojox.charting.Theme.defaultTheme;
  124. dojo.forEach(["chart", "plotarea", "axis", "series", "marker"], function(name){
  125. this[name] = dojo.delegate(def[name], kwArgs[name]);
  126. }, this);
  127. // personalize theme
  128. if(kwArgs.seriesThemes && kwArgs.seriesThemes.length){
  129. this.colors = null;
  130. this.seriesThemes = kwArgs.seriesThemes.slice(0);
  131. }else{
  132. this.seriesThemes = null;
  133. this.colors = (kwArgs.colors || dojox.charting.Theme.defaultColors).slice(0);
  134. }
  135. this.markerThemes = null;
  136. if(kwArgs.markerThemes && kwArgs.markerThemes.length){
  137. this.markerThemes = kwArgs.markerThemes.slice(0);
  138. }
  139. this.markers = kwArgs.markers ? dojo.clone(kwArgs.markers) : dojo.delegate(dojox.charting.Theme.defaultMarkers);
  140. // set flags
  141. this.noGradConv = kwArgs.noGradConv;
  142. this.noRadialConv = kwArgs.noRadialConv;
  143. if(kwArgs.reverseFills){
  144. this.reverseFills();
  145. }
  146. // private housekeeping
  147. this._current = 0;
  148. this._buildMarkerArray();
  149. },
  150. clone: function(){
  151. // summary:
  152. // Clone the current theme.
  153. // returns: dojox.charting.Theme
  154. // The cloned theme; any alterations made will not affect the original.
  155. var theme = new dojox.charting.Theme({
  156. // theme components
  157. chart: this.chart,
  158. plotarea: this.plotarea,
  159. axis: this.axis,
  160. series: this.series,
  161. marker: this.marker,
  162. // individual arrays
  163. colors: this.colors,
  164. markers: this.markers,
  165. seriesThemes: this.seriesThemes,
  166. markerThemes: this.markerThemes,
  167. // flags
  168. noGradConv: this.noGradConv,
  169. noRadialConv: this.noRadialConv
  170. });
  171. // copy custom methods
  172. dojo.forEach(
  173. ["clone", "clear", "next", "skip", "addMixin", "post", "getTick"],
  174. function(name){
  175. if(this.hasOwnProperty(name)){
  176. theme[name] = this[name];
  177. }
  178. },
  179. this
  180. );
  181. return theme; // dojox.charting.Theme
  182. },
  183. clear: function(){
  184. // summary:
  185. // Clear and reset the internal pointer to start fresh.
  186. this._current = 0;
  187. },
  188. next: function(elementType, mixin, doPost){
  189. // summary:
  190. // Get the next color or series theme.
  191. // elementType: String?
  192. // An optional element type (for use with series themes)
  193. // mixin: Object?
  194. // An optional object to mix into the theme.
  195. // doPost: Boolean?
  196. // A flag to post-process the results.
  197. // returns: Object
  198. // An object of the structure { series, marker, symbol }
  199. var merge = dojox.lang.utils.merge, series, marker;
  200. if(this.colors){
  201. series = dojo.delegate(this.series);
  202. marker = dojo.delegate(this.marker);
  203. var color = new dojo.Color(this.colors[this._current % this.colors.length]), old;
  204. // modify the stroke
  205. if(series.stroke && series.stroke.color){
  206. series.stroke = dojo.delegate(series.stroke);
  207. old = new dojo.Color(series.stroke.color);
  208. series.stroke.color = new dojo.Color(color);
  209. series.stroke.color.a = old.a;
  210. }else{
  211. series.stroke = {color: color};
  212. }
  213. if(marker.stroke && marker.stroke.color){
  214. marker.stroke = dojo.delegate(marker.stroke);
  215. old = new dojo.Color(marker.stroke.color);
  216. marker.stroke.color = new dojo.Color(color);
  217. marker.stroke.color.a = old.a;
  218. }else{
  219. marker.stroke = {color: color};
  220. }
  221. // modify the fill
  222. if(!series.fill || series.fill.type){
  223. series.fill = color;
  224. }else{
  225. old = new dojo.Color(series.fill);
  226. series.fill = new dojo.Color(color);
  227. series.fill.a = old.a;
  228. }
  229. if(!marker.fill || marker.fill.type){
  230. marker.fill = color;
  231. }else{
  232. old = new dojo.Color(marker.fill);
  233. marker.fill = new dojo.Color(color);
  234. marker.fill.a = old.a;
  235. }
  236. }else{
  237. series = this.seriesThemes ?
  238. merge(this.series, this.seriesThemes[this._current % this.seriesThemes.length]) :
  239. this.series;
  240. marker = this.markerThemes ?
  241. merge(this.marker, this.markerThemes[this._current % this.markerThemes.length]) :
  242. series;
  243. }
  244. var symbol = marker && marker.symbol || this._markers[this._current % this._markers.length];
  245. var theme = {series: series, marker: marker, symbol: symbol};
  246. // advance the counter
  247. ++this._current;
  248. if(mixin){
  249. theme = this.addMixin(theme, elementType, mixin);
  250. }
  251. if(doPost){
  252. theme = this.post(theme, elementType);
  253. }
  254. return theme; // Object
  255. },
  256. skip: function(){
  257. // summary:
  258. // Skip the next internal color.
  259. ++this._current;
  260. },
  261. addMixin: function(theme, elementType, mixin, doPost){
  262. // summary:
  263. // Add a mixin object to the passed theme and process.
  264. // theme: dojox.charting.Theme
  265. // The theme to mixin to.
  266. // elementType: String
  267. // The type of element in question. Can be "line", "bar" or "circle"
  268. // mixin: Object|Array
  269. // The object or objects to mix into the theme.
  270. // doPost: Boolean
  271. // If true, run the new theme through the post-processor.
  272. // returns: dojox.charting.Theme
  273. // The new theme.
  274. if(dojo.isArray(mixin)){
  275. dojo.forEach(mixin, function(m){
  276. theme = this.addMixin(theme, elementType, m);
  277. }, this);
  278. }else{
  279. var t = {};
  280. if("color" in mixin){
  281. if(elementType == "line" || elementType == "area"){
  282. dojo.setObject("series.stroke.color", mixin.color, t);
  283. dojo.setObject("marker.stroke.color", mixin.color, t);
  284. }else{
  285. dojo.setObject("series.fill", mixin.color, t);
  286. }
  287. }
  288. dojo.forEach(["stroke", "outline", "shadow", "fill", "font", "fontColor", "labelWiring"], function(name){
  289. var markerName = "marker" + name.charAt(0).toUpperCase() + name.substr(1),
  290. b = markerName in mixin;
  291. if(name in mixin){
  292. dojo.setObject("series." + name, mixin[name], t);
  293. if(!b){
  294. dojo.setObject("marker." + name, mixin[name], t);
  295. }
  296. }
  297. if(b){
  298. dojo.setObject("marker." + name, mixin[markerName], t);
  299. }
  300. });
  301. if("marker" in mixin){
  302. t.symbol = mixin.marker;
  303. }
  304. theme = dojox.lang.utils.merge(theme, t);
  305. }
  306. if(doPost){
  307. theme = this.post(theme, elementType);
  308. }
  309. return theme; // dojox.charting.Theme
  310. },
  311. post: function(theme, elementType){
  312. // summary:
  313. // Process any post-shape fills.
  314. // theme: dojox.charting.Theme
  315. // The theme to post process with.
  316. // elementType: String
  317. // The type of element being filled. Can be "bar" or "circle".
  318. // returns: dojox.charting.Theme
  319. // The post-processed theme.
  320. var fill = theme.series.fill, t;
  321. if(!this.noGradConv && this.shapeSpaces[fill.space] && fill.type == "linear"){
  322. if(elementType == "bar"){
  323. // transpose start and end points
  324. t = {
  325. x1: fill.y1,
  326. y1: fill.x1,
  327. x2: fill.y2,
  328. y2: fill.x2
  329. };
  330. }else if(!this.noRadialConv && fill.space == "shape" && (elementType == "slice" || elementType == "circle")){
  331. // switch to radial
  332. t = {
  333. type: "radial",
  334. cx: 0,
  335. cy: 0,
  336. r: 100
  337. };
  338. }
  339. if(t){
  340. return dojox.lang.utils.merge(theme, {series: {fill: t}});
  341. }
  342. }
  343. return theme; // dojox.charting.Theme
  344. },
  345. getTick: function(name, mixin){
  346. // summary:
  347. // Calculates and merges tick parameters.
  348. // name: String
  349. // Tick name, can be "major", "minor", or "micro".
  350. // mixin: Object?
  351. // Optional object to mix in to the tick.
  352. var tick = this.axis.tick, tickName = name + "Tick";
  353. merge = dojox.lang.utils.merge;
  354. if(tick){
  355. if(this.axis[tickName]){
  356. tick = merge(tick, this.axis[tickName]);
  357. }
  358. }else{
  359. tick = this.axis[tickName];
  360. }
  361. if(mixin){
  362. if(tick){
  363. if(mixin[tickName]){
  364. tick = merge(tick, mixin[tickName]);
  365. }
  366. }else{
  367. tick = mixin[tickName];
  368. }
  369. }
  370. return tick; // Object
  371. },
  372. inspectObjects: function(f){
  373. dojo.forEach(["chart", "plotarea", "axis", "series", "marker"], function(name){
  374. f(this[name]);
  375. }, this);
  376. if(this.seriesThemes){
  377. dojo.forEach(this.seriesThemes, f);
  378. }
  379. if(this.markerThemes){
  380. dojo.forEach(this.markerThemes, f);
  381. }
  382. },
  383. reverseFills: function(){
  384. this.inspectObjects(function(o){
  385. if(o && o.fill){
  386. o.fill = dojox.gfx.gradutils.reverse(o.fill);
  387. }
  388. });
  389. },
  390. addMarker:function(/*String*/ name, /*String*/ segment){
  391. // summary:
  392. // Add a custom marker to this theme.
  393. // example:
  394. // | myTheme.addMarker("Ellipse", foo);
  395. this.markers[name] = segment;
  396. this._buildMarkerArray();
  397. },
  398. setMarkers:function(/*Object*/ obj){
  399. // summary:
  400. // Set all the markers of this theme at once. obj should be a
  401. // dictionary of keys and path segments.
  402. //
  403. // example:
  404. // | myTheme.setMarkers({ "CIRCLE": foo });
  405. this.markers = obj;
  406. this._buildMarkerArray();
  407. },
  408. _buildMarkerArray: function(){
  409. this._markers = [];
  410. for(var p in this.markers){
  411. this._markers.push(this.markers[p]);
  412. }
  413. }
  414. });
  415. /*=====
  416. dojox.charting.Theme.__DefineColorArgs = function(num, colors, hue, saturation, low, high, base, generator){
  417. // summary:
  418. // The arguments object that can be passed to define colors for a theme.
  419. // num: Number?
  420. // The number of colors to generate. Defaults to 5.
  421. // colors: String[]|dojo.Color[]?
  422. // A pre-defined set of colors; this is passed through to the Theme directly.
  423. // hue: Number?
  424. // A hue to base the generated colors from (a number from 0 - 359).
  425. // saturation: Number?
  426. // If a hue is passed, this is used for the saturation value (0 - 100).
  427. // low: Number?
  428. // An optional value to determine the lowest value used to generate a color (HSV model)
  429. // high: Number?
  430. // An optional value to determine the highest value used to generate a color (HSV model)
  431. // base: String|dojo.Color?
  432. // A base color to use if we are defining colors using dojox.color.Palette
  433. // generator: String?
  434. // The generator function name from dojox.color.Palette.
  435. this.num = num;
  436. this.colors = colors;
  437. this.hue = hue;
  438. this.saturation = saturation;
  439. this.low = low;
  440. this.high = high;
  441. this.base = base;
  442. this.generator = generator;
  443. }
  444. =====*/
  445. dojo.mixin(dojox.charting.Theme, {
  446. defaultMarkers: {
  447. CIRCLE: "m-3,0 c0,-4 6,-4 6,0 m-6,0 c0,4 6,4 6,0",
  448. SQUARE: "m-3,-3 l0,6 6,0 0,-6 z",
  449. DIAMOND: "m0,-3 l3,3 -3,3 -3,-3 z",
  450. CROSS: "m0,-3 l0,6 m-3,-3 l6,0",
  451. X: "m-3,-3 l6,6 m0,-6 l-6,6",
  452. TRIANGLE: "m-3,3 l3,-6 3,6 z",
  453. TRIANGLE_INVERTED: "m-3,-3 l3,6 3,-6 z"
  454. },
  455. defaultColors:[
  456. // gray skies
  457. "#54544c", "#858e94", "#6e767a", "#948585", "#474747"
  458. ],
  459. defaultTheme: {
  460. // all objects are structs used directly in dojox.gfx
  461. chart:{
  462. stroke: null,
  463. fill: "white",
  464. pageStyle: null,
  465. titleGap: 20,
  466. titlePos: "top",
  467. titleFont: "normal normal bold 14pt Tahoma", // labels on axis
  468. titleFontColor: "#333"
  469. },
  470. plotarea:{
  471. stroke: null,
  472. fill: "white"
  473. },
  474. // TODO: label rotation on axis
  475. axis:{
  476. stroke: { // the axis itself
  477. color: "#333",
  478. width: 1
  479. },
  480. tick: { // used as a foundation for all ticks
  481. color: "#666",
  482. position: "center",
  483. font: "normal normal normal 7pt Tahoma", // labels on axis
  484. fontColor: "#333", // color of labels
  485. titleGap: 15,
  486. titleFont: "normal normal normal 11pt Tahoma", // labels on axis
  487. titleFontColor: "#333", // color of labels
  488. titleOrientation: "axis" // "axis": facing the axis, "away": facing away
  489. },
  490. majorTick: { // major ticks on axis, and used for major gridlines
  491. width: 1,
  492. length: 6
  493. },
  494. minorTick: { // minor ticks on axis, and used for minor gridlines
  495. width: 0.8,
  496. length: 3
  497. },
  498. microTick: { // minor ticks on axis, and used for minor gridlines
  499. width: 0.5,
  500. length: 1
  501. }
  502. },
  503. series: {
  504. // used as a "main" theme for series, sThemes augment it
  505. stroke: {width: 1.5, color: "#333"}, // line
  506. outline: {width: 0.1, color: "#ccc"}, // outline
  507. //shadow: {dx: 1, dy: 1, width: 2, color: [0, 0, 0, 0.3]},
  508. shadow: null, // no shadow
  509. fill: "#ccc", // fill, if appropriate
  510. font: "normal normal normal 8pt Tahoma", // if there's a label
  511. fontColor: "#000", // color of labels
  512. labelWiring: {width: 1, color: "#ccc"} // connect marker and target data item(slice, column, bar...)
  513. },
  514. marker: { // any markers on a series
  515. stroke: {width: 1.5, color: "#333"}, // stroke
  516. outline: {width: 0.1, color: "#ccc"}, // outline
  517. //shadow: {dx: 1, dy: 1, width: 2, color: [0, 0, 0, 0.3]},
  518. shadow: null, // no shadow
  519. fill: "#ccc", // fill if needed
  520. font: "normal normal normal 8pt Tahoma", // label
  521. fontColor: "#000"
  522. }
  523. },
  524. defineColors: function(kwArgs){
  525. // summary:
  526. // Generate a set of colors for the theme based on keyword
  527. // arguments.
  528. // kwArgs: dojox.charting.Theme.__DefineColorArgs
  529. // The arguments object used to define colors.
  530. // returns: dojo.Color[]
  531. // An array of colors for use in a theme.
  532. //
  533. // example:
  534. // | var colors = dojox.charting.Theme.defineColors({
  535. // | base: "#369",
  536. // | generator: "compound"
  537. // | });
  538. //
  539. // example:
  540. // | var colors = dojox.charting.Theme.defineColors({
  541. // | hue: 60,
  542. // | saturation: 90,
  543. // | low: 30,
  544. // | high: 80
  545. // | });
  546. kwArgs = kwArgs || {};
  547. var c = [], n = kwArgs.num || 5; // the number of colors to generate
  548. if(kwArgs.colors){
  549. // we have an array of colors predefined, so fix for the number of series.
  550. var l = kwArgs.colors.length;
  551. for(var i = 0; i < n; i++){
  552. c.push(kwArgs.colors[i % l]);
  553. }
  554. return c; // dojo.Color[]
  555. }
  556. if(kwArgs.hue){
  557. // single hue, generate a set based on brightness
  558. var s = kwArgs.saturation || 100; // saturation
  559. var st = kwArgs.low || 30;
  560. var end = kwArgs.high || 90;
  561. // we'd like it to be a little on the darker side.
  562. var l = (end + st) / 2;
  563. // alternately, use "shades"
  564. return dojox.color.Palette.generate(
  565. dojox.color.fromHsv(kwArgs.hue, s, l), "monochromatic"
  566. ).colors;
  567. }
  568. if(kwArgs.generator){
  569. // pass a base color and the name of a generator
  570. return dojox.color.Palette.generate(kwArgs.base, kwArgs.generator).colors;
  571. }
  572. return c; // dojo.Color[]
  573. },
  574. generateGradient: function(fillPattern, colorFrom, colorTo){
  575. var fill = dojo.delegate(fillPattern);
  576. fill.colors = [
  577. {offset: 0, color: colorFrom},
  578. {offset: 1, color: colorTo}
  579. ];
  580. return fill;
  581. },
  582. generateHslColor: function(color, luminance){
  583. color = new dojox.color.Color(color);
  584. var hsl = color.toHsl(),
  585. result = dojox.color.fromHsl(hsl.h, hsl.s, luminance);
  586. result.a = color.a; // add missing opacity
  587. return result;
  588. },
  589. generateHslGradient: function(color, fillPattern, lumFrom, lumTo){
  590. color = new dojox.color.Color(color);
  591. var hsl = color.toHsl(),
  592. colorFrom = dojox.color.fromHsl(hsl.h, hsl.s, lumFrom),
  593. colorTo = dojox.color.fromHsl(hsl.h, hsl.s, lumTo);
  594. colorFrom.a = colorTo.a = color.a; // add missing opacity
  595. return dojox.charting.Theme.generateGradient(fillPattern, colorFrom, colorTo); // Object
  596. }
  597. });
  598. }