@hpcc-js/chart 3.5.3 → 3.6.0

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/src/Pie.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { I2DChart, ITooltip } from "@hpcc-js/api";
2
- import { InputField, SVGWidget, Utility } from "@hpcc-js/common";
2
+ import { d3Event, InputField, SVGWidget, Utility } from "@hpcc-js/common";
3
3
  import { degreesToRadians, normalizeRadians } from "@hpcc-js/util";
4
4
  import { format as d3Format } from "d3-format";
5
5
  import { interpolate as d3Interpolate } from "d3-interpolate";
@@ -33,6 +33,7 @@ export class Pie extends SVGWidget {
33
33
  private _maxLabelBottom = 0;
34
34
  private _seriesValueFormatter;
35
35
  private _seriesPercentageFormatter;
36
+
36
37
  constructor() {
37
38
  super();
38
39
  I2DChart.call(this);
@@ -91,6 +92,11 @@ export class Pie extends SVGWidget {
91
92
  }, 0);
92
93
  }
93
94
 
95
+ calcPadAngleRadians(): number {
96
+ const paddingValue = this.slicePadding();
97
+ return paddingValue > 0 ? Math.min(paddingValue, 0.05) : 0;
98
+ }
99
+
94
100
  getLabelText(d, truncate?) {
95
101
  let len;
96
102
  let label = d.data[0];
@@ -140,12 +146,19 @@ export class Pie extends SVGWidget {
140
146
 
141
147
  _slices;
142
148
  _labels;
143
- enter(_domNode, element) {
144
- super.enter(_domNode, element);
145
- this._selection.widgetElement(element);
149
+
150
+ enter(domNode, element) {
151
+ super.enter(domNode, element);
152
+ this._selection
153
+ .widgetElement(element)
154
+ .skipBringToTop(true)
155
+ ;
156
+
146
157
  this._slices = element.append("g");
147
158
  this._labels = element.append("g");
159
+
148
160
  const context = this;
161
+
149
162
  this
150
163
  .tooltipHTML(function (d) {
151
164
  switch (context.tooltipStyle()) {
@@ -168,8 +181,10 @@ export class Pie extends SVGWidget {
168
181
  }
169
182
 
170
183
  update(_domNode, element) {
184
+ this.selectionGlow(!this.tabNavigation());
171
185
  super.update(_domNode, element);
172
186
  const context = this;
187
+
173
188
  this.updateD3Pie();
174
189
  this._palette = this._palette.switch(this.paletteID());
175
190
  this._seriesValueFormatter = d3Format(this.seriesValueFormat() as string);
@@ -179,13 +194,15 @@ export class Pie extends SVGWidget {
179
194
  }
180
195
  this._smallValueLabelHeight = this.calcSmallValueLabelHeight();
181
196
  this._totalValue = this.calcTotalValue();
182
- const innerRadius = this.calcInnerRadius();
183
197
  const outerRadius = this.calcOuterRadius();
198
+ const innerRadius = Math.max(this.calcInnerRadius(), Math.min(outerRadius / 30, 6));
184
199
  const labelRadius = outerRadius + 12;
200
+
185
201
  this.d3Arc
186
202
  .innerRadius(innerRadius)
187
203
  .padRadius(outerRadius)
188
204
  .outerRadius(outerRadius)
205
+ .padAngle(this.calcPadAngleRadians())
189
206
  ;
190
207
 
191
208
  this._quadIdxArr = [[], [], [], []];
@@ -213,6 +230,13 @@ export class Pie extends SVGWidget {
213
230
  .on("dblclick", function (d) {
214
231
  context.dblclick(context.rowToObj(d.data), context.columns()[1], context._selection.selected(this));
215
232
  })
233
+ .on("keydown", function (evt, d) {
234
+ const event = d3Event();
235
+ if (context.tabNavigation() && (event.code === "Space" || event.key === "Enter")) {
236
+ event.preventDefault();
237
+ context._selection.click(this);
238
+ }
239
+ })
216
240
  .each(function (d, i) {
217
241
  d3Select(this).append("path")
218
242
  .on("mouseout.tooltip", context.tooltip.hide)
@@ -223,6 +247,9 @@ export class Pie extends SVGWidget {
223
247
  })
224
248
  .merge(arc).transition()
225
249
  .attr("opacity", 1)
250
+ .attr("tabindex", context.tabNavigation() ? "0" : null)
251
+ .attr("role", context.tabNavigation() ? "button" : null)
252
+ .attr("aria-label", context.tabNavigation() ? (d: any) => `${d.data[0]}: ${d.data[1]}` : null)
226
253
  .each(function (d, i) {
227
254
  const quad = context.getQuadrant(midAngle(d));
228
255
  context._quadIdxArr[quad].push(i);
@@ -429,7 +456,7 @@ export class Pie extends SVGWidget {
429
456
  }
430
457
 
431
458
  this.d3Pie
432
- .padAngle(0.0025)
459
+ .padAngle(this.calcPadAngleRadians())
433
460
  .startAngle(startAngle)
434
461
  .endAngle(2 * Math.PI + startAngle)
435
462
  .value(function (d) {
@@ -456,6 +483,8 @@ export interface Pie {
456
483
  startAngle(_: number): this;
457
484
  labelHeight(): number;
458
485
  labelHeight(_: number): this;
486
+ slicePadding(): number;
487
+ slicePadding(_: number): this;
459
488
  seriesPercentageFormat(): string;
460
489
  seriesPercentageFormat(_: string): this;
461
490
  showLabels(): boolean;
@@ -463,10 +492,14 @@ export interface Pie {
463
492
  sortDataByValue(): "none" | "ascending" | "descending";
464
493
  sortDataByValue(_: "none" | "ascending" | "descending"): this;
465
494
 
466
- paletteID(_?: string): string | Pie;
467
- useClonedPalette(_?: boolean): boolean | Pie;
468
- outerText(_?: boolean): boolean | Pie;
495
+ paletteID(): string;
496
+ paletteID(_: string): this;
497
+ useClonedPalette(): boolean;
498
+ useClonedPalette(_: boolean): this;
499
+ outerText(): boolean;
500
+ outerText(_: boolean): this;
469
501
  innerRadius(): number;
502
+ innerRadius(_: number): this;
470
503
  innerRadius_exists(): boolean;
471
504
 
472
505
  // I2DChart
@@ -492,6 +525,10 @@ export interface Pie {
492
525
 
493
526
  // SimpleSelectionMixin
494
527
  _selection: Utility.SimpleSelection;
528
+
529
+ // Tab Navigation
530
+ tabNavigation(): boolean;
531
+ tabNavigation(_: boolean): this;
495
532
  }
496
533
  Pie.prototype.publish("showLabels", true, "boolean", "If true, wedge labels will display");
497
534
  Pie.prototype.publish("showSeriesValue", false, "boolean", "Append data series value next to label", null, { disable: w => !w.showLabels() });
@@ -504,4 +541,6 @@ Pie.prototype.publish("innerRadius", 0, "number", "Sets inner pie hole radius as
504
541
  Pie.prototype.publish("minOuterRadius", 20, "number", "Minimum outer radius (pixels)");
505
542
  Pie.prototype.publish("startAngle", 0, "number", "Starting angle of the first (and largest) wedge (degrees)");
506
543
  Pie.prototype.publish("labelHeight", 12, "number", "Font size of labels (pixels)", null, { disable: w => !w.showLabels() });
544
+ Pie.prototype.publish("slicePadding", 0.01, "number", "Padding between pie slices (converted to pixels)", null, { tags: ["Basic"], range: { min: 0, step: 0.01, max: 0.2 } });
507
545
  Pie.prototype.publish("sortDataByValue", "descending", "set", "Sort data by value", ["none", "ascending", "descending"]);
546
+ Pie.prototype.publish("tabNavigation", false, "boolean", "Enable or disable tab navigation");
package/src/Scatter.css CHANGED
@@ -6,11 +6,38 @@
6
6
 
7
7
  .chart_Scatter .point .pointSelection {
8
8
  fill: none;
9
- stroke: none;
9
+ stroke: transparent;
10
+ stroke-width: 2px;
10
11
  pointer-events: all;
12
+ transition: all 0.2s ease;
11
13
  }
12
14
 
13
15
  .chart_Scatter .point .pointSelection.selected {
14
- fill: none;
15
- stroke: red;
16
+ stroke: #dc3545 !important;
17
+ stroke-width: 3px !important;
18
+ paint-order: fill stroke !important;
19
+ }
20
+
21
+ .chart_Scatter .point .pointSelection:hover {
22
+ stroke: rgba(108, 117, 125, 0.6);
23
+ stroke-width: 2px;
24
+ filter: brightness(1.05);
25
+ }
26
+
27
+ .chart_Scatter .point .pointSelection:focus {
28
+ stroke: #007bff !important;
29
+ stroke-width: 3px !important;
30
+ paint-order: fill stroke !important;
16
31
  }
32
+
33
+ .chart_Scatter .point .pointSelection.selected:focus {
34
+ stroke: #6f42c1 !important;
35
+ }
36
+
37
+ .chart_Scatter .point .pointSelection:focus-visible {
38
+ outline: none;
39
+ }
40
+
41
+ .chart_Scatter .point .pointSelection:active {
42
+ outline: none !important;
43
+ }
package/src/Scatter.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { INDChart, ITooltip } from "@hpcc-js/api";
2
- import { InputField } from "@hpcc-js/common";
2
+ import { d3Event, InputField } from "@hpcc-js/common";
3
3
  import { extent as d3Extent } from "d3-array";
4
4
  import { scaleLinear as d3ScaleLinear, scaleLog as d3ScaleLog, scalePow as d3ScalePow, scaleSqrt as d3ScaleSqrt } from "d3-scale";
5
5
  import { select as d3Select } from "d3-selection";
@@ -129,6 +129,18 @@ export class Scatter extends XYAxis {
129
129
  const height = isHorizontal ? this.height() : this.width();
130
130
  const context = this;
131
131
 
132
+ if (this.tabNavigation() && host.parentRelativeDiv) {
133
+ host.parentRelativeDiv
134
+ .attr("tabindex", "0")
135
+ .attr("role", "group")
136
+ .attr("aria-label", `${this.columns()[0] || "Chart"} data`);
137
+ } else if (host.parentRelativeDiv) {
138
+ host.parentRelativeDiv
139
+ .attr("tabindex", null)
140
+ .attr("role", null)
141
+ .attr("aria-label", null);
142
+ }
143
+
132
144
  this._palette = this._palette.switch(this.paletteID());
133
145
  if (this.useClonedPalette()) {
134
146
  this._palette = this._palette.cloneNotExists(this.paletteID() + "_" + this.id());
@@ -258,6 +270,15 @@ export class Scatter extends XYAxis {
258
270
  .on("dblclick", function (d: any, _idx) {
259
271
  context.dblclick(host.rowToObj(host.data()[d.rowIdx]), d.column, host._selection.selected(this));
260
272
  })
273
+ .on("keydown", function (evt, d: any) {
274
+ if (context.tabNavigation()) {
275
+ const event = d3Event();
276
+ if (event.code === "Space" || event.key === "Enter") {
277
+ event.preventDefault();
278
+ host._selection.click(this);
279
+ }
280
+ }
281
+ })
261
282
  ;
262
283
  })
263
284
  .merge(points)
@@ -279,6 +300,9 @@ export class Scatter extends XYAxis {
279
300
  .attr("cx", function (d) { return context.xPos(host, d); })
280
301
  .attr("cy", function (d) { return context.yPos(host, d); })
281
302
  .attr("r", d2.size)
303
+ .attr("tabindex", context.tabNavigation() ? 0 : null)
304
+ .attr("role", context.tabNavigation() ? "button" : null)
305
+ .attr("aria-label", context.tabNavigation() ? (d: any) => `${d.column || "Value"}: ${d.value} @ ${d.label}` : null)
282
306
  ;
283
307
 
284
308
  const element = d3Select(this).select(".pointShape");
@@ -371,6 +395,7 @@ export interface Scatter {
371
395
  tooltipHTML(_): string;
372
396
  tooltipFormat(_): string;
373
397
  tooltipStyle(): "default" | "none" | "series-table";
398
+ tooltipStyle(_: "default" | "none" | "series-table"): this;
374
399
  }
375
400
  Scatter.prototype.publish("paletteID", "default", "set", "Color palette for this widget", Scatter.prototype._palette.switch(), { tags: ["Basic", "Shared"] });
376
401
  Scatter.prototype.publish("pointSizeScale", "linear", "set", "pointSizeScale", ["linear", "pow", "log", "sqrt"]);
package/src/XYAxis.ts CHANGED
@@ -323,6 +323,7 @@ export class XYAxis extends SVGWidget {
323
323
 
324
324
  protected _prevXAxisType;
325
325
  update(domNode, element) {
326
+ this.selectionGlow(!this.tabNavigation());
326
327
  super.update(domNode, element);
327
328
  const context = this;
328
329
 
@@ -754,6 +755,10 @@ export interface XYAxis {
754
755
  xAxisPadding(_: number): this;
755
756
  yAxisPadding(): number;
756
757
  yAxisPadding(_: number): this;
758
+
759
+ // Tab Navigation
760
+ tabNavigation(): boolean;
761
+ tabNavigation(_: boolean): this;
757
762
  }
758
763
 
759
764
  XYAxis.prototype.publish("orientation", "horizontal", "set", "Selects orientation for the axis", ["horizontal", "vertical"]);
@@ -801,3 +806,4 @@ XYAxis.prototype.publish("regions", [], "array", "Regions");
801
806
  XYAxis.prototype.publish("layers", [], "widgetArray", "Layers", null, { render: false });
802
807
  XYAxis.prototype.publishProxy("xAxisPadding", "domainAxis", "padding");
803
808
  XYAxis.prototype.publishProxy("yAxisPadding", "valueAxis", "padding");
809
+ XYAxis.prototype.publish("tabNavigation", false, "boolean", "Enable or disable tab navigation");
package/types/Pie.d.ts CHANGED
@@ -23,13 +23,14 @@ export declare class Pie extends SVGWidget {
23
23
  calcOuterRadius(): number;
24
24
  calcSmallValueLabelHeight(): number;
25
25
  calcTotalValue(): number;
26
+ calcPadAngleRadians(): number;
26
27
  getLabelText(d: any, truncate?: any): any;
27
28
  selection(): any[];
28
29
  selection(_: any[]): this;
29
30
  selectByLabel(_: string): void;
30
31
  _slices: any;
31
32
  _labels: any;
32
- enter(_domNode: any, element: any): void;
33
+ enter(domNode: any, element: any): void;
33
34
  update(_domNode: any, element: any): void;
34
35
  isLeftSide(midAngle: any): any;
35
36
  getQuadrant(radians: any): number;
@@ -51,16 +52,22 @@ export interface Pie {
51
52
  startAngle(_: number): this;
52
53
  labelHeight(): number;
53
54
  labelHeight(_: number): this;
55
+ slicePadding(): number;
56
+ slicePadding(_: number): this;
54
57
  seriesPercentageFormat(): string;
55
58
  seriesPercentageFormat(_: string): this;
56
59
  showLabels(): boolean;
57
60
  showLabels(_: boolean): this;
58
61
  sortDataByValue(): "none" | "ascending" | "descending";
59
62
  sortDataByValue(_: "none" | "ascending" | "descending"): this;
60
- paletteID(_?: string): string | Pie;
61
- useClonedPalette(_?: boolean): boolean | Pie;
62
- outerText(_?: boolean): boolean | Pie;
63
+ paletteID(): string;
64
+ paletteID(_: string): this;
65
+ useClonedPalette(): boolean;
66
+ useClonedPalette(_: boolean): this;
67
+ outerText(): boolean;
68
+ outerText(_: boolean): this;
63
69
  innerRadius(): number;
70
+ innerRadius(_: number): this;
64
71
  innerRadius_exists(): boolean;
65
72
  _palette: any;
66
73
  fillColor(row: any[], column: string, value: number): string;
@@ -80,4 +87,6 @@ export interface Pie {
80
87
  tooltipOffset_default(): number;
81
88
  tooltipOffset_default(_: number): Pie;
82
89
  _selection: Utility.SimpleSelection;
90
+ tabNavigation(): boolean;
91
+ tabNavigation(_: boolean): this;
83
92
  }
@@ -55,4 +55,5 @@ export interface Scatter {
55
55
  tooltipHTML(_: any): string;
56
56
  tooltipFormat(_: any): string;
57
57
  tooltipStyle(): "default" | "none" | "series-table";
58
+ tooltipStyle(_: "default" | "none" | "series-table"): this;
58
59
  }
package/types/XYAxis.d.ts CHANGED
@@ -177,4 +177,6 @@ export interface XYAxis {
177
177
  xAxisPadding(_: number): this;
178
178
  yAxisPadding(): number;
179
179
  yAxisPadding(_: number): this;
180
+ tabNavigation(): boolean;
181
+ tabNavigation(_: boolean): this;
180
182
  }