nanoplot 0.0.69 → 0.0.71

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 (48) hide show
  1. package/dist/src/components/Area/Area.d.ts +3 -2
  2. package/dist/src/components/Area/Area.js +2 -2
  3. package/dist/src/components/Bars/components/HorizontalBars.js +5 -7
  4. package/dist/src/components/Bars/components/VerticalBars.js +5 -5
  5. package/dist/src/components/GradientLegend/GradientLegend.js +2 -2
  6. package/dist/src/components/Heatmap/Heatmap.js +6 -6
  7. package/dist/src/components/Legend/Legend.d.ts +2 -1
  8. package/dist/src/components/Legend/Legend.js +30 -24
  9. package/dist/src/components/Lines/Lines.d.ts +30 -5
  10. package/dist/src/components/Lines/Lines.js +47 -56
  11. package/dist/src/components/Lines/components/Line.d.ts +1 -1
  12. package/dist/src/components/Lines/components/Line.js +14 -2
  13. package/dist/src/components/Lines/components/LinesJoints.d.ts +12 -0
  14. package/dist/src/components/Lines/components/LinesJoints.js +40 -0
  15. package/dist/src/components/Lines/components/LinesMouse.d.ts +18 -0
  16. package/dist/src/components/Lines/components/LinesMouse.js +24 -0
  17. package/dist/src/components/Lines/components/LinesTooltip.d.ts +3 -1
  18. package/dist/src/components/Lines/components/LinesTooltip.js +60 -128
  19. package/dist/src/components/Lines/components/LinesTooltipZone.d.ts +10 -0
  20. package/dist/src/components/Lines/components/LinesTooltipZone.js +14 -0
  21. package/dist/src/components/Overlay/Overlay.js +5 -5
  22. package/dist/src/components/Overlay/OverlayRect.js +5 -5
  23. package/dist/src/components/Pie/Pie.js +4 -4
  24. package/dist/src/components/Radar/Radar.js +4 -4
  25. package/dist/src/components/Scatter/components/ScatterLabels.js +5 -5
  26. package/dist/src/components/Scatter/components/ScatterTooltip.js +5 -5
  27. package/dist/src/components/Worldmap/Worldmap.js +2 -2
  28. package/dist/src/components/XAxis/XAxis.d.ts +5 -42
  29. package/dist/src/components/XAxis/XAxis.js +25 -9
  30. package/dist/src/components/YAxis/YAxis.js +4 -4
  31. package/dist/src/hooks/use-graph/use-graph.d.ts +41 -1
  32. package/dist/src/hooks/use-graph/use-graph.js +7 -1
  33. package/dist/src/hooks/use-mouse-coordinates.d.ts +7 -1
  34. package/dist/src/hooks/use-mouse-coordinates.js +68 -12
  35. package/dist/src/utils/coordinates/coordinates.d.ts +17 -1
  36. package/dist/src/utils/coordinates/coordinates.js +234 -0
  37. package/dist/src/utils/cx/cx.d.ts +3 -4
  38. package/dist/src/utils/cx/cx.js +31 -29
  39. package/dist/src/utils/domain/utils/date-domain.d.ts +1 -0
  40. package/dist/src/utils/domain/utils/date-domain.js +88 -41
  41. package/dist/src/utils/domain/utils/range.js +44 -24
  42. package/dist/src/utils/equals/equals.d.ts +1 -0
  43. package/dist/src/utils/equals/equals.js +18 -0
  44. package/dist/src/utils/gradient/gradient.js +8 -11
  45. package/dist/src/utils/math/math.d.ts +1 -3
  46. package/dist/src/utils/math/math.js +7 -8
  47. package/dist/tsconfig.typings.tsbuildinfo +1 -1
  48. package/package.json +1 -1
