@yuneta/gobj-ui 7.26.39 → 7.26.40
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/README.md +16 -0
- package/dist/gobj-ui.cjs.js +69 -34
- package/dist/gobj-ui.es.js +69 -34
- package/package.json +1 -1
- package/src/c_yui_uplot.js +8 -58
- package/src/uplot_ink.test.js +105 -0
- package/src/yui_uplot_ink.js +94 -0
package/README.md
CHANGED
|
@@ -3394,6 +3394,22 @@ the middle, and **a toolbar left with a single group is centred**. An unknown
|
|
|
3394
3394
|
name is reported, not silently dropped: a typo would otherwise remove the save
|
|
3395
3395
|
button with no trace of why.
|
|
3396
3396
|
|
|
3397
|
+
### Charts — the ink of the axes, on both schemes
|
|
3398
|
+
|
|
3399
|
+
uPlot is built for a white page: its axis labels are black, its grid 7% black.
|
|
3400
|
+
`C_YUI_UPLOT` gives its axes the ink of the theme -- both of them: uPlot always
|
|
3401
|
+
draws an X and a Y axis, and until 7.26.40 the Y axis kept uPlot's black, which
|
|
3402
|
+
no one could read on the dark scheme. A uPlot built by the app itself takes the
|
|
3403
|
+
same axes from `yui_uplot_axes()`, and redraws on a change of the theme
|
|
3404
|
+
(`yui_watch_theme(gobj)` sends `EV_THEME`; its action calls `chart.redraw()`):
|
|
3405
|
+
|
|
3406
|
+
```js
|
|
3407
|
+
import {yui_uplot_axes} from "@yuneta/gobj-ui/src/yui_uplot_ink.js";
|
|
3408
|
+
|
|
3409
|
+
new uPlot({width: 600, height: 300, series: [{}, {label: "temperature"}],
|
|
3410
|
+
axes: yui_uplot_axes([{}])}, data, $el);
|
|
3411
|
+
```
|
|
3412
|
+
|
|
3397
3413
|
### `C_YUI_FORM` — what closing it asks about
|
|
3398
3414
|
|
|
3399
3415
|
`changes` says the form is not what is stored: the reader changed it, or the
|
package/dist/gobj-ui.cjs.js
CHANGED
|
@@ -13396,41 +13396,58 @@ function register_c_yui_map() {
|
|
|
13396
13396
|
return create_gclass$16(GCLASS_NAME$16);
|
|
13397
13397
|
}
|
|
13398
13398
|
//#endregion
|
|
13399
|
-
//#region src/
|
|
13399
|
+
//#region src/yui_uplot_ink.js
|
|
13400
13400
|
/***********************************************************************
|
|
13401
|
-
*
|
|
13401
|
+
* yui_uplot_ink.js
|
|
13402
13402
|
*
|
|
13403
|
-
*
|
|
13403
|
+
* The ink of a uPlot chart, on both schemes, and its palette.
|
|
13404
13404
|
*
|
|
13405
|
-
*
|
|
13405
|
+
* uPlot is built for a white page: its axis labels are `#000`
|
|
13406
|
+
* and its grid `rgba(0,0,0,0.07)`, which on the dark scheme are
|
|
13407
|
+
* 1.16:1 and 1.04 -- an axis nobody can read and a grid that is
|
|
13408
|
+
* not there. The inks here are handed to uPlot as FUNCTIONS: it
|
|
13409
|
+
* calls them when it draws, so the value can never be stale --
|
|
13410
|
+
* what goes stale is the canvas, and a change of the theme has to
|
|
13411
|
+
* ask for a redraw (yui_watch_theme() turns it into an event).
|
|
13412
|
+
*
|
|
13413
|
+
* uPlot ALWAYS draws a Y axis: its setDefaults() makes axes[1]
|
|
13414
|
+
* whether it was given or not, with its own black. So the axes are
|
|
13415
|
+
* padded to two before they are inked. C_YUI_UPLOT's default is
|
|
13416
|
+
* `[{}]`, the X axis alone, and until 7.26.40 every chart of the
|
|
13417
|
+
* library had a Y axis whose values could not be read in the dark.
|
|
13418
|
+
*
|
|
13419
|
+
* C_YUI_UPLOT uses it, and so can an app that builds a uPlot of its
|
|
13420
|
+
* own:
|
|
13421
|
+
*
|
|
13422
|
+
* import {yui_uplot_axes} from "@yuneta/gobj-ui/src/yui_uplot_ink.js";
|
|
13423
|
+
*
|
|
13424
|
+
* const chart = new uPlot({
|
|
13425
|
+
* width: 600, height: 300,
|
|
13426
|
+
* series: [{}, {label: "temperature"}],
|
|
13427
|
+
* axes: yui_uplot_axes([{}]), // X and Y, with the ink of the theme
|
|
13428
|
+
* }, data, $el);
|
|
13429
|
+
*
|
|
13430
|
+
* The palette is six colours that clear 3:1 on BOTH grounds
|
|
13431
|
+
* (worst 3.39 on white, 3.71 on near-black), ordered so the first
|
|
13432
|
+
* two are the pair that survives colour blindness -- blue and
|
|
13433
|
+
* orange, never red and green as the opening pair.
|
|
13434
|
+
*
|
|
13435
|
+
* Copyright (c) 2026, ArtGins.
|
|
13406
13436
|
* All Rights Reserved.
|
|
13407
13437
|
***********************************************************************/
|
|
13408
|
-
|
|
13409
|
-
* The ink of
|
|
13410
|
-
|
|
13411
|
-
|
|
13412
|
-
* and its grid `rgba(0,0,0,0.07)`, which on the dark scheme are
|
|
13413
|
-
* 1.16:1 and 1.04 -- an axis nobody can read and a grid that is
|
|
13414
|
-
* not there. And the series were CSS colour names: `blue` is
|
|
13415
|
-
* 2.11:1 on the dark ground, `orange` 1.97 on the light one, so
|
|
13416
|
-
* whichever scheme you were in, one of the lines was a rumour.
|
|
13417
|
-
*
|
|
13418
|
-
* These are given to uPlot as FUNCTIONS: it calls them when it
|
|
13419
|
-
* draws, so the value can never be stale -- what goes stale is
|
|
13420
|
-
* the canvas, and that is what EV_THEME redraws.
|
|
13421
|
-
*
|
|
13422
|
-
* The palette is six colours that clear 3:1 on BOTH grounds
|
|
13423
|
-
* (worst 3.39 on white, 3.71 on near-black), ordered so the
|
|
13424
|
-
* first two are the pair that survives colour blindness -- blue
|
|
13425
|
-
* and orange, never red and green as the opening pair.
|
|
13426
|
-
***************************************************************/
|
|
13427
|
-
function axis_ink() {
|
|
13438
|
+
/************************************************************
|
|
13439
|
+
* The ink of the labels of an axis.
|
|
13440
|
+
************************************************************/
|
|
13441
|
+
function yui_uplot_axis_ink() {
|
|
13428
13442
|
return yui_is_dark() ? "#c7cdd8" : "#2e333d";
|
|
13429
13443
|
}
|
|
13430
|
-
|
|
13444
|
+
/************************************************************
|
|
13445
|
+
* The ink of the grid and of the ticks.
|
|
13446
|
+
************************************************************/
|
|
13447
|
+
function yui_uplot_grid_ink() {
|
|
13431
13448
|
return yui_is_dark() ? "rgba(199,205,216,0.16)" : "rgba(46,51,61,0.12)";
|
|
13432
13449
|
}
|
|
13433
|
-
var
|
|
13450
|
+
var YUI_UPLOT_PALETTE = [
|
|
13434
13451
|
{
|
|
13435
13452
|
stroke: "#2f6fd0",
|
|
13436
13453
|
fill: "rgba(47,111,208,0.10)"
|
|
@@ -13456,15 +13473,33 @@ var CHART_PALETTE = [
|
|
|
13456
13473
|
fill: "rgba(209,52,75,0.10)"
|
|
13457
13474
|
}
|
|
13458
13475
|
];
|
|
13459
|
-
|
|
13460
|
-
|
|
13476
|
+
/************************************************************
|
|
13477
|
+
* The axes the host asked for -- at least the X and the Y,
|
|
13478
|
+
* the two uPlot always draws -- with the ink it did not ask
|
|
13479
|
+
* about. A stroke, a grid or a ticks the host gave is kept.
|
|
13480
|
+
* Answers new objects: the host's are not touched.
|
|
13481
|
+
************************************************************/
|
|
13482
|
+
function yui_uplot_axes(axes) {
|
|
13483
|
+
let list = Array.isArray(axes) ? axes.slice() : [axes || {}];
|
|
13484
|
+
while (list.length < 2) list.push({});
|
|
13485
|
+
return list.map((ax) => {
|
|
13461
13486
|
let a = Object.assign({}, ax || {});
|
|
13462
|
-
if (a.stroke === void 0) a.stroke =
|
|
13463
|
-
a.grid = Object.assign({ stroke:
|
|
13464
|
-
a.ticks = Object.assign({ stroke:
|
|
13487
|
+
if (a.stroke === void 0) a.stroke = yui_uplot_axis_ink;
|
|
13488
|
+
a.grid = Object.assign({ stroke: yui_uplot_grid_ink }, a.grid || {});
|
|
13489
|
+
a.ticks = Object.assign({ stroke: yui_uplot_grid_ink }, a.ticks || {});
|
|
13465
13490
|
return a;
|
|
13466
13491
|
});
|
|
13467
13492
|
}
|
|
13493
|
+
//#endregion
|
|
13494
|
+
//#region src/c_yui_uplot.js
|
|
13495
|
+
/***********************************************************************
|
|
13496
|
+
* c_yui_uplot.js
|
|
13497
|
+
*
|
|
13498
|
+
* Graphics, Charts with uPlot
|
|
13499
|
+
*
|
|
13500
|
+
* Copyright (c) 2025-2026, ArtGins.
|
|
13501
|
+
* All Rights Reserved.
|
|
13502
|
+
***********************************************************************/
|
|
13468
13503
|
/***************************************************************
|
|
13469
13504
|
* Constants
|
|
13470
13505
|
***************************************************************/
|
|
@@ -13482,7 +13517,7 @@ var attrs_table$15 = [
|
|
|
13482
13517
|
(0, _yuneta_gobj_js.SDATA)(_yuneta_gobj_js.data_type_t.DTP_JSON, "axes", 0, [{}], "Chart axes"),
|
|
13483
13518
|
(0, _yuneta_gobj_js.SDATA)(_yuneta_gobj_js.data_type_t.DTP_JSON, "scales", 0, {}, "Chart scales"),
|
|
13484
13519
|
(0, _yuneta_gobj_js.SDATA)(_yuneta_gobj_js.data_type_t.DTP_JSON, "data", 0, [[]], "Chart data"),
|
|
13485
|
-
(0, _yuneta_gobj_js.SDATA)(_yuneta_gobj_js.data_type_t.DTP_JSON, "colors", 0,
|
|
13520
|
+
(0, _yuneta_gobj_js.SDATA)(_yuneta_gobj_js.data_type_t.DTP_JSON, "colors", 0, YUI_UPLOT_PALETTE, "Series colours, in order. The default palette clears 3:1 on both schemes and opens with the colour-blind-safe pair (blue, orange)"),
|
|
13486
13521
|
(0, _yuneta_gobj_js.SDATA)(_yuneta_gobj_js.data_type_t.DTP_POINTER, "$container", 0, null, "HTML container for the chart"),
|
|
13487
13522
|
(0, _yuneta_gobj_js.SDATA)(_yuneta_gobj_js.data_type_t.DTP_BOOLEAN, "own_container", 0, false, "If true, container is gobj-managed"),
|
|
13488
13523
|
(0, _yuneta_gobj_js.SDATA)(_yuneta_gobj_js.data_type_t.DTP_POINTER, "uplot", 0, null, "uPlot instance"),
|
|
@@ -13549,7 +13584,7 @@ function build_ui$14(gobj) {
|
|
|
13549
13584
|
width: (0, _yuneta_gobj_js.gobj_read_attr)(gobj, "width"),
|
|
13550
13585
|
height: (0, _yuneta_gobj_js.gobj_read_attr)(gobj, "height"),
|
|
13551
13586
|
series: (0, _yuneta_gobj_js.gobj_read_attr)(gobj, "series"),
|
|
13552
|
-
axes:
|
|
13587
|
+
axes: yui_uplot_axes((0, _yuneta_gobj_js.gobj_read_attr)(gobj, "axes")),
|
|
13553
13588
|
scales: (0, _yuneta_gobj_js.gobj_read_attr)(gobj, "scales")
|
|
13554
13589
|
};
|
|
13555
13590
|
let uplot$2 = new uplot.default(uPlot_options, (0, _yuneta_gobj_js.gobj_read_attr)(gobj, "data"), $container);
|
|
@@ -13650,7 +13685,7 @@ function ac_add_serie(gobj, event, kw, src) {
|
|
|
13650
13685
|
}
|
|
13651
13686
|
}
|
|
13652
13687
|
let colors = (0, _yuneta_gobj_js.gobj_read_attr)(gobj, "colors");
|
|
13653
|
-
if (!Array.isArray(colors) || !colors.length) colors =
|
|
13688
|
+
if (!Array.isArray(colors) || !colors.length) colors = YUI_UPLOT_PALETTE;
|
|
13654
13689
|
let color = colors[Math.max(0, idx - 1) % colors.length];
|
|
13655
13690
|
if (kw.stroke === void 0) kw.stroke = color.stroke;
|
|
13656
13691
|
if (kw.fill === void 0) kw.fill = color.fill;
|
package/dist/gobj-ui.es.js
CHANGED
|
@@ -13391,41 +13391,58 @@ function register_c_yui_map() {
|
|
|
13391
13391
|
return create_gclass$16(GCLASS_NAME$16);
|
|
13392
13392
|
}
|
|
13393
13393
|
//#endregion
|
|
13394
|
-
//#region src/
|
|
13394
|
+
//#region src/yui_uplot_ink.js
|
|
13395
13395
|
/***********************************************************************
|
|
13396
|
-
*
|
|
13396
|
+
* yui_uplot_ink.js
|
|
13397
13397
|
*
|
|
13398
|
-
*
|
|
13398
|
+
* The ink of a uPlot chart, on both schemes, and its palette.
|
|
13399
13399
|
*
|
|
13400
|
-
*
|
|
13400
|
+
* uPlot is built for a white page: its axis labels are `#000`
|
|
13401
|
+
* and its grid `rgba(0,0,0,0.07)`, which on the dark scheme are
|
|
13402
|
+
* 1.16:1 and 1.04 -- an axis nobody can read and a grid that is
|
|
13403
|
+
* not there. The inks here are handed to uPlot as FUNCTIONS: it
|
|
13404
|
+
* calls them when it draws, so the value can never be stale --
|
|
13405
|
+
* what goes stale is the canvas, and a change of the theme has to
|
|
13406
|
+
* ask for a redraw (yui_watch_theme() turns it into an event).
|
|
13407
|
+
*
|
|
13408
|
+
* uPlot ALWAYS draws a Y axis: its setDefaults() makes axes[1]
|
|
13409
|
+
* whether it was given or not, with its own black. So the axes are
|
|
13410
|
+
* padded to two before they are inked. C_YUI_UPLOT's default is
|
|
13411
|
+
* `[{}]`, the X axis alone, and until 7.26.40 every chart of the
|
|
13412
|
+
* library had a Y axis whose values could not be read in the dark.
|
|
13413
|
+
*
|
|
13414
|
+
* C_YUI_UPLOT uses it, and so can an app that builds a uPlot of its
|
|
13415
|
+
* own:
|
|
13416
|
+
*
|
|
13417
|
+
* import {yui_uplot_axes} from "@yuneta/gobj-ui/src/yui_uplot_ink.js";
|
|
13418
|
+
*
|
|
13419
|
+
* const chart = new uPlot({
|
|
13420
|
+
* width: 600, height: 300,
|
|
13421
|
+
* series: [{}, {label: "temperature"}],
|
|
13422
|
+
* axes: yui_uplot_axes([{}]), // X and Y, with the ink of the theme
|
|
13423
|
+
* }, data, $el);
|
|
13424
|
+
*
|
|
13425
|
+
* The palette is six colours that clear 3:1 on BOTH grounds
|
|
13426
|
+
* (worst 3.39 on white, 3.71 on near-black), ordered so the first
|
|
13427
|
+
* two are the pair that survives colour blindness -- blue and
|
|
13428
|
+
* orange, never red and green as the opening pair.
|
|
13429
|
+
*
|
|
13430
|
+
* Copyright (c) 2026, ArtGins.
|
|
13401
13431
|
* All Rights Reserved.
|
|
13402
13432
|
***********************************************************************/
|
|
13403
|
-
|
|
13404
|
-
* The ink of
|
|
13405
|
-
|
|
13406
|
-
|
|
13407
|
-
* and its grid `rgba(0,0,0,0.07)`, which on the dark scheme are
|
|
13408
|
-
* 1.16:1 and 1.04 -- an axis nobody can read and a grid that is
|
|
13409
|
-
* not there. And the series were CSS colour names: `blue` is
|
|
13410
|
-
* 2.11:1 on the dark ground, `orange` 1.97 on the light one, so
|
|
13411
|
-
* whichever scheme you were in, one of the lines was a rumour.
|
|
13412
|
-
*
|
|
13413
|
-
* These are given to uPlot as FUNCTIONS: it calls them when it
|
|
13414
|
-
* draws, so the value can never be stale -- what goes stale is
|
|
13415
|
-
* the canvas, and that is what EV_THEME redraws.
|
|
13416
|
-
*
|
|
13417
|
-
* The palette is six colours that clear 3:1 on BOTH grounds
|
|
13418
|
-
* (worst 3.39 on white, 3.71 on near-black), ordered so the
|
|
13419
|
-
* first two are the pair that survives colour blindness -- blue
|
|
13420
|
-
* and orange, never red and green as the opening pair.
|
|
13421
|
-
***************************************************************/
|
|
13422
|
-
function axis_ink() {
|
|
13433
|
+
/************************************************************
|
|
13434
|
+
* The ink of the labels of an axis.
|
|
13435
|
+
************************************************************/
|
|
13436
|
+
function yui_uplot_axis_ink() {
|
|
13423
13437
|
return yui_is_dark() ? "#c7cdd8" : "#2e333d";
|
|
13424
13438
|
}
|
|
13425
|
-
|
|
13439
|
+
/************************************************************
|
|
13440
|
+
* The ink of the grid and of the ticks.
|
|
13441
|
+
************************************************************/
|
|
13442
|
+
function yui_uplot_grid_ink() {
|
|
13426
13443
|
return yui_is_dark() ? "rgba(199,205,216,0.16)" : "rgba(46,51,61,0.12)";
|
|
13427
13444
|
}
|
|
13428
|
-
var
|
|
13445
|
+
var YUI_UPLOT_PALETTE = [
|
|
13429
13446
|
{
|
|
13430
13447
|
stroke: "#2f6fd0",
|
|
13431
13448
|
fill: "rgba(47,111,208,0.10)"
|
|
@@ -13451,15 +13468,33 @@ var CHART_PALETTE = [
|
|
|
13451
13468
|
fill: "rgba(209,52,75,0.10)"
|
|
13452
13469
|
}
|
|
13453
13470
|
];
|
|
13454
|
-
|
|
13455
|
-
|
|
13471
|
+
/************************************************************
|
|
13472
|
+
* The axes the host asked for -- at least the X and the Y,
|
|
13473
|
+
* the two uPlot always draws -- with the ink it did not ask
|
|
13474
|
+
* about. A stroke, a grid or a ticks the host gave is kept.
|
|
13475
|
+
* Answers new objects: the host's are not touched.
|
|
13476
|
+
************************************************************/
|
|
13477
|
+
function yui_uplot_axes(axes) {
|
|
13478
|
+
let list = Array.isArray(axes) ? axes.slice() : [axes || {}];
|
|
13479
|
+
while (list.length < 2) list.push({});
|
|
13480
|
+
return list.map((ax) => {
|
|
13456
13481
|
let a = Object.assign({}, ax || {});
|
|
13457
|
-
if (a.stroke === void 0) a.stroke =
|
|
13458
|
-
a.grid = Object.assign({ stroke:
|
|
13459
|
-
a.ticks = Object.assign({ stroke:
|
|
13482
|
+
if (a.stroke === void 0) a.stroke = yui_uplot_axis_ink;
|
|
13483
|
+
a.grid = Object.assign({ stroke: yui_uplot_grid_ink }, a.grid || {});
|
|
13484
|
+
a.ticks = Object.assign({ stroke: yui_uplot_grid_ink }, a.ticks || {});
|
|
13460
13485
|
return a;
|
|
13461
13486
|
});
|
|
13462
13487
|
}
|
|
13488
|
+
//#endregion
|
|
13489
|
+
//#region src/c_yui_uplot.js
|
|
13490
|
+
/***********************************************************************
|
|
13491
|
+
* c_yui_uplot.js
|
|
13492
|
+
*
|
|
13493
|
+
* Graphics, Charts with uPlot
|
|
13494
|
+
*
|
|
13495
|
+
* Copyright (c) 2025-2026, ArtGins.
|
|
13496
|
+
* All Rights Reserved.
|
|
13497
|
+
***********************************************************************/
|
|
13463
13498
|
/***************************************************************
|
|
13464
13499
|
* Constants
|
|
13465
13500
|
***************************************************************/
|
|
@@ -13477,7 +13512,7 @@ var attrs_table$15 = [
|
|
|
13477
13512
|
SDATA(data_type_t.DTP_JSON, "axes", 0, [{}], "Chart axes"),
|
|
13478
13513
|
SDATA(data_type_t.DTP_JSON, "scales", 0, {}, "Chart scales"),
|
|
13479
13514
|
SDATA(data_type_t.DTP_JSON, "data", 0, [[]], "Chart data"),
|
|
13480
|
-
SDATA(data_type_t.DTP_JSON, "colors", 0,
|
|
13515
|
+
SDATA(data_type_t.DTP_JSON, "colors", 0, YUI_UPLOT_PALETTE, "Series colours, in order. The default palette clears 3:1 on both schemes and opens with the colour-blind-safe pair (blue, orange)"),
|
|
13481
13516
|
SDATA(data_type_t.DTP_POINTER, "$container", 0, null, "HTML container for the chart"),
|
|
13482
13517
|
SDATA(data_type_t.DTP_BOOLEAN, "own_container", 0, false, "If true, container is gobj-managed"),
|
|
13483
13518
|
SDATA(data_type_t.DTP_POINTER, "uplot", 0, null, "uPlot instance"),
|
|
@@ -13544,7 +13579,7 @@ function build_ui$14(gobj) {
|
|
|
13544
13579
|
width: gobj_read_attr(gobj, "width"),
|
|
13545
13580
|
height: gobj_read_attr(gobj, "height"),
|
|
13546
13581
|
series: gobj_read_attr(gobj, "series"),
|
|
13547
|
-
axes:
|
|
13582
|
+
axes: yui_uplot_axes(gobj_read_attr(gobj, "axes")),
|
|
13548
13583
|
scales: gobj_read_attr(gobj, "scales")
|
|
13549
13584
|
};
|
|
13550
13585
|
let uplot = new uPlot(uPlot_options, gobj_read_attr(gobj, "data"), $container);
|
|
@@ -13645,7 +13680,7 @@ function ac_add_serie(gobj, event, kw, src) {
|
|
|
13645
13680
|
}
|
|
13646
13681
|
}
|
|
13647
13682
|
let colors = gobj_read_attr(gobj, "colors");
|
|
13648
|
-
if (!Array.isArray(colors) || !colors.length) colors =
|
|
13683
|
+
if (!Array.isArray(colors) || !colors.length) colors = YUI_UPLOT_PALETTE;
|
|
13649
13684
|
let color = colors[Math.max(0, idx - 1) % colors.length];
|
|
13650
13685
|
if (kw.stroke === void 0) kw.stroke = color.stroke;
|
|
13651
13686
|
if (kw.fill === void 0) kw.fill = color.fill;
|
package/package.json
CHANGED
package/src/c_yui_uplot.js
CHANGED
|
@@ -30,62 +30,12 @@ import {
|
|
|
30
30
|
import uPlot from "uplot";
|
|
31
31
|
import "uplot/dist/uPlot.min.css";
|
|
32
32
|
|
|
33
|
-
import {
|
|
33
|
+
import {yui_watch_theme} from "./yui_theme.js";
|
|
34
|
+
/* The ink of the axes -- the X and the Y -- and the palette of the
|
|
35
|
+
* series, on both schemes: see yui_uplot_ink.js. */
|
|
36
|
+
import {yui_uplot_axes, YUI_UPLOT_PALETTE} from "./yui_uplot_ink.js";
|
|
34
37
|
|
|
35
38
|
|
|
36
|
-
/***************************************************************
|
|
37
|
-
* The ink of a chart, and its palette.
|
|
38
|
-
*
|
|
39
|
-
* uPlot is built for a white page: its axis labels are `#000`
|
|
40
|
-
* and its grid `rgba(0,0,0,0.07)`, which on the dark scheme are
|
|
41
|
-
* 1.16:1 and 1.04 -- an axis nobody can read and a grid that is
|
|
42
|
-
* not there. And the series were CSS colour names: `blue` is
|
|
43
|
-
* 2.11:1 on the dark ground, `orange` 1.97 on the light one, so
|
|
44
|
-
* whichever scheme you were in, one of the lines was a rumour.
|
|
45
|
-
*
|
|
46
|
-
* These are given to uPlot as FUNCTIONS: it calls them when it
|
|
47
|
-
* draws, so the value can never be stale -- what goes stale is
|
|
48
|
-
* the canvas, and that is what EV_THEME redraws.
|
|
49
|
-
*
|
|
50
|
-
* The palette is six colours that clear 3:1 on BOTH grounds
|
|
51
|
-
* (worst 3.39 on white, 3.71 on near-black), ordered so the
|
|
52
|
-
* first two are the pair that survives colour blindness -- blue
|
|
53
|
-
* and orange, never red and green as the opening pair.
|
|
54
|
-
***************************************************************/
|
|
55
|
-
function axis_ink()
|
|
56
|
-
{
|
|
57
|
-
return yui_is_dark()? "#c7cdd8" : "#2e333d";
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
function grid_ink()
|
|
61
|
-
{
|
|
62
|
-
return yui_is_dark()? "rgba(199,205,216,0.16)" : "rgba(46,51,61,0.12)";
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
const CHART_PALETTE = [
|
|
66
|
-
{stroke: "#2f6fd0", fill: "rgba(47,111,208,0.10)"}, /* 4.88 / 3.71 */
|
|
67
|
-
{stroke: "#b8620a", fill: "rgba(184,98,10,0.10)"}, /* 4.38 / 4.13 */
|
|
68
|
-
{stroke: "#2f8f4e", fill: "rgba(47,143,78,0.10)"}, /* 4.07 / 4.45 */
|
|
69
|
-
{stroke: "#8b5cf6", fill: "rgba(139,92,246,0.10)"}, /* 4.23 / 4.28 */
|
|
70
|
-
{stroke: "#0e9aa7", fill: "rgba(14,154,167,0.10)"}, /* 3.39 / 5.35 */
|
|
71
|
-
{stroke: "#d1344b", fill: "rgba(209,52,75,0.10)"}, /* 4.88 / 3.71 */
|
|
72
|
-
];
|
|
73
|
-
|
|
74
|
-
/* The axes the host asked for, with the ink it did not ask about. */
|
|
75
|
-
function themed_axes(axes)
|
|
76
|
-
{
|
|
77
|
-
let list = Array.isArray(axes)? axes : [axes || {}];
|
|
78
|
-
return list.map((ax) => {
|
|
79
|
-
let a = Object.assign({}, ax || {});
|
|
80
|
-
if(a.stroke === undefined) {
|
|
81
|
-
a.stroke = axis_ink;
|
|
82
|
-
}
|
|
83
|
-
a.grid = Object.assign({stroke: grid_ink}, a.grid || {});
|
|
84
|
-
a.ticks = Object.assign({stroke: grid_ink}, a.ticks || {});
|
|
85
|
-
return a;
|
|
86
|
-
});
|
|
87
|
-
}
|
|
88
|
-
|
|
89
39
|
/***************************************************************
|
|
90
40
|
* Constants
|
|
91
41
|
***************************************************************/
|
|
@@ -104,7 +54,7 @@ SDATA(data_type_t.DTP_JSON, "series", 0, [{}], "Data series"),
|
|
|
104
54
|
SDATA(data_type_t.DTP_JSON, "axes", 0, [{}], "Chart axes"),
|
|
105
55
|
SDATA(data_type_t.DTP_JSON, "scales", 0, {}, "Chart scales"),
|
|
106
56
|
SDATA(data_type_t.DTP_JSON, "data", 0, [[]], "Chart data"),
|
|
107
|
-
SDATA(data_type_t.DTP_JSON, "colors", 0,
|
|
57
|
+
SDATA(data_type_t.DTP_JSON, "colors", 0, YUI_UPLOT_PALETTE,
|
|
108
58
|
"Series colours, in order. The default palette clears 3:1 on both schemes and opens with the colour-blind-safe pair (blue, orange)"),
|
|
109
59
|
SDATA(data_type_t.DTP_POINTER, "$container", 0, null, "HTML container for the chart"),
|
|
110
60
|
SDATA(data_type_t.DTP_BOOLEAN, "own_container", 0, false, "If true, container is gobj-managed"),
|
|
@@ -138,7 +88,7 @@ function mt_create(gobj)
|
|
|
138
88
|
build_ui(gobj);
|
|
139
89
|
|
|
140
90
|
/* A canvas does not restyle itself: the ink is read when uPlot
|
|
141
|
-
* DRAWS (
|
|
91
|
+
* DRAWS (yui_uplot_ink.js), so a theme change only has to reach the
|
|
142
92
|
* machine and ask for a redraw. Same wiring as the graphs. */
|
|
143
93
|
gobj.priv.theme_observer = yui_watch_theme(gobj);
|
|
144
94
|
|
|
@@ -220,7 +170,7 @@ function build_ui(gobj)
|
|
|
220
170
|
width: gobj_read_attr(gobj, "width"),
|
|
221
171
|
height: gobj_read_attr(gobj, "height"),
|
|
222
172
|
series: gobj_read_attr(gobj, "series"),
|
|
223
|
-
axes:
|
|
173
|
+
axes: yui_uplot_axes(gobj_read_attr(gobj, "axes")),
|
|
224
174
|
scales: gobj_read_attr(gobj, "scales"),
|
|
225
175
|
};
|
|
226
176
|
let uplot = new uPlot(
|
|
@@ -444,7 +394,7 @@ function ac_add_serie(gobj, event, kw, src)
|
|
|
444
394
|
}
|
|
445
395
|
let colors = gobj_read_attr(gobj, "colors");
|
|
446
396
|
if(!Array.isArray(colors) || !colors.length) {
|
|
447
|
-
colors =
|
|
397
|
+
colors = YUI_UPLOT_PALETTE;
|
|
448
398
|
}
|
|
449
399
|
/* `idx` counts uPlot's series, and series[0] is the X AXIS -- so
|
|
450
400
|
* the first line drawn was taking colours[1] and the palette's
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
/***********************************************************************
|
|
2
|
+
* uplot_ink.test.js
|
|
3
|
+
*
|
|
4
|
+
* The axes of a chart carry the ink of the theme -- the Y axis
|
|
5
|
+
* too. uPlot always draws one (its setDefaults() makes axes[1]
|
|
6
|
+
* whether it was given or not, with its own black), and
|
|
7
|
+
* C_YUI_UPLOT inked only the axes it was handed: by default one,
|
|
8
|
+
* the X. In the dark scheme the values of every Y axis of the
|
|
9
|
+
* library were black on near-black (a user's report, the cards of
|
|
10
|
+
* estadodelaire).
|
|
11
|
+
*
|
|
12
|
+
* Copyright (c) 2026, ArtGins.
|
|
13
|
+
* All Rights Reserved.
|
|
14
|
+
***********************************************************************/
|
|
15
|
+
import {describe, test, expect, beforeAll, beforeEach, afterEach, vi} from "vitest";
|
|
16
|
+
import {install_dom_double} from "../test/dom_double.js";
|
|
17
|
+
|
|
18
|
+
install_dom_double();
|
|
19
|
+
|
|
20
|
+
/* What C_YUI_UPLOT hands to uPlot, kept by the stand-in. */
|
|
21
|
+
let given = null;
|
|
22
|
+
vi.mock("uplot", () => ({
|
|
23
|
+
default: class {
|
|
24
|
+
constructor(opts) {
|
|
25
|
+
given = opts;
|
|
26
|
+
this.series = [{}];
|
|
27
|
+
}
|
|
28
|
+
setSize() {}
|
|
29
|
+
addSeries() {}
|
|
30
|
+
redraw() {}
|
|
31
|
+
destroy() {}
|
|
32
|
+
}
|
|
33
|
+
}));
|
|
34
|
+
|
|
35
|
+
const {
|
|
36
|
+
gobj_start_up, gobj_create_yuno, gobj_create_pure_child, gclass_create,
|
|
37
|
+
set_log_callback, SDATA_END,
|
|
38
|
+
} = await import("@yuneta/gobj-js");
|
|
39
|
+
const {register_c_yui_uplot} = await import("./c_yui_uplot.js");
|
|
40
|
+
const {
|
|
41
|
+
yui_uplot_axes, yui_uplot_axis_ink, yui_uplot_grid_ink,
|
|
42
|
+
} = await import("./yui_uplot_ink.js");
|
|
43
|
+
|
|
44
|
+
const logged = [];
|
|
45
|
+
let yuno = null;
|
|
46
|
+
|
|
47
|
+
beforeAll(() => {
|
|
48
|
+
gobj_start_up(null, null, null, null, null, null, null);
|
|
49
|
+
set_log_callback((level, msg) => {
|
|
50
|
+
logged.push({level: String(level), msg: String(msg)});
|
|
51
|
+
});
|
|
52
|
+
gclass_create("C_TEST_INK_HOST", [], [["ST_IDLE", []]], {}, 0, [SDATA_END()], {}, 0, 0, 0, 0);
|
|
53
|
+
register_c_yui_uplot();
|
|
54
|
+
yuno = gobj_create_yuno("ink_yuno", "C_TEST_INK_HOST", {});
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
beforeEach(() => {
|
|
58
|
+
logged.length = 0;
|
|
59
|
+
given = null;
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
afterEach(() => {
|
|
63
|
+
document.documentElement.removeAttribute("data-theme");
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
describe("yui_uplot_axes()", () => {
|
|
67
|
+
test("gives the X and the Y axes, the two uPlot draws", () => {
|
|
68
|
+
expect(yui_uplot_axes([{}]).length).toBe(2);
|
|
69
|
+
expect(yui_uplot_axes(undefined).length).toBe(2);
|
|
70
|
+
expect(yui_uplot_axes([]).length).toBe(2);
|
|
71
|
+
expect(yui_uplot_axes([{}, {}, {scale: "%"}]).length).toBe(3);
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
test("inks each one with the theme, read when uPlot draws", () => {
|
|
75
|
+
const axes = yui_uplot_axes([{}]);
|
|
76
|
+
for(const a of axes) {
|
|
77
|
+
expect(a.stroke).toBe(yui_uplot_axis_ink);
|
|
78
|
+
expect(a.grid.stroke).toBe(yui_uplot_grid_ink);
|
|
79
|
+
expect(a.ticks.stroke).toBe(yui_uplot_grid_ink);
|
|
80
|
+
}
|
|
81
|
+
document.documentElement.setAttribute("data-theme", "light");
|
|
82
|
+
expect(axes[1].stroke()).toBe("#2e333d");
|
|
83
|
+
document.documentElement.setAttribute("data-theme", "dark");
|
|
84
|
+
expect(axes[1].stroke()).toBe("#c7cdd8");
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
test("keeps what the host gave, and does not touch its objects", () => {
|
|
88
|
+
const mine = [{stroke: "red", grid: {show: false}}];
|
|
89
|
+
const axes = yui_uplot_axes(mine);
|
|
90
|
+
expect(axes[0].stroke).toBe("red");
|
|
91
|
+
expect(axes[0].grid).toEqual({stroke: yui_uplot_grid_ink, show: false});
|
|
92
|
+
expect(mine).toEqual([{stroke: "red", grid: {show: false}}]);
|
|
93
|
+
});
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
describe("C_YUI_UPLOT", () => {
|
|
97
|
+
test("hands uPlot a Y axis with the ink of the theme", () => {
|
|
98
|
+
gobj_create_pure_child("ink_chart", "C_YUI_UPLOT", {}, yuno);
|
|
99
|
+
expect(given).toBeTruthy();
|
|
100
|
+
expect(given.axes.length).toBe(2);
|
|
101
|
+
expect(given.axes[1].stroke).toBe(yui_uplot_axis_ink);
|
|
102
|
+
expect(given.axes[1].grid.stroke).toBe(yui_uplot_grid_ink);
|
|
103
|
+
expect(logged.filter((l) => /error/i.test(l.level))).toEqual([]);
|
|
104
|
+
});
|
|
105
|
+
});
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
/***********************************************************************
|
|
2
|
+
* yui_uplot_ink.js
|
|
3
|
+
*
|
|
4
|
+
* The ink of a uPlot chart, on both schemes, and its palette.
|
|
5
|
+
*
|
|
6
|
+
* uPlot is built for a white page: its axis labels are `#000`
|
|
7
|
+
* and its grid `rgba(0,0,0,0.07)`, which on the dark scheme are
|
|
8
|
+
* 1.16:1 and 1.04 -- an axis nobody can read and a grid that is
|
|
9
|
+
* not there. The inks here are handed to uPlot as FUNCTIONS: it
|
|
10
|
+
* calls them when it draws, so the value can never be stale --
|
|
11
|
+
* what goes stale is the canvas, and a change of the theme has to
|
|
12
|
+
* ask for a redraw (yui_watch_theme() turns it into an event).
|
|
13
|
+
*
|
|
14
|
+
* uPlot ALWAYS draws a Y axis: its setDefaults() makes axes[1]
|
|
15
|
+
* whether it was given or not, with its own black. So the axes are
|
|
16
|
+
* padded to two before they are inked. C_YUI_UPLOT's default is
|
|
17
|
+
* `[{}]`, the X axis alone, and until 7.26.40 every chart of the
|
|
18
|
+
* library had a Y axis whose values could not be read in the dark.
|
|
19
|
+
*
|
|
20
|
+
* C_YUI_UPLOT uses it, and so can an app that builds a uPlot of its
|
|
21
|
+
* own:
|
|
22
|
+
*
|
|
23
|
+
* import {yui_uplot_axes} from "@yuneta/gobj-ui/src/yui_uplot_ink.js";
|
|
24
|
+
*
|
|
25
|
+
* const chart = new uPlot({
|
|
26
|
+
* width: 600, height: 300,
|
|
27
|
+
* series: [{}, {label: "temperature"}],
|
|
28
|
+
* axes: yui_uplot_axes([{}]), // X and Y, with the ink of the theme
|
|
29
|
+
* }, data, $el);
|
|
30
|
+
*
|
|
31
|
+
* The palette is six colours that clear 3:1 on BOTH grounds
|
|
32
|
+
* (worst 3.39 on white, 3.71 on near-black), ordered so the first
|
|
33
|
+
* two are the pair that survives colour blindness -- blue and
|
|
34
|
+
* orange, never red and green as the opening pair.
|
|
35
|
+
*
|
|
36
|
+
* Copyright (c) 2026, ArtGins.
|
|
37
|
+
* All Rights Reserved.
|
|
38
|
+
***********************************************************************/
|
|
39
|
+
import {yui_is_dark} from "./yui_theme.js";
|
|
40
|
+
|
|
41
|
+
/************************************************************
|
|
42
|
+
* The ink of the labels of an axis.
|
|
43
|
+
************************************************************/
|
|
44
|
+
function yui_uplot_axis_ink()
|
|
45
|
+
{
|
|
46
|
+
return yui_is_dark()? "#c7cdd8" : "#2e333d";
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/************************************************************
|
|
50
|
+
* The ink of the grid and of the ticks.
|
|
51
|
+
************************************************************/
|
|
52
|
+
function yui_uplot_grid_ink()
|
|
53
|
+
{
|
|
54
|
+
return yui_is_dark()? "rgba(199,205,216,0.16)" : "rgba(46,51,61,0.12)";
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
const YUI_UPLOT_PALETTE = [
|
|
58
|
+
{stroke: "#2f6fd0", fill: "rgba(47,111,208,0.10)"}, /* 4.88 / 3.71 */
|
|
59
|
+
{stroke: "#b8620a", fill: "rgba(184,98,10,0.10)"}, /* 4.38 / 4.13 */
|
|
60
|
+
{stroke: "#2f8f4e", fill: "rgba(47,143,78,0.10)"}, /* 4.07 / 4.45 */
|
|
61
|
+
{stroke: "#8b5cf6", fill: "rgba(139,92,246,0.10)"}, /* 4.23 / 4.28 */
|
|
62
|
+
{stroke: "#0e9aa7", fill: "rgba(14,154,167,0.10)"}, /* 3.39 / 5.35 */
|
|
63
|
+
{stroke: "#d1344b", fill: "rgba(209,52,75,0.10)"}, /* 4.88 / 3.71 */
|
|
64
|
+
];
|
|
65
|
+
|
|
66
|
+
/************************************************************
|
|
67
|
+
* The axes the host asked for -- at least the X and the Y,
|
|
68
|
+
* the two uPlot always draws -- with the ink it did not ask
|
|
69
|
+
* about. A stroke, a grid or a ticks the host gave is kept.
|
|
70
|
+
* Answers new objects: the host's are not touched.
|
|
71
|
+
************************************************************/
|
|
72
|
+
function yui_uplot_axes(axes)
|
|
73
|
+
{
|
|
74
|
+
let list = Array.isArray(axes)? axes.slice() : [axes || {}];
|
|
75
|
+
while(list.length < 2) {
|
|
76
|
+
list.push({});
|
|
77
|
+
}
|
|
78
|
+
return list.map((ax) => {
|
|
79
|
+
let a = Object.assign({}, ax || {});
|
|
80
|
+
if(a.stroke === undefined) {
|
|
81
|
+
a.stroke = yui_uplot_axis_ink;
|
|
82
|
+
}
|
|
83
|
+
a.grid = Object.assign({stroke: yui_uplot_grid_ink}, a.grid || {});
|
|
84
|
+
a.ticks = Object.assign({stroke: yui_uplot_grid_ink}, a.ticks || {});
|
|
85
|
+
return a;
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
export {
|
|
90
|
+
yui_uplot_axes,
|
|
91
|
+
yui_uplot_axis_ink,
|
|
92
|
+
yui_uplot_grid_ink,
|
|
93
|
+
YUI_UPLOT_PALETTE,
|
|
94
|
+
};
|