Skip to content
This repository has been archived by the owner on Sep 11, 2024. It is now read-only.

Commit

Permalink
feat(radial-chart): Makes the legend interactable.
Browse files Browse the repository at this point in the history
  • Loading branch information
subarroca authored and lukasholzer committed Oct 13, 2020
1 parent e7c3555 commit 7ee0da1
Show file tree
Hide file tree
Showing 10 changed files with 115 additions and 43 deletions.
88 changes: 62 additions & 26 deletions apps/components-e2e/src/components/radial-chart/radial-chart.e2e.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,21 +16,20 @@

import { resetWindowSizeToDefault, waitForAngular } from '../../utils';
import {
absoluteBtn,
body,
chartTypeDonut,
chartTypePie,
chrome,
edge,
firefox,
nonSelectableBtn,
overlay,
pieChrome,
pieEdge,
pieFirefox,
pieSafari,
percentBtn,
pieSelected,
safari,
selectableBtn,
setSelectBtn,
pieSelected,
nonSelectableBtn,
legendChrome,
percentBtn,
absoluteBtn,
} from './radial-chart.po';

// Reduced speed of hovering should get our e2e tests stable.
Expand All @@ -42,6 +41,8 @@ const hover: MouseActionOptions = {
speed: 0.01,
};
const pathSelectedClassname = 'dt-radial-chart-path-selected';
const legendInactiveClassname = 'dt-radial-chart-legend-item-inactive';
const inactiveColor = /rgb\(248, 248, 248\)/;

fixture('Radial chart')
.page('http://localhost:4200/radial-chart')
Expand All @@ -52,7 +53,7 @@ fixture('Radial chart')

