cx 25.6.0 → 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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cx",
3
- "version": "25.6.0",
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",
@@ -14,7 +14,7 @@
14
14
  },
15
15
  "homepage": "https://cxjs.io",
16
16
  "dependencies": {
17
- "intl-io": "^0.4.3",
17
+ "intl-io": "^0.4.4",
18
18
  "route-parser": "^0.0.5"
19
19
  },
20
20
  "peerDependencies": {
@@ -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);