Spider.js 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651
  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.plot2d.Spider"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
  7. dojo._hasResource["dojox.charting.plot2d.Spider"] = true;
  8. dojo.provide("dojox.charting.plot2d.Spider");
  9. dojo.experimental("dojox.charting.plot2d.Spider");
  10. dojo.require("dojox.charting.Element");
  11. dojo.require("dojox.charting.plot2d._PlotEvents");
  12. dojo.require("dojox.charting.axis2d.common");
  13. dojo.require("dojox.charting.plot2d.common");
  14. dojo.require("dojox.charting.scaler.primitive");
  15. dojo.require("dojox.lang.functional");
  16. dojo.require("dojox.lang.utils");
  17. dojo.require("dojox.gfx");
  18. dojo.require("dojo.fx");
  19. dojo.require("dojo.fx.easing");
  20. dojo.require("dojox.gfx.fx");
  21. (function(){
  22. var df = dojox.lang.functional, du = dojox.lang.utils,
  23. dc = dojox.charting.plot2d.common,
  24. da = dojox.charting.axis2d.common,
  25. g = dojox.gfx, m = g.matrix,
  26. FUDGE_FACTOR = 0.2; // use to overlap fans
  27. dojo.declare("dojox.charting.plot2d.Spider", [dojox.charting.Element, dojox.charting.plot2d._PlotEvents], {
  28. // summary:
  29. // The plot that represents a typical Spider chart.
  30. defaultParams: {
  31. labels: true,
  32. ticks: false,
  33. fixed: true,
  34. precision: 1,
  35. labelOffset: -10,
  36. labelStyle: "default", // default/rows/auto
  37. htmlLabels: true, // use HTML to draw labels
  38. startAngle: -90, // start angle for slices in degrees
  39. divisions: 3, // radius tick count
  40. axisColor: "", // spider axis color
  41. axisWidth: 0, // spider axis stroke width
  42. spiderColor: "", // spider web color
  43. spiderWidth: 0, // spider web stroke width
  44. seriesWidth: 0, // plot border with
  45. seriesFillAlpha: 0.2, // plot fill alpha
  46. spiderOrigin: 0.16,
  47. markerSize: 3, // radius of plot vertex (px)
  48. spiderType: "polygon", //"circle"
  49. animationType: dojo.fx.easing.backOut,
  50. axisTickFont: "",
  51. axisTickFontColor: "",
  52. axisFont: "",
  53. axisFontColor: ""
  54. },
  55. optionalParams: {
  56. radius: 0,
  57. font: "",
  58. fontColor: ""
  59. },
  60. constructor: function(chart, kwArgs){
  61. // summary:
  62. // Create a Spider plot.
  63. this.opt = dojo.clone(this.defaultParams);
  64. du.updateWithObject(this.opt, kwArgs);
  65. du.updateWithPattern(this.opt, kwArgs, this.optionalParams);
  66. this.series = [];
  67. this.dyn = [];
  68. this.datas = {};
  69. this.labelKey = [];
  70. this.oldSeriePoints = {};
  71. this.animations = {};
  72. },
  73. clear: function(){
  74. // summary:
  75. // Clear out all of the information tied to this plot.
  76. // returns: dojox.charting.plot2d.Spider
  77. // A reference to this plot for functional chaining.
  78. this.dirty = true;
  79. this.dyn = [];
  80. this.series = [];
  81. this.datas = {};
  82. this.labelKey = [];
  83. this.oldSeriePoints = {};
  84. this.animations = {};
  85. return this; // dojox.charting.plot2d.Spider
  86. },
  87. setAxis: function(axis){
  88. // summary:
  89. // Dummy method, since axes are irrelevant with a Spider chart.
  90. // returns: dojox.charting.plot2d.Spider
  91. // The reference to this plot for functional chaining.
  92. return this; // dojox.charting.plot2d.Spider
  93. },
  94. addSeries: function(run){
  95. // summary:
  96. // Add a data series to this plot.
  97. // run: dojox.charting.Series
  98. // The series to be added.
  99. // returns: dojox.charting.plot2d.Base
  100. // A reference to this plot for functional chaining.
  101. var matched = false;
  102. this.series.push(run);
  103. for(var key in run.data){
  104. var val = run.data[key],
  105. data = this.datas[key];
  106. if(data){
  107. data.vlist.push(val);
  108. data.min = Math.min(data.min, val);
  109. data.max = Math.max(data.max, val);
  110. }else{
  111. this.datas[key] = {min: val, max: val, vlist: [val]};
  112. }
  113. }
  114. if (this.labelKey.length <= 0) {
  115. for (var key in run.data) {
  116. this.labelKey.push(key);
  117. }
  118. }
  119. return this; // dojox.charting.plot2d.Base
  120. },
  121. getSeriesStats: function(){
  122. // summary:
  123. // Calculate the min/max on all attached series in both directions.
  124. // returns: Object
  125. // {hmin, hmax, vmin, vmax} min/max in both directions.
  126. return dojox.charting.plot2d.common.collectSimpleStats(this.series);
  127. },
  128. calculateAxes: function(dim){
  129. // summary:
  130. // Stub function for running the axis calculations (depricated).
  131. // dim: Object
  132. // An object of the form { width, height }
  133. // returns: dojox.charting.plot2d.Base
  134. // A reference to this plot for functional chaining.
  135. this.initializeScalers(dim, this.getSeriesStats());
  136. return this; // dojox.charting.plot2d.Base
  137. },
  138. getRequiredColors: function(){
  139. // summary:
  140. // Get how many data series we have, so we know how many colors to use.
  141. // returns: Number
  142. // The number of colors needed.
  143. return this.series.length; // Number
  144. },
  145. initializeScalers: function(dim, stats){
  146. // summary:
  147. // Initializes scalers using attached axes.
  148. // dim: Object:
  149. // Size of a plot area in pixels as {width, height}.
  150. // stats: Object:
  151. // Min/max of data in both directions as {hmin, hmax, vmin, vmax}.
  152. // returns: dojox.charting.plot2d.Base
  153. // A reference to this plot for functional chaining.
  154. if(this._hAxis){
  155. if(!this._hAxis.initialized()){
  156. this._hAxis.calculate(stats.hmin, stats.hmax, dim.width);
  157. }
  158. this._hScaler = this._hAxis.getScaler();
  159. }else{
  160. this._hScaler = dojox.charting.scaler.primitive.buildScaler(stats.hmin, stats.hmax, dim.width);
  161. }
  162. if(this._vAxis){
  163. if(!this._vAxis.initialized()){
  164. this._vAxis.calculate(stats.vmin, stats.vmax, dim.height);
  165. }
  166. this._vScaler = this._vAxis.getScaler();
  167. }else{
  168. this._vScaler = dojox.charting.scaler.primitive.buildScaler(stats.vmin, stats.vmax, dim.height);
  169. }
  170. return this; // dojox.charting.plot2d.Base
  171. },
  172. render: function(dim, offsets){
  173. // summary:
  174. // Render the plot on the chart.
  175. // dim: Object
  176. // An object of the form { width, height }.
  177. // offsets: Object
  178. // An object of the form { l, r, t, b }.
  179. // returns: dojox.charting.plot2d.Spider
  180. // A reference to this plot for functional chaining.
  181. if(!this.dirty){ return this; }
  182. this.dirty = false;
  183. this.cleanGroup();
  184. var s = this.group, t = this.chart.theme;
  185. this.resetEvents();
  186. if(!this.series || !this.series.length){
  187. return this;
  188. }
  189. // calculate the geometry
  190. var o = this.opt, ta = t.axis,
  191. rx = (dim.width - offsets.l - offsets.r) / 2,
  192. ry = (dim.height - offsets.t - offsets.b) / 2,
  193. r = Math.min(rx, ry),
  194. axisTickFont = o.font || (ta.majorTick && ta.majorTick.font) || (ta.tick && ta.tick.font) || "normal normal normal 7pt Tahoma",
  195. axisFont = o.axisFont || (ta.tick && ta.tick.titleFont) || "normal normal normal 11pt Tahoma",
  196. axisTickFontColor = o.axisTickFontColor || (ta.majorTick && ta.majorTick.fontColor) || (ta.tick && ta.tick.fontColor) || "silver",
  197. axisFontColor = o.axisFontColor || (ta.tick && ta.tick.titleFontColor) || "black",
  198. axisColor = o.axisColor || (ta.tick && ta.tick.axisColor) || "silver",
  199. spiderColor = o.spiderColor || (ta.tick && ta.tick.spiderColor) || "silver",
  200. axisWidth = o.axisWidth || (ta.stroke && ta.stroke.width) || 2,
  201. spiderWidth = o.spiderWidth || (ta.stroke && ta.stroke.width) || 2,
  202. seriesWidth = o.seriesWidth || (ta.stroke && ta.stroke.width) || 2,
  203. asize = g.normalizedLength(g.splitFontString(axisFont).size),
  204. startAngle = m._degToRad(o.startAngle),
  205. start = startAngle, step, filteredRun, slices, labels, shift, labelR,
  206. outerPoints, innerPoints, divisionPoints, divisionRadius, labelPoints,
  207. ro = o.spiderOrigin, dv = o.divisions >= 3 ? o.divisions : 3, ms = o.markerSize,
  208. spt = o.spiderType, at = o.animationType, lboffset = o.labelOffset < -10 ? o.labelOffset : -10,
  209. axisExtra = 0.2;
  210. if(o.labels){
  211. labels = dojo.map(this.series, function(s){
  212. return s.name;
  213. }, this);
  214. shift = df.foldl1(df.map(labels, function(label, i){
  215. var font = t.series.font;
  216. return dojox.gfx._base._getTextBox(label, {
  217. font: font
  218. }).w;
  219. }, this), "Math.max(a, b)") / 2;
  220. r = Math.min(rx - 2 * shift, ry - asize) + lboffset;
  221. labelR = r - lboffset;
  222. }
  223. if ("radius" in o) {
  224. r = o.radius;
  225. labelR = r - lboffset;
  226. }
  227. r /= (1+axisExtra);
  228. var circle = {
  229. cx: offsets.l + rx,
  230. cy: offsets.t + ry,
  231. r: r
  232. };
  233. for (var i = this.series.length - 1; i >= 0; i--) {
  234. var serieEntry = this.series[i];
  235. if (!this.dirty && !serieEntry.dirty) {
  236. t.skip();
  237. continue;
  238. }
  239. serieEntry.cleanGroup();
  240. var run = serieEntry.data;
  241. if (run !== null) {
  242. var len = this._getObjectLength(run);
  243. //construct connect points
  244. if (!outerPoints || outerPoints.length <= 0) {
  245. outerPoints = [], innerPoints = [], labelPoints = [];
  246. this._buildPoints(outerPoints, len, circle, r, start, true);
  247. this._buildPoints(innerPoints, len, circle, r*ro, start, true);
  248. this._buildPoints(labelPoints, len, circle, labelR, start);
  249. if(dv > 2){
  250. divisionPoints = [], divisionRadius = [];
  251. for (var j = 0; j < dv - 2; j++) {
  252. divisionPoints[j] = [];
  253. this._buildPoints(divisionPoints[j], len, circle, r*(ro + (1-ro)*(j+1)/(dv-1)), start, true);
  254. divisionRadius[j] = r*(ro + (1-ro)*(j+1)/(dv-1));
  255. }
  256. }
  257. }
  258. }
  259. }
  260. //draw Spider
  261. //axis
  262. var axisGroup = s.createGroup(), axisStroke = {color: axisColor, width: axisWidth},
  263. spiderStroke = {color: spiderColor, width: spiderWidth};
  264. for (var j = outerPoints.length - 1; j >= 0; --j) {
  265. var point = outerPoints[j],
  266. st = {
  267. x: point.x + (point.x - circle.cx) * axisExtra,
  268. y: point.y + (point.y - circle.cy) * axisExtra
  269. },
  270. nd = {
  271. x: point.x + (point.x - circle.cx) * axisExtra / 2,
  272. y: point.y + (point.y - circle.cy) * axisExtra / 2
  273. };
  274. axisGroup.createLine({
  275. x1: circle.cx,
  276. y1: circle.cy,
  277. x2: st.x,
  278. y2: st.y
  279. }).setStroke(axisStroke);
  280. //arrow
  281. this._drawArrow(axisGroup, st, nd, axisStroke);
  282. }
  283. // draw the label
  284. var labelGroup = s.createGroup();
  285. for (var j = labelPoints.length - 1; j >= 0; --j) {
  286. var point = labelPoints[j],
  287. fontWidth = dojox.gfx._base._getTextBox(this.labelKey[j], {font: axisFont}).w || 0,
  288. render = this.opt.htmlLabels && dojox.gfx.renderer != "vml" ? "html" : "gfx";
  289. elem = da.createText[render](this.chart, labelGroup, (!dojo._isBodyLtr() && render == "html") ? (point.x + fontWidth - dim.width) : point.x, point.y,
  290. "middle", this.labelKey[j], axisFont, axisFontColor);
  291. if (this.opt.htmlLabels) {
  292. this.htmlElements.push(elem);
  293. }
  294. }
  295. //spider web: polygon or circle
  296. var spiderGroup = s.createGroup();
  297. if(spt == "polygon"){
  298. spiderGroup.createPolyline(outerPoints).setStroke(spiderStroke);
  299. spiderGroup.createPolyline(innerPoints).setStroke(spiderStroke);
  300. if (divisionPoints.length > 0) {
  301. for (var j = divisionPoints.length - 1; j >= 0; --j) {
  302. spiderGroup.createPolyline(divisionPoints[j]).setStroke(spiderStroke);
  303. }
  304. }
  305. }else{//circle
  306. var ccount = this._getObjectLength(this.datas);
  307. spiderGroup.createCircle({cx: circle.cx, cy: circle.cy, r: r}).setStroke(spiderStroke);
  308. spiderGroup.createCircle({cx: circle.cx, cy: circle.cy, r: r*ro}).setStroke(spiderStroke);
  309. if (divisionRadius.length > 0) {
  310. for (var j = divisionRadius.length - 1; j >= 0; --j) {
  311. spiderGroup.createCircle({cx: circle.cx, cy: circle.cy, r: divisionRadius[j]}).setStroke(spiderStroke);
  312. }
  313. }
  314. }
  315. //text
  316. var textGroup = s.createGroup(), len = this._getObjectLength(this.datas), k = 0;
  317. for(var key in this.datas){
  318. var data = this.datas[key], min = data.min, max = data.max, distance = max - min,
  319. end = start + 2 * Math.PI * k / len;
  320. for (var i = 0; i < dv; i++) {
  321. var text = min + distance*i/(dv-1), point = this._getCoordinate(circle, r*(ro + (1-ro)*i/(dv-1)), end);
  322. text = this._getLabel(text);
  323. var fontWidth = dojox.gfx._base._getTextBox(text, {font: axisTickFont}).w || 0,
  324. render = this.opt.htmlLabels && dojox.gfx.renderer != "vml" ? "html" : "gfx";
  325. if (this.opt.htmlLabels) {
  326. this.htmlElements.push(da.createText[render]
  327. (this.chart, textGroup, (!dojo._isBodyLtr() && render == "html") ? (point.x + fontWidth - dim.width) : point.x, point.y,
  328. "start", text, axisTickFont, axisTickFontColor));
  329. }
  330. }
  331. k++;
  332. }
  333. //draw series (animation)
  334. this.chart.seriesShapes = {};
  335. var animationConnections = [];
  336. for (var i = this.series.length - 1; i >= 0; i--) {
  337. var serieEntry = this.series[i], run = serieEntry.data;
  338. if (run !== null) {
  339. //series polygon
  340. var seriePoints = [], k = 0, tipData = [];
  341. for(var key in run){
  342. var data = this.datas[key], min = data.min, max = data.max, distance = max - min,
  343. entry = run[key], end = start + 2 * Math.PI * k / len,
  344. point = this._getCoordinate(circle, r*(ro + (1-ro)*(entry-min)/distance), end);
  345. seriePoints.push(point);
  346. tipData.push({sname: serieEntry.name, key: key, data: entry});
  347. k++;
  348. }
  349. seriePoints[seriePoints.length] = seriePoints[0];
  350. tipData[tipData.length] = tipData[0];
  351. var polygonBoundRect = this._getBoundary(seriePoints),
  352. theme = t.next("spider", [o, serieEntry]), ts = serieEntry.group,
  353. f = g.normalizeColor(theme.series.fill), sk = {color: theme.series.fill, width: seriesWidth};
  354. f.a = o.seriesFillAlpha;
  355. serieEntry.dyn = {fill: f, stroke: sk};
  356. var osps = this.oldSeriePoints[serieEntry.name];
  357. var cs = this._createSeriesEntry(ts, (osps || innerPoints), seriePoints, f, sk, r, ro, ms, at);
  358. this.chart.seriesShapes[serieEntry.name] = cs;
  359. this.oldSeriePoints[serieEntry.name] = seriePoints;
  360. var po = {
  361. element: "spider_poly",
  362. index: i,
  363. id: "spider_poly_"+serieEntry.name,
  364. run: serieEntry,
  365. plot: this,
  366. shape: cs.poly,
  367. parent: ts,
  368. brect: polygonBoundRect,
  369. cx: circle.cx,
  370. cy: circle.cy,
  371. cr: r,
  372. f: f,
  373. s: s
  374. };
  375. this._connectEvents(po);
  376. var so = {
  377. element: "spider_plot",
  378. index: i,
  379. id: "spider_plot_"+serieEntry.name,
  380. run: serieEntry,
  381. plot: this,
  382. shape: serieEntry.group
  383. };
  384. this._connectEvents(so);
  385. dojo.forEach(cs.circles, function(c, i){
  386. var shape = c.getShape(),
  387. co = {
  388. element: "spider_circle",
  389. index: i,
  390. id: "spider_circle_"+serieEntry.name+i,
  391. run: serieEntry,
  392. plot: this,
  393. shape: c,
  394. parent: ts,
  395. tdata: tipData[i],
  396. cx: seriePoints[i].x,
  397. cy: seriePoints[i].y,
  398. f: f,
  399. s: s
  400. };
  401. this._connectEvents(co);
  402. }, this);
  403. }
  404. }
  405. return this; // dojox.charting.plot2d.Spider
  406. },
  407. _createSeriesEntry: function(ts, osps, sps, f, sk, r, ro, ms, at){
  408. //polygon
  409. var spoly = ts.createPolyline(osps).setFill(f).setStroke(sk), scircle = [];
  410. for (var j = 0; j < osps.length; j++) {
  411. var point = osps[j], cr = ms;
  412. var circle = ts.createCircle({cx: point.x, cy: point.y, r: cr}).setFill(f).setStroke(sk);
  413. scircle.push(circle);
  414. }
  415. var anims = dojo.map(sps, function(np, j){
  416. // create animation
  417. var sp = osps[j],
  418. anim = new dojo._Animation({
  419. duration: 1000,
  420. easing: at,
  421. curve: [sp.y, np.y]
  422. });
  423. var spl = spoly, sc = scircle[j];
  424. dojo.connect(anim, "onAnimate", function(y){
  425. //apply poly
  426. var pshape = spl.getShape();
  427. pshape.points[j].y = y;
  428. spl.setShape(pshape);
  429. //apply circle
  430. var cshape = sc.getShape();
  431. cshape.cy = y;
  432. sc.setShape(cshape);
  433. });
  434. return anim;
  435. });
  436. var anims1 = dojo.map(sps, function(np, j){
  437. // create animation
  438. var sp = osps[j],
  439. anim = new dojo._Animation({
  440. duration: 1000,
  441. easing: at,
  442. curve: [sp.x, np.x]
  443. });
  444. var spl = spoly, sc = scircle[j];
  445. dojo.connect(anim, "onAnimate", function(x){
  446. //apply poly
  447. var pshape = spl.getShape();
  448. pshape.points[j].x = x;
  449. spl.setShape(pshape);
  450. //apply circle
  451. var cshape = sc.getShape();
  452. cshape.cx = x;
  453. sc.setShape(cshape);
  454. });
  455. return anim;
  456. });
  457. var masterAnimation = dojo.fx.combine(anims.concat(anims1)); //dojo.fx.chain(anims);
  458. masterAnimation.play();
  459. return {group :ts, poly: spoly, circles: scircle};
  460. },
  461. plotEvent: function(o){
  462. // summary:
  463. // Stub function for use by specific plots.
  464. // o: Object
  465. // An object intended to represent event parameters.
  466. var runName = o.id ? o.id : "default", a;
  467. if (runName in this.animations) {
  468. a = this.animations[runName];
  469. a.anim && a.anim.stop(true);
  470. } else {
  471. a = this.animations[runName] = {};
  472. }
  473. if(o.element == "spider_poly"){
  474. if(!a.color){
  475. var color = o.shape.getFill();
  476. if(!color || !(color instanceof dojo.Color)){
  477. return;
  478. }
  479. a.color = {
  480. start: color,
  481. end: transColor(color)
  482. };
  483. }
  484. var start = a.color.start, end = a.color.end;
  485. if(o.type == "onmouseout"){
  486. // swap colors
  487. var t = start; start = end; end = t;
  488. }
  489. a.anim = dojox.gfx.fx.animateFill({
  490. shape: o.shape,
  491. duration: 800,
  492. easing: dojo.fx.easing.backOut,
  493. color: {start: start, end: end}
  494. });
  495. a.anim.play();
  496. }else if(o.element == "spider_circle"){
  497. var init, scale, defaultScale = 1.5;
  498. if(o.type == "onmouseover"){
  499. init = dojox.gfx.matrix.identity;
  500. scale = defaultScale;
  501. //show tooltip
  502. var aroundRect = {type: "rect"};
  503. aroundRect.x = o.cx;
  504. aroundRect.y = o.cy;
  505. aroundRect.width = aroundRect.height = 1;
  506. var lt = dojo.coords(this.chart.node, true);
  507. aroundRect.x += lt.x;
  508. aroundRect.y += lt.y;
  509. aroundRect.x = Math.round(aroundRect.x);
  510. aroundRect.y = Math.round(aroundRect.y);
  511. aroundRect.width = Math.ceil(aroundRect.width);
  512. aroundRect.height = Math.ceil(aroundRect.height);
  513. this.aroundRect = aroundRect;
  514. var position = ["after", "before"];
  515. if(dijit && dijit.Tooltip){
  516. dijit.showTooltip(o.tdata.sname + "<br/>" + o.tdata.key + "<br/>" + o.tdata.data, this.aroundRect, position);
  517. }
  518. }else{
  519. init = dojox.gfx.matrix.scaleAt(defaultScale, o.cx, o.cy);
  520. scale = 1/defaultScale;
  521. if(dijit && dijit.Tooltip){
  522. this.aroundRect && dijit.hideTooltip(this.aroundRect);
  523. }
  524. }
  525. var cs = o.shape.getShape(),
  526. init = m.scaleAt(defaultScale, cs.cx, cs.cy),
  527. kwArgs = {
  528. shape: o.shape,
  529. duration: 200,
  530. easing: dojo.fx.easing.backOut,
  531. transform: [
  532. {name: "scaleAt", start: [1, cs.cx, cs.cy], end: [scale, cs.cx, cs.cy]},
  533. init
  534. ]
  535. };
  536. a.anim = dojox.gfx.fx.animateTransform(kwArgs);
  537. a.anim.play();
  538. }else if(o.element == "spider_plot"){
  539. //dojo gfx function "moveToFront" not work in IE
  540. if (o.type == "onmouseover" && !dojo.isIE) {
  541. o.shape.moveToFront();
  542. }
  543. }
  544. },
  545. _getBoundary: function(points){
  546. var xmax = points[0].x,
  547. xmin = points[0].x,
  548. ymax = points[0].y,
  549. ymin = points[0].y;
  550. for(var i = 0; i < points.length; i++){
  551. var point = points[i];
  552. xmax = Math.max(point.x, xmax);
  553. ymax = Math.max(point.y, ymax);
  554. xmin = Math.min(point.x, xmin);
  555. ymin = Math.min(point.y, ymin);
  556. }
  557. return {
  558. x: xmin,
  559. y: ymin,
  560. width: xmax - xmin,
  561. height: ymax - ymin
  562. };
  563. },
  564. _drawArrow: function(s, start, end, stroke){
  565. var len = Math.sqrt(Math.pow(end.x - start.x, 2) + Math.pow(end.y - start.y, 2)),
  566. sin = (end.y - start.y)/len, cos = (end.x - start.x)/len,
  567. point2 = {x: end.x + (len/3)*(-sin), y: end.y + (len/3)*cos},
  568. point3 = {x: end.x + (len/3)*sin, y: end.y + (len/3)*(-cos)};
  569. s.createPolyline([start, point2, point3]).setFill(stroke.color).setStroke(stroke);
  570. },
  571. _buildPoints: function(points, count, circle, radius, angle, recursive){
  572. for (var i = 0; i < count; i++) {
  573. var end = angle + 2 * Math.PI * i / count;
  574. points.push(this._getCoordinate(circle, radius, end));
  575. }
  576. if(recursive){
  577. points.push(this._getCoordinate(circle, radius, angle + 2 * Math.PI));
  578. }
  579. },
  580. _getCoordinate: function(circle, radius, angle){
  581. return {
  582. x: circle.cx + radius * Math.cos(angle),
  583. y: circle.cy + radius * Math.sin(angle)
  584. }
  585. },
  586. _getObjectLength: function(obj){
  587. var count = 0;
  588. if(dojo.isObject(obj)){
  589. for(var key in obj){
  590. count++;
  591. }
  592. }
  593. return count;
  594. },
  595. // utilities
  596. _getLabel: function(number){
  597. return dc.getLabel(number, this.opt.fixed, this.opt.precision);
  598. }
  599. });
  600. function transColor(color){
  601. var a = new dojox.color.Color(color),
  602. x = a.toHsl();
  603. if(x.s == 0){
  604. x.l = x.l < 50 ? 100 : 0;
  605. }else{
  606. x.s = 100;
  607. if(x.l < 50){
  608. x.l = 75;
  609. }else if(x.l > 75){
  610. x.l = 50;
  611. }else{
  612. x.l = x.l - 50 > 75 - x.l ?
  613. 50 : 75;
  614. }
  615. }
  616. var color = dojox.color.fromHsl(x);
  617. color.a = 0.7;
  618. return color;
  619. }
  620. })();
  621. }