Spider.js 20 KB

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