cx 25.6.1 → 25.6.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.
Files changed (99) hide show
  1. package/dist/charts.js +99 -8
  2. package/dist/manifest.js +714 -714
  3. package/package.json +1 -1
  4. package/src/charts/Legend.d.ts +45 -45
  5. package/src/charts/LegendEntry.js +128 -128
  6. package/src/charts/LegendEntry.scss +27 -27
  7. package/src/charts/LineGraph.d.ts +9 -0
  8. package/src/charts/LineGraph.js +77 -7
  9. package/src/charts/PieChart.d.ts +92 -92
  10. package/src/charts/RangeMarker.js +159 -159
  11. package/src/charts/axis/Axis.d.ts +113 -113
  12. package/src/charts/axis/Axis.js +280 -280
  13. package/src/charts/axis/CategoryAxis.d.ts +30 -30
  14. package/src/charts/axis/CategoryAxis.js +241 -241
  15. package/src/charts/axis/NumericAxis.js +351 -351
  16. package/src/charts/axis/Stack.js +55 -55
  17. package/src/charts/axis/TimeAxis.js +611 -611
  18. package/src/charts/helpers/SnapPointFinder.js +69 -69
  19. package/src/data/Binding.spec.js +69 -69
  20. package/src/data/Expression.js +229 -229
  21. package/src/data/Expression.spec.js +229 -229
  22. package/src/data/StringTemplate.js +92 -92
  23. package/src/data/StringTemplate.spec.js +132 -132
  24. package/src/data/StructuredSelector.js +132 -132
  25. package/src/data/getAccessor.spec.js +11 -11
  26. package/src/data/getSelector.js +49 -49
  27. package/src/hooks/createLocalStorageRef.d.ts +3 -3
  28. package/src/hooks/createLocalStorageRef.js +20 -20
  29. package/src/index.scss +6 -6
  30. package/src/ui/Culture.d.ts +57 -57
  31. package/src/ui/Culture.js +139 -139
  32. package/src/ui/FocusManager.js +171 -171
  33. package/src/ui/Format.js +108 -108
  34. package/src/ui/HoverSync.js +147 -147
  35. package/src/ui/Repeater.d.ts +61 -61
  36. package/src/ui/index.d.ts +42 -42
  37. package/src/ui/layout/ContentPlaceholder.d.ts +19 -19
  38. package/src/ui/layout/ContentPlaceholder.js +105 -105
  39. package/src/ui/layout/ContentPlaceholder.spec.js +579 -579
  40. package/src/ui/layout/LabelsTopLayout.js +134 -134
  41. package/src/util/Format.js +270 -270
  42. package/src/util/date/encodeDate.d.ts +1 -1
  43. package/src/util/date/encodeDate.js +8 -8
  44. package/src/util/date/encodeDateWithTimezoneOffset.d.ts +1 -1
  45. package/src/util/date/index.d.ts +11 -11
  46. package/src/util/date/index.js +11 -11
  47. package/src/util/date/parseDateInvariant.d.ts +3 -3
  48. package/src/util/date/parseDateInvariant.js +20 -20
  49. package/src/util/getSearchQueryPredicate.js +59 -59
  50. package/src/util/index.d.ts +51 -51
  51. package/src/util/index.js +54 -54
  52. package/src/util/isValidIdentifierName.d.ts +1 -1
  53. package/src/util/isValidIdentifierName.js +5 -5
  54. package/src/util/isValidIdentifierName.spec.js +33 -33
  55. package/src/util/scss/add-rules.scss +38 -38
  56. package/src/widgets/CxCredit.scss +37 -37
  57. package/src/widgets/HighlightedSearchText.js +36 -36
  58. package/src/widgets/HighlightedSearchText.scss +18 -18
  59. package/src/widgets/List.scss +91 -91
  60. package/src/widgets/drag-drop/DropZone.js +214 -214
  61. package/src/widgets/form/Calendar.js +618 -618
  62. package/src/widgets/form/Calendar.scss +196 -196
  63. package/src/widgets/form/Checkbox.scss +127 -127
  64. package/src/widgets/form/ColorField.js +397 -397
  65. package/src/widgets/form/ColorField.scss +96 -96
  66. package/src/widgets/form/ColorPicker.scss +283 -283
  67. package/src/widgets/form/DateTimeField.js +576 -576
  68. package/src/widgets/form/DateTimePicker.js +392 -392
  69. package/src/widgets/form/LookupField.d.ts +179 -179
  70. package/src/widgets/form/LookupField.scss +219 -219
  71. package/src/widgets/form/MonthPicker.scss +118 -118
  72. package/src/widgets/form/NumberField.js +459 -459
  73. package/src/widgets/form/NumberField.scss +61 -61
  74. package/src/widgets/form/Radio.scss +121 -121
  75. package/src/widgets/form/Select.scss +99 -99
  76. package/src/widgets/form/Slider.scss +118 -118
  77. package/src/widgets/form/Switch.scss +140 -140
  78. package/src/widgets/form/TextArea.scss +43 -43
  79. package/src/widgets/form/TextField.js +290 -290
  80. package/src/widgets/form/TextField.scss +55 -55
  81. package/src/widgets/form/UploadButton.d.ts +34 -34
  82. package/src/widgets/form/variables.scss +353 -353
  83. package/src/widgets/grid/Grid.d.ts +442 -442
  84. package/src/widgets/grid/GridRow.js +228 -228
  85. package/src/widgets/grid/TreeNode.d.ts +23 -23
  86. package/src/widgets/grid/TreeNode.scss +88 -88
  87. package/src/widgets/grid/variables.scss +133 -133
  88. package/src/widgets/nav/LinkButton.js +128 -128
  89. package/src/widgets/nav/Menu.scss +74 -74
  90. package/src/widgets/overlay/Dropdown.js +612 -612
  91. package/src/widgets/overlay/FlyweightTooltipTracker.js +39 -39
  92. package/src/widgets/overlay/Overlay.d.ts +73 -73
  93. package/src/widgets/overlay/Window.js +202 -202
  94. package/src/widgets/overlay/captureMouse.js +124 -124
  95. package/src/widgets/overlay/createHotPromiseWindowFactory.d.ts +18 -18
  96. package/src/widgets/overlay/createHotPromiseWindowFactory.js +56 -56
  97. package/src/widgets/overlay/index.d.ts +11 -11
  98. package/src/widgets/overlay/index.js +11 -11
  99. package/src/widgets/variables.scss +144 -144
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cx",
3
- "version": "25.6.1",
3
+ "version": "25.6.2",
4
4
  "description": "Advanced JavaScript UI framework for admin and dashboard applications with ready to use grid, form and chart components.",
