@apipass/design-system 6.1.0 → 6.2.0
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/lib/charts.index.cjs +1 -1
- package/dist/lib/charts.index.js +7 -5
- package/dist/lib/charts.index.js.map +1 -1
- package/dist/lib/embedded-styles.js +2 -2
- package/dist/lib/style.css +1 -1
- package/dist/lib/ui/components/charts/PieChart/PieChart.cjs +1 -1
- package/dist/lib/ui/components/charts/PieChart/PieChart.cjs.map +1 -1
- package/dist/lib/ui/components/charts/PieChart/PieChart.js +39 -38
- package/dist/lib/ui/components/charts/PieChart/PieChart.js.map +1 -1
- package/dist/lib/ui/components/charts/PieChart/pie-chart-option.cjs +1 -1
- package/dist/lib/ui/components/charts/PieChart/pie-chart-option.cjs.map +1 -1
- package/dist/lib/ui/components/charts/PieChart/pie-chart-option.js +65 -71
- package/dist/lib/ui/components/charts/PieChart/pie-chart-option.js.map +1 -1
- package/dist/lib/ui/components/charts/TopList/TopList.cjs +2 -0
- package/dist/lib/ui/components/charts/TopList/TopList.cjs.map +1 -0
- package/dist/lib/ui/components/charts/TopList/TopList.js +79 -0
- package/dist/lib/ui/components/charts/TopList/TopList.js.map +1 -0
- package/dist/lib/ui/components/charts/TopList/top-list-option.cjs +2 -0
- package/dist/lib/ui/components/charts/TopList/top-list-option.cjs.map +1 -0
- package/dist/lib/ui/components/charts/TopList/top-list-option.js +178 -0
- package/dist/lib/ui/components/charts/TopList/top-list-option.js.map +1 -0
- package/dist/lib/ui/components/charts/chart-share.cjs +2 -0
- package/dist/lib/ui/components/charts/chart-share.cjs.map +1 -0
- package/dist/lib/ui/components/charts/chart-share.js +11 -0
- package/dist/lib/ui/components/charts/chart-share.js.map +1 -0
- package/dist/types/charts.index.d.ts +1 -0
- package/dist/types/ui/components/charts/PieChart/pie-chart-option.d.ts +0 -1
- package/dist/types/ui/components/charts/TopList/TopList.d.ts +13 -0
- package/dist/types/ui/components/charts/TopList/top-list-option.d.ts +24 -0
- package/dist/types/ui/components/charts/chart-share.d.ts +1 -0
- package/package.json +1 -1
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const n=require("react/jsx-runtime"),ee=require("../../../../vendor/clsx/dist/clsx.cjs"),i=require("react"),te=require("../ChartLegend/ChartLegend.cjs"),re=require("../ChartLegend/use-chart-legend.cjs"),ne=require("../chart-palette.cjs"),ie=require("../useChartInstance.cjs"),
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const n=require("react/jsx-runtime"),ee=require("../../../../vendor/clsx/dist/clsx.cjs"),i=require("react"),te=require("../ChartLegend/ChartLegend.cjs"),re=require("../ChartLegend/use-chart-legend.cjs"),ne=require("../chart-palette.cjs"),I=require("../chart-share.cjs"),ie=require("../useChartInstance.cjs"),se=require("./pie-chart-option.cjs"),h=require("./pie-chart-slices.cjs");;/* empty css */const ce={others:"Others",total:"Total",backToPrevious:e=>`Back from ${e}`},oe=200,ae=["percent"],le=[];function ue(e,s,a){if(!e||s.length===0)return;const l=s.includes("percent"),S=s.includes("value");return l&&S?`${a(e.value)} (${I.formatShare(e.share)})`:S?a(e.value):I.formatShare(e.share)}function de(e){const[s,a]=i.useState(0);return i.useLayoutEffect(()=>{if(!e)return;const l=new ResizeObserver(()=>a(Math.min(e.clientWidth,e.clientHeight)));return l.observe(e),()=>l.disconnect()},[e]),s}function he({data:e,shape:s="donut",labelContent:a=ae,showTotal:l="auto",total:S,valueFormatter:p,legend:q="inline",legendPosition:y="bottom",legendValues:M=le,onSeriesColorChange:A,onFocusChange:b,legendLabels:R,labels:B,className:$,...D}){const{containerRef:U,chart:u,theme:c,resolveSeriesColor:H}=ie.useChartInstance(),o={...ce,...B},[f,V]=i.useState(null),[w,z]=i.useState(null),G=de(w),K=i.useMemo(()=>e.map(t=>({id:t.id,name:h.displayNameOf(t,o.others),colorToken:t.colorToken??(t.isOthers?ne.CHART_NEUTRAL_COLOR_TOKEN:void 0)})),[e,o.others]),{items:W,colorsBySeriesId:L,colorTokensBySeriesId:X,hiddenSeriesIds:O,toggleSeries:Z}=re.useChartLegend(K,(c==null?void 0:c.seriesColors)??[],H),d=i.useMemo(()=>h.buildPieSlices({nodes:e.filter(t=>!O.has(t.id)),colorsByRootId:L,fallbackColor:(c==null?void 0:c.neutralColor)??"#9ca3af",othersName:o.others}),[e,O,L,c,o.others]),r=i.useMemo(()=>f===null?void 0:h.findSlice(d,f),[d,f]),m=r?r.children:d,_=i.useCallback(t=>{V(t),b==null||b(t)},[b]);i.useEffect(()=>{f!==null&&!r&&_(null)},[f,r,_]),i.useEffect(()=>{!u||!c||u.setOption(se.buildPieChartOption({slices:m,shape:s,labelContent:a,theme:c,valueFormatter:p}),{notMerge:!0})},[u,c,m,s,a,p]),i.useEffect(()=>{if(!u)return;function t(C){var P;const x=(P=C.data)==null?void 0:P.id;if(typeof x!="string")return;const T=h.findSlice(m,x);T&&T.children.length>0&&_(T.id)}return u.on("click",t),()=>{u.off("click",t)}},[u,m,_]);function v(t){return p?p(t):String(t)}const J=W.map(t=>({...t,detail:ue(d.find(C=>C.id===t.id),M,v)})),g=l==="on"||l==="auto"&&G>=oe,N=r?r.value:S??h.totalOf(d),k=r?h.findParentSlice(d,r.id):void 0,Q=q!=="none"&&e.length>0,E=n.jsxs(n.Fragment,{children:[n.jsx("span",{className:"pie-chart__total-value",children:v(N)}),n.jsx("span",{className:"pie-chart__total-caption",children:r?r.name:o.total})]});function j(){_(k?k.id:null)}function Y(){return r?n.jsx("button",{type:"button",className:"pie-chart__center pie-chart__center--button","aria-label":o.backToPrevious(r.name),onClick:j,children:g&&E}):g&&n.jsx("div",{className:"pie-chart__center",children:E})}function F(){return r?n.jsxs("button",{type:"button",className:"pie-chart__footer pie-chart__footer--button","aria-label":o.backToPrevious(r.name),onClick:j,children:[r.name,g&&`: ${v(N)}`]}):g&&n.jsx("div",{className:"pie-chart__footer",children:`${o.total}: ${v(N)}`})}return n.jsxs("div",{className:ee.clsx("pie-chart",`pie-chart--legend-${y}`,$),...D,children:[Q&&n.jsx(te.ChartLegend,{className:"pie-chart__legend",items:J,onToggle:Z,onColorChange:A,colorTokensBySeriesId:X,labels:R}),n.jsxs("div",{className:"pie-chart__body",children:[n.jsxs("div",{ref:z,className:"pie-chart__stage",children:[n.jsx("div",{ref:U,className:"pie-chart__canvas"}),s==="donut"&&Y()]}),s==="pie"&&F()]})]})}exports.PieChart=he;
|
|
2
2
|
//# sourceMappingURL=PieChart.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PieChart.cjs","sources":["../../../../../../src/ui/components/charts/PieChart/PieChart.tsx"],"sourcesContent":["import clsx from \"clsx\";\nimport {\n type ComponentPropsWithoutRef,\n useCallback,\n useEffect,\n useLayoutEffect,\n useMemo,\n useState,\n} from \"react\";\nimport {\n ChartLegend,\n type ChartLegendItem,\n type ChartLegendLabels,\n} from \"../ChartLegend/ChartLegend\";\nimport {\n useChartLegend,\n type ChartLegendSeries,\n type ChartLegendState,\n} from \"../ChartLegend/use-chart-legend\";\nimport { CHART_NEUTRAL_COLOR_TOKEN } from \"../chart-palette\";\nimport { useChartInstance, type ChartInstance } from \"../useChartInstance\";\nimport {\n buildPieChartOption,\n formatShare,\n type PieChartLabelContent,\n type PieChartShape,\n} from \"./pie-chart-option\";\nimport {\n buildPieSlices,\n displayNameOf,\n findParentSlice,\n findSlice,\n totalOf,\n type PieChartNode,\n type PieSlice,\n} from \"./pie-chart-slices\";\nimport \"./pie-chart.css\";\n\nexport type { PieChartNode } from \"./pie-chart-slices\";\nexport type { PieChartLabelContent, PieChartShape } from \"./pie-chart-option\";\n\nexport type PieChartLegendMode = \"inline\" | \"none\";\n\nexport type PieChartLegendPosition = \"bottom\" | \"right\" | \"top\" | \"left\";\n\nexport type PieChartLegendValue = \"percent\" | \"value\";\n\nexport type PieChartShowTotal = \"auto\" | \"on\" | \"off\";\n\nexport interface PieChartLabels {\n others: string;\n total: string;\n backToPrevious: (categoryName: string) => string;\n}\n\nconst DEFAULT_LABELS: PieChartLabels = {\n others: \"Others\",\n total: \"Total\",\n backToPrevious: (categoryName: string) => `Back from ${categoryName}`,\n};\n\nconst MIN_SIZE_FOR_AUTO_TOTAL_PX: number = 200;\n\nconst DEFAULT_LABEL_CONTENT: PieChartLabelContent[] = [\"percent\"];\n\nconst NO_LEGEND_VALUES: PieChartLegendValue[] = [];\n\nexport type PieChartProps = Omit<ComponentPropsWithoutRef<\"div\">, \"children\"> & {\n data: PieChartNode[];\n shape?: PieChartShape;\n labelContent?: PieChartLabelContent[];\n showTotal?: PieChartShowTotal;\n total?: number;\n valueFormatter?: (value: number) => string;\n legend?: PieChartLegendMode;\n legendPosition?: PieChartLegendPosition;\n legendValues?: PieChartLegendValue[];\n onSeriesColorChange?: (seriesId: string, colorToken: string | null) => void;\n onFocusChange?: (focusedNodeId: string | null) => void;\n legendLabels?: Partial<ChartLegendLabels>;\n labels?: Partial<PieChartLabels>;\n};\n\nfunction legendDetail(\n slice: PieSlice | undefined,\n legendValues: PieChartLegendValue[],\n formatValue: (value: number) => string,\n): string | undefined {\n if (!slice || legendValues.length === 0) return undefined;\n const hasPercent: boolean = legendValues.includes(\"percent\");\n const hasValue: boolean = legendValues.includes(\"value\");\n if (hasPercent && hasValue) return `${formatValue(slice.value)} (${formatShare(slice.share)})`;\n return hasValue ? formatValue(slice.value) : formatShare(slice.share);\n}\n\nfunction useMinSide(element: HTMLElement | null): number {\n const [minSide, setMinSide] = useState<number>(0);\n\n useLayoutEffect(() => {\n if (!element) return undefined;\n const observer: ResizeObserver = new ResizeObserver(() =>\n setMinSide(Math.min(element.clientWidth, element.clientHeight)),\n );\n observer.observe(element);\n return () => observer.disconnect();\n }, [element]);\n\n return minSide;\n}\n\nexport function PieChart({\n data,\n shape = \"donut\",\n labelContent = DEFAULT_LABEL_CONTENT,\n showTotal = \"auto\",\n total,\n valueFormatter,\n legend = \"inline\",\n legendPosition = \"bottom\",\n legendValues = NO_LEGEND_VALUES,\n onSeriesColorChange,\n onFocusChange,\n legendLabels,\n labels,\n className,\n ...props\n}: PieChartProps) {\n const { containerRef, chart, theme, resolveSeriesColor }: ChartInstance = useChartInstance();\n const resolvedLabels: PieChartLabels = { ...DEFAULT_LABELS, ...labels };\n const [focusedNodeId, setFocusedNodeId] = useState<string | null>(null);\n const [stageElement, setStageElement] = useState<HTMLDivElement | null>(null);\n const stageMinSide: number = useMinSide(stageElement);\n\n const legendSeries: ChartLegendSeries[] = useMemo(\n () =>\n data.map((node: PieChartNode) => ({\n id: node.id,\n name: displayNameOf(node, resolvedLabels.others),\n colorToken: node.colorToken ?? (node.isOthers ? CHART_NEUTRAL_COLOR_TOKEN : undefined),\n })),\n [data, resolvedLabels.others],\n );\n\n const {\n items,\n colorsBySeriesId,\n colorTokensBySeriesId,\n hiddenSeriesIds,\n toggleSeries,\n }: ChartLegendState = useChartLegend(\n legendSeries,\n theme?.seriesColors ?? [],\n resolveSeriesColor,\n );\n\n const visibleSlices: PieSlice[] = useMemo(\n () =>\n buildPieSlices({\n nodes: data.filter((node: PieChartNode) => !hiddenSeriesIds.has(node.id)),\n colorsByRootId: colorsBySeriesId,\n fallbackColor: theme?.neutralColor ?? \"#9ca3af\",\n othersName: resolvedLabels.others,\n }),\n [data, hiddenSeriesIds, colorsBySeriesId, theme, resolvedLabels.others],\n );\n\n const focusedSlice: PieSlice | undefined = useMemo(\n () => (focusedNodeId === null ? undefined : findSlice(visibleSlices, focusedNodeId)),\n [visibleSlices, focusedNodeId],\n );\n\n const drawnSlices: PieSlice[] = focusedSlice ? focusedSlice.children : visibleSlices;\n\n const updateFocus = useCallback(\n (nextFocusedNodeId: string | null): void => {\n setFocusedNodeId(nextFocusedNodeId);\n onFocusChange?.(nextFocusedNodeId);\n },\n [onFocusChange],\n );\n\n useEffect(() => {\n if (focusedNodeId !== null && !focusedSlice) updateFocus(null);\n }, [focusedNodeId, focusedSlice, updateFocus]);\n\n useEffect(() => {\n if (!chart || !theme) return;\n chart.setOption(\n buildPieChartOption({ slices: drawnSlices, shape, labelContent, theme, valueFormatter }),\n { notMerge: true },\n );\n }, [chart, theme, drawnSlices, shape, labelContent, valueFormatter]);\n\n useEffect(() => {\n if (!chart) return undefined;\n\n function drillIntoClickedSlice(params: { data?: unknown }): void {\n const clickedId: unknown = (params.data as { id?: unknown } | null | undefined)?.id;\n if (typeof clickedId !== \"string\") return;\n const clickedSlice: PieSlice | undefined = findSlice(drawnSlices, clickedId);\n if (clickedSlice && clickedSlice.children.length > 0) updateFocus(clickedSlice.id);\n }\n\n chart.on(\"click\", drillIntoClickedSlice);\n return () => {\n chart.off(\"click\", drillIntoClickedSlice);\n };\n }, [chart, drawnSlices, updateFocus]);\n\n function formatValue(value: number): string {\n return valueFormatter ? valueFormatter(value) : String(value);\n }\n\n const legendItems: ChartLegendItem[] = items.map((item: ChartLegendItem) => ({\n ...item,\n detail: legendDetail(\n visibleSlices.find((slice: PieSlice) => slice.id === item.id),\n legendValues,\n formatValue,\n ),\n }));\n\n const isTotalVisible: boolean =\n showTotal === \"on\" || (showTotal === \"auto\" && stageMinSide >= MIN_SIZE_FOR_AUTO_TOTAL_PX);\n const centerTotal: number = focusedSlice ? focusedSlice.value : (total ?? totalOf(visibleSlices));\n const parentOfFocusedSlice: PieSlice | undefined = focusedSlice\n ? findParentSlice(visibleSlices, focusedSlice.id)\n : undefined;\n const isLegendVisible: boolean = legend !== \"none\" && data.length > 0;\n\n const centerContent = (\n <>\n <span className=\"pie-chart__total-value\">{formatValue(centerTotal)}</span>\n <span className=\"pie-chart__total-caption\">\n {focusedSlice ? focusedSlice.name : resolvedLabels.total}\n </span>\n </>\n );\n\n function goBack(): void {\n updateFocus(parentOfFocusedSlice ? parentOfFocusedSlice.id : null);\n }\n\n function renderDonutCenter() {\n if (focusedSlice) {\n return (\n <button\n type=\"button\"\n className=\"pie-chart__center pie-chart__center--button\"\n aria-label={resolvedLabels.backToPrevious(focusedSlice.name)}\n onClick={goBack}\n >\n {isTotalVisible && centerContent}\n </button>\n );\n }\n return isTotalVisible && <div className=\"pie-chart__center\">{centerContent}</div>;\n }\n\n function renderPieFooter() {\n if (focusedSlice) {\n return (\n <button\n type=\"button\"\n className=\"pie-chart__footer pie-chart__footer--button\"\n aria-label={resolvedLabels.backToPrevious(focusedSlice.name)}\n onClick={goBack}\n >\n {focusedSlice.name}\n {isTotalVisible && `: ${formatValue(centerTotal)}`}\n </button>\n );\n }\n return (\n isTotalVisible && (\n <div className=\"pie-chart__footer\">{`${resolvedLabels.total}: ${formatValue(centerTotal)}`}</div>\n )\n );\n }\n\n return (\n <div\n className={clsx(\"pie-chart\", `pie-chart--legend-${legendPosition}`, className)}\n {...props}\n >\n {isLegendVisible && (\n <ChartLegend\n className=\"pie-chart__legend\"\n items={legendItems}\n onToggle={toggleSeries}\n onColorChange={onSeriesColorChange}\n colorTokensBySeriesId={colorTokensBySeriesId}\n labels={legendLabels}\n />\n )}\n <div className=\"pie-chart__body\">\n <div ref={setStageElement} className=\"pie-chart__stage\">\n <div ref={containerRef} className=\"pie-chart__canvas\" />\n {shape === \"donut\" && renderDonutCenter()}\n </div>\n {shape === \"pie\" && renderPieFooter()}\n </div>\n </div>\n );\n}\n"],"names":["DEFAULT_LABELS","categoryName","MIN_SIZE_FOR_AUTO_TOTAL_PX","DEFAULT_LABEL_CONTENT","NO_LEGEND_VALUES","legendDetail","slice","legendValues","formatValue","hasPercent","hasValue","formatShare","useMinSide","element","minSide","setMinSide","useState","useLayoutEffect","observer","PieChart","data","shape","labelContent","showTotal","total","valueFormatter","legend","legendPosition","onSeriesColorChange","onFocusChange","legendLabels","labels","className","props","containerRef","chart","theme","resolveSeriesColor","useChartInstance","resolvedLabels","focusedNodeId","setFocusedNodeId","stageElement","setStageElement","stageMinSide","legendSeries","useMemo","node","displayNameOf","CHART_NEUTRAL_COLOR_TOKEN","items","colorsBySeriesId","colorTokensBySeriesId","hiddenSeriesIds","toggleSeries","useChartLegend","visibleSlices","buildPieSlices","focusedSlice","findSlice","drawnSlices","updateFocus","useCallback","nextFocusedNodeId","useEffect","buildPieChartOption","drillIntoClickedSlice","params","clickedId","_a","clickedSlice","value","legendItems","item","isTotalVisible","centerTotal","totalOf","parentOfFocusedSlice","findParentSlice","isLegendVisible","centerContent","jsxs","Fragment","jsx","goBack","renderDonutCenter","renderPieFooter","clsx","ChartLegend"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"PieChart.cjs","sources":["../../../../../../src/ui/components/charts/PieChart/PieChart.tsx"],"sourcesContent":["import clsx from \"clsx\";\nimport {\n type ComponentPropsWithoutRef,\n useCallback,\n useEffect,\n useLayoutEffect,\n useMemo,\n useState,\n} from \"react\";\nimport {\n ChartLegend,\n type ChartLegendItem,\n type ChartLegendLabels,\n} from \"../ChartLegend/ChartLegend\";\nimport {\n useChartLegend,\n type ChartLegendSeries,\n type ChartLegendState,\n} from \"../ChartLegend/use-chart-legend\";\nimport { CHART_NEUTRAL_COLOR_TOKEN } from \"../chart-palette\";\nimport { formatShare } from \"../chart-share\";\nimport { useChartInstance, type ChartInstance } from \"../useChartInstance\";\nimport {\n buildPieChartOption,\n type PieChartLabelContent,\n type PieChartShape,\n} from \"./pie-chart-option\";\nimport {\n buildPieSlices,\n displayNameOf,\n findParentSlice,\n findSlice,\n totalOf,\n type PieChartNode,\n type PieSlice,\n} from \"./pie-chart-slices\";\nimport \"./pie-chart.css\";\n\nexport type { PieChartNode } from \"./pie-chart-slices\";\nexport type { PieChartLabelContent, PieChartShape } from \"./pie-chart-option\";\n\nexport type PieChartLegendMode = \"inline\" | \"none\";\n\nexport type PieChartLegendPosition = \"bottom\" | \"right\" | \"top\" | \"left\";\n\nexport type PieChartLegendValue = \"percent\" | \"value\";\n\nexport type PieChartShowTotal = \"auto\" | \"on\" | \"off\";\n\nexport interface PieChartLabels {\n others: string;\n total: string;\n backToPrevious: (categoryName: string) => string;\n}\n\nconst DEFAULT_LABELS: PieChartLabels = {\n others: \"Others\",\n total: \"Total\",\n backToPrevious: (categoryName: string) => `Back from ${categoryName}`,\n};\n\nconst MIN_SIZE_FOR_AUTO_TOTAL_PX: number = 200;\n\nconst DEFAULT_LABEL_CONTENT: PieChartLabelContent[] = [\"percent\"];\n\nconst NO_LEGEND_VALUES: PieChartLegendValue[] = [];\n\nexport type PieChartProps = Omit<ComponentPropsWithoutRef<\"div\">, \"children\"> & {\n data: PieChartNode[];\n shape?: PieChartShape;\n labelContent?: PieChartLabelContent[];\n showTotal?: PieChartShowTotal;\n total?: number;\n valueFormatter?: (value: number) => string;\n legend?: PieChartLegendMode;\n legendPosition?: PieChartLegendPosition;\n legendValues?: PieChartLegendValue[];\n onSeriesColorChange?: (seriesId: string, colorToken: string | null) => void;\n onFocusChange?: (focusedNodeId: string | null) => void;\n legendLabels?: Partial<ChartLegendLabels>;\n labels?: Partial<PieChartLabels>;\n};\n\nfunction legendDetail(\n slice: PieSlice | undefined,\n legendValues: PieChartLegendValue[],\n formatValue: (value: number) => string,\n): string | undefined {\n if (!slice || legendValues.length === 0) return undefined;\n const hasPercent: boolean = legendValues.includes(\"percent\");\n const hasValue: boolean = legendValues.includes(\"value\");\n if (hasPercent && hasValue) return `${formatValue(slice.value)} (${formatShare(slice.share)})`;\n return hasValue ? formatValue(slice.value) : formatShare(slice.share);\n}\n\nfunction useMinSide(element: HTMLElement | null): number {\n const [minSide, setMinSide] = useState<number>(0);\n\n useLayoutEffect(() => {\n if (!element) return undefined;\n const observer: ResizeObserver = new ResizeObserver(() =>\n setMinSide(Math.min(element.clientWidth, element.clientHeight)),\n );\n observer.observe(element);\n return () => observer.disconnect();\n }, [element]);\n\n return minSide;\n}\n\nexport function PieChart({\n data,\n shape = \"donut\",\n labelContent = DEFAULT_LABEL_CONTENT,\n showTotal = \"auto\",\n total,\n valueFormatter,\n legend = \"inline\",\n legendPosition = \"bottom\",\n legendValues = NO_LEGEND_VALUES,\n onSeriesColorChange,\n onFocusChange,\n legendLabels,\n labels,\n className,\n ...props\n}: PieChartProps) {\n const { containerRef, chart, theme, resolveSeriesColor }: ChartInstance = useChartInstance();\n const resolvedLabels: PieChartLabels = { ...DEFAULT_LABELS, ...labels };\n const [focusedNodeId, setFocusedNodeId] = useState<string | null>(null);\n const [stageElement, setStageElement] = useState<HTMLDivElement | null>(null);\n const stageMinSide: number = useMinSide(stageElement);\n\n const legendSeries: ChartLegendSeries[] = useMemo(\n () =>\n data.map((node: PieChartNode) => ({\n id: node.id,\n name: displayNameOf(node, resolvedLabels.others),\n colorToken: node.colorToken ?? (node.isOthers ? CHART_NEUTRAL_COLOR_TOKEN : undefined),\n })),\n [data, resolvedLabels.others],\n );\n\n const {\n items,\n colorsBySeriesId,\n colorTokensBySeriesId,\n hiddenSeriesIds,\n toggleSeries,\n }: ChartLegendState = useChartLegend(\n legendSeries,\n theme?.seriesColors ?? [],\n resolveSeriesColor,\n );\n\n const visibleSlices: PieSlice[] = useMemo(\n () =>\n buildPieSlices({\n nodes: data.filter((node: PieChartNode) => !hiddenSeriesIds.has(node.id)),\n colorsByRootId: colorsBySeriesId,\n fallbackColor: theme?.neutralColor ?? \"#9ca3af\",\n othersName: resolvedLabels.others,\n }),\n [data, hiddenSeriesIds, colorsBySeriesId, theme, resolvedLabels.others],\n );\n\n const focusedSlice: PieSlice | undefined = useMemo(\n () => (focusedNodeId === null ? undefined : findSlice(visibleSlices, focusedNodeId)),\n [visibleSlices, focusedNodeId],\n );\n\n const drawnSlices: PieSlice[] = focusedSlice ? focusedSlice.children : visibleSlices;\n\n const updateFocus = useCallback(\n (nextFocusedNodeId: string | null): void => {\n setFocusedNodeId(nextFocusedNodeId);\n onFocusChange?.(nextFocusedNodeId);\n },\n [onFocusChange],\n );\n\n useEffect(() => {\n if (focusedNodeId !== null && !focusedSlice) updateFocus(null);\n }, [focusedNodeId, focusedSlice, updateFocus]);\n\n useEffect(() => {\n if (!chart || !theme) return;\n chart.setOption(\n buildPieChartOption({ slices: drawnSlices, shape, labelContent, theme, valueFormatter }),\n { notMerge: true },\n );\n }, [chart, theme, drawnSlices, shape, labelContent, valueFormatter]);\n\n useEffect(() => {\n if (!chart) return undefined;\n\n function drillIntoClickedSlice(params: { data?: unknown }): void {\n const clickedId: unknown = (params.data as { id?: unknown } | null | undefined)?.id;\n if (typeof clickedId !== \"string\") return;\n const clickedSlice: PieSlice | undefined = findSlice(drawnSlices, clickedId);\n if (clickedSlice && clickedSlice.children.length > 0) updateFocus(clickedSlice.id);\n }\n\n chart.on(\"click\", drillIntoClickedSlice);\n return () => {\n chart.off(\"click\", drillIntoClickedSlice);\n };\n }, [chart, drawnSlices, updateFocus]);\n\n function formatValue(value: number): string {\n return valueFormatter ? valueFormatter(value) : String(value);\n }\n\n const legendItems: ChartLegendItem[] = items.map((item: ChartLegendItem) => ({\n ...item,\n detail: legendDetail(\n visibleSlices.find((slice: PieSlice) => slice.id === item.id),\n legendValues,\n formatValue,\n ),\n }));\n\n const isTotalVisible: boolean =\n showTotal === \"on\" || (showTotal === \"auto\" && stageMinSide >= MIN_SIZE_FOR_AUTO_TOTAL_PX);\n const centerTotal: number = focusedSlice ? focusedSlice.value : (total ?? totalOf(visibleSlices));\n const parentOfFocusedSlice: PieSlice | undefined = focusedSlice\n ? findParentSlice(visibleSlices, focusedSlice.id)\n : undefined;\n const isLegendVisible: boolean = legend !== \"none\" && data.length > 0;\n\n const centerContent = (\n <>\n <span className=\"pie-chart__total-value\">{formatValue(centerTotal)}</span>\n <span className=\"pie-chart__total-caption\">\n {focusedSlice ? focusedSlice.name : resolvedLabels.total}\n </span>\n </>\n );\n\n function goBack(): void {\n updateFocus(parentOfFocusedSlice ? parentOfFocusedSlice.id : null);\n }\n\n function renderDonutCenter() {\n if (focusedSlice) {\n return (\n <button\n type=\"button\"\n className=\"pie-chart__center pie-chart__center--button\"\n aria-label={resolvedLabels.backToPrevious(focusedSlice.name)}\n onClick={goBack}\n >\n {isTotalVisible && centerContent}\n </button>\n );\n }\n return isTotalVisible && <div className=\"pie-chart__center\">{centerContent}</div>;\n }\n\n function renderPieFooter() {\n if (focusedSlice) {\n return (\n <button\n type=\"button\"\n className=\"pie-chart__footer pie-chart__footer--button\"\n aria-label={resolvedLabels.backToPrevious(focusedSlice.name)}\n onClick={goBack}\n >\n {focusedSlice.name}\n {isTotalVisible && `: ${formatValue(centerTotal)}`}\n </button>\n );\n }\n return (\n isTotalVisible && (\n <div className=\"pie-chart__footer\">{`${resolvedLabels.total}: ${formatValue(centerTotal)}`}</div>\n )\n );\n }\n\n return (\n <div\n className={clsx(\"pie-chart\", `pie-chart--legend-${legendPosition}`, className)}\n {...props}\n >\n {isLegendVisible && (\n <ChartLegend\n className=\"pie-chart__legend\"\n items={legendItems}\n onToggle={toggleSeries}\n onColorChange={onSeriesColorChange}\n colorTokensBySeriesId={colorTokensBySeriesId}\n labels={legendLabels}\n />\n )}\n <div className=\"pie-chart__body\">\n <div ref={setStageElement} className=\"pie-chart__stage\">\n <div ref={containerRef} className=\"pie-chart__canvas\" />\n {shape === \"donut\" && renderDonutCenter()}\n </div>\n {shape === \"pie\" && renderPieFooter()}\n </div>\n </div>\n );\n}\n"],"names":["DEFAULT_LABELS","categoryName","MIN_SIZE_FOR_AUTO_TOTAL_PX","DEFAULT_LABEL_CONTENT","NO_LEGEND_VALUES","legendDetail","slice","legendValues","formatValue","hasPercent","hasValue","formatShare","useMinSide","element","minSide","setMinSide","useState","useLayoutEffect","observer","PieChart","data","shape","labelContent","showTotal","total","valueFormatter","legend","legendPosition","onSeriesColorChange","onFocusChange","legendLabels","labels","className","props","containerRef","chart","theme","resolveSeriesColor","useChartInstance","resolvedLabels","focusedNodeId","setFocusedNodeId","stageElement","setStageElement","stageMinSide","legendSeries","useMemo","node","displayNameOf","CHART_NEUTRAL_COLOR_TOKEN","items","colorsBySeriesId","colorTokensBySeriesId","hiddenSeriesIds","toggleSeries","useChartLegend","visibleSlices","buildPieSlices","focusedSlice","findSlice","drawnSlices","updateFocus","useCallback","nextFocusedNodeId","useEffect","buildPieChartOption","drillIntoClickedSlice","params","clickedId","_a","clickedSlice","value","legendItems","item","isTotalVisible","centerTotal","totalOf","parentOfFocusedSlice","findParentSlice","isLegendVisible","centerContent","jsxs","Fragment","jsx","goBack","renderDonutCenter","renderPieFooter","clsx","ChartLegend"],"mappings":"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"}
|
|
@@ -1,11 +1,12 @@
|
|
|
1
|
-
import { jsxs as h, Fragment as
|
|
2
|
-
import { clsx as
|
|
3
|
-
import { useState as O, useMemo as k, useCallback as
|
|
1
|
+
import { jsxs as h, Fragment as ie, jsx as a } from "react/jsx-runtime";
|
|
2
|
+
import { clsx as oe } from "../../../../vendor/clsx/dist/clsx.js";
|
|
3
|
+
import { useState as O, useMemo as k, useCallback as ne, useEffect as L, useLayoutEffect as ce } from "react";
|
|
4
4
|
import { ChartLegend as se } from "../ChartLegend/ChartLegend.js";
|
|
5
5
|
import { useChartLegend as le } from "../ChartLegend/use-chart-legend.js";
|
|
6
6
|
import { CHART_NEUTRAL_COLOR_TOKEN as ae } from "../chart-palette.js";
|
|
7
|
+
import { formatShare as M } from "../chart-share.js";
|
|
7
8
|
import { useChartInstance as de } from "../useChartInstance.js";
|
|
8
|
-
import { buildPieChartOption as ue
|
|
9
|
+
import { buildPieChartOption as ue } from "./pie-chart-option.js";
|
|
9
10
|
import { displayNameOf as fe, buildPieSlices as he, findSlice as R, totalOf as me, findParentSlice as pe } from "./pie-chart-slices.js";
|
|
10
11
|
/* empty css */
|
|
11
12
|
const _e = {
|
|
@@ -13,24 +14,24 @@ const _e = {
|
|
|
13
14
|
total: "Total",
|
|
14
15
|
backToPrevious: (e) => `Back from ${e}`
|
|
15
16
|
}, Se = 200, be = ["percent"], ve = [];
|
|
16
|
-
function Ne(e,
|
|
17
|
-
if (!e ||
|
|
18
|
-
const s =
|
|
17
|
+
function Ne(e, i, c) {
|
|
18
|
+
if (!e || i.length === 0) return;
|
|
19
|
+
const s = i.includes("percent"), m = i.includes("value");
|
|
19
20
|
return s && m ? `${c(e.value)} (${M(e.share)})` : m ? c(e.value) : M(e.share);
|
|
20
21
|
}
|
|
21
22
|
function ge(e) {
|
|
22
|
-
const [
|
|
23
|
+
const [i, c] = O(0);
|
|
23
24
|
return ce(() => {
|
|
24
25
|
if (!e) return;
|
|
25
26
|
const s = new ResizeObserver(
|
|
26
27
|
() => c(Math.min(e.clientWidth, e.clientHeight))
|
|
27
28
|
);
|
|
28
29
|
return s.observe(e), () => s.disconnect();
|
|
29
|
-
}, [e]),
|
|
30
|
+
}, [e]), i;
|
|
30
31
|
}
|
|
31
|
-
function
|
|
32
|
+
function Me({
|
|
32
33
|
data: e,
|
|
33
|
-
shape:
|
|
34
|
+
shape: i = "donut",
|
|
34
35
|
labelContent: c = be,
|
|
35
36
|
showTotal: s = "auto",
|
|
36
37
|
total: m,
|
|
@@ -45,13 +46,13 @@ function Be({
|
|
|
45
46
|
className: V,
|
|
46
47
|
...w
|
|
47
48
|
}) {
|
|
48
|
-
const { containerRef: z, chart: l, theme:
|
|
49
|
+
const { containerRef: z, chart: l, theme: o, resolveSeriesColor: G } = de(), n = { ..._e, ...H }, [u, K] = O(null), [W, X] = O(null), Z = ge(W), q = k(
|
|
49
50
|
() => e.map((t) => ({
|
|
50
51
|
id: t.id,
|
|
51
|
-
name: fe(t,
|
|
52
|
+
name: fe(t, n.others),
|
|
52
53
|
colorToken: t.colorToken ?? (t.isOthers ? ae : void 0)
|
|
53
54
|
})),
|
|
54
|
-
[e,
|
|
55
|
+
[e, n.others]
|
|
55
56
|
), {
|
|
56
57
|
items: J,
|
|
57
58
|
colorsBySeriesId: E,
|
|
@@ -60,33 +61,33 @@ function Be({
|
|
|
60
61
|
toggleSeries: Y
|
|
61
62
|
} = le(
|
|
62
63
|
q,
|
|
63
|
-
(
|
|
64
|
+
(o == null ? void 0 : o.seriesColors) ?? [],
|
|
64
65
|
G
|
|
65
66
|
), d = k(
|
|
66
67
|
() => he({
|
|
67
68
|
nodes: e.filter((t) => !C.has(t.id)),
|
|
68
69
|
colorsByRootId: E,
|
|
69
|
-
fallbackColor: (
|
|
70
|
-
othersName:
|
|
70
|
+
fallbackColor: (o == null ? void 0 : o.neutralColor) ?? "#9ca3af",
|
|
71
|
+
othersName: n.others
|
|
71
72
|
}),
|
|
72
|
-
[e, C, E,
|
|
73
|
-
),
|
|
73
|
+
[e, C, E, o, n.others]
|
|
74
|
+
), r = k(
|
|
74
75
|
() => u === null ? void 0 : R(d, u),
|
|
75
76
|
[d, u]
|
|
76
|
-
), S =
|
|
77
|
+
), S = r ? r.children : d, f = ne(
|
|
77
78
|
(t) => {
|
|
78
79
|
K(t), _ == null || _(t);
|
|
79
80
|
},
|
|
80
81
|
[_]
|
|
81
82
|
);
|
|
82
83
|
L(() => {
|
|
83
|
-
u !== null && !
|
|
84
|
-
}, [u,
|
|
85
|
-
!l || !
|
|
86
|
-
ue({ slices: S, shape:
|
|
84
|
+
u !== null && !r && f(null);
|
|
85
|
+
}, [u, r, f]), L(() => {
|
|
86
|
+
!l || !o || l.setOption(
|
|
87
|
+
ue({ slices: S, shape: i, labelContent: c, theme: o, valueFormatter: p }),
|
|
87
88
|
{ notMerge: !0 }
|
|
88
89
|
);
|
|
89
|
-
}, [l,
|
|
90
|
+
}, [l, o, S, i, c, p]), L(() => {
|
|
90
91
|
if (!l) return;
|
|
91
92
|
function t(g) {
|
|
92
93
|
var B;
|
|
@@ -109,44 +110,44 @@ function Be({
|
|
|
109
110
|
U,
|
|
110
111
|
b
|
|
111
112
|
)
|
|
112
|
-
})), v = s === "on" || s === "auto" && Z >= Se, N =
|
|
113
|
+
})), v = s === "on" || s === "auto" && Z >= Se, N = r ? r.value : m ?? me(d), I = r ? pe(d, r.id) : void 0, ee = $ !== "none" && e.length > 0, P = /* @__PURE__ */ h(ie, { children: [
|
|
113
114
|
/* @__PURE__ */ a("span", { className: "pie-chart__total-value", children: b(N) }),
|
|
114
|
-
/* @__PURE__ */ a("span", { className: "pie-chart__total-caption", children:
|
|
115
|
+
/* @__PURE__ */ a("span", { className: "pie-chart__total-caption", children: r ? r.name : n.total })
|
|
115
116
|
] });
|
|
116
117
|
function y() {
|
|
117
118
|
f(I ? I.id : null);
|
|
118
119
|
}
|
|
119
120
|
function te() {
|
|
120
|
-
return
|
|
121
|
+
return r ? /* @__PURE__ */ a(
|
|
121
122
|
"button",
|
|
122
123
|
{
|
|
123
124
|
type: "button",
|
|
124
125
|
className: "pie-chart__center pie-chart__center--button",
|
|
125
|
-
"aria-label":
|
|
126
|
+
"aria-label": n.backToPrevious(r.name),
|
|
126
127
|
onClick: y,
|
|
127
128
|
children: v && P
|
|
128
129
|
}
|
|
129
130
|
) : v && /* @__PURE__ */ a("div", { className: "pie-chart__center", children: P });
|
|
130
131
|
}
|
|
131
|
-
function
|
|
132
|
-
return
|
|
132
|
+
function re() {
|
|
133
|
+
return r ? /* @__PURE__ */ h(
|
|
133
134
|
"button",
|
|
134
135
|
{
|
|
135
136
|
type: "button",
|
|
136
137
|
className: "pie-chart__footer pie-chart__footer--button",
|
|
137
|
-
"aria-label":
|
|
138
|
+
"aria-label": n.backToPrevious(r.name),
|
|
138
139
|
onClick: y,
|
|
139
140
|
children: [
|
|
140
|
-
|
|
141
|
+
r.name,
|
|
141
142
|
v && `: ${b(N)}`
|
|
142
143
|
]
|
|
143
144
|
}
|
|
144
|
-
) : v && /* @__PURE__ */ a("div", { className: "pie-chart__footer", children: `${
|
|
145
|
+
) : v && /* @__PURE__ */ a("div", { className: "pie-chart__footer", children: `${n.total}: ${b(N)}` });
|
|
145
146
|
}
|
|
146
147
|
return /* @__PURE__ */ h(
|
|
147
148
|
"div",
|
|
148
149
|
{
|
|
149
|
-
className:
|
|
150
|
+
className: oe("pie-chart", `pie-chart--legend-${D}`, V),
|
|
150
151
|
...w,
|
|
151
152
|
children: [
|
|
152
153
|
ee && /* @__PURE__ */ a(
|
|
@@ -163,15 +164,15 @@ function Be({
|
|
|
163
164
|
/* @__PURE__ */ h("div", { className: "pie-chart__body", children: [
|
|
164
165
|
/* @__PURE__ */ h("div", { ref: X, className: "pie-chart__stage", children: [
|
|
165
166
|
/* @__PURE__ */ a("div", { ref: z, className: "pie-chart__canvas" }),
|
|
166
|
-
|
|
167
|
+
i === "donut" && te()
|
|
167
168
|
] }),
|
|
168
|
-
|
|
169
|
+
i === "pie" && re()
|
|
169
170
|
] })
|
|
170
171
|
]
|
|
171
172
|
}
|
|
172
173
|
);
|
|
173
174
|
}
|
|
174
175
|
export {
|
|
175
|
-
|
|
176
|
+
Me as PieChart
|
|
176
177
|
};
|
|
177
178
|
//# sourceMappingURL=PieChart.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PieChart.js","sources":["../../../../../../src/ui/components/charts/PieChart/PieChart.tsx"],"sourcesContent":["import clsx from \"clsx\";\nimport {\n type ComponentPropsWithoutRef,\n useCallback,\n useEffect,\n useLayoutEffect,\n useMemo,\n useState,\n} from \"react\";\nimport {\n ChartLegend,\n type ChartLegendItem,\n type ChartLegendLabels,\n} from \"../ChartLegend/ChartLegend\";\nimport {\n useChartLegend,\n type ChartLegendSeries,\n type ChartLegendState,\n} from \"../ChartLegend/use-chart-legend\";\nimport { CHART_NEUTRAL_COLOR_TOKEN } from \"../chart-palette\";\nimport { useChartInstance, type ChartInstance } from \"../useChartInstance\";\nimport {\n buildPieChartOption,\n formatShare,\n type PieChartLabelContent,\n type PieChartShape,\n} from \"./pie-chart-option\";\nimport {\n buildPieSlices,\n displayNameOf,\n findParentSlice,\n findSlice,\n totalOf,\n type PieChartNode,\n type PieSlice,\n} from \"./pie-chart-slices\";\nimport \"./pie-chart.css\";\n\nexport type { PieChartNode } from \"./pie-chart-slices\";\nexport type { PieChartLabelContent, PieChartShape } from \"./pie-chart-option\";\n\nexport type PieChartLegendMode = \"inline\" | \"none\";\n\nexport type PieChartLegendPosition = \"bottom\" | \"right\" | \"top\" | \"left\";\n\nexport type PieChartLegendValue = \"percent\" | \"value\";\n\nexport type PieChartShowTotal = \"auto\" | \"on\" | \"off\";\n\nexport interface PieChartLabels {\n others: string;\n total: string;\n backToPrevious: (categoryName: string) => string;\n}\n\nconst DEFAULT_LABELS: PieChartLabels = {\n others: \"Others\",\n total: \"Total\",\n backToPrevious: (categoryName: string) => `Back from ${categoryName}`,\n};\n\nconst MIN_SIZE_FOR_AUTO_TOTAL_PX: number = 200;\n\nconst DEFAULT_LABEL_CONTENT: PieChartLabelContent[] = [\"percent\"];\n\nconst NO_LEGEND_VALUES: PieChartLegendValue[] = [];\n\nexport type PieChartProps = Omit<ComponentPropsWithoutRef<\"div\">, \"children\"> & {\n data: PieChartNode[];\n shape?: PieChartShape;\n labelContent?: PieChartLabelContent[];\n showTotal?: PieChartShowTotal;\n total?: number;\n valueFormatter?: (value: number) => string;\n legend?: PieChartLegendMode;\n legendPosition?: PieChartLegendPosition;\n legendValues?: PieChartLegendValue[];\n onSeriesColorChange?: (seriesId: string, colorToken: string | null) => void;\n onFocusChange?: (focusedNodeId: string | null) => void;\n legendLabels?: Partial<ChartLegendLabels>;\n labels?: Partial<PieChartLabels>;\n};\n\nfunction legendDetail(\n slice: PieSlice | undefined,\n legendValues: PieChartLegendValue[],\n formatValue: (value: number) => string,\n): string | undefined {\n if (!slice || legendValues.length === 0) return undefined;\n const hasPercent: boolean = legendValues.includes(\"percent\");\n const hasValue: boolean = legendValues.includes(\"value\");\n if (hasPercent && hasValue) return `${formatValue(slice.value)} (${formatShare(slice.share)})`;\n return hasValue ? formatValue(slice.value) : formatShare(slice.share);\n}\n\nfunction useMinSide(element: HTMLElement | null): number {\n const [minSide, setMinSide] = useState<number>(0);\n\n useLayoutEffect(() => {\n if (!element) return undefined;\n const observer: ResizeObserver = new ResizeObserver(() =>\n setMinSide(Math.min(element.clientWidth, element.clientHeight)),\n );\n observer.observe(element);\n return () => observer.disconnect();\n }, [element]);\n\n return minSide;\n}\n\nexport function PieChart({\n data,\n shape = \"donut\",\n labelContent = DEFAULT_LABEL_CONTENT,\n showTotal = \"auto\",\n total,\n valueFormatter,\n legend = \"inline\",\n legendPosition = \"bottom\",\n legendValues = NO_LEGEND_VALUES,\n onSeriesColorChange,\n onFocusChange,\n legendLabels,\n labels,\n className,\n ...props\n}: PieChartProps) {\n const { containerRef, chart, theme, resolveSeriesColor }: ChartInstance = useChartInstance();\n const resolvedLabels: PieChartLabels = { ...DEFAULT_LABELS, ...labels };\n const [focusedNodeId, setFocusedNodeId] = useState<string | null>(null);\n const [stageElement, setStageElement] = useState<HTMLDivElement | null>(null);\n const stageMinSide: number = useMinSide(stageElement);\n\n const legendSeries: ChartLegendSeries[] = useMemo(\n () =>\n data.map((node: PieChartNode) => ({\n id: node.id,\n name: displayNameOf(node, resolvedLabels.others),\n colorToken: node.colorToken ?? (node.isOthers ? CHART_NEUTRAL_COLOR_TOKEN : undefined),\n })),\n [data, resolvedLabels.others],\n );\n\n const {\n items,\n colorsBySeriesId,\n colorTokensBySeriesId,\n hiddenSeriesIds,\n toggleSeries,\n }: ChartLegendState = useChartLegend(\n legendSeries,\n theme?.seriesColors ?? [],\n resolveSeriesColor,\n );\n\n const visibleSlices: PieSlice[] = useMemo(\n () =>\n buildPieSlices({\n nodes: data.filter((node: PieChartNode) => !hiddenSeriesIds.has(node.id)),\n colorsByRootId: colorsBySeriesId,\n fallbackColor: theme?.neutralColor ?? \"#9ca3af\",\n othersName: resolvedLabels.others,\n }),\n [data, hiddenSeriesIds, colorsBySeriesId, theme, resolvedLabels.others],\n );\n\n const focusedSlice: PieSlice | undefined = useMemo(\n () => (focusedNodeId === null ? undefined : findSlice(visibleSlices, focusedNodeId)),\n [visibleSlices, focusedNodeId],\n );\n\n const drawnSlices: PieSlice[] = focusedSlice ? focusedSlice.children : visibleSlices;\n\n const updateFocus = useCallback(\n (nextFocusedNodeId: string | null): void => {\n setFocusedNodeId(nextFocusedNodeId);\n onFocusChange?.(nextFocusedNodeId);\n },\n [onFocusChange],\n );\n\n useEffect(() => {\n if (focusedNodeId !== null && !focusedSlice) updateFocus(null);\n }, [focusedNodeId, focusedSlice, updateFocus]);\n\n useEffect(() => {\n if (!chart || !theme) return;\n chart.setOption(\n buildPieChartOption({ slices: drawnSlices, shape, labelContent, theme, valueFormatter }),\n { notMerge: true },\n );\n }, [chart, theme, drawnSlices, shape, labelContent, valueFormatter]);\n\n useEffect(() => {\n if (!chart) return undefined;\n\n function drillIntoClickedSlice(params: { data?: unknown }): void {\n const clickedId: unknown = (params.data as { id?: unknown } | null | undefined)?.id;\n if (typeof clickedId !== \"string\") return;\n const clickedSlice: PieSlice | undefined = findSlice(drawnSlices, clickedId);\n if (clickedSlice && clickedSlice.children.length > 0) updateFocus(clickedSlice.id);\n }\n\n chart.on(\"click\", drillIntoClickedSlice);\n return () => {\n chart.off(\"click\", drillIntoClickedSlice);\n };\n }, [chart, drawnSlices, updateFocus]);\n\n function formatValue(value: number): string {\n return valueFormatter ? valueFormatter(value) : String(value);\n }\n\n const legendItems: ChartLegendItem[] = items.map((item: ChartLegendItem) => ({\n ...item,\n detail: legendDetail(\n visibleSlices.find((slice: PieSlice) => slice.id === item.id),\n legendValues,\n formatValue,\n ),\n }));\n\n const isTotalVisible: boolean =\n showTotal === \"on\" || (showTotal === \"auto\" && stageMinSide >= MIN_SIZE_FOR_AUTO_TOTAL_PX);\n const centerTotal: number = focusedSlice ? focusedSlice.value : (total ?? totalOf(visibleSlices));\n const parentOfFocusedSlice: PieSlice | undefined = focusedSlice\n ? findParentSlice(visibleSlices, focusedSlice.id)\n : undefined;\n const isLegendVisible: boolean = legend !== \"none\" && data.length > 0;\n\n const centerContent = (\n <>\n <span className=\"pie-chart__total-value\">{formatValue(centerTotal)}</span>\n <span className=\"pie-chart__total-caption\">\n {focusedSlice ? focusedSlice.name : resolvedLabels.total}\n </span>\n </>\n );\n\n function goBack(): void {\n updateFocus(parentOfFocusedSlice ? parentOfFocusedSlice.id : null);\n }\n\n function renderDonutCenter() {\n if (focusedSlice) {\n return (\n <button\n type=\"button\"\n className=\"pie-chart__center pie-chart__center--button\"\n aria-label={resolvedLabels.backToPrevious(focusedSlice.name)}\n onClick={goBack}\n >\n {isTotalVisible && centerContent}\n </button>\n );\n }\n return isTotalVisible && <div className=\"pie-chart__center\">{centerContent}</div>;\n }\n\n function renderPieFooter() {\n if (focusedSlice) {\n return (\n <button\n type=\"button\"\n className=\"pie-chart__footer pie-chart__footer--button\"\n aria-label={resolvedLabels.backToPrevious(focusedSlice.name)}\n onClick={goBack}\n >\n {focusedSlice.name}\n {isTotalVisible && `: ${formatValue(centerTotal)}`}\n </button>\n );\n }\n return (\n isTotalVisible && (\n <div className=\"pie-chart__footer\">{`${resolvedLabels.total}: ${formatValue(centerTotal)}`}</div>\n )\n );\n }\n\n return (\n <div\n className={clsx(\"pie-chart\", `pie-chart--legend-${legendPosition}`, className)}\n {...props}\n >\n {isLegendVisible && (\n <ChartLegend\n className=\"pie-chart__legend\"\n items={legendItems}\n onToggle={toggleSeries}\n onColorChange={onSeriesColorChange}\n colorTokensBySeriesId={colorTokensBySeriesId}\n labels={legendLabels}\n />\n )}\n <div className=\"pie-chart__body\">\n <div ref={setStageElement} className=\"pie-chart__stage\">\n <div ref={containerRef} className=\"pie-chart__canvas\" />\n {shape === \"donut\" && renderDonutCenter()}\n </div>\n {shape === \"pie\" && renderPieFooter()}\n </div>\n </div>\n );\n}\n"],"names":["DEFAULT_LABELS","categoryName","MIN_SIZE_FOR_AUTO_TOTAL_PX","DEFAULT_LABEL_CONTENT","NO_LEGEND_VALUES","legendDetail","slice","legendValues","formatValue","hasPercent","hasValue","formatShare","useMinSide","element","minSide","setMinSide","useState","useLayoutEffect","observer","PieChart","data","shape","labelContent","showTotal","total","valueFormatter","legend","legendPosition","onSeriesColorChange","onFocusChange","legendLabels","labels","className","props","containerRef","chart","theme","resolveSeriesColor","useChartInstance","resolvedLabels","focusedNodeId","setFocusedNodeId","stageElement","setStageElement","stageMinSide","legendSeries","useMemo","node","displayNameOf","CHART_NEUTRAL_COLOR_TOKEN","items","colorsBySeriesId","colorTokensBySeriesId","hiddenSeriesIds","toggleSeries","useChartLegend","visibleSlices","buildPieSlices","focusedSlice","findSlice","drawnSlices","updateFocus","useCallback","nextFocusedNodeId","useEffect","buildPieChartOption","drillIntoClickedSlice","params","clickedId","_a","clickedSlice","value","legendItems","item","isTotalVisible","centerTotal","totalOf","parentOfFocusedSlice","findParentSlice","isLegendVisible","centerContent","jsxs","Fragment","jsx","goBack","renderDonutCenter","renderPieFooter","clsx","ChartLegend"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"PieChart.js","sources":["../../../../../../src/ui/components/charts/PieChart/PieChart.tsx"],"sourcesContent":["import clsx from \"clsx\";\nimport {\n type ComponentPropsWithoutRef,\n useCallback,\n useEffect,\n useLayoutEffect,\n useMemo,\n useState,\n} from \"react\";\nimport {\n ChartLegend,\n type ChartLegendItem,\n type ChartLegendLabels,\n} from \"../ChartLegend/ChartLegend\";\nimport {\n useChartLegend,\n type ChartLegendSeries,\n type ChartLegendState,\n} from \"../ChartLegend/use-chart-legend\";\nimport { CHART_NEUTRAL_COLOR_TOKEN } from \"../chart-palette\";\nimport { formatShare } from \"../chart-share\";\nimport { useChartInstance, type ChartInstance } from \"../useChartInstance\";\nimport {\n buildPieChartOption,\n type PieChartLabelContent,\n type PieChartShape,\n} from \"./pie-chart-option\";\nimport {\n buildPieSlices,\n displayNameOf,\n findParentSlice,\n findSlice,\n totalOf,\n type PieChartNode,\n type PieSlice,\n} from \"./pie-chart-slices\";\nimport \"./pie-chart.css\";\n\nexport type { PieChartNode } from \"./pie-chart-slices\";\nexport type { PieChartLabelContent, PieChartShape } from \"./pie-chart-option\";\n\nexport type PieChartLegendMode = \"inline\" | \"none\";\n\nexport type PieChartLegendPosition = \"bottom\" | \"right\" | \"top\" | \"left\";\n\nexport type PieChartLegendValue = \"percent\" | \"value\";\n\nexport type PieChartShowTotal = \"auto\" | \"on\" | \"off\";\n\nexport interface PieChartLabels {\n others: string;\n total: string;\n backToPrevious: (categoryName: string) => string;\n}\n\nconst DEFAULT_LABELS: PieChartLabels = {\n others: \"Others\",\n total: \"Total\",\n backToPrevious: (categoryName: string) => `Back from ${categoryName}`,\n};\n\nconst MIN_SIZE_FOR_AUTO_TOTAL_PX: number = 200;\n\nconst DEFAULT_LABEL_CONTENT: PieChartLabelContent[] = [\"percent\"];\n\nconst NO_LEGEND_VALUES: PieChartLegendValue[] = [];\n\nexport type PieChartProps = Omit<ComponentPropsWithoutRef<\"div\">, \"children\"> & {\n data: PieChartNode[];\n shape?: PieChartShape;\n labelContent?: PieChartLabelContent[];\n showTotal?: PieChartShowTotal;\n total?: number;\n valueFormatter?: (value: number) => string;\n legend?: PieChartLegendMode;\n legendPosition?: PieChartLegendPosition;\n legendValues?: PieChartLegendValue[];\n onSeriesColorChange?: (seriesId: string, colorToken: string | null) => void;\n onFocusChange?: (focusedNodeId: string | null) => void;\n legendLabels?: Partial<ChartLegendLabels>;\n labels?: Partial<PieChartLabels>;\n};\n\nfunction legendDetail(\n slice: PieSlice | undefined,\n legendValues: PieChartLegendValue[],\n formatValue: (value: number) => string,\n): string | undefined {\n if (!slice || legendValues.length === 0) return undefined;\n const hasPercent: boolean = legendValues.includes(\"percent\");\n const hasValue: boolean = legendValues.includes(\"value\");\n if (hasPercent && hasValue) return `${formatValue(slice.value)} (${formatShare(slice.share)})`;\n return hasValue ? formatValue(slice.value) : formatShare(slice.share);\n}\n\nfunction useMinSide(element: HTMLElement | null): number {\n const [minSide, setMinSide] = useState<number>(0);\n\n useLayoutEffect(() => {\n if (!element) return undefined;\n const observer: ResizeObserver = new ResizeObserver(() =>\n setMinSide(Math.min(element.clientWidth, element.clientHeight)),\n );\n observer.observe(element);\n return () => observer.disconnect();\n }, [element]);\n\n return minSide;\n}\n\nexport function PieChart({\n data,\n shape = \"donut\",\n labelContent = DEFAULT_LABEL_CONTENT,\n showTotal = \"auto\",\n total,\n valueFormatter,\n legend = \"inline\",\n legendPosition = \"bottom\",\n legendValues = NO_LEGEND_VALUES,\n onSeriesColorChange,\n onFocusChange,\n legendLabels,\n labels,\n className,\n ...props\n}: PieChartProps) {\n const { containerRef, chart, theme, resolveSeriesColor }: ChartInstance = useChartInstance();\n const resolvedLabels: PieChartLabels = { ...DEFAULT_LABELS, ...labels };\n const [focusedNodeId, setFocusedNodeId] = useState<string | null>(null);\n const [stageElement, setStageElement] = useState<HTMLDivElement | null>(null);\n const stageMinSide: number = useMinSide(stageElement);\n\n const legendSeries: ChartLegendSeries[] = useMemo(\n () =>\n data.map((node: PieChartNode) => ({\n id: node.id,\n name: displayNameOf(node, resolvedLabels.others),\n colorToken: node.colorToken ?? (node.isOthers ? CHART_NEUTRAL_COLOR_TOKEN : undefined),\n })),\n [data, resolvedLabels.others],\n );\n\n const {\n items,\n colorsBySeriesId,\n colorTokensBySeriesId,\n hiddenSeriesIds,\n toggleSeries,\n }: ChartLegendState = useChartLegend(\n legendSeries,\n theme?.seriesColors ?? [],\n resolveSeriesColor,\n );\n\n const visibleSlices: PieSlice[] = useMemo(\n () =>\n buildPieSlices({\n nodes: data.filter((node: PieChartNode) => !hiddenSeriesIds.has(node.id)),\n colorsByRootId: colorsBySeriesId,\n fallbackColor: theme?.neutralColor ?? \"#9ca3af\",\n othersName: resolvedLabels.others,\n }),\n [data, hiddenSeriesIds, colorsBySeriesId, theme, resolvedLabels.others],\n );\n\n const focusedSlice: PieSlice | undefined = useMemo(\n () => (focusedNodeId === null ? undefined : findSlice(visibleSlices, focusedNodeId)),\n [visibleSlices, focusedNodeId],\n );\n\n const drawnSlices: PieSlice[] = focusedSlice ? focusedSlice.children : visibleSlices;\n\n const updateFocus = useCallback(\n (nextFocusedNodeId: string | null): void => {\n setFocusedNodeId(nextFocusedNodeId);\n onFocusChange?.(nextFocusedNodeId);\n },\n [onFocusChange],\n );\n\n useEffect(() => {\n if (focusedNodeId !== null && !focusedSlice) updateFocus(null);\n }, [focusedNodeId, focusedSlice, updateFocus]);\n\n useEffect(() => {\n if (!chart || !theme) return;\n chart.setOption(\n buildPieChartOption({ slices: drawnSlices, shape, labelContent, theme, valueFormatter }),\n { notMerge: true },\n );\n }, [chart, theme, drawnSlices, shape, labelContent, valueFormatter]);\n\n useEffect(() => {\n if (!chart) return undefined;\n\n function drillIntoClickedSlice(params: { data?: unknown }): void {\n const clickedId: unknown = (params.data as { id?: unknown } | null | undefined)?.id;\n if (typeof clickedId !== \"string\") return;\n const clickedSlice: PieSlice | undefined = findSlice(drawnSlices, clickedId);\n if (clickedSlice && clickedSlice.children.length > 0) updateFocus(clickedSlice.id);\n }\n\n chart.on(\"click\", drillIntoClickedSlice);\n return () => {\n chart.off(\"click\", drillIntoClickedSlice);\n };\n }, [chart, drawnSlices, updateFocus]);\n\n function formatValue(value: number): string {\n return valueFormatter ? valueFormatter(value) : String(value);\n }\n\n const legendItems: ChartLegendItem[] = items.map((item: ChartLegendItem) => ({\n ...item,\n detail: legendDetail(\n visibleSlices.find((slice: PieSlice) => slice.id === item.id),\n legendValues,\n formatValue,\n ),\n }));\n\n const isTotalVisible: boolean =\n showTotal === \"on\" || (showTotal === \"auto\" && stageMinSide >= MIN_SIZE_FOR_AUTO_TOTAL_PX);\n const centerTotal: number = focusedSlice ? focusedSlice.value : (total ?? totalOf(visibleSlices));\n const parentOfFocusedSlice: PieSlice | undefined = focusedSlice\n ? findParentSlice(visibleSlices, focusedSlice.id)\n : undefined;\n const isLegendVisible: boolean = legend !== \"none\" && data.length > 0;\n\n const centerContent = (\n <>\n <span className=\"pie-chart__total-value\">{formatValue(centerTotal)}</span>\n <span className=\"pie-chart__total-caption\">\n {focusedSlice ? focusedSlice.name : resolvedLabels.total}\n </span>\n </>\n );\n\n function goBack(): void {\n updateFocus(parentOfFocusedSlice ? parentOfFocusedSlice.id : null);\n }\n\n function renderDonutCenter() {\n if (focusedSlice) {\n return (\n <button\n type=\"button\"\n className=\"pie-chart__center pie-chart__center--button\"\n aria-label={resolvedLabels.backToPrevious(focusedSlice.name)}\n onClick={goBack}\n >\n {isTotalVisible && centerContent}\n </button>\n );\n }\n return isTotalVisible && <div className=\"pie-chart__center\">{centerContent}</div>;\n }\n\n function renderPieFooter() {\n if (focusedSlice) {\n return (\n <button\n type=\"button\"\n className=\"pie-chart__footer pie-chart__footer--button\"\n aria-label={resolvedLabels.backToPrevious(focusedSlice.name)}\n onClick={goBack}\n >\n {focusedSlice.name}\n {isTotalVisible && `: ${formatValue(centerTotal)}`}\n </button>\n );\n }\n return (\n isTotalVisible && (\n <div className=\"pie-chart__footer\">{`${resolvedLabels.total}: ${formatValue(centerTotal)}`}</div>\n )\n );\n }\n\n return (\n <div\n className={clsx(\"pie-chart\", `pie-chart--legend-${legendPosition}`, className)}\n {...props}\n >\n {isLegendVisible && (\n <ChartLegend\n className=\"pie-chart__legend\"\n items={legendItems}\n onToggle={toggleSeries}\n onColorChange={onSeriesColorChange}\n colorTokensBySeriesId={colorTokensBySeriesId}\n labels={legendLabels}\n />\n )}\n <div className=\"pie-chart__body\">\n <div ref={setStageElement} className=\"pie-chart__stage\">\n <div ref={containerRef} className=\"pie-chart__canvas\" />\n {shape === \"donut\" && renderDonutCenter()}\n </div>\n {shape === \"pie\" && renderPieFooter()}\n </div>\n </div>\n );\n}\n"],"names":["DEFAULT_LABELS","categoryName","MIN_SIZE_FOR_AUTO_TOTAL_PX","DEFAULT_LABEL_CONTENT","NO_LEGEND_VALUES","legendDetail","slice","legendValues","formatValue","hasPercent","hasValue","formatShare","useMinSide","element","minSide","setMinSide","useState","useLayoutEffect","observer","PieChart","data","shape","labelContent","showTotal","total","valueFormatter","legend","legendPosition","onSeriesColorChange","onFocusChange","legendLabels","labels","className","props","containerRef","chart","theme","resolveSeriesColor","useChartInstance","resolvedLabels","focusedNodeId","setFocusedNodeId","stageElement","setStageElement","stageMinSide","legendSeries","useMemo","node","displayNameOf","CHART_NEUTRAL_COLOR_TOKEN","items","colorsBySeriesId","colorTokensBySeriesId","hiddenSeriesIds","toggleSeries","useChartLegend","visibleSlices","buildPieSlices","focusedSlice","findSlice","drawnSlices","updateFocus","useCallback","nextFocusedNodeId","useEffect","buildPieChartOption","drillIntoClickedSlice","params","clickedId","_a","clickedSlice","value","legendItems","item","isTotalVisible","centerTotal","totalOf","parentOfFocusedSlice","findParentSlice","isLegendVisible","centerContent","jsxs","Fragment","jsx","goBack","renderDonutCenter","renderPieFooter","clsx","ChartLegend"],"mappings":";;;;;;;;;;;AAuDA,MAAMA,KAAiC;AAAA,EACrC,QAAQ;AAAA,EACR,OAAO;AAAA,EACP,gBAAgB,CAACC,MAAyB,aAAaA,CAAY;AACrE,GAEMC,KAAqC,KAErCC,KAAgD,CAAC,SAAS,GAE1DC,KAA0C,CAAA;AAkBhD,SAASC,GACPC,GACAC,GACAC,GACoB;AACpB,MAAI,CAACF,KAASC,EAAa,WAAW,EAAG;AACzC,QAAME,IAAsBF,EAAa,SAAS,SAAS,GACrDG,IAAoBH,EAAa,SAAS,OAAO;AACvD,SAAIE,KAAcC,IAAiB,GAAGF,EAAYF,EAAM,KAAK,CAAC,KAAKK,EAAYL,EAAM,KAAK,CAAC,MACpFI,IAAWF,EAAYF,EAAM,KAAK,IAAIK,EAAYL,EAAM,KAAK;AACtE;AAEA,SAASM,GAAWC,GAAqC;AACvD,QAAM,CAACC,GAASC,CAAU,IAAIC,EAAiB,CAAC;AAEhD,SAAAC,GAAgB,MAAM;AACpB,QAAI,CAACJ,EAAS;AACd,UAAMK,IAA2B,IAAI;AAAA,MAAe,MAClDH,EAAW,KAAK,IAAIF,EAAQ,aAAaA,EAAQ,YAAY,CAAC;AAAA,IAAA;AAEhE,WAAAK,EAAS,QAAQL,CAAO,GACjB,MAAMK,EAAS,WAAA;AAAA,EACxB,GAAG,CAACL,CAAO,CAAC,GAELC;AACT;AAEO,SAASK,GAAS;AAAA,EACvB,MAAAC;AAAA,EACA,OAAAC,IAAQ;AAAA,EACR,cAAAC,IAAenB;AAAA,EACf,WAAAoB,IAAY;AAAA,EACZ,OAAAC;AAAA,EACA,gBAAAC;AAAA,EACA,QAAAC,IAAS;AAAA,EACT,gBAAAC,IAAiB;AAAA,EACjB,cAAApB,IAAeH;AAAA,EACf,qBAAAwB;AAAA,EACA,eAAAC;AAAA,EACA,cAAAC;AAAA,EACA,QAAAC;AAAA,EACA,WAAAC;AAAA,EACA,GAAGC;AACL,GAAkB;AAChB,QAAM,EAAE,cAAAC,GAAc,OAAAC,GAAO,OAAAC,GAAO,oBAAAC,EAAA,IAAsCC,GAAA,GACpEC,IAAiC,EAAE,GAAGvC,IAAgB,GAAG+B,EAAA,GACzD,CAACS,GAAeC,CAAgB,IAAIzB,EAAwB,IAAI,GAChE,CAAC0B,GAAcC,CAAe,IAAI3B,EAAgC,IAAI,GACtE4B,IAAuBhC,GAAW8B,CAAY,GAE9CG,IAAoCC;AAAA,IACxC,MACE1B,EAAK,IAAI,CAAC2B,OAAwB;AAAA,MAChC,IAAIA,EAAK;AAAA,MACT,MAAMC,GAAcD,GAAMR,EAAe,MAAM;AAAA,MAC/C,YAAYQ,EAAK,eAAeA,EAAK,WAAWE,KAA4B;AAAA,IAAA,EAC5E;AAAA,IACJ,CAAC7B,GAAMmB,EAAe,MAAM;AAAA,EAAA,GAGxB;AAAA,IACJ,OAAAW;AAAA,IACA,kBAAAC;AAAA,IACA,uBAAAC;AAAA,IACA,iBAAAC;AAAA,IACA,cAAAC;AAAA,EAAA,IACoBC;AAAA,IACpBV;AAAA,KACAT,KAAA,gBAAAA,EAAO,iBAAgB,CAAA;AAAA,IACvBC;AAAA,EAAA,GAGImB,IAA4BV;AAAA,IAChC,MACEW,GAAe;AAAA,MACb,OAAOrC,EAAK,OAAO,CAAC2B,MAAuB,CAACM,EAAgB,IAAIN,EAAK,EAAE,CAAC;AAAA,MACxE,gBAAgBI;AAAA,MAChB,gBAAef,KAAA,gBAAAA,EAAO,iBAAgB;AAAA,MACtC,YAAYG,EAAe;AAAA,IAAA,CAC5B;AAAA,IACH,CAACnB,GAAMiC,GAAiBF,GAAkBf,GAAOG,EAAe,MAAM;AAAA,EAAA,GAGlEmB,IAAqCZ;AAAA,IACzC,MAAON,MAAkB,OAAO,SAAYmB,EAAUH,GAAehB,CAAa;AAAA,IAClF,CAACgB,GAAehB,CAAa;AAAA,EAAA,GAGzBoB,IAA0BF,IAAeA,EAAa,WAAWF,GAEjEK,IAAcC;AAAA,IAClB,CAACC,MAA2C;AAC1C,MAAAtB,EAAiBsB,CAAiB,GAClClC,KAAA,QAAAA,EAAgBkC;AAAA,IAClB;AAAA,IACA,CAAClC,CAAa;AAAA,EAAA;AAGhB,EAAAmC,EAAU,MAAM;AACd,IAAIxB,MAAkB,QAAQ,CAACkB,OAA0B,IAAI;AAAA,EAC/D,GAAG,CAAClB,GAAekB,GAAcG,CAAW,CAAC,GAE7CG,EAAU,MAAM;AACd,IAAI,CAAC7B,KAAS,CAACC,KACfD,EAAM;AAAA,MACJ8B,GAAoB,EAAE,QAAQL,GAAa,OAAAvC,GAAO,cAAAC,GAAc,OAAAc,GAAO,gBAAAX,GAAgB;AAAA,MACvF,EAAE,UAAU,GAAA;AAAA,IAAK;AAAA,EAErB,GAAG,CAACU,GAAOC,GAAOwB,GAAavC,GAAOC,GAAcG,CAAc,CAAC,GAEnEuC,EAAU,MAAM;AACd,QAAI,CAAC7B,EAAO;AAEZ,aAAS+B,EAAsBC,GAAkC;;AAC/D,YAAMC,KAAsBC,IAAAF,EAAO,SAAP,gBAAAE,EAAqD;AACjF,UAAI,OAAOD,KAAc,SAAU;AACnC,YAAME,IAAqCX,EAAUC,GAAaQ,CAAS;AAC3E,MAAIE,KAAgBA,EAAa,SAAS,SAAS,KAAGT,EAAYS,EAAa,EAAE;AAAA,IACnF;AAEA,WAAAnC,EAAM,GAAG,SAAS+B,CAAqB,GAChC,MAAM;AACX,MAAA/B,EAAM,IAAI,SAAS+B,CAAqB;AAAA,IAC1C;AAAA,EACF,GAAG,CAAC/B,GAAOyB,GAAaC,CAAW,CAAC;AAEpC,WAASrD,EAAY+D,GAAuB;AAC1C,WAAO9C,IAAiBA,EAAe8C,CAAK,IAAI,OAAOA,CAAK;AAAA,EAC9D;AAEA,QAAMC,IAAiCtB,EAAM,IAAI,CAACuB,OAA2B;AAAA,IAC3E,GAAGA;AAAA,IACH,QAAQpE;AAAA,MACNmD,EAAc,KAAK,CAAClD,MAAoBA,EAAM,OAAOmE,EAAK,EAAE;AAAA,MAC5DlE;AAAA,MACAC;AAAA,IAAA;AAAA,EACF,EACA,GAEIkE,IACJnD,MAAc,QAASA,MAAc,UAAUqB,KAAgB1C,IAC3DyE,IAAsBjB,IAAeA,EAAa,QAASlC,KAASoD,GAAQpB,CAAa,GACzFqB,IAA6CnB,IAC/CoB,GAAgBtB,GAAeE,EAAa,EAAE,IAC9C,QACEqB,KAA2BrD,MAAW,UAAUN,EAAK,SAAS,GAE9D4D,IACJ,gBAAAC,EAAAC,IAAA,EACE,UAAA;AAAA,IAAA,gBAAAC,EAAC,QAAA,EAAK,WAAU,0BAA0B,UAAA3E,EAAYmE,CAAW,GAAE;AAAA,IACnE,gBAAAQ,EAAC,UAAK,WAAU,4BACb,cAAezB,EAAa,OAAOnB,EAAe,MAAA,CACrD;AAAA,EAAA,GACF;AAGF,WAAS6C,IAAe;AACtB,IAAAvB,EAAYgB,IAAuBA,EAAqB,KAAK,IAAI;AAAA,EACnE;AAEA,WAASQ,KAAoB;AAC3B,WAAI3B,IAEA,gBAAAyB;AAAA,MAAC;AAAA,MAAA;AAAA,QACC,MAAK;AAAA,QACL,WAAU;AAAA,QACV,cAAY5C,EAAe,eAAemB,EAAa,IAAI;AAAA,QAC3D,SAAS0B;AAAA,QAER,UAAAV,KAAkBM;AAAA,MAAA;AAAA,IAAA,IAIlBN,KAAkB,gBAAAS,EAAC,OAAA,EAAI,WAAU,qBAAqB,UAAAH,GAAc;AAAA,EAC7E;AAEA,WAASM,KAAkB;AACzB,WAAI5B,IAEA,gBAAAuB;AAAA,MAAC;AAAA,MAAA;AAAA,QACC,MAAK;AAAA,QACL,WAAU;AAAA,QACV,cAAY1C,EAAe,eAAemB,EAAa,IAAI;AAAA,QAC3D,SAAS0B;AAAA,QAER,UAAA;AAAA,UAAA1B,EAAa;AAAA,UACbgB,KAAkB,KAAKlE,EAAYmE,CAAW,CAAC;AAAA,QAAA;AAAA,MAAA;AAAA,IAAA,IAKpDD,KACE,gBAAAS,EAAC,OAAA,EAAI,WAAU,qBAAqB,UAAA,GAAG5C,EAAe,KAAK,KAAK/B,EAAYmE,CAAW,CAAC,IAAG;AAAA,EAGjG;AAEA,SACE,gBAAAM;AAAA,IAAC;AAAA,IAAA;AAAA,MACC,WAAWM,GAAK,aAAa,qBAAqB5D,CAAc,IAAIK,CAAS;AAAA,MAC5E,GAAGC;AAAA,MAEH,UAAA;AAAA,QAAA8C,MACC,gBAAAI;AAAA,UAACK;AAAA,UAAA;AAAA,YACC,WAAU;AAAA,YACV,OAAOhB;AAAA,YACP,UAAUlB;AAAA,YACV,eAAe1B;AAAA,YACf,uBAAAwB;AAAA,YACA,QAAQtB;AAAA,UAAA;AAAA,QAAA;AAAA,QAGZ,gBAAAmD,EAAC,OAAA,EAAI,WAAU,mBACb,UAAA;AAAA,UAAA,gBAAAA,EAAC,OAAA,EAAI,KAAKtC,GAAiB,WAAU,oBACnC,UAAA;AAAA,YAAA,gBAAAwC,EAAC,OAAA,EAAI,KAAKjD,GAAc,WAAU,qBAAoB;AAAA,YACrDb,MAAU,WAAWgE,GAAA;AAAA,UAAkB,GAC1C;AAAA,UACChE,MAAU,SAASiE,GAAA;AAAA,QAAgB,EAAA,CACtC;AAAA,MAAA;AAAA,IAAA;AAAA,EAAA;AAGN;"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const E=require("../chart-label-color.cjs"),u=require("../chart-share.cjs"),p=require("./pie-chart-slices.cjs"),a=40,S=85,_=8,h=32,m=92,g=" > ",R=10,b=2;function d(e,t){return e.valueFormatter?e.valueFormatter(t):String(t)}function c(e){return e.replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,""")}function L(e,t){const o=[];return e.labelContent.includes("name")&&o.push(t.name),e.labelContent.includes("percent")&&o.push(u.formatShare(t.share)),e.labelContent.includes("value")&&o.push(d(e,t.value)),o.join(" ")}function v(e,t){const o=c(t.path.join(g)),r=c(d(e,t.value));return`<div>${o}</div><div><b>${r}</b> · ${u.formatShare(t.share)}</div>`}function s(e,t,o){return{id:t.id,name:t.name,value:t.value,itemStyle:{color:t.color},label:{color:E.labelColorOnFill(t.color)},labelText:L(e,t),tooltip:v(e,t),children:o?t.children.map(r=>s(e,r,!0)):void 0}}function T(e){const{theme:t}=e;return{trigger:"item",backgroundColor:t.tooltipBackgroundColor,borderColor:t.tooltipBorderColor,textStyle:{color:t.labelColor},formatter:o=>o.data.tooltip}}function n(e){return e.data.labelText}function f(e){return e.shape==="pie"?0:a}function I(e){return e.shape==="pie"?["0%",`${S}%`]:[`${a}%`,`${a+h}%`]}function y(e){const t=e.labelContent.length>0;return e.shape==="pie"?{show:t,position:"inside",formatter:n}:{show:t,position:"outside",color:e.theme.labelColor,formatter:n}}function A(e){const t=e.shape==="pie";return{type:"pie",radius:I(e),data:e.slices.map(o=>{const{label:r,...l}=s(e,o,!1);return t?{...l,label:r}:l}),itemStyle:{borderColor:e.theme.tooltipBackgroundColor,borderWidth:b},label:y(e),minShowLabelAngle:t?_:0,labelLine:{show:!t&&e.labelContent.length>0},labelLayout:{hideOverlap:!0},emphasis:{scale:!1}}}function N(e,t){const o=f(e),r=(m-o)/t,l=e.shape==="pie"?r:Math.min(h,r),C=Array.from({length:t},($,i)=>({r0:`${o+l*i}%`,r:`${o+l*(i+1)}%`}));return[{},...C]}function P(e){const t=e.labelContent.length>0;return{type:"sunburst",nodeClick:!1,sort:null,radius:[`${f(e)}%`,`${m}%`],data:e.slices.map(o=>s(e,o,!0)),levels:N(e,p.sliceDepth(e.slices)),itemStyle:{borderColor:e.theme.tooltipBackgroundColor,borderWidth:b},label:{show:t,rotate:"radial",minAngle:R,formatter:n},emphasis:{focus:"none"}}}function D(e){return e.some(t=>t.children.length>0)}function O(e){const{theme:t}=e;return{animation:!1,textStyle:{fontFamily:t.fontFamily,color:t.labelColor},tooltip:T(e),series:[D(e.slices)?P(e):A(e)]}}exports.buildPieChartOption=O;
|
|
2
2
|
//# sourceMappingURL=pie-chart-option.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pie-chart-option.cjs","sources":["../../../../../../src/ui/components/charts/PieChart/pie-chart-option.ts"],"sourcesContent":["import { labelColorOnFill } from \"../chart-label-color\";\nimport type { ChartTheme } from \"../chart-theme\";\nimport type { PieSlice } from \"./pie-chart-slices\";\nimport { sliceDepth } from \"./pie-chart-slices\";\n\nexport type PieChartLabelContent = \"name\" | \"percent\" | \"value\";\n\nexport type PieChartShape = \"donut\" | \"pie\";\n\nexport interface PieChartOptionInput {\n slices: PieSlice[];\n shape: PieChartShape;\n labelContent: PieChartLabelContent[];\n theme: ChartTheme;\n valueFormatter?: (value: number) => string;\n}\n\nconst DONUT_HOLE_RADIUS_PERCENT: number = 40;\n\nconst FULL_PIE_OUTER_RADIUS_PERCENT: number = 85;\n\nconst MIN_INSIDE_LABEL_ANGLE_DEGREES: number = 8;\n\nconst RING_THICKNESS_PERCENT: number = 32;\n\nconst OUTER_RADIUS_LIMIT_PERCENT: number = 92;\n\nconst PATH_SEPARATOR: string = \" > \";\n\nconst MIN_LABELED_ANGLE_DEGREES: number = 10;\n\nconst RING_BORDER_WIDTH_PX: number = 2;\n\nconst PERCENT_LABEL: Intl.NumberFormat = new Intl.NumberFormat(undefined, {\n style: \"percent\",\n maximumFractionDigits: 1,\n});\n\nexport function formatShare(share: number): string {\n return PERCENT_LABEL.format(share);\n}\n\nfunction formatValue(input: PieChartOptionInput, value: number): string {\n return input.valueFormatter ? input.valueFormatter(value) : String(value);\n}\n\nfunction escapeHtml(text: string): string {\n return text\n .replace(/&/g, \"&\")\n .replace(/</g, \"<\")\n .replace(/>/g, \">\")\n .replace(/\"/g, \""\");\n}\n\nfunction labelText(input: PieChartOptionInput, slice: PieSlice): string {\n const parts: string[] = [];\n if (input.labelContent.includes(\"name\")) parts.push(slice.name);\n if (input.labelContent.includes(\"percent\")) parts.push(formatShare(slice.share));\n if (input.labelContent.includes(\"value\")) parts.push(formatValue(input, slice.value));\n return parts.join(\" \");\n}\n\nfunction tooltipHtml(input: PieChartOptionInput, slice: PieSlice): string {\n const path: string = escapeHtml(slice.path.join(PATH_SEPARATOR));\n const value: string = escapeHtml(formatValue(input, slice.value));\n return `<div>${path}</div><div><b>${value}</b> · ${formatShare(slice.share)}</div>`;\n}\n\ninterface DataItem {\n id: string;\n name: string;\n value: number;\n itemStyle: { color: string };\n label?: { color: string };\n labelText: string;\n tooltip: string;\n children?: DataItem[];\n}\n\nfunction toDataItem(input: PieChartOptionInput, slice: PieSlice, withChildren: boolean): DataItem {\n return {\n id: slice.id,\n name: slice.name,\n value: slice.value,\n itemStyle: { color: slice.color },\n label: { color: labelColorOnFill(slice.color) },\n labelText: labelText(input, slice),\n tooltip: tooltipHtml(input, slice),\n children: withChildren\n ? slice.children.map((child: PieSlice) => toDataItem(input, child, true))\n : undefined,\n };\n}\n\nfunction tooltipOption(input: PieChartOptionInput): Record<string, unknown> {\n const { theme } = input;\n return {\n trigger: \"item\",\n backgroundColor: theme.tooltipBackgroundColor,\n borderColor: theme.tooltipBorderColor,\n textStyle: { color: theme.labelColor },\n formatter: (params: { data: DataItem }) => params.data.tooltip,\n };\n}\n\nfunction labelFormatter(params: { data: DataItem }): string {\n return params.data.labelText;\n}\n\nfunction holeRadiusPercent(input: PieChartOptionInput): number {\n return input.shape === \"pie\" ? 0 : DONUT_HOLE_RADIUS_PERCENT;\n}\n\nfunction pieRadius(input: PieChartOptionInput): [string, string] {\n if (input.shape === \"pie\") return [\"0%\", `${FULL_PIE_OUTER_RADIUS_PERCENT}%`];\n return [\n `${DONUT_HOLE_RADIUS_PERCENT}%`,\n `${DONUT_HOLE_RADIUS_PERCENT + RING_THICKNESS_PERCENT}%`,\n ];\n}\n\nfunction pieLabel(input: PieChartOptionInput): Record<string, unknown> {\n const show: boolean = input.labelContent.length > 0;\n if (input.shape === \"pie\") {\n return { show, position: \"inside\", formatter: labelFormatter };\n }\n return { show, position: \"outside\", color: input.theme.labelColor, formatter: labelFormatter };\n}\n\nfunction pieSeries(input: PieChartOptionInput): Record<string, unknown> {\n const isFullPie: boolean = input.shape === \"pie\";\n return {\n type: \"pie\",\n radius: pieRadius(input),\n data: input.slices.map((slice: PieSlice) => {\n const { label: fillLabel, ...item } = toDataItem(input, slice, false);\n return isFullPie ? { ...item, label: fillLabel } : item;\n }),\n itemStyle: { borderColor: input.theme.tooltipBackgroundColor, borderWidth: RING_BORDER_WIDTH_PX },\n label: pieLabel(input),\n minShowLabelAngle: isFullPie ? MIN_INSIDE_LABEL_ANGLE_DEGREES : 0,\n labelLine: { show: !isFullPie && input.labelContent.length > 0 },\n labelLayout: { hideOverlap: true },\n emphasis: { scale: false },\n };\n}\n\nfunction sunburstLevels(input: PieChartOptionInput, depth: number): Array<Record<string, unknown>> {\n const hole: number = holeRadiusPercent(input);\n const evenThickness: number = (OUTER_RADIUS_LIMIT_PERCENT - hole) / depth;\n const thickness: number =\n input.shape === \"pie\" ? evenThickness : Math.min(RING_THICKNESS_PERCENT, evenThickness);\n const rings: Array<Record<string, unknown>> = Array.from(\n { length: depth },\n (_unused, ringIndex: number) => ({\n r0: `${hole + thickness * ringIndex}%`,\n r: `${hole + thickness * (ringIndex + 1)}%`,\n }),\n );\n return [{}, ...rings];\n}\n\nfunction sunburstSeries(input: PieChartOptionInput): Record<string, unknown> {\n const hasLabels: boolean = input.labelContent.length > 0;\n return {\n type: \"sunburst\",\n nodeClick: false,\n sort: null,\n radius: [`${holeRadiusPercent(input)}%`, `${OUTER_RADIUS_LIMIT_PERCENT}%`],\n data: input.slices.map((slice: PieSlice) => toDataItem(input, slice, true)),\n levels: sunburstLevels(input, sliceDepth(input.slices)),\n itemStyle: { borderColor: input.theme.tooltipBackgroundColor, borderWidth: RING_BORDER_WIDTH_PX },\n label: {\n show: hasLabels,\n rotate: \"radial\",\n minAngle: MIN_LABELED_ANGLE_DEGREES,\n formatter: labelFormatter,\n },\n emphasis: { focus: \"none\" },\n };\n}\n\nfunction isHierarchical(slices: PieSlice[]): boolean {\n return slices.some((slice: PieSlice) => slice.children.length > 0);\n}\n\nexport function buildPieChartOption(input: PieChartOptionInput): Record<string, unknown> {\n const { theme } = input;\n return {\n animation: false,\n textStyle: { fontFamily: theme.fontFamily, color: theme.labelColor },\n tooltip: tooltipOption(input),\n series: [isHierarchical(input.slices) ? sunburstSeries(input) : pieSeries(input)],\n };\n}\n"],"names":["DONUT_HOLE_RADIUS_PERCENT","FULL_PIE_OUTER_RADIUS_PERCENT","MIN_INSIDE_LABEL_ANGLE_DEGREES","RING_THICKNESS_PERCENT","OUTER_RADIUS_LIMIT_PERCENT","PATH_SEPARATOR","MIN_LABELED_ANGLE_DEGREES","RING_BORDER_WIDTH_PX","PERCENT_LABEL","formatShare","share","formatValue","input","value","escapeHtml","text","labelText","slice","parts","tooltipHtml","path","toDataItem","withChildren","labelColorOnFill","child","tooltipOption","theme","params","labelFormatter","holeRadiusPercent","pieRadius","pieLabel","show","pieSeries","isFullPie","fillLabel","item","sunburstLevels","depth","hole","evenThickness","thickness","rings","_unused","ringIndex","sunburstSeries","hasLabels","sliceDepth","isHierarchical","slices","buildPieChartOption"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"pie-chart-option.cjs","sources":["../../../../../../src/ui/components/charts/PieChart/pie-chart-option.ts"],"sourcesContent":["import { labelColorOnFill } from \"../chart-label-color\";\nimport { formatShare } from \"../chart-share\";\nimport type { ChartTheme } from \"../chart-theme\";\nimport type { PieSlice } from \"./pie-chart-slices\";\nimport { sliceDepth } from \"./pie-chart-slices\";\n\nexport type PieChartLabelContent = \"name\" | \"percent\" | \"value\";\n\nexport type PieChartShape = \"donut\" | \"pie\";\n\nexport interface PieChartOptionInput {\n slices: PieSlice[];\n shape: PieChartShape;\n labelContent: PieChartLabelContent[];\n theme: ChartTheme;\n valueFormatter?: (value: number) => string;\n}\n\nconst DONUT_HOLE_RADIUS_PERCENT: number = 40;\n\nconst FULL_PIE_OUTER_RADIUS_PERCENT: number = 85;\n\nconst MIN_INSIDE_LABEL_ANGLE_DEGREES: number = 8;\n\nconst RING_THICKNESS_PERCENT: number = 32;\n\nconst OUTER_RADIUS_LIMIT_PERCENT: number = 92;\n\nconst PATH_SEPARATOR: string = \" > \";\n\nconst MIN_LABELED_ANGLE_DEGREES: number = 10;\n\nconst RING_BORDER_WIDTH_PX: number = 2;\n\nfunction formatValue(input: PieChartOptionInput, value: number): string {\n return input.valueFormatter ? input.valueFormatter(value) : String(value);\n}\n\nfunction escapeHtml(text: string): string {\n return text\n .replace(/&/g, \"&\")\n .replace(/</g, \"<\")\n .replace(/>/g, \">\")\n .replace(/\"/g, \""\");\n}\n\nfunction labelText(input: PieChartOptionInput, slice: PieSlice): string {\n const parts: string[] = [];\n if (input.labelContent.includes(\"name\")) parts.push(slice.name);\n if (input.labelContent.includes(\"percent\")) parts.push(formatShare(slice.share));\n if (input.labelContent.includes(\"value\")) parts.push(formatValue(input, slice.value));\n return parts.join(\" \");\n}\n\nfunction tooltipHtml(input: PieChartOptionInput, slice: PieSlice): string {\n const path: string = escapeHtml(slice.path.join(PATH_SEPARATOR));\n const value: string = escapeHtml(formatValue(input, slice.value));\n return `<div>${path}</div><div><b>${value}</b> · ${formatShare(slice.share)}</div>`;\n}\n\ninterface DataItem {\n id: string;\n name: string;\n value: number;\n itemStyle: { color: string };\n label?: { color: string };\n labelText: string;\n tooltip: string;\n children?: DataItem[];\n}\n\nfunction toDataItem(input: PieChartOptionInput, slice: PieSlice, withChildren: boolean): DataItem {\n return {\n id: slice.id,\n name: slice.name,\n value: slice.value,\n itemStyle: { color: slice.color },\n label: { color: labelColorOnFill(slice.color) },\n labelText: labelText(input, slice),\n tooltip: tooltipHtml(input, slice),\n children: withChildren\n ? slice.children.map((child: PieSlice) => toDataItem(input, child, true))\n : undefined,\n };\n}\n\nfunction tooltipOption(input: PieChartOptionInput): Record<string, unknown> {\n const { theme } = input;\n return {\n trigger: \"item\",\n backgroundColor: theme.tooltipBackgroundColor,\n borderColor: theme.tooltipBorderColor,\n textStyle: { color: theme.labelColor },\n formatter: (params: { data: DataItem }) => params.data.tooltip,\n };\n}\n\nfunction labelFormatter(params: { data: DataItem }): string {\n return params.data.labelText;\n}\n\nfunction holeRadiusPercent(input: PieChartOptionInput): number {\n return input.shape === \"pie\" ? 0 : DONUT_HOLE_RADIUS_PERCENT;\n}\n\nfunction pieRadius(input: PieChartOptionInput): [string, string] {\n if (input.shape === \"pie\") return [\"0%\", `${FULL_PIE_OUTER_RADIUS_PERCENT}%`];\n return [\n `${DONUT_HOLE_RADIUS_PERCENT}%`,\n `${DONUT_HOLE_RADIUS_PERCENT + RING_THICKNESS_PERCENT}%`,\n ];\n}\n\nfunction pieLabel(input: PieChartOptionInput): Record<string, unknown> {\n const show: boolean = input.labelContent.length > 0;\n if (input.shape === \"pie\") {\n return { show, position: \"inside\", formatter: labelFormatter };\n }\n return { show, position: \"outside\", color: input.theme.labelColor, formatter: labelFormatter };\n}\n\nfunction pieSeries(input: PieChartOptionInput): Record<string, unknown> {\n const isFullPie: boolean = input.shape === \"pie\";\n return {\n type: \"pie\",\n radius: pieRadius(input),\n data: input.slices.map((slice: PieSlice) => {\n const { label: fillLabel, ...item } = toDataItem(input, slice, false);\n return isFullPie ? { ...item, label: fillLabel } : item;\n }),\n itemStyle: { borderColor: input.theme.tooltipBackgroundColor, borderWidth: RING_BORDER_WIDTH_PX },\n label: pieLabel(input),\n minShowLabelAngle: isFullPie ? MIN_INSIDE_LABEL_ANGLE_DEGREES : 0,\n labelLine: { show: !isFullPie && input.labelContent.length > 0 },\n labelLayout: { hideOverlap: true },\n emphasis: { scale: false },\n };\n}\n\nfunction sunburstLevels(input: PieChartOptionInput, depth: number): Array<Record<string, unknown>> {\n const hole: number = holeRadiusPercent(input);\n const evenThickness: number = (OUTER_RADIUS_LIMIT_PERCENT - hole) / depth;\n const thickness: number =\n input.shape === \"pie\" ? evenThickness : Math.min(RING_THICKNESS_PERCENT, evenThickness);\n const rings: Array<Record<string, unknown>> = Array.from(\n { length: depth },\n (_unused, ringIndex: number) => ({\n r0: `${hole + thickness * ringIndex}%`,\n r: `${hole + thickness * (ringIndex + 1)}%`,\n }),\n );\n return [{}, ...rings];\n}\n\nfunction sunburstSeries(input: PieChartOptionInput): Record<string, unknown> {\n const hasLabels: boolean = input.labelContent.length > 0;\n return {\n type: \"sunburst\",\n nodeClick: false,\n sort: null,\n radius: [`${holeRadiusPercent(input)}%`, `${OUTER_RADIUS_LIMIT_PERCENT}%`],\n data: input.slices.map((slice: PieSlice) => toDataItem(input, slice, true)),\n levels: sunburstLevels(input, sliceDepth(input.slices)),\n itemStyle: { borderColor: input.theme.tooltipBackgroundColor, borderWidth: RING_BORDER_WIDTH_PX },\n label: {\n show: hasLabels,\n rotate: \"radial\",\n minAngle: MIN_LABELED_ANGLE_DEGREES,\n formatter: labelFormatter,\n },\n emphasis: { focus: \"none\" },\n };\n}\n\nfunction isHierarchical(slices: PieSlice[]): boolean {\n return slices.some((slice: PieSlice) => slice.children.length > 0);\n}\n\nexport function buildPieChartOption(input: PieChartOptionInput): Record<string, unknown> {\n const { theme } = input;\n return {\n animation: false,\n textStyle: { fontFamily: theme.fontFamily, color: theme.labelColor },\n tooltip: tooltipOption(input),\n series: [isHierarchical(input.slices) ? sunburstSeries(input) : pieSeries(input)],\n };\n}\n"],"names":["DONUT_HOLE_RADIUS_PERCENT","FULL_PIE_OUTER_RADIUS_PERCENT","MIN_INSIDE_LABEL_ANGLE_DEGREES","RING_THICKNESS_PERCENT","OUTER_RADIUS_LIMIT_PERCENT","PATH_SEPARATOR","MIN_LABELED_ANGLE_DEGREES","RING_BORDER_WIDTH_PX","formatValue","input","value","escapeHtml","text","labelText","slice","parts","formatShare","tooltipHtml","path","toDataItem","withChildren","labelColorOnFill","child","tooltipOption","theme","params","labelFormatter","holeRadiusPercent","pieRadius","pieLabel","show","pieSeries","isFullPie","fillLabel","item","sunburstLevels","depth","hole","evenThickness","thickness","rings","_unused","ringIndex","sunburstSeries","hasLabels","sliceDepth","isHierarchical","slices","buildPieChartOption"],"mappings":"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"}
|