From b131b91b820c6883eafa6a1d782a21b4ae269a17 Mon Sep 17 00:00:00 2001 From: Claire Bontempo Date: Mon, 20 Dec 2021 10:44:56 -0800 Subject: [PATCH 01/26] grid for stacked charts --- .../components/clients/client-counts-range.js | 155 ++++++++++++++++++ ui/app/components/clients/dashboard.js | 4 +- ui/app/styles/core/charts.scss | 7 + .../clients/client-counts-range.hbs | 85 ++++++++++ .../components/clients/dashboard.hbs | 6 + .../clients/horizontal-bar-charts.hbs | 4 +- .../components/clients/total-client-usage.hbs | 4 +- 7 files changed, 259 insertions(+), 6 deletions(-) create mode 100644 ui/app/components/clients/client-counts-range.js create mode 100644 ui/app/templates/components/clients/client-counts-range.hbs diff --git a/ui/app/components/clients/client-counts-range.js b/ui/app/components/clients/client-counts-range.js new file mode 100644 index 00000000000..237905bf02c --- /dev/null +++ b/ui/app/components/clients/client-counts-range.js @@ -0,0 +1,155 @@ +import Component from '@glimmer/component'; +import { action } from '@ember/object'; +import { tracked } from '@glimmer/tracking'; +import { max } from 'd3-array'; +// eslint-disable-next-line no-unused-vars +import { select, selectAll, node } from 'd3-selection'; +import { axisLeft, axisBottom } from 'd3-axis'; +import { scaleLinear, scaleBand } from 'd3-scale'; +import { format } from 'd3-format'; +import { stack } from 'd3-shape'; + +/** + * @module ClientCountsRange + * ClientCountsRange components are used to... + * + * @example + * ```js + * + * ``` + * @param {object} requiredParam - requiredParam is... + * @param {string} [optionalParam] - optionalParam is... + * @param {string} [param1=defaultValue] - param1 is... + */ + +const DATA = [ + { month: 'January', directEntities: 1000, nonEntityTokens: 322, total: 1322 }, + { month: 'February', directEntities: 1500, nonEntityTokens: 122, total: 1622 }, + { month: 'March', directEntities: 4300, nonEntityTokens: 700, total: 5000 }, + { month: 'April', directEntities: 1550, nonEntityTokens: 229, total: 1779 }, + { month: 'May', directEntities: 5560, nonEntityTokens: 124, total: 5684 }, + { month: 'June', directEntities: 1570, nonEntityTokens: 142, total: 1712 }, + { month: 'July', directEntities: 300, nonEntityTokens: 112, total: 412 }, + { month: 'August', directEntities: 1610, nonEntityTokens: 130, total: 1740 }, + { month: 'September', directEntities: 1900, nonEntityTokens: 222, total: 2122 }, + { month: 'October', directEntities: 500, nonEntityTokens: 166, total: 666 }, + { month: 'November', directEntities: 480, nonEntityTokens: 132, total: 612 }, + { month: 'December', directEntities: 980, nonEntityTokens: 202, total: 1182 }, +]; + +// COLOR THEME: +const BAR_COLOR_DEFAULT = ['#8AB1FF', '#1563FF']; +const BACKGROUND_BAR_COLOR = '#EBEEF2'; + +// TRANSLATIONS: +const TRANSLATE = { left: -11 }; +const SVG_DIMENSIONS = { height: 190, width: 500 }; + +export default class ClientCountsRange extends Component { + @tracked tooltipTarget = ''; + @tracked hoveredLabel = ''; + + @action + renderChart(element) { + // Define the chart + let dataset = DATA; // will be data passed in as argument + + let stackFunction = stack().keys(['directEntities', 'nonEntityTokens']); + let stackedData = stackFunction(dataset); + + let yScale = scaleLinear() + .domain([0, max(dataset.map(d => d.total))]) // TODO will need to recalculate when you get the data + .range([0, 100]); + + let xScale = scaleBand() + .domain(dataset.map(d => d.month)) + .range([0, SVG_DIMENSIONS.width]) // set width to fix number of pixels + .paddingInner(0.85); + + let chartSvg = select(element); + + chartSvg.attr('viewBox', `-50 20 600 ${SVG_DIMENSIONS.height}`); // set svg dimensions + + let groups = chartSvg + .selectAll('g') + .data(stackedData) + .enter() + .append('g') + .style('fill', (d, i) => BAR_COLOR_DEFAULT[i]); + + groups + .selectAll('rect') + .data(stackedData => stackedData) + .enter() + .append('rect') + .attr('width', '7px') + .attr('class', 'data-bar') + .attr('height', stackedData => `${yScale(stackedData[1] - stackedData[0])}%`) + .attr('x', ({ data }) => xScale(data.month)) // uses destructuring because was data.data.month + .attr('y', data => `${100 - yScale(data[1])}%`); // subtract higher than 100% to give space for x axis ticks + + // MAKE AXES // + let yAxisScale = scaleLinear() + .domain([0, max(dataset.map(d => d.total))]) // TODO will need to recalculate when you get the data + .range([`${SVG_DIMENSIONS.height}`, 0]); + + // Reference for tickFormat https://www.youtube.com/watch?v=c3MCROTNN8g + let formatNumbers = number => format('.2s')(number).replace('G', 'B'); // for billions to replace G with B. + + // customize y-axis + let yAxis = axisLeft(yAxisScale) + .ticks(7) + .tickPadding(10) + .tickSizeInner(-SVG_DIMENSIONS.width) // makes grid lines correct length + .tickFormat(formatNumbers); + + yAxis(chartSvg.append('g')); + + // customize x-axis + let xAxisGenerator = axisBottom(xScale).tickSize(0); + let xAxis = chartSvg.append('g').call(xAxisGenerator); + + xAxis.attr('transform', `translate(0, ${SVG_DIMENSIONS.height + 10})`); + + chartSvg.selectAll('.domain').remove(); // remove domain lines + + // creating wider area for tooltip hover + let greyBars = chartSvg + .append('g') + .attr('transform', `translate(${TRANSLATE.left})`) + .style('fill', `${BACKGROUND_BAR_COLOR}`) + .style('opacity', '0') + .style('mix-blend-mode', 'multiply'); + + let tooltipRect = greyBars + .selectAll('rect') + .data(dataset) + .enter() + .append('rect') + .style('cursor', 'pointer') + .attr('class', 'tooltip-rect') + .attr('height', '100%') + .attr('width', '30px') // three times width + .attr('y', '0') // start at bottom + .attr('x', data => xScale(data.month)); // not data.data because this is not stacked data + + // for tooltip + tooltipRect.on('mouseover', data => { + this.hoveredLabel = data.month; + // let node = chartSvg + // .selectAll('rect.tooltip-rect') + // .filter(data => data.month === this.hoveredLabel) + // .node(); + let node = chartSvg + .selectAll('rect.data-bar') + // filter for the top data bar (so y-coord !== 0) with matching month + .filter(data => data[0] !== 0 && data.data.month === this.hoveredLabel) + .node(); + this.tooltipTarget = node; // grab the node from the list of rects + }); + } + + @action removeTooltip() { + this.tooltipTarget = null; + } +} diff --git a/ui/app/components/clients/dashboard.js b/ui/app/components/clients/dashboard.js index 57e6154f22a..34d461a9ece 100644 --- a/ui/app/components/clients/dashboard.js +++ b/ui/app/components/clients/dashboard.js @@ -6,8 +6,8 @@ import { format } from 'date-fns'; export default class Dashboard extends Component { maxNamespaces = 10; chartLegend = [ - { key: 'distinct_entities', label: 'Direct entities' }, - { key: 'non_entity_tokens', label: 'Active direct tokens' }, + { key: 'distinct_entities', label: 'unique entities' }, + { key: 'non_entity_tokens', label: 'non-entity tokens' }, ]; @tracked selectedNamespace = null; diff --git a/ui/app/styles/core/charts.scss b/ui/app/styles/core/charts.scss index c1d17b47504..9a0a567f212 100644 --- a/ui/app/styles/core/charts.scss +++ b/ui/app/styles/core/charts.scss @@ -6,6 +6,13 @@ } // GRID LAYOUT // +.stacked-charts { + display: grid; + width: 100%; + // grid-template-columns: 1fr; + // grid-template-rows: 1fr; +} + .single-chart-grid { display: grid; grid-template-columns: 1fr 0.3fr 3.7fr; diff --git a/ui/app/templates/components/clients/client-counts-range.hbs b/ui/app/templates/components/clients/client-counts-range.hbs new file mode 100644 index 00000000000..20e4631d970 --- /dev/null +++ b/ui/app/templates/components/clients/client-counts-range.hbs @@ -0,0 +1,85 @@ +
+
+
+

{{@title}}

+

{{@description}}

+
+ +
+ +
+ +
+

Running client total

+

The number of clients which interacted with Vault during this date range.

+
+ +
+

{{capitalize @chartLegend.0.label}}

+

1,307

+
+ +
+

{{capitalize @chartLegend.1.label}}

+

8,005

+
+ +
+ {{capitalize @chartLegend.0.label}} + {{capitalize @chartLegend.1.label}} +
+
+ +
+ +
+ +
+ +
+

New monthly clients

+

Clients which interacted with Vault for the first time during this date range, displayed per month.

+
+ +
+

Average new {{@chartLegend.0.label}} per month

+

{{@dataOneData}}

+
+ +
+

Average new {{@chartLegend.1.label}} per month

+

{{@dataTwoData}}

