@funnest/charts-react 0.2.0 → 0.2.1
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/index.js +24 -8
- package/dist/viz/context.d.ts +9 -0
- package/package.json +4 -4
package/dist/index.js
CHANGED
|
@@ -93,6 +93,7 @@ import {
|
|
|
93
93
|
|
|
94
94
|
// src/viz/context.ts
|
|
95
95
|
import { createContext as createContext2, useContext as useContext2 } from "react";
|
|
96
|
+
var nearScrub = (ctx, x, within = 56) => ctx.scrubIndex !== null && Math.abs(ctx.x(ctx.scrubIndex) - x) < within;
|
|
96
97
|
var CartesianContext = createContext2(null);
|
|
97
98
|
function useCartesianChart() {
|
|
98
99
|
const ctx = useContext2(CartesianContext);
|
|
@@ -244,6 +245,7 @@ function CartesianChart({
|
|
|
244
245
|
const [motion, setMotion] = useState2(false);
|
|
245
246
|
const [hidden, setHidden] = useState2([]);
|
|
246
247
|
const [emphasis, setEmphasis] = useState2(null);
|
|
248
|
+
const [dimFuture, setDimFuture] = useState2(false);
|
|
247
249
|
useEffect2(() => setMotion(animate && !prefersReducedMotion()), [animate]);
|
|
248
250
|
const legendCfg = normalizeLegend(legend);
|
|
249
251
|
const axes = useMemo(() => {
|
|
@@ -325,9 +327,11 @@ function CartesianChart({
|
|
|
325
327
|
xData,
|
|
326
328
|
scrubIndex,
|
|
327
329
|
focused,
|
|
328
|
-
animate: motion
|
|
330
|
+
animate: motion,
|
|
331
|
+
futureMask: dimFuture && !band && scrubIndex !== null && scrubIndex < length ? `url(#${id}-future)` : void 0,
|
|
332
|
+
setDimFuture
|
|
329
333
|
};
|
|
330
|
-
}, [id, width, height, inset, axisSpace, all, visible, axes, firstAxis, xAxis, stacked, scrubIndex, focused, motion]);
|
|
334
|
+
}, [id, width, height, inset, axisSpace, all, visible, axes, firstAxis, xAxis, stacked, scrubIndex, focused, motion, dimFuture]);
|
|
331
335
|
const xsRef = useRef2([]);
|
|
332
336
|
xsRef.current = useMemo(() => Array.from({ length: ctx.length }, (_, i) => ctx.x(i)), [ctx.length, ctx.x]);
|
|
333
337
|
const updateScrub = useCallback(
|
|
@@ -415,6 +419,11 @@ function CartesianChart({
|
|
|
415
419
|
updateScrub(null);
|
|
416
420
|
} : void 0,
|
|
417
421
|
children: [
|
|
422
|
+
ctx.futureMask && // Fade everything right of the scrubber to 35% (luminance mask: works on any background).
|
|
423
|
+
/* @__PURE__ */ jsxs2("mask", { id: `${id}-future`, maskUnits: "userSpaceOnUse", x: -width, y: -height, width: width * 3, height: height * 3, children: [
|
|
424
|
+
/* @__PURE__ */ jsx3("rect", { x: -width, y: -height, width: width + ctx.x(scrubIndex), height: height * 3, fill: "#fff" }),
|
|
425
|
+
/* @__PURE__ */ jsx3("rect", { x: ctx.x(scrubIndex), y: -height, width: width * 2, height: height * 3, fill: "#fff", fillOpacity: 0.35 })
|
|
426
|
+
] }),
|
|
418
427
|
width > 0 && hasData && /* @__PURE__ */ jsx3(CartesianContext.Provider, { value: ctx, children }),
|
|
419
428
|
width > 0 && !hasData && /* @__PURE__ */ jsx3("text", { x: width / 2, y: height / 2, textAnchor: "middle", dominantBaseline: "central", fontSize: 13, style: { fill: VAR.text, fontFamily: VAR.font }, children: typeof emptyState === "string" || emptyState === void 0 ? emptyState ?? "" : null })
|
|
420
429
|
]
|
|
@@ -572,13 +581,13 @@ function Area({ seriesId, curve = "monotone", fill = "gradient", opacity, connec
|
|
|
572
581
|
] }, key);
|
|
573
582
|
};
|
|
574
583
|
if (splitColors && baseline !== void 0 && !run0IsStacked(ctx, s)) {
|
|
575
|
-
return /* @__PURE__ */ jsxs4("g", { children: [
|
|
584
|
+
return /* @__PURE__ */ jsxs4("g", { mask: ctx.futureMask, children: [
|
|
576
585
|
/* @__PURE__ */ jsx5(SplitClips, { id: gid, y: base, ctx }),
|
|
577
586
|
paint("above", splitColors.above, ctx.plot.top, `${gid}-above`),
|
|
578
587
|
paint("below", splitColors.below, ctx.plot.bottom, `${gid}-below`)
|
|
579
588
|
] });
|
|
580
589
|
}
|
|
581
|
-
return /* @__PURE__ */ jsx5("g", { children: paint("fill", s.color, ctx.plot.top) });
|
|
590
|
+
return /* @__PURE__ */ jsx5("g", { mask: ctx.futureMask, children: paint("fill", s.color, ctx.plot.top) });
|
|
582
591
|
}
|
|
583
592
|
var run0IsStacked = (ctx, s) => !!ctx.stacked?.get(s.id);
|
|
584
593
|
function Line({
|
|
@@ -606,7 +615,7 @@ function Line({
|
|
|
606
615
|
const gid = `${ctx.id}-line-${s.index}`;
|
|
607
616
|
const baseY = baselineY(ctx, s.scale, baseline);
|
|
608
617
|
const strokeOpacity = (opacity ?? 1) * (s.dimmed ? DIM_OPACITY : 1);
|
|
609
|
-
const strokes = (color, clip) => /* @__PURE__ */ jsx5("g", { clipPath: clip ? `url(#${clip})` : void 0, children: runs.map((run, k) => /* @__PURE__ */ jsx5(
|
|
618
|
+
const strokes = (color, clip) => /* @__PURE__ */ jsx5("g", { clipPath: clip ? `url(#${clip})` : void 0, mask: ctx.futureMask, children: runs.map((run, k) => /* @__PURE__ */ jsx5(
|
|
610
619
|
"path",
|
|
611
620
|
{
|
|
612
621
|
d: linePath(run.upper, curve),
|
|
@@ -640,6 +649,7 @@ function Line({
|
|
|
640
649
|
p.label && /* @__PURE__ */ jsx5(
|
|
641
650
|
"text",
|
|
642
651
|
{
|
|
652
|
+
opacity: nearScrub(ctx, x) ? 0 : 1,
|
|
643
653
|
x,
|
|
644
654
|
y: p.labelPosition === "bottom" ? y + r + 13 : y - r - 6,
|
|
645
655
|
textAnchor: "middle",
|
|
@@ -887,6 +897,7 @@ function HorizontalBarChart({
|
|
|
887
897
|
}
|
|
888
898
|
|
|
889
899
|
// src/viz/scrubber.tsx
|
|
900
|
+
import { useEffect as useEffect4 } from "react";
|
|
890
901
|
import { jsx as jsx8, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
891
902
|
var TIP_FONT = 12;
|
|
892
903
|
var ROW = 18;
|
|
@@ -905,6 +916,12 @@ function Scrubber({
|
|
|
905
916
|
}) {
|
|
906
917
|
const ctx = useCartesianChart();
|
|
907
918
|
const i = ctx.scrubIndex;
|
|
919
|
+
const { setDimFuture } = ctx;
|
|
920
|
+
const fade = dimFuture && !hideOverlay;
|
|
921
|
+
useEffect4(() => {
|
|
922
|
+
setDimFuture(fade);
|
|
923
|
+
return () => setDimFuture(false);
|
|
924
|
+
}, [fade, setDimFuture]);
|
|
908
925
|
const pick = seriesIds ? ctx.series.filter((s) => seriesIds.includes(s.id)) : ctx.series;
|
|
909
926
|
const colorOf = (s, v) => beaconColor?.(v, s.id) ?? s.color;
|
|
910
927
|
if (i === null || i >= ctx.length) {
|
|
@@ -944,7 +961,6 @@ function Scrubber({
|
|
|
944
961
|
const tipX = tipRight ? x + 12 : x - 12 - tipW;
|
|
945
962
|
const tipY = plot.top + 4;
|
|
946
963
|
return /* @__PURE__ */ jsxs6("g", { pointerEvents: "none", children: [
|
|
947
|
-
dimFuture && !hideOverlay && !ctx.band && /* @__PURE__ */ jsx8("rect", { x, y: plot.top, width: Math.max(0, plot.right - x + 2), height: plot.height, fillOpacity: 0.55, style: { fill: VAR.bg } }),
|
|
948
964
|
/* @__PURE__ */ jsx8("line", { x1: x, x2: x, y1: plot.top, y2: plot.bottom, strokeWidth: 1, shapeRendering: "crispEdges", style: { stroke: VAR.line } }),
|
|
949
965
|
text && /* @__PURE__ */ jsx8("text", { x: textX, y: Math.max(11, plot.top - 2), textAnchor: "middle", fontSize: 11, fontWeight: 600, strokeWidth: 3, strokeLinejoin: "round", paintOrder: "stroke", style: { stroke: VAR.bg, fill: VAR.textStrong }, children: text }),
|
|
950
966
|
!ctx.band && list.map((s) => {
|
|
@@ -1070,7 +1086,7 @@ function Point({ dataX, dataY, seriesId, yAxisId, color, radius = 4, label, labe
|
|
|
1070
1086
|
/* @__PURE__ */ jsx9("animate", { attributeName: "fill-opacity", values: "0.35;0", dur: "1.6s", repeatCount: "indefinite" })
|
|
1071
1087
|
] }),
|
|
1072
1088
|
/* @__PURE__ */ jsx9("circle", { cx: x, cy: y, r: radius, strokeWidth: 2, style: { fill, stroke: VAR.bg } }),
|
|
1073
|
-
label !== void 0 && /* @__PURE__ */ jsx9("text", { x: lx, y: ly, textAnchor: anchor, fontSize: 11, fontWeight: 600, strokeWidth: 3, strokeLinejoin: "round", paintOrder: "stroke", style: { stroke: VAR.bg, fill }, children: label })
|
|
1089
|
+
label !== void 0 && /* @__PURE__ */ jsx9("text", { opacity: nearScrub(ctx, x) ? 0 : 1, x: lx, y: ly, textAnchor: anchor, fontSize: 11, fontWeight: 600, strokeWidth: 3, strokeLinejoin: "round", paintOrder: "stroke", style: { stroke: VAR.bg, fill }, children: label })
|
|
1074
1090
|
] });
|
|
1075
1091
|
}
|
|
1076
1092
|
|
|
@@ -1272,7 +1288,7 @@ function AreaChart({
|
|
|
1272
1288
|
seriesId: s.id,
|
|
1273
1289
|
curve,
|
|
1274
1290
|
fill: own,
|
|
1275
|
-
...defined({ baseline, splitColors, gradientStops, opacity: fillOpacity ?? (chart.stacked && own === "solid" ? 0.
|
|
1291
|
+
...defined({ baseline, splitColors, gradientStops, opacity: fillOpacity ?? (chart.stacked && own === "solid" ? 0.3 : void 0) })
|
|
1276
1292
|
},
|
|
1277
1293
|
`a${s.id}`
|
|
1278
1294
|
) : null;
|
package/dist/viz/context.d.ts
CHANGED
|
@@ -65,7 +65,16 @@ export interface CartesianContextValue {
|
|
|
65
65
|
/** The chart has keyboard focus (scrubbing with arrow keys). */
|
|
66
66
|
focused: boolean;
|
|
67
67
|
animate: boolean;
|
|
68
|
+
/**
|
|
69
|
+
* `mask` value for series marks while a Scrubber dims the future (right of the pointer);
|
|
70
|
+
* undefined otherwise. Lines and areas apply it, so the fade works on any background.
|
|
71
|
+
*/
|
|
72
|
+
futureMask: string | undefined;
|
|
73
|
+
/** Scrubber turns future dimming on/off. */
|
|
74
|
+
setDimFuture(on: boolean): void;
|
|
68
75
|
}
|
|
76
|
+
/** Hide labels the scrubber line would run through. */
|
|
77
|
+
export declare const nearScrub: (ctx: CartesianContextValue, x: number, within?: number) => boolean;
|
|
69
78
|
export declare const CartesianContext: import("react").Context<CartesianContextValue | null>;
|
|
70
79
|
export declare function useCartesianChart(): CartesianContextValue;
|
|
71
80
|
/**
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@funnest/charts-react",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.1",
|
|
4
4
|
"description": "React bindings for Funnest Charts: the trading widget plus SVG line, area and bar charts",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"react",
|
|
@@ -46,9 +46,9 @@
|
|
|
46
46
|
"NOTICE"
|
|
47
47
|
],
|
|
48
48
|
"dependencies": {
|
|
49
|
-
"@funnest/charts": "0.2.
|
|
50
|
-
"@funnest/charts-
|
|
51
|
-
"@funnest/charts-
|
|
49
|
+
"@funnest/charts": "0.2.1",
|
|
50
|
+
"@funnest/charts-viz": "0.2.1",
|
|
51
|
+
"@funnest/charts-ui": "0.2.1"
|
|
52
52
|
},
|
|
53
53
|
"peerDependencies": {
|
|
54
54
|
"react": ">=18",
|