Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

UI/tooltip #13397

Merged
merged 11 commits into from
Dec 13, 2021
Prev Previous commit
Next Next commit
stuff
Monkeychip committed Dec 10, 2021
commit def7015639bf1d7eadf98388390c8da4d1f7be16
116 changes: 84 additions & 32 deletions ui/app/components/clients/total-client-usage.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
import Component from '@glimmer/component';
import { action } from '@ember/object';
import { tracked } from '@glimmer/tracking';
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';

/**
@@ -21,48 +24,57 @@ import { stack } from 'd3-shape';

// ARG TODO pull in data
const DATA = [
{ month: 'January', directEntities: 500, nonDirectTokens: 22 },
{ month: 'February', directEntities: 150, nonDirectTokens: 22 },
{ month: 'March', directEntities: 155, nonDirectTokens: 25 },
{ month: 'April', directEntities: 155, nonDirectTokens: 229 },
{ month: 'May', directEntities: 156, nonDirectTokens: 24 },
{ month: 'June', directEntities: 157, nonDirectTokens: 42 },
{ month: 'July', directEntities: 158, nonDirectTokens: 12 },
{ month: 'August', directEntities: 161, nonDirectTokens: 1 },
{ month: 'September', directEntities: 190, nonDirectTokens: 222 },
{ month: 'October', directEntities: 250, nonDirectTokens: 66 },
{ month: 'November', directEntities: 300, nonDirectTokens: 32 },
{ month: 'December', directEntities: 600, nonDirectTokens: 202 },
{ month: 'January', directEntities: 5000, nonDirectTokens: 22 },
{ month: 'February', directEntities: 1500, nonDirectTokens: 22 },
{ month: 'March', directEntities: 1550, nonDirectTokens: 25 },
{ month: 'April', directEntities: 1550, nonDirectTokens: 229 },
{ month: 'May', directEntities: 1560, nonDirectTokens: 24 },
{ month: 'June', directEntities: 1570, nonDirectTokens: 42 },
{ month: 'July', directEntities: 1580, nonDirectTokens: 12 },
{ month: 'August', directEntities: 1610, nonDirectTokens: 1 },
{ month: 'September', directEntities: 1900, nonDirectTokens: 222 },
{ month: 'October', directEntities: 2500, nonDirectTokens: 66 },
{ month: 'November', directEntities: 3000, nonDirectTokens: 32 },
{ month: 'December', directEntities: 6000, nonDirectTokens: 202 },
];

// COLOR THEME:
const BAR_COLOR_DEFAULT = ['#1563FF', '#8AB1FF'];
const BACKGROUND_BAR_COLOR = '#EBEEF2';

const CHART_MARGIN = { top: 10, right: 0, bottom: 0, left: 5 }; // makes space for y-axis legend
const LINE_HEIGHT = 30; // each bar w/ padding is 24 pixels thick

export default class TotalClientUsage extends Component {
@tracked tooltipTarget = '#wtf';
@tracked hoveredLabel = 'init';
@tracked trackingTest = 0;
@action
registerListener(element) {
// Define the chart
let chartSvg = select(element);
chartSvg.attr('width', '100%');
chartSvg.attr('height', '100%');
chartSvg.attr('viewBox', `0 0 1000 ${(DATA.length + 1) * LINE_HEIGHT}`);

let stackFunction = stack().keys(['directEntities', 'nonDirectTokens']);
let stackedData = stackFunction(DATA);

let yScale = scaleLinear()
.domain([0, 802]) // TODO calculate high of total combined
.range([100, 0]);
.domain([0, max(stackedData[1].map(d => d.data.directEntities + d.data.nonDirectTokens))]) // TODO will need to recalculate when you get the data
.range([98, 0]);

let xScale = scaleBand()
.domain(DATA.map(month => month.month))
.range([0, 100])
.range([0, 100]) // unsure about this 100 range?
.paddingInner(0.85);
let chartSvg = select(element);
chartSvg.attr('width', '100%');
chartSvg.attr('height', '100%');

let groups = chartSvg
.selectAll('g')
.data(stackedData)
.enter()
.append('g')
.attr('transform', `translate(${CHART_MARGIN.left}})`)
.style('fill', (d, i) => BAR_COLOR_DEFAULT[i]);

groups
@@ -73,19 +85,59 @@ export default class TotalClientUsage extends Component {
.attr('width', `${xScale.bandwidth()}%`)
.attr('height', data => `${100 - yScale(data[1])}%`)
.attr('x', data => `${xScale(data.data.month)}%`)
.attr('y', data => `${yScale(data[0]) + yScale(data[1]) - 100}%`)
// for tooltip
.on('mouseover', data => {
this.hoveredLabel = data.data.month;
let node = groups
.selectAll('rect')
.filter(data => data.data.month === this.hoveredLabel)
.nodes();
this.tooltipTarget = node[1]; // grab the second node from the list of 24 rects
})
.on('mouseout', () => {
this.hoveredLabel = null;
// this.tooltipTarget = null;
});
.attr('y', data => `${yScale(data[0]) + yScale(data[1]) - 102}%`) // subtract higher than 100% to give space for x axis ticks
// shifts chart to accommodate y-axis legend
.attr('transform', `translate(${CHART_MARGIN.left})`);

// creating wider area for tooltip hover
let tooltipRect = chartSvg
.selectAll('.tooltip-rect')
.data(DATA)
.enter()
.append('rect')
.style('cursor', 'pointer')
.attr('class', 'tooltip-rect')
.attr('height', '100%')
.attr('width', '50px') // three times width
.attr('y', '0') // start at bottom
.attr('x', data => `${xScale(data.month) - 1.1}%`) // not data.data because this is not stacked data
.style('fill', `${BACKGROUND_BAR_COLOR}`)
.style('opacity', '1')
.style('mix-blend-mode', 'multiply');

// for tooltip
tooltipRect.on('mouseover', data => {
this.hoveredLabel = data.month;
let node = chartSvg
.selectAll('rect.tooltip-rect')
.filter(data => data.month === this.hoveredLabel)
.node();
this.tooltipTarget = node; // grab the second node from the list of 24 rects
});

// axis lines

let xScaleNotPercent = scaleBand()
.domain(DATA.map(month => month.month))
.range([0, 1200]) //hard coded width because 100 before with percents 0 to width
.paddingInner(0.85);

let yScaleNotPercent = scaleLinear()
.domain([0, max(stackedData[1].map(d => d.data.directEntities + d.data.nonDirectTokens))]) // TODO calculate high of total combined
.range([800, 0]); // height to zero (it's inverted), TODO make 98 as a percent instead of a fixed number

let xAxis = axisBottom(xScaleNotPercent).tickSize(1);
xAxis(chartSvg.append('g').attr('transform', `translate(${CHART_MARGIN.left},375)`));

// Reference for tickFormat https://www.youtube.com/watch?v=c3MCROTNN8g
let yAxisTickFormat = number => format('.1s')(number).replace('G', 'B'); // for billions to replace G with B.

let yAxis = axisLeft(yScaleNotPercent).tickFormat(yAxisTickFormat); // format number as 8k or 8M
yAxis(chartSvg.append('g').attr('transform', `translate(${CHART_MARGIN.left},0)`));
}

// ARG TODO rename
@action closeMe() {
this.tooltipTarget = null;
}
}
24 changes: 14 additions & 10 deletions ui/app/templates/components/clients/total-client-usage.hbs
Original file line number Diff line number Diff line change
@@ -5,7 +5,7 @@
<p class="chart-description" id="blah">{{@description}}</p>
{{/if}}
</div>
<div class="chart-container">
<div class="chart-container" {{on "mouseleave" (fn this.closeMe)}}>
<svg
{{did-insert this.registerListener}}
class="chart"
@@ -32,13 +32,17 @@

{{!-- TOOLTIP --}}
{{!-- must be in curly bracket notation --}}
{{#modal-dialog
tetherTarget=this.tooltipTarget
targetAttachment='top middle'
attachment='bottom middle'
offset='14px 0'
}}
<p class="chart-tooltip">{{this.hoveredLabel}}</p>
<div class="chart-tooltip-arrow" />
{{/modal-dialog}}
{{#if this.tooltipTarget}}
{{!-- Required to set tag name = div https://github.com/yapplabs/ember-modal-dialog/issues/290 --}}
{{#modal-dialog
tagName='div'
tetherTarget=this.tooltipTarget
targetAttachment='bottom middle'
attachment='bottom middle'
offset='100px 0'
}}
<p class="chart-tooltip">{{this.hoveredLabel}}</p>
<div class="chart-tooltip-arrow" />
{{/modal-dialog}}
{{/if}}
</div>
1 change: 1 addition & 0 deletions ui/package.json
Original file line number Diff line number Diff line change
@@ -212,6 +212,7 @@
]
},
"dependencies": {
"d3-format": "^3.1.0",
"faker": "^5.5.3",
"handlebars": "^4.3.0",
"highlight.js": "^10.4.1",
5 changes: 5 additions & 0 deletions ui/yarn.lock
Original file line number Diff line number Diff line change
@@ -8097,6 +8097,11 @@ d3-format@1:
resolved "https://registry.yarnpkg.com/d3-format/-/d3-format-1.4.5.tgz#374f2ba1320e3717eb74a9356c67daee17a7edb4"
integrity sha512-J0piedu6Z8iB6TbIGfZgDzfXxUFN3qQRMofy2oPdXzQibYGqPB/9iMcxr/TGalU+2RsyDO+U4f33id8tbnSRMQ==

d3-format@^3.1.0:
version "3.1.0"
resolved "https://registry.yarnpkg.com/d3-format/-/d3-format-3.1.0.tgz#9260e23a28ea5cb109e93b21a06e24e2ebd55641"
integrity sha512-YyUI6AEuY/Wpt8KWLgZHsIU86atmikuoOmCfommt0LYHiQSPjvX2AcFc38PX0CBpr2RCyZhjex+NS/LPOv6YqA==

d3-geo@1:
version "1.12.1"
resolved "https://registry.yarnpkg.com/d3-geo/-/d3-geo-1.12.1.tgz#7fc2ab7414b72e59fbcbd603e80d9adc029b035f"