+
+ +
+ Updated Nov 15 2021, 4:07:32 pm +
+ +
+ {{capitalize @chartLegend.0.label}} + {{capitalize @chartLegend.1.label}} +
+
+ + + {{!-- TOOLTIP --}} + + {{#if this.tooltipTarget}} + {{!-- Required to set tag name = div https://github.com/yapplabs/ember-modal-dialog/issues/290 --}} + {{!-- Component must be in curly bracket notation --}} + {{#modal-dialog + tagName='div' + tetherTarget=this.tooltipTarget + targetAttachment='bottom middle' + attachment='bottom middle' + offset='40px 0' + }} +

{{this.hoveredLabel}}

+
+ {{/modal-dialog}} + {{/if}} +
diff --git a/ui/app/templates/components/clients/dashboard.hbs b/ui/app/templates/components/clients/dashboard.hbs index 587c9c42c7e..54a1e97c8ba 100644 --- a/ui/app/templates/components/clients/dashboard.hbs +++ b/ui/app/templates/components/clients/dashboard.hbs @@ -136,6 +136,12 @@ {{!-- ARG TODO end of part that goes to Running Client --}} {{#if this.showGraphs}} {{!-- ARG TODO chart playground --}} + +
- {{@chartLegend.0.label}} - {{@chartLegend.1.label}} + {{capitalize @chartLegend.0.label}} + {{capitalize @chartLegend.1.label}}
diff --git a/ui/app/templates/components/clients/total-client-usage.hbs b/ui/app/templates/components/clients/total-client-usage.hbs index 4940d848a08..b88388f1fed 100644 --- a/ui/app/templates/components/clients/total-client-usage.hbs +++ b/ui/app/templates/components/clients/total-client-usage.hbs @@ -31,8 +31,8 @@
- {{@chartLegend.0.label}} - {{@chartLegend.1.label}} + {{capitalize @chartLegend.0.label}} + {{capitalize @chartLegend.1.label}}
{{!-- TOOLTIP --}} From 37c75daecd15cd646571d811360682f161024457 Mon Sep 17 00:00:00 2001 From: Claire Bontempo Date: Mon, 20 Dec 2021 11:01:52 -0800 Subject: [PATCH 02/26] pass in data as arg from parent --- ui/app/components/clients/dashboard.js | 23 +++++++++++++++++++ .../components/clients/total-client-usage.js | 21 ++--------------- ui/app/components/vertical-bar-chart.js | 16 +++++++++++++ .../components/clients/dashboard.hbs | 4 ++++ .../components/clients/total-client-usage.hbs | 2 +- .../components/vertical-bar-chart.hbs | 1 + 6 files changed, 47 insertions(+), 20 deletions(-) create mode 100644 ui/app/components/vertical-bar-chart.js create mode 100644 ui/app/templates/components/vertical-bar-chart.hbs diff --git a/ui/app/components/clients/dashboard.js b/ui/app/components/clients/dashboard.js index 34d461a9ece..b5bb9037da4 100644 --- a/ui/app/components/clients/dashboard.js +++ b/ui/app/components/clients/dashboard.js @@ -62,6 +62,29 @@ export default class Dashboard extends Component { }); } + // TODO: dataset for vertical bar chart (manage in serializer?) + get verticalBarChartData() { + return [ + { month: 'January', directEntities: 1000, nonEntityTokens: 322, total: 1322 }, + { month: 'February', directEntities: 1500, nonEntityTokens: 122, total: 1622 }, + { month: 'March', directEntities: 4300, nonEntityTokens: 700, total: 5000 }, + { month: 'April', directEntities: 1550, nonEntityTokens: 229, total: 1779 }, + { month: 'May', directEntities: 5560, nonEntityTokens: 124, total: 5684 }, + { month: 'June', directEntities: 1570, nonEntityTokens: 142, total: 1712 }, + { month: 'July', directEntities: 300, nonEntityTokens: 112, total: 412 }, + { month: 'August', directEntities: 1610, nonEntityTokens: 130, total: 1740 }, + { month: 'September', directEntities: 1900, nonEntityTokens: 222, total: 2122 }, + { month: 'October', directEntities: 500, nonEntityTokens: 166, total: 666 }, + { month: 'November', directEntities: 480, nonEntityTokens: 132, total: 612 }, + { month: 'December', directEntities: 980, nonEntityTokens: 202, total: 1182 }, + ]; + } + + // TODO: dataset for line chart + get lineChartData() { + return 'hi'; + } + // Create namespaces data for csv format get getCsvData() { if (!this.args.model.activity || !this.args.model.activity.byNamespace) { diff --git a/ui/app/components/clients/total-client-usage.js b/ui/app/components/clients/total-client-usage.js index e1c137cc1ef..38db2a17384 100644 --- a/ui/app/components/clients/total-client-usage.js +++ b/ui/app/components/clients/total-client-usage.js @@ -23,22 +23,6 @@ import { stack } from 'd3-shape'; * @param {string} [param1=defaultValue] - param1 is... */ -// ARG TODO pull in data -const DATA = [ - { month: 'January', directEntities: 1000, nonEntityTokens: 322, total: 1322 }, - { month: 'February', directEntities: 1500, nonEntityTokens: 122, total: 1622 }, - { month: 'March', directEntities: 4300, nonEntityTokens: 700, total: 5000 }, - { month: 'April', directEntities: 1550, nonEntityTokens: 229, total: 1779 }, - { month: 'May', directEntities: 5560, nonEntityTokens: 124, total: 5684 }, - { month: 'June', directEntities: 1570, nonEntityTokens: 142, total: 1712 }, - { month: 'July', directEntities: 300, nonEntityTokens: 112, total: 412 }, - { month: 'August', directEntities: 1610, nonEntityTokens: 130, total: 1740 }, - { month: 'September', directEntities: 1900, nonEntityTokens: 222, total: 2122 }, - { month: 'October', directEntities: 500, nonEntityTokens: 166, total: 666 }, - { month: 'November', directEntities: 480, nonEntityTokens: 132, total: 612 }, - { month: 'December', directEntities: 980, nonEntityTokens: 202, total: 1182 }, -]; - // COLOR THEME: const BAR_COLOR_DEFAULT = ['#8AB1FF', '#1563FF']; const BACKGROUND_BAR_COLOR = '#EBEEF2'; @@ -53,10 +37,9 @@ export default class TotalClientUsage extends Component { @tracked trackingTest = 0; @action - registerListener(element) { + registerListener(element, args) { // Define the chart - let dataset = DATA; // will be data passed in as argument - + let dataset = args[0]; let stackFunction = stack().keys(['directEntities', 'nonEntityTokens']); let stackedData = stackFunction(dataset); diff --git a/ui/app/components/vertical-bar-chart.js b/ui/app/components/vertical-bar-chart.js new file mode 100644 index 00000000000..739a6ce228b --- /dev/null +++ b/ui/app/components/vertical-bar-chart.js @@ -0,0 +1,16 @@ +import Component from '@glimmer/component'; + +/** + * @module VerticalBarChart + * VerticalBarChart components are used to... + * + * @example + * ```js + * + * ``` + * @param {object} requiredParam - requiredParam is... + * @param {string} [optionalParam] - optionalParam is... + * @param {string} [param1=defaultValue] - param1 is... + */ + +export default class VerticalBarChart extends Component {} diff --git a/ui/app/templates/components/clients/dashboard.hbs b/ui/app/templates/components/clients/dashboard.hbs index 54a1e97c8ba..e85ac06416d 100644 --- a/ui/app/templates/components/clients/dashboard.hbs +++ b/ui/app/templates/components/clients/dashboard.hbs @@ -140,6 +140,8 @@ @title="Vault client counts" @description="A unique active client is any user or service that interacts with Vault. They are made up of direct entities and non-entity tokens. As Vault’s primary billing metric, your total client count is the number for which you will be charged at the end of your billing period." @chartLegend={{this.chartLegend}} + @barChartData={{this.verticalBarChartData}} + @lineChartData={{this.lineChartData}} />
diff --git a/ui/app/templates/components/vertical-bar-chart.hbs b/ui/app/templates/components/vertical-bar-chart.hbs new file mode 100644 index 00000000000..fb5c4b157d1 --- /dev/null +++ b/ui/app/templates/components/vertical-bar-chart.hbs @@ -0,0 +1 @@ +{{yield}} \ No newline at end of file From 1f37434d2b080909df2801c8bd2b3b45844ec674 Mon Sep 17 00:00:00 2001 From: Claire Bontempo Date: Mon, 20 Dec 2021 11:34:09 -0800 Subject: [PATCH 03/26] pull out vertical bar chart component --- .../components/clients/total-client-usage.js | 127 +--------------- .../components/clients/vertical-bar-chart.js | 139 ++++++++++++++++++ ui/app/components/vertical-bar-chart.js | 16 -- .../components/clients/dashboard.hbs | 10 +- .../components/clients/total-client-usage.hbs | 23 +-- .../components/clients/vertical-bar-chart.hbs | 20 +++ .../components/vertical-bar-chart.hbs | 1 - 7 files changed, 169 insertions(+), 167 deletions(-) create mode 100644 ui/app/components/clients/vertical-bar-chart.js delete mode 100644 ui/app/components/vertical-bar-chart.js create mode 100644 ui/app/templates/components/clients/vertical-bar-chart.hbs delete mode 100644 ui/app/templates/components/vertical-bar-chart.hbs diff --git a/ui/app/components/clients/total-client-usage.js b/ui/app/components/clients/total-client-usage.js index 38db2a17384..75c5febc167 100644 --- a/ui/app/components/clients/total-client-usage.js +++ b/ui/app/components/clients/total-client-usage.js @@ -1,13 +1,4 @@ import Component from '@glimmer/component'; -import { action } from '@ember/object'; -import { tracked } from '@glimmer/tracking'; -import { max } from 'd3-array'; -// eslint-disable-next-line no-unused-vars -import { select, selectAll, node } from 'd3-selection'; -import { axisLeft, axisBottom } from 'd3-axis'; -import { scaleLinear, scaleBand } from 'd3-scale'; -import { format } from 'd3-format'; -import { stack } from 'd3-shape'; /** * ARG TODO fill out @@ -22,120 +13,4 @@ import { stack } from 'd3-shape'; * @param {string} [optionalParam] - optionalParam is... * @param {string} [param1=defaultValue] - param1 is... */ - -// COLOR THEME: -const BAR_COLOR_DEFAULT = ['#8AB1FF', '#1563FF']; -const BACKGROUND_BAR_COLOR = '#EBEEF2'; - -// TRANSLATIONS: -const TRANSLATE = { left: -11 }; -const SVG_DIMENSIONS = { height: 190, width: 500 }; - -export default class TotalClientUsage extends Component { - @tracked tooltipTarget = ''; - @tracked hoveredLabel = ''; - @tracked trackingTest = 0; - - @action - registerListener(element, args) { - // Define the chart - let dataset = args[0]; - let stackFunction = stack().keys(['directEntities', 'nonEntityTokens']); - let stackedData = stackFunction(dataset); - - let yScale = scaleLinear() - .domain([0, max(dataset.map(d => d.total))]) // TODO will need to recalculate when you get the data - .range([0, 100]); - - let xScale = scaleBand() - .domain(dataset.map(d => d.month)) - .range([0, SVG_DIMENSIONS.width]) // set width to fix number of pixels - .paddingInner(0.85); - - let chartSvg = select(element); - - chartSvg.attr('viewBox', `-50 20 600 ${SVG_DIMENSIONS.height}`); // set svg dimensions - - let groups = chartSvg - .selectAll('g') - .data(stackedData) - .enter() - .append('g') - .style('fill', (d, i) => BAR_COLOR_DEFAULT[i]); - - groups - .selectAll('rect') - .data(stackedData => stackedData) - .enter() - .append('rect') - .attr('width', '7px') - .attr('class', 'data-bar') - .attr('height', stackedData => `${yScale(stackedData[1] - stackedData[0])}%`) - .attr('x', ({ data }) => xScale(data.month)) // uses destructuring because was data.data.month - .attr('y', data => `${100 - yScale(data[1])}%`); // subtract higher than 100% to give space for x axis ticks - - // MAKE AXES // - let yAxisScale = scaleLinear() - .domain([0, max(dataset.map(d => d.total))]) // TODO will need to recalculate when you get the data - .range([`${SVG_DIMENSIONS.height}`, 0]); - - // Reference for tickFormat https://www.youtube.com/watch?v=c3MCROTNN8g - let formatNumbers = number => format('.2s')(number).replace('G', 'B'); // for billions to replace G with B. - - // customize y-axis - let yAxis = axisLeft(yAxisScale) - .ticks(7) - .tickPadding(10) - .tickSizeInner(-SVG_DIMENSIONS.width) // makes grid lines correct length - .tickFormat(formatNumbers); - - yAxis(chartSvg.append('g')); - - // customize x-axis - let xAxisGenerator = axisBottom(xScale).tickSize(0); - let xAxis = chartSvg.append('g').call(xAxisGenerator); - - xAxis.attr('transform', `translate(0, ${SVG_DIMENSIONS.height + 10})`); - - chartSvg.selectAll('.domain').remove(); // remove domain lines - - // creating wider area for tooltip hover - let greyBars = chartSvg - .append('g') - .attr('transform', `translate(${TRANSLATE.left})`) - .style('fill', `${BACKGROUND_BAR_COLOR}`) - .style('opacity', '0') - .style('mix-blend-mode', 'multiply'); - - let tooltipRect = greyBars - .selectAll('rect') - .data(dataset) - .enter() - .append('rect') - .style('cursor', 'pointer') - .attr('class', 'tooltip-rect') - .attr('height', '100%') - .attr('width', '30px') // three times width - .attr('y', '0') // start at bottom - .attr('x', data => xScale(data.month)); // not data.data because this is not stacked data - - // for tooltip - tooltipRect.on('mouseover', data => { - this.hoveredLabel = data.month; - // let node = chartSvg - // .selectAll('rect.tooltip-rect') - // .filter(data => data.month === this.hoveredLabel) - // .node(); - let node = chartSvg - .selectAll('rect.data-bar') - // filter for the top data bar (so y-coord !== 0) with matching month - .filter(data => data[0] !== 0 && data.data.month === this.hoveredLabel) - .node(); - this.tooltipTarget = node; // grab the node from the list of rects - }); - } - - @action removeTooltip() { - this.tooltipTarget = null; - } -} +export default class TotalClientUsage extends Component {} diff --git a/ui/app/components/clients/vertical-bar-chart.js b/ui/app/components/clients/vertical-bar-chart.js new file mode 100644 index 00000000000..39cb98d755d --- /dev/null +++ b/ui/app/components/clients/vertical-bar-chart.js @@ -0,0 +1,139 @@ +import Component from '@glimmer/component'; +import { action } from '@ember/object'; +import { tracked } from '@glimmer/tracking'; +import { max } from 'd3-array'; +// eslint-disable-next-line no-unused-vars +import { select, selectAll, node } from 'd3-selection'; +import { axisLeft, axisBottom } from 'd3-axis'; +import { scaleLinear, scaleBand } from 'd3-scale'; +import { format } from 'd3-format'; +import { stack } from 'd3-shape'; + +/** + * @module VerticalBarChart + * VerticalBarChart components are used to... + * + * @example + * ```js + * + * ``` + * @param {object} requiredParam - requiredParam is... + * @param {string} [optionalParam] - optionalParam is... + * @param {string} [param1=defaultValue] - param1 is... + */ + +// COLOR THEME: +const BAR_COLOR_DEFAULT = ['#8AB1FF', '#1563FF']; +const BACKGROUND_BAR_COLOR = '#EBEEF2'; + +// TRANSLATIONS: +const TRANSLATE = { left: -11 }; +const SVG_DIMENSIONS = { height: 190, width: 500 }; + +export default class VerticalBarChart extends Component { + @tracked tooltipTarget = ''; + @tracked hoveredLabel = ''; + + @action + registerListener(element, args) { + // Define the chart + let dataset = args[0]; + let stackFunction = stack().keys(['directEntities', 'nonEntityTokens']); + let stackedData = stackFunction(dataset); + + let yScale = scaleLinear() + .domain([0, max(dataset.map(d => d.total))]) // TODO will need to recalculate when you get the data + .range([0, 100]); + + let xScale = scaleBand() + .domain(dataset.map(d => d.month)) + .range([0, SVG_DIMENSIONS.width]) // set width to fix number of pixels + .paddingInner(0.85); + + let chartSvg = select(element); + + chartSvg.attr('viewBox', `-50 20 600 ${SVG_DIMENSIONS.height}`); // set svg dimensions + + let groups = chartSvg + .selectAll('g') + .data(stackedData) + .enter() + .append('g') + .style('fill', (d, i) => BAR_COLOR_DEFAULT[i]); + + groups + .selectAll('rect') + .data(stackedData => stackedData) + .enter() + .append('rect') + .attr('width', '7px') + .attr('class', 'data-bar') + .attr('height', stackedData => `${yScale(stackedData[1] - stackedData[0])}%`) + .attr('x', ({ data }) => xScale(data.month)) // uses destructuring because was data.data.month + .attr('y', data => `${100 - yScale(data[1])}%`); // subtract higher than 100% to give space for x axis ticks + + // MAKE AXES // + let yAxisScale = scaleLinear() + .domain([0, max(dataset.map(d => d.total))]) // TODO will need to recalculate when you get the data + .range([`${SVG_DIMENSIONS.height}`, 0]); + + // Reference for tickFormat https://www.youtube.com/watch?v=c3MCROTNN8g + let formatNumbers = number => format('.2s')(number).replace('G', 'B'); // for billions to replace G with B. + + // customize y-axis + let yAxis = axisLeft(yAxisScale) + .ticks(7) + .tickPadding(10) + .tickSizeInner(-SVG_DIMENSIONS.width) // makes grid lines correct length + .tickFormat(formatNumbers); + + yAxis(chartSvg.append('g')); + + // customize x-axis + let xAxisGenerator = axisBottom(xScale).tickSize(0); + let xAxis = chartSvg.append('g').call(xAxisGenerator); + + xAxis.attr('transform', `translate(0, ${SVG_DIMENSIONS.height + 10})`); + + chartSvg.selectAll('.domain').remove(); // remove domain lines + + // creating wider area for tooltip hover + let greyBars = chartSvg + .append('g') + .attr('transform', `translate(${TRANSLATE.left})`) + .style('fill', `${BACKGROUND_BAR_COLOR}`) + .style('opacity', '0') + .style('mix-blend-mode', 'multiply'); + + let tooltipRect = greyBars + .selectAll('rect') + .data(dataset) + .enter() + .append('rect') + .style('cursor', 'pointer') + .attr('class', 'tooltip-rect') + .attr('height', '100%') + .attr('width', '30px') // three times width + .attr('y', '0') // start at bottom + .attr('x', data => xScale(data.month)); // not data.data because this is not stacked data + + // for tooltip + tooltipRect.on('mouseover', data => { + this.hoveredLabel = data.month; + // let node = chartSvg + // .selectAll('rect.tooltip-rect') + // .filter(data => data.month === this.hoveredLabel) + // .node(); + let node = chartSvg + .selectAll('rect.data-bar') + // filter for the top data bar (so y-coord !== 0) with matching month + .filter(data => data[0] !== 0 && data.data.month === this.hoveredLabel) + .node(); + this.tooltipTarget = node; // grab the node from the list of rects + }); + } + + @action removeTooltip() { + this.tooltipTarget = null; + } +} diff --git a/ui/app/components/vertical-bar-chart.js b/ui/app/components/vertical-bar-chart.js deleted file mode 100644 index 739a6ce228b..00000000000 --- a/ui/app/components/vertical-bar-chart.js +++ /dev/null @@ -1,16 +0,0 @@ -import Component from '@glimmer/component'; - -/** - * @module VerticalBarChart - * VerticalBarChart components are used to... - * - * @example - * ```js - * - * ``` - * @param {object} requiredParam - requiredParam is... - * @param {string} [optionalParam] - optionalParam is... - * @param {string} [param1=defaultValue] - param1 is... - */ - -export default class VerticalBarChart extends Component {} diff --git a/ui/app/templates/components/clients/dashboard.hbs b/ui/app/templates/components/clients/dashboard.hbs index e85ac06416d..4306361b2ee 100644 --- a/ui/app/templates/components/clients/dashboard.hbs +++ b/ui/app/templates/components/clients/dashboard.hbs @@ -160,16 +160,18 @@ + > + + {{!-- ARG TODO this is the search select from the old graph that can be reused --}} {{!--
diff --git a/ui/app/templates/components/clients/total-client-usage.hbs b/ui/app/templates/components/clients/total-client-usage.hbs index 288a5768cec..c8b6af2805b 100644 --- a/ui/app/templates/components/clients/total-client-usage.hbs +++ b/ui/app/templates/components/clients/total-client-usage.hbs @@ -5,10 +5,9 @@

{{@description}}

{{/if}}
-
- + +
+ {{yield}}
@@ -35,20 +34,4 @@ {{capitalize @chartLegend.1.label}}
- {{!-- TOOLTIP --}} - - {{#if this.tooltipTarget}} - {{!-- Required to set tag name = div https://github.com/yapplabs/ember-modal-dialog/issues/290 --}} - {{!-- Component must be in curly bracket notation --}} - {{#modal-dialog - tagName='div' - tetherTarget=this.tooltipTarget - targetAttachment='bottom middle' - attachment='bottom middle' - offset='40px 0' - }} -

{{this.hoveredLabel}}

-
- {{/modal-dialog}} - {{/if}}
diff --git a/ui/app/templates/components/clients/vertical-bar-chart.hbs b/ui/app/templates/components/clients/vertical-bar-chart.hbs new file mode 100644 index 00000000000..7160f1f9bf0 --- /dev/null +++ b/ui/app/templates/components/clients/vertical-bar-chart.hbs @@ -0,0 +1,20 @@ + + + +{{!-- TOOLTIP --}} + +{{#if this.tooltipTarget}} +{{!-- Required to set tag name = div https://github.com/yapplabs/ember-modal-dialog/issues/290 --}} +{{!-- Component must be in curly bracket notation --}} + {{#modal-dialog + tagName='div' + tetherTarget=this.tooltipTarget + targetAttachment='bottom middle' + attachment='bottom middle' + offset='40px 0' + }} +

{{this.hoveredLabel}}

+
+ {{/modal-dialog}} +{{/if}} diff --git a/ui/app/templates/components/vertical-bar-chart.hbs b/ui/app/templates/components/vertical-bar-chart.hbs deleted file mode 100644 index fb5c4b157d1..00000000000 --- a/ui/app/templates/components/vertical-bar-chart.hbs +++ /dev/null @@ -1 +0,0 @@ -{{yield}} \ No newline at end of file From 0bbe0b24ea54ef8f30592b34560038dd5ab37986 Mon Sep 17 00:00:00 2001 From: Claire Bontempo Date: Mon, 20 Dec 2021 11:41:24 -0800 Subject: [PATCH 04/26] refactor to use vertical bar chart component --- .../clients/client-counts-range.hbs | 26 +++---------------- .../components/clients/dashboard.hbs | 7 ++--- .../components/clients/total-client-usage.hbs | 2 +- 3 files changed, 6 insertions(+), 29 deletions(-) diff --git a/ui/app/templates/components/clients/client-counts-range.hbs b/ui/app/templates/components/clients/client-counts-range.hbs index 20e4631d970..bb0f97e5fec 100644 --- a/ui/app/templates/components/clients/client-counts-range.hbs +++ b/ui/app/templates/components/clients/client-counts-range.hbs @@ -5,6 +5,7 @@

{{@description}}

+ {{!-- LINE CHART HERE --}}
- -
- +
+
@@ -64,22 +62,4 @@ {{capitalize @chartLegend.1.label}}
- - - {{!-- TOOLTIP --}} - - {{#if this.tooltipTarget}} - {{!-- Required to set tag name = div https://github.com/yapplabs/ember-modal-dialog/issues/290 --}} - {{!-- Component must be in curly bracket notation --}} - {{#modal-dialog - tagName='div' - tetherTarget=this.tooltipTarget - targetAttachment='bottom middle' - attachment='bottom middle' - offset='40px 0' - }} -

{{this.hoveredLabel}}

-
- {{/modal-dialog}} - {{/if}}
diff --git a/ui/app/templates/components/clients/dashboard.hbs b/ui/app/templates/components/clients/dashboard.hbs index 4306361b2ee..4ed175db58d 100644 --- a/ui/app/templates/components/clients/dashboard.hbs +++ b/ui/app/templates/components/clients/dashboard.hbs @@ -161,17 +161,14 @@ @title="Vault usage" @description="This data can be used to understand how many total clients are using Vault each month for the time period selected above." @chartLegend={{this.chartLegend}} + @verticalBarChartData={{this.verticalBarChartData}} @subTitle="Total monthly clients" @subText="Each unique client is counted once per month. This can help with capacity planning." @dataOne="Average total clients per month" @dataOneData="100" @dataTwo="Average new clients per month" @dataTwoData="4" - > - - + /> {{!-- ARG TODO this is the search select from the old graph that can be reused --}} {{!--
diff --git a/ui/app/templates/components/clients/total-client-usage.hbs b/ui/app/templates/components/clients/total-client-usage.hbs index c8b6af2805b..d1e968cb7c9 100644 --- a/ui/app/templates/components/clients/total-client-usage.hbs +++ b/ui/app/templates/components/clients/total-client-usage.hbs @@ -7,7 +7,7 @@
- {{yield}} +
From 07db9857e3731f38f1eb4032b04c6e21ac1351ea Mon Sep 17 00:00:00 2001 From: Claire Bontempo Date: Mon, 20 Dec 2021 11:46:54 -0800 Subject: [PATCH 05/26] remove any chart handling stuff from parent --- .../components/clients/client-counts-range.js | 142 +----------------- .../clients/client-counts-range.hbs | 8 +- 2 files changed, 4 insertions(+), 146 deletions(-) diff --git a/ui/app/components/clients/client-counts-range.js b/ui/app/components/clients/client-counts-range.js index 237905bf02c..9a8194b2f54 100644 --- a/ui/app/components/clients/client-counts-range.js +++ b/ui/app/components/clients/client-counts-range.js @@ -1,13 +1,4 @@ import Component from '@glimmer/component'; -import { action } from '@ember/object'; -import { tracked } from '@glimmer/tracking'; -import { max } from 'd3-array'; -// eslint-disable-next-line no-unused-vars -import { select, selectAll, node } from 'd3-selection'; -import { axisLeft, axisBottom } from 'd3-axis'; -import { scaleLinear, scaleBand } from 'd3-scale'; -import { format } from 'd3-format'; -import { stack } from 'd3-shape'; /** * @module ClientCountsRange @@ -21,135 +12,4 @@ import { stack } from 'd3-shape'; * @param {string} [optionalParam] - optionalParam is... * @param {string} [param1=defaultValue] - param1 is... */ - -const DATA = [ - { month: 'January', directEntities: 1000, nonEntityTokens: 322, total: 1322 }, - { month: 'February', directEntities: 1500, nonEntityTokens: 122, total: 1622 }, - { month: 'March', directEntities: 4300, nonEntityTokens: 700, total: 5000 }, - { month: 'April', directEntities: 1550, nonEntityTokens: 229, total: 1779 }, - { month: 'May', directEntities: 5560, nonEntityTokens: 124, total: 5684 }, - { month: 'June', directEntities: 1570, nonEntityTokens: 142, total: 1712 }, - { month: 'July', directEntities: 300, nonEntityTokens: 112, total: 412 }, - { month: 'August', directEntities: 1610, nonEntityTokens: 130, total: 1740 }, - { month: 'September', directEntities: 1900, nonEntityTokens: 222, total: 2122 }, - { month: 'October', directEntities: 500, nonEntityTokens: 166, total: 666 }, - { month: 'November', directEntities: 480, nonEntityTokens: 132, total: 612 }, - { month: 'December', directEntities: 980, nonEntityTokens: 202, total: 1182 }, -]; - -// COLOR THEME: -const BAR_COLOR_DEFAULT = ['#8AB1FF', '#1563FF']; -const BACKGROUND_BAR_COLOR = '#EBEEF2'; - -// TRANSLATIONS: -const TRANSLATE = { left: -11 }; -const SVG_DIMENSIONS = { height: 190, width: 500 }; - -export default class ClientCountsRange extends Component { - @tracked tooltipTarget = ''; - @tracked hoveredLabel = ''; - - @action - renderChart(element) { - // Define the chart - let dataset = DATA; // will be data passed in as argument - - let stackFunction = stack().keys(['directEntities', 'nonEntityTokens']); - let stackedData = stackFunction(dataset); - - let yScale = scaleLinear() - .domain([0, max(dataset.map(d => d.total))]) // TODO will need to recalculate when you get the data - .range([0, 100]); - - let xScale = scaleBand() - .domain(dataset.map(d => d.month)) - .range([0, SVG_DIMENSIONS.width]) // set width to fix number of pixels - .paddingInner(0.85); - - let chartSvg = select(element); - - chartSvg.attr('viewBox', `-50 20 600 ${SVG_DIMENSIONS.height}`); // set svg dimensions - - let groups = chartSvg - .selectAll('g') - .data(stackedData) - .enter() - .append('g') - .style('fill', (d, i) => BAR_COLOR_DEFAULT[i]); - - groups - .selectAll('rect') - .data(stackedData => stackedData) - .enter() - .append('rect') - .attr('width', '7px') - .attr('class', 'data-bar') - .attr('height', stackedData => `${yScale(stackedData[1] - stackedData[0])}%`) - .attr('x', ({ data }) => xScale(data.month)) // uses destructuring because was data.data.month - .attr('y', data => `${100 - yScale(data[1])}%`); // subtract higher than 100% to give space for x axis ticks - - // MAKE AXES // - let yAxisScale = scaleLinear() - .domain([0, max(dataset.map(d => d.total))]) // TODO will need to recalculate when you get the data - .range([`${SVG_DIMENSIONS.height}`, 0]); - - // Reference for tickFormat https://www.youtube.com/watch?v=c3MCROTNN8g - let formatNumbers = number => format('.2s')(number).replace('G', 'B'); // for billions to replace G with B. - - // customize y-axis - let yAxis = axisLeft(yAxisScale) - .ticks(7) - .tickPadding(10) - .tickSizeInner(-SVG_DIMENSIONS.width) // makes grid lines correct length - .tickFormat(formatNumbers); - - yAxis(chartSvg.append('g')); - - // customize x-axis - let xAxisGenerator = axisBottom(xScale).tickSize(0); - let xAxis = chartSvg.append('g').call(xAxisGenerator); - - xAxis.attr('transform', `translate(0, ${SVG_DIMENSIONS.height + 10})`); - - chartSvg.selectAll('.domain').remove(); // remove domain lines - - // creating wider area for tooltip hover - let greyBars = chartSvg - .append('g') - .attr('transform', `translate(${TRANSLATE.left})`) - .style('fill', `${BACKGROUND_BAR_COLOR}`) - .style('opacity', '0') - .style('mix-blend-mode', 'multiply'); - - let tooltipRect = greyBars - .selectAll('rect') - .data(dataset) - .enter() - .append('rect') - .style('cursor', 'pointer') - .attr('class', 'tooltip-rect') - .attr('height', '100%') - .attr('width', '30px') // three times width - .attr('y', '0') // start at bottom - .attr('x', data => xScale(data.month)); // not data.data because this is not stacked data - - // for tooltip - tooltipRect.on('mouseover', data => { - this.hoveredLabel = data.month; - // let node = chartSvg - // .selectAll('rect.tooltip-rect') - // .filter(data => data.month === this.hoveredLabel) - // .node(); - let node = chartSvg - .selectAll('rect.data-bar') - // filter for the top data bar (so y-coord !== 0) with matching month - .filter(data => data[0] !== 0 && data.data.month === this.hoveredLabel) - .node(); - this.tooltipTarget = node; // grab the node from the list of rects - }); - } - - @action removeTooltip() { - this.tooltipTarget = null; - } -} +export default class ClientCountsRange extends Component {} diff --git a/ui/app/templates/components/clients/client-counts-range.hbs b/ui/app/templates/components/clients/client-counts-range.hbs index bb0f97e5fec..0d85e418596 100644 --- a/ui/app/templates/components/clients/client-counts-range.hbs +++ b/ui/app/templates/components/clients/client-counts-range.hbs @@ -6,10 +6,8 @@
{{!-- LINE CHART HERE --}} -
- +
+
@@ -35,7 +33,7 @@
- +
From f2054201ae099c99e01ebfbf4c1582d285d7d85a Mon Sep 17 00:00:00 2001 From: Claire Bontempo Date: Mon, 20 Dec 2021 11:57:53 -0800 Subject: [PATCH 06/26] rename variables --- ui/app/components/clients/dashboard.js | 28 +++++++++++++++---- .../components/clients/dashboard.hbs | 4 +-- 2 files changed, 25 insertions(+), 7 deletions(-) diff --git a/ui/app/components/clients/dashboard.js b/ui/app/components/clients/dashboard.js index b5bb9037da4..4d4daf41b86 100644 --- a/ui/app/components/clients/dashboard.js +++ b/ui/app/components/clients/dashboard.js @@ -62,8 +62,13 @@ export default class Dashboard extends Component { }); } - // TODO: dataset for vertical bar chart (manage in serializer?) - get verticalBarChartData() { + // TODO: dataset for line chart + get lineChartData() { + return 'hi'; + } + + // TODO: dataset for new monthly clients vertical bar chart (manage in serializer?) + get newMonthlyClients() { return [ { month: 'January', directEntities: 1000, nonEntityTokens: 322, total: 1322 }, { month: 'February', directEntities: 1500, nonEntityTokens: 122, total: 1622 }, @@ -80,9 +85,22 @@ export default class Dashboard extends Component { ]; } - // TODO: dataset for line chart - get lineChartData() { - return 'hi'; + // TODO: dataset for vault usage vertical bar chart (manage in serializer?) + get totalClientUsage() { + return [ + { month: 'January', directEntities: 1000, nonEntityTokens: 322, total: 1322 }, + { month: 'February', directEntities: 1500, nonEntityTokens: 122, total: 1622 }, + { month: 'March', directEntities: 4300, nonEntityTokens: 700, total: 5000 }, + { month: 'April', directEntities: 1550, nonEntityTokens: 229, total: 1779 }, + { month: 'May', directEntities: 5560, nonEntityTokens: 124, total: 5684 }, + { month: 'June', directEntities: 1570, nonEntityTokens: 142, total: 1712 }, + { month: 'July', directEntities: 300, nonEntityTokens: 112, total: 412 }, + { month: 'August', directEntities: 1610, nonEntityTokens: 130, total: 1740 }, + { month: 'September', directEntities: 1900, nonEntityTokens: 222, total: 2122 }, + { month: 'October', directEntities: 500, nonEntityTokens: 166, total: 666 }, + { month: 'November', directEntities: 480, nonEntityTokens: 132, total: 612 }, + { month: 'December', directEntities: 980, nonEntityTokens: 202, total: 1182 }, + ]; } // Create namespaces data for csv format diff --git a/ui/app/templates/components/clients/dashboard.hbs b/ui/app/templates/components/clients/dashboard.hbs index 4ed175db58d..b43840b4d8a 100644 --- a/ui/app/templates/components/clients/dashboard.hbs +++ b/ui/app/templates/components/clients/dashboard.hbs @@ -140,8 +140,8 @@ @title="Vault client counts" @description="A unique active client is any user or service that interacts with Vault. They are made up of direct entities and non-entity tokens. As Vault’s primary billing metric, your total client count is the number for which you will be charged at the end of your billing period." @chartLegend={{this.chartLegend}} - @barChartData={{this.verticalBarChartData}} @lineChartData={{this.lineChartData}} + @barChartData={{this.newMonthlyClients}} /> Date: Mon, 20 Dec 2021 12:14:48 -0800 Subject: [PATCH 07/26] refactor horizontal bar chart into separate component --- ui/app/components/clients/attribution.js | 19 +++++++++++++++++++ ...-bar-charts.js => horizontal-bar-chart.js} | 0 ...izontal-bar-charts.hbs => attribution.hbs} | 16 ++++++++-------- .../components/clients/dashboard.hbs | 7 ++++--- .../clients/horizontal-bar-chart.hbs | 4 ++++ 5 files changed, 35 insertions(+), 11 deletions(-) create mode 100644 ui/app/components/clients/attribution.js rename ui/app/components/clients/{horizontal-bar-charts.js => horizontal-bar-chart.js} (100%) rename ui/app/templates/components/clients/{horizontal-bar-charts.hbs => attribution.hbs} (78%) create mode 100644 ui/app/templates/components/clients/horizontal-bar-chart.hbs diff --git a/ui/app/components/clients/attribution.js b/ui/app/components/clients/attribution.js new file mode 100644 index 00000000000..052954840f0 --- /dev/null +++ b/ui/app/components/clients/attribution.js @@ -0,0 +1,19 @@ +import Component from '@glimmer/component'; + +// TODO: fill out below!! +/** + * @module Attribution + * Attribution components are used to... + * + * @example + * ```js + * + * Pass in export button + * + * ``` + * @param {object} requiredParam - requiredParam is... + * @param {string} [optionalParam] - optionalParam is... + * @param {string} [param1=defaultValue] - param1 is... + */ + +export default class Attribution extends Component {} diff --git a/ui/app/components/clients/horizontal-bar-charts.js b/ui/app/components/clients/horizontal-bar-chart.js similarity index 100% rename from ui/app/components/clients/horizontal-bar-charts.js rename to ui/app/components/clients/horizontal-bar-chart.js diff --git a/ui/app/templates/components/clients/horizontal-bar-charts.hbs b/ui/app/templates/components/clients/attribution.hbs similarity index 78% rename from ui/app/templates/components/clients/horizontal-bar-charts.hbs rename to ui/app/templates/components/clients/attribution.hbs index d34ade37c06..e2bed0dd690 100644 --- a/ui/app/templates/components/clients/horizontal-bar-charts.hbs +++ b/ui/app/templates/components/clients/attribution.hbs @@ -16,19 +16,19 @@

New Clients

{{@newClientsDescription}}

- - +

Total monthly clients

{{@totalDescription}}

- - +
diff --git a/ui/app/templates/components/clients/dashboard.hbs b/ui/app/templates/components/clients/dashboard.hbs index b43840b4d8a..f6c3d032c18 100644 --- a/ui/app/templates/components/clients/dashboard.hbs +++ b/ui/app/templates/components/clients/dashboard.hbs @@ -144,18 +144,19 @@ @barChartData={{this.newMonthlyClients}} /> - Export attribution data - + + \ No newline at end of file From 933004ef55d8ac5f3007120263a57d045985deb7 Mon Sep 17 00:00:00 2001 From: Claire Bontempo Date: Mon, 20 Dec 2021 12:19:49 -0800 Subject: [PATCH 08/26] move descriptions to inside template (not passed in) --- .../components/clients/attribution.hbs | 24 +++++++++---------- .../components/clients/dashboard.hbs | 3 --- 2 files changed, 12 insertions(+), 15 deletions(-) diff --git a/ui/app/templates/components/clients/attribution.hbs b/ui/app/templates/components/clients/attribution.hbs index e2bed0dd690..695434203f1 100644 --- a/ui/app/templates/components/clients/attribution.hbs +++ b/ui/app/templates/components/clients/attribution.hbs @@ -14,21 +14,21 @@
-

New Clients

-

{{@newClientsDescription}}

- +

New Clients

+

New client count numbers description

+
-

Total monthly clients

-

{{@totalDescription}}

- +

Total monthly clients

+

Total client count numbers description

+
diff --git a/ui/app/templates/components/clients/dashboard.hbs b/ui/app/templates/components/clients/dashboard.hbs index f6c3d032c18..b236f4aa8d0 100644 --- a/ui/app/templates/components/clients/dashboard.hbs +++ b/ui/app/templates/components/clients/dashboard.hbs @@ -151,9 +151,6 @@ @newClientsData={{this.barChartDataset}} @totalClientsData={{this.barChartDataset}} @chartLegend={{this.chartLegend}} - {{!-- Make these variables getters in dashboard.js depending on whether client counts are namespace vs auth method? --}} - @newClientsDescription="New client count numbers description" - @totalDescription="Total client count numbers description" > Export attribution data From 8768f1fa3d700876d19821aa02559e7057c0086d Mon Sep 17 00:00:00 2001 From: Claire Bontempo Date: Mon, 20 Dec 2021 17:24:30 -0800 Subject: [PATCH 09/26] constructs attribution copy --- ui/app/components/clients/attribution.js | 30 ++++++++++++++++++- .../components/clients/attribution.hbs | 14 ++++----- .../components/clients/dashboard.hbs | 4 +-- 3 files changed, 36 insertions(+), 12 deletions(-) diff --git a/ui/app/components/clients/attribution.js b/ui/app/components/clients/attribution.js index 052954840f0..23ba3d91f10 100644 --- a/ui/app/components/clients/attribution.js +++ b/ui/app/components/clients/attribution.js @@ -16,4 +16,32 @@ import Component from '@glimmer/component'; * @param {string} [param1=defaultValue] - param1 is... */ -export default class Attribution extends Component {} +export default class Attribution extends Component { + get dateRange() { + // some conditional that returns "date range" or "month" depending on what the params are + return 'date range'; + } + + get chartText() { + // something that determines if data is by namespace or by auth method + // and returns text + // if byNamespace + return { + description: + 'This data shows the top ten namespaces by client count and can be used to understand where clients are originating. Namespaces are identified by path. To see all namespaces, export this data.', + newCopy: `The new clients in the namespace for this ${ + this.dateRange + }. This aids in understanding which namespaces create and use new clients ${ + this.dateRange === 'date range' ? ' over time.' : '.' + }`, + totalCopy: `The total clients in the namespace for this ${this.dateRange}. This number is useful for identifying overall usage volume.`, + }; + // else if byAuthMethod + // return + // byAuthMethod = { + // description: "This data shows the top ten authentication methods by client count within this namespace, and can be used to understand where new clients and total clients are originating. Authentication methods are organized by path.", + // newCopy: `The new clients used by the auth method for this {{@range}}. This aids in understanding which auth methods create and use new clients ${this.dateRange === "date range" ? " over time." : "."}`, + // totalCopy: `The total clients used by the auth method for this ${this.dateRange}. This number is useful for identifying overall usage volume. ` + // } + } +} diff --git a/ui/app/templates/components/clients/attribution.hbs b/ui/app/templates/components/clients/attribution.hbs index 695434203f1..8a7641639a8 100644 --- a/ui/app/templates/components/clients/attribution.hbs +++ b/ui/app/templates/components/clients/attribution.hbs @@ -2,20 +2,18 @@

{{@title}}

- {{#if @description}} -

{{@description}}

- {{/if}} +

{{this.chartText.description}}

- {{#if @dataset}} + {{#if @totalClientsData}} {{yield}} {{/if}}
-

New Clients

-

New client count numbers description

+

New clients

+

{{this.chartText.newCopy}}

-

Total monthly clients

-

Total client count numbers description

+

Total clients

+

{{this.chartText.totalCopy}}

Date: Tue, 21 Dec 2021 10:54:14 -0800 Subject: [PATCH 10/26] add sample response to mirage config --- .../clients/horizontal-bar-chart.js | 62 ---- ui/mirage/config.js | 278 ++++++++++++++++++ 2 files changed, 278 insertions(+), 62 deletions(-) diff --git a/ui/app/components/clients/horizontal-bar-chart.js b/ui/app/components/clients/horizontal-bar-chart.js index 88f331b45a6..f04a7fb0f4c 100644 --- a/ui/app/components/clients/horizontal-bar-chart.js +++ b/ui/app/components/clients/horizontal-bar-chart.js @@ -35,68 +35,6 @@ const BAR_COLOR_DEFAULT = ['#BFD4FF', '#1563FF']; const BAR_COLOR_HOVER = ['#1563FF', '#0F4FD1']; const BACKGROUND_BAR_COLOR = '#EBEEF2'; -const SAMPLE_DATA = [ - { - label: 'longlongsuperlongnamespace80/', - non_entity_tokens: 1696, - distinct_entities: 1652, - total: 3348, - }, - { - label: 'namespace12/', - non_entity_tokens: 1568, - distinct_entities: 1663, - total: 3231, - }, - { - label: 'namespace44/', - non_entity_tokens: 1511, - distinct_entities: 1708, - total: 3219, - }, - { - label: 'namespace36/', - non_entity_tokens: 1574, - distinct_entities: 1553, - total: 3127, - }, - { - label: 'namespace2/', - non_entity_tokens: 1784, - distinct_entities: 1333, - total: 3117, - }, - { - label: 'namespace82/', - non_entity_tokens: 1245, - distinct_entities: 1702, - total: 2947, - }, - { - label: 'namespace28/', - non_entity_tokens: 1579, - distinct_entities: 1364, - total: 2943, - }, - { - label: 'namespace60/', - non_entity_tokens: 1962, - distinct_entities: 929, - total: 2891, - }, - { - label: 'namespace5/', - non_entity_tokens: 1448, - distinct_entities: 1418, - total: 2866, - }, - { - label: 'namespace67/', - non_entity_tokens: 1758, - distinct_entities: 1065, - total: 2823, - }, -]; export default class HorizontalBarChart extends Component { get labelKey() { return this.args.labelKey || 'label'; diff --git a/ui/mirage/config.js b/ui/mirage/config.js index 2e4124ce422..f917f750dc3 100644 --- a/ui/mirage/config.js +++ b/ui/mirage/config.js @@ -31,6 +31,284 @@ export default function() { // }; // }); + this.get('/sys/internal/counters/activity', function() { + return { + data: { + start_time: '2019-11-01T00:00:00Z', + end_time: '2020-10-31T23:59:59Z', + total: { + distinct_entities: 200, + non_entity_tokens: 100, + clients: 300, + }, + by_namespace: [ + { + _comment: 'by_namespace will remain as it is', + }, + ], + months: [ + { + 'jan/2022': { + counts: { + distinct_entities: 100, + non_entity_tokens: 50, + clients: 150, + }, + namespaces: [ + { + id: 'root', + path: '', + counts: { + distinct_entities: 50, + non_entity_tokens: 25, + clients: 75, + }, + mounts: [ + { + path: 'auth/aws/login', + counts: { + distinct_entities: 25, + non_entity_tokens: 12, + clients: 37, + }, + }, + { + path: 'auth/approle/login', + counts: { + distinct_entities: 25, + non_entity_tokens: 13, + clients: 38, + }, + }, + ], + }, + { + namespace_id: 'ns1', + namespace_path: '', + counts: { + distinct_entities: 50, + non_entity_tokens: 25, + clients: 75, + }, + mounts: [ + { + mount_path: 'auth/aws/login', + counts: { + distinct_entities: 20, + non_entity_tokens: 10, + clients: 30, + }, + }, + { + mount_path: 'auth/approle/login', + counts: { + distinct_entities: 30, + non_entity_tokens: 15, + clients: 45, + }, + }, + ], + }, + ], + new: { + counts: { + distinct_entities: 30, + non_entity_tokens: 10, + clients: 40, + }, + namespaces: [ + { + namespace_id: 'root', + namespace_path: '', + counts: { + distinct_entities: 15, + non_entity_tokens: 5, + clients: 20, + }, + mounts: [ + { + mount_path: 'auth/aws/login', + counts: { + distinct_entities: 5, + non_entity_tokens: 2, + clients: 7, + }, + }, + { + mount_path: 'auth/aws/login', + counts: { + distinct_entities: 10, + non_entity_tokens: 3, + clients: 13, + }, + }, + ], + }, + { + namespace_id: 'ns1', + namespace_path: '', + counts: { + distinct_entities: 15, + non_entity_tokens: 5, + clients: 20, + }, + mounts: [ + { + mount_path: 'auth/aws/login', + counts: { + distinct_entities: 10, + non_entity_tokens: 1, + clients: 11, + }, + }, + { + mount_path: 'auth/aws/login', + counts: { + distinct_entities: 5, + non_entity_tokens: 4, + clients: 9, + }, + }, + ], + }, + ], + }, + }, + }, + { + 'feb/2022': { + counts: { + _comment: 'total monthly clients', + distinct_entities: 100, + non_entity_tokens: 50, + clients: 150, + }, + namespaces: [ + { + namespace_id: 'root', + namespace_path: '', + counts: { + distinct_entities: 60, + non_entity_tokens: 10, + clients: 70, + }, + mounts: [ + { + mount_path: 'auth/aws/login', + counts: { + distinct_entities: 30, + non_entity_tokens: 5, + clients: 35, + }, + }, + { + mount_path: 'auth/approle/login', + counts: { + distinct_entities: 30, + non_entity_tokens: 5, + clients: 35, + }, + }, + ], + }, + { + namespace_id: 'ns1', + namespace_path: '', + counts: { + distinct_entities: 40, + non_entity_tokens: 40, + clients: 80, + }, + mounts: [ + { + mount_path: 'auth/aws/login', + counts: { + distinct_entities: 20, + non_entity_tokens: 20, + clients: 40, + }, + }, + { + mount_path: 'auth/approle/login', + counts: { + distinct_entities: 20, + non_entity_tokens: 20, + clients: 40, + }, + }, + ], + }, + ], + new: { + counts: { + distinct_entities: 20, + non_entity_tokens: 5, + clients: 25, + }, + namespaces: [ + { + namespace_id: 'root', + namespace_path: '', + counts: { + distinct_entities: 10, + non_entity_tokens: 3, + clients: 13, + }, + mounts: [ + { + mount_path: 'auth/aws/login', + counts: { + distinct_entities: 5, + non_entity_tokens: 1, + clients: 6, + }, + }, + { + mount_path: 'auth/aws/login', + counts: { + distinct_entities: 5, + non_entity_tokens: 2, + clients: 7, + }, + }, + ], + }, + { + namespace_id: 'ns1', + namespace_path: '', + counts: { + distinct_entities: 10, + non_entity_tokens: 2, + clients: 12, + }, + mounts: [ + { + mount_path: 'auth/aws/login', + counts: { + distinct_entities: 5, + non_entity_tokens: 2, + clients: 7, + }, + }, + { + mount_path: 'auth/aws/login', + counts: { + distinct_entities: 5, + non_entity_tokens: 0, + clients: 5, + }, + }, + ], + }, + ], + }, + }, + }, + ], + }, + }; + }); + this.get('/sys/internal/counters/activity/monthly', function() { return { data: { From c934ed11ebd6e92e50c42732649fc7314e1a59e0 Mon Sep 17 00:00:00 2001 From: Claire Bontempo Date: Tue, 21 Dec 2021 11:00:45 -0800 Subject: [PATCH 11/26] change indenting --- ui/app/components/clients/attribution.js | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/ui/app/components/clients/attribution.js b/ui/app/components/clients/attribution.js index 23ba3d91f10..7df0575cadd 100644 --- a/ui/app/components/clients/attribution.js +++ b/ui/app/components/clients/attribution.js @@ -29,14 +29,12 @@ export default class Attribution extends Component { return { description: 'This data shows the top ten namespaces by client count and can be used to understand where clients are originating. Namespaces are identified by path. To see all namespaces, export this data.', - newCopy: `The new clients in the namespace for this ${ - this.dateRange - }. This aids in understanding which namespaces create and use new clients ${ - this.dateRange === 'date range' ? ' over time.' : '.' - }`, + newCopy: `The new clients in the namespace for this ${this.dateRange}. + This aids in understanding which namespaces create and use new clients + ${this.dateRange === 'date range' ? ' over time.' : '.'}`, totalCopy: `The total clients in the namespace for this ${this.dateRange}. This number is useful for identifying overall usage volume.`, }; - // else if byAuthMethod + // if byAuthMethod // return // byAuthMethod = { // description: "This data shows the top ten authentication methods by client count within this namespace, and can be used to understand where new clients and total clients are originating. Authentication methods are organized by path.", From 608bfdd3b7c1c195d4ab51ab4f7db9590b6ba29e Mon Sep 17 00:00:00 2001 From: Claire Bontempo Date: Tue, 21 Dec 2021 11:07:49 -0800 Subject: [PATCH 12/26] rename to MonthlyUsage --- ui/app/components/clients/monthly-usage.js | 16 ++++++++++++++++ ui/app/components/clients/total-client-usage.js | 16 ---------------- .../templates/components/clients/dashboard.hbs | 4 ++-- ...{total-client-usage.hbs => monthly-usage.hbs} | 0 4 files changed, 18 insertions(+), 18 deletions(-) create mode 100644 ui/app/components/clients/monthly-usage.js delete mode 100644 ui/app/components/clients/total-client-usage.js rename ui/app/templates/components/clients/{total-client-usage.hbs => monthly-usage.hbs} (100%) diff --git a/ui/app/components/clients/monthly-usage.js b/ui/app/components/clients/monthly-usage.js new file mode 100644 index 00000000000..350d1ff2a3b --- /dev/null +++ b/ui/app/components/clients/monthly-usage.js @@ -0,0 +1,16 @@ +import Component from '@glimmer/component'; + +/** + * TODO fill out + * @module MonthlyUsage + * MonthlyUsage components are used to... + * + * @example + * ```js + * + * ``` + * @param {object} requiredParam - requiredParam is... + * @param {string} [optionalParam] - optionalParam is... + * @param {string} [param1=defaultValue] - param1 is... + */ +export default class MonthlyUsage extends Component {} diff --git a/ui/app/components/clients/total-client-usage.js b/ui/app/components/clients/total-client-usage.js deleted file mode 100644 index 75c5febc167..00000000000 --- a/ui/app/components/clients/total-client-usage.js +++ /dev/null @@ -1,16 +0,0 @@ -import Component from '@glimmer/component'; - -/** - * ARG TODO fill out - * @module TotalClientUsage - * TotalClientUsage components are used to... - * - * @example - * ```js - * - * ``` - * @param {object} requiredParam - requiredParam is... - * @param {string} [optionalParam] - optionalParam is... - * @param {string} [param1=defaultValue] - param1 is... - */ -export default class TotalClientUsage extends Component {} diff --git a/ui/app/templates/components/clients/dashboard.hbs b/ui/app/templates/components/clients/dashboard.hbs index e73044ff05b..b6b1fd127fc 100644 --- a/ui/app/templates/components/clients/dashboard.hbs +++ b/ui/app/templates/components/clients/dashboard.hbs @@ -150,10 +150,10 @@ @totalClientsData={{this.barChartDataset}} @chartLegend={{this.chartLegend}} > - Export attribution data + - Date: Tue, 21 Dec 2021 11:52:02 -0800 Subject: [PATCH 13/26] change name to running totals --- .../clients/{client-counts-range.js => running-totals.js} | 8 ++++---- ui/app/templates/components/clients/dashboard.hbs | 2 +- .../{client-counts-range.hbs => running-totals.hbs} | 0 3 files changed, 5 insertions(+), 5 deletions(-) rename ui/app/components/clients/{client-counts-range.js => running-totals.js} (51%) rename ui/app/templates/components/clients/{client-counts-range.hbs => running-totals.hbs} (100%) diff --git a/ui/app/components/clients/client-counts-range.js b/ui/app/components/clients/running-totals.js similarity index 51% rename from ui/app/components/clients/client-counts-range.js rename to ui/app/components/clients/running-totals.js index 9a8194b2f54..191211e4572 100644 --- a/ui/app/components/clients/client-counts-range.js +++ b/ui/app/components/clients/running-totals.js @@ -1,15 +1,15 @@ import Component from '@glimmer/component'; /** - * @module ClientCountsRange - * ClientCountsRange components are used to... + * @module RunningTotals + * RunningTotals components are used to... * * @example * ```js - * + * * ``` * @param {object} requiredParam - requiredParam is... * @param {string} [optionalParam] - optionalParam is... * @param {string} [param1=defaultValue] - param1 is... */ -export default class ClientCountsRange extends Component {} +export default class RunningTotals extends Component {} diff --git a/ui/app/templates/components/clients/dashboard.hbs b/ui/app/templates/components/clients/dashboard.hbs index b6b1fd127fc..72683af24fa 100644 --- a/ui/app/templates/components/clients/dashboard.hbs +++ b/ui/app/templates/components/clients/dashboard.hbs @@ -136,7 +136,7 @@ {{!-- ARG TODO end of part that goes to Running Client --}} {{#if this.showGraphs}} {{!-- ARG TODO chart playground --}} - Date: Tue, 21 Dec 2021 11:54:59 -0800 Subject: [PATCH 14/26] rename variable --- ui/app/components/clients/dashboard.js | 2 +- ui/app/templates/components/clients/dashboard.hbs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/ui/app/components/clients/dashboard.js b/ui/app/components/clients/dashboard.js index 4d4daf41b86..c80aa453352 100644 --- a/ui/app/components/clients/dashboard.js +++ b/ui/app/components/clients/dashboard.js @@ -86,7 +86,7 @@ export default class Dashboard extends Component { } // TODO: dataset for vault usage vertical bar chart (manage in serializer?) - get totalClientUsage() { + get monthlyUsage() { return [ { month: 'January', directEntities: 1000, nonEntityTokens: 322, total: 1322 }, { month: 'February', directEntities: 1500, nonEntityTokens: 122, total: 1622 }, diff --git a/ui/app/templates/components/clients/dashboard.hbs b/ui/app/templates/components/clients/dashboard.hbs index 72683af24fa..383c53cb278 100644 --- a/ui/app/templates/components/clients/dashboard.hbs +++ b/ui/app/templates/components/clients/dashboard.hbs @@ -157,7 +157,7 @@ @title="Vault usage" @description="This data can be used to understand how many total clients are using Vault each month for the time period selected above." @chartLegend={{this.chartLegend}} - @verticalBarChartData={{this.totalClientUsage}} + @verticalBarChartData={{this.monthlyUsage}} @subTitle="Total monthly clients" @subText="Each unique client is counted once per month. This can help with capacity planning." @dataOne="Average total clients per month" From 7f2a109d760ee59fa14acf3b5f83e0b4707fb50c Mon Sep 17 00:00:00 2001 From: Claire Bontempo Date: Tue, 21 Dec 2021 18:23:42 -0800 Subject: [PATCH 15/26] finishes line chart --- ui/app/components/clients/dashboard.js | 15 ++- ui/app/components/clients/line-chart.js | 103 ++++++++++++++++++ .../{running-totals.js => running-total.js} | 8 +- .../components/clients/vertical-bar-chart.js | 6 +- .../components/clients/dashboard.hbs | 2 +- .../components/clients/line-chart.hbs | 20 ++++ .../{running-totals.hbs => running-total.hbs} | 2 +- 7 files changed, 147 insertions(+), 9 deletions(-) create mode 100644 ui/app/components/clients/line-chart.js rename ui/app/components/clients/{running-totals.js => running-total.js} (52%) create mode 100644 ui/app/templates/components/clients/line-chart.hbs rename ui/app/templates/components/clients/{running-totals.hbs => running-total.hbs} (97%) diff --git a/ui/app/components/clients/dashboard.js b/ui/app/components/clients/dashboard.js index c80aa453352..ddaa68ae2aa 100644 --- a/ui/app/components/clients/dashboard.js +++ b/ui/app/components/clients/dashboard.js @@ -64,7 +64,20 @@ export default class Dashboard extends Component { // TODO: dataset for line chart get lineChartData() { - return 'hi'; + return [ + { month: '1/21', clients: 100 }, + { month: '2/21', clients: 300 }, + { month: '3/21', clients: 300 }, + { month: '4/21', clients: 300 }, + { month: '5/21', clients: 300 }, + { month: '6/21', clients: 300 }, + { month: '7/21', clients: 300 }, + { month: '8/21', clients: 350 }, + { month: '9/21', clients: 400 }, + { month: '10/21', clients: 450 }, + { month: '11/21', clients: 500 }, + { month: '12/21', clients: 1000 }, + ]; } // TODO: dataset for new monthly clients vertical bar chart (manage in serializer?) diff --git a/ui/app/components/clients/line-chart.js b/ui/app/components/clients/line-chart.js new file mode 100644 index 00000000000..14a5587e101 --- /dev/null +++ b/ui/app/components/clients/line-chart.js @@ -0,0 +1,103 @@ +import Component from '@glimmer/component'; +import { action } from '@ember/object'; +import { tracked } from '@glimmer/tracking'; +import { max } from 'd3-array'; +// eslint-disable-next-line no-unused-vars +import { select, selectAll, node } from 'd3-selection'; +import { axisLeft, axisBottom } from 'd3-axis'; +import { scaleLinear, scaleBand, scalePoint } from 'd3-scale'; +import { format } from 'd3-format'; +import { line } from 'd3-shape'; + +/** + * @module LineChart + * LineChart components are used to... + * + * @example + * ```js + * + * ``` + * @param {object} requiredParam - requiredParam is... + * @param {string} [optionalParam] - optionalParam is... + * @param {string} [param1=defaultValue] - param1 is... + */ + +// COLOR THEME: +const LINE_COLOR = '#1563FF'; +const DOT_COLOR = '#BFD4FF'; +const BACKGROUND_BAR_COLOR = '#EBEEF2'; + +// TRANSLATIONS: +const TRANSLATE = { left: -11 }; +const SVG_DIMENSIONS = { height: 190, width: 500 }; + +export default class LineChart extends Component { + @tracked tooltipTarget = ''; + @tracked hoveredLabel = ''; + + @action + renderChart(element, args) { + let dataset = args[0]; + let chartSvg = select(element); + chartSvg.attr('viewBox', `-50 20 600 ${SVG_DIMENSIONS.height}`); // set svg dimensions + + let yScale = scaleLinear() + .domain([0, max(dataset.map(d => d.clients))]) // TODO will need to recalculate when you get the data + .range([0, 100]); + + let yAxisScale = scaleLinear() + .domain([0, max(dataset.map(d => d.clients))]) // TODO will need to recalculate when you get the data + .range([SVG_DIMENSIONS.height, 0]); + + let xScale = scalePoint() //use scaleTime()? + .domain(dataset.map(d => d.month)) + .range([0, SVG_DIMENSIONS.width]) + .padding(0.2); + + let formatNumbers = number => format('.1s')(number).replace('G', 'B'); // replace SI sign of 'G' for billions to 'B' + + let yAxis = axisLeft(yAxisScale) + .ticks(7) + .tickPadding(10) + .tickSizeInner(-SVG_DIMENSIONS.width) // makes grid lines length of svg + .tickFormat(formatNumbers); + + let xAxis = axisBottom(xScale).tickSize(0); + + yAxis(chartSvg.append('g')); + xAxis(chartSvg.append('g').attr('transform', `translate(0, ${SVG_DIMENSIONS.height + 10})`)); + chartSvg.selectAll('.domain').remove(); // remove domain lines + + let lineGenerator = line() + .x(d => xScale(d.month)) + .y(d => yAxisScale(d.clients)); + + // PATH + chartSvg + .append('g') + .append('path') + .attr('fill', 'none') + .attr('stroke', LINE_COLOR) + .attr('stroke-width', 0.5) + .attr('d', lineGenerator(dataset)); + + // PLOT POINTS + chartSvg + .append('g') + .selectAll('circle') + .data(dataset) + .enter() + .append('circle') + .attr('class', 'data-plot') + .attr('cy', d => `${100 - yScale(d.clients)}%`) + .attr('cx', d => xScale(d.month)) + .attr('r', 3.5) + .attr('fill', DOT_COLOR) + .attr('stroke', LINE_COLOR) + .attr('stroke-width', 1.5); + } + + @action removeTooltip() { + this.tooltipTarget = null; + } +} diff --git a/ui/app/components/clients/running-totals.js b/ui/app/components/clients/running-total.js similarity index 52% rename from ui/app/components/clients/running-totals.js rename to ui/app/components/clients/running-total.js index 191211e4572..1828efb343a 100644 --- a/ui/app/components/clients/running-totals.js +++ b/ui/app/components/clients/running-total.js @@ -1,15 +1,15 @@ import Component from '@glimmer/component'; /** - * @module RunningTotals - * RunningTotals components are used to... + * @module RunningTotal + * RunningTotal components are used to... * * @example * ```js - * + * * ``` * @param {object} requiredParam - requiredParam is... * @param {string} [optionalParam] - optionalParam is... * @param {string} [param1=defaultValue] - param1 is... */ -export default class RunningTotals extends Component {} +export default class RunningTotal extends Component {} diff --git a/ui/app/components/clients/vertical-bar-chart.js b/ui/app/components/clients/vertical-bar-chart.js index 39cb98d755d..202f7438e26 100644 --- a/ui/app/components/clients/vertical-bar-chart.js +++ b/ui/app/components/clients/vertical-bar-chart.js @@ -43,7 +43,8 @@ export default class VerticalBarChart extends Component { let yScale = scaleLinear() .domain([0, max(dataset.map(d => d.total))]) // TODO will need to recalculate when you get the data - .range([0, 100]); + .range([0, 100]) + .nice(); let xScale = scaleBand() .domain(dataset.map(d => d.month)) @@ -75,7 +76,8 @@ export default class VerticalBarChart extends Component { // MAKE AXES // let yAxisScale = scaleLinear() .domain([0, max(dataset.map(d => d.total))]) // TODO will need to recalculate when you get the data - .range([`${SVG_DIMENSIONS.height}`, 0]); + .range([`${SVG_DIMENSIONS.height}`, 0]) + .nice(); // Reference for tickFormat https://www.youtube.com/watch?v=c3MCROTNN8g let formatNumbers = number => format('.2s')(number).replace('G', 'B'); // for billions to replace G with B. diff --git a/ui/app/templates/components/clients/dashboard.hbs b/ui/app/templates/components/clients/dashboard.hbs index 383c53cb278..40d8090a24e 100644 --- a/ui/app/templates/components/clients/dashboard.hbs +++ b/ui/app/templates/components/clients/dashboard.hbs @@ -136,7 +136,7 @@ {{!-- ARG TODO end of part that goes to Running Client --}} {{#if this.showGraphs}} {{!-- ARG TODO chart playground --}} - + + +{{!-- TOOLTIP --}} + +{{#if this.tooltipTarget}} +{{!-- Required to set tag name = div https://github.com/yapplabs/ember-modal-dialog/issues/290 --}} +{{!-- Component must be in curly bracket notation --}} + {{#modal-dialog + tagName='div' + tetherTarget=this.tooltipTarget + targetAttachment='bottom middle' + attachment='bottom middle' + offset='40px 0' + }} +

{{this.hoveredLabel}}

+
+ {{/modal-dialog}} +{{/if}} diff --git a/ui/app/templates/components/clients/running-totals.hbs b/ui/app/templates/components/clients/running-total.hbs similarity index 97% rename from ui/app/templates/components/clients/running-totals.hbs rename to ui/app/templates/components/clients/running-total.hbs index 0d85e418596..0b18c5906c6 100644 --- a/ui/app/templates/components/clients/running-totals.hbs +++ b/ui/app/templates/components/clients/running-total.hbs @@ -7,7 +7,7 @@ {{!-- LINE CHART HERE --}}
- +
From 49fc0e2344ccd36db6ac9cf09aec79429a85eb58 Mon Sep 17 00:00:00 2001 From: Claire Bontempo Date: Tue, 21 Dec 2021 18:57:57 -0800 Subject: [PATCH 16/26] pull constants to util --- .../clients/horizontal-bar-chart.js | 14 ++++----- ui/app/components/clients/line-chart.js | 30 ++++++++----------- .../components/clients/vertical-bar-chart.js | 25 +++++----------- .../components/clients/running-total.hbs | 1 - ui/app/utils/chart-helpers.js | 8 +++++ ui/lib/core/addon/components/bar-chart.js | 14 ++++----- 6 files changed, 39 insertions(+), 53 deletions(-) create mode 100644 ui/app/utils/chart-helpers.js diff --git a/ui/app/components/clients/horizontal-bar-chart.js b/ui/app/components/clients/horizontal-bar-chart.js index f04a7fb0f4c..bce0e55c3e9 100644 --- a/ui/app/components/clients/horizontal-bar-chart.js +++ b/ui/app/components/clients/horizontal-bar-chart.js @@ -6,6 +6,7 @@ import { select, event, selectAll } from 'd3-selection'; import { scaleLinear, scaleBand } from 'd3-scale'; import { axisLeft } from 'd3-axis'; import { max, maxIndex } from 'd3-array'; +import { GREY, LIGHT_AND_DARK_BLUE } from '../../utils/chart-helpers'; /** * @module HorizontalBarChart @@ -30,11 +31,6 @@ const TRANSLATE = { down: 13 }; const CHAR_LIMIT = 15; // character count limit for y-axis labels to trigger truncating const LINE_HEIGHT = 24; // each bar w/ padding is 24 pixels thick -// COLOR THEME: -const BAR_COLOR_DEFAULT = ['#BFD4FF', '#1563FF']; -const BAR_COLOR_HOVER = ['#1563FF', '#0F4FD1']; -const BACKGROUND_BAR_COLOR = '#EBEEF2'; - export default class HorizontalBarChart extends Component { get labelKey() { return this.args.labelKey || 'label'; @@ -82,7 +78,7 @@ export default class HorizontalBarChart extends Component { .append('g') // shifts chart to accommodate y-axis legend .attr('transform', `translate(${CHART_MARGIN.left}, ${CHART_MARGIN.top})`) - .style('fill', (d, i) => BAR_COLOR_DEFAULT[i]); + .style('fill', (d, i) => LIGHT_AND_DARK_BLUE[i]); let yAxis = axisLeft(yScale).tickSize(0); yAxis(chartSvg.append('g').attr('transform', `translate(${CHART_MARGIN.left}, ${CHART_MARGIN.top})`)); @@ -122,7 +118,7 @@ export default class HorizontalBarChart extends Component { .attr('height', `${LINE_HEIGHT}px`) .attr('x', '0') .attr('y', chartData => yScale(chartData[labelKey])) - .style('fill', `${BACKGROUND_BAR_COLOR}`) + .style('fill', `${GREY}`) .style('opacity', '0') .style('mix-blend-mode', 'multiply'); @@ -172,7 +168,7 @@ export default class HorizontalBarChart extends Component { .filter(function() { return compareAttributes(this, event.target, 'y'); }) - .style('fill', (b, i) => `${BAR_COLOR_DEFAULT[i]}`); + .style('fill', (b, i) => `${LIGHT_AND_DARK_BLUE[i]}`); }) .on('mousemove', function(chartData) { select('.chart-tooltip') @@ -218,7 +214,7 @@ export default class HorizontalBarChart extends Component { .filter(function() { return compareAttributes(this, event.target, 'y'); }) - .style('fill', (b, i) => `${BAR_COLOR_DEFAULT[i]}`); + .style('fill', (b, i) => `${LIGHT_AND_DARK_BLUE[i]}`); actionBarSelection .filter(function() { return compareAttributes(this, event.target, 'y'); diff --git a/ui/app/components/clients/line-chart.js b/ui/app/components/clients/line-chart.js index 14a5587e101..4a6f98892b9 100644 --- a/ui/app/components/clients/line-chart.js +++ b/ui/app/components/clients/line-chart.js @@ -5,9 +5,10 @@ import { max } from 'd3-array'; // eslint-disable-next-line no-unused-vars import { select, selectAll, node } from 'd3-selection'; import { axisLeft, axisBottom } from 'd3-axis'; -import { scaleLinear, scaleBand, scalePoint } from 'd3-scale'; +import { scaleLinear, scalePoint } from 'd3-scale'; import { format } from 'd3-format'; import { line } from 'd3-shape'; +import { LIGHT_AND_DARK_BLUE, SVG_DIMENSIONS } from '../../utils/chart-helpers'; /** * @module LineChart @@ -22,15 +23,6 @@ import { line } from 'd3-shape'; * @param {string} [param1=defaultValue] - param1 is... */ -// COLOR THEME: -const LINE_COLOR = '#1563FF'; -const DOT_COLOR = '#BFD4FF'; -const BACKGROUND_BAR_COLOR = '#EBEEF2'; - -// TRANSLATIONS: -const TRANSLATE = { left: -11 }; -const SVG_DIMENSIONS = { height: 190, width: 500 }; - export default class LineChart extends Component { @tracked tooltipTarget = ''; @tracked hoveredLabel = ''; @@ -39,18 +31,20 @@ export default class LineChart extends Component { renderChart(element, args) { let dataset = args[0]; let chartSvg = select(element); + let yMaxValue = max(dataset.map(d => d.clients)); // TODO will need to recalculate when we get the data + let xMaxValue = dataset.map(d => d.month); chartSvg.attr('viewBox', `-50 20 600 ${SVG_DIMENSIONS.height}`); // set svg dimensions let yScale = scaleLinear() - .domain([0, max(dataset.map(d => d.clients))]) // TODO will need to recalculate when you get the data + .domain([0, yMaxValue]) .range([0, 100]); let yAxisScale = scaleLinear() - .domain([0, max(dataset.map(d => d.clients))]) // TODO will need to recalculate when you get the data + .domain([0, yMaxValue]) // TODO will need to recalculate when you get the data .range([SVG_DIMENSIONS.height, 0]); let xScale = scalePoint() //use scaleTime()? - .domain(dataset.map(d => d.month)) + .domain(xMaxValue) .range([0, SVG_DIMENSIONS.width]) .padding(0.2); @@ -72,16 +66,16 @@ export default class LineChart extends Component { .x(d => xScale(d.month)) .y(d => yAxisScale(d.clients)); - // PATH + // LINE (PATH) BETWEEN DOTS chartSvg .append('g') .append('path') .attr('fill', 'none') - .attr('stroke', LINE_COLOR) + .attr('stroke', LIGHT_AND_DARK_BLUE[1]) .attr('stroke-width', 0.5) .attr('d', lineGenerator(dataset)); - // PLOT POINTS + // CIRCLES chartSvg .append('g') .selectAll('circle') @@ -92,8 +86,8 @@ export default class LineChart extends Component { .attr('cy', d => `${100 - yScale(d.clients)}%`) .attr('cx', d => xScale(d.month)) .attr('r', 3.5) - .attr('fill', DOT_COLOR) - .attr('stroke', LINE_COLOR) + .attr('fill', LIGHT_AND_DARK_BLUE[0]) + .attr('stroke', LIGHT_AND_DARK_BLUE[1]) .attr('stroke-width', 1.5); } diff --git a/ui/app/components/clients/vertical-bar-chart.js b/ui/app/components/clients/vertical-bar-chart.js index 202f7438e26..1a3a4d1829c 100644 --- a/ui/app/components/clients/vertical-bar-chart.js +++ b/ui/app/components/clients/vertical-bar-chart.js @@ -8,6 +8,7 @@ import { axisLeft, axisBottom } from 'd3-axis'; import { scaleLinear, scaleBand } from 'd3-scale'; import { format } from 'd3-format'; import { stack } from 'd3-shape'; +import { GREY, LIGHT_AND_DARK_BLUE, SVG_DIMENSIONS, TRANSLATE } from '../../utils/chart-helpers'; /** * @module VerticalBarChart @@ -22,14 +23,6 @@ import { stack } from 'd3-shape'; * @param {string} [param1=defaultValue] - param1 is... */ -// COLOR THEME: -const BAR_COLOR_DEFAULT = ['#8AB1FF', '#1563FF']; -const BACKGROUND_BAR_COLOR = '#EBEEF2'; - -// TRANSLATIONS: -const TRANSLATE = { left: -11 }; -const SVG_DIMENSIONS = { height: 190, width: 500 }; - export default class VerticalBarChart extends Component { @tracked tooltipTarget = ''; @tracked hoveredLabel = ''; @@ -60,7 +53,7 @@ export default class VerticalBarChart extends Component { .data(stackedData) .enter() .append('g') - .style('fill', (d, i) => BAR_COLOR_DEFAULT[i]); + .style('fill', (d, i) => LIGHT_AND_DARK_BLUE[i]); groups .selectAll('rect') @@ -82,20 +75,16 @@ export default class VerticalBarChart extends Component { // Reference for tickFormat https://www.youtube.com/watch?v=c3MCROTNN8g let formatNumbers = number => format('.2s')(number).replace('G', 'B'); // for billions to replace G with B. - // customize y-axis let yAxis = axisLeft(yAxisScale) .ticks(7) .tickPadding(10) - .tickSizeInner(-SVG_DIMENSIONS.width) // makes grid lines correct length + .tickSizeInner(-SVG_DIMENSIONS.width) .tickFormat(formatNumbers); - yAxis(chartSvg.append('g')); + let xAxis = axisBottom(xScale).tickSize(0); - // customize x-axis - let xAxisGenerator = axisBottom(xScale).tickSize(0); - let xAxis = chartSvg.append('g').call(xAxisGenerator); - - xAxis.attr('transform', `translate(0, ${SVG_DIMENSIONS.height + 10})`); + yAxis(chartSvg.append('g')); + xAxis(chartSvg.append('g').attr('transform', `translate(0, ${SVG_DIMENSIONS.height + 10})`)); chartSvg.selectAll('.domain').remove(); // remove domain lines @@ -103,7 +92,7 @@ export default class VerticalBarChart extends Component { let greyBars = chartSvg .append('g') .attr('transform', `translate(${TRANSLATE.left})`) - .style('fill', `${BACKGROUND_BAR_COLOR}`) + .style('fill', `${GREY}`) .style('opacity', '0') .style('mix-blend-mode', 'multiply'); diff --git a/ui/app/templates/components/clients/running-total.hbs b/ui/app/templates/components/clients/running-total.hbs index 0b18c5906c6..afda14ca9f3 100644 --- a/ui/app/templates/components/clients/running-total.hbs +++ b/ui/app/templates/components/clients/running-total.hbs @@ -5,7 +5,6 @@

{{@description}}

- {{!-- LINE CHART HERE --}}
diff --git a/ui/app/utils/chart-helpers.js b/ui/app/utils/chart-helpers.js new file mode 100644 index 00000000000..98129f3d986 --- /dev/null +++ b/ui/app/utils/chart-helpers.js @@ -0,0 +1,8 @@ +// COLOR THEME: +export const LIGHT_AND_DARK_BLUE = ['#BFD4FF', '#1563FF']; +export const BAR_COLOR_HOVER = ['#1563FF', '#0F4FD1']; +export const GREY = '#EBEEF2'; + +// TRANSLATIONS: +export const TRANSLATE = { left: -11 }; +export const SVG_DIMENSIONS = { height: 190, width: 500 }; diff --git a/ui/lib/core/addon/components/bar-chart.js b/ui/lib/core/addon/components/bar-chart.js index aba5c929b0d..7749ddb18cc 100644 --- a/ui/lib/core/addon/components/bar-chart.js +++ b/ui/lib/core/addon/components/bar-chart.js @@ -40,6 +40,7 @@ import { stack } from 'd3-shape'; import { select, event, selectAll } from 'd3-selection'; // eslint-disable-next-line no-unused-vars import { transition } from 'd3-transition'; +import { GREY } from '../../../../app/utils/chart-helpers'; // SIZING CONSTANTS const CHART_MARGIN = { top: 10, left: 137 }; // makes space for y-axis legend @@ -47,9 +48,8 @@ const CHAR_LIMIT = 18; // character count limit for y-axis labels to trigger tru const LINE_HEIGHT = 24; // each bar w/ padding is 24 pixels thick // COLOR THEME: -const BAR_COLOR_DEFAULT = ['#BFD4FF', '#8AB1FF']; +const LIGHT_AND_DARK_BLUE = ['#BFD4FF', '#8AB1FF']; const BAR_COLOR_HOVER = ['#1563FF', '#0F4FD1']; -const BACKGROUND_BAR_COLOR = '#EBEEF2'; const TOOLTIP_BACKGROUND = '#525761'; class BarChartComponent extends Component { @@ -121,7 +121,7 @@ class BarChartComponent extends Component { .append('g') // shifts chart to accommodate y-axis legend .attr('transform', `translate(${CHART_MARGIN.left}, ${CHART_MARGIN.top})`) - .style('fill', (d, i) => BAR_COLOR_DEFAULT[i]); + .style('fill', (d, i) => LIGHT_AND_DARK_BLUE[i]); let yAxis = axisLeft(yScale).tickSize(0); yAxis(chartSvg.append('g').attr('transform', `translate(${CHART_MARGIN.left}, ${CHART_MARGIN.top})`)); @@ -159,7 +159,7 @@ class BarChartComponent extends Component { .attr('height', `${LINE_HEIGHT}px`) .attr('x', '0') .attr('y', chartData => yScale(chartData[labelKey])) - .style('fill', `${BACKGROUND_BAR_COLOR}`) + .style('fill', `${GREY}`) .style('opacity', '0') .style('mix-blend-mode', 'multiply'); @@ -208,7 +208,7 @@ class BarChartComponent extends Component { .filter(function() { return compareAttributes(this, event.target, 'y'); }) - .style('fill', (b, i) => `${BAR_COLOR_DEFAULT[i]}`); + .style('fill', (b, i) => `${LIGHT_AND_DARK_BLUE[i]}`); }) .on('mousemove', function(chartData) { select('.chart-tooltip') @@ -254,7 +254,7 @@ class BarChartComponent extends Component { .filter(function() { return compareAttributes(this, event.target, 'y'); }) - .style('fill', (b, i) => `${BAR_COLOR_DEFAULT[i]}`); + .style('fill', (b, i) => `${LIGHT_AND_DARK_BLUE[i]}`); actionBarSelection .filter(function() { return compareAttributes(this, event.target, 'y'); @@ -302,7 +302,7 @@ class BarChartComponent extends Component { .attr('cx', `${xCoordinate}%`) .attr('cy', '50%') .attr('r', 6) - .style('fill', `${BAR_COLOR_DEFAULT[i]}`); + .style('fill', `${LIGHT_AND_DARK_BLUE[i]}`); legendSvg .append('text') .attr('x', `${xCoordinate + 2}%`) From 6863af97230bba4c76f60241df2b843b2eb97fbc Mon Sep 17 00:00:00 2001 From: Claire Bontempo Date: Thu, 23 Dec 2021 09:55:07 -0800 Subject: [PATCH 17/26] cleanup add todos --- ui/app/components/clients/dashboard.js | 48 +++++++++---------- .../clients/horizontal-bar-chart.js | 2 +- ui/app/components/clients/line-chart.js | 16 +++---- .../components/clients/vertical-bar-chart.js | 23 ++++++--- .../components/clients/monthly-usage.hbs | 5 +- .../components/clients/running-total.hbs | 5 +- ui/app/utils/chart-helpers.js | 8 ++++ ui/lib/core/addon/components/bar-chart.js | 3 +- 8 files changed, 64 insertions(+), 46 deletions(-) diff --git a/ui/app/components/clients/dashboard.js b/ui/app/components/clients/dashboard.js index ddaa68ae2aa..983159c2278 100644 --- a/ui/app/components/clients/dashboard.js +++ b/ui/app/components/clients/dashboard.js @@ -83,36 +83,36 @@ export default class Dashboard extends Component { // TODO: dataset for new monthly clients vertical bar chart (manage in serializer?) get newMonthlyClients() { return [ - { month: 'January', directEntities: 1000, nonEntityTokens: 322, total: 1322 }, - { month: 'February', directEntities: 1500, nonEntityTokens: 122, total: 1622 }, - { month: 'March', directEntities: 4300, nonEntityTokens: 700, total: 5000 }, - { month: 'April', directEntities: 1550, nonEntityTokens: 229, total: 1779 }, - { month: 'May', directEntities: 5560, nonEntityTokens: 124, total: 5684 }, - { month: 'June', directEntities: 1570, nonEntityTokens: 142, total: 1712 }, - { month: 'July', directEntities: 300, nonEntityTokens: 112, total: 412 }, - { month: 'August', directEntities: 1610, nonEntityTokens: 130, total: 1740 }, - { month: 'September', directEntities: 1900, nonEntityTokens: 222, total: 2122 }, - { month: 'October', directEntities: 500, nonEntityTokens: 166, total: 666 }, - { month: 'November', directEntities: 480, nonEntityTokens: 132, total: 612 }, - { month: 'December', directEntities: 980, nonEntityTokens: 202, total: 1182 }, + { month: 'January', distinct_entities: 1000, non_entity_tokens: 322, total: 1322 }, + { month: 'February', distinct_entities: 1500, non_entity_tokens: 122, total: 1622 }, + { month: 'March', distinct_entities: 4300, non_entity_tokens: 700, total: 5000 }, + { month: 'April', distinct_entities: 1550, non_entity_tokens: 229, total: 1779 }, + { month: 'May', distinct_entities: 5560, non_entity_tokens: 124, total: 5684 }, + { month: 'June', distinct_entities: 1570, non_entity_tokens: 142, total: 1712 }, + { month: 'July', distinct_entities: 300, non_entity_tokens: 112, total: 412 }, + { month: 'August', distinct_entities: 1610, non_entity_tokens: 130, total: 1740 }, + { month: 'September', distinct_entities: 1900, non_entity_tokens: 222, total: 2122 }, + { month: 'October', distinct_entities: 500, non_entity_tokens: 166, total: 666 }, + { month: 'November', distinct_entities: 480, non_entity_tokens: 132, total: 612 }, + { month: 'December', distinct_entities: 980, non_entity_tokens: 202, total: 1182 }, ]; } // TODO: dataset for vault usage vertical bar chart (manage in serializer?) get monthlyUsage() { return [ - { month: 'January', directEntities: 1000, nonEntityTokens: 322, total: 1322 }, - { month: 'February', directEntities: 1500, nonEntityTokens: 122, total: 1622 }, - { month: 'March', directEntities: 4300, nonEntityTokens: 700, total: 5000 }, - { month: 'April', directEntities: 1550, nonEntityTokens: 229, total: 1779 }, - { month: 'May', directEntities: 5560, nonEntityTokens: 124, total: 5684 }, - { month: 'June', directEntities: 1570, nonEntityTokens: 142, total: 1712 }, - { month: 'July', directEntities: 300, nonEntityTokens: 112, total: 412 }, - { month: 'August', directEntities: 1610, nonEntityTokens: 130, total: 1740 }, - { month: 'September', directEntities: 1900, nonEntityTokens: 222, total: 2122 }, - { month: 'October', directEntities: 500, nonEntityTokens: 166, total: 666 }, - { month: 'November', directEntities: 480, nonEntityTokens: 132, total: 612 }, - { month: 'December', directEntities: 980, nonEntityTokens: 202, total: 1182 }, + { month: 'January', distinct_entities: 1000, non_entity_tokens: 322, total: 1322 }, + { month: 'February', distinct_entities: 1500, non_entity_tokens: 122, total: 1622 }, + { month: 'March', distinct_entities: 4300, non_entity_tokens: 700, total: 5000 }, + { month: 'April', distinct_entities: 1550, non_entity_tokens: 229, total: 1779 }, + { month: 'May', distinct_entities: 5560, non_entity_tokens: 124, total: 5684 }, + { month: 'June', distinct_entities: 1570, non_entity_tokens: 142, total: 1712 }, + { month: 'July', distinct_entities: 300, non_entity_tokens: 112, total: 412 }, + { month: 'August', distinct_entities: 1610, non_entity_tokens: 130, total: 1740 }, + { month: 'September', distinct_entities: 1900, non_entity_tokens: 222, total: 2122 }, + { month: 'October', distinct_entities: 500, non_entity_tokens: 166, total: 666 }, + { month: 'November', distinct_entities: 480, non_entity_tokens: 132, total: 612 }, + { month: 'December', distinct_entities: 980, non_entity_tokens: 202, total: 1182 }, ]; } diff --git a/ui/app/components/clients/horizontal-bar-chart.js b/ui/app/components/clients/horizontal-bar-chart.js index bce0e55c3e9..9770e9dcedf 100644 --- a/ui/app/components/clients/horizontal-bar-chart.js +++ b/ui/app/components/clients/horizontal-bar-chart.js @@ -6,7 +6,7 @@ import { select, event, selectAll } from 'd3-selection'; import { scaleLinear, scaleBand } from 'd3-scale'; import { axisLeft } from 'd3-axis'; import { max, maxIndex } from 'd3-array'; -import { GREY, LIGHT_AND_DARK_BLUE } from '../../utils/chart-helpers'; +import { BAR_COLOR_HOVER, GREY, LIGHT_AND_DARK_BLUE } from '../../utils/chart-helpers'; /** * @module HorizontalBarChart diff --git a/ui/app/components/clients/line-chart.js b/ui/app/components/clients/line-chart.js index 4a6f98892b9..d9148ba33d4 100644 --- a/ui/app/components/clients/line-chart.js +++ b/ui/app/components/clients/line-chart.js @@ -6,10 +6,10 @@ import { max } from 'd3-array'; import { select, selectAll, node } from 'd3-selection'; import { axisLeft, axisBottom } from 'd3-axis'; import { scaleLinear, scalePoint } from 'd3-scale'; -import { format } from 'd3-format'; import { line } from 'd3-shape'; -import { LIGHT_AND_DARK_BLUE, SVG_DIMENSIONS } from '../../utils/chart-helpers'; +import { LIGHT_AND_DARK_BLUE, SVG_DIMENSIONS, formatNumbers } from '../../utils/chart-helpers'; +// TODO fill out below /** * @module LineChart * LineChart components are used to... @@ -31,25 +31,21 @@ export default class LineChart extends Component { renderChart(element, args) { let dataset = args[0]; let chartSvg = select(element); - let yMaxValue = max(dataset.map(d => d.clients)); // TODO will need to recalculate when we get the data - let xMaxValue = dataset.map(d => d.month); chartSvg.attr('viewBox', `-50 20 600 ${SVG_DIMENSIONS.height}`); // set svg dimensions let yScale = scaleLinear() - .domain([0, yMaxValue]) + .domain([0, max(dataset.map(d => d.clients))]) .range([0, 100]); let yAxisScale = scaleLinear() - .domain([0, yMaxValue]) // TODO will need to recalculate when you get the data + .domain([0, max(dataset.map(d => d.clients))]) // TODO will need to recalculate when you get the data .range([SVG_DIMENSIONS.height, 0]); - let xScale = scalePoint() //use scaleTime()? - .domain(xMaxValue) + let xScale = scalePoint() // use scaleTime()? + .domain(dataset.map(d => d.month)) .range([0, SVG_DIMENSIONS.width]) .padding(0.2); - let formatNumbers = number => format('.1s')(number).replace('G', 'B'); // replace SI sign of 'G' for billions to 'B' - let yAxis = axisLeft(yAxisScale) .ticks(7) .tickPadding(10) diff --git a/ui/app/components/clients/vertical-bar-chart.js b/ui/app/components/clients/vertical-bar-chart.js index 1a3a4d1829c..770306fbe5f 100644 --- a/ui/app/components/clients/vertical-bar-chart.js +++ b/ui/app/components/clients/vertical-bar-chart.js @@ -6,10 +6,16 @@ import { max } from 'd3-array'; import { select, selectAll, node } from 'd3-selection'; import { axisLeft, axisBottom } from 'd3-axis'; import { scaleLinear, scaleBand } from 'd3-scale'; -import { format } from 'd3-format'; import { stack } from 'd3-shape'; -import { GREY, LIGHT_AND_DARK_BLUE, SVG_DIMENSIONS, TRANSLATE } from '../../utils/chart-helpers'; - +import { + GREY, + LIGHT_AND_DARK_BLUE, + SVG_DIMENSIONS, + TRANSLATE, + formatNumbers, +} from '../../utils/chart-helpers'; + +// TODO fill out below /** * @module VerticalBarChart * VerticalBarChart components are used to... @@ -27,13 +33,19 @@ export default class VerticalBarChart extends Component { @tracked tooltipTarget = ''; @tracked hoveredLabel = ''; + get chartLegend() { + return this.args.chartLegend; + } + @action registerListener(element, args) { // Define the chart let dataset = args[0]; - let stackFunction = stack().keys(['directEntities', 'nonEntityTokens']); + console.log(this.chartLegend); + let stackFunction = stack().keys(this.chartLegend.map(l => l.key)); let stackedData = stackFunction(dataset); + // TODO pull out into helper? b/c same as line bar chart? let yScale = scaleLinear() .domain([0, max(dataset.map(d => d.total))]) // TODO will need to recalculate when you get the data .range([0, 100]) @@ -72,9 +84,6 @@ export default class VerticalBarChart extends Component { .range([`${SVG_DIMENSIONS.height}`, 0]) .nice(); - // Reference for tickFormat https://www.youtube.com/watch?v=c3MCROTNN8g - let formatNumbers = number => format('.2s')(number).replace('G', 'B'); // for billions to replace G with B. - let yAxis = axisLeft(yAxisScale) .ticks(7) .tickPadding(10) diff --git a/ui/app/templates/components/clients/monthly-usage.hbs b/ui/app/templates/components/clients/monthly-usage.hbs index d1e968cb7c9..62ade88e134 100644 --- a/ui/app/templates/components/clients/monthly-usage.hbs +++ b/ui/app/templates/components/clients/monthly-usage.hbs @@ -7,7 +7,10 @@
- +
diff --git a/ui/app/templates/components/clients/running-total.hbs b/ui/app/templates/components/clients/running-total.hbs index afda14ca9f3..d1b76f2b6d8 100644 --- a/ui/app/templates/components/clients/running-total.hbs +++ b/ui/app/templates/components/clients/running-total.hbs @@ -32,7 +32,10 @@
- +
diff --git a/ui/app/utils/chart-helpers.js b/ui/app/utils/chart-helpers.js index 98129f3d986..a8d5f07f2fc 100644 --- a/ui/app/utils/chart-helpers.js +++ b/ui/app/utils/chart-helpers.js @@ -1,3 +1,5 @@ +import { format } from 'd3-format'; + // COLOR THEME: export const LIGHT_AND_DARK_BLUE = ['#BFD4FF', '#1563FF']; export const BAR_COLOR_HOVER = ['#1563FF', '#0F4FD1']; @@ -6,3 +8,9 @@ export const GREY = '#EBEEF2'; // TRANSLATIONS: export const TRANSLATE = { left: -11 }; export const SVG_DIMENSIONS = { height: 190, width: 500 }; + +// Reference for tickFormat https://www.youtube.com/watch?v=c3MCROTNN8g +export function formatNumbers(number) { + // replace SI prefix of 'G' for billions to 'B' + format('.2s')(number).replace('G', 'B'); +} diff --git a/ui/lib/core/addon/components/bar-chart.js b/ui/lib/core/addon/components/bar-chart.js index 7749ddb18cc..0ac33266db1 100644 --- a/ui/lib/core/addon/components/bar-chart.js +++ b/ui/lib/core/addon/components/bar-chart.js @@ -40,7 +40,6 @@ import { stack } from 'd3-shape'; import { select, event, selectAll } from 'd3-selection'; // eslint-disable-next-line no-unused-vars import { transition } from 'd3-transition'; -import { GREY } from '../../../../app/utils/chart-helpers'; // SIZING CONSTANTS const CHART_MARGIN = { top: 10, left: 137 }; // makes space for y-axis legend @@ -51,7 +50,7 @@ const LINE_HEIGHT = 24; // each bar w/ padding is 24 pixels thick const LIGHT_AND_DARK_BLUE = ['#BFD4FF', '#8AB1FF']; const BAR_COLOR_HOVER = ['#1563FF', '#0F4FD1']; const TOOLTIP_BACKGROUND = '#525761'; - +const GREY = '#EBEEF2'; class BarChartComponent extends Component { get labelKey() { return this.args.labelKey || 'label'; From 41d2bca822f71cf5a4e84d57c63b64c0d2c94afb Mon Sep 17 00:00:00 2001 From: Claire Bontempo Date: Thu, 23 Dec 2021 09:59:37 -0800 Subject: [PATCH 18/26] fix formatNumbers return" --- ui/app/components/clients/vertical-bar-chart.js | 1 - ui/app/utils/chart-helpers.js | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/ui/app/components/clients/vertical-bar-chart.js b/ui/app/components/clients/vertical-bar-chart.js index 770306fbe5f..db321811520 100644 --- a/ui/app/components/clients/vertical-bar-chart.js +++ b/ui/app/components/clients/vertical-bar-chart.js @@ -41,7 +41,6 @@ export default class VerticalBarChart extends Component { registerListener(element, args) { // Define the chart let dataset = args[0]; - console.log(this.chartLegend); let stackFunction = stack().keys(this.chartLegend.map(l => l.key)); let stackedData = stackFunction(dataset); diff --git a/ui/app/utils/chart-helpers.js b/ui/app/utils/chart-helpers.js index a8d5f07f2fc..bf4b70ab732 100644 --- a/ui/app/utils/chart-helpers.js +++ b/ui/app/utils/chart-helpers.js @@ -12,5 +12,5 @@ export const SVG_DIMENSIONS = { height: 190, width: 500 }; // Reference for tickFormat https://www.youtube.com/watch?v=c3MCROTNN8g export function formatNumbers(number) { // replace SI prefix of 'G' for billions to 'B' - format('.2s')(number).replace('G', 'B'); + return format('.1s')(number).replace('G', 'B'); } From 26ef44671f08be87164f5d01309defe0498e542a Mon Sep 17 00:00:00 2001 From: Claire Bontempo Date: Thu, 23 Dec 2021 10:23:14 -0800 Subject: [PATCH 19/26] comments and cleanup --- ui/app/components/clients/line-chart.js | 22 +++++++++++++++---- .../components/clients/vertical-bar-chart.js | 18 +++++++-------- 2 files changed, 26 insertions(+), 14 deletions(-) diff --git a/ui/app/components/clients/line-chart.js b/ui/app/components/clients/line-chart.js index d9148ba33d4..1438457091d 100644 --- a/ui/app/components/clients/line-chart.js +++ b/ui/app/components/clients/line-chart.js @@ -33,6 +33,7 @@ export default class LineChart extends Component { let chartSvg = select(element); chartSvg.attr('viewBox', `-50 20 600 ${SVG_DIMENSIONS.height}`); // set svg dimensions + // DEFINE AXES SCALES let yScale = scaleLinear() .domain([0, max(dataset.map(d => d.clients))]) .range([0, 100]); @@ -46,6 +47,7 @@ export default class LineChart extends Component { .range([0, SVG_DIMENSIONS.width]) .padding(0.2); + // CUSTOMIZE AND APPEND AXES let yAxis = axisLeft(yAxisScale) .ticks(7) .tickPadding(10) @@ -56,13 +58,14 @@ export default class LineChart extends Component { yAxis(chartSvg.append('g')); xAxis(chartSvg.append('g').attr('transform', `translate(0, ${SVG_DIMENSIONS.height + 10})`)); - chartSvg.selectAll('.domain').remove(); // remove domain lines + chartSvg.selectAll('.domain').remove(); + + // PATH BETWEEN PLOT POINTS let lineGenerator = line() .x(d => xScale(d.month)) .y(d => yAxisScale(d.clients)); - // LINE (PATH) BETWEEN DOTS chartSvg .append('g') .append('path') @@ -71,8 +74,8 @@ export default class LineChart extends Component { .attr('stroke-width', 0.5) .attr('d', lineGenerator(dataset)); - // CIRCLES - chartSvg + // PLOT POINTS + let plotPoints = chartSvg .append('g') .selectAll('circle') .data(dataset) @@ -85,6 +88,17 @@ export default class LineChart extends Component { .attr('fill', LIGHT_AND_DARK_BLUE[0]) .attr('stroke', LIGHT_AND_DARK_BLUE[1]) .attr('stroke-width', 1.5); + + // MOUSE EVENT FOR TOOLTIP + plotPoints.on('mouseover', data => { + this.hoveredLabel = data.month; + console.log(data.month); + // let node = chartSvg + // .selectAll('rect.data-bar') + // .filter(data => data[0] !== 0 && data.data.month === this.hoveredLabel) + // .node(); + // this.tooltipTarget = node; // grab the node from the list of rects + }); } @action removeTooltip() { diff --git a/ui/app/components/clients/vertical-bar-chart.js b/ui/app/components/clients/vertical-bar-chart.js index db321811520..46f6e50d48f 100644 --- a/ui/app/components/clients/vertical-bar-chart.js +++ b/ui/app/components/clients/vertical-bar-chart.js @@ -39,12 +39,14 @@ export default class VerticalBarChart extends Component { @action registerListener(element, args) { - // Define the chart let dataset = args[0]; + // TODO pull out lines 44 - scales into helper? b/c same as line chart? let stackFunction = stack().keys(this.chartLegend.map(l => l.key)); let stackedData = stackFunction(dataset); + let chartSvg = select(element); + chartSvg.attr('viewBox', `-50 20 600 ${SVG_DIMENSIONS.height}`); // set svg dimensions - // TODO pull out into helper? b/c same as line bar chart? + // DEFINE DATA BAR SCALES let yScale = scaleLinear() .domain([0, max(dataset.map(d => d.total))]) // TODO will need to recalculate when you get the data .range([0, 100]) @@ -55,18 +57,14 @@ export default class VerticalBarChart extends Component { .range([0, SVG_DIMENSIONS.width]) // set width to fix number of pixels .paddingInner(0.85); - let chartSvg = select(element); - - chartSvg.attr('viewBox', `-50 20 600 ${SVG_DIMENSIONS.height}`); // set svg dimensions - - let groups = chartSvg + let dataBars = chartSvg .selectAll('g') .data(stackedData) .enter() .append('g') .style('fill', (d, i) => LIGHT_AND_DARK_BLUE[i]); - groups + dataBars .selectAll('rect') .data(stackedData => stackedData) .enter() @@ -96,7 +94,7 @@ export default class VerticalBarChart extends Component { chartSvg.selectAll('.domain').remove(); // remove domain lines - // creating wider area for tooltip hover + // WIDER SELECTION AREA FOR TOOLTIP HOVER let greyBars = chartSvg .append('g') .attr('transform', `translate(${TRANSLATE.left})`) @@ -116,7 +114,7 @@ export default class VerticalBarChart extends Component { .attr('y', '0') // start at bottom .attr('x', data => xScale(data.month)); // not data.data because this is not stacked data - // for tooltip + // MOUSE EVENT FOR TOOLTIP tooltipRect.on('mouseover', data => { this.hoveredLabel = data.month; // let node = chartSvg From ee9b44fd1b32623664e43e83a4bd8fbe2594843f Mon Sep 17 00:00:00 2001 From: Claire Bontempo Date: Thu, 23 Dec 2021 10:42:35 -0800 Subject: [PATCH 20/26] adds tooltip to line chart --- ui/app/components/clients/line-chart.js | 21 +++++++++---------- .../components/clients/line-chart.hbs | 4 ++-- 2 files changed, 12 insertions(+), 13 deletions(-) diff --git a/ui/app/components/clients/line-chart.js b/ui/app/components/clients/line-chart.js index 1438457091d..59d1869cd3c 100644 --- a/ui/app/components/clients/line-chart.js +++ b/ui/app/components/clients/line-chart.js @@ -25,7 +25,7 @@ import { LIGHT_AND_DARK_BLUE, SVG_DIMENSIONS, formatNumbers } from '../../utils/ export default class LineChart extends Component { @tracked tooltipTarget = ''; - @tracked hoveredLabel = ''; + @tracked tooltipText = ''; @action renderChart(element, args) { @@ -74,8 +74,8 @@ export default class LineChart extends Component { .attr('stroke-width', 0.5) .attr('d', lineGenerator(dataset)); - // PLOT POINTS - let plotPoints = chartSvg + // LINE PLOTS (CIRCLES) + chartSvg .append('g') .selectAll('circle') .data(dataset) @@ -89,15 +89,14 @@ export default class LineChart extends Component { .attr('stroke', LIGHT_AND_DARK_BLUE[1]) .attr('stroke-width', 1.5); + let linePlots = chartSvg.selectAll('.data-plot'); + // MOUSE EVENT FOR TOOLTIP - plotPoints.on('mouseover', data => { - this.hoveredLabel = data.month; - console.log(data.month); - // let node = chartSvg - // .selectAll('rect.data-bar') - // .filter(data => data[0] !== 0 && data.data.month === this.hoveredLabel) - // .node(); - // this.tooltipTarget = node; // grab the node from the list of rects + linePlots.on('mouseover', data => { + let hoveredMonth = data.month; + this.tooltipText = `${hoveredMonth} ${data.clients}`; + let node = linePlots.filter(plot => plot.month === hoveredMonth).node(); + this.tooltipTarget = node; }); } diff --git a/ui/app/templates/components/clients/line-chart.hbs b/ui/app/templates/components/clients/line-chart.hbs index b8bd6a4cd97..93965471a74 100644 --- a/ui/app/templates/components/clients/line-chart.hbs +++ b/ui/app/templates/components/clients/line-chart.hbs @@ -12,9 +12,9 @@ tetherTarget=this.tooltipTarget targetAttachment='bottom middle' attachment='bottom middle' - offset='40px 0' + offset='20px 0' }} -

{{this.hoveredLabel}}

+

{{this.tooltipText}}

{{/modal-dialog}} {{/if}} From ddddace224ebc1eb33882214b34fa42e31fe2a7e Mon Sep 17 00:00:00 2001 From: Claire Bontempo Date: Thu, 23 Dec 2021 10:50:28 -0800 Subject: [PATCH 21/26] make cover area larger --- ui/app/components/clients/line-chart.js | 20 ++++++++++++++++--- .../components/clients/line-chart.hbs | 2 +- 2 files changed, 18 insertions(+), 4 deletions(-) diff --git a/ui/app/components/clients/line-chart.js b/ui/app/components/clients/line-chart.js index 59d1869cd3c..2c4873f7052 100644 --- a/ui/app/components/clients/line-chart.js +++ b/ui/app/components/clients/line-chart.js @@ -89,13 +89,27 @@ export default class LineChart extends Component { .attr('stroke', LIGHT_AND_DARK_BLUE[1]) .attr('stroke-width', 1.5); - let linePlots = chartSvg.selectAll('.data-plot'); + // LARGER HOVER CIRCLES + chartSvg + .append('g') + .selectAll('circle') + .data(dataset) + .enter() + .append('circle') + .attr('class', 'hover-circle') + .style('cursor', 'pointer') + .style('opacity', '0') + .attr('cy', d => `${100 - yScale(d.clients)}%`) + .attr('cx', d => xScale(d.month)) + .attr('r', 10); + + let hoverCircles = chartSvg.selectAll('.hover-circle'); // MOUSE EVENT FOR TOOLTIP - linePlots.on('mouseover', data => { + hoverCircles.on('mouseover', data => { let hoveredMonth = data.month; this.tooltipText = `${hoveredMonth} ${data.clients}`; - let node = linePlots.filter(plot => plot.month === hoveredMonth).node(); + let node = hoverCircles.filter(plot => plot.month === hoveredMonth).node(); this.tooltipTarget = node; }); } diff --git a/ui/app/templates/components/clients/line-chart.hbs b/ui/app/templates/components/clients/line-chart.hbs index 93965471a74..6920e7250b6 100644 --- a/ui/app/templates/components/clients/line-chart.hbs +++ b/ui/app/templates/components/clients/line-chart.hbs @@ -12,7 +12,7 @@ tetherTarget=this.tooltipTarget targetAttachment='bottom middle' attachment='bottom middle' - offset='20px 0' + offset='35px 0' }}

{{this.tooltipText}}

From b305b77e54ba64cc46145b36bbddcb5a9f187b08 Mon Sep 17 00:00:00 2001 From: Claire Bontempo Date: Thu, 23 Dec 2021 15:40:42 -0800 Subject: [PATCH 22/26] fixes tooltip styling --- ui/app/components/clients/dashboard.js | 24 +++++++++---------- ui/app/components/clients/line-chart.js | 11 +++++---- ui/app/styles/core/charts.scss | 10 +++++--- .../components/clients/line-chart.hbs | 6 ++++- 4 files changed, 31 insertions(+), 20 deletions(-) diff --git a/ui/app/components/clients/dashboard.js b/ui/app/components/clients/dashboard.js index 983159c2278..7cb300076d6 100644 --- a/ui/app/components/clients/dashboard.js +++ b/ui/app/components/clients/dashboard.js @@ -65,18 +65,18 @@ export default class Dashboard extends Component { // TODO: dataset for line chart get lineChartData() { return [ - { month: '1/21', clients: 100 }, - { month: '2/21', clients: 300 }, - { month: '3/21', clients: 300 }, - { month: '4/21', clients: 300 }, - { month: '5/21', clients: 300 }, - { month: '6/21', clients: 300 }, - { month: '7/21', clients: 300 }, - { month: '8/21', clients: 350 }, - { month: '9/21', clients: 400 }, - { month: '10/21', clients: 450 }, - { month: '11/21', clients: 500 }, - { month: '12/21', clients: 1000 }, + { month: '1/21', clients: 100, new: 100 }, + { month: '2/21', clients: 300, new: 200 }, + { month: '3/21', clients: 300, new: 0 }, + { month: '4/21', clients: 300, new: 0 }, + { month: '5/21', clients: 300, new: 0 }, + { month: '6/21', clients: 300, new: 0 }, + { month: '7/21', clients: 300, new: 0 }, + { month: '8/21', clients: 350, new: 50 }, + { month: '9/21', clients: 400, new: 50 }, + { month: '10/21', clients: 450, new: 50 }, + { month: '11/21', clients: 500, new: 50 }, + { month: '12/21', clients: 1000, new: 1000 }, ]; } diff --git a/ui/app/components/clients/line-chart.js b/ui/app/components/clients/line-chart.js index 2c4873f7052..28df8c5a450 100644 --- a/ui/app/components/clients/line-chart.js +++ b/ui/app/components/clients/line-chart.js @@ -25,7 +25,9 @@ import { LIGHT_AND_DARK_BLUE, SVG_DIMENSIONS, formatNumbers } from '../../utils/ export default class LineChart extends Component { @tracked tooltipTarget = ''; - @tracked tooltipText = ''; + @tracked tooltipMonth = ''; + @tracked tooltipTotal = ''; + @tracked tooltipNew = ''; @action renderChart(element, args) { @@ -107,9 +109,10 @@ export default class LineChart extends Component { // MOUSE EVENT FOR TOOLTIP hoverCircles.on('mouseover', data => { - let hoveredMonth = data.month; - this.tooltipText = `${hoveredMonth} ${data.clients}`; - let node = hoverCircles.filter(plot => plot.month === hoveredMonth).node(); + this.tooltipMonth = data.month; + this.tooltipTotal = `${data.clients} total clients`; + this.tooltipNew = `${data.new} new clients`; + let node = hoverCircles.filter(plot => plot.month === data.month).node(); this.tooltipTarget = node; }); } diff --git a/ui/app/styles/core/charts.scss b/ui/app/styles/core/charts.scss index 9a0a567f212..17301b63a6c 100644 --- a/ui/app/styles/core/charts.scss +++ b/ui/app/styles/core/charts.scss @@ -204,9 +204,13 @@ p.data-details { .chart-tooltip { background-color: $ui-gray-700; color: white; - font-size: 0.929rem; - padding: 10px; - border-radius: 4px; + width: 117px; + font-size: $size-9; + padding: 6px; + border-radius: $radius-large; + > h4 { + font-weight: $font-weight-bold; + } } .chart-tooltip-arrow { diff --git a/ui/app/templates/components/clients/line-chart.hbs b/ui/app/templates/components/clients/line-chart.hbs index 6920e7250b6..0f32aed4cf4 100644 --- a/ui/app/templates/components/clients/line-chart.hbs +++ b/ui/app/templates/components/clients/line-chart.hbs @@ -14,7 +14,11 @@ attachment='bottom middle' offset='35px 0' }} -

{{this.tooltipText}}

+
+

{{this.tooltipMonth}}

+

{{this.tooltipTotal}}

+

{{this.tooltipNew}}

+
{{/modal-dialog}} {{/if}} From d473178b2e361e5e87d523c37300da482a54d33a Mon Sep 17 00:00:00 2001 From: Claire Bontempo Date: Thu, 23 Dec 2021 16:01:46 -0800 Subject: [PATCH 23/26] adds tooltip styling" --- ui/app/components/clients/vertical-bar-chart.js | 11 ++++++++--- ui/app/styles/core/charts.scss | 13 +++++++++++-- ui/app/templates/components/clients/line-chart.hbs | 4 ++-- .../components/clients/vertical-bar-chart.hbs | 6 +++++- 4 files changed, 26 insertions(+), 8 deletions(-) diff --git a/ui/app/components/clients/vertical-bar-chart.js b/ui/app/components/clients/vertical-bar-chart.js index 46f6e50d48f..e9b62f47d87 100644 --- a/ui/app/components/clients/vertical-bar-chart.js +++ b/ui/app/components/clients/vertical-bar-chart.js @@ -31,7 +31,9 @@ import { export default class VerticalBarChart extends Component { @tracked tooltipTarget = ''; - @tracked hoveredLabel = ''; + @tracked tooltipTotal = ''; + @tracked uniqueEntities = ''; + @tracked nonEntityTokens = ''; get chartLegend() { return this.args.chartLegend; @@ -116,7 +118,10 @@ export default class VerticalBarChart extends Component { // MOUSE EVENT FOR TOOLTIP tooltipRect.on('mouseover', data => { - this.hoveredLabel = data.month; + let hoveredMonth = data.month; + this.tooltipTotal = `${data.total} total clients`; + this.uniqueEntities = `${data.distinct_entities} unique entities`; + this.nonEntityTokens = `${data.non_entity_tokens} non-entity tokens`; // let node = chartSvg // .selectAll('rect.tooltip-rect') // .filter(data => data.month === this.hoveredLabel) @@ -124,7 +129,7 @@ export default class VerticalBarChart extends Component { let node = chartSvg .selectAll('rect.data-bar') // filter for the top data bar (so y-coord !== 0) with matching month - .filter(data => data[0] !== 0 && data.data.month === this.hoveredLabel) + .filter(data => data[0] !== 0 && data.data.month === hoveredMonth) .node(); this.tooltipTarget = node; // grab the node from the list of rects }); diff --git a/ui/app/styles/core/charts.scss b/ui/app/styles/core/charts.scss index 17301b63a6c..5c9cea49d38 100644 --- a/ui/app/styles/core/charts.scss +++ b/ui/app/styles/core/charts.scss @@ -204,13 +204,22 @@ p.data-details { .chart-tooltip { background-color: $ui-gray-700; color: white; - width: 117px; font-size: $size-9; padding: 6px; border-radius: $radius-large; - > h4 { + + .line-chart { + width: 117px; + } + + .bold { font-weight: $font-weight-bold; } + .vertical-chart { + text-align: center; + flex-wrap: nowrap; + width: fit-content; + } } .chart-tooltip-arrow { diff --git a/ui/app/templates/components/clients/line-chart.hbs b/ui/app/templates/components/clients/line-chart.hbs index 0f32aed4cf4..63942aa9921 100644 --- a/ui/app/templates/components/clients/line-chart.hbs +++ b/ui/app/templates/components/clients/line-chart.hbs @@ -14,8 +14,8 @@ attachment='bottom middle' offset='35px 0' }} -
-

{{this.tooltipMonth}}

+
+

{{this.tooltipMonth}}

{{this.tooltipTotal}}

{{this.tooltipNew}}

diff --git a/ui/app/templates/components/clients/vertical-bar-chart.hbs b/ui/app/templates/components/clients/vertical-bar-chart.hbs index 7160f1f9bf0..ac63496011b 100644 --- a/ui/app/templates/components/clients/vertical-bar-chart.hbs +++ b/ui/app/templates/components/clients/vertical-bar-chart.hbs @@ -14,7 +14,11 @@ attachment='bottom middle' offset='40px 0' }} -

{{this.hoveredLabel}}

+
+

{{this.tooltipTotal}}

+

{{this.uniqueEntities}}

+

{{this.nonEntityTokens}}

+
{{/modal-dialog}} {{/if}} From 33f1b2ce7d88f3ec0088dd353c69c920bfa8798b Mon Sep 17 00:00:00 2001 From: Claire Bontempo Date: Thu, 23 Dec 2021 17:03:25 -0800 Subject: [PATCH 24/26] adds tooltip modal to horizontal chart --- .../clients/horizontal-bar-chart.js | 126 ++++++++---------- ui/app/components/clients/line-chart.js | 1 + ui/app/styles/core/charts.scss | 12 +- .../clients/horizontal-bar-chart.hbs | 21 ++- 4 files changed, 85 insertions(+), 75 deletions(-) diff --git a/ui/app/components/clients/horizontal-bar-chart.js b/ui/app/components/clients/horizontal-bar-chart.js index 9770e9dcedf..579bd5a1dde 100644 --- a/ui/app/components/clients/horizontal-bar-chart.js +++ b/ui/app/components/clients/horizontal-bar-chart.js @@ -7,6 +7,9 @@ import { scaleLinear, scaleBand } from 'd3-scale'; import { axisLeft } from 'd3-axis'; import { max, maxIndex } from 'd3-array'; import { BAR_COLOR_HOVER, GREY, LIGHT_AND_DARK_BLUE } from '../../utils/chart-helpers'; +import { tracked } from '@glimmer/tracking'; +import OidcConsentBlockComponent from '../oidc-consent-block'; +import attachCapabilities from '../../lib/attach-capabilities'; /** * @module HorizontalBarChart @@ -32,6 +35,9 @@ const CHAR_LIMIT = 15; // character count limit for y-axis labels to trigger tru const LINE_HEIGHT = 24; // each bar w/ padding is 24 pixels thick export default class HorizontalBarChart extends Component { + @tracked tooltipTarget = ''; + @tracked tooltipText = ''; + get labelKey() { return this.args.labelKey || 'label'; } @@ -138,8 +144,9 @@ export default class HorizontalBarChart extends Component { let dataBars = chartSvg.selectAll('rect.data-bar'); let actionBarSelection = chartSvg.selectAll('rect.action-bar'); + let compareAttributes = (elementA, elementB, attr) => - select(elementA).attr(`${attr}`) === elementB.getAttribute(`${attr}`); + select(elementA).attr(`${attr}`) === select(elementB).attr(`${attr}`); // MOUSE AND CLICK EVENTS FOR DATA BARS actionBars @@ -148,90 +155,65 @@ export default class HorizontalBarChart extends Component { handleClick(chartData); } }) - .on('mouseover', function() { - select(this).style('opacity', 1); + .on('mouseover', data => { + let hoveredElement = actionBars.filter(bar => bar.label === data.label).node(); + this.tooltipTarget = hoveredElement; + this.tooltipText = `${Math.round((data.total * 100) / 19000)}% of total client counts: + ${data.non_entity_tokens} non-entity tokens, ${data.distinct_entities} unique entities.`; + + select(hoveredElement).style('opacity', 1); + dataBars .filter(function() { - return compareAttributes(this, event.target, 'y'); + return compareAttributes(this, hoveredElement, 'y'); }) .style('fill', (b, i) => `${BAR_COLOR_HOVER[i]}`); - // TODO: change to use modal instead of tooltip div - select('.chart-tooltip') - .transition() - .duration(200) - .style('opacity', 1); }) .on('mouseout', function() { select(this).style('opacity', 0); - select('.chart-tooltip').style('opacity', 0); dataBars .filter(function() { return compareAttributes(this, event.target, 'y'); }) .style('fill', (b, i) => `${LIGHT_AND_DARK_BLUE[i]}`); - }) - .on('mousemove', function(chartData) { - select('.chart-tooltip') - .style('opacity', 1) - .style('max-width', '200px') - .style('left', `${event.pageX - 325}px`) - .style('top', `${event.pageY - 140}px`) - .text( - `${Math.round((chartData.total * 100) / 19000)}% of total client counts: - ${chartData.non_entity_tokens} non-entity tokens, ${chartData.distinct_entities} unique entities. - ` - ); }); // MOUSE EVENTS FOR Y-AXIS LABELS - yLegendBars - .on('click', function(chartData) { - if (handleClick) { - handleClick(chartData); - } - }) - .on('mouseover', function(chartData) { - dataBars - .filter(function() { - return compareAttributes(this, event.target, 'y'); - }) - .style('fill', (b, i) => `${BAR_COLOR_HOVER[i]}`); - actionBarSelection - .filter(function() { - return compareAttributes(this, event.target, 'y'); - }) - .style('opacity', '1'); - if (chartData.label.length >= CHAR_LIMIT) { - select('.chart-tooltip') - .transition() - .duration(200) - .style('opacity', 1); - } - }) - .on('mouseout', function() { - select('.chart-tooltip').style('opacity', 0); - dataBars - .filter(function() { - return compareAttributes(this, event.target, 'y'); - }) - .style('fill', (b, i) => `${LIGHT_AND_DARK_BLUE[i]}`); - actionBarSelection - .filter(function() { - return compareAttributes(this, event.target, 'y'); - }) - .style('opacity', '0'); - }) - .on('mousemove', function(chartData) { - if (chartData.label.length >= CHAR_LIMIT) { - select('.chart-tooltip') - .style('left', `${event.pageX - 300}px`) - .style('top', `${event.pageY - 100}px`) - .text(`${chartData.label}`) - .style('max-width', 'fit-content'); - } else { - select('.chart-tooltip').style('opacity', 0); - } - }); + // yLegendBars + // .on('click', function(chartData) { + // if (handleClick) { + // handleClick(chartData); + // } + // }) + // .on('mouseover', function(data) { + // dataBars + // .filter(function() { + // return compareAttributes(this, event.target, 'y'); + // }) + // .style('fill', (b, i) => `${BAR_COLOR_HOVER[i]}`); + // actionBarSelection + // .filter(function() { + // return compareAttributes(this, event.target, 'y'); + // }) + // .style('opacity', '1'); + // if (data.label.length >= CHAR_LIMIT) { + // let hoveredElement = yLegendBars.filter( bar => bar.label === data.label).node() + // this.tooltipTarget = hoveredElement + // this.tooltipText = data.label + // } + // }) + // .on('mouseout', function() { + // dataBars + // .filter(function() { + // return compareAttributes(this, event.target, 'y'); + // }) + // .style('fill', (b, i) => `${LIGHT_AND_DARK_BLUE[i]}`); + // actionBarSelection + // .filter(function() { + // return compareAttributes(this, event.target, 'y'); + // }) + // .style('opacity', '0'); + // }); // add client count total values to the right chartSvg @@ -250,4 +232,8 @@ export default class HorizontalBarChart extends Component { .attr('x', chartData => `${xScale(chartData.total)}%`) .attr('y', chartData => yScale(chartData.label)); } + + @action removeTooltip() { + this.tooltipTarget = null; + } } diff --git a/ui/app/components/clients/line-chart.js b/ui/app/components/clients/line-chart.js index 28df8c5a450..b344c5d25d9 100644 --- a/ui/app/components/clients/line-chart.js +++ b/ui/app/components/clients/line-chart.js @@ -24,6 +24,7 @@ import { LIGHT_AND_DARK_BLUE, SVG_DIMENSIONS, formatNumbers } from '../../utils/ */ export default class LineChart extends Component { + // TODO make just one tracked variable tooltipText? @tracked tooltipTarget = ''; @tracked tooltipMonth = ''; @tracked tooltipTotal = ''; diff --git a/ui/app/styles/core/charts.scss b/ui/app/styles/core/charts.scss index 5c9cea49d38..6163608a028 100644 --- a/ui/app/styles/core/charts.scss +++ b/ui/app/styles/core/charts.scss @@ -208,18 +208,24 @@ p.data-details { padding: 6px; border-radius: $radius-large; + .bold { + font-weight: $font-weight-bold; + } + .line-chart { width: 117px; } - .bold { - font-weight: $font-weight-bold; - } .vertical-chart { text-align: center; flex-wrap: nowrap; width: fit-content; } + + .horizontal-chart { + width: 200px; + padding: $spacing-s; + } } .chart-tooltip-arrow { diff --git a/ui/app/templates/components/clients/horizontal-bar-chart.hbs b/ui/app/templates/components/clients/horizontal-bar-chart.hbs index 12cfdac9ad0..c3c8c6328cc 100644 --- a/ui/app/templates/components/clients/horizontal-bar-chart.hbs +++ b/ui/app/templates/components/clients/horizontal-bar-chart.hbs @@ -1,4 +1,21 @@ - - \ No newline at end of file + + +{{#if this.tooltipTarget}} +{{!-- Required to set tag name = div https://github.com/yapplabs/ember-modal-dialog/issues/290 --}} +{{!-- Component must be in curly bracket notation --}} + {{#modal-dialog + tagName='div' + tetherTarget=this.tooltipTarget + targetAttachment='bottom middle' + attachment='bottom middle' + offset='35px 0' + }} +
+

{{this.tooltipText}}

+
+
+ {{/modal-dialog}} +{{/if}} From 7988f80b438591c4bf2e1e4d823da54de6527ed5 Mon Sep 17 00:00:00 2001 From: Claire Bontempo Date: Thu, 23 Dec 2021 17:12:04 -0800 Subject: [PATCH 25/26] finishes tooltip for horizontal chart --- .../clients/horizontal-bar-chart.js | 81 ++++++++++--------- ui/app/components/clients/line-chart.js | 8 +- 2 files changed, 46 insertions(+), 43 deletions(-) diff --git a/ui/app/components/clients/horizontal-bar-chart.js b/ui/app/components/clients/horizontal-bar-chart.js index 579bd5a1dde..74042a60dcb 100644 --- a/ui/app/components/clients/horizontal-bar-chart.js +++ b/ui/app/components/clients/horizontal-bar-chart.js @@ -50,6 +50,10 @@ export default class HorizontalBarChart extends Component { return this.args.dataset[maxIndex(this.args.dataset, d => d.total)]; } + @action removeTooltip() { + this.tooltipTarget = null; + } + @action renderChart(element, args) { // chart legend tells stackFunction how to stack/organize data @@ -179,41 +183,44 @@ export default class HorizontalBarChart extends Component { }); // MOUSE EVENTS FOR Y-AXIS LABELS - // yLegendBars - // .on('click', function(chartData) { - // if (handleClick) { - // handleClick(chartData); - // } - // }) - // .on('mouseover', function(data) { - // dataBars - // .filter(function() { - // return compareAttributes(this, event.target, 'y'); - // }) - // .style('fill', (b, i) => `${BAR_COLOR_HOVER[i]}`); - // actionBarSelection - // .filter(function() { - // return compareAttributes(this, event.target, 'y'); - // }) - // .style('opacity', '1'); - // if (data.label.length >= CHAR_LIMIT) { - // let hoveredElement = yLegendBars.filter( bar => bar.label === data.label).node() - // this.tooltipTarget = hoveredElement - // this.tooltipText = data.label - // } - // }) - // .on('mouseout', function() { - // dataBars - // .filter(function() { - // return compareAttributes(this, event.target, 'y'); - // }) - // .style('fill', (b, i) => `${LIGHT_AND_DARK_BLUE[i]}`); - // actionBarSelection - // .filter(function() { - // return compareAttributes(this, event.target, 'y'); - // }) - // .style('opacity', '0'); - // }); + yLegendBars + .on('click', function(chartData) { + if (handleClick) { + handleClick(chartData); + } + }) + .on('mouseover', data => { + if (data.label.length >= CHAR_LIMIT) { + let hoveredElement = yLegendBars.filter(bar => bar.label === data.label).node(); + this.tooltipTarget = hoveredElement; + this.tooltipText = data.label; + } else { + this.tooltipTarget = null; + } + dataBars + .filter(function() { + return compareAttributes(this, event.target, 'y'); + }) + .style('fill', (b, i) => `${BAR_COLOR_HOVER[i]}`); + actionBarSelection + .filter(function() { + return compareAttributes(this, event.target, 'y'); + }) + .style('opacity', '1'); + }) + .on('mouseout', function() { + this.tooltipTarget = null; + dataBars + .filter(function() { + return compareAttributes(this, event.target, 'y'); + }) + .style('fill', (b, i) => `${LIGHT_AND_DARK_BLUE[i]}`); + actionBarSelection + .filter(function() { + return compareAttributes(this, event.target, 'y'); + }) + .style('opacity', '0'); + }); // add client count total values to the right chartSvg @@ -232,8 +239,4 @@ export default class HorizontalBarChart extends Component { .attr('x', chartData => `${xScale(chartData.total)}%`) .attr('y', chartData => yScale(chartData.label)); } - - @action removeTooltip() { - this.tooltipTarget = null; - } } diff --git a/ui/app/components/clients/line-chart.js b/ui/app/components/clients/line-chart.js index b344c5d25d9..4fd30a9b66d 100644 --- a/ui/app/components/clients/line-chart.js +++ b/ui/app/components/clients/line-chart.js @@ -30,6 +30,10 @@ export default class LineChart extends Component { @tracked tooltipTotal = ''; @tracked tooltipNew = ''; + @action removeTooltip() { + this.tooltipTarget = null; + } + @action renderChart(element, args) { let dataset = args[0]; @@ -117,8 +121,4 @@ export default class LineChart extends Component { this.tooltipTarget = node; }); } - - @action removeTooltip() { - this.tooltipTarget = null; - } } From a4d37a9830659f796060bdaffc00b031058118b0 Mon Sep 17 00:00:00 2001 From: Claire Bontempo Date: Mon, 3 Jan 2022 09:10:29 -0800 Subject: [PATCH 26/26] remove click event arg --- ui/app/components/clients/horizontal-bar-chart.js | 15 +-------------- 1 file changed, 1 insertion(+), 14 deletions(-) diff --git a/ui/app/components/clients/horizontal-bar-chart.js b/ui/app/components/clients/horizontal-bar-chart.js index 74042a60dcb..a042cddf17a 100644 --- a/ui/app/components/clients/horizontal-bar-chart.js +++ b/ui/app/components/clients/horizontal-bar-chart.js @@ -8,8 +8,6 @@ import { axisLeft } from 'd3-axis'; import { max, maxIndex } from 'd3-array'; import { BAR_COLOR_HOVER, GREY, LIGHT_AND_DARK_BLUE } from '../../utils/chart-helpers'; import { tracked } from '@glimmer/tracking'; -import OidcConsentBlockComponent from '../oidc-consent-block'; -import attachCapabilities from '../../lib/attach-capabilities'; /** * @module HorizontalBarChart @@ -64,7 +62,6 @@ export default class HorizontalBarChart extends Component { // let dataset = SAMPLE_DATA; let stackedData = stackFunction(dataset); let labelKey = this.labelKey; - let handleClick = this.args.onClick; let xScale = scaleLinear() .domain([0, max(dataset.map(d => d.total))]) @@ -152,13 +149,8 @@ export default class HorizontalBarChart extends Component { let compareAttributes = (elementA, elementB, attr) => select(elementA).attr(`${attr}`) === select(elementB).attr(`${attr}`); - // MOUSE AND CLICK EVENTS FOR DATA BARS + // MOUSE EVENTS FOR DATA BARS actionBars - .on('click', function(chartData) { - if (handleClick) { - handleClick(chartData); - } - }) .on('mouseover', data => { let hoveredElement = actionBars.filter(bar => bar.label === data.label).node(); this.tooltipTarget = hoveredElement; @@ -184,11 +176,6 @@ export default class HorizontalBarChart extends Component { // MOUSE EVENTS FOR Y-AXIS LABELS yLegendBars - .on('click', function(chartData) { - if (handleClick) { - handleClick(chartData); - } - }) .on('mouseover', data => { if (data.label.length >= CHAR_LIMIT) { let hoveredElement = yLegendBars.filter(bar => bar.label === data.label).node();