@@ -9,7 +9,7 @@ interface Props extends React.SVGAttributes<SVGSVGElement> {
9
9
  export declare const Area: {
10
10
  ({ className, curve, children, loading }: Props): React.JSX.Element | null;
11
11
  context(ctx: GraphContext): GraphContext;
12
- Tooltip: React.ComponentType<React.HTMLAttributes<HTMLDivElement> & {
12
+ Tooltip: React.ComponentType<Omit<React.HTMLAttributes<HTMLDivElement> & {
13
13
  tooltip?: ((points: Array<Omit<import("../../export").CartesianDataset[number], "data"> & {
14
14
  data: import("../../export").CartesianDataset[number]["data"][number];
15
15
  }>, x: number | string | Date) => React.ReactNode) | {
@@ -17,6 +17,7 @@ export declare const Area: {
17
17
  display: (point: import("../../export").CartesianDataset[number]["data"][number]) => React.ReactNode;
18
18
  };
19
19
  joints?: boolean;
20
- }>;
20
+ zoneRef: React.RefObject<SVGSVGElement | null>;
21
+ }, "zoneRef">>;
21
22
  };
22
23
  export {};
@@ -4,10 +4,10 @@ import { useGraph } from "../../hooks/use-graph/use-graph";
4
4
  import { CurveUtils } from "../../utils/path/curve";
5
5
  import { CoordinatesUtils } from "../../utils/coordinates/coordinates";
6
6
  import { cx } from "../../utils/cx/cx";
7
- import { LinesTooltip } from "../Lines/components/LinesTooltip";
8
7
  import { ObjectUtils } from "../../utils/object/object";
9
8
  import { Line } from "../Lines/components/Line";
10
9
  import { ColorUtils } from "../../utils/color/color";
10
+ import { LinesTooltipZone } from "../Lines/components/LinesTooltipZone";
11
11
  export const Area = ({ className, curve = "linear", children, loading }) => {
12
12
  const { interactions: { pinned, hovered }, data, viewbox, domain, colors, } = useGraph();
13
13
  if (!GraphUtils.isXYData(data))
@@ -55,4 +55,4 @@ export const Area = ({ className, curve = "linear", children, loading }) => {
55
55
  Area.context = (ctx) => {
56
56
  return Object.assign(Object.assign({}, ctx), { colors: ColorUtils.scheme.sunset });
57
57
  };
58
- Area.Tooltip = LinesTooltip;
58
+ Area.Tooltip = LinesTooltipZone;
@@ -16,7 +16,7 @@ import { useGraph } from "../../../hooks/use-graph/use-graph";
16
16
  import { cx } from "../../../utils/cx/cx";
17
17
  import { ObjectUtils } from "../../../utils/object/object";
18
18
  import { Rect } from "./Rect";
19
- import { MathUtils } from "../../../utils/math/math";
19
+ import { scale } from "../../../utils/math/math";
20
20
  import { overlay } from "../../Overlay/Overlay";
21
21
  import { ColorUtils } from "../../../utils/color/color";
22
22
  export const HorizontalBars = ({ children, labels, size = 50, radius = 0, anchor = 0, className }) => {
@@ -54,9 +54,9 @@ export const HorizontalBars = ({ children, labels, size = 50, radius = 0, anchor
54
54
  dataset.map((bar, i) => {
55
55
  const position = typeof labels === "object" && "position" in labels ? labels.position : "center";
56
56
  const collision = typeof labels === "object" && "collision" in labels ? labels.collision : true;
57
- const width = Math.abs(MathUtils.scale(bar.x2 - bar.x1, context.viewbox.x, 100) - (position === "above" ? 100 : 0)) + "%";
58
- const height = MathUtils.scale(bar.y2 - bar.y1, context.viewbox.y, 100);
59
- const top = MathUtils.scale(bar.y1, context.viewbox.y, 100);
57
+ const width = Math.abs(scale(bar.x2 - bar.x1, context.viewbox.x, 100) - (position === "above" ? 100 : 0)) + "%";
58
+ const height = scale(bar.y2 - bar.y1, context.viewbox.y, 100);
59
+ const top = scale(bar.y1, context.viewbox.y, 100);
60
60
  const label = (() => {
61
61
  var _a;
62
62
  if (typeof labels === "object" && "position" in labels)
@@ -67,9 +67,7 @@ export const HorizontalBars = ({ children, labels, size = 50, radius = 0, anchor
67
67
  return (React.createElement(overlay.div, { key: i, className: "bars__label @container-[size] absolute text-center", style: {
68
68
  width,
69
69
  height: height + "%",
70
- left: position === "above"
71
- ? "unset"
72
- : MathUtils.scale(Math.min(bar.x1, bar.x2), context.viewbox.x, 100) + "%",
70
+ left: position === "above" ? "unset" : scale(Math.min(bar.x1, bar.x2), context.viewbox.x, 100) + "%",
73
71
  right: position === "above" ? 0 : "unset",
74
72
  top: top + "%",
75
73
  } },
@@ -17,7 +17,7 @@ import { CoordinatesUtils } from "../../../utils/coordinates/coordinates";
17
17
  import { ObjectUtils } from "../../../utils/object/object";
18
18
  import { Rect } from "./Rect";
19
19
  import { cx } from "../../../utils/cx/cx";
20
- import { MathUtils } from "../../../utils/math/math";
20
+ import { scale } from "../../../utils/math/math";
21
21
  import { overlay } from "../../Overlay/Overlay";
22
22
  import { ColorUtils } from "../../../utils/color/color";
23
23
  export const VerticalBars = (_a) => {
@@ -66,9 +66,9 @@ export const VerticalBars = (_a) => {
66
66
  dataset.map((bar, i) => {
67
67
  const position = typeof labels === "object" && "position" in labels ? labels.position : "center";
68
68
  const collision = typeof labels === "object" && "collision" in labels ? labels.collision : true;
69
- const width = MathUtils.scale(bar.x2 - bar.x1, context.viewbox.x, 100) + "%";
70
- const height = MathUtils.scale(Math.abs(bar.y1 - bar.y2), context.viewbox.y, 100);
71
- const top = position === "above" ? -4 : MathUtils.scale(Math.min(bar.y2, bar.y1), context.viewbox.y, 100) + "%";
69
+ const width = scale(bar.x2 - bar.x1, context.viewbox.x, 100) + "%";
70
+ const height = scale(Math.abs(bar.y1 - bar.y2), context.viewbox.y, 100);
71
+ const top = position === "above" ? -4 : scale(Math.min(bar.y2, bar.y1), context.viewbox.y, 100) + "%";
72
72
  const label = (() => {
73
73
  var _a;
74
74
  if (typeof labels === "object" && "position" in labels)
@@ -79,7 +79,7 @@ export const VerticalBars = (_a) => {
79
79
  return (React.createElement(overlay.div, { key: i, className: "bars__label @container-[size] absolute text-center", style: {
80
80
  width,
81
81
  height: Math.abs(height - (position === "above" ? 100 : 0)) + "%",
82
- left: `${MathUtils.scale(bar.x1, context.viewbox.x, 100)}%`,
82
+ left: `${scale(bar.x1, context.viewbox.x, 100)}%`,
83
83
  top: top,
84
84
  } },
85
85
  React.createElement("div", { className: "h-full w-full relative" },
@@ -11,14 +11,14 @@ var __rest = (this && this.__rest) || function (s, e) {
11
11
  };
12
12
  import React from "react";
13
13
  import { useGraphColumn } from "../../hooks/use-graph/use-graph";
14
- import { MathUtils } from "../../utils/math/math";
14
+ import { scale } from "../../utils/math/math";
15
15
  import { cx } from "../../utils/cx/cx";
16
16
  export const GradientLegend = (_a) => {
17
17
  var { position, alignment = "center", gradient, scalars, labels = true } = _a, rest = __rest(_a, ["position", "alignment", "gradient", "scalars", "labels"]);
18
18
  const column = useGraphColumn().column;
19
19
  const ticks = scalars.map((tick, i, ticks) => {
20
20
  if (typeof tick === "number")
21
- return { label: tick, left: MathUtils.scale(i, ticks.length - 1, 100) + "%" };
21
+ return { label: tick, left: scale(i, ticks.length - 1, 100) + "%" };
22
22
  return { label: tick.tick, left: tick.percent + "%" };
23
23
  });
24
24
  return (React.createElement("div", Object.assign({}, rest, { className: cx("gradient-legend w-[100%] px-[20px]", alignment === "center" && "mx-auto", alignment === "start" && "mr-auto", alignment === "end" && "ml-auto", rest.className), style: Object.assign({ gridColumn: column }, rest.style) }),
@@ -14,7 +14,7 @@ import { cx } from "../../utils/cx/cx";
14
14
  import { Rect } from "../Bars/components/Rect";
15
15
  import { GraphUtils } from "../../utils/graph/graph";
16
16
  import { CoordinatesUtils } from "../../utils/coordinates/coordinates";
17
- import { MathUtils } from "../../utils/math/math";
17
+ import { scale } from "../../utils/math/math";
18
18
  import { GradientUtils } from "../../utils/gradient/gradient";
19
19
  import { overlay } from "../Overlay/Overlay";
20
20
  import { ColorUtils } from "../../utils/color/color";
@@ -34,7 +34,7 @@ export const Heatmap = (_a) => {
34
34
  const height = viewbox.y / yCategories.size;
35
35
  const ticks = scalars.map((tick, i) => {
36
36
  if (typeof tick === "number")
37
- return { tick: tick, percent: MathUtils.scale(i, scalars.length - 1, 100) };
37
+ return { tick: tick, percent: scale(i, scalars.length - 1, 100) };
38
38
  return tick;
39
39
  });
40
40
  const dataset = data.flatMap(({ data }) => {
@@ -57,9 +57,9 @@ export const Heatmap = (_a) => {
57
57
  labels &&
58
58
  dataset.map((rect, i) => {
59
59
  const collision = typeof labels === "object" && "collision" in labels ? labels.collision : true;
60
- const width = MathUtils.scale(rect.x2 - rect.x1, context.viewbox.x, 100) + "%";
61
- const height = MathUtils.scale(rect.y2 - rect.y1, context.viewbox.y, 100);
62
- const top = MathUtils.scale(rect.y1, context.viewbox.y, 100);
60
+ const width = scale(rect.x2 - rect.x1, context.viewbox.x, 100) + "%";
61
+ const height = scale(rect.y2 - rect.y1, context.viewbox.y, 100);
62
+ const top = scale(rect.y1, context.viewbox.y, 100);
63
63
  const label = (() => {
64
64
  var _a;
65
65
  if (typeof labels === "object")
@@ -70,7 +70,7 @@ export const Heatmap = (_a) => {
70
70
  return (React.createElement(overlay.div, { key: i, className: "heatmap__labels @container-[size] absolute text-center", style: {
71
71
  width,
72
72
  height: height + "%",
73
- left: `${MathUtils.scale(rect.x1, context.viewbox.x, 100)}%`,
73
+ left: `${scale(rect.x1, context.viewbox.x, 100)}%`,
74
74
  top: top + "%",
75
75
  } },
76
76
  React.createElement("div", { className: "h-full w-full relative" },
@@ -8,9 +8,10 @@ type Props = Omit<JSX.IntrinsicElements["div"], "onClick" | "onMouseEnter" | "on
8
8
  onMouseLeave?: (datapoint: CartesianDatasetDefaulted[number] | SegmentDatasetDefaulted[number]) => void;
9
9
  onMouseMove?: (datapoint: CartesianDatasetDefaulted[number] | SegmentDatasetDefaulted[number]) => void;
10
10
  children?: ReactNode;
11
+ datasets?: string[];
11
12
  };
12
13
  export declare const Legend: {
13
- ({ position, alignment, onClick, onMouseEnter, onMouseMove, onMouseLeave, ...rest }: Props): JSX.Element;
14
+ ({ position, alignment, onClick, onMouseEnter, onMouseMove, onMouseLeave, datasets, ...rest }: Props): JSX.Element;
14
15
  context(ctx: GraphContext, { position }: Props): {
15
16
  layout: {
16
17
  rows: string;
@@ -11,35 +11,41 @@ var __rest = (this && this.__rest) || function (s, e) {
11
11
  };
12
12
  import React from "react";
13
13
  import { Graph } from "../Graph/Graph";
14
- import { useGraph } from "../../hooks/use-graph/use-graph";
14
+ import { useDatasets, useGraph, } from "../../hooks/use-graph/use-graph";
15
15
  import { cx } from "../../utils/cx/cx";
16
16
  import { GradientUtils } from "../../utils/gradient/gradient";
17
17
  export const Legend = (_a) => {
18
- var { position = "top", alignment = "center", onClick, onMouseEnter, onMouseMove, onMouseLeave } = _a, rest = __rest(_a, ["position", "alignment", "onClick", "onMouseEnter", "onMouseMove", "onMouseLeave"]);
18
+ var { position = "top", alignment = "center", onClick, onMouseEnter, onMouseMove, onMouseLeave, datasets } = _a, rest = __rest(_a, ["position", "alignment", "onClick", "onMouseEnter", "onMouseMove", "onMouseLeave", "datasets"]);
19
19
  const context = useGraph();
20
+ const dsets = useDatasets(datasets);
20
21
  const Element = position === "top" || position === "bottom" ? Graph.Row : Graph.Column;
21
- const { viewbox, domain, interactions: { pinned, hovered }, } = context;
22
- return (React.createElement(Element, Object.assign({}, rest, { className: cx("flex gap-3", (position === "left" || position === "right") && "flex-col", position === "right" && "pl-4", position === "left" && "pr-4", position === "top" && "pb-3 pt-2", position === "bottom" && "pt-3 pb-2", alignment === "start" && "justify-start", alignment === "end" && "justify-end", alignment === "center" && "justify-center", rest.className) }), context.data
23
- .map((dp) => { var _a; return (Object.assign(Object.assign({}, dp), { group: (_a = dp.group) !== null && _a !== void 0 ? _a : "" })); })
24
- .sort((a, b) => a.group.localeCompare(b.group))
25
- .map((datapoint, i, datapoints) => {
26
- var _a, _b;
27
- const { id, name, fill, stroke } = datapoint;
28
- const disabled = pinned.length && !pinned.includes(String(id)) && !hovered.includes(String(id));
29
- const isLastInGroup = ((_a = datapoints[i + 1]) === null || _a === void 0 ? void 0 : _a.group) ? datapoints[i + 1].group !== datapoint.group : false;
30
- const bg = fill !== null && fill !== void 0 ? fill : stroke;
31
- const deserialized = ((_b = bg === null || bg === void 0 ? void 0 : bg.replace("mask:", "")) === null || _b === void 0 ? void 0 : _b.includes("linear-gradient"))
32
- ? GradientUtils.deserialize({
33
- gradient: bg.replace("mask:", ""),
34
- viewbox,
35
- domain,
36
- })
37
- : bg;
38
- return (React.createElement("div", { key: i, className: cx("flex items-center", (onClick || onMouseEnter || onMouseLeave || onMouseMove) && "cursor-pointer user-select-none"), onClick: () => onClick === null || onClick === void 0 ? void 0 : onClick(datapoint), onMouseEnter: () => onMouseEnter === null || onMouseEnter === void 0 ? void 0 : onMouseEnter(datapoint), onMouseLeave: () => onMouseLeave === null || onMouseLeave === void 0 ? void 0 : onMouseLeave(datapoint), onMouseMove: () => onMouseMove === null || onMouseMove === void 0 ? void 0 : onMouseMove(datapoint) },
39
- React.createElement("div", { className: cx("size-4 mr-1 rounded-full", disabled && "bg-gray-400 opacity-[0.8]"), style: disabled ? undefined : { background: deserialized } }),
40
- React.createElement("div", { className: cx("text-nowrap", disabled && "text-gray-400") }, name),
41
- isLastInGroup && React.createElement("div", { className: "h-[16px] bg-gray-700 w-[1px] ml-[10px]" })));
42
- })));
22
+ const { interactions: { pinned, hovered }, } = context;
23
+ const render = (ctx) => {
24
+ return ctx.data
25
+ .map((dp) => { var _a; return (Object.assign(Object.assign({}, dp), { group: (_a = dp.group) !== null && _a !== void 0 ? _a : "" })); })
26
+ .sort((a, b) => a.group.localeCompare(b.group))
27
+ .map((datapoint, i, datapoints) => {
28
+ var _a, _b;
29
+ const { id, name, fill, stroke } = datapoint;
30
+ const disabled = pinned.length && !pinned.includes(String(id)) && !hovered.includes(String(id));
31
+ const isLastInGroup = ((_a = datapoints[i + 1]) === null || _a === void 0 ? void 0 : _a.group) ? datapoints[i + 1].group !== datapoint.group : false;
32
+ const bg = fill !== null && fill !== void 0 ? fill : stroke;
33
+ const deserialized = ((_b = bg === null || bg === void 0 ? void 0 : bg.replace("mask:", "")) === null || _b === void 0 ? void 0 : _b.includes("linear-gradient"))
34
+ ? GradientUtils.deserialize({
35
+ gradient: bg.replace("mask:", ""),
36
+ viewbox: ctx.viewbox,
37
+ domain: ctx.domain,
38
+ })
39
+ : bg;
40
+ return (React.createElement("div", { key: i, className: cx("flex items-center", (onClick || onMouseEnter || onMouseLeave || onMouseMove) && "cursor-pointer user-select-none"), onClick: () => onClick === null || onClick === void 0 ? void 0 : onClick(datapoint), onMouseEnter: () => onMouseEnter === null || onMouseEnter === void 0 ? void 0 : onMouseEnter(datapoint), onMouseLeave: () => onMouseLeave === null || onMouseLeave === void 0 ? void 0 : onMouseLeave(datapoint), onMouseMove: () => onMouseMove === null || onMouseMove === void 0 ? void 0 : onMouseMove(datapoint) },
41
+ React.createElement("div", { className: cx("size-4 mr-1 rounded-full", disabled && "bg-gray-400 opacity-[0.8]"), style: disabled ? undefined : { background: deserialized } }),
42
+ React.createElement("div", { className: cx("text-nowrap", disabled && "text-gray-400") }, name),
43
+ isLastInGroup && React.createElement("div", { className: "h-[16px] bg-gray-700 w-[1px] ml-[10px]" })));
44
+ });
45
+ };
46
+ return (React.createElement(Element, Object.assign({}, rest, { className: cx("flex gap-3", (position === "left" || position === "right") && "flex-col", position === "right" && "pl-4", position === "left" && "pr-4", position === "top" && "pb-3 pt-2", position === "bottom" && "pt-3 pb-2", alignment === "start" && "justify-start", alignment === "end" && "justify-end", alignment === "center" && "justify-center", rest.className) }),
47
+ render(context),
48
+ dsets.map((d) => render(d))));
43
49
  };
44
50
  Legend.context = (ctx, { position = "top" }) => {
45
51
  const rows = (() => {
@@ -1,17 +1,19 @@
1
1
  import React, { ReactNode } from "react";
2
+ import { GraphContext } from "../../hooks/use-graph/use-graph";
2
3
  import { CurveUtils } from "../../utils/path/curve";
3
4
  interface Props extends React.SVGAttributes<SVGSVGElement> {
4
5
  children?: ReactNode;
5
6
  curve?: keyof typeof CurveUtils;
6
7
  joints?: boolean | {
7
- border: boolean;
8
+ border: string;
8
9
  };
9
10
  loading?: boolean;
10
- dataset?: string;
11
+ datasets?: string[];
12
+ context?: GraphContext;
11
13
  }
12
14
  export declare const Lines: {
13
- ({ className, curve, joints, children, loading, dataset }: Props): React.JSX.Element | null;
14
- Tooltip: React.ComponentType<React.HTMLAttributes<HTMLDivElement> & {
15
+ (props: Props): React.JSX.Element | null;
16
+ Tooltip: React.ComponentType<Omit<React.HTMLAttributes<HTMLDivElement> & {
15
17
  tooltip?: ((points: Array<Omit<import("../../export").CartesianDataset[number], "data"> & {
16
18
  data: import("../../export").CartesianDataset[number]["data"][number];
17
19
  }>, x: number | string | Date) => React.ReactNode) | {
@@ -19,6 +21,29 @@ export declare const Lines: {
19
21
  display: (point: import("../../export").CartesianDataset[number]["data"][number]) => React.ReactNode;
20
22
  };
21
23
  joints?: boolean;
22
- }>;
24
+ zoneRef: React.RefObject<SVGSVGElement | null>;
25
+ }, "zoneRef">>;
26
+ Mouse: ({ joints, datasets, onMove, onLeave, onEnter, className }: {
27
+ cross?: {
28
+ x: true;
29
+ y: true;
30
+ };
31
+ joints?: boolean | {
32
+ border: string;
33
+ };
34
+ className?: string;
35
+ datasets?: string[];
36
+ onMove?: (e: React.MouseEvent<SVGSVGElement>, mouse: ReturnType<typeof import("../../hooks/use-mouse-coordinates").useMouseCoordinates>) => void;
37
+ onEnter?: (e: React.MouseEvent<SVGSVGElement>) => void;
38
+ onLeave?: (e: React.MouseEvent<SVGSVGElement>) => void;
39
+ }) => React.JSX.Element;
40
+ Joints: ({ context, border, at, strokeWidth }: {
41
+ at?: {
42
+ x: string | number | Date;
43
+ };
44
+ border?: string;
45
+ strokeWidth?: number;
46
+ context: GraphContext;
47
+ }) => (React.JSX.Element | null)[] | null;
23
48
  };
24
49
  export {};
@@ -1,76 +1,67 @@
1
1
  import React from "react";
2
2
  import { GraphUtils } from "../../utils/graph/graph";
3
- import { useDataset, useGraph, useIsZooming } from "../../hooks/use-graph/use-graph";
3
+ import { useDatasets, useGraph, useIsZooming } from "../../hooks/use-graph/use-graph";
4
4
  import { CurveUtils } from "../../utils/path/curve";
5
5
  import { CoordinatesUtils } from "../../utils/coordinates/coordinates";
6
6
  import { LinesLoading } from "./components/LinesLoading";
7
7
  import { cx, tw } from "../../utils/cx/cx";
8
- import { LinesTooltip } from "./components/LinesTooltip";
9
8
  import { Line } from "./components/Line";
10
9
  import { toRgb } from "../../utils/color/to-rgb";
11
- import { GradientUtils } from "../../utils/gradient/gradient";
12
- const chunk = (points, size) => {
13
- const chunks = [];
14
- for (let i = 0; i < points.length; i += size) {
15
- chunks.push(points.slice(i, i + size));
10
+ import { LinesTooltipZone } from "./components/LinesTooltipZone";
11
+ import { LinesMouse } from "./components/LinesMouse";
12
+ import { LinesJoints } from "./components/LinesJoints";
13
+ const chunk = (a, s) => {
14
+ const len = Math.ceil(a.length / s);
15
+ const r = new Array(len);
16
+ for (let i = 0, j = 0; i < a.length; i += s, j++) {
17
+ r[j] = a.slice(i, i + s);
16
18
  }
17
- return chunks;
19
+ return r;
18
20
  };
19
- export const Lines = ({ className, curve = "linear", joints, children, loading, dataset }) => {
20
- const { interactions: { pinned, hovered }, viewbox, zoom, } = useGraph();
21
- const { data, domain, colors } = useDataset(dataset);
21
+ export const Lines = (props) => {
22
+ const { children, className, curve = "linear", joints, loading = false, datasets, context: ctx } = props;
23
+ const graph = useGraph();
24
+ const dsets = useDatasets(datasets);
22
25
  const isZooming = useIsZooming();
26
+ const context = ctx !== null && ctx !== void 0 ? ctx : graph;
27
+ const { data, viewbox, interactions: { pinned, hovered }, colors, } = context;
23
28
  if (!GraphUtils.isXYData(data))
24
29
  return null;
25
- const xForValue = CoordinatesUtils.xCoordinateFor({ domain, viewbox });
26
- const yForValue = CoordinatesUtils.yCoordinateFor({ domain, viewbox });
30
+ const xyForDataset = CoordinatesUtils.xyCoordinatesForDataset(context);
27
31
  const lines = data.map((line, i) => {
28
32
  var _a, _b;
29
- return Object.assign(Object.assign({}, line), { id: String(line.id), stroke: (_b = (_a = line.stroke) !== null && _a !== void 0 ? _a : colors[i]) !== null && _b !== void 0 ? _b : colors.at(-1), fill: line.fill, data: line.data.map((xy) => ({
30
- x: xForValue(xy.x),
31
- y: yForValue(xy.y),
32
- xValue: xy.x,
33
- yValue: xy.y,
34
- })) });
33
+ return Object.assign(Object.assign({}, line), { id: String(line.id), stroke: (_b = (_a = line.stroke) !== null && _a !== void 0 ? _a : colors[i]) !== null && _b !== void 0 ? _b : colors.at(-1), fill: line.fill, coordinates: xyForDataset(line.data) });
35
34
  });
36
35
  if (loading)
37
36
  return React.createElement(LinesLoading, null);
38
- return (React.createElement("svg", { viewBox: `0 0 ${viewbox.x} ${viewbox.y}`, preserveAspectRatio: "none", className: tw("absolute overflow-visible lines h-full w-full [grid-area:graph] will-change-transform [transform:translateZ(0)]", isZooming && "block overflow-hidden", className) },
39
- lines.map(({ id, stroke, fill, data: points }, i) => {
40
- var _a, _b;
41
- /* chunking is for high-performance rendering, when chunked GPU performance can improve by 3x+ at cost of allocating more DOM nodes */
42
- const isChunkingCandidate = !stroke.includes("linear-gradient") && points.length > 5000 && curve === "linear";
43
- const path = isChunkingCandidate ? "" : CurveUtils[curve](points);
44
- const disabled = pinned.length && !pinned.includes(id) && !hovered.includes(id);
45
- const isInteractiveFill = hovered.includes(id) || (pinned.includes(id) && !disabled) || fill;
46
- const identifier = id.replace(/[^a-zA-Z0-9]/g, "");
47
- return (React.createElement(React.Fragment, { key: i },
48
- isInteractiveFill && !disabled && (React.createElement("linearGradient", { id: identifier, x1: "0", y1: "0", x2: "0", y2: "1" },
49
- React.createElement("stop", { offset: "5%", stopColor: stroke, stopOpacity: "0.5" }),
50
- React.createElement("stop", { offset: "95%", stopColor: stroke, stopOpacity: "0" }))),
51
- isChunkingCandidate ? (chunk(points, 1000 /* chunk size determined by GPU benchmarking */).map((chunk, i) => {
52
- const chunkedPath = CurveUtils[curve](chunk);
53
- return (React.createElement(Line, { key: i, d: chunkedPath, stroke: stroke, fill: "transparent", className: cx("lines__stroke", disabled && "stroke-black dark:stroke-white [stroke-opacity:0.1]") }));
54
- })) : (React.createElement(React.Fragment, null,
55
- React.createElement(Line, { d: path, stroke: stroke, fill: "transparent", className: cx("lines__stroke", disabled && "stroke-black dark:stroke-white [stroke-opacity:0.1]") }),
56
- isInteractiveFill && points[0] && (React.createElement(Line, { d: path +
57
- `L ${(_b = (_a = points[points.length - 1]) === null || _a === void 0 ? void 0 : _a.x) !== null && _b !== void 0 ? _b : 0} ${viewbox.y} L 0 ${viewbox.y} L ${points[0].x} ${viewbox.y} Z`, stroke: "transparent", fill: fill || `linear-gradient(to bottom, ${toRgb(stroke, 0.5)}, ${toRgb(stroke, 0)})`, strokeOpacity: 0, className: "lines__fill" })))),
58
- joints &&
59
- points.map(({ x, y, xValue, yValue }, i) => {
60
- const color = stroke.includes("linear-gradient")
61
- ? GradientUtils.gradientColorFromValue({
62
- viewbox,
63
- domain,
64
- point: { x: xValue, y: yValue },
65
- gradient: stroke,
66
- dataset: points,
67
- })
68
- : stroke;
69
- return (React.createElement(React.Fragment, { key: i },
70
- typeof joints === "object" && joints.border && (React.createElement("path", { d: `M ${x} ${y} h 0.001`, strokeWidth: 8, stroke: "white", strokeLinecap: "round", strokeLinejoin: "round", vectorEffect: "non-scaling-stroke", className: "lines__joints" })),
71
- React.createElement("path", { d: `M ${x} ${y} h 0.001`, strokeWidth: 7, stroke: color, strokeLinecap: "round", strokeLinejoin: "round", vectorEffect: "non-scaling-stroke", className: "lines__joints" })));
72
- })));
37
+ return (React.createElement(React.Fragment, null,
38
+ dsets.map((dset, i) => {
39
+ return React.createElement(Lines, Object.assign({}, props, { datasets: undefined, context: dset, key: i })); // recurse for each dataset.
73
40
  }),
74
- children));
41
+ React.createElement("svg", { viewBox: `0 0 ${viewbox.x} ${viewbox.y}`, preserveAspectRatio: "none", className: tw("absolute overflow-visible lines h-full w-full [grid-area:graph] will-change-transform [transform:translateZ(0)]", isZooming && "block overflow-hidden", className) },
42
+ lines.map(({ id, stroke, fill, coordinates: points }, i) => {
43
+ var _a, _b;
44
+ /* chunking is for high-performance rendering, when chunked GPU performance can improve by 3x+ at cost of allocating more DOM nodes */
45
+ const isChunkingCandidate = !stroke.includes("linear-gradient") && points.length > 5000 && curve === "linear";
46
+ const path = isChunkingCandidate ? "" : CurveUtils[curve](points);
47
+ const disabled = pinned.length && !pinned.includes(id) && !hovered.includes(id);
48
+ const isInteractiveFill = hovered.includes(id) || (pinned.includes(id) && !disabled) || fill;
49
+ const identifier = id.replace(/[^a-zA-Z0-9]/g, "");
50
+ return (React.createElement(React.Fragment, { key: i },
51
+ isInteractiveFill && !disabled && (React.createElement("linearGradient", { id: identifier, x1: "0", y1: "0", x2: "0", y2: "1" },
52
+ React.createElement("stop", { offset: "5%", stopColor: stroke, stopOpacity: "0.5" }),
53
+ React.createElement("stop", { offset: "95%", stopColor: stroke, stopOpacity: "0" }))),
54
+ isChunkingCandidate ? (chunk(points, 1000 /* chunk size determined by GPU benchmarking */).map((chunk, i) => {
55
+ const chunkedPath = CurveUtils[curve](chunk);
56
+ return (React.createElement(Line, { key: i, d: chunkedPath, stroke: stroke, fill: "transparent", className: cx("lines__stroke", disabled && "stroke-black dark:stroke-white [stroke-opacity:0.1]") }));
57
+ })) : (React.createElement(React.Fragment, null,
58
+ React.createElement(Line, { d: path, stroke: stroke, fill: "transparent", className: cx("lines__stroke", disabled && "stroke-black dark:stroke-white [stroke-opacity:0.1]") }),
59
+ isInteractiveFill && points[0] && (React.createElement(Line, { d: path +
60
+ `L ${(_b = (_a = points.at(-1)) === null || _a === void 0 ? void 0 : _a.x) !== null && _b !== void 0 ? _b : 0} ${viewbox.y} L 0 ${viewbox.y} L ${points[0].x} ${viewbox.y} Z`, stroke: "transparent", fill: fill || `linear-gradient(to bottom, ${toRgb(stroke, 0.5)}, ${toRgb(stroke, 0)})`, strokeOpacity: 0, className: "lines__fill" })))),
61
+ joints && (React.createElement(Lines.Joints, { context: context, border: typeof joints === "object" ? joints["border"] : undefined }))));
62
+ }),
63
+ children)));
75
64
  };
76
- Lines.Tooltip = LinesTooltip;
65
+ Lines.Tooltip = LinesTooltipZone;
66
+ Lines.Mouse = LinesMouse;
67
+ Lines.Joints = LinesJoints;
@@ -9,5 +9,5 @@ type Props = JSX.IntrinsicElements["path"] & {
9
9
  y: number;
10
10
  }>;
11
11
  };
12
- export declare const Line: ({ stroke, d, disabled, fill, className, points }: Props) => JSX.Element;
12
+ export declare const Line: ({ stroke, d, disabled, fill, className, points, ...rest }: Props) => JSX.Element;
13
13
  export {};
@@ -1,6 +1,18 @@
1
+ var __rest = (this && this.__rest) || function (s, e) {
2
+ var t = {};
3
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
4
+ t[p] = s[p];
5
+ if (s != null && typeof Object.getOwnPropertySymbols === "function")
6
+ for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
7
+ if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
8
+ t[p[i]] = s[p[i]];
9
+ }
10
+ return t;
11
+ };
1
12
  import React, { useId } from "react";
2
13
  import { LinearGradient } from "../../LinearGradient/LinearGradient";
3
- export const Line = ({ stroke, d, disabled, fill, className, points }) => {
14
+ export const Line = (_a) => {
15
+ var { stroke, d, disabled, fill, className, points } = _a, rest = __rest(_a, ["stroke", "d", "disabled", "fill", "className", "points"]);
4
16
  const strokeId = useId();
5
17
  const fillId = useId();
6
18
  const clipId = useId();
@@ -14,5 +26,5 @@ export const Line = ({ stroke, d, disabled, fill, className, points }) => {
14
26
  React.createElement("rect", { width: "100%", height: "100%", fill: "black" }),
15
27
  React.createElement("path", { d: d, fill: "none", stroke: "white", strokeWidth: 1.5, vectorEffect: "non-scaling-stroke" }))),
16
28
  isMaskStroke && React.createElement("rect", { width: "100%", height: "100%", fill: `url(#${strokeId})`, mask: `url(#${clipId})` }),
17
- !isMaskStroke && (React.createElement("path", { d: d, stroke: isGradientStroke ? `url(#${strokeId})` : stroke, fill: isGradientFill ? `url(#${fillId})` : fill, vectorEffect: "non-scaling-stroke", strokeWidth: 1.5, className: className }))));
29
+ !isMaskStroke && (React.createElement("path", Object.assign({ d: d, stroke: isGradientStroke ? `url(#${strokeId})` : stroke, fill: isGradientFill ? `url(#${fillId})` : fill, vectorEffect: "non-scaling-stroke", strokeWidth: 1.5, className: className }, rest)))));
18
30
  };
@@ -0,0 +1,12 @@
1
+ import { GraphContext } from "../../../hooks/use-graph/use-graph";
2
+ import * as React from "react";
3
+ type Props = {
4
+ at?: {
5
+ x: string | number | Date;
6
+ };
7
+ border?: string;
8
+ strokeWidth?: number;
9
+ context: GraphContext;
10
+ };
11
+ export declare const LinesJoints: ({ context, border, at, strokeWidth }: Props) => (React.JSX.Element | null)[] | null;
12
+ export {};
@@ -0,0 +1,40 @@
1
+ import * as React from "react";
2
+ import { GraphUtils } from "../../../utils/graph/graph";
3
+ import { GradientUtils } from "../../../utils/gradient/gradient";
4
+ import { equals } from "../../../utils/equals/equals";
5
+ import { CoordinatesUtils } from "../../../utils/coordinates/coordinates";
6
+ export const LinesJoints = ({ context, border, at, strokeWidth = 8 }) => {
7
+ if (!GraphUtils.isXYData(context.data))
8
+ return null;
9
+ const xyForPoints = CoordinatesUtils.xyCoordinatesForDataset(context);
10
+ return context.data.flatMap(({ data, stroke }, i) => {
11
+ const points = xyForPoints(data);
12
+ const isLinearGradient = stroke === null || stroke === void 0 ? void 0 : stroke.includes("linear-gradient");
13
+ if (isLinearGradient && stroke) {
14
+ return data.map(({ x, y }, ii) => {
15
+ if ((at === null || at === void 0 ? void 0 : at.x) && !equals(x, at.x))
16
+ return null;
17
+ const color = GradientUtils.gradientColorFromValue({
18
+ gradient: stroke,
19
+ point: { x, y },
20
+ dataset: data,
21
+ viewbox: context.viewbox,
22
+ domain: context.domain,
23
+ });
24
+ const coordinates = points[ii];
25
+ return (React.createElement(React.Fragment, { key: i + "|" + ii },
26
+ border && (React.createElement("path", { stroke: border, fill: border, d: `M ${coordinates.x} ${coordinates.y} h 0.001`, strokeWidth: strokeWidth + 1, strokeLinecap: "round", vectorEffect: "non-scaling-stroke" })),
27
+ React.createElement("path", { stroke: color, fill: color, d: `M ${coordinates.x} ${coordinates.y} h 0.001`, strokeWidth: strokeWidth, strokeLinecap: "round", vectorEffect: "non-scaling-stroke" })));
28
+ });
29
+ }
30
+ let path = "";
31
+ for (let i = 0; i < data.length; i++) {
32
+ if ((at === null || at === void 0 ? void 0 : at.x) && !equals(data[i].x, at.x))
33
+ continue; /* Skip if at.x is set and data[i].x !== at.x */
34
+ path += `M ${points[i].x} ${points[i].y} h 0.001 `; /* += for perf; see V8 and other engine string types. */
35
+ }
36
+ return (React.createElement(React.Fragment, { key: i },
37
+ border && (React.createElement("path", { stroke: border, fill: border, d: path, strokeWidth: strokeWidth + 1, strokeLinecap: "round", vectorEffect: "non-scaling-stroke" })),
38
+ React.createElement("path", { stroke: stroke, fill: stroke, d: path, strokeWidth: strokeWidth, strokeLinecap: "round", vectorEffect: "non-scaling-stroke" })));
39
+ });
40
+ };
@@ -0,0 +1,18 @@
1
+ import { useMouseCoordinates } from "../../../hooks/use-mouse-coordinates";
2
+ import { MouseEvent } from "react";
3
+ type Props = {
4
+ cross?: {
5
+ x: true;
6
+ y: true;
7
+ };
8
+ joints?: boolean | {
9
+ border: string;
10
+ };
11
+ className?: string;
12
+ datasets?: string[];
13
+ onMove?: (e: MouseEvent<SVGSVGElement>, mouse: ReturnType<typeof useMouseCoordinates>) => void;
14
+ onEnter?: (e: MouseEvent<SVGSVGElement>) => void;
15
+ onLeave?: (e: MouseEvent<SVGSVGElement>) => void;
16
+ };
17
+ export declare const LinesMouse: ({ joints, datasets, onMove, onLeave, onEnter, className }: Props) => import("react").JSX.Element;
18
+ export {};
@@ -0,0 +1,24 @@
1
+ "use client";
2
+ import { useMouseCoordinates } from "../../../hooks/use-mouse-coordinates";
3
+ import { useRef } from "react";
4
+ import { useDatasets, useGraph, useIsZooming } from "../../../hooks/use-graph/use-graph";
5
+ import { tw } from "../../../utils/cx/cx";
6
+ import { Lines } from "../Lines";
7
+ export const LinesMouse = ({ joints, datasets, onMove, onLeave, onEnter, className }) => {
8
+ const ref = useRef(null);
9
+ const isZooming = useIsZooming();
10
+ const context = useGraph();
11
+ const { viewbox } = context;
12
+ const dsets = useDatasets(datasets);
13
+ const mouse = useMouseCoordinates(ref, { x: true, lazy: true });
14
+ return (React.createElement("svg", { ref: ref, viewBox: `0 0 ${viewbox.x} ${viewbox.y}`, preserveAspectRatio: "none", className: tw("lines-tooltip h-full w-full [grid-area:graph] absolute overflow-visible [backface-visibility:hidden]", isZooming && "block overflow-hidden", className), onMouseEnter: onEnter, onMouseLeave: onLeave, onMouseMove: (e) => onMove === null || onMove === void 0 ? void 0 : onMove(e, mouse) },
15
+ (mouse === null || mouse === void 0 ? void 0 : mouse.closest.x) && joints && (React.createElement(Lines.Joints, { context: context, at: { x: mouse.closest.x }, border: typeof joints === "object" ? joints["border"] : undefined })),
16
+ (mouse === null || mouse === void 0 ? void 0 : mouse.closest.x) &&
17
+ joints &&
18
+ dsets.map((dataset, i) => {
19
+ return (React.createElement(Lines.Joints, { context: dataset, at: { x: mouse.closest.x }, border: typeof joints === "object" ? joints["border"] : undefined, key: i }));
20
+ }),
21
+ mouse && (React.createElement(React.Fragment, null,
22
+ React.createElement("line", { x1: 0, y1: mouse.coordinates.y, x2: viewbox.x, y2: mouse.coordinates.y, stroke: "currentColor", strokeDasharray: "4,4", strokeWidth: 10, className: "stroke-gray-200 dark:stroke-white" }),
23
+ React.createElement("line", { x1: mouse.coordinates.x, y1: viewbox.y, x2: mouse.coordinates.x, y2: 0, strokeDasharray: "6,6", className: "stroke-gray-200 dark:stroke-white", strokeWidth: 5 })))));
24
+ };
@@ -1,4 +1,5 @@
1
1
  import * as React from "react";
2
+ import { RefObject } from "react";
2
3
  import { CartesianDataset } from "../../../hooks/use-graph/use-graph";
3
4
  type Props = React.HTMLAttributes<HTMLDivElement> & {
4
5
  tooltip?: ((points: Array<Omit<CartesianDataset[number], "data"> & {
@@ -8,6 +9,7 @@ type Props = React.HTMLAttributes<HTMLDivElement> & {
8
9
  display: (point: CartesianDataset[number]["data"][number]) => React.ReactNode;
9
10
  };
10
11
  joints?: boolean;
12
+ zoneRef: RefObject<SVGSVGElement | null>;
11
13
  };
12
- export declare const LinesTooltip: React.ComponentType<Props>;
14
+ export declare const LinesTooltip: ({ tooltip, joints, zoneRef: ref, ...rest }: Props) => React.JSX.Element | null;
13
15
  export {};