UI/bar chart horizontal (#12437)
* creates bar chart component * WIP//starts styling * fixes width of bars * WIP//barchart * uses d3 max method instead of Math.max * stacks data * adds y axis * fixes styling and spacing * adds spacing between bars * styling DONE * adds legend * adds tooltip * tweaks styling adds pointer cursor to rects * fixes tooltip placement * moves starget from bar to whole area * finishes hover selection styling * cleans up * cleans up a tiny bit * stopping point * adjusts tooltip placemnt * WIP//clean up time * sort of not broken * unbroken, ish * tooltip position fixed * truncates text and adds tooltip * changes tooltip width depending on content * unbroken * finishes initial refactor/cleanup * finishes documentation * passes in map legend to component * more tidying * add export option * adds grid to header for export button option * updates comments * fix variable name change * moves dataset formatting to parent * removes unused code" * adds assertions and empty state if no data * cleans up comments adds assertion to check for map legend * adds storybook * adds changelog * deletes dummy parent: * restores index.hbs * uses scss variables instead * exchanges more variables * remove unused variable in storybook * writes basic test * removes pauseTest()
This commit is contained in:
parent
b4b61efc75
commit
c9eb55cc16
|
@ -0,0 +1,3 @@
|
||||||
|
```release-note:feature
|
||||||
|
ui: creates bar chart component for displaying client count data by namespace
|
||||||
|
```
|
|
@ -0,0 +1,68 @@
|
||||||
|
.bar-chart-wrapper {
|
||||||
|
border: $light-border;
|
||||||
|
border-radius: $radius-large;
|
||||||
|
padding: $spacing-l $spacing-l $spacing-s $spacing-l;
|
||||||
|
height: 100%;
|
||||||
|
width: 100%;
|
||||||
|
|
||||||
|
> div.is-border {
|
||||||
|
border: 0.3px solid $ui-gray-200;
|
||||||
|
width: 94%;
|
||||||
|
margin-left: 3%;
|
||||||
|
margin-bottom: $spacing-xxs;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.chart-header {
|
||||||
|
margin-left: $spacing-l;
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 3fr 1fr;
|
||||||
|
|
||||||
|
.header-left {
|
||||||
|
.chart-title {
|
||||||
|
font-size: $size-5;
|
||||||
|
font-weight: $font-weight-bold;
|
||||||
|
line-height: normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
.chart-description {
|
||||||
|
font-size: $size-8;
|
||||||
|
font-weight: $font-weight-normal;
|
||||||
|
color: $ui-gray-700;
|
||||||
|
margin-bottom: $spacing-xs;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.header-right {
|
||||||
|
text-align: center;
|
||||||
|
|
||||||
|
> button {
|
||||||
|
font-size: $size-8;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.bar-chart-container {
|
||||||
|
padding: $spacing-m $spacing-l $spacing-m $spacing-l;
|
||||||
|
}
|
||||||
|
|
||||||
|
.bar-chart {
|
||||||
|
.tick > text {
|
||||||
|
font-weight: $font-weight-semibold;
|
||||||
|
font-size: $size-8;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.legend-container {
|
||||||
|
height: $spacing-l;
|
||||||
|
margin-top: $spacing-xs;
|
||||||
|
}
|
||||||
|
|
||||||
|
.legend {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
}
|
|
@ -45,6 +45,7 @@
|
||||||
@import './components/auth-buttons';
|
@import './components/auth-buttons';
|
||||||
@import './components/auth-form';
|
@import './components/auth-form';
|
||||||
@import './components/b64-toggle';
|
@import './components/b64-toggle';
|
||||||
|
@import './components/bar-chart';
|
||||||
@import './components/box-label';
|
@import './components/box-label';
|
||||||
@import './components/box-radio';
|
@import './components/box-radio';
|
||||||
@import './components/codemirror';
|
@import './components/codemirror';
|
||||||
|
|
|
@ -0,0 +1,327 @@
|
||||||
|
/**
|
||||||
|
* @module BarChart
|
||||||
|
* BarChart components are used to display data in the form of a stacked bar chart, with accompanying legend and tooltip. Anything passed into the block will display in the top right of the chart header.
|
||||||
|
*
|
||||||
|
* @example
|
||||||
|
* ```js
|
||||||
|
* <BarChartComponent @title="Top 10 Namespaces" @description="Each namespace's client count includes clients in child namespaces." @labelKey="namespace_path" @dataset={{this.testData}} @mapLegend={{ array (hash key="non_entity_tokens" label="Active direct tokens") (hash key="distinct_entities" label="Unique Entities") }} @onClick={{this.onClick}} >
|
||||||
|
* <button type="button" class="link">
|
||||||
|
* Export all namespace data
|
||||||
|
* </button>/>
|
||||||
|
* </BarChartComponent>
|
||||||
|
*
|
||||||
|
* mapLegendSample = [{
|
||||||
|
* key: "api_key_for_label",
|
||||||
|
* label: "Label Displayed on Legend"
|
||||||
|
* }]
|
||||||
|
* ```
|
||||||
|
*
|
||||||
|
* @param {string} title - title of the chart
|
||||||
|
* @param {array} mapLegend - array of objects with key names 'key' and 'label' for the map legend
|
||||||
|
* @param {object} dataset - dataset for the chart
|
||||||
|
* @param {string} [description] - description of the chart
|
||||||
|
* @param {string} [labelKey=label] - labelKey is the key name in the dataset passed in that corresponds to the value labeling the y-axis
|
||||||
|
* @param {function} [onClick] - takes function from parent and passes it to click event on data bars
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
import Component from '@glimmer/component';
|
||||||
|
import layout from '../templates/components/bar-chart';
|
||||||
|
import { setComponentTemplate } from '@ember/component';
|
||||||
|
import { assert } from '@ember/debug';
|
||||||
|
import { action } from '@ember/object';
|
||||||
|
import { guidFor } from '@ember/object/internals';
|
||||||
|
import { scaleLinear, scaleBand } from 'd3-scale';
|
||||||
|
import { axisLeft } from 'd3-axis';
|
||||||
|
import { max } from 'd3-array';
|
||||||
|
import { stack } from 'd3-shape';
|
||||||
|
// eslint-disable-next-line no-unused-vars
|
||||||
|
import { select, event, selectAll } from 'd3-selection';
|
||||||
|
// eslint-disable-next-line no-unused-vars
|
||||||
|
import { transition } from 'd3-transition';
|
||||||
|
|
||||||
|
// SIZING CONSTANTS
|
||||||
|
const CHART_MARGIN = { top: 10, left: 137 }; // makes space for y-axis legend
|
||||||
|
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
|
||||||
|
|
||||||
|
// COLOR THEME:
|
||||||
|
const BAR_COLOR_DEFAULT = ['#BFD4FF', '#8AB1FF'];
|
||||||
|
const BAR_COLOR_HOVER = ['#1563FF', '#0F4FD1'];
|
||||||
|
const BACKGROUND_BAR_COLOR = '#EBEEF2';
|
||||||
|
const TOOLTIP_BACKGROUND = '#525761';
|
||||||
|
|
||||||
|
class BarChartComponent extends Component {
|
||||||
|
get labelKey() {
|
||||||
|
return this.args.labelKey || 'label';
|
||||||
|
}
|
||||||
|
|
||||||
|
get mapLegend() {
|
||||||
|
assert(
|
||||||
|
'map legend is required, must be an array of objects with key names of "key" and "label"',
|
||||||
|
this.hasLegend()
|
||||||
|
);
|
||||||
|
return this.args.mapLegend;
|
||||||
|
}
|
||||||
|
|
||||||
|
get dataset() {
|
||||||
|
return this.args.dataset || null;
|
||||||
|
}
|
||||||
|
|
||||||
|
hasLegend() {
|
||||||
|
if (!this.args.mapLegend || !Array.isArray(this.args.mapLegend)) {
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
let legendKeys = this.args.mapLegend.map(obj => Object.keys(obj));
|
||||||
|
return legendKeys.map(array => array.includes('key', 'label')).every(element => element === true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@action
|
||||||
|
renderBarChart(element) {
|
||||||
|
let elementId = guidFor(element);
|
||||||
|
let totalCount = this.dataset.reduce((prevValue, currValue) => prevValue + currValue.total, 0);
|
||||||
|
let handleClick = this.args.onClick;
|
||||||
|
let labelKey = this.labelKey;
|
||||||
|
let dataset = this.dataset;
|
||||||
|
let stackFunction = stack().keys(this.mapLegend.map(l => l.key));
|
||||||
|
// creates an array of data for each map legend key
|
||||||
|
// each array contains coordinates for each data bar
|
||||||
|
let stackedData = stackFunction(dataset);
|
||||||
|
|
||||||
|
// creates and appends tooltip
|
||||||
|
let container = select('.bar-chart-container');
|
||||||
|
container
|
||||||
|
.append('div')
|
||||||
|
.attr('class', 'chart-tooltip')
|
||||||
|
.attr('style', 'position: fixed; opacity: 0;')
|
||||||
|
.style('color', 'white')
|
||||||
|
.style('background', `${TOOLTIP_BACKGROUND}`)
|
||||||
|
.style('font-size', '.929rem')
|
||||||
|
.style('padding', '10px')
|
||||||
|
.style('border-radius', '4px');
|
||||||
|
|
||||||
|
let xScale = scaleLinear()
|
||||||
|
.domain([0, max(dataset.map(d => d.total))])
|
||||||
|
.range([0, 75]); // 25% reserved for margins
|
||||||
|
|
||||||
|
let yScale = scaleBand()
|
||||||
|
.domain(dataset.map(d => d[labelKey]))
|
||||||
|
.range([0, dataset.length * LINE_HEIGHT])
|
||||||
|
.paddingInner(0.765); // percent of the total width to reserve for padding between bars
|
||||||
|
|
||||||
|
let chartSvg = select(element);
|
||||||
|
chartSvg.attr('viewBox', `0 0 710 ${(dataset.length + 1) * LINE_HEIGHT}`);
|
||||||
|
chartSvg.attr('id', elementId);
|
||||||
|
|
||||||
|
// creates group for each array of stackedData
|
||||||
|
let groups = chartSvg
|
||||||
|
.selectAll('g')
|
||||||
|
.data(stackedData)
|
||||||
|
.enter()
|
||||||
|
.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]);
|
||||||
|
|
||||||
|
let yAxis = axisLeft(yScale);
|
||||||
|
yAxis(groups.append('g'));
|
||||||
|
|
||||||
|
let truncate = selection =>
|
||||||
|
selection.text(string =>
|
||||||
|
string.length < CHAR_LIMIT ? string : string.slice(0, CHAR_LIMIT - 3) + '...'
|
||||||
|
);
|
||||||
|
|
||||||
|
chartSvg.selectAll('.tick text').call(truncate);
|
||||||
|
|
||||||
|
let rects = groups
|
||||||
|
.selectAll('rect')
|
||||||
|
.data(d => d)
|
||||||
|
.enter()
|
||||||
|
.append('rect')
|
||||||
|
.attr('class', 'data-bar')
|
||||||
|
.style('cursor', 'pointer')
|
||||||
|
.attr('width', chartData => `${xScale(chartData[1] - chartData[0] - 5)}%`)
|
||||||
|
.attr('height', yScale.bandwidth())
|
||||||
|
.attr('x', chartData => `${xScale(chartData[0])}%`)
|
||||||
|
.attr('y', ({ data }) => yScale(data[labelKey]))
|
||||||
|
.attr('rx', 3)
|
||||||
|
.attr('ry', 3);
|
||||||
|
|
||||||
|
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}`);
|
||||||
|
|
||||||
|
// handles click and mouseover/out/move event 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]}`);
|
||||||
|
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 - 90}px`)
|
||||||
|
.style('top', `${event.pageY - 90}px`)
|
||||||
|
.text(
|
||||||
|
`${Math.round((chartData.total * 100) / totalCount)}% of total client counts:
|
||||||
|
${chartData.distinct_entities} unique entities, ${chartData.non_entity_tokens} active tokens.
|
||||||
|
`
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
// handles mouseover/out/move event for y-axis legend
|
||||||
|
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 - 100}px`)
|
||||||
|
.style('top', `${event.pageY - 50}px`)
|
||||||
|
.text(`${chartData.label}`)
|
||||||
|
.style('max-width', 'fit-content');
|
||||||
|
} else {
|
||||||
|
select('.chart-tooltip').style('opacity', 0);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// TODO: these render twice, need to only render and append once per line
|
||||||
|
// creates total count text and coordinates to display to the right of data bars
|
||||||
|
let totalCountData = [];
|
||||||
|
rects.each(function(d) {
|
||||||
|
let textDatum = {
|
||||||
|
total: d.data.total,
|
||||||
|
x: parseFloat(select(this).attr('width')) + parseFloat(select(this).attr('x')),
|
||||||
|
y: parseFloat(select(this).attr('y')) + parseFloat(select(this).attr('height')),
|
||||||
|
};
|
||||||
|
totalCountData.push(textDatum);
|
||||||
|
});
|
||||||
|
|
||||||
|
groups
|
||||||
|
.selectAll('text')
|
||||||
|
.data(totalCountData)
|
||||||
|
.enter()
|
||||||
|
.append('text')
|
||||||
|
.text(d => d.total)
|
||||||
|
.attr('fill', '#000')
|
||||||
|
.attr('class', 'total-value')
|
||||||
|
.style('font-size', '.8rem')
|
||||||
|
.attr('text-anchor', 'start')
|
||||||
|
.attr('y', d => `${d.y}`)
|
||||||
|
.attr('x', d => `${d.x + 1}%`);
|
||||||
|
|
||||||
|
// removes axes lines
|
||||||
|
groups.selectAll('.domain, .tick line').remove();
|
||||||
|
|
||||||
|
// TODO: make more flexible, make legend a div instead of svg?
|
||||||
|
// each map key symbol & label takes up 20% of legend SVG width
|
||||||
|
let startingXCoordinate = 100 - this.mapLegend.length * 20; // subtract from 100% to find starting x-coordinate
|
||||||
|
let legendSvg = select('.legend');
|
||||||
|
this.mapLegend.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');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default setComponentTemplate(layout, BarChartComponent);
|
|
@ -0,0 +1,28 @@
|
||||||
|
<div class="bar-chart-wrapper">
|
||||||
|
<div class="chart-header">
|
||||||
|
<div class="header-left">
|
||||||
|
<h2 class="chart-title">{{@title}}</h2>
|
||||||
|
{{#if @description}}
|
||||||
|
<p class="chart-description">{{@description}}</p>
|
||||||
|
{{/if}}
|
||||||
|
</div>
|
||||||
|
<div class="header-right">
|
||||||
|
{{#if this.dataset}}
|
||||||
|
{{yield}}
|
||||||
|
{{/if}}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{{#unless this.dataset}}
|
||||||
|
<div class="toolbar"></div>
|
||||||
|
<EmptyState @title="No namespace data" @message="There is no data to display for namespaces."/>
|
||||||
|
{{else}}
|
||||||
|
<div class="is-border"></div>
|
||||||
|
<div class="bar-chart-container">
|
||||||
|
<svg {{did-insert this.renderBarChart}} class="bar-chart"></svg>
|
||||||
|
</div>
|
||||||
|
<div class="is-border"></div>
|
||||||
|
<div class="legend-container">
|
||||||
|
<svg class="legend"></svg>
|
||||||
|
</div>
|
||||||
|
{{/unless}}
|
||||||
|
</div>
|
|
@ -0,0 +1 @@
|
||||||
|
export { default } from 'core/components/bar-chart';
|
|
@ -0,0 +1,37 @@
|
||||||
|
<!--THIS FILE IS AUTO GENERATED. This file is generated from JSDoc comments in lib/core/addon/components/bar-chart.js. To make changes, first edit that file and run "yarn gen-story-md bar-chart" to re-generate the content.-->
|
||||||
|
|
||||||
|
## BarChart
|
||||||
|
BarChart components are used to display data in the form of a stacked bar chart, with accompanying legend and tooltip. Anything passed into the block will display in the top right of the chart header.
|
||||||
|
|
||||||
|
**Params**
|
||||||
|
|
||||||
|
| Param | Type | Default | Description |
|
||||||
|
| --- | --- | --- | --- |
|
||||||
|
| title | <code>string</code> | | title of the chart |
|
||||||
|
| mapLegend | <code>array</code> | | array of objects with key names 'key' and 'label' for the map legend |
|
||||||
|
| dataset | <code>object</code> | | dataset for the chart |
|
||||||
|
| [description] | <code>string</code> | | description of the chart |
|
||||||
|
| [labelKey] | <code>string</code> | <code>"label"</code> | labelKey is the key name in the dataset passed in that corresponds to the value labeling the y-axis |
|
||||||
|
| [onClick] | <code>function</code> | | takes function from parent and passes it to click event on data bars |
|
||||||
|
|
||||||
|
**Example**
|
||||||
|
|
||||||
|
```js
|
||||||
|
<BarChartComponent @title="Top 10 Namespaces" @description="Each namespace's client count includes clients in child namespaces." @labelKey="namespace_path" @dataset={{this.testData}} @mapLegend={{ array (hash key="non_entity_tokens" label="Active direct tokens") (hash key="distinct_entities" label="Unique Entities") }} @onClick={{this.onClick}} >
|
||||||
|
<button type="button" class="link">
|
||||||
|
Export all namespace data
|
||||||
|
</button>/>
|
||||||
|
</BarChartComponent>
|
||||||
|
|
||||||
|
mapLegendSample = [{
|
||||||
|
key: "api_key_for_label",
|
||||||
|
label: "Label Displayed on Legend"
|
||||||
|
}]
|
||||||
|
```
|
||||||
|
|
||||||
|
**See**
|
||||||
|
|
||||||
|
- [Uses of BarChart](https://github.com/hashicorp/vault/search?l=Handlebars&q=BarChart+OR+bar-chart)
|
||||||
|
- [BarChart Source Code](https://github.com/hashicorp/vault/blob/master/ui/lib/core/addon/components/bar-chart.js)
|
||||||
|
|
||||||
|
---
|
|
@ -0,0 +1,99 @@
|
||||||
|
import hbs from 'htmlbars-inline-precompile';
|
||||||
|
import { storiesOf } from '@storybook/ember';
|
||||||
|
import { object, text, withKnobs } from '@storybook/addon-knobs';
|
||||||
|
import notes from './bar-chart.md';
|
||||||
|
|
||||||
|
const dataset = [
|
||||||
|
{
|
||||||
|
namespace_id: 'root',
|
||||||
|
namespace_path: 'root',
|
||||||
|
counts: {
|
||||||
|
distinct_entities: 268,
|
||||||
|
non_entity_tokens: 985,
|
||||||
|
clients: 1253,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
namespace_id: 'O0i4m',
|
||||||
|
namespace_path: 'top-namespace',
|
||||||
|
counts: {
|
||||||
|
distinct_entities: 648,
|
||||||
|
non_entity_tokens: 220,
|
||||||
|
clients: 868,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
namespace_id: '1oihz',
|
||||||
|
namespace_path: 'anotherNamespace',
|
||||||
|
counts: {
|
||||||
|
distinct_entities: 547,
|
||||||
|
non_entity_tokens: 337,
|
||||||
|
clients: 884,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
namespace_id: '1oihz',
|
||||||
|
namespace_path: 'someOtherNamespaceawgagawegawgawgawgaweg',
|
||||||
|
counts: {
|
||||||
|
distinct_entities: 807,
|
||||||
|
non_entity_tokens: 234,
|
||||||
|
clients: 1041,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
const flattenData = () => {
|
||||||
|
return dataset.map(d => {
|
||||||
|
return {
|
||||||
|
label: d['namespace_path'],
|
||||||
|
non_entity_tokens: d['counts']['non_entity_tokens'],
|
||||||
|
distinct_entities: d['counts']['distinct_entities'],
|
||||||
|
total: d['counts']['clients'],
|
||||||
|
};
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
storiesOf('BarChart', module)
|
||||||
|
.addParameters({ options: { showPanel: true } })
|
||||||
|
.addDecorator(withKnobs())
|
||||||
|
.add(
|
||||||
|
`BarChart`,
|
||||||
|
() => ({
|
||||||
|
template: hbs`
|
||||||
|
<h5 class="title is-5">Bar Chart</h5>
|
||||||
|
|
||||||
|
<p> <code>dataset</code> is passed to a function in the parent to format it appropriately for the chart. Any data passed should be flattened (not nested).</p>
|
||||||
|
<p> The legend typically displays within the bar chart border, below the second grey divider. There is also a tooltip that pops up when hovering over the data bars and overflowing labels. Gotta love storybook :) </p>
|
||||||
|
<div class="chart-container" style="margin-top:24px; max-width:750px; max-height:500px;" >
|
||||||
|
<BarChart
|
||||||
|
@title={{title}}
|
||||||
|
@description={{description}}
|
||||||
|
@dataset={{dataset}}
|
||||||
|
@mapLegend={{array
|
||||||
|
(hash key="non_entity_tokens" label="Active direct tokens")
|
||||||
|
(hash key="distinct_entities" label="Unique Entities")}}
|
||||||
|
>
|
||||||
|
<button type="button" class="link">
|
||||||
|
Export all namespace data
|
||||||
|
</button>
|
||||||
|
</BarChart>
|
||||||
|
<br>
|
||||||
|
<h6 class="title is-6">Legend:</h6>
|
||||||
|
<svg class="legend">
|
||||||
|
<circle cx="60%" cy="10%" r="6" style="fill: rgb(191, 212, 255);"></circle>
|
||||||
|
<text x="62%" y="10%" alignment-baseline="middle" style="font-size: 0.8rem;">Active direct tokens</text>
|
||||||
|
<circle cx="80%" cy="10%" r="6" style="fill: rgb(138, 177, 255);"></circle>
|
||||||
|
<text x="82%" y="10%" alignment-baseline="middle" style="font-size: 0.8rem;">Unique Entities</text></svg>
|
||||||
|
</div>
|
||||||
|
`,
|
||||||
|
context: {
|
||||||
|
title: text('title', 'Top Namespaces'),
|
||||||
|
description: text(
|
||||||
|
'description',
|
||||||
|
'Each namespaces client count includes clients in child namespaces.'
|
||||||
|
),
|
||||||
|
dataset: object('dataset', flattenData()),
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
{ notes }
|
||||||
|
);
|
|
@ -97,6 +97,7 @@
|
||||||
"ember-concurrency-test-waiter": "^0.3.2",
|
"ember-concurrency-test-waiter": "^0.3.2",
|
||||||
"ember-copy": "^1.0.0",
|
"ember-copy": "^1.0.0",
|
||||||
"ember-cp-validations": "^4.0.0-beta.12",
|
"ember-cp-validations": "^4.0.0-beta.12",
|
||||||
|
"ember-d3": "^0.5.1",
|
||||||
"ember-data": "~3.22.0",
|
"ember-data": "~3.22.0",
|
||||||
"ember-data-model-fragments": "5.0.0-beta.0",
|
"ember-data-model-fragments": "5.0.0-beta.0",
|
||||||
"ember-engines": "^0.8.3",
|
"ember-engines": "^0.8.3",
|
||||||
|
|
|
@ -0,0 +1,81 @@
|
||||||
|
import { module, test } from 'qunit';
|
||||||
|
import { setupRenderingTest } from 'ember-qunit';
|
||||||
|
import { render } from '@ember/test-helpers';
|
||||||
|
import { hbs } from 'ember-cli-htmlbars';
|
||||||
|
|
||||||
|
module('Integration | Component | bar-chart', function(hooks) {
|
||||||
|
setupRenderingTest(hooks);
|
||||||
|
|
||||||
|
test('it renders', async function(assert) {
|
||||||
|
let dataset = [
|
||||||
|
{
|
||||||
|
namespace_id: 'root',
|
||||||
|
namespace_path: 'root',
|
||||||
|
counts: {
|
||||||
|
distinct_entities: 268,
|
||||||
|
non_entity_tokens: 985,
|
||||||
|
clients: 1253,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
namespace_id: 'O0i4m',
|
||||||
|
namespace_path: 'top-namespace',
|
||||||
|
counts: {
|
||||||
|
distinct_entities: 648,
|
||||||
|
non_entity_tokens: 220,
|
||||||
|
clients: 868,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
namespace_id: '1oihz',
|
||||||
|
namespace_path: 'anotherNamespace',
|
||||||
|
counts: {
|
||||||
|
distinct_entities: 547,
|
||||||
|
non_entity_tokens: 337,
|
||||||
|
clients: 884,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
namespace_id: '1oihz',
|
||||||
|
namespace_path: 'someOtherNamespaceawgagawegawgawgawgaweg',
|
||||||
|
counts: {
|
||||||
|
distinct_entities: 807,
|
||||||
|
non_entity_tokens: 234,
|
||||||
|
clients: 1041,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
let flattenData = () => {
|
||||||
|
return dataset.map(d => {
|
||||||
|
return {
|
||||||
|
label: d['namespace_path'],
|
||||||
|
non_entity_tokens: d['counts']['non_entity_tokens'],
|
||||||
|
distinct_entities: d['counts']['distinct_entities'],
|
||||||
|
total: d['counts']['clients'],
|
||||||
|
};
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
this.set('title', 'Top Namespaces');
|
||||||
|
this.set('description', 'Each namespaces client count includes clients in child namespaces.');
|
||||||
|
this.set('dataset', flattenData());
|
||||||
|
|
||||||
|
await render(hbs`
|
||||||
|
<BarChart
|
||||||
|
@title={{title}}
|
||||||
|
@description={{description}}
|
||||||
|
@dataset={{dataset}}
|
||||||
|
@mapLegend={{array
|
||||||
|
(hash key="non_entity_tokens" label="Active direct tokens")
|
||||||
|
(hash key="distinct_entities" label="Unique Entities")}}
|
||||||
|
>
|
||||||
|
<button type="button" class="link">
|
||||||
|
Export all namespace data
|
||||||
|
</button>
|
||||||
|
</BarChart>
|
||||||
|
`);
|
||||||
|
|
||||||
|
assert.dom('.bar-chart-wrapper').exists('it renders');
|
||||||
|
});
|
||||||
|
});
|
216
ui/yarn.lock
216
ui/yarn.lock
|
@ -6288,6 +6288,11 @@ command-line-usage@^4.1.0:
|
||||||
table-layout "^0.4.2"
|
table-layout "^0.4.2"
|
||||||
typical "^2.6.1"
|
typical "^2.6.1"
|
||||||
|
|
||||||
|
commander@2, commander@^2.15.1, commander@^2.20.0, commander@^2.6.0:
|
||||||
|
version "2.20.3"
|
||||||
|
resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33"
|
||||||
|
integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==
|
||||||
|
|
||||||
commander@2.8.x:
|
commander@2.8.x:
|
||||||
version "2.8.1"
|
version "2.8.1"
|
||||||
resolved "https://registry.yarnpkg.com/commander/-/commander-2.8.1.tgz#06be367febfda0c330aa1e2a072d3dc9762425d4"
|
resolved "https://registry.yarnpkg.com/commander/-/commander-2.8.1.tgz#06be367febfda0c330aa1e2a072d3dc9762425d4"
|
||||||
|
@ -6300,11 +6305,6 @@ commander@7.1.0:
|
||||||
resolved "https://registry.yarnpkg.com/commander/-/commander-7.1.0.tgz#f2eaecf131f10e36e07d894698226e36ae0eb5ff"
|
resolved "https://registry.yarnpkg.com/commander/-/commander-7.1.0.tgz#f2eaecf131f10e36e07d894698226e36ae0eb5ff"
|
||||||
integrity sha512-pRxBna3MJe6HKnBGsDyMv8ETbptw3axEdYHoqNh7gu5oDcew8fs0xnivZGm06Ogk8zGAJ9VX+OPEr2GXEQK4dg==
|
integrity sha512-pRxBna3MJe6HKnBGsDyMv8ETbptw3axEdYHoqNh7gu5oDcew8fs0xnivZGm06Ogk8zGAJ9VX+OPEr2GXEQK4dg==
|
||||||
|
|
||||||
commander@^2.15.1, commander@^2.20.0, commander@^2.6.0:
|
|
||||||
version "2.20.3"
|
|
||||||
resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33"
|
|
||||||
integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==
|
|
||||||
|
|
||||||
commander@^4.1.1:
|
commander@^4.1.1:
|
||||||
version "4.1.1"
|
version "4.1.1"
|
||||||
resolved "https://registry.yarnpkg.com/commander/-/commander-4.1.1.tgz#9fd602bd936294e9e9ef46a3f4d6964044b18068"
|
resolved "https://registry.yarnpkg.com/commander/-/commander-4.1.1.tgz#9fd602bd936294e9e9ef46a3f4d6964044b18068"
|
||||||
|
@ -6853,16 +6853,35 @@ cyclist@^1.0.1:
|
||||||
resolved "https://registry.yarnpkg.com/cyclist/-/cyclist-1.0.1.tgz#596e9698fd0c80e12038c2b82d6eb1b35b6224d9"
|
resolved "https://registry.yarnpkg.com/cyclist/-/cyclist-1.0.1.tgz#596e9698fd0c80e12038c2b82d6eb1b35b6224d9"
|
||||||
integrity sha1-WW6WmP0MgOEgOMK4LW6xs1tiJNk=
|
integrity sha1-WW6WmP0MgOEgOMK4LW6xs1tiJNk=
|
||||||
|
|
||||||
d3-array@^1.2.0:
|
d3-array@1, d3-array@^1.1.1, d3-array@^1.2.0:
|
||||||
version "1.2.4"
|
version "1.2.4"
|
||||||
resolved "https://registry.yarnpkg.com/d3-array/-/d3-array-1.2.4.tgz#635ce4d5eea759f6f605863dbcfc30edc737f71f"
|
resolved "https://registry.yarnpkg.com/d3-array/-/d3-array-1.2.4.tgz#635ce4d5eea759f6f605863dbcfc30edc737f71f"
|
||||||
integrity sha512-KHW6M86R+FUPYGb3R5XiYjXPq7VzwxZ22buHhAEVG5ztoEcZZMLov530mmccaqA1GghZArjQV46fuc8kUqhhHw==
|
integrity sha512-KHW6M86R+FUPYGb3R5XiYjXPq7VzwxZ22buHhAEVG5ztoEcZZMLov530mmccaqA1GghZArjQV46fuc8kUqhhHw==
|
||||||
|
|
||||||
d3-axis@^1.0.8:
|
d3-axis@1, d3-axis@^1.0.8:
|
||||||
version "1.0.12"
|
version "1.0.12"
|
||||||
resolved "https://registry.yarnpkg.com/d3-axis/-/d3-axis-1.0.12.tgz#cdf20ba210cfbb43795af33756886fb3638daac9"
|
resolved "https://registry.yarnpkg.com/d3-axis/-/d3-axis-1.0.12.tgz#cdf20ba210cfbb43795af33756886fb3638daac9"
|
||||||
integrity sha512-ejINPfPSNdGFKEOAtnBtdkpr24c4d4jsei6Lg98mxf424ivoDP2956/5HDpIAtmHo85lqT4pruy+zEgvRUBqaQ==
|
integrity sha512-ejINPfPSNdGFKEOAtnBtdkpr24c4d4jsei6Lg98mxf424ivoDP2956/5HDpIAtmHo85lqT4pruy+zEgvRUBqaQ==
|
||||||
|
|
||||||
|
d3-brush@1:
|
||||||
|
version "1.1.6"
|
||||||
|
resolved "https://registry.yarnpkg.com/d3-brush/-/d3-brush-1.1.6.tgz#b0a22c7372cabec128bdddf9bddc058592f89e9b"
|
||||||
|
integrity sha512-7RW+w7HfMCPyZLifTz/UnJmI5kdkXtpCbombUSs8xniAyo0vIbrDzDwUJB6eJOgl9u5DQOt2TQlYumxzD1SvYA==
|
||||||
|
dependencies:
|
||||||
|
d3-dispatch "1"
|
||||||
|
d3-drag "1"
|
||||||
|
d3-interpolate "1"
|
||||||
|
d3-selection "1"
|
||||||
|
d3-transition "1"
|
||||||
|
|
||||||
|
d3-chord@1:
|
||||||
|
version "1.0.6"
|
||||||
|
resolved "https://registry.yarnpkg.com/d3-chord/-/d3-chord-1.0.6.tgz#309157e3f2db2c752f0280fedd35f2067ccbb15f"
|
||||||
|
integrity sha512-JXA2Dro1Fxw9rJe33Uv+Ckr5IrAa74TlfDEhE/jfLOaXegMQFQTAgAw9WnZL8+HxVBRXaRGCkrNU7pJeylRIuA==
|
||||||
|
dependencies:
|
||||||
|
d3-array "1"
|
||||||
|
d3-path "1"
|
||||||
|
|
||||||
d3-collection@1, d3-collection@^1.0.4:
|
d3-collection@1, d3-collection@^1.0.4:
|
||||||
version "1.0.7"
|
version "1.0.7"
|
||||||
resolved "https://registry.yarnpkg.com/d3-collection/-/d3-collection-1.0.7.tgz#349bd2aa9977db071091c13144d5e4f16b5b310e"
|
resolved "https://registry.yarnpkg.com/d3-collection/-/d3-collection-1.0.7.tgz#349bd2aa9977db071091c13144d5e4f16b5b310e"
|
||||||
|
@ -6873,21 +6892,74 @@ d3-color@1:
|
||||||
resolved "https://registry.yarnpkg.com/d3-color/-/d3-color-1.4.1.tgz#c52002bf8846ada4424d55d97982fef26eb3bc8a"
|
resolved "https://registry.yarnpkg.com/d3-color/-/d3-color-1.4.1.tgz#c52002bf8846ada4424d55d97982fef26eb3bc8a"
|
||||||
integrity sha512-p2sTHSLCJI2QKunbGb7ocOh7DgTAn8IrLx21QRc/BSnodXM4sv6aLQlnfpvehFMLZEfBc6g9pH9SWQccFYfJ9Q==
|
integrity sha512-p2sTHSLCJI2QKunbGb7ocOh7DgTAn8IrLx21QRc/BSnodXM4sv6aLQlnfpvehFMLZEfBc6g9pH9SWQccFYfJ9Q==
|
||||||
|
|
||||||
|
d3-contour@1:
|
||||||
|
version "1.3.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/d3-contour/-/d3-contour-1.3.2.tgz#652aacd500d2264cb3423cee10db69f6f59bead3"
|
||||||
|
integrity sha512-hoPp4K/rJCu0ladiH6zmJUEz6+u3lgR+GSm/QdM2BBvDraU39Vr7YdDCicJcxP1z8i9B/2dJLgDC1NcvlF8WCg==
|
||||||
|
dependencies:
|
||||||
|
d3-array "^1.1.1"
|
||||||
|
|
||||||
d3-dispatch@1:
|
d3-dispatch@1:
|
||||||
version "1.0.6"
|
version "1.0.6"
|
||||||
resolved "https://registry.yarnpkg.com/d3-dispatch/-/d3-dispatch-1.0.6.tgz#00d37bcee4dd8cd97729dd893a0ac29caaba5d58"
|
resolved "https://registry.yarnpkg.com/d3-dispatch/-/d3-dispatch-1.0.6.tgz#00d37bcee4dd8cd97729dd893a0ac29caaba5d58"
|
||||||
integrity sha512-fVjoElzjhCEy+Hbn8KygnmMS7Or0a9sI2UzGwoB7cCtvI1XpVN9GpoYlnb3xt2YV66oXYb1fLJ8GMvP4hdU1RA==
|
integrity sha512-fVjoElzjhCEy+Hbn8KygnmMS7Or0a9sI2UzGwoB7cCtvI1XpVN9GpoYlnb3xt2YV66oXYb1fLJ8GMvP4hdU1RA==
|
||||||
|
|
||||||
|
d3-drag@1:
|
||||||
|
version "1.2.5"
|
||||||
|
resolved "https://registry.yarnpkg.com/d3-drag/-/d3-drag-1.2.5.tgz#2537f451acd39d31406677b7dc77c82f7d988f70"
|
||||||
|
integrity sha512-rD1ohlkKQwMZYkQlYVCrSFxsWPzI97+W+PaEIBNTMxRuxz9RF0Hi5nJWHGVJ3Om9d2fRTe1yOBINJyy/ahV95w==
|
||||||
|
dependencies:
|
||||||
|
d3-dispatch "1"
|
||||||
|
d3-selection "1"
|
||||||
|
|
||||||
|
d3-dsv@1:
|
||||||
|
version "1.2.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/d3-dsv/-/d3-dsv-1.2.0.tgz#9d5f75c3a5f8abd611f74d3f5847b0d4338b885c"
|
||||||
|
integrity sha512-9yVlqvZcSOMhCYzniHE7EVUws7Fa1zgw+/EAV2BxJoG3ME19V6BQFBwI855XQDsxyOuG7NibqRMTtiF/Qup46g==
|
||||||
|
dependencies:
|
||||||
|
commander "2"
|
||||||
|
iconv-lite "0.4"
|
||||||
|
rw "1"
|
||||||
|
|
||||||
d3-ease@1, d3-ease@^1.0.5:
|
d3-ease@1, d3-ease@^1.0.5:
|
||||||
version "1.0.7"
|
version "1.0.7"
|
||||||
resolved "https://registry.yarnpkg.com/d3-ease/-/d3-ease-1.0.7.tgz#9a834890ef8b8ae8c558b2fe55bd57f5993b85e2"
|
resolved "https://registry.yarnpkg.com/d3-ease/-/d3-ease-1.0.7.tgz#9a834890ef8b8ae8c558b2fe55bd57f5993b85e2"
|
||||||
integrity sha512-lx14ZPYkhNx0s/2HX5sLFUI3mbasHjSSpwO/KaaNACweVwxUruKyWVcb293wMv1RqTPZyZ8kSZ2NogUZNcLOFQ==
|
integrity sha512-lx14ZPYkhNx0s/2HX5sLFUI3mbasHjSSpwO/KaaNACweVwxUruKyWVcb293wMv1RqTPZyZ8kSZ2NogUZNcLOFQ==
|
||||||
|
|
||||||
|
d3-fetch@1:
|
||||||
|
version "1.2.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/d3-fetch/-/d3-fetch-1.2.0.tgz#15ce2ecfc41b092b1db50abd2c552c2316cf7fc7"
|
||||||
|
integrity sha512-yC78NBVcd2zFAyR/HnUiBS7Lf6inSCoWcSxFfw8FYL7ydiqe80SazNwoffcqOfs95XaLo7yebsmQqDKSsXUtvA==
|
||||||
|
dependencies:
|
||||||
|
d3-dsv "1"
|
||||||
|
|
||||||
|
d3-force@1:
|
||||||
|
version "1.2.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/d3-force/-/d3-force-1.2.1.tgz#fd29a5d1ff181c9e7f0669e4bd72bdb0e914ec0b"
|
||||||
|
integrity sha512-HHvehyaiUlVo5CxBJ0yF/xny4xoaxFxDnBXNvNcfW9adORGZfyNF1dj6DGLKyk4Yh3brP/1h3rnDzdIAwL08zg==
|
||||||
|
dependencies:
|
||||||
|
d3-collection "1"
|
||||||
|
d3-dispatch "1"
|
||||||
|
d3-quadtree "1"
|
||||||
|
d3-timer "1"
|
||||||
|
|
||||||
d3-format@1:
|
d3-format@1:
|
||||||
version "1.4.5"
|
version "1.4.5"
|
||||||
resolved "https://registry.yarnpkg.com/d3-format/-/d3-format-1.4.5.tgz#374f2ba1320e3717eb74a9356c67daee17a7edb4"
|
resolved "https://registry.yarnpkg.com/d3-format/-/d3-format-1.4.5.tgz#374f2ba1320e3717eb74a9356c67daee17a7edb4"
|
||||||
integrity sha512-J0piedu6Z8iB6TbIGfZgDzfXxUFN3qQRMofy2oPdXzQibYGqPB/9iMcxr/TGalU+2RsyDO+U4f33id8tbnSRMQ==
|
integrity sha512-J0piedu6Z8iB6TbIGfZgDzfXxUFN3qQRMofy2oPdXzQibYGqPB/9iMcxr/TGalU+2RsyDO+U4f33id8tbnSRMQ==
|
||||||
|
|
||||||
|
d3-geo@1:
|
||||||
|
version "1.12.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/d3-geo/-/d3-geo-1.12.1.tgz#7fc2ab7414b72e59fbcbd603e80d9adc029b035f"
|
||||||
|
integrity sha512-XG4d1c/UJSEX9NfU02KwBL6BYPj8YKHxgBEw5om2ZnTRSbIcego6dhHwcxuSR3clxh0EpE38os1DVPOmnYtTPg==
|
||||||
|
dependencies:
|
||||||
|
d3-array "1"
|
||||||
|
|
||||||
|
d3-hierarchy@1:
|
||||||
|
version "1.1.9"
|
||||||
|
resolved "https://registry.yarnpkg.com/d3-hierarchy/-/d3-hierarchy-1.1.9.tgz#2f6bee24caaea43f8dc37545fa01628559647a83"
|
||||||
|
integrity sha512-j8tPxlqh1srJHAtxfvOUwKNYJkQuBFdM1+JAUfq6xqH5eAqf93L7oG1NVqDa4CpFZNvnNKtCYEUC8KY9yEn9lQ==
|
||||||
|
|
||||||
d3-interpolate@1:
|
d3-interpolate@1:
|
||||||
version "1.4.0"
|
version "1.4.0"
|
||||||
resolved "https://registry.yarnpkg.com/d3-interpolate/-/d3-interpolate-1.4.0.tgz#526e79e2d80daa383f9e0c1c1c7dcc0f0583e987"
|
resolved "https://registry.yarnpkg.com/d3-interpolate/-/d3-interpolate-1.4.0.tgz#526e79e2d80daa383f9e0c1c1c7dcc0f0583e987"
|
||||||
|
@ -6895,6 +6967,46 @@ d3-interpolate@1:
|
||||||
dependencies:
|
dependencies:
|
||||||
d3-color "1"
|
d3-color "1"
|
||||||
|
|
||||||
|
d3-path@1:
|
||||||
|
version "1.0.9"
|
||||||
|
resolved "https://registry.yarnpkg.com/d3-path/-/d3-path-1.0.9.tgz#48c050bb1fe8c262493a8caf5524e3e9591701cf"
|
||||||
|
integrity sha512-VLaYcn81dtHVTjEHd8B+pbe9yHWpXKZUC87PzoFmsFrJqgFwDe/qxfp5MlfsfM1V5E/iVt0MmEbWQ7FVIXh/bg==
|
||||||
|
|
||||||
|
d3-polygon@1:
|
||||||
|
version "1.0.6"
|
||||||
|
resolved "https://registry.yarnpkg.com/d3-polygon/-/d3-polygon-1.0.6.tgz#0bf8cb8180a6dc107f518ddf7975e12abbfbd38e"
|
||||||
|
integrity sha512-k+RF7WvI08PC8reEoXa/w2nSg5AUMTi+peBD9cmFc+0ixHfbs4QmxxkarVal1IkVkgxVuk9JSHhJURHiyHKAuQ==
|
||||||
|
|
||||||
|
d3-quadtree@1:
|
||||||
|
version "1.0.7"
|
||||||
|
resolved "https://registry.yarnpkg.com/d3-quadtree/-/d3-quadtree-1.0.7.tgz#ca8b84df7bb53763fe3c2f24bd435137f4e53135"
|
||||||
|
integrity sha512-RKPAeXnkC59IDGD0Wu5mANy0Q2V28L+fNe65pOCXVdVuTJS3WPKaJlFHer32Rbh9gIo9qMuJXio8ra4+YmIymA==
|
||||||
|
|
||||||
|
d3-random@1:
|
||||||
|
version "1.1.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/d3-random/-/d3-random-1.1.2.tgz#2833be7c124360bf9e2d3fd4f33847cfe6cab291"
|
||||||
|
integrity sha512-6AK5BNpIFqP+cx/sreKzNjWbwZQCSUatxq+pPRmFIQaWuoD+NrbVWw7YWpHiXpCQ/NanKdtGDuB+VQcZDaEmYQ==
|
||||||
|
|
||||||
|
d3-scale-chromatic@1:
|
||||||
|
version "1.5.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/d3-scale-chromatic/-/d3-scale-chromatic-1.5.0.tgz#54e333fc78212f439b14641fb55801dd81135a98"
|
||||||
|
integrity sha512-ACcL46DYImpRFMBcpk9HhtIyC7bTBR4fNOPxwVSl0LfulDAwyiHyPOTqcDG1+t5d4P9W7t/2NAuWu59aKko/cg==
|
||||||
|
dependencies:
|
||||||
|
d3-color "1"
|
||||||
|
d3-interpolate "1"
|
||||||
|
|
||||||
|
d3-scale@2:
|
||||||
|
version "2.2.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/d3-scale/-/d3-scale-2.2.2.tgz#4e880e0b2745acaaddd3ede26a9e908a9e17b81f"
|
||||||
|
integrity sha512-LbeEvGgIb8UMcAa0EATLNX0lelKWGYDQiPdHj+gLblGVhGLyNbaCn3EvrJf0A3Y/uOOU5aD6MTh5ZFCdEwGiCw==
|
||||||
|
dependencies:
|
||||||
|
d3-array "^1.2.0"
|
||||||
|
d3-collection "1"
|
||||||
|
d3-format "1"
|
||||||
|
d3-interpolate "1"
|
||||||
|
d3-time "1"
|
||||||
|
d3-time-format "2"
|
||||||
|
|
||||||
d3-scale@^1.0.7:
|
d3-scale@^1.0.7:
|
||||||
version "1.0.7"
|
version "1.0.7"
|
||||||
resolved "https://registry.yarnpkg.com/d3-scale/-/d3-scale-1.0.7.tgz#fa90324b3ea8a776422bd0472afab0b252a0945d"
|
resolved "https://registry.yarnpkg.com/d3-scale/-/d3-scale-1.0.7.tgz#fa90324b3ea8a776422bd0472afab0b252a0945d"
|
||||||
|
@ -6908,11 +7020,26 @@ d3-scale@^1.0.7:
|
||||||
d3-time "1"
|
d3-time "1"
|
||||||
d3-time-format "2"
|
d3-time-format "2"
|
||||||
|
|
||||||
d3-selection@^1.1.0, d3-selection@^1.3.0:
|
d3-selection-multi@^1.0.1:
|
||||||
|
version "1.0.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/d3-selection-multi/-/d3-selection-multi-1.0.1.tgz#cd6c25413d04a2cb97470e786f2cd877f3e34f58"
|
||||||
|
integrity sha1-zWwlQT0EosuXRw54byzYd/PjT1g=
|
||||||
|
dependencies:
|
||||||
|
d3-selection "1"
|
||||||
|
d3-transition "1"
|
||||||
|
|
||||||
|
d3-selection@1, d3-selection@^1.1.0, d3-selection@^1.3.0:
|
||||||
version "1.4.2"
|
version "1.4.2"
|
||||||
resolved "https://registry.yarnpkg.com/d3-selection/-/d3-selection-1.4.2.tgz#dcaa49522c0dbf32d6c1858afc26b6094555bc5c"
|
resolved "https://registry.yarnpkg.com/d3-selection/-/d3-selection-1.4.2.tgz#dcaa49522c0dbf32d6c1858afc26b6094555bc5c"
|
||||||
integrity sha512-SJ0BqYihzOjDnnlfyeHT0e30k0K1+5sR3d5fNueCNeuhZTnGw4M4o8mqJchSwgKMXCNFo+e2VTChiSJ0vYtXkg==
|
integrity sha512-SJ0BqYihzOjDnnlfyeHT0e30k0K1+5sR3d5fNueCNeuhZTnGw4M4o8mqJchSwgKMXCNFo+e2VTChiSJ0vYtXkg==
|
||||||
|
|
||||||
|
d3-shape@1:
|
||||||
|
version "1.3.7"
|
||||||
|
resolved "https://registry.yarnpkg.com/d3-shape/-/d3-shape-1.3.7.tgz#df63801be07bc986bc54f63789b4fe502992b5d7"
|
||||||
|
integrity sha512-EUkvKjqPFUAZyOlhY5gzCxCeI0Aep04LwIRpsZ/mLFelJiUfnK56jo5JMDSE7yyP2kLSb6LtF+S5chMk7uqPqw==
|
||||||
|
dependencies:
|
||||||
|
d3-path "1"
|
||||||
|
|
||||||
d3-time-format@2, d3-time-format@^2.1.1:
|
d3-time-format@2, d3-time-format@^2.1.1:
|
||||||
version "2.3.0"
|
version "2.3.0"
|
||||||
resolved "https://registry.yarnpkg.com/d3-time-format/-/d3-time-format-2.3.0.tgz#107bdc028667788a8924ba040faf1fbccd5a7850"
|
resolved "https://registry.yarnpkg.com/d3-time-format/-/d3-time-format-2.3.0.tgz#107bdc028667788a8924ba040faf1fbccd5a7850"
|
||||||
|
@ -6938,7 +7065,7 @@ d3-tip@^0.9.1:
|
||||||
d3-collection "^1.0.4"
|
d3-collection "^1.0.4"
|
||||||
d3-selection "^1.3.0"
|
d3-selection "^1.3.0"
|
||||||
|
|
||||||
d3-transition@^1.2.0:
|
d3-transition@1, d3-transition@^1.2.0:
|
||||||
version "1.3.2"
|
version "1.3.2"
|
||||||
resolved "https://registry.yarnpkg.com/d3-transition/-/d3-transition-1.3.2.tgz#a98ef2151be8d8600543434c1ca80140ae23b398"
|
resolved "https://registry.yarnpkg.com/d3-transition/-/d3-transition-1.3.2.tgz#a98ef2151be8d8600543434c1ca80140ae23b398"
|
||||||
integrity sha512-sc0gRU4PFqZ47lPVHloMn9tlPcv8jxgOQg+0zjhfZXMQuvppjG6YuwdMBE0TuqCZjeJkLecku/l9R0JPcRhaDA==
|
integrity sha512-sc0gRU4PFqZ47lPVHloMn9tlPcv8jxgOQg+0zjhfZXMQuvppjG6YuwdMBE0TuqCZjeJkLecku/l9R0JPcRhaDA==
|
||||||
|
@ -6950,6 +7077,59 @@ d3-transition@^1.2.0:
|
||||||
d3-selection "^1.1.0"
|
d3-selection "^1.1.0"
|
||||||
d3-timer "1"
|
d3-timer "1"
|
||||||
|
|
||||||
|
d3-voronoi@1:
|
||||||
|
version "1.1.4"
|
||||||
|
resolved "https://registry.yarnpkg.com/d3-voronoi/-/d3-voronoi-1.1.4.tgz#dd3c78d7653d2bb359284ae478645d95944c8297"
|
||||||
|
integrity sha512-dArJ32hchFsrQ8uMiTBLq256MpnZjeuBtdHpaDlYuQyjU0CVzCJl/BVW+SkszaAeH95D/8gxqAhgx0ouAWAfRg==
|
||||||
|
|
||||||
|
d3-zoom@1:
|
||||||
|
version "1.8.3"
|
||||||
|
resolved "https://registry.yarnpkg.com/d3-zoom/-/d3-zoom-1.8.3.tgz#b6a3dbe738c7763121cd05b8a7795ffe17f4fc0a"
|
||||||
|
integrity sha512-VoLXTK4wvy1a0JpH2Il+F2CiOhVu7VRXWF5M/LroMIh3/zBAC3WAt7QoIvPibOavVo20hN6/37vwAsdBejLyKQ==
|
||||||
|
dependencies:
|
||||||
|
d3-dispatch "1"
|
||||||
|
d3-drag "1"
|
||||||
|
d3-interpolate "1"
|
||||||
|
d3-selection "1"
|
||||||
|
d3-transition "1"
|
||||||
|
|
||||||
|
d3@^5.0.0:
|
||||||
|
version "5.16.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/d3/-/d3-5.16.0.tgz#9c5e8d3b56403c79d4ed42fbd62f6113f199c877"
|
||||||
|
integrity sha512-4PL5hHaHwX4m7Zr1UapXW23apo6pexCgdetdJ5kTmADpG/7T9Gkxw0M0tf/pjoB63ezCCm0u5UaFYy2aMt0Mcw==
|
||||||
|
dependencies:
|
||||||
|
d3-array "1"
|
||||||
|
d3-axis "1"
|
||||||
|
d3-brush "1"
|
||||||
|
d3-chord "1"
|
||||||
|
d3-collection "1"
|
||||||
|
d3-color "1"
|
||||||
|
d3-contour "1"
|
||||||
|
d3-dispatch "1"
|
||||||
|
d3-drag "1"
|
||||||
|
d3-dsv "1"
|
||||||
|
d3-ease "1"
|
||||||
|
d3-fetch "1"
|
||||||
|
d3-force "1"
|
||||||
|
d3-format "1"
|
||||||
|
d3-geo "1"
|
||||||
|
d3-hierarchy "1"
|
||||||
|
d3-interpolate "1"
|
||||||
|
d3-path "1"
|
||||||
|
d3-polygon "1"
|
||||||
|
d3-quadtree "1"
|
||||||
|
d3-random "1"
|
||||||
|
d3-scale "2"
|
||||||
|
d3-scale-chromatic "1"
|
||||||
|
d3-selection "1"
|
||||||
|
d3-shape "1"
|
||||||
|
d3-time "1"
|
||||||
|
d3-time-format "2"
|
||||||
|
d3-timer "1"
|
||||||
|
d3-transition "1"
|
||||||
|
d3-voronoi "1"
|
||||||
|
d3-zoom "1"
|
||||||
|
|
||||||
dag-map@^2.0.2:
|
dag-map@^2.0.2:
|
||||||
version "2.0.2"
|
version "2.0.2"
|
||||||
resolved "https://registry.yarnpkg.com/dag-map/-/dag-map-2.0.2.tgz#9714b472de82a1843de2fba9b6876938cab44c68"
|
resolved "https://registry.yarnpkg.com/dag-map/-/dag-map-2.0.2.tgz#9714b472de82a1843de2fba9b6876938cab44c68"
|
||||||
|
@ -8252,6 +8432,17 @@ ember-cp-validations@^4.0.0-beta.12:
|
||||||
ember-require-module "^0.3.0"
|
ember-require-module "^0.3.0"
|
||||||
ember-validators "^3.0.1"
|
ember-validators "^3.0.1"
|
||||||
|
|
||||||
|
ember-d3@^0.5.1:
|
||||||
|
version "0.5.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/ember-d3/-/ember-d3-0.5.1.tgz#b23ce145863f082b5e73d25d9a43a0f1d9e9f412"
|
||||||
|
integrity sha512-NyjTUuIOxGxZdyrxLasNwwjqyFgay1pVHGRAWFj7mriwTI44muKsM9ZMl6YeepqixceuFig2fDxHmLLrkQV+QQ==
|
||||||
|
dependencies:
|
||||||
|
broccoli-funnel "^2.0.0"
|
||||||
|
broccoli-merge-trees "^3.0.0"
|
||||||
|
d3 "^5.0.0"
|
||||||
|
d3-selection-multi "^1.0.1"
|
||||||
|
ember-cli-babel "^7.1.2"
|
||||||
|
|
||||||
ember-data-model-fragments@5.0.0-beta.0:
|
ember-data-model-fragments@5.0.0-beta.0:
|
||||||
version "5.0.0-beta.0"
|
version "5.0.0-beta.0"
|
||||||
resolved "https://registry.yarnpkg.com/ember-data-model-fragments/-/ember-data-model-fragments-5.0.0-beta.0.tgz#da90799970317ca852f96b2ea1548ca70094a5bb"
|
resolved "https://registry.yarnpkg.com/ember-data-model-fragments/-/ember-data-model-fragments-5.0.0-beta.0.tgz#da90799970317ca852f96b2ea1548ca70094a5bb"
|
||||||
|
@ -11075,7 +11266,7 @@ human-signals@^1.1.1:
|
||||||
resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-1.1.1.tgz#c5b1cd14f50aeae09ab6c59fe63ba3395fe4dfa3"
|
resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-1.1.1.tgz#c5b1cd14f50aeae09ab6c59fe63ba3395fe4dfa3"
|
||||||
integrity sha512-SEQu7vl8KjNL2eoGBLF3+wAjpsNfA9XMlXAYj/3EdaNfAlxKthD1xjEQfGOUhllCGGJVNY34bRr6lPINhNjyZw==
|
integrity sha512-SEQu7vl8KjNL2eoGBLF3+wAjpsNfA9XMlXAYj/3EdaNfAlxKthD1xjEQfGOUhllCGGJVNY34bRr6lPINhNjyZw==
|
||||||
|
|
||||||
iconv-lite@0.4.24, iconv-lite@^0.4.24:
|
iconv-lite@0.4, iconv-lite@0.4.24, iconv-lite@^0.4.24:
|
||||||
version "0.4.24"
|
version "0.4.24"
|
||||||
resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b"
|
resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b"
|
||||||
integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==
|
integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==
|
||||||
|
@ -15938,6 +16129,11 @@ run-queue@^1.0.0, run-queue@^1.0.3:
|
||||||
dependencies:
|
dependencies:
|
||||||
aproba "^1.1.1"
|
aproba "^1.1.1"
|
||||||
|
|
||||||
|
rw@1:
|
||||||
|
version "1.3.3"
|
||||||
|
resolved "https://registry.yarnpkg.com/rw/-/rw-1.3.3.tgz#3f862dfa91ab766b14885ef4d01124bfda074fb4"
|
||||||
|
integrity sha1-P4Yt+pGrdmsUiF700BEkv9oHT7Q=
|
||||||
|
|
||||||
rxjs@^6.4.0, rxjs@^6.5.2, rxjs@^6.6.0, rxjs@^6.6.7:
|
rxjs@^6.4.0, rxjs@^6.5.2, rxjs@^6.6.0, rxjs@^6.6.7:
|
||||||
version "6.6.7"
|
version "6.6.7"
|
||||||
resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-6.6.7.tgz#90ac018acabf491bf65044235d5863c4dab804c9"
|
resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-6.6.7.tgz#90ac018acabf491bf65044235d5863c4dab804c9"
|
||||||
|
|
Loading…
Reference in New Issue