API Docs for:
Show:

File: app/components/nf-y-axis.js

  1. import Ember from 'ember';
  2. import HasGraphParent from 'ember-nf-graph/mixins/graph-has-graph-parent';
  3. import RequireScaleSource from 'ember-nf-graph/mixins/graph-requires-scale-source';
  4.  
  5. import layout from '../templates/components/nf-y-axis';
  6.  
  7. /**
  8. A component for adding a templated y axis to an `nf-graph` component.
  9. All items contained within this component are used to template each tick mark on the
  10. rendered graph. Tick values are supplied to the inner scope of this component on the
  11. view template via `tick`.
  12. ### Styling
  13. The main container will have a `nf-y-axis` class.
  14. A `orient-left` or `orient-right` container will be applied to the container
  15. depending on the `orient` setting.
  16.  
  17. Ticks are positioned via a `<g>` tag, that will contain whatever is passed into it via
  18. templating, along with the tick line. `<text>` tags within tick templates do have some
  19. default styling applied to them to position them appropriately based off of orientation.
  20.  
  21. ### Example
  22.  
  23. {{#nf-graph width=500 height=300}}
  24. {{#nf-y-axis width=40 as |tick|}}
  25. <text>y is {{tick.value}}</text>
  26. {{/nf-y-axis}}
  27. {{/nf-graph}}
  28.  
  29.  
  30. @namespace components
  31. @class nf-y-axis
  32. @uses mixins.graph-has-graph-parent
  33. @uses mixins.graph-requires-scale-source
  34. */
  35. export default Ember.Component.extend(HasGraphParent, RequireScaleSource, {
  36. tagName: 'g',
  37.  
  38. layout: layout,
  39. template: null,
  40.  
  41. useTemplate: Ember.computed(function(){
  42. var preGlimmerCheck = this.get('template.blockParams');
  43. var postGlimmerCheck = this.get('hasBlock') && this.get('hasBlockParams');
  44. return Boolean(postGlimmerCheck || preGlimmerCheck);
  45. }),
  46.  
  47. /**
  48. The number of ticks to display
  49. @property tickCount
  50. @type Number
  51. @default 5
  52. */
  53. tickCount: 5,
  54.  
  55. /**
  56. The length of the tick's accompanying line.
  57. @property tickLength
  58. @type Number
  59. @default 5
  60. */
  61. tickLength: 5,
  62.  
  63. /**
  64. The distance between the tick line and the origin tick's templated output
  65. @property tickPadding
  66. @type Number
  67. @default 3
  68. */
  69. tickPadding: 3,
  70.  
  71. /**
  72. The total width of the y axis
  73. @property width
  74. @type Number
  75. @default 40
  76. */
  77. width: 40,
  78.  
  79. /**
  80. The orientation of the y axis. Possible values are `'left'` and `'right'`
  81. @property orient
  82. @type String
  83. @default 'left'
  84. */
  85. orient: 'left',
  86.  
  87. attributeBindings: ['transform'],
  88.  
  89. classNameBindings: [':nf-y-axis', 'isOrientRight:orient-right:orient-left'],
  90. _tickFilter: null,
  91.  
  92. /**
  93. An optional filtering function to allow more control over what tick marks are displayed.
  94. The function should have exactly the same signature as the function you'd use for an
  95. `Array.prototype.filter()`.
  96. @property tickFilter
  97. @type Function
  98. @default null
  99. @example
  100.  
  101. {{#nf-y-axis tickFilter=myFilter as |tick|}}
  102. <text>{{tick.value}}</text>
  103. {{/nf-y-axis}}
  104. And on your controller:
  105. myFilter: function(tick, index, ticks) {
  106. return tick.value < 1000;
  107. },
  108. The above example will filter down the set of ticks to only those that are less than 1000.
  109. */
  110. tickFilter: Ember.computed(function(name, value) {
  111. if(arguments.length > 1) {
  112. this._tickFilter = value;
  113. }
  114. return this._tickFilter;
  115. }),
  116.  
  117. /**
  118. computed property. returns true if `orient` is equal to `'right'`.
  119. @property isOrientRight
  120. @type Boolean
  121. @readonly
  122. */
  123. isOrientRight: Ember.computed.equal('orient', 'right'),
  124.  
  125.  
  126. /**
  127. The SVG transform for positioning the component.
  128. @property transform
  129. @type String
  130. @readonly
  131. */
  132. transform: Ember.computed('x', 'y', function(){
  133. var x = this.get('x');
  134. var y = this.get('y');
  135. return `translate(${x} ${y})`;
  136. }),
  137.  
  138. /**
  139. The x position of the component
  140. @property x
  141. @type Number
  142. @readonly
  143. */
  144. x: Ember.computed(
  145. 'orient',
  146. 'graph.width',
  147. 'width',
  148. 'graph.paddingLeft',
  149. 'graph.paddingRight',
  150. function(){
  151. var orient = this.get('orient');
  152. if(orient !== 'left') {
  153. return this.get('graph.width') - this.get('width') - this.get('graph.paddingRight');
  154. }
  155. return this.get('graph.paddingLeft');
  156. }
  157. ),
  158.  
  159. /**
  160. The y position of the component
  161. @property y
  162. @type Number
  163. @readonly
  164. */
  165. y: Ember.computed.alias('graph.graphY'),
  166.  
  167. /**
  168. the height of the component
  169. @property height
  170. @type Number
  171. @readonly
  172. */
  173. height: Ember.computed.alias('graph.height'),
  174.  
  175. init() {
  176. this._super(...arguments);
  177. this.set('graph.yAxis', this);
  178. },
  179.  
  180. /**
  181. A method to call to override the default behavior of how ticks are created.
  182.  
  183. The function signature should match:
  184.  
  185. // - scale: d3.Scale
  186. // - tickCount: number of ticks
  187. // - uniqueData: unique data points for the axis
  188. // - scaleType: string of "linear" or "ordinal"
  189. // returns: an array of tick values.
  190. function(scale, tickCount, uniqueData, scaleType) {
  191. return [100,200,300];
  192. }
  193.  
  194. @property tickFactory
  195. @type {Function}
  196. @default null
  197. */
  198. tickFactory: null,
  199.  
  200. tickData: Ember.computed('graph.yScaleType', 'uniqueYData', 'yScale', 'tickCount', function(){
  201. var tickFactory = this.get('tickFactory');
  202. var scale = this.get('yScale');
  203. var uniqueData = this.get('uniqueYData');
  204. var scaleType = this.get('graph.yScaleType');
  205. var tickCount = this.get('tickCount');
  206.  
  207. if(tickFactory) {
  208. return tickFactory(scale, tickCount, uniqueData, scaleType);
  209. }
  210. else if(scaleType === 'ordinal') {
  211. return uniqueData;
  212. }
  213. else {
  214. var ticks = scale.ticks(tickCount);
  215. if (scaleType === 'log') {
  216. var step = Math.round(ticks.length / tickCount);
  217. ticks = ticks.filter(function (tick, i) {
  218. return i % step === 0;
  219. });
  220. }
  221. return ticks;
  222. }
  223. }),
  224.  
  225. /**
  226. All y data from the graph, filtered to unique values.
  227. @property uniqueYData
  228. @type Array
  229. @readonly
  230. */
  231. uniqueYData: Ember.computed.uniq('graph.yData'),
  232.  
  233. /**
  234. The ticks to be displayed.
  235. @property ticks
  236. @type Array
  237. @readonly
  238. */
  239. ticks: Ember.computed(
  240. 'yScale',
  241. 'tickPadding',
  242. 'axisLineX',
  243. 'tickLength',
  244. 'isOrientRight',
  245. 'tickFilter',
  246. function(){
  247. var yScale = this.get('yScale');
  248. var tickPadding = this.get('tickPadding');
  249. var axisLineX = this.get('axisLineX');
  250. var tickLength = this.get('tickLength');
  251. var isOrientRight = this.get('isOrientRight');
  252. var tickFilter = this.get('tickFilter');
  253. var ticks = this.get('tickData');
  254. var x1 = isOrientRight ? axisLineX + tickLength : axisLineX - tickLength;
  255. var x2 = axisLineX;
  256. var labelx = isOrientRight ? (tickLength + tickPadding) : (axisLineX - tickLength - tickPadding);
  257.  
  258. var result = ticks.map(function (tick) {
  259. return {
  260. value: tick,
  261. y: yScale(tick),
  262. x1: x1,
  263. x2: x2,
  264. labelx: labelx,
  265. };
  266. });
  267.  
  268. if(tickFilter) {
  269. result = result.filter(tickFilter);
  270. }
  271.  
  272. return Ember.A(result);
  273. }
  274. ),
  275.  
  276.  
  277. /**
  278. The x position of the axis line.
  279. @property axisLineX
  280. @type Number
  281. @readonly
  282. */
  283. axisLineX: Ember.computed('isOrientRight', 'width', function(){
  284. return this.get('isOrientRight') ? 0 : this.get('width');
  285. }),
  286. });
  287.