@mlw-packages/react-components 1.5.4 → 1.5.6
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.css +216 -3
- package/dist/index.d.mts +137 -1
- package/dist/index.d.ts +137 -1
- package/dist/index.js +3109 -6
- package/dist/index.mjs +3148 -6
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -620,7 +620,7 @@ var AlertDialogFooterBase = ({
|
|
|
620
620
|
"div",
|
|
621
621
|
{
|
|
622
622
|
className: cn(
|
|
623
|
-
"flex flex-col-reverse sm:flex-row sm:justify-end
|
|
623
|
+
"flex flex-col-reverse sm:flex-row sm:justify-end",
|
|
624
624
|
className
|
|
625
625
|
),
|
|
626
626
|
...props
|
|
@@ -661,11 +661,7 @@ var AlertDialogCancelBase = React2.forwardRef(({ className, testid = "alertdialo
|
|
|
661
661
|
AlertDialogPrimitive.Cancel,
|
|
662
662
|
{
|
|
663
663
|
ref,
|
|
664
|
-
className: cn(
|
|
665
|
-
buttonVariantsBase({ variant: "outline" }),
|
|
666
|
-
"mt-2 sm:mt-0",
|
|
667
|
-
className
|
|
668
|
-
),
|
|
664
|
+
className: cn(buttonVariantsBase({ variant: "outline" }), className),
|
|
669
665
|
"data-testid": testid,
|
|
670
666
|
...props
|
|
671
667
|
}
|
|
@@ -4843,6 +4839,3147 @@ var DestructiveDialog = ({
|
|
|
4843
4839
|
)
|
|
4844
4840
|
] });
|
|
4845
4841
|
};
|
|
4842
|
+
|
|
4843
|
+
// src/components/rechart/LineChart.tsx
|
|
4844
|
+
import { useState as useState10, useEffect as useEffect8, useCallback as useCallback7, useMemo as useMemo5 } from "react";
|
|
4845
|
+
import {
|
|
4846
|
+
LineChart as RechartsLineChart,
|
|
4847
|
+
Line,
|
|
4848
|
+
XAxis,
|
|
4849
|
+
YAxis,
|
|
4850
|
+
CartesianGrid,
|
|
4851
|
+
Tooltip,
|
|
4852
|
+
Legend,
|
|
4853
|
+
LabelList
|
|
4854
|
+
} from "recharts";
|
|
4855
|
+
|
|
4856
|
+
// src/components/rechart/DraggableTooltip.tsx
|
|
4857
|
+
import { useEffect as useEffect7, useRef as useRef2, useState as useState9, useCallback as useCallback6 } from "react";
|
|
4858
|
+
import { MouseIcon } from "@phosphor-icons/react";
|
|
4859
|
+
import { XIcon as XIcon6 } from "@phosphor-icons/react/dist/ssr";
|
|
4860
|
+
|
|
4861
|
+
// src/components/rechart/CloseAllButton.tsx
|
|
4862
|
+
import { XIcon as XIcon5 } from "@phosphor-icons/react/dist/ssr";
|
|
4863
|
+
import { jsx as jsx48, jsxs as jsxs29 } from "react/jsx-runtime";
|
|
4864
|
+
var CloseAllButton = ({
|
|
4865
|
+
count,
|
|
4866
|
+
onCloseAll,
|
|
4867
|
+
position = "top-center",
|
|
4868
|
+
variant = "floating"
|
|
4869
|
+
}) => {
|
|
4870
|
+
if (count <= 1) return null;
|
|
4871
|
+
const getPositionClasses = () => {
|
|
4872
|
+
if (variant === "inline") return "";
|
|
4873
|
+
switch (position) {
|
|
4874
|
+
case "top-left":
|
|
4875
|
+
return "fixed top-6 left-6 z-50";
|
|
4876
|
+
case "top-right":
|
|
4877
|
+
return "fixed top-6 right-6 z-50";
|
|
4878
|
+
case "top-center":
|
|
4879
|
+
return "fixed top-6 left-1/2 transform -translate-x-1/2 z-50";
|
|
4880
|
+
default:
|
|
4881
|
+
return "fixed top-6 left-1/2 transform -translate-x-1/2 z-50";
|
|
4882
|
+
}
|
|
4883
|
+
};
|
|
4884
|
+
const getVariantClasses = () => {
|
|
4885
|
+
if (variant === "inline") {
|
|
4886
|
+
return "text-xs px-2 py-1 h-auto bg-card border border-border shadow-sm hover:bg-accent";
|
|
4887
|
+
}
|
|
4888
|
+
return `
|
|
4889
|
+
rounded-full px-4 py-2.5 bg-transparent hover:bg-white/15 active:bg-white/20
|
|
4890
|
+
text-white font-semibold text-sm
|
|
4891
|
+
transition-all duration-200 ease-in-out
|
|
4892
|
+
hover:scale-105 active:scale-95 hover:shadow-2xl
|
|
4893
|
+
flex items-center gap-2.5
|
|
4894
|
+
group
|
|
4895
|
+
min-w-max
|
|
4896
|
+
`;
|
|
4897
|
+
};
|
|
4898
|
+
if (variant === "inline") {
|
|
4899
|
+
return /* @__PURE__ */ jsx48("div", { className: "absolute top-4 right-4 z-30", children: /* @__PURE__ */ jsxs29(
|
|
4900
|
+
ButtonBase,
|
|
4901
|
+
{
|
|
4902
|
+
variant: "ghost",
|
|
4903
|
+
size: "sm",
|
|
4904
|
+
onClick: onCloseAll,
|
|
4905
|
+
className: getVariantClasses(),
|
|
4906
|
+
children: [
|
|
4907
|
+
/* @__PURE__ */ jsx48(XIcon5, { size: 12, className: "mr-1" }),
|
|
4908
|
+
"Fechar Todos"
|
|
4909
|
+
]
|
|
4910
|
+
}
|
|
4911
|
+
) });
|
|
4912
|
+
}
|
|
4913
|
+
return /* @__PURE__ */ jsx48("div", { className: `${getPositionClasses()} animate-in fade-in slide-in-from-top-2 duration-300`, children: /* @__PURE__ */ jsx48("div", { className: "bg-red-500 rounded-full shadow-xl border border-white/20 backdrop-blur-sm", children: /* @__PURE__ */ jsxs29(
|
|
4914
|
+
ButtonBase,
|
|
4915
|
+
{
|
|
4916
|
+
onClick: onCloseAll,
|
|
4917
|
+
variant: "destructive",
|
|
4918
|
+
size: "sm",
|
|
4919
|
+
className: getVariantClasses(),
|
|
4920
|
+
children: [
|
|
4921
|
+
/* @__PURE__ */ jsx48(
|
|
4922
|
+
XIcon5,
|
|
4923
|
+
{
|
|
4924
|
+
size: 18,
|
|
4925
|
+
className: "\n group-hover:rotate-90 transition-all duration-300 ease-out\n drop-shadow-sm\n "
|
|
4926
|
+
}
|
|
4927
|
+
),
|
|
4928
|
+
/* @__PURE__ */ jsx48("span", { className: "min-w-0 tracking-wide", children: "Fechar Todos" }),
|
|
4929
|
+
/* @__PURE__ */ jsx48(
|
|
4930
|
+
"div",
|
|
4931
|
+
{
|
|
4932
|
+
className: "\n bg-white/20 text-white text-xs font-bold\n rounded-full w-6 h-6 \n flex items-center justify-center\n transition-colors duration-200\n ",
|
|
4933
|
+
children: count
|
|
4934
|
+
}
|
|
4935
|
+
)
|
|
4936
|
+
]
|
|
4937
|
+
}
|
|
4938
|
+
) }) });
|
|
4939
|
+
};
|
|
4940
|
+
var CloseAllButton_default = CloseAllButton;
|
|
4941
|
+
|
|
4942
|
+
// src/components/rechart/DraggableTooltip.tsx
|
|
4943
|
+
import { Fragment as Fragment6, jsx as jsx49, jsxs as jsxs30 } from "react/jsx-runtime";
|
|
4944
|
+
var DraggableTooltip = ({
|
|
4945
|
+
id,
|
|
4946
|
+
data,
|
|
4947
|
+
position,
|
|
4948
|
+
title,
|
|
4949
|
+
dataKeys,
|
|
4950
|
+
finalColors,
|
|
4951
|
+
onClose,
|
|
4952
|
+
periodLabel = "Per\xEDodo Selecionado",
|
|
4953
|
+
dataLabel = "Dados do Per\xEDodo",
|
|
4954
|
+
showCloseAllButton = false,
|
|
4955
|
+
globalTooltipCount,
|
|
4956
|
+
onCloseAll,
|
|
4957
|
+
closeAllButtonPosition = "top-center",
|
|
4958
|
+
closeAllButtonVariant = "floating",
|
|
4959
|
+
onPositionChange
|
|
4960
|
+
}) => {
|
|
4961
|
+
const [localPos, setLocalPos] = useState9(
|
|
4962
|
+
position
|
|
4963
|
+
);
|
|
4964
|
+
const [dragging, setDragging] = useState9(false);
|
|
4965
|
+
const offsetRef = useRef2({ x: 0, y: 0 });
|
|
4966
|
+
const lastMouse = useRef2({ x: 0, y: 0 });
|
|
4967
|
+
const [alignmentGuides, setAlignmentGuides] = useState9([]);
|
|
4968
|
+
const [globalTooltipCountLocal, setGlobalTooltipCountLocal] = useState9(0);
|
|
4969
|
+
useEffect7(() => setLocalPos(position), [position]);
|
|
4970
|
+
const ALIGNMENT_THRESHOLD = 25;
|
|
4971
|
+
const GUIDE_THRESHOLD = 60;
|
|
4972
|
+
const STRONG_SNAP_THRESHOLD = 35;
|
|
4973
|
+
const PRECISION_SNAP_THRESHOLD = 8;
|
|
4974
|
+
const getAllTooltips = useCallback6(() => {
|
|
4975
|
+
const response = [];
|
|
4976
|
+
const ev = new CustomEvent("requestGlobalTooltips", {
|
|
4977
|
+
detail: { requesterId: id, response }
|
|
4978
|
+
});
|
|
4979
|
+
window.dispatchEvent(ev);
|
|
4980
|
+
return response;
|
|
4981
|
+
}, [id]);
|
|
4982
|
+
const updateAlignmentGuides = useCallback6(
|
|
4983
|
+
(currentPosition) => {
|
|
4984
|
+
const allTooltips = getAllTooltips();
|
|
4985
|
+
const otherTooltips = allTooltips.filter((t) => t.id !== id);
|
|
4986
|
+
const guides = [];
|
|
4987
|
+
const tooltipDimensions = { width: 224, height: 120 };
|
|
4988
|
+
otherTooltips.forEach((tooltip) => {
|
|
4989
|
+
const topDiff = Math.abs(currentPosition.top - tooltip.position.top);
|
|
4990
|
+
if (topDiff <= GUIDE_THRESHOLD) {
|
|
4991
|
+
guides.push({
|
|
4992
|
+
type: "horizontal",
|
|
4993
|
+
position: tooltip.position.top,
|
|
4994
|
+
sourceTooltip: {
|
|
4995
|
+
top: currentPosition.top,
|
|
4996
|
+
left: currentPosition.left,
|
|
4997
|
+
width: tooltipDimensions.width,
|
|
4998
|
+
height: tooltipDimensions.height
|
|
4999
|
+
},
|
|
5000
|
+
targetTooltip: {
|
|
5001
|
+
top: tooltip.position.top,
|
|
5002
|
+
left: tooltip.position.left,
|
|
5003
|
+
width: tooltipDimensions.width,
|
|
5004
|
+
height: tooltipDimensions.height
|
|
5005
|
+
}
|
|
5006
|
+
});
|
|
5007
|
+
}
|
|
5008
|
+
const leftDiff = Math.abs(currentPosition.left - tooltip.position.left);
|
|
5009
|
+
if (leftDiff <= GUIDE_THRESHOLD) {
|
|
5010
|
+
guides.push({
|
|
5011
|
+
type: "vertical",
|
|
5012
|
+
position: tooltip.position.left,
|
|
5013
|
+
sourceTooltip: {
|
|
5014
|
+
top: currentPosition.top,
|
|
5015
|
+
left: currentPosition.left,
|
|
5016
|
+
width: tooltipDimensions.width,
|
|
5017
|
+
height: tooltipDimensions.height
|
|
5018
|
+
},
|
|
5019
|
+
targetTooltip: {
|
|
5020
|
+
top: tooltip.position.top,
|
|
5021
|
+
left: tooltip.position.left,
|
|
5022
|
+
width: tooltipDimensions.width,
|
|
5023
|
+
height: tooltipDimensions.height
|
|
5024
|
+
}
|
|
5025
|
+
});
|
|
5026
|
+
}
|
|
5027
|
+
});
|
|
5028
|
+
setAlignmentGuides(guides);
|
|
5029
|
+
},
|
|
5030
|
+
[getAllTooltips, id]
|
|
5031
|
+
);
|
|
5032
|
+
const snapToGuides = useCallback6(
|
|
5033
|
+
(position2) => {
|
|
5034
|
+
const snappedPosition = { ...position2 };
|
|
5035
|
+
let hasSnapped = false;
|
|
5036
|
+
alignmentGuides.forEach((guide) => {
|
|
5037
|
+
if (guide.type === "horizontal") {
|
|
5038
|
+
const diff = Math.abs(position2.top - guide.position);
|
|
5039
|
+
if (diff <= PRECISION_SNAP_THRESHOLD) {
|
|
5040
|
+
snappedPosition.top = guide.position;
|
|
5041
|
+
hasSnapped = true;
|
|
5042
|
+
}
|
|
5043
|
+
} else {
|
|
5044
|
+
const diff = Math.abs(position2.left - guide.position);
|
|
5045
|
+
if (diff <= PRECISION_SNAP_THRESHOLD) {
|
|
5046
|
+
snappedPosition.left = guide.position;
|
|
5047
|
+
hasSnapped = true;
|
|
5048
|
+
}
|
|
5049
|
+
}
|
|
5050
|
+
});
|
|
5051
|
+
if (!hasSnapped) {
|
|
5052
|
+
alignmentGuides.forEach((guide) => {
|
|
5053
|
+
if (guide.type === "horizontal") {
|
|
5054
|
+
const diff = Math.abs(position2.top - guide.position);
|
|
5055
|
+
if (diff <= STRONG_SNAP_THRESHOLD)
|
|
5056
|
+
snappedPosition.top = guide.position;
|
|
5057
|
+
} else {
|
|
5058
|
+
const diff = Math.abs(position2.left - guide.position);
|
|
5059
|
+
if (diff <= STRONG_SNAP_THRESHOLD)
|
|
5060
|
+
snappedPosition.left = guide.position;
|
|
5061
|
+
}
|
|
5062
|
+
});
|
|
5063
|
+
}
|
|
5064
|
+
alignmentGuides.forEach((guide) => {
|
|
5065
|
+
if (guide.type === "horizontal") {
|
|
5066
|
+
const diff = Math.abs(position2.top - guide.position);
|
|
5067
|
+
if (diff <= ALIGNMENT_THRESHOLD && snappedPosition.top === position2.top)
|
|
5068
|
+
snappedPosition.top = guide.position;
|
|
5069
|
+
} else {
|
|
5070
|
+
const diff = Math.abs(position2.left - guide.position);
|
|
5071
|
+
if (diff <= ALIGNMENT_THRESHOLD && snappedPosition.left === position2.left)
|
|
5072
|
+
snappedPosition.left = guide.position;
|
|
5073
|
+
}
|
|
5074
|
+
});
|
|
5075
|
+
return snappedPosition;
|
|
5076
|
+
},
|
|
5077
|
+
[alignmentGuides]
|
|
5078
|
+
);
|
|
5079
|
+
useEffect7(() => {
|
|
5080
|
+
let rafId = null;
|
|
5081
|
+
const handleMouseMove = (e) => {
|
|
5082
|
+
if (!dragging) return;
|
|
5083
|
+
lastMouse.current = { x: e.clientX, y: e.clientY };
|
|
5084
|
+
if (rafId) cancelAnimationFrame(rafId);
|
|
5085
|
+
rafId = requestAnimationFrame(() => {
|
|
5086
|
+
const newLeft = lastMouse.current.x - offsetRef.current.x;
|
|
5087
|
+
const newTop = lastMouse.current.y - offsetRef.current.y;
|
|
5088
|
+
const rawPosition = {
|
|
5089
|
+
top: Math.max(0, Math.min(newTop, window.innerHeight - 200)),
|
|
5090
|
+
left: Math.max(0, Math.min(newLeft, window.innerWidth - 250))
|
|
5091
|
+
};
|
|
5092
|
+
updateAlignmentGuides(rawPosition);
|
|
5093
|
+
const snapped = snapToGuides(rawPosition);
|
|
5094
|
+
setLocalPos(snapped);
|
|
5095
|
+
if (onPositionChange) onPositionChange(id, snapped);
|
|
5096
|
+
});
|
|
5097
|
+
};
|
|
5098
|
+
const handleMouseUp = () => {
|
|
5099
|
+
if (dragging) {
|
|
5100
|
+
setDragging(false);
|
|
5101
|
+
setAlignmentGuides([]);
|
|
5102
|
+
if (rafId) cancelAnimationFrame(rafId);
|
|
5103
|
+
}
|
|
5104
|
+
};
|
|
5105
|
+
if (dragging) {
|
|
5106
|
+
document.addEventListener("mousemove", handleMouseMove, {
|
|
5107
|
+
passive: true
|
|
5108
|
+
});
|
|
5109
|
+
document.addEventListener("mouseup", handleMouseUp);
|
|
5110
|
+
document.body.style.cursor = "grabbing";
|
|
5111
|
+
document.body.style.userSelect = "none";
|
|
5112
|
+
}
|
|
5113
|
+
return () => {
|
|
5114
|
+
if (rafId) cancelAnimationFrame(rafId);
|
|
5115
|
+
document.removeEventListener("mousemove", handleMouseMove);
|
|
5116
|
+
document.removeEventListener("mouseup", handleMouseUp);
|
|
5117
|
+
document.body.style.cursor = "";
|
|
5118
|
+
document.body.style.userSelect = "";
|
|
5119
|
+
};
|
|
5120
|
+
}, [dragging, snapToGuides, updateAlignmentGuides, id, onPositionChange]);
|
|
5121
|
+
useEffect7(() => {
|
|
5122
|
+
const handleCloseAll = () => {
|
|
5123
|
+
onClose(id);
|
|
5124
|
+
};
|
|
5125
|
+
const handleRequestTooltipCount = () => {
|
|
5126
|
+
window.dispatchEvent(
|
|
5127
|
+
new CustomEvent("tooltipCountResponse", { detail: { count: 1 } })
|
|
5128
|
+
);
|
|
5129
|
+
};
|
|
5130
|
+
const handleRequestGlobalTooltips = (event) => {
|
|
5131
|
+
const customEvent = event;
|
|
5132
|
+
const detail = customEvent.detail;
|
|
5133
|
+
if (detail && detail.response && detail.requesterId) {
|
|
5134
|
+
if (!detail.response.find((t) => t.id === id)) {
|
|
5135
|
+
detail.response.push({ id, position: localPos });
|
|
5136
|
+
}
|
|
5137
|
+
}
|
|
5138
|
+
};
|
|
5139
|
+
window.addEventListener("closeAllTooltips", handleCloseAll);
|
|
5140
|
+
window.addEventListener("requestTooltipCount", handleRequestTooltipCount);
|
|
5141
|
+
window.addEventListener(
|
|
5142
|
+
"requestGlobalTooltips",
|
|
5143
|
+
handleRequestGlobalTooltips
|
|
5144
|
+
);
|
|
5145
|
+
return () => {
|
|
5146
|
+
window.removeEventListener("closeAllTooltips", handleCloseAll);
|
|
5147
|
+
window.removeEventListener(
|
|
5148
|
+
"requestTooltipCount",
|
|
5149
|
+
handleRequestTooltipCount
|
|
5150
|
+
);
|
|
5151
|
+
window.removeEventListener(
|
|
5152
|
+
"requestGlobalTooltips",
|
|
5153
|
+
handleRequestGlobalTooltips
|
|
5154
|
+
);
|
|
5155
|
+
};
|
|
5156
|
+
}, [id, localPos, onClose]);
|
|
5157
|
+
useEffect7(() => {
|
|
5158
|
+
if (dragging) return;
|
|
5159
|
+
let total = 0;
|
|
5160
|
+
const handleCountResponse = (event) => {
|
|
5161
|
+
const customEvent = event;
|
|
5162
|
+
total += customEvent.detail.count || 0;
|
|
5163
|
+
};
|
|
5164
|
+
window.addEventListener("tooltipCountResponse", handleCountResponse);
|
|
5165
|
+
window.dispatchEvent(new CustomEvent("requestTooltipCount"));
|
|
5166
|
+
const timeoutId = setTimeout(() => {
|
|
5167
|
+
window.removeEventListener("tooltipCountResponse", handleCountResponse);
|
|
5168
|
+
setGlobalTooltipCountLocal(total);
|
|
5169
|
+
}, 50);
|
|
5170
|
+
return () => {
|
|
5171
|
+
clearTimeout(timeoutId);
|
|
5172
|
+
window.removeEventListener("tooltipCountResponse", handleCountResponse);
|
|
5173
|
+
};
|
|
5174
|
+
}, [localPos, dragging]);
|
|
5175
|
+
useEffect7(() => {
|
|
5176
|
+
const recount = () => {
|
|
5177
|
+
if (dragging) return;
|
|
5178
|
+
let total = 0;
|
|
5179
|
+
const handleCountResponse = (event) => {
|
|
5180
|
+
const customEvent = event;
|
|
5181
|
+
total += customEvent.detail.count || 0;
|
|
5182
|
+
};
|
|
5183
|
+
window.addEventListener("tooltipCountResponse", handleCountResponse);
|
|
5184
|
+
window.dispatchEvent(new CustomEvent("requestTooltipCount"));
|
|
5185
|
+
setTimeout(() => {
|
|
5186
|
+
window.removeEventListener("tooltipCountResponse", handleCountResponse);
|
|
5187
|
+
setGlobalTooltipCountLocal(total);
|
|
5188
|
+
}, 50);
|
|
5189
|
+
};
|
|
5190
|
+
window.addEventListener("recountTooltips", recount);
|
|
5191
|
+
return () => window.removeEventListener("recountTooltips", recount);
|
|
5192
|
+
}, [dragging]);
|
|
5193
|
+
const handleMouseDownLocal = (e) => {
|
|
5194
|
+
e.preventDefault();
|
|
5195
|
+
e.stopPropagation();
|
|
5196
|
+
const rect = e.currentTarget.getBoundingClientRect();
|
|
5197
|
+
offsetRef.current = { x: e.clientX - rect.left, y: e.clientY - rect.top };
|
|
5198
|
+
setDragging(true);
|
|
5199
|
+
};
|
|
5200
|
+
return /* @__PURE__ */ jsxs30(Fragment6, { children: [
|
|
5201
|
+
dragging && alignmentGuides.map((guide, index) => {
|
|
5202
|
+
const isHorizontal = guide.type === "horizontal";
|
|
5203
|
+
const color = isHorizontal ? "#3b82f6" : "#ef4444";
|
|
5204
|
+
const startX = isHorizontal ? Math.min(
|
|
5205
|
+
guide.sourceTooltip.left + guide.sourceTooltip.width / 2,
|
|
5206
|
+
guide.targetTooltip.left + guide.targetTooltip.width / 2
|
|
5207
|
+
) : guide.sourceTooltip.left + guide.sourceTooltip.width / 2;
|
|
5208
|
+
const endX = isHorizontal ? Math.max(
|
|
5209
|
+
guide.sourceTooltip.left + guide.sourceTooltip.width / 2,
|
|
5210
|
+
guide.targetTooltip.left + guide.targetTooltip.width / 2
|
|
5211
|
+
) : guide.targetTooltip.left + guide.targetTooltip.width / 2;
|
|
5212
|
+
const startY = isHorizontal ? guide.sourceTooltip.top + guide.sourceTooltip.height / 2 : Math.min(
|
|
5213
|
+
guide.sourceTooltip.top + guide.sourceTooltip.height / 2,
|
|
5214
|
+
guide.targetTooltip.top + guide.targetTooltip.height / 2
|
|
5215
|
+
);
|
|
5216
|
+
const endY = isHorizontal ? guide.targetTooltip.top + guide.targetTooltip.height / 2 : Math.max(
|
|
5217
|
+
guide.sourceTooltip.top + guide.sourceTooltip.height / 2,
|
|
5218
|
+
guide.targetTooltip.top + guide.targetTooltip.height / 2
|
|
5219
|
+
);
|
|
5220
|
+
return /* @__PURE__ */ jsxs30("div", { children: [
|
|
5221
|
+
/* @__PURE__ */ jsx49(
|
|
5222
|
+
"div",
|
|
5223
|
+
{
|
|
5224
|
+
className: "fixed pointer-events-none z-30",
|
|
5225
|
+
style: {
|
|
5226
|
+
left: startX,
|
|
5227
|
+
top: startY,
|
|
5228
|
+
width: isHorizontal ? endX - startX : "2px",
|
|
5229
|
+
height: isHorizontal ? "2px" : endY - startY,
|
|
5230
|
+
backgroundColor: color,
|
|
5231
|
+
boxShadow: `0 0 8px ${color}60`,
|
|
5232
|
+
opacity: 0.9,
|
|
5233
|
+
borderStyle: "dashed",
|
|
5234
|
+
borderWidth: "1px",
|
|
5235
|
+
borderColor: color,
|
|
5236
|
+
transform: "translateZ(0)"
|
|
5237
|
+
}
|
|
5238
|
+
}
|
|
5239
|
+
),
|
|
5240
|
+
/* @__PURE__ */ jsx49(
|
|
5241
|
+
"div",
|
|
5242
|
+
{
|
|
5243
|
+
className: "fixed pointer-events-none z-31",
|
|
5244
|
+
style: {
|
|
5245
|
+
left: guide.sourceTooltip.left + guide.sourceTooltip.width / 2 - 4,
|
|
5246
|
+
top: guide.sourceTooltip.top + guide.sourceTooltip.height / 2 - 4,
|
|
5247
|
+
width: "8px",
|
|
5248
|
+
height: "8px",
|
|
5249
|
+
backgroundColor: color,
|
|
5250
|
+
borderRadius: "50%",
|
|
5251
|
+
boxShadow: `0 0 4px ${color}80`,
|
|
5252
|
+
opacity: 0.8
|
|
5253
|
+
}
|
|
5254
|
+
}
|
|
5255
|
+
),
|
|
5256
|
+
/* @__PURE__ */ jsx49(
|
|
5257
|
+
"div",
|
|
5258
|
+
{
|
|
5259
|
+
className: "fixed pointer-events-none z-31",
|
|
5260
|
+
style: {
|
|
5261
|
+
left: guide.targetTooltip.left + guide.targetTooltip.width / 2 - 4,
|
|
5262
|
+
top: guide.targetTooltip.top + guide.targetTooltip.height / 2 - 4,
|
|
5263
|
+
width: "8px",
|
|
5264
|
+
height: "8px",
|
|
5265
|
+
backgroundColor: color,
|
|
5266
|
+
borderRadius: "50%",
|
|
5267
|
+
boxShadow: `0 0 4px ${color}80`,
|
|
5268
|
+
opacity: 0.8
|
|
5269
|
+
}
|
|
5270
|
+
}
|
|
5271
|
+
)
|
|
5272
|
+
] }, index);
|
|
5273
|
+
}),
|
|
5274
|
+
/* @__PURE__ */ jsxs30(
|
|
5275
|
+
"div",
|
|
5276
|
+
{
|
|
5277
|
+
className: "fixed bg-card border border-border rounded-lg shadow-lg z-50 min-w-56 select-none",
|
|
5278
|
+
style: {
|
|
5279
|
+
top: localPos.top,
|
|
5280
|
+
left: localPos.left,
|
|
5281
|
+
cursor: dragging ? "grabbing" : "grab"
|
|
5282
|
+
},
|
|
5283
|
+
onMouseDown: handleMouseDownLocal,
|
|
5284
|
+
onClick: (e) => e.stopPropagation(),
|
|
5285
|
+
children: [
|
|
5286
|
+
/* @__PURE__ */ jsxs30("div", { className: "flex items-center justify-between mb-2 p-3 pb-2 border-b bg-muted/20 rounded-t-lg", children: [
|
|
5287
|
+
/* @__PURE__ */ jsx49("div", { className: "flex flex-col gap-1", children: title && /* @__PURE__ */ jsxs30("div", { className: "flex items-center gap-2", children: [
|
|
5288
|
+
/* @__PURE__ */ jsx49("div", { className: "w-2 h-2 bg-blue-500 rounded-full" }),
|
|
5289
|
+
/* @__PURE__ */ jsx49("p", { className: "font-bold text-foreground text-base", children: title })
|
|
5290
|
+
] }) }),
|
|
5291
|
+
/* @__PURE__ */ jsx49(
|
|
5292
|
+
"button",
|
|
5293
|
+
{
|
|
5294
|
+
onClick: (e) => {
|
|
5295
|
+
e.stopPropagation();
|
|
5296
|
+
onClose(id);
|
|
5297
|
+
},
|
|
5298
|
+
className: "text-muted-foreground hover:text-destructive ml-2 text-sm hover:bg-destructive/10 rounded p-1",
|
|
5299
|
+
title: "Fechar este tooltip",
|
|
5300
|
+
children: /* @__PURE__ */ jsx49(XIcon6, { size: 14 })
|
|
5301
|
+
}
|
|
5302
|
+
)
|
|
5303
|
+
] }),
|
|
5304
|
+
/* @__PURE__ */ jsxs30("div", { className: "px-3 py-2 bg-accent/30 border-l-4 border-primary", children: [
|
|
5305
|
+
/* @__PURE__ */ jsx49("div", { className: "flex items-center gap-2", children: /* @__PURE__ */ jsx49("span", { className: "text-xs font-medium text-muted-foreground uppercase tracking-wide", children: periodLabel }) }),
|
|
5306
|
+
/* @__PURE__ */ jsx49("p", { className: "font-bold text-lg text-foreground mt-1", children: data.name })
|
|
5307
|
+
] }),
|
|
5308
|
+
/* @__PURE__ */ jsxs30("div", { className: "p-3 pt-2 space-y-2", children: [
|
|
5309
|
+
/* @__PURE__ */ jsx49("p", { className: "text-xs font-medium text-muted-foreground uppercase tracking-wide mb-2", children: dataLabel }),
|
|
5310
|
+
dataKeys.map((key) => {
|
|
5311
|
+
const value = data[key];
|
|
5312
|
+
if (value === void 0) return null;
|
|
5313
|
+
return /* @__PURE__ */ jsxs30(
|
|
5314
|
+
"div",
|
|
5315
|
+
{
|
|
5316
|
+
className: "flex items-center justify-between gap-3 text-sm mb-2 p-2 rounded bg-muted/20 hover:bg-muted/40 transition-colors",
|
|
5317
|
+
children: [
|
|
5318
|
+
/* @__PURE__ */ jsxs30("div", { className: "flex items-center gap-2", children: [
|
|
5319
|
+
/* @__PURE__ */ jsx49(
|
|
5320
|
+
"div",
|
|
5321
|
+
{
|
|
5322
|
+
className: "w-3 h-3 rounded-sm shadow-sm",
|
|
5323
|
+
style: { backgroundColor: finalColors[key] || "#666" }
|
|
5324
|
+
}
|
|
5325
|
+
),
|
|
5326
|
+
/* @__PURE__ */ jsx49("span", { className: "font-medium text-foreground", children: key.charAt(0).toUpperCase() + key.slice(1) })
|
|
5327
|
+
] }),
|
|
5328
|
+
/* @__PURE__ */ jsx49("span", { className: "font-semibold text-foreground bg-background px-2 py-1 rounded text-xs", children: value.toLocaleString("pt-BR") })
|
|
5329
|
+
]
|
|
5330
|
+
},
|
|
5331
|
+
key
|
|
5332
|
+
);
|
|
5333
|
+
}),
|
|
5334
|
+
/* @__PURE__ */ jsx49("div", { className: "mt-3 pt-2 border-t", children: /* @__PURE__ */ jsxs30("p", { className: "text-xs text-muted-foreground flex items-center gap-1", children: [
|
|
5335
|
+
/* @__PURE__ */ jsx49("span", { children: /* @__PURE__ */ jsx49(MouseIcon, {}) }),
|
|
5336
|
+
"Arraste para mover \u2022 Clique no ",
|
|
5337
|
+
/* @__PURE__ */ jsx49(XIcon6, { size: 12 }),
|
|
5338
|
+
" para remover"
|
|
5339
|
+
] }) })
|
|
5340
|
+
] })
|
|
5341
|
+
]
|
|
5342
|
+
}
|
|
5343
|
+
),
|
|
5344
|
+
showCloseAllButton && onCloseAll && /* @__PURE__ */ jsx49(
|
|
5345
|
+
CloseAllButton_default,
|
|
5346
|
+
{
|
|
5347
|
+
count: typeof globalTooltipCount === "number" ? globalTooltipCount : globalTooltipCountLocal,
|
|
5348
|
+
onCloseAll,
|
|
5349
|
+
position: closeAllButtonPosition,
|
|
5350
|
+
variant: closeAllButtonVariant
|
|
5351
|
+
}
|
|
5352
|
+
)
|
|
5353
|
+
] });
|
|
5354
|
+
};
|
|
5355
|
+
var DraggableTooltip_default = DraggableTooltip;
|
|
5356
|
+
|
|
5357
|
+
// src/components/rechart/pillLabelRenderer.tsx
|
|
5358
|
+
import { jsx as jsx50, jsxs as jsxs31 } from "react/jsx-runtime";
|
|
5359
|
+
var formatCompactNumber = (value) => {
|
|
5360
|
+
if (value >= 1e9)
|
|
5361
|
+
return (value / 1e9).toFixed(1).replace(/\.0$/, "") + "B";
|
|
5362
|
+
if (value >= 1e6)
|
|
5363
|
+
return (value / 1e6).toFixed(1).replace(/\.0$/, "") + "M";
|
|
5364
|
+
if (value >= 1e3) return (value / 1e3).toFixed(1).replace(/\.0$/, "") + "K";
|
|
5365
|
+
return value.toString();
|
|
5366
|
+
};
|
|
5367
|
+
var parseNumber = (v) => {
|
|
5368
|
+
if (typeof v === "number") return v;
|
|
5369
|
+
if (typeof v === "string" && v.trim() !== "" && !Number.isNaN(Number(v)))
|
|
5370
|
+
return Number(v);
|
|
5371
|
+
return void 0;
|
|
5372
|
+
};
|
|
5373
|
+
var renderPillLabel = (color, variant) => {
|
|
5374
|
+
return (props) => {
|
|
5375
|
+
const { x, y, value } = props;
|
|
5376
|
+
const text = typeof value === "number" ? formatCompactNumber(value) : String(value ?? "");
|
|
5377
|
+
const paddingX = 8;
|
|
5378
|
+
const approxCharWidth = 7;
|
|
5379
|
+
const pillWidth = Math.max(
|
|
5380
|
+
40,
|
|
5381
|
+
String(text).length * approxCharWidth + paddingX * 2
|
|
5382
|
+
);
|
|
5383
|
+
const pillHeight = 20;
|
|
5384
|
+
const xNum = parseNumber(x);
|
|
5385
|
+
const px = parseNumber(props.x);
|
|
5386
|
+
const pWidth = parseNumber(props.width);
|
|
5387
|
+
const vb = props.viewBox;
|
|
5388
|
+
const cxNum = parseNumber(props.cx);
|
|
5389
|
+
let centerX;
|
|
5390
|
+
if (typeof px === "number" && typeof pWidth === "number") {
|
|
5391
|
+
centerX = px + pWidth / 2;
|
|
5392
|
+
} else if (typeof xNum === "number" && typeof pWidth === "number") {
|
|
5393
|
+
centerX = xNum + pWidth / 2;
|
|
5394
|
+
} else if (typeof cxNum === "number") {
|
|
5395
|
+
centerX = cxNum;
|
|
5396
|
+
} else if (vb && typeof vb.x === "number" && typeof vb.width === "number" && typeof props.index === "number") {
|
|
5397
|
+
const approxCols = Math.max(1, props.index + 1);
|
|
5398
|
+
const colWidth = vb.width / approxCols;
|
|
5399
|
+
centerX = vb.x + colWidth * (props.index + 0.5);
|
|
5400
|
+
} else if (vb && typeof vb.x === "number" && typeof vb.width === "number") {
|
|
5401
|
+
centerX = vb.x + vb.width / 2;
|
|
5402
|
+
} else {
|
|
5403
|
+
centerX = typeof props.index === "number" ? props.index * 40 + 24 : 0;
|
|
5404
|
+
}
|
|
5405
|
+
if (vb && typeof vb.x === "number" && typeof vb.width === "number") {
|
|
5406
|
+
const minX = vb.x + 0 + pillWidth / 22;
|
|
5407
|
+
const maxX = vb.x + vb.width - 2 - pillWidth / 2;
|
|
5408
|
+
centerX = Math.max(minX, Math.min(maxX, centerX));
|
|
5409
|
+
}
|
|
5410
|
+
const yNum = parseNumber(y);
|
|
5411
|
+
const py = parseNumber(props.y);
|
|
5412
|
+
const cyNum = parseNumber(props.cy);
|
|
5413
|
+
const centerY = yNum ?? (typeof py === "number" ? py : vb && typeof vb.y === "number" && typeof vb.height === "number" ? vb.y + vb.height / 2 : typeof cyNum === "number" ? cyNum : 0);
|
|
5414
|
+
const rectX = centerX - pillWidth / 2;
|
|
5415
|
+
const rectY = centerY - pillHeight - 6;
|
|
5416
|
+
const textX = centerX;
|
|
5417
|
+
const textY = rectY + pillHeight / 2 + 3;
|
|
5418
|
+
const rectFill = variant === "filled" ? color : variant === "soft" ? `${color}` : "#ffffff";
|
|
5419
|
+
const rectStroke = variant === "outline" ? `${color}CC` : void 0;
|
|
5420
|
+
const textColor = variant === "filled" ? "#ffffff" : variant === "outline" ? color : "#111827";
|
|
5421
|
+
return /* @__PURE__ */ jsxs31("g", { children: [
|
|
5422
|
+
/* @__PURE__ */ jsx50(
|
|
5423
|
+
"rect",
|
|
5424
|
+
{
|
|
5425
|
+
x: rectX,
|
|
5426
|
+
y: rectY,
|
|
5427
|
+
rx: pillHeight / 2,
|
|
5428
|
+
width: pillWidth,
|
|
5429
|
+
height: pillHeight,
|
|
5430
|
+
fill: rectFill,
|
|
5431
|
+
stroke: rectStroke,
|
|
5432
|
+
strokeWidth: rectStroke ? 1 : 0
|
|
5433
|
+
}
|
|
5434
|
+
),
|
|
5435
|
+
/* @__PURE__ */ jsx50(
|
|
5436
|
+
"text",
|
|
5437
|
+
{
|
|
5438
|
+
x: textX,
|
|
5439
|
+
y: textY - 3,
|
|
5440
|
+
fill: textColor,
|
|
5441
|
+
fontSize: 13,
|
|
5442
|
+
fontWeight: 700,
|
|
5443
|
+
textAnchor: "middle",
|
|
5444
|
+
dominantBaseline: "central",
|
|
5445
|
+
letterSpacing: 0.2,
|
|
5446
|
+
children: text
|
|
5447
|
+
}
|
|
5448
|
+
)
|
|
5449
|
+
] });
|
|
5450
|
+
};
|
|
5451
|
+
};
|
|
5452
|
+
var pillLabelRenderer_default = renderPillLabel;
|
|
5453
|
+
|
|
5454
|
+
// src/components/rechart/LineChart.tsx
|
|
5455
|
+
import { jsx as jsx51, jsxs as jsxs32 } from "react/jsx-runtime";
|
|
5456
|
+
var defaultData = [
|
|
5457
|
+
{ name: "A", value: 100 },
|
|
5458
|
+
{ name: "B", value: 200 },
|
|
5459
|
+
{ name: "C", value: 150 }
|
|
5460
|
+
];
|
|
5461
|
+
var DEFAULT_COLORS = ["#55af7d", "#8e68ff", "#2273e1"];
|
|
5462
|
+
var generateAdditionalColors = (baseColors, count) => {
|
|
5463
|
+
const colors2 = [...baseColors];
|
|
5464
|
+
const variations = [
|
|
5465
|
+
"#ff6b6b",
|
|
5466
|
+
"#4ecdc4",
|
|
5467
|
+
"#45b7d1",
|
|
5468
|
+
"#f9ca24",
|
|
5469
|
+
"#6c5ce7",
|
|
5470
|
+
"#a29bfe",
|
|
5471
|
+
"#fd79a8",
|
|
5472
|
+
"#00b894"
|
|
5473
|
+
];
|
|
5474
|
+
while (colors2.length < count) {
|
|
5475
|
+
colors2.push(
|
|
5476
|
+
variations[(colors2.length - baseColors.length) % variations.length]
|
|
5477
|
+
);
|
|
5478
|
+
}
|
|
5479
|
+
return colors2;
|
|
5480
|
+
};
|
|
5481
|
+
var compactTick = (value) => {
|
|
5482
|
+
if (value >= 1e9)
|
|
5483
|
+
return (value / 1e9).toFixed(1).replace(/\.0$/, "") + "B";
|
|
5484
|
+
if (value >= 1e6)
|
|
5485
|
+
return (value / 1e6).toFixed(1).replace(/\.0$/, "") + "M";
|
|
5486
|
+
if (value >= 1e3) return (value / 1e3).toFixed(1).replace(/\.0$/, "") + "K";
|
|
5487
|
+
return String(value);
|
|
5488
|
+
};
|
|
5489
|
+
var CustomLineChart = ({
|
|
5490
|
+
data = defaultData,
|
|
5491
|
+
className,
|
|
5492
|
+
height = 300,
|
|
5493
|
+
width = "100%",
|
|
5494
|
+
colors: colors2 = DEFAULT_COLORS,
|
|
5495
|
+
gridColor,
|
|
5496
|
+
showGrid = true,
|
|
5497
|
+
showTooltip = true,
|
|
5498
|
+
showLegend = true,
|
|
5499
|
+
title,
|
|
5500
|
+
titlePosition = "left",
|
|
5501
|
+
strokeWidth = 2,
|
|
5502
|
+
showDots = true,
|
|
5503
|
+
showLabels = false
|
|
5504
|
+
}) => {
|
|
5505
|
+
const [activeTooltips, setActiveTooltips] = useState10([]);
|
|
5506
|
+
const [isDragging, setIsDragging] = useState10(null);
|
|
5507
|
+
const [dragOffset, setDragOffset] = useState10({
|
|
5508
|
+
x: 0,
|
|
5509
|
+
y: 0
|
|
5510
|
+
});
|
|
5511
|
+
const [globalTooltipCount, setGlobalTooltipCount] = useState10(0);
|
|
5512
|
+
const [alignmentGuides, setAlignmentGuides] = useState10([]);
|
|
5513
|
+
const generateColors = (dataKeys2) => {
|
|
5514
|
+
const colorMap = {};
|
|
5515
|
+
const allColors = generateAdditionalColors(colors2, dataKeys2.length);
|
|
5516
|
+
dataKeys2.forEach((key, index) => {
|
|
5517
|
+
colorMap[key] = allColors[index] || colors2[index % colors2.length];
|
|
5518
|
+
});
|
|
5519
|
+
return colorMap;
|
|
5520
|
+
};
|
|
5521
|
+
const dataKeys = useMemo5(
|
|
5522
|
+
() => data.length > 0 ? Object.keys(data[0]).filter((key) => key !== "name") : [],
|
|
5523
|
+
[data]
|
|
5524
|
+
);
|
|
5525
|
+
const finalColors = generateColors(dataKeys);
|
|
5526
|
+
const niceCeil = (value) => {
|
|
5527
|
+
if (!isFinite(value) || value <= 0) return 1;
|
|
5528
|
+
const pow = Math.pow(10, Math.floor(Math.log10(value)));
|
|
5529
|
+
const normalized = value / pow;
|
|
5530
|
+
const multipliers = [
|
|
5531
|
+
1,
|
|
5532
|
+
1.25,
|
|
5533
|
+
1.5,
|
|
5534
|
+
2,
|
|
5535
|
+
2.5,
|
|
5536
|
+
3,
|
|
5537
|
+
4,
|
|
5538
|
+
5,
|
|
5539
|
+
7.5,
|
|
5540
|
+
10,
|
|
5541
|
+
15,
|
|
5542
|
+
20,
|
|
5543
|
+
25,
|
|
5544
|
+
50,
|
|
5545
|
+
100
|
|
5546
|
+
];
|
|
5547
|
+
for (const m of multipliers) {
|
|
5548
|
+
if (m >= normalized) return Math.ceil(m * pow);
|
|
5549
|
+
}
|
|
5550
|
+
return Math.ceil(100 * pow);
|
|
5551
|
+
};
|
|
5552
|
+
const maxDataValue = useMemo5(() => {
|
|
5553
|
+
let max = 0;
|
|
5554
|
+
for (const row of data) {
|
|
5555
|
+
const r = row;
|
|
5556
|
+
for (const key of dataKeys) {
|
|
5557
|
+
const v = r[key];
|
|
5558
|
+
if (typeof v === "number" && Number.isFinite(v) && v > max)
|
|
5559
|
+
max = v;
|
|
5560
|
+
}
|
|
5561
|
+
}
|
|
5562
|
+
return max;
|
|
5563
|
+
}, [data, dataKeys]);
|
|
5564
|
+
const niceMax = useMemo5(() => {
|
|
5565
|
+
let padding = 0.08;
|
|
5566
|
+
if (maxDataValue > 1e6) padding = 0.05;
|
|
5567
|
+
if (maxDataValue > 1e7) padding = 0.03;
|
|
5568
|
+
if (maxDataValue === 0) padding = 0.12;
|
|
5569
|
+
const padded = maxDataValue * (1 + padding);
|
|
5570
|
+
return niceCeil(padded);
|
|
5571
|
+
}, [maxDataValue]);
|
|
5572
|
+
const ClickableDot = (props) => {
|
|
5573
|
+
const { cx, cy, payload, dataKey } = props;
|
|
5574
|
+
const handleDotClick = (e) => {
|
|
5575
|
+
e.stopPropagation();
|
|
5576
|
+
if (!payload || !cx || !cy) return;
|
|
5577
|
+
const tooltipId = `${payload.name}`;
|
|
5578
|
+
const existingIndex = activeTooltips.findIndex(
|
|
5579
|
+
(tooltip) => tooltip.id === tooltipId
|
|
5580
|
+
);
|
|
5581
|
+
if (existingIndex !== -1) {
|
|
5582
|
+
setActiveTooltips(
|
|
5583
|
+
(prev) => prev.filter((tooltip) => tooltip.id !== tooltipId)
|
|
5584
|
+
);
|
|
5585
|
+
} else {
|
|
5586
|
+
const newTooltip = {
|
|
5587
|
+
id: tooltipId,
|
|
5588
|
+
data: payload,
|
|
5589
|
+
position: {
|
|
5590
|
+
top: cy - 50,
|
|
5591
|
+
// Posição relativa ao SVG
|
|
5592
|
+
left: cx - 100
|
|
5593
|
+
}
|
|
5594
|
+
};
|
|
5595
|
+
setActiveTooltips((prev) => [...prev, newTooltip]);
|
|
5596
|
+
}
|
|
5597
|
+
};
|
|
5598
|
+
return /* @__PURE__ */ jsx51(
|
|
5599
|
+
"circle",
|
|
5600
|
+
{
|
|
5601
|
+
cx,
|
|
5602
|
+
cy,
|
|
5603
|
+
r: 6,
|
|
5604
|
+
fill: finalColors[dataKey || ""] || colors2[0],
|
|
5605
|
+
stroke: finalColors[dataKey || ""] || colors2[0],
|
|
5606
|
+
strokeWidth: 2,
|
|
5607
|
+
style: { cursor: "pointer" },
|
|
5608
|
+
onClick: handleDotClick
|
|
5609
|
+
}
|
|
5610
|
+
);
|
|
5611
|
+
};
|
|
5612
|
+
const handleChartClick = (e) => {
|
|
5613
|
+
if (e && e.activePayload && e.activePayload.length > 0) {
|
|
5614
|
+
const clickedData = e.activePayload[0].payload;
|
|
5615
|
+
const tooltipId = `${clickedData.name}`;
|
|
5616
|
+
const existingIndex = activeTooltips.findIndex(
|
|
5617
|
+
(tooltip) => tooltip.id === tooltipId
|
|
5618
|
+
);
|
|
5619
|
+
if (existingIndex !== -1) {
|
|
5620
|
+
setActiveTooltips(
|
|
5621
|
+
(prev) => prev.filter((tooltip) => tooltip.id !== tooltipId)
|
|
5622
|
+
);
|
|
5623
|
+
} else {
|
|
5624
|
+
const newTooltip = {
|
|
5625
|
+
id: tooltipId,
|
|
5626
|
+
data: clickedData,
|
|
5627
|
+
position: {
|
|
5628
|
+
top: (e.chartY || 100) - 10,
|
|
5629
|
+
left: (e.chartX || 100) - 100
|
|
5630
|
+
}
|
|
5631
|
+
};
|
|
5632
|
+
setActiveTooltips((prev) => [...prev, newTooltip]);
|
|
5633
|
+
}
|
|
5634
|
+
} else {
|
|
5635
|
+
}
|
|
5636
|
+
};
|
|
5637
|
+
const handleChartBackgroundClick = () => {
|
|
5638
|
+
setActiveTooltips([]);
|
|
5639
|
+
};
|
|
5640
|
+
const handleCloseAllTooltips = useCallback7(() => {
|
|
5641
|
+
window.dispatchEvent(new CustomEvent("closeAllTooltips"));
|
|
5642
|
+
}, []);
|
|
5643
|
+
const updateAlignmentGuides = useCallback7(
|
|
5644
|
+
(draggedTooltipId, draggedPosition) => {
|
|
5645
|
+
const SNAP_THRESHOLD = 15;
|
|
5646
|
+
const draggedTooltip = activeTooltips.find(
|
|
5647
|
+
(t) => t.id === draggedTooltipId
|
|
5648
|
+
);
|
|
5649
|
+
if (!draggedTooltip) return;
|
|
5650
|
+
const tooltipWidth = 200;
|
|
5651
|
+
const tooltipHeight = 80;
|
|
5652
|
+
const globalTooltips = [];
|
|
5653
|
+
window.dispatchEvent(
|
|
5654
|
+
new CustomEvent("requestGlobalTooltips", {
|
|
5655
|
+
detail: { requesterId: draggedTooltipId }
|
|
5656
|
+
})
|
|
5657
|
+
);
|
|
5658
|
+
activeTooltips.forEach((tooltip) => {
|
|
5659
|
+
if (tooltip.id !== draggedTooltipId) {
|
|
5660
|
+
globalTooltips.push({
|
|
5661
|
+
top: tooltip.position.top,
|
|
5662
|
+
left: tooltip.position.left,
|
|
5663
|
+
width: tooltipWidth,
|
|
5664
|
+
height: tooltipHeight,
|
|
5665
|
+
id: tooltip.id
|
|
5666
|
+
});
|
|
5667
|
+
}
|
|
5668
|
+
});
|
|
5669
|
+
const newGuides = [];
|
|
5670
|
+
globalTooltips.forEach((otherTooltip) => {
|
|
5671
|
+
const draggedCenter = {
|
|
5672
|
+
x: draggedPosition.left + tooltipWidth / 2,
|
|
5673
|
+
y: draggedPosition.top + tooltipHeight / 2
|
|
5674
|
+
};
|
|
5675
|
+
const otherCenter = {
|
|
5676
|
+
x: otherTooltip.left + otherTooltip.width / 2,
|
|
5677
|
+
y: otherTooltip.top + otherTooltip.height / 2
|
|
5678
|
+
};
|
|
5679
|
+
const horizontalDistance = Math.abs(draggedCenter.y - otherCenter.y);
|
|
5680
|
+
if (horizontalDistance <= SNAP_THRESHOLD) {
|
|
5681
|
+
newGuides.push({
|
|
5682
|
+
type: "horizontal",
|
|
5683
|
+
position: otherCenter.y,
|
|
5684
|
+
visible: true,
|
|
5685
|
+
sourceTooltip: {
|
|
5686
|
+
top: draggedPosition.top,
|
|
5687
|
+
left: draggedPosition.left,
|
|
5688
|
+
width: tooltipWidth,
|
|
5689
|
+
height: tooltipHeight
|
|
5690
|
+
},
|
|
5691
|
+
targetTooltip: {
|
|
5692
|
+
top: otherTooltip.top,
|
|
5693
|
+
left: otherTooltip.left,
|
|
5694
|
+
width: otherTooltip.width,
|
|
5695
|
+
height: otherTooltip.height
|
|
5696
|
+
}
|
|
5697
|
+
});
|
|
5698
|
+
}
|
|
5699
|
+
const verticalDistance = Math.abs(draggedCenter.x - otherCenter.x);
|
|
5700
|
+
if (verticalDistance <= SNAP_THRESHOLD) {
|
|
5701
|
+
newGuides.push({
|
|
5702
|
+
type: "vertical",
|
|
5703
|
+
position: otherCenter.x,
|
|
5704
|
+
visible: true,
|
|
5705
|
+
sourceTooltip: {
|
|
5706
|
+
top: draggedPosition.top,
|
|
5707
|
+
left: draggedPosition.left,
|
|
5708
|
+
width: tooltipWidth,
|
|
5709
|
+
height: tooltipHeight
|
|
5710
|
+
},
|
|
5711
|
+
targetTooltip: {
|
|
5712
|
+
top: otherTooltip.top,
|
|
5713
|
+
left: otherTooltip.left,
|
|
5714
|
+
width: otherTooltip.width,
|
|
5715
|
+
height: otherTooltip.height
|
|
5716
|
+
}
|
|
5717
|
+
});
|
|
5718
|
+
}
|
|
5719
|
+
});
|
|
5720
|
+
setAlignmentGuides(newGuides);
|
|
5721
|
+
},
|
|
5722
|
+
[activeTooltips]
|
|
5723
|
+
);
|
|
5724
|
+
const snapToGuides = useCallback7(
|
|
5725
|
+
(position) => {
|
|
5726
|
+
const SNAP_DISTANCE = 10;
|
|
5727
|
+
const snappedPosition = { ...position };
|
|
5728
|
+
alignmentGuides.forEach((guide) => {
|
|
5729
|
+
if (guide.type === "horizontal") {
|
|
5730
|
+
const tooltipCenter = position.top + 40;
|
|
5731
|
+
if (Math.abs(tooltipCenter - guide.position) <= SNAP_DISTANCE) {
|
|
5732
|
+
snappedPosition.top = guide.position - 40;
|
|
5733
|
+
}
|
|
5734
|
+
} else if (guide.type === "vertical") {
|
|
5735
|
+
const tooltipCenter = position.left + 100;
|
|
5736
|
+
if (Math.abs(tooltipCenter - guide.position) <= SNAP_DISTANCE) {
|
|
5737
|
+
snappedPosition.left = guide.position - 100;
|
|
5738
|
+
}
|
|
5739
|
+
}
|
|
5740
|
+
});
|
|
5741
|
+
return snappedPosition;
|
|
5742
|
+
},
|
|
5743
|
+
[alignmentGuides]
|
|
5744
|
+
);
|
|
5745
|
+
const handleMouseDown = (tooltipId, e) => {
|
|
5746
|
+
const rect = e.target.getBoundingClientRect();
|
|
5747
|
+
const offsetX = e.clientX - rect.left;
|
|
5748
|
+
const offsetY = e.clientY - rect.top;
|
|
5749
|
+
setIsDragging(tooltipId);
|
|
5750
|
+
setDragOffset({ x: offsetX, y: offsetY });
|
|
5751
|
+
};
|
|
5752
|
+
useEffect8(() => {
|
|
5753
|
+
let rafId;
|
|
5754
|
+
let lastMousePosition = { x: 0, y: 0 };
|
|
5755
|
+
const handleGlobalMouseMove = (e) => {
|
|
5756
|
+
if (!isDragging) return;
|
|
5757
|
+
lastMousePosition = { x: e.clientX, y: e.clientY };
|
|
5758
|
+
if (rafId) cancelAnimationFrame(rafId);
|
|
5759
|
+
rafId = requestAnimationFrame(() => {
|
|
5760
|
+
const newLeft = lastMousePosition.x - dragOffset.x;
|
|
5761
|
+
const newTop = lastMousePosition.y - dragOffset.y;
|
|
5762
|
+
let finalPosition = { top: newTop, left: newLeft };
|
|
5763
|
+
finalPosition = snapToGuides(finalPosition);
|
|
5764
|
+
setActiveTooltips(
|
|
5765
|
+
(prev) => prev.map(
|
|
5766
|
+
(tooltip) => tooltip.id === isDragging ? { ...tooltip, position: finalPosition } : tooltip
|
|
5767
|
+
)
|
|
5768
|
+
);
|
|
5769
|
+
updateAlignmentGuides(isDragging, finalPosition);
|
|
5770
|
+
});
|
|
5771
|
+
};
|
|
5772
|
+
const handleGlobalMouseUp = () => {
|
|
5773
|
+
if (rafId) cancelAnimationFrame(rafId);
|
|
5774
|
+
setIsDragging(null);
|
|
5775
|
+
setAlignmentGuides([]);
|
|
5776
|
+
document.body.style.cursor = "";
|
|
5777
|
+
document.body.style.userSelect = "";
|
|
5778
|
+
};
|
|
5779
|
+
if (isDragging) {
|
|
5780
|
+
document.body.style.cursor = "grabbing";
|
|
5781
|
+
document.body.style.userSelect = "none";
|
|
5782
|
+
window.addEventListener("mousemove", handleGlobalMouseMove);
|
|
5783
|
+
window.addEventListener("mouseup", handleGlobalMouseUp);
|
|
5784
|
+
}
|
|
5785
|
+
return () => {
|
|
5786
|
+
if (rafId) cancelAnimationFrame(rafId);
|
|
5787
|
+
window.removeEventListener("mousemove", handleGlobalMouseMove);
|
|
5788
|
+
window.removeEventListener("mouseup", handleGlobalMouseUp);
|
|
5789
|
+
document.body.style.cursor = "";
|
|
5790
|
+
document.body.style.userSelect = "";
|
|
5791
|
+
};
|
|
5792
|
+
}, [
|
|
5793
|
+
isDragging,
|
|
5794
|
+
dragOffset,
|
|
5795
|
+
alignmentGuides,
|
|
5796
|
+
updateAlignmentGuides,
|
|
5797
|
+
snapToGuides
|
|
5798
|
+
]);
|
|
5799
|
+
useEffect8(() => {
|
|
5800
|
+
const handleCloseAllTooltips2 = () => {
|
|
5801
|
+
setActiveTooltips([]);
|
|
5802
|
+
setGlobalTooltipCount(0);
|
|
5803
|
+
};
|
|
5804
|
+
window.addEventListener("closeAllTooltips", handleCloseAllTooltips2);
|
|
5805
|
+
return () => {
|
|
5806
|
+
window.removeEventListener("closeAllTooltips", handleCloseAllTooltips2);
|
|
5807
|
+
};
|
|
5808
|
+
}, []);
|
|
5809
|
+
useEffect8(() => {
|
|
5810
|
+
const handleTooltipCountRequest = () => {
|
|
5811
|
+
window.dispatchEvent(
|
|
5812
|
+
new CustomEvent("tooltipCountResponse", {
|
|
5813
|
+
detail: { count: activeTooltips.length }
|
|
5814
|
+
})
|
|
5815
|
+
);
|
|
5816
|
+
};
|
|
5817
|
+
const handleGlobalTooltipsRequest = (event) => {
|
|
5818
|
+
const requesterId = event.detail?.requesterId;
|
|
5819
|
+
activeTooltips.forEach((tooltip) => {
|
|
5820
|
+
if (tooltip.id !== requesterId) {
|
|
5821
|
+
window.dispatchEvent(
|
|
5822
|
+
new CustomEvent("globalTooltipResponse", {
|
|
5823
|
+
detail: {
|
|
5824
|
+
tooltip: {
|
|
5825
|
+
top: tooltip.position.top,
|
|
5826
|
+
left: tooltip.position.left,
|
|
5827
|
+
width: 200,
|
|
5828
|
+
height: 80,
|
|
5829
|
+
id: tooltip.id
|
|
5830
|
+
}
|
|
5831
|
+
}
|
|
5832
|
+
})
|
|
5833
|
+
);
|
|
5834
|
+
}
|
|
5835
|
+
});
|
|
5836
|
+
};
|
|
5837
|
+
window.addEventListener("requestTooltipCount", handleTooltipCountRequest);
|
|
5838
|
+
window.addEventListener(
|
|
5839
|
+
"requestGlobalTooltips",
|
|
5840
|
+
handleGlobalTooltipsRequest
|
|
5841
|
+
);
|
|
5842
|
+
return () => {
|
|
5843
|
+
window.removeEventListener(
|
|
5844
|
+
"requestTooltipCount",
|
|
5845
|
+
handleTooltipCountRequest
|
|
5846
|
+
);
|
|
5847
|
+
window.removeEventListener(
|
|
5848
|
+
"requestGlobalTooltips",
|
|
5849
|
+
handleGlobalTooltipsRequest
|
|
5850
|
+
);
|
|
5851
|
+
};
|
|
5852
|
+
}, [activeTooltips]);
|
|
5853
|
+
useEffect8(() => {
|
|
5854
|
+
if (isDragging) return;
|
|
5855
|
+
let totalCount = 0;
|
|
5856
|
+
const handleCountResponse = (event) => {
|
|
5857
|
+
const customEvent = event;
|
|
5858
|
+
totalCount += customEvent.detail.count;
|
|
5859
|
+
};
|
|
5860
|
+
window.addEventListener("tooltipCountResponse", handleCountResponse);
|
|
5861
|
+
window.dispatchEvent(new CustomEvent("requestTooltipCount"));
|
|
5862
|
+
const timeoutId = setTimeout(() => {
|
|
5863
|
+
window.removeEventListener("tooltipCountResponse", handleCountResponse);
|
|
5864
|
+
setGlobalTooltipCount(totalCount);
|
|
5865
|
+
}, 5);
|
|
5866
|
+
return () => {
|
|
5867
|
+
clearTimeout(timeoutId);
|
|
5868
|
+
window.removeEventListener("tooltipCountResponse", handleCountResponse);
|
|
5869
|
+
};
|
|
5870
|
+
}, [activeTooltips.length, isDragging]);
|
|
5871
|
+
const getTitleClass = () => {
|
|
5872
|
+
switch (titlePosition) {
|
|
5873
|
+
case "center":
|
|
5874
|
+
return "text-center";
|
|
5875
|
+
case "right":
|
|
5876
|
+
return "text-right";
|
|
5877
|
+
default:
|
|
5878
|
+
return "text-left";
|
|
5879
|
+
}
|
|
5880
|
+
};
|
|
5881
|
+
return /* @__PURE__ */ jsx51("div", { className: cn("relative", className), children: /* @__PURE__ */ jsxs32(
|
|
5882
|
+
"div",
|
|
5883
|
+
{
|
|
5884
|
+
className: "rounded-lg bg-card p-4 relative border border-border",
|
|
5885
|
+
style: {
|
|
5886
|
+
width: typeof width === "number" ? `${width + 32}px` : "fit-content",
|
|
5887
|
+
maxWidth: "100%"
|
|
5888
|
+
},
|
|
5889
|
+
onClick: handleChartBackgroundClick,
|
|
5890
|
+
children: [
|
|
5891
|
+
title && /* @__PURE__ */ jsx51("div", { className: cn("mb-4", getTitleClass()), children: /* @__PURE__ */ jsx51("h3", { className: "text-lg font-semibold text-foreground", children: title }) }),
|
|
5892
|
+
/* @__PURE__ */ jsxs32(
|
|
5893
|
+
RechartsLineChart,
|
|
5894
|
+
{
|
|
5895
|
+
data,
|
|
5896
|
+
width: typeof width === "number" ? width : 900,
|
|
5897
|
+
height,
|
|
5898
|
+
margin: {
|
|
5899
|
+
top: showLabels ? 48 : 20,
|
|
5900
|
+
right: 30,
|
|
5901
|
+
left: 20,
|
|
5902
|
+
bottom: 5
|
|
5903
|
+
},
|
|
5904
|
+
onClick: handleChartClick,
|
|
5905
|
+
children: [
|
|
5906
|
+
showGrid && /* @__PURE__ */ jsx51(
|
|
5907
|
+
CartesianGrid,
|
|
5908
|
+
{
|
|
5909
|
+
strokeDasharray: "3 3",
|
|
5910
|
+
stroke: gridColor || "hsl(var(--muted-foreground))",
|
|
5911
|
+
opacity: 0.3
|
|
5912
|
+
}
|
|
5913
|
+
),
|
|
5914
|
+
/* @__PURE__ */ jsx51(
|
|
5915
|
+
XAxis,
|
|
5916
|
+
{
|
|
5917
|
+
dataKey: "name",
|
|
5918
|
+
className: "fill-muted-foreground text-xs",
|
|
5919
|
+
fontSize: 12
|
|
5920
|
+
}
|
|
5921
|
+
),
|
|
5922
|
+
/* @__PURE__ */ jsx51(
|
|
5923
|
+
YAxis,
|
|
5924
|
+
{
|
|
5925
|
+
className: "fill-muted-foreground text-xs",
|
|
5926
|
+
fontSize: 12,
|
|
5927
|
+
tickFormatter: (value) => compactTick(Number(value)),
|
|
5928
|
+
domain: [0, niceMax],
|
|
5929
|
+
tickCount: 6
|
|
5930
|
+
}
|
|
5931
|
+
),
|
|
5932
|
+
showTooltip && /* @__PURE__ */ jsx51(Tooltip, { content: () => null }),
|
|
5933
|
+
showLegend && /* @__PURE__ */ jsx51(
|
|
5934
|
+
Legend,
|
|
5935
|
+
{
|
|
5936
|
+
wrapperStyle: {
|
|
5937
|
+
fontSize: "12px",
|
|
5938
|
+
color: "hsl(var(--muted-foreground))"
|
|
5939
|
+
}
|
|
5940
|
+
}
|
|
5941
|
+
),
|
|
5942
|
+
dataKeys.map((key) => /* @__PURE__ */ jsx51(
|
|
5943
|
+
Line,
|
|
5944
|
+
{
|
|
5945
|
+
type: "monotone",
|
|
5946
|
+
dataKey: key,
|
|
5947
|
+
stroke: finalColors[key],
|
|
5948
|
+
strokeWidth,
|
|
5949
|
+
dot: showDots ? { r: 4, cursor: "pointer" } : false,
|
|
5950
|
+
activeDot: (props) => /* @__PURE__ */ jsx51(ClickableDot, { ...props, dataKey: key }),
|
|
5951
|
+
children: showLabels && /* @__PURE__ */ jsx51(
|
|
5952
|
+
LabelList,
|
|
5953
|
+
{
|
|
5954
|
+
dataKey: key,
|
|
5955
|
+
position: "top",
|
|
5956
|
+
content: pillLabelRenderer_default(
|
|
5957
|
+
finalColors[key] || "#000",
|
|
5958
|
+
"filled"
|
|
5959
|
+
),
|
|
5960
|
+
offset: 14
|
|
5961
|
+
}
|
|
5962
|
+
)
|
|
5963
|
+
},
|
|
5964
|
+
key
|
|
5965
|
+
))
|
|
5966
|
+
]
|
|
5967
|
+
}
|
|
5968
|
+
),
|
|
5969
|
+
alignmentGuides.map((guide, index) => {
|
|
5970
|
+
const isHorizontal = guide.type === "horizontal";
|
|
5971
|
+
const color = isHorizontal ? "#3b82f6" : "#ef4444";
|
|
5972
|
+
const startX = isHorizontal ? Math.min(
|
|
5973
|
+
guide.sourceTooltip.left + guide.sourceTooltip.width / 2,
|
|
5974
|
+
guide.targetTooltip.left + guide.targetTooltip.width / 2
|
|
5975
|
+
) : guide.sourceTooltip.left + (isHorizontal ? 0 : guide.sourceTooltip.width / 2);
|
|
5976
|
+
const endX = isHorizontal ? Math.max(
|
|
5977
|
+
guide.sourceTooltip.left + guide.sourceTooltip.width / 2,
|
|
5978
|
+
guide.targetTooltip.left + guide.targetTooltip.width / 2
|
|
5979
|
+
) : guide.targetTooltip.left + (isHorizontal ? 0 : guide.targetTooltip.width / 2);
|
|
5980
|
+
const startY = isHorizontal ? guide.sourceTooltip.top + (isHorizontal ? guide.sourceTooltip.height / 2 : 0) : Math.min(
|
|
5981
|
+
guide.sourceTooltip.top + guide.sourceTooltip.height / 2,
|
|
5982
|
+
guide.targetTooltip.top + guide.targetTooltip.height / 2
|
|
5983
|
+
);
|
|
5984
|
+
const endY = isHorizontal ? guide.targetTooltip.top + (isHorizontal ? guide.targetTooltip.height / 2 : 0) : Math.max(
|
|
5985
|
+
guide.sourceTooltip.top + guide.sourceTooltip.height / 2,
|
|
5986
|
+
guide.targetTooltip.top + guide.targetTooltip.height / 2
|
|
5987
|
+
);
|
|
5988
|
+
return /* @__PURE__ */ jsxs32("div", { children: [
|
|
5989
|
+
/* @__PURE__ */ jsx51(
|
|
5990
|
+
"div",
|
|
5991
|
+
{
|
|
5992
|
+
className: "fixed pointer-events-none z-30",
|
|
5993
|
+
style: {
|
|
5994
|
+
left: startX,
|
|
5995
|
+
top: startY,
|
|
5996
|
+
width: isHorizontal ? endX - startX : "2px",
|
|
5997
|
+
height: isHorizontal ? "2px" : endY - startY,
|
|
5998
|
+
backgroundColor: color,
|
|
5999
|
+
boxShadow: `0 0 8px ${color}60`,
|
|
6000
|
+
opacity: 0.9,
|
|
6001
|
+
borderStyle: "dashed",
|
|
6002
|
+
borderWidth: "1px",
|
|
6003
|
+
borderColor: color,
|
|
6004
|
+
transform: "translateZ(0)"
|
|
6005
|
+
}
|
|
6006
|
+
}
|
|
6007
|
+
),
|
|
6008
|
+
/* @__PURE__ */ jsx51(
|
|
6009
|
+
"div",
|
|
6010
|
+
{
|
|
6011
|
+
className: "fixed pointer-events-none z-31",
|
|
6012
|
+
style: {
|
|
6013
|
+
left: guide.sourceTooltip.left + guide.sourceTooltip.width / 2 - 4,
|
|
6014
|
+
top: guide.sourceTooltip.top + guide.sourceTooltip.height / 2 - 4,
|
|
6015
|
+
width: "8px",
|
|
6016
|
+
height: "8px",
|
|
6017
|
+
backgroundColor: color,
|
|
6018
|
+
borderRadius: "50%",
|
|
6019
|
+
boxShadow: `0 0 4px ${color}80`,
|
|
6020
|
+
opacity: 0.8
|
|
6021
|
+
}
|
|
6022
|
+
}
|
|
6023
|
+
),
|
|
6024
|
+
/* @__PURE__ */ jsx51(
|
|
6025
|
+
"div",
|
|
6026
|
+
{
|
|
6027
|
+
className: "fixed pointer-events-none z-31",
|
|
6028
|
+
style: {
|
|
6029
|
+
left: guide.targetTooltip.left + guide.targetTooltip.width / 2 - 4,
|
|
6030
|
+
top: guide.targetTooltip.top + guide.targetTooltip.height / 2 - 4,
|
|
6031
|
+
width: "8px",
|
|
6032
|
+
height: "8px",
|
|
6033
|
+
backgroundColor: color,
|
|
6034
|
+
borderRadius: "50%",
|
|
6035
|
+
boxShadow: `0 0 4px ${color}80`,
|
|
6036
|
+
opacity: 0.8
|
|
6037
|
+
}
|
|
6038
|
+
}
|
|
6039
|
+
)
|
|
6040
|
+
] }, index);
|
|
6041
|
+
}),
|
|
6042
|
+
activeTooltips.map((tooltip, index) => /* @__PURE__ */ jsx51(
|
|
6043
|
+
DraggableTooltip_default,
|
|
6044
|
+
{
|
|
6045
|
+
id: tooltip.id,
|
|
6046
|
+
data: tooltip.data,
|
|
6047
|
+
position: tooltip.position,
|
|
6048
|
+
isDragging: isDragging === tooltip.id,
|
|
6049
|
+
title,
|
|
6050
|
+
dataKeys,
|
|
6051
|
+
finalColors,
|
|
6052
|
+
onMouseDown: (id, e) => handleMouseDown(id, e),
|
|
6053
|
+
onClose: (id) => {
|
|
6054
|
+
setActiveTooltips((prev) => prev.filter((t) => t.id !== id));
|
|
6055
|
+
},
|
|
6056
|
+
periodLabel: "Ponto Selecionado",
|
|
6057
|
+
dataLabel: "Dados do Ponto",
|
|
6058
|
+
showCloseAllButton: index === 0,
|
|
6059
|
+
globalTooltipCount,
|
|
6060
|
+
onCloseAll: handleCloseAllTooltips,
|
|
6061
|
+
closeAllButtonPosition: "top-center",
|
|
6062
|
+
closeAllButtonVariant: "floating"
|
|
6063
|
+
},
|
|
6064
|
+
tooltip.id
|
|
6065
|
+
))
|
|
6066
|
+
]
|
|
6067
|
+
}
|
|
6068
|
+
) });
|
|
6069
|
+
};
|
|
6070
|
+
var LineChart_default = CustomLineChart;
|
|
6071
|
+
|
|
6072
|
+
// src/components/rechart/PieChart.tsx
|
|
6073
|
+
import { PieChart as RechartsPieChart, Pie, Cell, ResponsiveContainer, Tooltip as Tooltip2, Legend as Legend2 } from "recharts";
|
|
6074
|
+
import { jsx as jsx52, jsxs as jsxs33 } from "react/jsx-runtime";
|
|
6075
|
+
var defaultData2 = [
|
|
6076
|
+
{ name: "Vendas", value: 4e3 },
|
|
6077
|
+
{ name: "Marketing", value: 3e3 },
|
|
6078
|
+
{ name: "Desenvolvimento", value: 2e3 },
|
|
6079
|
+
{ name: "Suporte", value: 1e3 },
|
|
6080
|
+
{ name: "Outros", value: 800 }
|
|
6081
|
+
];
|
|
6082
|
+
var DEFAULT_COLORS2 = [
|
|
6083
|
+
"#55af7d",
|
|
6084
|
+
// verde do projeto
|
|
6085
|
+
"#8e68ff",
|
|
6086
|
+
// roxo do projeto
|
|
6087
|
+
"#2273e1",
|
|
6088
|
+
// azul do projeto
|
|
6089
|
+
"#f59e0b",
|
|
6090
|
+
// amarelo complementar
|
|
6091
|
+
"#ef4444",
|
|
6092
|
+
// vermelho complementar
|
|
6093
|
+
"#8b5cf6",
|
|
6094
|
+
// roxo claro
|
|
6095
|
+
"#06b6d4",
|
|
6096
|
+
// ciano
|
|
6097
|
+
"#84cc16"
|
|
6098
|
+
// verde lima
|
|
6099
|
+
];
|
|
6100
|
+
var RADIAN = Math.PI / 180;
|
|
6101
|
+
var renderCustomizedLabel = ({ cx = 0, cy = 0, midAngle = 0, innerRadius = 0, outerRadius = 0, percent = 0 }) => {
|
|
6102
|
+
const radius = innerRadius + (outerRadius - innerRadius) * 0.5;
|
|
6103
|
+
const x = cx + radius * Math.cos(-midAngle * RADIAN);
|
|
6104
|
+
const y = cy + radius * Math.sin(-midAngle * RADIAN);
|
|
6105
|
+
return /* @__PURE__ */ jsx52(
|
|
6106
|
+
"text",
|
|
6107
|
+
{
|
|
6108
|
+
x,
|
|
6109
|
+
y,
|
|
6110
|
+
fill: "white",
|
|
6111
|
+
textAnchor: x > cx ? "start" : "end",
|
|
6112
|
+
dominantBaseline: "central",
|
|
6113
|
+
fontSize: 12,
|
|
6114
|
+
fontWeight: "600",
|
|
6115
|
+
children: `${(percent * 100).toFixed(0)}%`
|
|
6116
|
+
}
|
|
6117
|
+
);
|
|
6118
|
+
};
|
|
6119
|
+
var CustomPieChart = ({
|
|
6120
|
+
data = defaultData2,
|
|
6121
|
+
className,
|
|
6122
|
+
height = 400,
|
|
6123
|
+
width = "100%",
|
|
6124
|
+
colors: colors2,
|
|
6125
|
+
showTooltip = true,
|
|
6126
|
+
showLegend = true,
|
|
6127
|
+
showLabels = true,
|
|
6128
|
+
innerRadius = 0,
|
|
6129
|
+
outerRadius = 120,
|
|
6130
|
+
centerX = "50%",
|
|
6131
|
+
centerY = "50%"
|
|
6132
|
+
}) => {
|
|
6133
|
+
const finalColors = colors2 || DEFAULT_COLORS2;
|
|
6134
|
+
return /* @__PURE__ */ jsx52("div", { className: cn("w-full rounded-lg bg-card p-4", className), children: /* @__PURE__ */ jsx52(ResponsiveContainer, { width, height, children: /* @__PURE__ */ jsxs33(RechartsPieChart, { children: [
|
|
6135
|
+
/* @__PURE__ */ jsx52(
|
|
6136
|
+
Pie,
|
|
6137
|
+
{
|
|
6138
|
+
data,
|
|
6139
|
+
cx: centerX,
|
|
6140
|
+
cy: centerY,
|
|
6141
|
+
labelLine: false,
|
|
6142
|
+
label: showLabels ? renderCustomizedLabel : false,
|
|
6143
|
+
outerRadius,
|
|
6144
|
+
innerRadius,
|
|
6145
|
+
fill: "#8884d8",
|
|
6146
|
+
dataKey: "value",
|
|
6147
|
+
children: data.map((entry, index) => /* @__PURE__ */ jsx52(
|
|
6148
|
+
Cell,
|
|
6149
|
+
{
|
|
6150
|
+
fill: finalColors[index % finalColors.length]
|
|
6151
|
+
},
|
|
6152
|
+
`cell-${entry.name}-${index}`
|
|
6153
|
+
))
|
|
6154
|
+
}
|
|
6155
|
+
),
|
|
6156
|
+
showTooltip && /* @__PURE__ */ jsx52(
|
|
6157
|
+
Tooltip2,
|
|
6158
|
+
{
|
|
6159
|
+
contentStyle: {
|
|
6160
|
+
backgroundColor: "hsl(var(--popover))",
|
|
6161
|
+
border: "1px solid hsl(var(--border))",
|
|
6162
|
+
borderRadius: "6px",
|
|
6163
|
+
color: "hsl(var(--popover-foreground))"
|
|
6164
|
+
}
|
|
6165
|
+
}
|
|
6166
|
+
),
|
|
6167
|
+
showLegend && /* @__PURE__ */ jsx52(Legend2, {})
|
|
6168
|
+
] }) }) });
|
|
6169
|
+
};
|
|
6170
|
+
var PieChart_default = CustomPieChart;
|
|
6171
|
+
|
|
6172
|
+
// src/components/rechart/BarChart.tsx
|
|
6173
|
+
import { useState as useState11, useEffect as useEffect9, useCallback as useCallback8, useMemo as useMemo6 } from "react";
|
|
6174
|
+
import {
|
|
6175
|
+
BarChart as RechartsBarChart,
|
|
6176
|
+
Bar,
|
|
6177
|
+
Rectangle,
|
|
6178
|
+
XAxis as XAxis2,
|
|
6179
|
+
YAxis as YAxis2,
|
|
6180
|
+
CartesianGrid as CartesianGrid2,
|
|
6181
|
+
Tooltip as Tooltip3,
|
|
6182
|
+
Legend as Legend3,
|
|
6183
|
+
LabelList as LabelList2
|
|
6184
|
+
} from "recharts";
|
|
6185
|
+
import { jsx as jsx53, jsxs as jsxs34 } from "react/jsx-runtime";
|
|
6186
|
+
var formatFieldName = (fieldName) => {
|
|
6187
|
+
return fieldName.replace(/([A-Z])/g, " $1").replace(/[_-]/g, " ").replace(/\b\w/g, (l) => l.toUpperCase()).trim();
|
|
6188
|
+
};
|
|
6189
|
+
var detectXAxis = (data) => {
|
|
6190
|
+
if (!data || data.length === 0) return "name";
|
|
6191
|
+
const firstItem = data[0];
|
|
6192
|
+
const stringFields = Object.keys(firstItem).filter(
|
|
6193
|
+
(key) => typeof firstItem[key] === "string" || typeof firstItem[key] === "number" && String(firstItem[key]).length <= 4
|
|
6194
|
+
// Anos, IDs curtos
|
|
6195
|
+
);
|
|
6196
|
+
return stringFields[0] || Object.keys(firstItem)[0] || "name";
|
|
6197
|
+
};
|
|
6198
|
+
var detectDataFields = (data, xAxisKey) => {
|
|
6199
|
+
if (!data || data.length === 0) return [];
|
|
6200
|
+
const firstItem = data[0];
|
|
6201
|
+
return Object.keys(firstItem).filter(
|
|
6202
|
+
(key) => key !== xAxisKey && typeof firstItem[key] === "number"
|
|
6203
|
+
);
|
|
6204
|
+
};
|
|
6205
|
+
var DEFAULT_COLORS3 = ["#55af7d", "#8e68ff", "#2273e1"];
|
|
6206
|
+
var generateAdditionalColors2 = (baseColors, count) => {
|
|
6207
|
+
const colors2 = [...baseColors];
|
|
6208
|
+
const variations = [
|
|
6209
|
+
"#ff6b6b",
|
|
6210
|
+
"#4ecdc4",
|
|
6211
|
+
"#45b7d1",
|
|
6212
|
+
"#f9ca24",
|
|
6213
|
+
"#6c5ce7",
|
|
6214
|
+
"#a29bfe",
|
|
6215
|
+
"#fd79a8",
|
|
6216
|
+
"#00b894"
|
|
6217
|
+
];
|
|
6218
|
+
while (colors2.length < count) {
|
|
6219
|
+
colors2.push(
|
|
6220
|
+
variations[(colors2.length - baseColors.length) % variations.length]
|
|
6221
|
+
);
|
|
6222
|
+
}
|
|
6223
|
+
return colors2;
|
|
6224
|
+
};
|
|
6225
|
+
var BarChart = ({
|
|
6226
|
+
data,
|
|
6227
|
+
className,
|
|
6228
|
+
height = 350,
|
|
6229
|
+
width = 900,
|
|
6230
|
+
colors: colors2 = DEFAULT_COLORS3,
|
|
6231
|
+
gridColor,
|
|
6232
|
+
showGrid = true,
|
|
6233
|
+
showTooltip = true,
|
|
6234
|
+
showLegend = true,
|
|
6235
|
+
title,
|
|
6236
|
+
titlePosition = "left",
|
|
6237
|
+
showLabels = false,
|
|
6238
|
+
xAxis,
|
|
6239
|
+
mapper,
|
|
6240
|
+
yAxis,
|
|
6241
|
+
labelMap,
|
|
6242
|
+
autoDetect = false
|
|
6243
|
+
}) => {
|
|
6244
|
+
const smartConfig = useMemo6(() => {
|
|
6245
|
+
const providedMapper = yAxis ?? mapper;
|
|
6246
|
+
if (autoDetect === true || xAxis == null || providedMapper == null) {
|
|
6247
|
+
const detectedXAxis = detectXAxis(data);
|
|
6248
|
+
const detectedFields = detectDataFields(data, detectedXAxis);
|
|
6249
|
+
return {
|
|
6250
|
+
xAxisConfig: {
|
|
6251
|
+
dataKey: detectedXAxis,
|
|
6252
|
+
label: labelMap?.[detectedXAxis] ?? formatFieldName(detectedXAxis),
|
|
6253
|
+
autoLabel: true
|
|
6254
|
+
},
|
|
6255
|
+
mapperConfig: detectedFields.reduce((acc, field) => {
|
|
6256
|
+
acc[field] = {
|
|
6257
|
+
label: labelMap?.[field] ?? formatFieldName(field),
|
|
6258
|
+
type: "number",
|
|
6259
|
+
visible: true
|
|
6260
|
+
};
|
|
6261
|
+
return acc;
|
|
6262
|
+
}, {})
|
|
6263
|
+
};
|
|
6264
|
+
}
|
|
6265
|
+
const xAxisConfig2 = typeof xAxis === "string" ? { dataKey: xAxis, label: formatFieldName(xAxis), autoLabel: true } : xAxis;
|
|
6266
|
+
let mapperConfig2;
|
|
6267
|
+
if (Array.isArray(providedMapper)) {
|
|
6268
|
+
mapperConfig2 = providedMapper.reduce((acc, field) => {
|
|
6269
|
+
acc[field] = {
|
|
6270
|
+
label: labelMap?.[field] ?? formatFieldName(field),
|
|
6271
|
+
type: "auto",
|
|
6272
|
+
visible: true
|
|
6273
|
+
};
|
|
6274
|
+
return acc;
|
|
6275
|
+
}, {});
|
|
6276
|
+
} else {
|
|
6277
|
+
mapperConfig2 = Object.keys(providedMapper).reduce(
|
|
6278
|
+
(acc, key) => {
|
|
6279
|
+
acc[key] = {
|
|
6280
|
+
label: providedMapper[key]?.label ?? labelMap?.[key] ?? formatFieldName(key),
|
|
6281
|
+
type: "auto",
|
|
6282
|
+
visible: true,
|
|
6283
|
+
...providedMapper[key]
|
|
6284
|
+
// Sobrescreve com configurações do usuário
|
|
6285
|
+
};
|
|
6286
|
+
return acc;
|
|
6287
|
+
},
|
|
6288
|
+
{}
|
|
6289
|
+
);
|
|
6290
|
+
}
|
|
6291
|
+
return { xAxisConfig: xAxisConfig2, mapperConfig: mapperConfig2 };
|
|
6292
|
+
}, [data, xAxis, mapper, yAxis, autoDetect, labelMap]);
|
|
6293
|
+
const { xAxisConfig, mapperConfig } = smartConfig;
|
|
6294
|
+
const [activeTooltips, setActiveTooltips] = useState11([]);
|
|
6295
|
+
const [isDragging, setIsDragging] = useState11(null);
|
|
6296
|
+
const [dragOffset, setDragOffset] = useState11({
|
|
6297
|
+
x: 0,
|
|
6298
|
+
y: 0
|
|
6299
|
+
});
|
|
6300
|
+
const [globalTooltipCount, setGlobalTooltipCount] = useState11(0);
|
|
6301
|
+
const [alignmentGuides, setAlignmentGuides] = useState11([]);
|
|
6302
|
+
const processedData = data.map((item) => ({
|
|
6303
|
+
...item,
|
|
6304
|
+
name: String(item[xAxisConfig.dataKey] || "N/A")
|
|
6305
|
+
// Garantir propriedade 'name' para tooltip
|
|
6306
|
+
}));
|
|
6307
|
+
const generateColors = (dataKeys2) => {
|
|
6308
|
+
const colorMap = {};
|
|
6309
|
+
const allColors = generateAdditionalColors2(colors2, dataKeys2.length);
|
|
6310
|
+
dataKeys2.forEach((key, index) => {
|
|
6311
|
+
colorMap[key] = allColors[index] || colors2[index % colors2.length];
|
|
6312
|
+
});
|
|
6313
|
+
return colorMap;
|
|
6314
|
+
};
|
|
6315
|
+
const dataKeys = Object.keys(mapperConfig);
|
|
6316
|
+
const finalColors = generateColors(dataKeys);
|
|
6317
|
+
const adaptDataForTooltip = (universalData) => {
|
|
6318
|
+
return {
|
|
6319
|
+
...universalData,
|
|
6320
|
+
name: String(universalData[xAxisConfig.dataKey] || "N/A")
|
|
6321
|
+
// Garantir que tem a propriedade 'name'
|
|
6322
|
+
};
|
|
6323
|
+
};
|
|
6324
|
+
const niceCeil = (value) => {
|
|
6325
|
+
if (!isFinite(value) || value <= 0) return 1;
|
|
6326
|
+
const pow = Math.pow(10, Math.floor(Math.log10(value)));
|
|
6327
|
+
const normalized = value / pow;
|
|
6328
|
+
const multipliers = [
|
|
6329
|
+
1,
|
|
6330
|
+
1.25,
|
|
6331
|
+
1.5,
|
|
6332
|
+
2,
|
|
6333
|
+
2.5,
|
|
6334
|
+
3,
|
|
6335
|
+
4,
|
|
6336
|
+
5,
|
|
6337
|
+
7.5,
|
|
6338
|
+
10,
|
|
6339
|
+
15,
|
|
6340
|
+
20,
|
|
6341
|
+
25,
|
|
6342
|
+
50,
|
|
6343
|
+
100
|
|
6344
|
+
];
|
|
6345
|
+
for (const m of multipliers) {
|
|
6346
|
+
if (m >= normalized) return Math.ceil(m * pow);
|
|
6347
|
+
}
|
|
6348
|
+
return Math.ceil(100 * pow);
|
|
6349
|
+
};
|
|
6350
|
+
const maxDataValue = useMemo6(() => {
|
|
6351
|
+
let max = 0;
|
|
6352
|
+
const keys = Object.keys(mapperConfig);
|
|
6353
|
+
for (const row of processedData) {
|
|
6354
|
+
const r = row;
|
|
6355
|
+
for (const key of keys) {
|
|
6356
|
+
const v = r[key];
|
|
6357
|
+
if (typeof v === "number" && Number.isFinite(v) && v > max)
|
|
6358
|
+
max = v;
|
|
6359
|
+
}
|
|
6360
|
+
}
|
|
6361
|
+
return max;
|
|
6362
|
+
}, [processedData, mapperConfig]);
|
|
6363
|
+
const niceMax = useMemo6(() => {
|
|
6364
|
+
let padding = 0.08;
|
|
6365
|
+
if (maxDataValue > 1e6) padding = 0.05;
|
|
6366
|
+
if (maxDataValue > 1e7) padding = 0.03;
|
|
6367
|
+
if (maxDataValue === 0) padding = 0.12;
|
|
6368
|
+
const padded = maxDataValue * (1 + padding);
|
|
6369
|
+
return niceCeil(padded);
|
|
6370
|
+
}, [maxDataValue]);
|
|
6371
|
+
const handleBarClick = (data2, index, event) => {
|
|
6372
|
+
event.stopPropagation();
|
|
6373
|
+
const xAxisValue = data2[xAxisConfig.dataKey] || "N/A";
|
|
6374
|
+
const tooltipId = `${xAxisValue}`;
|
|
6375
|
+
const rect = event.target.getBoundingClientRect();
|
|
6376
|
+
const existingIndex = activeTooltips.findIndex(
|
|
6377
|
+
(tooltip) => tooltip.id === tooltipId
|
|
6378
|
+
);
|
|
6379
|
+
if (existingIndex !== -1) {
|
|
6380
|
+
setActiveTooltips(
|
|
6381
|
+
(prev) => prev.filter((tooltip) => tooltip.id !== tooltipId)
|
|
6382
|
+
);
|
|
6383
|
+
} else {
|
|
6384
|
+
const newTooltip = {
|
|
6385
|
+
id: tooltipId,
|
|
6386
|
+
data: data2,
|
|
6387
|
+
position: {
|
|
6388
|
+
top: rect.top - 10,
|
|
6389
|
+
// Posição fixa da viewport
|
|
6390
|
+
left: rect.right + 10
|
|
6391
|
+
// À direita da barra clicada
|
|
6392
|
+
}
|
|
6393
|
+
};
|
|
6394
|
+
setActiveTooltips((prev) => [...prev, newTooltip]);
|
|
6395
|
+
}
|
|
6396
|
+
};
|
|
6397
|
+
const handleChartClick = () => {
|
|
6398
|
+
setActiveTooltips([]);
|
|
6399
|
+
};
|
|
6400
|
+
const ALIGNMENT_THRESHOLD = 25;
|
|
6401
|
+
const GUIDE_THRESHOLD = 60;
|
|
6402
|
+
const STRONG_SNAP_THRESHOLD = 35;
|
|
6403
|
+
const PRECISION_SNAP_THRESHOLD = 8;
|
|
6404
|
+
const updateAlignmentGuides = useCallback8(
|
|
6405
|
+
(draggedTooltipId, currentPosition) => {
|
|
6406
|
+
if (!isDragging) return;
|
|
6407
|
+
const getAllTooltips = () => {
|
|
6408
|
+
const allTooltips2 = [];
|
|
6409
|
+
allTooltips2.push(...activeTooltips);
|
|
6410
|
+
const globalEvent = new CustomEvent("requestGlobalTooltips", {
|
|
6411
|
+
detail: { requesterId: draggedTooltipId, response: allTooltips2 }
|
|
6412
|
+
});
|
|
6413
|
+
window.dispatchEvent(globalEvent);
|
|
6414
|
+
return allTooltips2;
|
|
6415
|
+
};
|
|
6416
|
+
const allTooltips = getAllTooltips();
|
|
6417
|
+
const otherTooltips = allTooltips.filter(
|
|
6418
|
+
(t) => t.id !== draggedTooltipId
|
|
6419
|
+
);
|
|
6420
|
+
const guides = [];
|
|
6421
|
+
const tooltipDimensions = { width: 224, height: 120 };
|
|
6422
|
+
otherTooltips.forEach((tooltip) => {
|
|
6423
|
+
const topDiff = Math.abs(currentPosition.top - tooltip.position.top);
|
|
6424
|
+
if (topDiff <= GUIDE_THRESHOLD) {
|
|
6425
|
+
guides.push({
|
|
6426
|
+
type: "horizontal",
|
|
6427
|
+
position: tooltip.position.top,
|
|
6428
|
+
visible: true,
|
|
6429
|
+
sourceTooltip: {
|
|
6430
|
+
top: currentPosition.top,
|
|
6431
|
+
left: currentPosition.left,
|
|
6432
|
+
width: tooltipDimensions.width,
|
|
6433
|
+
height: tooltipDimensions.height
|
|
6434
|
+
},
|
|
6435
|
+
targetTooltip: {
|
|
6436
|
+
top: tooltip.position.top,
|
|
6437
|
+
left: tooltip.position.left,
|
|
6438
|
+
width: tooltipDimensions.width,
|
|
6439
|
+
height: tooltipDimensions.height
|
|
6440
|
+
}
|
|
6441
|
+
});
|
|
6442
|
+
}
|
|
6443
|
+
const leftDiff = Math.abs(currentPosition.left - tooltip.position.left);
|
|
6444
|
+
if (leftDiff <= GUIDE_THRESHOLD) {
|
|
6445
|
+
guides.push({
|
|
6446
|
+
type: "vertical",
|
|
6447
|
+
position: tooltip.position.left,
|
|
6448
|
+
visible: true,
|
|
6449
|
+
sourceTooltip: {
|
|
6450
|
+
top: currentPosition.top,
|
|
6451
|
+
left: currentPosition.left,
|
|
6452
|
+
width: tooltipDimensions.width,
|
|
6453
|
+
height: tooltipDimensions.height
|
|
6454
|
+
},
|
|
6455
|
+
targetTooltip: {
|
|
6456
|
+
top: tooltip.position.top,
|
|
6457
|
+
left: tooltip.position.left,
|
|
6458
|
+
width: tooltipDimensions.width,
|
|
6459
|
+
height: tooltipDimensions.height
|
|
6460
|
+
}
|
|
6461
|
+
});
|
|
6462
|
+
}
|
|
6463
|
+
});
|
|
6464
|
+
setAlignmentGuides(guides);
|
|
6465
|
+
},
|
|
6466
|
+
[isDragging, activeTooltips]
|
|
6467
|
+
);
|
|
6468
|
+
const snapToGuides = useCallback8(
|
|
6469
|
+
(position) => {
|
|
6470
|
+
const snappedPosition = { ...position };
|
|
6471
|
+
let hasSnapped = false;
|
|
6472
|
+
alignmentGuides.forEach((guide) => {
|
|
6473
|
+
if (guide.type === "horizontal") {
|
|
6474
|
+
const diff = Math.abs(position.top - guide.position);
|
|
6475
|
+
if (diff <= PRECISION_SNAP_THRESHOLD) {
|
|
6476
|
+
snappedPosition.top = guide.position;
|
|
6477
|
+
hasSnapped = true;
|
|
6478
|
+
}
|
|
6479
|
+
} else if (guide.type === "vertical") {
|
|
6480
|
+
const diff = Math.abs(position.left - guide.position);
|
|
6481
|
+
if (diff <= PRECISION_SNAP_THRESHOLD) {
|
|
6482
|
+
snappedPosition.left = guide.position;
|
|
6483
|
+
hasSnapped = true;
|
|
6484
|
+
}
|
|
6485
|
+
}
|
|
6486
|
+
});
|
|
6487
|
+
if (!hasSnapped) {
|
|
6488
|
+
alignmentGuides.forEach((guide) => {
|
|
6489
|
+
if (guide.type === "horizontal") {
|
|
6490
|
+
const diff = Math.abs(position.top - guide.position);
|
|
6491
|
+
if (diff <= STRONG_SNAP_THRESHOLD) {
|
|
6492
|
+
snappedPosition.top = guide.position;
|
|
6493
|
+
}
|
|
6494
|
+
} else if (guide.type === "vertical") {
|
|
6495
|
+
const diff = Math.abs(position.left - guide.position);
|
|
6496
|
+
if (diff <= STRONG_SNAP_THRESHOLD) {
|
|
6497
|
+
snappedPosition.left = guide.position;
|
|
6498
|
+
}
|
|
6499
|
+
}
|
|
6500
|
+
});
|
|
6501
|
+
}
|
|
6502
|
+
alignmentGuides.forEach((guide) => {
|
|
6503
|
+
if (guide.type === "horizontal") {
|
|
6504
|
+
const diff = Math.abs(position.top - guide.position);
|
|
6505
|
+
if (diff <= ALIGNMENT_THRESHOLD && snappedPosition.top === position.top) {
|
|
6506
|
+
snappedPosition.top = guide.position;
|
|
6507
|
+
}
|
|
6508
|
+
} else if (guide.type === "vertical") {
|
|
6509
|
+
const diff = Math.abs(position.left - guide.position);
|
|
6510
|
+
if (diff <= ALIGNMENT_THRESHOLD && snappedPosition.left === position.left) {
|
|
6511
|
+
snappedPosition.left = guide.position;
|
|
6512
|
+
}
|
|
6513
|
+
}
|
|
6514
|
+
});
|
|
6515
|
+
return snappedPosition;
|
|
6516
|
+
},
|
|
6517
|
+
[alignmentGuides]
|
|
6518
|
+
);
|
|
6519
|
+
const handleMouseDown = (e, tooltipId) => {
|
|
6520
|
+
e.preventDefault();
|
|
6521
|
+
e.stopPropagation();
|
|
6522
|
+
const tooltip = activeTooltips.find((t) => t.id === tooltipId);
|
|
6523
|
+
if (!tooltip) return;
|
|
6524
|
+
const rect = e.currentTarget.getBoundingClientRect();
|
|
6525
|
+
const offsetX = e.clientX - rect.left;
|
|
6526
|
+
const offsetY = e.clientY - rect.top;
|
|
6527
|
+
setIsDragging(tooltipId);
|
|
6528
|
+
setDragOffset({ x: offsetX, y: offsetY });
|
|
6529
|
+
};
|
|
6530
|
+
useEffect9(() => {
|
|
6531
|
+
let rafId;
|
|
6532
|
+
let lastMousePosition = { x: 0, y: 0 };
|
|
6533
|
+
const handleGlobalMouseMove = (e) => {
|
|
6534
|
+
if (!isDragging) return;
|
|
6535
|
+
lastMousePosition = { x: e.clientX, y: e.clientY };
|
|
6536
|
+
if (rafId) cancelAnimationFrame(rafId);
|
|
6537
|
+
rafId = requestAnimationFrame(() => {
|
|
6538
|
+
const newLeft = lastMousePosition.x - dragOffset.x;
|
|
6539
|
+
const newTop = lastMousePosition.y - dragOffset.y;
|
|
6540
|
+
const rawPosition = {
|
|
6541
|
+
top: Math.max(0, Math.min(newTop, window.innerHeight - 200)),
|
|
6542
|
+
left: Math.max(0, Math.min(newLeft, window.innerWidth - 250))
|
|
6543
|
+
};
|
|
6544
|
+
updateAlignmentGuides(isDragging, rawPosition);
|
|
6545
|
+
const snappedPosition = snapToGuides(rawPosition);
|
|
6546
|
+
setActiveTooltips(
|
|
6547
|
+
(prev) => prev.map((tooltip) => {
|
|
6548
|
+
if (tooltip.id === isDragging) {
|
|
6549
|
+
return {
|
|
6550
|
+
...tooltip,
|
|
6551
|
+
position: snappedPosition
|
|
6552
|
+
};
|
|
6553
|
+
}
|
|
6554
|
+
return tooltip;
|
|
6555
|
+
})
|
|
6556
|
+
);
|
|
6557
|
+
});
|
|
6558
|
+
};
|
|
6559
|
+
const handleGlobalMouseUp = () => {
|
|
6560
|
+
if (isDragging) {
|
|
6561
|
+
setIsDragging(null);
|
|
6562
|
+
setAlignmentGuides([]);
|
|
6563
|
+
if (rafId) cancelAnimationFrame(rafId);
|
|
6564
|
+
}
|
|
6565
|
+
};
|
|
6566
|
+
if (isDragging) {
|
|
6567
|
+
document.addEventListener("mousemove", handleGlobalMouseMove, {
|
|
6568
|
+
passive: true
|
|
6569
|
+
});
|
|
6570
|
+
document.addEventListener("mouseup", handleGlobalMouseUp);
|
|
6571
|
+
document.body.style.cursor = "grabbing";
|
|
6572
|
+
document.body.style.userSelect = "none";
|
|
6573
|
+
}
|
|
6574
|
+
return () => {
|
|
6575
|
+
if (rafId) cancelAnimationFrame(rafId);
|
|
6576
|
+
document.removeEventListener("mousemove", handleGlobalMouseMove);
|
|
6577
|
+
document.removeEventListener("mouseup", handleGlobalMouseUp);
|
|
6578
|
+
document.body.style.cursor = "";
|
|
6579
|
+
document.body.style.userSelect = "";
|
|
6580
|
+
};
|
|
6581
|
+
}, [
|
|
6582
|
+
isDragging,
|
|
6583
|
+
dragOffset,
|
|
6584
|
+
alignmentGuides,
|
|
6585
|
+
updateAlignmentGuides,
|
|
6586
|
+
snapToGuides
|
|
6587
|
+
]);
|
|
6588
|
+
useEffect9(() => {
|
|
6589
|
+
const handleCloseAllTooltips = () => {
|
|
6590
|
+
setActiveTooltips([]);
|
|
6591
|
+
setGlobalTooltipCount(0);
|
|
6592
|
+
};
|
|
6593
|
+
window.addEventListener("closeAllTooltips", handleCloseAllTooltips);
|
|
6594
|
+
return () => {
|
|
6595
|
+
window.removeEventListener("closeAllTooltips", handleCloseAllTooltips);
|
|
6596
|
+
};
|
|
6597
|
+
}, []);
|
|
6598
|
+
useEffect9(() => {
|
|
6599
|
+
const handleTooltipCountRequest = () => {
|
|
6600
|
+
window.dispatchEvent(
|
|
6601
|
+
new CustomEvent("tooltipCountResponse", {
|
|
6602
|
+
detail: { count: activeTooltips.length }
|
|
6603
|
+
})
|
|
6604
|
+
);
|
|
6605
|
+
};
|
|
6606
|
+
const handleGlobalTooltipsRequest = (event) => {
|
|
6607
|
+
const { detail } = event;
|
|
6608
|
+
if (detail && detail.response && detail.requesterId) {
|
|
6609
|
+
activeTooltips.forEach((tooltip) => {
|
|
6610
|
+
if (!detail.response.find(
|
|
6611
|
+
(t) => t.id === tooltip.id
|
|
6612
|
+
)) {
|
|
6613
|
+
detail.response.push({
|
|
6614
|
+
id: tooltip.id,
|
|
6615
|
+
position: tooltip.position
|
|
6616
|
+
});
|
|
6617
|
+
}
|
|
6618
|
+
});
|
|
6619
|
+
}
|
|
6620
|
+
};
|
|
6621
|
+
window.addEventListener("requestTooltipCount", handleTooltipCountRequest);
|
|
6622
|
+
window.addEventListener(
|
|
6623
|
+
"requestGlobalTooltips",
|
|
6624
|
+
handleGlobalTooltipsRequest
|
|
6625
|
+
);
|
|
6626
|
+
return () => {
|
|
6627
|
+
window.removeEventListener(
|
|
6628
|
+
"requestTooltipCount",
|
|
6629
|
+
handleTooltipCountRequest
|
|
6630
|
+
);
|
|
6631
|
+
window.removeEventListener(
|
|
6632
|
+
"requestGlobalTooltips",
|
|
6633
|
+
handleGlobalTooltipsRequest
|
|
6634
|
+
);
|
|
6635
|
+
};
|
|
6636
|
+
}, [activeTooltips]);
|
|
6637
|
+
useEffect9(() => {
|
|
6638
|
+
if (isDragging) return;
|
|
6639
|
+
let totalCount = 0;
|
|
6640
|
+
const handleCountResponse = (event) => {
|
|
6641
|
+
const customEvent = event;
|
|
6642
|
+
totalCount += customEvent.detail.count;
|
|
6643
|
+
};
|
|
6644
|
+
window.addEventListener("tooltipCountResponse", handleCountResponse);
|
|
6645
|
+
window.dispatchEvent(new CustomEvent("requestTooltipCount"));
|
|
6646
|
+
const timeoutId = setTimeout(() => {
|
|
6647
|
+
window.removeEventListener("tooltipCountResponse", handleCountResponse);
|
|
6648
|
+
setGlobalTooltipCount(totalCount);
|
|
6649
|
+
}, 5);
|
|
6650
|
+
return () => {
|
|
6651
|
+
clearTimeout(timeoutId);
|
|
6652
|
+
window.removeEventListener("tooltipCountResponse", handleCountResponse);
|
|
6653
|
+
};
|
|
6654
|
+
}, [activeTooltips.length, isDragging]);
|
|
6655
|
+
const CustomTooltip = ({
|
|
6656
|
+
active,
|
|
6657
|
+
payload,
|
|
6658
|
+
label
|
|
6659
|
+
}) => {
|
|
6660
|
+
if (!active || !payload) return null;
|
|
6661
|
+
return /* @__PURE__ */ jsxs34("div", { className: "bg-card border border-border rounded-lg p-3 shadow-lg", children: [
|
|
6662
|
+
/* @__PURE__ */ jsx53("p", { className: "font-medium text-foreground mb-2", children: label }),
|
|
6663
|
+
payload.map(
|
|
6664
|
+
(entry, index) => /* @__PURE__ */ jsxs34("div", { className: "flex items-center gap-2 text-sm", children: [
|
|
6665
|
+
/* @__PURE__ */ jsx53(
|
|
6666
|
+
"div",
|
|
6667
|
+
{
|
|
6668
|
+
className: "w-3 h-3 rounded-sm",
|
|
6669
|
+
style: { backgroundColor: entry.color }
|
|
6670
|
+
}
|
|
6671
|
+
),
|
|
6672
|
+
/* @__PURE__ */ jsxs34("span", { className: "text-muted-foreground", children: [
|
|
6673
|
+
entry.name,
|
|
6674
|
+
":"
|
|
6675
|
+
] }),
|
|
6676
|
+
/* @__PURE__ */ jsx53("span", { className: "text-foreground font-medium", children: entry.value?.toLocaleString("pt-BR") })
|
|
6677
|
+
] }, index)
|
|
6678
|
+
),
|
|
6679
|
+
/* @__PURE__ */ jsx53("p", { className: "text-xs text-muted-foreground mt-1", children: "Clique para fixar este tooltip" })
|
|
6680
|
+
] });
|
|
6681
|
+
};
|
|
6682
|
+
const getTitleClassName = (position) => {
|
|
6683
|
+
const baseClasses = "text-xl font-semibold text-foreground mb-3";
|
|
6684
|
+
switch (position) {
|
|
6685
|
+
case "center":
|
|
6686
|
+
return `${baseClasses} text-center`;
|
|
6687
|
+
case "right":
|
|
6688
|
+
return `${baseClasses} text-right`;
|
|
6689
|
+
default:
|
|
6690
|
+
return `${baseClasses} text-left`;
|
|
6691
|
+
}
|
|
6692
|
+
};
|
|
6693
|
+
return /* @__PURE__ */ jsxs34(
|
|
6694
|
+
"div",
|
|
6695
|
+
{
|
|
6696
|
+
className: cn("rounded-lg bg-card p-4 relative", className),
|
|
6697
|
+
style: {
|
|
6698
|
+
width: typeof width === "number" ? `${width + 32}px` : "fit-content",
|
|
6699
|
+
maxWidth: "100%"
|
|
6700
|
+
},
|
|
6701
|
+
children: [
|
|
6702
|
+
title && /* @__PURE__ */ jsx53("h3", { className: getTitleClassName(titlePosition), children: title }),
|
|
6703
|
+
/* @__PURE__ */ jsxs34(
|
|
6704
|
+
RechartsBarChart,
|
|
6705
|
+
{
|
|
6706
|
+
data: processedData,
|
|
6707
|
+
width: typeof width === "number" ? width : 900,
|
|
6708
|
+
height,
|
|
6709
|
+
margin: { top: showLabels ? 48 : 20, right: 30, left: 20, bottom: 5 },
|
|
6710
|
+
onClick: handleChartClick,
|
|
6711
|
+
children: [
|
|
6712
|
+
showGrid && /* @__PURE__ */ jsx53(
|
|
6713
|
+
CartesianGrid2,
|
|
6714
|
+
{
|
|
6715
|
+
strokeDasharray: "3 3",
|
|
6716
|
+
stroke: gridColor || "hsl(var(--muted-foreground))",
|
|
6717
|
+
opacity: 0.5
|
|
6718
|
+
}
|
|
6719
|
+
),
|
|
6720
|
+
/* @__PURE__ */ jsx53(
|
|
6721
|
+
XAxis2,
|
|
6722
|
+
{
|
|
6723
|
+
dataKey: xAxisConfig.dataKey,
|
|
6724
|
+
stroke: "hsl(var(--muted-foreground))",
|
|
6725
|
+
fontSize: 12,
|
|
6726
|
+
tickLine: false,
|
|
6727
|
+
axisLine: false,
|
|
6728
|
+
tickFormatter: xAxisConfig.formatter
|
|
6729
|
+
}
|
|
6730
|
+
),
|
|
6731
|
+
/* @__PURE__ */ jsx53(
|
|
6732
|
+
YAxis2,
|
|
6733
|
+
{
|
|
6734
|
+
stroke: "hsl(var(--muted-foreground))",
|
|
6735
|
+
fontSize: 12,
|
|
6736
|
+
tickLine: false,
|
|
6737
|
+
axisLine: false,
|
|
6738
|
+
tickFormatter: (value) => value.toLocaleString("pt-BR"),
|
|
6739
|
+
domain: [0, niceMax],
|
|
6740
|
+
tickCount: 6
|
|
6741
|
+
}
|
|
6742
|
+
),
|
|
6743
|
+
showTooltip && /* @__PURE__ */ jsx53(
|
|
6744
|
+
Tooltip3,
|
|
6745
|
+
{
|
|
6746
|
+
content: /* @__PURE__ */ jsx53(CustomTooltip, {}),
|
|
6747
|
+
cursor: { fill: "hsl(var(--muted))", opacity: 0.1 }
|
|
6748
|
+
}
|
|
6749
|
+
),
|
|
6750
|
+
showLegend && /* @__PURE__ */ jsx53(
|
|
6751
|
+
Legend3,
|
|
6752
|
+
{
|
|
6753
|
+
wrapperStyle: {
|
|
6754
|
+
color: "hsl(var(--foreground))",
|
|
6755
|
+
fontSize: "14px"
|
|
6756
|
+
}
|
|
6757
|
+
}
|
|
6758
|
+
),
|
|
6759
|
+
dataKeys.map((key) => {
|
|
6760
|
+
const fieldConfig = mapperConfig[key];
|
|
6761
|
+
return /* @__PURE__ */ jsx53(
|
|
6762
|
+
Bar,
|
|
6763
|
+
{
|
|
6764
|
+
dataKey: key,
|
|
6765
|
+
name: fieldConfig?.label || key,
|
|
6766
|
+
fill: fieldConfig?.color || finalColors[key],
|
|
6767
|
+
radius: [4, 4, 0, 0],
|
|
6768
|
+
onClick: handleBarClick,
|
|
6769
|
+
style: { cursor: "pointer" },
|
|
6770
|
+
activeBar: /* @__PURE__ */ jsx53(
|
|
6771
|
+
Rectangle,
|
|
6772
|
+
{
|
|
6773
|
+
fill: finalColors[key],
|
|
6774
|
+
stroke: finalColors[key],
|
|
6775
|
+
strokeWidth: 2,
|
|
6776
|
+
opacity: 0.8
|
|
6777
|
+
}
|
|
6778
|
+
),
|
|
6779
|
+
children: showLabels && /* @__PURE__ */ jsx53(
|
|
6780
|
+
LabelList2,
|
|
6781
|
+
{
|
|
6782
|
+
dataKey: key,
|
|
6783
|
+
position: "top",
|
|
6784
|
+
content: pillLabelRenderer_default(
|
|
6785
|
+
finalColors[key] || "#000",
|
|
6786
|
+
"filled"
|
|
6787
|
+
)
|
|
6788
|
+
}
|
|
6789
|
+
)
|
|
6790
|
+
},
|
|
6791
|
+
key
|
|
6792
|
+
);
|
|
6793
|
+
})
|
|
6794
|
+
]
|
|
6795
|
+
}
|
|
6796
|
+
),
|
|
6797
|
+
alignmentGuides.map((guide, index) => {
|
|
6798
|
+
const isHorizontal = guide.type === "horizontal";
|
|
6799
|
+
const color = isHorizontal ? "#3b82f6" : "#ef4444";
|
|
6800
|
+
const startX = isHorizontal ? Math.min(
|
|
6801
|
+
guide.sourceTooltip.left + guide.sourceTooltip.width / 2,
|
|
6802
|
+
guide.targetTooltip.left + guide.targetTooltip.width / 2
|
|
6803
|
+
) : guide.sourceTooltip.left + (isHorizontal ? 0 : guide.sourceTooltip.width / 2);
|
|
6804
|
+
const endX = isHorizontal ? Math.max(
|
|
6805
|
+
guide.sourceTooltip.left + guide.sourceTooltip.width / 2,
|
|
6806
|
+
guide.targetTooltip.left + guide.targetTooltip.width / 2
|
|
6807
|
+
) : guide.targetTooltip.left + (isHorizontal ? 0 : guide.targetTooltip.width / 2);
|
|
6808
|
+
const startY = isHorizontal ? guide.sourceTooltip.top + (isHorizontal ? guide.sourceTooltip.height / 2 : 0) : Math.min(
|
|
6809
|
+
guide.sourceTooltip.top + guide.sourceTooltip.height / 2,
|
|
6810
|
+
guide.targetTooltip.top + guide.targetTooltip.height / 2
|
|
6811
|
+
);
|
|
6812
|
+
const endY = isHorizontal ? guide.targetTooltip.top + (isHorizontal ? guide.targetTooltip.height / 2 : 0) : Math.max(
|
|
6813
|
+
guide.sourceTooltip.top + guide.sourceTooltip.height / 2,
|
|
6814
|
+
guide.targetTooltip.top + guide.targetTooltip.height / 2
|
|
6815
|
+
);
|
|
6816
|
+
return /* @__PURE__ */ jsxs34("div", { children: [
|
|
6817
|
+
/* @__PURE__ */ jsx53(
|
|
6818
|
+
"div",
|
|
6819
|
+
{
|
|
6820
|
+
className: "fixed pointer-events-none z-30",
|
|
6821
|
+
style: {
|
|
6822
|
+
left: startX,
|
|
6823
|
+
top: startY,
|
|
6824
|
+
width: isHorizontal ? endX - startX : "2px",
|
|
6825
|
+
height: isHorizontal ? "2px" : endY - startY,
|
|
6826
|
+
backgroundColor: color,
|
|
6827
|
+
boxShadow: `0 0 8px ${color}60`,
|
|
6828
|
+
opacity: 0.9,
|
|
6829
|
+
borderStyle: "dashed",
|
|
6830
|
+
borderWidth: "1px",
|
|
6831
|
+
borderColor: color,
|
|
6832
|
+
transform: "translateZ(0)"
|
|
6833
|
+
}
|
|
6834
|
+
}
|
|
6835
|
+
),
|
|
6836
|
+
/* @__PURE__ */ jsx53(
|
|
6837
|
+
"div",
|
|
6838
|
+
{
|
|
6839
|
+
className: "fixed pointer-events-none z-31",
|
|
6840
|
+
style: {
|
|
6841
|
+
left: guide.sourceTooltip.left + guide.sourceTooltip.width / 2 - 4,
|
|
6842
|
+
top: guide.sourceTooltip.top + guide.sourceTooltip.height / 2 - 4,
|
|
6843
|
+
width: "8px",
|
|
6844
|
+
height: "8px",
|
|
6845
|
+
backgroundColor: color,
|
|
6846
|
+
borderRadius: "50%",
|
|
6847
|
+
boxShadow: `0 0 4px ${color}80`,
|
|
6848
|
+
opacity: 0.8
|
|
6849
|
+
}
|
|
6850
|
+
}
|
|
6851
|
+
),
|
|
6852
|
+
/* @__PURE__ */ jsx53(
|
|
6853
|
+
"div",
|
|
6854
|
+
{
|
|
6855
|
+
className: "fixed pointer-events-none z-31",
|
|
6856
|
+
style: {
|
|
6857
|
+
left: guide.targetTooltip.left + guide.targetTooltip.width / 2 - 4,
|
|
6858
|
+
top: guide.targetTooltip.top + guide.targetTooltip.height / 2 - 4,
|
|
6859
|
+
width: "8px",
|
|
6860
|
+
height: "8px",
|
|
6861
|
+
backgroundColor: color,
|
|
6862
|
+
borderRadius: "50%",
|
|
6863
|
+
boxShadow: `0 0 4px ${color}80`,
|
|
6864
|
+
opacity: 0.8
|
|
6865
|
+
}
|
|
6866
|
+
}
|
|
6867
|
+
)
|
|
6868
|
+
] }, index);
|
|
6869
|
+
}),
|
|
6870
|
+
activeTooltips.map((tooltip, index) => /* @__PURE__ */ jsx53(
|
|
6871
|
+
DraggableTooltip_default,
|
|
6872
|
+
{
|
|
6873
|
+
id: tooltip.id,
|
|
6874
|
+
data: adaptDataForTooltip(tooltip.data),
|
|
6875
|
+
position: tooltip.position,
|
|
6876
|
+
isDragging: isDragging === tooltip.id,
|
|
6877
|
+
title,
|
|
6878
|
+
dataKeys,
|
|
6879
|
+
finalColors,
|
|
6880
|
+
onMouseDown: (id, e) => handleMouseDown(e, id),
|
|
6881
|
+
onClose: (id) => {
|
|
6882
|
+
setActiveTooltips((prev) => prev.filter((t) => t.id !== id));
|
|
6883
|
+
},
|
|
6884
|
+
periodLabel: "Per\xEDodo Selecionado",
|
|
6885
|
+
dataLabel: "Dados do Per\xEDodo",
|
|
6886
|
+
showCloseAllButton: index === 0,
|
|
6887
|
+
globalTooltipCount,
|
|
6888
|
+
onCloseAll: () => {
|
|
6889
|
+
window.dispatchEvent(new Event("closeAllTooltips"));
|
|
6890
|
+
},
|
|
6891
|
+
closeAllButtonPosition: "top-center",
|
|
6892
|
+
closeAllButtonVariant: "floating"
|
|
6893
|
+
},
|
|
6894
|
+
tooltip.id
|
|
6895
|
+
))
|
|
6896
|
+
]
|
|
6897
|
+
}
|
|
6898
|
+
);
|
|
6899
|
+
};
|
|
6900
|
+
var BarChart_default = BarChart;
|
|
6901
|
+
|
|
6902
|
+
// src/components/rechart/Chart.tsx
|
|
6903
|
+
import {
|
|
6904
|
+
useState as useState13,
|
|
6905
|
+
useEffect as useEffect11,
|
|
6906
|
+
useCallback as useCallback9,
|
|
6907
|
+
useMemo as useMemo7,
|
|
6908
|
+
useRef as useRef4,
|
|
6909
|
+
useLayoutEffect
|
|
6910
|
+
} from "react";
|
|
6911
|
+
import {
|
|
6912
|
+
ComposedChart,
|
|
6913
|
+
Bar as Bar2,
|
|
6914
|
+
Line as Line2,
|
|
6915
|
+
Area,
|
|
6916
|
+
Rectangle as Rectangle2,
|
|
6917
|
+
XAxis as XAxis3,
|
|
6918
|
+
YAxis as YAxis3,
|
|
6919
|
+
CartesianGrid as CartesianGrid3,
|
|
6920
|
+
Tooltip as Tooltip4,
|
|
6921
|
+
Legend as Legend4,
|
|
6922
|
+
LabelList as LabelList3,
|
|
6923
|
+
ResponsiveContainer as ResponsiveContainer2
|
|
6924
|
+
} from "recharts";
|
|
6925
|
+
|
|
6926
|
+
// src/components/rechart/helpers.ts
|
|
6927
|
+
var formatFieldName2 = (fieldName) => {
|
|
6928
|
+
return fieldName.replace(/([A-Z])/g, " $1").replace(/[_-]/g, " ").replace(/\b\w/g, (l) => l.toUpperCase()).trim();
|
|
6929
|
+
};
|
|
6930
|
+
var detectDataFields2 = (data, xAxisKey) => {
|
|
6931
|
+
if (!data || data.length === 0) return [];
|
|
6932
|
+
const firstItem = data[0];
|
|
6933
|
+
return Object.keys(firstItem).filter(
|
|
6934
|
+
(key) => key !== xAxisKey && typeof firstItem[key] === "number"
|
|
6935
|
+
);
|
|
6936
|
+
};
|
|
6937
|
+
var generateAdditionalColors3 = (baseColors, count) => {
|
|
6938
|
+
const hexToRgb = (hex) => {
|
|
6939
|
+
const clean = hex.replace("#", "");
|
|
6940
|
+
const bigint = parseInt(
|
|
6941
|
+
clean.length === 3 ? clean.split("").map((c) => c + c).join("") : clean,
|
|
6942
|
+
16
|
|
6943
|
+
);
|
|
6944
|
+
return { r: bigint >> 16 & 255, g: bigint >> 8 & 255, b: bigint & 255 };
|
|
6945
|
+
};
|
|
6946
|
+
const rgbToHsl = ({ r, g, b }) => {
|
|
6947
|
+
r /= 255;
|
|
6948
|
+
g /= 255;
|
|
6949
|
+
b /= 255;
|
|
6950
|
+
const max = Math.max(r, g, b), min = Math.min(r, g, b);
|
|
6951
|
+
let h = 0;
|
|
6952
|
+
let s = 0;
|
|
6953
|
+
const l = (max + min) / 2;
|
|
6954
|
+
if (max !== min) {
|
|
6955
|
+
const d = max - min;
|
|
6956
|
+
s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
|
|
6957
|
+
switch (max) {
|
|
6958
|
+
case r:
|
|
6959
|
+
h = (g - b) / d + (g < b ? 6 : 0);
|
|
6960
|
+
break;
|
|
6961
|
+
case g:
|
|
6962
|
+
h = (b - r) / d + 2;
|
|
6963
|
+
break;
|
|
6964
|
+
case b:
|
|
6965
|
+
h = (r - g) / d + 4;
|
|
6966
|
+
break;
|
|
6967
|
+
}
|
|
6968
|
+
h /= 6;
|
|
6969
|
+
}
|
|
6970
|
+
return {
|
|
6971
|
+
h: Math.round(h * 360),
|
|
6972
|
+
s: Math.round(s * 100),
|
|
6973
|
+
l: Math.round(l * 100)
|
|
6974
|
+
};
|
|
6975
|
+
};
|
|
6976
|
+
const hslToHex = (h, s, l) => {
|
|
6977
|
+
s /= 100;
|
|
6978
|
+
l /= 100;
|
|
6979
|
+
const k = (n) => (n + h / 30) % 5;
|
|
6980
|
+
const a = s * Math.min(l, 1 - l);
|
|
6981
|
+
const f = (n) => {
|
|
6982
|
+
const color = l - a * Math.max(-1, Math.min(k(n) - 3, Math.min(9 - k(n), 1)));
|
|
6983
|
+
return Math.round(255 * color).toString(16).padStart(2, "0");
|
|
6984
|
+
};
|
|
6985
|
+
return `#${f(0)}${f(8)}${f(4)}`;
|
|
6986
|
+
};
|
|
6987
|
+
const anchors = baseColors.map((c) => rgbToHsl(hexToRgb(c)));
|
|
6988
|
+
const colors2 = [...baseColors];
|
|
6989
|
+
let i = 0;
|
|
6990
|
+
while (colors2.length < count) {
|
|
6991
|
+
const anchor = anchors[i % anchors.length];
|
|
6992
|
+
const step = Math.floor(i / anchors.length + 1);
|
|
6993
|
+
const hueOffset = step * 25 * (i % 2 === 0 ? 1 : -1);
|
|
6994
|
+
const satOffset = i % 3 === 0 ? -6 : 6;
|
|
6995
|
+
const lightOffset = i % 4 === 0 ? 6 : -4;
|
|
6996
|
+
const newH = (anchor.h + hueOffset + 360) % 360;
|
|
6997
|
+
const newS = Math.max(30, Math.min(95, anchor.s + satOffset));
|
|
6998
|
+
const newL = Math.max(25, Math.min(45, anchor.l + lightOffset));
|
|
6999
|
+
colors2.push(hslToHex(newH, newS, newL));
|
|
7000
|
+
i += 1;
|
|
7001
|
+
}
|
|
7002
|
+
return colors2.slice(0, count);
|
|
7003
|
+
};
|
|
7004
|
+
|
|
7005
|
+
// src/components/rechart/PeriodsDropdown.tsx
|
|
7006
|
+
import { useState as useState12, useRef as useRef3, useEffect as useEffect10 } from "react";
|
|
7007
|
+
import { motion as motion7, AnimatePresence as AnimatePresence4 } from "framer-motion";
|
|
7008
|
+
import { DotsThreeIcon as DotsThreeIcon2 } from "@phosphor-icons/react/dist/ssr";
|
|
7009
|
+
import { Check } from "@phosphor-icons/react/dist/ssr";
|
|
7010
|
+
import { jsx as jsx54, jsxs as jsxs35 } from "react/jsx-runtime";
|
|
7011
|
+
var menuVariants = {
|
|
7012
|
+
hidden: { opacity: 0, y: -6, scale: 0.98 },
|
|
7013
|
+
visible: { opacity: 1, y: 0, scale: 1 },
|
|
7014
|
+
exit: { opacity: 0, y: -6, scale: 0.98 }
|
|
7015
|
+
};
|
|
7016
|
+
var itemVariants = {
|
|
7017
|
+
hidden: { opacity: 0, x: -6 },
|
|
7018
|
+
visible: { opacity: 1, x: 0 }
|
|
7019
|
+
};
|
|
7020
|
+
var PeriodsDropdown = ({
|
|
7021
|
+
processedData,
|
|
7022
|
+
onOpenPeriod,
|
|
7023
|
+
rightOffset,
|
|
7024
|
+
topOffset,
|
|
7025
|
+
activePeriod,
|
|
7026
|
+
activePeriods
|
|
7027
|
+
}) => {
|
|
7028
|
+
const periods = processedData.map((d) => String(d.name));
|
|
7029
|
+
const [open, setOpen] = useState12(false);
|
|
7030
|
+
const wrapperRef = useRef3(null);
|
|
7031
|
+
const firstItemRef = useRef3(null);
|
|
7032
|
+
const listRef = useRef3(null);
|
|
7033
|
+
useEffect10(() => {
|
|
7034
|
+
const handleClickOutside = (e) => {
|
|
7035
|
+
if (!wrapperRef.current) return;
|
|
7036
|
+
if (!wrapperRef.current.contains(e.target)) setOpen(false);
|
|
7037
|
+
};
|
|
7038
|
+
const handleEscape = (e) => {
|
|
7039
|
+
if (e.key === "Escape") setOpen(false);
|
|
7040
|
+
};
|
|
7041
|
+
document.addEventListener("mousedown", handleClickOutside);
|
|
7042
|
+
document.addEventListener("keydown", handleEscape);
|
|
7043
|
+
return () => {
|
|
7044
|
+
document.removeEventListener("mousedown", handleClickOutside);
|
|
7045
|
+
document.removeEventListener("keydown", handleEscape);
|
|
7046
|
+
};
|
|
7047
|
+
}, []);
|
|
7048
|
+
useEffect10(() => {
|
|
7049
|
+
if (open && firstItemRef.current) {
|
|
7050
|
+
firstItemRef.current.focus();
|
|
7051
|
+
}
|
|
7052
|
+
}, [open]);
|
|
7053
|
+
const handleSelect = (p) => {
|
|
7054
|
+
onOpenPeriod(p);
|
|
7055
|
+
setOpen(false);
|
|
7056
|
+
};
|
|
7057
|
+
const containerStyle = typeof rightOffset === "number" ? { position: "relative", zIndex: 60 } : { position: "relative", zIndex: 60 };
|
|
7058
|
+
return /* @__PURE__ */ jsxs35("div", { ref: wrapperRef, style: containerStyle, className: "mr-4", children: [
|
|
7059
|
+
/* @__PURE__ */ jsxs35(
|
|
7060
|
+
"button",
|
|
7061
|
+
{
|
|
7062
|
+
className: "relative p-2 rounded-md hover:bg-accent/10 focus:outline-none focus:ring-2 focus:ring-accent focus:ring-offset-2 transition z-10 flex items-center",
|
|
7063
|
+
"aria-expanded": open,
|
|
7064
|
+
onClick: () => setOpen((v) => !v),
|
|
7065
|
+
onKeyDown: (e) => {
|
|
7066
|
+
if (e.key === "ArrowDown") setOpen(true);
|
|
7067
|
+
},
|
|
7068
|
+
title: open ? "Fechar lista de per\xEDodos" : "Abrir lista de per\xEDodos",
|
|
7069
|
+
children: [
|
|
7070
|
+
/* @__PURE__ */ jsx54(DotsThreeIcon2, { size: 18 }),
|
|
7071
|
+
periods.length > 0 && /* @__PURE__ */ jsx54("span", { className: "absolute -top-1 -right-1 bg-accent text-foreground text-xs rounded-full w-5 h-5 flex items-center justify-center", children: periods.length })
|
|
7072
|
+
]
|
|
7073
|
+
}
|
|
7074
|
+
),
|
|
7075
|
+
/* @__PURE__ */ jsx54(AnimatePresence4, { children: open && /* @__PURE__ */ jsxs35(
|
|
7076
|
+
motion7.div,
|
|
7077
|
+
{
|
|
7078
|
+
initial: "hidden",
|
|
7079
|
+
animate: "visible",
|
|
7080
|
+
exit: "exit",
|
|
7081
|
+
variants: menuVariants,
|
|
7082
|
+
transition: { type: "spring", stiffness: 500, damping: 30 },
|
|
7083
|
+
className: "bg-card border border-border rounded-lg shadow-lg overflow-hidden",
|
|
7084
|
+
style: {
|
|
7085
|
+
minWidth: 180,
|
|
7086
|
+
maxHeight: 260,
|
|
7087
|
+
overflow: "hidden",
|
|
7088
|
+
position: "absolute",
|
|
7089
|
+
top: typeof topOffset === "number" ? topOffset : "calc(100% + 6px)",
|
|
7090
|
+
right: typeof rightOffset === "number" ? rightOffset : 0
|
|
7091
|
+
},
|
|
7092
|
+
role: "menu",
|
|
7093
|
+
"aria-orientation": "vertical",
|
|
7094
|
+
children: [
|
|
7095
|
+
/* @__PURE__ */ jsx54("div", { className: "px-3 py-2 text-sm font-medium text-muted-foreground", children: "Per\xEDodos" }),
|
|
7096
|
+
/* @__PURE__ */ jsx54("div", { className: "h-px bg-border" }),
|
|
7097
|
+
/* @__PURE__ */ jsx54(
|
|
7098
|
+
"div",
|
|
7099
|
+
{
|
|
7100
|
+
ref: listRef,
|
|
7101
|
+
className: "flex flex-col p-2 gap-1",
|
|
7102
|
+
style: { maxHeight: 200, overflowY: "auto" },
|
|
7103
|
+
children: periods.map((p, idx) => /* @__PURE__ */ jsxs35(
|
|
7104
|
+
motion7.button,
|
|
7105
|
+
{
|
|
7106
|
+
className: "flex items-center justify-between w-full text-left px-3 py-2 rounded focus:outline-none transition-colors " + (activePeriods && activePeriods.includes(p) || p === activePeriod ? "bg-accent/10" : "hover:bg-accent/5 focus:bg-accent/10"),
|
|
7107
|
+
variants: itemVariants,
|
|
7108
|
+
initial: "hidden",
|
|
7109
|
+
animate: "visible",
|
|
7110
|
+
whileTap: { scale: 0.98 },
|
|
7111
|
+
onClick: () => handleSelect(p),
|
|
7112
|
+
ref: idx === 0 ? firstItemRef : void 0,
|
|
7113
|
+
role: "menuitem",
|
|
7114
|
+
"aria-checked": activePeriods && activePeriods.includes(p) || p === activePeriod,
|
|
7115
|
+
children: [
|
|
7116
|
+
/* @__PURE__ */ jsx54("span", { className: "truncate", children: p }),
|
|
7117
|
+
(activePeriods && activePeriods.includes(p) || p === activePeriod) && /* @__PURE__ */ jsx54("span", { className: "ml-2 text-primary", children: /* @__PURE__ */ jsx54(Check, { size: 16, weight: "bold" }) })
|
|
7118
|
+
]
|
|
7119
|
+
},
|
|
7120
|
+
p
|
|
7121
|
+
))
|
|
7122
|
+
}
|
|
7123
|
+
)
|
|
7124
|
+
]
|
|
7125
|
+
}
|
|
7126
|
+
) })
|
|
7127
|
+
] });
|
|
7128
|
+
};
|
|
7129
|
+
var PeriodsDropdown_default = PeriodsDropdown;
|
|
7130
|
+
|
|
7131
|
+
// src/components/rechart/ShowOnly.tsx
|
|
7132
|
+
import { motion as motion8 } from "framer-motion";
|
|
7133
|
+
import { Eye, EyeSlash } from "@phosphor-icons/react";
|
|
7134
|
+
import { Fragment as Fragment7, jsx as jsx55 } from "react/jsx-runtime";
|
|
7135
|
+
var ShowOnly = ({
|
|
7136
|
+
showOnlyHighlighted,
|
|
7137
|
+
setShowOnlyHighlighted,
|
|
7138
|
+
highlightedSeriesSize
|
|
7139
|
+
}) => {
|
|
7140
|
+
const hasHighlights = highlightedSeriesSize > 0;
|
|
7141
|
+
if (!hasHighlights) return null;
|
|
7142
|
+
return /* @__PURE__ */ jsx55("div", { className: "ml-auto flex items-center gap-2", children: /* @__PURE__ */ jsx55(
|
|
7143
|
+
motion8.div,
|
|
7144
|
+
{
|
|
7145
|
+
whileTap: { scale: hasHighlights ? 0.985 : 1 },
|
|
7146
|
+
whileHover: { y: hasHighlights ? -2 : 0 },
|
|
7147
|
+
children: /* @__PURE__ */ jsx55(
|
|
7148
|
+
ButtonBase,
|
|
7149
|
+
{
|
|
7150
|
+
variant: "secondary",
|
|
7151
|
+
onClick: () => hasHighlights && setShowOnlyHighlighted((v) => !v),
|
|
7152
|
+
"aria-pressed": showOnlyHighlighted,
|
|
7153
|
+
"aria-label": showOnlyHighlighted ? "Exibir todos" : "Mostrar somente destacados",
|
|
7154
|
+
title: showOnlyHighlighted ? "Exibir todos" : "Mostrar somente destacados",
|
|
7155
|
+
disabled: !hasHighlights,
|
|
7156
|
+
className: cn(
|
|
7157
|
+
"flex items-center gap-2 text-sm px-3 py-1 rounded-md transition-shadow",
|
|
7158
|
+
!hasHighlights ? "opacity-60 cursor-not-allowed" : showOnlyHighlighted ? "bg-primary/10 text-primary shadow-sm border" : "bg-transparent text-muted-foreground border border-transparent hover:bg-muted/5"
|
|
7159
|
+
),
|
|
7160
|
+
children: showOnlyHighlighted ? /* @__PURE__ */ jsx55(Fragment7, { children: /* @__PURE__ */ jsx55(EyeSlash, { size: 16, weight: "regular" }) }) : /* @__PURE__ */ jsx55(Fragment7, { children: /* @__PURE__ */ jsx55(Eye, { size: 16, weight: "bold" }) })
|
|
7161
|
+
}
|
|
7162
|
+
)
|
|
7163
|
+
}
|
|
7164
|
+
) });
|
|
7165
|
+
};
|
|
7166
|
+
var ShowOnly_default = ShowOnly;
|
|
7167
|
+
|
|
7168
|
+
// src/components/rechart/Highlights.tsx
|
|
7169
|
+
import { motion as motion9, AnimatePresence as AnimatePresence5 } from "framer-motion";
|
|
7170
|
+
import { jsx as jsx56, jsxs as jsxs36 } from "react/jsx-runtime";
|
|
7171
|
+
var Highlights = ({
|
|
7172
|
+
allKeys,
|
|
7173
|
+
mapperConfig,
|
|
7174
|
+
finalColors,
|
|
7175
|
+
highlightedSeries,
|
|
7176
|
+
toggleHighlight,
|
|
7177
|
+
containerWidth
|
|
7178
|
+
}) => {
|
|
7179
|
+
const count = allKeys.length || 1;
|
|
7180
|
+
const available = containerWidth && containerWidth > 0 ? containerWidth : 600;
|
|
7181
|
+
const perPill = Math.floor(available / count);
|
|
7182
|
+
const showFullLabel = perPill >= 96;
|
|
7183
|
+
const showShortLabel = perPill >= 64;
|
|
7184
|
+
const containerVariants = {
|
|
7185
|
+
hidden: { opacity: 0 },
|
|
7186
|
+
visible: { opacity: 1, transition: { staggerChildren: 0.03 } }
|
|
7187
|
+
};
|
|
7188
|
+
return /* @__PURE__ */ jsx56(
|
|
7189
|
+
motion9.div,
|
|
7190
|
+
{
|
|
7191
|
+
className: "flex-1 flex items-center gap-2 flex-wrap",
|
|
7192
|
+
initial: "hidden",
|
|
7193
|
+
animate: "visible",
|
|
7194
|
+
variants: containerVariants,
|
|
7195
|
+
children: /* @__PURE__ */ jsx56(AnimatePresence5, { initial: false, mode: "popLayout", children: allKeys.map((k) => {
|
|
7196
|
+
const isHighlighted = highlightedSeries.has(k);
|
|
7197
|
+
const label = mapperConfig[k]?.label ?? k;
|
|
7198
|
+
const color = finalColors[k];
|
|
7199
|
+
const pillClasses = cn(
|
|
7200
|
+
"inline-flex items-center gap-2 px-3 py-1 rounded-full text-sm border transition-all select-none",
|
|
7201
|
+
isHighlighted ? "bg-card/95 border-2 text-foreground shadow-[0_6px_18px_rgba(0,0,0,0.12)]" : "bg-muted/10 border-border text-muted-foreground"
|
|
7202
|
+
);
|
|
7203
|
+
return /* @__PURE__ */ jsx56(
|
|
7204
|
+
motion9.div,
|
|
7205
|
+
{
|
|
7206
|
+
layout: true,
|
|
7207
|
+
initial: "hidden",
|
|
7208
|
+
animate: "visible",
|
|
7209
|
+
exit: "exit",
|
|
7210
|
+
children: /* @__PURE__ */ jsx56(
|
|
7211
|
+
ButtonBase,
|
|
7212
|
+
{
|
|
7213
|
+
asChild: true,
|
|
7214
|
+
variant: "ghost",
|
|
7215
|
+
onClick: () => toggleHighlight(k),
|
|
7216
|
+
title: isHighlighted ? `Desativar ${label}` : `Ativar ${label}`,
|
|
7217
|
+
className: pillClasses,
|
|
7218
|
+
style: { minWidth: showFullLabel ? void 0 : 36 },
|
|
7219
|
+
"aria-pressed": isHighlighted,
|
|
7220
|
+
children: /* @__PURE__ */ jsxs36(
|
|
7221
|
+
motion9.button,
|
|
7222
|
+
{
|
|
7223
|
+
whileHover: { scale: isHighlighted ? 1.04 : 1.03 },
|
|
7224
|
+
whileTap: { scale: 0.96 },
|
|
7225
|
+
animate: isHighlighted ? { scale: 1.02 } : { scale: 1 },
|
|
7226
|
+
className: "flex items-center gap-2",
|
|
7227
|
+
children: [
|
|
7228
|
+
/* @__PURE__ */ jsx56(
|
|
7229
|
+
motion9.span,
|
|
7230
|
+
{
|
|
7231
|
+
className: cn("w-3 h-3 rounded-sm flex-shrink-0 border"),
|
|
7232
|
+
style: {
|
|
7233
|
+
backgroundColor: color,
|
|
7234
|
+
borderColor: isHighlighted ? color : "transparent",
|
|
7235
|
+
boxShadow: isHighlighted ? `0 6px 20px ${color}33` : void 0
|
|
7236
|
+
},
|
|
7237
|
+
layout: true,
|
|
7238
|
+
initial: { scale: 0.8, opacity: 0.9 },
|
|
7239
|
+
animate: { scale: 1, opacity: 1 },
|
|
7240
|
+
transition: { type: "spring", stiffness: 400, damping: 30 }
|
|
7241
|
+
}
|
|
7242
|
+
),
|
|
7243
|
+
showFullLabel ? /* @__PURE__ */ jsx56(motion9.span, { className: "truncate max-w-[10rem]", layout: true, children: label }) : showShortLabel ? /* @__PURE__ */ jsx56(
|
|
7244
|
+
motion9.span,
|
|
7245
|
+
{
|
|
7246
|
+
className: "truncate max-w-[6rem] text-xs",
|
|
7247
|
+
layout: true,
|
|
7248
|
+
children: label
|
|
7249
|
+
}
|
|
7250
|
+
) : null,
|
|
7251
|
+
isHighlighted ? /* @__PURE__ */ jsx56(
|
|
7252
|
+
motion9.span,
|
|
7253
|
+
{
|
|
7254
|
+
initial: { opacity: 0, scale: 0.6 },
|
|
7255
|
+
animate: { opacity: 1, scale: 1 },
|
|
7256
|
+
transition: {
|
|
7257
|
+
type: "spring",
|
|
7258
|
+
stiffness: 450,
|
|
7259
|
+
damping: 28
|
|
7260
|
+
},
|
|
7261
|
+
className: "ml-1 text-xs text-foreground",
|
|
7262
|
+
children: /* @__PURE__ */ jsx56(
|
|
7263
|
+
"svg",
|
|
7264
|
+
{
|
|
7265
|
+
width: "12",
|
|
7266
|
+
height: "12",
|
|
7267
|
+
viewBox: "0 0 24 24",
|
|
7268
|
+
fill: "none",
|
|
7269
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
7270
|
+
"aria-hidden": true,
|
|
7271
|
+
children: /* @__PURE__ */ jsx56(
|
|
7272
|
+
"path",
|
|
7273
|
+
{
|
|
7274
|
+
d: "M20 6L9 17l-5-5",
|
|
7275
|
+
stroke: "currentColor",
|
|
7276
|
+
strokeWidth: "2",
|
|
7277
|
+
strokeLinecap: "round",
|
|
7278
|
+
strokeLinejoin: "round"
|
|
7279
|
+
}
|
|
7280
|
+
)
|
|
7281
|
+
}
|
|
7282
|
+
)
|
|
7283
|
+
}
|
|
7284
|
+
) : null
|
|
7285
|
+
]
|
|
7286
|
+
}
|
|
7287
|
+
)
|
|
7288
|
+
}
|
|
7289
|
+
)
|
|
7290
|
+
},
|
|
7291
|
+
`pill-${k}`
|
|
7292
|
+
);
|
|
7293
|
+
}) })
|
|
7294
|
+
}
|
|
7295
|
+
);
|
|
7296
|
+
};
|
|
7297
|
+
var Highlights_default = Highlights;
|
|
7298
|
+
|
|
7299
|
+
// src/components/rechart/Chart.tsx
|
|
7300
|
+
import { jsx as jsx57, jsxs as jsxs37 } from "react/jsx-runtime";
|
|
7301
|
+
var DEFAULT_COLORS4 = ["#55af7d", "#8e68ff", "#2273e1"];
|
|
7302
|
+
var Chart = ({
|
|
7303
|
+
data,
|
|
7304
|
+
series,
|
|
7305
|
+
className,
|
|
7306
|
+
height = 350,
|
|
7307
|
+
width = 900,
|
|
7308
|
+
colors: colors2 = DEFAULT_COLORS4,
|
|
7309
|
+
gridColor,
|
|
7310
|
+
showGrid = true,
|
|
7311
|
+
showTooltip = true,
|
|
7312
|
+
showLegend = true,
|
|
7313
|
+
title,
|
|
7314
|
+
titlePosition = "left",
|
|
7315
|
+
showLabels = false,
|
|
7316
|
+
xAxis,
|
|
7317
|
+
labelMap,
|
|
7318
|
+
enableHighlights = false,
|
|
7319
|
+
enableShowOnly = false,
|
|
7320
|
+
enablePeriodsDropdown = false,
|
|
7321
|
+
enableDraggableTooltips = false
|
|
7322
|
+
}) => {
|
|
7323
|
+
const smartConfig = useMemo7(() => {
|
|
7324
|
+
const xAxisConfig2 = typeof xAxis === "string" ? { dataKey: xAxis, label: formatFieldName2(xAxis), autoLabel: true } : xAxis;
|
|
7325
|
+
const detectedFields = detectDataFields2(data, xAxisConfig2.dataKey);
|
|
7326
|
+
const mapperConfig2 = detectedFields.reduce((acc, field) => {
|
|
7327
|
+
acc[field] = {
|
|
7328
|
+
label: labelMap?.[field] ?? formatFieldName2(field),
|
|
7329
|
+
type: "number",
|
|
7330
|
+
visible: true
|
|
7331
|
+
};
|
|
7332
|
+
return acc;
|
|
7333
|
+
}, {});
|
|
7334
|
+
return { xAxisConfig: xAxisConfig2, mapperConfig: mapperConfig2 };
|
|
7335
|
+
}, [data, xAxis, labelMap]);
|
|
7336
|
+
const { xAxisConfig, mapperConfig } = smartConfig;
|
|
7337
|
+
const [activeTooltips, setActiveTooltips] = useState13([]);
|
|
7338
|
+
const [highlightedSeries, setHighlightedSeries] = useState13(
|
|
7339
|
+
/* @__PURE__ */ new Set()
|
|
7340
|
+
);
|
|
7341
|
+
const [showOnlyHighlighted, setShowOnlyHighlighted] = useState13(false);
|
|
7342
|
+
useEffect11(() => {
|
|
7343
|
+
if (highlightedSeries.size === 0 && showOnlyHighlighted) {
|
|
7344
|
+
setShowOnlyHighlighted(false);
|
|
7345
|
+
}
|
|
7346
|
+
}, [highlightedSeries, showOnlyHighlighted]);
|
|
7347
|
+
const processedData = data.map((item) => ({
|
|
7348
|
+
...item,
|
|
7349
|
+
name: String(item[xAxisConfig.dataKey] || "N/A")
|
|
7350
|
+
}));
|
|
7351
|
+
const wrapperRef = useRef4(null);
|
|
7352
|
+
const [measuredWidth, setMeasuredWidth] = useState13(null);
|
|
7353
|
+
useLayoutEffect(() => {
|
|
7354
|
+
const el = wrapperRef.current;
|
|
7355
|
+
if (!el) return;
|
|
7356
|
+
const ro = new ResizeObserver((entries) => {
|
|
7357
|
+
const r = entries[0];
|
|
7358
|
+
if (r && typeof r.contentRect.width === "number") {
|
|
7359
|
+
setMeasuredWidth(Math.round(r.contentRect.width));
|
|
7360
|
+
}
|
|
7361
|
+
});
|
|
7362
|
+
ro.observe(el);
|
|
7363
|
+
setMeasuredWidth(Math.round(el.getBoundingClientRect().width));
|
|
7364
|
+
return () => ro.disconnect();
|
|
7365
|
+
}, []);
|
|
7366
|
+
const seriesOrder = [];
|
|
7367
|
+
if (series) {
|
|
7368
|
+
if (series.bar)
|
|
7369
|
+
series.bar.forEach((k) => seriesOrder.push({ type: "bar", key: k }));
|
|
7370
|
+
if (series.line)
|
|
7371
|
+
series.line.forEach((k) => seriesOrder.push({ type: "line", key: k }));
|
|
7372
|
+
if (series.area)
|
|
7373
|
+
series.area.forEach((k) => seriesOrder.push({ type: "area", key: k }));
|
|
7374
|
+
} else {
|
|
7375
|
+
Object.keys(mapperConfig).forEach(
|
|
7376
|
+
(k) => seriesOrder.push({ type: "bar", key: k })
|
|
7377
|
+
);
|
|
7378
|
+
}
|
|
7379
|
+
const allKeys = seriesOrder.map((s) => s.key).filter(Boolean);
|
|
7380
|
+
const generateColors = (dataKeys) => {
|
|
7381
|
+
const colorMap = {};
|
|
7382
|
+
const allColors = generateAdditionalColors3(colors2, dataKeys.length);
|
|
7383
|
+
dataKeys.forEach((key, index) => {
|
|
7384
|
+
colorMap[key] = mapperConfig[key] && mapperConfig[key].color || allColors[index] || colors2[index % colors2.length];
|
|
7385
|
+
});
|
|
7386
|
+
return colorMap;
|
|
7387
|
+
};
|
|
7388
|
+
const finalColors = generateColors(allKeys);
|
|
7389
|
+
const adaptDataForTooltip = useCallback9(
|
|
7390
|
+
(universalData) => ({
|
|
7391
|
+
...universalData,
|
|
7392
|
+
name: String(universalData[xAxisConfig.dataKey] || "N/A")
|
|
7393
|
+
}),
|
|
7394
|
+
[xAxisConfig.dataKey]
|
|
7395
|
+
);
|
|
7396
|
+
const activePeriods = useMemo7(
|
|
7397
|
+
() => activeTooltips.map((t) => adaptDataForTooltip(t.data).name),
|
|
7398
|
+
[activeTooltips, adaptDataForTooltip]
|
|
7399
|
+
);
|
|
7400
|
+
const openTooltipForPeriod = (periodName) => {
|
|
7401
|
+
if (!enableDraggableTooltips) return;
|
|
7402
|
+
const row = processedData.find((r) => String(r.name) === periodName);
|
|
7403
|
+
if (!row) return;
|
|
7404
|
+
const tooltipId = `${periodName}`;
|
|
7405
|
+
const existingIndex = activeTooltips.findIndex((t) => t.id === tooltipId);
|
|
7406
|
+
if (existingIndex !== -1) {
|
|
7407
|
+
setActiveTooltips((prev) => prev.filter((t) => t.id !== tooltipId));
|
|
7408
|
+
return;
|
|
7409
|
+
}
|
|
7410
|
+
const offsetIndex = activeTooltips.length;
|
|
7411
|
+
const availableWidth = typeof width === "number" ? width : measuredWidth ? Math.max(0, measuredWidth - 32) : computedWidth;
|
|
7412
|
+
const newTooltip = {
|
|
7413
|
+
id: tooltipId,
|
|
7414
|
+
data: row,
|
|
7415
|
+
position: {
|
|
7416
|
+
top: 48 + offsetIndex * 28,
|
|
7417
|
+
left: Math.max(120, availableWidth - 260 - offsetIndex * 28)
|
|
7418
|
+
}
|
|
7419
|
+
};
|
|
7420
|
+
setActiveTooltips((prev) => [...prev, newTooltip]);
|
|
7421
|
+
};
|
|
7422
|
+
useEffect11(() => {
|
|
7423
|
+
window.dispatchEvent(new Event("recountTooltips"));
|
|
7424
|
+
}, [activeTooltips.length]);
|
|
7425
|
+
const toggleHighlight = useCallback9((key) => {
|
|
7426
|
+
setHighlightedSeries((prev) => {
|
|
7427
|
+
const next = new Set(prev);
|
|
7428
|
+
if (next.has(key)) next.delete(key);
|
|
7429
|
+
else next.add(key);
|
|
7430
|
+
return next;
|
|
7431
|
+
});
|
|
7432
|
+
}, []);
|
|
7433
|
+
const niceCeil = (value) => {
|
|
7434
|
+
if (!isFinite(value) || value <= 0) return 1;
|
|
7435
|
+
const pow = Math.pow(10, Math.floor(Math.log10(value)));
|
|
7436
|
+
const normalized = value / pow;
|
|
7437
|
+
const multipliers = [
|
|
7438
|
+
1,
|
|
7439
|
+
1.25,
|
|
7440
|
+
1.5,
|
|
7441
|
+
2,
|
|
7442
|
+
2.5,
|
|
7443
|
+
3,
|
|
7444
|
+
4,
|
|
7445
|
+
5,
|
|
7446
|
+
7.5,
|
|
7447
|
+
10,
|
|
7448
|
+
15,
|
|
7449
|
+
20,
|
|
7450
|
+
25,
|
|
7451
|
+
50,
|
|
7452
|
+
100
|
|
7453
|
+
];
|
|
7454
|
+
for (const m of multipliers) {
|
|
7455
|
+
if (m >= normalized) return Math.ceil(m * pow);
|
|
7456
|
+
}
|
|
7457
|
+
return Math.ceil(100 * pow);
|
|
7458
|
+
};
|
|
7459
|
+
const maxDataValue = useMemo7(() => {
|
|
7460
|
+
let max = 0;
|
|
7461
|
+
const numericKeys = allKeys;
|
|
7462
|
+
for (const row of processedData) {
|
|
7463
|
+
const r = row;
|
|
7464
|
+
for (const key of numericKeys) {
|
|
7465
|
+
const v = r[key];
|
|
7466
|
+
if (typeof v === "number" && Number.isFinite(v) && v > max) max = v;
|
|
7467
|
+
}
|
|
7468
|
+
}
|
|
7469
|
+
return max;
|
|
7470
|
+
}, [processedData, allKeys]);
|
|
7471
|
+
const niceMax = useMemo7(() => {
|
|
7472
|
+
let padding = 0.08;
|
|
7473
|
+
if (maxDataValue > 1e6) padding = 0.05;
|
|
7474
|
+
if (maxDataValue > 1e7) padding = 0.03;
|
|
7475
|
+
if (maxDataValue === 0) padding = 0.12;
|
|
7476
|
+
const padded = maxDataValue * (1 + padding);
|
|
7477
|
+
return niceCeil(padded);
|
|
7478
|
+
}, [maxDataValue]);
|
|
7479
|
+
const computedWidth = useMemo7(() => {
|
|
7480
|
+
if (typeof width === "number") return width;
|
|
7481
|
+
const points = processedData.length || 1;
|
|
7482
|
+
const barCount = series?.bar?.length ?? 0;
|
|
7483
|
+
const lineCount = series?.line?.length ?? 0;
|
|
7484
|
+
const areaCount = series?.area?.length ?? 0;
|
|
7485
|
+
const basePerPoint = 84;
|
|
7486
|
+
const perBarExtra = Math.max(0, barCount - 1) * 10;
|
|
7487
|
+
const perOtherExtra = (lineCount + areaCount) * 6;
|
|
7488
|
+
let sizeFactor = 1;
|
|
7489
|
+
if (niceMax > 1e5) sizeFactor = 1.18;
|
|
7490
|
+
if (niceMax > 1e6) sizeFactor = 1.36;
|
|
7491
|
+
if (niceMax > 1e7) sizeFactor = 1.6;
|
|
7492
|
+
const perPoint = Math.round(
|
|
7493
|
+
(basePerPoint + perBarExtra + perOtherExtra) * sizeFactor
|
|
7494
|
+
);
|
|
7495
|
+
const marginExtra = 140;
|
|
7496
|
+
const raw = Math.round(points * perPoint + marginExtra);
|
|
7497
|
+
const min = 380;
|
|
7498
|
+
const max = 2200;
|
|
7499
|
+
return Math.max(min, Math.min(max, raw));
|
|
7500
|
+
}, [
|
|
7501
|
+
width,
|
|
7502
|
+
processedData.length,
|
|
7503
|
+
series?.bar?.length,
|
|
7504
|
+
series?.line?.length,
|
|
7505
|
+
series?.area?.length,
|
|
7506
|
+
niceMax
|
|
7507
|
+
]);
|
|
7508
|
+
const handleBarClick = (data2, index, event) => {
|
|
7509
|
+
if (!enableDraggableTooltips) return;
|
|
7510
|
+
event.stopPropagation();
|
|
7511
|
+
const xAxisValue = data2[xAxisConfig.dataKey] || "N/A";
|
|
7512
|
+
const tooltipId = `${xAxisValue}`;
|
|
7513
|
+
const rect = event.target.getBoundingClientRect();
|
|
7514
|
+
const existingIndex = activeTooltips.findIndex((t) => t.id === tooltipId);
|
|
7515
|
+
if (existingIndex !== -1) {
|
|
7516
|
+
setActiveTooltips((prev) => prev.filter((t) => t.id !== tooltipId));
|
|
7517
|
+
} else {
|
|
7518
|
+
const newTooltip = {
|
|
7519
|
+
id: tooltipId,
|
|
7520
|
+
data: data2,
|
|
7521
|
+
position: { top: rect.top - 10, left: rect.right + 10 }
|
|
7522
|
+
};
|
|
7523
|
+
setActiveTooltips((prev) => [...prev, newTooltip]);
|
|
7524
|
+
}
|
|
7525
|
+
};
|
|
7526
|
+
const handleChartClick = (e) => {
|
|
7527
|
+
if (!enableDraggableTooltips) return;
|
|
7528
|
+
const ev = e;
|
|
7529
|
+
if (ev && ev.activePayload && ev.activePayload.length > 0) {
|
|
7530
|
+
const clickedData = ev.activePayload[0].payload;
|
|
7531
|
+
const xAxisValue = clickedData[xAxisConfig.dataKey] || clickedData.name || "N/A";
|
|
7532
|
+
const tooltipId = `${xAxisValue}`;
|
|
7533
|
+
const existingIndex = activeTooltips.findIndex((t) => t.id === tooltipId);
|
|
7534
|
+
if (existingIndex !== -1) {
|
|
7535
|
+
setActiveTooltips((prev) => prev.filter((t) => t.id !== tooltipId));
|
|
7536
|
+
} else {
|
|
7537
|
+
const newTooltip = {
|
|
7538
|
+
id: tooltipId,
|
|
7539
|
+
data: clickedData,
|
|
7540
|
+
position: {
|
|
7541
|
+
top: (ev?.chartY || 100) - 10,
|
|
7542
|
+
left: (ev?.chartX || 100) - 100
|
|
7543
|
+
}
|
|
7544
|
+
};
|
|
7545
|
+
setActiveTooltips((prev) => [...prev, newTooltip]);
|
|
7546
|
+
}
|
|
7547
|
+
return;
|
|
7548
|
+
}
|
|
7549
|
+
setActiveTooltips([]);
|
|
7550
|
+
};
|
|
7551
|
+
const handleSeriesClick = (...args) => {
|
|
7552
|
+
if (args.length >= 3) {
|
|
7553
|
+
const [data2, index, event] = args;
|
|
7554
|
+
handleBarClick(data2, index, event);
|
|
7555
|
+
return;
|
|
7556
|
+
}
|
|
7557
|
+
handleChartClick(args[0]);
|
|
7558
|
+
};
|
|
7559
|
+
const onTooltipPositionChange = (id, position) => {
|
|
7560
|
+
setActiveTooltips(
|
|
7561
|
+
(prev) => prev.map((t) => t.id === id ? { ...t, position } : t)
|
|
7562
|
+
);
|
|
7563
|
+
};
|
|
7564
|
+
const CustomTooltip = ({
|
|
7565
|
+
active,
|
|
7566
|
+
payload,
|
|
7567
|
+
label
|
|
7568
|
+
}) => {
|
|
7569
|
+
if (!active || !payload) return null;
|
|
7570
|
+
return /* @__PURE__ */ jsxs37("div", { className: "bg-card border border-border rounded-lg p-3 shadow-lg", children: [
|
|
7571
|
+
/* @__PURE__ */ jsx57("p", { className: "font-medium text-foreground mb-2", children: label }),
|
|
7572
|
+
payload.map((entry, index) => /* @__PURE__ */ jsxs37("div", { className: "flex items-center gap-2 text-sm", children: [
|
|
7573
|
+
/* @__PURE__ */ jsx57(
|
|
7574
|
+
"div",
|
|
7575
|
+
{
|
|
7576
|
+
className: "w-3 h-3 rounded-sm",
|
|
7577
|
+
style: {
|
|
7578
|
+
backgroundColor: finalColors[entry.dataKey] || entry.color
|
|
7579
|
+
}
|
|
7580
|
+
}
|
|
7581
|
+
),
|
|
7582
|
+
/* @__PURE__ */ jsxs37("span", { className: "text-muted-foreground", children: [
|
|
7583
|
+
entry.name,
|
|
7584
|
+
":"
|
|
7585
|
+
] }),
|
|
7586
|
+
/* @__PURE__ */ jsx57("span", { className: "text-foreground font-medium", children: entry.value?.toLocaleString("pt-BR") })
|
|
7587
|
+
] }, index)),
|
|
7588
|
+
/* @__PURE__ */ jsx57("p", { className: "text-xs text-muted-foreground mt-1", children: "Clique para fixar este tooltip" })
|
|
7589
|
+
] });
|
|
7590
|
+
};
|
|
7591
|
+
const getTitleClassName = () => {
|
|
7592
|
+
return "text-xl font-semibold text-foreground mb-3";
|
|
7593
|
+
};
|
|
7594
|
+
const finalEnableHighlights = enableHighlights;
|
|
7595
|
+
const finalEnableShowOnly = enableShowOnly;
|
|
7596
|
+
const finalEnablePeriodsDropdown = enablePeriodsDropdown && enableDraggableTooltips;
|
|
7597
|
+
const chartRightMargin = 30;
|
|
7598
|
+
const containerPaddingLeft = 16;
|
|
7599
|
+
const chartLeftMargin = 20;
|
|
7600
|
+
const measuredInner = measuredWidth ? Math.max(0, measuredWidth - 32) : void 0;
|
|
7601
|
+
const effectiveChartWidth = typeof width === "number" ? width : measuredInner ?? computedWidth;
|
|
7602
|
+
const chartInnerWidth = effectiveChartWidth - chartLeftMargin - chartRightMargin;
|
|
7603
|
+
return /* @__PURE__ */ jsx57(
|
|
7604
|
+
"div",
|
|
7605
|
+
{
|
|
7606
|
+
ref: wrapperRef,
|
|
7607
|
+
style: {
|
|
7608
|
+
width: "100%",
|
|
7609
|
+
overflowX: typeof width === "number" ? "auto" : "visible",
|
|
7610
|
+
overflowY: "hidden"
|
|
7611
|
+
},
|
|
7612
|
+
children: /* @__PURE__ */ jsxs37(
|
|
7613
|
+
"div",
|
|
7614
|
+
{
|
|
7615
|
+
className: cn("rounded-lg bg-card p-4 relative", className),
|
|
7616
|
+
style: typeof width === "number" ? { width: `${width + 32}px` } : { width: "100%", maxWidth: "100%" },
|
|
7617
|
+
children: [
|
|
7618
|
+
title && /* @__PURE__ */ jsx57(
|
|
7619
|
+
"div",
|
|
7620
|
+
{
|
|
7621
|
+
style: {
|
|
7622
|
+
paddingLeft: `${containerPaddingLeft + chartLeftMargin}px`,
|
|
7623
|
+
width: "100%",
|
|
7624
|
+
maxWidth: `${chartInnerWidth}px`,
|
|
7625
|
+
display: "flex",
|
|
7626
|
+
justifyContent: titlePosition === "center" ? "center" : titlePosition === "right" ? "flex-end" : "flex-start",
|
|
7627
|
+
alignItems: "center"
|
|
7628
|
+
},
|
|
7629
|
+
children: /* @__PURE__ */ jsx57("h3", { className: getTitleClassName(), children: title })
|
|
7630
|
+
}
|
|
7631
|
+
),
|
|
7632
|
+
allKeys.length > 0 && (finalEnableHighlights || finalEnableShowOnly) && /* @__PURE__ */ jsxs37(
|
|
7633
|
+
"div",
|
|
7634
|
+
{
|
|
7635
|
+
className: "flex items-center w-full",
|
|
7636
|
+
style: {
|
|
7637
|
+
paddingLeft: `${containerPaddingLeft + chartLeftMargin}px`,
|
|
7638
|
+
width: "98%",
|
|
7639
|
+
display: "flex",
|
|
7640
|
+
alignItems: "center",
|
|
7641
|
+
gap: "0.5rem"
|
|
7642
|
+
},
|
|
7643
|
+
children: [
|
|
7644
|
+
finalEnableHighlights && /* @__PURE__ */ jsx57(
|
|
7645
|
+
Highlights_default,
|
|
7646
|
+
{
|
|
7647
|
+
allKeys,
|
|
7648
|
+
mapperConfig,
|
|
7649
|
+
finalColors,
|
|
7650
|
+
highlightedSeries,
|
|
7651
|
+
toggleHighlight,
|
|
7652
|
+
containerWidth: chartInnerWidth
|
|
7653
|
+
}
|
|
7654
|
+
),
|
|
7655
|
+
finalEnableShowOnly && /* @__PURE__ */ jsx57(
|
|
7656
|
+
ShowOnly_default,
|
|
7657
|
+
{
|
|
7658
|
+
showOnlyHighlighted,
|
|
7659
|
+
setShowOnlyHighlighted,
|
|
7660
|
+
highlightedSeriesSize: highlightedSeries.size,
|
|
7661
|
+
clearHighlights: () => setHighlightedSeries(/* @__PURE__ */ new Set())
|
|
7662
|
+
}
|
|
7663
|
+
),
|
|
7664
|
+
finalEnablePeriodsDropdown && /* @__PURE__ */ jsx57(
|
|
7665
|
+
"div",
|
|
7666
|
+
{
|
|
7667
|
+
style: {
|
|
7668
|
+
marginLeft: "auto",
|
|
7669
|
+
display: "flex",
|
|
7670
|
+
alignItems: "center"
|
|
7671
|
+
},
|
|
7672
|
+
children: /* @__PURE__ */ jsx57(
|
|
7673
|
+
PeriodsDropdown_default,
|
|
7674
|
+
{
|
|
7675
|
+
processedData,
|
|
7676
|
+
onOpenPeriod: openTooltipForPeriod,
|
|
7677
|
+
rightOffset: chartRightMargin,
|
|
7678
|
+
activePeriods
|
|
7679
|
+
}
|
|
7680
|
+
)
|
|
7681
|
+
}
|
|
7682
|
+
)
|
|
7683
|
+
]
|
|
7684
|
+
}
|
|
7685
|
+
),
|
|
7686
|
+
!(allKeys.length > 0 && (finalEnableHighlights || finalEnableShowOnly)) && finalEnablePeriodsDropdown && /* @__PURE__ */ jsx57(
|
|
7687
|
+
"div",
|
|
7688
|
+
{
|
|
7689
|
+
style: {
|
|
7690
|
+
paddingLeft: `${containerPaddingLeft + chartLeftMargin}px`,
|
|
7691
|
+
paddingRight: `${chartRightMargin}px`,
|
|
7692
|
+
width: "100%",
|
|
7693
|
+
maxWidth: `${chartInnerWidth}px`,
|
|
7694
|
+
display: "flex",
|
|
7695
|
+
justifyContent: "flex-end"
|
|
7696
|
+
},
|
|
7697
|
+
children: /* @__PURE__ */ jsx57(
|
|
7698
|
+
PeriodsDropdown_default,
|
|
7699
|
+
{
|
|
7700
|
+
processedData,
|
|
7701
|
+
onOpenPeriod: openTooltipForPeriod,
|
|
7702
|
+
rightOffset: chartRightMargin
|
|
7703
|
+
}
|
|
7704
|
+
)
|
|
7705
|
+
}
|
|
7706
|
+
),
|
|
7707
|
+
/* @__PURE__ */ jsx57(ResponsiveContainer2, { width: "100%", height, children: /* @__PURE__ */ jsxs37(
|
|
7708
|
+
ComposedChart,
|
|
7709
|
+
{
|
|
7710
|
+
data: processedData,
|
|
7711
|
+
height,
|
|
7712
|
+
margin: {
|
|
7713
|
+
top: showLabels ? 48 : 20,
|
|
7714
|
+
right: 30,
|
|
7715
|
+
left: 20,
|
|
7716
|
+
bottom: 5
|
|
7717
|
+
},
|
|
7718
|
+
onClick: handleChartClick,
|
|
7719
|
+
children: [
|
|
7720
|
+
showGrid && /* @__PURE__ */ jsx57(
|
|
7721
|
+
CartesianGrid3,
|
|
7722
|
+
{
|
|
7723
|
+
strokeDasharray: "3 3",
|
|
7724
|
+
stroke: gridColor || "hsl(var(--muted-foreground))",
|
|
7725
|
+
opacity: 0.5
|
|
7726
|
+
}
|
|
7727
|
+
),
|
|
7728
|
+
/* @__PURE__ */ jsx57(
|
|
7729
|
+
XAxis3,
|
|
7730
|
+
{
|
|
7731
|
+
dataKey: xAxisConfig.dataKey,
|
|
7732
|
+
stroke: "hsl(var(--muted-foreground))",
|
|
7733
|
+
fontSize: 12,
|
|
7734
|
+
tickLine: false,
|
|
7735
|
+
axisLine: false,
|
|
7736
|
+
tickFormatter: xAxisConfig.formatter
|
|
7737
|
+
}
|
|
7738
|
+
),
|
|
7739
|
+
/* @__PURE__ */ jsx57(
|
|
7740
|
+
YAxis3,
|
|
7741
|
+
{
|
|
7742
|
+
stroke: "hsl(var(--muted-foreground))",
|
|
7743
|
+
fontSize: 12,
|
|
7744
|
+
tickLine: false,
|
|
7745
|
+
axisLine: false,
|
|
7746
|
+
tickFormatter: (value) => Number(value).toLocaleString("pt-BR"),
|
|
7747
|
+
domain: [0, niceMax],
|
|
7748
|
+
tickCount: 6
|
|
7749
|
+
}
|
|
7750
|
+
),
|
|
7751
|
+
showTooltip && /* @__PURE__ */ jsx57(
|
|
7752
|
+
Tooltip4,
|
|
7753
|
+
{
|
|
7754
|
+
content: /* @__PURE__ */ jsx57(CustomTooltip, {}),
|
|
7755
|
+
cursor: { fill: "hsl(var(--muted))", opacity: 0.1 }
|
|
7756
|
+
}
|
|
7757
|
+
),
|
|
7758
|
+
showLegend && /* @__PURE__ */ jsx57(
|
|
7759
|
+
Legend4,
|
|
7760
|
+
{
|
|
7761
|
+
wrapperStyle: {
|
|
7762
|
+
color: "hsl(var(--foreground))",
|
|
7763
|
+
fontSize: "14px"
|
|
7764
|
+
}
|
|
7765
|
+
}
|
|
7766
|
+
),
|
|
7767
|
+
seriesOrder.map((s) => {
|
|
7768
|
+
const key = s.key;
|
|
7769
|
+
if (showOnlyHighlighted && !highlightedSeries.has(key))
|
|
7770
|
+
return null;
|
|
7771
|
+
const label = mapperConfig[key]?.label ?? labelMap?.[key] ?? formatFieldName2(key);
|
|
7772
|
+
const color = finalColors[key];
|
|
7773
|
+
if (s.type === "bar") {
|
|
7774
|
+
return /* @__PURE__ */ jsx57(
|
|
7775
|
+
Bar2,
|
|
7776
|
+
{
|
|
7777
|
+
dataKey: key,
|
|
7778
|
+
name: label,
|
|
7779
|
+
fill: color,
|
|
7780
|
+
radius: [4, 4, 0, 0],
|
|
7781
|
+
onClick: handleBarClick,
|
|
7782
|
+
style: {
|
|
7783
|
+
cursor: "pointer",
|
|
7784
|
+
opacity: highlightedSeries.size > 0 ? highlightedSeries.has(key) ? 1 : 0.25 : 1
|
|
7785
|
+
},
|
|
7786
|
+
activeBar: /* @__PURE__ */ jsx57(
|
|
7787
|
+
Rectangle2,
|
|
7788
|
+
{
|
|
7789
|
+
fill: color,
|
|
7790
|
+
stroke: color,
|
|
7791
|
+
strokeWidth: 2,
|
|
7792
|
+
opacity: 0.8
|
|
7793
|
+
}
|
|
7794
|
+
),
|
|
7795
|
+
children: showLabels && highlightedSeries.size === 0 || highlightedSeries.has(key) ? /* @__PURE__ */ jsx57(
|
|
7796
|
+
LabelList3,
|
|
7797
|
+
{
|
|
7798
|
+
dataKey: key,
|
|
7799
|
+
position: "top",
|
|
7800
|
+
content: pillLabelRenderer_default(color, "filled"),
|
|
7801
|
+
offset: 8
|
|
7802
|
+
}
|
|
7803
|
+
) : null
|
|
7804
|
+
},
|
|
7805
|
+
`bar-${key}`
|
|
7806
|
+
);
|
|
7807
|
+
}
|
|
7808
|
+
if (s.type === "line") {
|
|
7809
|
+
return /* @__PURE__ */ jsx57(
|
|
7810
|
+
Line2,
|
|
7811
|
+
{
|
|
7812
|
+
dataKey: key,
|
|
7813
|
+
name: label,
|
|
7814
|
+
stroke: color,
|
|
7815
|
+
strokeWidth: 2,
|
|
7816
|
+
dot: { r: 3 },
|
|
7817
|
+
activeDot: { r: 6 },
|
|
7818
|
+
onClick: handleSeriesClick,
|
|
7819
|
+
style: {
|
|
7820
|
+
cursor: "pointer",
|
|
7821
|
+
pointerEvents: "all",
|
|
7822
|
+
opacity: highlightedSeries.size > 0 ? highlightedSeries.has(key) ? 1 : 0.25 : 1
|
|
7823
|
+
},
|
|
7824
|
+
children: showLabels && highlightedSeries.size === 0 || highlightedSeries.has(key) ? /* @__PURE__ */ jsx57(
|
|
7825
|
+
LabelList3,
|
|
7826
|
+
{
|
|
7827
|
+
dataKey: key,
|
|
7828
|
+
position: "top",
|
|
7829
|
+
content: pillLabelRenderer_default(color, "filled"),
|
|
7830
|
+
offset: 14
|
|
7831
|
+
}
|
|
7832
|
+
) : null
|
|
7833
|
+
},
|
|
7834
|
+
`line-${key}`
|
|
7835
|
+
);
|
|
7836
|
+
}
|
|
7837
|
+
if (s.type === "area") {
|
|
7838
|
+
return /* @__PURE__ */ jsx57(
|
|
7839
|
+
Area,
|
|
7840
|
+
{
|
|
7841
|
+
dataKey: key,
|
|
7842
|
+
name: label,
|
|
7843
|
+
stroke: color,
|
|
7844
|
+
fill: color,
|
|
7845
|
+
fillOpacity: 0.15,
|
|
7846
|
+
onClick: handleSeriesClick,
|
|
7847
|
+
style: {
|
|
7848
|
+
cursor: "pointer",
|
|
7849
|
+
pointerEvents: "all",
|
|
7850
|
+
opacity: highlightedSeries.size > 0 ? highlightedSeries.has(key) ? 1 : 0.25 : 1
|
|
7851
|
+
},
|
|
7852
|
+
children: showLabels && highlightedSeries.size === 0 || highlightedSeries.has(key) ? /* @__PURE__ */ jsx57(
|
|
7853
|
+
LabelList3,
|
|
7854
|
+
{
|
|
7855
|
+
dataKey: key,
|
|
7856
|
+
position: "top",
|
|
7857
|
+
content: pillLabelRenderer_default(color, "soft"),
|
|
7858
|
+
offset: 12
|
|
7859
|
+
}
|
|
7860
|
+
) : null
|
|
7861
|
+
},
|
|
7862
|
+
`area-${key}`
|
|
7863
|
+
);
|
|
7864
|
+
}
|
|
7865
|
+
return null;
|
|
7866
|
+
})
|
|
7867
|
+
]
|
|
7868
|
+
}
|
|
7869
|
+
) }),
|
|
7870
|
+
enableDraggableTooltips && activeTooltips.map((tooltip) => /* @__PURE__ */ jsx57(
|
|
7871
|
+
DraggableTooltip_default,
|
|
7872
|
+
{
|
|
7873
|
+
id: tooltip.id,
|
|
7874
|
+
data: adaptDataForTooltip(tooltip.data),
|
|
7875
|
+
position: tooltip.position,
|
|
7876
|
+
title,
|
|
7877
|
+
dataKeys: allKeys,
|
|
7878
|
+
finalColors,
|
|
7879
|
+
onClose: (id) => setActiveTooltips((prev) => prev.filter((t) => t.id !== id)),
|
|
7880
|
+
onPositionChange: onTooltipPositionChange,
|
|
7881
|
+
periodLabel: "Per\xEDodo Selecionado",
|
|
7882
|
+
dataLabel: "Dados do Per\xEDodo",
|
|
7883
|
+
globalTooltipCount: activeTooltips.length,
|
|
7884
|
+
onCloseAll: () => window.dispatchEvent(new Event("closeAllTooltips")),
|
|
7885
|
+
closeAllButtonPosition: "top-center",
|
|
7886
|
+
closeAllButtonVariant: "floating"
|
|
7887
|
+
},
|
|
7888
|
+
tooltip.id
|
|
7889
|
+
)),
|
|
7890
|
+
enableDraggableTooltips && activeTooltips.length > 1 && /* @__PURE__ */ jsx57(
|
|
7891
|
+
CloseAllButton_default,
|
|
7892
|
+
{
|
|
7893
|
+
count: activeTooltips.length,
|
|
7894
|
+
onCloseAll: () => window.dispatchEvent(new Event("closeAllTooltips")),
|
|
7895
|
+
position: "top-center",
|
|
7896
|
+
variant: "floating"
|
|
7897
|
+
}
|
|
7898
|
+
)
|
|
7899
|
+
]
|
|
7900
|
+
}
|
|
7901
|
+
)
|
|
7902
|
+
}
|
|
7903
|
+
);
|
|
7904
|
+
};
|
|
7905
|
+
var Chart_default = Chart;
|
|
7906
|
+
|
|
7907
|
+
// src/hooks/use-drag.tsx
|
|
7908
|
+
import { useState as useState14, useCallback as useCallback10, useRef as useRef5, useEffect as useEffect12 } from "react";
|
|
7909
|
+
var useDrag = (options = {}) => {
|
|
7910
|
+
const [isDragging, setIsDragging] = useState14(null);
|
|
7911
|
+
const [positions, setPositions] = useState14({});
|
|
7912
|
+
const dragStartPos = useRef5(null);
|
|
7913
|
+
const dragId = useRef5(null);
|
|
7914
|
+
const handleMouseDown = useCallback10((id, e) => {
|
|
7915
|
+
e.preventDefault();
|
|
7916
|
+
const currentPosition = positions[id] || { top: 0, left: 0 };
|
|
7917
|
+
dragStartPos.current = {
|
|
7918
|
+
x: e.clientX,
|
|
7919
|
+
y: e.clientY,
|
|
7920
|
+
elementX: currentPosition.left,
|
|
7921
|
+
elementY: currentPosition.top
|
|
7922
|
+
};
|
|
7923
|
+
dragId.current = id;
|
|
7924
|
+
setIsDragging(id);
|
|
7925
|
+
options.onDragStart?.(id);
|
|
7926
|
+
}, [positions, options]);
|
|
7927
|
+
const handleMouseMove = useCallback10((e) => {
|
|
7928
|
+
if (!isDragging || !dragStartPos.current || !dragId.current) return;
|
|
7929
|
+
const deltaX = e.clientX - dragStartPos.current.x;
|
|
7930
|
+
const deltaY = e.clientY - dragStartPos.current.y;
|
|
7931
|
+
const newPosition = {
|
|
7932
|
+
left: dragStartPos.current.elementX + deltaX,
|
|
7933
|
+
top: dragStartPos.current.elementY + deltaY
|
|
7934
|
+
};
|
|
7935
|
+
newPosition.left = Math.max(0, Math.min(window.innerWidth - 300, newPosition.left));
|
|
7936
|
+
newPosition.top = Math.max(0, Math.min(window.innerHeight - 200, newPosition.top));
|
|
7937
|
+
setPositions((prev) => ({
|
|
7938
|
+
...prev,
|
|
7939
|
+
[dragId.current]: newPosition
|
|
7940
|
+
}));
|
|
7941
|
+
options.onDrag?.(dragId.current, newPosition);
|
|
7942
|
+
}, [isDragging, options]);
|
|
7943
|
+
const handleMouseUp = useCallback10(() => {
|
|
7944
|
+
if (dragId.current) {
|
|
7945
|
+
options.onDragEnd?.(dragId.current);
|
|
7946
|
+
}
|
|
7947
|
+
setIsDragging(null);
|
|
7948
|
+
dragStartPos.current = null;
|
|
7949
|
+
dragId.current = null;
|
|
7950
|
+
}, [options]);
|
|
7951
|
+
useEffect12(() => {
|
|
7952
|
+
if (isDragging) {
|
|
7953
|
+
document.addEventListener("mousemove", handleMouseMove);
|
|
7954
|
+
document.addEventListener("mouseup", handleMouseUp);
|
|
7955
|
+
document.body.style.userSelect = "none";
|
|
7956
|
+
return () => {
|
|
7957
|
+
document.removeEventListener("mousemove", handleMouseMove);
|
|
7958
|
+
document.removeEventListener("mouseup", handleMouseUp);
|
|
7959
|
+
document.body.style.userSelect = "";
|
|
7960
|
+
};
|
|
7961
|
+
}
|
|
7962
|
+
}, [isDragging, handleMouseMove, handleMouseUp]);
|
|
7963
|
+
const setPosition = useCallback10((id, position) => {
|
|
7964
|
+
setPositions((prev) => ({
|
|
7965
|
+
...prev,
|
|
7966
|
+
[id]: position
|
|
7967
|
+
}));
|
|
7968
|
+
}, []);
|
|
7969
|
+
const getPosition = useCallback10((id) => {
|
|
7970
|
+
return positions[id] || { top: 0, left: 0 };
|
|
7971
|
+
}, [positions]);
|
|
7972
|
+
const isElementDragging = useCallback10((id) => {
|
|
7973
|
+
return isDragging === id;
|
|
7974
|
+
}, [isDragging]);
|
|
7975
|
+
return {
|
|
7976
|
+
handleMouseDown,
|
|
7977
|
+
getPosition,
|
|
7978
|
+
setPosition,
|
|
7979
|
+
isElementDragging,
|
|
7980
|
+
isDragging: isDragging !== null
|
|
7981
|
+
};
|
|
7982
|
+
};
|
|
4846
7983
|
export {
|
|
4847
7984
|
AlertDialogActionBase,
|
|
4848
7985
|
AlertDialogBase,
|
|
@@ -4859,6 +7996,7 @@ export {
|
|
|
4859
7996
|
AvatarFallbackBase,
|
|
4860
7997
|
AvatarImageBase,
|
|
4861
7998
|
BadgeBase,
|
|
7999
|
+
BarChart_default as BarChart,
|
|
4862
8000
|
BreadcrumbBase,
|
|
4863
8001
|
BreadcrumbEllipsisBase,
|
|
4864
8002
|
BreadcrumbItemBase,
|
|
@@ -4880,6 +8018,7 @@ export {
|
|
|
4880
8018
|
CarouselItemBase,
|
|
4881
8019
|
CarouselNextBase,
|
|
4882
8020
|
CarouselPrevious,
|
|
8021
|
+
Chart_default as Chart,
|
|
4883
8022
|
CheckboxBase,
|
|
4884
8023
|
CollapsibleBase,
|
|
4885
8024
|
CollapsibleContentBase,
|
|
@@ -4955,6 +8094,7 @@ export {
|
|
|
4955
8094
|
InputOTPSeparatorBase,
|
|
4956
8095
|
InputOTPSlotBase,
|
|
4957
8096
|
LabelBase_default as LabelBase,
|
|
8097
|
+
LineChart_default as LineChart,
|
|
4958
8098
|
ModeToggleBase,
|
|
4959
8099
|
MultiCombobox,
|
|
4960
8100
|
NavigationMenuBase,
|
|
@@ -4965,6 +8105,7 @@ export {
|
|
|
4965
8105
|
NavigationMenuListBase,
|
|
4966
8106
|
NavigationMenuTriggerBase,
|
|
4967
8107
|
NavigationMenuViewportBase,
|
|
8108
|
+
PieChart_default as PieChart,
|
|
4968
8109
|
PopoverAnchorBase,
|
|
4969
8110
|
PopoverBase,
|
|
4970
8111
|
PopoverContentBase,
|
|
@@ -5048,6 +8189,7 @@ export {
|
|
|
5048
8189
|
badgeVariants,
|
|
5049
8190
|
buttonVariantsBase,
|
|
5050
8191
|
toast,
|
|
8192
|
+
useDrag,
|
|
5051
8193
|
useIsMobile,
|
|
5052
8194
|
useTheme
|
|
5053
8195
|
};
|