test('should show overlay on hover', async (testController: TestController) => {
await testController
.hover(pieChrome, hover)
.hover(chrome.pie, hover)
.expect(overlay.exists)
.ok()
.expect(overlay.textContent)
Expand All @@ -64,7 +65,7 @@ test('should show overlay on hover', async (testController: TestController) => {

test('should show correct overlays when switching from pie to donut chart and back', async (testController: TestController) => {
await testController
.hover(pieChrome, hover)
.hover(chrome.pie, hover)
.expect(overlay.exists)
.ok()
.click(chartTypeDonut, { speed: 0.3 })
Expand All @@ -77,24 +78,24 @@ test('should show correct overlays when switching from pie to donut chart and ba
.expect(overlay.exists)
.ok()
.click(chartTypePie, { speed: 0.3 })
.hover(pieChrome, hover)
.hover(chrome.pie, hover)
.expect(overlay.exists)
.ok();
});

test('should show correct overlay contents when hovering over pies', async (testController: TestController) => {
await testController
.click(body, { speed: 0.5, offsetX: 0, offsetY: 0 }) // triggering change detection
.hover(pieChrome, hover)
.hover(chrome.pie, hover)
.expect(overlay.textContent)
.match(/Chrome: 43 of 89/)
.hover(pieSafari, hover)
.hover(safari.pie, hover)
.expect(overlay.textContent)
.match(/Safari: 22 of 89/)
.hover(pieFirefox, hover)
.hover(firefox.pie, hover)
.expect(overlay.textContent)
.match(/Firefox: 15 of 89/)
.hover(pieEdge, hover)
.hover(edge.pie, hover)
.expect(overlay.textContent)
.match(/Microsoft Edge: 9 of 89/);
});
Expand All @@ -104,35 +105,70 @@ test('should enable selection and select', async (testController: TestController
// selectable + input
.click(selectableBtn)
.click(setSelectBtn)
.expect(pieChrome.classNames)
.expect(chrome.pie.classNames)
.contains(pathSelectedClassname)
// non selectable
.click(nonSelectableBtn)
.expect(pieSelected.exists)
.notOk()
// selectable + click
.click(selectableBtn)
.click(pieChrome)
.expect(pieChrome.classNames)
.click(chrome.pie)
.expect(chrome.pie.classNames)
.contains(pathSelectedClassname)
// deselect
.click(pieChrome)
.click(chrome.pie)
.expect(pieSelected.exists)
.notOk()
// select other
.click(pieChrome)
.click(pieFirefox)
.expect(pieChrome.classNames)
.click(chrome.pie)
.click(firefox.pie)
.expect(chrome.pie.classNames)
.notContains(pathSelectedClassname)
.expect(pieFirefox.classNames)
.expect(firefox.pie.classNames)
.contains(pathSelectedClassname);
});
test('should show legend with percent and absolute values', async (testController: TestController) => {
await testController
.click(absoluteBtn)
.expect(legendChrome.textContent)
.expect(chrome.legend.textContent)
.match(/43 Chrome/)
.click(percentBtn)
.expect(legendChrome.textContent)
.expect(chrome.legend.textContent)
.match(/48\.3 % Chrome/);
});

test('should fade legend and slice', async (testController: TestController) => {
await testController
.click(chrome.legend)
.expect(chrome.legend.classNames)
.contains(legendInactiveClassname)
.expect(chrome.legendSymbol.getStyleProperty('background-color'))
.match(inactiveColor)
.expect(chrome.piePath.getStyleProperty('fill'))
.match(inactiveColor);
});

test('should keep at least one slice active', async (testController: TestController) => {
await testController
.click(chrome.legend)
.click(firefox.legend)
.click(edge.legend)
.click(safari.legend)
.expect(chrome.legendSymbol.getStyleProperty('background-color'))
.match(inactiveColor)
.expect(chrome.piePath.getStyleProperty('fill'))
.match(inactiveColor)
.expect(firefox.legendSymbol.getStyleProperty('background-color'))
.match(inactiveColor)
.expect(chrome.piePath.getStyleProperty('fill'))
.match(inactiveColor)
.expect(edge.legendSymbol.getStyleProperty('background-color'))
.match(inactiveColor)
.expect(edge.piePath.getStyleProperty('fill'))
.match(inactiveColor)
.expect(safari.legendSymbol.getStyleProperty('background-color'))
.notMatch(inactiveColor)
.expect(safari.piePath.getStyleProperty('fill'))
.notMatch(inactiveColor);
});
28 changes: 16 additions & 12 deletions apps/components-e2e/src/components/radial-chart/radial-chart.po.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,19 +21,23 @@ export const chartTypePie = Selector('#chart-type-pie');
export const chartTypeDonut = Selector('#chart-type-donut');
export const overlay = Selector('.dt-overlay-container');

export const pieChrome = Selector(
'.dt-radial-chart-series-group:nth-of-type(1)',
);
export const pieSafari = Selector(
'.dt-radial-chart-series-group:nth-of-type(2)',
);
export const pieFirefox = Selector(
'.dt-radial-chart-series-group:nth-of-type(3)',
);
export const pieEdge = Selector('.dt-radial-chart-series-group:nth-of-type(4)');
export const pieSelected = Selector('.dt-radial-chart-path-selected');
const getBrowserSelectors = (nth: number) => ({
pie: Selector(`.dt-radial-chart-series-group:nth-of-type(${nth})`),
piePath: Selector(
`.dt-radial-chart-series-group:nth-of-type(${nth}) .dt-radial-chart-series`,
),
legend: Selector(`dt-legend-item:nth-of-type(${nth})`),
legendSymbol: Selector(
`dt-legend-item:nth-of-type(${nth}) .dt-radial-chart-legend-symbol`,
),
});

export const chrome = getBrowserSelectors(1);
export const safari = getBrowserSelectors(2);
export const firefox = getBrowserSelectors(3);
export const edge = getBrowserSelectors(4);

export const legendChrome = Selector('dt-legend-item:nth-of-type(1)');
export const pieSelected = Selector('.dt-radial-chart-path-selected');

// interaction

Expand Down
2 changes: 1 addition & 1 deletion libs/barista-components/overlay/src/overlay-trigger.ts
Original file line number Diff line number Diff line change
Expand Up @@ -167,7 +167,7 @@ export class DtOverlayTrigger<T> extends _DtOverlayTriggerMixin

/** @internal Ensures the trigger is selected when activated from the keyboard. */
_handleKeydown(event: KeyboardEvent): void {
if (!this.disabled) {
if (!this.disabled && this._content) {
const keyCode = _readKeyCode(event);
if (keyCode === ENTER || keyCode === SPACE) {
event.preventDefault();
Expand Down
1 change: 1 addition & 0 deletions libs/barista-components/radial-chart/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ You can specify the position of the radial chart by adjusting the value of the
| `color` | `string` | `DT_CHART_COLOR_PALETTE_ORDERED[i]` | The color in which the series is displayed within the chart. |
| `valueRelative` | `number` | - | Numeric percentage value based on this node vs sum of top level. |
| `selected` | `boolean` | false | Marks series as selected. |
| `active` | `boolean` | true | Marks series as activated through legend. |

#### Outputs

Expand Down
Original file line number Diff line number Diff line change
@@ -1,18 +1,18 @@
<svg:path
class="dt-radial-chart-path dt-radial-chart-series"
[attr.d]="series.path"
[attr.fill]="series.color"
[attr.fill]="color"
[attr.aria-label]="series.ariaLabel"
></svg:path>

<svg:path
class="dt-radial-chart-path dt-radial-chart-path-hover"
[attr.fill]="series.color"
[attr.fill]="color"
[attr.d]="series.hoverPath"
></svg:path>

<svg:path
class="dt-radial-chart-path dt-radial-chart-path-selection"
[attr.fill]="series.color"
[attr.fill]="color"
[attr.d]="series.selectionPath"
></svg:path>
6 changes: 6 additions & 0 deletions libs/barista-components/radial-chart/src/radial-chart-path.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@

import { AfterContentInit, Component, Input, TemplateRef } from '@angular/core';
import { DtOverlayTrigger } from '@dynatrace/barista-components/overlay';
import { DtColors } from '@dynatrace/barista-components/theming';
import { DtRadialChartRenderData } from './utils/radial-chart-interfaces';

export interface DtRadialChartOverlayData {
Expand Down Expand Up @@ -74,4 +75,9 @@ export class DtRadialChartPath
};
}
}

/** @internal Get slice color based on its status */
get color(): string {
return this.series.origin.active ? this.series.color : DtColors.GRAY_100;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,9 @@ export class DtRadialChartSeries implements OnChanges, OnDestroy {
/** Marks series as selected */
@Input() selected: boolean = false;

/** Marks series as active according to legend */
@Input() active: boolean = true;

/** Emits when event is selected. */
@Output() selectedChange = new EventEmitter<boolean>();

Expand Down
6 changes: 5 additions & 1 deletion libs/barista-components/radial-chart/src/radial-chart.html
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,11 @@
></svg:g>
</svg>
<dt-legend class="dt-radial-chart-legend">
<dt-legend-item *ngFor="let series of _renderData">
<dt-legend-item
*ngFor="let series of _renderData"
(click)="_toggleLegend(series)"
[class.dt-radial-chart-legend-item-inactive]="!series.origin.active"
>
<dt-legend-symbol
class="dt-radial-chart-legend-symbol"
[style]="
Expand Down
4 changes: 4 additions & 0 deletions libs/barista-components/radial-chart/src/radial-chart.scss
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,10 @@ text {
background-color: var(--dt-radial-chart-legend-symbol-color);
}

.dt-radial-chart-legend-item-inactive .dt-radial-chart-legend-symbol {
background-color: $gray-100;
}

.dt-radial-chart-wrapper {
display: flex;
}
Expand Down
14 changes: 14 additions & 0 deletions libs/barista-components/radial-chart/src/radial-chart.ts
Original file line number Diff line number Diff line change
Expand Up @@ -377,4 +377,18 @@ export class DtRadialChart implements AfterContentInit, OnDestroy {
series.origin.selectedChange.emit(series.origin.selected);
}
}

/** @internal Toggle the visibility of an element */
_toggleLegend(slice: DtRadialChartRenderData): void {
if (
// Keep at least one element visible at any time
this._renderData.filter((node) => node.origin.active).length > 1 ||
// If all but one are inactive, allow the clicked one to be activated again
!slice.origin.active
) {
slice.origin.active = !slice.origin.active;

this._updateRenderData();
}
}
}

0 comments on commit 7ee0da1

Please sign in to comment.