├── .gitignore ├── .npmignore ├── README.md ├── dist ├── d3.d.ts ├── example │ └── index.html ├── index.d.ts ├── initializeSVG.d.ts ├── links │ ├── draw-links.d.ts │ ├── link-enter.d.ts │ ├── link-exit.d.ts │ └── link-update.d.ts ├── nodes │ ├── node-enter.d.ts │ ├── node-exit.d.ts │ └── node-update.d.ts ├── prepare-data.d.ts ├── treeviz.js ├── typings.d.ts └── utils.d.ts ├── example ├── example.ts └── index.html ├── package.json ├── src ├── d3.ts ├── index.ts ├── initializeSVG.ts ├── links │ ├── draw-links.ts │ ├── link-enter.ts │ ├── link-exit.ts │ └── link-update.ts ├── nodes │ ├── node-enter.ts │ ├── node-exit.ts │ └── node-update.ts ├── prepare-data.ts ├── typings.ts ├── utils.ts └── vite-env.d.ts ├── tsconfig.json ├── vite.config.ts └── yarn.lock /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | pnpm-debug.log* 8 | lerna-debug.log* 9 | 10 | node_modules 11 | dist-ssr 12 | *.local 13 | 14 | # Editor directories and files 15 | .vscode/* 16 | !.vscode/extensions.json 17 | .idea 18 | .DS_Store 19 | *.suo 20 | *.ntvs* 21 | *.njsproj 22 | *.sln 23 | *.sw? 24 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | src/ 2 | example/ 3 | vite.config.ts 4 | tsconfig.json 5 | dist/example/ -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Treeviz 2 | 3 | [![Known Vulnerabilities](https://snyk.io/test/github/dwyl/hapi-auth-jwt2/badge.svg?targetFile=package.json)](https://snyk.io/test/github/dwyl/hapi-auth-jwt2?targetFile=package.json) 4 | [![license](https://badgen.now.sh/badge/license/MIT)](./LICENSE) 5 | 6 | This javascript module aims at providing an easy interface in order to represent tree diagrams on screen with the ability to handle dynamic data flows. The data format must be JSON. 7 | 8 | ![](https://i.imgur.com/vyB2Erg.gif) 9 | 10 | ## Installation 11 | 12 | With npm : 13 | 14 | ```Bash 15 | npm install treeviz 16 | ``` 17 | 18 | and then you can use it with : 19 | 20 | ```JavaScript 21 | import {Treeviz} from 'treeviz'; 22 | ``` 23 | 24 | Or download this zip repository in the Github Release section and link the dist/treeviz.js file in your page directly : ` 55 | ``` 56 | 57 | To update the tree visually you will just have to pass new data to the `refresh` method like this : 58 | 59 | ```JS 60 | myTree.refresh(data); 61 | myTree.refresh(data_update1); 62 | myTree.refresh(data_update2); 63 | ``` 64 | 65 | The tree will be clever enough to updates only the part of the trees that have been added or removed in the dataset, and so it won't redraw the entire tree. 66 | 67 | [Treeviz Example](https://codepen.io/pierrecapo/pen/MPbBdv) 68 | 69 | #### Hierarchical data case : 70 | 71 | ```js 72 | var hierarchical_data_example = { 73 | name: "Mom", 74 | qty: 10, 75 | children: [ 76 | { name: "Son A", qty: 3 }, 77 | { name: "Son B", qty: 7 }, 78 | ], 79 | }; 80 | 81 | var myTree = Treeviz.create({ 82 | htmlId: "tree", 83 | idKey: "name", 84 | hasFlatData: false, 85 | relationnalField: "children", 86 | }); 87 | 88 | myTree.refresh(hierarchical_data_example); 89 | ``` 90 | 91 | ## API 92 | 93 | The big part of the API is configuring the tree before passing data to it : 94 | 95 | ```JS 96 | Treeviz.create(config); 97 | ``` 98 | 99 | The table below lists all the avalaible key that the config object can have 100 | 101 | | Key | Type | Default | Definition | 102 | | -------------------------- | --------------------------------------------- | ----------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | 103 | | `htmlId` | string (Required) | | The HTML id tag on the page where the tree should be drawn. It must have a width and an height specified | 104 | | `idKey` | string | "id" | The key in a data item representing the unique identifier of a node | 105 | | `relationnalField` | string | "father" | In case of flat dataset, usually the relationnal field between each node is the field representing the father of the node, linking it to the id of the field. (See example below). | 106 | | `hasFlatData` | boolean | true | Specify whether the data passed to the tree is flat or already hierarchical | 107 | | `hasPan` | boolean | false | Toggle the ability to pan the tree | 108 | | `hasZoom` | boolean | false | Toggle the ability to zoom the tree | 109 | | `nodeWidth` | number | 160 | Width of a node in px | 110 | | `nodeHeight` | number | 100 | Height of a node in px | 111 | | `linkColor` | function | (node: NodeData) => "#ffcc80" | Color of the link | 112 | | `linkWidth` | function | (node: NodeData) => 10 | Width of the link | 113 | | `linkShape` | "quadraticBeziers" \| "orthogonal" \| "curve" | "quadraticBeziers" | Shape of the link | 114 | | `renderNode` | function | (node: NodeData) => null | HTML template for every node | 115 | | `isHorizontal` | boolean | true | Direction of the tree. If true, the tree expands from left to right. If false, it goes from top to bottom | 116 | | `onNodeClick` | function | (node: NodeData) => null | Function handling the event when someone click on it | 117 | | `onNodeMouseEnter` | function | (node: NodeData) => null | Function handling the event when someone hover a node | 118 | | `onNodeMouseLeave` | function | (node: NodeData) => null | Function handling the event when the mouse pointer leaves a node | 119 | | `mainAxisNodeSpacing` | number or "auto" | 300 | Set the distance in pixels between two depths in the tree. If the value is `auto` it will automatically display the tree to fit the size of the container. | 120 | | `secondaryAxisNodeSpacing` | number | 1.25 | Set the distance between nodes in the same level as a coefficient of node dimensions. Recommended to have the value superior to 1 | 121 | | `marginTop` | number | 1.25 | Set the margin between the SVG element and the tree | 122 | | `marginBottom` | number | 1.25 | Set the margin between the SVG element and the tree | 123 | | `marginLeft` | number | 1.25 | Set the margin between the SVG element and the tree | 124 | | `marginRight` | number | 1.25 | Set the margin between the SVG element and the tree | 125 | | `duration` | number | 600 | The duration of the animation transition between layouts | 126 | | `data` | any | | Needed for Typescript projects only to type the `NodeData` argument | 127 | 128 | And then, we have the `NodeData` type that is passed as callback of some functions: 129 | ` 130 | type NodeData { 131 | data: // the data of each item 132 | settings: // the settings object 133 | } 134 | ` 135 | 136 | ## Contributing 137 | 138 | - Clone the repo. 139 | - Run `npm install`. 140 | - Run `npm run dev`, then you can edit the files in the `./src` folder and the `./example/index.html` file. 141 | - To publish (admin rights), run `npm run build && npm publish`. 142 | 143 | ## Credits 144 | 145 | This module is based on d3 library, credit to all the contributors of this project. 146 | 147 | ## License 148 | 149 | MIT 150 | -------------------------------------------------------------------------------- /dist/d3.d.ts: -------------------------------------------------------------------------------- 1 | import { hierarchy, stratify, tree, treemap } from "d3-hierarchy"; 2 | import { select, selectAll } from "d3-selection"; 3 | import { zoom } from "d3-zoom"; 4 | declare const _default: { 5 | hierarchy: typeof hierarchy; 6 | stratify: typeof stratify; 7 | tree: typeof tree; 8 | treemap: typeof treemap; 9 | select: typeof select; 10 | selectAll: typeof selectAll; 11 | zoom: typeof zoom; 12 | }; 13 | export default _default; 14 | -------------------------------------------------------------------------------- /dist/example/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 |
16 | 17 | 18 | 25 | 26 | -------------------------------------------------------------------------------- /dist/index.d.ts: -------------------------------------------------------------------------------- 1 | import { ITreeConfig } from "./typings"; 2 | export declare const Treeviz: { 3 | create: typeof create; 4 | }; 5 | declare function create(userSettings: Partial): { 6 | refresh: (data: any, newSettings?: Partial) => void; 7 | clean: (keepConfig: boolean) => void; 8 | }; 9 | export {}; 10 | -------------------------------------------------------------------------------- /dist/initializeSVG.d.ts: -------------------------------------------------------------------------------- 1 | import { ITreeConfig } from "./typings"; 2 | export declare const initiliazeSVG: (treeConfig: ITreeConfig) => import("d3-selection").Selection; 3 | -------------------------------------------------------------------------------- /dist/links/draw-links.d.ts: -------------------------------------------------------------------------------- 1 | import { ITreeConfig } from "../typings"; 2 | interface ICoordinates { 3 | x: number; 4 | y: number; 5 | } 6 | export declare const generateLinkLayout: (s: ICoordinates, d: ICoordinates, treeConfig: ITreeConfig) => string; 7 | export {}; 8 | -------------------------------------------------------------------------------- /dist/links/link-enter.d.ts: -------------------------------------------------------------------------------- 1 | import { HierarchyPointNode } from "d3-hierarchy"; 2 | import { BaseType, Selection } from "d3-selection"; 3 | import { ExtendedHierarchyPointNode, ITreeConfig } from "../typings"; 4 | export declare const drawLinkEnter: (link: Selection, SVGGElement, {}>, settings: ITreeConfig, nodes: ExtendedHierarchyPointNode[], oldNodes: ExtendedHierarchyPointNode[]) => Selection, SVGGElement, {}>; 5 | -------------------------------------------------------------------------------- /dist/links/link-exit.d.ts: -------------------------------------------------------------------------------- 1 | import { HierarchyPointNode } from "d3-hierarchy"; 2 | import { BaseType, Selection } from "d3-selection"; 3 | import { ExtendedHierarchyPointNode, ITreeConfig } from "../typings"; 4 | export declare const drawLinkExit: (link: Selection, SVGGElement, {}>, settings: ITreeConfig, nodes: ExtendedHierarchyPointNode[], oldNodes: ExtendedHierarchyPointNode[]) => void; 5 | -------------------------------------------------------------------------------- /dist/links/link-update.d.ts: -------------------------------------------------------------------------------- 1 | import { HierarchyPointNode } from "d3-hierarchy"; 2 | import { Selection } from "d3-selection"; 3 | import { ITreeConfig } from "../typings"; 4 | export declare const drawLinkUpdate: (linkEnter: Selection, SVGGElement, {}>, link: Selection, SVGGElement, {}>, settings: ITreeConfig) => void; 5 | -------------------------------------------------------------------------------- /dist/nodes/node-enter.d.ts: -------------------------------------------------------------------------------- 1 | import { BaseType, Selection } from "d3-selection"; 2 | import { ExtendedHierarchyPointNode, ITreeConfig } from "../typings"; 3 | export declare const drawNodeEnter: (node: Selection, settings: ITreeConfig, nodes: ExtendedHierarchyPointNode[], oldNodes: ExtendedHierarchyPointNode[]) => string & Selection; 4 | -------------------------------------------------------------------------------- /dist/nodes/node-exit.d.ts: -------------------------------------------------------------------------------- 1 | import { BaseType, Selection } from "d3-selection"; 2 | import { ExtendedHierarchyPointNode, ITreeConfig } from "../typings"; 3 | export declare const drawNodeExit: (node: Selection, settings: ITreeConfig, nodes: ExtendedHierarchyPointNode[], oldNodes: ExtendedHierarchyPointNode[]) => void; 4 | -------------------------------------------------------------------------------- /dist/nodes/node-update.d.ts: -------------------------------------------------------------------------------- 1 | import { Selection } from "d3-selection"; 2 | import { ExtendedHierarchyPointNode, ITreeConfig } from "../typings"; 3 | export declare const drawNodeUpdate: (nodeEnter: Selection, node: Selection, settings: ITreeConfig) => void; 4 | -------------------------------------------------------------------------------- /dist/prepare-data.d.ts: -------------------------------------------------------------------------------- 1 | import { HierarchyNode } from "d3-hierarchy"; 2 | import { ITreeConfig } from "./typings"; 3 | export declare const generateNestedData: (data: any, treeConfig: ITreeConfig) => HierarchyNode; 4 | export declare const generateBasicTreemap: (treeConfig: ITreeConfig) => import("d3-hierarchy").TreeLayout; 5 | -------------------------------------------------------------------------------- /dist/treeviz.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | const e = document.createElement("link").relList; 3 | if (e && e.supports && e.supports("modulepreload")) 4 | return; 5 | for (const r of document.querySelectorAll('link[rel="modulepreload"]')) 6 | d(r); 7 | new MutationObserver((r) => { 8 | for (const i of r) 9 | if (i.type === "childList") 10 | for (const l of i.addedNodes) 11 | l.tagName === "LINK" && l.rel === "modulepreload" && d(l); 12 | }).observe(document, { childList: !0, subtree: !0 }); 13 | function a(r) { 14 | const i = {}; 15 | return r.integrity && (i.integrity = r.integrity), r.referrerPolicy && (i.referrerPolicy = r.referrerPolicy), r.crossOrigin === "use-credentials" ? i.credentials = "include" : r.crossOrigin === "anonymous" ? i.credentials = "omit" : i.credentials = "same-origin", i; 16 | } 17 | function d(r) { 18 | if (r.ep) 19 | return; 20 | r.ep = !0; 21 | const i = a(r); 22 | fetch(r.href, i); 23 | } 24 | })(); 25 | function s(t, e, a) { 26 | this.k = t, this.x = e, this.y = a; 27 | } 28 | s.prototype = { 29 | constructor: s, 30 | scale: function(t) { 31 | return t === 1 ? this : new s(this.k * t, this.x, this.y); 32 | }, 33 | translate: function(t, e) { 34 | return t === 0 & e === 0 ? this : new s(this.k, this.x + this.k * t, this.y + this.k * e); 35 | }, 36 | apply: function(t) { 37 | return [t[0] * this.k + this.x, t[1] * this.k + this.y]; 38 | }, 39 | applyX: function(t) { 40 | return t * this.k + this.x; 41 | }, 42 | applyY: function(t) { 43 | return t * this.k + this.y; 44 | }, 45 | invert: function(t) { 46 | return [(t[0] - this.x) / this.k, (t[1] - this.y) / this.k]; 47 | }, 48 | invertX: function(t) { 49 | return (t - this.x) / this.k; 50 | }, 51 | invertY: function(t) { 52 | return (t - this.y) / this.k; 53 | }, 54 | rescaleX: function(t) { 55 | return t.copy().domain(t.range().map(this.invertX, this).map(t.invert, t)); 56 | }, 57 | rescaleY: function(t) { 58 | return t.copy().domain(t.range().map(this.invertY, this).map(t.invert, t)); 59 | }, 60 | toString: function() { 61 | return "translate(" + this.x + "," + this.y + ") scale(" + this.k + ")"; 62 | } 63 | }; 64 | s.prototype; 65 | var h = [{ 66 | id: 1, 67 | text_1: "Chaos", 68 | text_2: "Void", 69 | father: null, 70 | color: "#FF5722" 71 | }, { 72 | id: 2, 73 | text_1: "Tartarus", 74 | text_2: "Abyss", 75 | father: 1, 76 | color: "#FFC107" 77 | }, { 78 | id: 3, 79 | text_1: "Gaia", 80 | text_2: "Earth", 81 | father: 1, 82 | color: "#8BC34A" 83 | }, { 84 | id: 4, 85 | text_1: "Eros", 86 | text_2: "Desire", 87 | father: 1, 88 | color: "#00BCD4" 89 | }], f = [{ 90 | id: 1, 91 | text_1: "Chaos", 92 | text_2: " Void", 93 | father: null, 94 | color: "#2196F3" 95 | }, { 96 | id: 2, 97 | text_1: "Tartarus", 98 | text_2: "Abyss", 99 | father: 1, 100 | color: "#F44336" 101 | }, { 102 | id: 3, 103 | text_1: "Gaia", 104 | text_2: "Earth", 105 | father: 1, 106 | color: "#673AB7" 107 | }, { 108 | id: 4, 109 | text_1: "Eros", 110 | text_2: "Desire", 111 | father: 1, 112 | color: "#009688" 113 | }, { 114 | id: 5, 115 | text_1: "Uranus", 116 | text_2: "Sky", 117 | father: 3, 118 | color: "#4CAF50" 119 | }, { 120 | id: 6, 121 | text_1: "Ourea", 122 | text_2: "Mountains", 123 | father: 3, 124 | color: "#FF9800" 125 | }], x = [{ 126 | id: 1, 127 | text_1: "Chaos", 128 | text_2: "Void", 129 | father: null, 130 | color: "#2196F3" 131 | }, { 132 | id: 2, 133 | text_1: "Tartarus", 134 | text_2: "Abyss", 135 | father: 1, 136 | color: "#F44336" 137 | }, { 138 | id: 3, 139 | text_1: "Gaia", 140 | text_2: "Earth", 141 | father: 1, 142 | color: "#673AB7" 143 | }, { 144 | id: 4, 145 | text_1: "Eros", 146 | text_2: "Desire", 147 | father: 1, 148 | color: "#009688" 149 | }, { 150 | id: 5, 151 | text_1: "Uranus", 152 | text_2: "Sky", 153 | father: 3, 154 | color: "#4CAF50" 155 | }, { 156 | id: 6, 157 | text_1: "Ourea", 158 | text_2: "Mountains", 159 | father: 3, 160 | color: "#FF9800" 161 | }, { 162 | id: 7, 163 | text_1: "Hermes", 164 | text_2: " Sky", 165 | father: 4, 166 | color: "#2196F3" 167 | }, { 168 | id: 8, 169 | text_1: "Aphrodite", 170 | text_2: "Love", 171 | father: 4, 172 | color: "#8BC34A" 173 | }, { 174 | id: 3.3, 175 | text_1: "Love", 176 | text_2: "Peace", 177 | father: 8, 178 | color: "#c72e99" 179 | }, { 180 | id: 4.1, 181 | text_1: "Hope", 182 | text_2: "Life", 183 | father: 8, 184 | color: "#2eecc7" 185 | }], c = (void 0)({ 186 | htmlId: "tree", 187 | idKey: "id", 188 | hasFlatData: !0, 189 | relationnalField: "father", 190 | nodeWidth: 120, 191 | hasPan: !0, 192 | hasZoom: !0, 193 | nodeHeight: 80, 194 | mainAxisNodeSpacing: 2, 195 | isHorizontal: !1, 196 | renderNode: function(e) { 197 | return "
" + e.data.text_1 + "
is
" + e.data.text_2 + "
"; 198 | }, 199 | linkWidth: function(e) { 200 | return 5; 201 | }, 202 | linkShape: "curve", 203 | linkColor: function(e) { 204 | return e.linkColor || "#B0BEC5"; 205 | }, 206 | onNodeClick: function(e) { 207 | return console.log(e); 208 | } 209 | }); 210 | c.refresh(h); 211 | var u = !0, n = document.querySelector("#add"), o = document.querySelector("#remove"), _ = document.querySelector("#doTasks"); 212 | n.addEventListener("click", function() { 213 | console.log("addButton clicked"), u ? c.refresh(f) : c.refresh(x), u = !1; 214 | }); 215 | o.addEventListener("click", function() { 216 | console.log("removeButton clicked"), c.refresh(h); 217 | }); 218 | _.addEventListener("click", function() { 219 | n.click(), o.click(), n.click(), o.click(), o.click(), n.click(), o.click(), n.click(), n.click(), o.click(), o.click(); 220 | }); 221 | -------------------------------------------------------------------------------- /dist/typings.d.ts: -------------------------------------------------------------------------------- 1 | import { HierarchyPointNode } from "d3-hierarchy"; 2 | export interface ITreeConfig { 3 | htmlId: string; 4 | idKey: string; 5 | relationnalField: string; 6 | hasFlatData: boolean; 7 | nodeWidth: number; 8 | nodeHeight: number; 9 | mainAxisNodeSpacing: number | "auto"; 10 | renderNode: (node: any) => string | null; 11 | linkShape?: "quadraticBeziers" | "curve" | "orthogonal" | ""; 12 | linkColor: (node: any) => string; 13 | linkWidth: (node: any) => number; 14 | onNodeClick: (node: any) => void; 15 | onNodeMouseEnter: (node: any) => void; 16 | onNodeMouseLeave: (node: any) => void; 17 | isHorizontal: boolean; 18 | hasPan: boolean; 19 | hasZoom: boolean; 20 | duration: number; 21 | marginTop: number; 22 | marginBottom: number; 23 | marginLeft: number; 24 | marginRight: number; 25 | secondaryAxisNodeSpacing: number; 26 | } 27 | export interface ExtendedHierarchyPointNode extends HierarchyPointNode<{}> { 28 | x0?: number; 29 | y0?: number; 30 | } 31 | -------------------------------------------------------------------------------- /dist/utils.d.ts: -------------------------------------------------------------------------------- 1 | import { ExtendedHierarchyPointNode, ITreeConfig } from "./typings"; 2 | export declare const getAreaSize: (htmlId: string) => { 3 | areaWidth: number; 4 | areaHeight: number; 5 | }; 6 | type Result = ExtendedHierarchyPointNode & { 7 | x0: number; 8 | y0: number; 9 | }; 10 | export declare const getFirstDisplayedAncestor: (ghostNodes: ExtendedHierarchyPointNode[], viewableNodes: ExtendedHierarchyPointNode[], id: string) => Result; 11 | export declare const setNodeLocation: (xPosition: number, yPosition: number, settings: ITreeConfig) => string; 12 | export declare class RefreshQueue { 13 | private static queue; 14 | private static runner; 15 | private static runnerSpeed; 16 | private static readonly extraDelayBetweenCallbacks; 17 | private static showQueueLog; 18 | static add(duration: number, callback: () => any): void; 19 | private static runnerFunction; 20 | private static log; 21 | } 22 | export {}; 23 | -------------------------------------------------------------------------------- /example/example.ts: -------------------------------------------------------------------------------- 1 | import { Treeviz } from "../src"; 2 | 3 | var data_1 = [ 4 | { 5 | id: 1, 6 | text_1: "Chaos", 7 | text_2: "Void", 8 | father: null, 9 | color: "#FF5722", 10 | }, 11 | { 12 | id: 2, 13 | text_1: "Tartarus", 14 | text_2: "Abyss", 15 | father: 1, 16 | color: "#FFC107", 17 | }, 18 | { 19 | id: 3, 20 | text_1: "Gaia", 21 | text_2: "Earth", 22 | father: 1, 23 | color: "#8BC34A", 24 | }, 25 | { 26 | id: 4, 27 | text_1: "Eros", 28 | text_2: "Desire", 29 | father: 1, 30 | color: "#00BCD4", 31 | }, 32 | ]; 33 | var data_2 = [ 34 | { 35 | id: 1, 36 | text_1: "Chaos", 37 | text_2: " Void", 38 | father: null, 39 | color: "#2196F3", 40 | }, 41 | { 42 | id: 2, 43 | text_1: "Tartarus", 44 | text_2: "Abyss", 45 | father: 1, 46 | color: "#F44336", 47 | }, 48 | { 49 | id: 3, 50 | text_1: "Gaia", 51 | text_2: "Earth", 52 | father: 1, 53 | color: "#673AB7", 54 | }, 55 | { 56 | id: 4, 57 | text_1: "Eros", 58 | text_2: "Desire", 59 | father: 1, 60 | color: "#009688", 61 | }, 62 | { 63 | id: 5, 64 | text_1: "Uranus", 65 | text_2: "Sky", 66 | father: 3, 67 | color: "#4CAF50", 68 | }, 69 | { 70 | id: 6, 71 | text_1: "Ourea", 72 | text_2: "Mountains", 73 | father: 3, 74 | color: "#FF9800", 75 | }, 76 | ]; 77 | var data_3 = [ 78 | { 79 | id: 1, 80 | text_1: "Chaos", 81 | text_2: "Void", 82 | father: null, 83 | color: "#2196F3", 84 | }, 85 | { 86 | id: 2, 87 | text_1: "Tartarus", 88 | text_2: "Abyss", 89 | father: 1, 90 | color: "#F44336", 91 | }, 92 | { 93 | id: 3, 94 | text_1: "Gaia", 95 | text_2: "Earth", 96 | father: 1, 97 | color: "#673AB7", 98 | }, 99 | { 100 | id: 4, 101 | text_1: "Eros", 102 | text_2: "Desire", 103 | father: 1, 104 | color: "#009688", 105 | }, 106 | { 107 | id: 5, 108 | text_1: "Uranus", 109 | text_2: "Sky", 110 | father: 3, 111 | color: "#4CAF50", 112 | }, 113 | { 114 | id: 6, 115 | text_1: "Ourea", 116 | text_2: "Mountains", 117 | father: 3, 118 | color: "#FF9800", 119 | }, 120 | { 121 | id: 7, 122 | text_1: "Hermes", 123 | text_2: " Sky", 124 | father: 4, 125 | color: "#2196F3", 126 | }, 127 | { 128 | id: 8, 129 | text_1: "Aphrodite", 130 | text_2: "Love", 131 | father: 4, 132 | color: "#8BC34A", 133 | }, 134 | { 135 | id: 3.3, 136 | text_1: "Love", 137 | text_2: "Peace", 138 | father: 8, 139 | color: "#c72e99", 140 | }, 141 | { 142 | id: 4.1, 143 | text_1: "Hope", 144 | text_2: "Life", 145 | father: 8, 146 | color: "#2eecc7", 147 | }, 148 | ]; 149 | 150 | var myTree = Treeviz.create({ 151 | data: data_1, // for Typescript projects only. 152 | htmlId: "tree", 153 | idKey: "id", 154 | hasFlatData: true, 155 | relationnalField: "father", 156 | nodeWidth: 120, 157 | hasPan: true, 158 | hasZoom: true, 159 | nodeHeight: 80, 160 | mainAxisNodeSpacing: 2, 161 | isHorizontal: false, 162 | renderNode: function renderNode(node) { 163 | return ( 164 | "
" + 171 | node.data.text_1 + 172 | "
is
" + 173 | node.data.text_2 + 174 | "
" 175 | ); 176 | }, 177 | linkWidth: (node) => { 178 | return node.data.id * 2; 179 | }, 180 | linkShape: "curve", 181 | linkColor: () => `#B0BEC5`, 182 | onNodeClick: (node) => { 183 | console.log(node.data); 184 | }, 185 | onNodeMouseEnter: (node) => { 186 | console.log(node.data); 187 | }, 188 | }); 189 | myTree.refresh(data_1); 190 | 191 | var toggle = true; 192 | var addButton = document.querySelector("#add"); 193 | var removeButton = document.querySelector("#remove"); 194 | var doTasksButton = document.querySelector("#doTasks"); 195 | addButton?.addEventListener("click", function () { 196 | console.log("addButton clicked"); 197 | toggle ? myTree.refresh(data_2) : myTree.refresh(data_3); 198 | toggle = false; 199 | }); 200 | removeButton?.addEventListener("click", function () { 201 | console.log("removeButton clicked"); 202 | myTree.refresh(data_1); 203 | }); 204 | doTasksButton?.addEventListener("click", function () { 205 | addButton?.click(); 206 | removeButton?.click(); 207 | addButton?.click(); 208 | removeButton?.click(); 209 | removeButton?.click(); 210 | addButton?.click(); 211 | removeButton?.click(); 212 | addButton?.click(); 213 | addButton?.click(); 214 | removeButton?.click(); 215 | removeButton?.click(); 216 | }); 217 | -------------------------------------------------------------------------------- /example/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 8 | 9 | 10 | 11 | 17 | 23 |
24 | 25 | 26 | 34 | 35 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "treeviz", 3 | "version": "3.0.1", 4 | "type": "module", 5 | "description": "Library which aims to represent trees for data visualization", 6 | "license": "MIT", 7 | "main": "./dist/treeviz.js", 8 | "types": "./dist/index.d.ts", 9 | "keywords": [ 10 | "d3", 11 | "data", 12 | "visualization", 13 | "tree", 14 | "decision", 15 | "hierarchy", 16 | "dynamic" 17 | ], 18 | "repository": { 19 | "type": "git", 20 | "url": "https://github.com/PierreCapo/treeviz" 21 | }, 22 | "scripts": { 23 | "dev": "vite", 24 | "build": "tsc && vite build", 25 | "preview": "vite preview" 26 | }, 27 | "devDependencies": { 28 | "@types/node": "^20.10.3", 29 | "typescript": "^5.3.2", 30 | "vite": "^5.0.6", 31 | "vite-plugin-dts": "^3.6.4" 32 | }, 33 | "dependencies": { 34 | "@types/d3-hierarchy": "^3.1.6", 35 | "@types/d3-selection": "^3.0.10", 36 | "@types/d3-transition": "^3.0.8", 37 | "@types/d3-zoom": "^3.0.8", 38 | "d3-hierarchy": "^3.1.2", 39 | "d3-selection": "^3.0.0", 40 | "d3-transition": "^3.0.1", 41 | "d3-zoom": "^3.0.0" 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/d3.ts: -------------------------------------------------------------------------------- 1 | import { hierarchy, stratify, tree, treemap } from "d3-hierarchy"; 2 | import { select, selectAll } from "d3-selection"; 3 | import { zoom } from "d3-zoom"; 4 | 5 | export default { 6 | hierarchy, 7 | stratify, 8 | tree, 9 | treemap, 10 | select, 11 | selectAll, 12 | zoom, 13 | }; 14 | -------------------------------------------------------------------------------- /src/index.ts: -------------------------------------------------------------------------------- 1 | import { HierarchyPointNode } from "d3-hierarchy"; 2 | import { BaseType, Selection } from "d3-selection"; 3 | import { initiliazeSVG } from "./initializeSVG"; 4 | import { drawLinkEnter } from "./links/link-enter"; 5 | import { drawLinkExit } from "./links/link-exit"; 6 | import { drawLinkUpdate } from "./links/link-update"; 7 | import { drawNodeEnter } from "./nodes/node-enter"; 8 | import { drawNodeExit } from "./nodes/node-exit"; 9 | import { drawNodeUpdate } from "./nodes/node-update"; 10 | import { generateBasicTreemap, generateNestedData } from "./prepare-data"; 11 | import { ExtendedHierarchyPointNode, ITreeConfig } from "./typings"; 12 | import { RefreshQueue } from "./utils"; 13 | 14 | export const Treeviz = { 15 | create, 16 | }; 17 | 18 | function create(userSettings: Partial>) { 19 | const defaultSettings: ITreeConfig = { 20 | data: [], 21 | htmlId: "", 22 | idKey: "id", 23 | relationnalField: "father", 24 | hasFlatData: true, 25 | nodeWidth: 160, 26 | nodeHeight: 100, 27 | mainAxisNodeSpacing: 300, 28 | renderNode: () => "Node", 29 | linkColor: () => "#ffcc80", 30 | linkWidth: () => 10, 31 | linkShape: "quadraticBeziers", 32 | isHorizontal: true, 33 | hasPan: false, 34 | hasZoom: false, 35 | duration: 600, 36 | onNodeClick: () => undefined, 37 | onNodeMouseEnter: () => undefined, 38 | onNodeMouseLeave: () => undefined, 39 | marginBottom: 0, 40 | marginLeft: 0, 41 | marginRight: 0, 42 | marginTop: 0, 43 | secondaryAxisNodeSpacing: 1.25, 44 | }; 45 | 46 | // @ts-ignore 47 | let settings: ITreeConfig = { 48 | ...defaultSettings, 49 | ...userSettings, 50 | }; 51 | 52 | let oldNodes: ExtendedHierarchyPointNode[] = []; 53 | 54 | function draw( 55 | svg: Selection, 56 | computedTree: HierarchyPointNode<{}> 57 | ) { 58 | const nodes = computedTree.descendants() as ExtendedHierarchyPointNode[]; 59 | 60 | const links = computedTree.descendants().slice(1); 61 | 62 | const { mainAxisNodeSpacing: mainAxisNodeSpacing } = settings; 63 | if (mainAxisNodeSpacing !== "auto") { 64 | // Normalize for fixed-depth. 65 | nodes.forEach((d) => { 66 | d.y = d.depth * settings.nodeWidth * mainAxisNodeSpacing; 67 | }); 68 | } 69 | 70 | nodes.forEach((currentNode: ExtendedHierarchyPointNode) => { 71 | const currentNodeOldPosition = oldNodes.find( 72 | (node) => node.id === currentNode.id 73 | ); 74 | currentNode.x0 = currentNodeOldPosition 75 | ? currentNodeOldPosition.x0 76 | : currentNode.x; 77 | currentNode.y0 = currentNodeOldPosition 78 | ? currentNodeOldPosition.y0 79 | : currentNode.y; 80 | }); 81 | 82 | // ****************** Nodes section *************************** 83 | const node: Selection< 84 | BaseType, 85 | ExtendedHierarchyPointNode, 86 | SVGGElement, 87 | {} 88 | > = svg.selectAll("g.node").data(nodes, (d: any) => { 89 | return d[settings.idKey]; 90 | }); 91 | 92 | const nodeEnter = drawNodeEnter(node, settings, nodes, oldNodes); 93 | //@ts-ignore 94 | drawNodeUpdate(nodeEnter, node, settings); 95 | drawNodeExit(node, settings, nodes, oldNodes); 96 | 97 | // ****************** links section *************************** 98 | 99 | const link = svg.selectAll("path.link").data(links, (d: any) => { 100 | return d.id; 101 | }); 102 | 103 | const linkEnter = drawLinkEnter(link, settings, nodes, oldNodes); 104 | // @ts-ignore 105 | drawLinkUpdate(linkEnter, link, settings); 106 | drawLinkExit(link, settings, nodes, oldNodes); 107 | 108 | oldNodes = [...nodes]; 109 | } 110 | 111 | function refresh(data: any, newSettings?: Partial) { 112 | RefreshQueue.add(settings.duration, () => { 113 | if (newSettings) { 114 | settings = { ...settings, ...newSettings }; 115 | } 116 | const nestedData = generateNestedData(data, settings); 117 | const treemap = generateBasicTreemap(settings); 118 | const computedTree = treemap(nestedData); // mutation 119 | 120 | // @ts-ignore 121 | draw(svg, computedTree); 122 | }); 123 | } 124 | 125 | function clean(keepConfig: boolean) { 126 | const myNode = keepConfig 127 | ? document.querySelector(`#${settings.htmlId} svg g`) 128 | : document.querySelector(`#${settings.htmlId}`); 129 | if (myNode) { 130 | while (myNode.firstChild) { 131 | myNode.removeChild(myNode.firstChild); 132 | } 133 | } 134 | oldNodes = []; 135 | } 136 | 137 | const treeObject = { refresh, clean }; 138 | 139 | const svg = initiliazeSVG(settings); 140 | return treeObject; 141 | } 142 | -------------------------------------------------------------------------------- /src/initializeSVG.ts: -------------------------------------------------------------------------------- 1 | import d3 from "./d3"; 2 | import { ITreeConfig } from "./typings"; 3 | import { getAreaSize } from "./utils"; 4 | 5 | export const initiliazeSVG = (treeConfig: ITreeConfig) => { 6 | const { 7 | htmlId, 8 | isHorizontal, 9 | hasPan, 10 | hasZoom, 11 | mainAxisNodeSpacing, 12 | nodeHeight, 13 | nodeWidth, 14 | marginBottom, 15 | marginLeft, 16 | marginRight, 17 | marginTop, 18 | } = treeConfig; 19 | const margin = { 20 | top: marginTop, 21 | right: marginRight, 22 | bottom: marginBottom, 23 | left: marginLeft, 24 | }; 25 | const { areaHeight, areaWidth } = getAreaSize(treeConfig.htmlId); 26 | const width = areaWidth - margin.left - margin.right; 27 | const height = areaHeight - margin.top - margin.bottom; 28 | 29 | const svg = d3 30 | .select("#" + htmlId) 31 | .append("svg") 32 | .attr("width", areaWidth) 33 | .attr("height", areaHeight); 34 | 35 | // Create a G container and move it according to the Zoom Behavior attached to the main element 36 | const ZoomContainer = svg.append("g"); 37 | const zoom = d3.zoom().on("zoom", (e) => { 38 | ZoomContainer.attr("transform", () => e.transform); 39 | }); 40 | // @ts-ignore 41 | svg.call(zoom); 42 | 43 | if (!hasPan) { 44 | svg 45 | .on("mousedown.zoom", null) 46 | .on("touchstart.zoom", null) 47 | .on("touchmove.zoom", null) 48 | .on("touchend.zoom", null); 49 | } 50 | 51 | if (!hasZoom) { 52 | svg 53 | .on("wheel.zoom", null) 54 | .on("mousewheel.zoom", null) 55 | .on("mousemove.zoom", null) 56 | .on("DOMMouseScroll.zoom", null) 57 | .on("dblclick.zoom", null); 58 | } 59 | 60 | const MainG = ZoomContainer.append("g").attr( 61 | "transform", 62 | mainAxisNodeSpacing === "auto" 63 | ? "translate(0,0)" 64 | : isHorizontal 65 | ? "translate(" + 66 | margin.left + 67 | "," + 68 | (margin.top + height / 2 - nodeHeight / 2) + 69 | ")" 70 | : "translate(" + 71 | (margin.left + width / 2 - nodeWidth / 2) + 72 | "," + 73 | margin.top + 74 | ")" 75 | ); 76 | return MainG; 77 | }; 78 | -------------------------------------------------------------------------------- /src/links/draw-links.ts: -------------------------------------------------------------------------------- 1 | import { ITreeConfig } from "../typings"; 2 | 3 | interface ICoordinates { 4 | x: number; 5 | y: number; 6 | } 7 | 8 | export const generateLinkLayout = ( 9 | s: ICoordinates, // source 10 | d: ICoordinates, // destination 11 | treeConfig: ITreeConfig 12 | ): string => { 13 | const { isHorizontal, nodeHeight, nodeWidth, linkShape } = treeConfig; 14 | if (linkShape === "orthogonal") { 15 | if (isHorizontal) { 16 | return `M ${s.y} ${s.x + nodeHeight / 2} 17 | L ${(s.y + d.y + nodeWidth) / 2} ${s.x + nodeHeight / 2} 18 | L ${(s.y + d.y + nodeWidth) / 2} ${d.x + nodeHeight / 2} 19 | ${d.y + nodeWidth} ${d.x + nodeHeight / 2}`; 20 | } else { 21 | return `M ${s.x + nodeWidth / 2} ${s.y} 22 | L ${s.x + nodeWidth / 2} ${(s.y + d.y + nodeHeight) / 2} 23 | L ${d.x + nodeWidth / 2} ${(s.y + d.y + nodeHeight) / 2} 24 | ${d.x + nodeWidth / 2} ${d.y + nodeHeight} `; 25 | } 26 | } else if (linkShape === "curve") { 27 | if (isHorizontal) { 28 | return `M ${s.y} ${s.x + nodeHeight / 2} 29 | L ${s.y - (s.y - d.y - nodeWidth) / 2 + 15} ${s.x + nodeHeight / 2} 30 | Q${s.y - (s.y - d.y - nodeWidth) / 2} ${s.x + nodeHeight / 2} 31 | ${s.y - (s.y - d.y - nodeWidth) / 2} ${s.x + 32 | nodeHeight / 2 - 33 | offsetPosOrNeg(s.x, d.x, 15)} 34 | L ${s.y - (s.y - d.y - nodeWidth) / 2} ${d.x + nodeHeight / 2} 35 | L ${d.y + nodeWidth} ${d.x + nodeHeight / 2}`; 36 | } else { 37 | return `M ${s.x + nodeWidth / 2} ${s.y} 38 | L ${s.x + nodeWidth / 2} ${s.y - (s.y - d.y - nodeHeight) / 2 + 15} 39 | Q${s.x + nodeWidth / 2} ${s.y - (s.y - d.y - nodeHeight) / 2} 40 | ${s.x + nodeWidth / 2 - offsetPosOrNeg(s.x, d.x, 15)} ${s.y - 41 | (s.y - d.y - nodeHeight) / 2} 42 | L ${d.x + nodeWidth / 2} ${s.y - (s.y - d.y - nodeHeight) / 2} 43 | L ${d.x + nodeWidth / 2} ${d.y + nodeHeight} `; 44 | } 45 | } else { 46 | if (isHorizontal) { 47 | return `M ${s.y} ${s.x + nodeHeight / 2} 48 | C ${(s.y + d.y + nodeWidth) / 2} ${s.x + nodeHeight / 2} 49 | ${(s.y + d.y + nodeWidth) / 2} ${d.x + nodeHeight / 2} 50 | ${d.y + nodeWidth} ${d.x + nodeHeight / 2}`; 51 | } else { 52 | return `M ${s.x + nodeWidth / 2} ${s.y} 53 | C ${s.x + nodeWidth / 2} ${(s.y + d.y + nodeHeight) / 2} 54 | ${d.x + nodeWidth / 2} ${(s.y + d.y + nodeHeight) / 2} 55 | ${d.x + nodeWidth / 2} ${d.y + nodeHeight} `; 56 | } 57 | } 58 | }; 59 | 60 | const offsetPosOrNeg = (val1: number, val2: number, offset: number) => 61 | val1 > val2 ? offset : val1 < val2 ? -offset : 0; 62 | -------------------------------------------------------------------------------- /src/links/link-enter.ts: -------------------------------------------------------------------------------- 1 | import { HierarchyPointNode } from "d3-hierarchy"; 2 | import { BaseType, Selection } from "d3-selection"; 3 | import { ExtendedHierarchyPointNode, ITreeConfig } from "../typings"; 4 | import { getFirstDisplayedAncestor } from "../utils"; 5 | import { generateLinkLayout } from "./draw-links"; 6 | 7 | export const drawLinkEnter = ( 8 | link: Selection, SVGGElement, {}>, 9 | settings: ITreeConfig, 10 | nodes: ExtendedHierarchyPointNode[], 11 | oldNodes: ExtendedHierarchyPointNode[] 12 | ) => 13 | link 14 | .enter() 15 | .insert("path", "g") 16 | .attr("class", "link") 17 | .attr("d", (d: any) => { 18 | const firstDisplayedParentNode = getFirstDisplayedAncestor( 19 | nodes, 20 | oldNodes, 21 | d.id 22 | ); 23 | const o = { 24 | x: firstDisplayedParentNode.x0, 25 | y: firstDisplayedParentNode.y0, 26 | }; 27 | return generateLinkLayout(o, o, settings); 28 | }) 29 | .attr("fill", "none") 30 | .attr("stroke-width", ({ data }: { data: any }) => 31 | settings.linkWidth({ data, settings }) 32 | ) 33 | .attr("stroke", ({ data }: { data: any }) => 34 | settings.linkColor({ data, settings }) 35 | ); 36 | -------------------------------------------------------------------------------- /src/links/link-exit.ts: -------------------------------------------------------------------------------- 1 | import { HierarchyPointNode } from "d3-hierarchy"; 2 | import { BaseType, Selection } from "d3-selection"; 3 | import { ExtendedHierarchyPointNode, ITreeConfig } from "../typings"; 4 | import { getFirstDisplayedAncestor } from "../utils"; 5 | import { generateLinkLayout } from "./draw-links"; 6 | 7 | export const drawLinkExit = ( 8 | link: Selection, SVGGElement, {}>, 9 | settings: ITreeConfig, 10 | nodes: ExtendedHierarchyPointNode[], 11 | oldNodes: ExtendedHierarchyPointNode[] 12 | ) => { 13 | link 14 | .exit() 15 | //@ts-ignore 16 | .transition() 17 | .duration(settings.duration) 18 | .style("opacity", 0) 19 | .attr("d", (d: any) => { 20 | const firstDisplayedParentNode = getFirstDisplayedAncestor( 21 | oldNodes, 22 | nodes, 23 | d.id 24 | ); 25 | const o = { 26 | x: firstDisplayedParentNode.x0, 27 | y: firstDisplayedParentNode.y0, 28 | }; 29 | return generateLinkLayout(o, o, settings); 30 | }) 31 | .remove(); 32 | }; 33 | -------------------------------------------------------------------------------- /src/links/link-update.ts: -------------------------------------------------------------------------------- 1 | import { HierarchyPointNode } from "d3-hierarchy"; 2 | import { Selection } from "d3-selection"; 3 | import { ITreeConfig } from "../typings"; 4 | import { generateLinkLayout } from "./draw-links"; 5 | 6 | export const drawLinkUpdate = ( 7 | linkEnter: Selection, SVGGElement, {}>, 8 | link: Selection, SVGGElement, {}>, 9 | settings: ITreeConfig 10 | ) => { 11 | const linkUpdate = linkEnter.merge(link); 12 | 13 | linkUpdate 14 | //@ts-ignore 15 | .transition() 16 | .duration(settings.duration) 17 | .attr("d", (d: any) => { 18 | return generateLinkLayout(d, d.parent, settings); 19 | }) 20 | .attr("fill", "none") 21 | .attr("stroke-width", ({ data }: { data: any }) => 22 | settings.linkWidth({ data, settings }) 23 | ) 24 | .attr("stroke", ({ data }: { data: any }) => 25 | settings.linkColor({ data, settings }) 26 | ); 27 | }; 28 | -------------------------------------------------------------------------------- /src/nodes/node-enter.ts: -------------------------------------------------------------------------------- 1 | import { BaseType, Selection } from "d3-selection"; 2 | import { ExtendedHierarchyPointNode, ITreeConfig } from "../typings"; 3 | import { getFirstDisplayedAncestor, setNodeLocation } from "../utils"; 4 | 5 | export const drawNodeEnter = ( 6 | node: Selection, 7 | settings: ITreeConfig, 8 | nodes: ExtendedHierarchyPointNode[], 9 | oldNodes: ExtendedHierarchyPointNode[] 10 | ) => { 11 | const nodeEnter = node 12 | .enter() 13 | .append("g") 14 | .attr("class", "node") 15 | // @ts-ignore 16 | .attr("id", (d) => d?.id) 17 | .attr("transform", (d: any) => { 18 | const firstDisplayedParentNode = getFirstDisplayedAncestor( 19 | nodes, 20 | oldNodes, 21 | d.id 22 | ); 23 | return setNodeLocation( 24 | firstDisplayedParentNode.x0, 25 | firstDisplayedParentNode.y0, 26 | settings 27 | ); 28 | }); 29 | 30 | nodeEnter 31 | .append("foreignObject") 32 | .attr("width", settings.nodeWidth) 33 | .attr("height", settings.nodeHeight); 34 | 35 | return nodeEnter; 36 | }; 37 | -------------------------------------------------------------------------------- /src/nodes/node-exit.ts: -------------------------------------------------------------------------------- 1 | import { BaseType, Selection } from "d3-selection"; 2 | import { ExtendedHierarchyPointNode, ITreeConfig } from "../typings"; 3 | import { getFirstDisplayedAncestor, setNodeLocation } from "../utils"; 4 | 5 | export const drawNodeExit = ( 6 | node: Selection, 7 | settings: ITreeConfig, 8 | nodes: ExtendedHierarchyPointNode[], 9 | oldNodes: ExtendedHierarchyPointNode[] 10 | ) => { 11 | const nodeExit = node 12 | .exit() 13 | //@ts-ignore 14 | .transition() 15 | .duration(settings.duration) 16 | .style("opacity", 0) 17 | .attr("transform", (d: any) => { 18 | const firstDisplayedParentNode = getFirstDisplayedAncestor( 19 | oldNodes, 20 | nodes, 21 | d.id 22 | ); 23 | return setNodeLocation( 24 | firstDisplayedParentNode.x0, 25 | firstDisplayedParentNode.y0, 26 | settings 27 | ); 28 | }) 29 | .remove(); 30 | 31 | nodeExit.select("rect").style("fill-opacity", 1e-6); 32 | nodeExit.select("circle").attr("r", 1e-6); 33 | nodeExit.select("text").style("fill-opacity", 1e-6); 34 | }; 35 | -------------------------------------------------------------------------------- /src/nodes/node-update.ts: -------------------------------------------------------------------------------- 1 | import { Selection } from "d3-selection"; 2 | import { ExtendedHierarchyPointNode, ITreeConfig } from "../typings"; 3 | 4 | export const drawNodeUpdate = ( 5 | nodeEnter: Selection< 6 | SVGGElement, 7 | ExtendedHierarchyPointNode, 8 | SVGGElement, 9 | {} 10 | >, 11 | node: Selection, 12 | settings: ITreeConfig 13 | ) => { 14 | const nodeUpdate = nodeEnter.merge(node); 15 | nodeUpdate 16 | //@ts-ignore 17 | .transition() 18 | .duration(settings.duration) 19 | //@ts-ignore 20 | .attr("transform", (d) => { 21 | return settings.isHorizontal 22 | ? "translate(" + d.y + "," + d.x + ")" 23 | : "translate(" + d.x + "," + d.y + ")"; 24 | }); 25 | 26 | nodeUpdate 27 | .select("foreignObject") 28 | .attr("width", settings.nodeWidth) 29 | .attr("height", settings.nodeHeight) 30 | .style("overflow", "visible") 31 | .on("click", (_, d) => settings.onNodeClick({ ...d, settings })) 32 | .on("mouseenter", (_, d) => settings.onNodeMouseEnter({ ...d, settings })) 33 | .on("mouseleave", (_, d) => settings.onNodeMouseLeave({ ...d, settings })) 34 | .html((d) => settings.renderNode({ ...d, settings })); 35 | }; 36 | -------------------------------------------------------------------------------- /src/prepare-data.ts: -------------------------------------------------------------------------------- 1 | import { HierarchyNode } from "d3-hierarchy"; 2 | import d3 from "./d3"; 3 | import { ITreeConfig } from "./typings"; 4 | import { getAreaSize } from "./utils"; 5 | 6 | export const generateNestedData = ( 7 | data: any, 8 | treeConfig: ITreeConfig 9 | ): HierarchyNode => { 10 | const { idKey, relationnalField, hasFlatData } = treeConfig; 11 | return hasFlatData 12 | ? d3 13 | .stratify() 14 | .id((d: any) => d[idKey]) 15 | .parentId((d: any) => d[relationnalField])(data) 16 | : d3.hierarchy(data, d => d[relationnalField]); 17 | }; 18 | 19 | export const generateBasicTreemap = (treeConfig: ITreeConfig) => { 20 | const { areaHeight, areaWidth } = getAreaSize(treeConfig.htmlId); 21 | return treeConfig.mainAxisNodeSpacing === "auto" && treeConfig.isHorizontal 22 | ? d3 23 | .tree() 24 | .size([ 25 | areaHeight - treeConfig.nodeHeight, 26 | areaWidth - treeConfig.nodeWidth, 27 | ]) 28 | : treeConfig.mainAxisNodeSpacing === "auto" && !treeConfig.isHorizontal 29 | ? d3 30 | .tree() 31 | .size([ 32 | areaWidth - treeConfig.nodeWidth, 33 | areaHeight - treeConfig.nodeHeight, 34 | ]) 35 | : treeConfig.isHorizontal === true 36 | ? d3 37 | .tree() 38 | .nodeSize([ 39 | treeConfig.nodeHeight * treeConfig.secondaryAxisNodeSpacing, 40 | treeConfig.nodeWidth, 41 | ]) 42 | : d3 43 | .tree() 44 | .nodeSize([ 45 | treeConfig.nodeWidth * treeConfig.secondaryAxisNodeSpacing, 46 | treeConfig.nodeHeight, 47 | ]); 48 | }; 49 | -------------------------------------------------------------------------------- /src/typings.ts: -------------------------------------------------------------------------------- 1 | import { HierarchyPointNode } from "d3-hierarchy"; 2 | 3 | type NodeData = { 4 | data: T; 5 | settings: ITreeConfig; 6 | } & ExtendedHierarchyPointNode; 7 | 8 | export interface ITreeConfig { 9 | data: T[]; 10 | htmlId: string; 11 | idKey: string; 12 | relationnalField: string; 13 | hasFlatData: boolean; 14 | nodeWidth: number; 15 | nodeHeight: number; 16 | mainAxisNodeSpacing: number | "auto"; 17 | linkShape?: "quadraticBeziers" | "curve" | "orthogonal" | ""; 18 | renderNode: (node: NodeData) => string | null; 19 | linkColor: (node: NodeData) => string; 20 | linkWidth: (node: NodeData) => number; 21 | onNodeClick: (node: NodeData) => void; 22 | onNodeMouseEnter: (node: NodeData) => void; 23 | onNodeMouseLeave: (node: NodeData) => void; 24 | isHorizontal: boolean; 25 | hasPan: boolean; 26 | hasZoom: boolean; 27 | duration: number; 28 | marginTop: number; 29 | marginBottom: number; 30 | marginLeft: number; 31 | marginRight: number; 32 | secondaryAxisNodeSpacing: number; 33 | } 34 | 35 | export interface ExtendedHierarchyPointNode extends HierarchyPointNode<{}> { 36 | x0?: number; 37 | y0?: number; 38 | } 39 | 40 | // https://github.com/DefinitelyTyped/DefinitelyTyped/issues/16176#issuecomment-348095843 41 | import { select as d3Select } from "d3-selection"; 42 | import { transition as d3Transition } from "d3-transition"; 43 | d3Select.prototype.transition = d3Transition; 44 | -------------------------------------------------------------------------------- /src/utils.ts: -------------------------------------------------------------------------------- 1 | import { ExtendedHierarchyPointNode, ITreeConfig } from "./typings"; 2 | 3 | export const getAreaSize = (htmlId: string) => { 4 | const SVGContainer = document.querySelector(`#${htmlId}`); 5 | if (SVGContainer === null) { 6 | throw new Error(`Cannot find dom element with id:${htmlId}`); 7 | } 8 | const areaWidth = SVGContainer.clientWidth; 9 | const areaHeight = SVGContainer.clientHeight; 10 | if (areaHeight === 0 || areaWidth === 0) { 11 | throw new Error( 12 | "The tree can't be display because the svg height or width of the container is null" 13 | ); 14 | } 15 | return { areaWidth, areaHeight }; 16 | }; 17 | 18 | type Result = ExtendedHierarchyPointNode & { x0: number; y0: number }; 19 | 20 | export const getFirstDisplayedAncestor = ( 21 | ghostNodes: ExtendedHierarchyPointNode[], 22 | viewableNodes: ExtendedHierarchyPointNode[], 23 | id: string 24 | ): Result => { 25 | try { 26 | // @ts-ignore 27 | const parentNode: Result = ghostNodes.find((node) => node.id === id); 28 | 29 | // @ts-ignore 30 | const parentNodeId: string = parentNode.ancestors()[1].id; 31 | const isPresentInOldNodes = viewableNodes.some( 32 | (oldNode) => oldNode.id === parentNodeId 33 | ); 34 | 35 | if (isPresentInOldNodes) { 36 | return parentNode.ancestors()[1]; 37 | } else { 38 | return getFirstDisplayedAncestor(ghostNodes, viewableNodes, parentNodeId); 39 | } 40 | } catch (e) { 41 | // @ts-ignore 42 | return ghostNodes.find((node) => node.id === id); 43 | } 44 | }; 45 | 46 | export const setNodeLocation = ( 47 | xPosition: number, 48 | yPosition: number, 49 | settings: ITreeConfig 50 | ) => { 51 | if (settings.isHorizontal) { 52 | return "translate(" + yPosition + "," + xPosition + ")"; 53 | } else { 54 | return "translate(" + xPosition + "," + yPosition + ")"; 55 | } 56 | }; 57 | 58 | // RefreshQueue ensures that don't run a refresh while another refresh 59 | // is in transition. 60 | export class RefreshQueue { 61 | // The queue is an array that contains objects. Each object represents an 62 | // refresh action and only they have 2 properties: 63 | // { 64 | // callback: triggers when it's the first of queue and then it 65 | // becomes null to prevent that callback executes more 66 | // than once. 67 | // delayNextCallback: when callback is executed, queue will subtracts 68 | // milliseconds from it. When it becomes 0, the entire 69 | // object is destroyed (shifted) from the array and then 70 | // the next item (if exists) will be executed similary 71 | // to this. 72 | // } 73 | private static queue: Array<{ 74 | delayNextCallback: number; 75 | callback: any; 76 | }> = []; 77 | 78 | // Contains setInterval ID 79 | private static runner: number; 80 | 81 | // Milliseconds of each iteration 82 | private static runnerSpeed: number = 100; 83 | 84 | // Developer internal magic number. Time added at end of refresh transition to 85 | // let DOM and d3 rest before another refresh. 86 | // 0 creates console and visual errors because getFirstDisplayedAncestor never 87 | // found the needed id and setNodeLocation receives undefined parameters. 88 | // Between 50 and 100 milliseconds seems enough for 10 nodes (demo example) 89 | private static readonly extraDelayBetweenCallbacks: number = 100; 90 | 91 | // Developer internal for debugging RefreshQueue class. Set true to see 92 | // console "real time" queue of tasks. 93 | // If there is a cleaner method, remove it! 94 | private static showQueueLog: boolean = false; 95 | 96 | // Adds one refresh action to the queue. When safe callback will be 97 | // triggered 98 | public static add(duration: number, callback: () => any) { 99 | this.queue.push({ 100 | delayNextCallback: duration + this.extraDelayBetweenCallbacks, 101 | callback: callback, 102 | }); 103 | this.log( 104 | this.queue.map((_) => _.delayNextCallback), 105 | "<-- New task !!!" 106 | ); 107 | if (!this.runner) { 108 | this.runnerFunction(); 109 | //@ts-ignore 110 | this.runner = setInterval(() => this.runnerFunction(), this.runnerSpeed); 111 | } 112 | } 113 | 114 | // Each this.runnerSpeed milliseconds it's executed. It stops when finish. 115 | private static runnerFunction() { 116 | if (this.queue[0]) { 117 | // ************************ Callback section ************************ 118 | if (this.queue[0].callback) { 119 | this.log("Executing task, delaying next task..."); 120 | try { 121 | this.queue[0].callback(); 122 | } catch (e) { 123 | console.error(e); 124 | } finally { 125 | // To prevent trigger callback more than once 126 | this.queue[0].callback = null; 127 | } 128 | } 129 | // ******************** Delay until next callback ******************** 130 | this.queue[0].delayNextCallback -= this.runnerSpeed; 131 | this.log(this.queue.map((_) => _.delayNextCallback)); 132 | if (this.queue[0].delayNextCallback <= 0) { 133 | this.queue.shift(); 134 | } 135 | } else { 136 | this.log("No task found"); 137 | clearInterval(this.runner); 138 | this.runner = 0; 139 | } 140 | } 141 | 142 | // Print to console debug data if this.showQueueLog = true 143 | private static log(...msg: any) { 144 | if (this.showQueueLog) console.log(...msg); 145 | } 146 | } 147 | -------------------------------------------------------------------------------- /src/vite-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ES2020", 4 | "useDefineForClassFields": true, 5 | "module": "ESNext", 6 | "lib": ["ES2020", "DOM", "DOM.Iterable"], 7 | "skipLibCheck": true, 8 | 9 | /* Bundler mode */ 10 | "moduleResolution": "bundler", 11 | "allowImportingTsExtensions": true, 12 | "resolveJsonModule": true, 13 | "isolatedModules": true, 14 | "noEmit": true, 15 | 16 | /* Linting */ 17 | "strict": true, 18 | "noUnusedLocals": true, 19 | "noUnusedParameters": true, 20 | "noFallthroughCasesInSwitch": true, 21 | "sourceMap": true, 22 | }, 23 | "include": ["src", "example/example.ts"] 24 | } 25 | -------------------------------------------------------------------------------- /vite.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from "vite"; 2 | import { resolve } from "path"; 3 | import dts from "vite-plugin-dts"; 4 | 5 | export default defineConfig({ 6 | plugins: [dts({ include: ["src"] })], 7 | build: { 8 | lib: { 9 | entry: resolve(__dirname, "src/index.ts"), 10 | formats: ["es"], 11 | }, 12 | rollupOptions: { 13 | input: { 14 | app: "./example/index.html", 15 | }, 16 | }, 17 | copyPublicDir: false, 18 | }, 19 | server: { 20 | open: "/example/index.html", 21 | }, 22 | }); 23 | -------------------------------------------------------------------------------- /yarn.lock: -------------------------------------------------------------------------------- 1 | # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. 2 | # yarn lockfile v1 3 | 4 | 5 | "@babel/parser@^7.23.5": 6 | version "7.23.5" 7 | resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.23.5.tgz#37dee97c4752af148e1d38c34b856b2507660563" 8 | integrity sha512-hOOqoiNXrmGdFbhgCzu6GiURxUgM27Xwd/aPuu8RfHEZPBzL1Z54okAHAQjXfcQNwvrlkAmAp4SlRTZ45vlthQ== 9 | 10 | "@esbuild/android-arm64@0.19.8": 11 | version "0.19.8" 12 | resolved "https://registry.yarnpkg.com/@esbuild/android-arm64/-/android-arm64-0.19.8.tgz#fb7130103835b6d43ea499c3f30cfb2b2ed58456" 13 | integrity sha512-B8JbS61bEunhfx8kasogFENgQfr/dIp+ggYXwTqdbMAgGDhRa3AaPpQMuQU0rNxDLECj6FhDzk1cF9WHMVwrtA== 14 | 15 | "@esbuild/android-arm@0.19.8": 16 | version "0.19.8" 17 | resolved "https://registry.yarnpkg.com/@esbuild/android-arm/-/android-arm-0.19.8.tgz#b46e4d9e984e6d6db6c4224d72c86b7757e35bcb" 18 | integrity sha512-31E2lxlGM1KEfivQl8Yf5aYU/mflz9g06H6S15ITUFQueMFtFjESRMoDSkvMo8thYvLBax+VKTPlpnx+sPicOA== 19 | 20 | "@esbuild/android-x64@0.19.8": 21 | version "0.19.8" 22 | resolved "https://registry.yarnpkg.com/@esbuild/android-x64/-/android-x64-0.19.8.tgz#a13db9441b5a4f4e4fec4a6f8ffacfea07888db7" 23 | integrity sha512-rdqqYfRIn4jWOp+lzQttYMa2Xar3OK9Yt2fhOhzFXqg0rVWEfSclJvZq5fZslnz6ypHvVf3CT7qyf0A5pM682A== 24 | 25 | "@esbuild/darwin-arm64@0.19.8": 26 | version "0.19.8" 27 | resolved "https://registry.yarnpkg.com/@esbuild/darwin-arm64/-/darwin-arm64-0.19.8.tgz#49f5718d36541f40dd62bfdf84da9c65168a0fc2" 28 | integrity sha512-RQw9DemMbIq35Bprbboyf8SmOr4UXsRVxJ97LgB55VKKeJOOdvsIPy0nFyF2l8U+h4PtBx/1kRf0BelOYCiQcw== 29 | 30 | "@esbuild/darwin-x64@0.19.8": 31 | version "0.19.8" 32 | resolved "https://registry.yarnpkg.com/@esbuild/darwin-x64/-/darwin-x64-0.19.8.tgz#75c5c88371eea4bfc1f9ecfd0e75104c74a481ac" 33 | integrity sha512-3sur80OT9YdeZwIVgERAysAbwncom7b4bCI2XKLjMfPymTud7e/oY4y+ci1XVp5TfQp/bppn7xLw1n/oSQY3/Q== 34 | 35 | "@esbuild/freebsd-arm64@0.19.8": 36 | version "0.19.8" 37 | resolved "https://registry.yarnpkg.com/@esbuild/freebsd-arm64/-/freebsd-arm64-0.19.8.tgz#9d7259fea4fd2b5f7437b52b542816e89d7c8575" 38 | integrity sha512-WAnPJSDattvS/XtPCTj1tPoTxERjcTpH6HsMr6ujTT+X6rylVe8ggxk8pVxzf5U1wh5sPODpawNicF5ta/9Tmw== 39 | 40 | "@esbuild/freebsd-x64@0.19.8": 41 | version "0.19.8" 42 | resolved "https://registry.yarnpkg.com/@esbuild/freebsd-x64/-/freebsd-x64-0.19.8.tgz#abac03e1c4c7c75ee8add6d76ec592f46dbb39e3" 43 | integrity sha512-ICvZyOplIjmmhjd6mxi+zxSdpPTKFfyPPQMQTK/w+8eNK6WV01AjIztJALDtwNNfFhfZLux0tZLC+U9nSyA5Zg== 44 | 45 | "@esbuild/linux-arm64@0.19.8": 46 | version "0.19.8" 47 | resolved "https://registry.yarnpkg.com/@esbuild/linux-arm64/-/linux-arm64-0.19.8.tgz#c577932cf4feeaa43cb9cec27b89cbe0df7d9098" 48 | integrity sha512-z1zMZivxDLHWnyGOctT9JP70h0beY54xDDDJt4VpTX+iwA77IFsE1vCXWmprajJGa+ZYSqkSbRQ4eyLCpCmiCQ== 49 | 50 | "@esbuild/linux-arm@0.19.8": 51 | version "0.19.8" 52 | resolved "https://registry.yarnpkg.com/@esbuild/linux-arm/-/linux-arm-0.19.8.tgz#d6014d8b98b5cbc96b95dad3d14d75bb364fdc0f" 53 | integrity sha512-H4vmI5PYqSvosPaTJuEppU9oz1dq2A7Mr2vyg5TF9Ga+3+MGgBdGzcyBP7qK9MrwFQZlvNyJrvz6GuCaj3OukQ== 54 | 55 | "@esbuild/linux-ia32@0.19.8": 56 | version "0.19.8" 57 | resolved "https://registry.yarnpkg.com/@esbuild/linux-ia32/-/linux-ia32-0.19.8.tgz#2379a0554307d19ac4a6cdc15b08f0ea28e7a40d" 58 | integrity sha512-1a8suQiFJmZz1khm/rDglOc8lavtzEMRo0v6WhPgxkrjcU0LkHj+TwBrALwoz/OtMExvsqbbMI0ChyelKabSvQ== 59 | 60 | "@esbuild/linux-loong64@0.19.8": 61 | version "0.19.8" 62 | resolved "https://registry.yarnpkg.com/@esbuild/linux-loong64/-/linux-loong64-0.19.8.tgz#e2a5bbffe15748b49356a6cd7b2d5bf60c5a7123" 63 | integrity sha512-fHZWS2JJxnXt1uYJsDv9+b60WCc2RlvVAy1F76qOLtXRO+H4mjt3Tr6MJ5l7Q78X8KgCFudnTuiQRBhULUyBKQ== 64 | 65 | "@esbuild/linux-mips64el@0.19.8": 66 | version "0.19.8" 67 | resolved "https://registry.yarnpkg.com/@esbuild/linux-mips64el/-/linux-mips64el-0.19.8.tgz#1359331e6f6214f26f4b08db9b9df661c57cfa24" 68 | integrity sha512-Wy/z0EL5qZYLX66dVnEg9riiwls5IYnziwuju2oUiuxVc+/edvqXa04qNtbrs0Ukatg5HEzqT94Zs7J207dN5Q== 69 | 70 | "@esbuild/linux-ppc64@0.19.8": 71 | version "0.19.8" 72 | resolved "https://registry.yarnpkg.com/@esbuild/linux-ppc64/-/linux-ppc64-0.19.8.tgz#9ba436addc1646dc89dae48c62d3e951ffe70951" 73 | integrity sha512-ETaW6245wK23YIEufhMQ3HSeHO7NgsLx8gygBVldRHKhOlD1oNeNy/P67mIh1zPn2Hr2HLieQrt6tWrVwuqrxg== 74 | 75 | "@esbuild/linux-riscv64@0.19.8": 76 | version "0.19.8" 77 | resolved "https://registry.yarnpkg.com/@esbuild/linux-riscv64/-/linux-riscv64-0.19.8.tgz#fbcf0c3a0b20f40b5fc31c3b7695f0769f9de66b" 78 | integrity sha512-T2DRQk55SgoleTP+DtPlMrxi/5r9AeFgkhkZ/B0ap99zmxtxdOixOMI570VjdRCs9pE4Wdkz7JYrsPvsl7eESg== 79 | 80 | "@esbuild/linux-s390x@0.19.8": 81 | version "0.19.8" 82 | resolved "https://registry.yarnpkg.com/@esbuild/linux-s390x/-/linux-s390x-0.19.8.tgz#989e8a05f7792d139d5564ffa7ff898ac6f20a4a" 83 | integrity sha512-NPxbdmmo3Bk7mbNeHmcCd7R7fptJaczPYBaELk6NcXxy7HLNyWwCyDJ/Xx+/YcNH7Im5dHdx9gZ5xIwyliQCbg== 84 | 85 | "@esbuild/linux-x64@0.19.8": 86 | version "0.19.8" 87 | resolved "https://registry.yarnpkg.com/@esbuild/linux-x64/-/linux-x64-0.19.8.tgz#b187295393a59323397fe5ff51e769ec4e72212b" 88 | integrity sha512-lytMAVOM3b1gPypL2TRmZ5rnXl7+6IIk8uB3eLsV1JwcizuolblXRrc5ShPrO9ls/b+RTp+E6gbsuLWHWi2zGg== 89 | 90 | "@esbuild/netbsd-x64@0.19.8": 91 | version "0.19.8" 92 | resolved "https://registry.yarnpkg.com/@esbuild/netbsd-x64/-/netbsd-x64-0.19.8.tgz#c1ec0e24ea82313cb1c7bae176bd5acd5bde7137" 93 | integrity sha512-hvWVo2VsXz/8NVt1UhLzxwAfo5sioj92uo0bCfLibB0xlOmimU/DeAEsQILlBQvkhrGjamP0/el5HU76HAitGw== 94 | 95 | "@esbuild/openbsd-x64@0.19.8": 96 | version "0.19.8" 97 | resolved "https://registry.yarnpkg.com/@esbuild/openbsd-x64/-/openbsd-x64-0.19.8.tgz#0c5b696ac66c6d70cf9ee17073a581a28af9e18d" 98 | integrity sha512-/7Y7u77rdvmGTxR83PgaSvSBJCC2L3Kb1M/+dmSIvRvQPXXCuC97QAwMugBNG0yGcbEGfFBH7ojPzAOxfGNkwQ== 99 | 100 | "@esbuild/sunos-x64@0.19.8": 101 | version "0.19.8" 102 | resolved "https://registry.yarnpkg.com/@esbuild/sunos-x64/-/sunos-x64-0.19.8.tgz#2a697e1f77926ff09fcc457d8f29916d6cd48fb1" 103 | integrity sha512-9Lc4s7Oi98GqFA4HzA/W2JHIYfnXbUYgekUP/Sm4BG9sfLjyv6GKKHKKVs83SMicBF2JwAX6A1PuOLMqpD001w== 104 | 105 | "@esbuild/win32-arm64@0.19.8": 106 | version "0.19.8" 107 | resolved "https://registry.yarnpkg.com/@esbuild/win32-arm64/-/win32-arm64-0.19.8.tgz#ec029e62a2fca8c071842ecb1bc5c2dd20b066f1" 108 | integrity sha512-rq6WzBGjSzihI9deW3fC2Gqiak68+b7qo5/3kmB6Gvbh/NYPA0sJhrnp7wgV4bNwjqM+R2AApXGxMO7ZoGhIJg== 109 | 110 | "@esbuild/win32-ia32@0.19.8": 111 | version "0.19.8" 112 | resolved "https://registry.yarnpkg.com/@esbuild/win32-ia32/-/win32-ia32-0.19.8.tgz#cbb9a3146bde64dc15543e48afe418c7a3214851" 113 | integrity sha512-AIAbverbg5jMvJznYiGhrd3sumfwWs8572mIJL5NQjJa06P8KfCPWZQ0NwZbPQnbQi9OWSZhFVSUWjjIrn4hSw== 114 | 115 | "@esbuild/win32-x64@0.19.8": 116 | version "0.19.8" 117 | resolved "https://registry.yarnpkg.com/@esbuild/win32-x64/-/win32-x64-0.19.8.tgz#c8285183dbdb17008578dbacb6e22748709b4822" 118 | integrity sha512-bfZ0cQ1uZs2PqpulNL5j/3w+GDhP36k1K5c38QdQg+Swy51jFZWWeIkteNsufkQxp986wnqRRsb/bHbY1WQ7TA== 119 | 120 | "@microsoft/api-extractor-model@7.28.2": 121 | version "7.28.2" 122 | resolved "https://registry.yarnpkg.com/@microsoft/api-extractor-model/-/api-extractor-model-7.28.2.tgz#91c66dd820ccc70e0c163e06b392d8363f1b9269" 123 | integrity sha512-vkojrM2fo3q4n4oPh4uUZdjJ2DxQ2+RnDQL/xhTWSRUNPF6P4QyrvY357HBxbnltKcYu+nNNolVqc6TIGQ73Ig== 124 | dependencies: 125 | "@microsoft/tsdoc" "0.14.2" 126 | "@microsoft/tsdoc-config" "~0.16.1" 127 | "@rushstack/node-core-library" "3.61.0" 128 | 129 | "@microsoft/api-extractor@^7.38.0": 130 | version "7.38.4" 131 | resolved "https://registry.yarnpkg.com/@microsoft/api-extractor/-/api-extractor-7.38.4.tgz#bb7847cbec6af4f762762a0897c312d434e12ae5" 132 | integrity sha512-0SW3Of6os4bAYlHdiD1hJx/ygXr7vRZi92E1pREufNERH87aZ0B9Vhku/4Mj2Oxp58gyV5d18t7uZold6HCSEw== 133 | dependencies: 134 | "@microsoft/api-extractor-model" "7.28.2" 135 | "@microsoft/tsdoc" "0.14.2" 136 | "@microsoft/tsdoc-config" "~0.16.1" 137 | "@rushstack/node-core-library" "3.61.0" 138 | "@rushstack/rig-package" "0.5.1" 139 | "@rushstack/ts-command-line" "4.17.1" 140 | colors "~1.2.1" 141 | lodash "~4.17.15" 142 | resolve "~1.22.1" 143 | semver "~7.5.4" 144 | source-map "~0.6.1" 145 | typescript "~5.0.4" 146 | 147 | "@microsoft/tsdoc-config@~0.16.1": 148 | version "0.16.2" 149 | resolved "https://registry.yarnpkg.com/@microsoft/tsdoc-config/-/tsdoc-config-0.16.2.tgz#b786bb4ead00d54f53839a458ce626c8548d3adf" 150 | integrity sha512-OGiIzzoBLgWWR0UdRJX98oYO+XKGf7tiK4Zk6tQ/E4IJqGCe7dvkTvgDZV5cFJUzLGDOjeAXrnZoA6QkVySuxw== 151 | dependencies: 152 | "@microsoft/tsdoc" "0.14.2" 153 | ajv "~6.12.6" 154 | jju "~1.4.0" 155 | resolve "~1.19.0" 156 | 157 | "@microsoft/tsdoc@0.14.2": 158 | version "0.14.2" 159 | resolved "https://registry.yarnpkg.com/@microsoft/tsdoc/-/tsdoc-0.14.2.tgz#c3ec604a0b54b9a9b87e9735dfc59e1a5da6a5fb" 160 | integrity sha512-9b8mPpKrfeGRuhFH5iO1iwCLeIIsV6+H1sRfxbkoGXIyQE2BTsPd9zqSqQJ+pv5sJ/hT5M1zvOFL02MnEezFug== 161 | 162 | "@rollup/pluginutils@^5.0.5": 163 | version "5.1.0" 164 | resolved "https://registry.yarnpkg.com/@rollup/pluginutils/-/pluginutils-5.1.0.tgz#7e53eddc8c7f483a4ad0b94afb1f7f5fd3c771e0" 165 | integrity sha512-XTIWOPPcpvyKI6L1NHo0lFlCyznUEyPmPY1mc3KpPVDYulHSTvyeLNVW00QTLIAFNhR3kYnJTQHeGqU4M3n09g== 166 | dependencies: 167 | "@types/estree" "^1.0.0" 168 | estree-walker "^2.0.2" 169 | picomatch "^2.3.1" 170 | 171 | "@rollup/rollup-android-arm-eabi@4.6.1": 172 | version "4.6.1" 173 | resolved "https://registry.yarnpkg.com/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.6.1.tgz#0ea289f68ff248b50fea5716ca9f65f7d4dba3ae" 174 | integrity sha512-0WQ0ouLejaUCRsL93GD4uft3rOmB8qoQMU05Kb8CmMtMBe7XUDLAltxVZI1q6byNqEtU7N1ZX1Vw5lIpgulLQA== 175 | 176 | "@rollup/rollup-android-arm64@4.6.1": 177 | version "4.6.1" 178 | resolved "https://registry.yarnpkg.com/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.6.1.tgz#27c8c67fc5de574874085a1b480ac65b3e18378e" 179 | integrity sha512-1TKm25Rn20vr5aTGGZqo6E4mzPicCUD79k17EgTLAsXc1zysyi4xXKACfUbwyANEPAEIxkzwue6JZ+stYzWUTA== 180 | 181 | "@rollup/rollup-darwin-arm64@4.6.1": 182 | version "4.6.1" 183 | resolved "https://registry.yarnpkg.com/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.6.1.tgz#c5735c042980c85495411af7183dd20294763bd8" 184 | integrity sha512-cEXJQY/ZqMACb+nxzDeX9IPLAg7S94xouJJCNVE5BJM8JUEP4HeTF+ti3cmxWeSJo+5D+o8Tc0UAWUkfENdeyw== 185 | 186 | "@rollup/rollup-darwin-x64@4.6.1": 187 | version "4.6.1" 188 | resolved "https://registry.yarnpkg.com/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.6.1.tgz#af844bd54abb73ca3c9cf89a31eec17861d1375d" 189 | integrity sha512-LoSU9Xu56isrkV2jLldcKspJ7sSXmZWkAxg7sW/RfF7GS4F5/v4EiqKSMCFbZtDu2Nc1gxxFdQdKwkKS4rwxNg== 190 | 191 | "@rollup/rollup-linux-arm-gnueabihf@4.6.1": 192 | version "4.6.1" 193 | resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.6.1.tgz#5e972f63c441eaf859551039b3f18db9b035977d" 194 | integrity sha512-EfI3hzYAy5vFNDqpXsNxXcgRDcFHUWSx5nnRSCKwXuQlI5J9dD84g2Usw81n3FLBNsGCegKGwwTVsSKK9cooSQ== 195 | 196 | "@rollup/rollup-linux-arm64-gnu@4.6.1": 197 | version "4.6.1" 198 | resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.6.1.tgz#f4cfbc71e3b6fdb395b28b1472414e181515c72d" 199 | integrity sha512-9lhc4UZstsegbNLhH0Zu6TqvDfmhGzuCWtcTFXY10VjLLUe4Mr0Ye2L3rrtHaDd/J5+tFMEuo5LTCSCMXWfUKw== 200 | 201 | "@rollup/rollup-linux-arm64-musl@4.6.1": 202 | version "4.6.1" 203 | resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.6.1.tgz#6a94c691830dc29bf708de7c640f494996130893" 204 | integrity sha512-FfoOK1yP5ksX3wwZ4Zk1NgyGHZyuRhf99j64I5oEmirV8EFT7+OhUZEnP+x17lcP/QHJNWGsoJwrz4PJ9fBEXw== 205 | 206 | "@rollup/rollup-linux-x64-gnu@4.6.1": 207 | version "4.6.1" 208 | resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.6.1.tgz#f07bae3f7dc532d9ea5ab36c9071db329f9a1efb" 209 | integrity sha512-DNGZvZDO5YF7jN5fX8ZqmGLjZEXIJRdJEdTFMhiyXqyXubBa0WVLDWSNlQ5JR2PNgDbEV1VQowhVRUh+74D+RA== 210 | 211 | "@rollup/rollup-linux-x64-musl@4.6.1": 212 | version "4.6.1" 213 | resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.6.1.tgz#357a34fdbf410af88ce48bd802bea6462bb9a8bc" 214 | integrity sha512-RkJVNVRM+piYy87HrKmhbexCHg3A6Z6MU0W9GHnJwBQNBeyhCJG9KDce4SAMdicQnpURggSvtbGo9xAWOfSvIQ== 215 | 216 | "@rollup/rollup-win32-arm64-msvc@4.6.1": 217 | version "4.6.1" 218 | resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.6.1.tgz#b6e97fd38281667e35297033393cd1101f4a31be" 219 | integrity sha512-v2FVT6xfnnmTe3W9bJXl6r5KwJglMK/iRlkKiIFfO6ysKs0rDgz7Cwwf3tjldxQUrHL9INT/1r4VA0n9L/F1vQ== 220 | 221 | "@rollup/rollup-win32-ia32-msvc@4.6.1": 222 | version "4.6.1" 223 | resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.6.1.tgz#a95db026c640c8128bfd38546d85342f2329beaf" 224 | integrity sha512-YEeOjxRyEjqcWphH9dyLbzgkF8wZSKAKUkldRY6dgNR5oKs2LZazqGB41cWJ4Iqqcy9/zqYgmzBkRoVz3Q9MLw== 225 | 226 | "@rollup/rollup-win32-x64-msvc@4.6.1": 227 | version "4.6.1" 228 | resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.6.1.tgz#45785b5caf83200a34a9867ba50d69560880c120" 229 | integrity sha512-0zfTlFAIhgz8V2G8STq8toAjsYYA6eci1hnXuyOTUFnymrtJwnS6uGKiv3v5UrPZkBlamLvrLV2iiaeqCKzb0A== 230 | 231 | "@rushstack/node-core-library@3.61.0": 232 | version "3.61.0" 233 | resolved "https://registry.yarnpkg.com/@rushstack/node-core-library/-/node-core-library-3.61.0.tgz#7441a0d2ae5268b758a7a49588a78cd55af57e66" 234 | integrity sha512-tdOjdErme+/YOu4gPed3sFS72GhtWCgNV9oDsHDnoLY5oDfwjKUc9Z+JOZZ37uAxcm/OCahDHfuu2ugqrfWAVQ== 235 | dependencies: 236 | colors "~1.2.1" 237 | fs-extra "~7.0.1" 238 | import-lazy "~4.0.0" 239 | jju "~1.4.0" 240 | resolve "~1.22.1" 241 | semver "~7.5.4" 242 | z-schema "~5.0.2" 243 | 244 | "@rushstack/rig-package@0.5.1": 245 | version "0.5.1" 246 | resolved "https://registry.yarnpkg.com/@rushstack/rig-package/-/rig-package-0.5.1.tgz#6c9c283cc96b5bb1eae9875946d974ac5429bb21" 247 | integrity sha512-pXRYSe29TjRw7rqxD4WS3HN/sRSbfr+tJs4a9uuaSIBAITbUggygdhuG0VrO0EO+QqH91GhYMN4S6KRtOEmGVA== 248 | dependencies: 249 | resolve "~1.22.1" 250 | strip-json-comments "~3.1.1" 251 | 252 | "@rushstack/ts-command-line@4.17.1": 253 | version "4.17.1" 254 | resolved "https://registry.yarnpkg.com/@rushstack/ts-command-line/-/ts-command-line-4.17.1.tgz#c78db928ce5b93f2e98fd9e14c24f3f3876e57f1" 255 | integrity sha512-2jweO1O57BYP5qdBGl6apJLB+aRIn5ccIRTPDyULh0KMwVzFqWtw6IZWt1qtUoZD/pD2RNkIOosH6Cq45rIYeg== 256 | dependencies: 257 | "@types/argparse" "1.0.38" 258 | argparse "~1.0.9" 259 | colors "~1.2.1" 260 | string-argv "~0.3.1" 261 | 262 | "@types/argparse@1.0.38": 263 | version "1.0.38" 264 | resolved "https://registry.yarnpkg.com/@types/argparse/-/argparse-1.0.38.tgz#a81fd8606d481f873a3800c6ebae4f1d768a56a9" 265 | integrity sha512-ebDJ9b0e702Yr7pWgB0jzm+CX4Srzz8RcXtLJDJB+BSccqMa36uyH/zUsSYao5+BD1ytv3k3rPYCq4mAE1hsXA== 266 | 267 | "@types/d3-color@*": 268 | version "3.1.2" 269 | resolved "https://registry.yarnpkg.com/@types/d3-color/-/d3-color-3.1.2.tgz#7939eed011a908287cd1bcfd11580c17b2ac7f8a" 270 | integrity sha512-At+Ski7dL8Bs58E8g8vPcFJc8tGcaC12Z4m07+p41+DRqnZQcAlp3NfYjLrhNYv+zEyQitU1CUxXNjqUyf+c0g== 271 | 272 | "@types/d3-hierarchy@^3.1.6": 273 | version "3.1.6" 274 | resolved "https://registry.yarnpkg.com/@types/d3-hierarchy/-/d3-hierarchy-3.1.6.tgz#8d3638df273ec90da34b3ac89d8784c59708cb0d" 275 | integrity sha512-qlmD/8aMk5xGorUvTUWHCiumvgaUXYldYjNVOWtYoTYY/L+WwIEAmJxUmTgr9LoGNG0PPAOmqMDJVDPc7DOpPw== 276 | 277 | "@types/d3-interpolate@*": 278 | version "3.0.3" 279 | resolved "https://registry.yarnpkg.com/@types/d3-interpolate/-/d3-interpolate-3.0.3.tgz#e10c06c4bf11bd770ed56184a0d76cd516ff4ded" 280 | integrity sha512-6OZ2EIB4lLj+8cUY7I/Cgn9Q+hLdA4DjJHYOQDiHL0SzqS1K9DL5xIOVBSIHgF+tiuO9MU1D36qvdIvRDRPh+Q== 281 | dependencies: 282 | "@types/d3-color" "*" 283 | 284 | "@types/d3-selection@*": 285 | version "3.0.8" 286 | resolved "https://registry.yarnpkg.com/@types/d3-selection/-/d3-selection-3.0.8.tgz#9423511db3ed00a55aad4217ac8d546db5d8e5f5" 287 | integrity sha512-pxCZUfQyedq/DIlPXIR5wE1mIH37omOdx1yxRudL3KZ4AC+156jMjOv1z5RVlGq62f8WX2kyO0hTVgEx627QFg== 288 | 289 | "@types/d3-selection@^3.0.10": 290 | version "3.0.10" 291 | resolved "https://registry.yarnpkg.com/@types/d3-selection/-/d3-selection-3.0.10.tgz#98cdcf986d0986de6912b5892e7c015a95ca27fe" 292 | integrity sha512-cuHoUgS/V3hLdjJOLTT691+G2QoqAjCVLmr4kJXR4ha56w1Zdu8UUQ5TxLRqudgNjwXeQxKMq4j+lyf9sWuslg== 293 | 294 | "@types/d3-transition@^3.0.8": 295 | version "3.0.8" 296 | resolved "https://registry.yarnpkg.com/@types/d3-transition/-/d3-transition-3.0.8.tgz#677707f5eed5b24c66a1918cde05963021351a8f" 297 | integrity sha512-ew63aJfQ/ms7QQ4X7pk5NxQ9fZH/z+i24ZfJ6tJSfqxJMrYLiK01EAs2/Rtw/JreGUsS3pLPNV644qXFGnoZNQ== 298 | dependencies: 299 | "@types/d3-selection" "*" 300 | 301 | "@types/d3-zoom@^3.0.8": 302 | version "3.0.8" 303 | resolved "https://registry.yarnpkg.com/@types/d3-zoom/-/d3-zoom-3.0.8.tgz#dccb32d1c56b1e1c6e0f1180d994896f038bc40b" 304 | integrity sha512-iqMC4/YlFCSlO8+2Ii1GGGliCAY4XdeG748w5vQUbevlbDu0zSjH/+jojorQVBK/se0j6DUFNPBGSqD3YWYnDw== 305 | dependencies: 306 | "@types/d3-interpolate" "*" 307 | "@types/d3-selection" "*" 308 | 309 | "@types/estree@^1.0.0": 310 | version "1.0.5" 311 | resolved "https://registry.yarnpkg.com/@types/estree/-/estree-1.0.5.tgz#a6ce3e556e00fd9895dd872dd172ad0d4bd687f4" 312 | integrity sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw== 313 | 314 | "@types/node@^20.10.3": 315 | version "20.10.3" 316 | resolved "https://registry.yarnpkg.com/@types/node/-/node-20.10.3.tgz#4900adcc7fc189d5af5bb41da8f543cea6962030" 317 | integrity sha512-XJavIpZqiXID5Yxnxv3RUDKTN5b81ddNC3ecsA0SoFXz/QU8OGBwZGMomiq0zw+uuqbL/krztv/DINAQ/EV4gg== 318 | dependencies: 319 | undici-types "~5.26.4" 320 | 321 | "@volar/language-core@1.11.1", "@volar/language-core@~1.11.1": 322 | version "1.11.1" 323 | resolved "https://registry.yarnpkg.com/@volar/language-core/-/language-core-1.11.1.tgz#ecdf12ea8dc35fb8549e517991abcbf449a5ad4f" 324 | integrity sha512-dOcNn3i9GgZAcJt43wuaEykSluAuOkQgzni1cuxLxTV0nJKanQztp7FxyswdRILaKH+P2XZMPRp2S4MV/pElCw== 325 | dependencies: 326 | "@volar/source-map" "1.11.1" 327 | 328 | "@volar/source-map@1.11.1", "@volar/source-map@~1.11.1": 329 | version "1.11.1" 330 | resolved "https://registry.yarnpkg.com/@volar/source-map/-/source-map-1.11.1.tgz#535b0328d9e2b7a91dff846cab4058e191f4452f" 331 | integrity sha512-hJnOnwZ4+WT5iupLRnuzbULZ42L7BWWPMmruzwtLhJfpDVoZLjNBxHDi2sY2bgZXCKlpU5XcsMFoYrsQmPhfZg== 332 | dependencies: 333 | muggle-string "^0.3.1" 334 | 335 | "@volar/typescript@~1.11.1": 336 | version "1.11.1" 337 | resolved "https://registry.yarnpkg.com/@volar/typescript/-/typescript-1.11.1.tgz#ba86c6f326d88e249c7f5cfe4b765be3946fd627" 338 | integrity sha512-iU+t2mas/4lYierSnoFOeRFQUhAEMgsFuQxoxvwn5EdQopw43j+J27a4lt9LMInx1gLJBC6qL14WYGlgymaSMQ== 339 | dependencies: 340 | "@volar/language-core" "1.11.1" 341 | path-browserify "^1.0.1" 342 | 343 | "@vue/compiler-core@3.3.10": 344 | version "3.3.10" 345 | resolved "https://registry.yarnpkg.com/@vue/compiler-core/-/compiler-core-3.3.10.tgz#9ca4123a1458df43db641aaa8b7d1e636aa22545" 346 | integrity sha512-doe0hODR1+i1menPkRzJ5MNR6G+9uiZHIknK3Zn5OcIztu6GGw7u0XUzf3AgB8h/dfsZC9eouzoLo3c3+N/cVA== 347 | dependencies: 348 | "@babel/parser" "^7.23.5" 349 | "@vue/shared" "3.3.10" 350 | estree-walker "^2.0.2" 351 | source-map-js "^1.0.2" 352 | 353 | "@vue/compiler-dom@^3.3.0": 354 | version "3.3.10" 355 | resolved "https://registry.yarnpkg.com/@vue/compiler-dom/-/compiler-dom-3.3.10.tgz#183811252be6aff4ac923f783124bb1590301907" 356 | integrity sha512-NCrqF5fm10GXZIK0GrEAauBqdy+F2LZRt3yNHzrYjpYBuRssQbuPLtSnSNjyR9luHKkWSH8we5LMB3g+4z2HvA== 357 | dependencies: 358 | "@vue/compiler-core" "3.3.10" 359 | "@vue/shared" "3.3.10" 360 | 361 | "@vue/language-core@1.8.25", "@vue/language-core@^1.8.20": 362 | version "1.8.25" 363 | resolved "https://registry.yarnpkg.com/@vue/language-core/-/language-core-1.8.25.tgz#b44b4e3c244ba9b1b79cccf9eb7b046535a4676f" 364 | integrity sha512-NJk/5DnAZlpvXX8BdWmHI45bWGLViUaS3R/RMrmFSvFMSbJKuEODpM4kR0F0Ofv5SFzCWuNiMhxameWpVdQsnA== 365 | dependencies: 366 | "@volar/language-core" "~1.11.1" 367 | "@volar/source-map" "~1.11.1" 368 | "@vue/compiler-dom" "^3.3.0" 369 | "@vue/shared" "^3.3.0" 370 | computeds "^0.0.1" 371 | minimatch "^9.0.3" 372 | muggle-string "^0.3.1" 373 | path-browserify "^1.0.1" 374 | vue-template-compiler "^2.7.14" 375 | 376 | "@vue/shared@3.3.10", "@vue/shared@^3.3.0": 377 | version "3.3.10" 378 | resolved "https://registry.yarnpkg.com/@vue/shared/-/shared-3.3.10.tgz#1583a8d85a957d8b819078c465d2a11db7914b2f" 379 | integrity sha512-2y3Y2J1a3RhFa0WisHvACJR2ncvWiVHcP8t0Inxo+NKz+8RKO4ZV8eZgCxRgQoA6ITfV12L4E6POOL9HOU5nqw== 380 | 381 | ajv@~6.12.6: 382 | version "6.12.6" 383 | resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4" 384 | integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g== 385 | dependencies: 386 | fast-deep-equal "^3.1.1" 387 | fast-json-stable-stringify "^2.0.0" 388 | json-schema-traverse "^0.4.1" 389 | uri-js "^4.2.2" 390 | 391 | argparse@~1.0.9: 392 | version "1.0.10" 393 | resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911" 394 | integrity sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg== 395 | dependencies: 396 | sprintf-js "~1.0.2" 397 | 398 | balanced-match@^1.0.0: 399 | version "1.0.2" 400 | resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" 401 | integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== 402 | 403 | brace-expansion@^2.0.1: 404 | version "2.0.1" 405 | resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-2.0.1.tgz#1edc459e0f0c548486ecf9fc99f2221364b9a0ae" 406 | integrity sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA== 407 | dependencies: 408 | balanced-match "^1.0.0" 409 | 410 | colors@~1.2.1: 411 | version "1.2.5" 412 | resolved "https://registry.yarnpkg.com/colors/-/colors-1.2.5.tgz#89c7ad9a374bc030df8013241f68136ed8835afc" 413 | integrity sha512-erNRLao/Y3Fv54qUa0LBB+//Uf3YwMUmdJinN20yMXm9zdKKqH9wt7R9IIVZ+K7ShzfpLV/Zg8+VyrBJYB4lpg== 414 | 415 | commander@^10.0.0: 416 | version "10.0.1" 417 | resolved "https://registry.yarnpkg.com/commander/-/commander-10.0.1.tgz#881ee46b4f77d1c1dccc5823433aa39b022cbe06" 418 | integrity sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug== 419 | 420 | computeds@^0.0.1: 421 | version "0.0.1" 422 | resolved "https://registry.yarnpkg.com/computeds/-/computeds-0.0.1.tgz#215b08a4ba3e08a11ff6eee5d6d8d7166a97ce2e" 423 | integrity sha512-7CEBgcMjVmitjYo5q8JTJVra6X5mQ20uTThdK+0kR7UEaDrAWEQcRiBtWJzga4eRpP6afNwwLsX2SET2JhVB1Q== 424 | 425 | "d3-color@1 - 3": 426 | version "3.1.0" 427 | resolved "https://registry.yarnpkg.com/d3-color/-/d3-color-3.1.0.tgz#395b2833dfac71507f12ac2f7af23bf819de24e2" 428 | integrity sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA== 429 | 430 | "d3-dispatch@1 - 3": 431 | version "3.0.1" 432 | resolved "https://registry.yarnpkg.com/d3-dispatch/-/d3-dispatch-3.0.1.tgz#5fc75284e9c2375c36c839411a0cf550cbfc4d5e" 433 | integrity sha512-rzUyPU/S7rwUflMyLc1ETDeBj0NRuHKKAcvukozwhshr6g6c5d8zh4c2gQjY2bZ0dXeGLWc1PF174P2tVvKhfg== 434 | 435 | "d3-drag@2 - 3": 436 | version "3.0.0" 437 | resolved "https://registry.yarnpkg.com/d3-drag/-/d3-drag-3.0.0.tgz#994aae9cd23c719f53b5e10e3a0a6108c69607ba" 438 | integrity sha512-pWbUJLdETVA8lQNJecMxoXfH6x+mO2UQo8rSmZ+QqxcbyA3hfeprFgIT//HW2nlHChWeIIMwS2Fq+gEARkhTkg== 439 | dependencies: 440 | d3-dispatch "1 - 3" 441 | d3-selection "3" 442 | 443 | "d3-ease@1 - 3": 444 | version "3.0.1" 445 | resolved "https://registry.yarnpkg.com/d3-ease/-/d3-ease-3.0.1.tgz#9658ac38a2140d59d346160f1f6c30fda0bd12f4" 446 | integrity sha512-wR/XK3D3XcLIZwpbvQwQ5fK+8Ykds1ip7A2Txe0yxncXSdq1L9skcG7blcedkOX+ZcgxGAmLX1FrRGbADwzi0w== 447 | 448 | d3-hierarchy@^3.1.2: 449 | version "3.1.2" 450 | resolved "https://registry.yarnpkg.com/d3-hierarchy/-/d3-hierarchy-3.1.2.tgz#b01cd42c1eed3d46db77a5966cf726f8c09160c6" 451 | integrity sha512-FX/9frcub54beBdugHjDCdikxThEqjnR93Qt7PvQTOHxyiNCAlvMrHhclk3cD5VeAaq9fxmfRp+CnWw9rEMBuA== 452 | 453 | "d3-interpolate@1 - 3": 454 | version "3.0.1" 455 | resolved "https://registry.yarnpkg.com/d3-interpolate/-/d3-interpolate-3.0.1.tgz#3c47aa5b32c5b3dfb56ef3fd4342078a632b400d" 456 | integrity sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g== 457 | dependencies: 458 | d3-color "1 - 3" 459 | 460 | "d3-selection@2 - 3", d3-selection@3, d3-selection@^3.0.0: 461 | version "3.0.0" 462 | resolved "https://registry.yarnpkg.com/d3-selection/-/d3-selection-3.0.0.tgz#c25338207efa72cc5b9bd1458a1a41901f1e1b31" 463 | integrity sha512-fmTRWbNMmsmWq6xJV8D19U/gw/bwrHfNXxrIN+HfZgnzqTHp9jOmKMhsTUjXOJnZOdZY9Q28y4yebKzqDKlxlQ== 464 | 465 | "d3-timer@1 - 3": 466 | version "3.0.1" 467 | resolved "https://registry.yarnpkg.com/d3-timer/-/d3-timer-3.0.1.tgz#6284d2a2708285b1abb7e201eda4380af35e63b0" 468 | integrity sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA== 469 | 470 | "d3-transition@2 - 3", d3-transition@^3.0.1: 471 | version "3.0.1" 472 | resolved "https://registry.yarnpkg.com/d3-transition/-/d3-transition-3.0.1.tgz#6869fdde1448868077fdd5989200cb61b2a1645f" 473 | integrity sha512-ApKvfjsSR6tg06xrL434C0WydLr7JewBB3V+/39RMHsaXTOG0zmt/OAXeng5M5LBm0ojmxJrpomQVZ1aPvBL4w== 474 | dependencies: 475 | d3-color "1 - 3" 476 | d3-dispatch "1 - 3" 477 | d3-ease "1 - 3" 478 | d3-interpolate "1 - 3" 479 | d3-timer "1 - 3" 480 | 481 | d3-zoom@^3.0.0: 482 | version "3.0.0" 483 | resolved "https://registry.yarnpkg.com/d3-zoom/-/d3-zoom-3.0.0.tgz#d13f4165c73217ffeaa54295cd6969b3e7aee8f3" 484 | integrity sha512-b8AmV3kfQaqWAuacbPuNbL6vahnOJflOhexLzMMNLga62+/nh0JzvJ0aO/5a5MVgUFGS7Hu1P9P03o3fJkDCyw== 485 | dependencies: 486 | d3-dispatch "1 - 3" 487 | d3-drag "2 - 3" 488 | d3-interpolate "1 - 3" 489 | d3-selection "2 - 3" 490 | d3-transition "2 - 3" 491 | 492 | de-indent@^1.0.2: 493 | version "1.0.2" 494 | resolved "https://registry.yarnpkg.com/de-indent/-/de-indent-1.0.2.tgz#b2038e846dc33baa5796128d0804b455b8c1e21d" 495 | integrity sha512-e/1zu3xH5MQryN2zdVaF0OrdNLUbvWxzMbi+iNA6Bky7l1RoP8a2fIbRocyHclXt/arDrrR6lL3TqFD9pMQTsg== 496 | 497 | debug@^4.3.4: 498 | version "4.3.4" 499 | resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865" 500 | integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ== 501 | dependencies: 502 | ms "2.1.2" 503 | 504 | esbuild@^0.19.3: 505 | version "0.19.8" 506 | resolved "https://registry.yarnpkg.com/esbuild/-/esbuild-0.19.8.tgz#ad05b72281d84483fa6b5345bd246c27a207b8f1" 507 | integrity sha512-l7iffQpT2OrZfH2rXIp7/FkmaeZM0vxbxN9KfiCwGYuZqzMg/JdvX26R31Zxn/Pxvsrg3Y9N6XTcnknqDyyv4w== 508 | optionalDependencies: 509 | "@esbuild/android-arm" "0.19.8" 510 | "@esbuild/android-arm64" "0.19.8" 511 | "@esbuild/android-x64" "0.19.8" 512 | "@esbuild/darwin-arm64" "0.19.8" 513 | "@esbuild/darwin-x64" "0.19.8" 514 | "@esbuild/freebsd-arm64" "0.19.8" 515 | "@esbuild/freebsd-x64" "0.19.8" 516 | "@esbuild/linux-arm" "0.19.8" 517 | "@esbuild/linux-arm64" "0.19.8" 518 | "@esbuild/linux-ia32" "0.19.8" 519 | "@esbuild/linux-loong64" "0.19.8" 520 | "@esbuild/linux-mips64el" "0.19.8" 521 | "@esbuild/linux-ppc64" "0.19.8" 522 | "@esbuild/linux-riscv64" "0.19.8" 523 | "@esbuild/linux-s390x" "0.19.8" 524 | "@esbuild/linux-x64" "0.19.8" 525 | "@esbuild/netbsd-x64" "0.19.8" 526 | "@esbuild/openbsd-x64" "0.19.8" 527 | "@esbuild/sunos-x64" "0.19.8" 528 | "@esbuild/win32-arm64" "0.19.8" 529 | "@esbuild/win32-ia32" "0.19.8" 530 | "@esbuild/win32-x64" "0.19.8" 531 | 532 | estree-walker@^2.0.2: 533 | version "2.0.2" 534 | resolved "https://registry.yarnpkg.com/estree-walker/-/estree-walker-2.0.2.tgz#52f010178c2a4c117a7757cfe942adb7d2da4cac" 535 | integrity sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w== 536 | 537 | fast-deep-equal@^3.1.1: 538 | version "3.1.3" 539 | resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525" 540 | integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q== 541 | 542 | fast-json-stable-stringify@^2.0.0: 543 | version "2.1.0" 544 | resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633" 545 | integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw== 546 | 547 | fs-extra@~7.0.1: 548 | version "7.0.1" 549 | resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-7.0.1.tgz#4f189c44aa123b895f722804f55ea23eadc348e9" 550 | integrity sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw== 551 | dependencies: 552 | graceful-fs "^4.1.2" 553 | jsonfile "^4.0.0" 554 | universalify "^0.1.0" 555 | 556 | fsevents@~2.3.2, fsevents@~2.3.3: 557 | version "2.3.3" 558 | resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.3.tgz#cac6407785d03675a2a5e1a5305c697b347d90d6" 559 | integrity sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw== 560 | 561 | function-bind@^1.1.2: 562 | version "1.1.2" 563 | resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.2.tgz#2c02d864d97f3ea6c8830c464cbd11ab6eab7a1c" 564 | integrity sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA== 565 | 566 | graceful-fs@^4.1.2, graceful-fs@^4.1.6: 567 | version "4.2.11" 568 | resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.11.tgz#4183e4e8bf08bb6e05bbb2f7d2e0c8f712ca40e3" 569 | integrity sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ== 570 | 571 | hasown@^2.0.0: 572 | version "2.0.0" 573 | resolved "https://registry.yarnpkg.com/hasown/-/hasown-2.0.0.tgz#f4c513d454a57b7c7e1650778de226b11700546c" 574 | integrity sha512-vUptKVTpIJhcczKBbgnS+RtcuYMB8+oNzPK2/Hp3hanz8JmpATdmmgLgSaadVREkDm+e2giHwY3ZRkyjSIDDFA== 575 | dependencies: 576 | function-bind "^1.1.2" 577 | 578 | he@^1.2.0: 579 | version "1.2.0" 580 | resolved "https://registry.yarnpkg.com/he/-/he-1.2.0.tgz#84ae65fa7eafb165fddb61566ae14baf05664f0f" 581 | integrity sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw== 582 | 583 | import-lazy@~4.0.0: 584 | version "4.0.0" 585 | resolved "https://registry.yarnpkg.com/import-lazy/-/import-lazy-4.0.0.tgz#e8eb627483a0a43da3c03f3e35548be5cb0cc153" 586 | integrity sha512-rKtvo6a868b5Hu3heneU+L4yEQ4jYKLtjpnPeUdK7h0yzXGmyBTypknlkCvHFBqfX9YlorEiMM6Dnq/5atfHkw== 587 | 588 | is-core-module@^2.1.0, is-core-module@^2.13.0: 589 | version "2.13.1" 590 | resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.13.1.tgz#ad0d7532c6fea9da1ebdc82742d74525c6273384" 591 | integrity sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw== 592 | dependencies: 593 | hasown "^2.0.0" 594 | 595 | jju@~1.4.0: 596 | version "1.4.0" 597 | resolved "https://registry.yarnpkg.com/jju/-/jju-1.4.0.tgz#a3abe2718af241a2b2904f84a625970f389ae32a" 598 | integrity sha512-8wb9Yw966OSxApiCt0K3yNJL8pnNeIv+OEq2YMidz4FKP6nonSRoOXc80iXY4JaN2FC11B9qsNmDsm+ZOfMROA== 599 | 600 | json-schema-traverse@^0.4.1: 601 | version "0.4.1" 602 | resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660" 603 | integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg== 604 | 605 | jsonfile@^4.0.0: 606 | version "4.0.0" 607 | resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-4.0.0.tgz#8771aae0799b64076b76640fca058f9c10e33ecb" 608 | integrity sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg== 609 | optionalDependencies: 610 | graceful-fs "^4.1.6" 611 | 612 | kolorist@^1.8.0: 613 | version "1.8.0" 614 | resolved "https://registry.yarnpkg.com/kolorist/-/kolorist-1.8.0.tgz#edddbbbc7894bc13302cdf740af6374d4a04743c" 615 | integrity sha512-Y+60/zizpJ3HRH8DCss+q95yr6145JXZo46OTpFvDZWLfRCE4qChOyk1b26nMaNpfHHgxagk9dXT5OP0Tfe+dQ== 616 | 617 | lodash.get@^4.4.2: 618 | version "4.4.2" 619 | resolved "https://registry.yarnpkg.com/lodash.get/-/lodash.get-4.4.2.tgz#2d177f652fa31e939b4438d5341499dfa3825e99" 620 | integrity sha512-z+Uw/vLuy6gQe8cfaFWD7p0wVv8fJl3mbzXh33RS+0oW2wvUqiRXiQ69gLWSLpgB5/6sU+r6BlQR0MBILadqTQ== 621 | 622 | lodash.isequal@^4.5.0: 623 | version "4.5.0" 624 | resolved "https://registry.yarnpkg.com/lodash.isequal/-/lodash.isequal-4.5.0.tgz#415c4478f2bcc30120c22ce10ed3226f7d3e18e0" 625 | integrity sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ== 626 | 627 | lodash@~4.17.15: 628 | version "4.17.21" 629 | resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" 630 | integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== 631 | 632 | lru-cache@^6.0.0: 633 | version "6.0.0" 634 | resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-6.0.0.tgz#6d6fe6570ebd96aaf90fcad1dafa3b2566db3a94" 635 | integrity sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA== 636 | dependencies: 637 | yallist "^4.0.0" 638 | 639 | minimatch@^9.0.3: 640 | version "9.0.3" 641 | resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-9.0.3.tgz#a6e00c3de44c3a542bfaae70abfc22420a6da825" 642 | integrity sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg== 643 | dependencies: 644 | brace-expansion "^2.0.1" 645 | 646 | ms@2.1.2: 647 | version "2.1.2" 648 | resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" 649 | integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== 650 | 651 | muggle-string@^0.3.1: 652 | version "0.3.1" 653 | resolved "https://registry.yarnpkg.com/muggle-string/-/muggle-string-0.3.1.tgz#e524312eb1728c63dd0b2ac49e3282e6ed85963a" 654 | integrity sha512-ckmWDJjphvd/FvZawgygcUeQCxzvohjFO5RxTjj4eq8kw359gFF3E1brjfI+viLMxss5JrHTDRHZvu2/tuy0Qg== 655 | 656 | nanoid@^3.3.7: 657 | version "3.3.7" 658 | resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.7.tgz#d0c301a691bc8d54efa0a2226ccf3fe2fd656bd8" 659 | integrity sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g== 660 | 661 | path-browserify@^1.0.1: 662 | version "1.0.1" 663 | resolved "https://registry.yarnpkg.com/path-browserify/-/path-browserify-1.0.1.tgz#d98454a9c3753d5790860f16f68867b9e46be1fd" 664 | integrity sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g== 665 | 666 | path-parse@^1.0.6, path-parse@^1.0.7: 667 | version "1.0.7" 668 | resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735" 669 | integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw== 670 | 671 | picocolors@^1.0.0: 672 | version "1.0.0" 673 | resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.0.0.tgz#cb5bdc74ff3f51892236eaf79d68bc44564ab81c" 674 | integrity sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ== 675 | 676 | picomatch@^2.3.1: 677 | version "2.3.1" 678 | resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42" 679 | integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA== 680 | 681 | postcss@^8.4.32: 682 | version "8.4.32" 683 | resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.32.tgz#1dac6ac51ab19adb21b8b34fd2d93a86440ef6c9" 684 | integrity sha512-D/kj5JNu6oo2EIy+XL/26JEDTlIbB8hw85G8StOE6L74RQAVVP5rej6wxCNqyMbR4RkPfqvezVbPw81Ngd6Kcw== 685 | dependencies: 686 | nanoid "^3.3.7" 687 | picocolors "^1.0.0" 688 | source-map-js "^1.0.2" 689 | 690 | punycode@^2.1.0: 691 | version "2.3.1" 692 | resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.3.1.tgz#027422e2faec0b25e1549c3e1bd8309b9133b6e5" 693 | integrity sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg== 694 | 695 | resolve@~1.19.0: 696 | version "1.19.0" 697 | resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.19.0.tgz#1af5bf630409734a067cae29318aac7fa29a267c" 698 | integrity sha512-rArEXAgsBG4UgRGcynxWIWKFvh/XZCcS8UJdHhwy91zwAvCZIbcs+vAbflgBnNjYMs/i/i+/Ux6IZhML1yPvxg== 699 | dependencies: 700 | is-core-module "^2.1.0" 701 | path-parse "^1.0.6" 702 | 703 | resolve@~1.22.1: 704 | version "1.22.8" 705 | resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.8.tgz#b6c87a9f2aa06dfab52e3d70ac8cde321fa5a48d" 706 | integrity sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw== 707 | dependencies: 708 | is-core-module "^2.13.0" 709 | path-parse "^1.0.7" 710 | supports-preserve-symlinks-flag "^1.0.0" 711 | 712 | rollup@^4.2.0: 713 | version "4.6.1" 714 | resolved "https://registry.yarnpkg.com/rollup/-/rollup-4.6.1.tgz#351501c86b5b4f976dde8c5837516452b59921f8" 715 | integrity sha512-jZHaZotEHQaHLgKr8JnQiDT1rmatjgKlMekyksz+yk9jt/8z9quNjnKNRoaM0wd9DC2QKXjmWWuDYtM3jfF8pQ== 716 | optionalDependencies: 717 | "@rollup/rollup-android-arm-eabi" "4.6.1" 718 | "@rollup/rollup-android-arm64" "4.6.1" 719 | "@rollup/rollup-darwin-arm64" "4.6.1" 720 | "@rollup/rollup-darwin-x64" "4.6.1" 721 | "@rollup/rollup-linux-arm-gnueabihf" "4.6.1" 722 | "@rollup/rollup-linux-arm64-gnu" "4.6.1" 723 | "@rollup/rollup-linux-arm64-musl" "4.6.1" 724 | "@rollup/rollup-linux-x64-gnu" "4.6.1" 725 | "@rollup/rollup-linux-x64-musl" "4.6.1" 726 | "@rollup/rollup-win32-arm64-msvc" "4.6.1" 727 | "@rollup/rollup-win32-ia32-msvc" "4.6.1" 728 | "@rollup/rollup-win32-x64-msvc" "4.6.1" 729 | fsevents "~2.3.2" 730 | 731 | semver@^7.5.4, semver@~7.5.4: 732 | version "7.5.4" 733 | resolved "https://registry.yarnpkg.com/semver/-/semver-7.5.4.tgz#483986ec4ed38e1c6c48c34894a9182dbff68a6e" 734 | integrity sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA== 735 | dependencies: 736 | lru-cache "^6.0.0" 737 | 738 | source-map-js@^1.0.2: 739 | version "1.0.2" 740 | resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-1.0.2.tgz#adbc361d9c62df380125e7f161f71c826f1e490c" 741 | integrity sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw== 742 | 743 | source-map@~0.6.1: 744 | version "0.6.1" 745 | resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" 746 | integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== 747 | 748 | sprintf-js@~1.0.2: 749 | version "1.0.3" 750 | resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" 751 | integrity sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g== 752 | 753 | string-argv@~0.3.1: 754 | version "0.3.2" 755 | resolved "https://registry.yarnpkg.com/string-argv/-/string-argv-0.3.2.tgz#2b6d0ef24b656274d957d54e0a4bbf6153dc02b6" 756 | integrity sha512-aqD2Q0144Z+/RqG52NeHEkZauTAUWJO8c6yTftGJKO3Tja5tUgIfmIl6kExvhtxSDP7fXB6DvzkfMpCd/F3G+Q== 757 | 758 | strip-json-comments@~3.1.1: 759 | version "3.1.1" 760 | resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006" 761 | integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig== 762 | 763 | supports-preserve-symlinks-flag@^1.0.0: 764 | version "1.0.0" 765 | resolved "https://registry.yarnpkg.com/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz#6eda4bd344a3c94aea376d4cc31bc77311039e09" 766 | integrity sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w== 767 | 768 | typescript@^5.3.2: 769 | version "5.3.2" 770 | resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.3.2.tgz#00d1c7c1c46928c5845c1ee8d0cc2791031d4c43" 771 | integrity sha512-6l+RyNy7oAHDfxC4FzSJcz9vnjTKxrLpDG5M2Vu4SHRVNg6xzqZp6LYSR9zjqQTu8DU/f5xwxUdADOkbrIX2gQ== 772 | 773 | typescript@~5.0.4: 774 | version "5.0.4" 775 | resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.0.4.tgz#b217fd20119bd61a94d4011274e0ab369058da3b" 776 | integrity sha512-cW9T5W9xY37cc+jfEnaUvX91foxtHkza3Nw3wkoF4sSlKn0MONdkdEndig/qPBWXNkmplh3NzayQzCiHM4/hqw== 777 | 778 | undici-types@~5.26.4: 779 | version "5.26.5" 780 | resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-5.26.5.tgz#bcd539893d00b56e964fd2657a4866b221a65617" 781 | integrity sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA== 782 | 783 | universalify@^0.1.0: 784 | version "0.1.2" 785 | resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.1.2.tgz#b646f69be3942dabcecc9d6639c80dc105efaa66" 786 | integrity sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg== 787 | 788 | uri-js@^4.2.2: 789 | version "4.4.1" 790 | resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.4.1.tgz#9b1a52595225859e55f669d928f88c6c57f2a77e" 791 | integrity sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg== 792 | dependencies: 793 | punycode "^2.1.0" 794 | 795 | validator@^13.7.0: 796 | version "13.11.0" 797 | resolved "https://registry.yarnpkg.com/validator/-/validator-13.11.0.tgz#23ab3fd59290c61248364eabf4067f04955fbb1b" 798 | integrity sha512-Ii+sehpSfZy+At5nPdnyMhx78fEoPDkR2XW/zimHEL3MyGJQOCQ7WeP20jPYRz7ZCpcKLB21NxuXHF3bxjStBQ== 799 | 800 | vite-plugin-dts@^3.6.4: 801 | version "3.6.4" 802 | resolved "https://registry.yarnpkg.com/vite-plugin-dts/-/vite-plugin-dts-3.6.4.tgz#4ac51f6a5ca081ed18bc331cebc967545dac31fd" 803 | integrity sha512-yOVhUI/kQhtS6lCXRYYLv2UUf9bftcwQK9ROxCX2ul17poLQs02ctWX7+vXB8GPRzH8VCK3jebEFtPqqijXx6w== 804 | dependencies: 805 | "@microsoft/api-extractor" "^7.38.0" 806 | "@rollup/pluginutils" "^5.0.5" 807 | "@vue/language-core" "^1.8.20" 808 | debug "^4.3.4" 809 | kolorist "^1.8.0" 810 | vue-tsc "^1.8.20" 811 | 812 | vite@^5.0.6: 813 | version "5.0.6" 814 | resolved "https://registry.yarnpkg.com/vite/-/vite-5.0.6.tgz#f9e13503a4c5ccd67312c67803dec921f3bdea7c" 815 | integrity sha512-MD3joyAEBtV7QZPl2JVVUai6zHms3YOmLR+BpMzLlX2Yzjfcc4gTgNi09d/Rua3F4EtC8zdwPU8eQYyib4vVMQ== 816 | dependencies: 817 | esbuild "^0.19.3" 818 | postcss "^8.4.32" 819 | rollup "^4.2.0" 820 | optionalDependencies: 821 | fsevents "~2.3.3" 822 | 823 | vue-template-compiler@^2.7.14: 824 | version "2.7.15" 825 | resolved "https://registry.yarnpkg.com/vue-template-compiler/-/vue-template-compiler-2.7.15.tgz#ec88ba8ceafe0f17a528b89c57e01e02da92b0de" 826 | integrity sha512-yQxjxMptBL7UAog00O8sANud99C6wJF+7kgbcwqkvA38vCGF7HWE66w0ZFnS/kX5gSoJr/PQ4/oS3Ne2pW37Og== 827 | dependencies: 828 | de-indent "^1.0.2" 829 | he "^1.2.0" 830 | 831 | vue-tsc@^1.8.20: 832 | version "1.8.25" 833 | resolved "https://registry.yarnpkg.com/vue-tsc/-/vue-tsc-1.8.25.tgz#90cd03e71d28c5c4a8068167b232eb97cc96b77f" 834 | integrity sha512-lHsRhDc/Y7LINvYhZ3pv4elflFADoEOo67vfClAfF2heVHpHmVquLSjojgCSIwzA4F0Pc4vowT/psXCYcfk+iQ== 835 | dependencies: 836 | "@volar/typescript" "~1.11.1" 837 | "@vue/language-core" "1.8.25" 838 | semver "^7.5.4" 839 | 840 | yallist@^4.0.0: 841 | version "4.0.0" 842 | resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72" 843 | integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A== 844 | 845 | z-schema@~5.0.2: 846 | version "5.0.6" 847 | resolved "https://registry.yarnpkg.com/z-schema/-/z-schema-5.0.6.tgz#46d6a687b15e4a4369e18d6cb1c7b8618fc256c5" 848 | integrity sha512-+XR1GhnWklYdfr8YaZv/iu+vY+ux7V5DS5zH1DQf6bO5ufrt/5cgNhVO5qyhsjFXvsqQb/f08DWE9b6uPscyAg== 849 | dependencies: 850 | lodash.get "^4.4.2" 851 | lodash.isequal "^4.5.0" 852 | validator "^13.7.0" 853 | optionalDependencies: 854 | commander "^10.0.0" 855 | --------------------------------------------------------------------------------