diff --git a/ui/app/components/clients/horizontal-bar-charts.js b/ui/app/components/clients/horizontal-bar-charts.js
index 65561d069303..7e191341f627 100644
--- a/ui/app/components/clients/horizontal-bar-charts.js
+++ b/ui/app/components/clients/horizontal-bar-charts.js
@@ -1,6 +1,5 @@
import Component from '@glimmer/component';
import { action } from '@ember/object';
-import { assert } from '@ember/debug';
import { stack } from 'd3-shape';
// eslint-disable-next-line no-unused-vars
import { select, event, selectAll } from 'd3-selection';
@@ -17,7 +16,7 @@ import { max, maxIndex } from 'd3-array';
*
* ```
* @param {object} dataset - dataset for the chart
- * @param {array} chartLegend - array of objects with key names 'key' and 'label' for the map legend
+ * @param {array} chartLegend - array of objects with key names 'key' and 'label' for the chart legend
* @param {string} [labelKey=label] - labelKey is the key name in the dataset passed in that corresponds to the value labeling the y-axis (i.e. 'namespace_path')
* @param {string} [param1=defaultValue] - param1 is...
*/
@@ -27,6 +26,7 @@ import { max, maxIndex } from 'd3-array';
// SIZING CONSTANTS
const CHART_MARGIN = { top: 10, left: 137 }; // makes space for y-axis legend
+const TRANSLATE = { down: 16 };
const CHAR_LIMIT = 18; // character count limit for y-axis labels to trigger truncating
const LINE_HEIGHT = 24; // each bar w/ padding is 24 pixels thick
@@ -103,28 +103,13 @@ export default class HorizontalBarChart extends Component {
}
get chartLegend() {
- assert(
- 'chart legend is required, must be an array of objects with key names of "key" and "label"',
- this.hasLegend()
- );
return this.args.chartLegend;
}
- // TODO: use maxIndex function when packages are updated
get topNamespace() {
- console.log(this.args.dataset[maxIndex(this.args.dataset, d => d.total)]);
return this.args.dataset[maxIndex(this.args.dataset, d => d.total)];
}
- hasLegend() {
- if (!this.args.chartLegend || !Array.isArray(this.args.chartLegend)) {
- return false;
- } else {
- let legendKeys = this.args.chartLegend.map(obj => Object.keys(obj));
- return legendKeys.map(array => array.includes('key', 'label')).every(element => element === true);
- }
- }
-
@action
renderChart(element, args) {
// chart legend tells stackFunction how to stack/organize data
@@ -134,6 +119,7 @@ export default class HorizontalBarChart extends Component {
let dataset = args[0];
let stackedData = stackFunction(dataset);
let labelKey = this.labelKey;
+ let handleClick = this.args.onClick;
let xScale = scaleLinear()
.domain([0, max(dataset.map(d => d.total))])
@@ -161,13 +147,14 @@ export default class HorizontalBarChart extends Component {
let yAxis = axisLeft(yScale).tickSize(0);
yAxis(chartSvg.append('g').attr('transform', `translate(${CHART_MARGIN.left}, ${CHART_MARGIN.top})`));
+ chartSvg.select('.domain').remove();
+
let truncate = selection =>
selection.text(string =>
string.length < CHAR_LIMIT ? string : string.slice(0, CHAR_LIMIT - 3) + '...'
);
chartSvg.selectAll('.tick text').call(truncate);
- chartSvg.select('.domain').remove();
groups
.selectAll('rect')
@@ -184,23 +171,147 @@ export default class HorizontalBarChart extends Component {
.attr('rx', 3)
.attr('ry', 3);
- let startingXCoordinate = 100 - this.chartLegend.length * 20;
- let legendSvg = select('.legend');
- this.chartLegend.map((legend, i) => {
- let xCoordinate = startingXCoordinate + i * 20;
- legendSvg
- .append('circle')
- .attr('cx', `${xCoordinate}%`)
- .attr('cy', '50%')
- .attr('r', 6)
- .style('fill', `${BAR_COLOR_DEFAULT[i]}`);
- legendSvg
- .append('text')
- .attr('x', `${xCoordinate + 2}%`)
- .attr('y', '50%')
- .text(`${legend.label}`)
- .style('font-size', '.8rem')
- .attr('alignment-baseline', 'middle');
- });
+ let actionBars = chartSvg
+ .selectAll('.action-bar')
+ .data(dataset)
+ .enter()
+ .append('rect')
+ .style('cursor', 'pointer')
+ .attr('class', 'action-bar')
+ .attr('width', '100%')
+ .attr('height', `${LINE_HEIGHT}px`)
+ .attr('x', '0')
+ .attr('y', chartData => yScale(chartData[labelKey]))
+ .style('fill', `${BACKGROUND_BAR_COLOR}`)
+ .style('opacity', '0')
+ .style('mix-blend-mode', 'multiply');
+
+ let yLegendBars = chartSvg
+ .selectAll('.label-bar')
+ .data(dataset)
+ .enter()
+ .append('rect')
+ .style('cursor', 'pointer')
+ .attr('class', 'label-action-bar')
+ .attr('width', CHART_MARGIN.left)
+ .attr('height', `${LINE_HEIGHT}px`)
+ .attr('x', '0')
+ .attr('y', chartData => yScale(chartData[labelKey]))
+ .style('opacity', '0')
+ .style('mix-blend-mode', 'multiply');
+
+ 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}`);
+
+ // MOUSE AND CLICK EVENTS FOR DATA BARS
+ actionBars
+ .on('click', function(chartData) {
+ if (handleClick) {
+ handleClick(chartData);
+ }
+ })
+ .on('mouseover', function() {
+ select(this).style('opacity', 1);
+ dataBars
+ .filter(function() {
+ return compareAttributes(this, event.target, '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) => `${BAR_COLOR_DEFAULT[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) / totalCount)}% 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) => `${BAR_COLOR_DEFAULT[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);
+ }
+ });
+
+ // add client count total values to the right
+ chartSvg
+ .append('g')
+ .attr('transform', `translate(${CHART_MARGIN.left}, ${TRANSLATE.down})`)
+ .selectAll('text')
+ .data(dataset)
+ .enter()
+ .append('text')
+ .text(d => d.total)
+ .attr('fill', '#000')
+ .attr('class', 'total-value')
+ .style('font-size', '.8rem')
+ .attr('text-anchor', 'start')
+ .attr('alignment-baseline', 'middle')
+ .attr('x', chartData => `${xScale(chartData.total)}%`)
+ .attr('y', chartData => yScale(chartData.label));
}
}
diff --git a/ui/app/styles/components/horizontal-bar-charts.scss b/ui/app/styles/components/horizontal-bar-charts.scss
deleted file mode 100644
index 0ff97574b84c..000000000000
--- a/ui/app/styles/components/horizontal-bar-charts.scss
+++ /dev/null
@@ -1,8 +0,0 @@
-// TODO: combine into main chart css file and delete/unimport this file
-div.horizontal-bar-chart {
- > div.legend {
- height: $spacing-l;
- margin-top: $spacing-xs;
- float: right;
- }
-}
diff --git a/ui/app/styles/core.scss b/ui/app/styles/core.scss
index 40f4209dec4c..6ec797e43dda 100644
--- a/ui/app/styles/core.scss
+++ b/ui/app/styles/core.scss
@@ -60,7 +60,6 @@
@import './components/features-selection';
@import './components/form-section';
@import './components/global-flash';
-@import './components/horizontal-bar-charts';
@import './components/hover-copy-button';
@import './components/init-illustration';
@import './components/info-table';
diff --git a/ui/app/styles/core/charts.scss b/ui/app/styles/core/charts.scss
index 4d9a5de9215d..960170255fb7 100644
--- a/ui/app/styles/core/charts.scss
+++ b/ui/app/styles/core/charts.scss
@@ -36,12 +36,13 @@
line-height: normal;
margin-bottom: $spacing-xs;
}
- .chart-description {
- font-size: $size-8;
- font-weight: $font-weight-normal;
- color: $ui-gray-700;
- margin-bottom: $spacing-xs;
- }
+}
+
+p.chart-description {
+ font-size: $size-8;
+ font-weight: $font-weight-normal;
+ color: $ui-gray-700;
+ margin-bottom: $spacing-xs;
}
.has-export {
@@ -74,27 +75,41 @@
}
}
-.chart-column-left {
+.chart-container-left {
grid-column-start: 1;
grid-column-end: 4;
grid-row-start: 2;
grid-row-end: 5;
- h2.title {
+ box-shadow: inset 0 -1px 0 $vault-gray-200;
+
+ h2.chart-title {
font-size: $size-5;
font-weight: $font-weight-bold;
- margin-bottom: $spacing-l;
}
}
-.chart-column-right {
+.chart-container-right {
grid-column-start: 4;
grid-column-end: 8;
grid-row-start: 2;
grid-row-end: 5;
- h2.title {
+ box-shadow: inset 0 -1px 0 $vault-gray-200;
+
+ h2.chart-title {
font-size: $size-5;
font-weight: $font-weight-bold;
- margin-bottom: $spacing-l;
+ }
+}
+
+.horizontal-bar-chart {
+ .tick > text {
+ font-weight: $font-weight-semibold;
+ font-size: $size-8;
+ }
+ > div.legend {
+ height: $spacing-l;
+ margin-top: $spacing-xs;
+ float: right;
}
}
@@ -141,22 +156,40 @@
}
}
-.legend-container-center {
+.timestamp {
+ grid-column-start: 1;
+ grid-column-end: 2;
+ grid-row-start: 5;
+ color: $ui-gray-500;
+ font-size: $size-9;
+ align-self: end;
+}
+
+.light-dot {
+ background-color: #bfd4ff;
+ height: 10px;
+ width: 10px;
+ border-radius: 50%;
+ display: inline-block;
+ padding-right: 10px;
+}
+
+.dark-dot {
+ background-color: #1563ff;
+ height: 10px;
+ width: 10px;
+ border-radius: 50%;
+ display: inline-block;
+}
+
+.legend-container {
grid-row-start: 5;
grid-column-start: 3;
grid-column-end: 4;
height: $spacing-l;
align-self: center;
justify-self: center;
-}
-
-.legend-container-right {
- grid-row-start: 5;
- grid-column-start: 5;
- grid-column-end: 6;
- height: $spacing-l;
- align-self: start;
- justify-self: start;
+ font-size: $size-9;
}
.chart-tooltip {
diff --git a/ui/app/templates/components/clients/dashboard.hbs b/ui/app/templates/components/clients/dashboard.hbs
index 59f9f063e82e..ec5d327747ac 100644
--- a/ui/app/templates/components/clients/dashboard.hbs
+++ b/ui/app/templates/components/clients/dashboard.hbs
@@ -136,27 +136,29 @@
{{!-- ARG TODO end of part that goes to Running Client --}}
{{#if this.showGraphs}}
{{!-- ARG TODO chart playground --}}
-
-
+
-
- Export attribution data
-
+
+ Export attribution data
+
{{!-- ARG TODO this is the search select from the old graph that can be reused --}}
{{!--
diff --git a/ui/app/templates/components/clients/horizontal-bar-charts.hbs b/ui/app/templates/components/clients/horizontal-bar-charts.hbs
index 2ac8d2894f6a..6898fc7d1b3a 100644
--- a/ui/app/templates/components/clients/horizontal-bar-charts.hbs
+++ b/ui/app/templates/components/clients/horizontal-bar-charts.hbs
@@ -13,25 +13,32 @@
-
-
New Clients
+
+
New Clients
+
{{@newClientsDescription}}
-
-
Total monthly clients
+
+
Total monthly clients
+
{{@totalDescription}}
-
- LEGEND
- {{!--
--}}
+
+ Updated Nov 15 2021, 4:07:32 pm
+
+
+
+ {{!-- TO DO - fix styling --}}
+
{{@chartLegend.0.label}}
+
{{@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 97ed43eacee9..f245f0a609e4 100644
--- a/ui/app/templates/components/clients/total-client-usage.hbs
+++ b/ui/app/templates/components/clients/total-client-usage.hbs
@@ -23,6 +23,10 @@
{{@dataTwoData}}
+
+ Updated Nov 15 2021, 4:07:32 pm
+
+
legend
{{!-- --}}