@redvars/peacock 3.3.1 → 3.3.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{IndividualComponent-tDnXrOLV.js → IndividualComponent-Dt5xirYG.js} +2 -2
- package/dist/{IndividualComponent-tDnXrOLV.js.map → IndividualComponent-Dt5xirYG.js.map} +1 -1
- package/dist/array-D5vjT2Xm.js +14 -0
- package/dist/array-D5vjT2Xm.js.map +1 -0
- package/dist/{button-trIfcqC7.js → button-ClzS8JLq.js} +3 -3
- package/dist/{button-trIfcqC7.js.map → button-ClzS8JLq.js.map} +1 -1
- package/dist/{button-group-DA7xoziD.js → button-group-BMS5WvaF.js} +4 -4
- package/dist/{button-group-DA7xoziD.js.map → button-group-BMS5WvaF.js.map} +1 -1
- package/dist/button-group.js +4 -4
- package/dist/button.js +3 -3
- package/dist/card.js +104 -0
- package/dist/card.js.map +1 -0
- package/dist/chart-bar-DbnXQgvS.js +1121 -0
- package/dist/chart-bar-DbnXQgvS.js.map +1 -0
- package/dist/chart-bar.js +259 -0
- package/dist/chart-bar.js.map +1 -0
- package/dist/chart-donut.js +4 -2
- package/dist/chart-donut.js.map +1 -1
- package/dist/chart-doughnut.js +4 -2
- package/dist/chart-doughnut.js.map +1 -1
- package/dist/chart-pie.js +4 -2
- package/dist/chart-pie.js.map +1 -1
- package/dist/chart-stacked-bar.js +401 -0
- package/dist/chart-stacked-bar.js.map +1 -0
- package/dist/{class-map-hJdvjl-W.js → class-map-59YGWLnx.js} +2 -2
- package/dist/{class-map-hJdvjl-W.js.map → class-map-59YGWLnx.js.map} +1 -1
- package/dist/clock.js +1 -1
- package/dist/code-editor.js +3 -3
- package/dist/code-highlighter.js +3 -3
- package/dist/custom-elements-jsdocs.json +2308 -766
- package/dist/custom-elements.json +909 -25
- package/dist/index.js +16 -9
- package/dist/index.js.map +1 -1
- package/dist/number-counter.js +2 -2
- package/dist/{observe-theme-change-BISF-Gl5.js → observe-theme-change-pALI5fmV.js} +2 -2
- package/dist/{observe-theme-change-BISF-Gl5.js.map → observe-theme-change-pALI5fmV.js.map} +1 -1
- package/dist/peacock-loader.js +22 -526
- package/dist/peacock-loader.js.map +1 -1
- package/dist/pie-Dz0IDiPt.js +537 -0
- package/dist/pie-Dz0IDiPt.js.map +1 -0
- package/dist/{tree-view-CLolVlU0.js → snackbar-74YCdMPL.js} +1005 -143
- package/dist/snackbar-74YCdMPL.js.map +1 -0
- package/dist/src/card/card.d.ts +27 -0
- package/dist/src/card/index.d.ts +1 -0
- package/dist/src/chart-bar/chart-bar.d.ts +53 -0
- package/dist/src/chart-bar/chart-stacked-bar.d.ts +78 -0
- package/dist/src/chart-bar/index.d.ts +2 -0
- package/dist/src/index.d.ts +5 -0
- package/dist/src/menu/menu-item/menu-item.d.ts +1 -1
- package/dist/src/snackbar/index.d.ts +1 -0
- package/dist/src/snackbar/snackbar.d.ts +40 -0
- package/dist/src/tabs/tab-group.d.ts +1 -1
- package/dist/src/tabs/tab-panel.d.ts +1 -0
- package/dist/src/tabs/tab.d.ts +2 -1
- package/dist/{style-map-CfNHEkQp.js → style-map-DcB52w-l.js} +2 -2
- package/dist/{style-map-CfNHEkQp.js.map → style-map-DcB52w-l.js.map} +1 -1
- package/dist/test/card.test.d.ts +1 -0
- package/dist/test/chart-bar.test.d.ts +1 -0
- package/dist/test/snackbar.test.d.ts +1 -0
- package/dist/{transform-DRuHEvar.js → transform-DSwFSqzD.js} +13 -558
- package/dist/transform-DSwFSqzD.js.map +1 -0
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/dist/{unsafe-html-CV6Je6HL.js → unsafe-html-C2r3PyzF.js} +2 -2
- package/dist/{unsafe-html-CV6Je6HL.js.map → unsafe-html-C2r3PyzF.js.map} +1 -1
- package/package.json +1 -1
- package/readme.md +2 -2
- package/src/card/card.scss +61 -0
- package/src/card/card.ts +38 -0
- package/src/card/index.ts +1 -0
- package/src/chart-bar/chart-bar.scss +58 -0
- package/src/chart-bar/chart-bar.ts +306 -0
- package/src/chart-bar/chart-stacked-bar.ts +402 -0
- package/src/chart-bar/index.ts +2 -0
- package/src/index.ts +5 -0
- package/src/menu/menu-item/menu-item.ts +1 -1
- package/src/peacock-loader.ts +14 -0
- package/src/snackbar/demo/index.html +29 -0
- package/src/snackbar/index.ts +1 -0
- package/src/snackbar/snackbar.scss +73 -0
- package/src/snackbar/snackbar.ts +151 -0
- package/src/tabs/tab-group.ts +57 -28
- package/src/tabs/tab-panel.scss +3 -3
- package/src/tabs/tab-panel.ts +2 -0
- package/src/tabs/tab.scss +76 -2
- package/src/tabs/tab.ts +28 -6
- package/src/tabs/tabs.ts +15 -3
- package/dist/transform-DRuHEvar.js.map +0 -1
- package/dist/tree-view-CLolVlU0.js.map +0 -1
package/package.json
CHANGED
package/readme.md
CHANGED
|
@@ -44,9 +44,9 @@ Visit [https://peacock.redvars.com](https://peacock.redvars.com) to view the doc
|
|
|
44
44
|
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
|
45
45
|
<link href="https://fonts.googleapis.com/css2?family=Noto+Sans+Mono:wght@100..900&family=Noto+Sans:ital,wght@0,100..900;1,100..900&display=swap" rel="stylesheet">
|
|
46
46
|
|
|
47
|
-
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@redvars/peacock@3.3.
|
|
47
|
+
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@redvars/peacock@3.3.2/dist/assets/styles.css"></link>
|
|
48
48
|
<script type='module'
|
|
49
|
-
src='https://cdn.jsdelivr.net/npm/@redvars/peacock@3.3.
|
|
49
|
+
src='https://cdn.jsdelivr.net/npm/@redvars/peacock@3.3.2/dist/peacock-loader.js'></script>
|
|
50
50
|
</head>
|
|
51
51
|
|
|
52
52
|
<wc-button>Button</wc-button>
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
:host {
|
|
2
|
+
display: block;
|
|
3
|
+
--card-background: var(--color-surface, #ffffff);
|
|
4
|
+
--card-border-color: transparent;
|
|
5
|
+
--card-shadow: none;
|
|
6
|
+
--card-shape: var(--global-shape-corner-large, 1rem);
|
|
7
|
+
--card-padding: 1rem;
|
|
8
|
+
--card-gap: 0;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
.card {
|
|
12
|
+
display: flex;
|
|
13
|
+
flex-direction: column;
|
|
14
|
+
gap: var(--card-gap);
|
|
15
|
+
background: var(--card-background);
|
|
16
|
+
border-radius: var(--card-shape);
|
|
17
|
+
border: 1px solid var(--card-border-color);
|
|
18
|
+
box-shadow: var(--card-shadow);
|
|
19
|
+
color: var(--color-on-surface, inherit);
|
|
20
|
+
padding: var(--card-padding);
|
|
21
|
+
transition: box-shadow 150ms ease, transform 150ms ease;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
:host([variant='elevated']) {
|
|
25
|
+
--card-background: var(--color-surface-container-low, #fdfcfe);
|
|
26
|
+
--card-shadow: var(--shadow-sm, 0px 1px 3px rgba(16, 24, 40, 0.1), 0px 1px 2px rgba(16, 24, 40, 0.06));
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
:host([variant='filled']) {
|
|
30
|
+
--card-background: var(--color-surface-container-highest, #f5f5f5);
|
|
31
|
+
--card-shadow: none;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
:host([variant='outlined']) {
|
|
35
|
+
--card-border-color: var(--color-outline, rgba(0, 0, 0, 0.12));
|
|
36
|
+
--card-shadow: none;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
:host([elevation='0']) {
|
|
40
|
+
--card-shadow: none;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
:host([elevation='1']) {
|
|
44
|
+
--card-shadow: var(--shadow-sm, 0px 1px 3px rgba(16, 24, 40, 0.1), 0px 1px 2px rgba(16, 24, 40, 0.06));
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
:host([elevation='2']) {
|
|
48
|
+
--card-shadow: var(--shadow-md, 0px 4px 8px -2px rgba(16, 24, 40, 0.1), 0px 2px 4px -2px rgba(16, 24, 40, 0.06));
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
:host([elevation='3']) {
|
|
52
|
+
--card-shadow: var(--shadow-lg, 0px 12px 16px -4px rgba(16, 24, 40, 0.08), 0px 4px 6px -2px rgba(16, 24, 40, 0.03));
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
:host([elevation='4']) {
|
|
56
|
+
--card-shadow: var(--shadow-xl, 0px 20px 24px -4px rgba(16, 24, 40, 0.08), 0px 8px 8px -4px rgba(16, 24, 40, 0.03));
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
:host([elevation='5']) {
|
|
60
|
+
--card-shadow: var(--shadow-xxl, 0px 24px 48px -12px rgba(16, 24, 40, 0.18));
|
|
61
|
+
}
|
package/src/card/card.ts
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { LitElement, html } from 'lit';
|
|
2
|
+
import { property } from 'lit/decorators.js';
|
|
3
|
+
import IndividualComponent from '../IndividualComponent.js';
|
|
4
|
+
import styles from './card.scss';
|
|
5
|
+
|
|
6
|
+
type CardVariant = 'elevated' | 'filled' | 'outlined';
|
|
7
|
+
type CardElevation = 0 | 1 | 2 | 3 | 4 | 5;
|
|
8
|
+
/**
|
|
9
|
+
* @label Card
|
|
10
|
+
* @tag wc-card
|
|
11
|
+
* @rawTag card
|
|
12
|
+
* @summary A Material 3 inspired card surface for grouping related content.
|
|
13
|
+
* @cssprop --card-padding - Inner padding for the card container. Defaults to 1rem.
|
|
14
|
+
* @cssprop --card-shape - Corner radius for the card container. Defaults to a large radius.
|
|
15
|
+
* @cssprop --card-gap - Gap between slotted children.
|
|
16
|
+
*
|
|
17
|
+
* @example
|
|
18
|
+
* ```html
|
|
19
|
+
* <wc-card variant="outlined">
|
|
20
|
+
* <h3>Title</h3>
|
|
21
|
+
* <p>Supportive text</p>
|
|
22
|
+
* </wc-card>
|
|
23
|
+
* ```
|
|
24
|
+
*/
|
|
25
|
+
@IndividualComponent
|
|
26
|
+
export class Card extends LitElement {
|
|
27
|
+
static styles = [styles];
|
|
28
|
+
|
|
29
|
+
@property({ type: String, reflect: true })
|
|
30
|
+
variant: CardVariant = 'elevated';
|
|
31
|
+
|
|
32
|
+
@property({ type: Number, reflect: true })
|
|
33
|
+
elevation: CardElevation = 1;
|
|
34
|
+
|
|
35
|
+
render() {
|
|
36
|
+
return html`<div class="card"><slot></slot></div>`;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { Card } from './card.js';
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
@use '../../scss/mixin';
|
|
2
|
+
|
|
3
|
+
@include mixin.base-styles;
|
|
4
|
+
|
|
5
|
+
:host {
|
|
6
|
+
display: block;
|
|
7
|
+
color: var(--color-on-surface);
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
.chart-frame {
|
|
11
|
+
background: var(--color-surface-container-low);
|
|
12
|
+
border: 1px solid var(--color-outline-variant);
|
|
13
|
+
border-radius: var(--shape-corner-medium);
|
|
14
|
+
padding: var(--spacing-300);
|
|
15
|
+
box-shadow: var(--md-sys-elevation-1);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
svg {
|
|
19
|
+
width: 100%;
|
|
20
|
+
height: 100%;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
.axis-label {
|
|
24
|
+
@include mixin.get-typography('label-medium');
|
|
25
|
+
fill: var(--color-on-surface-variant);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
.value-label {
|
|
29
|
+
@include mixin.get-typography('label-small');
|
|
30
|
+
fill: var(--color-on-surface);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
.gridline {
|
|
34
|
+
stroke: var(--color-outline-variant);
|
|
35
|
+
opacity: 0.6;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
.legend {
|
|
39
|
+
display: flex;
|
|
40
|
+
flex-wrap: wrap;
|
|
41
|
+
gap: var(--spacing-200);
|
|
42
|
+
margin-top: var(--spacing-200);
|
|
43
|
+
color: var(--color-on-surface);
|
|
44
|
+
@include mixin.get-typography('label-medium');
|
|
45
|
+
|
|
46
|
+
.legend-item {
|
|
47
|
+
display: inline-flex;
|
|
48
|
+
align-items: center;
|
|
49
|
+
gap: var(--spacing-150);
|
|
50
|
+
|
|
51
|
+
.swatch {
|
|
52
|
+
width: 12px;
|
|
53
|
+
height: 12px;
|
|
54
|
+
border-radius: var(--shape-corner-full);
|
|
55
|
+
border: 1px solid var(--color-outline-variant);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
}
|
|
@@ -0,0 +1,306 @@
|
|
|
1
|
+
import { html, LitElement, PropertyValues } from 'lit';
|
|
2
|
+
import { property, query } from 'lit/decorators.js';
|
|
3
|
+
import { styleMap } from 'lit/directives/style-map.js';
|
|
4
|
+
import IndividualComponent from 'src/IndividualComponent.js';
|
|
5
|
+
import * as d3 from 'd3';
|
|
6
|
+
import styles from './chart-bar.scss';
|
|
7
|
+
|
|
8
|
+
export type ChartBarItem = {
|
|
9
|
+
name: string;
|
|
10
|
+
value: number;
|
|
11
|
+
label?: string;
|
|
12
|
+
color?: string;
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
const chartColors: string[] = [];
|
|
16
|
+
['purple', 'blue', 'red', 'green', 'yellow', 'orange'].forEach(colorName => {
|
|
17
|
+
chartColors.push(`var(--color-${colorName})`);
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
const DEFAULT_WIDTH = 480;
|
|
21
|
+
const DEFAULT_HEIGHT = 320;
|
|
22
|
+
const BAR_RADIUS = 10;
|
|
23
|
+
const DURATION = 450;
|
|
24
|
+
|
|
25
|
+
function debounce<T extends (...args: any[]) => void>(fn: T, wait: number): T {
|
|
26
|
+
let timer: ReturnType<typeof setTimeout>;
|
|
27
|
+
return ((...args: any[]) => {
|
|
28
|
+
clearTimeout(timer);
|
|
29
|
+
timer = setTimeout(() => fn(...args), wait);
|
|
30
|
+
}) as T;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* @label Chart Bar
|
|
35
|
+
* @tag wc-chart-bar
|
|
36
|
+
* @rawTag chart-bar
|
|
37
|
+
* @summary A vertical bar chart that follows Material Design 3 color and spacing tokens.
|
|
38
|
+
* @tags charts
|
|
39
|
+
*
|
|
40
|
+
* @example
|
|
41
|
+
* ```html
|
|
42
|
+
* <wc-chart-bar width="520" height="320"></wc-chart-bar>
|
|
43
|
+
* <script>
|
|
44
|
+
* document.querySelector('wc-chart-bar').data = [
|
|
45
|
+
* { name: 'apples', label: 'Apples', value: 20 },
|
|
46
|
+
* { name: 'bananas', label: 'Bananas', value: 35 },
|
|
47
|
+
* { name: 'cherries', label: 'Cherries', value: 15 },
|
|
48
|
+
* ];
|
|
49
|
+
* </script>
|
|
50
|
+
* ```
|
|
51
|
+
*/
|
|
52
|
+
@IndividualComponent
|
|
53
|
+
export class ChartBar extends LitElement {
|
|
54
|
+
static styles = [styles];
|
|
55
|
+
|
|
56
|
+
@query('svg')
|
|
57
|
+
private svgElement?: SVGElement;
|
|
58
|
+
|
|
59
|
+
/** Width of the chart in pixels. */
|
|
60
|
+
@property({ type: Number, reflect: true }) width: number = 0;
|
|
61
|
+
|
|
62
|
+
/** Height of the chart in pixels. */
|
|
63
|
+
@property({ type: Number, reflect: true }) height: number = DEFAULT_HEIGHT;
|
|
64
|
+
|
|
65
|
+
/** Margin around the chart drawing area. */
|
|
66
|
+
@property({ type: Number }) margin: number = 24;
|
|
67
|
+
|
|
68
|
+
/** Chart data array. Each item should have name, value, and optional label and color. */
|
|
69
|
+
@property({ type: Array }) data: ChartBarItem[] = [];
|
|
70
|
+
|
|
71
|
+
/** Whether to render value labels above bars. */
|
|
72
|
+
@property({ type: Boolean, attribute: 'show-values' }) showValues: boolean = true;
|
|
73
|
+
|
|
74
|
+
private _initialized = false;
|
|
75
|
+
|
|
76
|
+
private _debouncedRenderChart = debounce(() => {
|
|
77
|
+
this._renderChart(true);
|
|
78
|
+
}, 200);
|
|
79
|
+
|
|
80
|
+
firstUpdated() {
|
|
81
|
+
this._renderChart(false);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
updated(changedProperties: PropertyValues) {
|
|
85
|
+
if (!this._initialized) {
|
|
86
|
+
this._initialized = true;
|
|
87
|
+
return;
|
|
88
|
+
}
|
|
89
|
+
const watchedProps = ['width', 'height', 'margin', 'data', 'showValues'];
|
|
90
|
+
const hasChanged = watchedProps.some(prop => changedProperties.has(prop));
|
|
91
|
+
if (hasChanged) {
|
|
92
|
+
this._debouncedRenderChart();
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
private _getPaletteScale() {
|
|
97
|
+
return d3
|
|
98
|
+
.scaleOrdinal<string, string>()
|
|
99
|
+
.domain(this.data.map(d => d.name))
|
|
100
|
+
.range(chartColors);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
private _resolveColor(
|
|
104
|
+
name: string,
|
|
105
|
+
override: string | undefined,
|
|
106
|
+
scale: d3.ScaleOrdinal<string, string>,
|
|
107
|
+
) {
|
|
108
|
+
return override || scale(name);
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
private _renderChart(animate: boolean) {
|
|
112
|
+
if (!this.svgElement) return;
|
|
113
|
+
|
|
114
|
+
const width = this.width > 0 ? this.width : DEFAULT_WIDTH;
|
|
115
|
+
const height = this.height > 0 ? this.height : DEFAULT_HEIGHT;
|
|
116
|
+
const margin = Math.max(this.margin, 12);
|
|
117
|
+
const data = this.data ?? [];
|
|
118
|
+
|
|
119
|
+
const svg = d3.select(this.svgElement);
|
|
120
|
+
svg.attr('width', width).attr('height', height);
|
|
121
|
+
|
|
122
|
+
const innerWidth = Math.max(width - margin * 2, 0);
|
|
123
|
+
const innerHeight = Math.max(height - margin * 2, 0);
|
|
124
|
+
const colorScale = this._getPaletteScale();
|
|
125
|
+
|
|
126
|
+
const container = svg.select<SVGGElement>('.chart-container');
|
|
127
|
+
container.attr('transform', `translate(${margin},${margin})`);
|
|
128
|
+
|
|
129
|
+
if (!data.length || innerWidth === 0 || innerHeight === 0) {
|
|
130
|
+
container.select('.bars').selectAll('*').remove();
|
|
131
|
+
container.select('.x-axis').selectAll('*').remove();
|
|
132
|
+
container.select('.y-grid').selectAll('*').remove();
|
|
133
|
+
container.select('.value-labels').selectAll('*').remove();
|
|
134
|
+
return;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
const xScale = d3
|
|
138
|
+
.scaleBand<string>()
|
|
139
|
+
.domain(data.map(d => d.name))
|
|
140
|
+
.range([0, innerWidth])
|
|
141
|
+
.padding(0.28);
|
|
142
|
+
|
|
143
|
+
const maxValue = d3.max(data, d => d.value) ?? 0;
|
|
144
|
+
const yScale = d3
|
|
145
|
+
.scaleLinear()
|
|
146
|
+
.domain([0, maxValue || 1])
|
|
147
|
+
.nice()
|
|
148
|
+
.range([innerHeight, 0]);
|
|
149
|
+
|
|
150
|
+
const yGrid = container.select<SVGGElement>('.y-grid');
|
|
151
|
+
yGrid
|
|
152
|
+
.call(
|
|
153
|
+
d3
|
|
154
|
+
.axisLeft(yScale)
|
|
155
|
+
.ticks(5)
|
|
156
|
+
.tickSize(-innerWidth)
|
|
157
|
+
.tickFormat(() => ''),
|
|
158
|
+
)
|
|
159
|
+
.selectAll('.tick text')
|
|
160
|
+
.remove();
|
|
161
|
+
yGrid.select('.domain').remove();
|
|
162
|
+
yGrid.selectAll('.tick line').attr('class', 'gridline');
|
|
163
|
+
|
|
164
|
+
const xAxis = container.select<SVGGElement>('.x-axis');
|
|
165
|
+
xAxis
|
|
166
|
+
.attr('transform', `translate(0,${innerHeight})`)
|
|
167
|
+
.call(
|
|
168
|
+
d3
|
|
169
|
+
.axisBottom(xScale)
|
|
170
|
+
.tickSizeOuter(0)
|
|
171
|
+
.tickFormat(name => {
|
|
172
|
+
const entry = data.find(d => d.name === name);
|
|
173
|
+
return entry?.label ?? name;
|
|
174
|
+
}),
|
|
175
|
+
);
|
|
176
|
+
xAxis.select('.domain').attr('stroke', 'var(--color-outline-variant)');
|
|
177
|
+
xAxis.selectAll('.tick line').remove();
|
|
178
|
+
xAxis
|
|
179
|
+
.selectAll('.tick text')
|
|
180
|
+
.attr('class', 'axis-label')
|
|
181
|
+
.attr('dy', '1.1em');
|
|
182
|
+
|
|
183
|
+
const bars = container
|
|
184
|
+
.select('.bars')
|
|
185
|
+
.selectAll<SVGRectElement, ChartBarItem>('rect')
|
|
186
|
+
.data(data, d => d.name)
|
|
187
|
+
.join(
|
|
188
|
+
enter =>
|
|
189
|
+
enter
|
|
190
|
+
.append('rect')
|
|
191
|
+
.attr('class', 'bar')
|
|
192
|
+
.attr('x', d => xScale(d.name) ?? 0)
|
|
193
|
+
.attr('width', xScale.bandwidth())
|
|
194
|
+
.attr('y', innerHeight)
|
|
195
|
+
.attr('height', 0)
|
|
196
|
+
.attr('rx', BAR_RADIUS)
|
|
197
|
+
.attr('ry', BAR_RADIUS)
|
|
198
|
+
.style('fill', d =>
|
|
199
|
+
this._resolveColor(d.name, d.color, colorScale),
|
|
200
|
+
),
|
|
201
|
+
update => update,
|
|
202
|
+
exit =>
|
|
203
|
+
exit
|
|
204
|
+
.transition()
|
|
205
|
+
.duration(DURATION)
|
|
206
|
+
.attr('height', 0)
|
|
207
|
+
.attr('y', innerHeight)
|
|
208
|
+
.remove(),
|
|
209
|
+
);
|
|
210
|
+
|
|
211
|
+
bars
|
|
212
|
+
.attr('x', d => xScale(d.name) ?? 0)
|
|
213
|
+
.attr('width', xScale.bandwidth())
|
|
214
|
+
.attr('rx', BAR_RADIUS)
|
|
215
|
+
.attr('ry', BAR_RADIUS)
|
|
216
|
+
.style('fill', d => this._resolveColor(d.name, d.color, colorScale));
|
|
217
|
+
|
|
218
|
+
if (animate) {
|
|
219
|
+
bars
|
|
220
|
+
.transition()
|
|
221
|
+
.duration(DURATION)
|
|
222
|
+
.attr('y', d => yScale(d.value))
|
|
223
|
+
.attr('height', d => innerHeight - yScale(d.value));
|
|
224
|
+
} else {
|
|
225
|
+
bars
|
|
226
|
+
.attr('y', d => yScale(d.value))
|
|
227
|
+
.attr('height', d => innerHeight - yScale(d.value));
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
const valueLabels = container
|
|
231
|
+
.select('.value-labels')
|
|
232
|
+
.selectAll<SVGTextElement, ChartBarItem>('text')
|
|
233
|
+
.data(this.showValues ? data : [], d => d.name)
|
|
234
|
+
.join(
|
|
235
|
+
enter =>
|
|
236
|
+
enter
|
|
237
|
+
.append('text')
|
|
238
|
+
.attr('class', 'value-label')
|
|
239
|
+
.attr('text-anchor', 'middle')
|
|
240
|
+
.attr('x', d => (xScale(d.name) ?? 0) + xScale.bandwidth() / 2)
|
|
241
|
+
.attr('y', innerHeight - 6)
|
|
242
|
+
.text(d => d.value.toLocaleString()),
|
|
243
|
+
update => update,
|
|
244
|
+
exit => exit.remove(),
|
|
245
|
+
);
|
|
246
|
+
|
|
247
|
+
const resolveLabelY = (value: number) => {
|
|
248
|
+
const offset = yScale(value) - 8;
|
|
249
|
+
return Math.min(offset, innerHeight - 8);
|
|
250
|
+
};
|
|
251
|
+
|
|
252
|
+
if (animate) {
|
|
253
|
+
valueLabels
|
|
254
|
+
.transition()
|
|
255
|
+
.duration(DURATION)
|
|
256
|
+
.attr('x', d => (xScale(d.name) ?? 0) + xScale.bandwidth() / 2)
|
|
257
|
+
.attr('y', d => resolveLabelY(d.value))
|
|
258
|
+
.text(d => d.value.toLocaleString());
|
|
259
|
+
} else {
|
|
260
|
+
valueLabels
|
|
261
|
+
.attr('x', d => (xScale(d.name) ?? 0) + xScale.bandwidth() / 2)
|
|
262
|
+
.attr('y', d => resolveLabelY(d.value))
|
|
263
|
+
.text(d => d.value.toLocaleString());
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
render() {
|
|
268
|
+
const paletteScale = this._getPaletteScale();
|
|
269
|
+
const legendItems = this.data.map(item => ({
|
|
270
|
+
name: item.label ?? item.name,
|
|
271
|
+
color: this._resolveColor(item.name, item.color, paletteScale),
|
|
272
|
+
}));
|
|
273
|
+
|
|
274
|
+
return html`
|
|
275
|
+
<div class="chart-frame">
|
|
276
|
+
<svg role="img" aria-label="Bar chart">
|
|
277
|
+
<g class="chart-container">
|
|
278
|
+
<g class="y-grid"></g>
|
|
279
|
+
<g class="bars"></g>
|
|
280
|
+
<g class="x-axis"></g>
|
|
281
|
+
<g class="value-labels"></g>
|
|
282
|
+
</g>
|
|
283
|
+
</svg>
|
|
284
|
+
${legendItems.length
|
|
285
|
+
? html`<div class="legend" role="list">
|
|
286
|
+
${legendItems.map(
|
|
287
|
+
item => html`<span class="legend-item" role="listitem">
|
|
288
|
+
<span
|
|
289
|
+
class="swatch"
|
|
290
|
+
style=${styleMap({ background: item.color })}
|
|
291
|
+
></span>
|
|
292
|
+
<span>${item.name}</span>
|
|
293
|
+
</span>`,
|
|
294
|
+
)}
|
|
295
|
+
</div>`
|
|
296
|
+
: null}
|
|
297
|
+
</div>
|
|
298
|
+
`;
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
declare global {
|
|
303
|
+
interface HTMLElementTagNameMap {
|
|
304
|
+
'wc-chart-bar': ChartBar;
|
|
305
|
+
}
|
|
306
|
+
}
|