UNPKG

analytica-frontend-lib

Version:

Repositório público dos componentes utilizados nas plataformas da Analytica Ensino

303 lines (301 loc) 8.82 kB
import { bgClassToCssVar, describeArc, polarToCartesian } from "./chunk-REYQHCVW.mjs"; import { Text_default } from "./chunk-IMCIR6TJ.mjs"; import { cn } from "./chunk-53ICLDGS.mjs"; // src/components/shared/ChartComponents.tsx import { useState } from "react"; import { jsx, jsxs } from "react/jsx-runtime"; var calculateYAxisTicks = (maxValue) => { if (maxValue <= 0) return [0]; const niceMax = Math.ceil(maxValue / 10) * 10; const step = niceMax / 4; return [ niceMax, Math.round(step * 3), Math.round(step * 2), Math.round(step), 0 ]; }; var LegendItem = ({ color, label }) => /* @__PURE__ */ jsxs("div", { className: "flex flex-row items-center gap-2", children: [ /* @__PURE__ */ jsx("div", { className: cn("w-2 h-2 rounded-full", color) }), /* @__PURE__ */ jsx(Text_default, { size: "xs", weight: "medium", className: "text-text-600", children: label }) ] }); var DataBar = ({ label, value, maxValue, colorClass, chartHeight }) => { const percentage = maxValue === 0 ? 0 : value / maxValue * 100; const barHeight = percentage / 100 * chartHeight; return /* @__PURE__ */ jsxs("div", { className: "flex flex-col items-center gap-2 flex-1", children: [ /* @__PURE__ */ jsx( "div", { className: "w-full flex items-end justify-center", style: { height: chartHeight }, children: /* @__PURE__ */ jsx( "div", { className: cn( "w-16 rounded-lg transition-all duration-300", colorClass ), style: { height: `${barHeight}px` } } ) } ), /* @__PURE__ */ jsx(Text_default, { size: "xs", weight: "medium", className: "text-text-600 text-center", children: label }) ] }); }; var GridLines = ({ ticks, chartHeight }) => /* @__PURE__ */ jsx( "div", { className: "absolute inset-0 flex flex-col justify-between pointer-events-none", style: { height: chartHeight }, children: ticks.map((tick, index) => /* @__PURE__ */ jsx( "div", { className: "w-full border-t border-dashed border-border-200", style: { marginTop: index === 0 ? 0 : void 0 } }, `${tick}-${index}` )) } ); var YAxis = ({ ticks, chartHeight }) => /* @__PURE__ */ jsx( "div", { className: "flex flex-col justify-between items-end pr-3", style: { height: chartHeight }, "aria-hidden": "true", children: ticks.map((tick, index) => /* @__PURE__ */ jsx( Text_default, { size: "xs", weight: "medium", className: "text-text-500", children: tick }, `${tick}-${index}` )) } ); var PIE_RADIUS_RATIO = 0.44; var PIE_LABEL_RADIUS_RATIO = 0.62; var PIE_MIN_PERCENTAGE_FOR_LABEL = 5; var PIE_WHOLE_THRESHOLD = 99.9999; var SimplePieChart = ({ slices, size = 130, emptyText, minPercentageForLabel = PIE_MIN_PERCENTAGE_FOR_LABEL, labelRadiusRatio = PIE_LABEL_RADIUS_RATIO, labelColor = "var(--color-text-950)", labelFontWeight = 500, labelTextShadow, hoverOpacity = 0.4, hoveredSlice: externalHovered, onSliceHover }) => { const [internalHovered, setInternalHovered] = useState(null); const isControlled = externalHovered !== void 0; const hovered = isControlled ? externalHovered : internalHovered; const handleSliceHover = (label) => { if (!isControlled) { setInternalHovered(label); } onSliceHover?.(label); }; const total = slices.reduce((sum, s) => sum + s.value, 0); const radius = size * PIE_RADIUS_RATIO; const center = size / 2; if (total === 0) { return /* @__PURE__ */ jsxs( "svg", { width: size, height: size, viewBox: `0 0 ${size} ${size}`, "aria-hidden": !emptyText, "aria-label": emptyText || void 0, children: [ /* @__PURE__ */ jsx( "circle", { cx: center, cy: center, r: radius, className: "fill-background-200" } ), emptyText && /* @__PURE__ */ jsx( "text", { x: center, y: center, textAnchor: "middle", dominantBaseline: "central", fill: "var(--color-text-400)", style: { fontSize: 12, fontWeight: 500, fontFamily: "Roboto, sans-serif" }, children: emptyText } ) ] } ); } let cumAngle = 0; const computed = slices.map((s) => { const pct = s.value / total * 100; const startAngle = cumAngle; cumAngle += pct / 100 * 360; const endAngle = cumAngle; const midAngle = startAngle + (endAngle - startAngle) / 2; return { ...s, pct, startAngle, endAngle, midAngle }; }).filter((s) => s.pct > 0); return /* @__PURE__ */ jsx( "svg", { width: size, height: size, viewBox: `0 0 ${size} ${size}`, "aria-hidden": "true", onMouseLeave: () => handleSliceHover(null), children: computed.map((slice) => { const sliceKey = slice.key ?? slice.label; const isHovered = hovered === sliceKey; const isWhole = slice.pct >= PIE_WHOLE_THRESHOLD; const arcPath = isWhole ? void 0 : describeArc( center, center, radius, slice.startAngle, slice.endAngle ); const labelPos = polarToCartesian( center, center, radius * labelRadiusRatio, slice.midAngle ); const fill = slice.color ?? bgClassToCssVar(slice.colorClass); return /* @__PURE__ */ jsxs( "g", { onMouseEnter: () => handleSliceHover(sliceKey), className: "cursor-pointer", children: [ isWhole ? /* @__PURE__ */ jsx("circle", { cx: center, cy: center, r: radius, fill }) : /* @__PURE__ */ jsx("path", { d: arcPath, fill }), isHovered && (isWhole ? /* @__PURE__ */ jsx( "circle", { cx: center, cy: center, r: radius, fill: "white", opacity: hoverOpacity, style: { pointerEvents: "none" } } ) : /* @__PURE__ */ jsx( "path", { d: arcPath, fill: "white", opacity: hoverOpacity, style: { pointerEvents: "none" } } )), slice.pct >= minPercentageForLabel && /* @__PURE__ */ jsx( "text", { x: labelPos.x, y: labelPos.y, textAnchor: "middle", dominantBaseline: "central", fill: labelColor, style: { fontSize: 14, fontWeight: labelFontWeight, fontFamily: "Roboto, sans-serif", lineHeight: 1, letterSpacing: 0, pointerEvents: "none", textShadow: labelTextShadow }, children: `${Math.round(slice.pct)}%` } ) ] }, sliceKey ); }) } ); }; var LegendRow = ({ colorClass, color, label, value, displayValue }) => /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [ /* @__PURE__ */ jsx( "div", { className: cn("w-2 h-2 rounded-full shrink-0", !color && colorClass), style: color ? { backgroundColor: color } : void 0 } ), /* @__PURE__ */ jsx(Text_default, { size: "sm", weight: "medium", className: "text-text-950 flex-1", children: label }), /* @__PURE__ */ jsx(Text_default, { size: "sm", weight: "medium", className: "text-text-600 ml-3", children: displayValue ?? value }) ] }); var LegendPieCard = ({ slices }) => /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between gap-4 p-4 bg-background border border-border-50 rounded-xl", children: [ /* @__PURE__ */ jsx("div", { className: "flex flex-col gap-2", children: slices.map((s) => /* @__PURE__ */ jsx( LegendRow, { colorClass: s.colorClass, color: s.color, label: s.label, value: s.value, displayValue: s.displayValue }, s.key ?? s.label )) }), /* @__PURE__ */ jsx(SimplePieChart, { slices }) ] }); export { calculateYAxisTicks, LegendItem, DataBar, GridLines, YAxis, SimplePieChart, LegendRow, LegendPieCard }; //# sourceMappingURL=chunk-Y4MZ2KAU.mjs.map