- import Ember from 'ember';
- import HasGraphParent from 'ember-nf-graph/mixins/graph-has-graph-parent';
- import RequireScaleSource from 'ember-nf-graph/mixins/graph-requires-scale-source';
-
- import layout from '../templates/components/nf-y-axis';
-
- /**
- A component for adding a templated y axis to an `nf-graph` component.
- All items contained within this component are used to template each tick mark on the
- rendered graph. Tick values are supplied to the inner scope of this component on the
- view template via `tick`.
-
- ### Styling
-
- The main container will have a `nf-y-axis` class.
- A `orient-left` or `orient-right` container will be applied to the container
- depending on the `orient` setting.
-
- Ticks are positioned via a `<g>` tag, that will contain whatever is passed into it via
- templating, along with the tick line. `<text>` tags within tick templates do have some
- default styling applied to them to position them appropriately based off of orientation.
-
- ### Example
-
- {{#nf-graph width=500 height=300}}
- {{#nf-y-axis width=40 as |tick|}}
- <text>y is {{tick.value}}</text>
- {{/nf-y-axis}}
- {{/nf-graph}}
-
-
- @namespace components
- @class nf-y-axis
- @uses mixins.graph-has-graph-parent
- @uses mixins.graph-requires-scale-source
- */
- export default Ember.Component.extend(HasGraphParent, RequireScaleSource, {
- tagName: 'g',
-
- layout: layout,
- template: null,
-
- useTemplate: Ember.computed(function(){
- var preGlimmerCheck = this.get('template.blockParams');
- var postGlimmerCheck = this.get('hasBlock') && this.get('hasBlockParams');
- return Boolean(postGlimmerCheck || preGlimmerCheck);
- }),
-
- /**
- The number of ticks to display
- @property tickCount
- @type Number
- @default 5
- */
- tickCount: 5,
-
- /**
- The length of the tick's accompanying line.
- @property tickLength
- @type Number
- @default 5
- */
- tickLength: 5,
-
- /**
- The distance between the tick line and the origin tick's templated output
- @property tickPadding
- @type Number
- @default 3
- */
- tickPadding: 3,
-
- /**
- The total width of the y axis
- @property width
- @type Number
- @default 40
- */
- width: 40,
-
- /**
- The orientation of the y axis. Possible values are `'left'` and `'right'`
- @property orient
- @type String
- @default 'left'
- */
- orient: 'left',
-
- attributeBindings: ['transform'],
-
- classNameBindings: [':nf-y-axis', 'isOrientRight:orient-right:orient-left'],
-
- _tickFilter: null,
-
- /**
- An optional filtering function to allow more control over what tick marks are displayed.
- The function should have exactly the same signature as the function you'd use for an
- `Array.prototype.filter()`.
-
- @property tickFilter
- @type Function
- @default null
- @example
-
- {{#nf-y-axis tickFilter=myFilter as |tick|}}
- <text>{{tick.value}}</text>
- {{/nf-y-axis}}
-
- And on your controller:
-
- myFilter: function(tick, index, ticks) {
- return tick.value < 1000;
- },
-
- The above example will filter down the set of ticks to only those that are less than 1000.
- */
- tickFilter: Ember.computed(function(name, value) {
- if(arguments.length > 1) {
- this._tickFilter = value;
- }
- return this._tickFilter;
- }),
-
- /**
- computed property. returns true if `orient` is equal to `'right'`.
- @property isOrientRight
- @type Boolean
- @readonly
- */
- isOrientRight: Ember.computed.equal('orient', 'right'),
-
-
- /**
- The SVG transform for positioning the component.
- @property transform
- @type String
- @readonly
- */
- transform: Ember.computed('x', 'y', function(){
- var x = this.get('x');
- var y = this.get('y');
- return `translate(${x} ${y})`;
- }),
-
- /**
- The x position of the component
- @property x
- @type Number
- @readonly
- */
- x: Ember.computed(
- 'orient',
- 'graph.width',
- 'width',
- 'graph.paddingLeft',
- 'graph.paddingRight',
- function(){
- var orient = this.get('orient');
- if(orient !== 'left') {
- return this.get('graph.width') - this.get('width') - this.get('graph.paddingRight');
- }
- return this.get('graph.paddingLeft');
- }
- ),
-
- /**
- The y position of the component
- @property y
- @type Number
- @readonly
- */
- y: Ember.computed.alias('graph.graphY'),
-
- /**
- the height of the component
- @property height
- @type Number
- @readonly
- */
- height: Ember.computed.alias('graph.height'),
-
- init() {
- this._super(...arguments);
- this.set('graph.yAxis', this);
- },
-
- /**
- A method to call to override the default behavior of how ticks are created.
-
- The function signature should match:
-
- // - scale: d3.Scale
- // - tickCount: number of ticks
- // - uniqueData: unique data points for the axis
- // - scaleType: string of "linear" or "ordinal"
- // returns: an array of tick values.
- function(scale, tickCount, uniqueData, scaleType) {
- return [100,200,300];
- }
-
- @property tickFactory
- @type {Function}
- @default null
- */
- tickFactory: null,
-
- tickData: Ember.computed('graph.yScaleType', 'uniqueYData', 'yScale', 'tickCount', function(){
- var tickFactory = this.get('tickFactory');
- var scale = this.get('yScale');
- var uniqueData = this.get('uniqueYData');
- var scaleType = this.get('graph.yScaleType');
- var tickCount = this.get('tickCount');
-
- if(tickFactory) {
- return tickFactory(scale, tickCount, uniqueData, scaleType);
- }
- else if(scaleType === 'ordinal') {
- return uniqueData;
- }
- else {
- var ticks = scale.ticks(tickCount);
- if (scaleType === 'log') {
- var step = Math.round(ticks.length / tickCount);
- ticks = ticks.filter(function (tick, i) {
- return i % step === 0;
- });
- }
- return ticks;
- }
- }),
-
- /**
- All y data from the graph, filtered to unique values.
- @property uniqueYData
- @type Array
- @readonly
- */
- uniqueYData: Ember.computed.uniq('graph.yData'),
-
- /**
- The ticks to be displayed.
- @property ticks
- @type Array
- @readonly
- */
- ticks: Ember.computed(
- 'yScale',
- 'tickPadding',
- 'axisLineX',
- 'tickLength',
- 'isOrientRight',
- 'tickFilter',
- function(){
- var yScale = this.get('yScale');
- var tickPadding = this.get('tickPadding');
- var axisLineX = this.get('axisLineX');
- var tickLength = this.get('tickLength');
- var isOrientRight = this.get('isOrientRight');
- var tickFilter = this.get('tickFilter');
- var ticks = this.get('tickData');
- var x1 = isOrientRight ? axisLineX + tickLength : axisLineX - tickLength;
- var x2 = axisLineX;
- var labelx = isOrientRight ? (tickLength + tickPadding) : (axisLineX - tickLength - tickPadding);
-
- var result = ticks.map(function (tick) {
- return {
- value: tick,
- y: yScale(tick),
- x1: x1,
- x2: x2,
- labelx: labelx,
- };
- });
-
- if(tickFilter) {
- result = result.filter(tickFilter);
- }
-
- return Ember.A(result);
- }
- ),
-
-
- /**
- The x position of the axis line.
- @property axisLineX
- @type Number
- @readonly
- */
- axisLineX: Ember.computed('isOrientRight', 'width', function(){
- return this.get('isOrientRight') ? 0 : this.get('width');
- }),
- });
-
-