5
5
  "main": "index.js",
6
6
  "jsnext:main": "src/index.js",
@@ -1,45 +1,45 @@
1
- import * as Cx from "../core";
2
-
3
- interface LegendProps extends Cx.HtmlElementProps {
4
- /** Name of the legend. Default is `legend`. */
5
- name?: string;
6
-
7
- /** Base CSS class to be applied to the element. Defaults to `legend`. */
8
- baseClass?: string;
9
-
10
- /** Switch to vertical mode. */
11
- vertical?: boolean;
12
-
13
- /** Size of the svg shape container in pixels. Default value is 20. */
14
- svgSize?: number;
15
-
16
- /** Shape size in pixels. Default value is 18. */
17
- shapeSize?: number;
18
-
19
- /** Default shape that will be applied to the all legend items. */
20
- shape?: Cx.StringProp;
21
-
22
- /** CSS style that will be applied to the legend entry. */
23
- entryStyle?: Cx.StyleProp;
24
-
25
- /** CSS class that will be applied to the legend entry. */
26
- entryClass?: Cx.ClassProp;
27
-
28
- /** CSS style that will be applied to the legend entry value segment. */
29
- valueStyle?: Cx.StyleProp;
30
-
31
- /** CSS class that will be applied to the legend entry value segment. */
32
- valueClass?: Cx.ClassProp;
33
-
34
- /** Set to true to show values. Mostly used for PieChart legends. */
35
- showValues?: Cx.BooleanProp;
36
-
37
- /** Format used for values, i.e. n;2 or currency. The default value is s.*/
38
- valueFormat?: string;
39
- }
40
-
41
- export class Legend extends Cx.Widget<LegendProps> {
42
- static Scope(): any;
43
- }
44
-
45
- export class LegendScope extends Cx.Widget<Cx.PureContainerProps> {}
1
+ import * as Cx from "../core";
2
+
3
+ interface LegendProps extends Cx.HtmlElementProps {
4
+ /** Name of the legend. Default is `legend`. */
5
+ name?: string;
6
+
7
+ /** Base CSS class to be applied to the element. Defaults to `legend`. */
8
+ baseClass?: string;
9
+
10
+ /** Switch to vertical mode. */
11
+ vertical?: boolean;
12
+
13
+ /** Size of the svg shape container in pixels. Default value is 20. */
14
+ svgSize?: number;
15
+
16
+ /** Shape size in pixels. Default value is 18. */
17
+ shapeSize?: number;
18
+
19
+ /** Default shape that will be applied to the all legend items. */
20
+ shape?: Cx.StringProp;
21
+
22
+ /** CSS style that will be applied to the legend entry. */
23
+ entryStyle?: Cx.StyleProp;
24
+
25
+ /** CSS class that will be applied to the legend entry. */
26
+ entryClass?: Cx.ClassProp;
27
+
28
+ /** CSS style that will be applied to the legend entry value segment. */
29
+ valueStyle?: Cx.StyleProp;
30
+
31
+ /** CSS class that will be applied to the legend entry value segment. */
32
+ valueClass?: Cx.ClassProp;
33
+
34
+ /** Set to true to show values. Mostly used for PieChart legends. */
35
+ showValues?: Cx.BooleanProp;
36
+
37
+ /** Format used for values, i.e. n;2 or currency. The default value is s.*/
38
+ valueFormat?: string;
39
+ }
40
+
41
+ export class Legend extends Cx.Widget<LegendProps> {
42
+ static Scope(): any;
43
+ }
44
+
45
+ export class LegendScope extends Cx.Widget<Cx.PureContainerProps> {}
@@ -1,128 +1,128 @@
1
- import { Widget, VDOM } from "../ui/Widget";
2
- import { getShape } from "./shapes";
3
- import { Selection } from "../ui/selection/Selection";
4
- import { stopPropagation } from "../util/eventCallbacks";
5
- import { isUndefined } from "../util/isUndefined";
6
- import { Container } from "../ui/Container";
7
-
8
- export class LegendEntry extends Container {
9
- init() {
10
- this.selection = Selection.create(this.selection);
11
- super.init();
12
- }
13
-
14
- declareData() {
15
- var selection = this.selection.configureWidget(this);
16
-
17
- super.declareData(...arguments, selection, {
18
- selected: undefined,
19
- shape: undefined,
20
- colorIndex: undefined,
21
- colorMap: undefined,
22
- colorName: undefined,
23
- name: undefined,
24
- active: true,
25
- size: undefined,
26
- rx: undefined,
27
- ry: undefined,
28
- text: undefined,
29
- });
30
- }
31
-
32
- prepareData(context, instance) {
33
- let { data } = instance;
34
-
35
- if (data.name && !data.colorName) data.colorName = data.name;
36
-
37
- super.prepareData(context, instance);
38
- }
39
-
40
- explore(context, instance) {
41
- var { data } = instance;
42
- instance.colorMap = data.colorMap && context.getColorMap && context.getColorMap(data.colorMap);
43
- if (instance.colorMap && data.colorName) instance.colorMap.acknowledge(data.colorName);
44
- super.explore(context, instance);
45
- }
46
-
47
- prepare(context, instance) {
48
- var { data, colorMap } = instance;
49
-
50
- if (colorMap && data.colorName) {
51
- data.colorIndex = colorMap.map(data.colorName);
52
- if (instance.cache("colorIndex", data.colorIndex)) instance.markShouldUpdate(context);
53
- }
54
- }
55
-
56
- handleClick(e, instance) {
57
- if (this.onClick && instance.invoke("onClick", e, instance) === false) return;
58
-
59
- e.stopPropagation();
60
-
61
- var any = this.legendAction == "auto";
62
-
63
- if (any || this.legendAction == "toggle") if (instance.set("active", !instance.data.active)) return;
64
-
65
- if ((any || this.legendAction == "select") && !this.selection.isDummy) this.selection.selectInstance(instance);
66
- }
67
-
68
- render(context, instance, key) {
69
- let { data } = instance;
70
- let content = !isUndefined(this.text) ? data.text : this.renderChildren(context, instance);
71
- return (
72
- <div
73
- key={key}
74
- className={data.classNames}
75
- style={data.style}
76
- onMouseDown={stopPropagation}
77
- onClick={(e) => {
78
- this.handleClick(e, instance);
79
- }}
80
- >
81
- {this.renderShape(instance)}
82
- {content != null && <div>{content}</div>}
83
- </div>
84
- );
85
- }
86
-
87
- renderShape(instance) {
88
- var entry = instance.data;
89
- var className = this.CSS.element(this.baseClass, "shape", {
90
- disabled: entry.disabled,
91
- selected: entry.selected || this.selection.isInstanceSelected(instance),
92
- [`color-${entry.colorIndex}`]: entry.colorIndex != null && (isUndefined(entry.active) || entry.active),
93
- });
94
- var shape = getShape(entry.shape || "square");
95
-
96
- // if the entry has a custom fill or stroke set, use it for both values
97
- let style = { ...entry.style };
98
- style.fill = style.fill ?? style.stroke;
99
- style.stroke = style.stroke ?? style.fill;
100
-
101
- return (
102
- <svg
103
- key="svg"
104
- className={this.CSS.element(this.baseClass, "svg")}
105
- style={{
106
- width: `${this.svgSize}px`,
107
- height: `${this.svgSize}px`,
108
- }}
109
- >
110
- {shape(this.svgSize / 2, this.svgSize / 2, entry.size, {
111
- style,
112
- className,
113
- rx: entry.rx,
114
- ry: entry.ry,
115
- })}
116
- </svg>
117
- );
118
- }
119
- }
120
-
121
- LegendEntry.prototype.baseClass = "legendentry";
122
- LegendEntry.prototype.shape = "square";
123
- LegendEntry.prototype.legendAction = "auto";
124
- LegendEntry.prototype.size = 18;
125
- LegendEntry.prototype.svgSize = 20;
126
- LegendEntry.prototype.styled = true;
127
-
128
- Widget.alias("legend-entry", LegendEntry);
1
+ import { Widget, VDOM } from "../ui/Widget";
2
+ import { getShape } from "./shapes";
3
+ import { Selection } from "../ui/selection/Selection";
4
+ import { stopPropagation } from "../util/eventCallbacks";
5
+ import { isUndefined } from "../util/isUndefined";
6
+ import { Container } from "../ui/Container";
7
+
8
+ export class LegendEntry extends Container {
9
+ init() {
10
+ this.selection = Selection.create(this.selection);
11
+ super.init();
12
+ }
13
+
14
+ declareData() {
15
+ var selection = this.selection.configureWidget(this);
16
+
17
+ super.declareData(...arguments, selection, {
18
+ selected: undefined,
19
+ shape: undefined,
20
+ colorIndex: undefined,
21
+ colorMap: undefined,
22
+ colorName: undefined,
23
+ name: undefined,
24
+ active: true,
25
+ size: undefined,
26
+ rx: undefined,
27
+ ry: undefined,
28
+ text: undefined,
29
+ });
30
+ }
31
+
32
+ prepareData(context, instance) {
33
+ let { data } = instance;
34
+
35
+ if (data.name && !data.colorName) data.colorName = data.name;
36
+
37
+ super.prepareData(context, instance);
38
+ }
39
+
40
+ explore(context, instance) {
41
+ var { data } = instance;
42
+ instance.colorMap = data.colorMap && context.getColorMap && context.getColorMap(data.colorMap);
43
+ if (instance.colorMap && data.colorName) instance.colorMap.acknowledge(data.colorName);
44
+ super.explore(context, instance);
45
+ }
46
+
47
+ prepare(context, instance) {
48
+ var { data, colorMap } = instance;
49
+
50
+ if (colorMap && data.colorName) {
51
+ data.colorIndex = colorMap.map(data.colorName);
52
+ if (instance.cache("colorIndex", data.colorIndex)) instance.markShouldUpdate(context);
53
+ }
54
+ }
55
+
56
+ handleClick(e, instance) {
57
+ if (this.onClick && instance.invoke("onClick", e, instance) === false) return;
58
+
59
+ e.stopPropagation();
60
+
61
+ var any = this.legendAction == "auto";
62
+
63
+ if (any || this.legendAction == "toggle") if (instance.set("active", !instance.data.active)) return;
64
+
65
+ if ((any || this.legendAction == "select") && !this.selection.isDummy) this.selection.selectInstance(instance);
66
+ }
67
+
68
+ render(context, instance, key) {
69
+ let { data } = instance;
70
+ let content = !isUndefined(this.text) ? data.text : this.renderChildren(context, instance);
71
+ return (
72
+ <div
73
+ key={key}
74
+ className={data.classNames}
75
+ style={data.style}
76
+ onMouseDown={stopPropagation}
77
+ onClick={(e) => {
78
+ this.handleClick(e, instance);
79
+ }}
80
+ >
81
+ {this.renderShape(instance)}
82
+ {content != null && <div>{content}</div>}
83
+ </div>
84
+ );
85
+ }
86
+
87
+ renderShape(instance) {
88
+ var entry = instance.data;
89
+ var className = this.CSS.element(this.baseClass, "shape", {
90
+ disabled: entry.disabled,
91
+ selected: entry.selected || this.selection.isInstanceSelected(instance),
92
+ [`color-${entry.colorIndex}`]: entry.colorIndex != null && (isUndefined(entry.active) || entry.active),
93
+ });
94
+ var shape = getShape(entry.shape || "square");
95
+
96
+ // if the entry has a custom fill or stroke set, use it for both values
97
+ let style = { ...entry.style };
98
+ style.fill = style.fill ?? style.stroke;
99
+ style.stroke = style.stroke ?? style.fill;
100
+
101
+ return (
102
+ <svg
103
+ key="svg"
104
+ className={this.CSS.element(this.baseClass, "svg")}
105
+ style={{
106
+ width: `${this.svgSize}px`,
107
+ height: `${this.svgSize}px`,
108
+ }}
109
+ >
110
+ {shape(this.svgSize / 2, this.svgSize / 2, entry.size, {
111
+ style,
112
+ className,
113
+ rx: entry.rx,
114
+ ry: entry.ry,
115
+ })}
116
+ </svg>
117
+ );
118
+ }
119
+ }
120
+
121
+ LegendEntry.prototype.baseClass = "legendentry";
122
+ LegendEntry.prototype.shape = "square";
123
+ LegendEntry.prototype.legendAction = "auto";
124
+ LegendEntry.prototype.size = 18;
125
+ LegendEntry.prototype.svgSize = 20;
126
+ LegendEntry.prototype.styled = true;
127
+
128
+ Widget.alias("legend-entry", LegendEntry);
@@ -1,27 +1,27 @@
1
- @mixin cx-legendentry($name: "legendentry", $besm: $cx-besm) {
2
- $block: map-get($besm, block);
3
- $element: map-get($besm, element);
4
- $state: map-get($besm, state);
5
-
6
- .#{$block}#{$name} {
7
- display: inline-flex;
8
- align-items: center;
9
- padding: 5px;
10
- gap: 5px;
11
- position: relative;
12
- box-sizing: border-box;
13
- cursor: pointer;
14
- }
15
-
16
- .#{$element}#{$name}-svg {
17
- flex-shrink: 0;
18
- }
19
-
20
- .#{$element}#{$name}-shape {
21
- fill: #eee;
22
- }
23
- }
24
-
25
- @if (cx-should-include("cx/charts/LegendEntry")) {
26
- @include cx-legendentry();
27
- }
1
+ @mixin cx-legendentry($name: "legendentry", $besm: $cx-besm) {
2
+ $block: map-get($besm, block);
3
+ $element: map-get($besm, element);
4
+ $state: map-get($besm, state);
5
+
6
+ .#{$block}#{$name} {
7
+ display: inline-flex;
8
+ align-items: center;
9
+ padding: 5px;
10
+ gap: 5px;
11
+ position: relative;
12
+ box-sizing: border-box;
13
+ cursor: pointer;
14
+ }
15
+
16
+ .#{$element}#{$name}-svg {
17
+ flex-shrink: 0;
18
+ }
19
+
20
+ .#{$element}#{$name}-shape {
21
+ fill: #eee;
22
+ }
23
+ }
24
+
25
+ @if (cx-should-include("cx/charts/LegendEntry")) {
26
+ @include cx-legendentry();
27
+ }
@@ -87,6 +87,15 @@ interface LineGraphProps extends Cx.WidgetProps {
87
87
 
88
88
  /** Set to true to avoid forcing the vertical axis to accommodate y0 values. */
89
89
  hiddenBase?: boolean;
90
+
91
+ /** Set to `true` to draw smoothed lines between data points using cubic Bézier curve.
92
+ * When enabled, the graph uses control points calculated from neighboring values to create smooth transitions between data points. */
93
+ smooth?: boolean;
94
+
95
+ /** Controls the intensity of the smoothing effect applied to Bézier curves when `smooth` is enabled.
96
+ * Accepts a number between `0` (straight lines) and `0.4` (maximum smoothing).
97
+ * Values outside this range are automatically clamped. Default value is `0.05`. */
98
+ smoothingRatio?: number;
90
99
  }
