@nivo/circle-packing
Version:
1 lines • 70 kB
Source Map (JSON)
{"version":3,"file":"nivo-circle-packing.mjs","sources":["../src/hooks.ts","../src/CircleHtml.tsx","../src/defaults.ts","../src/CirclePackingTooltip.tsx","../src/CircleSvg.tsx","../src/LabelSvg.tsx","../src/LabelHtml.tsx","../src/Circles.tsx","../src/Labels.tsx","../src/CirclePacking.tsx","../src/ResponsiveCirclePacking.tsx","../src/CirclePackingHtml.tsx","../src/ResponsiveCirclePackingHtml.tsx","../src/CirclePackingCanvas.tsx","../src/ResponsiveCirclePackingCanvas.tsx"],"sourcesContent":["import { useMemo, MouseEvent, MutableRefObject, useCallback } from 'react'\nimport { pack as d3Pack, hierarchy as d3Hierarchy } from 'd3-hierarchy'\nimport cloneDeep from 'lodash/cloneDeep.js'\nimport sortBy from 'lodash/sortBy.js'\nimport { usePropertyAccessor, useValueFormatter, getRelativeCursor, getDistance } from '@nivo/core'\nimport { useTheme } from '@nivo/theming'\nimport { useInheritedColor, useOrdinalColorScale } from '@nivo/colors'\nimport {\n CirclePackingDataProps,\n CirclePackingCommonProps,\n CirclePackingCustomLayerProps,\n ComputedDatum,\n MouseHandlers,\n} from './types'\n\nexport const useCirclePacking = <Datum>({\n data,\n id,\n value,\n valueFormat,\n width,\n height,\n padding,\n leavesOnly,\n colors,\n colorBy,\n inheritColorFromParent,\n childColor,\n}: {\n data: CirclePackingDataProps<Datum>['data']\n id: CirclePackingCommonProps<Datum>['id']\n value: CirclePackingCommonProps<Datum>['value']\n valueFormat?: CirclePackingCommonProps<Datum>['valueFormat']\n width: number\n height: number\n padding: CirclePackingCommonProps<Datum>['padding']\n leavesOnly: CirclePackingCommonProps<Datum>['leavesOnly']\n colors: CirclePackingCommonProps<Datum>['colors']\n colorBy: CirclePackingCommonProps<Datum>['colorBy']\n inheritColorFromParent: CirclePackingCommonProps<Datum>['inheritColorFromParent']\n childColor: CirclePackingCommonProps<Datum>['childColor']\n}): ComputedDatum<Datum>[] => {\n const getId = usePropertyAccessor<Datum, string>(id)\n const getValue = usePropertyAccessor<Datum, number>(value)\n const formatValue = useValueFormatter(valueFormat)\n\n const getColor = useOrdinalColorScale<Omit<ComputedDatum<Datum>, 'color' | 'fill'>>(\n colors,\n colorBy\n )\n const theme = useTheme()\n const getChildColor = useInheritedColor<ComputedDatum<Datum>>(childColor, theme)\n\n // d3 mutates the data for performance reasons,\n // however it does not work well with reactive programming,\n // this ensures that we don't mutate the input data\n const clonedData = cloneDeep(data)\n\n const hierarchy = d3Hierarchy<Datum>(clonedData).sum(getValue)\n\n const pack = d3Pack<Datum>().size([width, height]).padding(padding)\n const packedData = pack(hierarchy)\n\n const nodes = leavesOnly ? packedData.leaves() : packedData.descendants()\n\n // It's important to sort node by depth,\n // it ensures that we assign a parent node\n // which has already been computed, because parent nodes\n // are going to be computed first\n const sortedNodes = sortBy(nodes, 'depth')\n\n const total = hierarchy.value ?? 0\n\n return sortedNodes.reduce<ComputedDatum<Datum>[]>((acc, descendant) => {\n const id = getId(descendant.data)\n const value = descendant.value!\n const percentage = (100 * value) / total\n const path = descendant.ancestors().map(ancestor => getId(ancestor.data))\n\n let parent: ComputedDatum<Datum> | undefined\n if (descendant.parent) {\n parent = acc.find(node => node.id === getId(descendant.parent!.data))\n }\n\n const normalizedNode: ComputedDatum<Datum> = {\n id,\n path,\n value,\n percentage,\n formattedValue: valueFormat ? formatValue(value) : `${percentage.toFixed(2)}%`,\n x: descendant.x,\n y: descendant.y,\n radius: descendant.r,\n color: '',\n data: descendant.data,\n depth: descendant.depth,\n height: descendant.height,\n }\n\n if (inheritColorFromParent && parent && normalizedNode.depth > 1) {\n normalizedNode.color = getChildColor(parent)\n } else {\n normalizedNode.color = getColor(normalizedNode)\n }\n\n return [...acc, normalizedNode]\n }, [])\n}\n\nexport const useCirclePackingZoom = <Datum>(\n nodes: ComputedDatum<Datum>[],\n zoomedId: CirclePackingCommonProps<Datum>['zoomedId'],\n width: number,\n height: number\n) =>\n useMemo(() => {\n if (!zoomedId) return nodes\n\n const zoomedNode = nodes.find(({ id }) => id === zoomedId)\n if (!zoomedNode) return nodes\n\n const ratio = Math.min(width, height) / (zoomedNode.radius * 2)\n const offsetX = width / 2 - zoomedNode.x * ratio\n const offsetY = height / 2 - zoomedNode.y * ratio\n\n return nodes.map(node => ({\n ...node,\n x: node.x * ratio + offsetX,\n y: node.y * ratio + offsetY,\n radius: node.radius * ratio,\n }))\n }, [nodes, zoomedId, width, height])\n\nexport const useCirclePackingLabels = <Datum>({\n nodes,\n label,\n filter,\n skipRadius,\n textColor,\n}: {\n nodes: ComputedDatum<Datum>[]\n label: CirclePackingCommonProps<Datum>['label']\n filter: CirclePackingCommonProps<Datum>['labelsFilter']\n skipRadius: CirclePackingCommonProps<Datum>['labelsSkipRadius']\n textColor: CirclePackingCommonProps<Datum>['labelTextColor']\n}) => {\n const getLabel = usePropertyAccessor<ComputedDatum<Datum>, string | number>(label)\n const theme = useTheme()\n const getTextColor = useInheritedColor<ComputedDatum<Datum>>(textColor, theme)\n\n // computing the labels\n const labels = useMemo(\n () =>\n nodes\n .filter(node => node.radius >= skipRadius)\n .map(node => ({\n label: getLabel(node),\n textColor: getTextColor(node),\n node,\n })),\n [nodes, skipRadius, getLabel, getTextColor]\n )\n\n // apply extra filtering if provided\n return useMemo(() => {\n if (!filter) return labels\n\n return labels.filter(filter)\n }, [labels, filter])\n}\n\nexport const useNodeMouseHandlers = <Datum>(\n node: ComputedDatum<Datum>,\n { onMouseEnter, onMouseMove, onMouseLeave, onClick }: MouseHandlers<Datum>\n): Partial<\n Record<'onMouseEnter' | 'onMouseMove' | 'onMouseLeave' | 'onClick', (event: MouseEvent) => void>\n> =>\n useMemo(\n () => ({\n onMouseEnter: onMouseEnter\n ? (event: MouseEvent) => {\n onMouseEnter(node, event)\n }\n : undefined,\n onMouseMove: onMouseMove\n ? (event: MouseEvent) => {\n onMouseMove(node, event)\n }\n : undefined,\n onMouseLeave: onMouseLeave\n ? (event: MouseEvent) => {\n onMouseLeave(node, event)\n }\n : undefined,\n onClick: onClick\n ? (event: MouseEvent) => {\n onClick(node, event)\n }\n : undefined,\n }),\n [node, onMouseEnter, onMouseMove, onMouseLeave, onClick]\n )\n\nexport const useMouseCircleDetection = <Datum>({\n nodes,\n canvasEl,\n margin,\n}: {\n nodes: ComputedDatum<Datum>[]\n canvasEl: MutableRefObject<HTMLCanvasElement | null>\n margin: {\n top: number\n left: number\n }\n}) => {\n // we need to sort in order to detect higher nodes first\n const sortedNodes = useMemo(() => sortBy(nodes, 'height'), [nodes])\n\n return useCallback(\n (event: MouseEvent) => {\n if (!canvasEl.current) return null\n\n const [x, y] = getRelativeCursor(canvasEl.current, event)\n\n return sortedNodes.find(node => {\n const distanceFromNode = getDistance(\n node.x,\n node.y,\n x - margin.left,\n y - margin.top\n )\n return distanceFromNode <= node.radius\n })\n },\n [canvasEl, margin, sortedNodes]\n )\n}\n\n/**\n * Memoize the context to pass to custom layers.\n */\nexport const useCirclePackingLayerContext = <Datum>({\n nodes,\n}: {\n nodes: ComputedDatum<Datum>[]\n}): CirclePackingCustomLayerProps<Datum> =>\n useMemo(\n () => ({\n nodes,\n }),\n [nodes]\n )\n","import { animated, to, SpringValue, Interpolation } from '@react-spring/web'\nimport { CircleProps } from './types'\nimport { useNodeMouseHandlers } from './hooks'\n\nexport const interpolatePosition = (\n positionValue: SpringValue<number>,\n radiusValue: Interpolation<number>\n) => to([positionValue, radiusValue], (position, radius) => position - radius)\n\nexport const interpolateSize = (radiusValue: Interpolation<number>) =>\n to([radiusValue], radius => radius * 2)\n\nexport const interpolateBorderWidth = (borderWidth: number, radiusValue: Interpolation<number>) =>\n to([radiusValue], radius => Math.min(borderWidth, radius))\n\nexport const CircleHtml = <Datum,>({\n node,\n style,\n onMouseEnter,\n onMouseMove,\n onMouseLeave,\n onClick,\n}: CircleProps<Datum>) => {\n const size = interpolateSize(style.radius)\n\n const handlers = useNodeMouseHandlers<Datum>(node, {\n onMouseEnter,\n onMouseMove,\n onMouseLeave,\n onClick,\n })\n\n return (\n <animated.div\n style={{\n position: 'absolute',\n top: interpolatePosition(style.y, style.radius),\n left: interpolatePosition(style.x, style.radius),\n height: size,\n width: size,\n borderRadius: style.radius,\n backgroundColor: style.color,\n borderWidth: interpolateBorderWidth(style.borderWidth, style.radius),\n borderStyle: 'solid',\n borderColor: style.borderColor,\n boxSizing: 'border-box',\n }}\n onMouseEnter={handlers.onMouseEnter}\n onMouseMove={handlers.onMouseMove}\n onMouseLeave={handlers.onMouseLeave}\n onClick={handlers.onClick}\n />\n )\n}\n","import {\n CirclePackingCommonProps,\n CirclePackingLayerId,\n CirclePackingSvgPropsWithDefaults,\n CirclePackingHtmlPropsWithDefaults,\n CirclePackingCanvasPropsWithDefaults,\n} from './types'\nimport { CirclePackingTooltip } from './CirclePackingTooltip'\nimport { CircleSvg } from './CircleSvg'\nimport { LabelSvg } from './LabelSvg'\nimport { CircleHtml } from './CircleHtml'\nimport { LabelHtml } from './LabelHtml'\n\nexport const commonDefaultProps: Omit<\n CirclePackingCommonProps<any>,\n 'layers' | 'margin' | 'theme' | 'circleComponent' | 'labelComponent'\n> & {\n layers: CirclePackingLayerId[]\n} = {\n id: 'id',\n value: 'value',\n padding: 0,\n leavesOnly: false,\n layers: ['circles', 'labels'],\n colors: { scheme: 'nivo' },\n colorBy: 'depth' as const,\n inheritColorFromParent: false,\n childColor: {\n from: 'color',\n modifiers: [['darker', 0.3]],\n },\n borderWidth: 0,\n borderColor: {\n from: 'color',\n modifiers: [['darker', 0.3]],\n },\n enableLabels: false,\n label: 'id',\n labelTextColor: {\n theme: 'labels.text.fill',\n },\n labelsSkipRadius: 8,\n isInteractive: true,\n tooltip: CirclePackingTooltip,\n animate: true,\n motionConfig: 'gentle',\n role: 'img',\n renderWrapper: true,\n}\n\nexport const svgDefaultProps: Omit<\n CirclePackingSvgPropsWithDefaults<any>,\n 'data' | 'width' | 'height' | 'margin' | 'theme'\n> = {\n ...commonDefaultProps,\n circleComponent: CircleSvg,\n labelComponent: LabelSvg,\n defs: [],\n fill: [],\n}\n\nexport const htmlDefaultProps: Omit<\n CirclePackingHtmlPropsWithDefaults<any>,\n 'data' | 'width' | 'height' | 'margin' | 'theme'\n> = {\n ...commonDefaultProps,\n circleComponent: CircleHtml,\n labelComponent: LabelHtml,\n}\n\nexport const canvasDefaultProps: Omit<\n CirclePackingCanvasPropsWithDefaults<any>,\n 'data' | 'width' | 'height' | 'margin' | 'theme'\n> = {\n ...commonDefaultProps,\n pixelRatio: typeof window !== 'undefined' ? (window.devicePixelRatio ?? 1) : 1,\n}\n","import { BasicTooltip } from '@nivo/tooltip'\nimport { ComputedDatum } from './types'\n\nexport const CirclePackingTooltip = <Datum,>({\n id,\n formattedValue,\n color,\n}: ComputedDatum<Datum>) => (\n <BasicTooltip id={id} value={formattedValue} enableChip={true} color={color} />\n)\n","import { animated } from '@react-spring/web'\nimport { CircleProps } from './types'\nimport { useNodeMouseHandlers } from './hooks'\n\nexport const CircleSvg = <Datum,>({\n node,\n style,\n onMouseEnter,\n onMouseMove,\n onMouseLeave,\n onClick,\n}: CircleProps<Datum>) => {\n const handlers = useNodeMouseHandlers<Datum>(node, {\n onMouseEnter,\n onMouseMove,\n onMouseLeave,\n onClick,\n })\n\n return (\n <animated.circle\n key={node.id}\n cx={style.x}\n cy={style.y}\n r={style.radius}\n fill={node.fill || style.color}\n stroke={style.borderColor}\n strokeWidth={style.borderWidth}\n opacity={style.opacity}\n onMouseEnter={handlers.onMouseEnter}\n onMouseMove={handlers.onMouseMove}\n onMouseLeave={handlers.onMouseLeave}\n onClick={handlers.onClick}\n />\n )\n}\n","import { animated } from '@react-spring/web'\nimport { useTheme } from '@nivo/theming'\nimport { LabelProps } from './types'\n\nexport const LabelSvg = <Datum,>({ node, label, style }: LabelProps<Datum>) => {\n const theme = useTheme()\n\n return (\n <animated.text\n key={node.id}\n x={style.x}\n y={style.y}\n textAnchor=\"middle\"\n dominantBaseline=\"central\"\n style={{\n ...theme.labels.text,\n fill: style.textColor,\n opacity: style.opacity,\n pointerEvents: 'none',\n }}\n >\n {label}\n </animated.text>\n )\n}\n","import { animated } from '@react-spring/web'\nimport { useTheme } from '@nivo/theming'\nimport { LabelProps } from './types'\nimport { interpolatePosition, interpolateSize } from './CircleHtml'\n\nexport const LabelHtml = <Datum,>({ node, label, style }: LabelProps<Datum>) => {\n const theme = useTheme()\n const size = interpolateSize(style.radius)\n\n return (\n <animated.div\n key={node.id}\n style={{\n ...theme.labels.text,\n position: 'absolute',\n display: 'flex',\n justifyContent: 'center',\n alignItems: 'center',\n top: interpolatePosition(style.y, style.radius),\n left: interpolatePosition(style.x, style.radius),\n width: size,\n height: size,\n color: style.textColor,\n opacity: style.opacity,\n pointerEvents: 'none',\n }}\n >\n {label}\n </animated.div>\n )\n}\n","import { createElement, useMemo, MouseEvent } from 'react'\nimport * as React from 'react'\nimport { useTransition, to, SpringValue } from '@react-spring/web'\nimport { useMotionConfig } from '@nivo/core'\nimport { useTheme } from '@nivo/theming'\nimport { useInheritedColor } from '@nivo/colors'\nimport { useTooltip } from '@nivo/tooltip'\nimport { ComputedDatum, CircleComponent, MouseHandlers, CirclePackingCommonProps } from './types'\n\n/**\n * A negative radius value is invalid for an SVG circle,\n * this custom interpolation makes sure it's either\n * positive or zero.\n */\nexport const interpolateRadius = (radiusValue: SpringValue<number>) =>\n to([radiusValue], radius => Math.max(0, radius))\n\ntype CirclesProps<Datum> = {\n nodes: ComputedDatum<Datum>[]\n borderWidth: CirclePackingCommonProps<Datum>['borderWidth']\n borderColor: CirclePackingCommonProps<Datum>['borderColor']\n component: CircleComponent<Datum>\n isInteractive: CirclePackingCommonProps<Datum>['isInteractive']\n tooltip: CirclePackingCommonProps<Datum>['tooltip']\n} & MouseHandlers<Datum>\n\nconst getTransitionPhases = <Datum,>(getBorderColor: (node: ComputedDatum<Datum>) => string) => ({\n enter: (node: ComputedDatum<Datum>) => ({\n x: node.x,\n y: node.y,\n radius: 0,\n color: node.color,\n borderColor: getBorderColor(node),\n opacity: 0,\n }),\n update: (node: ComputedDatum<Datum>) => ({\n x: node.x,\n y: node.y,\n radius: node.radius,\n color: node.color,\n borderColor: getBorderColor(node),\n opacity: 1,\n }),\n leave: (node: ComputedDatum<Datum>) => ({\n x: node.x,\n y: node.y,\n radius: 0,\n color: node.color,\n borderColor: getBorderColor(node),\n opacity: 0,\n }),\n})\n\nexport const Circles = <Datum,>({\n nodes,\n borderWidth,\n borderColor,\n component,\n isInteractive,\n onMouseEnter,\n onMouseMove,\n onMouseLeave,\n onClick,\n tooltip,\n}: CirclesProps<Datum>) => {\n const { showTooltipFromEvent, hideTooltip } = useTooltip()\n\n const handleMouseEnter = useMemo(() => {\n if (!isInteractive) return undefined\n\n return (node: ComputedDatum<Datum>, event: MouseEvent) => {\n showTooltipFromEvent(createElement(tooltip, node), event)\n onMouseEnter?.(node, event)\n }\n }, [isInteractive, showTooltipFromEvent, tooltip, onMouseEnter])\n\n const handleMouseMove = useMemo(() => {\n if (!isInteractive) return undefined\n\n return (node: ComputedDatum<Datum>, event: MouseEvent) => {\n showTooltipFromEvent(createElement(tooltip, node), event)\n onMouseMove?.(node, event)\n }\n }, [isInteractive, showTooltipFromEvent, tooltip, onMouseMove])\n\n const handleMouseLeave = useMemo(() => {\n if (!isInteractive) return undefined\n\n return (node: ComputedDatum<Datum>, event: MouseEvent) => {\n hideTooltip()\n onMouseLeave?.(node, event)\n }\n }, [isInteractive, hideTooltip, onMouseLeave])\n\n const handleClick = useMemo(() => {\n if (!isInteractive) return undefined\n\n return (node: ComputedDatum<Datum>, event: MouseEvent) => {\n onClick?.(node, event)\n }\n }, [isInteractive, onClick])\n\n const { animate, config: springConfig } = useMotionConfig()\n\n const theme = useTheme()\n const getBorderColor = useInheritedColor<ComputedDatum<Datum>>(borderColor, theme)\n\n const transitionPhases = useMemo(\n () => getTransitionPhases<Datum>(getBorderColor),\n [getBorderColor]\n )\n\n const transition = useTransition<\n ComputedDatum<Datum>,\n {\n x: number\n y: number\n radius: number\n color: string\n borderColor: string\n opacity: number\n }\n >(nodes, {\n keys: node => node.id,\n initial: transitionPhases.update,\n from: transitionPhases.enter,\n enter: transitionPhases.update,\n update: transitionPhases.update,\n leave: transitionPhases.leave,\n config: springConfig,\n immediate: !animate,\n })\n\n return (\n <>\n {transition((transitionProps, node) => {\n return React.createElement(component, {\n key: node.id,\n node,\n style: {\n ...transitionProps,\n radius: interpolateRadius(transitionProps.radius),\n borderWidth,\n },\n onMouseEnter: handleMouseEnter,\n onMouseMove: handleMouseMove,\n onMouseLeave: handleMouseLeave,\n onClick: handleClick,\n })\n })}\n </>\n )\n}\n","import { createElement, useMemo } from 'react'\nimport { useTransition } from '@react-spring/web'\nimport { useMotionConfig } from '@nivo/core'\nimport { CirclePackingCommonProps, ComputedDatum, LabelComponent, ComputedLabel } from './types'\nimport { useCirclePackingLabels } from './hooks'\nimport { interpolateRadius } from './Circles'\n\ninterface CirclesProps<Datum> {\n nodes: ComputedDatum<Datum>[]\n label: CirclePackingCommonProps<Datum>['label']\n filter?: CirclePackingCommonProps<Datum>['labelsFilter']\n skipRadius: CirclePackingCommonProps<Datum>['labelsSkipRadius']\n textColor: CirclePackingCommonProps<Datum>['labelTextColor']\n component: LabelComponent<Datum>\n}\n\nconst getTransitionPhases = <Datum,>() => ({\n enter: (label: ComputedLabel<Datum>) => ({\n x: label.node.x,\n y: label.node.y,\n radius: label.node.radius,\n textColor: label.textColor,\n opacity: 0,\n }),\n update: (label: ComputedLabel<Datum>) => ({\n x: label.node.x,\n y: label.node.y,\n radius: label.node.radius,\n textColor: label.textColor,\n opacity: 1,\n }),\n leave: (label: ComputedLabel<Datum>) => ({\n x: label.node.x,\n y: label.node.y,\n radius: label.node.radius,\n textColor: label.textColor,\n opacity: 0,\n }),\n})\n\nexport const Labels = <Datum,>({\n nodes,\n label,\n filter,\n skipRadius,\n textColor,\n component,\n}: CirclesProps<Datum>) => {\n const { animate, config: springConfig } = useMotionConfig()\n\n const labels = useCirclePackingLabels({\n nodes,\n label,\n filter,\n skipRadius,\n textColor,\n })\n\n const transitionPhases = useMemo(() => getTransitionPhases<Datum>(), [])\n\n const transition = useTransition<\n ComputedLabel<Datum>,\n {\n x: number\n y: number\n radius: number\n textColor: string\n opacity: number\n }\n >(labels, {\n keys: label => label.node.id,\n initial: transitionPhases.update,\n from: transitionPhases.enter,\n enter: transitionPhases.update,\n update: transitionPhases.update,\n leave: transitionPhases.leave,\n config: springConfig,\n immediate: !animate,\n })\n\n return (\n <>\n {transition((transitionProps, label) => {\n return createElement(component, {\n key: label.node.id,\n label: label.label,\n style: {\n ...transitionProps,\n radius: interpolateRadius(transitionProps.radius),\n },\n node: label.node,\n })\n })}\n </>\n )\n}\n","import { createElement, forwardRef, Fragment, ReactElement, ReactNode, Ref, useMemo } from 'react'\nimport {\n // @ts-expect-error no types\n bindDefs,\n useDimensions,\n Container,\n SvgWrapper,\n WithChartRef,\n} from '@nivo/core'\nimport { InheritedColorConfig, OrdinalColorScaleConfig } from '@nivo/colors'\nimport { CirclePackingLayerId, CirclePackingSvgProps, ComputedDatum } from './types'\nimport { useCirclePacking, useCirclePackingZoom, useCirclePackingLayerContext } from './hooks'\nimport { svgDefaultProps } from './defaults'\nimport { Circles } from './Circles'\nimport { Labels } from './Labels'\n\ntype InnerCirclePackingProps<Datum> = Omit<\n CirclePackingSvgProps<Datum>,\n 'animate' | 'motionConfig'\n> & {\n forwardedRef: Ref<SVGSVGElement>\n}\n\nconst InnerCirclePacking = <Datum,>({\n data,\n id = svgDefaultProps.id,\n value = svgDefaultProps.value,\n valueFormat,\n width,\n height,\n margin: partialMargin,\n padding = svgDefaultProps.padding,\n leavesOnly = svgDefaultProps.leavesOnly,\n colors = svgDefaultProps.colors as OrdinalColorScaleConfig<\n Omit<ComputedDatum<Datum>, 'color' | 'fill'>\n >,\n colorBy = svgDefaultProps.colorBy,\n inheritColorFromParent = svgDefaultProps.inheritColorFromParent,\n childColor = svgDefaultProps.childColor as InheritedColorConfig<ComputedDatum<Datum>>,\n borderWidth = svgDefaultProps.borderWidth,\n borderColor = svgDefaultProps.borderColor as InheritedColorConfig<ComputedDatum<Datum>>,\n circleComponent = svgDefaultProps.circleComponent,\n defs = svgDefaultProps.defs,\n fill = svgDefaultProps.fill,\n enableLabels = svgDefaultProps.enableLabels,\n label = svgDefaultProps.label,\n labelsFilter,\n labelsSkipRadius = svgDefaultProps.labelsSkipRadius,\n labelTextColor = svgDefaultProps.labelTextColor as InheritedColorConfig<ComputedDatum<Datum>>,\n labelComponent = svgDefaultProps.labelComponent,\n layers = svgDefaultProps.layers,\n isInteractive = svgDefaultProps.isInteractive,\n onMouseEnter,\n onMouseMove,\n onMouseLeave,\n onClick,\n tooltip = svgDefaultProps.tooltip,\n zoomedId,\n role = svgDefaultProps.role,\n forwardedRef,\n}: InnerCirclePackingProps<Datum>) => {\n const { outerWidth, outerHeight, margin, innerWidth, innerHeight } = useDimensions(\n width,\n height,\n partialMargin\n )\n\n const nodes = useCirclePacking<Datum>({\n data,\n id,\n value,\n valueFormat,\n width: innerWidth,\n height: innerHeight,\n padding,\n leavesOnly,\n colors,\n colorBy,\n inheritColorFromParent,\n childColor,\n })\n\n const zoomedNodes = useCirclePackingZoom<Datum>(nodes, zoomedId, innerWidth, innerHeight)\n\n const boundDefs = useMemo(\n () => bindDefs(defs, zoomedNodes, fill, { targetKey: 'fill' }),\n [defs, zoomedNodes, fill]\n )\n\n const layerById: Record<CirclePackingLayerId, ReactNode> = {\n circles: null,\n labels: null,\n }\n\n if (layers.includes('circles')) {\n layerById.circles = (\n <Circles<Datum>\n key=\"circles\"\n nodes={zoomedNodes}\n borderWidth={borderWidth}\n borderColor={borderColor}\n isInteractive={isInteractive}\n onMouseEnter={onMouseEnter}\n onMouseMove={onMouseMove}\n onMouseLeave={onMouseLeave}\n onClick={onClick}\n component={circleComponent}\n tooltip={tooltip}\n />\n )\n }\n\n if (enableLabels && layers.includes('labels')) {\n layerById.labels = (\n <Labels<Datum>\n key=\"labels\"\n nodes={zoomedNodes}\n label={label}\n filter={labelsFilter}\n skipRadius={labelsSkipRadius}\n textColor={labelTextColor}\n component={labelComponent}\n />\n )\n }\n\n const layerContext = useCirclePackingLayerContext<Datum>({\n nodes,\n })\n\n return (\n <SvgWrapper\n width={outerWidth}\n height={outerHeight}\n margin={margin}\n defs={boundDefs}\n role={role}\n ref={forwardedRef}\n >\n {layers.map((layer, i) => {\n if (layerById[layer as CirclePackingLayerId] !== undefined) {\n return layerById[layer as CirclePackingLayerId]\n }\n\n if (typeof layer === 'function') {\n return <Fragment key={i}>{createElement(layer, layerContext)}</Fragment>\n }\n\n return null\n })}\n </SvgWrapper>\n )\n}\n\nexport const CirclePacking = forwardRef(\n <Datum,>(\n {\n isInteractive = svgDefaultProps.isInteractive,\n animate = svgDefaultProps.animate,\n motionConfig = svgDefaultProps.motionConfig,\n theme,\n renderWrapper,\n ...props\n }: CirclePackingSvgProps<Datum>,\n ref: Ref<SVGSVGElement>\n ) => (\n <Container\n animate={animate}\n isInteractive={isInteractive}\n motionConfig={motionConfig}\n renderWrapper={renderWrapper}\n theme={theme}\n >\n <InnerCirclePacking<Datum>\n isInteractive={isInteractive}\n {...props}\n forwardedRef={ref}\n />\n </Container>\n )\n) as <Datum>(props: WithChartRef<CirclePackingSvgProps<Datum>, SVGSVGElement>) => ReactElement\n","import { forwardRef, ReactElement, Ref } from 'react'\nimport { ResponsiveProps, ResponsiveWrapper, WithChartRef } from '@nivo/core'\nimport { CirclePackingSvgProps } from './types'\nimport { CirclePacking } from './CirclePacking'\n\nexport const ResponsiveCirclePacking = forwardRef(\n <Datum,>(\n {\n defaultWidth,\n defaultHeight,\n onResize,\n debounceResize,\n ...props\n }: ResponsiveProps<CirclePackingSvgProps<Datum>>,\n ref: Ref<SVGSVGElement>\n ) => (\n <ResponsiveWrapper\n defaultWidth={defaultWidth}\n defaultHeight={defaultHeight}\n onResize={onResize}\n debounceResize={debounceResize}\n >\n {({ width, height }) => (\n <CirclePacking<Datum> width={width} height={height} {...props} ref={ref} />\n )}\n </ResponsiveWrapper>\n )\n) as <Datum>(\n props: WithChartRef<ResponsiveProps<CirclePackingSvgProps<Datum>>, SVGSVGElement>\n) => ReactElement\n","import { createElement, Fragment, ReactNode, forwardRef, Ref, ReactElement } from 'react'\nimport { Container, useDimensions, WithChartRef } from '@nivo/core'\nimport { InheritedColorConfig, OrdinalColorScaleConfig } from '@nivo/colors'\nimport { CirclePackingHtmlProps, CirclePackingLayerId, ComputedDatum } from './types'\nimport { useCirclePacking, useCirclePackingLayerContext, useCirclePackingZoom } from './hooks'\nimport { Circles } from './Circles'\nimport { htmlDefaultProps } from './defaults'\nimport { Labels } from './Labels'\n\ntype InnerCirclePackingHtmlProps<Datum> = Omit<\n CirclePackingHtmlProps<Datum>,\n 'animate' | 'motionConfig'\n> & {\n forwardedRef: Ref<HTMLDivElement>\n}\n\nexport const InnerCirclePackingHtml = <Datum,>({\n data,\n id = htmlDefaultProps.id,\n value = htmlDefaultProps.value,\n valueFormat,\n width,\n height,\n margin: partialMargin,\n padding = htmlDefaultProps.padding,\n leavesOnly = htmlDefaultProps.leavesOnly,\n colors = htmlDefaultProps.colors as OrdinalColorScaleConfig<\n Omit<ComputedDatum<Datum>, 'color' | 'fill'>\n >,\n colorBy = htmlDefaultProps.colorBy,\n inheritColorFromParent = htmlDefaultProps.inheritColorFromParent,\n childColor = htmlDefaultProps.childColor as InheritedColorConfig<ComputedDatum<Datum>>,\n borderWidth = htmlDefaultProps.borderWidth,\n borderColor = htmlDefaultProps.borderColor as InheritedColorConfig<ComputedDatum<Datum>>,\n circleComponent = htmlDefaultProps.circleComponent,\n enableLabels = htmlDefaultProps.enableLabels,\n label = htmlDefaultProps.label,\n labelsFilter,\n labelsSkipRadius = htmlDefaultProps.labelsSkipRadius,\n labelTextColor = htmlDefaultProps.labelTextColor as InheritedColorConfig<ComputedDatum<Datum>>,\n labelComponent = htmlDefaultProps.labelComponent,\n layers = htmlDefaultProps.layers,\n isInteractive = htmlDefaultProps.isInteractive,\n onMouseEnter,\n onMouseMove,\n onMouseLeave,\n onClick,\n tooltip = htmlDefaultProps.tooltip,\n zoomedId,\n role = htmlDefaultProps.role,\n forwardedRef,\n}: InnerCirclePackingHtmlProps<Datum>) => {\n const { outerWidth, outerHeight, margin, innerWidth, innerHeight } = useDimensions(\n width,\n height,\n partialMargin\n )\n\n const nodes = useCirclePacking<Datum>({\n data,\n id,\n value,\n valueFormat,\n width: innerWidth,\n height: innerHeight,\n padding,\n leavesOnly,\n colors,\n colorBy,\n inheritColorFromParent,\n childColor,\n })\n\n const zoomedNodes = useCirclePackingZoom<Datum>(nodes, zoomedId, innerWidth, innerHeight)\n\n const layerById: Record<CirclePackingLayerId, ReactNode> = {\n circles: null,\n labels: null,\n }\n\n if (layers.includes('circles')) {\n layerById.circles = (\n <Circles<Datum>\n key=\"circles\"\n nodes={zoomedNodes}\n borderWidth={borderWidth}\n borderColor={borderColor}\n isInteractive={isInteractive}\n onMouseEnter={onMouseEnter}\n onMouseMove={onMouseMove}\n onMouseLeave={onMouseLeave}\n onClick={onClick}\n component={circleComponent}\n tooltip={tooltip}\n />\n )\n }\n\n if (enableLabels && layers.includes('labels')) {\n layerById.labels = (\n <Labels<Datum>\n key=\"labels\"\n nodes={zoomedNodes}\n label={label}\n filter={labelsFilter}\n skipRadius={labelsSkipRadius}\n textColor={labelTextColor}\n component={labelComponent}\n />\n )\n }\n\n const layerContext = useCirclePackingLayerContext<Datum>({\n nodes,\n })\n\n return (\n <div\n role={role}\n style={{\n position: 'relative',\n overflow: 'hidden',\n width: outerWidth,\n height: outerHeight,\n }}\n ref={forwardedRef}\n >\n <div\n style={{\n position: 'absolute',\n top: margin.top,\n left: margin.left,\n }}\n >\n {layers.map((layer, i) => {\n if (layerById[layer as CirclePackingLayerId] !== undefined) {\n return layerById[layer as CirclePackingLayerId]\n }\n\n if (typeof layer === 'function') {\n return <Fragment key={i}>{createElement(layer, layerContext)}</Fragment>\n }\n\n return null\n })}\n </div>\n </div>\n )\n}\n\nexport const CirclePackingHtml = forwardRef(\n <Datum,>(\n {\n theme,\n isInteractive = htmlDefaultProps.isInteractive,\n animate = htmlDefaultProps.animate,\n motionConfig = htmlDefaultProps.motionConfig,\n ...otherProps\n }: CirclePackingHtmlProps<Datum>,\n ref: Ref<HTMLDivElement>\n ) => (\n <Container\n isInteractive={isInteractive}\n animate={animate}\n motionConfig={motionConfig}\n theme={theme}\n >\n <InnerCirclePackingHtml<Datum>\n isInteractive={isInteractive}\n {...otherProps}\n forwardedRef={ref}\n />\n </Container>\n )\n) as <Datum>(props: WithChartRef<CirclePackingHtmlProps<Datum>, HTMLDivElement>) => ReactElement\n","import { forwardRef, Ref, ReactElement } from 'react'\nimport { ResponsiveWrapper, ResponsiveProps, WithChartRef } from '@nivo/core'\nimport { CirclePackingHtmlProps } from './types'\nimport { CirclePackingHtml } from './CirclePackingHtml'\n\nexport const ResponsiveCirclePackingHtml = forwardRef(\n <Datum,>(\n {\n defaultWidth,\n defaultHeight,\n onResize,\n debounceResize,\n ...props\n }: ResponsiveProps<CirclePackingHtmlProps<Datum>>,\n ref: Ref<HTMLDivElement>\n ) => (\n <ResponsiveWrapper\n defaultWidth={defaultWidth}\n defaultHeight={defaultHeight}\n onResize={onResize}\n debounceResize={debounceResize}\n >\n {({ width, height }: { width: number; height: number }) => (\n <CirclePackingHtml<Datum> width={width} height={height} {...props} ref={ref} />\n )}\n </ResponsiveWrapper>\n )\n) as <Datum>(\n props: WithChartRef<ResponsiveProps<CirclePackingHtmlProps<Datum>>, HTMLDivElement>\n) => ReactElement\n","import {\n useCallback,\n useEffect,\n useRef,\n createElement,\n MouseEvent,\n forwardRef,\n ReactElement,\n Ref,\n} from 'react'\nimport { useDimensions, Container, mergeRefs, WithChartRef } from '@nivo/core'\nimport { useTheme } from '@nivo/theming'\nimport { InheritedColorConfig, OrdinalColorScaleConfig, useInheritedColor } from '@nivo/colors'\nimport { useTooltip } from '@nivo/tooltip'\nimport { CirclePackingCanvasProps, ComputedDatum } from './types'\nimport { canvasDefaultProps } from './defaults'\nimport {\n useCirclePacking,\n useCirclePackingZoom,\n useCirclePackingLabels,\n useMouseCircleDetection,\n} from './hooks'\n\ntype InnerCirclePackingCanvasProps<Datum> = Omit<\n CirclePackingCanvasProps<Datum>,\n 'animate' | 'motionConfig'\n> & {\n forwardedRef: Ref<HTMLCanvasElement>\n}\n\nconst InnerCirclePackingCanvas = <Datum,>({\n data,\n id = canvasDefaultProps.id,\n value = canvasDefaultProps.value,\n valueFormat,\n width,\n height,\n margin: partialMargin,\n padding = canvasDefaultProps.padding,\n leavesOnly = canvasDefaultProps.leavesOnly,\n colors = canvasDefaultProps.colors as OrdinalColorScaleConfig<\n Omit<ComputedDatum<Datum>, 'color' | 'fill'>\n >,\n colorBy = canvasDefaultProps.colorBy,\n inheritColorFromParent = canvasDefaultProps.inheritColorFromParent,\n childColor = canvasDefaultProps.childColor as InheritedColorConfig<ComputedDatum<Datum>>,\n borderWidth = canvasDefaultProps.borderWidth,\n borderColor = canvasDefaultProps.borderColor as InheritedColorConfig<ComputedDatum<Datum>>,\n enableLabels = canvasDefaultProps.enableLabels,\n label = canvasDefaultProps.label,\n labelsFilter,\n labelsSkipRadius = canvasDefaultProps.labelsSkipRadius,\n labelTextColor = canvasDefaultProps.labelTextColor as InheritedColorConfig<\n ComputedDatum<Datum>\n >,\n isInteractive = canvasDefaultProps.isInteractive,\n onMouseMove,\n onClick,\n tooltip = canvasDefaultProps.tooltip,\n zoomedId,\n role = canvasDefaultProps.role,\n pixelRatio = canvasDefaultProps.pixelRatio,\n forwardedRef,\n}: InnerCirclePackingCanvasProps<Datum>) => {\n const canvasEl = useRef<HTMLCanvasElement | null>(null)\n const theme = useTheme()\n\n const { margin, innerWidth, innerHeight, outerWidth, outerHeight } = useDimensions(\n width,\n height,\n partialMargin\n )\n\n const nodes = useCirclePacking<Datum>({\n data,\n id,\n value,\n valueFormat,\n width: innerWidth,\n height: innerHeight,\n padding,\n leavesOnly,\n colors,\n colorBy,\n inheritColorFromParent,\n childColor,\n })\n\n const zoomedNodes = useCirclePackingZoom<Datum>(nodes, zoomedId, innerWidth, innerHeight)\n\n const labels = useCirclePackingLabels({\n nodes: zoomedNodes,\n label,\n filter: labelsFilter,\n skipRadius: labelsSkipRadius,\n textColor: labelTextColor,\n })\n\n const getBorderColor = useInheritedColor<ComputedDatum<Datum>>(borderColor, theme)\n\n useEffect(() => {\n if (!canvasEl.current) return\n\n canvasEl.current.width = outerWidth * pixelRatio\n canvasEl.current.height = outerHeight * pixelRatio\n\n const ctx = canvasEl.current.getContext('2d')!\n\n ctx.scale(pixelRatio, pixelRatio)\n\n ctx.fillStyle = theme.background\n ctx.fillRect(0, 0, outerWidth, outerHeight)\n\n ctx.save()\n ctx.translate(margin.left, margin.top)\n\n zoomedNodes.forEach(node => {\n if (borderWidth > 0) {\n ctx.strokeStyle = getBorderColor(node)\n ctx.lineWidth = borderWidth\n }\n\n ctx.beginPath()\n ctx.arc(node.x, node.y, node.radius, 0, 2 * Math.PI)\n ctx.fillStyle = node.color\n ctx.fill()\n\n if (borderWidth > 0) {\n ctx.stroke()\n }\n })\n\n if (enableLabels) {\n ctx.textAlign = 'center'\n ctx.textBaseline = 'middle'\n ctx.font = `${theme.labels.text.fontSize}px ${theme.labels.text.fontFamily}`\n\n labels.forEach(label => {\n ctx.fillStyle = label.textColor\n ctx.fillText(`${label.label}`, label.node.x, label.node.y)\n })\n }\n }, [\n canvasEl,\n innerWidth,\n innerHeight,\n outerWidth,\n outerHeight,\n margin.top,\n margin.left,\n theme,\n pixelRatio,\n zoomedNodes,\n enableLabels,\n labels,\n borderWidth,\n getBorderColor,\n ])\n\n const getNodeFromMouseEvent = useMouseCircleDetection<Datum>({\n nodes: zoomedNodes,\n canvasEl,\n margin,\n })\n\n const { showTooltipFromEvent, hideTooltip } = useTooltip()\n\n const handleMouseHover = useCallback(\n (event: MouseEvent<HTMLCanvasElement>) => {\n const node = getNodeFromMouseEvent(event)\n if (node) {\n onMouseMove?.(node, event)\n showTooltipFromEvent(createElement(tooltip, node), event)\n } else {\n hideTooltip()\n }\n },\n [getNodeFromMouseEvent, showTooltipFromEvent, tooltip, hideTooltip, onMouseMove]\n )\n\n const handleMouseLeave = useCallback(() => {\n hideTooltip()\n }, [hideTooltip])\n\n const handleClick = useCallback(\n (event: MouseEvent<HTMLCanvasElement>) => {\n if (!onClick) return\n\n const node = getNodeFromMouseEvent(event)\n if (node) {\n onClick(node, event)\n }\n },\n [getNodeFromMouseEvent, onClick]\n )\n\n return (\n <canvas\n ref={mergeRefs(canvasEl, forwardedRef)}\n width={outerWidth * pixelRatio}\n height={outerHeight * pixelRatio}\n style={{\n width: outerWidth,\n height: outerHeight,\n cursor: isInteractive ? 'auto' : 'normal',\n }}\n role={role}\n onMouseEnter={isInteractive ? handleMouseHover : undefined}\n onMouseMove={isInteractive ? handleMouseHover : undefined}\n onMouseLeave={isInteractive ? handleMouseLeave : undefined}\n onClick={isInteractive ? handleClick : undefined}\n />\n )\n}\n\nexport const CirclePackingCanvas = forwardRef(\n <Datum,>(\n {\n isInteractive = canvasDefaultProps.isInteractive,\n theme,\n ...otherProps\n }: CirclePackingCanvasProps<Datum>,\n ref: Ref<HTMLCanvasElement>\n ) => (\n <Container isInteractive={isInteractive} theme={theme}>\n <InnerCirclePackingCanvas<Datum>\n isInteractive={isInteractive}\n {...otherProps}\n forwardedRef={ref}\n />\n </Container>\n )\n) as <Datum>(\n props: WithChartRef<CirclePackingCanvasProps<Datum>, HTMLCanvasElement>\n) => ReactElement\n","import { forwardRef, ReactElement, Ref } from 'react'\nimport { ResponsiveWrapper, WithChartRef, ResponsiveProps } from '@nivo/core'\nimport { CirclePackingCanvasProps } from './types'\nimport { CirclePackingCanvas } from './CirclePackingCanvas'\n\nexport const ResponsiveCirclePackingCanvas = forwardRef(\n <Datum,>(\n {\n defaultWidth,\n defaultHeight,\n onResize,\n debounceResize,\n ...props\n }: ResponsiveProps<CirclePackingCanvasProps<Datum>>,\n ref: Ref<HTMLCanvasElement>\n ) => (\n <ResponsiveWrapper\n defaultWidth={defaultWidth}\n defaultHeight={defaultWidth}\n onResize={onResize}\n debounceResize={debounceResize}\n >\n {({ width, height }: { width: number; height: number }) => (\n <CirclePackingCanvas<Datum> width={width} height={height} {...props} ref={ref} />\n )}\n </ResponsiveWrapper>\n )\n) as <Datum>(\n props: WithChartRef<ResponsiveProps<CirclePackingCanvasProps<Datum>>, HTMLCanvasElement>\n) => ReactElement\n"],"names":["useCirclePacking","_ref","_hierarchy$value","data","id","value","valueFormat","width","height","padding","leavesOnly","colors","colorBy","inheritColorFromParent","childColor","getId","usePropertyAccessor","getValue","formatValue","useValueFormatter","getColor","useOrdinalColorScale","theme","useTheme","getChildColor","useInheritedColor","clonedData","cloneDeep","hierarchy","d3Hierarchy","sum","packedData","d3Pack","size","pack","nodes","leaves","descendants","sortedNodes","sortBy","total","reduce","acc","descendant","parent","percentage","path","ancestors","map","ancestor","find","node","normalizedNode","formattedValue","toFixed","x","y","radius","r","color","depth","concat","useCirclePackingZoom","zoomedId","useMemo","zoomedNode","_ref2","ratio","Math","min","offsetX","offsetY","_extends","useCirclePackingLabels","_ref3","label","filter","skipRadius","textColor","getLabel","getTextColor","labels","useNodeMouseHandlers","_ref4","onMouseEnter","onMouseMove","onMouseLeave","onClick","event","undefined","useMouseCircleDetection","_ref5","canvasEl","margin","useCallback","current","_getRelativeCursor","getRelativeCursor","getDistance","left","top","useCirclePackingLayerContext","_ref6","interpolatePosition","positionValue","radiusValue","to","position","interpolateSize","commonDefaultProps","layers","scheme","from","modifiers","borderWidth","borderColor","enableLabels","labelTextColor","labelsSkipRadius","isInteractive","tooltip","_jsx","BasicTooltip","enableChip","animate","motionConfig","role","renderWrapper","svgDefaultProps","circleComponent","style","handlers","animated","circle","cx","cy","fill","stroke","strokeWidth","opacity","labelComponent","text","textAnchor","dominantBaseline","pointerEvents","children","defs","htmlDefaultProps","div","borderRadius","backgroundColor","borderStyle","boxSizing","display","justifyContent","alignItems","canvasDefaultProps","pixelRatio","window","_window$devicePixelRa","devicePixelRatio","interpolateRadius","max","Circles","component","_useTooltip","useTooltip","showTooltipFromEvent","hideTooltip","handleMouseEnter","createElement","handleMouseMove","handleMouseLeave","handleClick","_useMotionConfig","useMotionConfig","springConfig","config","getBorderColor","transitionPhases","enter","update","leave","getTransitionPhases","transition","useTransition","keys","initial","immediate","_Fragment","transitionProps","React","key","Labels","InnerCirclePacking","_ref$id","_ref$value","partialMargin","_ref$padding","_ref$leavesOnly","_ref$colors","_ref$colorBy","_ref$inheritColorFrom","_ref$childColor","_ref$borderWidth","_ref$borderColor","_ref$circleComponent","_ref$defs","_ref$fill","_ref$enableLabels","_ref$label","labelsFilter","_ref$labelsSkipRadius","_ref$labelTextColor","_ref$labelComponent","_ref$layers","_ref$isInteractive","_ref$tooltip","_ref$role","forwardedRef","_useDimensions","useDimensions","outerWidth","outerHeight","innerWidth","innerHeight","zoomedNodes","boundDefs","bindDefs","targetKey","layerById","circles","includes","layerContext","SvgWrapper","ref","layer","i","Fragment","CirclePacking","forwardRef","_ref2$isInteractive","_ref2$animate","_ref2$motionConfig","props","_objectWithoutPropertiesLoose","_excluded","Container","ResponsiveCirclePacking","defaultWidth","defaultHeight","onResize","debounceResize","ResponsiveWrapper","InnerCirclePackingHtml","overflow","CirclePackingHtml","otherProps","ResponsiveCirclePackingHtml","InnerCirclePackingCanvas","_ref$pixelRatio","useRef","useEffect","ctx","getContext","scale","fillStyle","background","fillRect","save","translate","forEach","strokeStyle","lineWidth","beginPath","arc","PI","textAlign","textBaseline","font","fontSize","fontFamily","fillText","getNodeFromMouseEvent","handleMouseHover","mergeRefs","cursor","CirclePackingCanvas","ResponsiveCirclePackingCanvas"],"mappings":"gpCAeaA,EAAmB,SAAHC,GA0BC,IAAAC,EAzB1BC,EAAIF,EAAJE,KACAC,EAAEH,EAAFG,GACAC,EAAKJ,EAALI,MACAC,EAAWL,EAAXK,YACAC,EAAKN,EAALM,MACAC,EAAMP,EAANO,OACAC,EAAOR,EAAPQ,QACAC,EAAUT,EAAVS,WACAC,EAAMV,EAANU,OACAC,EAAOX,EAAPW,QACAC,EAAsBZ,EAAtBY,uBACAC,EAAUb,EAAVa,WAeMC,EAAQC,EAAmCZ,GAC3Ca,EAAWD,EAAmCX,GAC9Ca,EAAcC,EAAkBb,GAEhCc,EAAWC,EACbV,EACAC,GAEEU,EAAQC,IACRC,EAAgBC,EAAwCX,EAAYQ,GAKpEI,