API Docs for: 3.13.0
Show:

File: charts/js/Graph.js

  1. /**
  2. * Graph manages and contains series instances for a `CartesianChart`
  3. * instance.
  4. *
  5. * @class Graph
  6. * @constructor
  7. * @extends Widget
  8. * @uses Renderer
  9. * @submodule charts-base
  10. */
  11. Y.Graph = Y.Base.create("graph", Y.Widget, [Y.Renderer], {
  12. /**
  13. * @method bindUI
  14. * @private
  15. */
  16. bindUI: function()
  17. {
  18. var bb = this.get("boundingBox");
  19. bb.setStyle("position", "absolute");
  20. this.after("widthChange", this._sizeChangeHandler);
  21. this.after("heightChange", this._sizeChangeHandler);
  22. this.after("stylesChange", this._updateStyles);
  23. this.after("groupMarkersChange", this._drawSeries);
  24. },
  25.  
  26. /**
  27. * @method syncUI
  28. * @private
  29. */
  30. syncUI: function()
  31. {
  32. var background,
  33. cb,
  34. bg,
  35. sc = this.get("seriesCollection"),
  36. series,
  37. i = 0,
  38. len = sc ? sc.length : 0,
  39. hgl = this.get("horizontalGridlines"),
  40. vgl = this.get("verticalGridlines");
  41. if(this.get("showBackground"))
  42. {
  43. background = this.get("background");
  44. cb = this.get("contentBox");
  45. bg = this.get("styles").background;
  46. bg.stroke = bg.border;
  47. bg.stroke.opacity = bg.stroke.alpha;
  48. bg.fill.opacity = bg.fill.alpha;
  49. bg.width = this.get("width");
  50. bg.height = this.get("height");
  51. bg.type = bg.shape;
  52. background.set(bg);
  53. }
  54. for(; i < len; ++i)
  55. {
  56. series = sc[i];
  57. if(series instanceof Y.SeriesBase)
  58. {
  59. series.render();
  60. }
  61. }
  62. if(hgl && hgl instanceof Y.Gridlines)
  63. {
  64. hgl.draw();
  65. }
  66. if(vgl && vgl instanceof Y.Gridlines)
  67. {
  68. vgl.draw();
  69. }
  70. },
  71.  
  72. /**
  73. * Object of arrays containing series mapped to a series type.
  74. *
  75. * @property seriesTypes
  76. * @type Object
  77. * @private
  78. */
  79. seriesTypes: null,
  80.  
  81. /**
  82. * Returns a series instance based on an index.
  83. *
  84. * @method getSeriesByIndex
  85. * @param {Number} val index of the series
  86. * @return CartesianSeries
  87. */
  88. getSeriesByIndex: function(val)
  89. {
  90. var col = this.get("seriesCollection"),
  91. series;
  92. if(col && col.length > val)
  93. {
  94. series = col[val];
  95. }
  96. return series;
  97. },
  98.  
  99. /**
  100. * Returns a series instance based on a key value.
  101. *
  102. * @method getSeriesByKey
  103. * @param {String} val key value of the series
  104. * @return CartesianSeries
  105. */
  106. getSeriesByKey: function(val)
  107. {
  108. var obj = this._seriesDictionary,
  109. series;
  110. if(obj && obj.hasOwnProperty(val))
  111. {
  112. series = obj[val];
  113. }
  114. return series;
  115. },
  116.  
  117. /**
  118. * Adds dispatcher to a `_dispatcher` used to
  119. * to ensure all series have redrawn before for firing event.
  120. *
  121. * @method addDispatcher
  122. * @param {CartesianSeries} val series instance to add
  123. * @protected
  124. */
  125. addDispatcher: function(val)
  126. {
  127. if(!this._dispatchers)
  128. {
  129. this._dispatchers = [];
  130. }
  131. this._dispatchers.push(val);
  132. },
  133.  
  134. /**
  135. * Collection of series to be displayed in the graph.
  136. *
  137. * @property _seriesCollection
  138. * @type Array
  139. * @private
  140. */
  141. _seriesCollection: null,
  142.  
  143. /**
  144. * Object containing key value pairs of `CartesianSeries` instances.
  145. *
  146. * @property _seriesDictionary
  147. * @type Object
  148. * @private
  149. */
  150. _seriesDictionary: null,
  151.  
  152. /**
  153. * Parses series instances to be displayed in the graph.
  154. *
  155. * @method _parseSeriesCollection
  156. * @param {Array} Collection of `CartesianSeries` instances or objects container `CartesianSeries` attributes values.
  157. * @private
  158. */
  159. _parseSeriesCollection: function(val)
  160. {
  161. if(!val)
  162. {
  163. return;
  164. }
  165. var len = val.length,
  166. i = 0,
  167. series,
  168. seriesKey;
  169. this._seriesCollection = [];
  170. this._seriesDictionary = {};
  171. this.seriesTypes = [];
  172. for(; i < len; ++i)
  173. {
  174. series = val[i];
  175. if(!(series instanceof Y.CartesianSeries) && !(series instanceof Y.PieSeries))
  176. {
  177. this._createSeries(series);
  178. continue;
  179. }
  180. this._addSeries(series);
  181. }
  182. len = this._seriesCollection.length;
  183. for(i = 0; i < len; ++i)
  184. {
  185. series = this.get("seriesCollection")[i];
  186. seriesKey = series.get("direction") === "horizontal" ? "yKey" : "xKey";
  187. this._seriesDictionary[series.get(seriesKey)] = series;
  188. }
  189. },
  190.  
  191. /**
  192. * Adds a series to the graph.
  193. *
  194. * @method _addSeries
  195. * @param {CartesianSeries} series Series to add to the graph.
  196. * @private
  197. */
  198. _addSeries: function(series)
  199. {
  200. var type = series.get("type"),
  201. seriesCollection = this.get("seriesCollection"),
  202. graphSeriesLength = seriesCollection.length,
  203. seriesTypes = this.seriesTypes,
  204. typeSeriesCollection;
  205. if(!series.get("graph"))
  206. {
  207. series.set("graph", this);
  208. }
  209. seriesCollection.push(series);
  210. if(!seriesTypes.hasOwnProperty(type))
  211. {
  212. this.seriesTypes[type] = [];
  213. }
  214. typeSeriesCollection = this.seriesTypes[type];
  215. series.set("graphOrder", graphSeriesLength);
  216. series.set("order", typeSeriesCollection.length);
  217. typeSeriesCollection.push(series);
  218. series.set("seriesTypeCollection", typeSeriesCollection);
  219. this.addDispatcher(series);
  220. series.after("drawingComplete", Y.bind(this._drawingCompleteHandler, this));
  221. this.fire("seriesAdded", series);
  222. },
  223.  
  224. /**
  225. * Creates a `CartesianSeries` instance from an object containing attribute key value pairs. The key value pairs include
  226. * attributes for the specific series and a type value which defines the type of series to be used.
  227. *
  228. * @method createSeries
  229. * @param {Object} seriesData Series attribute key value pairs.
  230. * @private
  231. */
  232. _createSeries: function(seriesData)
  233. {
  234. var type = seriesData.type,
  235. seriesCollection = this.get("seriesCollection"),
  236. seriesTypes = this.seriesTypes,
  237. typeSeriesCollection,
  238. SeriesClass,
  239. series;
  240. seriesData.graph = this;
  241. if(!seriesTypes.hasOwnProperty(type))
  242. {
  243. seriesTypes[type] = [];
  244. }
  245. typeSeriesCollection = seriesTypes[type];
  246. seriesData.graph = this;
  247. seriesData.order = typeSeriesCollection.length;
  248. seriesData.graphOrder = seriesCollection.length;
  249. SeriesClass = this._getSeries(seriesData.type);
  250. series = new SeriesClass(seriesData);
  251. this.addDispatcher(series);
  252. series.after("drawingComplete", Y.bind(this._drawingCompleteHandler, this));
  253. typeSeriesCollection.push(series);
  254. seriesCollection.push(series);
  255. series.set("seriesTypeCollection", typeSeriesCollection);
  256. if(this.get("rendered"))
  257. {
  258. series.render();
  259. }
  260. },
  261.  
  262. /**
  263. * String reference for pre-defined `Series` classes.
  264. *
  265. * @property _seriesMap
  266. * @type Object
  267. * @private
  268. */
  269. _seriesMap: {
  270. line : Y.LineSeries,
  271. column : Y.ColumnSeries,
  272. bar : Y.BarSeries,
  273. area : Y.AreaSeries,
  274. candlestick : Y.CandlestickSeries,
  275. ohlc : Y.OHLCSeries,
  276. stackedarea : Y.StackedAreaSeries,
  277. stackedline : Y.StackedLineSeries,
  278. stackedcolumn : Y.StackedColumnSeries,
  279. stackedbar : Y.StackedBarSeries,
  280. markerseries : Y.MarkerSeries,
  281. spline : Y.SplineSeries,
  282. areaspline : Y.AreaSplineSeries,
  283. stackedspline : Y.StackedSplineSeries,
  284. stackedareaspline : Y.StackedAreaSplineSeries,
  285. stackedmarkerseries : Y.StackedMarkerSeries,
  286. pie : Y.PieSeries,
  287. combo : Y.ComboSeries,
  288. stackedcombo : Y.StackedComboSeries,
  289. combospline : Y.ComboSplineSeries,
  290. stackedcombospline : Y.StackedComboSplineSeries
  291. },
  292.  
  293. /**
  294. * Returns a specific `CartesianSeries` class based on key value from a look up table of a direct reference to a
  295. * class. When specifying a key value, the following options are available:
  296. *
  297. * <table>
  298. * <tr><th>Key Value</th><th>Class</th></tr>
  299. * <tr><td>line</td><td>Y.LineSeries</td></tr>
  300. * <tr><td>column</td><td>Y.ColumnSeries</td></tr>
  301. * <tr><td>bar</td><td>Y.BarSeries</td></tr>
  302. * <tr><td>area</td><td>Y.AreaSeries</td></tr>
  303. * <tr><td>stackedarea</td><td>Y.StackedAreaSeries</td></tr>
  304. * <tr><td>stackedline</td><td>Y.StackedLineSeries</td></tr>
  305. * <tr><td>stackedcolumn</td><td>Y.StackedColumnSeries</td></tr>
  306. * <tr><td>stackedbar</td><td>Y.StackedBarSeries</td></tr>
  307. * <tr><td>markerseries</td><td>Y.MarkerSeries</td></tr>
  308. * <tr><td>spline</td><td>Y.SplineSeries</td></tr>
  309. * <tr><td>areaspline</td><td>Y.AreaSplineSeries</td></tr>
  310. * <tr><td>stackedspline</td><td>Y.StackedSplineSeries</td></tr>
  311. * <tr><td>stackedareaspline</td><td>Y.StackedAreaSplineSeries</td></tr>
  312. * <tr><td>stackedmarkerseries</td><td>Y.StackedMarkerSeries</td></tr>
  313. * <tr><td>pie</td><td>Y.PieSeries</td></tr>
  314. * <tr><td>combo</td><td>Y.ComboSeries</td></tr>
  315. * <tr><td>stackedcombo</td><td>Y.StackedComboSeries</td></tr>
  316. * <tr><td>combospline</td><td>Y.ComboSplineSeries</td></tr>
  317. * <tr><td>stackedcombospline</td><td>Y.StackedComboSplineSeries</td></tr>
  318. * </table>
  319. *
  320. * When referencing a class directly, you can specify any of the above classes or any custom class that extends
  321. * `CartesianSeries` or `PieSeries`.
  322. *
  323. * @method _getSeries
  324. * @param {String | Object} type Series type.
  325. * @return CartesianSeries
  326. * @private
  327. */
  328. _getSeries: function(type)
  329. {
  330. var seriesClass;
  331. if(Y_Lang.isString(type))
  332. {
  333. seriesClass = this._seriesMap[type];
  334. }
  335. else
  336. {
  337. seriesClass = type;
  338. }
  339. return seriesClass;
  340. },
  341.  
  342. /**
  343. * Event handler for marker events.
  344. *
  345. * @method _markerEventHandler
  346. * @param {Object} e Event object.
  347. * @private
  348. */
  349. _markerEventHandler: function(e)
  350. {
  351. var type = e.type,
  352. markerNode = e.currentTarget,
  353. strArr = markerNode.getAttribute("id").split("_"),
  354. series = this.getSeriesByIndex(strArr[1]),
  355. index = strArr[2];
  356. series.updateMarkerState(type, index);
  357. },
  358.  
  359. /**
  360. * Collection of `CartesianSeries` instances to be redrawn.
  361. *
  362. * @property _dispatchers
  363. * @type Array
  364. * @private
  365. */
  366. _dispatchers: null,
  367.  
  368. /**
  369. * Updates the `Graph` styles.
  370. *
  371. * @method _updateStyles
  372. * @private
  373. */
  374. _updateStyles: function()
  375. {
  376. var styles = this.get("styles").background,
  377. border = styles.border;
  378. border.opacity = border.alpha;
  379. styles.stroke = border;
  380. styles.fill.opacity = styles.fill.alpha;
  381. this.get("background").set(styles);
  382. this._sizeChangeHandler();
  383. },
  384.  
  385. /**
  386. * Event handler for size changes.
  387. *
  388. * @method _sizeChangeHandler
  389. * @param {Object} e Event object.
  390. * @private
  391. */
  392. _sizeChangeHandler: function()
  393. {
  394. var hgl = this.get("horizontalGridlines"),
  395. vgl = this.get("verticalGridlines"),
  396. w = this.get("width"),
  397. h = this.get("height"),
  398. bg = this.get("styles").background,
  399. weight,
  400. background;
  401. if(bg && bg.border)
  402. {
  403. weight = bg.border.weight || 0;
  404. }
  405. if(this.get("showBackground"))
  406. {
  407. background = this.get("background");
  408. if(w && h)
  409. {
  410. background.set("width", w);
  411. background.set("height", h);
  412. }
  413. }
  414. if(this._gridlines)
  415. {
  416. this._gridlines.clear();
  417. }
  418. if(hgl && hgl instanceof Y.Gridlines)
  419. {
  420. hgl.draw();
  421. }
  422. if(vgl && vgl instanceof Y.Gridlines)
  423. {
  424. vgl.draw();
  425. }
  426. this._drawSeries();
  427. },
  428.  
  429. /**
  430. * Draws each series.
  431. *
  432. * @method _drawSeries
  433. * @private
  434. */
  435. _drawSeries: function()
  436. {
  437. if(this._drawing)
  438. {
  439. this._callLater = true;
  440. return;
  441. }
  442. var sc,
  443. i,
  444. len,
  445. graphic = this.get("graphic");
  446. graphic.set("autoDraw", false);
  447. graphic.set("width", this.get("width"));
  448. graphic.set("height", this.get("height"));
  449. this._callLater = false;
  450. this._drawing = true;
  451. sc = this.get("seriesCollection");
  452. i = 0;
  453. len = sc ? sc.length : 0;
  454. for(; i < len; ++i)
  455. {
  456. sc[i].draw();
  457. if((!sc[i].get("xcoords") || !sc[i].get("ycoords")) && !sc[i] instanceof Y.PieSeries)
  458. {
  459. this._callLater = true;
  460. break;
  461. }
  462. }
  463. this._drawing = false;
  464. if(this._callLater)
  465. {
  466. this._drawSeries();
  467. }
  468. },
  469.  
  470. /**
  471. * Event handler for series drawingComplete event.
  472. *
  473. * @method _drawingCompleteHandler
  474. * @param {Object} e Event object.
  475. * @private
  476. */
  477. _drawingCompleteHandler: function(e)
  478. {
  479. var series = e.currentTarget,
  480. graphic,
  481. index = Y.Array.indexOf(this._dispatchers, series);
  482. if(index > -1)
  483. {
  484. this._dispatchers.splice(index, 1);
  485. }
  486. if(this._dispatchers.length < 1)
  487. {
  488. graphic = this.get("graphic");
  489. if(!graphic.get("autoDraw"))
  490. {
  491. graphic._redraw();
  492. }
  493. this.fire("chartRendered");
  494. }
  495. },
  496.  
  497. /**
  498. * Gets the default value for the `styles` attribute. Overrides
  499. * base implementation.
  500. *
  501. * @method _getDefaultStyles
  502. * @return Object
  503. * @protected
  504. */
  505. _getDefaultStyles: function()
  506. {
  507. var defs = {
  508. background: {
  509. shape: "rect",
  510. fill:{
  511. color:"#faf9f2"
  512. },
  513. border: {
  514. color:"#dad8c9",
  515. weight: 1
  516. }
  517. }
  518. };
  519. return defs;
  520. },
  521.  
  522. /**
  523. * Destructor implementation Graph class. Removes all Graphic instances from the widget.
  524. *
  525. * @method destructor
  526. * @protected
  527. */
  528. destructor: function()
  529. {
  530. if(this._graphic)
  531. {
  532. this._graphic.destroy();
  533. this._graphic = null;
  534. }
  535. if(this._background)
  536. {
  537. this._background.get("graphic").destroy();
  538. this._background = null;
  539. }
  540. if(this._gridlines)
  541. {
  542. this._gridlines.get("graphic").destroy();
  543. this._gridlines = null;
  544. }
  545. }
  546. }, {
  547. ATTRS: {
  548. /**
  549. * The x-coordinate for the graph.
  550. *
  551. * @attribute x
  552. * @type Number
  553. * @protected
  554. */
  555. x: {
  556. setter: function(val)
  557. {
  558. this.get("boundingBox").setStyle("left", val + "px");
  559. return val;
  560. }
  561. },
  562.  
  563. /**
  564. * The y-coordinate for the graph.
  565. *
  566. * @attribute y
  567. * @type Number
  568. * @protected
  569. */
  570. y: {
  571. setter: function(val)
  572. {
  573. this.get("boundingBox").setStyle("top", val + "px");
  574. return val;
  575. }
  576. },
  577.  
  578. /**
  579. * Reference to the chart instance using the graph.
  580. *
  581. * @attribute chart
  582. * @type ChartBase
  583. * @readOnly
  584. */
  585. chart: {
  586. getter: function() {
  587. var chart = this._state.chart || this;
  588. return chart;
  589. }
  590. },
  591.  
  592. /**
  593. * Collection of series. When setting the `seriesCollection` the array can contain a combination of either
  594. * `CartesianSeries` instances or object literals with properties that will define a series.
  595. *
  596. * @attribute seriesCollection
  597. * @type CartesianSeries
  598. */
  599. seriesCollection: {
  600. getter: function()
  601. {
  602. return this._seriesCollection;
  603. },
  604.  
  605. setter: function(val)
  606. {
  607. this._parseSeriesCollection(val);
  608. return this._seriesCollection;
  609. }
  610. },
  611.  
  612. /**
  613. * Indicates whether the `Graph` has a background.
  614. *
  615. * @attribute showBackground
  616. * @type Boolean
  617. * @default true
  618. */
  619. showBackground: {
  620. value: true
  621. },
  622.  
  623. /**
  624. * Read-only hash lookup for all series on in the `Graph`.
  625. *
  626. * @attribute seriesDictionary
  627. * @type Object
  628. * @readOnly
  629. */
  630. seriesDictionary: {
  631. readOnly: true,
  632.  
  633. getter: function()
  634. {
  635. return this._seriesDictionary;
  636. }
  637. },
  638.  
  639. /**
  640. * Reference to the horizontal `Gridlines` instance.
  641. *
  642. * @attribute horizontalGridlines
  643. * @type Gridlines
  644. * @default null
  645. */
  646. horizontalGridlines: {
  647. value: null,
  648.  
  649. setter: function(val)
  650. {
  651. var cfg,
  652. key,
  653. gl = this.get("horizontalGridlines");
  654. if(gl && gl instanceof Y.Gridlines)
  655. {
  656. gl.remove();
  657. }
  658. if(val instanceof Y.Gridlines)
  659. {
  660. gl = val;
  661. val.set("graph", this);
  662. return val;
  663. }
  664. else if(val)
  665. {
  666. cfg = {
  667. direction: "horizonal",
  668. graph: this
  669. };
  670. for(key in val)
  671. {
  672. if(val.hasOwnProperty(key))
  673. {
  674. cfg[key] = val[key];
  675. }
  676. }
  677. gl = new Y.Gridlines(cfg);
  678. return gl;
  679. }
  680. }
  681. },
  682.  
  683. /**
  684. * Reference to the vertical `Gridlines` instance.
  685. *
  686. * @attribute verticalGridlines
  687. * @type Gridlines
  688. * @default null
  689. */
  690. verticalGridlines: {
  691. value: null,
  692.  
  693. setter: function(val)
  694. {
  695. var cfg,
  696. key,
  697. gl = this.get("verticalGridlines");
  698. if(gl && gl instanceof Y.Gridlines)
  699. {
  700. gl.remove();
  701. }
  702. if(val instanceof Y.Gridlines)
  703. {
  704. gl = val;
  705. val.set("graph", this);
  706. return val;
  707. }
  708. else if(val)
  709. {
  710. cfg = {
  711. direction: "vertical",
  712. graph: this
  713. };
  714. for(key in val)
  715. {
  716. if(val.hasOwnProperty(key))
  717. {
  718. cfg[key] = val[key];
  719. }
  720. }
  721. gl = new Y.Gridlines(cfg);
  722. return gl;
  723. }
  724. }
  725. },
  726.  
  727. /**
  728. * Reference to graphic instance used for the background.
  729. *
  730. * @attribute background
  731. * @type Graphic
  732. * @readOnly
  733. */
  734. background: {
  735. getter: function()
  736. {
  737. if(!this._background)
  738. {
  739. this._backgroundGraphic = new Y.Graphic({render:this.get("contentBox")});
  740. this._backgroundGraphic.get("node").style.zIndex = 0;
  741. this._background = this._backgroundGraphic.addShape({type: "rect"});
  742. }
  743. return this._background;
  744. }
  745. },
  746.  
  747. /**
  748. * Reference to graphic instance used for gridlines.
  749. *
  750. * @attribute gridlines
  751. * @type Graphic
  752. * @readOnly
  753. */
  754. gridlines: {
  755. readOnly: true,
  756.  
  757. getter: function()
  758. {
  759. if(!this._gridlines)
  760. {
  761. this._gridlinesGraphic = new Y.Graphic({render:this.get("contentBox")});
  762. this._gridlinesGraphic.get("node").style.zIndex = 1;
  763. this._gridlines = this._gridlinesGraphic.addShape({type: "path"});
  764. }
  765. return this._gridlines;
  766. }
  767. },
  768.  
  769. /**
  770. * Reference to graphic instance used for series.
  771. *
  772. * @attribute graphic
  773. * @type Graphic
  774. * @readOnly
  775. */
  776. graphic: {
  777. readOnly: true,
  778.  
  779. getter: function()
  780. {
  781. if(!this._graphic)
  782. {
  783. this._graphic = new Y.Graphic({render:this.get("contentBox")});
  784. this._graphic.get("node").style.zIndex = 2;
  785. this._graphic.set("autoDraw", false);
  786. }
  787. return this._graphic;
  788. }
  789. },
  790.  
  791. /**
  792. * Indicates whether or not markers for a series will be grouped and rendered in a single complex shape instance.
  793. *
  794. * @attribute groupMarkers
  795. * @type Boolean
  796. */
  797. groupMarkers: {
  798. value: false
  799. }
  800.  
  801. /**
  802. * Style properties used for drawing a background. Below are the default values:
  803. * <dl>
  804. * <dt>background</dt><dd>An object containing the following values:
  805. * <dl>
  806. * <dt>fill</dt><dd>Defines the style properties for the fill. Contains the following values:
  807. * <dl>
  808. * <dt>color</dt><dd>Color of the fill. The default value is #faf9f2.</dd>
  809. * <dt>alpha</dt><dd>Number from 0 to 1 indicating the opacity of the background fill.
  810. * The default value is 1.</dd>
  811. * </dl>
  812. * </dd>
  813. * <dt>border</dt><dd>Defines the style properties for the border. Contains the following values:
  814. * <dl>
  815. * <dt>color</dt><dd>Color of the border. The default value is #dad8c9.</dd>
  816. * <dt>alpha</dt><dd>Number from 0 to 1 indicating the opacity of the background border.
  817. * The default value is 1.</dd>
  818. * <dt>weight</dt><dd>Number indicating the width of the border. The default value is 1.</dd>
  819. * </dl>
  820. * </dd>
  821. * </dl>
  822. * </dd>
  823. * </dl>
  824. *
  825. * @attribute styles
  826. * @type Object
  827. */
  828. }
  829. });
  830.