UNPKG

@onesy/ui-react

Version:
1,146 lines (1,131 loc) 60 kB
import _objectWithoutProperties from "@babel/runtime/helpers/objectWithoutProperties"; import _defineProperty from "@babel/runtime/helpers/defineProperty"; const _excluded = ["ref", "tonal", "color", "title", "subtitle", "values", "pre", "elements", "names", "nameX", "nameY", "tooltip", "tooltipIndividually", "tooltipCloseOnMouseLeave", "elementTooltip", "guidelines", "guidelinesAppend", "guidelinesDisplayInactive", "additionalLines", "legend", "legendManageVisibility", "legendPosition", "animate", "animateTimeout", "labels", "labelsX", "labelsY", "labelDecimalPlaces", "labelsAutoNumber", "labelsYAutoNumber", "labelsXAutoNumber", "marks", "marksX", "marksY", "marksAutoNumber", "marksYAutoNumber", "marksXAutoNumber", "grid", "gridX", "gridY", "gridAutoNumber", "gridYAutoNumber", "gridXAutoNumber", "points", "pointsVisibility", "borders", "borderStart", "borderLeft", "borderEnd", "borderRight", "borderTop", "borderBottom", "minX", "maxX", "minY", "maxY", "minMaxPadding", "minPadding", "maxPadding", "minPaddingX", "minPaddingY", "maxPaddingX", "maxPaddingY", "noMain", "tooltipRender", "tooltipGroupRender", "labelRender", "labelResolve", "onUpdateRects", "Component", "SvgProps", "TypeProps", "TitleProps", "SubtitleProps", "PointsProps", "PointProps", "HeaderProps", "AppendProps", "AdditionalLineProps", "AdditionalLinesProps", "LegendProps", "LegendItemProps", "GuidelineProps", "WrapperProps", "className", "children"], _excluded2 = ["item", "className"]; function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; } function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; } import React from 'react'; import { castParam, clamp, copy, is, isEnvironment, percentageFromValueWithinRange, unique, valueFromPercentageWithinRange } from '@onesy/utils'; import { classNames, style as styleMethod, useOnesyTheme } from '@onesy/style-react'; import SurfaceElement from '../Surface'; import LineElement from '../Line'; import TypeElement from '../Type'; import PathElement from '../Path'; import AppendElement from '../Append'; import GrowElement from '../Grow'; import useMediaQuery from '../useMediaQuery'; import { valueBreakpoints, staticClassName, minMaxBetweenNumbers } from '../utils'; import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime"; const useStyle = styleMethod(theme => ({ root: { width: '100%', '&.onesy-Surface-root': { background: 'transparent' } }, additionalLines: { pointerEvents: 'none' }, append_wrapper: { userSelect: 'none', pointerEvents: 'none', zIndex: theme.z_index.tooltip }, wrapper: { position: 'relative', height: '400px', width: '100%', maxWidth: '1000px' }, wrapper_label_x: { margin: '0 0 30px 0' }, wrapper_label_y: { margin: '0 0 0 40px' }, wrapper_labels: { margin: '0 0 30px 40px' }, wrapper_name_x: { margin: '0 0 60px 0' }, wrapper_name_y: { margin: '0 0 0 70px' }, wrapper_names: { margin: '0 0 60px 70px' }, legend_offset_labels_y: { paddingLeft: theme.methods.space.value(5, 'px') }, legend_offset_names_y: { paddingLeft: theme.methods.space.value(9, 'px') }, svg: { position: 'relative', touchAction: 'none', userSelect: 'none', '& path, & circle, & rect, & g': { transition: theme.methods.transitions.make('opacity', { duration: 'xs' }) } }, header: { width: '100%', marginBottom: '24px' }, subtitle: { opacity: '0.74' }, append: { padding: `${theme.methods.space.value(1.5, 'px')} ${theme.methods.space.value(2.5, 'px')}`, borderRadius: theme.methods.shape.radius.value(1.5, 'px') }, name: { position: 'absolute', userSelect: 'none' }, name_x: { bottom: '-61px', left: '50%', transform: 'translateX(-50%)' }, name_y: { left: '-87px', top: '50%', transform: 'translateY(-50%) rotate(-90deg)' }, labels: { position: 'absolute', userSelect: 'none' }, labels_x: { top: 'calc(100% + 12px)', left: '0', width: '100%' }, labels_y: { top: '0', right: 'calc(100% + 12px)', height: '100%' }, label: { position: 'absolute', whiteSpace: 'nowrap' }, label_x: { transform: 'translateX(-50%)', top: '0' }, label_y: { transform: 'translateY(50%)', right: '0' }, marks: { position: 'absolute' }, marks_x: { top: 'calc(100% + 0px)', left: '0', width: '100%' }, marks_y: { top: '0', right: 'calc(100% + 0px)', height: '100%' }, mark: { position: 'absolute' }, mark_x: { width: '1px', height: '7px', top: '0', background: 'currentColor' }, mark_y: { width: '7px', height: '1px', right: '0', background: 'currentColor' }, grids: { position: 'absolute', width: '100%', height: '100%' }, grids_x: { top: '0', left: '0' }, grids_y: { top: '0', left: '0' }, grid: { position: 'absolute', width: '100%', height: '100%', opacity: theme.palette.light ? '0.07' : '0.14' }, grid_x: { width: '1px', background: 'currentColor' }, grid_y: { height: '1px', background: 'currentColor' }, border: { position: 'absolute', background: 'currentColor' }, borderX: { height: '1px', width: 'calc(100% + 1px)', left: '0' }, borderTop: { top: '0' }, borderBottom: { bottom: '0' }, borderY: { width: '1px', height: 'calc(100% + 1px)', top: '-1px' }, borderStart: { insetInlineStart: '0' }, borderLeft: { left: '0' }, borderEnd: { insetInlineEnd: '0' }, borderRight: { right: '0' }, point_visibility_hover: { opacity: '0', transition: theme.methods.transitions.make('opacity', { duration: 'xxs' }), '&:hover': { opacity: '1' } }, point_visibility_visible: { opacity: '1' }, point_active: { opacity: '1' }, point_visibility_hidden: { opacity: '0', pointerEvents: 'none' }, // Legend legend: {}, legend_position_top: { marginBottom: '16px' }, legend_position_bottom: { marginTop: '16px' }, legend_item: { userSelect: 'none' }, legend_item_manage_visibility: { cursor: 'pointer', transition: theme.methods.transitions.make('opacity', { duration: 'xs' }) }, legend_item_hidden: { opacity: '0.4' }, legend_icon: { width: '10px', height: '10px', borderRadius: theme.methods.shape.radius.value(40, 'px'), boxSizing: 'border-box' }, append_icon: { width: '8px', height: '8px', borderRadius: theme.methods.shape.radius.value(40, 'px'), boxSizing: 'border-box' }, // Guideline guidelines: { stroke: 'currentColor', strokeDasharray: '4', opacity: '0.44', pointerEvents: 'none' } }), { name: 'onesy-Chart' }); const Chart = props_ => { const theme = useOnesyTheme(); const props = _objectSpread(_objectSpread(_objectSpread({}, theme?.ui?.elements?.all?.props?.default), theme?.ui?.elements?.onesyChart?.props?.default), props_); const Line = theme?.elements?.Line || LineElement; const Surface = theme?.elements?.Surface || SurfaceElement; const Type = theme?.elements?.Type || TypeElement; const Path = theme?.elements?.Path || PathElement; const Append = theme?.elements?.Append || AppendElement; const Grow = theme?.elements?.Grow || GrowElement; const { ref, tonal = true, color = 'primary', title, subtitle, // Values values, // Pre pre, // Elements elements, // Names names, nameX: nameX_, nameY: nameY_, // Tooltip tooltip: tooltip_, tooltipIndividually: tooltipIndividually_, tooltipCloseOnMouseLeave: tooltipCloseOnMouseLeave_, elementTooltip: elementTooltip_, // Guideline guidelines: guidelines_, guidelinesAppend: guidelinesAppend_, guidelinesDisplayInactive: guidelinesDisplayInactive_, // Additional lines additionalLines: additionalLines__, // Legend legend: legend___, legendManageVisibility = true, legendPosition = 'bottom', // Animation animate: animate_, animateTimeout: animateTimeout_, // Labels labels: labels___, labelsX: labelsX_, labelsY: labelsY_, labelDecimalPlaces: labelDecimalPlaces_, labelsAutoNumber: labelsAutoNumber_, labelsYAutoNumber: labelsYAutoNumber_, labelsXAutoNumber: labelsXAutoNumber_, // Marks marks: marks___, marksX: marksX_, marksY: marksY_, marksAutoNumber: marksAutoNumber_, marksYAutoNumber: marksYAutoNumber_, marksXAutoNumber: marksXAutoNumber_, // Grid grid: grid___, gridX: gridX_, gridY: gridY_, gridAutoNumber: gridAutoNumber_, gridYAutoNumber: gridYAutoNumber_, gridXAutoNumber: gridXAutoNumber_, // Points points: points___, pointsVisibility: pointsVisibility_, // Borders borders: borders_ = true, borderStart: borderStart_ = false, borderLeft: borderLeft_ = true, borderEnd: borderEnd_ = false, borderRight: borderRight_ = false, borderTop: borderTop_ = false, borderBottom: borderBottom_ = true, // Min, max minX: minX_, maxX: maxX_, minY: minY_, maxY: maxY_, minMaxPadding: minMaxPadding__, minPadding: minPadding__, maxPadding: maxPadding__, minPaddingX: minPaddingX__, minPaddingY: minPaddingY__, maxPaddingX: maxPaddingX__, maxPaddingY: maxPaddingY__, noMain, tooltipRender, tooltipGroupRender, labelRender, labelResolve, onUpdateRects, Component = 'div', SvgProps, TypeProps, TitleProps, SubtitleProps, PointsProps, PointProps, HeaderProps, AppendProps, AdditionalLineProps, AdditionalLinesProps, LegendProps, LegendItemProps, GuidelineProps, WrapperProps, className, children } = props, other = _objectWithoutProperties(props, _excluded); const { classes } = useStyle(); const refs = { root: React.useRef(undefined), wrapper: React.useRef(undefined), svg: React.useRef(undefined), defs: React.useRef(undefined), minMax: React.useRef(undefined), rects: React.useRef(undefined), guidelines: React.useRef(undefined), guidelinesIn: React.useRef(undefined), guidelinesPosition: React.useRef(undefined), guidelinesAppend: React.useRef(undefined), hover: React.useRef(undefined), allValues: React.useRef([]), values: React.useRef([]), visible: React.useRef([]), appendStyle: React.useRef({}), theme: React.useRef([]) }; const keys = React.useMemo(() => { const result = []; const items = [nameX_, nameY_, tooltip_, tooltipIndividually_, tooltipCloseOnMouseLeave_, elementTooltip_, guidelines_, guidelinesAppend_, guidelinesDisplayInactive_, animate_, animateTimeout_, legend___, labels___, labelsX_, labelsY_, labelDecimalPlaces_, labelsAutoNumber_, labelsYAutoNumber_, labelsXAutoNumber_, marks___, marksX_, marksY_, marksAutoNumber_, marksYAutoNumber_, marksXAutoNumber_, grid___, gridX_, gridY_, gridAutoNumber_, gridYAutoNumber_, gridXAutoNumber_, points___, pointsVisibility_]; items.forEach(item => { if (is('object', item)) Object.keys(item).filter(key => theme.breakpoints.media[key]).forEach(key_0 => result.push(key_0)); }); return unique(result); }, [nameX_, nameY_, tooltip_, tooltipIndividually_, tooltipCloseOnMouseLeave_, elementTooltip_, guidelines_, guidelinesAppend_, guidelinesDisplayInactive_, animate_, animateTimeout_, legend___, labels___, labelsX_, labelsY_, labelDecimalPlaces_, labelsAutoNumber_, labelsYAutoNumber_, labelsXAutoNumber_, marks___, marksX_, marksY_, marksAutoNumber_, marksYAutoNumber_, marksXAutoNumber_, grid___, gridX_, gridY_, gridAutoNumber_, gridYAutoNumber_, gridXAutoNumber_, points___, pointsVisibility_, borders_, borderStart_, borderLeft_, borderEnd_, borderRight_, borderTop_, borderBottom_, minX_, maxX_, minY_, maxY_, minMaxPadding__, minPadding__, maxPadding__, minPaddingX__, minPaddingY__, maxPaddingX__, maxPaddingY__]); const breakpoints = {}; keys.forEach(key_1 => { breakpoints[key_1] = useMediaQuery(theme.breakpoints.media[key_1], { element: refs.root.current }); }); const nameX = valueBreakpoints(nameX_, undefined, breakpoints, theme); const nameY = valueBreakpoints(nameY_, undefined, breakpoints, theme); const tooltip = valueBreakpoints(tooltip_, true, breakpoints, theme); const tooltipIndividually = valueBreakpoints(tooltipIndividually_, true, breakpoints, theme); const tooltipCloseOnMouseLeave = valueBreakpoints(tooltipCloseOnMouseLeave_, true, breakpoints, theme); const elementTooltip = valueBreakpoints(elementTooltip_, undefined, breakpoints, theme); const guidelines = valueBreakpoints(guidelines_, undefined, breakpoints, theme); const guidelinesAppend = valueBreakpoints(guidelinesAppend_, true, breakpoints, theme); const guidelinesDisplayInactive = valueBreakpoints(guidelinesDisplayInactive_, false, breakpoints, theme); const animate = valueBreakpoints(animate_, true, breakpoints, theme); const animateTimeout = valueBreakpoints(animateTimeout_, 140, breakpoints, theme); const legend__ = valueBreakpoints(legend___, 'auto', breakpoints, theme); const labels__ = valueBreakpoints(labels___, 'auto', breakpoints, theme); const labelsX = valueBreakpoints(labelsX_, true, breakpoints, theme); const labelsY = valueBreakpoints(labelsY_, true, breakpoints, theme); const labelDecimalPlaces = valueBreakpoints(labelDecimalPlaces_, 0, breakpoints, theme); const labelsAutoNumber = valueBreakpoints(labelsAutoNumber_, 10, breakpoints, theme); const labelsYAutoNumber = valueBreakpoints(labelsYAutoNumber_, undefined, breakpoints, theme); const labelsXAutoNumber = valueBreakpoints(labelsXAutoNumber_, undefined, breakpoints, theme); const marks__ = valueBreakpoints(marks___, 'auto', breakpoints, theme); const marksX = valueBreakpoints(marksX_, true, breakpoints, theme); const marksY = valueBreakpoints(marksY_, true, breakpoints, theme); const marksAutoNumber = valueBreakpoints(marksAutoNumber_, 10, breakpoints, theme); const marksYAutoNumber = valueBreakpoints(marksYAutoNumber_, undefined, breakpoints, theme); const marksXAutoNumber = valueBreakpoints(marksXAutoNumber_, undefined, breakpoints, theme); const grid__ = valueBreakpoints(grid___, undefined, breakpoints, theme); const gridX = valueBreakpoints(gridX_, true, breakpoints, theme); const gridY = valueBreakpoints(gridY_, true, breakpoints, theme); const gridAutoNumber = valueBreakpoints(gridAutoNumber_, 10, breakpoints, theme); const gridYAutoNumber = valueBreakpoints(gridYAutoNumber_, undefined, breakpoints, theme); const gridXAutoNumber = valueBreakpoints(gridXAutoNumber_, undefined, breakpoints, theme); const points__ = valueBreakpoints(points___, true, breakpoints, theme); const pointsVisibility = valueBreakpoints(pointsVisibility_, 'hover', breakpoints, theme); const borders = valueBreakpoints(borders_, true, breakpoints, theme); const borderStart = valueBreakpoints(borderStart_, false, breakpoints, theme); const borderLeft = valueBreakpoints(borderLeft_, true, breakpoints, theme); const borderEnd = valueBreakpoints(borderEnd_, false, breakpoints, theme); const borderRight = valueBreakpoints(borderRight_, false, breakpoints, theme); const borderTop = valueBreakpoints(borderTop_, false, breakpoints, theme); const borderBottom = valueBreakpoints(borderBottom_, true, breakpoints, theme); const minX = valueBreakpoints(minX_, undefined, breakpoints, theme); const maxX = valueBreakpoints(maxX_, undefined, breakpoints, theme); const minY = valueBreakpoints(minY_, undefined, breakpoints, theme); const maxY = valueBreakpoints(maxY_, undefined, breakpoints, theme); const minMaxPadding = valueBreakpoints(minMaxPadding__, undefined, breakpoints, theme); const minPadding = valueBreakpoints(minPadding__, undefined, breakpoints, theme); const maxPadding = valueBreakpoints(maxPadding__, undefined, breakpoints, theme); const minPaddingX = valueBreakpoints(minPaddingX__, undefined, breakpoints, theme); const minPaddingY = valueBreakpoints(minPaddingY__, undefined, breakpoints, theme); const maxPaddingX = valueBreakpoints(maxPaddingX__, undefined, breakpoints, theme); const maxPaddingY = valueBreakpoints(maxPaddingY__, undefined, breakpoints, theme); const [rects, setRects] = React.useState(); const [points, setPoints] = React.useState(); const [labels, setLabels] = React.useState(); const [marks, setMarks] = React.useState(); const [grid, setGrid] = React.useState(); const [additionalLines, setAdditionalLines] = React.useState(); const [legend, setLegend] = React.useState([]); const [defs, setDefs] = React.useState([]); const [append, setAppend] = React.useState(); const [visible, setVisible] = React.useState({}); const [guidelinesIn, setGuidelineIn] = React.useState(false); const [guidelinesPosition, setGuidelinePosition] = React.useState({}); const [hover, setHover] = React.useState(false); refs.rects.current = rects; refs.guidelines.current = guidelines; refs.guidelinesIn.current = guidelinesIn; refs.guidelinesPosition.current = guidelinesPosition; refs.guidelinesAppend.current = guidelinesAppend; refs.hover.current = hover; refs.values.current = values; refs.visible.current = visible; refs.theme.current = theme; const minMax = React.useMemo(() => { const values_ = { min: { x: minX || Number.MAX_SAFE_INTEGER, y: minY || Number.MAX_SAFE_INTEGER }, max: { x: maxX || Number.MIN_SAFE_INTEGER, y: maxY || Number.MIN_SAFE_INTEGER } }; if (!noMain) { const allItems = values.flatMap(item_0 => is('array', item_0.values[0]) ? item_0.values : [item_0.values]); if (is('array', values)) { allItems.forEach(item_1 => { const [x, y] = item_1; if (minX === undefined) values_.min.x = Math.min(values_.min.x, x); if (maxX === undefined) values_.max.x = Math.max(values_.max.x, x); if (minY === undefined) values_.min.y = Math.min(values_.min.y, y); if (maxY === undefined) values_.max.y = Math.max(values_.max.y, y); }); } const minPaddingY_ = minPaddingY !== undefined ? minPaddingY : minPadding !== undefined ? minPadding : minMaxPadding; const maxPaddingY_ = maxPaddingY !== undefined ? maxPaddingY : maxPadding !== undefined ? maxPadding : minMaxPadding; const minPaddingX_ = minPaddingX !== undefined ? minPaddingX : minPadding !== undefined ? minPadding : minMaxPadding; const maxPaddingX_ = maxPaddingX !== undefined ? maxPaddingX : maxPadding !== undefined ? maxPadding : minMaxPadding; const totals = { x: values_.max.x - values_.min.x, y: values_.max.y - values_.min.y }; if (minPaddingY_ !== undefined) values_.min.y -= totals.y * minPaddingY_; if (maxPaddingY_ !== undefined) values_.max.y += totals.y * maxPaddingY_; if (minPaddingX_ !== undefined) values_.min.x -= totals.x * minPaddingX_; if (maxPaddingX_ !== undefined) values_.max.x += totals.x * maxPaddingX_; } return values_; }, [values, minX, maxX, minY, maxY, minMaxPadding, minPadding, maxPadding, minPaddingX, minPaddingY, maxPaddingX, maxPaddingY, noMain]); refs.minMax.current = minMax; const onWrapperMouseEnter = () => { if (!refs.guidelinesIn.current) setGuidelineIn(true); setHover(true); }; const onWrapperMouseLeave = () => { if (refs.hover.current) { setHover(false); setTimeout(() => { if (tooltipCloseOnMouseLeave) setAppend(values__0 => _objectSpread(_objectSpread({}, values__0), {}, { open: false })); if (!guidelinesDisplayInactive) setGuidelineIn(false); setGuidelinePosition({}); }); } }; const makeGroupTooltip = (x_, y_) => { const items_0 = refs.allValues.current.filter(item_2 => item_2.normalized[0] === x_); const itemsY = copy(items_0).sort((a, b) => a.normalized[1] - b.normalized[1]); const x_0 = x_; const y_0 = itemsY[0].normalized[1]; const groups = {}; items_0.forEach(item_3 => { const color_ = item_3.item?.color || 'primary'; if (!groups[color_]) groups[color_] = []; groups[color_].push(item_3); }); // Group sorted by y largest, to smallest Object.keys(groups).forEach(group => groups[group].sort((a_0, b_0) => a_0.normalized?.[1] - b_0.normalized?.[1])); // Groups sorted by y largest, to smallest const groupsSorted = Object.keys(groups).sort((a_1, b_1) => groups[a_1][0]?.normalized?.[1] - groups[b_1][0]?.normalized?.[1]); const element = is('function', tooltipGroupRender) ? tooltipGroupRender(groups, groupsSorted) : /*#__PURE__*/_jsx(Line, { tonal: tonal, color: color, elevation: 1, gap: 0.25, direction: "column", Component: Surface, className: classNames([staticClassName('Chart', theme) && ['onesy-Chart-append'], classes.append]), children: /*#__PURE__*/_jsxs(Line, { gap: 1, direction: "column", style: { width: '100%' }, children: [/*#__PURE__*/_jsxs(Line, { gap: 1, direction: "row", align: "center", children: [/*#__PURE__*/_jsx(Type, { version: "b3", style: { fontWeight: 600 }, children: names?.y || 'y' }), /*#__PURE__*/_jsx(Type, { version: "b3", style: { fontWeight: 600 }, children: names?.x || 'x' })] }), /*#__PURE__*/_jsx(Line, { gap: 1, direction: "column", children: groupsSorted.map((group_0, index) => /*#__PURE__*/_jsxs(Line, { gap: 1, direction: "column", style: { width: '100%' }, children: [/*#__PURE__*/_jsx("span", { className: classNames([staticClassName('Chart', theme) && ['onesy-Chart-append-icon'], classes.append_icon]), style: { background: !refs.theme.current.palette.color[group_0] ? group_0 : refs.theme.current.palette.color[group_0][groups[group_0][0]?.item?.tone || 'main'] } }), /*#__PURE__*/_jsx(Line, { gap: 0, direction: "column", style: { width: '100%' }, children: groups[group_0].map((item_4, index_) => /*#__PURE__*/_jsxs(Line, { gap: 1, direction: "row", style: { width: '100%' }, children: [/*#__PURE__*/_jsx(Type, { version: "b3", children: is('function', labelResolve) ? labelResolve(item_4?.values?.[1], 'y', item_4, 'group') : item_4?.values?.[1] }), /*#__PURE__*/_jsx(Type, { version: "b3", children: is('function', labelResolve) ? labelResolve(item_4?.values?.[0], 'x', item_4, 'group') : item_4?.values?.[0] })] }, index_)) })] }, index)) })] }) }); const rectSvg = refs.svg.current.getBoundingClientRect(); const width = 8; const height = 8; const rect_ = { x: x_0 + rectSvg.x - width, y: y_0 + rectSvg.y - width, width, height }; rect_.top = rect_.y; rect_.bottom = rect_.y + height; rect_.left = rect_.x; rect_.right = rect_.x + width; setAppend({ open: true, element, rect: rect_ }); }; React.useEffect(() => { const onMove = (x__0, y__0) => { // Only horizontal move at the moment // ie. vertical guidelines const rectWrapper = refs.rects.current.wrapper; const rectSvg_0 = refs.svg.current.getBoundingClientRect(); let x_1 = clamp(x__0 - rectSvg_0?.x, 0, rectWrapper?.width); const y_1 = clamp(y__0 - rectSvg_0?.y, 0, rectWrapper?.height); if (refs.guidelinesAppend.current && ['both', 'vertical'].includes(refs.guidelines.current)) { const allValues = refs.allValues.current; let index_0; let previous; let item_5; for (let i = 0; i < allValues.length; i++) { previous = allValues[i - 1]; item_5 = allValues[i]; if (previous?.normalized?.[0] <= x_1 && x_1 <= item_5?.normalized?.[0]) { index_0 = i; break; } } if (index_0 === undefined) { index_0 = x_1 <= allValues[0]?.normalized?.[0] ? 0 : allValues.length - 1; previous = allValues[index_0 - 1]; item_5 = allValues[index_0]; } if (previous || item_5) { if (!previous) x_1 = item_5.normalized?.[0];else if (!item_5) x_1 = previous.normalized?.[0];else { const len = item_5.normalized[0] - previous.normalized[0]; const part = len / 2; x_1 = x_1 < previous.normalized[0] + part ? previous.normalized[0] : item_5.normalized[0]; } } makeGroupTooltip(x_1, y_1); } setGuidelinePosition(value_ => _objectSpread(_objectSpread({}, value_), {}, { x: x_1, y: y_1 })); }; const onMouseMove = event => { if (refs.hover.current) { const x_2 = event.clientX; const y_2 = event.clientY; onMove(x_2, y_2); } }; const onTouchMove = event_0 => { if (refs.hover.current) { const x_3 = event_0.touches[0].clientX; const y_3 = event_0.touches[0].clientY; onMove(x_3, y_3); } }; const method = () => { if (refs.wrapper.current) { const rectWrapper_0 = refs.wrapper.current.getBoundingClientRect(); const rectSvg_1 = refs.svg.current.getBoundingClientRect(); const rects_ = { wrapper: rectWrapper_0, svg: rectSvg_1 }; setRects(rects_); if (is('function', onUpdateRects)) onUpdateRects(rects_); } }; method(); const observer = new ResizeObserver(method); observer.observe(refs.root.current); const rootDocument = isEnvironment('browser') ? refs.root.current?.ownerDocument || window.document : undefined; rootDocument.addEventListener('mousemove', onMouseMove); rootDocument.addEventListener('touchmove', onTouchMove); rootDocument.addEventListener('touchend', onWrapperMouseLeave); return () => { observer.disconnect(); rootDocument.removeEventListener('mousemove', onMouseMove); rootDocument.removeEventListener('touchmove', onTouchMove); rootDocument.removeEventListener('touchend', onWrapperMouseLeave); }; }, []); React.useEffect(() => { make(); }, [values, labels__, marks__, grid__, additionalLines__, legend__, visible, guidelinesAppend && guidelinesPosition, rects, theme]); const onPointMouseEnter = values__1 => { if (tooltipIndividually) { setAppend(_objectSpread(_objectSpread({}, is('function', tooltipRender) ? tooltipRender(values__1) : values__1), {}, { rect: values__1.rect, open: true })); } }; const onPointMouseLeave = () => { setAppend(append_ => _objectSpread(_objectSpread({}, append_), {}, { open: false })); }; const onLegendClick = value => { if (value !== undefined && legendManageVisibility) { setVisible(visible_ => _objectSpread(_objectSpread({}, visible_), {}, { [value]: ![undefined, true].includes(visible_[value]) })); } }; const LegendItem = props__ => { const { item: item_6 = {}, className: className_ } = props__, other_ = _objectWithoutProperties(props__, _excluded2); const { color: color__0, tone = 'main', name = 'No name' } = item_6; return /*#__PURE__*/_jsxs(Line, _objectSpread(_objectSpread(_objectSpread({ gap: 1, direction: "row", align: "center" }, LegendItemProps), {}, { className: classNames([staticClassName('Chart', theme) && ['onesy-Chart-legend-item'], className_, LegendItemProps?.className, classes.legend_item]) }, other_), {}, { children: [/*#__PURE__*/_jsx("span", { className: classNames([staticClassName('Chart', theme) && ['onesy-Chart-legend-icon'], classes.legend_icon]), style: { color: !theme.palette.color[color__0] ? color__0 : theme.palette.color[color__0][tone], background: !theme.palette.color[color__0] ? color__0 : theme.palette.color[color__0][tone] } }), /*#__PURE__*/_jsx(Type, { version: "b2", children: name })] })); }; const make = (valueNew = refs.values.current) => { // Make values into x, y, coordinates // normalized in rect width, height values // invert y so 0, 0 is at bottom left if (refs.rects.current && valueNew && !noMain) { const { width: width_0, height: height_0 } = refs.rects.current.wrapper; // Labels const labels_ = { x: is('array', labels__?.x) ? labels__.x : minMaxBetweenNumbers(labelsXAutoNumber !== undefined ? labelsXAutoNumber : labelsAutoNumber !== undefined ? labelsAutoNumber : 10, refs.minMax.current.min.x, refs.minMax.current.max.x).map(item_7 => ({ value: item_7, label: castParam(item_7.toFixed(labelDecimalPlaces || 0)) })), y: is('array', labels__?.y) ? labels__.y : minMaxBetweenNumbers(labelsYAutoNumber !== undefined ? labelsYAutoNumber : labelsAutoNumber !== undefined ? labelsAutoNumber : 10, refs.minMax.current.min.y, refs.minMax.current.max.y).map(item_8 => ({ value: item_8, label: castParam(item_8.toFixed(labelDecimalPlaces || 0)) })) }; labels_.x = labels_.x.map(item_9 => _objectSpread(_objectSpread({}, item_9), {}, { percentage: percentageFromValueWithinRange(item_9.value, refs.minMax.current.min.x, refs.minMax.current.max.x) })); labels_.y = labels_.y.map(item_10 => _objectSpread(_objectSpread({}, item_10), {}, { percentage: percentageFromValueWithinRange(item_10.value, refs.minMax.current.min.y, refs.minMax.current.max.y) })); // Marks const marks_ = { x: is('array', marks__?.x) ? marks__.x : minMaxBetweenNumbers(marksXAutoNumber !== undefined ? marksXAutoNumber : marksAutoNumber !== undefined ? marksAutoNumber : 10, refs.minMax.current.min.x, refs.minMax.current.max.x).map(item_11 => ({ value: item_11 })), y: is('array', marks__?.y) ? marks__.y : minMaxBetweenNumbers(marksYAutoNumber !== undefined ? marksYAutoNumber : marksAutoNumber !== undefined ? marksAutoNumber : 10, refs.minMax.current.min.y, refs.minMax.current.max.y).map(item_12 => ({ value: item_12 })) }; marks_.x = marks_.x.map(item_13 => _objectSpread(_objectSpread({}, item_13), {}, { percentage: percentageFromValueWithinRange(item_13.value, refs.minMax.current.min.x, refs.minMax.current.max.x) })); marks_.y = marks_.y.map(item_14 => _objectSpread(_objectSpread({}, item_14), {}, { percentage: percentageFromValueWithinRange(item_14.value, refs.minMax.current.min.y, refs.minMax.current.max.y) })); // Grid const grid_ = { x: is('array', grid__?.x) ? grid__.x : minMaxBetweenNumbers(gridXAutoNumber !== undefined ? gridXAutoNumber : gridAutoNumber !== undefined ? gridAutoNumber : 10, refs.minMax.current.min.x, refs.minMax.current.max.x).map(item_15 => ({ value: item_15 })), y: is('array', grid__?.y) ? grid__.y : minMaxBetweenNumbers(gridYAutoNumber !== undefined ? gridYAutoNumber : gridAutoNumber !== undefined ? gridAutoNumber : 10, refs.minMax.current.min.y, refs.minMax.current.max.y).map(item_16 => ({ value: item_16 })) }; grid_.x = grid_.x.map(item_17 => _objectSpread(_objectSpread({}, item_17), {}, { percentage: percentageFromValueWithinRange(item_17.value, refs.minMax.current.min.x, refs.minMax.current.max.x) })); grid_.y = grid_.y.map(item_18 => _objectSpread(_objectSpread({}, item_18), {}, { percentage: percentageFromValueWithinRange(item_18.value, refs.minMax.current.min.y, refs.minMax.current.max.y) })); refs.allValues.current = []; // Points const points_ = copy(valueNew).flatMap(item_19 => { const { color: color__1, tone: tone_0 = 'main', name: name_0 } = item_19; const itemValues = ([x_4, y_4, ...args]) => { const values__ = { x: percentageFromValueWithinRange(x_4, refs.minMax.current.min.x, refs.minMax.current.max.x), y: percentageFromValueWithinRange(y_4, refs.minMax.current.min.y, refs.minMax.current.max.y) }; values__.x = valueFromPercentageWithinRange(values__.x, 0, width_0); values__.y = valueFromPercentageWithinRange(values__.y, 0, height_0); if (refs.visible.current[name_0] !== false) { refs.allValues.current.push({ item: item_19, values: [x_4, y_4, ...args], normalized: [values__.x, height_0 - values__.y].map(item_ => Math.abs(item_)) }); } return { values: [x_4, y_4, ...args], normalized: [values__.x, height_0 - values__.y].map(item__0 => Math.abs(item__0)) }; }; const itemArrayNested = is('array', item_19.values?.[0]); const values__2 = itemArrayNested ? copy(item_19.values) // Sort for x from smallest to largest .sort((a_2, b_2) => a_2[0] - b_2[0]).map(itemValues) : [itemValues(item_19.values)]; return values__2.map((item__1, index_1) => /*#__PURE__*/_jsx(Path, _objectSpread(_objectSpread(_objectSpread({ Component: "circle", r: 4, cx: item__1.normalized[0], cy: item__1.normalized[1], fill: !theme.palette.color[color__1] ? color__1 : theme.palette.color[color__1][tone_0], stroke: "none" }, !elementTooltip ? { onMouseEnter: event_1 => { const rect__0 = event_1.target.getBoundingClientRect(); onPointMouseEnter({ values: item__1.values, rect: rect__0 }); }, onMouseLeave: onPointMouseLeave } : undefined), PointProps), {}, { className: classNames([staticClassName('Chart', theme) && ['onesy-Chart-point'], PointProps?.className, classes.point, classes[`point_visibility_${pointsVisibility}`], refs.guidelinesAppend.current && refs.guidelinesPosition.current.x === item__1.normalized[0] && classes.point_active]), style: _objectSpread(_objectSpread({}, refs.visible.current[name_0] === false ? { opacity: 0, pointerEvents: 'none' } : undefined), PointProps?.style) }), index_1)); }); refs.allValues.current.sort((a_3, b_3) => a_3?.normalized[0] - b_3?.normalized[0]); // Guidelines const additionalLines_ = additionalLines__ && additionalLines__.map((item_20, index_2) => { const { color: color__2, tone: tone_1 = 'main', style } = item_20; const values__3 = { x1: percentageFromValueWithinRange(item_20.x1, refs.minMax.current.min.x, refs.minMax.current.max.x), y1: percentageFromValueWithinRange(item_20.y1, refs.minMax.current.min.y, refs.minMax.current.max.y), x2: percentageFromValueWithinRange(item_20.x2, refs.minMax.current.min.x, refs.minMax.current.max.x), y2: percentageFromValueWithinRange(item_20.y2, refs.minMax.current.min.y, refs.minMax.current.max.y) }; values__3.x1 = valueFromPercentageWithinRange(values__3.x1, 0, width_0); values__3.y1 = valueFromPercentageWithinRange(values__3.y1, 0, height_0); values__3.x2 = valueFromPercentageWithinRange(values__3.x2, 0, width_0); values__3.y2 = valueFromPercentageWithinRange(values__3.y2, 0, height_0); return /*#__PURE__*/_jsx(Path, _objectSpread(_objectSpread({ d: `M ${values__3.x1} ${height_0 - values__3.y1} L ${values__3.x2} ${height_0 - values__3.y2}`, fill: "none", stroke: !theme.palette.color[color__2] ? color__2 : theme.palette.color[color__2][tone_1] }, AdditionalLineProps), {}, { className: classNames([staticClassName('Chart', theme) && ['onesy-Chart-additional-lines'], AdditionalLineProps?.className, classes.additionalLines]), style: _objectSpread(_objectSpread({}, style), AdditionalLineProps?.style) }), index_2); }); // Labels setLabels(labels_); // Marks setMarks(marks_); // Grid setGrid(grid_); // Guidelines setAdditionalLines(additionalLines_); // Update children value setPoints(points_); } // Legend const legend_ = legend__ !== 'auto' ? legend__ : []; if (legend__ === 'auto') { const map = {}; values.forEach(item_21 => { const name_1 = item_21?.name || ''; if (!map[name_1]) { legend_.push({ item: item_21, element: /*#__PURE__*/_jsx(LegendItem, { item: item_21 }) }); map[name_1] = true; } }); } // Legend if (is('array', legend_)) setLegend(legend_); }; return /*#__PURE__*/_jsxs(Surface, _objectSpread(_objectSpread({ ref: item_22 => { if (ref) { if (is('function', ref)) ref(item_22);else ref.current = item_22; } refs.root.current = item_22; }, tonal: tonal, color: color, gap: 0, direction: "column", align: "center", Component: Line, AdditionalProps: { Component }, className: classNames([staticClassName('Chart', theme) && ['onesy-Chart-root'], className, classes.root]) }, other), {}, { children: [(title || subtitle) && /*#__PURE__*/_jsxs(Line, _objectSpread(_objectSpread({ gap: 0.5, align: "center", justify: "center" }, HeaderProps), {}, { className: classNames([staticClassName('Chart', theme) && ['onesy-Chart-header'], HeaderProps?.className, classes.header, labels?.y && labelsY && classes.legend_offset_labels_y, names?.y && nameY && classes.legend_offset_names_y]), children: [is('simple', title) ? /*#__PURE__*/_jsx(Type, _objectSpread(_objectSpread(_objectSpread({ version: "t2" }, TypeProps), TitleProps), {}, { className: classNames([staticClassName('Chart', theme) && ['onesy-Chart-title'], TypeProps?.className, TitleProps?.className, classes.title]), children: title })) : title, is('simple', subtitle) ? /*#__PURE__*/_jsx(Type, _objectSpread(_objectSpread(_objectSpread({ version: "b3" }, TypeProps), SubtitleProps), {}, { className: classNames([staticClassName('Chart', theme) && ['onesy-Chart-title'], TypeProps?.className, SubtitleProps?.className, classes.subtitle]), children: subtitle })) : subtitle] })), legend__ && legendPosition === 'top' && legend && /*#__PURE__*/_jsx(Line, _objectSpread(_objectSpread({ gap: 2, direction: "row", align: "center", justify: "center", wrap: "wrap" }, LegendProps), {}, { className: classNames([staticClassName('Chart', theme) && ['onesy-Chart-legend', `onesy-Chart-legend-position-${legendPosition}`], LegendProps?.className, classes.legend, classes[`legend_position_${legendPosition}`], labels?.y && labelsY && classes.legend_offset_labels_y, names?.y && nameY && classes.legend_offset_names_y]), children: legend.map(({ item: item_23, element: element_0 }) => { return /*#__PURE__*/React.cloneElement(element_0, { onClick: () => onLegendClick(item_23.name), className: classNames([element_0?.props?.className, legendManageVisibility && classes.legend_item_manage_visibility, refs.visible.current[item_23.name] === false && classes.legend_item_hidden]) }); }) })), /*#__PURE__*/_jsx(Line, _objectSpread(_objectSpread({ ref: refs.wrapper }, WrapperProps), {}, { className: classNames([staticClassName('Chart', theme) && ['onesy-Chart-wrapper'], WrapperProps?.className, classes.wrapper, labels?.x && labels?.y && labelsX && labelsY && classes.wrapper_labels, !(labels?.x && labels?.y && labelsX && labelsY) && labels?.x && labelsX && classes.wrapper_label_x, !(labels?.x && labels?.y && labelsX && labelsY) && labels?.y && labelsY && classes.wrapper_label_y, names?.x && names?.y && nameX && nameY && classes.wrapper_names, !(names?.x && names?.y && nameX && nameY) && names?.x && nameX && classes.wrapper_name_x, !(names?.x && names?.y && nameX && nameY) && names?.y && nameY && classes.wrapper_name_y]), children: /*#__PURE__*/_jsx(Surface, { tonal: tonal, color: color, children: ({ color: color__3, backgroundColor, palette }) => { return /*#__PURE__*/_jsxs(_Fragment, { children: [!!grid__ && gridX && grid?.x && /*#__PURE__*/_jsx(Line, { gap: 0, direction: "row", align: "flex-start", className: classNames([staticClassName('Chart', theme) && ['onesy-Chart-grids', 'onesy-Chart-grids-x'], classes.grids, classes.grids_x]), children: grid.x.map((item_24, index_3) => /*#__PURE__*/_jsx("div", { className: classNames([staticClassName('Chart', theme) && ['onesy-Chart-grid', 'onesy-Chart-grid-x'], classes.grid, classes.grid_x]), style: { left: `${item_24.percentage}%` } }, index_3)) }), !!grid__ && gridY && grid?.y && /*#__PURE__*/_jsx(Line, { gap: 0, direction: "column", align: "flex-end", justify: "center", className: classNames([staticClassName('Chart', theme) && ['onesy-Chart-grids', 'onesy-Chart-grids-y'], classes.grids, classes.grids_y]), children: grid.y.map((item_25, index_4) => /*#__PURE__*/_jsx("div", { className: classNames([staticClassName('Chart', theme) && ['onesy-Chart-grid', 'onesy-Chart-grid-y'], classes.grid, classes.grid_y]), style: { bottom: `${item_25.percentage}%` } }, index_4)) }), /*#__PURE__*/_jsxs("svg", _objectSpread(_objectSpread(_objectSpread({ ref: refs.svg, xmlns: "http://www.w3.org/2000/svg", viewBox: `0 0 ${rects?.wrapper?.width || 0} ${rects?.wrapper?.height || 0}` }, guidelines ? { onMouseEnter: onWrapperMouseEnter, onTouchStart: onWrapperMouseEnter, onMouseLeave: onWrapperMouseLeave } : undefined), SvgProps), {}, { className: classNames([staticClassName('Chart', theme) && ['onesy-Chart-svg'], SvgProps?.className, classes.svg]), children: [/*#__PURE__*/_jsx("defs", { ref: refs.defs, children: defs && defs.map((item_26, index_5) => (/*#__PURE__*/React.cloneElement(item_26, { key: index_5 }))) }), pre, elements && elements.map(({ item: item_27, element: element_1 }, index_6) => { const isVisible = visible[item_27?.name] === undefined || !!visible[item_27?.name]; return /*#__PURE__*/React.cloneElement(element_1, _objectSpread(_objectSpread({ key: index_6 }, elementTooltip ? { onMouseEnter: event_2 => { const rect__1 = event_2.target.getBoundingClientRect(); onPointMouseEnter(_objectSpread(_objectSpread({}, item_27), {}, { rect: rect__1 })); }, onMouseLeave: onPointMouseLeave } : undefined), {}, { style: _objectSpread(_objectSpread({}, element_1?.props?.style), !isVisible ? { opacity: '0', pointerEvents: 'none' } : undefined) })); }), children && React.Children.toArray(children).map((element_2, index_7) => { const isVisible_0 = visible[element_2.props?.name] === undefined || !!visible[element_2.props?.name]; return /*#__PURE__*/React.cloneElement(element_2, _objectSpread(_objectSpread({ key: index_7, refs: { wrapper: refs.wrapper.current, defs: refs.defs.current }, rects, animate: element_2.props.animate !== undefined ? element_2.props.animate : animate, animateTimeout: element_2.props.animateTimeout !== undefined ? element_2.props.animateTimeout : animateTimeout, updateDefs: setDefs, updateLegend: setLegend }, elementTooltip ? { onMouseEnter: event_3 => { const rect__2 = event_3.target.getBoundingClientRect(); onPointMouseEnter(_objectSpread(_objectSpread({}, element_2.props), {}, { rect: rect__2 })); }, onMouseLeave: onPointMouseLeave } : undefined), {}, { minMax: element_2.props.minMax !== undefined ? element_2.props.minMax : minMax, minX: element_2.props.minX !== undefined ? element_2.props.minX : minX, maxX: element_2.props.maxX !== undefined ? element_2.props.maxX : maxX, minY: element_2.props.minY !== undefined ? element_2.props.minY : minY, maxY: element_2.props.maxY !== undefined ? element_2.props.maxY : maxY, minMaxPadding: element_2.props.minMaxPadding !== undefined ? element_2.props.minMaxPadding : minMaxPadding, minPadding: element_2.props.minPadding !== undefined ? element_2.props.minPadding : minPadding, maxPadding: element_2.props.maxPadding !== undefined ? element_2.props.maxPadding : maxPadding, minPaddingX: element_2.props.minPaddingX !== undefined ? element_2.props.minPaddingX : minPaddingX, minPaddingY: element_2.props.minPaddingY !== undefined ? element_2.props.minPaddingY : minPaddingY, maxPaddingX: element_2.props.maxPaddingX !== undefined ? element_2.props.maxPaddingX : maxPaddingX, maxPaddingY: element_2.props.maxPaddingY !== undefined ? element_2.props.maxPaddingY : maxPaddingY, style: _objectSpread(_objectSpread({}, element_2?.props?.style), !isVisible_0 ? { opacity: '0', pointerEvents: 'none' } : undefined) })); }), additionalLines && /*#__PURE__*/_jsx("g", _objectSpread(_objectSpread({}, AdditionalLinesProps), {}, { className: classNames([staticClassName('Chart', theme) && ['onesy-Chart-additional-lines'], AdditionalLinesProps?.className, classes.additionalLines]), children: additionalLines })), guidelines && guidelinesIn && /*#__PURE__*/_jsxs(_Fragment, { children: [['both', 'vertical'].includes(guidelines) && /*#__PURE__*/_jsx("path", _objectSpread(_objectSpread({ d: `M ${guidelinesPosition?.x || 0} 0 ${guidelinesPosition?.x || 0} ${rects?.wrapper?.height || 0}` }, GuidelineProps), {}, { className: classNames([staticClassName('Chart', theme) && ['onesy-Chart-guidelines', 'onesy-Chart-guidelines-vertical'], GuidelineProps?.className, classes.guidelines, classes.guidelines_vertical]) })), ['both', 'horizontal'].includes(guidelines) && /*#__PURE__*/_jsx("path", _objectSpread(_objectSpread({ d: `M 0 ${guidelinesPosition?.y || 0} ${rects?.wrapper?.width || 0} ${guidelinesPosition?.y || 0}` }, GuidelineProps), {}, { className: classNames([staticClassName('Chart', theme) && ['onesy-Chart-guidelines', 'onesy-Chart-guidelines-horizontal'], GuidelineProps?.className, classes.guidelines, classes.guidelines_horizontal]) }))] }), points__ && points && /*#__PURE__*/_jsx("g", _objectSpread(_objectSpread({}, PointsProps), {}, { className: classNames([staticClassName('Chart', theme) && ['onesy-Chart-points'], PointsProps?.className, classes.