{"version":3,"sources":["../src/constants/index.ts","../src/utils/svgHelpers.ts","../src/utils/treeFormatter.ts","../src/utils/ConnectionDrawer.ts","../src/nodeRenderers/BaseNodeRenderer.ts","../src/nodeRenderers/RectangleNodeRenderer.ts","../src/nodeRenderers/NodeWithDescriptionRenderer.ts","../src/nodeRenderers/CollapsibleNodeRenderer.ts","../src/nodeRenderers/ImageNodeRenderer.ts","../src/nodeRenderers/ShapeNodeRenderer.ts","../src/utils/NodeDrawer.ts","../src/utils/TitleDrawer.ts","../src/utils/ActionDrawer.ts","../src/utils/LayoutCalculator.ts","../src/utils/NodeFactory.ts","../src/renderers/BaseRenderer.ts","../src/renderers/DirectRenderer.ts","../src/renderers/RightAngleRenderer.ts","../src/renderers/CurvedRenderer.ts","../src/renderers/AllDirectionRenderer.ts","../src/renderers/index.ts","../src/TreeChart.ts","../src/index.ts"],"sourcesContent":["import {\r\n  TreeChartOptions,\r\n  NodeConfig,\r\n  EdgeConfig,\r\n  TitleConfig,\r\n  ActionConfig,\r\n} from \"../types\";\r\n\r\n/**\r\n * SVG namespace for creating SVG elements\r\n */\r\nexport const SVG_NS = \"http://www.w3.org/2000/svg\";\r\n\r\n/**\r\n * Node-related constants used throughout the library\r\n */\r\nexport const NODE_CONSTANTS = {\r\n  // Default dimensions\r\n  DEFAULT_MAX_WIDTH: 200,\r\n  DEFAULT_PADDING: 5,\r\n\r\n  // Layout constants\r\n  BASE_PADDING: 20,\r\n  SPACE_FOR_ARROW_BUTTON: 20,\r\n  SMALL_MARGIN: 20,\r\n  EXTRA_TITLE_SPACING: 30,\r\n\r\n  // Text and typography\r\n  DESCRIPTION_LINE_HEIGHT: 1.2,\r\n  DESCRIPTION_FONT_SIZE: 11,\r\n  DESCRIPTION_MARGIN_TOP: 4,\r\n  BUTTON_FONT_SIZE: 10,\r\n  DEFAULT_FONT_SIZE: 14,\r\n  DEFAULT_TEXT_SIZE: 12,\r\n  MIN_WIDTH_FOR_DESCRIPTION: 100,\r\n\r\n  // Collapsible node specific\r\n  BUTTON_WIDTH: 16,\r\n  ACTION_BUTTON_SIZE: 24,\r\n  ACTION_BUTTON_CENTER_OFFSET: 12,\r\n\r\n  // Animation and visual effects\r\n  STAR_POINTS: 8,\r\n  CIRCLE_POINTS: 10,\r\n\r\n  // Image node specific constants\r\n  DEFAULT_IMAGE_WIDTH: 60,\r\n  DEFAULT_IMAGE_HEIGHT: 60,\r\n  DEFAULT_IMAGE_MARGIN: 8,\r\n  DEFAULT_TEXT_PADDING: 8,\r\n  DEFAULT_TEXT_SPACING: 4,\r\n  DEFAULT_IMAGE_BORDER_RADIUS: 4,\r\n  DEFAULT_IMAGE_BORDER_WIDTH: 1,\r\n  DEFAULT_IMAGE_OPACITY: 1,\r\n  DEFAULT_TITLE_FONT_SIZE: 12,\r\n  DEFAULT_SUBTITLE_FONT_SIZE: 10,\r\n  MIN_IMAGE_NODE_WIDTH: 120,\r\n  MIN_IMAGE_NODE_HEIGHT: 60,\r\n\r\n  // Default styling values\r\n  DEFAULT_SHADOW_COLOR: \"rgba(0,0,0,0.3)\",\r\n  DEFAULT_SHADOW_OFFSET: { x: 2, y: 2 },\r\n  DEFAULT_BORDER_COLOR: \"black\",\r\n  DEFAULT_BORDER_WIDTH: 1,\r\n  DEFAULT_BORDER_RADIUS: 6,\r\n  DEFAULT_OPACITY: 1,\r\n  DEFAULT_FILL_COLOR: \"skyblue\",\r\n  DEFAULT_FONT_COLOR: \"black\",\r\n  DEFAULT_FONT_FAMILY: \"Arial, sans-serif\",\r\n  DESCRIPTION_FONT_COLOR: \"#666666\",\r\n  DEFAULT_TEXT_ANCHOR: \"middle\",\r\n  DEFAULT_IMAGE_BORDER_COLOR: \"#333333\",\r\n  DEFAULT_TITLE_COLOR: \"#000000\",\r\n  DEFAULT_SUBTITLE_COLOR: \"#666666\",\r\n} as const;\r\n\r\n/**\r\n * Default options for tree chart rendering\r\n */\r\nexport const DEFAULT_OPTIONS: Required<\r\n  Omit<TreeChartOptions, \"actionConfig\">\r\n> & { actionConfig?: ActionConfig } = {\r\n  // Chart layout defaults\r\n  horizontalGap: 30,\r\n  verticalGap: 80,\r\n  verticalAlign: \"center\",\r\n  horizontalAlign: \"top-to-bottom\",\r\n  type: \"direct\",\r\n\r\n  // Default node configuration\r\n  nodeConfig: {\r\n    type: \"rectangle\",\r\n    width: 80,\r\n    height: 40,\r\n    color: \"skyblue\",\r\n    borderColor: \"black\",\r\n    borderWidth: 1,\r\n    borderRadius: 6,\r\n    opacity: 1,\r\n    fontSize: 14,\r\n    fontColor: \"black\",\r\n    fontFamily: \"Arial, sans-serif\",\r\n    shadow: false,\r\n    shadowColor: \"rgba(0,0,0,0.3)\",\r\n    shadowOffset: { x: 2, y: 2 },\r\n    gradient: false,\r\n    gradientStartColor: \"\",\r\n    gradientEndColor: \"\",\r\n    customAttributes: {},\r\n  } as Required<NodeConfig>,\r\n\r\n  // Default edge configuration\r\n  edgeConfig: {\r\n    color: \"black\",\r\n    width: 1,\r\n    opacity: 1,\r\n    dasharray: \"\",\r\n    showArrows: false,\r\n    arrowDirection: \"source-to-target\",\r\n    arrowSize: 4,\r\n    arrowColor: \"black\",\r\n    curveRadius: 20,\r\n    customPath: \"\",\r\n    textSize: 12,\r\n    textColor: \"#666666\",\r\n    textBackgroundColor: \"\",\r\n  } as Required<EdgeConfig>,\r\n\r\n  // Default title configuration\r\n  titleConfig: {\r\n    title: \"\",\r\n    description: \"\",\r\n    position: {\r\n      horizontal: \"center\",\r\n      vertical: \"top\",\r\n    },\r\n    titleStyle: {\r\n      fontSize: 14,\r\n      fontColor: \"#333333\",\r\n      fontFamily: \"Arial, sans-serif\",\r\n      fontWeight: \"bold\",\r\n      margin: 30,\r\n    },\r\n    descriptionStyle: {\r\n      fontSize: 12,\r\n      fontColor: \"#666666\",\r\n      fontFamily: \"Arial, sans-serif\",\r\n      fontWeight: \"normal\",\r\n      margin: 20,\r\n    },\r\n  } as Required<TitleConfig>,\r\n};\r\n/**\r\n * Fixed dimensions for all-direction tree\r\n */\r\nexport const ALL_DIRECTION_DIMENSIONS = {\r\n  svgWidth: 1200,\r\n  svgHeight: 800,\r\n  horizontalGap: 160,\r\n  verticalGap: 100,\r\n};\r\n","import { SVG_NS, NODE_CONSTANTS } from \"../constants\";\r\nimport { FormattedTree, TreeChartOptions } from \"../types\";\r\n\r\n/**\r\n * Creates an SVG element with the specified dimensions\r\n *\r\n * @param width Width of the SVG\r\n * @param height Height of the SVG\r\n * @param viewBox Optional viewBox attribute\r\n * @returns SVG element\r\n */\r\nexport function createSvgElement(\r\n  width: number,\r\n  height: number,\r\n  viewBox?: string\r\n): SVGSVGElement {\r\n  const svg = document.createElementNS(SVG_NS, \"svg\");\r\n  svg.setAttribute(\"width\", width.toString());\r\n  svg.setAttribute(\"height\", height.toString());\r\n\r\n  if (viewBox) {\r\n    svg.setAttribute(\"viewBox\", viewBox);\r\n  }\r\n\r\n  return svg;\r\n}\r\n\r\n/**\r\n * Calculate width needed for the SVG based on tree data\r\n */\r\nexport function calculateSvgWidth(\r\n  formattedTree: FormattedTree,\r\n  options: any,\r\n  nodeDrawer: any\r\n): number {\r\n  const { horizontalGap } = options;\r\n  const basePadding = NODE_CONSTANTS.BASE_PADDING;\r\n  const nodeConfig = options.nodeConfig!;\r\n  const boxWidth = nodeConfig.width!;\r\n\r\n  // Calculate the maximum width needed for any level\r\n  let maxLevelWidth = 0;\r\n\r\n  formattedTree.forEach((level) => {\r\n    // Calculate actual node widths for this level\r\n    const nodeWidths: number[] = [];\r\n    level.forEach((node: any) => {\r\n      const effectiveNodeConfig = node.nodeConfig\r\n        ? { ...nodeConfig, ...node.nodeConfig }\r\n        : nodeConfig;\r\n\r\n      // Use actual node width based on type\r\n      let actualWidth = effectiveNodeConfig.width || boxWidth;\r\n\r\n      // For dynamic nodes, calculate their actual width\r\n      if (\r\n        effectiveNodeConfig.type === \"node-with-description\" ||\r\n        effectiveNodeConfig.type === \"collapsible-node\" ||\r\n        effectiveNodeConfig.type === \"image\"\r\n      ) {\r\n        actualWidth = nodeDrawer.calculateDynamicNodeWidth(\r\n          node,\r\n          effectiveNodeConfig\r\n        );\r\n      }\r\n\r\n      nodeWidths.push(actualWidth);\r\n    });\r\n\r\n    // Calculate total level width with proper spacing\r\n    const totalNodesWidth = nodeWidths.reduce((sum, width) => sum + width, 0);\r\n    const totalGaps = (level.length - 1) * horizontalGap;\r\n    const levelWidth = totalNodesWidth + totalGaps;\r\n\r\n    maxLevelWidth = Math.max(maxLevelWidth, levelWidth);\r\n  });\r\n\r\n  return maxLevelWidth + basePadding * 2;\r\n}\r\n\r\n/**\r\n * Calculate height needed for the SVG based on tree data\r\n */\r\nexport function calculateSvgHeight(\r\n  formattedTree: FormattedTree,\r\n  options: any,\r\n  nodeDrawer: any,\r\n  titleSpace: { top: number; bottom: number }\r\n): number {\r\n  const boxHeight = options.nodeConfig!.height!;\r\n  const { verticalGap } = options;\r\n  const basePadding = NODE_CONSTANTS.BASE_PADDING;\r\n\r\n  // Calculate actual heights for each level\r\n  let totalHeight = 0;\r\n  formattedTree.forEach((level, levelIndex) => {\r\n    let maxHeightInLevel = boxHeight;\r\n\r\n    level.forEach((node: any) => {\r\n      const effectiveNodeConfig = node.nodeConfig\r\n        ? { ...options.nodeConfig!, ...node.nodeConfig }\r\n        : options.nodeConfig!;\r\n\r\n      // Calculate dynamic height for nodes that need it\r\n      if (\r\n        effectiveNodeConfig.type === \"node-with-description\" ||\r\n        effectiveNodeConfig.type === \"collapsible-node\" ||\r\n        effectiveNodeConfig.type === \"image\"\r\n      ) {\r\n        const dynamicHeight = nodeDrawer.calculateDynamicNodeHeight(\r\n          node,\r\n          effectiveNodeConfig\r\n        );\r\n        maxHeightInLevel = Math.max(maxHeightInLevel, dynamicHeight);\r\n      }\r\n    });\r\n\r\n    totalHeight += maxHeightInLevel;\r\n    if (levelIndex < formattedTree.length - 1) {\r\n      totalHeight += verticalGap;\r\n    }\r\n  });\r\n\r\n  const baseHeight = totalHeight + basePadding * 2;\r\n  return baseHeight + titleSpace.top + titleSpace.bottom;\r\n}\r\n\r\n/**\r\n * Utility to get node map key from level and position\r\n *\r\n * @param level Level in the tree\r\n * @param position Position within the level\r\n * @returns String key for the node map\r\n */\r\nexport function getNodeKey(level: number, position: number): string {\r\n  return `${level}-${position}`;\r\n}\r\n\r\n/**\r\n * Export utility functions\r\n */\r\nexport const svgHelpers = {\r\n  createSvgElement,\r\n  getNodeKey,\r\n  calculateSvgWidth,\r\n  calculateSvgHeight,\r\n};\r\n","import { TreeNode, FormattedTree, NodePosition } from \"../types\";\r\nimport { getNodeKey } from \"./svgHelpers\";\r\n\r\n/**\r\n * Converts a hierarchical tree structure into a level-by-level array representation\r\n * that's easier to render visually\r\n *\r\n * @param tree The hierarchical tree structure\r\n * @param options Optional formatting options including alignment\r\n * @returns A formatted representation of the tree organized by levels\r\n */\r\nexport function formatTree(\r\n  tree: TreeNode,\r\n  options?: { horizontalAlign?: string }\r\n): FormattedTree {\r\n  const formattedTree: FormattedTree = [];\r\n  const stack: Array<{\r\n    level: number;\r\n    parent?: NodePosition;\r\n    tree: TreeNode;\r\n  }> = [];\r\n\r\n  // Start with the root node\r\n  stack.push({ level: 0, tree });\r\n\r\n  while (stack.length > 0) {\r\n    const node = stack.pop()!;\r\n    let position = 0;\r\n\r\n    // Add the node to its level in the formatted tree\r\n    if (formattedTree.length > node.level) {\r\n      // Add to existing level\r\n      position = formattedTree[node.level].length;\r\n      formattedTree[node.level].push({\r\n        text: node.tree.value,\r\n        description: node.tree.description || undefined, // Include description if present\r\n        parent: node.parent ? JSON.stringify(node.parent) : null,\r\n        edgeText: node.tree.edgeText || null, // Preserve edge text if present\r\n        nodeConfig: node.tree.nodeConfig || undefined, // Preserve node-specific config if present\r\n        collapsibleState: node.tree.collapsibleState || undefined, // Include collapsible state if present\r\n        // Image node properties\r\n        imageUrl: node.tree.imageUrl || undefined,\r\n        title: node.tree.title || undefined,\r\n        subtitle: node.tree.subtitle || undefined,\r\n      });\r\n    } else {\r\n      // Create a new level\r\n      formattedTree.push([\r\n        {\r\n          text: node.tree.value,\r\n          description: node.tree.description || undefined, // Include description if present\r\n          parent: node.parent ? JSON.stringify(node.parent) : null,\r\n          edgeText: node.tree.edgeText || null, // Preserve edge text if present\r\n          nodeConfig: node.tree.nodeConfig || undefined, // Preserve node-specific config if present\r\n          collapsibleState: node.tree.collapsibleState || undefined, // Include collapsible state if present\r\n          // Image node properties\r\n          imageUrl: node.tree.imageUrl || undefined,\r\n          title: node.tree.title || undefined,\r\n          subtitle: node.tree.subtitle || undefined,\r\n        },\r\n      ]);\r\n    }\r\n\r\n    // Process children (if any)\r\n    if (node.tree.child && node.tree.child.length) {\r\n      // We need to process the nodes in reverse order for the desired display order\r\n      // since we're using unshift to add to the beginning of the stack\r\n      for (let i = node.tree.child.length - 1; i >= 0; i--) {\r\n        const childNode = node.tree.child[i];\r\n        stack.push({\r\n          level: node.level + 1,\r\n          parent: { level: node.level, position },\r\n          tree: childNode,\r\n        });\r\n      }\r\n    }\r\n  }\r\n\r\n  // If bottom-to-top alignment, reverse the levels and update parent references\r\n  if (options?.horizontalAlign === \"bottom-to-top\") {\r\n    return reverseTreeForBottomToTop(formattedTree);\r\n  }\r\n\r\n  return formattedTree;\r\n}\r\n\r\n/**\r\n * Reverses the tree structure for bottom-to-top alignment\r\n * This places the root at the bottom and children flowing upward\r\n */\r\nfunction reverseTreeForBottomToTop(\r\n  formattedTree: FormattedTree\r\n): FormattedTree {\r\n  // Reverse the order of levels\r\n  const reversedTree = [...formattedTree].reverse();\r\n\r\n  // Update parent references to match the new level indices\r\n  const maxLevel = formattedTree.length - 1;\r\n\r\n  reversedTree.forEach((level, newLevelIndex) => {\r\n    level.forEach((node) => {\r\n      if (node.parent) {\r\n        const parentPos = JSON.parse(node.parent) as NodePosition;\r\n        const newParentLevel = maxLevel - parentPos.level;\r\n\r\n        // Update the parent reference to the new level index\r\n        node.parent = JSON.stringify({\r\n          level: newParentLevel,\r\n          position: parentPos.position,\r\n        });\r\n      }\r\n    });\r\n  });\r\n\r\n  return reversedTree;\r\n}\r\n\r\n/**\r\n * Creates a map of parent nodes to their child nodes for connection drawing\r\n * This is specifically useful for renderers that need to group children by parent\r\n *\r\n * @param formattedTree The formatted tree\r\n * @returns A map where keys are parent keys (level-position) and values are arrays of child node info\r\n */\r\nexport function createParentToChildrenMap(\r\n  formattedTree: FormattedTree\r\n): Record<string, Array<{ levelIndex: number; nodeIndex: number; node: any }>> {\r\n  const parentToChildren: Record<\r\n    string,\r\n    Array<{ levelIndex: number; nodeIndex: number; node: any }>\r\n  > = {};\r\n\r\n  formattedTree.forEach((level, levelIndex) => {\r\n    level.forEach((node, nodeIndex) => {\r\n      if (node.parent) {\r\n        const parent = JSON.parse(node.parent);\r\n        const parentKey = getNodeKey(parent.level, parent.position);\r\n\r\n        if (!parentToChildren[parentKey]) {\r\n          parentToChildren[parentKey] = [];\r\n        }\r\n        parentToChildren[parentKey].push({ levelIndex, nodeIndex, node });\r\n      }\r\n    });\r\n  });\r\n\r\n  return parentToChildren;\r\n}\r\n\r\n/**\r\n * Creates a map of parent nodes to their child nodes\r\n *\r\n * @param formattedTree The formatted tree\r\n * @returns A map of parent positions to child positions\r\n */\r\nexport function createParentChildMap(\r\n  formattedTree: FormattedTree\r\n): Record<string, Array<NodePosition>> {\r\n  const parentChildPair: Record<string, Array<NodePosition>> = {};\r\n\r\n  // Start from level 1 (skip root level)\r\n  for (let i = 1; i < formattedTree.length; i++) {\r\n    for (let j = 0; j < formattedTree[i].length; j++) {\r\n      const node = formattedTree[i][j];\r\n\r\n      if (node.parent) {\r\n        if (parentChildPair[node.parent]) {\r\n          parentChildPair[node.parent].push({ level: i, position: j });\r\n        } else {\r\n          parentChildPair[node.parent] = [{ level: i, position: j }];\r\n        }\r\n      }\r\n    }\r\n  }\r\n\r\n  return parentChildPair;\r\n}\r\n\r\n/**\r\n * Calculate height offset for parent-child connections to avoid overlapping\r\n * Uses a repeating pattern to create visual distinction between connection levels\r\n *\r\n * @param parentIndex The global index of the parent (across all levels)\r\n * @param pattern Optional custom pattern array (defaults to [0, -10, 10, -20, 20, -5])\r\n * @returns Height offset in pixels\r\n */\r\nexport function calculateHeightOffset(\r\n  parentIndex: number,\r\n  pattern: number[] = [0, -10, 10, -20, 20, -5]\r\n): number {\r\n  return pattern[parentIndex % pattern.length];\r\n}\r\n","import { SVG_NS, NODE_CONSTANTS } from \"../constants\";\r\nimport { ConnectionOptions, Point } from \"../types\";\r\n\r\n/**\r\n * ConnectionDrawer class for drawing connections between tree nodes\r\n * Provides unified connection drawing with customizable styling\r\n */\r\nexport class ConnectionDrawer {\r\n  private svg: SVGSVGElement;\r\n  private defaultOptions: Required<ConnectionOptions> = {\r\n    type: \"direct\",\r\n    color: \"black\",\r\n    width: 1,\r\n    dasharray: \"\",\r\n    opacity: 1,\r\n    showArrows: false,\r\n    arrowDirection: \"source-to-target\",\r\n    arrowSize: 6,\r\n    arrowColor: \"black\",\r\n    curveRadius: 20,\r\n    customPath: \"\",\r\n    edgeText: \"\",\r\n    textSize: 12,\r\n    textColor: \"black\",\r\n    textBackgroundColor: \"white\",\r\n  };\r\n\r\n  constructor(svg: SVGSVGElement) {\r\n    this.svg = svg;\r\n  }\r\n\r\n  /**\r\n   * Draw a connection between two points\r\n   */\r\n  public drawConnection(\r\n    fromPoint: Point,\r\n    toPoint: Point,\r\n    options: Partial<ConnectionOptions> = {}\r\n  ): SVGElement {\r\n    const finalOptions = { ...this.defaultOptions, ...options };\r\n\r\n    let pathElement: SVGElement;\r\n\r\n    switch (finalOptions.type) {\r\n      case \"direct\":\r\n        pathElement = this.createDirectConnection(fromPoint, toPoint);\r\n        break;\r\n      case \"right-angle\":\r\n        pathElement = this.createRightAngleConnection(fromPoint, toPoint);\r\n        break;\r\n      case \"curved\":\r\n        pathElement = this.createCurvedConnection(\r\n          fromPoint,\r\n          toPoint,\r\n          finalOptions.curveRadius\r\n        );\r\n        break;\r\n      case \"custom\":\r\n        pathElement = this.createCustomConnection(finalOptions);\r\n        break;\r\n      default:\r\n        pathElement = this.createDirectConnection(fromPoint, toPoint);\r\n    }\r\n\r\n    this.applyLineStyles(pathElement, finalOptions);\r\n\r\n    if (finalOptions.showArrows) {\r\n      this.addArrow(pathElement, finalOptions);\r\n    }\r\n\r\n    // Add edge text if provided\r\n    if (finalOptions.edgeText && finalOptions.edgeText.trim()) {\r\n      this.addEdgeText(pathElement, fromPoint, toPoint, finalOptions);\r\n    }\r\n\r\n    this.svg.appendChild(pathElement);\r\n    return pathElement;\r\n  }\r\n\r\n  /**\r\n   * Draw a complete right-angle connection with three segments (parent → midpoint → child)\r\n   * This is a higher-level method that creates the full L-shaped connection in one call\r\n   */\r\n  public drawThreeSegmentRightAngle(\r\n    parentPoint: Point,\r\n    childPoint: Point,\r\n    options: Partial<ConnectionOptions> = {}\r\n  ): SVGElement[] {\r\n    const finalOptions = { ...this.defaultOptions, ...options };\r\n    const elements: SVGElement[] = [];\r\n\r\n    // Calculate midpoint for the horizontal segment\r\n    const midY = parentPoint.y + (childPoint.y - parentPoint.y) / 2;\r\n\r\n    // Determine arrow placement based on arrow direction AND if arrows are enabled\r\n    const showArrowOnParentSegment =\r\n      finalOptions.showArrows &&\r\n      (finalOptions.arrowDirection === \"target-to-source\" ||\r\n        finalOptions.arrowDirection === \"both\");\r\n    const showArrowOnChildSegment =\r\n      finalOptions.showArrows &&\r\n      (finalOptions.arrowDirection === \"source-to-target\" ||\r\n        finalOptions.arrowDirection === \"both\");\r\n\r\n    // Segment 1: Parent → Midpoint (vertical, arrows only for target-to-source or both)\r\n    const segment1 = this.drawConnection(\r\n      parentPoint,\r\n      { x: parentPoint.x, y: midY },\r\n      {\r\n        ...finalOptions,\r\n        edgeText: \"\", // No text on parent's vertical segment\r\n        showArrows: showArrowOnParentSegment,\r\n        arrowDirection: showArrowOnParentSegment\r\n          ? finalOptions.arrowDirection === \"both\"\r\n            ? \"target-to-source\"\r\n            : finalOptions.arrowDirection\r\n          : \"source-to-target\",\r\n      }\r\n    );\r\n    elements.push(segment1);\r\n\r\n    // Segment 2: Horizontal line (no arrows, no text)\r\n    const segment2 = this.drawConnection(\r\n      { x: parentPoint.x, y: midY },\r\n      { x: childPoint.x, y: midY },\r\n      {\r\n        ...finalOptions,\r\n        edgeText: \"\", // No text on horizontal segment\r\n        showArrows: false, // Never show arrows on horizontal connector\r\n      }\r\n    );\r\n    elements.push(segment2);\r\n\r\n    // Segment 3: Midpoint → Child (vertical, arrows only for source-to-target or both)\r\n    const segment3 = this.drawConnection(\r\n      { x: childPoint.x, y: midY },\r\n      childPoint,\r\n      {\r\n        ...finalOptions,\r\n        edgeText: finalOptions.edgeText, // Text goes on the final segment connecting to child\r\n        showArrows: showArrowOnChildSegment,\r\n        arrowDirection: showArrowOnChildSegment\r\n          ? finalOptions.arrowDirection === \"both\"\r\n            ? \"source-to-target\"\r\n            : finalOptions.arrowDirection\r\n          : \"source-to-target\",\r\n      }\r\n    );\r\n    elements.push(segment3);\r\n\r\n    return elements;\r\n  }\r\n\r\n  /**\r\n   * Draw a multi-child right-angle connection system\r\n   * This creates a horizontal connector line with vertical drops to each child\r\n   */\r\n  public drawMultiChildRightAngle(\r\n    parentPoint: Point,\r\n    childPoints: Point[],\r\n    horizontalY: number,\r\n    options: Partial<ConnectionOptions> = {}\r\n  ): SVGElement[] {\r\n    const finalOptions = { ...this.defaultOptions, ...options };\r\n    const elements: SVGElement[] = [];\r\n\r\n    if (childPoints.length === 0) return elements;\r\n\r\n    // Find the extent of the horizontal line\r\n    const childXValues = childPoints.map((p) => p.x);\r\n    const minX = Math.min(...childXValues, parentPoint.x);\r\n    const maxX = Math.max(...childXValues, parentPoint.x);\r\n\r\n    // Determine arrow placement based on arrow direction\r\n    const showArrowOnParentSegment =\r\n      finalOptions.arrowDirection === \"target-to-source\" ||\r\n      finalOptions.arrowDirection === \"both\";\r\n\r\n    // Draw vertical line from parent to horizontal line (arrows only for target-to-source or both)\r\n    const parentToHorizontal = this.drawConnection(\r\n      parentPoint,\r\n      { x: parentPoint.x, y: horizontalY },\r\n      {\r\n        ...finalOptions,\r\n        edgeText: \"\", // No text on parent's vertical segment\r\n        showArrows: showArrowOnParentSegment,\r\n        arrowDirection: showArrowOnParentSegment\r\n          ? finalOptions.arrowDirection === \"both\"\r\n            ? \"target-to-source\"\r\n            : finalOptions.arrowDirection\r\n          : \"source-to-target\",\r\n      }\r\n    );\r\n    elements.push(parentToHorizontal);\r\n\r\n    // Draw horizontal connector line (no arrows, no text)\r\n    const horizontalLine = this.drawConnection(\r\n      { x: minX, y: horizontalY },\r\n      { x: maxX, y: horizontalY },\r\n      {\r\n        ...finalOptions,\r\n        edgeText: \"\", // No text on horizontal line\r\n        showArrows: false, // No arrows on structural lines\r\n      }\r\n    );\r\n    elements.push(horizontalLine);\r\n\r\n    // Note: Individual child connections are now handled by drawChildConnectionsWithText\r\n    // to avoid duplication and ensure proper arrow placement\r\n\r\n    return elements;\r\n  }\r\n\r\n  /**\r\n   * Draw individual child connections with text for multi-child right-angle systems\r\n   * This method should be called after drawMultiChildRightAngle to add child connections with text and arrows\r\n   */\r\n  public drawChildConnectionsWithText(\r\n    childPoints: Point[],\r\n    horizontalY: number,\r\n    childTexts: (string | undefined)[],\r\n    options: Partial<ConnectionOptions> = {}\r\n  ): SVGElement[] {\r\n    const finalOptions = { ...this.defaultOptions, ...options };\r\n    const elements: SVGElement[] = [];\r\n\r\n    // Determine arrow placement based on arrow direction AND if arrows are enabled\r\n    const showArrowOnChildSegment =\r\n      finalOptions.showArrows &&\r\n      (finalOptions.arrowDirection === \"source-to-target\" ||\r\n        finalOptions.arrowDirection === \"both\");\r\n\r\n    childPoints.forEach((childPoint, index) => {\r\n      const edgeText = childTexts[index];\r\n\r\n      // Draw the vertical connection to child with arrows and optional text\r\n      // Always draw from horizontal line to child (normal direction)\r\n      // The arrowDirection property will handle which end gets the arrow\r\n      const childConnection = this.drawConnection(\r\n        { x: childPoint.x, y: horizontalY },\r\n        childPoint,\r\n        {\r\n          ...finalOptions,\r\n          edgeText: edgeText || \"\", // Text goes on the vertical segment connecting to this specific child\r\n          showArrows: showArrowOnChildSegment, // Only show arrows when appropriate\r\n          arrowDirection: showArrowOnChildSegment\r\n            ? finalOptions.arrowDirection === \"both\"\r\n              ? \"source-to-target\"\r\n              : finalOptions.arrowDirection\r\n            : \"source-to-target\",\r\n        }\r\n      );\r\n      elements.push(childConnection);\r\n    });\r\n\r\n    return elements;\r\n  }\r\n\r\n  /**\r\n   * Create a direct line connection\r\n   */\r\n  private createDirectConnection(\r\n    fromPoint: Point,\r\n    toPoint: Point\r\n  ): SVGLineElement {\r\n    const line = document.createElementNS(SVG_NS, \"line\");\r\n    line.setAttribute(\"x1\", fromPoint.x.toString());\r\n    line.setAttribute(\"y1\", fromPoint.y.toString());\r\n    line.setAttribute(\"x2\", toPoint.x.toString());\r\n    line.setAttribute(\"y2\", toPoint.y.toString());\r\n    return line;\r\n  }\r\n\r\n  /**\r\n   * Create a right-angle connection (L-shaped)\r\n   */\r\n  private createRightAngleConnection(\r\n    fromPoint: Point,\r\n    toPoint: Point\r\n  ): SVGPathElement {\r\n    const path = document.createElementNS(SVG_NS, \"path\");\r\n\r\n    // Create an L-shaped path with a vertical then horizontal segment\r\n    const midY = fromPoint.y + (toPoint.y - fromPoint.y) / 2;\r\n\r\n    const pathData = `M ${fromPoint.x} ${fromPoint.y} L ${fromPoint.x} ${midY} L ${toPoint.x} ${midY} L ${toPoint.x} ${toPoint.y}`;\r\n    path.setAttribute(\"d\", pathData);\r\n    path.setAttribute(\"fill\", \"none\");\r\n    return path;\r\n  }\r\n\r\n  /**\r\n   * Create a curved connection\r\n   */\r\n  private createCurvedConnection(\r\n    fromPoint: Point,\r\n    toPoint: Point,\r\n    curveRadius: number\r\n  ): SVGPathElement {\r\n    const path = document.createElementNS(SVG_NS, \"path\");\r\n\r\n    // Create a smooth curve using quadratic Bezier curve\r\n    // Use curveRadius to control the intensity of the curve\r\n    const controlX = fromPoint.x;\r\n    const controlY =\r\n      fromPoint.y + Math.min(curveRadius, (toPoint.y - fromPoint.y) / 2);\r\n\r\n    const pathData = `M ${fromPoint.x} ${fromPoint.y} Q ${controlX} ${controlY} ${toPoint.x} ${toPoint.y}`;\r\n    path.setAttribute(\"d\", pathData);\r\n    path.setAttribute(\"fill\", \"none\");\r\n    return path;\r\n  }\r\n\r\n  /**\r\n   * Create a custom path connection\r\n   */\r\n  private createCustomConnection(\r\n    options: Required<ConnectionOptions>\r\n  ): SVGPathElement {\r\n    const path = document.createElementNS(SVG_NS, \"path\");\r\n    path.setAttribute(\"d\", options.customPath);\r\n    path.setAttribute(\"fill\", \"none\");\r\n    return path;\r\n  }\r\n\r\n  /**\r\n   * Apply line styling to a path element\r\n   */\r\n  private applyLineStyles(\r\n    element: SVGElement,\r\n    options: Required<ConnectionOptions>\r\n  ): void {\r\n    element.setAttribute(\"stroke\", options.color);\r\n    element.setAttribute(\"stroke-width\", options.width.toString());\r\n    element.setAttribute(\"opacity\", options.opacity.toString());\r\n\r\n    if (options.dasharray) {\r\n      element.setAttribute(\"stroke-dasharray\", options.dasharray);\r\n    }\r\n  }\r\n\r\n  /**\r\n   * Add arrow markers to the connection\r\n   */\r\n  private addArrow(\r\n    pathElement: SVGElement,\r\n    options: Required<ConnectionOptions>\r\n  ): void {\r\n    // Use edge color for arrow if arrowColor is not explicitly set\r\n    const arrowColor =\r\n      options.arrowColor === this.defaultOptions.arrowColor\r\n        ? options.color\r\n        : options.arrowColor;\r\n\r\n    const colorId = arrowColor.replace(\"#\", \"\").replace(/[^a-zA-Z0-9]/g, \"\");\r\n\r\n    // Apply markers based on direction\r\n    if (\r\n      options.arrowDirection === \"source-to-target\" ||\r\n      options.arrowDirection === \"both\"\r\n    ) {\r\n      const endMarkerId = `arrowhead-end-${options.arrowSize}-${colorId}`;\r\n      let endMarker = this.svg.querySelector(\r\n        `#${endMarkerId}`\r\n      ) as SVGMarkerElement;\r\n\r\n      if (!endMarker) {\r\n        endMarker = this.createArrowMarker(\r\n          endMarkerId,\r\n          options,\r\n          arrowColor,\r\n          \"end\"\r\n        );\r\n        this.addMarkerToDefs(endMarker);\r\n      }\r\n      pathElement.setAttribute(\"marker-end\", `url(#${endMarkerId})`);\r\n    }\r\n\r\n    if (\r\n      options.arrowDirection === \"target-to-source\" ||\r\n      options.arrowDirection === \"both\"\r\n    ) {\r\n      const startMarkerId = `arrowhead-start-${options.arrowSize}-${colorId}`;\r\n      let startMarker = this.svg.querySelector(\r\n        `#${startMarkerId}`\r\n      ) as SVGMarkerElement;\r\n\r\n      if (!startMarker) {\r\n        startMarker = this.createArrowMarker(\r\n          startMarkerId,\r\n          options,\r\n          arrowColor,\r\n          \"start\"\r\n        );\r\n        this.addMarkerToDefs(startMarker);\r\n      }\r\n      pathElement.setAttribute(\"marker-start\", `url(#${startMarkerId})`);\r\n    }\r\n  }\r\n\r\n  /**\r\n   * Add marker to defs element\r\n   */\r\n  private addMarkerToDefs(marker: SVGMarkerElement): void {\r\n    let defs = this.svg.querySelector(\"defs\");\r\n    if (!defs) {\r\n      defs = document.createElementNS(SVG_NS, \"defs\");\r\n      this.svg.insertBefore(defs, this.svg.firstChild);\r\n    }\r\n    defs.appendChild(marker);\r\n  }\r\n\r\n  /**\r\n   * Create an arrow marker element\r\n   */\r\n  private createArrowMarker(\r\n    markerId: string,\r\n    options: Required<ConnectionOptions>,\r\n    arrowColor: string,\r\n    position: \"start\" | \"end\"\r\n  ): SVGMarkerElement {\r\n    const marker = document.createElementNS(SVG_NS, \"marker\");\r\n    marker.setAttribute(\"id\", markerId);\r\n    marker.setAttribute(\"markerWidth\", (options.arrowSize * 2).toString());\r\n    marker.setAttribute(\"markerHeight\", (options.arrowSize * 2).toString());\r\n    marker.setAttribute(\"orient\", \"auto\");\r\n    marker.setAttribute(\"markerUnits\", \"strokeWidth\");\r\n\r\n    const arrow = document.createElementNS(SVG_NS, \"polygon\");\r\n\r\n    if (position === \"end\") {\r\n      // Arrow pointing right (for line endings)\r\n      marker.setAttribute(\"refX\", options.arrowSize.toString());\r\n      marker.setAttribute(\"refY\", options.arrowSize.toString());\r\n      const points = `0,0 0,${options.arrowSize * 2} ${options.arrowSize * 2},${\r\n        options.arrowSize\r\n      }`;\r\n      arrow.setAttribute(\"points\", points);\r\n    } else {\r\n      // Arrow pointing left (for line starts)\r\n      marker.setAttribute(\"refX\", options.arrowSize.toString());\r\n      marker.setAttribute(\"refY\", options.arrowSize.toString());\r\n      const points = `${options.arrowSize * 2},0 ${options.arrowSize * 2},${\r\n        options.arrowSize * 2\r\n      } 0,${options.arrowSize}`;\r\n      arrow.setAttribute(\"points\", points);\r\n    }\r\n\r\n    arrow.setAttribute(\"fill\", arrowColor);\r\n    marker.appendChild(arrow);\r\n    return marker;\r\n  }\r\n\r\n  private addEdgeText(\r\n    pathElement: SVGElement,\r\n    fromPoint: Point,\r\n    toPoint: Point,\r\n    options: ConnectionOptions\r\n  ): void {\r\n    const textElement = document.createElementNS(\r\n      \"http://www.w3.org/2000/svg\",\r\n      \"text\"\r\n    );\r\n\r\n    // Calculate midpoint of the connection\r\n    const midX = (fromPoint.x + toPoint.x) / 2;\r\n    const midY = (fromPoint.y + toPoint.y) / 2;\r\n\r\n    // Set text position\r\n    textElement.setAttribute(\"x\", midX.toString());\r\n    textElement.setAttribute(\"y\", midY.toString());\r\n\r\n    // Set text content\r\n    textElement.textContent = options.edgeText || \"\";\r\n\r\n    // Set text styles\r\n    textElement.setAttribute(\r\n      \"font-size\",\r\n      (options.textSize || NODE_CONSTANTS.DEFAULT_TEXT_SIZE).toString()\r\n    );\r\n    textElement.setAttribute(\"fill\", options.textColor || \"#000000\");\r\n    textElement.setAttribute(\"text-anchor\", \"middle\");\r\n    textElement.setAttribute(\"dominant-baseline\", \"central\");\r\n\r\n    // Add background rectangle if background color is specified\r\n    if (options.textBackgroundColor) {\r\n      const bbox = textElement.getBBox();\r\n      const rectElement = document.createElementNS(\r\n        \"http://www.w3.org/2000/svg\",\r\n        \"rect\"\r\n      );\r\n      rectElement.setAttribute(\"x\", (midX - bbox.width / 2 - 2).toString());\r\n      rectElement.setAttribute(\"y\", (midY - bbox.height / 2 - 1).toString());\r\n      rectElement.setAttribute(\"width\", (bbox.width + 4).toString());\r\n      rectElement.setAttribute(\"height\", (bbox.height + 2).toString());\r\n      rectElement.setAttribute(\"fill\", options.textBackgroundColor);\r\n      rectElement.setAttribute(\"rx\", \"2\");\r\n\r\n      this.svg.appendChild(rectElement);\r\n    }\r\n\r\n    this.svg.appendChild(textElement);\r\n  }\r\n}\r\n","import { SVG_NS, NODE_CONSTANTS } from \"../constants\";\r\nimport { NodeOptions } from \"../types\";\r\nimport { NodeRenderer, NodeRenderResult } from \"./types\";\r\n\r\n/**\r\n * BaseNodeRenderer provides common functionality for all node renderers\r\n * Contains shared methods for styling, effects, and text handling\r\n */\r\nexport abstract class BaseNodeRenderer implements NodeRenderer {\r\n  protected svg: SVGSVGElement;\r\n\r\n  constructor(svg: SVGSVGElement) {\r\n    this.svg = svg;\r\n  }\r\n\r\n  /**\r\n   * Abstract method that subclasses must implement to create their specific shape\r\n   */\r\n  abstract render(options: Required<NodeOptions>): NodeRenderResult;\r\n\r\n  /**\r\n   * Apply common styling to an SVG element\r\n   */\r\n  protected applyCommonStyling(\r\n    element: SVGElement,\r\n    options: Required<NodeOptions>\r\n  ): void {\r\n    // Only set fill if not using gradient\r\n    if (\r\n      !options.gradient ||\r\n      !options.gradientStartColor ||\r\n      !options.gradientEndColor\r\n    ) {\r\n      element.setAttribute(\"fill\", options.fill);\r\n    }\r\n    element.setAttribute(\"stroke\", options.stroke);\r\n    element.setAttribute(\"stroke-width\", options.strokeWidth.toString());\r\n    element.setAttribute(\"opacity\", options.opacity.toString());\r\n\r\n    // Apply custom attributes\r\n    Object.entries(options.customAttributes).forEach(([key, value]) => {\r\n      element.setAttribute(key, value.toString());\r\n    });\r\n  }\r\n\r\n  /**\r\n   * Create shadow effect if enabled\r\n   */\r\n  protected createShadow(options: Required<NodeOptions>): SVGElement | null {\r\n    if (!options.shadow) return null;\r\n\r\n    const shadowElement = document.createElementNS(SVG_NS, \"rect\");\r\n    shadowElement.setAttribute(\"width\", options.width.toString());\r\n    shadowElement.setAttribute(\"height\", options.height.toString());\r\n    shadowElement.setAttribute(\r\n      \"x\",\r\n      (options.x + options.shadowOffset.x).toString()\r\n    );\r\n    shadowElement.setAttribute(\r\n      \"y\",\r\n      (options.y + options.shadowOffset.y).toString()\r\n    );\r\n    shadowElement.setAttribute(\"fill\", options.shadowColor);\r\n\r\n    // Remove any stroke/border from shadow\r\n    shadowElement.setAttribute(\"stroke\", \"none\");\r\n    shadowElement.setAttribute(\"stroke-width\", \"0\");\r\n\r\n    // Only add opacity if shadowColor doesn't already include alpha channel\r\n    if (!options.shadowColor.includes(\"rgba\")) {\r\n      shadowElement.setAttribute(\"opacity\", \"0.3\"); // Add transparency for shadow effect\r\n    }\r\n    shadowElement.setAttribute(\"rx\", options.borderRadius.toString());\r\n    shadowElement.setAttribute(\"ry\", options.borderRadius.toString());\r\n\r\n    return shadowElement;\r\n  }\r\n\r\n  /**\r\n   * Create gradient definition if enabled\r\n   */\r\n  protected createGradient(options: Required<NodeOptions>): string | null {\r\n    if (\r\n      !options.gradient ||\r\n      !options.gradientStartColor ||\r\n      !options.gradientEndColor\r\n    ) {\r\n      return null;\r\n    }\r\n\r\n    const gradientId = `gradient-${Math.random().toString(36).substr(2, 9)}`;\r\n\r\n    // Check if defs element exists, create if not\r\n    let defs = this.svg.querySelector(\"defs\");\r\n    if (!defs) {\r\n      defs = document.createElementNS(SVG_NS, \"defs\");\r\n      this.svg.appendChild(defs);\r\n    }\r\n\r\n    const gradient = document.createElementNS(SVG_NS, \"linearGradient\");\r\n    gradient.setAttribute(\"id\", gradientId);\r\n    gradient.setAttribute(\"x1\", \"0%\");\r\n    gradient.setAttribute(\"y1\", \"0%\");\r\n    gradient.setAttribute(\"x2\", \"100%\");\r\n    gradient.setAttribute(\"y2\", \"100%\");\r\n\r\n    const stop1 = document.createElementNS(SVG_NS, \"stop\");\r\n    stop1.setAttribute(\"offset\", \"0%\");\r\n    stop1.setAttribute(\"stop-color\", options.gradientStartColor);\r\n\r\n    const stop2 = document.createElementNS(SVG_NS, \"stop\");\r\n    stop2.setAttribute(\"offset\", \"100%\");\r\n    stop2.setAttribute(\"stop-color\", options.gradientEndColor);\r\n\r\n    gradient.appendChild(stop1);\r\n    gradient.appendChild(stop2);\r\n    defs.appendChild(gradient);\r\n\r\n    return `url(#${gradientId})`;\r\n  }\r\n\r\n  /**\r\n   * Create basic text element\r\n   */\r\n  protected createBasicText(options: Required<NodeOptions>): SVGTextElement {\r\n    const textElement = document.createElementNS(SVG_NS, \"text\");\r\n    textElement.setAttribute(\"x\", (options.x + options.width / 2).toString());\r\n    textElement.setAttribute(\"y\", (options.y + options.height / 2).toString());\r\n    textElement.setAttribute(\"text-anchor\", options.textAnchor);\r\n    textElement.setAttribute(\"dominant-baseline\", \"middle\");\r\n    textElement.setAttribute(\"font-family\", options.fontFamily);\r\n    textElement.setAttribute(\"font-size\", options.fontSize.toString());\r\n    textElement.setAttribute(\"font-weight\", \"bold\");\r\n    textElement.setAttribute(\"fill\", options.fontColor);\r\n    textElement.setAttribute(\"stroke\", \"none\");\r\n    textElement.setAttribute(\"stroke-width\", \"0\");\r\n    textElement.textContent = options.text;\r\n\r\n    return textElement;\r\n  }\r\n\r\n  /**\r\n   * Measure text width using canvas context\r\n   */\r\n  public measureText(\r\n    text: string,\r\n    fontSize: number,\r\n    fontFamily: string\r\n  ): number {\r\n    const canvas = document.createElement(\"canvas\");\r\n    const context = canvas.getContext(\"2d\");\r\n    if (!context) return text.length * fontSize * 0.6; // Fallback estimation\r\n\r\n    context.font = `${fontSize}px ${fontFamily}`;\r\n    return context.measureText(text).width;\r\n  }\r\n\r\n  /**\r\n   * Calculate lines needed for text wrapping\r\n   */\r\n  public calculateTextLines(\r\n    text: string,\r\n    maxWidth: number,\r\n    fontSize: number,\r\n    fontFamily: string\r\n  ): string[] {\r\n    const canvas = document.createElement(\"canvas\");\r\n    const context = canvas.getContext(\"2d\");\r\n    if (!context) return [text]; // Fallback\r\n\r\n    context.font = `${fontSize}px ${fontFamily}`;\r\n\r\n    const words = text.split(\" \");\r\n    const lines: string[] = [];\r\n    let currentLine = \"\";\r\n\r\n    for (const word of words) {\r\n      const testLine = currentLine ? `${currentLine} ${word}` : word;\r\n      const testWidth = context.measureText(testLine).width;\r\n\r\n      if (testWidth > maxWidth && currentLine) {\r\n        lines.push(currentLine);\r\n        currentLine = word;\r\n      } else {\r\n        currentLine = testLine;\r\n      }\r\n    }\r\n\r\n    if (currentLine) {\r\n      lines.push(currentLine);\r\n    }\r\n\r\n    return lines;\r\n  }\r\n\r\n  /**\r\n   * Create multiple text lines for wrapped text\r\n   */\r\n  protected createWrappedText(\r\n    lines: string[],\r\n    x: number,\r\n    startY: number,\r\n    fontSize: number,\r\n    fontFamily: string,\r\n    fontColor: string,\r\n    lineHeight: number = 1.2\r\n  ): SVGTextElement[] {\r\n    const textElements: SVGTextElement[] = [];\r\n\r\n    lines.forEach((line, index) => {\r\n      const textElement = document.createElementNS(SVG_NS, \"text\");\r\n      textElement.setAttribute(\"x\", x.toString());\r\n      textElement.setAttribute(\r\n        \"y\",\r\n        (startY + index * fontSize * lineHeight).toString()\r\n      );\r\n      textElement.setAttribute(\"text-anchor\", \"middle\");\r\n      textElement.setAttribute(\"dominant-baseline\", \"middle\");\r\n      textElement.setAttribute(\"font-family\", fontFamily);\r\n      textElement.setAttribute(\"font-size\", fontSize.toString());\r\n      textElement.setAttribute(\"font-weight\", \"normal\");\r\n      textElement.setAttribute(\"fill\", fontColor);\r\n      textElement.setAttribute(\"stroke\", \"none\");\r\n      textElement.setAttribute(\"stroke-width\", \"0\");\r\n      textElement.textContent = line;\r\n\r\n      textElements.push(textElement);\r\n    });\r\n\r\n    return textElements;\r\n  }\r\n\r\n  /**\r\n   * Create a rectangle element with common styling\r\n   */\r\n  protected createRectangleElement(\r\n    options: Required<NodeOptions>\r\n  ): SVGRectElement {\r\n    const rect = document.createElementNS(SVG_NS, \"rect\");\r\n\r\n    rect.setAttribute(\"width\", options.width.toString());\r\n    rect.setAttribute(\"height\", options.height.toString());\r\n    rect.setAttribute(\"x\", options.x.toString());\r\n    rect.setAttribute(\"y\", options.y.toString());\r\n    rect.setAttribute(\"rx\", options.borderRadius.toString());\r\n    rect.setAttribute(\"ry\", options.borderRadius.toString());\r\n\r\n    // Apply gradient or solid fill\r\n    const gradientUrl = this.createGradient(options);\r\n    const fill = gradientUrl || options.fill;\r\n    rect.setAttribute(\"fill\", fill);\r\n\r\n    // Apply common styling\r\n    this.applyCommonStyling(rect, options);\r\n\r\n    return rect;\r\n  }\r\n\r\n  /**\r\n   * Create canvas-based text wrapping for descriptions\r\n   */\r\n  protected createWrappedDescriptionText(\r\n    description: string,\r\n    maxTextWidth: number,\r\n    fontSize: number,\r\n    fontFamily: string,\r\n    x: number,\r\n    startY: number,\r\n    fillColor: string,\r\n    lineHeight: number = NODE_CONSTANTS.DESCRIPTION_LINE_HEIGHT,\r\n    textAnchor: \"start\" | \"middle\" | \"end\" = \"middle\"\r\n  ): SVGElement[] {\r\n    return this.createAutoWrappedText(\r\n      description,\r\n      maxTextWidth,\r\n      fontSize,\r\n      fontFamily,\r\n      x,\r\n      startY,\r\n      fillColor,\r\n      lineHeight,\r\n      textAnchor,\r\n      \"normal\",\r\n      \"alphabetic\"\r\n    );\r\n  }\r\n\r\n  /**\r\n   * Create canvas-based text wrapping for titles\r\n   */\r\n  protected createWrappedTitleText(\r\n    title: string,\r\n    maxTextWidth: number,\r\n    fontSize: number,\r\n    fontFamily: string,\r\n    x: number,\r\n    startY: number,\r\n    fillColor: string,\r\n    lineHeight: number = 1.2,\r\n    textAnchor: \"start\" | \"middle\" | \"end\" = \"middle\"\r\n  ): SVGElement[] {\r\n    return this.createAutoWrappedText(\r\n      title,\r\n      maxTextWidth,\r\n      fontSize,\r\n      fontFamily,\r\n      x,\r\n      startY,\r\n      fillColor,\r\n      lineHeight,\r\n      textAnchor,\r\n      \"bold\",\r\n      \"alphabetic\"\r\n    );\r\n  }\r\n\r\n  /**\r\n   * Create canvas-based text wrapping with automatic line calculation\r\n   */\r\n  protected createAutoWrappedText(\r\n    text: string,\r\n    maxTextWidth: number,\r\n    fontSize: number,\r\n    fontFamily: string,\r\n    x: number,\r\n    startY: number,\r\n    fillColor: string,\r\n    lineHeight: number = NODE_CONSTANTS.DESCRIPTION_LINE_HEIGHT,\r\n    textAnchor: \"start\" | \"middle\" | \"end\" = \"middle\",\r\n    fontWeight: string = \"normal\",\r\n    dominantBaseline: string = \"alphabetic\"\r\n  ): SVGElement[] {\r\n    // Use the existing calculateTextLines method to avoid duplication\r\n    const lines = this.calculateTextLines(\r\n      text,\r\n      maxTextWidth,\r\n      fontSize,\r\n      fontFamily\r\n    );\r\n\r\n    // Create text elements for each line\r\n    const elements: SVGElement[] = [];\r\n    lines.forEach((line, index) => {\r\n      const lineY = startY + index * fontSize * lineHeight;\r\n\r\n      const textElement = document.createElementNS(SVG_NS, \"text\");\r\n      textElement.setAttribute(\"x\", x.toString());\r\n      textElement.setAttribute(\"y\", lineY.toString());\r\n      textElement.setAttribute(\"font-family\", fontFamily);\r\n      textElement.setAttribute(\"font-size\", fontSize.toString());\r\n      textElement.setAttribute(\"font-weight\", fontWeight);\r\n      textElement.setAttribute(\"fill\", fillColor);\r\n      textElement.setAttribute(\"stroke\", \"none\");\r\n      textElement.setAttribute(\"stroke-width\", \"0\");\r\n      textElement.setAttribute(\"text-anchor\", textAnchor);\r\n      textElement.setAttribute(\"dominant-baseline\", dominantBaseline);\r\n      textElement.textContent = line;\r\n      elements.push(textElement);\r\n    });\r\n\r\n    return elements;\r\n  }\r\n\r\n  /**\r\n   * Calculate height needed for wrapped title text\r\n   */\r\n  protected calculateWrappedTitleHeight(\r\n    title: string,\r\n    maxTextWidth: number,\r\n    fontSize: number,\r\n    fontFamily: string,\r\n    lineHeight: number = 1.2\r\n  ): number {\r\n    // Use the existing calculateTextLines method to avoid duplication\r\n    const lines = this.calculateTextLines(\r\n      title,\r\n      maxTextWidth,\r\n      fontSize,\r\n      fontFamily\r\n    );\r\n    return lines.length * fontSize * lineHeight;\r\n  }\r\n\r\n  /**\r\n   * Calculate lines needed for text wrapping using canvas measurement\r\n   */\r\n  protected calculateWrappedTextLines(\r\n    text: string,\r\n    maxWidth: number,\r\n    fontSize: number,\r\n    fontFamily: string\r\n  ): number {\r\n    // Use the existing calculateTextLines method to avoid duplication\r\n    const lines = this.calculateTextLines(text, maxWidth, fontSize, fontFamily);\r\n    return lines.length;\r\n  }\r\n\r\n  /**\r\n   * Create an SVG group container\r\n   */\r\n  protected createGroup(): SVGGElement {\r\n    return document.createElementNS(SVG_NS, \"g\");\r\n  }\r\n}\r\n","import { NodeOptions } from \"../types\";\r\nimport { BaseNodeRenderer } from \"./BaseNodeRenderer\";\r\nimport { NodeRenderResult } from \"./types\";\r\n\r\n/**\r\n * RectangleNodeRenderer handles rendering of rectangular nodes\r\n */\r\nexport class RectangleNodeRenderer extends BaseNodeRenderer {\r\n  public render(options: Required<NodeOptions>): NodeRenderResult {\r\n    const group = this.createGroup();\r\n\r\n    // Create shadow if enabled\r\n    const shadow = this.createShadow(options);\r\n    if (shadow) {\r\n      group.appendChild(shadow);\r\n    }\r\n\r\n    // Create the rectangle\r\n    const rect = this.createRectangleElement(options);\r\n    group.appendChild(rect);\r\n\r\n    // Create text\r\n    const text = this.createBasicText(options);\r\n    group.appendChild(text);\r\n\r\n    return {\r\n      element: group,\r\n      bounds: {\r\n        x: options.x,\r\n        y: options.y,\r\n        width: options.width,\r\n        height: options.height,\r\n      },\r\n      centerX: options.x + options.width / 2,\r\n      centerY: options.y + options.height / 2,\r\n    };\r\n  }\r\n}\r\n","import { SVG_NS, NODE_CONSTANTS } from \"../constants\";\r\nimport { NodeOptions } from \"../types\";\r\nimport { BaseNodeRenderer } from \"./BaseNodeRenderer\";\r\nimport { NodeRenderResult } from \"./types\";\r\n\r\n/**\r\n * NodeWithDescriptionRenderer handles rendering of nodes with description text\r\n * These nodes auto-size based on content and support text wrapping\r\n */\r\nexport class NodeWithDescriptionRenderer extends BaseNodeRenderer {\r\n  public render(options: Required<NodeOptions>): NodeRenderResult {\r\n    const group = this.createGroup();\r\n\r\n    // Calculate actual dimensions based on content\r\n    const actualWidth = this.calculateWidth(options);\r\n    const actualHeight = this.calculateHeight(options);\r\n\r\n    // Update options with calculated dimensions\r\n    const updatedOptions = {\r\n      ...options,\r\n      width: actualWidth,\r\n      height: actualHeight,\r\n    };\r\n\r\n    // Create shadow if enabled\r\n    const shadow = this.createShadow(updatedOptions);\r\n    if (shadow) {\r\n      group.appendChild(shadow);\r\n    }\r\n\r\n    // Create the rectangle\r\n    const rect = this.createRectangleElement(updatedOptions);\r\n    group.appendChild(rect);\r\n\r\n    // Create text elements\r\n    const textElements = this.createTextElements(updatedOptions);\r\n    textElements.forEach((element) => group.appendChild(element));\r\n\r\n    return {\r\n      element: group,\r\n      bounds: {\r\n        x: options.x,\r\n        y: options.y,\r\n        width: actualWidth,\r\n        height: actualHeight,\r\n      },\r\n      centerX: options.x + actualWidth / 2,\r\n      centerY: options.y + actualHeight / 2,\r\n    };\r\n  }\r\n\r\n  /**\r\n   * Calculate dynamic width based on content (matches original NodeDrawer logic)\r\n   */\r\n  public calculateDynamicWidth(node: any, nodeConfig: any): number {\r\n    const maxNodeWidth = nodeConfig.width || NODE_CONSTANTS.DEFAULT_MAX_WIDTH;\r\n    const padding = nodeConfig.padding || NODE_CONSTANTS.DEFAULT_PADDING;\r\n    const fontSize = nodeConfig.fontSize || NODE_CONSTANTS.DEFAULT_FONT_SIZE;\r\n    const descriptionFontSize =\r\n      nodeConfig.descriptionFontSize || NODE_CONSTANTS.DESCRIPTION_FONT_SIZE;\r\n    const fontFamily = nodeConfig.fontFamily || \"Arial, sans-serif\";\r\n\r\n    // Measure main text using inherited method\r\n    const textWidth = this.measureText(node.value || \"\", fontSize, fontFamily);\r\n    let maxRequiredWidth = textWidth;\r\n\r\n    // Handle description if present\r\n    if (node.description && node.description.trim()) {\r\n      // Calculate available width for description\r\n      const availableWidth = maxNodeWidth - padding * 2;\r\n\r\n      // Use inherited method for text line calculation\r\n      const lines = this.calculateTextLines(\r\n        node.description,\r\n        availableWidth,\r\n        descriptionFontSize,\r\n        fontFamily\r\n      );\r\n\r\n      // Find the maximum line width\r\n      let maxLineWidth = 0;\r\n      for (const line of lines) {\r\n        const lineWidth = this.measureText(\r\n          line,\r\n          descriptionFontSize,\r\n          fontFamily\r\n        );\r\n        maxLineWidth = Math.max(maxLineWidth, lineWidth);\r\n      }\r\n\r\n      maxRequiredWidth = Math.max(maxRequiredWidth, maxLineWidth);\r\n    }\r\n\r\n    // Calculate final width - use the maximum of configured width or required width\r\n    // Don't cap at maxNodeWidth for dynamic nodes since they need to fit their content\r\n    const minWidthRequired = maxRequiredWidth + padding * 2;\r\n    const finalWidth = Math.min(\r\n      Math.max(nodeConfig.width || 0, minWidthRequired),\r\n      maxNodeWidth\r\n    );\r\n    return finalWidth;\r\n  }\r\n\r\n  /**\r\n   * Calculate dynamic height based on content (matches original NodeDrawer logic)\r\n   */\r\n  public calculateDynamicHeight(node: any, nodeConfig: any): number {\r\n    const lineHeight = NODE_CONSTANTS.DESCRIPTION_LINE_HEIGHT;\r\n    const padding = nodeConfig.padding || NODE_CONSTANTS.DEFAULT_PADDING;\r\n    const fontSize = nodeConfig.fontSize || NODE_CONSTANTS.DEFAULT_FONT_SIZE;\r\n    const descriptionFontSize =\r\n      nodeConfig.descriptionFontSize || NODE_CONSTANTS.DESCRIPTION_FONT_SIZE;\r\n\r\n    // Calculate available width for text wrapping\r\n    const maxWidth = nodeConfig.width || NODE_CONSTANTS.DEFAULT_MAX_WIDTH;\r\n    const availableWidth = maxWidth - padding * 2;\r\n\r\n    // Calculate wrapped title height\r\n    const titleHeight = this.calculateWrappedTitleHeight(\r\n      node.value || \"\",\r\n      availableWidth,\r\n      fontSize,\r\n      nodeConfig.fontFamily || \"Arial, sans-serif\",\r\n      1.2\r\n    );\r\n\r\n    let totalRequiredHeight = titleHeight; // Start with wrapped title height\r\n\r\n    // Handle description if present\r\n    if (node.description && node.description.trim()) {\r\n      // Use base class method to calculate lines\r\n      const lines = this.calculateWrappedTextLines(\r\n        node.description,\r\n        availableWidth,\r\n        descriptionFontSize,\r\n        nodeConfig.fontFamily || \"Arial, sans-serif\"\r\n      );\r\n\r\n      // Calculate description height with proper spacing\r\n      const descriptionSpacing = 12; // Same spacing as in text positioning\r\n      const descriptionHeight = lines * descriptionFontSize * lineHeight;\r\n      totalRequiredHeight += descriptionSpacing + descriptionHeight;\r\n    }\r\n\r\n    // Calculate final height with padding\r\n    const minHeightRequired = totalRequiredHeight + padding * 2;\r\n    return Math.max(nodeConfig.height || 0, minHeightRequired);\r\n  }\r\n\r\n  /**\r\n   * Helper method to calculate width from options (adapter for render method)\r\n   */\r\n  private calculateWidth(options: Required<NodeOptions>): number {\r\n    // Convert options to node-like object for dynamic calculation\r\n    const node = {\r\n      value: options.text,\r\n      description: options.description,\r\n    };\r\n\r\n    const nodeConfig = {\r\n      padding: options.padding,\r\n      fontSize: options.fontSize,\r\n      descriptionFontSize: options.descriptionFontSize,\r\n      fontFamily: options.fontFamily,\r\n      width: options.width,\r\n    };\r\n\r\n    return this.calculateDynamicWidth(node, nodeConfig);\r\n  }\r\n\r\n  /**\r\n   * Helper method to calculate height from options (adapter for render method)\r\n   */\r\n  private calculateHeight(options: Required<NodeOptions>): number {\r\n    // Convert options to node-like object for dynamic calculation\r\n    const node = {\r\n      value: options.text,\r\n      description: options.description,\r\n    };\r\n\r\n    const nodeConfig = {\r\n      padding: options.padding,\r\n      fontSize: options.fontSize,\r\n      descriptionFontSize: options.descriptionFontSize,\r\n      descriptionMarginTop: options.descriptionMarginTop,\r\n      fontFamily: options.fontFamily,\r\n      height: options.height,\r\n    };\r\n\r\n    return this.calculateDynamicHeight(node, nodeConfig);\r\n  }\r\n\r\n  private createTextElements(options: Required<NodeOptions>): SVGElement[] {\r\n    const elements: SVGElement[] = [];\r\n    const centerX = options.x + options.width / 2;\r\n    const padding = options.padding;\r\n\r\n    // Calculate available width for title text\r\n    const maxTitleWidth = options.width - padding * 2;\r\n\r\n    // Create wrapped title text\r\n    const titleStartY = options.y + padding + options.fontSize;\r\n    const titleElements = this.createAutoWrappedText(\r\n      options.text,\r\n      maxTitleWidth,\r\n      options.fontSize,\r\n      options.fontFamily,\r\n      centerX,\r\n      titleStartY,\r\n      options.fontColor,\r\n      1.2,\r\n      \"middle\",\r\n      \"bold\",\r\n      \"alphabetic\"\r\n    );\r\n    elements.push(...titleElements);\r\n\r\n    // Calculate actual height used by title\r\n    const titleHeight = this.calculateWrappedTitleHeight(\r\n      options.text,\r\n      maxTitleWidth,\r\n      options.fontSize,\r\n      options.fontFamily,\r\n      1.2\r\n    );\r\n\r\n    // Create description text if present (only if width is sufficient)\r\n    if (\r\n      options.description &&\r\n      options.description.trim() &&\r\n      options.width >= NODE_CONSTANTS.MIN_WIDTH_FOR_DESCRIPTION\r\n    ) {\r\n      const maxTextWidth = options.width - padding * 2;\r\n\r\n      // Position description after the wrapped title\r\n      const titleBottomY = options.y + padding + titleHeight;\r\n      const descriptionSpacing = 12; // Add more spacing between title and description\r\n      const textStartY =\r\n        titleBottomY + descriptionSpacing + options.descriptionFontSize;\r\n\r\n      const centerX = options.x + options.width / 2;\r\n\r\n      // Use base class method for text wrapping\r\n      const descriptionElements = this.createAutoWrappedText(\r\n        options.description,\r\n        maxTextWidth,\r\n        options.descriptionFontSize,\r\n        options.fontFamily,\r\n        centerX,\r\n        textStartY,\r\n        options.descriptionFontColor,\r\n        NODE_CONSTANTS.DESCRIPTION_LINE_HEIGHT,\r\n        \"middle\",\r\n        \"normal\",\r\n        \"alphabetic\"\r\n      );\r\n\r\n      elements.push(...descriptionElements);\r\n    }\r\n\r\n    return elements;\r\n  }\r\n}\r\n","import { SVG_NS, NODE_CONSTANTS } from \"../constants\";\r\nimport { NodeOptions } from \"../types\";\r\nimport { BaseNodeRenderer } from \"./BaseNodeRenderer\";\r\nimport { NodeRenderResult } from \"./types\";\r\n\r\n/**\r\n * CollapsibleNodeRenderer handles rendering of collapsible nodes with expand/collapse func    // Position chevron vertically centered with the title text\r\n    // Calculate the actual visual center of the text for perfect alignment\r\n    const textY = options.y + options.padding + options.fontSize;\r\n    const textVisualCenter = textY - (options.fontSize * 0.1); // Adjust for text visual center\r\n    const chevronY = textVisualCenter;\r\n    const chevronSize = 8;ity\r\n * These nodes can show/hide description based on expanded state and include chevron icons\r\n */\r\nexport class CollapsibleNodeRenderer extends BaseNodeRenderer {\r\n  public render(options: Required<NodeOptions>): NodeRenderResult {\r\n    const group = this.createGroup();\r\n\r\n    // Calculate actual dimensions based on content and expanded state\r\n    const actualWidth = this.calculateWidth(options);\r\n    const actualHeight = this.calculateHeight(options);\r\n\r\n    // Update options with calculated dimensions\r\n    const updatedOptions = {\r\n      ...options,\r\n      width: actualWidth,\r\n      height: actualHeight,\r\n    };\r\n\r\n    // Create shadow if enabled\r\n    const shadow = this.createShadow(updatedOptions);\r\n    if (shadow) {\r\n      group.appendChild(shadow);\r\n    }\r\n\r\n    // Create the rectangle\r\n    const rect = this.createRectangleElement(updatedOptions);\r\n    group.appendChild(rect);\r\n\r\n    // Create text elements\r\n    const textElements = this.createTextElements(updatedOptions);\r\n    textElements.forEach((element) => group.appendChild(element));\r\n\r\n    // Create chevron icon for expand/collapse\r\n    const chevron = this.createChevronIcon(updatedOptions);\r\n    group.appendChild(chevron);\r\n\r\n    // Add click handler for expand/collapse\r\n    this.addClickHandler(group, updatedOptions);\r\n\r\n    return {\r\n      element: group,\r\n      bounds: {\r\n        x: options.x,\r\n        y: options.y,\r\n        width: actualWidth,\r\n        height: actualHeight,\r\n      },\r\n      centerX: options.x + actualWidth / 2,\r\n      centerY: options.y + actualHeight / 2,\r\n    };\r\n  }\r\n\r\n  /**\r\n   * Calculate dynamic width based on content and collapsible state (matches original NodeDrawer logic)\r\n   */\r\n  public calculateDynamicWidth(node: any, nodeConfig: any): number {\r\n    const maxNodeWidth = nodeConfig.width || NODE_CONSTANTS.DEFAULT_MAX_WIDTH;\r\n    const padding = nodeConfig.padding || NODE_CONSTANTS.DEFAULT_PADDING;\r\n    const fontSize = nodeConfig.fontSize || NODE_CONSTANTS.DEFAULT_FONT_SIZE;\r\n    const descriptionFontSize =\r\n      nodeConfig.descriptionFontSize || NODE_CONSTANTS.DESCRIPTION_FONT_SIZE;\r\n    const fontFamily = nodeConfig.fontFamily || \"Arial, sans-serif\";\r\n\r\n    // Measure main text using inherited method\r\n    const textWidth = this.measureText(node.value || \"\", fontSize, fontFamily);\r\n    let maxRequiredWidth = textWidth;\r\n\r\n    // Add space for chevron button\r\n    maxRequiredWidth += NODE_CONSTANTS.SPACE_FOR_ARROW_BUTTON;\r\n\r\n    // Handle description if present and expanded\r\n    if (\r\n      node.description &&\r\n      node.description.trim() &&\r\n      node.collapsibleState?.expanded\r\n    ) {\r\n      // Calculate available width for description\r\n      const availableWidth = maxNodeWidth - padding * 2;\r\n\r\n      // Use inherited method for text line calculation\r\n      const lines = this.calculateTextLines(\r\n        node.description,\r\n        availableWidth,\r\n        descriptionFontSize,\r\n        fontFamily\r\n      );\r\n\r\n      // Find the maximum line width\r\n      let maxLineWidth = 0;\r\n      for (const line of lines) {\r\n        const lineWidth = this.measureText(\r\n          line,\r\n          descriptionFontSize,\r\n          fontFamily\r\n        );\r\n        maxLineWidth = Math.max(maxLineWidth, lineWidth);\r\n      }\r\n\r\n      maxRequiredWidth = Math.max(maxRequiredWidth, maxLineWidth);\r\n    }\r\n\r\n    // Calculate final width\r\n    const minWidthRequired = maxRequiredWidth + padding * 2;\r\n    const finalWidth = Math.min(\r\n      Math.max(nodeConfig.width || 0, minWidthRequired),\r\n      maxNodeWidth\r\n    );\r\n    return finalWidth;\r\n  }\r\n\r\n  /**\r\n   * Calculate dynamic height based on content and collapsible state (matches original NodeDrawer logic)\r\n   */\r\n  public calculateDynamicHeight(node: any, nodeConfig: any): number {\r\n    const lineHeight = NODE_CONSTANTS.DESCRIPTION_LINE_HEIGHT;\r\n    const padding = nodeConfig.padding || NODE_CONSTANTS.DEFAULT_PADDING;\r\n    const fontSize = nodeConfig.fontSize || NODE_CONSTANTS.DEFAULT_FONT_SIZE;\r\n    const descriptionFontSize =\r\n      nodeConfig.descriptionFontSize || NODE_CONSTANTS.DESCRIPTION_FONT_SIZE;\r\n\r\n    // Calculate available width for text wrapping (accounting for chevron space)\r\n    const maxWidth = nodeConfig.width || NODE_CONSTANTS.DEFAULT_MAX_WIDTH;\r\n    const chevronSpace = NODE_CONSTANTS.SPACE_FOR_ARROW_BUTTON;\r\n    const titleAvailableWidth = maxWidth - padding * 2 - chevronSpace;\r\n\r\n    // Calculate wrapped title height\r\n    const titleHeight = this.calculateWrappedTitleHeight(\r\n      node.value || \"\",\r\n      titleAvailableWidth,\r\n      fontSize,\r\n      nodeConfig.fontFamily || \"Arial, sans-serif\",\r\n      1.2\r\n    );\r\n\r\n    let totalRequiredHeight = titleHeight; // Start with wrapped title height\r\n\r\n    // Handle description if present and expanded\r\n    if (\r\n      node.description &&\r\n      node.description.trim() &&\r\n      node.collapsibleState?.expanded\r\n    ) {\r\n      // Calculate available width for description text wrapping\r\n      const availableWidth = maxWidth - padding * 2;\r\n\r\n      // Use base class method to calculate lines\r\n      const lines = this.calculateWrappedTextLines(\r\n        node.description,\r\n        availableWidth,\r\n        descriptionFontSize,\r\n        nodeConfig.fontFamily || \"Arial, sans-serif\"\r\n      );\r\n\r\n      // Calculate description height with proper spacing\r\n      const descriptionSpacing = 12; // Same spacing as in text positioning\r\n      const descriptionHeight = lines * descriptionFontSize * lineHeight;\r\n      totalRequiredHeight += descriptionSpacing + descriptionHeight;\r\n    }\r\n\r\n    // Calculate final height with padding\r\n    // Add extra padding at bottom when expanded for better visual spacing\r\n    const bottomPadding = node.collapsibleState?.expanded\r\n      ? padding * 2\r\n      : padding;\r\n    const minHeightRequired = totalRequiredHeight + padding + bottomPadding;\r\n    return Math.max(nodeConfig.height || 0, minHeightRequired);\r\n  }\r\n\r\n  /**\r\n   * Helper method to calculate width from options (adapter for render method)\r\n   */\r\n  private calculateWidth(options: Required<NodeOptions>): number {\r\n    // Convert options to node-like object for dynamic calculation\r\n    const node = {\r\n      value: options.text,\r\n      description: options.description,\r\n      collapsibleState: { expanded: options.expanded },\r\n    };\r\n\r\n    const nodeConfig = {\r\n      padding: options.padding,\r\n      fontSize: options.fontSize,\r\n      descriptionFontSize: options.descriptionFontSize,\r\n      fontFamily: options.fontFamily,\r\n      width: options.width,\r\n    };\r\n\r\n    return this.calculateDynamicWidth(node, nodeConfig);\r\n  }\r\n\r\n  /**\r\n   * Helper method to calculate height from options (adapter for render method)\r\n   */\r\n  private calculateHeight(options: Required<NodeOptions>): number {\r\n    // Convert options to node-like object for dynamic calculation\r\n    const node = {\r\n      value: options.text,\r\n      description: options.description,\r\n      collapsibleState: { expanded: options.expanded },\r\n    };\r\n\r\n    const nodeConfig = {\r\n      padding: options.padding,\r\n      fontSize: options.fontSize,\r\n      descriptionFontSize: options.descriptionFontSize,\r\n      descriptionMarginTop: options.descriptionMarginTop,\r\n      fontFamily: options.fontFamily,\r\n      height: options.height,\r\n    };\r\n\r\n    return this.calculateDynamicHeight(node, nodeConfig);\r\n  }\r\n\r\n  private createTextElements(options: Required<NodeOptions>): SVGElement[] {\r\n    const elements: SVGElement[] = [];\r\n    const padding = options.padding;\r\n\r\n    // Calculate text positioning (accounting for chevron space)\r\n    const chevronSpace = NODE_CONSTANTS.SPACE_FOR_ARROW_BUTTON;\r\n    const textCenterX = options.x + (options.width - chevronSpace) / 2;\r\n\r\n    // Calculate available width for title text (accounting for chevron space)\r\n    const maxTitleWidth = options.width - padding * 2 - chevronSpace;\r\n\r\n    // Create wrapped title text\r\n    const titleStartY = options.y + padding + options.fontSize;\r\n    const titleElements = this.createAutoWrappedText(\r\n      options.text,\r\n      maxTitleWidth,\r\n      options.fontSize,\r\n      options.fontFamily,\r\n      textCenterX,\r\n      titleStartY,\r\n      options.fontColor,\r\n      1.2,\r\n      \"middle\",\r\n      \"bold\",\r\n      \"alphabetic\"\r\n    );\r\n    elements.push(...titleElements);\r\n\r\n    // Calculate actual height used by title\r\n    const titleHeight = this.calculateWrappedTitleHeight(\r\n      options.text,\r\n      maxTitleWidth,\r\n      options.fontSize,\r\n      options.fontFamily,\r\n      1.2\r\n    );\r\n\r\n    // Create description text if present and expanded (only if width is sufficient)\r\n    if (\r\n      options.description &&\r\n      options.description.trim() &&\r\n      options.expanded &&\r\n      options.width >= NODE_CONSTANTS.MIN_WIDTH_FOR_DESCRIPTION\r\n    ) {\r\n      const maxTextWidth = options.width - padding * 2;\r\n\r\n      // Position description after the wrapped title\r\n      const titleBottomY = options.y + padding + titleHeight;\r\n      const descriptionSpacing = 12; // Add more spacing between title and description\r\n      const textStartY =\r\n        titleBottomY + descriptionSpacing + options.descriptionFontSize;\r\n\r\n      const centerX = options.x + options.width / 2;\r\n\r\n      // Use base class method for text wrapping\r\n      const descriptionElements = this.createAutoWrappedText(\r\n        options.description,\r\n        maxTextWidth,\r\n        options.descriptionFontSize,\r\n        options.fontFamily,\r\n        centerX,\r\n        textStartY,\r\n        options.descriptionFontColor,\r\n        NODE_CONSTANTS.DESCRIPTION_LINE_HEIGHT,\r\n        \"middle\",\r\n        \"normal\",\r\n        \"alphabetic\"\r\n      );\r\n\r\n      elements.push(...descriptionElements);\r\n    }\r\n\r\n    return elements;\r\n  }\r\n\r\n  private createChevronIcon(options: Required<NodeOptions>): SVGGElement {\r\n    const chevronGroup = this.createGroup();\r\n    chevronGroup.style.outline = \"none\";\r\n\r\n    // Position chevron with proper padding from the edge\r\n    const chevronPadding = 8; // More padding from the edge\r\n    const chevronX = options.x + options.width - chevronPadding - 6; // 6 is half of chevronSize for centering\r\n\r\n    // Position chevron vertically centered with the first line of the title text\r\n    // The first line starts at y = options.y + options.padding + options.fontSize\r\n    const firstLineCenterY = options.y + options.padding + options.fontSize;\r\n    const textVisualCenter = firstLineCenterY - options.fontSize * 0.1;\r\n    const chevronY = textVisualCenter;\r\n    const chevronSize = 8;\r\n\r\n    // Create chevron path based on expanded state\r\n    const chevronPath = document.createElementNS(SVG_NS, \"path\");\r\n\r\n    if (options.expanded) {\r\n      // Up chevron (expanded state) - pointing up when expanded\r\n      const pathData = `M ${chevronX - chevronSize / 2} ${\r\n        chevronY + chevronSize / 4\r\n      } \r\n                       L ${chevronX} ${chevronY - chevronSize / 4} \r\n                       L ${chevronX + chevronSize / 2} ${\r\n        chevronY + chevronSize / 4\r\n      }`;\r\n      chevronPath.setAttribute(\"d\", pathData);\r\n    } else {\r\n      // Down chevron (collapsed state) - pointing down when collapsed\r\n      const pathData = `M ${chevronX - chevronSize / 2} ${\r\n        chevronY - chevronSize / 4\r\n      } \r\n                       L ${chevronX} ${chevronY + chevronSize / 4} \r\n                       L ${chevronX + chevronSize / 2} ${\r\n        chevronY - chevronSize / 4\r\n      }`;\r\n      chevronPath.setAttribute(\"d\", pathData);\r\n    }\r\n\r\n    chevronPath.setAttribute(\"fill\", \"none\");\r\n    chevronPath.setAttribute(\"stroke\", options.fontColor);\r\n    chevronPath.setAttribute(\"stroke-width\", \"2\");\r\n    chevronPath.setAttribute(\"stroke-linecap\", \"round\");\r\n    chevronPath.setAttribute(\"stroke-linejoin\", \"round\");\r\n\r\n    // Add clickable area for better UX - positioned around the chevron with proper padding\r\n    const clickArea = document.createElementNS(SVG_NS, \"rect\");\r\n    const clickAreaSize = 20; // Make it a bit larger for easier clicking\r\n    clickArea.setAttribute(\"x\", (chevronX - clickAreaSize / 2).toString());\r\n    clickArea.setAttribute(\"y\", (chevronY - clickAreaSize / 2).toString());\r\n    clickArea.setAttribute(\"width\", clickAreaSize.toString());\r\n    clickArea.setAttribute(\"height\", clickAreaSize.toString());\r\n    clickArea.setAttribute(\"fill\", \"transparent\");\r\n    clickArea.setAttribute(\"stroke\", \"none\");\r\n    clickArea.setAttribute(\"outline\", \"none\");\r\n    clickArea.setAttribute(\"cursor\", \"pointer\");\r\n    clickArea.style.outline = \"none\";\r\n    clickArea.style.border = \"none\";\r\n\r\n    chevronGroup.appendChild(clickArea);\r\n    chevronGroup.appendChild(chevronPath);\r\n\r\n    return chevronGroup;\r\n  }\r\n\r\n  private addClickHandler(\r\n    group: SVGGElement,\r\n    options: Required<NodeOptions>\r\n  ): void {\r\n    // Find the chevron area for click handling\r\n    const clickArea = group.querySelector('rect[fill=\"transparent\"]');\r\n    if (clickArea && options.onToggleExpand) {\r\n      clickArea.addEventListener(\"click\", (event) => {\r\n        event.stopPropagation();\r\n        options.onToggleExpand(!options.expanded);\r\n      });\r\n    }\r\n  }\r\n}\r\n","import { SVG_NS, NODE_CONSTANTS } from \"../constants\";\r\nimport { NodeOptions } from \"../types\";\r\nimport { BaseNodeRenderer } from \"./BaseNodeRenderer\";\r\nimport { NodeRenderResult } from \"./types\";\r\n\r\n/**\r\n * ImageNodeRenderer handles rendering of nodes with images and optional text\r\n * Follows the same pattern as other node renderers in the codebase\r\n */\r\nexport class ImageNodeRenderer extends BaseNodeRenderer {\r\n  public render(options: Required<NodeOptions>): NodeRenderResult {\r\n    const group = this.createGroup();\r\n\r\n    // Calculate actual dimensions based on content and text position\r\n    const layout = this.calculateLayout(options);\r\n\r\n    // Update options with calculated dimensions\r\n    const updatedOptions = {\r\n      ...options,\r\n      width: layout.totalWidth,\r\n      height: layout.totalHeight,\r\n    };\r\n\r\n    // Create background container if needed\r\n    if (updatedOptions.fill && updatedOptions.fill !== \"none\") {\r\n      const background = this.createBackgroundContainer(updatedOptions, layout);\r\n      group.appendChild(background);\r\n    }\r\n\r\n    // Create shadow if enabled\r\n    const shadow = this.createShadow(updatedOptions);\r\n    if (shadow) {\r\n      group.appendChild(shadow);\r\n    }\r\n\r\n    // Create the image element\r\n    if (options.imageUrl) {\r\n      const imageElement = this.createImageElement(options, layout);\r\n      group.appendChild(imageElement);\r\n    }\r\n\r\n    // Create text elements if present\r\n    const textElements = this.createTextElements(options, layout);\r\n    textElements.forEach((element) => group.appendChild(element));\r\n\r\n    return {\r\n      element: group,\r\n      bounds: {\r\n        x: options.x,\r\n        y: options.y,\r\n        width: layout.totalWidth,\r\n        height: layout.totalHeight,\r\n      },\r\n      centerX: options.x + layout.totalWidth / 2,\r\n      centerY: options.y + layout.totalHeight / 2,\r\n    };\r\n  }\r\n\r\n  /**\r\n   * Calculate dynamic width based on content and text position\r\n   */\r\n  public calculateDynamicWidth(node: any, nodeConfig: any): number {\r\n    const layout = this.calculateLayoutForNode(node, nodeConfig);\r\n    return layout.totalWidth;\r\n  }\r\n\r\n  /**\r\n   * Calculate dynamic height based on content and text position\r\n   */\r\n  public calculateDynamicHeight(node: any, nodeConfig: any): number {\r\n    const layout = this.calculateLayoutForNode(node, nodeConfig);\r\n    return layout.totalHeight;\r\n  }\r\n\r\n  /**\r\n   * Calculate layout for a node and config (used by dynamic sizing)\r\n   */\r\n  private calculateLayoutForNode(node: any, nodeConfig: any) {\r\n    const imageConfig = nodeConfig.imageConfig || {};\r\n    const imageTitleConfig = nodeConfig.imageTitleConfig || {};\r\n    const imageSubtitleConfig = nodeConfig.imageSubtitleConfig || {};\r\n    const imageTextPositionConfig = nodeConfig.imageTextPositionConfig || {};\r\n\r\n    const imageWidth =\r\n      imageConfig.imageWidth || NODE_CONSTANTS.DEFAULT_IMAGE_WIDTH;\r\n    const imageHeight =\r\n      imageConfig.imageHeight || NODE_CONSTANTS.DEFAULT_IMAGE_HEIGHT;\r\n    const textPosition = imageTextPositionConfig.position || \"bottom\";\r\n    const textPadding =\r\n      imageTextPositionConfig.padding || NODE_CONSTANTS.DEFAULT_TEXT_PADDING;\r\n    const textSpacing =\r\n      imageTextPositionConfig.spacing || NODE_CONSTANTS.DEFAULT_TEXT_SPACING;\r\n    const imageMargin =\r\n      nodeConfig.imageMargin || NODE_CONSTANTS.DEFAULT_IMAGE_MARGIN;\r\n\r\n    const title = node.title || node.value || \"\";\r\n    const subtitle = node.subtitle || node.description || \"\";\r\n    const titleFontSize =\r\n      imageTitleConfig.fontSize ||\r\n      nodeConfig.fontSize ||\r\n      NODE_CONSTANTS.DEFAULT_TITLE_FONT_SIZE;\r\n    const subtitleFontSize =\r\n      imageSubtitleConfig.fontSize || NODE_CONSTANTS.DEFAULT_SUBTITLE_FONT_SIZE;\r\n    const fontFamily = nodeConfig.fontFamily || \"Arial\";\r\n\r\n    // Calculate text dimensions using inherited method to avoid duplication\r\n    let maxTextWidth = 0;\r\n\r\n    if (title) {\r\n      maxTextWidth = Math.max(\r\n        maxTextWidth,\r\n        this.measureText(title, titleFontSize, fontFamily)\r\n      );\r\n    }\r\n    if (subtitle) {\r\n      maxTextWidth = Math.max(\r\n        maxTextWidth,\r\n        this.measureText(subtitle, subtitleFontSize, fontFamily)\r\n      );\r\n    }\r\n\r\n    // Calculate text height\r\n    let textHeight = 0;\r\n    if (title) {\r\n      textHeight += titleFontSize * 1.2;\r\n    }\r\n    if (subtitle) {\r\n      if (title) textHeight += textSpacing;\r\n      textHeight += subtitleFontSize * 1.2;\r\n    }\r\n\r\n    // Calculate total dimensions based on text position\r\n    let totalWidth, totalHeight;\r\n\r\n    switch (textPosition) {\r\n      case \"left\":\r\n      case \"right\":\r\n        totalWidth = Math.max(\r\n          NODE_CONSTANTS.MIN_IMAGE_NODE_WIDTH,\r\n          imageWidth + maxTextWidth + textPadding + imageMargin * 2\r\n        );\r\n        totalHeight = Math.max(\r\n          NODE_CONSTANTS.MIN_IMAGE_NODE_HEIGHT,\r\n          Math.max(imageHeight, textHeight) + imageMargin * 2\r\n        );\r\n        break;\r\n      case \"bottom\":\r\n      default:\r\n        totalWidth = Math.max(\r\n          NODE_CONSTANTS.MIN_IMAGE_NODE_WIDTH,\r\n          Math.max(imageWidth, maxTextWidth) + imageMargin * 2\r\n        );\r\n        totalHeight = Math.max(\r\n          NODE_CONSTANTS.MIN_IMAGE_NODE_HEIGHT,\r\n          imageHeight +\r\n            textHeight +\r\n            (textHeight > 0 ? textPadding : 0) +\r\n            imageMargin * 2\r\n        );\r\n        break;\r\n    }\r\n\r\n    return {\r\n      totalWidth,\r\n      totalHeight,\r\n      imageWidth,\r\n      imageHeight,\r\n      textHeight,\r\n      maxTextWidth,\r\n    };\r\n  }\r\n\r\n  /**\r\n   * Calculate layout dimensions and positions based on text position\r\n   */\r\n  private calculateLayout(options: Required<NodeOptions>) {\r\n    const imageConfig = options.imageConfig || {};\r\n    const imageTitleConfig = options.imageTitleConfig || {};\r\n    const imageSubtitleConfig = options.imageSubtitleConfig || {};\r\n    const imageTextPositionConfig = options.imageTextPositionConfig || {};\r\n\r\n    const imageWidth =\r\n      imageConfig.imageWidth || NODE_CONSTANTS.DEFAULT_IMAGE_WIDTH;\r\n    const imageHeight =\r\n      imageConfig.imageHeight || NODE_CONSTANTS.DEFAULT_IMAGE_HEIGHT;\r\n    const textPosition = imageTextPositionConfig.position || \"bottom\";\r\n    const textPadding =\r\n      imageTextPositionConfig.padding || NODE_CONSTANTS.DEFAULT_TEXT_PADDING;\r\n    const textSpacing =\r\n      imageTextPositionConfig.spacing || NODE_CONSTANTS.DEFAULT_TEXT_SPACING;\r\n    const imageMargin =\r\n      options.imageMargin || NODE_CONSTANTS.DEFAULT_IMAGE_MARGIN;\r\n\r\n    const title = options.title || options.text || \"\";\r\n    const subtitle = options.subtitle || options.description || \"\";\r\n    const titleFontSize =\r\n      imageTitleConfig.fontSize ||\r\n      options.fontSize ||\r\n      NODE_CONSTANTS.DEFAULT_TITLE_FONT_SIZE;\r\n    const subtitleFontSize =\r\n      imageSubtitleConfig.fontSize || NODE_CONSTANTS.DEFAULT_SUBTITLE_FONT_SIZE;\r\n\r\n    // Measure text dimensions\r\n    const titleWidth = title\r\n      ? this.measureText(title, titleFontSize, options.fontFamily)\r\n      : 0;\r\n    const subtitleWidth = subtitle\r\n      ? this.measureText(subtitle, subtitleFontSize, options.fontFamily)\r\n      : 0;\r\n    const maxTextWidth = Math.max(titleWidth, subtitleWidth);\r\n\r\n    const titleHeight = title ? titleFontSize * 1.2 : 0;\r\n    const subtitleHeight = subtitle ? subtitleFontSize * 1.2 : 0;\r\n    const totalTextHeight =\r\n      titleHeight + (title && subtitle ? textSpacing : 0) + subtitleHeight;\r\n\r\n    let totalWidth: number;\r\n    let totalHeight: number;\r\n    let imageX: number;\r\n    let imageY: number;\r\n    let textAreaX: number;\r\n    let textAreaY: number;\r\n    let textAreaWidth: number;\r\n\r\n    switch (textPosition) {\r\n      case \"bottom\":\r\n        totalWidth = Math.max(imageWidth, maxTextWidth) + imageMargin * 2;\r\n        totalHeight =\r\n          imageHeight +\r\n          totalTextHeight +\r\n          imageMargin * 2 +\r\n          (totalTextHeight > 0 ? textPadding : 0);\r\n        imageX = imageMargin + (totalWidth - imageMargin * 2 - imageWidth) / 2;\r\n        imageY = imageMargin;\r\n        textAreaX = imageMargin;\r\n        textAreaY = imageY + imageHeight + textPadding;\r\n        textAreaWidth = totalWidth - imageMargin * 2;\r\n        break;\r\n\r\n      case \"left\":\r\n        totalWidth =\r\n          maxTextWidth +\r\n          imageWidth +\r\n          imageMargin * 2 +\r\n          (maxTextWidth > 0 ? textPadding : 0);\r\n        totalHeight = Math.max(imageHeight, totalTextHeight) + imageMargin * 2;\r\n        imageX = totalWidth - imageMargin - imageWidth;\r\n        imageY =\r\n          imageMargin + (totalHeight - imageMargin * 2 - imageHeight) / 2;\r\n        textAreaX = imageMargin;\r\n        textAreaY =\r\n          imageMargin + (totalHeight - imageMargin * 2 - totalTextHeight) / 2;\r\n        textAreaWidth = maxTextWidth;\r\n        break;\r\n\r\n      case \"right\":\r\n        totalWidth =\r\n          imageWidth +\r\n          maxTextWidth +\r\n          imageMargin * 2 +\r\n          (maxTextWidth > 0 ? textPadding : 0);\r\n        totalHeight = Math.max(imageHeight, totalTextHeight) + imageMargin * 2;\r\n        imageX = imageMargin;\r\n        imageY =\r\n          imageMargin + (totalHeight - imageMargin * 2 - imageHeight) / 2;\r\n        textAreaX = imageX + imageWidth + textPadding;\r\n        textAreaY =\r\n          imageMargin + (totalHeight - imageMargin * 2 - totalTextHeight) / 2;\r\n        textAreaWidth = maxTextWidth;\r\n        break;\r\n\r\n      default:\r\n        totalWidth = Math.max(imageWidth, maxTextWidth) + imageMargin * 2;\r\n        totalHeight =\r\n          imageHeight +\r\n          totalTextHeight +\r\n          imageMargin * 2 +\r\n          (totalTextHeight > 0 ? textPadding : 0);\r\n        imageX = imageMargin + (totalWidth - imageMargin * 2 - imageWidth) / 2;\r\n        imageY = imageMargin;\r\n        textAreaX = imageMargin;\r\n        textAreaY = imageY + imageHeight + textPadding;\r\n        textAreaWidth = totalWidth - imageMargin * 2;\r\n        break;\r\n    }\r\n\r\n    return {\r\n      totalWidth,\r\n      totalHeight,\r\n      imageX,\r\n      imageY,\r\n      textAreaX,\r\n      textAreaY,\r\n      textAreaWidth,\r\n      titleHeight,\r\n      subtitleHeight,\r\n      totalTextHeight,\r\n      textSpacing,\r\n    };\r\n  }\r\n\r\n  /**\r\n   * Create background container for the entire node\r\n   */\r\n  private createBackgroundContainer(\r\n    options: Required<NodeOptions>,\r\n    layout: any\r\n  ): SVGRectElement {\r\n    const rect = document.createElementNS(SVG_NS, \"rect\");\r\n\r\n    rect.setAttribute(\"x\", options.x.toString());\r\n    rect.setAttribute(\"y\", options.y.toString());\r\n    rect.setAttribute(\"width\", layout.totalWidth.toString());\r\n    rect.setAttribute(\"height\", layout.totalHeight.toString());\r\n    rect.setAttribute(\"rx\", options.borderRadius.toString());\r\n    rect.setAttribute(\"ry\", options.borderRadius.toString());\r\n\r\n    // Apply gradient or solid fill\r\n    const gradientUrl = this.createGradient(options);\r\n    const fill = gradientUrl || options.fill;\r\n    rect.setAttribute(\"fill\", fill);\r\n\r\n    this.applyCommonStyling(rect, options);\r\n\r\n    return rect;\r\n  }\r\n\r\n  /**\r\n   * Create the image element\r\n   */\r\n  private createImageElement(\r\n    options: Required<NodeOptions>,\r\n    layout: any\r\n  ): SVGImageElement {\r\n    const imageConfig = options.imageConfig || {};\r\n    const imageElement = document.createElementNS(SVG_NS, \"image\");\r\n\r\n    // Position the image\r\n    imageElement.setAttribute(\"x\", (options.x + layout.imageX).toString());\r\n    imageElement.setAttribute(\"y\", (options.y + layout.imageY).toString());\r\n    imageElement.setAttribute(\r\n      \"width\",\r\n      (imageConfig.imageWidth || NODE_CONSTANTS.DEFAULT_IMAGE_WIDTH).toString()\r\n    );\r\n    imageElement.setAttribute(\r\n      \"height\",\r\n      (\r\n        imageConfig.imageHeight || NODE_CONSTANTS.DEFAULT_IMAGE_HEIGHT\r\n      ).toString()\r\n    );\r\n    imageElement.setAttribute(\"href\", options.imageUrl || \"\");\r\n    imageElement.setAttribute(\r\n      \"opacity\",\r\n      (\r\n        imageConfig.imageOpacity || NODE_CONSTANTS.DEFAULT_IMAGE_OPACITY\r\n      ).toString()\r\n    );\r\n\r\n    // Add image styling through a clipping path and background\r\n    const borderRadius =\r\n      imageConfig.imageBorderRadius ||\r\n      NODE_CONSTANTS.DEFAULT_IMAGE_BORDER_RADIUS;\r\n    const borderWidth =\r\n      imageConfig.imageBorderWidth || NODE_CONSTANTS.DEFAULT_IMAGE_BORDER_WIDTH;\r\n\r\n    if (borderRadius > 0) {\r\n      imageElement.setAttribute(\"rx\", borderRadius.toString());\r\n      imageElement.setAttribute(\"ry\", borderRadius.toString());\r\n    }\r\n\r\n    return imageElement;\r\n  }\r\n\r\n  /**\r\n   * Create text elements (title and subtitle)\r\n   */\r\n  private createTextElements(\r\n    options: Required<NodeOptions>,\r\n    layout: any\r\n  ): SVGElement[] {\r\n    const elements: SVGElement[] = [];\r\n    const imageTitleConfig = options.imageTitleConfig || {};\r\n    const imageSubtitleConfig = options.imageSubtitleConfig || {};\r\n    const imageTextPositionConfig = options.imageTextPositionConfig || {};\r\n\r\n    const title = options.title || options.text || \"\";\r\n    const subtitle = options.subtitle || options.description || \"\";\r\n    const textPosition = imageTextPositionConfig.position || \"bottom\";\r\n\r\n    if (!title && !subtitle) {\r\n      return elements;\r\n    }\r\n\r\n    const textAnchor = textPosition === \"bottom\" ? \"middle\" : \"start\";\r\n    const textX =\r\n      textPosition === \"bottom\"\r\n        ? options.x + layout.textAreaX + layout.textAreaWidth / 2\r\n        : options.x + layout.textAreaX;\r\n\r\n    let currentY = options.y + layout.textAreaY;\r\n\r\n    // Create title\r\n    if (title) {\r\n      const titleElement = document.createElementNS(SVG_NS, \"text\");\r\n      titleElement.setAttribute(\"x\", textX.toString());\r\n      titleElement.setAttribute(\r\n        \"y\",\r\n        (currentY + layout.titleHeight * 0.8).toString()\r\n      );\r\n      titleElement.setAttribute(\"text-anchor\", textAnchor);\r\n      titleElement.setAttribute(\"dominant-baseline\", \"text-top\");\r\n      titleElement.setAttribute(\r\n        \"font-size\",\r\n        (\r\n          imageTitleConfig.fontSize || NODE_CONSTANTS.DEFAULT_TITLE_FONT_SIZE\r\n        ).toString()\r\n      );\r\n      titleElement.setAttribute(\r\n        \"font-weight\",\r\n        imageTitleConfig.fontWeight || \"bold\"\r\n      );\r\n      titleElement.setAttribute(\r\n        \"fill\",\r\n        imageTitleConfig.fontColor || NODE_CONSTANTS.DEFAULT_TITLE_COLOR\r\n      );\r\n      titleElement.setAttribute(\"stroke\", \"none\");\r\n      titleElement.setAttribute(\"stroke-width\", \"0\");\r\n      titleElement.setAttribute(\r\n        \"font-family\",\r\n        options.fontFamily || \"Arial, sans-serif\"\r\n      );\r\n      titleElement.textContent = title;\r\n\r\n      elements.push(titleElement);\r\n      currentY += layout.titleHeight + layout.textSpacing;\r\n    }\r\n\r\n    // Create subtitle\r\n    if (subtitle) {\r\n      const subtitleElement = document.createElementNS(SVG_NS, \"text\");\r\n      subtitleElement.setAttribute(\"x\", textX.toString());\r\n      subtitleElement.setAttribute(\r\n        \"y\",\r\n        (currentY + layout.subtitleHeight * 0.8).toString()\r\n      );\r\n      subtitleElement.setAttribute(\"text-anchor\", textAnchor);\r\n      subtitleElement.setAttribute(\"dominant-baseline\", \"text-top\");\r\n      subtitleElement.setAttribute(\r\n        \"font-size\",\r\n        (\r\n          imageSubtitleConfig.fontSize ||\r\n          NODE_CONSTANTS.DEFAULT_SUBTITLE_FONT_SIZE\r\n        ).toString()\r\n      );\r\n      subtitleElement.setAttribute(\r\n        \"font-weight\",\r\n        imageSubtitleConfig.fontWeight || \"normal\"\r\n      );\r\n      subtitleElement.setAttribute(\r\n        \"fill\",\r\n        imageSubtitleConfig.fontColor || NODE_CONSTANTS.DEFAULT_SUBTITLE_COLOR\r\n      );\r\n      subtitleElement.setAttribute(\"stroke\", \"none\");\r\n      subtitleElement.setAttribute(\"stroke-width\", \"0\");\r\n      subtitleElement.setAttribute(\r\n        \"font-family\",\r\n        options.fontFamily || \"Arial, sans-serif\"\r\n      );\r\n      subtitleElement.textContent = subtitle;\r\n\r\n      elements.push(subtitleElement);\r\n    }\r\n\r\n    return elements;\r\n  }\r\n}\r\n","import { SVG_NS, NODE_CONSTANTS } from \"../constants\";\r\nimport { NodeOptions } from \"../types\";\r\nimport { BaseNodeRenderer } from \"./BaseNodeRenderer\";\r\nimport { NodeRenderResult } from \"./types\";\r\n\r\n/**\r\n * ShapeNodeRenderer handles rendering of various geometric shapes\r\n * Supports ellipse, diamond, hexagon, triangle, pentagon, octagon, star, and custom shapes\r\n */\r\nexport class ShapeNodeRenderer extends BaseNodeRenderer {\r\n  public render(options: Required<NodeOptions>): NodeRenderResult {\r\n    const group = this.createGroup();\r\n\r\n    // Create shadow if enabled\r\n    const shadow = this.createShapeShadow(options);\r\n    if (shadow) {\r\n      group.appendChild(shadow);\r\n    }\r\n\r\n    // Create the shape based on type\r\n    const shape = this.createShape(options);\r\n    group.appendChild(shape);\r\n\r\n    // Apply gradient or solid fill\r\n    const gradientUrl = this.createGradient(options);\r\n    const fill = gradientUrl || options.fill;\r\n    shape.setAttribute(\"fill\", fill);\r\n\r\n    // Apply common styling\r\n    this.applyCommonStyling(shape, options);\r\n\r\n    // Create text if provided\r\n    if (options.text && options.text.trim()) {\r\n      const text = this.createBasicText(options);\r\n      group.appendChild(text);\r\n    }\r\n\r\n    return {\r\n      element: group,\r\n      bounds: {\r\n        x: options.x,\r\n        y: options.y,\r\n        width: options.width,\r\n        height: options.height,\r\n      },\r\n      centerX: options.x + options.width / 2,\r\n      centerY: options.y + options.height / 2,\r\n    };\r\n  }\r\n\r\n  /**\r\n   * Create shadow for shapes (uses appropriate shadow shape)\r\n   */\r\n  private createShapeShadow(options: Required<NodeOptions>): SVGElement | null {\r\n    if (!options.shadow) return null;\r\n\r\n    // Create the same shape as the main shape for shadow\r\n    const shadowOptions = {\r\n      ...options,\r\n      x: options.x + options.shadowOffset.x,\r\n      y: options.y + options.shadowOffset.y,\r\n    };\r\n\r\n    const shadowShape = this.createShape(shadowOptions);\r\n    shadowShape.setAttribute(\"fill\", options.shadowColor);\r\n    shadowShape.setAttribute(\"stroke\", \"none\");\r\n    shadowShape.setAttribute(\"stroke-width\", \"0\");\r\n\r\n    // Only add opacity if shadowColor doesn't already include alpha channel\r\n    if (!options.shadowColor.includes(\"rgba\")) {\r\n      shadowShape.setAttribute(\"opacity\", \"0.3\");\r\n    }\r\n\r\n    return shadowShape;\r\n  }\r\n\r\n  /**\r\n   * Create the appropriate shape based on the node type\r\n   */\r\n  private createShape(options: Required<NodeOptions>): SVGElement {\r\n    switch (options.type) {\r\n      case \"circle\":\r\n        return this.createCircle(options);\r\n      case \"ellipse\":\r\n        return this.createEllipse(options);\r\n      case \"diamond\":\r\n        return this.createDiamond(options);\r\n      case \"hexagon\":\r\n        return this.createHexagon(options);\r\n      case \"triangle\":\r\n        return this.createTriangle(options);\r\n      case \"pentagon\":\r\n        return this.createPentagon(options);\r\n      case \"octagon\":\r\n        return this.createOctagon(options);\r\n      case \"star\":\r\n        return this.createStar(options);\r\n      case \"custom\":\r\n        return this.createCustomShape(options);\r\n      default:\r\n        // Fallback to ellipse for unknown shape types\r\n        return this.createEllipse(options);\r\n    }\r\n  }\r\n\r\n  /**\r\n   * Create a circle node\r\n   */\r\n  private createCircle(options: Required<NodeOptions>): SVGCircleElement {\r\n    const circle = document.createElementNS(SVG_NS, \"circle\");\r\n\r\n    const radius = Math.min(options.width, options.height) / 2;\r\n    const centerX = options.x + options.width / 2;\r\n    const centerY = options.y + options.height / 2;\r\n\r\n    circle.setAttribute(\"cx\", centerX.toString());\r\n    circle.setAttribute(\"cy\", centerY.toString());\r\n    circle.setAttribute(\"r\", radius.toString());\r\n\r\n    return circle;\r\n  }\r\n\r\n  /**\r\n   * Create an ellipse node\r\n   */\r\n  private createEllipse(options: Required<NodeOptions>): SVGEllipseElement {\r\n    const ellipse = document.createElementNS(SVG_NS, \"ellipse\");\r\n    const centerX = options.x + options.width / 2;\r\n    const centerY = options.y + options.height / 2;\r\n\r\n    ellipse.setAttribute(\"cx\", centerX.toString());\r\n    ellipse.setAttribute(\"cy\", centerY.toString());\r\n    ellipse.setAttribute(\"rx\", (options.width / 2).toString());\r\n    ellipse.setAttribute(\"ry\", (options.height / 2).toString());\r\n\r\n    return ellipse;\r\n  }\r\n\r\n  /**\r\n   * Create a diamond node\r\n   */\r\n  private createDiamond(options: Required<NodeOptions>): SVGPolygonElement {\r\n    const diamond = document.createElementNS(SVG_NS, \"polygon\");\r\n    const centerX = options.x + options.width / 2;\r\n    const centerY = options.y + options.height / 2;\r\n\r\n    const points = [\r\n      `${centerX},${options.y}`, // top\r\n      `${options.x + options.width},${centerY}`, // right\r\n      `${centerX},${options.y + options.height}`, // bottom\r\n      `${options.x},${centerY}`, // left\r\n    ].join(\" \");\r\n\r\n    diamond.setAttribute(\"points\", points);\r\n    return diamond;\r\n  }\r\n\r\n  /**\r\n   * Create a hexagon node\r\n   */\r\n  private createHexagon(options: Required<NodeOptions>): SVGPolygonElement {\r\n    const hexagon = document.createElementNS(SVG_NS, \"polygon\");\r\n    const centerX = options.x + options.width / 2;\r\n    const centerY = options.y + options.height / 2;\r\n    const halfWidth = options.width / 2;\r\n\r\n    const points = [\r\n      `${centerX - halfWidth * 0.5},${options.y}`, // top left\r\n      `${centerX + halfWidth * 0.5},${options.y}`, // top right\r\n      `${options.x + options.width},${centerY}`, // right\r\n      `${centerX + halfWidth * 0.5},${options.y + options.height}`, // bottom right\r\n      `${centerX - halfWidth * 0.5},${options.y + options.height}`, // bottom left\r\n      `${options.x},${centerY}`, // left\r\n    ].join(\" \");\r\n\r\n    hexagon.setAttribute(\"points\", points);\r\n    return hexagon;\r\n  }\r\n\r\n  /**\r\n   * Create a triangle node\r\n   */\r\n  private createTriangle(options: Required<NodeOptions>): SVGPolygonElement {\r\n    const triangle = document.createElementNS(SVG_NS, \"polygon\");\r\n    const centerX = options.x + options.width / 2;\r\n\r\n    const points = [\r\n      `${centerX},${options.y}`, // top\r\n      `${options.x + options.width},${options.y + options.height}`, // bottom right\r\n      `${options.x},${options.y + options.height}`, // bottom left\r\n    ].join(\" \");\r\n\r\n    triangle.setAttribute(\"points\", points);\r\n    return triangle;\r\n  }\r\n\r\n  /**\r\n   * Create a pentagon node\r\n   */\r\n  private createPentagon(options: Required<NodeOptions>): SVGPolygonElement {\r\n    const pentagon = document.createElementNS(SVG_NS, \"polygon\");\r\n    const centerX = options.x + options.width / 2;\r\n    const centerY = options.y + options.height / 2;\r\n    const radius = Math.min(options.width, options.height) / 2;\r\n\r\n    const points = [];\r\n    for (let i = 0; i < 5; i++) {\r\n      const angle = (i * 2 * Math.PI) / 5 - Math.PI / 2; // Start from top\r\n      const x = centerX + radius * Math.cos(angle);\r\n      const y = centerY + radius * Math.sin(angle);\r\n      points.push(`${x},${y}`);\r\n    }\r\n\r\n    pentagon.setAttribute(\"points\", points.join(\" \"));\r\n    return pentagon;\r\n  }\r\n\r\n  /**\r\n   * Create an octagon node\r\n   */\r\n  private createOctagon(options: Required<NodeOptions>): SVGPolygonElement {\r\n    const octagon = document.createElementNS(SVG_NS, \"polygon\");\r\n    const centerX = options.x + options.width / 2;\r\n    const centerY = options.y + options.height / 2;\r\n    const radius = Math.min(options.width, options.height) / 2;\r\n\r\n    const points = [];\r\n    for (let i = 0; i < 8; i++) {\r\n      // Fixed: use 8 for octagon, not NODE_CONSTANTS.STAR_POINTS\r\n      const angle = (i * 2 * Math.PI) / 8 - Math.PI / 2; // Start from top\r\n      const x = centerX + radius * Math.cos(angle);\r\n      const y = centerY + radius * Math.sin(angle);\r\n      points.push(`${x},${y}`);\r\n    }\r\n\r\n    octagon.setAttribute(\"points\", points.join(\" \"));\r\n    return octagon;\r\n  }\r\n\r\n  /**\r\n   * Create a star node\r\n   */\r\n  private createStar(options: Required<NodeOptions>): SVGPolygonElement {\r\n    const star = document.createElementNS(SVG_NS, \"polygon\");\r\n    const centerX = options.x + options.width / 2;\r\n    const centerY = options.y + options.height / 2;\r\n    const outerRadius = Math.min(options.width, options.height) / 2;\r\n    const innerRadius = outerRadius * 0.4;\r\n\r\n    const points = [];\r\n    for (let i = 0; i < 10; i++) {\r\n      // 10 points for 5-pointed star (5 outer + 5 inner)\r\n      const angle = (i * Math.PI) / 5 - Math.PI / 2; // Start from top\r\n      const radius = i % 2 === 0 ? outerRadius : innerRadius;\r\n      const x = centerX + radius * Math.cos(angle);\r\n      const y = centerY + radius * Math.sin(angle);\r\n      points.push(`${x},${y}`);\r\n    }\r\n\r\n    star.setAttribute(\"points\", points.join(\" \"));\r\n    return star;\r\n  }\r\n\r\n  /**\r\n   * Create a custom shape node\r\n   */\r\n  private createCustomShape(options: Required<NodeOptions>): SVGElement {\r\n    // For custom shapes, users can provide custom path data\r\n    if (options.customAttributes.d) {\r\n      const path = document.createElementNS(SVG_NS, \"path\");\r\n      path.setAttribute(\"d\", String(options.customAttributes.d));\r\n\r\n      // Apply transformation to position the path correctly\r\n      path.setAttribute(\"transform\", `translate(${options.x}, ${options.y})`);\r\n\r\n      return path;\r\n    }\r\n\r\n    // Default to ellipse if no custom path is provided\r\n    return this.createEllipse(options);\r\n  }\r\n}\r\n","import { SVG_NS, NODE_CONSTANTS } from \"../constants\";\r\nimport { NodeOptions, Point } from \"../types\";\r\nimport {\r\n  ImageNodeRenderer,\r\n  NodeWithDescriptionRenderer,\r\n  CollapsibleNodeRenderer,\r\n  RectangleNodeRenderer,\r\n  ShapeNodeRenderer,\r\n} from \"../nodeRenderers\";\r\n\r\n/**\r\n * NodeDrawer class for drawing different types of tree nodes\r\n * Provides unified node drawing with customizable styling and types\r\n */\r\nexport class NodeDrawer {\r\n  private svg: SVGSVGElement;\r\n  private imageNodeRenderer: ImageNodeRenderer;\r\n  private nodeWithDescriptionRenderer: NodeWithDescriptionRenderer;\r\n  private collapsibleNodeRenderer: CollapsibleNodeRenderer;\r\n  private rectangleNodeRenderer: RectangleNodeRenderer;\r\n  private shapeNodeRenderer: ShapeNodeRenderer;\r\n  private defaultOptions: Required<NodeOptions> = {\r\n    type: \"rectangle\",\r\n    width: 80,\r\n    height: 40,\r\n    x: 0,\r\n    y: 0,\r\n    fill: NODE_CONSTANTS.DEFAULT_FILL_COLOR,\r\n    stroke: NODE_CONSTANTS.DEFAULT_BORDER_COLOR,\r\n    strokeWidth: NODE_CONSTANTS.DEFAULT_BORDER_WIDTH,\r\n    borderRadius: NODE_CONSTANTS.DEFAULT_BORDER_RADIUS,\r\n    opacity: NODE_CONSTANTS.DEFAULT_OPACITY,\r\n    text: \"\",\r\n    description: \"\",\r\n    fontSize: NODE_CONSTANTS.DEFAULT_FONT_SIZE,\r\n    fontColor: NODE_CONSTANTS.DEFAULT_FONT_COLOR,\r\n    fontFamily: NODE_CONSTANTS.DEFAULT_FONT_FAMILY,\r\n    textAnchor: NODE_CONSTANTS.DEFAULT_TEXT_ANCHOR,\r\n    padding: NODE_CONSTANTS.DEFAULT_PADDING,\r\n    descriptionFontSize: NODE_CONSTANTS.DESCRIPTION_FONT_SIZE,\r\n    descriptionFontColor: NODE_CONSTANTS.DESCRIPTION_FONT_COLOR,\r\n    descriptionMarginTop: NODE_CONSTANTS.DESCRIPTION_MARGIN_TOP,\r\n    shadow: false,\r\n    shadowColor: NODE_CONSTANTS.DEFAULT_SHADOW_COLOR,\r\n    shadowOffset: NODE_CONSTANTS.DEFAULT_SHADOW_OFFSET,\r\n    gradient: false,\r\n    gradientStartColor: \"\",\r\n    gradientEndColor: \"\",\r\n    customAttributes: {},\r\n    collapsible: false,\r\n    expanded: false,\r\n    onToggleExpand: () => {},\r\n    imageConfig: {\r\n      imageWidth: NODE_CONSTANTS.DEFAULT_IMAGE_WIDTH,\r\n      imageHeight: NODE_CONSTANTS.DEFAULT_IMAGE_HEIGHT,\r\n      imageBorderRadius: NODE_CONSTANTS.DEFAULT_IMAGE_BORDER_RADIUS,\r\n      imageBorderColor: NODE_CONSTANTS.DEFAULT_IMAGE_BORDER_COLOR,\r\n      imageBorderWidth: NODE_CONSTANTS.DEFAULT_IMAGE_BORDER_WIDTH,\r\n      imageOpacity: NODE_CONSTANTS.DEFAULT_IMAGE_OPACITY,\r\n      backgroundColor: \"transparent\",\r\n    },\r\n    imageTitleConfig: {\r\n      fontSize: NODE_CONSTANTS.DEFAULT_TITLE_FONT_SIZE,\r\n      fontColor: NODE_CONSTANTS.DEFAULT_TITLE_COLOR,\r\n      fontWeight: \"bold\",\r\n      marginTop: 6,\r\n      alignment: \"center\",\r\n    },\r\n    imageSubtitleConfig: {\r\n      fontSize: NODE_CONSTANTS.DEFAULT_SUBTITLE_FONT_SIZE,\r\n      fontColor: NODE_CONSTANTS.DEFAULT_SUBTITLE_COLOR,\r\n      fontWeight: \"normal\",\r\n      marginTop: 2,\r\n      alignment: \"center\",\r\n    },\r\n    imageTextPositionConfig: {\r\n      position: \"bottom\",\r\n      padding: NODE_CONSTANTS.DEFAULT_TEXT_PADDING,\r\n      spacing: NODE_CONSTANTS.DEFAULT_TEXT_SPACING,\r\n    },\r\n    imageMargin: NODE_CONSTANTS.DEFAULT_IMAGE_MARGIN,\r\n    imageUrl: \"\",\r\n    title: \"\",\r\n    subtitle: \"\",\r\n  };\r\n\r\n  constructor(svg: SVGSVGElement) {\r\n    this.svg = svg;\r\n    this.imageNodeRenderer = new ImageNodeRenderer(svg);\r\n    this.nodeWithDescriptionRenderer = new NodeWithDescriptionRenderer(svg);\r\n    this.collapsibleNodeRenderer = new CollapsibleNodeRenderer(svg);\r\n    this.rectangleNodeRenderer = new RectangleNodeRenderer(svg);\r\n    this.shapeNodeRenderer = new ShapeNodeRenderer(svg);\r\n  }\r\n\r\n  /**\r\n   * Measure text width using BaseNodeRenderer utilities\r\n   * @private\r\n   */\r\n  private measureText(\r\n    text: string,\r\n    fontSize: number,\r\n    fontFamily: string = \"Arial, sans-serif\"\r\n  ): number {\r\n    return this.rectangleNodeRenderer.measureText(text, fontSize, fontFamily);\r\n  }\r\n\r\n  /**\r\n   * Calculate text lines using BaseNodeRenderer utilities\r\n   * @private\r\n   */\r\n  private calculateTextLines(\r\n    text: string,\r\n    maxWidth: number,\r\n    fontSize: number,\r\n    fontFamily: string = \"Arial, sans-serif\"\r\n  ): string[] {\r\n    return this.rectangleNodeRenderer.calculateTextLines(\r\n      text,\r\n      maxWidth,\r\n      fontSize,\r\n      fontFamily\r\n    );\r\n  }\r\n\r\n  /**\r\n   * Calculate text wrapping with line width information\r\n   * @private\r\n   */\r\n  private calculateTextWrapping(\r\n    text: string,\r\n    maxWidth: number,\r\n    fontSize: number,\r\n    fontFamily: string = \"Arial, sans-serif\"\r\n  ): { lines: string[]; totalWidth: number } {\r\n    const lines = this.calculateTextLines(text, maxWidth, fontSize, fontFamily);\r\n\r\n    // Calculate the maximum line width\r\n    let maxLineWidth = 0;\r\n    for (const line of lines) {\r\n      const lineWidth = this.measureText(line, fontSize, fontFamily);\r\n      maxLineWidth = Math.max(maxLineWidth, lineWidth);\r\n    }\r\n\r\n    return { lines, totalWidth: maxLineWidth };\r\n  }\r\n\r\n  /**\r\n   * Delegate calculation to appropriate specialized renderer\r\n   * @private\r\n   */\r\n  private delegateCalculation(\r\n    method: \"calculateDynamicWidth\" | \"calculateDynamicHeight\",\r\n    node: any,\r\n    nodeConfig: any\r\n  ): number {\r\n    switch (nodeConfig.type) {\r\n      case \"node-with-description\":\r\n        return this.nodeWithDescriptionRenderer[method](node, nodeConfig);\r\n      case \"collapsible-node\":\r\n        return this.collapsibleNodeRenderer[method](node, nodeConfig);\r\n      case \"image\":\r\n        return this.imageNodeRenderer[method](node, nodeConfig);\r\n      default:\r\n        return 0; // Will be handled by legacy calculation\r\n    }\r\n  }\r\n\r\n  /**\r\n   * Calculate dynamic width for nodes that auto-size based on content\r\n   */\r\n  public calculateDynamicNodeWidth(node: any, nodeConfig: any): number {\r\n    // Delegate to specialized renderers for advanced node types\r\n    if (\r\n      [\"node-with-description\", \"collapsible-node\", \"image\"].includes(\r\n        nodeConfig.type\r\n      )\r\n    ) {\r\n      return this.delegateCalculation(\r\n        \"calculateDynamicWidth\",\r\n        node,\r\n        nodeConfig\r\n      );\r\n    }\r\n\r\n    // Legacy calculation for basic node types\r\n    const maxNodeWidth = nodeConfig.width || NODE_CONSTANTS.DEFAULT_MAX_WIDTH;\r\n    const padding = nodeConfig.padding || NODE_CONSTANTS.DEFAULT_PADDING;\r\n    const fontSize = nodeConfig.fontSize || NODE_CONSTANTS.DEFAULT_FONT_SIZE;\r\n    const descriptionFontSize =\r\n      nodeConfig.descriptionFontSize || NODE_CONSTANTS.DESCRIPTION_FONT_SIZE;\r\n    const fontFamily = nodeConfig.fontFamily || \"Arial, sans-serif\";\r\n\r\n    // Measure main text\r\n    const textWidth = this.measureText(node.value || \"\", fontSize, fontFamily);\r\n    let maxRequiredWidth = textWidth;\r\n\r\n    // Handle description if present\r\n    if (node.description && node.description.trim()) {\r\n      const { totalWidth } = this.calculateTextWrapping(\r\n        node.description,\r\n        maxNodeWidth - padding * 2,\r\n        descriptionFontSize,\r\n        fontFamily\r\n      );\r\n      maxRequiredWidth = Math.max(maxRequiredWidth, totalWidth);\r\n    }\r\n\r\n    // Calculate final width\r\n    const minWidthRequired = maxRequiredWidth + padding * 2;\r\n    return Math.max(nodeConfig.width || 0, minWidthRequired);\r\n  }\r\n\r\n  /**\r\n   * Calculate dynamic height for nodes that auto-size based on content\r\n   */\r\n  public calculateDynamicNodeHeight(node: any, nodeConfig: any): number {\r\n    // Delegate to specialized renderers for advanced node types\r\n    if (\r\n      [\"node-with-description\", \"collapsible-node\", \"image\"].includes(\r\n        nodeConfig.type\r\n      )\r\n    ) {\r\n      return this.delegateCalculation(\r\n        \"calculateDynamicHeight\",\r\n        node,\r\n        nodeConfig\r\n      );\r\n    }\r\n\r\n    // Legacy calculation for basic node types\r\n    const lineHeight = NODE_CONSTANTS.DESCRIPTION_LINE_HEIGHT;\r\n    const padding = nodeConfig.padding || NODE_CONSTANTS.DEFAULT_PADDING;\r\n    const fontSize = nodeConfig.fontSize || NODE_CONSTANTS.DEFAULT_FONT_SIZE;\r\n    const descriptionFontSize =\r\n      nodeConfig.descriptionFontSize || NODE_CONSTANTS.DESCRIPTION_FONT_SIZE;\r\n    const descriptionMarginTop =\r\n      nodeConfig.descriptionMarginTop || NODE_CONSTANTS.DESCRIPTION_MARGIN_TOP;\r\n    const fontFamily = nodeConfig.fontFamily || \"Arial, sans-serif\";\r\n\r\n    let totalRequiredHeight = fontSize; // Start with main text height\r\n\r\n    // Handle description if present\r\n    if (node.description && node.description.trim()) {\r\n      const maxWidth = nodeConfig.width || NODE_CONSTANTS.DEFAULT_MAX_WIDTH;\r\n      const availableWidth = maxWidth - padding * 2;\r\n\r\n      const { lines } = this.calculateTextWrapping(\r\n        node.description,\r\n        availableWidth,\r\n        descriptionFontSize,\r\n        fontFamily\r\n      );\r\n\r\n      const descriptionHeight = lines.length * descriptionFontSize * lineHeight;\r\n      totalRequiredHeight += descriptionMarginTop + descriptionHeight;\r\n    }\r\n\r\n    // Calculate final height with padding\r\n    const minHeightRequired = totalRequiredHeight + padding * 2;\r\n    return Math.max(nodeConfig.height || 0, minHeightRequired);\r\n  }\r\n\r\n  /**\r\n   * Draw a node at the specified position\r\n   */\r\n  public drawNode(options: Partial<NodeOptions> = {}): {\r\n    elements: SVGElement[];\r\n    centerX: number;\r\n    centerY: number;\r\n    bounds: { x: number; y: number; width: number; height: number };\r\n  } {\r\n    const finalOptions = { ...this.defaultOptions, ...options };\r\n\r\n    let nodeElements: SVGElement[] = [];\r\n\r\n    // Create the main node shape based on type (this will set calculated dimensions for node-with-description)\r\n    const shapeElement = this.createNodeShape(finalOptions);\r\n    nodeElements.push(shapeElement);\r\n\r\n    // Calculate bounds after shape creation to get calculated dimensions\r\n    let bounds = {\r\n      x: finalOptions.x,\r\n      y: finalOptions.y,\r\n      width:\r\n        finalOptions.type === \"node-with-description\" ||\r\n        finalOptions.type === \"collapsible-node\" ||\r\n        finalOptions.type === \"image\"\r\n          ? (finalOptions as any).calculatedWidth || finalOptions.width\r\n          : finalOptions.width,\r\n      height:\r\n        finalOptions.type === \"node-with-description\" ||\r\n        finalOptions.type === \"collapsible-node\" ||\r\n        finalOptions.type === \"image\"\r\n          ? (finalOptions as any).calculatedHeight || finalOptions.height\r\n          : finalOptions.height,\r\n    };\r\n\r\n    // Add shadow if enabled - only for legacy node types that don't use dedicated renderers\r\n    if (\r\n      finalOptions.shadow &&\r\n      finalOptions.type !== \"rectangle\" &&\r\n      finalOptions.type !== \"circle\" &&\r\n      finalOptions.type !== \"image\" &&\r\n      finalOptions.type !== \"node-with-description\" &&\r\n      finalOptions.type !== \"collapsible-node\"\r\n    ) {\r\n      const shadowElement = this.createShadow(finalOptions);\r\n      if (shadowElement) {\r\n        this.svg.appendChild(shadowElement);\r\n        nodeElements.push(shadowElement);\r\n      }\r\n    }\r\n\r\n    // Add gradient if enabled\r\n    if (\r\n      finalOptions.gradient &&\r\n      finalOptions.gradientStartColor &&\r\n      finalOptions.gradientEndColor\r\n    ) {\r\n      this.applyGradient(shapeElement, finalOptions);\r\n    }\r\n\r\n    // Apply basic styling\r\n    this.applyBasicStyling(shapeElement, finalOptions);\r\n\r\n    // Add text if provided - only for legacy node types that don't use dedicated renderers\r\n    const typesWithDedicatedRenderers = [\r\n      \"rectangle\",\r\n      \"circle\",\r\n      \"ellipse\",\r\n      \"diamond\",\r\n      \"hexagon\",\r\n      \"triangle\",\r\n      \"pentagon\",\r\n      \"octagon\",\r\n      \"star\",\r\n      \"custom\",\r\n      \"image\",\r\n      \"node-with-description\",\r\n      \"collapsible-node\",\r\n    ];\r\n\r\n    if (\r\n      finalOptions.text &&\r\n      finalOptions.text.trim() &&\r\n      !typesWithDedicatedRenderers.includes(finalOptions.type)\r\n    ) {\r\n      const textElement = this.createText(finalOptions);\r\n      nodeElements.push(textElement);\r\n    }\r\n\r\n    // Add all elements to SVG\r\n    nodeElements.forEach((element) => {\r\n      this.svg.appendChild(element);\r\n    });\r\n\r\n    const centerX = finalOptions.x + bounds.width / 2;\r\n    const centerY = finalOptions.y + bounds.height / 2;\r\n\r\n    return {\r\n      elements: nodeElements,\r\n      centerX,\r\n      centerY,\r\n      bounds,\r\n    };\r\n  }\r\n\r\n  /**\r\n   * Create the main node shape based on type\r\n   */\r\n  private createNodeShape(options: Required<NodeOptions>): SVGElement {\r\n    const shapeTypes = [\r\n      \"ellipse\",\r\n      \"diamond\",\r\n      \"hexagon\",\r\n      \"triangle\",\r\n      \"pentagon\",\r\n      \"octagon\",\r\n      \"star\",\r\n      \"custom\",\r\n    ];\r\n\r\n    if (options.type === \"rectangle\") {\r\n      return this.createRectangleUsingRenderer(options);\r\n    } else if (options.type === \"circle\") {\r\n      return this.createCircleUsingRenderer(options);\r\n    } else if (shapeTypes.includes(options.type)) {\r\n      return this.createShapeUsingRenderer(options);\r\n    } else if (options.type === \"node-with-description\") {\r\n      return this.createNodeWithDescriptionUsingRenderer(options);\r\n    } else if (options.type === \"collapsible-node\") {\r\n      return this.createCollapsibleNodeUsingRenderer(options);\r\n    } else if (options.type === \"image\") {\r\n      return this.createImageNodeUsingRenderer(options);\r\n    } else {\r\n      // Default to rectangle for unknown types\r\n      return this.createRectangleUsingRenderer(options);\r\n    }\r\n  }\r\n\r\n  /**\r\n   * Create an image node using the dedicated ImageNodeRenderer\r\n   */\r\n  private createImageNodeUsingRenderer(\r\n    options: Required<NodeOptions>\r\n  ): SVGElement {\r\n    const result = this.imageNodeRenderer.render(options);\r\n    // Store calculated dimensions for compatibility\r\n    (options as any).calculatedWidth = result.bounds.width;\r\n    (options as any).calculatedHeight = result.bounds.height;\r\n    return result.element;\r\n  }\r\n\r\n  /**\r\n   * Create a node-with-description using the dedicated NodeWithDescriptionRenderer\r\n   */\r\n  private createNodeWithDescriptionUsingRenderer(\r\n    options: Required<NodeOptions>\r\n  ): SVGElement {\r\n    const result = this.nodeWithDescriptionRenderer.render(options);\r\n    // Store calculated dimensions for compatibility\r\n    (options as any).calculatedWidth = result.bounds.width;\r\n    (options as any).calculatedHeight = result.bounds.height;\r\n    return result.element;\r\n  }\r\n\r\n  /**\r\n   * Create a collapsible node using the dedicated CollapsibleNodeRenderer\r\n   */\r\n  private createCollapsibleNodeUsingRenderer(\r\n    options: Required<NodeOptions>\r\n  ): SVGElement {\r\n    const result = this.collapsibleNodeRenderer.render(options);\r\n    // Store calculated dimensions for compatibility\r\n    (options as any).calculatedWidth = result.bounds.width;\r\n    (options as any).calculatedHeight = result.bounds.height;\r\n    return result.element;\r\n  }\r\n\r\n  /**\r\n   * Create a rectangle node using the dedicated RectangleNodeRenderer\r\n   */\r\n  private createRectangleUsingRenderer(\r\n    options: Required<NodeOptions>\r\n  ): SVGElement {\r\n    const result = this.rectangleNodeRenderer.render(options);\r\n    return result.element;\r\n  }\r\n\r\n  /**\r\n   * Create a circle node using the ShapeNodeRenderer\r\n   */\r\n  private createCircleUsingRenderer(\r\n    options: Required<NodeOptions>\r\n  ): SVGElement {\r\n    // Use shape renderer with circle type\r\n    const shapeOptions = {\r\n      ...options,\r\n      type: \"circle\" as const,\r\n    };\r\n    const result = this.shapeNodeRenderer.render(shapeOptions);\r\n    return result.element;\r\n  }\r\n\r\n  /**\r\n   * Create a shape node using the dedicated ShapeNodeRenderer\r\n   */\r\n  private createShapeUsingRenderer(options: Required<NodeOptions>): SVGElement {\r\n    const result = this.shapeNodeRenderer.render(options);\r\n    return result.element;\r\n  }\r\n\r\n  /**\r\n   * Create shadow for the node\r\n   */\r\n  private createShadow(options: Required<NodeOptions>): SVGElement | null {\r\n    if (!options.shadow) return null;\r\n\r\n    // Create a copy of the main shape for shadow\r\n    const shadowOptions = {\r\n      ...options,\r\n      x: options.x + options.shadowOffset.x,\r\n      y: options.y + options.shadowOffset.y,\r\n      fill: options.shadowColor,\r\n      stroke: \"none\",\r\n    };\r\n\r\n    const shadowElement = this.createNodeShape(shadowOptions);\r\n    shadowElement.setAttribute(\"fill\", options.shadowColor);\r\n    shadowElement.setAttribute(\"stroke\", \"none\");\r\n\r\n    return shadowElement;\r\n  }\r\n\r\n  /**\r\n   * Apply gradient to the node\r\n   */\r\n  private applyGradient(\r\n    element: SVGElement,\r\n    options: Required<NodeOptions>\r\n  ): void {\r\n    const gradientId = `gradient-${Date.now()}-${Math.random()\r\n      .toString(36)\r\n      .substr(2, 9)}`;\r\n\r\n    let defs = this.svg.querySelector(\"defs\");\r\n    if (!defs) {\r\n      defs = document.createElementNS(SVG_NS, \"defs\");\r\n      this.svg.insertBefore(defs, this.svg.firstChild);\r\n    }\r\n\r\n    const gradient = document.createElementNS(SVG_NS, \"linearGradient\");\r\n    gradient.setAttribute(\"id\", gradientId);\r\n    gradient.setAttribute(\"x1\", \"0%\");\r\n    gradient.setAttribute(\"y1\", \"0%\");\r\n    gradient.setAttribute(\"x2\", \"0%\");\r\n    gradient.setAttribute(\"y2\", \"100%\");\r\n\r\n    const stop1 = document.createElementNS(SVG_NS, \"stop\");\r\n    stop1.setAttribute(\"offset\", \"0%\");\r\n    stop1.setAttribute(\"stop-color\", options.gradientStartColor);\r\n\r\n    const stop2 = document.createElementNS(SVG_NS, \"stop\");\r\n    stop2.setAttribute(\"offset\", \"100%\");\r\n    stop2.setAttribute(\"stop-color\", options.gradientEndColor);\r\n\r\n    gradient.appendChild(stop1);\r\n    gradient.appendChild(stop2);\r\n    defs.appendChild(gradient);\r\n\r\n    element.setAttribute(\"fill\", `url(#${gradientId})`);\r\n  }\r\n\r\n  /**\r\n   * Apply basic styling to the node element\r\n   */\r\n  private applyBasicStyling(\r\n    element: SVGElement,\r\n    options: Required<NodeOptions>\r\n  ): void {\r\n    if (!options.gradient) {\r\n      element.setAttribute(\"fill\", options.fill);\r\n    }\r\n    element.setAttribute(\"stroke\", options.stroke);\r\n    element.setAttribute(\"stroke-width\", options.strokeWidth.toString());\r\n    element.setAttribute(\"opacity\", options.opacity.toString());\r\n\r\n    // Apply any custom attributes\r\n    Object.entries(options.customAttributes).forEach(([key, value]) => {\r\n      if (key !== \"d\") {\r\n        // Skip path data for non-path elements\r\n        element.setAttribute(key, String(value));\r\n      }\r\n    });\r\n  }\r\n\r\n  /**\r\n   * Create text element for the node\r\n   */\r\n  private createText(options: Required<NodeOptions>): SVGTextElement {\r\n    const text = document.createElementNS(SVG_NS, \"text\");\r\n    const centerX = options.x + options.width / 2;\r\n    const centerY = options.y + options.height / 2;\r\n\r\n    text.setAttribute(\"x\", centerX.toString());\r\n    text.setAttribute(\"y\", centerY.toString()); // Perfect vertical centering\r\n    text.setAttribute(\"text-anchor\", options.textAnchor);\r\n    text.setAttribute(\"font-size\", options.fontSize.toString());\r\n    text.setAttribute(\"font-family\", options.fontFamily);\r\n    text.setAttribute(\"font-weight\", \"bold\");\r\n    text.setAttribute(\"fill\", options.fontColor);\r\n    text.setAttribute(\"stroke\", \"none\");\r\n    text.setAttribute(\"stroke-width\", \"0\");\r\n    text.setAttribute(\"dominant-baseline\", \"central\");\r\n\r\n    // Handle multi-line text\r\n    const lines = options.text.split(\"\\n\");\r\n    if (lines.length === 1) {\r\n      text.textContent = options.text;\r\n    } else {\r\n      lines.forEach((line: string, index: number) => {\r\n        const tspan = document.createElementNS(SVG_NS, \"tspan\");\r\n        tspan.setAttribute(\"x\", centerX.toString());\r\n        tspan.setAttribute(\"dy\", index === 0 ? \"0\" : \"1.2em\");\r\n        tspan.setAttribute(\"stroke\", \"none\");\r\n        tspan.setAttribute(\"stroke-width\", \"0\");\r\n        tspan.textContent = line;\r\n        text.appendChild(tspan);\r\n      });\r\n    }\r\n\r\n    return text;\r\n  }\r\n}\r\n","import { TitleConfig } from \"../types\";\r\nimport { SVG_NS, DEFAULT_OPTIONS, NODE_CONSTANTS } from \"../constants\";\r\n\r\n/**\r\n * TitleDrawer class for rendering chart titles and descriptions\r\n */\r\nexport class TitleDrawer {\r\n  private svg: SVGSVGElement;\r\n  private titleConfig: Required<TitleConfig>;\r\n\r\n  constructor(svg: SVGSVGElement, titleConfig: Partial<TitleConfig> = {}) {\r\n    this.svg = svg;\r\n    // Merge with defaults from DEFAULT_OPTIONS\r\n    this.titleConfig = {\r\n      ...DEFAULT_OPTIONS.titleConfig,\r\n      ...titleConfig,\r\n      position: {\r\n        ...DEFAULT_OPTIONS.titleConfig.position,\r\n        ...titleConfig.position,\r\n      },\r\n      titleStyle: {\r\n        ...DEFAULT_OPTIONS.titleConfig.titleStyle,\r\n        ...titleConfig.titleStyle,\r\n      },\r\n      descriptionStyle: {\r\n        ...DEFAULT_OPTIONS.titleConfig.descriptionStyle,\r\n        ...titleConfig.descriptionStyle,\r\n      },\r\n    } as Required<TitleConfig>;\r\n  }\r\n\r\n  /**\r\n   * Measure text width using canvas context (similar to BaseNodeRenderer)\r\n   */\r\n  private measureText(\r\n    text: string,\r\n    fontSize: number,\r\n    fontFamily: string\r\n  ): number {\r\n    const canvas = document.createElement(\"canvas\");\r\n    const context = canvas.getContext(\"2d\");\r\n    if (!context) return text.length * fontSize * 0.6; // Fallback estimation\r\n\r\n    context.font = `${fontSize}px ${fontFamily}`;\r\n    return context.measureText(text).width;\r\n  }\r\n\r\n  /**\r\n   * Calculate lines needed for text wrapping (similar to BaseNodeRenderer)\r\n   */\r\n  private calculateTextLines(\r\n    text: string,\r\n    maxWidth: number,\r\n    fontSize: number,\r\n    fontFamily: string\r\n  ): string[] {\r\n    const canvas = document.createElement(\"canvas\");\r\n    const context = canvas.getContext(\"2d\");\r\n    if (!context) return [text]; // Fallback\r\n\r\n    context.font = `${fontSize}px ${fontFamily}`;\r\n\r\n    const words = text.split(\" \");\r\n    const lines: string[] = [];\r\n    let currentLine = \"\";\r\n\r\n    for (const word of words) {\r\n      const testLine = currentLine ? `${currentLine} ${word}` : word;\r\n      const testWidth = context.measureText(testLine).width;\r\n\r\n      if (testWidth > maxWidth && currentLine) {\r\n        lines.push(currentLine);\r\n        currentLine = word;\r\n      } else {\r\n        currentLine = testLine;\r\n      }\r\n    }\r\n\r\n    if (currentLine) {\r\n      lines.push(currentLine);\r\n    }\r\n\r\n    return lines;\r\n  }\r\n\r\n  /**\r\n   * Draw the title and description on the SVG\r\n   * @param svgWidth - Width of the SVG\r\n   * @param svgHeight - Height of the SVG\r\n   * @returns Object containing title and description heights for layout calculations\r\n   */\r\n  public drawTitle(\r\n    svgWidth: number,\r\n    svgHeight: number,\r\n    titleSpace?: { top: number; bottom: number }\r\n  ): { titleHeight: number; descriptionHeight: number } {\r\n    let titleHeight = 0;\r\n    let descriptionHeight = 0;\r\n\r\n    // Only draw if title or description is provided\r\n    if (!this.titleConfig.title && !this.titleConfig.description) {\r\n      return { titleHeight, descriptionHeight };\r\n    }\r\n\r\n    // Calculate positions based on alignment\r\n    const { horizontal, vertical } = this.titleConfig.position;\r\n\r\n    let titleX = this.calculateHorizontalPosition(horizontal, svgWidth);\r\n    let titleY;\r\n\r\n    if (vertical === \"top\") {\r\n      // Position title within the reserved space at the top\r\n      titleY = this.titleConfig.titleStyle.margin;\r\n    } else {\r\n      // Position title within the reserved space at the bottom\r\n      const computedTitleSpace =\r\n        titleSpace || this.calculateTitleSpace(svgWidth);\r\n      titleY =\r\n        svgHeight -\r\n        computedTitleSpace.bottom +\r\n        this.titleConfig.titleStyle.margin;\r\n    }\r\n\r\n    // Create title group\r\n    const titleGroup = document.createElementNS(SVG_NS, \"g\");\r\n    titleGroup.setAttribute(\"class\", \"chart-title-group\");\r\n\r\n    let currentY = titleY;\r\n\r\n    // Draw title if provided\r\n    if (this.titleConfig.title) {\r\n      const titleElements = this.createWrappedTextElements(\r\n        this.titleConfig.title,\r\n        titleX,\r\n        currentY,\r\n        this.titleConfig.titleStyle,\r\n        horizontal,\r\n        svgWidth\r\n      );\r\n\r\n      titleElements.forEach((element: SVGTextElement) =>\r\n        titleGroup.appendChild(element)\r\n      );\r\n\r\n      // Calculate actual title height based on number of lines\r\n      const lineHeight = this.titleConfig.titleStyle.fontSize * 1.2;\r\n      titleHeight = titleElements.length * lineHeight;\r\n\r\n      // Adjust position for description (keep them close together)\r\n      if (vertical === \"top\") {\r\n        currentY += titleHeight + 5; // Small gap between title and description\r\n      } else {\r\n        currentY -= titleHeight + 5; // Small gap between title and description\r\n      }\r\n    }\r\n\r\n    // Draw description if provided\r\n    if (this.titleConfig.description) {\r\n      const descriptionElements = this.createWrappedTextElements(\r\n        this.titleConfig.description,\r\n        titleX,\r\n        currentY,\r\n        this.titleConfig.descriptionStyle,\r\n        horizontal,\r\n        svgWidth\r\n      );\r\n\r\n      descriptionElements.forEach((element: SVGTextElement) =>\r\n        titleGroup.appendChild(element)\r\n      );\r\n\r\n      // Calculate actual description height based on number of lines\r\n      const lineHeight = this.titleConfig.descriptionStyle.fontSize * 1.2;\r\n      descriptionHeight = descriptionElements.length * lineHeight;\r\n    }\r\n\r\n    // Insert title group at the beginning (so it appears on top/bottom)\r\n    if (vertical === \"top\") {\r\n      this.svg.insertBefore(titleGroup, this.svg.firstChild);\r\n    } else {\r\n      this.svg.appendChild(titleGroup);\r\n    }\r\n\r\n    return { titleHeight, descriptionHeight };\r\n  }\r\n\r\n  /**\r\n   * Calculate horizontal position based on alignment\r\n   */\r\n  private calculateHorizontalPosition(\r\n    horizontal: \"left\" | \"center\" | \"right\",\r\n    svgWidth: number\r\n  ): number {\r\n    switch (horizontal) {\r\n      case \"left\":\r\n        return NODE_CONSTANTS.SMALL_MARGIN; // Small margin from left\r\n      case \"right\":\r\n        return svgWidth - NODE_CONSTANTS.SMALL_MARGIN; // Small margin from right\r\n      case \"center\":\r\n      default:\r\n        return svgWidth / 2;\r\n    }\r\n  }\r\n\r\n  /**\r\n   * Create wrapped text elements for title or description\r\n   */\r\n  private createWrappedTextElements(\r\n    text: string,\r\n    x: number,\r\n    startY: number,\r\n    style:\r\n      | Required<TitleConfig>[\"titleStyle\"]\r\n      | Required<TitleConfig>[\"descriptionStyle\"],\r\n    horizontal: \"left\" | \"center\" | \"right\",\r\n    svgWidth: number\r\n  ): SVGTextElement[] {\r\n    // Calculate available width for text wrapping\r\n    const padding = NODE_CONSTANTS.SMALL_MARGIN;\r\n    const maxWidth = svgWidth - padding * 2;\r\n\r\n    // Calculate text lines using our wrapping method\r\n    const lines = this.calculateTextLines(\r\n      text,\r\n      maxWidth,\r\n      style.fontSize,\r\n      style.fontFamily\r\n    );\r\n\r\n    // Create text elements for each line\r\n    const textElements: SVGTextElement[] = [];\r\n    const lineHeight = style.fontSize * 1.2;\r\n\r\n    lines.forEach((line, index) => {\r\n      const textElement = this.createTextElement(\r\n        line,\r\n        x,\r\n        startY + index * lineHeight,\r\n        style,\r\n        horizontal\r\n      );\r\n      textElements.push(textElement);\r\n    });\r\n\r\n    return textElements;\r\n  }\r\n\r\n  /**\r\n   * Create a text element with styling\r\n   */\r\n  private createTextElement(\r\n    text: string,\r\n    x: number,\r\n    y: number,\r\n    style:\r\n      | Required<TitleConfig>[\"titleStyle\"]\r\n      | Required<TitleConfig>[\"descriptionStyle\"],\r\n    horizontal: \"left\" | \"center\" | \"right\"\r\n  ): SVGTextElement {\r\n    const textElement = document.createElementNS(SVG_NS, \"text\");\r\n\r\n    // Set position\r\n    textElement.setAttribute(\"x\", x.toString());\r\n    textElement.setAttribute(\"y\", y.toString());\r\n\r\n    // Set text anchor based on horizontal alignment\r\n    const textAnchor =\r\n      horizontal === \"left\"\r\n        ? \"start\"\r\n        : horizontal === \"right\"\r\n        ? \"end\"\r\n        : \"middle\";\r\n    textElement.setAttribute(\"text-anchor\", textAnchor);\r\n    textElement.setAttribute(\"dominant-baseline\", \"central\");\r\n\r\n    // Set styling\r\n    textElement.setAttribute(\"font-size\", style.fontSize.toString());\r\n    textElement.setAttribute(\"font-family\", style.fontFamily);\r\n    textElement.setAttribute(\"font-weight\", style.fontWeight);\r\n    textElement.setAttribute(\"fill\", style.fontColor);\r\n    textElement.setAttribute(\"stroke\", \"none\");\r\n    textElement.setAttribute(\"stroke-width\", \"0\");\r\n\r\n    // Set text content\r\n    textElement.textContent = text;\r\n\r\n    return textElement;\r\n  }\r\n\r\n  /**\r\n   * Calculate total height needed for titles (useful for adjusting chart layout)\r\n   */\r\n  public calculateTitleSpace(svgWidth?: number): {\r\n    top: number;\r\n    bottom: number;\r\n  } {\r\n    let topSpace = 0;\r\n    let bottomSpace = 0;\r\n\r\n    if (!this.titleConfig.title && !this.titleConfig.description) {\r\n      return { top: topSpace, bottom: bottomSpace };\r\n    }\r\n\r\n    const { vertical } = this.titleConfig.position;\r\n    const extraSpacing = NODE_CONSTANTS.EXTRA_TITLE_SPACING; // Additional space between entire title section and tree\r\n\r\n    // Get SVG width for text wrapping calculations\r\n    const actualSvgWidth =\r\n      svgWidth || parseFloat(this.svg.getAttribute(\"width\") || \"800\");\r\n    const padding = NODE_CONSTANTS.SMALL_MARGIN;\r\n    const maxWidth = actualSvgWidth - padding * 2;\r\n\r\n    if (vertical === \"top\") {\r\n      // Add space for title margin (space above title)\r\n      if (this.titleConfig.title) {\r\n        // Calculate actual title height based on text wrapping\r\n        const titleLines = this.calculateTextLines(\r\n          this.titleConfig.title,\r\n          maxWidth,\r\n          this.titleConfig.titleStyle.fontSize,\r\n          this.titleConfig.titleStyle.fontFamily\r\n        );\r\n        const titleHeight =\r\n          titleLines.length * this.titleConfig.titleStyle.fontSize * 1.2;\r\n        topSpace += this.titleConfig.titleStyle.margin + titleHeight;\r\n      }\r\n      // Add space for description (close to title, no extra margin)\r\n      if (this.titleConfig.description) {\r\n        const descriptionLines = this.calculateTextLines(\r\n          this.titleConfig.description,\r\n          maxWidth,\r\n          this.titleConfig.descriptionStyle.fontSize,\r\n          this.titleConfig.descriptionStyle.fontFamily\r\n        );\r\n        const descriptionHeight =\r\n          descriptionLines.length *\r\n          this.titleConfig.descriptionStyle.fontSize *\r\n          1.2;\r\n        topSpace += 5 + descriptionHeight; // Small gap + font height\r\n      }\r\n      // Add extra spacing between entire title section and tree\r\n      if (this.titleConfig.title || this.titleConfig.description) {\r\n        topSpace += extraSpacing;\r\n      }\r\n    } else {\r\n      // Similar logic for bottom positioning\r\n      if (this.titleConfig.title) {\r\n        const titleLines = this.calculateTextLines(\r\n          this.titleConfig.title,\r\n          maxWidth,\r\n          this.titleConfig.titleStyle.fontSize,\r\n          this.titleConfig.titleStyle.fontFamily\r\n        );\r\n        const titleHeight =\r\n          titleLines.length * this.titleConfig.titleStyle.fontSize * 1.2;\r\n        bottomSpace += this.titleConfig.titleStyle.margin + titleHeight;\r\n      }\r\n      if (this.titleConfig.description) {\r\n        const descriptionLines = this.calculateTextLines(\r\n          this.titleConfig.description,\r\n          maxWidth,\r\n          this.titleConfig.descriptionStyle.fontSize,\r\n          this.titleConfig.descriptionStyle.fontFamily\r\n        );\r\n        const descriptionHeight =\r\n          descriptionLines.length *\r\n          this.titleConfig.descriptionStyle.fontSize *\r\n          1.2;\r\n        bottomSpace += 5 + descriptionHeight;\r\n      }\r\n      // Add extra spacing between entire title section and tree\r\n      if (this.titleConfig.title || this.titleConfig.description) {\r\n        bottomSpace += extraSpacing;\r\n      }\r\n    }\r\n\r\n    return { top: topSpace, bottom: bottomSpace };\r\n  }\r\n}\r\n","import { ActionConfig, ActionPosition } from \"../types\";\r\nimport { NODE_CONSTANTS } from \"../constants\";\r\n\r\n/**\r\n * ActionDrawer handles drawing and managing action buttons on the chart\r\n */\r\nexport class ActionDrawer {\r\n  private svg: SVGSVGElement;\r\n  private actionConfig: ActionConfig;\r\n  private containerElement: HTMLElement;\r\n  private actionGroup?: SVGGElement;\r\n\r\n  constructor(\r\n    svg: SVGSVGElement,\r\n    actionConfig: ActionConfig,\r\n    containerElement: HTMLElement\r\n  ) {\r\n    this.svg = svg;\r\n    this.actionConfig = actionConfig;\r\n    this.containerElement = containerElement;\r\n  }\r\n\r\n  /**\r\n   * Draw action buttons on the chart\r\n   */\r\n  public drawActions(): void {\r\n    if (!this.actionConfig) return;\r\n\r\n    // Remove existing actions\r\n    this.removeActions();\r\n\r\n    // Create action group\r\n    this.actionGroup = document.createElementNS(\r\n      \"http://www.w3.org/2000/svg\",\r\n      \"g\"\r\n    );\r\n    this.actionGroup.setAttribute(\"class\", \"treechart-actions\");\r\n    this.svg.appendChild(this.actionGroup);\r\n\r\n    // Draw download button if enabled\r\n    if (this.actionConfig.download?.enabled) {\r\n      this.drawDownloadButton();\r\n    }\r\n  }\r\n\r\n  /**\r\n   * Draw download button\r\n   */\r\n  private drawDownloadButton(): void {\r\n    if (!this.actionGroup || !this.actionConfig.download) return;\r\n\r\n    const position = this.actionConfig.download.position || \"top-right\";\r\n    const { x, y } = this.calculateButtonPosition(position);\r\n\r\n    // Create button group\r\n    const buttonGroup = document.createElementNS(\r\n      \"http://www.w3.org/2000/svg\",\r\n      \"g\"\r\n    );\r\n    buttonGroup.setAttribute(\"class\", \"download-button\");\r\n    buttonGroup.style.cursor = \"pointer\";\r\n\r\n    // Button background\r\n    const buttonBg = document.createElementNS(\r\n      \"http://www.w3.org/2000/svg\",\r\n      \"rect\"\r\n    );\r\n    buttonBg.setAttribute(\"x\", x.toString());\r\n    buttonBg.setAttribute(\"y\", y.toString());\r\n    buttonBg.setAttribute(\r\n      \"width\",\r\n      NODE_CONSTANTS.ACTION_BUTTON_SIZE.toString()\r\n    );\r\n    buttonBg.setAttribute(\r\n      \"height\",\r\n      NODE_CONSTANTS.ACTION_BUTTON_SIZE.toString()\r\n    );\r\n    buttonBg.setAttribute(\"rx\", \"4\");\r\n    buttonBg.setAttribute(\"fill\", \"#ffffff\");\r\n    buttonBg.setAttribute(\"stroke\", \"#dee2e6\");\r\n    buttonBg.setAttribute(\"stroke-width\", \"1\");\r\n    buttonBg.setAttribute(\"filter\", \"drop-shadow(0px 1px 3px rgba(0,0,0,0.1))\");\r\n    buttonBg.style.transition = \"all 0.2s ease\";\r\n\r\n    // Download icon (simple arrow down with line)\r\n    const iconGroup = document.createElementNS(\r\n      \"http://www.w3.org/2000/svg\",\r\n      \"g\"\r\n    );\r\n    iconGroup.setAttribute(\r\n      \"transform\",\r\n      `translate(${x + NODE_CONSTANTS.ACTION_BUTTON_CENTER_OFFSET}, ${\r\n        y + NODE_CONSTANTS.ACTION_BUTTON_CENTER_OFFSET\r\n      })`\r\n    );\r\n\r\n    // Arrow shaft\r\n    const shaft = document.createElementNS(\r\n      \"http://www.w3.org/2000/svg\",\r\n      \"line\"\r\n    );\r\n    shaft.setAttribute(\"x1\", \"0\");\r\n    shaft.setAttribute(\"y1\", \"-6\");\r\n    shaft.setAttribute(\"x2\", \"0\");\r\n    shaft.setAttribute(\"y2\", \"2\");\r\n    shaft.setAttribute(\"stroke\", \"#495057\");\r\n    shaft.setAttribute(\"stroke-width\", \"1.5\");\r\n    shaft.setAttribute(\"stroke-linecap\", \"round\");\r\n\r\n    // Arrow head\r\n    const arrowPath = document.createElementNS(\r\n      \"http://www.w3.org/2000/svg\",\r\n      \"path\"\r\n    );\r\n    arrowPath.setAttribute(\"d\", \"M -3 -1 L 0 2 L 3 -1\");\r\n    arrowPath.setAttribute(\"stroke\", \"#495057\");\r\n    arrowPath.setAttribute(\"stroke-width\", \"1.5\");\r\n    arrowPath.setAttribute(\"stroke-linecap\", \"round\");\r\n    arrowPath.setAttribute(\"stroke-linejoin\", \"round\");\r\n    arrowPath.setAttribute(\"fill\", \"none\");\r\n\r\n    // Base line\r\n    const baseLine = document.createElementNS(\r\n      \"http://www.w3.org/2000/svg\",\r\n      \"line\"\r\n    );\r\n    baseLine.setAttribute(\"x1\", \"-4\");\r\n    baseLine.setAttribute(\"y1\", \"5\");\r\n    baseLine.setAttribute(\"x2\", \"4\");\r\n    baseLine.setAttribute(\"y2\", \"5\");\r\n    baseLine.setAttribute(\"stroke\", \"#495057\");\r\n    baseLine.setAttribute(\"stroke-width\", \"1.5\");\r\n    baseLine.setAttribute(\"stroke-linecap\", \"round\");\r\n\r\n    iconGroup.appendChild(shaft);\r\n    iconGroup.appendChild(arrowPath);\r\n    iconGroup.appendChild(baseLine);\r\n\r\n    buttonGroup.appendChild(buttonBg);\r\n    buttonGroup.appendChild(iconGroup);\r\n\r\n    // Add hover effects\r\n    buttonGroup.addEventListener(\"mouseenter\", () => {\r\n      buttonBg.setAttribute(\"fill\", \"#f8f9fa\");\r\n      buttonBg.setAttribute(\"stroke\", \"#adb5bd\");\r\n      buttonBg.setAttribute(\r\n        \"filter\",\r\n        \"drop-shadow(0px 2px 6px rgba(0,0,0,0.15))\"\r\n      );\r\n    });\r\n\r\n    buttonGroup.addEventListener(\"mouseleave\", () => {\r\n      buttonBg.setAttribute(\"fill\", \"#ffffff\");\r\n      buttonBg.setAttribute(\"stroke\", \"#dee2e6\");\r\n      buttonBg.setAttribute(\r\n        \"filter\",\r\n        \"drop-shadow(0px 1px 3px rgba(0,0,0,0.1))\"\r\n      );\r\n    });\r\n\r\n    // Add click handler\r\n    buttonGroup.addEventListener(\"click\", () => {\r\n      this.downloadChart();\r\n    });\r\n\r\n    // Add tooltip\r\n    const title = document.createElementNS(\r\n      \"http://www.w3.org/2000/svg\",\r\n      \"title\"\r\n    );\r\n    title.textContent = \"Download Chart\";\r\n    buttonGroup.appendChild(title);\r\n\r\n    this.actionGroup.appendChild(buttonGroup);\r\n  }\r\n\r\n  /**\r\n   * Calculate button position based on configuration\r\n   */\r\n  private calculateButtonPosition(position: ActionPosition): {\r\n    x: number;\r\n    y: number;\r\n  } {\r\n    const containerRect = this.containerElement.getBoundingClientRect();\r\n    const svgRect = this.svg.getBoundingClientRect();\r\n\r\n    // Get SVG dimensions\r\n    const svgWidth = parseFloat(this.svg.getAttribute(\"width\") || \"0\");\r\n    const svgHeight = parseFloat(this.svg.getAttribute(\"height\") || \"0\");\r\n\r\n    // Position at the very edge to avoid overlap with title text\r\n    const buttonSize = NODE_CONSTANTS.ACTION_BUTTON_SIZE;\r\n\r\n    switch (position) {\r\n      case \"top-left\":\r\n        return { x: 0, y: 0 };\r\n      case \"top-right\":\r\n        return { x: svgWidth - buttonSize, y: 0 };\r\n      case \"bottom-left\":\r\n        return { x: 0, y: svgHeight - buttonSize };\r\n      case \"bottom-right\":\r\n        return { x: svgWidth - buttonSize, y: svgHeight - buttonSize };\r\n      default:\r\n        return { x: svgWidth - buttonSize, y: 0 };\r\n    }\r\n  }\r\n\r\n  /**\r\n   * Download the chart as SVG\r\n   */\r\n  private downloadChart(): void {\r\n    try {\r\n      // Clone the SVG to avoid modifying the original\r\n      const svgClone = this.svg.cloneNode(true) as SVGSVGElement;\r\n\r\n      // Remove action buttons from the cloned SVG\r\n      const actionsGroup = svgClone.querySelector(\".treechart-actions\");\r\n      if (actionsGroup) {\r\n        actionsGroup.remove();\r\n      }\r\n\r\n      // Get SVG string\r\n      const serializer = new XMLSerializer();\r\n      const svgString = serializer.serializeToString(svgClone);\r\n\r\n      // Create blob and download\r\n      const blob = new Blob([svgString], {\r\n        type: \"image/svg+xml;charset=utf-8\",\r\n      });\r\n      const url = URL.createObjectURL(blob);\r\n\r\n      // Create download link\r\n      const link = document.createElement(\"a\");\r\n      link.href = url;\r\n      link.download = this.actionConfig.download?.filename || \"treechart.svg\";\r\n      document.body.appendChild(link);\r\n      link.click();\r\n      document.body.removeChild(link);\r\n\r\n      // Clean up\r\n      URL.revokeObjectURL(url);\r\n    } catch (error) {\r\n      console.error(\"Error downloading chart:\", error);\r\n    }\r\n  }\r\n\r\n  /**\r\n   * Remove existing action buttons\r\n   */\r\n  private removeActions(): void {\r\n    if (this.actionGroup) {\r\n      this.actionGroup.remove();\r\n      this.actionGroup = undefined;\r\n    }\r\n  }\r\n\r\n  /**\r\n   * Update action configuration and redraw\r\n   */\r\n  public updateActions(newActionConfig: ActionConfig): void {\r\n    this.actionConfig = newActionConfig;\r\n    this.drawActions();\r\n  }\r\n\r\n  /**\r\n   * Clean up resources\r\n   */\r\n  public destroy(): void {\r\n    this.removeActions();\r\n  }\r\n}\r\n","import { NODE_CONSTANTS } from \"../constants\";\r\nimport { NodeLayoutPosition, LevelLayout, TreeLayout } from \"../types\";\r\nimport { calculateSvgWidth, calculateSvgHeight } from \"./svgHelpers\";\r\nimport { NodeDrawer } from \"./NodeDrawer\";\r\nimport { TitleDrawer } from \"./TitleDrawer\";\r\n\r\nexport class LayoutCalculator {\r\n  constructor(\r\n    private formattedTree: any[][],\r\n    private options: any,\r\n    private nodeDrawer: NodeDrawer,\r\n    private titleDrawer: TitleDrawer\r\n  ) {}\r\n\r\n  /**\r\n   * Calculate the complete layout for the tree\r\n   */\r\n  public calculateTreeLayout(): TreeLayout {\r\n    const { verticalAlign, horizontalGap, verticalGap, horizontalAlign } =\r\n      this.options;\r\n    const nodeConfig = this.options.nodeConfig!;\r\n    const boxWidth = nodeConfig.width!;\r\n    const boxHeight = nodeConfig.height!;\r\n    const basePadding = NODE_CONSTANTS.BASE_PADDING;\r\n\r\n    const totalWidth = calculateSvgWidth(\r\n      this.formattedTree,\r\n      this.options,\r\n      this.nodeDrawer\r\n    );\r\n    const titleSpace = this.titleDrawer.calculateTitleSpace(totalWidth);\r\n    const totalHeight = calculateSvgHeight(\r\n      this.formattedTree,\r\n      this.options,\r\n      this.nodeDrawer,\r\n      titleSpace\r\n    );\r\n    const yOffset = titleSpace.top + basePadding;\r\n\r\n    // Calculate layouts for all levels\r\n    const levels = this.calculateLevelLayouts(\r\n      totalWidth,\r\n      totalHeight,\r\n      yOffset,\r\n      basePadding,\r\n      boxWidth,\r\n      boxHeight,\r\n      horizontalGap,\r\n      verticalGap,\r\n      verticalAlign,\r\n      horizontalAlign,\r\n      titleSpace,\r\n      nodeConfig\r\n    );\r\n\r\n    return {\r\n      levels,\r\n      totalWidth,\r\n      totalHeight,\r\n      yOffset,\r\n    };\r\n  }\r\n\r\n  /**\r\n   * Calculate layouts for all levels in the tree\r\n   */\r\n  private calculateLevelLayouts(\r\n    totalWidth: number,\r\n    totalHeight: number,\r\n    yOffset: number,\r\n    basePadding: number,\r\n    boxWidth: number,\r\n    boxHeight: number,\r\n    horizontalGap: number,\r\n    verticalGap: number,\r\n    verticalAlign: string,\r\n    horizontalAlign: string,\r\n    titleSpace: any,\r\n    nodeConfig: any\r\n  ): LevelLayout[] {\r\n    // First pass: calculate heights and node data for each level\r\n    const levelHeights: number[] = [];\r\n    const levelNodeData: Array<Array<any>> = [];\r\n\r\n    this.formattedTree.forEach((level, levelIndex) => {\r\n      const { maxHeightInLevel, nodeData } = this.calculateLevelNodeData(\r\n        level,\r\n        levelIndex,\r\n        nodeConfig,\r\n        boxWidth,\r\n        boxHeight,\r\n        horizontalGap,\r\n        totalWidth,\r\n        basePadding,\r\n        verticalAlign\r\n      );\r\n\r\n      levelHeights.push(maxHeightInLevel);\r\n      levelNodeData.push(nodeData);\r\n    });\r\n\r\n    // Second pass: create final layouts with Y positions\r\n    return this.createFinalLayouts(\r\n      levelNodeData,\r\n      levelHeights,\r\n      yOffset,\r\n      verticalGap,\r\n      horizontalAlign,\r\n      totalHeight,\r\n      titleSpace,\r\n      basePadding\r\n    );\r\n  }\r\n\r\n  /**\r\n   * Calculate node data and maximum height for a single level\r\n   */\r\n  private calculateLevelNodeData(\r\n    level: any[],\r\n    levelIndex: number,\r\n    nodeConfig: any,\r\n    boxWidth: number,\r\n    boxHeight: number,\r\n    horizontalGap: number,\r\n    totalWidth: number,\r\n    basePadding: number,\r\n    verticalAlign: string\r\n  ) {\r\n    let maxHeightInLevel = boxHeight;\r\n\r\n    // Calculate actual node widths for this level\r\n    const nodeWidths: number[] = [];\r\n    level.forEach((node: any) => {\r\n      const effectiveNodeConfig = node.nodeConfig\r\n        ? { ...nodeConfig, ...node.nodeConfig }\r\n        : nodeConfig;\r\n\r\n      // Use actual node width based on type\r\n      let actualWidth = effectiveNodeConfig.width || boxWidth;\r\n      if (\r\n        effectiveNodeConfig.type === \"node-with-description\" ||\r\n        effectiveNodeConfig.type === \"collapsible-node\" ||\r\n        effectiveNodeConfig.type === \"image\"\r\n      ) {\r\n        actualWidth = this.nodeDrawer.calculateDynamicNodeWidth(\r\n          node,\r\n          effectiveNodeConfig\r\n        );\r\n      }\r\n      nodeWidths.push(actualWidth);\r\n    });\r\n\r\n    // Calculate total level width and starting position\r\n    const totalNodesWidth = nodeWidths.reduce((sum, width) => sum + width, 0);\r\n    const totalGaps = (level.length - 1) * horizontalGap;\r\n    const levelWidth = totalNodesWidth + totalGaps;\r\n\r\n    // Calculate starting X based on alignment\r\n    let startX = basePadding;\r\n    if (verticalAlign === \"center\") {\r\n      startX = (totalWidth - levelWidth) / 2;\r\n    } else if (verticalAlign === \"right\") {\r\n      startX = totalWidth - levelWidth - basePadding;\r\n    }\r\n\r\n    // Create node data for this level\r\n    const nodeData: Array<any> = [];\r\n    level.forEach((node: any, nodeIndex: number) => {\r\n      // Calculate X position based on actual node widths\r\n      let x = startX;\r\n      for (let i = 0; i < nodeIndex; i++) {\r\n        x += nodeWidths[i] + horizontalGap;\r\n      }\r\n\r\n      // Merge default nodeConfig with node-specific config\r\n      const effectiveNodeConfig = node.nodeConfig\r\n        ? { ...nodeConfig, ...node.nodeConfig }\r\n        : nodeConfig;\r\n\r\n      // Calculate effective dimensions\r\n      let effectiveWidth = effectiveNodeConfig.width || boxWidth;\r\n      if (\r\n        effectiveNodeConfig.type === \"node-with-description\" ||\r\n        effectiveNodeConfig.type === \"collapsible-node\" ||\r\n        effectiveNodeConfig.type === \"image\"\r\n      ) {\r\n        effectiveWidth = this.nodeDrawer.calculateDynamicNodeWidth(\r\n          node,\r\n          effectiveNodeConfig\r\n        );\r\n      }\r\n      const effectiveHeight = effectiveNodeConfig.height || boxHeight;\r\n\r\n      // For dynamic node types, calculate the actual height\r\n      let effectiveActualHeight = effectiveHeight;\r\n      if (\r\n        effectiveNodeConfig.type === \"node-with-description\" ||\r\n        effectiveNodeConfig.type === \"image\" ||\r\n        (effectiveNodeConfig.type === \"collapsible-node\" &&\r\n          node.description &&\r\n          node.collapsibleState?.expanded)\r\n      ) {\r\n        effectiveActualHeight = this.nodeDrawer.calculateDynamicNodeHeight(\r\n          node,\r\n          effectiveNodeConfig\r\n        );\r\n        maxHeightInLevel = Math.max(maxHeightInLevel, effectiveActualHeight);\r\n      } else {\r\n        maxHeightInLevel = Math.max(maxHeightInLevel, effectiveHeight);\r\n      }\r\n\r\n      nodeData.push({\r\n        node,\r\n        nodeIndex,\r\n        effectiveNodeConfig,\r\n        effectiveWidth,\r\n        effectiveHeight,\r\n        effectiveActualHeight,\r\n        x,\r\n      });\r\n    });\r\n\r\n    return { maxHeightInLevel, nodeData };\r\n  }\r\n\r\n  /**\r\n   * Create final layouts with Y positions calculated\r\n   */\r\n  private createFinalLayouts(\r\n    levelNodeData: Array<Array<any>>,\r\n    levelHeights: number[],\r\n    yOffset: number,\r\n    verticalGap: number,\r\n    horizontalAlign: string,\r\n    totalHeight: number,\r\n    titleSpace: any,\r\n    basePadding: number\r\n  ): LevelLayout[] {\r\n    const levels: LevelLayout[] = [];\r\n    let cumulativeY = yOffset;\r\n\r\n    levelNodeData.forEach((levelNodes, levelIndex) => {\r\n      const levelHeight = levelHeights[levelIndex];\r\n\r\n      const nodes: NodeLayoutPosition[] = levelNodes.map((nodeData) => {\r\n        // Calculate Y position using actual level heights\r\n        let y;\r\n        if (horizontalAlign === \"bottom-to-top\") {\r\n          // For bottom-to-top, use simple cumulative positioning since levels are already reversed\r\n          y = cumulativeY;\r\n        } else {\r\n          y = cumulativeY;\r\n        }\r\n\r\n        return {\r\n          node: nodeData.node,\r\n          nodeIndex: nodeData.nodeIndex,\r\n          effectiveNodeConfig: nodeData.effectiveNodeConfig,\r\n          x: nodeData.x,\r\n          y,\r\n          width: nodeData.effectiveWidth,\r\n          height: nodeData.effectiveHeight,\r\n          actualHeight: nodeData.effectiveActualHeight,\r\n        };\r\n      });\r\n\r\n      levels.push({\r\n        levelIndex,\r\n        levelHeight,\r\n        nodes,\r\n      });\r\n\r\n      // Move to next level\r\n      cumulativeY += levelHeight + verticalGap;\r\n    });\r\n\r\n    return levels;\r\n  }\r\n}\r\n","import { NodeDrawer } from \"./NodeDrawer\";\r\nimport { getNodeKey } from \"./svgHelpers\";\r\nimport { TreeLayout, NodeLayoutPosition, NodeMapEntry } from \"../types\";\r\n\r\nexport class NodeFactory {\r\n  constructor(\r\n    private nodeDrawer: NodeDrawer,\r\n    private onTreeUpdate?: () => void\r\n  ) {}\r\n\r\n  /**\r\n   * Create all nodes from the calculated layout\r\n   */\r\n  public createNodesFromLayout(\r\n    layout: TreeLayout\r\n  ): Record<string, NodeMapEntry> {\r\n    const nodeMap: Record<string, NodeMapEntry> = {};\r\n\r\n    layout.levels.forEach((level) => {\r\n      level.nodes.forEach((nodePosition) => {\r\n        const nodeResult = this.createSingleNode(nodePosition);\r\n        const nodeKey = getNodeKey(level.levelIndex, nodePosition.nodeIndex);\r\n\r\n        nodeMap[nodeKey] = {\r\n          x: nodeResult.bounds.x,\r\n          y: nodeResult.bounds.y,\r\n          centerX: nodeResult.centerX,\r\n          centerY: nodeResult.centerY,\r\n          width: nodeResult.bounds.width,\r\n          height: nodeResult.bounds.height,\r\n          bottomY: nodeResult.bounds.y + nodeResult.bounds.height,\r\n          topY: nodeResult.bounds.y,\r\n          node: nodePosition.node,\r\n        };\r\n      });\r\n    });\r\n\r\n    return nodeMap;\r\n  }\r\n\r\n  /**\r\n   * Create a single node with the given position and configuration\r\n   */\r\n  private createSingleNode(nodePosition: NodeLayoutPosition) {\r\n    const { node, effectiveNodeConfig, x, y, width, height } = nodePosition;\r\n\r\n    return this.nodeDrawer.drawNode({\r\n      type: effectiveNodeConfig.type,\r\n      x,\r\n      y,\r\n      width,\r\n      height,\r\n      fill: effectiveNodeConfig.color,\r\n      stroke: effectiveNodeConfig.borderColor,\r\n      strokeWidth: effectiveNodeConfig.borderWidth,\r\n      borderRadius: effectiveNodeConfig.borderRadius,\r\n      text: node.text,\r\n      description: node.description,\r\n      fontSize: effectiveNodeConfig.fontSize,\r\n      fontColor: effectiveNodeConfig.fontColor,\r\n      padding: effectiveNodeConfig.padding || 5,\r\n      opacity: effectiveNodeConfig.opacity,\r\n      shadow: effectiveNodeConfig.shadow,\r\n      shadowColor: effectiveNodeConfig.shadowColor,\r\n      shadowOffset: effectiveNodeConfig.shadowOffset,\r\n      gradient: effectiveNodeConfig.gradient,\r\n      gradientStartColor: effectiveNodeConfig.gradientStartColor,\r\n      gradientEndColor: effectiveNodeConfig.gradientEndColor,\r\n      collapsible: effectiveNodeConfig.collapsible,\r\n      expanded: node.collapsibleState?.expanded || false,\r\n      onToggleExpand: this.createToggleHandler(node),\r\n      // Image node specific configurations\r\n      imageConfig: effectiveNodeConfig.imageConfig,\r\n      imageTitleConfig: effectiveNodeConfig.imageTitleConfig,\r\n      imageSubtitleConfig: effectiveNodeConfig.imageSubtitleConfig,\r\n      imageTextPositionConfig: effectiveNodeConfig.imageTextPositionConfig,\r\n      imageMargin: effectiveNodeConfig.imageMargin,\r\n      // Image node specific data\r\n      imageUrl: node.imageUrl,\r\n      title: node.title,\r\n      subtitle: node.subtitle,\r\n      // Custom attributes for advanced customization\r\n      customAttributes: effectiveNodeConfig.customAttributes || {},\r\n    });\r\n  }\r\n\r\n  /**\r\n   * Create a toggle handler for collapsible nodes\r\n   */\r\n  private createToggleHandler(node: any) {\r\n    return (expanded: boolean) => {\r\n      // Update the node state\r\n      if (node.collapsibleState) {\r\n        node.collapsibleState.expanded = expanded;\r\n      } else {\r\n        node.collapsibleState = { expanded };\r\n      }\r\n\r\n      // Trigger tree re-rendering\r\n      if (this.onTreeUpdate) {\r\n        this.onTreeUpdate();\r\n      }\r\n    };\r\n  }\r\n}\r\n","import { FormattedTree, TreeChartOptions, NodeMap } from \"../types\";\r\nimport { DEFAULT_OPTIONS } from \"../constants\";\r\nimport {\r\n  createSvgElement,\r\n  calculateSvgWidth,\r\n  calculateSvgHeight,\r\n} from \"../utils/svgHelpers\";\r\nimport { ConnectionDrawer } from \"../utils/ConnectionDrawer\";\r\nimport { NodeDrawer } from \"../utils/NodeDrawer\";\r\nimport { TitleDrawer } from \"../utils/TitleDrawer\";\r\nimport { ActionDrawer } from \"../utils/ActionDrawer\";\r\nimport { LayoutCalculator } from \"../utils/LayoutCalculator\";\r\nimport { NodeFactory } from \"../utils/NodeFactory\";\r\n\r\n/**\r\n * BaseRenderer class that all specific renderers extend\r\n * Provides common functionality for tree rendering\r\n */\r\nexport abstract class BaseRenderer {\r\n  protected formattedTree: FormattedTree;\r\n  protected options: Required<Omit<TreeChartOptions, \"actionConfig\">> & {\r\n    actionConfig?: TreeChartOptions[\"actionConfig\"];\r\n  };\r\n  protected nodeMap: NodeMap = {};\r\n  protected svg: SVGSVGElement;\r\n  protected connectionDrawer: ConnectionDrawer;\r\n  protected nodeDrawer: NodeDrawer;\r\n  protected titleDrawer: TitleDrawer;\r\n  protected actionDrawer?: ActionDrawer;\r\n  protected layoutCalculator: LayoutCalculator;\r\n  protected nodeFactory: NodeFactory;\r\n  protected containerElement?: HTMLElement;\r\n  protected onTreeUpdate?: () => void;\r\n  protected titleSpace?: { top: number; bottom: number };\r\n\r\n  /**\r\n   * Constructor for BaseRenderer\r\n   *\r\n   * @param formattedTree The formatted tree data\r\n   * @param options Rendering options\r\n   */\r\n  constructor(formattedTree: FormattedTree, options: TreeChartOptions = {}) {\r\n    this.formattedTree = formattedTree;\r\n\r\n    // Merge default options with provided options\r\n    this.options = {\r\n      ...DEFAULT_OPTIONS,\r\n      ...options,\r\n      nodeConfig: {\r\n        ...DEFAULT_OPTIONS.nodeConfig,\r\n        ...options.nodeConfig,\r\n      },\r\n      edgeConfig: {\r\n        ...DEFAULT_OPTIONS.edgeConfig,\r\n        ...options.edgeConfig,\r\n      },\r\n      titleConfig: {\r\n        ...DEFAULT_OPTIONS.titleConfig,\r\n        ...options.titleConfig,\r\n      },\r\n      actionConfig: {\r\n        ...options.actionConfig,\r\n      },\r\n    } as Required<Omit<TreeChartOptions, \"actionConfig\">> & {\r\n      actionConfig?: TreeChartOptions[\"actionConfig\"];\r\n    };\r\n\r\n    // Create temporary SVG for initialization\r\n    this.svg = createSvgElement(100, 100);\r\n\r\n    // Initialize drawers\r\n    this.connectionDrawer = new ConnectionDrawer(this.svg);\r\n    this.nodeDrawer = new NodeDrawer(this.svg);\r\n    this.titleDrawer = new TitleDrawer(this.svg, options.titleConfig);\r\n\r\n    // Initialize layout and node factory utilities\r\n    this.layoutCalculator = new LayoutCalculator(\r\n      this.formattedTree,\r\n      this.options,\r\n      this.nodeDrawer,\r\n      this.titleDrawer\r\n    );\r\n    this.nodeFactory = new NodeFactory(this.nodeDrawer, () => {\r\n      if (this.onTreeUpdate) {\r\n        this.onTreeUpdate();\r\n      }\r\n    });\r\n\r\n    // Calculate proper SVG dimensions\r\n    const svgWidth = calculateSvgWidth(\r\n      this.formattedTree,\r\n      this.options,\r\n      this.nodeDrawer\r\n    );\r\n    this.titleSpace = this.titleDrawer.calculateTitleSpace(svgWidth);\r\n    const svgHeight = calculateSvgHeight(\r\n      this.formattedTree,\r\n      this.options,\r\n      this.nodeDrawer,\r\n      this.titleSpace\r\n    );\r\n\r\n    // Update SVG with correct dimensions\r\n    this.svg.setAttribute(\"width\", svgWidth.toString());\r\n    this.svg.setAttribute(\"height\", svgHeight.toString());\r\n  }\r\n\r\n  /**\r\n   * Set the callback for tree updates (for collapsible nodes)\r\n   */\r\n  public setTreeUpdateCallback(callback: () => void): void {\r\n    this.onTreeUpdate = callback;\r\n  }\r\n\r\n  /**\r\n   * Create nodes for the tree using the layout calculator and node factory\r\n   */\r\n  protected createNodes(): void {\r\n    // Calculate the complete layout for the tree\r\n    const layout = this.layoutCalculator.calculateTreeLayout();\r\n\r\n    // Create all nodes from the calculated layout\r\n    this.nodeMap = this.nodeFactory.createNodesFromLayout(layout);\r\n  }\r\n\r\n  /**\r\n   * Abstract method to draw connections between nodes\r\n   * Each renderer must implement this\r\n   */\r\n  protected abstract drawConnections(): void;\r\n\r\n  /**\r\n   * Render the tree and return the SVG element\r\n   */\r\n  public render(): SVGSVGElement {\r\n    this.createNodes();\r\n    this.drawConnections();\r\n\r\n    // Draw title and description\r\n    this.renderTitle();\r\n\r\n    // Draw action buttons if configured\r\n    this.renderActions();\r\n\r\n    return this.svg;\r\n  }\r\n\r\n  /**\r\n   * Set container element for action positioning\r\n   */\r\n  public setContainer(containerElement: HTMLElement): void {\r\n    this.containerElement = containerElement;\r\n  }\r\n\r\n  /**\r\n   * Render action buttons\r\n   */\r\n  protected renderActions(): void {\r\n    if (this.options.actionConfig && this.containerElement) {\r\n      this.actionDrawer = new ActionDrawer(\r\n        this.svg,\r\n        this.options.actionConfig,\r\n        this.containerElement\r\n      );\r\n      this.actionDrawer.drawActions();\r\n    }\r\n  }\r\n\r\n  /**\r\n   * Render chart title and description\r\n   */\r\n  protected renderTitle(): void {\r\n    const svgWidth = parseInt(this.svg.getAttribute(\"width\") || \"0\");\r\n    const svgHeight = parseInt(this.svg.getAttribute(\"height\") || \"0\");\r\n\r\n    this.titleDrawer.drawTitle(svgWidth, svgHeight, this.titleSpace);\r\n  }\r\n}\r\n","import { BaseRenderer } from \"./BaseRenderer\";\r\nimport { getNodeKey } from \"../utils/svgHelpers\";\r\n\r\n/**\r\n * DirectRenderer creates a tree with direct straight line connections between nodes\r\n */\r\nexport class DirectRenderer extends BaseRenderer {\r\n  /**\r\n   * Draw direct straight line connections between parent and child nodes\r\n   */\r\n  protected drawConnections(): void {\r\n    const { horizontalAlign, edgeConfig } = this.options;\r\n\r\n    this.formattedTree.forEach((level, levelIndex) => {\r\n      level.forEach((node, nodeIndex) => {\r\n        if (node.parent) {\r\n          const parent = JSON.parse(node.parent);\r\n          const childKey = getNodeKey(levelIndex, nodeIndex);\r\n          const parentKey = getNodeKey(parent.level, parent.position);\r\n\r\n          const child = this.nodeMap[childKey];\r\n          const parentNode = this.nodeMap[parentKey];\r\n\r\n          if (child && parentNode) {\r\n            // X values stay the same (center of each node)\r\n            const x1 = parentNode.centerX!;\r\n            const x2 = child.centerX!;\r\n\r\n            let y1, y2;\r\n            if (horizontalAlign === \"bottom-to-top\") {\r\n              // Parent is visually below the child\r\n              y1 = parentNode.topY!; // top of parent\r\n              y2 = child.bottomY!; // bottom of child\r\n            } else {\r\n              // Default: top to bottom\r\n              y1 = parentNode.bottomY!; // bottom of parent\r\n              y2 = child.topY!; // top of child\r\n            }\r\n\r\n            this.connectionDrawer.drawConnection(\r\n              { x: x1, y: y1 },\r\n              { x: x2, y: y2 },\r\n              {\r\n                type: \"direct\", // Always use direct connections for DirectRenderer\r\n                color: edgeConfig!.color,\r\n                width: edgeConfig!.width,\r\n                dasharray: edgeConfig!.dasharray,\r\n                showArrows: edgeConfig!.showArrows,\r\n                arrowDirection: edgeConfig!.arrowDirection,\r\n                arrowSize: edgeConfig!.arrowSize,\r\n                edgeText: node.edgeText || undefined,\r\n                textSize: edgeConfig!.textSize,\r\n                textColor: edgeConfig!.textColor,\r\n                textBackgroundColor:\r\n                  edgeConfig!.textBackgroundColor || undefined,\r\n              }\r\n            );\r\n          }\r\n        }\r\n      });\r\n    });\r\n  }\r\n}\r\n","import { BaseRenderer } from \"./BaseRenderer\";\r\nimport { getNodeKey } from \"../utils/svgHelpers\";\r\nimport {\r\n  createParentToChildrenMap,\r\n  calculateHeightOffset,\r\n} from \"../utils/treeFormatter\";\r\n\r\n/**\r\n * RightAngleRenderer creates a tree with right-angle connections between nodes\r\n */\r\nexport class RightAngleRenderer extends BaseRenderer {\r\n  /**\r\n   * Draw right-angle connections between parent and child nodes\r\n   */\r\n  protected drawConnections(): void {\r\n    const { horizontalAlign, verticalGap } = this.options;\r\n\r\n    // Use utility function to collect parent-child relationships\r\n    const parentToChildren = createParentToChildrenMap(this.formattedTree);\r\n\r\n    // Now draw connections for each parent with a global height offset pattern\r\n    let globalParentIndex = 0; // Global counter for height offset pattern\r\n\r\n    Object.keys(parentToChildren).forEach((parentKey) => {\r\n      const children = parentToChildren[parentKey];\r\n      const parentNode = this.nodeMap[parentKey];\r\n\r\n      if (!parentNode || children.length === 0) return;\r\n\r\n      if (children.length === 1) {\r\n        // Single child - draw simple right-angle connection\r\n        const child = children[0];\r\n        const childKey = getNodeKey(child.levelIndex, child.nodeIndex);\r\n        const childNode = this.nodeMap[childKey];\r\n\r\n        if (childNode) {\r\n          this.drawSingleChildConnection(\r\n            parentNode,\r\n            childNode,\r\n            horizontalAlign\r\n          );\r\n        }\r\n      } else {\r\n        // Multiple children - draw horizontal connector line and individual connections\r\n        this.drawMultipleChildrenConnections(\r\n          parentNode,\r\n          children,\r\n          horizontalAlign,\r\n          verticalGap,\r\n          globalParentIndex // Pass the global index for height offset\r\n        );\r\n        globalParentIndex++; // Only increment for parents with multiple children\r\n      }\r\n    });\r\n  }\r\n\r\n  private drawSingleChildConnection(\r\n    parentNode: any,\r\n    childNode: any,\r\n    horizontalAlign: string\r\n  ): void {\r\n    const parentPoint = {\r\n      x: parentNode.centerX!,\r\n      y:\r\n        horizontalAlign === \"bottom-to-top\"\r\n          ? parentNode.topY!\r\n          : parentNode.bottomY!,\r\n    };\r\n\r\n    const childPoint = {\r\n      x: childNode.centerX!,\r\n      y:\r\n        horizontalAlign === \"bottom-to-top\"\r\n          ? childNode.bottomY!\r\n          : childNode.topY!,\r\n    };\r\n\r\n    // Use the new high-level method for cleaner three-segment right-angle connection\r\n    this.connectionDrawer.drawThreeSegmentRightAngle(parentPoint, childPoint, {\r\n      type: \"right-angle\",\r\n      color: this.options.edgeConfig!.color,\r\n      width: this.options.edgeConfig!.width,\r\n      edgeText: childNode.node?.edgeText || undefined,\r\n      textSize: this.options.edgeConfig!.textSize,\r\n      textColor: this.options.edgeConfig!.textColor,\r\n      showArrows: this.options.edgeConfig!.showArrows,\r\n      arrowDirection: this.options.edgeConfig!.arrowDirection,\r\n      arrowSize: this.options.edgeConfig!.arrowSize,\r\n    });\r\n  }\r\n\r\n  private drawMultipleChildrenConnections(\r\n    parentNode: any,\r\n    children: any[],\r\n    horizontalAlign: string,\r\n    verticalGap: number,\r\n    parentIndex: number\r\n  ): void {\r\n    // Get child nodes\r\n    const childNodes = children\r\n      .map((child) => {\r\n        const childKey = getNodeKey(child.levelIndex, child.nodeIndex);\r\n        return { ...child, nodeData: this.nodeMap[childKey] };\r\n      })\r\n      .filter((child) => child.nodeData);\r\n\r\n    if (childNodes.length === 0) return;\r\n\r\n    // Calculate connection points with alternating height offset\r\n    let parentY, childrenY, horizontalY;\r\n\r\n    // Use utility function to calculate height offset\r\n    const heightOffset = calculateHeightOffset(parentIndex);\r\n\r\n    if (horizontalAlign === \"bottom-to-top\") {\r\n      parentY = parentNode.topY!;\r\n      childrenY = childNodes[0].nodeData.bottomY!;\r\n      horizontalY = childrenY + verticalGap / 2 + heightOffset;\r\n    } else {\r\n      parentY = parentNode.bottomY!;\r\n      childrenY = childNodes[0].nodeData.topY!;\r\n      horizontalY = childrenY - verticalGap / 2 + heightOffset;\r\n    }\r\n\r\n    const parentPoint = { x: parentNode.centerX!, y: parentY };\r\n    const childPoints = childNodes.map((child) => ({\r\n      x: child.nodeData.centerX!,\r\n      y: childrenY,\r\n    }));\r\n\r\n    // Use the new high-level method for multi-child connections (without text)\r\n    this.connectionDrawer.drawMultiChildRightAngle(\r\n      parentPoint,\r\n      childPoints,\r\n      horizontalY,\r\n      {\r\n        type: \"right-angle\",\r\n        color: this.options.edgeConfig!.color,\r\n        width: this.options.edgeConfig!.width,\r\n        showArrows: this.options.edgeConfig!.showArrows,\r\n        arrowDirection: this.options.edgeConfig!.arrowDirection,\r\n        arrowSize: this.options.edgeConfig!.arrowSize,\r\n      }\r\n    );\r\n\r\n    // Now add text to individual child connections using the dedicated method\r\n    const childTexts = childNodes.map((child) => child.nodeData.node?.edgeText);\r\n    this.connectionDrawer.drawChildConnectionsWithText(\r\n      childPoints,\r\n      horizontalY,\r\n      childTexts,\r\n      {\r\n        type: \"right-angle\",\r\n        color: this.options.edgeConfig!.color,\r\n        width: this.options.edgeConfig!.width,\r\n        textSize: this.options.edgeConfig!.textSize,\r\n        textColor: this.options.edgeConfig!.textColor,\r\n        textBackgroundColor: this.options.edgeConfig!.textBackgroundColor,\r\n        showArrows: this.options.edgeConfig!.showArrows,\r\n        arrowDirection: this.options.edgeConfig!.arrowDirection,\r\n        arrowSize: this.options.edgeConfig!.arrowSize,\r\n      }\r\n    );\r\n  }\r\n}\r\n","import { BaseRenderer } from \"./BaseRenderer\";\r\nimport { getNodeKey } from \"../utils/svgHelpers\";\r\n\r\n/**\r\n * CurvedRenderer creates a tree with curved connections between nodes\r\n */\r\nexport class CurvedRenderer extends BaseRenderer {\r\n  /**\r\n   * Draw curved bezier connections between parent and child nodes\r\n   */\r\n  protected drawConnections(): void {\r\n    const { horizontalAlign } = this.options;\r\n\r\n    this.formattedTree.forEach((level, levelIndex) => {\r\n      level.forEach((node, nodeIndex) => {\r\n        if (node.parent) {\r\n          const parent = JSON.parse(node.parent);\r\n          const childKey = getNodeKey(levelIndex, nodeIndex);\r\n          const parentKey = getNodeKey(parent.level, parent.position);\r\n\r\n          const child = this.nodeMap[childKey];\r\n          const parentNode = this.nodeMap[parentKey];\r\n\r\n          if (child && parentNode) {\r\n            // X values stay the same (center of each node)\r\n            const x1 = parentNode.centerX!;\r\n            const x2 = child.centerX!;\r\n\r\n            let y1, y2;\r\n            if (horizontalAlign === \"bottom-to-top\") {\r\n              // Parent is visually below the child\r\n              y1 = parentNode.topY!; // top of parent\r\n              y2 = child.bottomY!; // bottom of child\r\n            } else {\r\n              // Default: top to bottom\r\n              y1 = parentNode.bottomY!; // bottom of parent\r\n              y2 = child.topY!; // top of child\r\n            }\r\n\r\n            this.connectionDrawer.drawConnection(\r\n              { x: x1, y: y1 },\r\n              { x: x2, y: y2 },\r\n              {\r\n                type: \"curved\", // Always use curved connections for CurvedRenderer\r\n                color: this.options.edgeConfig!.color,\r\n                width: this.options.edgeConfig!.width,\r\n                dasharray: this.options.edgeConfig!.dasharray,\r\n                showArrows: this.options.edgeConfig!.showArrows,\r\n                arrowDirection: this.options.edgeConfig!.arrowDirection,\r\n                arrowSize: this.options.edgeConfig!.arrowSize,\r\n                curveRadius: this.options.edgeConfig!.curveRadius,\r\n                edgeText: node.edgeText || undefined,\r\n                textSize: this.options.edgeConfig!.textSize,\r\n                textColor: this.options.edgeConfig!.textColor,\r\n                textBackgroundColor:\r\n                  this.options.edgeConfig!.textBackgroundColor,\r\n              }\r\n            );\r\n          }\r\n        }\r\n      });\r\n    });\r\n  }\r\n}\r\n","import { BaseRenderer } from \"./BaseRenderer\";\r\nimport { createSvgElement, getNodeKey } from \"../utils/svgHelpers\";\r\nimport { createParentChildMap } from \"../utils/treeFormatter\";\r\nimport { ALL_DIRECTION_DIMENSIONS, SVG_NS } from \"../constants\";\r\nimport { ConnectionDrawer } from \"../utils/ConnectionDrawer\";\r\nimport { NodeDrawer } from \"../utils/NodeDrawer\";\r\nimport { TitleDrawer } from \"../utils/TitleDrawer\";\r\nimport { TreeChartOptions } from \"../types\";\r\n\r\n/**\r\n * AllDirectionRenderer creates a radial tree layout where nodes spread out in all directions\r\n */\r\nexport class AllDirectionRenderer extends BaseRenderer {\r\n  private centerX: number;\r\n  private centerY: number;\r\n\r\n  /**\r\n   * Override constructor to calculate dynamic dimensions for all-direction layout\r\n   */\r\n  constructor(formattedTree: any, options: TreeChartOptions = {}) {\r\n    super(formattedTree, {\r\n      ...options,\r\n      horizontalGap: ALL_DIRECTION_DIMENSIONS.horizontalGap,\r\n      verticalGap: ALL_DIRECTION_DIMENSIONS.verticalGap,\r\n    });\r\n\r\n    // Calculate dynamic dimensions based on tree depth and breadth\r\n    const { svgWidth, svgHeight } = this.calculateDynamicDimensions();\r\n\r\n    // Calculate title space to adjust the chart positioning\r\n    const titleSpace = this.titleDrawer.calculateTitleSpace(svgWidth);\r\n\r\n    this.centerX = svgWidth / 2;\r\n    // Position chart center in the available space after accounting for titles\r\n    this.centerY =\r\n      titleSpace.top + (svgHeight - titleSpace.top - titleSpace.bottom) / 2;\r\n\r\n    // Override SVG with calculated dimensions + title space\r\n    const totalSvgHeight = svgHeight + titleSpace.top + titleSpace.bottom;\r\n    this.svg = createSvgElement(\r\n      svgWidth,\r\n      totalSvgHeight,\r\n      `0 0 ${svgWidth} ${totalSvgHeight}`\r\n    );\r\n\r\n    // Reinitialize connection drawer with the new SVG\r\n    this.connectionDrawer = new ConnectionDrawer(this.svg);\r\n\r\n    // Reinitialize node drawer with the new SVG\r\n    this.nodeDrawer = new NodeDrawer(this.svg);\r\n\r\n    // Reinitialize title drawer with the new SVG\r\n    this.titleDrawer = new TitleDrawer(this.svg, options.titleConfig);\r\n  }\r\n\r\n  /**\r\n   * Calculate dynamic SVG dimensions based on tree structure\r\n   */\r\n  private calculateDynamicDimensions(): {\r\n    svgWidth: number;\r\n    svgHeight: number;\r\n  } {\r\n    const treeDepth = this.formattedTree.length;\r\n    const nodeConfig = this.options.nodeConfig!;\r\n    const boxWidth = nodeConfig.width!;\r\n    const boxHeight = nodeConfig.height!;\r\n    const { horizontalGap, verticalGap } = this.options;\r\n\r\n    // Calculate the actual maximum distances we'll use\r\n    const firstLevelHorizontalDistance = Math.min(\r\n      140,\r\n      ALL_DIRECTION_DIMENSIONS.horizontalGap\r\n    );\r\n    const firstLevelVerticalDistance = Math.min(\r\n      120,\r\n      ALL_DIRECTION_DIMENSIONS.verticalGap\r\n    );\r\n    const deeperLevelHorizontalDistance = Math.min(\r\n      110,\r\n      ALL_DIRECTION_DIMENSIONS.horizontalGap\r\n    );\r\n    const deeperLevelVerticalDistance = Math.min(\r\n      90,\r\n      ALL_DIRECTION_DIMENSIONS.verticalGap\r\n    );\r\n\r\n    // Calculate maximum extent from center in any direction\r\n    let maxHorizontalExtent = firstLevelHorizontalDistance; // First level horizontal\r\n    let maxVerticalExtent = firstLevelVerticalDistance; // First level vertical\r\n\r\n    // Add distances for deeper levels\r\n    if (treeDepth > 2) {\r\n      maxHorizontalExtent += (treeDepth - 2) * deeperLevelHorizontalDistance;\r\n      maxVerticalExtent += (treeDepth - 2) * deeperLevelVerticalDistance;\r\n    }\r\n\r\n    // Add half the node size to account for node dimensions\r\n    maxHorizontalExtent += boxWidth / 2;\r\n    maxVerticalExtent += boxHeight / 2;\r\n\r\n    // Add generous padding to ensure no clipping\r\n    const padding = 50;\r\n\r\n    // Calculate required canvas size for the chart content only\r\n    const requiredWidth = maxHorizontalExtent * 2 + padding;\r\n    const requiredHeight = maxVerticalExtent * 2 + padding;\r\n\r\n    // Use the larger of the calculated sizes to ensure everything fits\r\n    const svgWidth = Math.max(400, requiredWidth);\r\n    const svgHeight = Math.max(400, requiredHeight);\r\n\r\n    return { svgWidth, svgHeight };\r\n  }\r\n\r\n  /**\r\n   * Override node creation for radial layout\r\n   */\r\n  protected createNodes(): void {\r\n    const nodeConfig = this.options.nodeConfig!;\r\n    const boxWidth = nodeConfig.width!;\r\n    const boxHeight = nodeConfig.height!;\r\n\r\n    // Group nodes by their parent\r\n    const parentToChildrenMap = createParentChildMap(this.formattedTree);\r\n\r\n    // Process root node (level 0) first\r\n    if (this.formattedTree.length > 0 && this.formattedTree[0].length > 0) {\r\n      const rootNode = this.formattedTree[0][0];\r\n      const rootX = this.centerX - boxWidth / 2;\r\n      const rootY = this.centerY - boxHeight / 2;\r\n\r\n      // Merge default nodeConfig with node-specific config (if provided)\r\n      const effectiveNodeConfig = rootNode.nodeConfig\r\n        ? { ...nodeConfig, ...rootNode.nodeConfig }\r\n        : nodeConfig;\r\n\r\n      // Use effective width and height (might be overridden by node-specific config)\r\n      const effectiveWidth = effectiveNodeConfig.width || boxWidth;\r\n      const effectiveHeight = effectiveNodeConfig.height || boxHeight;\r\n\r\n      // Create root node using NodeDrawer\r\n      const rootNodeResult = this.nodeDrawer.drawNode({\r\n        type: effectiveNodeConfig.type,\r\n        x: rootX,\r\n        y: rootY,\r\n        width: effectiveWidth,\r\n        height: effectiveHeight,\r\n        fill: effectiveNodeConfig.color,\r\n        stroke: effectiveNodeConfig.borderColor,\r\n        strokeWidth: effectiveNodeConfig.borderWidth,\r\n        borderRadius: effectiveNodeConfig.borderRadius,\r\n        text: rootNode.text,\r\n        fontSize: effectiveNodeConfig.fontSize,\r\n        fontColor: effectiveNodeConfig.fontColor,\r\n        opacity: effectiveNodeConfig.opacity,\r\n        shadow: effectiveNodeConfig.shadow,\r\n        shadowColor: effectiveNodeConfig.shadowColor,\r\n        shadowOffset: effectiveNodeConfig.shadowOffset,\r\n        gradient: effectiveNodeConfig.gradient,\r\n        gradientStartColor: effectiveNodeConfig.gradientStartColor,\r\n        gradientEndColor: effectiveNodeConfig.gradientEndColor,\r\n        customAttributes: effectiveNodeConfig.customAttributes || {},\r\n      });\r\n\r\n      this.nodeMap[`0-0`] = {\r\n        centerX: this.centerX,\r\n        centerY: this.centerY,\r\n        x: rootX,\r\n        y: rootY,\r\n        width: effectiveWidth,\r\n        height: effectiveHeight,\r\n      };\r\n    }\r\n\r\n    // Process first level children using a radial distribution\r\n    if (this.formattedTree.length > 1) {\r\n      const firstLevelParent = JSON.stringify({ level: 0, position: 0 });\r\n      const firstLevelChildren = parentToChildrenMap[firstLevelParent] || [];\r\n      const childCount = firstLevelChildren.length;\r\n\r\n      // Distribute first level children in a circle\r\n      firstLevelChildren.forEach((childInfo: any, index: number) => {\r\n        const childNode =\r\n          this.formattedTree[childInfo.level][childInfo.position];\r\n\r\n        // Merge default nodeConfig with node-specific config (if provided)\r\n        const effectiveNodeConfig = childNode.nodeConfig\r\n          ? { ...nodeConfig, ...childNode.nodeConfig }\r\n          : nodeConfig;\r\n\r\n        // Use effective width and height (might be overridden by node-specific config)\r\n        const effectiveWidth = effectiveNodeConfig.width || boxWidth;\r\n        const effectiveHeight = effectiveNodeConfig.height || boxHeight;\r\n\r\n        // Calculate angle (in radians)\r\n        const angleStep = (2 * Math.PI) / childCount;\r\n        const angle = index * angleStep;\r\n\r\n        // Determine which spacing to use based on angle - balanced distances\r\n        const isMoreHorizontal =\r\n          Math.abs(Math.cos(angle)) > Math.abs(Math.sin(angle));\r\n        const distance = isMoreHorizontal\r\n          ? Math.min(140, ALL_DIRECTION_DIMENSIONS.horizontalGap) // Increased horizontal distance\r\n          : Math.min(120, ALL_DIRECTION_DIMENSIONS.verticalGap); // Increased vertical distance\r\n\r\n        // Calculate position\r\n        const nodeX =\r\n          this.centerX + Math.cos(angle) * distance - effectiveWidth / 2;\r\n        const nodeY =\r\n          this.centerY + Math.sin(angle) * distance - effectiveHeight / 2;\r\n\r\n        // Create node using NodeDrawer\r\n        const nodeResult = this.nodeDrawer.drawNode({\r\n          type: effectiveNodeConfig.type,\r\n          x: nodeX,\r\n          y: nodeY,\r\n          width: effectiveWidth,\r\n          height: effectiveHeight,\r\n          fill: effectiveNodeConfig.color,\r\n          stroke: effectiveNodeConfig.borderColor,\r\n          strokeWidth: effectiveNodeConfig.borderWidth,\r\n          borderRadius: effectiveNodeConfig.borderRadius,\r\n          text: childNode.text,\r\n          fontSize: effectiveNodeConfig.fontSize,\r\n          fontColor: effectiveNodeConfig.fontColor,\r\n          opacity: effectiveNodeConfig.opacity,\r\n          shadow: effectiveNodeConfig.shadow,\r\n          shadowColor: effectiveNodeConfig.shadowColor,\r\n          shadowOffset: effectiveNodeConfig.shadowOffset,\r\n          gradient: effectiveNodeConfig.gradient,\r\n          gradientStartColor: effectiveNodeConfig.gradientStartColor,\r\n          gradientEndColor: effectiveNodeConfig.gradientEndColor,\r\n          customAttributes: effectiveNodeConfig.customAttributes || {},\r\n        });\r\n\r\n        // Store node data with direction\r\n        const dirX = Math.cos(angle);\r\n        const dirY = Math.sin(angle);\r\n\r\n        this.nodeMap[getNodeKey(childInfo.level, childInfo.position)] = {\r\n          centerX: nodeX + effectiveWidth / 2,\r\n          centerY: nodeY + effectiveHeight / 2,\r\n          x: nodeX,\r\n          y: nodeY,\r\n          width: effectiveWidth,\r\n          height: effectiveHeight,\r\n          direction: { x: dirX, y: dirY },\r\n          angle: angle,\r\n        };\r\n      });\r\n    }\r\n\r\n    // Process remaining levels - continue in the same general direction as the parent\r\n    for (\r\n      let levelIndex = 2;\r\n      levelIndex < this.formattedTree.length;\r\n      levelIndex++\r\n    ) {\r\n      const level = this.formattedTree[levelIndex];\r\n\r\n      level.forEach((node: any, nodeIndex: number) => {\r\n        if (node.parent) {\r\n          const parent = JSON.parse(node.parent);\r\n          const parentKey = getNodeKey(parent.level, parent.position);\r\n          const parentNode = this.nodeMap[parentKey];\r\n\r\n          if (parentNode) {\r\n            // Merge default nodeConfig with node-specific config (if provided)\r\n            const effectiveNodeConfig = node.nodeConfig\r\n              ? { ...nodeConfig, ...node.nodeConfig }\r\n              : nodeConfig;\r\n\r\n            // Use effective width and height (might be overridden by node-specific config)\r\n            const effectiveWidth = effectiveNodeConfig.width || boxWidth;\r\n            const effectiveHeight = effectiveNodeConfig.height || boxHeight;\r\n\r\n            // Get parent's direction and angle\r\n            const direction = parentNode.direction || { x: 0, y: 0 };\r\n            const parentAngle = parentNode.angle || 0;\r\n\r\n            // Find siblings\r\n            const parentJsonStr = node.parent;\r\n            const siblings = parentToChildrenMap[parentJsonStr] || [];\r\n            const siblingCount = siblings.length;\r\n            const siblingIndex = siblings.findIndex(\r\n              (s: any) => s.level === levelIndex && s.position === nodeIndex\r\n            );\r\n\r\n            // Calculate child angle with fan effect for siblings\r\n            let angle = parentAngle;\r\n\r\n            if (siblingCount > 1) {\r\n              // Fan siblings out slightly\r\n              const fanAngle = Math.PI / 6; // 30 degrees total fan\r\n              const fanStep = fanAngle / (siblingCount - 1);\r\n              angle = parentAngle - fanAngle / 2 + siblingIndex * fanStep;\r\n            }\r\n\r\n            // Determine distance based on direction - balanced distances for better spacing\r\n            const isMoreHorizontal =\r\n              Math.abs(Math.cos(angle)) > Math.abs(Math.sin(angle));\r\n            const distance = isMoreHorizontal\r\n              ? Math.min(110, ALL_DIRECTION_DIMENSIONS.horizontalGap) // Increased horizontal distance\r\n              : Math.min(90, ALL_DIRECTION_DIMENSIONS.verticalGap); // Increased vertical distance\r\n\r\n            // Calculate position\r\n            const dirX = Math.cos(angle);\r\n            const dirY = Math.sin(angle);\r\n\r\n            const nodeX = parentNode.x + dirX * distance;\r\n            const nodeY = parentNode.y + dirY * distance;\r\n\r\n            // Create node using NodeDrawer\r\n            const nodeResult = this.nodeDrawer.drawNode({\r\n              type: effectiveNodeConfig.type,\r\n              x: nodeX,\r\n              y: nodeY,\r\n              width: effectiveWidth,\r\n              height: effectiveHeight,\r\n              fill: effectiveNodeConfig.color,\r\n              stroke: effectiveNodeConfig.borderColor,\r\n              strokeWidth: effectiveNodeConfig.borderWidth,\r\n              borderRadius: effectiveNodeConfig.borderRadius,\r\n              text: node.text,\r\n              fontSize: effectiveNodeConfig.fontSize,\r\n              fontColor: effectiveNodeConfig.fontColor,\r\n              opacity: effectiveNodeConfig.opacity,\r\n              shadow: effectiveNodeConfig.shadow,\r\n              shadowColor: effectiveNodeConfig.shadowColor,\r\n              shadowOffset: effectiveNodeConfig.shadowOffset,\r\n              gradient: effectiveNodeConfig.gradient,\r\n              gradientStartColor: effectiveNodeConfig.gradientStartColor,\r\n              gradientEndColor: effectiveNodeConfig.gradientEndColor,\r\n              customAttributes: effectiveNodeConfig.customAttributes || {},\r\n            });\r\n\r\n            // Store node data\r\n            this.nodeMap[getNodeKey(levelIndex, nodeIndex)] = {\r\n              centerX: nodeX + effectiveWidth / 2,\r\n              centerY: nodeY + effectiveHeight / 2,\r\n              x: nodeX,\r\n              y: nodeY,\r\n              width: effectiveWidth,\r\n              height: effectiveHeight,\r\n              direction: { x: dirX, y: dirY },\r\n              angle: angle,\r\n            };\r\n          }\r\n        }\r\n      });\r\n    }\r\n  }\r\n\r\n  /**\r\n   * Draw edges between nodes for all-direction tree with improved edge connection\r\n   */\r\n  protected drawConnections(): void {\r\n    this.formattedTree.forEach((level: any, levelIndex: number) => {\r\n      // Skip the root level (level 0)\r\n      if (levelIndex === 0) return;\r\n\r\n      level.forEach((node: any, nodeIndex: number) => {\r\n        if (node.parent) {\r\n          const parent = JSON.parse(node.parent);\r\n          const childKey = getNodeKey(levelIndex, nodeIndex);\r\n          const parentKey = getNodeKey(parent.level, parent.position);\r\n\r\n          const childNode = this.nodeMap[childKey];\r\n          const parentNode = this.nodeMap[parentKey];\r\n\r\n          if (childNode && parentNode) {\r\n            // Calculate edge-to-edge connection points\r\n            const childCenterX = childNode.centerX!;\r\n            const childCenterY = childNode.centerY!;\r\n            const parentCenterX = parentNode.centerX!;\r\n            const parentCenterY = parentNode.centerY!;\r\n\r\n            // Vector from parent to child\r\n            const vectorX = childCenterX - parentCenterX;\r\n            const vectorY = childCenterY - parentCenterY;\r\n            const length = Math.sqrt(vectorX * vectorX + vectorY * vectorY);\r\n            const normalizedVectorX = vectorX / length;\r\n            const normalizedVectorY = vectorY / length;\r\n\r\n            // Find intersection points with rectangles - improved calculation\r\n            let parentConnectX, parentConnectY, childConnectX, childConnectY;\r\n            const nodeConfig = this.options.nodeConfig!;\r\n            const boxWidth = nodeConfig.width!;\r\n            const boxHeight = nodeConfig.height!;\r\n\r\n            // Calculate connection points on the edges of rectangles\r\n            // For parent node - find where the line intersects the rectangle edge\r\n            const parentHalfWidth = boxWidth / 2;\r\n            const parentHalfHeight = boxHeight / 2;\r\n\r\n            // Check which edge the line intersects\r\n            const parentTx =\r\n              Math.abs(normalizedVectorX) < 1e-10\r\n                ? 1e10\r\n                : parentHalfWidth / Math.abs(normalizedVectorX);\r\n            const parentTy =\r\n              Math.abs(normalizedVectorY) < 1e-10\r\n                ? 1e10\r\n                : parentHalfHeight / Math.abs(normalizedVectorY);\r\n\r\n            if (parentTx < parentTy) {\r\n              // Intersects vertical edge\r\n              parentConnectX =\r\n                parentCenterX +\r\n                (normalizedVectorX > 0 ? parentHalfWidth : -parentHalfWidth);\r\n              parentConnectY = parentCenterY + normalizedVectorY * parentTx;\r\n            } else {\r\n              // Intersects horizontal edge\r\n              parentConnectX = parentCenterX + normalizedVectorX * parentTy;\r\n              parentConnectY =\r\n                parentCenterY +\r\n                (normalizedVectorY > 0 ? parentHalfHeight : -parentHalfHeight);\r\n            }\r\n\r\n            // For child node - find where the line intersects the rectangle edge\r\n            const childHalfWidth = boxWidth / 2;\r\n            const childHalfHeight = boxHeight / 2;\r\n\r\n            const childTx =\r\n              Math.abs(normalizedVectorX) < 1e-10\r\n                ? 1e10\r\n                : childHalfWidth / Math.abs(normalizedVectorX);\r\n            const childTy =\r\n              Math.abs(normalizedVectorY) < 1e-10\r\n                ? 1e10\r\n                : childHalfHeight / Math.abs(normalizedVectorY);\r\n\r\n            if (childTx < childTy) {\r\n              // Intersects vertical edge\r\n              childConnectX =\r\n                childCenterX +\r\n                (normalizedVectorX < 0 ? childHalfWidth : -childHalfWidth);\r\n              childConnectY = childCenterY - normalizedVectorY * childTx;\r\n            } else {\r\n              // Intersects horizontal edge\r\n              childConnectX = childCenterX - normalizedVectorX * childTy;\r\n              childConnectY =\r\n                childCenterY +\r\n                (normalizedVectorY < 0 ? childHalfHeight : -childHalfHeight);\r\n            }\r\n\r\n            // Draw the connection using ConnectionDrawer\r\n            this.connectionDrawer.drawConnection(\r\n              { x: parentConnectX, y: parentConnectY },\r\n              { x: childConnectX, y: childConnectY },\r\n              {\r\n                type: \"direct\", // Always use direct connections for AllDirectionRenderer (radial layout)\r\n                color: this.options.edgeConfig!.color,\r\n                width: this.options.edgeConfig!.width,\r\n                dasharray: this.options.edgeConfig!.dasharray,\r\n                showArrows: this.options.edgeConfig!.showArrows,\r\n                arrowDirection: this.options.edgeConfig!.arrowDirection,\r\n                arrowSize: this.options.edgeConfig!.arrowSize,\r\n                edgeText: node.edgeText || undefined,\r\n                textSize: this.options.edgeConfig!.textSize,\r\n                textColor: this.options.edgeConfig!.textColor,\r\n                textBackgroundColor:\r\n                  this.options.edgeConfig!.textBackgroundColor,\r\n              }\r\n            );\r\n          }\r\n        }\r\n      });\r\n    });\r\n  }\r\n}\r\n","export { BaseRenderer } from \"./BaseRenderer\";\r\nexport { DirectRenderer } from \"./DirectRenderer\";\r\nexport { RightAngleRenderer } from \"./RightAngleRenderer\";\r\nexport { CurvedRenderer } from \"./CurvedRenderer\";\r\nexport { AllDirectionRenderer } from \"./AllDirectionRenderer\";\r\n\r\nimport { BaseRenderer } from \"./BaseRenderer\";\r\nimport { DirectRenderer } from \"./DirectRenderer\";\r\nimport { RightAngleRenderer } from \"./RightAngleRenderer\";\r\nimport { CurvedRenderer } from \"./CurvedRenderer\";\r\nimport { AllDirectionRenderer } from \"./AllDirectionRenderer\";\r\nimport { TreeType, FormattedTree, TreeChartOptions } from \"../types\";\r\n\r\n/**\r\n * Factory function to create the appropriate renderer based on tree type\r\n *\r\n * @param type Type of tree visualization\r\n * @param formattedTree Formatted tree data\r\n * @param options Rendering options\r\n * @returns The appropriate renderer instance\r\n */\r\nexport function createRenderer(\r\n  type: TreeType,\r\n  formattedTree: FormattedTree,\r\n  options: TreeChartOptions\r\n): BaseRenderer {\r\n  switch (type) {\r\n    case \"direct\":\r\n      return new DirectRenderer(formattedTree, options);\r\n    case \"right-angle\":\r\n      return new RightAngleRenderer(formattedTree, options);\r\n    case \"curved\":\r\n      return new CurvedRenderer(formattedTree, options);\r\n    case \"all-direction\":\r\n      return new AllDirectionRenderer(formattedTree, options);\r\n    default:\r\n      return new DirectRenderer(formattedTree, options);\r\n  }\r\n}\r\n","import { TreeNode, TreeChartOptions, FormattedTree, TreeType } from \"./types\";\r\nimport { formatTree } from \"./utils/treeFormatter\";\r\nimport { createRenderer } from \"./renderers\";\r\nimport { DEFAULT_OPTIONS } from \"./constants\";\r\n\r\n/**\r\n * Main TreeChart class for creating tree visualizations\r\n */\r\nexport class TreeChart {\r\n  private container: HTMLElement | null = null;\r\n  private options: Required<Omit<TreeChartOptions, \"actionConfig\">> & {\r\n    actionConfig?: TreeChartOptions[\"actionConfig\"];\r\n  };\r\n  private formattedTree: FormattedTree = [];\r\n  private svg: SVGSVGElement | null = null;\r\n\r\n  /**\r\n   * Constructor for TreeChart\r\n   *\r\n   * @param containerId ID of the HTML element to render the chart in (optional)\r\n   * @param options Configuration options for the chart\r\n   */\r\n  constructor(containerId?: string, options: TreeChartOptions = {}) {\r\n    // If containerId is provided, get the container element\r\n    if (containerId) {\r\n      this.container = document.getElementById(containerId);\r\n      if (!this.container) {\r\n        console.warn(`Container element with ID \"${containerId}\" not found.`);\r\n      }\r\n    }\r\n\r\n    // Merge default options with provided options\r\n    this.options = {\r\n      ...DEFAULT_OPTIONS,\r\n      ...options,\r\n    } as Required<Omit<TreeChartOptions, \"actionConfig\">> & {\r\n      actionConfig?: TreeChartOptions[\"actionConfig\"];\r\n    };\r\n  }\r\n\r\n  /**\r\n   * Set the container element for the chart\r\n   *\r\n   * @param containerId ID of the HTML element\r\n   * @returns The TreeChart instance for chaining\r\n   */\r\n  public setContainer(containerId: string): TreeChart {\r\n    this.container = document.getElementById(containerId);\r\n    if (!this.container) {\r\n      console.warn(`Container element with ID \"${containerId}\" not found.`);\r\n    }\r\n    return this;\r\n  }\r\n\r\n  /**\r\n   * Set chart options\r\n   *\r\n   * @param options Configuration options\r\n   * @returns The TreeChart instance for chaining\r\n   */\r\n  public setOptions(options: TreeChartOptions): TreeChart {\r\n    this.options = {\r\n      ...this.options,\r\n      ...options,\r\n    } as Required<Omit<TreeChartOptions, \"actionConfig\">> & {\r\n      actionConfig?: TreeChartOptions[\"actionConfig\"];\r\n    };\r\n    return this;\r\n  }\r\n\r\n  /**\r\n   * Set the type of tree visualization\r\n   *\r\n   * @param type Type of tree visualization\r\n   * @returns The TreeChart instance for chaining\r\n   */\r\n  public setType(type: TreeType): TreeChart {\r\n    this.options.type = type;\r\n    return this;\r\n  }\r\n\r\n  /**\r\n   * Render the tree chart\r\n   *\r\n   * @param data Tree data to visualize\r\n   * @returns The created SVG element\r\n   */\r\n  public render(data: TreeNode): SVGSVGElement {\r\n    // Format the tree data for rendering\r\n    // Only apply alignment options for chart types that support them\r\n    // All-direction (radial) charts don't use alignment as nodes are positioned radially\r\n    const formatOptions =\r\n      this.options.type === \"all-direction\"\r\n        ? undefined\r\n        : { horizontalAlign: this.options.horizontalAlign };\r\n\r\n    this.formattedTree = formatTree(data, formatOptions);\r\n\r\n    // Create appropriate renderer based on type\r\n    const renderer = createRenderer(\r\n      this.options.type,\r\n      this.formattedTree,\r\n      this.options\r\n    );\r\n\r\n    // Set up callback for collapsible nodes to trigger re-rendering\r\n    renderer.setTreeUpdateCallback(() => {\r\n      this.render(data);\r\n    });\r\n\r\n    // Set container for action positioning\r\n    if (this.container) {\r\n      renderer.setContainer(this.container);\r\n    }\r\n\r\n    // Render the tree\r\n    this.svg = renderer.render();\r\n\r\n    // If container exists, append the SVG to it\r\n    if (this.container) {\r\n      this.container.innerHTML = \"\"; // Clear container\r\n      this.container.appendChild(this.svg);\r\n    }\r\n\r\n    return this.svg;\r\n  }\r\n\r\n  /**\r\n   * Update the chart with new data\r\n   *\r\n   * @param data New tree data\r\n   * @returns The updated SVG element\r\n   */\r\n  public update(data: TreeNode): SVGSVGElement {\r\n    return this.render(data);\r\n  }\r\n\r\n  /**\r\n   * Get the SVG element\r\n   *\r\n   * @returns The SVG element or null if not rendered\r\n   */\r\n  public getSvg(): SVGSVGElement | null {\r\n    return this.svg;\r\n  }\r\n\r\n  /**\r\n   * Resize the chart\r\n   *\r\n   * @param width New width\r\n   * @param height New height\r\n   * @returns The TreeChart instance for chaining\r\n   */\r\n  public resize(width: number, height: number): TreeChart {\r\n    if (this.svg) {\r\n      this.svg.setAttribute(\"width\", width.toString());\r\n      this.svg.setAttribute(\"height\", height.toString());\r\n    }\r\n    return this;\r\n  }\r\n}\r\n","// Export main TreeChart class\r\nexport { TreeChart } from \"./TreeChart\";\r\n\r\n// Export types\r\nexport * from \"./types\";\r\n\r\n// Export constants\r\nexport { DEFAULT_OPTIONS } from \"./constants\";\r\n\r\n// Export utils\r\nexport { formatTree } from \"./utils/treeFormatter\";\r\nexport { svgHelpers } from \"./utils/svgHelpers\";\r\n\r\n// Export renderers\r\nexport {\r\n  BaseRenderer,\r\n  DirectRenderer,\r\n  RightAngleRenderer,\r\n  CurvedRenderer,\r\n  AllDirectionRenderer,\r\n} from \"./renderers\";\r\n\r\n// Export node renderers\r\nexport {\r\n  BaseNodeRenderer,\r\n  RectangleNodeRenderer,\r\n  NodeWithDescriptionRenderer,\r\n  CollapsibleNodeRenderer,\r\n  ImageNodeRenderer,\r\n  ShapeNodeRenderer,\r\n} from \"./nodeRenderers\";\r\n\r\n// Default export\r\nimport { TreeChart } from \"./TreeChart\";\r\nexport default TreeChart;\r\n"],"mappings":"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","names":["SVG_NS","NODE_CONSTANTS","DEFAULT_OPTIONS","ALL_DIRECTION_DIMENSIONS","createSvgElement","width","height","viewBox","svg","SVG_NS","calculateSvgWidth","formattedTree","options","nodeDrawer","horizontalGap","basePadding","NODE_CONSTANTS","nodeConfig","boxWidth","maxLevelWidth","level","nodeWidths","node","effectiveNodeConfig","actualWidth","totalNodesWidth","sum","totalGaps","levelWidth","calculateSvgHeight","titleSpace","boxHeight","verticalGap","totalHeight","levelIndex","maxHeightInLevel","dynamicHeight","getNodeKey","position","svgHelpers","formatTree","tree","options","formattedTree","stack","node","position","i","childNode","reverseTreeForBottomToTop","reversedTree","maxLevel","level","newLevelIndex","parentPos","newParentLevel","createParentToChildrenMap","parentToChildren","levelIndex","nodeIndex","parent","parentKey","getNodeKey","createParentChildMap","parentChildPair","j","calculateHeightOffset","parentIndex","pattern","ConnectionDrawer","svg","fromPoint","toPoint","options","finalOptions","pathElement","parentPoint","childPoint","elements","midY","showArrowOnParentSegment","showArrowOnChildSegment","segment1","segment2","segment3","childPoints","horizontalY","childXValues","p","minX","maxX","parentToHorizontal","horizontalLine","childTexts","index","edgeText","childConnection","line","SVG_NS","path","pathData","curveRadius","controlX","controlY","element","arrowColor","colorId","endMarkerId","endMarker","startMarkerId","startMarker","marker","defs","markerId","position","arrow","points","textElement","midX","NODE_CONSTANTS","bbox","rectElement","BaseNodeRenderer","svg","element","options","key","value","shadowElement","SVG_NS","gradientId","defs","gradient","stop1","stop2","textElement","text","fontSize","fontFamily","context","maxWidth","words","lines","currentLine","word","testLine","x","startY","fontColor","lineHeight","textElements","line","index","rect","fill","description","maxTextWidth","fillColor","NODE_CONSTANTS","textAnchor","title","fontWeight","dominantBaseline","elements","lineY","RectangleNodeRenderer","BaseNodeRenderer","options","group","shadow","rect","text","NodeWithDescriptionRenderer","BaseNodeRenderer","options","group","actualWidth","actualHeight","updatedOptions","shadow","rect","element","node","nodeConfig","maxNodeWidth","NODE_CONSTANTS","padding","fontSize","descriptionFontSize","fontFamily","maxRequiredWidth","availableWidth","lines","maxLineWidth","line","lineWidth","minWidthRequired","lineHeight","totalRequiredHeight","descriptionSpacing","descriptionHeight","minHeightRequired","elements","centerX","maxTitleWidth","titleStartY","titleElements","titleHeight","maxTextWidth","textStartY","descriptionElements","CollapsibleNodeRenderer","BaseNodeRenderer","options","group","actualWidth","actualHeight","updatedOptions","shadow","rect","element","chevron","node","nodeConfig","maxNodeWidth","NODE_CONSTANTS","padding","fontSize","descriptionFontSize","fontFamily","maxRequiredWidth","availableWidth","lines","maxLineWidth","line","lineWidth","minWidthRequired","lineHeight","maxWidth","chevronSpace","titleAvailableWidth","totalRequiredHeight","descriptionSpacing","descriptionHeight","bottomPadding","minHeightRequired","elements","textCenterX","maxTitleWidth","titleStartY","titleElements","titleHeight","maxTextWidth","textStartY","centerX","descriptionElements","chevronGroup","chevronPadding","chevronX","chevronY","chevronSize","chevronPath","SVG_NS","pathData","clickArea","clickAreaSize","event","ImageNodeRenderer","BaseNodeRenderer","options","group","layout","updatedOptions","background","shadow","imageElement","element","node","nodeConfig","imageConfig","imageTitleConfig","imageSubtitleConfig","imageTextPositionConfig","imageWidth","NODE_CONSTANTS","imageHeight","textPosition","textPadding","textSpacing","imageMargin","title","subtitle","titleFontSize","subtitleFontSize","fontFamily","maxTextWidth","textHeight","totalWidth","totalHeight","titleWidth","subtitleWidth","titleHeight","subtitleHeight","totalTextHeight","imageX","imageY","textAreaX","textAreaY","textAreaWidth","rect","SVG_NS","fill","borderRadius","borderWidth","elements","textAnchor","textX","currentY","titleElement","subtitleElement","ShapeNodeRenderer","BaseNodeRenderer","options","group","shadow","shape","fill","text","shadowOptions","shadowShape","circle","SVG_NS","radius","centerX","centerY","ellipse","diamond","points","hexagon","halfWidth","triangle","pentagon","i","angle","x","y","octagon","star","outerRadius","innerRadius","path","NodeDrawer","svg","NODE_CONSTANTS","ImageNodeRenderer","NodeWithDescriptionRenderer","CollapsibleNodeRenderer","RectangleNodeRenderer","ShapeNodeRenderer","text","fontSize","fontFamily","maxWidth","lines","maxLineWidth","line","lineWidth","method","node","nodeConfig","maxNodeWidth","padding","descriptionFontSize","maxRequiredWidth","totalWidth","minWidthRequired","lineHeight","descriptionMarginTop","totalRequiredHeight","availableWidth","descriptionHeight","minHeightRequired","options","finalOptions","nodeElements","shapeElement","bounds","shadowElement","typesWithDedicatedRenderers","textElement","element","centerX","centerY","shapeTypes","result","shapeOptions","shadowOptions","gradientId","defs","SVG_NS","gradient","stop1","stop2","key","value","index","tspan","TitleDrawer","svg","titleConfig","DEFAULT_OPTIONS","text","fontSize","fontFamily","context","maxWidth","words","lines","currentLine","word","testLine","svgWidth","svgHeight","titleSpace","titleHeight","descriptionHeight","horizontal","vertical","titleX","titleY","computedTitleSpace","titleGroup","SVG_NS","currentY","titleElements","element","lineHeight","descriptionElements","NODE_CONSTANTS","x","startY","style","padding","textElements","line","index","textElement","y","textAnchor","topSpace","bottomSpace","extraSpacing","actualSvgWidth","ActionDrawer","svg","actionConfig","containerElement","position","x","y","buttonGroup","buttonBg","NODE_CONSTANTS","iconGroup","shaft","arrowPath","baseLine","title","containerRect","svgRect","svgWidth","svgHeight","buttonSize","svgClone","actionsGroup","svgString","blob","url","link","error","newActionConfig","LayoutCalculator","formattedTree","options","nodeDrawer","titleDrawer","verticalAlign","horizontalGap","verticalGap","horizontalAlign","nodeConfig","boxWidth","boxHeight","basePadding","NODE_CONSTANTS","totalWidth","calculateSvgWidth","titleSpace","totalHeight","calculateSvgHeight","yOffset","levelHeights","levelNodeData","level","levelIndex","maxHeightInLevel","nodeData","nodeWidths","node","effectiveNodeConfig","actualWidth","totalNodesWidth","sum","width","totalGaps","levelWidth","startX","nodeIndex","i","effectiveWidth","effectiveHeight","effectiveActualHeight","levels","cumulativeY","levelNodes","levelHeight","nodes","y","NodeFactory","nodeDrawer","onTreeUpdate","layout","nodeMap","level","nodePosition","nodeResult","nodeKey","getNodeKey","node","effectiveNodeConfig","x","y","width","height","expanded","BaseRenderer","formattedTree","options","DEFAULT_OPTIONS","createSvgElement","ConnectionDrawer","NodeDrawer","TitleDrawer","LayoutCalculator","NodeFactory","svgWidth","calculateSvgWidth","svgHeight","calculateSvgHeight","callback","layout","containerElement","ActionDrawer","DirectRenderer","BaseRenderer","horizontalAlign","edgeConfig","level","levelIndex","node","nodeIndex","parent","childKey","getNodeKey","parentKey","child","parentNode","x1","x2","y1","y2","RightAngleRenderer","BaseRenderer","horizontalAlign","verticalGap","parentToChildren","createParentToChildrenMap","globalParentIndex","parentKey","children","parentNode","child","childKey","getNodeKey","childNode","parentPoint","childPoint","parentIndex","childNodes","parentY","childrenY","horizontalY","heightOffset","calculateHeightOffset","childPoints","childTexts","CurvedRenderer","BaseRenderer","horizontalAlign","level","levelIndex","node","nodeIndex","parent","childKey","getNodeKey","parentKey","child","parentNode","x1","x2","y1","y2","AllDirectionRenderer","BaseRenderer","formattedTree","options","ALL_DIRECTION_DIMENSIONS","svgWidth","svgHeight","titleSpace","totalSvgHeight","createSvgElement","ConnectionDrawer","NodeDrawer","TitleDrawer","treeDepth","nodeConfig","boxWidth","boxHeight","horizontalGap","verticalGap","firstLevelHorizontalDistance","firstLevelVerticalDistance","deeperLevelHorizontalDistance","deeperLevelVerticalDistance","maxHorizontalExtent","maxVerticalExtent","padding","requiredWidth","requiredHeight","parentToChildrenMap","createParentChildMap","rootNode","rootX","rootY","effectiveNodeConfig","effectiveWidth","effectiveHeight","rootNodeResult","firstLevelParent","firstLevelChildren","childCount","childInfo","index","childNode","angleStep","angle","distance","nodeX","nodeY","nodeResult","dirX","dirY","getNodeKey","levelIndex","node","nodeIndex","parent","parentKey","parentNode","direction","parentAngle","parentJsonStr","siblings","siblingCount","siblingIndex","s","fanAngle","fanStep","level","childKey","childCenterX","childCenterY","parentCenterX","parentCenterY","vectorX","vectorY","length","normalizedVectorX","normalizedVectorY","parentConnectX","parentConnectY","childConnectX","childConnectY","parentHalfWidth","parentHalfHeight","parentTx","parentTy","childHalfWidth","childHalfHeight","childTx","childTy","createRenderer","type","formattedTree","options","DirectRenderer","RightAngleRenderer","CurvedRenderer","AllDirectionRenderer","TreeChart","containerId","options","DEFAULT_OPTIONS","type","data","formatOptions","formatTree","renderer","createRenderer","width","height","src_default","TreeChart"]}