From e0b72198d38c008d9ef086d9ac0598bafc653ee4 Mon Sep 17 00:00:00 2001 From: cptran777 Date: Mon, 30 Jul 2018 16:55:08 -0700 Subject: [PATCH 1/4] Create a custom graphing component that can handle horizontal bar graphs --- .../datasets/containers/dataset-health.ts | 3 + .../charts/horizontal-bar-chart.ts | 133 ++++++++++++++++++ .../app/styles/abstracts/_functions.scss | 58 +++++++- wherehows-web/app/styles/base/_all.scss | 9 +- .../app/styles/base/_visualization.scss | 9 ++ wherehows-web/app/styles/components/_all.scss | 1 + .../styles/components/visualization/_all.scss | 1 + .../components/visualization/charts/_all.scss | 1 + .../visualization/charts/_bar-chart.scss | 25 ++++ .../datasets/containers/dataset-health.hbs | 7 +- .../charts/horizontal-bar-chart.hbs | 20 +++ .../app/typings/app/visualization/charts.d.ts | 7 + .../charts/horizontal-bar-chart-test.js | 26 ++++ 13 files changed, 293 insertions(+), 7 deletions(-) create mode 100644 wherehows-web/app/components/visualization/charts/horizontal-bar-chart.ts create mode 100644 wherehows-web/app/styles/base/_visualization.scss create mode 100644 wherehows-web/app/styles/components/visualization/_all.scss create mode 100644 wherehows-web/app/styles/components/visualization/charts/_all.scss create mode 100644 wherehows-web/app/styles/components/visualization/charts/_bar-chart.scss create mode 100644 wherehows-web/app/templates/components/visualization/charts/horizontal-bar-chart.hbs create mode 100644 wherehows-web/app/typings/app/visualization/charts.d.ts create mode 100644 wherehows-web/tests/integration/components/visualization/charts/horizontal-bar-chart-test.js diff --git a/wherehows-web/app/components/datasets/containers/dataset-health.ts b/wherehows-web/app/components/datasets/containers/dataset-health.ts index 7f24e1e60e..0cd799eb2f 100644 --- a/wherehows-web/app/components/datasets/containers/dataset-health.ts +++ b/wherehows-web/app/components/datasets/containers/dataset-health.ts @@ -29,4 +29,7 @@ export default class DatasetHealthContainer extends Component { getContainerDataTask = task(function*(this: DatasetHealthContainer): IterableIterator>> { // Do something in the future }); + + // Mock data for testing demo purposes, to be deleted once we have actual data and further development + testSeries = [{ name: 'Test1', value: 10 }, { name: 'Test2', value: 5 }, { name: 'Test3', value: 3 }]; } diff --git a/wherehows-web/app/components/visualization/charts/horizontal-bar-chart.ts b/wherehows-web/app/components/visualization/charts/horizontal-bar-chart.ts new file mode 100644 index 0000000000..9fcfb90b05 --- /dev/null +++ b/wherehows-web/app/components/visualization/charts/horizontal-bar-chart.ts @@ -0,0 +1,133 @@ +import Component from '@ember/component'; +import { IChartDatum } from 'wherehows-web/typings/app/visualization/charts'; +import { computed, get, set } from '@ember/object'; +import ComputedProperty from '@ember/object/computed'; + +interface IBarSeriesDatum extends IChartDatum { + yOffset: number; + barLength: number; + labelOffset: number; +} + +/** + * This custom component exists outside of highcharts as the library does not provide the amount + * of capabilities we need to match up with our design vision for horizontal bar charts. As such, + * there are similarities between this component and a highcharts component but it has been + * tailor-fit to our needs + */ +export default class HorizontalBarChart extends Component { + /** + * Represents the series of data needed to power our chart. Format is + * [ { name: string, value: number } ]. + * Since this chart is only meant to handle a single series of data where each bar is connected + * to one value with one label, we don't have to worry about the idea of an "x axis * y axis" + * @type {Array} + */ + series: Array; + + /** + * Helps to set the size of the svg element rendered by the component + * @type {number} + */ + size: number = 0; + + /** + * Sets the tag for the rendered html elemenet for the component + * @type {string} + */ + tagName = 'figure'; + + /** + * Sets the classes for the rendered html element for the component + * @type {Array} + */ + classNames = ['vz-chart', 'viz-bar-chart', 'single-series']; + + /** + * Constant properties to be used in calculations for the size of the svg elements drawn + */ + BAR_HEIGHT = 16; + BAR_MARGIN_BOTTOM = 8; + LABEL_HEIGHT = 15; + LABEL_MARGIN_BOTTOM = 16; + + /** + * Overall width of our chart. If we have a size, that means that the component and available space + * has been measured. + * @type {ComputedProperty} + */ + width: ComputedProperty = computed('size', function(this: HorizontalBarChart) { + return get(this, 'size') ? this.$(this.element).width() : 0; + }); + + /** + * Overall height of our chart, calculated based on the amount of items we have in our series + * @type {ComputedProperty} + */ + height: ComputedProperty = computed('categories', function(this: HorizontalBarChart) { + return (get(this, 'series') || []).length * this.heightModifier(); + }); + + /** + * Calculates information needed for the svg element to properly render each bar of our graph using the + * correct dimensions relative to the data it's receiving + * @type {ComputedProperty> = computed('series', 'size', function(this: HorizontalBarChart) { + return (this.get('series') || []).map(this.bar.bind(this)); + }); + + /** + * Sets our highest value for the chart's Y axis, based on the highest value inside the series + * @type {ComputedProperty} + */ + maxY: ComputedProperty = computed('series', function(this: HorizontalBarChart) { + return (get(this, 'series') || []).reduce((memo, dataPoint) => { + if (dataPoint.value > memo) { + return dataPoint.value; + } + return memo; + }, Number.MIN_VALUE); + }); + + /** + * Returns a "modifier" that is the height of a single bar and label in the chart, and can be multiplied + * by the number of rows in the chart to get the total chart height + * @param this - explicit this keyword declaration for typescript + */ + heightModifier(this: HorizontalBarChart): number { + return ( + get(this, 'BAR_HEIGHT') + + get(this, 'BAR_MARGIN_BOTTOM') + + get(this, 'LABEL_HEIGHT') + + get(this, 'LABEL_MARGIN_BOTTOM') + ); + } + + /** + * Used as a predicate function in the mapping function for the series array to be mapped into the + * seriesData array, this function adds values to each chart datum object so that the svg template + * can render each bar with the correct dimensions and position + * @param this - explicit this keyword declaration for typescript + * @param data - single datum object in our series + * @param index - current index in the series array + */ + bar(this: HorizontalBarChart, data: IChartDatum, index: number) { + const yOffset = 1 + index * this.heightModifier(); + + return { + ...data, + yOffset, + barLength: Math.max(1, Math.floor(data.value / get(this, 'maxY') * get(this, 'width'))), + labelOffset: yOffset + get(this, 'BAR_HEIGHT') + get(this, 'BAR_MARGIN_BOTTOM') + get(this, 'LABEL_HEIGHT') + }; + } + + /** + * Once we have inserted our html element, we can determine the width (size) of our chart + */ + didInsertElement() { + this._super(...arguments); + set(this, 'size', this.$(this.element).width() || 0); + } +} diff --git a/wherehows-web/app/styles/abstracts/_functions.scss b/wherehows-web/app/styles/abstracts/_functions.scss index 6d9def771a..0891429082 100644 --- a/wherehows-web/app/styles/abstracts/_functions.scss +++ b/wherehows-web/app/styles/abstracts/_functions.scss @@ -6,7 +6,7 @@ /// @param {String} $path - asset path /// @return {Url} @function asset($base, $type, $path) { - @return url($base + $type + $path); + @return url($base+$type+$path); } /// Returns URL to an image based on its path @@ -90,7 +90,7 @@ blue: (oxford: rgb(53, 75, 87), curious: rgb(26, 161, 217), eastern: rgb(26, 132, 188), blue5: rgb(26, 161, 217)), grey: (light: rgb(237, 237, 237), dark: rgb(68, 68, 68), mid: rgb(153, 153, 153)), black: (dune: rgb(41, 39, 36)), - white: (base: rgb(255, 255, 255), catskill: rgb(243, 247, 249), earlydawn:rgb(255, 249, 232)) + white: (base: rgb(255, 255, 255), catskill: rgb(243, 247, 249), earlydawn: rgb(255, 249, 232)) ); @return map-get(map-get($color-scheme, $color), $hue); @@ -285,3 +285,57 @@ @return $color; } + +@function get-dataviz-color($value) { + $color-palette-dataviz: ( + order: + ( + get-color(blue5), + get-color(teal7), + get-color(purple5), + get-color(slate3), + get-color(orange5), + get-color(pink7), + get-color(blue3), + get-color(teal5), + get-color(purple3), + get-color(slate7), + get-color(orange3), + get-color(pink5), + get-color(blue7), + get-color(teal3), + get-color(purple7), + get-color(slate5), + get-color(orange7), + get-color(pink3) + ), + positive: get-color(green6), + negative: get-color(red6) + ); + + $list: map-get($color-palette-dataviz, order); + + @if (type-of($value) == 'number') { + $index: $value % length($list); + + @if ($value < 1) { + @error 'get-dataviz-color requires a number greater than 0, got #{$value}.'; + } + + @if ($index == 0) { + @return nth($list, length($list)); + } + + @return nth($list, $index); + } + + @if ($value == 'positive') { + @return map-get($color-palette-dataviz, positive); + } + + @if ($value == 'negative') { + @return map-get($color-palette-dataviz, negative); + } + + @error '#{$value} is not a valid data-visualization-color option'; +} diff --git a/wherehows-web/app/styles/base/_all.scss b/wherehows-web/app/styles/base/_all.scss index 31e2c59826..caec94262c 100644 --- a/wherehows-web/app/styles/base/_all.scss +++ b/wherehows-web/app/styles/base/_all.scss @@ -1,4 +1,5 @@ -@import "base"; -@import "fonts"; -@import "typography"; -@import "helpers"; \ No newline at end of file +@import 'base'; +@import 'fonts'; +@import 'typography'; +@import 'helpers'; +@import 'visualization'; diff --git a/wherehows-web/app/styles/base/_visualization.scss b/wherehows-web/app/styles/base/_visualization.scss new file mode 100644 index 0000000000..9f7c540162 --- /dev/null +++ b/wherehows-web/app/styles/base/_visualization.scss @@ -0,0 +1,9 @@ +/* Sets the default colors for the visualization colors. When rendering a series of data, the color + order for each item should always be the same */ +@for $i from 1 through 18 { + $color: get-dataviz-color($i); + .highcharts-color-#{$i - 1} { + fill: $color; + stroke: $color; + } +} diff --git a/wherehows-web/app/styles/components/_all.scss b/wherehows-web/app/styles/components/_all.scss index 880f9c19dd..4fa83fbc98 100644 --- a/wherehows-web/app/styles/components/_all.scss +++ b/wherehows-web/app/styles/components/_all.scss @@ -25,6 +25,7 @@ @import 'entity-header/all'; @import 'dataset-fabric/all'; @import 'dataset-relationships/all'; +@import 'visualization/all'; @import 'nacho/nacho-button'; @import 'nacho/nacho-global-search'; diff --git a/wherehows-web/app/styles/components/visualization/_all.scss b/wherehows-web/app/styles/components/visualization/_all.scss new file mode 100644 index 0000000000..206bb90212 --- /dev/null +++ b/wherehows-web/app/styles/components/visualization/_all.scss @@ -0,0 +1 @@ +@import 'charts/all'; diff --git a/wherehows-web/app/styles/components/visualization/charts/_all.scss b/wherehows-web/app/styles/components/visualization/charts/_all.scss new file mode 100644 index 0000000000..771e6fb151 --- /dev/null +++ b/wherehows-web/app/styles/components/visualization/charts/_all.scss @@ -0,0 +1 @@ +@import 'bar-chart'; diff --git a/wherehows-web/app/styles/components/visualization/charts/_bar-chart.scss b/wherehows-web/app/styles/components/visualization/charts/_bar-chart.scss new file mode 100644 index 0000000000..d0af343a6e --- /dev/null +++ b/wherehows-web/app/styles/components/visualization/charts/_bar-chart.scss @@ -0,0 +1,25 @@ +.viz-bar-chart { + .highcharts-root { + .highcharts { + &-label, + &-data-label { + fill: $text-color; + stroke: $text-color; + + text { + font-weight: 100; + } + + .highcharts-emphasized { + font-weight: 400; + } + } + } + } + + &__title { + font-weight: bold; + font-size: 15px; + margin-bottom: 16px; + } +} diff --git a/wherehows-web/app/templates/components/datasets/containers/dataset-health.hbs b/wherehows-web/app/templates/components/datasets/containers/dataset-health.hbs index 809b2abd25..7fadacc97b 100644 --- a/wherehows-web/app/templates/components/datasets/containers/dataset-health.hbs +++ b/wherehows-web/app/templates/components/datasets/containers/dataset-health.hbs @@ -1 +1,6 @@ -Coming Soon! \ No newline at end of file +Coming Soon! +
+ {{visualization/charts/horizontal-bar-chart + title="Test Chart" + series=testSeries}} +
\ No newline at end of file diff --git a/wherehows-web/app/templates/components/visualization/charts/horizontal-bar-chart.hbs b/wherehows-web/app/templates/components/visualization/charts/horizontal-bar-chart.hbs new file mode 100644 index 0000000000..49210fa67b --- /dev/null +++ b/wherehows-web/app/templates/components/visualization/charts/horizontal-bar-chart.hbs @@ -0,0 +1,20 @@ +
{{title}}
+ + + + {{#each seriesData as |datum index|}} + + {{/each}} + + + {{#each seriesData as |datum index|}} + + + {{datum.value}} + | {{datum.name}} + + + {{/each}} + + + \ No newline at end of file diff --git a/wherehows-web/app/typings/app/visualization/charts.d.ts b/wherehows-web/app/typings/app/visualization/charts.d.ts new file mode 100644 index 0000000000..93d6693a4e --- /dev/null +++ b/wherehows-web/app/typings/app/visualization/charts.d.ts @@ -0,0 +1,7 @@ +/** + * Expected basic chart data object for a single item in a chart series. + */ +export interface IChartDatum { + name: string; + value: number; +} diff --git a/wherehows-web/tests/integration/components/visualization/charts/horizontal-bar-chart-test.js b/wherehows-web/tests/integration/components/visualization/charts/horizontal-bar-chart-test.js new file mode 100644 index 0000000000..56e1d724d4 --- /dev/null +++ b/wherehows-web/tests/integration/components/visualization/charts/horizontal-bar-chart-test.js @@ -0,0 +1,26 @@ +import { module, test } from 'qunit'; +import { setupRenderingTest } from 'ember-qunit'; +import { render } from '@ember/test-helpers'; +import hbs from 'htmlbars-inline-precompile'; + +module('Integration | Component | visualization/charts/horizontal-bar-chart', function(hooks) { + setupRenderingTest(hooks); + + test('it renders', async function(assert) { + // Set any properties with this.set('myProperty', 'value'); + // Handle any actions with this.set('myAction', function(val) { ... }); + + await render(hbs`{{visualization/charts/horizontal-bar-chart}}`); + + assert.equal(this.element.textContent.trim(), ''); + + // Template block usage: + await render(hbs` + {{#visualization/charts/horizontal-bar-chart}} + template block text + {{/visualization/charts/horizontal-bar-chart}} + `); + + assert.equal(this.element.textContent.trim(), 'template block text'); + }); +}); From 9a36bdbc5fbcb864737e32b7f880c33082325e6f Mon Sep 17 00:00:00 2001 From: cptran777 Date: Mon, 30 Jul 2018 20:58:27 -0700 Subject: [PATCH 2/4] add tests for previous commit for horizontal-bar-chart --- .../charts/horizontal-bar-chart-test.js | 62 ++++++++++++------- 1 file changed, 41 insertions(+), 21 deletions(-) diff --git a/wherehows-web/tests/integration/components/visualization/charts/horizontal-bar-chart-test.js b/wherehows-web/tests/integration/components/visualization/charts/horizontal-bar-chart-test.js index 56e1d724d4..571fa7ed2d 100644 --- a/wherehows-web/tests/integration/components/visualization/charts/horizontal-bar-chart-test.js +++ b/wherehows-web/tests/integration/components/visualization/charts/horizontal-bar-chart-test.js @@ -1,26 +1,46 @@ -import { module, test } from 'qunit'; -import { setupRenderingTest } from 'ember-qunit'; -import { render } from '@ember/test-helpers'; +import { moduleForComponent, test } from 'ember-qunit'; import hbs from 'htmlbars-inline-precompile'; -module('Integration | Component | visualization/charts/horizontal-bar-chart', function(hooks) { - setupRenderingTest(hooks); +moduleForComponent( + 'visualization/charts/horizontal-bar-chart', + 'Integration | Component | visualization/charts/horizontal-bar-chart', + { integration: true } +); - test('it renders', async function(assert) { - // Set any properties with this.set('myProperty', 'value'); - // Handle any actions with this.set('myAction', function(val) { ... }); +/* Selectors */ +const chartTitle = '.viz-bar-chart__title'; +const chartBar = 'rect'; +const chartLabel = '.highcharts-data-label'; - await render(hbs`{{visualization/charts/horizontal-bar-chart}}`); - - assert.equal(this.element.textContent.trim(), ''); - - // Template block usage: - await render(hbs` - {{#visualization/charts/horizontal-bar-chart}} - template block text - {{/visualization/charts/horizontal-bar-chart}} - `); - - assert.equal(this.element.textContent.trim(), 'template block text'); - }); +test('it renders', async function(assert) { + this.render(hbs`{{visualization/charts/horizontal-bar-chart}}`); + assert.ok(this.$(), 'Renders without errors'); +}); + +test('it displays the correct graph information', async function(assert) { + const title = 'Pokemon Values'; + const series = [ + { name: 'Mewtwo', value: 150 }, + { name: 'Alakazam', value: 65 }, + { name: 'Pikachu', value: 25 }, + { name: 'Charmander', value: 4 } + ]; + + this.setProperties({ title, series }); + this.render(hbs`{{visualization/charts/horizontal-bar-chart + series=series + title=title}}`); + + assert.ok(this.$(), 'Still renders without errors'); + assert.equal(this.$(chartBar).length, series.length, 'Renders 3 bars'); + assert.equal(this.$(chartLabel).length, series.length, 'Renders 3 labels'); + + assert.equal( + this.$('text:eq(0)') + .text() + .trim() + .replace(/[ \n]/g, ''), + '150|Mewtwo', + 'Renders the correct first label' + ); }); From 88fad6cf882711b1796f31c2264ccd175dbb8c2f Mon Sep 17 00:00:00 2001 From: cptran777 Date: Tue, 31 Jul 2018 13:11:57 -0700 Subject: [PATCH 3/4] add optional customizations to horizontal bar chart labels --- .../charts/horizontal-bar-chart.ts | 52 ++++++++++++++++--- .../datasets/containers/dataset-health.hbs | 3 +- .../charts/horizontal-bar-chart.hbs | 4 +- 3 files changed, 50 insertions(+), 9 deletions(-) diff --git a/wherehows-web/app/components/visualization/charts/horizontal-bar-chart.ts b/wherehows-web/app/components/visualization/charts/horizontal-bar-chart.ts index 9fcfb90b05..886de0f76e 100644 --- a/wherehows-web/app/components/visualization/charts/horizontal-bar-chart.ts +++ b/wherehows-web/app/components/visualization/charts/horizontal-bar-chart.ts @@ -1,6 +1,6 @@ import Component from '@ember/component'; import { IChartDatum } from 'wherehows-web/typings/app/visualization/charts'; -import { computed, get, set } from '@ember/object'; +import { computed, get, set, setProperties } from '@ember/object'; import ComputedProperty from '@ember/object/computed'; interface IBarSeriesDatum extends IChartDatum { @@ -14,8 +14,28 @@ interface IBarSeriesDatum extends IChartDatum { * of capabilities we need to match up with our design vision for horizontal bar charts. As such, * there are similarities between this component and a highcharts component but it has been * tailor-fit to our needs + * + * Bar Chart Usage + * {{visualization/charts/horizontal-bar-chart + * series=[ { name: string, value: number, otherKey: otherValue } ] + * title="string" + * labelTagProperty="optionStringOverridesDefault" + * labelAppendTag="optionalStringAppendsEachTag" + * labelAppendValue="optionalStringSuchAs%"}} */ export default class HorizontalBarChart extends Component { + /** + * Sets the tag for the rendered html elemenet for the component + * @type {string} + */ + tagName = 'figure'; + + /** + * Sets the classes for the rendered html element for the component + * @type {Array} + */ + classNames = ['vz-chart', 'viz-bar-chart', 'single-series']; + /** * Represents the series of data needed to power our chart. Format is * [ { name: string, value: number } ]. @@ -32,19 +52,29 @@ export default class HorizontalBarChart extends Component { size: number = 0; /** - * Sets the tag for the rendered html elemenet for the component + * Property in the series datum to use as the tag for each value in the bar legend. Note, each + * legend item will appear as VALUE | TAG * @type {string} + * @default 'name' */ - tagName = 'figure'; + labelTagProperty: string; /** - * Sets the classes for the rendered html element for the component - * @type {Array} + * Any string we want to append to each tag in the label, such as a unit. + * @type {string} */ - classNames = ['vz-chart', 'viz-bar-chart', 'single-series']; + labelAppendTag: string; + + /** + * Any string that we want to append to each value in the label, such as %. Doing so would + * append every value, such as 60, in the label with % and appear as 60% + * @type {string} + */ + labelAppendValue: string; /** * Constant properties to be used in calculations for the size of the svg elements drawn + * @type {number} */ BAR_HEIGHT = 16; BAR_MARGIN_BOTTOM = 8; @@ -123,6 +153,16 @@ export default class HorizontalBarChart extends Component { }; } + constructor() { + super(); + // Applying passed in properties or setting to default values + setProperties(this, { + labelTagProperty: this.labelTagProperty || 'name', + labelAppendTag: this.labelAppendTag || '', + labelAppendValue: this.labelAppendValue || '' + }); + } + /** * Once we have inserted our html element, we can determine the width (size) of our chart */ diff --git a/wherehows-web/app/templates/components/datasets/containers/dataset-health.hbs b/wherehows-web/app/templates/components/datasets/containers/dataset-health.hbs index 7fadacc97b..2fb02b5407 100644 --- a/wherehows-web/app/templates/components/datasets/containers/dataset-health.hbs +++ b/wherehows-web/app/templates/components/datasets/containers/dataset-health.hbs @@ -2,5 +2,6 @@ Coming Soon!
{{visualization/charts/horizontal-bar-chart title="Test Chart" - series=testSeries}} + series=testSeries + labelAppendValue="%"}}
\ No newline at end of file diff --git a/wherehows-web/app/templates/components/visualization/charts/horizontal-bar-chart.hbs b/wherehows-web/app/templates/components/visualization/charts/horizontal-bar-chart.hbs index 49210fa67b..4026b44ee3 100644 --- a/wherehows-web/app/templates/components/visualization/charts/horizontal-bar-chart.hbs +++ b/wherehows-web/app/templates/components/visualization/charts/horizontal-bar-chart.hbs @@ -10,8 +10,8 @@ {{#each seriesData as |datum index|}} - {{datum.value}} - | {{datum.name}} + {{datum.value}}{{labelAppendValue}} + | {{get datum labelTagProperty}} {{/each}} From ae39090c0cdce919630b5b087c4da0ba06b3827a Mon Sep 17 00:00:00 2001 From: cptran777 Date: Tue, 31 Jul 2018 13:28:47 -0700 Subject: [PATCH 4/4] Add type annotations for callback function return values in horizontal bar graphs component --- .../visualization/charts/horizontal-bar-chart.ts | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/wherehows-web/app/components/visualization/charts/horizontal-bar-chart.ts b/wherehows-web/app/components/visualization/charts/horizontal-bar-chart.ts index 886de0f76e..e9f9a20050 100644 --- a/wherehows-web/app/components/visualization/charts/horizontal-bar-chart.ts +++ b/wherehows-web/app/components/visualization/charts/horizontal-bar-chart.ts @@ -86,15 +86,15 @@ export default class HorizontalBarChart extends Component { * has been measured. * @type {ComputedProperty} */ - width: ComputedProperty = computed('size', function(this: HorizontalBarChart) { - return get(this, 'size') ? this.$(this.element).width() : 0; + width: ComputedProperty = computed('size', function(this: HorizontalBarChart): number { + return get(this, 'size') ? this.$(this.element).width() || 0 : 0; }); /** * Overall height of our chart, calculated based on the amount of items we have in our series * @type {ComputedProperty} */ - height: ComputedProperty = computed('categories', function(this: HorizontalBarChart) { + height: ComputedProperty = computed('categories', function(this: HorizontalBarChart): number { return (get(this, 'series') || []).length * this.heightModifier(); }); @@ -103,7 +103,9 @@ export default class HorizontalBarChart extends Component { * correct dimensions relative to the data it's receiving * @type {ComputedProperty> = computed('series', 'size', function(this: HorizontalBarChart) { + seriesData: ComputedProperty> = computed('series', 'size', function( + this: HorizontalBarChart + ): Array { return (this.get('series') || []).map(this.bar.bind(this)); }); @@ -111,7 +113,7 @@ export default class HorizontalBarChart extends Component { * Sets our highest value for the chart's Y axis, based on the highest value inside the series * @type {ComputedProperty} */ - maxY: ComputedProperty = computed('series', function(this: HorizontalBarChart) { + maxY: ComputedProperty = computed('series', function(this: HorizontalBarChart): number { return (get(this, 'series') || []).reduce((memo, dataPoint) => { if (dataPoint.value > memo) { return dataPoint.value; @@ -142,7 +144,7 @@ export default class HorizontalBarChart extends Component { * @param data - single datum object in our series * @param index - current index in the series array */ - bar(this: HorizontalBarChart, data: IChartDatum, index: number) { + bar(this: HorizontalBarChart, data: IChartDatum, index: number): IBarSeriesDatum { const yOffset = 1 + index * this.heightModifier(); return { @@ -154,7 +156,7 @@ export default class HorizontalBarChart extends Component { } constructor() { - super(); + super(...arguments); // Applying passed in properties or setting to default values setProperties(this, { labelTagProperty: this.labelTagProperty || 'name',