@plait/graph-viz
Version:
#### Dependence - `@plait/core`
1 lines • 65.8 kB
Source Map (JSON)
{"version":3,"file":"plait-graph-viz.mjs","sources":["../../../packages/graph-viz/src/constants/default.ts","../../../packages/graph-viz/src/force-atlas/types.ts","../../../packages/graph-viz/src/force-atlas/constants.ts","../../../packages/graph-viz/src/interfaces/element.ts","../../../packages/graph-viz/src/force-atlas/force-atlas.flavour.ts","../../../packages/graph-viz/src/perfect-arrows/utils.ts","../../../packages/graph-viz/src/perfect-arrows/get-arrow.ts","../../../packages/graph-viz/src/force-atlas/utils/draw.ts","../../../packages/graph-viz/src/force-atlas/generators/edge.generator.ts","../../../packages/graph-viz/src/force-atlas/utils/edge.ts","../../../packages/graph-viz/src/force-atlas/utils/node.ts","../../../packages/graph-viz/src/force-atlas/generators/node.generator.ts","../../../packages/graph-viz/src/force-atlas/node.flavour.ts","../../../packages/graph-viz/src/force-atlas/edge.flavour.ts","../../../packages/graph-viz/src/force-atlas/with-node-icon.ts","../../../packages/graph-viz/src/force-atlas/with-force-atlas.ts","../../../packages/graph-viz/src/force-atlas/core/node-icon-base.component.ts","../../../packages/graph-viz/src/public-api.ts","../../../packages/graph-viz/src/plait-graph-viz.ts"],"sourcesContent":["import { Options } from 'roughjs/bin/core';\n\nexport const DEFAULT_STYLES: Options = {\n fillStyle: 'solid',\n strokeWidth: 1\n};\n","import { GeneratorExtraData } from '@plait/common';\nimport { Point } from '@plait/core';\n\nexport enum EdgeDirection {\n IN,\n OUT,\n NONE\n}\n\nexport interface NodeStyles {\n stroke?: string;\n strokeWidth?: number;\n fill?: string;\n fillStyle?: string;\n activeStroke?: string;\n activeFill?: string;\n borderRadius?: number;\n hoverStroke?: string;\n}\n\nexport interface EdgeGeneratorData extends GeneratorExtraData {\n startPoint: Point;\n endPoint: Point;\n isSourceActive: boolean;\n isTargetActive: boolean;\n direction: EdgeDirection;\n isTargetSelf?: boolean;\n}\n\nexport interface NodeGeneratorData extends GeneratorExtraData {\n isActive: boolean;\n opacity: number;\n}\n\nexport interface NodeIconItem {\n name: string;\n fontSize?: number;\n color?: string;\n}\n","import { Options } from 'roughjs/bin/core';\nimport { DEFAULT_STYLES } from '../constants/default';\nimport { EdgeDirection } from './types';\n\nexport const DEFAULT_EDGE_STYLES: Options = {\n ...DEFAULT_STYLES,\n stroke: '#ddd'\n};\n\nexport const DEFAULT_NODE_SIZE = 30;\n\nexport const DEFAULT_ACTIVE_NODE_SIZE_MULTIPLIER = 1.2;\n\nexport const DEFAULT_ACTIVE_WAVE_NODE_SIZE_MULTIPLIER = 1.5;\n\nexport const DEFAULT_NODE_LABEL_MARGIN_TOP = 4;\n\nexport const DEFAULT_NODE_LABEL_FONT_SIZE = 12;\n\nexport const DEFAULT_NODE_LABEL_WIDTH = 72;\n\nexport const DEFAULT_NODE_LABEL_HEIGHT = 22;\n\nexport const DEFAULT_NODE_LABEL_STYLE = `user-select:none;max-width:${DEFAULT_NODE_LABEL_WIDTH}px;text-align:center;line-height:${DEFAULT_NODE_LABEL_HEIGHT}px;font-size:${DEFAULT_NODE_LABEL_FONT_SIZE}px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;`;\n\nexport const NODE_LABEL_CLASS_NAME = 'force-atlas-node-label';\n\nexport const SECOND_DEPTH_NODE_ALPHA = 0.5;\n\nexport const SECOND_DEPTH_LINE_ALPHA = 0.5;\n\nexport const ACTIVE_BACKGROUND_NODE_ALPHA = 0.1;\n\nexport const NODE_ICON_CLASS_NAME = 'force-atlas-node-icon';\n\nexport const ACTIVE_NODE_ICON_CLASS_NAME = 'force-atlas-node-icon-active';\n\nexport const NODE_ICON_FONT_SIZE = 16;\n\nexport const ACTIVE_NODE_ICON_FONT_SIZE = 18;\n\nexport const DEFAULT_NODE_BACKGROUND_COLOR = '#9c9cfb';\n\nexport const DEFAULT_NODE_ICON_COLOR = '#fff';\n\nexport const DEFAULT_NODE_STYLES: Options = {\n ...DEFAULT_STYLES,\n fill: DEFAULT_NODE_BACKGROUND_COLOR,\n strokeWidth: 0\n};\n\nexport const DEFAULT_NODE_SCALING_RATIO = 20;\n\nexport const DEFAULT_LINE_STYLES = {\n color: {\n [EdgeDirection.IN]: '#73D897',\n [EdgeDirection.OUT]: '#6698FF',\n [EdgeDirection.NONE]: `#eee`\n },\n opacity: {\n [EdgeDirection.IN]: 0.4,\n [EdgeDirection.OUT]: 0.4,\n [EdgeDirection.NONE]: 1\n }\n};\n\nexport const DEFAULT_EDGE_PARTICLE_SIZE = 4;\n","import { PlaitElement } from '@plait/core';\nimport { NodeIconItem } from '../force-atlas/types';\nexport interface ForceAtlasNodeElement extends PlaitElement {\n label: string;\n icon: string | NodeIconItem;\n size?: number;\n isActive?: boolean;\n}\n\nexport interface ForceAtlasEdgeElement extends PlaitElement {\n source: string;\n target: string;\n}\n\nexport interface ForceAtlasElement extends PlaitElement {\n children: (ForceAtlasNodeElement | ForceAtlasEdgeElement)[];\n}\n\nexport const ForceAtlasElement = {\n isForceAtlas: (value: any) => {\n return value?.type === 'force-atlas';\n },\n isForceAtlasNodeElement: (value: any): value is ForceAtlasNodeElement => {\n return value && value.label && value.icon;\n },\n isForceAtlasEdgeElement: (value: any): value is ForceAtlasEdgeElement => {\n return value && value.source && value.target;\n }\n};\n","import { CommonElementFlavour } from '@plait/common';\nimport { OnContextChanged, PlaitBoard, PlaitPluginElementContext, cacheSelectedElements } from '@plait/core';\nimport Graph from 'graphology';\nimport circular from 'graphology-layout/circular';\nimport forceAtlas2 from 'graphology-layout-forceatlas2';\nimport { ForceAtlasElement, ForceAtlasNodeElement } from '../interfaces';\nimport { DEFAULT_NODE_SIZE } from './constants';\n\nexport class ForceAtlasFlavour extends CommonElementFlavour<ForceAtlasElement, PlaitBoard>\n implements OnContextChanged<ForceAtlasElement, PlaitBoard> {\n graph!: Graph<ForceAtlasNodeElement>;\n\n constructor() {\n super();\n }\n\n initializeGraph() {\n this.graph = new Graph<ForceAtlasNodeElement>();\n this.element.children?.forEach(child => {\n if (ForceAtlasElement.isForceAtlasNodeElement(child)) {\n if (typeof child?.size === 'undefined') {\n child.size = DEFAULT_NODE_SIZE;\n }\n if (child.isActive) {\n cacheSelectedElements(this.board, [child]);\n }\n this.graph.addNode(child.id, child);\n } else if (ForceAtlasElement.isForceAtlasEdgeElement(child)) {\n this.graph.addEdge(child.source, child.target);\n }\n });\n circular.assign(this.graph);\n const nodeCount = this.graph.nodes().length;\n const settings = forceAtlas2.inferSettings(this.graph);\n settings.scalingRatio = 450;\n if (nodeCount > 5) {\n settings.gravity = 0.2;\n settings.adjustSizes = false;\n } else {\n settings.gravity = 0;\n settings.adjustSizes = true;\n }\n const positions = forceAtlas2(this.graph, { iterations: 500, settings });\n this.element.children?.forEach(child => {\n if (ForceAtlasElement.isForceAtlasNodeElement(child)) {\n const pos = positions[child.id];\n child.points = [[pos.x, pos.y]];\n }\n });\n }\n\n initialize(): void {\n super.initialize();\n this.initializeGraph();\n }\n\n onContextChanged(\n value: PlaitPluginElementContext<ForceAtlasElement, PlaitBoard>,\n previous: PlaitPluginElementContext<ForceAtlasElement, PlaitBoard>\n ) {}\n\n updateText(previousElement: ForceAtlasElement, currentElement: ForceAtlasElement) {}\n\n destroy(): void {\n super.destroy();\n }\n}\n","// Credits to perfect-arrows\n// https://github.com/steveruizok/perfect-arrows/blob/master/src/lib/utils.ts\n\nconst PI = Math.PI;\n\n/**\n * Modulate a value between two ranges.\n * @param value\n * @param rangeA from [low, high]\n * @param rangeB to [low, high]\n * @param clamp\n */\nexport function modulate(value: number, rangeA: number[], rangeB: number[], clamp = false) {\n const [fromLow, fromHigh] = rangeA;\n const [toLow, toHigh] = rangeB;\n const result = toLow + ((value - fromLow) / (fromHigh - fromLow)) * (toHigh - toLow);\n if (clamp === true) {\n if (toLow < toHigh) {\n if (result < toLow) {\n return toLow;\n }\n if (result > toHigh) {\n return toHigh;\n }\n } else {\n if (result > toLow) {\n return toLow;\n }\n if (result < toHigh) {\n return toHigh;\n }\n }\n }\n return result;\n}\n\n/**\n * Rotate a point around a center.\n * @param x The x-axis coordinate of the point.\n * @param y The y-axis coordinate of the point.\n * @param cx The x-axis coordinate of the point to rotate round.\n * @param cy The y-axis coordinate of the point to rotate round.\n * @param angle The distance (in radians) to rotate.\n */\nexport function rotatePoint(x: number, y: number, cx: number, cy: number, angle: number) {\n const s = Math.sin(angle);\n const c = Math.cos(angle);\n\n const px = x - cx;\n const py = y - cy;\n\n const nx = px * c - py * s;\n const ny = px * s + py * c;\n\n return [nx + cx, ny + cy];\n}\n\n/**\n * Get the distance between two points.\n * @param x0 The x-axis coordinate of the first point.\n * @param y0 The y-axis coordinate of the first point.\n * @param x1 The x-axis coordinate of the second point.\n * @param y1 The y-axis coordinate of the second point.\n */\nexport function getDistance(x0: number, y0: number, x1: number, y1: number) {\n return Math.hypot(y1 - y0, x1 - x0);\n}\n\n/**\n * Get an angle (radians) between two points.\n * @param x0 The x-axis coordinate of the first point.\n * @param y0 The y-axis coordinate of the first point.\n * @param x1 The x-axis coordinate of the second point.\n * @param y1 The y-axis coordinate of the second point.\n */\nexport function getAngle(x0: number, y0: number, x1: number, y1: number) {\n return Math.atan2(y1 - y0, x1 - x0);\n}\n\n/**\n * Move a point in an angle by a distance.\n * @param x0\n * @param y0\n * @param a angle (radians)\n * @param d distance\n */\nexport function projectPoint(x0: number, y0: number, a: number, d: number) {\n return [Math.cos(a) * d + x0, Math.sin(a) * d + y0];\n}\n\n/**\n * Get the sector of an angle (e.g. quadrant, octant)\n * @param a The angle to check.\n * @param s The number of sectors to check.\n */\nexport function getSector(a: number, s = 8) {\n return Math.floor(s * (0.5 + ((a / (PI * 2)) % s)));\n}\n\n/**\n * Get a normal value representing how close two points are from being at a 45 degree angle.\n * @param x0 The x-axis coordinate of the first point.\n * @param y0 The y-axis coordinate of the first point.\n * @param x1 The x-axis coordinate of the second point.\n * @param y1 The y-axis coordinate of the second point.\n */\nexport function getAngliness(x0: number, y0: number, x1: number, y1: number) {\n return Math.abs((x1 - x0) / 2 / ((y1 - y0) / 2));\n}\n","// Credits to perfect-arrows\n// https://github.com/steveruizok/perfect-arrows/blob/master/src/lib/getArrow.ts\n\nimport { getPointBetween } from '@plait/core';\nimport { getAngle, getDistance, getAngliness, projectPoint, getSector, rotatePoint, modulate } from './utils';\n\nexport type ArrowOptions = {\n bow?: number;\n stretchMin?: number;\n stretchMax?: number;\n stretch?: number;\n padStart?: number;\n padEnd?: number;\n flip?: boolean;\n straights?: boolean;\n};\n\n/**\n * getArrow\n * Get the points for a linking line between two points.\n * @description Draw an arrow between two points.\n * @param x0 The x position of the \"from\" point.\n * @param y0 The y position of the \"from\" point.\n * @param x1 The x position of the \"to\" point.\n * @param y1 The y position of the \"to\" point.\n * @param options Additional options for computing the line.\n * @returns [sx, sy, cx, cy, e1, e2, ae, as, ac]\n * @example\n * const arrow = getArrow(0, 0, 100, 200, {\n bow: 0\n stretch: .5\n stretchMin: 0\n stretchMax: 420\n padStart: 0\n padEnd: 0\n flip: false\n straights: true\n * })\n * \n * const [\n * startX, startY, \n * controlX, controlY, \n * endX, endY, \n * endAngle, \n * startAngle,\n * controlAngle\n * ] = arrow\n */\nexport default function getArrow(x0: number, y0: number, x1: number, y1: number, options: ArrowOptions = {} as ArrowOptions): number[] {\n const { bow = 0, stretch = 0.5, stretchMin = 0, stretchMax = 420, padStart = 0, padEnd = 0, flip = false, straights = true } = options;\n\n const angle = getAngle(x0, y0, x1, y1);\n const dist = getDistance(x0, y0, x1, y1);\n const angliness = getAngliness(x0, y0, x1, y1);\n\n // Step 0 ⤜⤏ Should the arrow be straight?\n\n if (\n dist < (padStart + padEnd) * 2 || // Too short\n (bow === 0 && stretch === 0) || // No bow, no stretch\n (straights && [0, 1, Infinity].includes(angliness)) // 45 degree angle\n ) {\n // ⤜⤏ Arrow is straight! Just pad start and end points.\n\n // Padding distances\n const ps = Math.max(0, Math.min(dist - padStart, padStart));\n const pe = Math.max(0, Math.min(dist - ps, padEnd));\n\n // Move start point toward end point\n let [px0, py0] = projectPoint(x0, y0, angle, ps);\n\n // Move end point toward start point\n let [px1, py1] = projectPoint(x1, y1, angle + Math.PI, pe);\n\n // Get midpoint between new points\n const [mx, my] = getPointBetween(px0, py0, px1, py1, 0.5);\n\n return [px0, py0, mx, my, px1, py1, angle, angle, angle];\n }\n\n // ⤜⤏ Arrow is an arc!\n\n // Is the arc clockwise or counterclockwise?\n let rot = (getSector(angle) % 2 === 0 ? 1 : -1) * (flip ? -1 : 1);\n\n // Calculate how much the line should \"bow\" away from center\n const arc = bow + modulate(dist, [stretchMin, stretchMax], [1, 0], true) * stretch;\n\n // Step 1 ⤜⤏ Find padded points.\n\n // Get midpoint.\n const [mx, my] = getPointBetween(x0, y0, x1, y1, 0.5);\n\n // Get control point.\n let [cx, cy] = getPointBetween(x0, y0, x1, y1, 0.5 - arc);\n\n // Rotate control point (clockwise or counterclockwise).\n [cx, cy] = rotatePoint(cx, cy, mx, my, (Math.PI / 2) * rot);\n\n // Get padded start point.\n const a0 = getAngle(x0, y0, cx, cy);\n const [px0, py0] = projectPoint(x0, y0, a0, padStart);\n\n // Get padded end point.\n const a1 = getAngle(x1, y1, cx, cy);\n const [px1, py1] = projectPoint(x1, y1, a1, padEnd);\n\n // Step 2 ⤜⤏ Find start and end angles.\n\n // Start angle\n const as = getAngle(cx, cy, x0, y0);\n\n // End angle\n const ae = getAngle(cx, cy, x1, y1);\n\n // Step 3 ⤜⤏ Find control point for padded points.\n\n // Get midpoint between padded start / end points.\n const [mx1, my1] = getPointBetween(px0, py0, px1, py1, 0.5);\n\n // Get control point for padded start / end points.\n let [cx1, cy1] = getPointBetween(px0, py0, px1, py1, 0.5 - arc);\n\n // Rotate control point (clockwise or counterclockwise).\n [cx1, cy1] = rotatePoint(cx1, cy1, mx1, my1, (Math.PI / 2) * rot);\n\n // Finally, average the two control points.\n let [cx2, cy2] = getPointBetween(cx, cy, cx1, cy1, 0.5);\n\n return [px0, py0, cx2, cy2, px1, py1, ae, as, angle];\n}\n","import { EdgeDirection, NodeStyles } from '../types';\nimport { PlaitBoard, Point, createForeignObject, createG, createPath, drawCircle, normalizePoint } from '@plait/core';\nimport getArrow from '../../perfect-arrows/get-arrow';\nimport {\n ACTIVE_BACKGROUND_NODE_ALPHA,\n DEFAULT_ACTIVE_NODE_SIZE_MULTIPLIER,\n DEFAULT_ACTIVE_WAVE_NODE_SIZE_MULTIPLIER,\n DEFAULT_EDGE_PARTICLE_SIZE,\n DEFAULT_LINE_STYLES,\n DEFAULT_NODE_LABEL_HEIGHT,\n DEFAULT_NODE_LABEL_STYLE,\n DEFAULT_NODE_LABEL_WIDTH,\n DEFAULT_NODE_SIZE,\n DEFAULT_NODE_STYLES,\n NODE_LABEL_CLASS_NAME,\n SECOND_DEPTH_NODE_ALPHA\n} from '../constants';\nimport { DEFAULT_STYLES } from '../../constants/default';\nimport { ForceAtlasNodeElement } from '../../interfaces';\n\nexport function drawNode(\n board: PlaitBoard,\n node: ForceAtlasNodeElement,\n point: Point,\n options: { iconG?: SVGGElement; isActive: boolean; opacity?: number }\n) {\n const roughSVG = PlaitBoard.getRoughSVG(board);\n const nodeStyles: NodeStyles = {\n ...DEFAULT_NODE_STYLES,\n ...(node.styles || {})\n };\n let { x, y } = normalizePoint(point);\n let diameter = node.size ?? DEFAULT_NODE_SIZE;\n if (options.isActive) {\n diameter = diameter * DEFAULT_ACTIVE_NODE_SIZE_MULTIPLIER;\n }\n const nodeG = drawCircle(roughSVG, [x, y], diameter, nodeStyles);\n const labelWidth = node.styles?.labelWidth ?? DEFAULT_NODE_LABEL_WIDTH;\n const labelHeight = node.styles?.labelHeight ?? DEFAULT_NODE_LABEL_HEIGHT;\n const textForeignObject = createForeignObject(x - labelWidth / 2, y, labelWidth, labelHeight);\n const textContainer = document.createElement('div');\n textContainer.classList.add(NODE_LABEL_CLASS_NAME);\n textContainer.setAttribute('style', DEFAULT_NODE_LABEL_STYLE);\n const text = document.createElement('span');\n text.innerText = node.label;\n textContainer.append(text);\n textForeignObject.append(textContainer);\n if (options.isActive) {\n const waveDiameter = diameter * DEFAULT_ACTIVE_WAVE_NODE_SIZE_MULTIPLIER;\n const waveCircle = drawCircle(roughSVG, [x, y], waveDiameter, nodeStyles);\n waveCircle.setAttribute('opacity', ACTIVE_BACKGROUND_NODE_ALPHA.toString());\n nodeG.append(waveCircle);\n textForeignObject.setAttribute('y', `${y + waveDiameter / 2}`);\n } else {\n textForeignObject.setAttribute('y', `${y + diameter / 2}`);\n nodeG.setAttribute('opacity', (options.opacity ?? 1).toString());\n }\n if (options.iconG) {\n nodeG.append(options.iconG);\n }\n nodeG.append(textForeignObject);\n return nodeG;\n}\n\nexport function drawEdge(startPoint: Point, endPoint: Point, direction: EdgeDirection, isMutual: boolean, isTargetSelf?: boolean) {\n const nodeRadius = DEFAULT_NODE_SIZE / 2;\n const arrow = getArrow(startPoint[0], startPoint[1], endPoint[0], endPoint[1], {\n stretch: 0.4,\n flip: direction === EdgeDirection.NONE ? false : isMutual,\n padEnd: nodeRadius,\n padStart: nodeRadius\n });\n const [sx, sy, cx, cy, ex, ey, ae, as, ec] = arrow;\n const g = createG();\n const path = createPath();\n if (!isTargetSelf) {\n path.setAttribute('d', `M${sx},${sy} Q${cx},${cy} ${ex},${ey}`);\n } else {\n const x = startPoint[0];\n const y = startPoint[1];\n const besselX = 40;\n const besselY = 75;\n const angle = 55;\n const angleRad = (angle * Math.PI) / 180;\n const offsetX = nodeRadius * Math.cos(angleRad);\n const offsetY = nodeRadius * Math.sin(angleRad);\n path.setAttribute(\n 'd',\n `M ${x - offsetX},${y - offsetY}\n C ${x - besselX},${y - besselY}, ${x + besselX} ${y - besselY}\n ${x + offsetX},${y - offsetY}`\n );\n }\n path.setAttribute('fill', 'none');\n path.setAttribute('stroke', DEFAULT_LINE_STYLES.color[direction]);\n path.setAttribute('opacity', DEFAULT_LINE_STYLES.opacity[direction].toString());\n g.append(path);\n return {\n g,\n path\n };\n}\n\nexport function drawParticle(board: PlaitBoard, startPoint: Point, direction: EdgeDirection) {\n const roughSVG = PlaitBoard.getRoughSVG(board);\n const pointG = drawCircle(roughSVG, [0, 0], DEFAULT_EDGE_PARTICLE_SIZE, {\n ...DEFAULT_STYLES,\n strokeWidth: 0,\n fill: DEFAULT_LINE_STYLES.color[direction]\n });\n pointG.setAttribute('transform', `translate(${startPoint[0]}, ${startPoint[1]})`);\n return pointG;\n}\n","import { PlaitBoard, createG } from '@plait/core';\nimport { Generator } from '@plait/common';\nimport { ForceAtlasEdgeElement } from '../../interfaces';\nimport { EdgeDirection, EdgeGeneratorData } from '../types';\nimport { drawEdge, drawParticle } from '../utils/draw';\nimport { playEdgeParticleAnimate } from '../utils/edge';\n\nexport class ForceAtlasEdgeGenerator extends Generator<ForceAtlasEdgeElement, EdgeGeneratorData> {\n static key = 'force-atlas-edge';\n particleAnimation?: { stop: () => void; start: () => void };\n constructor(board: PlaitBoard) {\n super(board);\n }\n\n canDraw(element: ForceAtlasEdgeElement): boolean {\n return true;\n }\n\n draw(element: ForceAtlasEdgeElement, data: EdgeGeneratorData) {\n const edgeG = createG();\n const edgeElement = drawEdge(\n data.startPoint,\n data.endPoint,\n data.direction,\n data.isSourceActive && data.isTargetActive,\n data.isTargetSelf\n );\n edgeG.append(edgeElement.g);\n if (data.direction !== EdgeDirection.NONE) {\n const particle = drawParticle(this.board, data.startPoint, data.direction);\n edgeElement.g.append(particle);\n this.particleAnimation = playEdgeParticleAnimate(edgeElement.path, particle);\n }\n return edgeG;\n }\n\n destroy(): void {\n super.destroy();\n this.particleAnimation?.stop();\n }\n}\n","import { PlaitBoard, PlaitElement, PlaitNode, getSelectedElements } from '@plait/core';\nimport { ForceAtlasEdgeElement, ForceAtlasElement, ForceAtlasNodeElement } from '../../interfaces';\nimport { EdgeDirection, EdgeGeneratorData } from '../types';\nimport { PlaitCommonElementRef, animate, linear } from '@plait/common';\nimport { ForceAtlasEdgeGenerator } from '../generators/edge.generator';\nimport { getIsNodeActive, getNodeById } from './node';\n\nexport function getEdges(forceAtlasElement: ForceAtlasElement, andCallBack?: (edge: ForceAtlasEdgeElement) => boolean) {\n return forceAtlasElement.children?.filter(\n f => ForceAtlasElement.isForceAtlasEdgeElement(f) && (andCallBack?.(f) ?? true)\n ) as ForceAtlasEdgeElement[];\n}\n\nexport function getEdgeById(id: string, forceAtlasElement: ForceAtlasElement) {\n const edge = getEdges(forceAtlasElement, e => e.id === id)?.[0];\n if (!edge) {\n throw new Error('can not find edge.');\n }\n return edge;\n}\n\nexport function getEdgesInSourceOrTarget(id: string, forceAtlasElement: ForceAtlasElement) {\n const edges = getEdges(forceAtlasElement, edge => edge.source === id || edge.target === id);\n return edges;\n}\n\nexport function getEdgeGenerator(edge: ForceAtlasEdgeElement) {\n const edgeRef = PlaitElement.getElementRef<PlaitCommonElementRef>(edge);\n return edgeRef.getGenerator<ForceAtlasEdgeGenerator>(ForceAtlasEdgeGenerator.key);\n}\n\nexport function getEdgeDirection(isSourceActive: boolean, isTargetActive: boolean) {\n if (isSourceActive) {\n return EdgeDirection.OUT;\n } else if (isTargetActive) {\n return EdgeDirection.IN;\n }\n return EdgeDirection.NONE;\n}\n\nexport function getEdgeGeneratorData(edge: ForceAtlasEdgeElement, board: PlaitBoard): EdgeGeneratorData {\n const forceAtlasElement = PlaitNode.parent(board, PlaitBoard.findPath(board, edge)) as ForceAtlasElement;\n const sourceNode = getNodeById(edge.source, forceAtlasElement);\n const targetNode = getNodeById(edge.target, forceAtlasElement);\n if (!sourceNode?.points || !targetNode?.points) {\n throw new Error(\"Source or target node doesn't have points\");\n }\n const startPoint = sourceNode.points[0];\n const endPoint = targetNode.points[0];\n const selectElements = getSelectedElements(board) as ForceAtlasNodeElement[];\n const isSourceActive = getIsNodeActive(sourceNode.id, selectElements);\n const isTargetActive = getIsNodeActive(targetNode.id, selectElements);\n const direction = getEdgeDirection(isSourceActive, isTargetActive);\n\n return {\n startPoint,\n endPoint,\n direction,\n isSourceActive,\n isTargetActive,\n isTargetSelf: sourceNode.id === targetNode.id\n };\n}\n\nexport function playEdgeParticleAnimate(path: SVGPathElement, pointG: SVGGElement) {\n const pathLength = path.getTotalLength();\n let anim = animate(\n (t: number) => {\n const point = path.getPointAtLength(t * pathLength);\n pointG.setAttribute('transform', `translate(${point.x}, ${point.y})`);\n },\n 1000,\n linear,\n () => {\n anim = playEdgeParticleAnimate(path, pointG);\n }\n );\n return {\n stop: () => {\n anim.stop();\n },\n start: () => {\n anim.start();\n }\n };\n}\n","import { PlaitElement, Point, RectangleClient, normalizePoint } from '@plait/core';\nimport { ForceAtlasElement, ForceAtlasNodeElement } from '../../interfaces';\nimport { getEdges, getEdgesInSourceOrTarget } from './edge';\nimport { PlaitCommonElementRef } from '@plait/common';\nimport { ForceAtlasNodeGenerator } from '../generators/node.generator';\nimport { DEFAULT_NODE_ICON_COLOR, NODE_ICON_FONT_SIZE } from '../constants';\n\nexport function getNodes(forceAtlasElement: ForceAtlasElement, andBack?: (edge: ForceAtlasNodeElement) => boolean) {\n return forceAtlasElement.children?.filter(\n f => ForceAtlasElement.isForceAtlasNodeElement(f) && (andBack?.(f) ?? true)\n ) as ForceAtlasNodeElement[];\n}\n\nexport function getNodeById(id: string, forceAtlasElement: ForceAtlasElement) {\n const node = getNodes(forceAtlasElement, node => node.id === id)?.[0];\n if (!node) {\n throw new Error('can not find node.');\n }\n return node;\n}\n\nexport function getIsNodeActive(id: string, selectElements: ForceAtlasNodeElement[]) {\n return selectElements.some(node => node.id === id);\n}\n\nexport function isHitNode(node: ForceAtlasNodeElement, point: [Point, Point]) {\n const { x, y } = normalizePoint(node.points![0]);\n const size = node.size!;\n const hitFlowNode = RectangleClient.isHit(RectangleClient.getRectangleByPoints(point), {\n x: x - size / 2,\n y: y - size / 2,\n width: size,\n height: size\n });\n return hitFlowNode;\n}\n\nexport function getAssociatedNodesById(id: string, forceAtlasElement: ForceAtlasElement) {\n const edges = getEdgesInSourceOrTarget(id, forceAtlasElement);\n const nodes: ForceAtlasNodeElement[] = [];\n edges.forEach(edge => {\n nodes.push(getNodeById(edge.source, forceAtlasElement));\n nodes.push(getNodeById(edge.target, forceAtlasElement));\n });\n return nodes;\n}\n\nexport function getNodeGenerator(node: ForceAtlasNodeElement) {\n const edgeRef = PlaitElement.getElementRef<PlaitCommonElementRef>(node);\n return edgeRef.getGenerator<ForceAtlasNodeGenerator>(ForceAtlasNodeGenerator.key);\n}\n\nexport function isFirstDepthNode(currentNodeId: string, activeNodeId: string, forceAtlasElement: ForceAtlasElement) {\n const edges = getEdges(forceAtlasElement);\n return edges.some(\n s => (s.source === activeNodeId && s.target === currentNodeId) || (s.target === activeNodeId && s.source === currentNodeId)\n );\n}\n\nexport function getNodeIcon(node: ForceAtlasNodeElement) {\n const iconItem = typeof node.icon === 'object' && node.icon.name ? node.icon : null;\n return {\n name: iconItem ? iconItem.name : (node.icon as string),\n fontSize: (iconItem && iconItem.fontSize) || NODE_ICON_FONT_SIZE,\n color: (iconItem && iconItem.color) || DEFAULT_NODE_ICON_COLOR\n };\n}\n","import { PlaitBoard, createForeignObject, createG, normalizePoint } from '@plait/core';\nimport { Generator, RenderComponentRef } from '@plait/common';\nimport { ForceAtlasNodeElement } from '../../interfaces';\nimport { drawNode } from '../utils/draw';\nimport { NodeGeneratorData } from '../types';\nimport { ForceAtlasNodeIconBoard, NodeIconProps } from '../with-node-icon';\nimport { ACTIVE_NODE_ICON_CLASS_NAME, ACTIVE_NODE_ICON_FONT_SIZE, NODE_ICON_CLASS_NAME } from '../constants';\nimport { getNodeIcon } from '../utils/node';\n\nexport class ForceAtlasNodeGenerator extends Generator<ForceAtlasNodeElement, NodeGeneratorData> {\n static key = 'force-atlas-node';\n\n constructor(board: PlaitBoard) {\n super(board);\n }\n\n canDraw(element: ForceAtlasNodeElement): boolean {\n return true;\n }\n\n draw(element: ForceAtlasNodeElement, data: NodeGeneratorData) {\n const iconRef = this.drawIcon(element, data);\n return drawNode(this.board, element, element?.points?.[0] || [0, 0], { ...data, iconG: iconRef.iconG });\n }\n\n drawIcon(element: ForceAtlasNodeElement, data: NodeGeneratorData) {\n const iconG = createG();\n let { x, y } = normalizePoint(element.points?.[0] || [0, 0]);\n const size = element.size!;\n const foreignObject = createForeignObject(x - size / 2, y - size / 2, size, size);\n iconG.append(foreignObject);\n const container = document.createElement('div');\n container.classList.add(NODE_ICON_CLASS_NAME);\n if (data.isActive) {\n container.classList.add(ACTIVE_NODE_ICON_CLASS_NAME);\n }\n foreignObject.append(container);\n const nodeIcon = getNodeIcon(element);\n const props: NodeIconProps = {\n iconItem: {\n name: nodeIcon.name,\n fontSize: data.isActive ? ACTIVE_NODE_ICON_FONT_SIZE : nodeIcon.fontSize,\n color: nodeIcon.color\n },\n board: this.board,\n element: element\n };\n const ref = ((this.board as unknown) as ForceAtlasNodeIconBoard).renderNodeIcon(container, props);\n return { ref, iconG };\n }\n}\n","import { CommonElementFlavour } from '@plait/common';\nimport {\n OnContextChanged,\n PlaitBoard,\n PlaitNode,\n PlaitPluginElementContext,\n cacheSelectedElements,\n getSelectedElements\n} from '@plait/core';\nimport Graph from 'graphology';\nimport { ForceAtlasElement, ForceAtlasNodeElement } from '../interfaces';\nimport { ForceAtlasNodeGenerator } from './generators/node.generator';\nimport { getEdgeGenerator, getEdgeGeneratorData, getEdgesInSourceOrTarget } from './utils/edge';\nimport { getNodeGenerator, getNodes, isFirstDepthNode } from './utils/node';\nimport { SECOND_DEPTH_NODE_ALPHA } from './constants';\n\nexport class ForceAtlasNodeFlavour extends CommonElementFlavour<ForceAtlasNodeElement, PlaitBoard>\n implements OnContextChanged<ForceAtlasNodeElement, PlaitBoard> {\n graph!: Graph<Node>;\n nodeGenerator!: ForceAtlasNodeGenerator;\n\n constructor() {\n super();\n }\n\n initializeGenerator() {\n this.nodeGenerator = new ForceAtlasNodeGenerator(this.board);\n this.getRef().addGenerator(ForceAtlasNodeGenerator.key, this.nodeGenerator);\n }\n\n initialize(): void {\n super.initialize();\n this.initializeGenerator();\n const parent = PlaitNode.parent(this.board, PlaitBoard.findPath(this.board, this.element)) as ForceAtlasElement;\n const selectElements = getSelectedElements(this.board);\n const activeNodeId = selectElements[0]?.id;\n const isActive = activeNodeId === this.element.id;\n this.nodeGenerator.processDrawing(this.element, this.getElementG(), {\n isActive,\n opacity: isFirstDepthNode(this.element.id, activeNodeId, parent) ? 1 : SECOND_DEPTH_NODE_ALPHA\n });\n }\n\n onContextChanged(\n value: PlaitPluginElementContext<ForceAtlasNodeElement, PlaitBoard>,\n previous: PlaitPluginElementContext<ForceAtlasNodeElement, PlaitBoard>\n ) {\n if (value !== previous && value.selected !== previous.selected) {\n const parent = value.parent as any;\n if (value.selected) {\n cacheSelectedElements(this.board, [value.element]);\n }\n const selectElements = getSelectedElements(this.board);\n const nodes = getNodes(parent);\n nodes.forEach(node => {\n const nodeGenerator = getNodeGenerator(node);\n nodeGenerator.destroy();\n const isFirstDepth = selectElements.length > 0 && isFirstDepthNode(node.id, selectElements[0].id, parent);\n nodeGenerator.processDrawing(node, this.getElementG(), {\n isActive: selectElements?.[0]?.id === node.id,\n opacity: selectElements.length === 0 ? 1 : isFirstDepth ? 1 : SECOND_DEPTH_NODE_ALPHA\n });\n });\n\n const associatedEdges = getEdgesInSourceOrTarget(value.element.id, parent);\n associatedEdges.forEach(edge => {\n const edgeGenerator = getEdgeGenerator(edge);\n edgeGenerator.destroy();\n edgeGenerator.processDrawing(edge, PlaitBoard.getElementLowerHost(this.board), getEdgeGeneratorData(edge, this.board));\n });\n }\n }\n\n updateText(previousElement: ForceAtlasNodeElement, currentElement: ForceAtlasNodeElement) {}\n\n destroy(): void {\n super.destroy();\n }\n}\n","import { CommonElementFlavour } from '@plait/common';\nimport { OnContextChanged, PlaitBoard, PlaitPluginElementContext } from '@plait/core';\nimport Graph from 'graphology';\nimport { ForceAtlasEdgeElement } from '../interfaces';\nimport { ForceAtlasEdgeGenerator } from './generators/edge.generator';\nimport { getEdgeGeneratorData } from './utils/edge';\n\nexport class ForceAtlasEdgeFlavour extends CommonElementFlavour<ForceAtlasEdgeElement, PlaitBoard>\n implements OnContextChanged<ForceAtlasEdgeElement, PlaitBoard> {\n graph!: Graph<Node>;\n edgeGenerator!: ForceAtlasEdgeGenerator;\n\n constructor() {\n super();\n }\n\n initializeGenerator() {\n this.edgeGenerator = new ForceAtlasEdgeGenerator(this.board);\n this.getRef().addGenerator(ForceAtlasEdgeGenerator.key, this.edgeGenerator);\n }\n\n initialize(): void {\n super.initialize();\n this.initializeGenerator();\n this.edgeGenerator.processDrawing(\n this.element,\n PlaitBoard.getElementLowerHost(this.board),\n getEdgeGeneratorData(this.element, this.board)\n );\n }\n\n onContextChanged(\n value: PlaitPluginElementContext<ForceAtlasEdgeElement, PlaitBoard>,\n previous: PlaitPluginElementContext<ForceAtlasEdgeElement, PlaitBoard>\n ) {}\n\n updateText(previousElement: ForceAtlasEdgeElement, currentElement: ForceAtlasEdgeElement) {}\n\n destroy(): void {\n super.destroy();\n this.edgeGenerator.destroy();\n }\n}\n","import { PlaitBoard } from '@plait/core';\nimport { ForceAtlasNodeElement } from '../interfaces/element';\nimport { RenderComponentRef } from '@plait/common';\nimport { NodeIconItem } from './types';\n\nexport interface ForceAtlasNodeIconBoard {\n renderNodeIcon: (container: Element | DocumentFragment, props: NodeIconProps) => RenderComponentRef<NodeIconProps>;\n}\n\nexport const withNodeIcon = <T extends PlaitBoard = PlaitBoard>(board: T) => {\n const newBoard = board as T & ForceAtlasNodeIconBoard;\n\n newBoard.renderNodeIcon = (container: Element | DocumentFragment, props: NodeIconProps) => {\n throw new Error('No implementation for renderLabeIcon method.');\n };\n return newBoard;\n};\n\nexport interface NodeIconProps {\n board: PlaitBoard;\n iconItem: NodeIconItem;\n element: ForceAtlasNodeElement;\n}\n","import {\n isHitElement,\n PlaitBoard,\n PlaitElement,\n PlaitOptionsBoard,\n PlaitPluginElementContext,\n PlaitPluginKey,\n PlaitPointerType,\n Point,\n RectangleClient,\n Selection,\n setSelectionOptions,\n toHostPoint,\n toViewBoxPoint,\n WithHandPluginOptions\n} from '@plait/core';\nimport { ForceAtlasFlavour } from './force-atlas.flavour';\nimport { ForceAtlasNodeFlavour } from './node.flavour';\nimport { ForceAtlasEdgeFlavour } from './edge.flavour';\nimport { ForceAtlasElement } from '../interfaces';\nimport { isHitNode } from './utils/node';\nimport { withNodeIcon } from './with-node-icon';\n\nexport const withForceAtlas = (board: PlaitBoard) => {\n const { drawElement, getRectangle, isRectangleHit, isHit, isInsidePoint, isMovable, isAlign, getRelatedFragment } = board;\n\n board.drawElement = (context: PlaitPluginElementContext) => {\n if (ForceAtlasElement.isForceAtlas(context.element)) {\n return ForceAtlasFlavour;\n } else if (ForceAtlasElement.isForceAtlasNodeElement(context.element)) {\n return ForceAtlasNodeFlavour;\n } else if (ForceAtlasElement.isForceAtlasEdgeElement(context.element)) {\n return ForceAtlasEdgeFlavour;\n }\n return drawElement(context);\n };\n\n board.getRectangle = (element: PlaitElement) => {\n if (element.type === 'force-atlas') {\n return {\n width: 0,\n height: 0,\n x: 0,\n y: 0\n };\n } else if (ForceAtlasElement.isForceAtlasNodeElement(element)) {\n return RectangleClient.getRectangleByPoints(element.points || []);\n } else if (ForceAtlasElement.isForceAtlasEdgeElement(element)) {\n return {\n width: 0,\n height: 0,\n x: 0,\n y: 0\n };\n }\n return getRectangle(element);\n };\n\n board.isRectangleHit = (element: PlaitElement, selection: Selection) => {\n return isRectangleHit(element, selection);\n };\n board.isRectangleHit = (element, range) => {\n if (ForceAtlasElement.isForceAtlasNodeElement(element)) {\n return isHitNode(element, [range.anchor, range.focus]);\n }\n return isRectangleHit(element, range);\n };\n\n board.isHit = (element, point) => {\n if (ForceAtlasElement.isForceAtlasNodeElement(element)) {\n return isHitNode(element, [point, point]);\n }\n return isHit(element, point);\n };\n\n board.isInsidePoint = (element: PlaitElement, point: Point) => {\n return isInsidePoint(element, point);\n };\n\n setSelectionOptions(board, { isMultipleSelection: false, isPreventClearSelection: true });\n\n (board as PlaitOptionsBoard).setPluginOptions<WithHandPluginOptions>(PlaitPluginKey.withHand, {\n isHandMode: (board, event) => {\n const point = toViewBoxPoint(board, toHostPoint(board, event.x, event.y));\n const isHitTarget = isHitElement(board, point);\n return PlaitBoard.isPointer(board, PlaitPointerType.selection) && !isHitTarget;\n }\n });\n\n return withNodeIcon(board);\n};\n","import { PlaitBoard } from '@plait/core';\nimport { ForceAtlasNodeElement } from '../../interfaces/element';\nimport { DEFAULT_NODE_ICON_COLOR, NODE_ICON_CLASS_NAME, NODE_ICON_FONT_SIZE } from '../constants';\nimport { NodeIconItem } from '../types';\n\nexport abstract class ForceAtlasNodeIconBaseComponent {\n iconItem!: NodeIconItem;\n\n board!: PlaitBoard;\n\n element!: ForceAtlasNodeElement;\n\n abstract nativeElement(): HTMLElement;\n\n initialize() {\n if (!this.iconItem.fontSize) {\n this.iconItem.fontSize = NODE_ICON_FONT_SIZE;\n }\n if (!this.iconItem.color) {\n this.iconItem.color = DEFAULT_NODE_ICON_COLOR;\n }\n this.nativeElement().style.fontSize = `${this.iconItem.fontSize}px`;\n this.nativeElement().style.color = `${this.iconItem.color}`;\n this.nativeElement().classList.add(NODE_ICON_CLASS_NAME);\n }\n}\n","/*\n * Public API Surface of utils\n */\n\nexport * from './force-atlas/constants';\nexport * from './force-atlas/types';\nexport * from './force-atlas/with-force-atlas';\nexport * from './force-atlas/with-node-icon';\nexport * from './interfaces/index';\nexport * from './force-atlas/core/node-icon-base.component';\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":";;;;;;AAEO,MAAM,cAAc,GAAY;AACnC,IAAA,SAAS,EAAE,OAAO;AAClB,IAAA,WAAW,EAAE;CAChB;;ICFW;AAAZ,CAAA,UAAY,aAAa,EAAA;AACrB,IAAA,aAAA,CAAA,aAAA,CAAA,IAAA,CAAA,GAAA,CAAA,CAAA,GAAA,IAAE;AACF,IAAA,aAAA,CAAA,aAAA,CAAA,KAAA,CAAA,GAAA,CAAA,CAAA,GAAA,KAAG;AACH,IAAA,aAAA,CAAA,aAAA,CAAA,MAAA,CAAA,GAAA,CAAA,CAAA,GAAA,MAAI;AACR,CAAC,EAJW,aAAa,KAAb,aAAa,GAAA,EAAA,CAAA,CAAA;;ACClB,MAAM,mBAAmB,GAAY;AACxC,IAAA,GAAG,cAAc;AACjB,IAAA,MAAM,EAAE;;AAGL,MAAM,iBAAiB,GAAG;AAE1B,MAAM,mCAAmC,GAAG;AAE5C,MAAM,wCAAwC,GAAG;AAEjD,MAAM,6BAA6B,GAAG;AAEtC,MAAM,4BAA4B,GAAG;AAErC,MAAM,wBAAwB,GAAG;AAEjC,MAAM,yBAAyB,GAAG;AAElC,MAAM,wBAAwB,GAAG,CAAA,2BAAA,EAA8B,wBAAwB,CAAA,iCAAA,EAAoC,yBAAyB,CAAA,aAAA,EAAgB,4BAA4B,CAAA,6DAAA;AAEhM,MAAM,qBAAqB,GAAG;AAE9B,MAAM,uBAAuB,GAAG;AAEhC,MAAM,uBAAuB,GAAG;AAEhC,MAAM,4BAA4B,GAAG;AAErC,MAAM,oBAAoB,GAAG;AAE7B,MAAM,2BAA2B,GAAG;AAEpC,MAAM,mBAAmB,GAAG;AAE5B,MAAM,0BAA0B,GAAG;AAEnC,MAAM,6BAA6B,GAAG;AAEtC,MAAM,uBAAuB,GAAG;AAEhC,MAAM,mBAAmB,GAAY;AACxC,IAAA,GAAG,cAAc;AACjB,IAAA,IAAI,EAAE,6BAA6B;AACnC,IAAA,WAAW,EAAE;;AAGV,MAAM,0BAA0B,GAAG;AAEnC,MAAM,mBAAmB,GAAG;AAC/B,IAAA,KAAK,EAAE;AACH,QAAA,CAAC,aAAa,CAAC,EAAE,GAAG,SAAS;AAC7B,QAAA,CAAC,aAAa,CAAC,GAAG,GAAG,SAAS;AAC9B,QAAA,CAAC,aAAa,CAAC,IAAI,GAAG,CAAA,IAAA;AACzB,KAAA;AACD,IAAA,OAAO,EAAE;AACL,QAAA,CAAC,aAAa,CAAC,EAAE,GAAG,GAAG;AACvB,QAAA,CAAC,aAAa,CAAC,GAAG,GAAG,GAAG;AACxB,QAAA,CAAC,aAAa,CAAC,IAAI,GAAG;AACzB;;AAGE,MAAM,0BAA0B,GAAG;;AChDnC,MAAM,iBAAiB,GAAG;AAC7B,IAAA,YAAY,EAAE,CAAC,KAAU,KAAI;AACzB,QAAA,OAAO,KAAK,EAAE,IAAI,KAAK,aAAa;IACxC,CAAC;AACD,IAAA,uBAAuB,EAAE,CAAC,KAAU,KAAoC;QACpE,OAAO,KAAK,IAAI,KAAK,CAAC,KAAK,IAAI,KAAK,CAAC,IAAI;IAC7C,CAAC;AACD,IAAA,uBAAuB,EAAE,CAAC,KAAU,KAAoC;QACpE,OAAO,KAAK,IAAI,KAAK,CAAC,MAAM,IAAI,KAAK,CAAC,MAAM;IAChD;;;ACnBE,MAAO,iBAAkB,SAAQ,oBAAmD,CAAA;AAItF,IAAA,WAAA,GAAA;AACI,QAAA,KAAK,EAAE;IACX;IAEA,eAAe,GAAA;AACX,QAAA,IAAI,CAAC,KAAK,GAAG,IAAI,KAAK,EAAyB;QAC/C,IAAI,CAAC,OAAO,CAAC,QAAQ,EAAE,OAAO,CAAC,KAAK,IAAG;AACnC,YAAA,IAAI,iBAAiB,CAAC,uBAAuB,CAAC,KAAK,CAAC,EAAE;AAClD,gBAAA,IAAI,OAAO,KAAK,EAAE,IAAI,KAAK,WAAW,EAAE;AACpC,oBAAA,KAAK,CAAC,IAAI,GAAG,iBAAiB;gBAClC;AACA,gBAAA,IAAI,KAAK,CAAC,QAAQ,EAAE;oBAChB,qBAAqB,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC,KAAK,CAAC,CAAC;gBAC9C;gBACA,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,EAAE,KAAK,CAAC;YACvC;AAAO,iBAAA,IAAI,iBAAiB,CAAC,uBAAuB,CAAC,KAAK,CAAC,EAAE;AACzD,gBAAA,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,MAAM,EAAE,KAAK,CAAC,MAAM,CAAC;YAClD;AACJ,QAAA,CAAC,CAAC;AACF,QAAA,QAAQ,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC;QAC3B,MAAM,SAAS,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC,MAAM;QAC3C,MAAM,QAAQ,GAAG,WAAW,CAAC,aAAa,CAAC,IAAI,CAAC,KAAK,CAAC;AACtD,QAAA,QAAQ,CAAC,YAAY,GAAG,GAAG;AAC3B,QAAA,IAAI,SAAS,GAAG,CAAC,EAAE;AACf,YAAA,QAAQ,CAAC,OAAO,GAAG,GAAG;AACtB,YAAA,QAAQ,CAAC,WAAW,GAAG,KAAK;QAChC;aAAO;AACH,YAAA,QAAQ,CAAC,OAAO,GAAG,CAAC;AACpB,YAAA,QAAQ,CAAC,WAAW,GAAG,IAAI;QAC/B;AACA,QAAA,MAAM,SAAS,GAAG,WAAW,CAAC,IAAI,CAAC,KAAK,EAAE,EAAE,UAAU,EAAE,GAAG,EAAE,QAAQ,EAAE,CAAC;QACxE,IAAI,CAAC,OAAO,CAAC,QAAQ,EAAE,OAAO,CAAC,KAAK,IAAG;AACnC,YAAA,IAAI,iBAAiB,CAAC,uBAAuB,CAAC,KAAK,CAAC,EAAE;gBAClD,MAAM,GAAG,GAAG,SAAS,CAAC,KAAK,CAAC,EAAE,CAAC;AAC/B,gBAAA,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC;YACnC;AACJ,QAAA,CAAC,CAAC;IACN;IAEA,UAAU,GAAA;QACN,KAAK,CAAC,UAAU,EAAE;QAClB,IAAI,CAAC,eAAe,EAAE;IAC1B;AAEA,IAAA,gBAAgB,CACZ,KAA+D,EAC/D,QAAkE,IACnE;AAEH,IAAA,UAAU,CAAC,eAAkC,EAAE,cAAiC,IAAG;IAEnF,OAAO,GAAA;QACH,KAAK,CAAC,OAAO,EAAE;IACnB;AACH;;AClED;AACA;AAEA,MAAM,EAAE,GAAG,IAAI,CAAC,EAAE;AAElB;;;;;;AAMG;AACG,SAAU,QAAQ,CAAC,KAAa,EAAE,MAAgB,EAAE,MAAgB,EAAE,KAAK,GAAG,KAAK,EAAA;AACrF,IAAA,MAAM,CAAC,OAAO,EAAE,QAAQ,CAAC,GAAG,MAAM;AAClC,IAAA,MAAM,CAAC,KAAK,EAAE,MAAM,CAAC,GAAG,MAAM;IAC9B,MAAM,MAAM,GAAG,KAAK,GAAG,CAAC,CAAC,KAAK,GAAG,OAAO,KAAK,QAAQ,GAAG,OAAO,CAAC,KAAK,MAAM,GAAG,KAAK,CAAC;AACpF,IAAA,IAAI,KAAK,KAAK,IAAI,EAAE;AAChB,QAAA,IAAI,KAAK,GAAG,MAAM,EAAE;AAChB,YAAA,IAAI,MAAM,GAAG,KAAK,EAAE;AAChB,gBAAA,OAAO,KAAK;YAChB;AACA,YAAA,IAAI,MAAM,GAAG,MAAM,EAAE;AACjB,gBAAA,OAAO,MAAM;YACjB;QACJ;aAAO;AACH,YAAA,IAAI,MAAM,GAAG,KAAK,EAAE;AAChB,gBAAA,OAAO,KAAK;YAChB;AACA,YAAA,IAAI,MAAM,GAAG,MAAM,EAAE;AACjB,gBAAA,OAAO,MAAM;YACjB;QACJ;IACJ;AACA,IAAA,OAAO,MAAM;AACjB;AAEA;;;;;;;AAOG;AACG,SAAU,WAAW,CAAC,CAAS,EAAE,CAAS,EAAE,EAAU,EAAE,EAAU,EAAE,KAAa,EAAA;IACnF,MAAM,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC;IACzB,MAAM,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC;AAEzB,IAAA,MAAM,EAAE,GAAG,CAAC,GAAG,EAAE;AACjB,IAAA,MAAM,EAAE,GAAG,CAAC,GAAG,EAAE;IAEjB,MAAM,EAAE,GAAG,EAAE,GAAG,CAAC,GAAG,EAAE,GAAG,CAAC;IAC1B,MAAM,EAAE,GAAG,EAAE,GAAG,CAAC,GAAG,EAAE,GAAG,CAAC;IAE1B,OAAO,CAAC,EAAE,GAAG,EAAE,EAAE,EAAE,GAAG,EAAE,CAAC;AAC7B;AAEA;;;;;;AAMG;AACG,SAAU,WAAW,CAAC,EAAU,EAAE,EAAU,EAAE,EAAU,EAAE,EAAU,EAAA;AACtE,IAAA,OAAO,IAAI,CAAC,KAAK,CAAC,EAAE,GAAG,EAAE,EAAE,EAAE,GAAG,EAAE,CAAC;AACvC;AAEA;;;;;;AAMG;AACG,SAAU,QAAQ,CAAC,EAAU,EAAE,EAAU,EAAE,EAAU,EAAE,EAAU,EAAA;AACnE,IAAA,OAAO,IAAI,CAAC,KAAK,CAAC,EAAE,GAAG,EAAE,EAAE,EAAE,GAAG,EAAE,CAAC;AACvC;AAEA;;;;;;AAMG;AACG,SAAU,YAAY,CAAC,EAAU,EAAE,EAAU,EAAE,CAAS,EAAE,CAAS,EAAA;IACrE,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,EAAE,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC;AACvD;AAEA;;;;AAIG;SACa,SAAS,CAAC,CAAS,EAAE,CAAC,GAAG,CAAC,EAAA;IACtC,OAAO,IAAI,CAAC,KAAK,CAAC,CAAC,IAAI,GAAG,IAAI,CAAC,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AACvD;AAEA;;;;;;AAMG;AACG,SAAU,YAAY,CAAC,EAAU,EAAE,EAAU,EAAE,EAAU,EAAE,EAAU,EAAA;IACvE,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,GAAG,EAAE,IAAI,CAAC,IAAI,CAAC,EAAE,GAAG,EAAE,IAAI,CAAC,CAAC,CAAC;AACpD;;AC5GA;AACA;AAgBA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA8BK;AACS,SAAU,QAAQ,CAAC,EAAU,EAAE,EAAU,EAAE,EAAU,EAAE,EAAU,EAAE,UAAwB,EAAkB,EAAA;AACvH,IAAA,MAAM,EAAE,GAAG,GAAG,CAAC,EAAE,OAAO,GAAG,GAAG,EAAE,UAAU,GAAG,CAAC,EAAE,UAAU,GAAG,GAAG,EAAE,QAAQ,GAAG,CAAC,EAAE,MAAM,GAAG,CAAC,EAAE,IAAI,GAAG,KAAK,EAAE,SAAS,GAAG,IAAI,EAAE,GAAG,OAAO;AAEtI,IAAA,MAAM,KAAK,GAAG,QAAQ,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,CAAC;AACtC,IAAA,MAAM,IAAI,GAAG,WAAW,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,CAAC;AACxC,IAAA,MAAM,SAAS,GAAG,YAAY,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,CAAC;;IAI9C,IACI,IAAI,GAAG,CAAC,QAAQ,GAAG,MAAM,IAAI,CAAC;SAC7B,GAAG,KAAK,CAAC,IAAI,OAAO,KAAK,CAAC,CAAC;AAC5B,SAAC,SAAS,IAAI,CAAC,CAAC,EAAE,CAAC,EAAE,QAAQ,CAAC,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC;MACrD;;;AAIE,QAAA,MAAM,EAAE,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,IAAI,GAAG,QAAQ,EAAE,QAAQ,CAAC,CAAC;AAC3D,QAAA,MAAM,EAAE,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,IAAI,GAAG,EAAE,EAAE,MAAM,CAAC,CAAC;;AAGnD,QAAA,IAAI,CAAC,GAAG,EAAE,GAAG,CAAC,GAAG,YAAY,CAAC,EAAE,EAAE,EAAE,EAAE,KAAK,EAAE,EAAE,CAAC;;QAGhD,IAAI,CAAC,GAAG,EAAE,GAAG,CAAC,GAAG,YAAY,CAAC,EAAE,EAAE,EAAE,EAAE,KAAK,GAAG,IAAI,CAAC,EAAE,EAAE,EAAE,CAAC;;AAG1D,QAAA,MAAM,CAAC,EAAE,EAAE,EAAE,CAAC,GAAG,eAAe,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC;AAEzD,QAAA,OAAO,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE,EAAE,EAAE,EAAE,GAAG,EAAE,GAAG,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,CAAC;IAC5D;;;AAKA,IAAA,IAAI,GAAG,GAAG,CAAC,SAAS,CAAC,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,KAAK,IAAI,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC;;IAGjE,MAAM,GAAG,GAAG,GAAG,GAAG,QAAQ,CAAC,IAAI,EAAE,CAAC,UAAU,EAAE,UAAU,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,OAAO;;;AAKlF,IAAA,MAAM,CAAC,EAAE,EAAE,EAAE,CAAC,GAAG,eAAe,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,GAAG,CAAC;;IAGrD,IAAI,CAAC,EAAE,EAAE,EAAE,CAAC,GAAG,eAAe,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,GAAG,GAAG,GAAG,CAAC;;IAGzD,CAAC,EAAE,EAAE,EAAE,CAAC,GAAG,WAAW,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,CAAC,IAAI,CAAC,EAAE,GAAG,CAAC,IAAI,GAAG,CAAC;;AAG3D,IAAA,MAAM,EAAE,GAAG,QAAQ,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,CAAC;AACnC,IAAA,MAAM,CAAC,GAAG,EAAE,GAAG,CAAC,GAAG,YAAY,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,QAAQ,CAAC;;AAGrD,IAAA,MAAM,EAAE,GAAG,QAAQ,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,CAAC;AACnC,IAAA,MAAM,CAAC,GAAG,EAAE,GAAG,CAAC,GAAG,YAAY,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,MAAM,CAAC;;;AAKnD,IAAA,MAAM,EAAE,GAAG,QAAQ,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,CAAC;;AAGnC,IAAA,MAAM,EAAE,GAAG,QAAQ,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,CAAC;;;AAKnC,IAAA,MAAM,CAAC,GAAG,EAAE,GAAG,CAAC,GAAG,eAAe,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC;;IAG3D,IAAI,CAAC,GAAG,EAAE,GAAG,CAAC,GAAG,eAAe,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,GAAG,GAAG,CAAC;;IAG/D,CAAC,GAAG,EAAE,GAAG,CAAC,GAAG,WAAW,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,CAAC,IAAI,CAAC,EAAE,GAAG,CAAC,IAAI,GAAG,CAAC;;AAGjE,IAAA,IAAI,CAAC,GAAG,EAAE,GAAG,CAAC,GAAG,eAAe,CAAC,EAAE,EAAE,EAAE,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC;AAEvD,IAAA,OAAO,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,EAAE,EAAE,EAAE,EAAE,KAAK,CAAC;AACxD;;AC9GM,SAAU,QAAQ,CACpB,KAAiB,EACjB,IAA2B,EAC3B,KAAY,EACZ,OAAqE,EAAA;IAErE,MAAM,QAAQ,GAAG,UAAU,CAAC,WAAW,CAAC,KAAK,CAAC;AAC9C,IAAA,MAAM,UAAU,GAAe;AAC3B,QAAA,GAAG,mBAAmB;AACtB,QAAA,IAAI,IAAI,CAAC,MAAM,IAAI,EAAE;KACxB;IACD,IAAI,EAAE,CAAC,EAAE,CAAC,EAAE,GAAG,cAAc,CAAC,KAAK,CAAC;AACpC,IAAA,IAAI,QAAQ,GAAG,IAAI,CAAC,IAAI,IAAI,iBAAiB;AAC7C,IAAA,IAAI,OAAO,CAAC,QAAQ,EAAE;AAClB,QAAA,QAAQ,GAAG,QAAQ,GAAG,mCAAmC;IAC7D;AACA,IAAA,MAAM,KAAK,GAAG,UAAU,CAAC,QAAQ,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,QAAQ,EAAE,UAAU,CAAC;IAChE,MAAM,UAAU,GAAG,IAAI,CAAC,MAAM,EAAE,UAAU,IAAI,wBAAwB;IACtE,MAAM,WAAW,GAAG,IAAI,CAAC,MAAM,EAAE,WAAW,IAAI,yBAAyB;AACzE,IAAA,MAAM,iBAAiB,GAAG,mBAAmB,CAAC,CAAC,GAAG,UAAU,GAAG,CAAC,EAAE,CAAC,EAAE,UAAU,EAAE,WAAW,CAAC;IAC7F,MAAM,aAAa,GAAG,QAAQ,CAAC,aAAa,CAAC,KAAK,CAAC;AACnD,IAAA,aAAa,CAAC,SAAS,CAAC,GAAG,CAAC,qBAAqB,CAAC;AAClD,IAAA,aAAa,CAAC,YAA