91
100
 
92
101
  export class LineGraph extends Cx.Widget<LineGraphProps> {}
@@ -27,6 +27,8 @@ export class LineGraph extends Widget {
27
27
  active: true,
28
28
  stack: undefined,
29
29
  stacked: undefined,
30
+ smooth: undefined,
31
+ smoothingRatio: undefined,
30
32
  });
31
33
  }
32
34
 
@@ -35,6 +37,11 @@ export class LineGraph extends Widget {
35
37
 
36
38
  if (data.name && !data.colorName) data.colorName = data.name;
37
39
 
40
+ if (data.smooth && data.smoothingRatio != null) {
41
+ if (data.smoothingRatio < 0) data.smoothingRatio = 0;
42
+ if (data.smoothingRatio > 0.4) data.smoothingRatio = 0.4;
43
+ }
44
+
38
45
  super.prepareData(context, instance);
39
46
  }
40
47
 
@@ -161,13 +168,18 @@ export class LineGraph extends Widget {
161
168
  };
162
169
 
163
170
  let line, area;
171
+ const r = data.smoothingRatio;
164
172
 
173
+ let linePath = "";
165
174
  if (data.line) {
166
- let linePath = "";
167
175
  lineSpans.forEach((span) => {
168
176
  span.forEach((p, i) => {
169
- linePath += i == 0 ? " M " : " L ";
170
- linePath += p.x + " " + p.y;
177
+ linePath +=
178
+ i == 0
179
+ ? `M ${p.x} ${p.y}`
180
+ : !data.smooth || span.length < 2
181
+ ? `L ${p.x} ${p.y}`
182
+ : this.getCurvedPathSegment(p, span, i - 1, i - 2, i - 1, i + 1, r);
171
183
  });
172
184
  });
173
185
 
@@ -185,13 +197,35 @@ export class LineGraph extends Widget {
185
197
  lineSpans.forEach((span) => {
186
198
  let closePath = "";
187
199
  span.forEach((p, i) => {
188
- areaPath += i == 0 ? " M " : " L ";
189
- areaPath += p.x + " " + p.y;
190
- if (data.area) closePath = `L ${p.x} ${p.y0} ` + closePath;
200
+ let segment = "";
201
+ if (i == 0) {
202
+ segment = `M ${p.x} ${p.y}`;
203
+
204
+ // closing point
205
+ closePath =
206
+ !data.smooth || span.length < 2
207
+ ? `L ${p.x} ${p.y0}`
208
+ : this.getCurvedPathSegment(p, span, i + 1, i + 2, i + 1, i - 1, r, "y0");
209
+ } else {
210
+ if (!data.smooth) {
211
+ segment = `L ${p.x} ${p.y}`;
212
+ closePath = `L ${p.x} ${p.y0}` + closePath;
213
+ } else {
214
+ segment = this.getCurvedPathSegment(p, span, i - 1, i - 2, i - 1, i + 1, r, "y");
215
+
216
+ // closing point
217
+ if (i < span.length - 1)
218
+ closePath = this.getCurvedPathSegment(p, span, i + 1, i + 2, i + 1, i - 1, r, "y0") + closePath;
219
+ }
220
+ }
221
+ areaPath += segment;
191
222
  });
223
+
224
+ areaPath += `L ${span[span.length - 1].x} ${span[span.length - 1].y0}`;
192
225
  areaPath += closePath;
193
- areaPath += `L ${span[0].x} ${span[0].y}`;
226
+ areaPath += "Z";
194
227
  });
228
+
195
229
  area = (
196
230
  <path
197
231
  className={this.CSS.element(this.baseClass, "area", stateMods)}
@@ -208,6 +242,39 @@ export class LineGraph extends Widget {
208
242
  </g>
209
243
  );
210
244
  }
245
+
246
+ getCurvedPathSegment(p, points, i1, i2, j1, j2, r, yField = "y") {
247
+ const [sx, sy] = this.getControlPoint({ cp: points[i1], pp: points[i2], r, np: p, yField });
248
+ const [ex, ey] = this.getControlPoint({ cp: p, pp: points[j1], np: points[j2], r, reverse: true, yField });
249
+
250
+ return `C ${sx} ${sy}, ${ex} ${ey}, ${p.x} ${p[yField]}`;
251
+ }
252
+
253
+ getControlPoint({ cp, pp, np, r, reverse, yField = "y" }) {
254
+ // When 'current' is the first or last point of the array 'previous' or 'next' don't exist. Replace with 'current'.
255
+ const p = pp || cp;
256
+ const n = np || cp;
257
+
258
+ // Properties of the opposed-line
259
+ let { angle, length } = this.getLineInfo(p.x, p[yField], n.x, n[yField]);
260
+ // If it is end-control-point, add PI to the angle to go backward
261
+ angle = angle + (reverse ? Math.PI : 0);
262
+ length = length * r;
263
+ // The control point position is relative to the current point
264
+ const x = cp.x + Math.cos(angle) * length;
265
+ const y = cp[yField] + Math.sin(angle) * length;
266
+ return [x, y];
267
+ }
268
+
269
+ getLineInfo(p1x, p1y, p2x, p2y) {
270
+ const lengthX = p2x - p1x;
271
+ const lengthY = p2y - p1y;
272
+
273
+ return {
274
+ length: Math.sqrt(Math.pow(lengthX, 2) + Math.pow(lengthY, 2)),
275
+ angle: Math.atan2(lengthY, lengthX),
276
+ };
277
+ }
211
278
  }
212
279
 
213
280
  LineGraph.prototype.xAxis = "x";
@@ -227,4 +294,7 @@ LineGraph.prototype.legendShape = "rect";
227
294
  LineGraph.prototype.stack = "stack";
228
295
  LineGraph.prototype.hiddenBase = false;
229
296
 
297
+ LineGraph.prototype.smooth = false;
298
+ LineGraph.prototype.smoothingRatio = 0.05;
299
+
230
300
  Widget.alias("line-graph", LineGraph);