Repository: flavioschneider/graphire
Branch: main
Commit: caf24320669e
Files: 32
Total size: 145.1 KB
Directory structure:
gitextract_o4sk2iiy/
├── .eslintrc.json
├── .gitignore
├── .npmignore
├── .prettierrc
├── .storybook/
│ ├── index.css
│ ├── main.js
│ ├── preview.js
│ ├── public/
│ │ ├── tree.json
│ │ └── treeLarge.json
│ ├── stories/
│ │ ├── LayoutForceGraph.stories.tsx
│ │ ├── LayoutForceParticles.stories.tsx
│ │ ├── NoLayoutDragDropR3F.stories.tsx
│ │ ├── NoLayoutDragDropSVG.stories.jsx
│ │ └── useDrag.tsx
│ └── tsconfig.json
├── LICENSE
├── README.md
├── package.json
├── rollup.config.js
├── src/
│ ├── graph.tsx
│ ├── hooks.js
│ ├── index.ts
│ ├── layouts/
│ │ ├── force/
│ │ │ ├── forceCenter.jsx
│ │ │ ├── forceCollide.jsx
│ │ │ ├── forceDirection.jsx
│ │ │ ├── forceLink.jsx
│ │ │ ├── forceManyBody.jsx
│ │ │ └── layoutForce.jsx
│ │ ├── index.jsx
│ │ └── layer/
│ │ └── layoutLayer.jsx
│ └── utils.js
└── tsconfig.json
================================================
FILE CONTENTS
================================================
================================================
FILE: .eslintrc.json
================================================
{
"env": {
"browser": true,
"es6": true,
"node": true
},
"extends": [
"prettier",
"prettier/react",
"prettier/@typescript-eslint",
"plugin:prettier/recommended",
"plugin:react-hooks/recommended",
"plugin:import/errors",
"plugin:import/warnings",
"prettier",
"prettier/react",
"prettier/@typescript-eslint"
],
"plugins": ["@typescript-eslint", "react", "react-hooks", "import", "jest", "prettier"],
"parser": "@typescript-eslint/parser",
"parserOptions": {
"ecmaFeatures": {
"jsx": true
},
"ecmaVersion": 2018,
"sourceType": "module",
"rules": {
"curly": ["warn", "multi-line", "consistent"],
"no-console": "off",
"no-empty-pattern": "warn",
"no-duplicate-imports": "error",
"import/no-unresolved": "off",
"import/export": "error",
// https://github.com/typescript-eslint/typescript-eslint/blob/master/docs/getting-started/linting/FAQ.md#eslint-plugin-import
// We recommend you do not use the following import/* rules, as TypeScript provides the same checks as part of standard type checking:
"import/named": "off",
"import/namespace": "off",
"import/default": "off",
"no-unused-vars": ["warn", { "argsIgnorePattern": "^_", "varsIgnorePattern": "^_" }],
"@typescript-eslint/no-unused-vars": ["warn", { "argsIgnorePattern": "^_", "varsIgnorePattern": "^_" }],
"@typescript-eslint/no-use-before-define": "off",
"@typescript-eslint/no-empty-function": "off",
"@typescript-eslint/no-empty-interface": "off",
"@typescript-eslint/no-explicit-any": "off",
"jest/consistent-test-it": ["error", { "fn": "it", "withinDescribe": "it" }]
}
},
"settings": {
"react": {
"version": "detect"
},
"import/extensions": [".js", ".jsx", ".ts", ".tsx"],
"import/parsers": {
"@typescript-eslint/parser": [".js", ".jsx", ".ts", ".tsx"]
},
"import/resolver": {
"node": {
"extensions": [".js", ".jsx", ".ts", ".tsx", ".json"],
"paths": ["src"]
},
"alias": {
"extensions": [".js", ".jsx", ".ts", ".tsx", ".json"],
"map": [["react-three-fiber", "./src/targets/web.tsx"]]
}
}
},
"overrides": [
{
"files": ["src"],
"parserOptions": {
"project": "./tsconfig.json"
}
}
]
}
================================================
FILE: .gitignore
================================================
# misc
.DS_Store
.env.local
.env.development.local
.env.test.local
.env.production.local
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
# Directory for instrumented libs generated by jscoverage/JSCover
lib-cov
# Coverage directory used by tools like istanbul
coverage
*.lcov
# nyc test coverage
.nyc_output
# Compiled binary addons (https://nodejs.org/api/addons.html)
build/
# Dependency directories
node_modules/
jspm_packages/
# TypeScript cache
*.tsbuildinfo
# Optional eslint cache
.eslintcache
# Output of 'npm pack'
*.tgz
# Yarn Integrity file
.yarn-integrity
# pnpm lock
pnpm-lock.yaml
dist
================================================
FILE: .npmignore
================================================
.storybook
storybook-static
================================================
FILE: .prettierrc
================================================
{
"semi": false,
"trailingComma": "es5",
"singleQuote": true,
"tabWidth": 2,
"printWidth": 120
}
================================================
FILE: .storybook/index.css
================================================
html,
body,
#root {
width: 100%;
height: 100%;
margin: 0;
padding: 0;
overflow: hidden;
background-color: #2f3542;
}
#root {
overflow: auto;
}
================================================
FILE: .storybook/main.js
================================================
const path = require('path')
module.exports = {
stories: ['./stories/**/*.stories.{js,jsx,ts,tsx}'],
addons: [
//'@storybook/addon-knobs/register',
'@storybook/addon-controls',
'@storybook/addon-actions',
'@storybook/addon-storysource',
],
webpackFinal: (config) => {
config.module.rules.push({
test: /\.(glsl|vs|fs|vert|frag)$/,
exclude: /node_modules/,
use: ['raw-loader', 'glslify-loader'],
include: path.resolve(__dirname, '../'),
})
return config
},
}
================================================
FILE: .storybook/preview.js
================================================
import './index.css'
export const parameters = {
layout: 'fullscreen',
}
================================================
FILE: .storybook/public/tree.json
================================================
{
"nodes": [
{ "id": 0 },
{ "id": 1 },
{ "id": 2 },
{ "id": 3 },
{ "id": 4 },
{ "id": 5 },
{ "id": 6 },
{ "id": 7 },
{ "id": 8 },
{ "id": 9 },
{ "id": 10 },
{ "id": 11 },
{ "id": 12 },
{ "id": 13 },
{ "id": 14 },
{ "id": 15 },
{ "id": 16 },
{ "id": 17 },
{ "id": 18 },
{ "id": 19 },
{ "id": 20 },
{ "id": 21 },
{ "id": 22 },
{ "id": 23 },
{ "id": 24 },
{ "id": 25 },
{ "id": 26 },
{ "id": 27 },
{ "id": 28 },
{ "id": 29 },
{ "id": 30 },
{ "id": 31 },
{ "id": 32 },
{ "id": 33 },
{ "id": 34 },
{ "id": 35 },
{ "id": 36 },
{ "id": 37 },
{ "id": 38 },
{ "id": 39 },
{ "id": 40 },
{ "id": 41 },
{ "id": 42 },
{ "id": 43 },
{ "id": 44 },
{ "id": 45 },
{ "id": 46 },
{ "id": 47 },
{ "id": 48 },
{ "id": 49 },
{ "id": 50 },
{ "id": 51 },
{ "id": 52 },
{ "id": 53 },
{ "id": 54 },
{ "id": 55 },
{ "id": 56 },
{ "id": 57 },
{ "id": 58 },
{ "id": 59 },
{ "id": 60 },
{ "id": 61 },
{ "id": 62 },
{ "id": 63 },
{ "id": 64 },
{ "id": 65 },
{ "id": 66 },
{ "id": 67 },
{ "id": 68 },
{ "id": 69 },
{ "id": 70 },
{ "id": 71 },
{ "id": 72 },
{ "id": 73 },
{ "id": 74 },
{ "id": 75 },
{ "id": 76 },
{ "id": 77 },
{ "id": 78 },
{ "id": 79 },
{ "id": 80 },
{ "id": 81 },
{ "id": 82 },
{ "id": 83 },
{ "id": 84 },
{ "id": 85 },
{ "id": 86 },
{ "id": 87 },
{ "id": 88 },
{ "id": 89 },
{ "id": 90 },
{ "id": 91 },
{ "id": 92 },
{ "id": 93 },
{ "id": 94 },
{ "id": 95 },
{ "id": 96 },
{ "id": 97 },
{ "id": 98 },
{ "id": 99 },
{ "id": 100 },
{ "id": 101 },
{ "id": 102 },
{ "id": 103 },
{ "id": 104 },
{ "id": 105 },
{ "id": 106 },
{ "id": 107 },
{ "id": 108 },
{ "id": 109 },
{ "id": 110 },
{ "id": 111 },
{ "id": 112 },
{ "id": 113 },
{ "id": 114 },
{ "id": 115 },
{ "id": 116 },
{ "id": 117 },
{ "id": 118 },
{ "id": 119 },
{ "id": 120 },
{ "id": 121 },
{ "id": 122 },
{ "id": 123 },
{ "id": 124 },
{ "id": 125 },
{ "id": 126 },
{ "id": 127 },
{ "id": 128 },
{ "id": 129 },
{ "id": 130 },
{ "id": 131 },
{ "id": 132 },
{ "id": 133 },
{ "id": 134 },
{ "id": 135 },
{ "id": 136 },
{ "id": 137 },
{ "id": 138 },
{ "id": 139 },
{ "id": 140 },
{ "id": 141 },
{ "id": 142 },
{ "id": 143 },
{ "id": 144 },
{ "id": 145 },
{ "id": 146 },
{ "id": 147 },
{ "id": 148 },
{ "id": 149 },
{ "id": 150 },
{ "id": 151 },
{ "id": 152 },
{ "id": 153 },
{ "id": 154 },
{ "id": 155 },
{ "id": 156 },
{ "id": 157 },
{ "id": 158 },
{ "id": 159 },
{ "id": 160 },
{ "id": 161 },
{ "id": 162 },
{ "id": 163 },
{ "id": 164 },
{ "id": 165 },
{ "id": 166 },
{ "id": 167 },
{ "id": 168 },
{ "id": 169 },
{ "id": 170 },
{ "id": 171 },
{ "id": 172 },
{ "id": 173 },
{ "id": 174 },
{ "id": 175 },
{ "id": 176 },
{ "id": 177 },
{ "id": 178 },
{ "id": 179 },
{ "id": 180 },
{ "id": 181 },
{ "id": 182 },
{ "id": 183 },
{ "id": 184 },
{ "id": 185 },
{ "id": 186 },
{ "id": 187 },
{ "id": 188 },
{ "id": 189 },
{ "id": 190 },
{ "id": 191 },
{ "id": 192 },
{ "id": 193 },
{ "id": 194 },
{ "id": 195 },
{ "id": 196 },
{ "id": 197 },
{ "id": 198 },
{ "id": 199 },
{ "id": 200 },
{ "id": 201 },
{ "id": 202 },
{ "id": 203 },
{ "id": 204 },
{ "id": 205 },
{ "id": 206 },
{ "id": 207 },
{ "id": 208 },
{ "id": 209 },
{ "id": 210 },
{ "id": 211 },
{ "id": 212 },
{ "id": 213 },
{ "id": 214 },
{ "id": 215 },
{ "id": 216 },
{ "id": 217 },
{ "id": 218 },
{ "id": 219 },
{ "id": 220 },
{ "id": 221 },
{ "id": 222 },
{ "id": 223 },
{ "id": 224 },
{ "id": 225 },
{ "id": 226 },
{ "id": 227 },
{ "id": 228 },
{ "id": 229 },
{ "id": 230 },
{ "id": 231 },
{ "id": 232 },
{ "id": 233 },
{ "id": 234 },
{ "id": 235 },
{ "id": 236 },
{ "id": 237 },
{ "id": 238 },
{ "id": 239 },
{ "id": 240 },
{ "id": 241 },
{ "id": 242 },
{ "id": 243 },
{ "id": 244 },
{ "id": 245 },
{ "id": 246 },
{ "id": 247 },
{ "id": 248 },
{ "id": 249 },
{ "id": 250 },
{ "id": 251 },
{ "id": 252 },
{ "id": 253 },
{ "id": 254 },
{ "id": 255 },
{ "id": 256 },
{ "id": 257 },
{ "id": 258 },
{ "id": 259 },
{ "id": 260 },
{ "id": 261 },
{ "id": 262 },
{ "id": 263 },
{ "id": 264 },
{ "id": 265 },
{ "id": 266 },
{ "id": 267 },
{ "id": 268 },
{ "id": 269 },
{ "id": 270 },
{ "id": 271 },
{ "id": 272 },
{ "id": 273 },
{ "id": 274 },
{ "id": 275 },
{ "id": 276 },
{ "id": 277 },
{ "id": 278 },
{ "id": 279 },
{ "id": 280 },
{ "id": 281 },
{ "id": 282 },
{ "id": 283 },
{ "id": 284 },
{ "id": 285 },
{ "id": 286 },
{ "id": 287 },
{ "id": 288 },
{ "id": 289 },
{ "id": 290 },
{ "id": 291 },
{ "id": 292 },
{ "id": 293 },
{ "id": 294 },
{ "id": 295 },
{ "id": 296 },
{ "id": 297 },
{ "id": 298 },
{ "id": 299 },
{ "id": 300 },
{ "id": 301 },
{ "id": 302 },
{ "id": 303 },
{ "id": 304 },
{ "id": 305 },
{ "id": 306 },
{ "id": 307 },
{ "id": 308 },
{ "id": 309 },
{ "id": 310 },
{ "id": 311 },
{ "id": 312 },
{ "id": 313 },
{ "id": 314 },
{ "id": 315 },
{ "id": 316 },
{ "id": 317 },
{ "id": 318 },
{ "id": 319 },
{ "id": 320 },
{ "id": 321 },
{ "id": 322 },
{ "id": 323 },
{ "id": 324 },
{ "id": 325 },
{ "id": 326 },
{ "id": 327 },
{ "id": 328 },
{ "id": 329 },
{ "id": 330 },
{ "id": 331 },
{ "id": 332 },
{ "id": 333 },
{ "id": 334 },
{ "id": 335 },
{ "id": 336 },
{ "id": 337 },
{ "id": 338 },
{ "id": 339 },
{ "id": 340 },
{ "id": 341 },
{ "id": 342 },
{ "id": 343 },
{ "id": 344 },
{ "id": 345 },
{ "id": 346 },
{ "id": 347 },
{ "id": 348 },
{ "id": 349 },
{ "id": 350 },
{ "id": 351 },
{ "id": 352 },
{ "id": 353 },
{ "id": 354 },
{ "id": 355 },
{ "id": 356 },
{ "id": 357 },
{ "id": 358 },
{ "id": 359 },
{ "id": 360 },
{ "id": 361 },
{ "id": 362 },
{ "id": 363 },
{ "id": 364 },
{ "id": 365 },
{ "id": 366 },
{ "id": 367 },
{ "id": 368 },
{ "id": 369 },
{ "id": 370 },
{ "id": 371 },
{ "id": 372 },
{ "id": 373 },
{ "id": 374 },
{ "id": 375 },
{ "id": 376 },
{ "id": 377 },
{ "id": 378 },
{ "id": 379 },
{ "id": 380 },
{ "id": 381 },
{ "id": 382 },
{ "id": 383 },
{ "id": 384 },
{ "id": 385 },
{ "id": 386 },
{ "id": 387 },
{ "id": 388 },
{ "id": 389 },
{ "id": 390 },
{ "id": 391 },
{ "id": 392 },
{ "id": 393 },
{ "id": 394 },
{ "id": 395 },
{ "id": 396 },
{ "id": 397 },
{ "id": 398 },
{ "id": 399 },
{ "id": 400 },
{ "id": 401 },
{ "id": 402 },
{ "id": 403 },
{ "id": 404 },
{ "id": 405 },
{ "id": 406 },
{ "id": 407 },
{ "id": 408 },
{ "id": 409 },
{ "id": 410 },
{ "id": 411 },
{ "id": 412 },
{ "id": 413 },
{ "id": 414 },
{ "id": 415 },
{ "id": 416 },
{ "id": 417 },
{ "id": 418 },
{ "id": 419 },
{ "id": 420 },
{ "id": 421 },
{ "id": 422 },
{ "id": 423 },
{ "id": 424 },
{ "id": 425 },
{ "id": 426 },
{ "id": 427 },
{ "id": 428 },
{ "id": 429 },
{ "id": 430 },
{ "id": 431 },
{ "id": 432 },
{ "id": 433 },
{ "id": 434 },
{ "id": 435 },
{ "id": 436 },
{ "id": 437 },
{ "id": 438 },
{ "id": 439 },
{ "id": 440 },
{ "id": 441 },
{ "id": 442 },
{ "id": 443 },
{ "id": 444 },
{ "id": 445 },
{ "id": 446 },
{ "id": 447 },
{ "id": 448 },
{ "id": 449 },
{ "id": 450 },
{ "id": 451 },
{ "id": 452 },
{ "id": 453 },
{ "id": 454 },
{ "id": 455 },
{ "id": 456 },
{ "id": 457 },
{ "id": 458 },
{ "id": 459 },
{ "id": 460 },
{ "id": 461 },
{ "id": 462 },
{ "id": 463 },
{ "id": 464 },
{ "id": 465 },
{ "id": 466 },
{ "id": 467 },
{ "id": 468 },
{ "id": 469 },
{ "id": 470 },
{ "id": 471 },
{ "id": 472 },
{ "id": 473 },
{ "id": 474 },
{ "id": 475 },
{ "id": 476 },
{ "id": 477 },
{ "id": 478 },
{ "id": 479 },
{ "id": 480 },
{ "id": 481 },
{ "id": 482 },
{ "id": 483 },
{ "id": 484 },
{ "id": 485 },
{ "id": 486 },
{ "id": 487 },
{ "id": 488 },
{ "id": 489 },
{ "id": 490 },
{ "id": 491 },
{ "id": 492 },
{ "id": 493 },
{ "id": 494 },
{ "id": 495 },
{ "id": 496 },
{ "id": 497 },
{ "id": 498 },
{ "id": 499 },
{ "id": 500 },
{ "id": 501 },
{ "id": 502 },
{ "id": 503 }
],
"links": [
{ "source": 0, "target": 1 },
{ "source": 1, "target": 2 },
{ "source": 2, "target": 3 },
{ "source": 2, "target": 4 },
{ "source": 2, "target": 5 },
{ "source": 2, "target": 6 },
{ "source": 1, "target": 7 },
{ "source": 7, "target": 8 },
{ "source": 7, "target": 9 },
{ "source": 7, "target": 10 },
{ "source": 7, "target": 11 },
{ "source": 7, "target": 12 },
{ "source": 1, "target": 13 },
{ "source": 13, "target": 14 },
{ "source": 0, "target": 15 },
{ "source": 15, "target": 16 },
{ "source": 15, "target": 17 },
{ "source": 15, "target": 18 },
{ "source": 18, "target": 19 },
{ "source": 18, "target": 20 },
{ "source": 18, "target": 21 },
{ "source": 18, "target": 22 },
{ "source": 18, "target": 23 },
{ "source": 18, "target": 24 },
{ "source": 18, "target": 25 },
{ "source": 18, "target": 26 },
{ "source": 18, "target": 27 },
{ "source": 15, "target": 28 },
{ "source": 15, "target": 29 },
{ "source": 15, "target": 30 },
{ "source": 15, "target": 31 },
{ "source": 15, "target": 32 },
{ "source": 15, "target": 33 },
{ "source": 15, "target": 34 },
{ "source": 15, "target": 35 },
{ "source": 15, "target": 36 },
{ "source": 0, "target": 37 },
{ "source": 37, "target": 38 },
{ "source": 38, "target": 39 },
{ "source": 38, "target": 40 },
{ "source": 38, "target": 41 },
{ "source": 38, "target": 42 },
{ "source": 38, "target": 43 },
{ "source": 37, "target": 44 },
{ "source": 37, "target": 45 },
{ "source": 37, "target": 46 },
{ "source": 37, "target": 47 },
{ "source": 37, "target": 48 },
{ "source": 37, "target": 49 },
{ "source": 0, "target": 50 },
{ "source": 50, "target": 51 },
{ "source": 50, "target": 52 },
{ "source": 50, "target": 53 },
{ "source": 50, "target": 54 },
{ "source": 0, "target": 55 },
{ "source": 55, "target": 56 },
{ "source": 0, "target": 57 },
{ "source": 57, "target": 58 },
{ "source": 57, "target": 59 },
{ "source": 57, "target": 60 },
{ "source": 57, "target": 61 },
{ "source": 57, "target": 62 },
{ "source": 57, "target": 63 },
{ "source": 57, "target": 64 },
{ "source": 57, "target": 65 },
{ "source": 0, "target": 66 },
{ "source": 66, "target": 67 },
{ "source": 66, "target": 68 },
{ "source": 66, "target": 69 },
{ "source": 66, "target": 70 },
{ "source": 66, "target": 71 },
{ "source": 66, "target": 72 },
{ "source": 66, "target": 73 },
{ "source": 66, "target": 74 },
{ "source": 66, "target": 75 },
{ "source": 66, "target": 76 },
{ "source": 66, "target": 77 },
{ "source": 66, "target": 78 },
{ "source": 66, "target": 79 },
{ "source": 66, "target": 80 },
{ "source": 66, "target": 81 },
{ "source": 66, "target": 82 },
{ "source": 66, "target": 83 },
{ "source": 66, "target": 84 },
{ "source": 66, "target": 85 },
{ "source": 85, "target": 86 },
{ "source": 85, "target": 87 },
{ "source": 85, "target": 88 },
{ "source": 85, "target": 89 },
{ "source": 85, "target": 90 },
{ "source": 85, "target": 91 },
{ "source": 85, "target": 92 },
{ "source": 85, "target": 93 },
{ "source": 85, "target": 94 },
{ "source": 85, "target": 95 },
{ "source": 85, "target": 96 },
{ "source": 85, "target": 97 },
{ "source": 85, "target": 98 },
{ "source": 85, "target": 99 },
{ "source": 85, "target": 100 },
{ "source": 85, "target": 101 },
{ "source": 85, "target": 102 },
{ "source": 85, "target": 103 },
{ "source": 85, "target": 104 },
{ "source": 85, "target": 105 },
{ "source": 85, "target": 106 },
{ "source": 85, "target": 107 },
{ "source": 85, "target": 108 },
{ "source": 85, "target": 109 },
{ "source": 85, "target": 110 },
{ "source": 85, "target": 111 },
{ "source": 85, "target": 112 },
{ "source": 85, "target": 113 },
{ "source": 85, "target": 114 },
{ "source": 85, "target": 115 },
{ "source": 85, "target": 116 },
{ "source": 85, "target": 117 },
{ "source": 66, "target": 118 },
{ "source": 66, "target": 119 },
{ "source": 66, "target": 120 },
{ "source": 66, "target": 121 },
{ "source": 66, "target": 122 },
{ "source": 66, "target": 123 },
{ "source": 66, "target": 124 },
{ "source": 66, "target": 125 },
{ "source": 66, "target": 126 },
{ "source": 66, "target": 127 },
{ "source": 0, "target": 128 },
{ "source": 128, "target": 129 },
{ "source": 128, "target": 130 },
{ "source": 128, "target": 131 },
{ "source": 128, "target": 132 },
{ "source": 128, "target": 133 },
{ "source": 128, "target": 134 },
{ "source": 128, "target": 135 },
{ "source": 128, "target": 136 },
{ "source": 128, "target": 137 },
{ "source": 128, "target": 138 },
{ "source": 0, "target": 139 },
{ "source": 139, "target": 140 },
{ "source": 139, "target": 141 },
{ "source": 139, "target": 142 },
{ "source": 139, "target": 143 },
{ "source": 139, "target": 144 },
{ "source": 139, "target": 145 },
{ "source": 139, "target": 146 },
{ "source": 146, "target": 147 },
{ "source": 146, "target": 148 },
{ "source": 139, "target": 149 },
{ "source": 139, "target": 150 },
{ "source": 139, "target": 151 },
{ "source": 139, "target": 152 },
{ "source": 152, "target": 153 },
{ "source": 152, "target": 154 },
{ "source": 152, "target": 155 },
{ "source": 139, "target": 156 },
{ "source": 139, "target": 157 },
{ "source": 139, "target": 158 },
{ "source": 158, "target": 159 },
{ "source": 158, "target": 160 },
{ "source": 158, "target": 161 },
{ "source": 158, "target": 162 },
{ "source": 139, "target": 163 },
{ "source": 139, "target": 164 },
{ "source": 139, "target": 165 },
{ "source": 139, "target": 166 },
{ "source": 139, "target": 167 },
{ "source": 0, "target": 168 },
{ "source": 168, "target": 169 },
{ "source": 169, "target": 170 },
{ "source": 169, "target": 171 },
{ "source": 169, "target": 172 },
{ "source": 169, "target": 173 },
{ "source": 169, "target": 174 },
{ "source": 168, "target": 175 },
{ "source": 175, "target": 176 },
{ "source": 175, "target": 177 },
{ "source": 175, "target": 178 },
{ "source": 175, "target": 179 },
{ "source": 175, "target": 180 },
{ "source": 175, "target": 181 },
{ "source": 175, "target": 182 },
{ "source": 175, "target": 183 },
{ "source": 175, "target": 184 },
{ "source": 175, "target": 185 },
{ "source": 175, "target": 186 },
{ "source": 168, "target": 187 },
{ "source": 187, "target": 188 },
{ "source": 187, "target": 189 },
{ "source": 187, "target": 190 },
{ "source": 187, "target": 191 },
{ "source": 187, "target": 192 },
{ "source": 187, "target": 193 },
{ "source": 193, "target": 194 },
{ "source": 193, "target": 195 },
{ "source": 193, "target": 196 },
{ "source": 193, "target": 197 },
{ "source": 187, "target": 198 },
{ "source": 187, "target": 199 },
{ "source": 187, "target": 200 },
{ "source": 168, "target": 201 },
{ "source": 201, "target": 202 },
{ "source": 201, "target": 203 },
{ "source": 201, "target": 204 },
{ "source": 201, "target": 205 },
{ "source": 168, "target": 206 },
{ "source": 206, "target": 207 },
{ "source": 206, "target": 208 },
{ "source": 206, "target": 209 },
{ "source": 168, "target": 210 },
{ "source": 210, "target": 211 },
{ "source": 211, "target": 212 },
{ "source": 211, "target": 213 },
{ "source": 211, "target": 214 },
{ "source": 210, "target": 215 },
{ "source": 215, "target": 216 },
{ "source": 215, "target": 217 },
{ "source": 215, "target": 218 },
{ "source": 215, "target": 219 },
{ "source": 215, "target": 220 },
{ "source": 210, "target": 221 },
{ "source": 221, "target": 222 },
{ "source": 221, "target": 223 },
{ "source": 221, "target": 224 },
{ "source": 210, "target": 225 },
{ "source": 210, "target": 226 },
{ "source": 226, "target": 227 },
{ "source": 226, "target": 228 },
{ "source": 226, "target": 229 },
{ "source": 210, "target": 230 },
{ "source": 230, "target": 231 },
{ "source": 230, "target": 232 },
{ "source": 230, "target": 233 },
{ "source": 230, "target": 234 },
{ "source": 230, "target": 235 },
{ "source": 230, "target": 236 },
{ "source": 230, "target": 237 },
{ "source": 230, "target": 238 },
{ "source": 230, "target": 239 },
{ "source": 230, "target": 240 },
{ "source": 230, "target": 241 },
{ "source": 230, "target": 242 },
{ "source": 230, "target": 243 },
{ "source": 230, "target": 244 },
{ "source": 230, "target": 245 },
{ "source": 210, "target": 246 },
{ "source": 210, "target": 247 },
{ "source": 210, "target": 248 },
{ "source": 210, "target": 249 },
{ "source": 210, "target": 250 },
{ "source": 168, "target": 251 },
{ "source": 0, "target": 300 },
{ "source": 252, "target": 253 },
{ "source": 253, "target": 254 },
{ "source": 254, "target": 255 },
{ "source": 254, "target": 256 },
{ "source": 254, "target": 257 },
{ "source": 254, "target": 258 },
{ "source": 253, "target": 259 },
{ "source": 259, "target": 260 },
{ "source": 259, "target": 261 },
{ "source": 259, "target": 262 },
{ "source": 259, "target": 263 },
{ "source": 259, "target": 264 },
{ "source": 253, "target": 265 },
{ "source": 265, "target": 266 },
{ "source": 252, "target": 267 },
{ "source": 267, "target": 268 },
{ "source": 267, "target": 269 },
{ "source": 267, "target": 270 },
{ "source": 270, "target": 271 },
{ "source": 270, "target": 272 },
{ "source": 270, "target": 273 },
{ "source": 270, "target": 274 },
{ "source": 270, "target": 275 },
{ "source": 270, "target": 276 },
{ "source": 270, "target": 277 },
{ "source": 270, "target": 278 },
{ "source": 270, "target": 279 },
{ "source": 267, "target": 280 },
{ "source": 267, "target": 281 },
{ "source": 267, "target": 282 },
{ "source": 267, "target": 283 },
{ "source": 267, "target": 284 },
{ "source": 267, "target": 285 },
{ "source": 267, "target": 286 },
{ "source": 267, "target": 287 },
{ "source": 267, "target": 288 },
{ "source": 252, "target": 289 },
{ "source": 289, "target": 290 },
{ "source": 290, "target": 291 },
{ "source": 290, "target": 292 },
{ "source": 290, "target": 293 },
{ "source": 290, "target": 294 },
{ "source": 290, "target": 295 },
{ "source": 289, "target": 296 },
{ "source": 289, "target": 297 },
{ "source": 289, "target": 298 },
{ "source": 289, "target": 299 },
{ "source": 289, "target": 300 },
{ "source": 289, "target": 301 },
{ "source": 252, "target": 302 },
{ "source": 302, "target": 303 },
{ "source": 302, "target": 304 },
{ "source": 302, "target": 305 },
{ "source": 302, "target": 306 },
{ "source": 252, "target": 307 },
{ "source": 307, "target": 308 },
{ "source": 252, "target": 309 },
{ "source": 309, "target": 310 },
{ "source": 309, "target": 311 },
{ "source": 309, "target": 312 },
{ "source": 309, "target": 313 },
{ "source": 309, "target": 314 },
{ "source": 309, "target": 315 },
{ "source": 309, "target": 316 },
{ "source": 309, "target": 317 },
{ "source": 252, "target": 318 },
{ "source": 318, "target": 319 },
{ "source": 318, "target": 320 },
{ "source": 318, "target": 321 },
{ "source": 318, "target": 322 },
{ "source": 318, "target": 323 },
{ "source": 318, "target": 324 },
{ "source": 318, "target": 325 },
{ "source": 318, "target": 326 },
{ "source": 318, "target": 327 },
{ "source": 318, "target": 328 },
{ "source": 318, "target": 329 },
{ "source": 318, "target": 330 },
{ "source": 318, "target": 331 },
{ "source": 318, "target": 332 },
{ "source": 318, "target": 333 },
{ "source": 318, "target": 334 },
{ "source": 318, "target": 335 },
{ "source": 318, "target": 336 },
{ "source": 318, "target": 337 },
{ "source": 337, "target": 338 },
{ "source": 337, "target": 339 },
{ "source": 337, "target": 340 },
{ "source": 337, "target": 341 },
{ "source": 337, "target": 342 },
{ "source": 337, "target": 343 },
{ "source": 337, "target": 344 },
{ "source": 337, "target": 345 },
{ "source": 337, "target": 346 },
{ "source": 337, "target": 347 },
{ "source": 337, "target": 348 },
{ "source": 337, "target": 349 },
{ "source": 337, "target": 350 },
{ "source": 337, "target": 351 },
{ "source": 337, "target": 352 },
{ "source": 337, "target": 353 },
{ "source": 337, "target": 354 },
{ "source": 337, "target": 355 },
{ "source": 337, "target": 356 },
{ "source": 337, "target": 357 },
{ "source": 337, "target": 358 },
{ "source": 337, "target": 359 },
{ "source": 337, "target": 360 },
{ "source": 337, "target": 361 },
{ "source": 337, "target": 362 },
{ "source": 337, "target": 363 },
{ "source": 337, "target": 364 },
{ "source": 337, "target": 365 },
{ "source": 337, "target": 366 },
{ "source": 337, "target": 367 },
{ "source": 337, "target": 368 },
{ "source": 337, "target": 369 },
{ "source": 318, "target": 370 },
{ "source": 318, "target": 371 },
{ "source": 318, "target": 372 },
{ "source": 318, "target": 373 },
{ "source": 318, "target": 374 },
{ "source": 318, "target": 375 },
{ "source": 318, "target": 376 },
{ "source": 318, "target": 377 },
{ "source": 318, "target": 378 },
{ "source": 318, "target": 379 },
{ "source": 252, "target": 380 },
{ "source": 380, "target": 381 },
{ "source": 380, "target": 382 },
{ "source": 380, "target": 383 },
{ "source": 380, "target": 384 },
{ "source": 380, "target": 385 },
{ "source": 380, "target": 386 },
{ "source": 380, "target": 387 },
{ "source": 380, "target": 388 },
{ "source": 380, "target": 389 },
{ "source": 380, "target": 390 },
{ "source": 252, "target": 391 },
{ "source": 391, "target": 392 },
{ "source": 391, "target": 393 },
{ "source": 391, "target": 394 },
{ "source": 391, "target": 395 },
{ "source": 391, "target": 396 },
{ "source": 391, "target": 397 },
{ "source": 391, "target": 398 },
{ "source": 398, "target": 399 },
{ "source": 398, "target": 400 },
{ "source": 391, "target": 401 },
{ "source": 391, "target": 402 },
{ "source": 391, "target": 403 },
{ "source": 391, "target": 404 },
{ "source": 404, "target": 405 },
{ "source": 404, "target": 406 },
{ "source": 404, "target": 407 },
{ "source": 391, "target": 408 },
{ "source": 391, "target": 409 },
{ "source": 391, "target": 410 },
{ "source": 410, "target": 411 },
{ "source": 410, "target": 412 },
{ "source": 410, "target": 413 },
{ "source": 410, "target": 414 },
{ "source": 391, "target": 415 },
{ "source": 391, "target": 416 },
{ "source": 391, "target": 417 },
{ "source": 391, "target": 418 },
{ "source": 391, "target": 419 },
{ "source": 252, "target": 420 },
{ "source": 420, "target": 421 },
{ "source": 421, "target": 422 },
{ "source": 421, "target": 423 },
{ "source": 421, "target": 424 },
{ "source": 421, "target": 425 },
{ "source": 421, "target": 426 },
{ "source": 420, "target": 427 },
{ "source": 427, "target": 428 },
{ "source": 427, "target": 429 },
{ "source": 427, "target": 430 },
{ "source": 427, "target": 431 },
{ "source": 427, "target": 432 },
{ "source": 427, "target": 433 },
{ "source": 427, "target": 434 },
{ "source": 427, "target": 435 },
{ "source": 427, "target": 436 },
{ "source": 427, "target": 437 },
{ "source": 427, "target": 438 },
{ "source": 420, "target": 439 },
{ "source": 439, "target": 440 },
{ "source": 439, "target": 441 },
{ "source": 439, "target": 442 },
{ "source": 439, "target": 443 },
{ "source": 439, "target": 444 },
{ "source": 439, "target": 445 },
{ "source": 445, "target": 446 },
{ "source": 445, "target": 447 },
{ "source": 445, "target": 448 },
{ "source": 445, "target": 449 },
{ "source": 439, "target": 450 },
{ "source": 439, "target": 451 },
{ "source": 439, "target": 452 },
{ "source": 420, "target": 453 },
{ "source": 453, "target": 454 },
{ "source": 453, "target": 455 },
{ "source": 453, "target": 456 },
{ "source": 453, "target": 457 },
{ "source": 420, "target": 458 },
{ "source": 458, "target": 459 },
{ "source": 458, "target": 460 },
{ "source": 458, "target": 461 },
{ "source": 420, "target": 462 },
{ "source": 462, "target": 463 },
{ "source": 463, "target": 464 },
{ "source": 463, "target": 465 },
{ "source": 463, "target": 466 },
{ "source": 462, "target": 467 },
{ "source": 467, "target": 468 },
{ "source": 467, "target": 469 },
{ "source": 467, "target": 470 },
{ "source": 467, "target": 471 },
{ "source": 467, "target": 472 },
{ "source": 462, "target": 473 },
{ "source": 473, "target": 474 },
{ "source": 473, "target": 475 },
{ "source": 473, "target": 476 },
{ "source": 462, "target": 477 },
{ "source": 462, "target": 478 },
{ "source": 478, "target": 479 },
{ "source": 478, "target": 480 },
{ "source": 478, "target": 481 },
{ "source": 462, "target": 482 },
{ "source": 482, "target": 483 },
{ "source": 482, "target": 484 },
{ "source": 482, "target": 485 },
{ "source": 482, "target": 486 },
{ "source": 482, "target": 487 },
{ "source": 482, "target": 488 },
{ "source": 482, "target": 489 },
{ "source": 482, "target": 490 },
{ "source": 482, "target": 491 },
{ "source": 482, "target": 492 },
{ "source": 482, "target": 493 },
{ "source": 482, "target": 494 },
{ "source": 482, "target": 495 },
{ "source": 482, "target": 496 },
{ "source": 482, "target": 497 },
{ "source": 462, "target": 498 },
{ "source": 462, "target": 499 },
{ "source": 462, "target": 500 },
{ "source": 462, "target": 501 },
{ "source": 462, "target": 502 },
{ "source": 420, "target": 503 },
{ "source": 300, "target": 600 }
]
}
================================================
FILE: .storybook/public/treeLarge.json
================================================
{"nodes":[{"id":0},{"id":1},{"id":2},{"id":3},{"id":4},{"id":5},{"id":6},{"id":7},{"id":8},{"id":9},{"id":10},{"id":11},{"id":12},{"id":13},{"id":14},{"id":15},{"id":16},{"id":17},{"id":18},{"id":19},{"id":20},{"id":21},{"id":22},{"id":23},{"id":24},{"id":25},{"id":26},{"id":27},{"id":28},{"id":29},{"id":30},{"id":31},{"id":32},{"id":33},{"id":34},{"id":35},{"id":36},{"id":37},{"id":38},{"id":39},{"id":40},{"id":41},{"id":42},{"id":43},{"id":44},{"id":45},{"id":46},{"id":47},{"id":48},{"id":49},{"id":50},{"id":51},{"id":52},{"id":53},{"id":54},{"id":55},{"id":56},{"id":57},{"id":58},{"id":59},{"id":60},{"id":61},{"id":62},{"id":63},{"id":64},{"id":65},{"id":66},{"id":67},{"id":68},{"id":69},{"id":70},{"id":71},{"id":72},{"id":73},{"id":74},{"id":75},{"id":76},{"id":77},{"id":78},{"id":79},{"id":80},{"id":81},{"id":82},{"id":83},{"id":84},{"id":85},{"id":86},{"id":87},{"id":88},{"id":89},{"id":90},{"id":91},{"id":92},{"id":93},{"id":94},{"id":95},{"id":96},{"id":97},{"id":98},{"id":99},{"id":100},{"id":101},{"id":102},{"id":103},{"id":104},{"id":105},{"id":106},{"id":107},{"id":108},{"id":109},{"id":110},{"id":111},{"id":112},{"id":113},{"id":114},{"id":115},{"id":116},{"id":117},{"id":118},{"id":119},{"id":120},{"id":121},{"id":122},{"id":123},{"id":124},{"id":125},{"id":126},{"id":127},{"id":128},{"id":129},{"id":130},{"id":131},{"id":132},{"id":133},{"id":134},{"id":135},{"id":136},{"id":137},{"id":138},{"id":139},{"id":140},{"id":141},{"id":142},{"id":143},{"id":144},{"id":145},{"id":146},{"id":147},{"id":148},{"id":149},{"id":150},{"id":151},{"id":152},{"id":153},{"id":154},{"id":155},{"id":156},{"id":157},{"id":158},{"id":159},{"id":160},{"id":161},{"id":162},{"id":163},{"id":164},{"id":165},{"id":166},{"id":167},{"id":168},{"id":169},{"id":170},{"id":171},{"id":172},{"id":173},{"id":174},{"id":175},{"id":176},{"id":177},{"id":178},{"id":179},{"id":180},{"id":181},{"id":182},{"id":183},{"id":184},{"id":185},{"id":186},{"id":187},{"id":188},{"id":189},{"id":190},{"id":191},{"id":192},{"id":193},{"id":194},{"id":195},{"id":196},{"id":197},{"id":198},{"id":199},{"id":200},{"id":201},{"id":202},{"id":203},{"id":204},{"id":205},{"id":206},{"id":207},{"id":208},{"id":209},{"id":210},{"id":211},{"id":212},{"id":213},{"id":214},{"id":215},{"id":216},{"id":217},{"id":218},{"id":219},{"id":220},{"id":221},{"id":222},{"id":223},{"id":224},{"id":225},{"id":226},{"id":227},{"id":228},{"id":229},{"id":230},{"id":231},{"id":232},{"id":233},{"id":234},{"id":235},{"id":236},{"id":237},{"id":238},{"id":239},{"id":240},{"id":241},{"id":242},{"id":243},{"id":244},{"id":245},{"id":246},{"id":247},{"id":248},{"id":249},{"id":250},{"id":251},{"id":252},{"id":253},{"id":254},{"id":255},{"id":256},{"id":257},{"id":258},{"id":259},{"id":260},{"id":261},{"id":262},{"id":263},{"id":264},{"id":265},{"id":266},{"id":267},{"id":268},{"id":269},{"id":270},{"id":271},{"id":272},{"id":273},{"id":274},{"id":275},{"id":276},{"id":277},{"id":278},{"id":279},{"id":280},{"id":281},{"id":282},{"id":283},{"id":284},{"id":285},{"id":286},{"id":287},{"id":288},{"id":289},{"id":290},{"id":291},{"id":292},{"id":293},{"id":294},{"id":295},{"id":296},{"id":297},{"id":298},{"id":299},{"id":300},{"id":301},{"id":302},{"id":303},{"id":304},{"id":305},{"id":306},{"id":307},{"id":308},{"id":309},{"id":310},{"id":311},{"id":312},{"id":313},{"id":314},{"id":315},{"id":316},{"id":317},{"id":318},{"id":319},{"id":320},{"id":321},{"id":322},{"id":323},{"id":324},{"id":325},{"id":326},{"id":327},{"id":328},{"id":329},{"id":330},{"id":331},{"id":332},{"id":333},{"id":334},{"id":335},{"id":336},{"id":337},{"id":338},{"id":339},{"id":340},{"id":341},{"id":342},{"id":343},{"id":344},{"id":345},{"id":346},{"id":347},{"id":348},{"id":349},{"id":350},{"id":351},{"id":352},{"id":353},{"id":354},{"id":355},{"id":356},{"id":357},{"id":358},{"id":359},{"id":360},{"id":361},{"id":362},{"id":363},{"id":364},{"id":365},{"id":366},{"id":367},{"id":368},{"id":369},{"id":370},{"id":371},{"id":372},{"id":373},{"id":374},{"id":375},{"id":376},{"id":377},{"id":378},{"id":379},{"id":380},{"id":381},{"id":382},{"id":383},{"id":384},{"id":385},{"id":386},{"id":387},{"id":388},{"id":389},{"id":390},{"id":391},{"id":392},{"id":393},{"id":394},{"id":395},{"id":396},{"id":397},{"id":398},{"id":399},{"id":400},{"id":401},{"id":402},{"id":403},{"id":404},{"id":405},{"id":406},{"id":407},{"id":408},{"id":409},{"id":410},{"id":411},{"id":412},{"id":413},{"id":414},{"id":415},{"id":416},{"id":417},{"id":418},{"id":419},{"id":420},{"id":421},{"id":422},{"id":423},{"id":424},{"id":425},{"id":426},{"id":427},{"id":428},{"id":429},{"id":430},{"id":431},{"id":432},{"id":433},{"id":434},{"id":435},{"id":436},{"id":437},{"id":438},{"id":439},{"id":440},{"id":441},{"id":442},{"id":443},{"id":444},{"id":445},{"id":446},{"id":447},{"id":448},{"id":449},{"id":450},{"id":451},{"id":452},{"id":453},{"id":454},{"id":455},{"id":456},{"id":457},{"id":458},{"id":459},{"id":460},{"id":461},{"id":462},{"id":463},{"id":464},{"id":465},{"id":466},{"id":467},{"id":468},{"id":469},{"id":470},{"id":471},{"id":472},{"id":473},{"id":474},{"id":475},{"id":476},{"id":477},{"id":478},{"id":479},{"id":480},{"id":481},{"id":482},{"id":483},{"id":484},{"id":485},{"id":486},{"id":487},{"id":488},{"id":489},{"id":490},{"id":491},{"id":492},{"id":493},{"id":494},{"id":495},{"id":496},{"id":497},{"id":498},{"id":499},{"id":500},{"id":501},{"id":502},{"id":503},{"id":504},{"id":505},{"id":506},{"id":507},{"id":508},{"id":509},{"id":510},{"id":511},{"id":512},{"id":513},{"id":514},{"id":515},{"id":516},{"id":517},{"id":518},{"id":519},{"id":520},{"id":521},{"id":522},{"id":523},{"id":524},{"id":525},{"id":526},{"id":527},{"id":528},{"id":529},{"id":530},{"id":531},{"id":532},{"id":533},{"id":534},{"id":535},{"id":536},{"id":537},{"id":538},{"id":539},{"id":540},{"id":541},{"id":542},{"id":543},{"id":544},{"id":545},{"id":546},{"id":547},{"id":548},{"id":549},{"id":550},{"id":551},{"id":552},{"id":553},{"id":554},{"id":555},{"id":556},{"id":557},{"id":558},{"id":559},{"id":560},{"id":561},{"id":562},{"id":563},{"id":564},{"id":565},{"id":566},{"id":567},{"id":568},{"id":569},{"id":570},{"id":571},{"id":572},{"id":573},{"id":574},{"id":575},{"id":576},{"id":577},{"id":578},{"id":579},{"id":580},{"id":581},{"id":582},{"id":583},{"id":584},{"id":585},{"id":586},{"id":587},{"id":588},{"id":589},{"id":590},{"id":591},{"id":592},{"id":593},{"id":594},{"id":595},{"id":596},{"id":597},{"id":598},{"id":599},{"id":600},{"id":601},{"id":602},{"id":603},{"id":604},{"id":605},{"id":606},{"id":607},{"id":608},{"id":609},{"id":610},{"id":611},{"id":612},{"id":613},{"id":614},{"id":615},{"id":616},{"id":617},{"id":618},{"id":619},{"id":620},{"id":621},{"id":622},{"id":623},{"id":624},{"id":625},{"id":626},{"id":627},{"id":628},{"id":629},{"id":630},{"id":631},{"id":632},{"id":633},{"id":634},{"id":635},{"id":636},{"id":637},{"id":638},{"id":639},{"id":640},{"id":641},{"id":642},{"id":643},{"id":644},{"id":645},{"id":646},{"id":647},{"id":648},{"id":649},{"id":650},{"id":651},{"id":652},{"id":653},{"id":654},{"id":655},{"id":656},{"id":657},{"id":658},{"id":659},{"id":660},{"id":661},{"id":662},{"id":663},{"id":664},{"id":665},{"id":666},{"id":667},{"id":668},{"id":669},{"id":670},{"id":671},{"id":672},{"id":673},{"id":674},{"id":675},{"id":676},{"id":677},{"id":678},{"id":679},{"id":680},{"id":681},{"id":682},{"id":683},{"id":684},{"id":685},{"id":686},{"id":687},{"id":688},{"id":689},{"id":690},{"id":691},{"id":692},{"id":693},{"id":694},{"id":695},{"id":696},{"id":697},{"id":698},{"id":699},{"id":700},{"id":701},{"id":702},{"id":703},{"id":704},{"id":705},{"id":706},{"id":707},{"id":708},{"id":709},{"id":710},{"id":711},{"id":712},{"id":713},{"id":714},{"id":715},{"id":716},{"id":717},{"id":718},{"id":719},{"id":720},{"id":721},{"id":722},{"id":723},{"id":724},{"id":725},{"id":726},{"id":727},{"id":728},{"id":729},{"id":730},{"id":731},{"id":732},{"id":733},{"id":734},{"id":735},{"id":736},{"id":737},{"id":738},{"id":739},{"id":740},{"id":741},{"id":742},{"id":743},{"id":744},{"id":745},{"id":746},{"id":747},{"id":748},{"id":749},{"id":750},{"id":751},{"id":752},{"id":753},{"id":754},{"id":755},{"id":755},{"id":756},{"id":757},{"id":758},{"id":759},{"id":760},{"id":761},{"id":762},{"id":763},{"id":764},{"id":765},{"id":766},{"id":767},{"id":768},{"id":769},{"id":770},{"id":771},{"id":772},{"id":773},{"id":774},{"id":775},{"id":776},{"id":777},{"id":778},{"id":779},{"id":780},{"id":781},{"id":782},{"id":783},{"id":784},{"id":785},{"id":786},{"id":787},{"id":788},{"id":789},{"id":790},{"id":791},{"id":792},{"id":793},{"id":794},{"id":795},{"id":796},{"id":797},{"id":798},{"id":799},{"id":800},{"id":801},{"id":802},{"id":803},{"id":804},{"id":805},{"id":806},{"id":807},{"id":808},{"id":809},{"id":810},{"id":811},{"id":812},{"id":813},{"id":814},{"id":815},{"id":816},{"id":817},{"id":818},{"id":819},{"id":820},{"id":821},{"id":822},{"id":823},{"id":824},{"id":825},{"id":826},{"id":827},{"id":828},{"id":829},{"id":830},{"id":831},{"id":832},{"id":833},{"id":834},{"id":835},{"id":836},{"id":837},{"id":838},{"id":839},{"id":840},{"id":841},{"id":842},{"id":843},{"id":844},{"id":845},{"id":846},{"id":847},{"id":848},{"id":849},{"id":850},{"id":851},{"id":852},{"id":853},{"id":854},{"id":855},{"id":856},{"id":857},{"id":858},{"id":859},{"id":860},{"id":861},{"id":862},{"id":863},{"id":864},{"id":865},{"id":866},{"id":867},{"id":868},{"id":869},{"id":870},{"id":871},{"id":872},{"id":873},{"id":874},{"id":875},{"id":876},{"id":877},{"id":878},{"id":879},{"id":880},{"id":881},{"id":882},{"id":883},{"id":884},{"id":885},{"id":886},{"id":887},{"id":888},{"id":889},{"id":890},{"id":891},{"id":892},{"id":893},{"id":894},{"id":895},{"id":896},{"id":897},{"id":898},{"id":899},{"id":900},{"id":901},{"id":902},{"id":903},{"id":904},{"id":905},{"id":906},{"id":907},{"id":908},{"id":909},{"id":910},{"id":911},{"id":912},{"id":913},{"id":914},{"id":915},{"id":916},{"id":917},{"id":918},{"id":919},{"id":920},{"id":921},{"id":922},{"id":923},{"id":924},{"id":925},{"id":926},{"id":927},{"id":928},{"id":929},{"id":930},{"id":931},{"id":932},{"id":933},{"id":934},{"id":935},{"id":936},{"id":937},{"id":938},{"id":939},{"id":940},{"id":941},{"id":942},{"id":943},{"id":944},{"id":945},{"id":946},{"id":947},{"id":948},{"id":949},{"id":950},{"id":951},{"id":952},{"id":953},{"id":954},{"id":955},{"id":956},{"id":957},{"id":958},{"id":959},{"id":960},{"id":961},{"id":962},{"id":963},{"id":964},{"id":965},{"id":966},{"id":967},{"id":968},{"id":969},{"id":970},{"id":971},{"id":972},{"id":973},{"id":974},{"id":975},{"id":976},{"id":977},{"id":978},{"id":979},{"id":980},{"id":981},{"id":982},{"id":983},{"id":984},{"id":985},{"id":986},{"id":987},{"id":988},{"id":989},{"id":990},{"id":991},{"id":992},{"id":993},{"id":994},{"id":995},{"id":996},{"id":997},{"id":998},{"id":999},{"id":1000},{"id":1001},{"id":1002},{"id":1003},{"id":1004},{"id":1005},{"id":1006},{"id":1006},{"id":1007},{"id":1008},{"id":1009},{"id":1010},{"id":1011},{"id":1012},{"id":1013},{"id":1014},{"id":1015},{"id":1016},{"id":1017},{"id":1018},{"id":1019},{"id":1020},{"id":1021},{"id":1022},{"id":1023},{"id":1024},{"id":1025},{"id":1026},{"id":1027},{"id":1028},{"id":1029},{"id":1030},{"id":1031},{"id":1032},{"id":1033},{"id":1034},{"id":1035},{"id":1036},{"id":1037},{"id":1038},{"id":1039},{"id":1040},{"id":1041},{"id":1042},{"id":1043},{"id":1044},{"id":1045},{"id":1046},{"id":1047},{"id":1048},{"id":1049},{"id":1050},{"id":1051},{"id":1052},{"id":1053},{"id":1054},{"id":1055},{"id":1056},{"id":1057},{"id":1058},{"id":1059},{"id":1060},{"id":1061},{"id":1062},{"id":1063},{"id":1064},{"id":1065},{"id":1066},{"id":1067},{"id":1068},{"id":1069},{"id":1070},{"id":1071},{"id":1072},{"id":1073},{"id":1074},{"id":1075},{"id":1076},{"id":1077},{"id":1078},{"id":1079},{"id":1080},{"id":1081},{"id":1082},{"id":1083},{"id":1084},{"id":1085},{"id":1086},{"id":1087},{"id":1088},{"id":1089},{"id":1090},{"id":1091},{"id":1092},{"id":1093},{"id":1094},{"id":1095},{"id":1096},{"id":1097},{"id":1098},{"id":1099},{"id":1100},{"id":1101},{"id":1102},{"id":1103},{"id":1104},{"id":1105},{"id":1106},{"id":1107},{"id":1108},{"id":1109},{"id":1110},{"id":1111},{"id":1112},{"id":1113},{"id":1114},{"id":1115},{"id":1116},{"id":1117},{"id":1118},{"id":1119},{"id":1120},{"id":1121},{"id":1122},{"id":1123},{"id":1124},{"id":1125},{"id":1126},{"id":1127},{"id":1128},{"id":1129},{"id":1130},{"id":1131},{"id":1132},{"id":1133},{"id":1134},{"id":1135},{"id":1136},{"id":1137},{"id":1138},{"id":1139},{"id":1140},{"id":1141},{"id":1142},{"id":1143},{"id":1144},{"id":1145},{"id":1146},{"id":1147},{"id":1148},{"id":1149},{"id":1150},{"id":1151},{"id":1152},{"id":1153},{"id":1154},{"id":1155},{"id":1156},{"id":1157},{"id":1158},{"id":1159},{"id":1160},{"id":1161},{"id":1162},{"id":1163},{"id":1164},{"id":1165},{"id":1166},{"id":1167},{"id":1168},{"id":1169},{"id":1170},{"id":1171},{"id":1172},{"id":1173},{"id":1174},{"id":1175},{"id":1176},{"id":1177},{"id":1178},{"id":1179},{"id":1180},{"id":1181},{"id":1182},{"id":1183},{"id":1184},{"id":1185},{"id":1186},{"id":1187},{"id":1188},{"id":1189},{"id":1190},{"id":1191},{"id":1192},{"id":1193},{"id":1194},{"id":1195},{"id":1196},{"id":1197},{"id":1198},{"id":1199},{"id":1200},{"id":1201},{"id":1202},{"id":1203},{"id":1204},{"id":1205},{"id":1206},{"id":1207},{"id":1208},{"id":1209},{"id":1210},{"id":1211},{"id":1212},{"id":1213},{"id":1214},{"id":1215},{"id":1216},{"id":1217},{"id":1218},{"id":1219},{"id":1220},{"id":1221},{"id":1222},{"id":1223},{"id":1224},{"id":1225},{"id":1226},{"id":1227},{"id":1228},{"id":1229},{"id":1230},{"id":1231},{"id":1232},{"id":1233},{"id":1234},{"id":1235},{"id":1236},{"id":1237},{"id":1238},{"id":1239},{"id":1240},{"id":1241},{"id":1242},{"id":1243},{"id":1244},{"id":1245},{"id":1246},{"id":1247},{"id":1248},{"id":1249},{"id":1250},{"id":1251},{"id":1252},{"id":1253},{"id":1254},{"id":1255},{"id":1256},{"id":1257},{"id":1257},{"id":1258},{"id":1259},{"id":1260},{"id":1261},{"id":1262},{"id":1263},{"id":1264},{"id":1265},{"id":1266},{"id":1267},{"id":1268},{"id":1269},{"id":1270},{"id":1271},{"id":1272},{"id":1273},{"id":1274},{"id":1275},{"id":1276},{"id":1277},{"id":1278},{"id":1279},{"id":1280},{"id":1281},{"id":1282},{"id":1283},{"id":1284},{"id":1285},{"id":1286},{"id":1287},{"id":1288},{"id":1289},{"id":1290},{"id":1291},{"id":1292},{"id":1293},{"id":1294},{"id":1295},{"id":1296},{"id":1297},{"id":1298},{"id":1299},{"id":1300},{"id":1301},{"id":1302},{"id":1303},{"id":1304},{"id":1305},{"id":1306},{"id":1307},{"id":1308},{"id":1309},{"id":1310},{"id":1311},{"id":1312},{"id":1313},{"id":1314},{"id":1315},{"id":1316},{"id":1317},{"id":1318},{"id":1319},{"id":1320},{"id":1321},{"id":1322},{"id":1323},{"id":1324},{"id":1325},{"id":1326},{"id":1327},{"id":1328},{"id":1329},{"id":1330},{"id":1331},{"id":1332},{"id":1333},{"id":1334},{"id":1335},{"id":1336},{"id":1337},{"id":1338},{"id":1339},{"id":1340},{"id":1341},{"id":1342},{"id":1343},{"id":1344},{"id":1345},{"id":1346},{"id":1347},{"id":1348},{"id":1349},{"id":1350},{"id":1351},{"id":1352},{"id":1353},{"id":1354},{"id":1355},{"id":1356},{"id":1357},{"id":1358},{"id":1359},{"id":1360},{"id":1361},{"id":1362},{"id":1363},{"id":1364},{"id":1365},{"id":1366},{"id":1367},{"id":1368},{"id":1369},{"id":1370},{"id":1371},{"id":1372},{"id":1373},{"id":1374},{"id":1375},{"id":1376},{"id":1377},{"id":1378},{"id":1379},{"id":1380},{"id":1381},{"id":1382},{"id":1383},{"id":1384},{"id":1385},{"id":1386},{"id":1387},{"id":1388},{"id":1389},{"id":1390},{"id":1391},{"id":1392},{"id":1393},{"id":1394},{"id":1395},{"id":1396},{"id":1397},{"id":1398},{"id":1399},{"id":1400},{"id":1401},{"id":1402},{"id":1403},{"id":1404},{"id":1405},{"id":1406},{"id":1407},{"id":1408},{"id":1409},{"id":1410},{"id":1411},{"id":1412},{"id":1413},{"id":1414},{"id":1415},{"id":1416},{"id":1417},{"id":1418},{"id":1419},{"id":1420},{"id":1421},{"id":1422},{"id":1423},{"id":1424},{"id":1425},{"id":1426},{"id":1427},{"id":1428},{"id":1429},{"id":1430},{"id":1431},{"id":1432},{"id":1433},{"id":1434},{"id":1435},{"id":1436},{"id":1437},{"id":1438},{"id":1439},{"id":1440},{"id":1441},{"id":1442},{"id":1443},{"id":1444},{"id":1445},{"id":1446},{"id":1447},{"id":1448},{"id":1449},{"id":1450},{"id":1451},{"id":1452},{"id":1453},{"id":1454},{"id":1455},{"id":1456},{"id":1457},{"id":1458},{"id":1459},{"id":1460},{"id":1461},{"id":1462},{"id":1463},{"id":1464},{"id":1465},{"id":1466},{"id":1467},{"id":1468},{"id":1469},{"id":1470},{"id":1471},{"id":1472},{"id":1473},{"id":1474},{"id":1475},{"id":1476},{"id":1477},{"id":1478},{"id":1479},{"id":1480},{"id":1481},{"id":1482},{"id":1483},{"id":1484},{"id":1485},{"id":1486},{"id":1487},{"id":1488},{"id":1489},{"id":1490},{"id":1491},{"id":1492},{"id":1493},{"id":1494},{"id":1495},{"id":1496},{"id":1497},{"id":1498},{"id":1499},{"id":1500},{"id":1501},{"id":1502},{"id":1503},{"id":1504},{"id":1505},{"id":1506},{"id":1507},{"id":1508},{"id":1508},{"id":1509},{"id":1510},{"id":1511},{"id":1512},{"id":1513},{"id":1514},{"id":1515},{"id":1516},{"id":1517},{"id":1518},{"id":1519},{"id":1520},{"id":1521},{"id":1522},{"id":1523},{"id":1524},{"id":1525},{"id":1526},{"id":1527},{"id":1528},{"id":1529},{"id":1530},{"id":1531},{"id":1532},{"id":1533},{"id":1534},{"id":1535},{"id":1536},{"id":1537},{"id":1538},{"id":1539},{"id":1540},{"id":1541},{"id":1542},{"id":1543},{"id":1544},{"id":1545},{"id":1546},{"id":1547},{"id":1548},{"id":1549},{"id":1550},{"id":1551},{"id":1552},{"id":1553},{"id":1554},{"id":1555},{"id":1556},{"id":1557},{"id":1558},{"id":1559},{"id":1560},{"id":1561},{"id":1562},{"id":1563},{"id":1564},{"id":1565},{"id":1566},{"id":1567},{"id":1568},{"id":1569},{"id":1570},{"id":1571},{"id":1572},{"id":1573},{"id":1574},{"id":1575},{"id":1576},{"id":1577},{"id":1578},{"id":1579},{"id":1580},{"id":1581},{"id":1582},{"id":1583},{"id":1584},{"id":1585},{"id":1586},{"id":1587},{"id":1588},{"id":1589},{"id":1590},{"id":1591},{"id":1592},{"id":1593},{"id":1594},{"id":1595},{"id":1596},{"id":1597},{"id":1598},{"id":1599},{"id":1600},{"id":1601},{"id":1602},{"id":1603},{"id":1604},{"id":1605},{"id":1606},{"id":1607},{"id":1608},{"id":1609},{"id":1610},{"id":1611},{"id":1612},{"id":1613},{"id":1614},{"id":1615},{"id":1616},{"id":1617},{"id":1618},{"id":1619},{"id":1620},{"id":1621},{"id":1622},{"id":1623},{"id":1624},{"id":1625},{"id":1626},{"id":1627},{"id":1628},{"id":1629},{"id":1630},{"id":1631},{"id":1632},{"id":1633},{"id":1634},{"id":1635},{"id":1636},{"id":1637},{"id":1638},{"id":1639},{"id":1640},{"id":1641},{"id":1642},{"id":1643},{"id":1644},{"id":1645},{"id":1646},{"id":1647},{"id":1648},{"id":1649},{"id":1650},{"id":1651},{"id":1652},{"id":1653},{"id":1654},{"id":1655},{"id":1656},{"id":1657},{"id":1658},{"id":1659},{"id":1660},{"id":1661},{"id":1662},{"id":1663},{"id":1664},{"id":1665},{"id":1666},{"id":1667},{"id":1668},{"id":1669},{"id":1670},{"id":1671},{"id":1672},{"id":1673},{"id":1674},{"id":1675},{"id":1676},{"id":1677},{"id":1678},{"id":1679},{"id":1680},{"id":1681},{"id":1682},{"id":1683},{"id":1684},{"id":1685},{"id":1686},{"id":1687},{"id":1688},{"id":1689},{"id":1690},{"id":1691},{"id":1692},{"id":1693},{"id":1694},{"id":1695},{"id":1696},{"id":1697},{"id":1698},{"id":1699},{"id":1700},{"id":1701},{"id":1702},{"id":1703},{"id":1704},{"id":1705},{"id":1706},{"id":1707},{"id":1708},{"id":1709},{"id":1710},{"id":1711},{"id":1712},{"id":1713},{"id":1714},{"id":1715},{"id":1716},{"id":1717},{"id":1718},{"id":1719},{"id":1720},{"id":1721},{"id":1722},{"id":1723},{"id":1724},{"id":1725},{"id":1726},{"id":1727},{"id":1728},{"id":1729},{"id":1730},{"id":1731},{"id":1732},{"id":1733},{"id":1734},{"id":1735},{"id":1736},{"id":1737},{"id":1738},{"id":1739},{"id":1740},{"id":1741},{"id":1742},{"id":1743},{"id":1744},{"id":1745},{"id":1746},{"id":1747},{"id":1748},{"id":1749},{"id":1750},{"id":1751},{"id":1752},{"id":1753},{"id":1754},{"id":1755},{"id":1756},{"id":1757},{"id":1758},{"id":1759}],"links":[{"source":0,"target":1},{"source":1,"target":2},{"source":2,"target":3},{"source":2,"target":4},{"source":2,"target":5},{"source":2,"target":6},{"source":1,"target":7},{"source":7,"target":8},{"source":7,"target":9},{"source":7,"target":10},{"source":7,"target":11},{"source":7,"target":12},{"source":1,"target":13},{"source":13,"target":14},{"source":0,"target":15},{"source":15,"target":16},{"source":15,"target":17},{"source":15,"target":18},{"source":18,"target":19},{"source":18,"target":20},{"source":18,"target":21},{"source":18,"target":22},{"source":18,"target":23},{"source":18,"target":24},{"source":18,"target":25},{"source":18,"target":26},{"source":18,"target":27},{"source":15,"target":28},{"source":15,"target":29},{"source":15,"target":30},{"source":15,"target":31},{"source":15,"target":32},{"source":15,"target":33},{"source":15,"target":34},{"source":15,"target":35},{"source":15,"target":36},{"source":0,"target":37},{"source":37,"target":38},{"source":38,"target":39},{"source":38,"target":40},{"source":38,"target":41},{"source":38,"target":42},{"source":38,"target":43},{"source":37,"target":44},{"source":37,"target":45},{"source":37,"target":46},{"source":37,"target":47},{"source":37,"target":48},{"source":37,"target":49},{"source":0,"target":50},{"source":50,"target":51},{"source":50,"target":52},{"source":50,"target":53},{"source":50,"target":54},{"source":0,"target":55},{"source":55,"target":56},{"source":0,"target":57},{"source":57,"target":58},{"source":57,"target":59},{"source":57,"target":60},{"source":57,"target":61},{"source":57,"target":62},{"source":57,"target":63},{"source":57,"target":64},{"source":57,"target":65},{"source":0,"target":66},{"source":66,"target":67},{"source":66,"target":68},{"source":66,"target":69},{"source":66,"target":70},{"source":66,"target":71},{"source":66,"target":72},{"source":66,"target":73},{"source":66,"target":74},{"source":66,"target":75},{"source":66,"target":76},{"source":66,"target":77},{"source":66,"target":78},{"source":66,"target":79},{"source":66,"target":80},{"source":66,"target":81},{"source":66,"target":82},{"source":66,"target":83},{"source":66,"target":84},{"source":66,"target":85},{"source":85,"target":86},{"source":85,"target":87},{"source":85,"target":88},{"source":85,"target":89},{"source":85,"target":90},{"source":85,"target":91},{"source":85,"target":92},{"source":85,"target":93},{"source":85,"target":94},{"source":85,"target":95},{"source":85,"target":96},{"source":85,"target":97},{"source":85,"target":98},{"source":85,"target":99},{"source":85,"target":100},{"source":85,"target":101},{"source":85,"target":102},{"source":85,"target":103},{"source":85,"target":104},{"source":85,"target":105},{"source":85,"target":106},{"source":85,"target":107},{"source":85,"target":108},{"source":85,"target":109},{"source":85,"target":110},{"source":85,"target":111},{"source":85,"target":112},{"source":85,"target":113},{"source":85,"target":114},{"source":85,"target":115},{"source":85,"target":116},{"source":85,"target":117},{"source":66,"target":118},{"source":66,"target":119},{"source":66,"target":120},{"source":66,"target":121},{"source":66,"target":122},{"source":66,"target":123},{"source":66,"target":124},{"source":66,"target":125},{"source":66,"target":126},{"source":66,"target":127},{"source":0,"target":128},{"source":128,"target":129},{"source":128,"target":130},{"source":128,"target":131},{"source":128,"target":132},{"source":128,"target":133},{"source":128,"target":134},{"source":128,"target":135},{"source":128,"target":136},{"source":128,"target":137},{"source":128,"target":138},{"source":0,"target":139},{"source":139,"target":140},{"source":139,"target":141},{"source":139,"target":142},{"source":139,"target":143},{"source":139,"target":144},{"source":139,"target":145},{"source":139,"target":146},{"source":146,"target":147},{"source":146,"target":148},{"source":139,"target":149},{"source":139,"target":150},{"source":139,"target":151},{"source":139,"target":152},{"source":152,"target":153},{"source":152,"target":154},{"source":152,"target":155},{"source":139,"target":156},{"source":139,"target":157},{"source":139,"target":158},{"source":158,"target":159},{"source":158,"target":160},{"source":158,"target":161},{"source":158,"target":162},{"source":139,"target":163},{"source":139,"target":164},{"source":139,"target":165},{"source":139,"target":166},{"source":139,"target":167},{"source":0,"target":168},{"source":168,"target":169},{"source":169,"target":170},{"source":169,"target":171},{"source":169,"target":172},{"source":169,"target":173},{"source":169,"target":174},{"source":168,"target":175},{"source":175,"target":176},{"source":175,"target":177},{"source":175,"target":178},{"source":175,"target":179},{"source":175,"target":180},{"source":175,"target":181},{"source":175,"target":182},{"source":175,"target":183},{"source":175,"target":184},{"source":175,"target":185},{"source":175,"target":186},{"source":168,"target":187},{"source":187,"target":188},{"source":187,"target":189},{"source":187,"target":190},{"source":187,"target":191},{"source":187,"target":192},{"source":187,"target":193},{"source":193,"target":194},{"source":193,"target":195},{"source":193,"target":196},{"source":193,"target":197},{"source":187,"target":198},{"source":187,"target":199},{"source":187,"target":200},{"source":168,"target":201},{"source":201,"target":202},{"source":201,"target":203},{"source":201,"target":204},{"source":201,"target":205},{"source":168,"target":206},{"source":206,"target":207},{"source":206,"target":208},{"source":206,"target":209},{"source":168,"target":210},{"source":210,"target":211},{"source":211,"target":212},{"source":211,"target":213},{"source":211,"target":214},{"source":210,"target":215},{"source":215,"target":216},{"source":215,"target":217},{"source":215,"target":218},{"source":215,"target":219},{"source":215,"target":220},{"source":210,"target":221},{"source":221,"target":222},{"source":221,"target":223},{"source":221,"target":224},{"source":210,"target":225},{"source":210,"target":226},{"source":226,"target":227},{"source":226,"target":228},{"source":226,"target":229},{"source":210,"target":230},{"source":230,"target":231},{"source":230,"target":232},{"source":230,"target":233},{"source":230,"target":234},{"source":230,"target":235},{"source":230,"target":236},{"source":230,"target":237},{"source":230,"target":238},{"source":230,"target":239},{"source":230,"target":240},{"source":230,"target":241},{"source":230,"target":242},{"source":230,"target":243},{"source":230,"target":244},{"source":230,"target":245},{"source":210,"target":246},{"source":210,"target":247},{"source":210,"target":248},{"source":210,"target":249},{"source":210,"target":250},{"source":168,"target":251},{"source":0,"target":300},{"source":252,"target":253},{"source":253,"target":254},{"source":254,"target":255},{"source":254,"target":256},{"source":254,"target":257},{"source":254,"target":258},{"source":253,"target":259},{"source":259,"target":260},{"source":259,"target":261},{"source":259,"target":262},{"source":259,"target":263},{"source":259,"target":264},{"source":253,"target":265},{"source":265,"target":266},{"source":252,"target":267},{"source":267,"target":268},{"source":267,"target":269},{"source":267,"target":270},{"source":270,"target":271},{"source":270,"target":272},{"source":270,"target":273},{"source":270,"target":274},{"source":270,"target":275},{"source":270,"target":276},{"source":270,"target":277},{"source":270,"target":278},{"source":270,"target":279},{"source":267,"target":280},{"source":267,"target":281},{"source":267,"target":282},{"source":267,"target":283},{"source":267,"target":284},{"source":267,"target":285},{"source":267,"target":286},{"source":267,"target":287},{"source":267,"target":288},{"source":252,"target":289},{"source":289,"target":290},{"source":290,"target":291},{"source":290,"target":292},{"source":290,"target":293},{"source":290,"target":294},{"source":290,"target":295},{"source":289,"target":296},{"source":289,"target":297},{"source":289,"target":298},{"source":289,"target":299},{"source":289,"target":300},{"source":289,"target":301},{"source":252,"target":302},{"source":302,"target":303},{"source":302,"target":304},{"source":302,"target":305},{"source":302,"target":306},{"source":252,"target":307},{"source":307,"target":308},{"source":252,"target":309},{"source":309,"target":310},{"source":309,"target":311},{"source":309,"target":312},{"source":309,"target":313},{"source":309,"target":314},{"source":309,"target":315},{"source":309,"target":316},{"source":309,"target":317},{"source":252,"target":318},{"source":318,"target":319},{"source":318,"target":320},{"source":318,"target":321},{"source":318,"target":322},{"source":318,"target":323},{"source":318,"target":324},{"source":318,"target":325},{"source":318,"target":326},{"source":318,"target":327},{"source":318,"target":328},{"source":318,"target":329},{"source":318,"target":330},{"source":318,"target":331},{"source":318,"target":332},{"source":318,"target":333},{"source":318,"target":334},{"source":318,"target":335},{"source":318,"target":336},{"source":318,"target":337},{"source":337,"target":338},{"source":337,"target":339},{"source":337,"target":340},{"source":337,"target":341},{"source":337,"target":342},{"source":337,"target":343},{"source":337,"target":344},{"source":337,"target":345},{"source":337,"target":346},{"source":337,"target":347},{"source":337,"target":348},{"source":337,"target":349},{"source":337,"target":350},{"source":337,"target":351},{"source":337,"target":352},{"source":337,"target":353},{"source":337,"target":354},{"source":337,"target":355},{"source":337,"target":356},{"source":337,"target":357},{"source":337,"target":358},{"source":337,"target":359},{"source":337,"target":360},{"source":337,"target":361},{"source":337,"target":362},{"source":337,"target":363},{"source":337,"target":364},{"source":337,"target":365},{"source":337,"target":366},{"source":337,"target":367},{"source":337,"target":368},{"source":337,"target":369},{"source":318,"target":370},{"source":318,"target":371},{"source":318,"target":372},{"source":318,"target":373},{"source":318,"target":374},{"source":318,"target":375},{"source":318,"target":376},{"source":318,"target":377},{"source":318,"target":378},{"source":318,"target":379},{"source":252,"target":380},{"source":380,"target":381},{"source":380,"target":382},{"source":380,"target":383},{"source":380,"target":384},{"source":380,"target":385},{"source":380,"target":386},{"source":380,"target":387},{"source":380,"target":388},{"source":380,"target":389},{"source":380,"target":390},{"source":252,"target":391},{"source":391,"target":392},{"source":391,"target":393},{"source":391,"target":394},{"source":391,"target":395},{"source":391,"target":396},{"source":391,"target":397},{"source":391,"target":398},{"source":398,"target":399},{"source":398,"target":400},{"source":391,"target":401},{"source":391,"target":402},{"source":391,"target":403},{"source":391,"target":404},{"source":404,"target":405},{"source":404,"target":406},{"source":404,"target":407},{"source":391,"target":408},{"source":391,"target":409},{"source":391,"target":410},{"source":410,"target":411},{"source":410,"target":412},{"source":410,"target":413},{"source":410,"target":414},{"source":391,"target":415},{"source":391,"target":416},{"source":391,"target":417},{"source":391,"target":418},{"source":391,"target":419},{"source":252,"target":420},{"source":420,"target":421},{"source":421,"target":422},{"source":421,"target":423},{"source":421,"target":424},{"source":421,"target":425},{"source":421,"target":426},{"source":420,"target":427},{"source":427,"target":428},{"source":427,"target":429},{"source":427,"target":430},{"source":427,"target":431},{"source":427,"target":432},{"source":427,"target":433},{"source":427,"target":434},{"source":427,"target":435},{"source":427,"target":436},{"source":427,"target":437},{"source":427,"target":438},{"source":420,"target":439},{"source":439,"target":440},{"source":439,"target":441},{"source":439,"target":442},{"source":439,"target":443},{"source":439,"target":444},{"source":439,"target":445},{"source":445,"target":446},{"source":445,"target":447},{"source":445,"target":448},{"source":445,"target":449},{"source":439,"target":450},{"source":439,"target":451},{"source":439,"target":452},{"source":420,"target":453},{"source":453,"target":454},{"source":453,"target":455},{"source":453,"target":456},{"source":453,"target":457},{"source":420,"target":458},{"source":458,"target":459},{"source":458,"target":460},{"source":458,"target":461},{"source":420,"target":462},{"source":462,"target":463},{"source":463,"target":464},{"source":463,"target":465},{"source":463,"target":466},{"source":462,"target":467},{"source":467,"target":468},{"source":467,"target":469},{"source":467,"target":470},{"source":467,"target":471},{"source":467,"target":472},{"source":462,"target":473},{"source":473,"target":474},{"source":473,"target":475},{"source":473,"target":476},{"source":462,"target":477},{"source":462,"target":478},{"source":478,"target":479},{"source":478,"target":480},{"source":478,"target":481},{"source":462,"target":482},{"source":482,"target":483},{"source":482,"target":484},{"source":482,"target":485},{"source":482,"target":486},{"source":482,"target":487},{"source":482,"target":488},{"source":482,"target":489},{"source":482,"target":490},{"source":482,"target":491},{"source":482,"target":492},{"source":482,"target":493},{"source":482,"target":494},{"source":482,"target":495},{"source":482,"target":496},{"source":482,"target":497},{"source":462,"target":498},{"source":462,"target":499},{"source":462,"target":500},{"source":462,"target":501},{"source":462,"target":502},{"source":420,"target":503},{"source":300,"target":600},{"source":504,"target":505},{"source":505,"target":506},{"source":506,"target":507},{"source":506,"target":508},{"source":506,"target":509},{"source":506,"target":510},{"source":505,"target":511},{"source":511,"target":512},{"source":511,"target":513},{"source":511,"target":514},{"source":511,"target":515},{"source":511,"target":516},{"source":505,"target":517},{"source":517,"target":518},{"source":504,"target":519},{"source":519,"target":520},{"source":519,"target":521},{"source":519,"target":522},{"source":522,"target":523},{"source":522,"target":524},{"source":522,"target":525},{"source":522,"target":526},{"source":522,"target":527},{"source":522,"target":528},{"source":522,"target":529},{"source":522,"target":530},{"source":522,"target":531},{"source":519,"target":532},{"source":519,"target":533},{"source":519,"target":534},{"source":519,"target":535},{"source":519,"target":536},{"source":519,"target":537},{"source":519,"target":538},{"source":519,"target":539},{"source":519,"target":540},{"source":504,"target":541},{"source":541,"target":542},{"source":542,"target":543},{"source":542,"target":544},{"source":542,"target":545},{"source":542,"target":546},{"source":542,"target":547},{"source":541,"target":548},{"source":541,"target":549},{"source":541,"target":550},{"source":541,"target":551},{"source":541,"target":552},{"source":541,"target":553},{"source":504,"target":554},{"source":554,"target":555},{"source":554,"target":556},{"source":554,"target":557},{"source":554,"target":558},{"source":504,"target":559},{"source":559,"target":560},{"source":504,"target":561},{"source":561,"target":562},{"source":561,"target":563},{"source":561,"target":564},{"source":561,"target":565},{"source":561,"target":566},{"source":561,"target":567},{"source":561,"target":568},{"source":561,"target":569},{"source":504,"target":570},{"source":570,"target":571},{"source":570,"target":572},{"source":570,"target":573},{"source":570,"target":574},{"source":570,"target":575},{"source":570,"target":576},{"source":570,"target":577},{"source":570,"target":578},{"source":570,"target":579},{"source":570,"target":580},{"source":570,"target":581},{"source":570,"target":582},{"source":570,"target":583},{"source":570,"target":584},{"source":570,"target":585},{"source":570,"target":586},{"source":570,"target":587},{"source":570,"target":588},{"source":570,"target":589},{"source":589,"target":590},{"source":589,"target":591},{"source":589,"target":592},{"source":589,"target":593},{"source":589,"target":594},{"source":589,"target":595},{"source":589,"target":596},{"source":589,"target":597},{"source":589,"target":598},{"source":589,"target":599},{"source":589,"target":600},{"source":589,"target":601},{"source":589,"target":602},{"source":589,"target":603},{"source":589,"target":604},{"source":589,"target":605},{"source":589,"target":606},{"source":589,"target":607},{"source":589,"target":608},{"source":589,"target":609},{"source":589,"target":610},{"source":589,"target":611},{"source":589,"target":612},{"source":589,"target":613},{"source":589,"target":614},{"source":589,"target":615},{"source":589,"target":616},{"source":589,"target":617},{"source":589,"target":618},{"source":589,"target":619},{"source":589,"target":620},{"source":589,"target":621},{"source":570,"target":622},{"source":570,"target":623},{"source":570,"target":624},{"source":570,"target":625},{"source":570,"target":626},{"source":570,"target":627},{"source":570,"target":628},{"source":570,"target":629},{"source":570,"target":630},{"source":570,"target":631},{"source":504,"target":632},{"source":632,"target":633},{"source":632,"target":634},{"source":632,"target":635},{"source":632,"target":636},{"source":632,"target":637},{"source":632,"target":638},{"source":632,"target":639},{"source":632,"target":640},{"source":632,"target":641},{"source":632,"target":642},{"source":504,"target":643},{"source":643,"target":644},{"source":643,"target":645},{"source":643,"target":646},{"source":643,"target":647},{"source":643,"target":648},{"source":643,"target":649},{"source":643,"target":650},{"source":650,"target":651},{"source":650,"target":652},{"source":643,"target":653},{"source":643,"target":654},{"source":643,"target":655},{"source":643,"target":656},{"source":656,"target":657},{"source":656,"target":658},{"source":656,"target":659},{"source":643,"target":660},{"source":643,"target":661},{"source":643,"target":662},{"source":662,"target":663},{"source":662,"target":664},{"source":662,"target":665},{"source":662,"target":666},{"source":643,"target":667},{"source":643,"target":668},{"source":643,"target":669},{"source":643,"target":670},{"source":643,"target":671},{"source":504,"target":672},{"source":672,"target":673},{"source":673,"target":674},{"source":673,"target":675},{"source":673,"target":676},{"source":673,"target":677},{"source":673,"target":678},{"source":672,"target":679},{"source":679,"target":680},{"source":679,"target":681},{"source":679,"target":682},{"source":679,"target":683},{"source":679,"target":684},{"source":679,"target":685},{"source":679,"target":686},{"source":679,"target":687},{"source":679,"target":688},{"source":679,"target":689},{"source":679,"target":690},{"source":672,"target":691},{"source":691,"target":692},{"source":691,"target":693},{"source":691,"target":694},{"source":691,"target":695},{"source":691,"target":696},{"source":691,"target":697},{"source":697,"target":698},{"source":697,"target":699},{"source":697,"target":700},{"source":697,"target":701},{"source":691,"target":702},{"source":691,"target":703},{"source":691,"target":704},{"source":672,"target":705},{"source":705,"target":706},{"source":705,"target":707},{"source":705,"target":708},{"source":705,"target":709},{"source":672,"target":710},{"source":710,"target":711},{"source":710,"target":712},{"source":710,"target":713},{"source":672,"target":714},{"source":714,"target":715},{"source":715,"target":716},{"source":715,"target":717},{"source":715,"target":718},{"source":714,"target":719},{"source":719,"target":720},{"source":719,"target":721},{"source":719,"target":722},{"source":719,"target":723},{"source":719,"target":724},{"source":714,"target":725},{"source":725,"target":726},{"source":725,"target":727},{"source":725,"target":728},{"source":714,"target":729},{"source":714,"target":730},{"source":730,"target":731},{"source":730,"target":732},{"source":730,"target":733},{"source":714,"target":734},{"source":734,"target":735},{"source":734,"target":736},{"source":734,"target":737},{"source":734,"target":738},{"source":734,"target":739},{"source":734,"target":740},{"source":734,"target":741},{"source":734,"target":742},{"source":734,"target":743},{"source":734,"target":744},{"source":734,"target":745},{"source":734,"target":746},{"source":734,"target":747},{"source":734,"target":748},{"source":734,"target":749},{"source":714,"target":750},{"source":714,"target":751},{"source":714,"target":752},{"source":714,"target":753},{"source":714,"target":754},{"source":672,"target":755},{"source":600,"target":800},{"source":755,"target":756},{"source":756,"target":757},{"source":757,"target":758},{"source":757,"target":759},{"source":757,"target":760},{"source":757,"target":761},{"source":756,"target":762},{"source":762,"target":763},{"source":762,"target":764},{"source":762,"target":765},{"source":762,"target":766},{"source":762,"target":767},{"source":756,"target":768},{"source":768,"target":769},{"source":755,"target":770},{"source":770,"target":771},{"source":770,"target":772},{"source":770,"target":773},{"source":773,"target":774},{"source":773,"target":775},{"source":773,"target":776},{"source":773,"target":777},{"source":773,"target":778},{"source":773,"target":779},{"source":773,"target":780},{"source":773,"target":781},{"source":773,"target":782},{"source":770,"target":783},{"source":770,"target":784},{"source":770,"target":785},{"source":770,"target":786},{"source":770,"target":787},{"source":770,"target":788},{"source":770,"target":789},{"source":770,"target":790},{"source":770,"target":791},{"source":755,"target":792},{"source":792,"target":793},{"source":793,"target":794},{"source":793,"target":795},{"source":793,"target":796},{"source":793,"target":797},{"source":793,"target":798},{"source":792,"target":799},{"source":792,"target":800},{"source":792,"target":801},{"source":792,"target":802},{"source":792,"target":803},{"source":792,"target":804},{"source":755,"target":805},{"source":805,"target":806},{"source":805,"target":807},{"source":805,"target":808},{"source":805,"target":809},{"source":755,"target":810},{"source":810,"target":811},{"source":755,"target":812},{"source":812,"target":813},{"source":812,"target":814},{"source":812,"target":815},{"source":812,"target":816},{"source":812,"target":817},{"source":812,"target":818},{"source":812,"target":819},{"source":812,"target":820},{"source":755,"target":821},{"source":821,"target":822},{"source":821,"target":823},{"source":821,"target":824},{"source":821,"target":825},{"source":821,"target":826},{"source":821,"target":827},{"source":821,"target":828},{"source":821,"target":829},{"source":821,"target":830},{"source":821,"target":831},{"source":821,"target":832},{"source":821,"target":833},{"source":821,"target":834},{"source":821,"target":835},{"source":821,"target":836},{"source":821,"target":837},{"source":821,"target":838},{"source":821,"target":839},{"source":821,"target":840},{"source":840,"target":841},{"source":840,"target":842},{"source":840,"target":843},{"source":840,"target":844},{"source":840,"target":845},{"source":840,"target":846},{"source":840,"target":847},{"source":840,"target":848},{"source":840,"target":849},{"source":840,"target":850},{"source":840,"target":851},{"source":840,"target":852},{"source":840,"target":853},{"source":840,"target":854},{"source":840,"target":855},{"source":840,"target":856},{"source":840,"target":857},{"source":840,"target":858},{"source":840,"target":859},{"source":840,"target":860},{"source":840,"target":861},{"source":840,"target":862},{"source":840,"target":863},{"source":840,"target":864},{"source":840,"target":865},{"source":840,"target":866},{"source":840,"target":867},{"source":840,"target":868},{"source":840,"target":869},{"source":840,"target":870},{"source":840,"target":871},{"source":840,"target":872},{"source":821,"target":873},{"source":821,"target":874},{"source":821,"target":875},{"source":821,"target":876},{"source":821,"target":877},{"source":821,"target":878},{"source":821,"target":879},{"source":821,"target":880},{"source":821,"target":881},{"source":821,"target":882},{"source":755,"target":883},{"source":883,"target":884},{"source":883,"target":885},{"source":883,"target":886},{"source":883,"target":887},{"source":883,"target":888},{"source":883,"target":889},{"source":883,"target":890},{"source":883,"target":891},{"source":883,"target":892},{"source":883,"target":893},{"source":755,"target":894},{"source":894,"target":895},{"source":894,"target":896},{"source":894,"target":897},{"source":894,"target":898},{"source":894,"target":899},{"source":894,"target":900},{"source":894,"target":901},{"source":901,"target":902},{"source":901,"target":903},{"source":894,"target":904},{"source":894,"target":905},{"source":894,"target":906},{"source":894,"target":907},{"source":907,"target":908},{"source":907,"target":909},{"source":907,"target":910},{"source":894,"target":911},{"source":894,"target":912},{"source":894,"target":913},{"source":913,"target":914},{"source":913,"target":915},{"source":913,"target":916},{"source":913,"target":917},{"source":894,"target":918},{"source":894,"target":919},{"source":894,"target":920},{"source":894,"target":921},{"source":894,"target":922},{"source":755,"target":923},{"source":923,"target":924},{"source":924,"target":925},{"source":924,"target":926},{"source":924,"target":927},{"source":924,"target":928},{"source":924,"target":929},{"source":923,"target":930},{"source":930,"target":931},{"source":930,"target":932},{"source":930,"target":933},{"source":930,"target":934},{"source":930,"target":935},{"source":930,"target":936},{"source":930,"target":937},{"source":930,"target":938},{"source":930,"target":939},{"source":930,"target":940},{"source":930,"target":941},{"source":923,"target":942},{"source":942,"target":943},{"source":942,"target":944},{"source":942,"target":945},{"source":942,"target":946},{"source":942,"target":947},{"source":942,"target":948},{"source":948,"target":949},{"source":948,"target":950},{"source":948,"target":951},{"source":948,"target":952},{"source":942,"target":953},{"source":942,"target":954},{"source":942,"target":955},{"source":923,"target":956},{"source":956,"target":957},{"source":956,"target":958},{"source":956,"target":959},{"source":956,"target":960},{"source":923,"target":961},{"source":961,"target":962},{"source":961,"target":963},{"source":961,"target":964},{"source":923,"target":965},{"source":965,"target":966},{"source":966,"target":967},{"source":966,"target":968},{"source":966,"target":969},{"source":965,"target":970},{"source":970,"target":971},{"source":970,"target":972},{"source":970,"target":973},{"source":970,"target":974},{"source":970,"target":975},{"source":965,"target":976},{"source":976,"target":977},{"source":976,"target":978},{"source":976,"target":979},{"source":965,"target":980},{"source":965,"target":981},{"source":981,"target":982},{"source":981,"target":983},{"source":981,"target":984},{"source":965,"target":985},{"source":985,"target":986},{"source":985,"target":987},{"source":985,"target":988},{"source":985,"target":989},{"source":985,"target":990},{"source":985,"target":991},{"source":985,"target":992},{"source":985,"target":993},{"source":985,"target":994},{"source":985,"target":995},{"source":985,"target":996},{"source":985,"target":997},{"source":985,"target":998},{"source":985,"target":999},{"source":985,"target":1000},{"source":965,"target":1001},{"source":965,"target":1002},{"source":965,"target":1003},{"source":965,"target":1004},{"source":965,"target":1005},{"source":923,"target":1006},{"source":800,"target":1000},{"source":1006,"target":1007},{"source":1007,"target":1008},{"source":1008,"target":1009},{"source":1008,"target":1010},{"source":1008,"target":1011},{"source":1008,"target":1012},{"source":1007,"target":1013},{"source":1013,"target":1014},{"source":1013,"target":1015},{"source":1013,"target":1016},{"source":1013,"target":1017},{"source":1013,"target":1018},{"source":1007,"target":1019},{"source":1019,"target":1020},{"source":1006,"target":1021},{"source":1021,"target":1022},{"source":1021,"target":1023},{"source":1021,"target":1024},{"source":1024,"target":1025},{"source":1024,"target":1026},{"source":1024,"target":1027},{"source":1024,"target":1028},{"source":1024,"target":1029},{"source":1024,"target":1030},{"source":1024,"target":1031},{"source":1024,"target":1032},{"source":1024,"target":1033},{"source":1021,"target":1034},{"source":1021,"target":1035},{"source":1021,"target":1036},{"source":1021,"target":1037},{"source":1021,"target":1038},{"source":1021,"target":1039},{"source":1021,"target":1040},{"source":1021,"target":1041},{"source":1021,"target":1042},{"source":1006,"target":1043},{"source":1043,"target":1044},{"source":1044,"target":1045},{"source":1044,"target":1046},{"source":1044,"target":1047},{"source":1044,"target":1048},{"source":1044,"target":1049},{"source":1043,"target":1050},{"source":1043,"target":1051},{"source":1043,"target":1052},{"source":1043,"target":1053},{"source":1043,"target":1054},{"source":1043,"target":1055},{"source":1006,"target":1056},{"source":1056,"target":1057},{"source":1056,"target":1058},{"source":1056,"target":1059},{"source":1056,"target":1060},{"source":1006,"target":1061},{"source":1061,"target":1062},{"source":1006,"target":1063},{"source":1063,"target":1064},{"source":1063,"target":1065},{"source":1063,"target":1066},{"source":1063,"target":1067},{"source":1063,"target":1068},{"source":1063,"target":1069},{"source":1063,"target":1070},{"source":1063,"target":1071},{"source":1006,"target":1072},{"source":1072,"target":1073},{"source":1072,"target":1074},{"source":1072,"target":1075},{"source":1072,"target":1076},{"source":1072,"target":1077},{"source":1072,"target":1078},{"source":1072,"target":1079},{"source":1072,"target":1080},{"source":1072,"target":1081},{"source":1072,"target":1082},{"source":1072,"target":1083},{"source":1072,"target":1084},{"source":1072,"target":1085},{"source":1072,"target":1086},{"source":1072,"target":1087},{"source":1072,"target":1088},{"source":1072,"target":1089},{"source":1072,"target":1090},{"source":1072,"target":1091},{"source":1091,"target":1092},{"source":1091,"target":1093},{"source":1091,"target":1094},{"source":1091,"target":1095},{"source":1091,"target":1096},{"source":1091,"target":1097},{"source":1091,"target":1098},{"source":1091,"target":1099},{"source":1091,"target":1100},{"source":1091,"target":1101},{"source":1091,"target":1102},{"source":1091,"target":1103},{"source":1091,"target":1104},{"source":1091,"target":1105},{"source":1091,"target":1106},{"source":1091,"target":1107},{"source":1091,"target":1108},{"source":1091,"target":1109},{"source":1091,"target":1110},{"source":1091,"target":1111},{"source":1091,"target":1112},{"source":1091,"target":1113},{"source":1091,"target":1114},{"source":1091,"target":1115},{"source":1091,"target":1116},{"source":1091,"target":1117},{"source":1091,"target":1118},{"source":1091,"target":1119},{"source":1091,"target":1120},{"source":1091,"target":1121},{"source":1091,"target":1122},{"source":1091,"target":1123},{"source":1072,"target":1124},{"source":1072,"target":1125},{"source":1072,"target":1126},{"source":1072,"target":1127},{"source":1072,"target":1128},{"source":1072,"target":1129},{"source":1072,"target":1130},{"source":1072,"target":1131},{"source":1072,"target":1132},{"source":1072,"target":1133},{"source":1006,"target":1134},{"source":1134,"target":1135},{"source":1134,"target":1136},{"source":1134,"target":1137},{"source":1134,"target":1138},{"source":1134,"target":1139},{"source":1134,"target":1140},{"source":1134,"target":1141},{"source":1134,"target":1142},{"source":1134,"target":1143},{"source":1134,"target":1144},{"source":1006,"target":1145},{"source":1145,"target":1146},{"source":1145,"target":1147},{"source":1145,"target":1148},{"source":1145,"target":1149},{"source":1145,"target":1150},{"source":1145,"target":1151},{"source":1145,"target":1152},{"source":1152,"target":1153},{"source":1152,"target":1154},{"source":1145,"target":1155},{"source":1145,"target":1156},{"source":1145,"target":1157},{"source":1145,"target":1158},{"source":1158,"target":1159},{"source":1158,"target":1160},{"source":1158,"target":1161},{"source":1145,"target":1162},{"source":1145,"target":1163},{"source":1145,"target":1164},{"source":1164,"target":1165},{"source":1164,"target":1166},{"source":1164,"target":1167},{"source":1164,"target":1168},{"source":1145,"target":1169},{"source":1145,"target":1170},{"source":1145,"target":1171},{"source":1145,"target":1172},{"source":1145,"target":1173},{"source":1006,"target":1174},{"source":1174,"target":1175},{"source":1175,"target":1176},{"source":1175,"target":1177},{"source":1175,"target":1178},{"source":1175,"target":1179},{"source":1175,"target":1180},{"source":1174,"target":1181},{"source":1181,"target":1182},{"source":1181,"target":1183},{"source":1181,"target":1184},{"source":1181,"target":1185},{"source":1181,"target":1186},{"source":1181,"target":1187},{"source":1181,"target":1188},{"source":1181,"target":1189},{"source":1181,"target":1190},{"source":1181,"target":1191},{"source":1181,"target":1192},{"source":1174,"target":1193},{"source":1193,"target":1194},{"source":1193,"target":1195},{"source":1193,"target":1196},{"source":1193,"target":1197},{"source":1193,"target":1198},{"source":1193,"target":1199},{"source":1199,"target":1200},{"source":1199,"target":1201},{"source":1199,"target":1202},{"source":1199,"target":1203},{"source":1193,"target":1204},{"source":1193,"target":1205},{"source":1193,"target":1206},{"source":1174,"target":1207},{"source":1207,"target":1208},{"source":1207,"target":1209},{"source":1207,"target":1210},{"source":1207,"target":1211},{"source":1174,"target":1212},{"source":1212,"target":1213},{"source":1212,"target":1214},{"source":1212,"target":1215},{"source":1174,"target":1216},{"source":1216,"target":1217},{"source":1217,"target":1218},{"source":1217,"target":1219},{"source":1217,"target":1220},{"source":1216,"target":1221},{"source":1221,"target":1222},{"source":1221,"target":1223},{"source":1221,"target":1224},{"source":1221,"target":1225},{"source":1221,"target":1226},{"source":1216,"target":1227},{"source":1227,"target":1228},{"source":1227,"target":1229},{"source":1227,"target":1230},{"source":1216,"target":1231},{"source":1216,"target":1232},{"source":1232,"target":1233},{"source":1232,"target":1234},{"source":1232,"target":1235},{"source":1216,"target":1236},{"source":1236,"target":1237},{"source":1236,"target":1238},{"source":1236,"target":1239},{"source":1236,"target":1240},{"source":1236,"target":1241},{"source":1236,"target":1242},{"source":1236,"target":1243},{"source":1236,"target":1244},{"source":1236,"target":1245},{"source":1236,"target":1246},{"source":1236,"target":1247},{"source":1236,"target":1248},{"source":1236,"target":1249},{"source":1236,"target":1250},{"source":1236,"target":1251},{"source":1216,"target":1252},{"source":1216,"target":1253},{"source":1216,"target":1254},{"source":1216,"target":1255},{"source":1216,"target":1256},{"source":1174,"target":1257},{"source":1000,"target":1200},{"source":1257,"target":1258},{"source":1258,"target":1259},{"source":1259,"target":1260},{"source":1259,"target":1261},{"source":1259,"target":1262},{"source":1259,"target":1263},{"source":1258,"target":1264},{"source":1264,"target":1265},{"source":1264,"target":1266},{"source":1264,"target":1267},{"source":1264,"target":1268},{"source":1264,"target":1269},{"source":1258,"target":1270},{"source":1270,"target":1271},{"source":1257,"target":1272},{"source":1272,"target":1273},{"source":1272,"target":1274},{"source":1272,"target":1275},{"source":1275,"target":1276},{"source":1275,"target":1277},{"source":1275,"target":1278},{"source":1275,"target":1279},{"source":1275,"target":1280},{"source":1275,"target":1281},{"source":1275,"target":1282},{"source":1275,"target":1283},{"source":1275,"target":1284},{"source":1272,"target":1285},{"source":1272,"target":1286},{"source":1272,"target":1287},{"source":1272,"target":1288},{"source":1272,"target":1289},{"source":1272,"target":1290},{"source":1272,"target":1291},{"source":1272,"target":1292},{"source":1272,"target":1293},{"source":1257,"target":1294},{"source":1294,"target":1295},{"source":1295,"target":1296},{"source":1295,"target":1297},{"source":1295,"target":1298},{"source":1295,"target":1299},{"source":1295,"target":1300},{"source":1294,"target":1301},{"source":1294,"target":1302},{"source":1294,"target":1303},{"source":1294,"target":1304},{"source":1294,"target":1305},{"source":1294,"target":1306},{"source":1257,"target":1307},{"source":1307,"target":1308},{"source":1307,"target":1309},{"source":1307,"target":1310},{"source":1307,"target":1311},{"source":1257,"target":1312},{"source":1312,"target":1313},{"source":1257,"target":1314},{"source":1314,"target":1315},{"source":1314,"target":1316},{"source":1314,"target":1317},{"source":1314,"target":1318},{"source":1314,"target":1319},{"source":1314,"target":1320},{"source":1314,"target":1321},{"source":1314,"target":1322},{"source":1257,"target":1323},{"source":1323,"target":1324},{"source":1323,"target":1325},{"source":1323,"target":1326},{"source":1323,"target":1327},{"source":1323,"target":1328},{"source":1323,"target":1329},{"source":1323,"target":1330},{"source":1323,"target":1331},{"source":1323,"target":1332},{"source":1323,"target":1333},{"source":1323,"target":1334},{"source":1323,"target":1335},{"source":1323,"target":1336},{"source":1323,"target":1337},{"source":1323,"target":1338},{"source":1323,"target":1339},{"source":1323,"target":1340},{"source":1323,"target":1341},{"source":1323,"target":1342},{"source":1342,"target":1343},{"source":1342,"target":1344},{"source":1342,"target":1345},{"source":1342,"target":1346},{"source":1342,"target":1347},{"source":1342,"target":1348},{"source":1342,"target":1349},{"source":1342,"target":1350},{"source":1342,"target":1351},{"source":1342,"target":1352},{"source":1342,"target":1353},{"source":1342,"target":1354},{"source":1342,"target":1355},{"source":1342,"target":1356},{"source":1342,"target":1357},{"source":1342,"target":1358},{"source":1342,"target":1359},{"source":1342,"target":1360},{"source":1342,"target":1361},{"source":1342,"target":1362},{"source":1342,"target":1363},{"source":1342,"target":1364},{"source":1342,"target":1365},{"source":1342,"target":1366},{"source":1342,"target":1367},{"source":1342,"target":1368},{"source":1342,"target":1369},{"source":1342,"target":1370},{"source":1342,"target":1371},{"source":1342,"target":1372},{"source":1342,"target":1373},{"source":1342,"target":1374},{"source":1323,"target":1375},{"source":1323,"target":1376},{"source":1323,"target":1377},{"source":1323,"target":1378},{"source":1323,"target":1379},{"source":1323,"target":1380},{"source":1323,"target":1381},{"source":1323,"target":1382},{"source":1323,"target":1383},{"source":1323,"target":1384},{"source":1257,"target":1385},{"source":1385,"target":1386},{"source":1385,"target":1387},{"source":1385,"target":1388},{"source":1385,"target":1389},{"source":1385,"target":1390},{"source":1385,"target":1391},{"source":1385,"target":1392},{"source":1385,"target":1393},{"source":1385,"target":1394},{"source":1385,"target":1395},{"source":1257,"target":1396},{"source":1396,"target":1397},{"source":1396,"target":1398},{"source":1396,"target":1399},{"source":1396,"target":1400},{"source":1396,"target":1401},{"source":1396,"target":1402},{"source":1396,"target":1403},{"source":1403,"target":1404},{"source":1403,"target":1405},{"source":1396,"target":1406},{"source":1396,"target":1407},{"source":1396,"target":1408},{"source":1396,"target":1409},{"source":1409,"target":1410},{"source":1409,"target":1411},{"source":1409,"target":1412},{"source":1396,"target":1413},{"source":1396,"target":1414},{"source":1396,"target":1415},{"source":1415,"target":1416},{"source":1415,"target":1417},{"source":1415,"target":1418},{"source":1415,"target":1419},{"source":1396,"target":1420},{"source":1396,"target":1421},{"source":1396,"target":1422},{"source":1396,"target":1423},{"source":1396,"target":1424},{"source":1257,"target":1425},{"source":1425,"target":1426},{"source":1426,"target":1427},{"source":1426,"target":1428},{"source":1426,"target":1429},{"source":1426,"target":1430},{"source":1426,"target":1431},{"source":1425,"target":1432},{"source":1432,"target":1433},{"source":1432,"target":1434},{"source":1432,"target":1435},{"source":1432,"target":1436},{"source":1432,"target":1437},{"source":1432,"target":1438},{"source":1432,"target":1439},{"source":1432,"target":1440},{"source":1432,"target":1441},{"source":1432,"target":1442},{"source":1432,"target":1443},{"source":1425,"target":1444},{"source":1444,"target":1445},{"source":1444,"target":1446},{"source":1444,"target":1447},{"source":1444,"target":1448},{"source":1444,"target":1449},{"source":1444,"target":1450},{"source":1450,"target":1451},{"source":1450,"target":1452},{"source":1450,"target":1453},{"source":1450,"target":1454},{"source":1444,"target":1455},{"source":1444,"target":1456},{"source":1444,"target":1457},{"source":1425,"target":1458},{"source":1458,"target":1459},{"source":1458,"target":1460},{"source":1458,"target":1461},{"source":1458,"target":1462},{"source":1425,"target":1463},{"source":1463,"target":1464},{"source":1463,"target":1465},{"source":1463,"target":1466},{"source":1425,"target":1467},{"source":1467,"target":1468},{"source":1468,"target":1469},{"source":1468,"target":1470},{"source":1468,"target":1471},{"source":1467,"target":1472},{"source":1472,"target":1473},{"source":1472,"target":1474},{"source":1472,"target":1475},{"source":1472,"target":1476},{"source":1472,"target":1477},{"source":1467,"target":1478},{"source":1478,"target":1479},{"source":1478,"target":1480},{"source":1478,"target":1481},{"source":1467,"target":1482},{"source":1467,"target":1483},{"source":1483,"target":1484},{"source":1483,"target":1485},{"source":1483,"target":1486},{"source":1467,"target":1487},{"source":1487,"target":1488},{"source":1487,"target":1489},{"source":1487,"target":1490},{"source":1487,"target":1491},{"source":1487,"target":1492},{"source":1487,"target":1493},{"source":1487,"target":1494},{"source":1487,"target":1495},{"source":1487,"target":1496},{"source":1487,"target":1497},{"source":1487,"target":1498},{"source":1487,"target":1499},{"source":1487,"target":1500},{"source":1487,"target":1501},{"source":1487,"target":1502},{"source":1467,"target":1503},{"source":1467,"target":1504},{"source":1467,"target":1505},{"source":1467,"target":1506},{"source":1467,"target":1507},{"source":1425,"target":1508},{"source":1100,"target":1300},{"source":1508,"target":1509},{"source":1509,"target":1510},{"source":1510,"target":1511},{"source":1510,"target":1512},{"source":1510,"target":1513},{"source":1510,"target":1514},{"source":1509,"target":1515},{"source":1515,"target":1516},{"source":1515,"target":1517},{"source":1515,"target":1518},{"source":1515,"target":1519},{"source":1515,"target":1520},{"source":1509,"target":1521},{"source":1521,"target":1522},{"source":1508,"target":1523},{"source":1523,"target":1524},{"source":1523,"target":1525},{"source":1523,"target":1526},{"source":1526,"target":1527},{"source":1526,"target":1528},{"source":1526,"target":1529},{"source":1526,"target":1530},{"source":1526,"target":1531},{"source":1526,"target":1532},{"source":1526,"target":1533},{"source":1526,"target":1534},{"source":1526,"target":1535},{"source":1523,"target":1536},{"source":1523,"target":1537},{"source":1523,"target":1538},{"source":1523,"target":1539},{"source":1523,"target":1540},{"source":1523,"target":1541},{"source":1523,"target":1542},{"source":1523,"target":1543},{"source":1523,"target":1544},{"source":1508,"target":1545},{"source":1545,"target":1546},{"source":1546,"target":1547},{"source":1546,"target":1548},{"source":1546,"target":1549},{"source":1546,"target":1550},{"source":1546,"target":1551},{"source":1545,"target":1552},{"source":1545,"target":1553},{"source":1545,"target":1554},{"source":1545,"target":1555},{"source":1545,"target":1556},{"source":1545,"target":1557},{"source":1508,"target":1558},{"source":1558,"target":1559},{"source":1558,"target":1560},{"source":1558,"target":1561},{"source":1558,"target":1562},{"source":1508,"target":1563},{"source":1563,"target":1564},{"source":1508,"target":1565},{"source":1565,"target":1566},{"source":1565,"target":1567},{"source":1565,"target":1568},{"source":1565,"target":1569},{"source":1565,"target":1570},{"source":1565,"target":1571},{"source":1565,"target":1572},{"source":1565,"target":1573},{"source":1508,"target":1574},{"source":1574,"target":1575},{"source":1574,"target":1576},{"source":1574,"target":1577},{"source":1574,"target":1578},{"source":1574,"target":1579},{"source":1574,"target":1580},{"source":1574,"target":1581},{"source":1574,"target":1582},{"source":1574,"target":1583},{"source":1574,"target":1584},{"source":1574,"target":1585},{"source":1574,"target":1586},{"source":1574,"target":1587},{"source":1574,"target":1588},{"source":1574,"target":1589},{"source":1574,"target":1590},{"source":1574,"target":1591},{"source":1574,"target":1592},{"source":1574,"target":1593},{"source":1593,"target":1594},{"source":1593,"target":1595},{"source":1593,"target":1596},{"source":1593,"target":1597},{"source":1593,"target":1598},{"source":1593,"target":1599},{"source":1593,"target":1600},{"source":1593,"target":1601},{"source":1593,"target":1602},{"source":1593,"target":1603},{"source":1593,"target":1604},{"source":1593,"target":1605},{"source":1593,"target":1606},{"source":1593,"target":1607},{"source":1593,"target":1608},{"source":1593,"target":1609},{"source":1593,"target":1610},{"source":1593,"target":1611},{"source":1593,"target":1612},{"source":1593,"target":1613},{"source":1593,"target":1614},{"source":1593,"target":1615},{"source":1593,"target":1616},{"source":1593,"target":1617},{"source":1593,"target":1618},{"source":1593,"target":1619},{"source":1593,"target":1620},{"source":1593,"target":1621},{"source":1593,"target":1622},{"source":1593,"target":1623},{"source":1593,"target":1624},{"source":1593,"target":1625},{"source":1574,"target":1626},{"source":1574,"target":1627},{"source":1574,"target":1628},{"source":1574,"target":1629},{"source":1574,"target":1630},{"source":1574,"target":1631},{"source":1574,"target":1632},{"source":1574,"target":1633},{"source":1574,"target":1634},{"source":1574,"target":1635},{"source":1508,"target":1636},{"source":1636,"target":1637},{"source":1636,"target":1638},{"source":1636,"target":1639},{"source":1636,"target":1640},{"source":1636,"target":1641},{"source":1636,"target":1642},{"source":1636,"target":1643},{"source":1636,"target":1644},{"source":1636,"target":1645},{"source":1636,"target":1646},{"source":1508,"target":1647},{"source":1647,"target":1648},{"source":1647,"target":1649},{"source":1647,"target":1650},{"source":1647,"target":1651},{"source":1647,"target":1652},{"source":1647,"target":1653},{"source":1647,"target":1654},{"source":1654,"target":1655},{"source":1654,"target":1656},{"source":1647,"target":1657},{"source":1647,"target":1658},{"source":1647,"target":1659},{"source":1647,"target":1660},{"source":1660,"target":1661},{"source":1660,"target":1662},{"source":1660,"target":1663},{"source":1647,"target":1664},{"source":1647,"target":1665},{"source":1647,"target":1666},{"source":1666,"target":1667},{"source":1666,"target":1668},{"source":1666,"target":1669},{"source":1666,"target":1670},{"source":1647,"target":1671},{"source":1647,"target":1672},{"source":1647,"target":1673},{"source":1647,"target":1674},{"source":1647,"target":1675},{"source":1508,"target":1676},{"source":1676,"target":1677},{"source":1677,"target":1678},{"source":1677,"target":1679},{"source":1677,"target":1680},{"source":1677,"target":1681},{"source":1677,"target":1682},{"source":1676,"target":1683},{"source":1683,"target":1684},{"source":1683,"target":1685},{"source":1683,"target":1686},{"source":1683,"target":1687},{"source":1683,"target":1688},{"source":1683,"target":1689},{"source":1683,"target":1690},{"source":1683,"target":1691},{"source":1683,"target":1692},{"source":1683,"target":1693},{"source":1683,"target":1694},{"source":1676,"target":1695},{"source":1695,"target":1696},{"source":1695,"target":1697},{"source":1695,"target":1698},{"source":1695,"target":1699},{"source":1695,"target":1700},{"source":1695,"target":1701},{"source":1701,"target":1702},{"source":1701,"target":1703},{"source":1701,"target":1704},{"source":1701,"target":1705},{"source":1695,"target":1706},{"source":1695,"target":1707},{"source":1695,"target":1708},{"source":1676,"target":1709},{"source":1709,"target":1710},{"source":1709,"target":1711},{"source":1709,"target":1712},{"source":1709,"target":1713},{"source":1676,"target":1714},{"source":1714,"target":1715},{"source":1714,"target":1716},{"source":1714,"target":1717},{"source":1676,"target":1718},{"source":1718,"target":1719},{"source":1719,"target":1720},{"source":1719,"target":1721},{"source":1719,"target":1722},{"source":1718,"target":1723},{"source":1723,"target":1724},{"source":1723,"target":1725},{"source":1723,"target":1726},{"source":1723,"target":1727},{"source":1723,"target":1728},{"source":1718,"target":1729},{"source":1729,"target":1730},{"source":1729,"target":1731},{"source":1729,"target":1732},{"source":1718,"target":1733},{"source":1718,"target":1734},{"source":1734,"target":1735},{"source":1734,"target":1736},{"source":1734,"target":1737},{"source":1718,"target":1738},{"source":1738,"target":1739},{"source":1738,"target":1740},{"source":1738,"target":1741},{"source":1738,"target":1742},{"source":1738,"target":1743},{"source":1738,"target":1744},{"source":1738,"target":1745},{"source":1738,"target":1746},{"source":1738,"target":1747},{"source":1738,"target":1748},{"source":1738,"target":1749},{"source":1738,"target":1750},{"source":1738,"target":1751},{"source":1738,"target":1752},{"source":1738,"target":1753},{"source":1718,"target":1754},{"source":1718,"target":1755},{"source":1718,"target":1756},{"source":1718,"target":1757},{"source":1718,"target":1758},{"source":1676,"target":1759}]}
================================================
FILE: .storybook/stories/LayoutForceGraph.stories.tsx
================================================
import * as React from 'react'
import { useState } from "react";
import { Canvas, useFrame } from "@react-three/fiber";
import { Instances, Instance, Segment, Segments, OrbitControls } from "@react-three/drei";
import { useControls } from "leva";
import tree from "../public/treeLarge.json";
// Check out the library: https://github.com/flavioschneider/graphire
import {
Graph,
useGraph,
useNode,
useLink,
LayoutForce,
ForceLink,
ForceManyBody,
ForceDirection
} from "../../src";
const colors = ["#ff7675", "#74b9ff", "#26de81", "#F79F1F"];
export function App() {
const { links, repulsion, distance } = useControls({
links: { value: 100, min: 0, max: 1800 },
repulsion: { value: 20, min: -1, max: 100 },
distance: { value: 30, min: 0, max: 100 }
});
const [graph] = useState(() => tree);
return (
<Canvas
dpr={[1, 1.5]}
camera={{ position: [0, 0, 400], up: [0, 0, 1], near: 1, far: 10000 }}
>
<ambientLight intensity={0.4} />
<OrbitControls enableDamping={false} />
<Graph dim={3}>
<LayoutForce alphaTarget={0.4} velocityDecay={0.1}>
<ForceLink distance={distance} />
<ForceManyBody strength={repulsion} />
<ForceDirection x={0} y={0} z={0} strength={0.05} />
</LayoutForce>
<FrameLoop />
{/* Instanced nodes (for efficency)*/}
<Instances limit={10000}>
<sphereGeometry args={[4, 10, 10]} />
<meshStandardMaterial />
{graph.nodes.map((node, id) => (
<Node key={node.id} uid={node.id} color={colors[node.id % 4]} />
))}
</Instances>
{/* Segmented links (for efficiency) */}
<Segments limit={10000} lineWidth={1.0}>
{graph.links.map((link, id) => id < links && <Link key={id} source={link.source} target={link.target} />)}
<Segment start={[0,0,0]} end={[10,10,10]} color={'red'}/>
</Segments>
</Graph>
</Canvas>
);
}
const Node = (props) => {
const { color = "white", ...rest } = props;
const ref = React.useRef();
useNode((pos) => {
// Called on node position change
ref.current.position.fromArray(pos);
}, rest);
return <Instance ref={ref} color={color} />;
};
const Link = (props) => {
const { source, target, ...rest } = props;
const ref = React.useRef()
useLink((spos, tpos) => {
// Called when source or target node position changes
ref.current.start.set(...spos)
ref.current.end.set(...tpos)
}, source, target, rest);
return <Segment ref={ref} />;
};
/*
This component is used to share the frame loop between threejs and the
graphire simulation, it is not strictly necessary but a good pratice.
*/
const FrameLoop = () => {
const graph = useGraph();
return useFrame(() => graph.frame());
};
export default {
title: 'Layout Force / Graph Instancing (R3F)'
}
================================================
FILE: .storybook/stories/LayoutForceParticles.stories.tsx
================================================
import * as React from 'react'
import { useState } from "react";
import { Canvas, useFrame } from "@react-three/fiber";
import { Instances, Instance, Segment, Segments, OrbitControls } from "@react-three/drei";
import { useControls } from "leva";
// Check out the library: https://github.com/flavioschneider/graphire
import {
Graph,
useGraph,
useNode,
useLink,
LayoutForce,
ForceLink,
ForceManyBody,
ForceDirection
} from "../../src";
const colors = ["#ff7675", "#74b9ff", "#26de81", "#F79F1F"];
export function App() {
const { repulsion } = useControls({
repulsion: { value: 20, min: -1, max: 100 },
});
return (
<Canvas
dpr={[1, 1.5]}
camera={{ position: [0, 0, 400], up: [0, 0, 1], near: 1, far: 10000 }}
>
<ambientLight intensity={0.4} />
<OrbitControls enableDamping={false} />
<Graph dim={3}>
<LayoutForce alphaTarget={0.4} velocityDecay={0.1}>
<ForceManyBody strength={repulsion} />
<ForceDirection x={0} y={0} z={0} strength={0.05} />
</LayoutForce>
<FrameLoop />
{/* Instanced nodes (for efficency)*/}
<Instances limit={10000}>
<sphereGeometry args={[4, 20, 20]} />
<meshStandardMaterial />
{Array(10000).fill(0).map((_, id) => (
<Particle key={id} uid={id} color={colors[id % 4]} />
))}
</Instances>
</Graph>
</Canvas>
);
}
const Particle = (props) => {
const { color = "white", ...rest } = props;
const ref = React.useRef();
useNode((pos) => {
// Called on node position change
ref.current.position.fromArray(pos);
}, rest);
return <Instance ref={ref} color={color} />;
};
/*
This component is used to share the frame loop between threejs and the
graphire simulation, it is not strictly necessary but a good pratice.
*/
const FrameLoop = () => {
const graph = useGraph();
return useFrame(() => graph.frame());
};
export default {
title: 'Layout Force / Particles Instancing (R3F)'
}
================================================
FILE: .storybook/stories/NoLayoutDragDropR3F.stories.tsx
================================================
import * as React from 'react'
import { Canvas } from "@react-three/fiber";
import { Segment, Segments, OrbitControls } from "@react-three/drei";
import * as THREE from "three";
import useDrag from "./useDrag";
// Check out the library: https://github.com/flavioschneider/graphire
import {
Graph,
useNode,
useLink
} from "../../src";
export function App() {
return (
<Canvas
dpr={[1, 1.5]}
camera={{ position: [10, 15, 10], up: [0, 0, 1], near: 1, far: 10000 }}
shadows
>
<spotLight position={[0,0,10]}
penumbra={1}
angle={1}
castShadow
intensity={0.5}
shadow-mapSize={[512, 512]}/>
<ambientLight intensity={1} />
<OrbitControls makeDefault enableDamping={false} />
<mesh position={[0, 0, -0.5]} receiveShadow>
<planeBufferGeometry args={[200, 200]} />
<shadowMaterial transparent opacity={0.3}/>
</mesh>
<Graph dim={3}>
<Node uid={0} color="#EF5B5B" x={0} y={3}/>
<Node uid={1} color="#20A39E" x={-2} y={6}/>
<Node uid={2} color="#FFBA49" x={4} y={3}/>
<Node uid={3} color="#FFBA49" x={-3} y={3}/>
<Node uid={4} color="#20A39E" x={3} y={-3}/>
<Node uid={5} color="#EF5B5B" x={-7} y={4}/>
<Segments limit={6} lineWidth={3.0}>
<Link source={0} target={1}/>
<Link source={0} target={2}/>
<Link source={0} target={3}/>
<Link source={3} target={4}/>
<Link source={3} target={5}/>
<Link source={3} target={1}/>
</Segments>
</Graph>
</Canvas>
);
}
const plane = new THREE.Plane(new THREE.Vector3(0, 0, 1), 0)
const Node = (props) => {
const { color = "white", ...rest } = props;
const ref = React.useRef();
const api = useNode((pos) => {
ref.current.position.fromArray(pos);
}, rest);
const bind = useDrag(([x, y], e) => {
e.stopPropagation()
api.set({ x, y })
}, plane)
return (
<mesh ref={ref} {...bind()} rotation={[Math.PI/2,0,0]} castShadow>
<cylinderGeometry args={[1,1,0.2, 40]}/>
<meshStandardMaterial attach="material" color={color} />
</mesh>
)
};
const Link = (props) => {
const { source, target, ...rest } = props;
const ref = React.useRef()
useLink((spos, tpos) => {
ref.current.start.set(...spos)
ref.current.end.set(...tpos)
}, source, target, rest);
return <Segment ref={ref} />;
};
export default {
title: 'No Layout / Drag & Drop (R3F)'
}
================================================
FILE: .storybook/stories/NoLayoutDragDropSVG.stories.jsx
================================================
import * as React from 'react'
import { useState, useRef } from 'react'
import { useDrag } from '@use-gesture/react'
// Check out the library doc: https://github.com/flavioschneider/graphire
import {
Graph,
useNode,
useLink,
LayoutForce,
ForceCollide,
ForceManyBody
} from '../../src'
const colors = ["#ff7675", "#74b9ff", "#26de81", "#F79F1F"];
export function App() {
const [ bubbles ] = useState(() => [ 13, 7, 38, 7, 10, 17, 10, 3, 10, 15, 20, 31, 22, 40, 10, 10, 30, 22])
return (
<svg style={{width: '100vw', height: '100vh'}}>
<Graph>
<LayoutForce alphaTarget={0.3} velocityDecay={0.1}>
<ForceManyBody strength={-2} />
<ForceCollide strength={1}/>
</LayoutForce>
<g id='nodes'>
{ bubbles.map((r, id) => <Node key={id} uid={id} x={200+Math.random()} y={200+Math.random()} radius={r} color={colors[id%4]} />)}
</g>
<Link source={0} target={1} />
<use href='#nodes' style={{ pointerEvents: 'none' }} />
</Graph>
</svg>
);
}
const Node = (props) => {
const { color='black', radius=5, x=0, y=0 } = props
const ref = useRef()
const node = useNode(([x, y]) => {
// When node position changes we update the circle position using react-spring
ref.current.setAttribute('cx', x)
ref.current.setAttribute('cy', y)
}, { radius, x, y })
const bind = useDrag(({ active, offset: [x, y] }) => {
// When drag starts, we update the graphire node simulation by fixing x and y
node.set({ fx: active ? x : undefined, fy: active ? y : undefined })
}, { from: () => [node.get().x, node.get().y] })
return <circle ref={ref} r={radius} fill={color} {...bind()} />
}
const Link = (props) => {
const { source, target, color = '#95a5a6', ...rest } = props
const ref = useRef()
useLink(([x1, y1], [x2, y2]) => {
ref.current.setAttribute('x1', x1)
ref.current.setAttribute('y1', y1)
ref.current.setAttribute('x2', x2)
ref.current.setAttribute('y2', y2)
}, source, target, rest)
return (
<line ref={ref} stroke={color} strokeWidth={1} />
)
}
export default {
title: 'No Layout / Drag & Drop (SVG)'
}
================================================
FILE: .storybook/stories/useDrag.tsx
================================================
import { useState } from "react";
import { useDrag } from "@use-gesture/react";
import { useThree } from "@react-three/fiber";
import * as THREE from "three";
function useDragSnap(callback, plane, snap = {x: 0, y: 0}) {
const { controls } = useThree()
const [ intersect ] = useState(() => new THREE.Vector3())
const nearest = (val, snap) => snap ? Math.round(val / snap) * snap : val
return useDrag(({ active, event }) => {
if (active) {
controls.enabled = false
event.ray.intersectPlane(plane, intersect)
const [x, y, z] = intersect.toArray()
callback([nearest(x, snap.x), nearest(y, snap.y), nearest(z, snap.z)], event)
} else {
controls.enabled = true
}
})
}
export default useDragSnap;
================================================
FILE: .storybook/tsconfig.json
================================================
{
"extends": "../tsconfig",
"exclude": [],
"include": ["./stories/*"]
}
================================================
FILE: LICENSE
================================================
MIT License
Copyright (c) 2020 react-spring
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
================================================
FILE: README.md
================================================
<img src="markdown/logo.png">
[](https://www.npmjs.com/package/graphire)
[](https://www.npmjs.com/package/graphire)
[](https://www.npmjs.com/package/graphire)
```bash
npm install graphire
```
### What is it?
Graphire is a declarative and unopinionated graph visualization library for React. It supports different layouts to visualize large dynamic networks of nodes and links in both 2D and 3D.
### How does it work?
Internally it stores the graph using a bidirectional adjacency list that allows fast insertion, deletion, and iteration. It then exposes a `Graph` wrapper and two essential hooks: `useNode` and `useLink`. Those will help you to update the node and links position in an unopinionated way.
### Unopinionated?
It means that you can choose nodes and links to be anything you like: a `<circle>`/`<line>` (SVGs), `<div>`, `<canvas>`, `<mesh>`/instanced mesh (ThreeJS with R3F). The exposed hooks will only care for positioning. It will be up to you to decide how to display and style the nodes and links.
### Why?
Some graph/network visualization libraries like D3.js are not made to work with React, hence uncomfortable to use. Other libraries are made for React but do not decouple styling from positioning, making it hard to customize. Graphire solves that. And it's _fast_.
# [Documentation](https://github.com/flavioschneider/graphire/wiki)
# Examples
<table>
<tr>
<td width='50%'>
<a href="https://codesandbox.io/s/graphire-svg-simple-graph-example-eftpc?file=/src/App.js:184-633"><img src="markdown/svg-example.png"></a>
Simple example using SVGs (no layout).
</td>
<td width='50%'>
<a href="https://codesandbox.io/s/graphire-svg-bubble-example-e33ss"><img src="markdown/svg-bubble-example.png"></a>
Bubble example using SVGs (layout force).
</td>
</tr>
<tr>
<td width='50%'>
<a href="https://codesandbox.io/s/graphire-forcelayout-example-jet3q"><img src="markdown/preview.png"></a>
Graph example in 3D with react-three-fiber (Three.js) using very efficient node instancing and segments (layout force).
</td>
<td width='50%'>
<a href="https://codesandbox.io/s/graphire-drag-drop-r3f-uski3"><img src="markdown/dragdrop-example.gif"></a>
Drag and drop nodes with @use-gesture and react-three-fiber (no layout).
</td>
</tr>
</table>
# Basic Usage:
1. Use `Node` and `Link`components (defined in step 2 and 3) inside an svg by using the `Graph` wrapper.
```jsx
import { Graph } from 'graphire'
const MyComponent = (
return (
<svg>
<Graph>
<Node uid={0} x={110} y={300} color='red'/>
<Node uid={1} x={50} y={30} color='orange' />
<Node uid={2} x={150} y={80} color='green' />
<Node uid='k' x={200} y={200} color='blue' />
<Node uid={3} x={400} y={100} color='yellow' />
<Link source={0} target={1} />
<Link source={1} target={2} />
<Link source={1} target='k' />
<Link source={3} target='k' />
</Graph>
</svg>
)
)
```
2. Build the `Node` component using the `useNode` hook.
```jsx
import { useRef } from 'react'
import { useNode } from 'graphire'
const Node = (props) => {
const { color='black', radius=5, ...rest } = props
const ref = useRef()
useNode(([cx, cy]) => {
ref.current.setAttribute('cx', cx)
ref.current.setAttribute('cy', cy)
}, rest)
return <circle ref={ref} cx='0' cy='0' r={radius} fill={color} />
}
```
3. Build the `Link` component using the `useLink` hook.
```jsx
import { useRef } from 'react'
import { useLink } from 'graphire'
// Link
const Link = (props) => {
const { source, target, color = 'black', ...rest } = props
const ref = useRef()
useLink(([x1, y1], [x2, y2]) => {
ref.current.setAttribute('x1', x1)
ref.current.setAttribute('y1', y1)
ref.current.setAttribute('x2', x2)
ref.current.setAttribute('y2', y2)
}, source, target, rest)
return (
<line ref={ref} x1='0' y1='0' x2='0' y2='0' stroke={color} strokeWidth={1} />
)
}
```
## Goals:
Short-term:
- [ ] -
Medium-term:
- [ ] Convert to typescript (50% done)
Long-term:
- [ ] Layout circular
================================================
FILE: package.json
================================================
{
"name": "graphire",
"version": "0.0.0-beta.11",
"description": "A unopinionated react graph library.",
"keywords": [
"react",
"graph",
"network",
"visualization"
],
"author": "Flavio Schneider",
"license": "MIT",
"repository": "flavioschneider/graphire",
"homepage": "https://github.com/flavioschneider/graphire",
"main": "dist/index.cjs",
"module": "dist/index.js",
"types": "dist/index.d.ts",
"sideEffects": false,
"husky": {
"hooks": {
"pre-commit": "lint-staged"
}
},
"lint-staged": {
"*.{js,jsx,ts,tsx}": [
"eslint --fix"
]
},
"scripts": {
"build": "rollup -c",
"postbuild": "tsc --emitDeclarationOnly",
"prepublishOnly": "npm run build",
"test": "echo no tests yet",
"storybook": "start-storybook -s ./.storybook/public -p 6006",
"build-storybook": "build-storybook -s ./.storybook/public"
},
"dependencies": {
"@react-spring/rafz": "^9.3.0",
"caniuse-lite": "^1.0.30001279"
},
"devDependencies": {
"@babel/core": "^7.14.3",
"@babel/plugin-transform-modules-commonjs": "^7.14.0",
"@babel/plugin-transform-runtime": "^7.14.3",
"@babel/preset-env": "^7.14.2",
"@babel/preset-react": "^7.13.13",
"@babel/preset-typescript": "^7.10.4",
"@commitlint/cli": "^12.0.1",
"@commitlint/config-conventional": "^12.0.1",
"@react-three/drei": "^7.20.5",
"@react-three/fiber": "^6.0.0",
"@rollup/plugin-babel": "^5.3.0",
"@rollup/plugin-commonjs": "^19.0.0",
"@rollup/plugin-json": "^4.1.0",
"@rollup/plugin-node-resolve": "^13.0.0",
"@storybook/addon-actions": "^6.3.12",
"@storybook/addon-controls": "^6.3.12",
"@storybook/addon-knobs": "^6.3.1",
"@storybook/addon-storysource": "^6.3.12",
"@storybook/addons": "^6.3.12",
"@storybook/preset-typescript": "^3.0.0",
"@storybook/react": "^6.3.12",
"@storybook/theming": "^6.3.12",
"@types/jest": "^26.0.10",
"@types/lodash-es": "^4.17.3",
"@types/react": "^17.0.5",
"@types/react-dom": "^17.0.5",
"@types/three": "^0.128.0",
"@typescript-eslint/eslint-plugin": "^4.24.0",
"@typescript-eslint/parser": "^4.24.0",
"@use-gesture/react": "^10.1.4",
"babel-eslint": "^10.1.0",
"babel-loader": "^8.1.0",
"copyfiles": "^2.3.0",
"eslint": "^7.7.0",
"eslint-config-prettier": "^8.3.0",
"eslint-plugin-import": "^2.22.0",
"eslint-plugin-prettier": "^3.1.4",
"eslint-plugin-react": "^7.20.6",
"eslint-plugin-react-hooks": "^4.1.0",
"glslify-loader": "^2.0.0",
"graphire": "^0.0.0-beta.10",
"husky": "^6.0.0",
"jest": "^26.4.1",
"json": "^11.0.0",
"leva": "^0.9.14",
"prettier": "^2.4.1",
"pretty-quick": "^3.1.0",
"react": "^17.0.2",
"react-dom": "^17.0.2",
"rimraf": "^3.0.2",
"rollup": "^2.58.0",
"rollup-plugin-glslify": "^1.2.1",
"rollup-plugin-multi-input": "^1.3.1",
"rollup-plugin-terser": "^7.0.2",
"three": "^0.128.0",
"typescript": "^4.2.3"
},
"peerDependencies": {
"react": ">=17.0"
}
}
================================================
FILE: rollup.config.js
================================================
import path from 'path'
import babel from '@rollup/plugin-babel'
import resolve from '@rollup/plugin-node-resolve'
const root = process.platform === 'win32' ? path.resolve('/') : '/'
const external = (id) => !id.startsWith('.') && !id.startsWith(root)
const extensions = ['.js', '.jsx', '.ts', '.tsx', '.json']
const getBabelOptions = ({ useESModules }) => ({
babelrc: false,
extensions,
exclude: '**/node_modules/**',
babelHelpers: 'runtime',
presets: [
[
'@babel/preset-env',
{
include: [
'@babel/plugin-proposal-optional-chaining',
'@babel/plugin-proposal-nullish-coalescing-operator',
'@babel/plugin-proposal-numeric-separator',
'@babel/plugin-proposal-logical-assignment-operators',
],
bugfixes: true,
loose: true,
modules: false,
targets: '> 1%, not dead, not ie 11, not op_mini all',
},
],
'@babel/preset-react',
'@babel/preset-typescript',
],
plugins: [['@babel/transform-runtime', { regenerator: false, useESModules }]],
})
export default [
{
input: `./src/index.ts`,
output: { file: `dist/index.js`, format: 'esm' },
external,
plugins: [
babel(getBabelOptions({ useESModules: true })),
resolve({ extensions }),
],
},
{
input: `./src/index.ts`,
output: { file: `dist/index.cjs.js`, format: 'cjs' },
external,
plugins: [babel(getBabelOptions({ useESModules: false })), resolve({ extensions })],
},
]
================================================
FILE: src/graph.tsx
================================================
import * as React from 'react'
import {
useState,
useLayoutEffect,
useRef,
useContext,
createContext,
RefObject
} from 'react'
import { is, arr } from './utils'
import { useUpdatedRef, useObserver } from './hooks'
import { raf } from '@react-spring/rafz'
type UID = number | string
type Position = [number, number, number]
type CallbackNode = (position: Position, node?: Node) => void
type RefCallbackNode = RefObject<CallbackNode>
interface ParamsNode {
uid?: UID
x?: number
y?: number
z?: number
fx?: number
fy?: number
fz?: number
}
interface Node extends ParamsNode {
callback: RefCallbackNode
x: number
y: number
z: number
linksTo: Link[]
linksFrom: Link[]
}
type CallbackLink = (sourcePosition: Position, targetPosition: Position, sourceNode?: Node, targetNode?: Node, link?: Link) => void
type RefCallbackLink = RefObject<CallbackLink>
interface Link {
callback: RefCallbackLink
node: Node
}
interface LinkPair {
to: Link
from: Link
}
interface Subscriber {
onAddNode: (node: Node) => void
onBeforeAddNode: (node: Node) => void
onRemoveNode: (node: Node) => void
onAddLink: (source: Link, target: Link) => void
onRemoveLink: (source: Link, target: Link) => void
onParamsChange: (params: ParamsGraph) => void
}
type Unsusbscribe = () => void
interface ParamsGraph {
dim: number
}
interface GraphState {
params: ParamsGraph
adjacency: Node[]
uids: { [key in UID]: Node },
subscribers: Set<Subscriber>
}
type ParamsLink = { [key: string]: (string | number | ((fn: any) => any) ) }
const GraphContext = createContext<GraphState | null>(null)
class GraphState {
constructor() {
this.params = { dim: 2 }
this.adjacency = []
this.uids = {}
this.subscribers = new Set()
}
frame() {
raf.frameLoop = 'demand'
raf.advance();
}
updateParams(params: ParamsGraph) {
Object.assign(this.params, params)
this.subscribers.forEach(({ onParamsChange }) => onParamsChange && onParamsChange(this.params))
}
getNodeById(id: UID, useUid: boolean = true) {
return useUid ? this.uids[id] : this.adjacency[id as number]
}
addNode(callback: RefCallbackNode): Node {
// Initialize node
const node = {
x: 0,
y: 0,
z: 0,
linksTo: [],
linksFrom: [],
callback
}
// Notify subscribers
this.subscribers.forEach(({ onBeforeAddNode }) => onBeforeAddNode && onBeforeAddNode(node))
// Add node to adjacency list
this.adjacency.push(node)
// Notify subscribers
this.subscribers.forEach(({ onAddNode }) => onAddNode && onAddNode(node))
return node
}
removeNode(node: Node) {
// Remove node from adjacency list
arr.remove(this.adjacency, node)
// Remove node from uids object if present
!is.und(node.uid) && (delete this.uids[node.uid!])
// Remove parent links
node.linksFrom.forEach((linkFrom) => {
linkFrom.node.linksTo = linkFrom.node.linksTo.filter(linkTo => linkTo.node !== node)
})
// Remove child links
node.linksTo.forEach((linkTo) => {
linkTo.node.linksFrom = linkTo.node.linksFrom.filter(linkFrom => linkFrom.node !== node)
})
// Notify subscribers
this.subscribers.forEach(({ onRemoveNode }) => onRemoveNode && onRemoveNode(node))
}
updateNode(node: Node, params: ParamsNode = {}, updateInLinks: boolean = true) {
Object.assign(node, params)
// Add/update uids if uid present
!is.und(node.uid) && (this.uids[node.uid!] = node) // TODO: delete if changed
// Set fixed position if present
node.fx && (node.x = node.fx)
node.fy && (node.y = node.fy)
node.fz && (node.z = node.fz)
// Update node position
this.notifyNode(node)
// Update attached links position
// Links from this node to other nodes
node.linksTo.forEach((link) => {
this.notifyLink(link, node, link.node)
//return
})
// Links from other nodes to this node
updateInLinks && node.linksFrom.forEach((link) => {
this.notifyLink(link, link.node, node)
})
}
notifyNode(node: Node) {
node.callback.current!([node.x, node.y, node.z], node)
}
isLinkValid(source: Node, target: Node) {
return !is.und(source) && !is.und(target)
}
addLinkById(callback: RefCallbackLink, sid: UID, tid: UID, useUid = false) : LinkPair {
const source = this.getNodeById(sid, useUid)
const target = this.getNodeById(tid, useUid)
if (!this.isLinkValid(source, target)) throw `You are trying to add a link to unexisting nodes: [${sid}]->[${tid}]`
return this.addLink(callback, source, target)
}
addLink(callback: RefCallbackLink, source: Node, target: Node): LinkPair {
// Add source link
const linkTo = { node: target, callback }
source.linksTo.push(linkTo)
// Add target link
const linkFrom = { node: source, callback }
target.linksFrom.push(linkFrom)
// Update initial position
this.notifyLink(linkTo, source, target)
// Notify subscribers
this.subscribers.forEach(({ onAddLink }) => onAddLink && onAddLink(linkTo, linkFrom))
return { to: linkTo, from: linkFrom }
}
removeLinkById(sid: UID, tid: UID, linkTo: Link, linkFrom: Link, useUid: boolean = false) {
const source = this.getNodeById(sid, useUid)
const target = this.getNodeById(tid, useUid)
if (!this.isLinkValid(source, target)) return
this.removeLink(source, target, linkTo, linkFrom)
}
removeLink(source: Node, target: Node, linkTo: Link, linkFrom: Link) {
arr.remove(source.linksTo, linkTo)
arr.remove(target.linksFrom, linkFrom)
// Notify subscribers
this.subscribers.forEach(({ onRemoveLink }) => onRemoveLink && onRemoveLink(linkTo, linkFrom))
}
updateLink(to: Link, from: Link, params: ParamsLink) {
Object.assign(to, params)
}
notifyLink(link: Link, source: Node, target: Node) {
link.callback.current!(
[source.x, source.y, source.z],
[target.x, target.y, target.z],
source,
target,
link
)
}
subscribeChanges(callbacks: Subscriber) : Unsusbscribe {
this.subscribers.add(callbacks)
return () => this.subscribers.delete(callbacks)
}
log() {
this.adjacency.forEach((node) => this.logNode(node))
console.log('\n')
}
logNode(node: Node) {
const to: any [] = [], from: any[] = []
node.linksTo.forEach((link) => {
to.push(is.und(link.node.uid) ? 'Noid' : link.node.uid )
})
node.linksFrom.forEach((link) => {
from.push(is.und(link.node.uid) ? 'Noid' : link.node.uid)
})
const id = is.und(node.uid) ? 'Noid' : node.uid
console.log(id +': (to->):['+to+'], (from<-):['+from+']\n')
}
}
export const useGraph = () => {
const graph = useContext(GraphContext)
if (!graph) throw 'Hooks must used inside Graph'
return graph
}
export const useNode = (callback: CallbackNode, params: ParamsNode = {}) => {
const graph = useGraph()
const nodeRef = useRef<Node>()
const callbackRef = useUpdatedRef(callback)
// Subscribe node
useLayoutEffect(() => {
const node = graph.addNode(callbackRef)
nodeRef.current = node
return () => graph.removeNode(node)
}, [graph, callbackRef, nodeRef])
// Deep observe params changes
useObserver((change: ParamsNode) => {
const node = nodeRef.current
node && graph.updateNode(node, change, true)
}, params)
// Return API for fast (transient) changes e.g. x,y,z.
const api = {
set: (change: ParamsNode) => {
const node = nodeRef.current
node && graph.updateNode(node, change, true)
},
get: () => nodeRef.current
}
return api
}
export const useLink = (callback: CallbackLink, source: UID, target: UID, params: ParamsLink = {}) => {
const graph = useGraph()
const linkRef = useRef<LinkPair>()
const callbackRef = useUpdatedRef(callback)
// Subscribe link
useLayoutEffect(() => {
const { to, from } = graph.addLinkById(callbackRef, source, target, true)
linkRef.current = { to, from }
return () => graph.removeLinkById(source, target, to, from, true)
}, [graph, callbackRef, source, target])
// Deep observe params changes
useObserver((change: ParamsLink) => {
const links = linkRef.current
links && graph.updateLink(links.to, links.from, change)
}, params)
// Return API for fast (transient) changes e.g. distance.
const api = {
set: (change: ParamsLink) => {
const links = linkRef.current
links && graph.updateLink(links.to, links.from, change)
},
get: () => linkRef.current
}
return api
}
interface PropsGraph extends ParamsGraph {
children?: React.ReactNode
}
export const Graph = (props: PropsGraph) => {
const { children, ...rest } = props
const [graph] = useState(() => new GraphState())
// Update params
useObserver((change: ParamsGraph) => graph.updateParams(change), rest)
return <GraphContext.Provider value={graph}>{children}</GraphContext.Provider>
}
================================================
FILE: src/hooks.js
================================================
import { useRef, useLayoutEffect } from 'react'
import { is } from './utils'
export const useUpdatedRef = (params) => {
const ref = useRef(params)
useLayoutEffect(() => void (ref.current = params), [params])
return ref
}
export const useObserver = (callback, params) => {
const paramsRef = useRef()
useLayoutEffect(() => {
const prev = paramsRef.current
if (!is.dequ(prev, params)) {
callback(params)
paramsRef.current = params
}
}, [callback, params, paramsRef])
return null
}
================================================
FILE: src/index.ts
================================================
export * from './graph'
export * from './layouts'
================================================
FILE: src/layouts/force/forceCenter.jsx
================================================
import { useForce } from './layoutForce'
export const ForceCenter = (props) => {
const { strength = 1, x = 0, y = 0, z = 0 } = props
useForce((graph) => {
var n = graph.length
// Find average center vector
var sx = 0, sy = 0, sz = 0
graph.forEach((node) => ((sx += node.x), (sy += node.y), (sz += node.z)))
sx = (sx / n - x) * strength
sy = (sy / n - y) * strength
sz = (sz / n - z) * strength
// Correct position
graph.forEach((node) => ((node.x -= sx), (node.y -= sy), (node.z -= sz)))
})
return null
}
================================================
FILE: src/layouts/force/forceCollide.jsx
================================================
import { useForce } from './layoutForce'
import { is } from '../../utils'
export const ForceCollide = (props) => {
const { strength = 1.0, radius = 1.0 } = props
useForce((graph, { dim }) => {
// N-body Newton O(n^2) (most inefficient): https://en.wikipedia.org/wiki/N-body_problem
graph.forEach((source) => {
var rs = !is.und(source.radius) ? source.radius : radius
graph.forEach((target) => {
if (is.equ(source, target)) return
var rt = !is.und(target.radius) ? target.radius : radius
var dist = rt + rs // Minimum distance to collision
var x = target.x + target.vx - source.x - source.vx
var y = target.y + target.vy - source.y - source.vy
var z = (target.z + target.vz - source.z - source.vz) * (dim === 3)
var len2 = x * x + y * y + z * z * (dim === 3)
if (len2 < dist * dist) {
if (len2 < 1e-6) len2 = 1e-6 // To avoid division by 0
var len = Math.sqrt(len2)
var force = ((dist - len) / len) * strength
var rt2 = rt*rt
var rs2 = rs*rs
var k = rt2 / (rs2 + rt2)
source.vx -= x * force * k
source.vy -= y * force * k
source.vz -= z * force * k
k = (1 - k)
target.vx += x * force * k
target.vy += y * force * k
target.vz += z * force * k
}
})
})
})
return null
}
================================================
FILE: src/layouts/force/forceDirection.jsx
================================================
import { useForce } from './layoutForce'
import { is } from '../../utils'
export const ForceDirection = (props) => {
const { strength = 0.1, x, y, z } = props
useForce((graph, { alpha }) => {
graph.forEach((node) => {
!is.und(x) && (node.vx += (x - node.x) * strength * alpha)
!is.und(y) && (node.vy += (y - node.y) * strength * alpha)
!is.und(z) && (node.vz += (z - node.z) * strength * alpha)
})
})
return null
}
================================================
FILE: src/layouts/force/forceLink.jsx
================================================
import { useForce } from './layoutForce'
export const ForceLink = (props) => {
const { strength = 1, distance = 50 } = props
useForce((graph, { alpha, dim }) => {
graph.forEach((source) => {
const sourceLinks = source.linksTo.length + source.linksFrom.length
source.linksTo.forEach((link) => {
const target = link.node
const targetLinks = target.linksTo.length + target.linksFrom.length
var x = target.x + target.vx - source.x - source.vx
var y = target.y + target.vy - source.y - source.vy
var z = (target.z + target.vz - source.z - source.vz) * (dim === 3)
var l = Math.sqrt(x * x + y * y + z * z)
if (l < 1e-6) l = 1e-6 // To avoid division by 0
l = ((l - distance) / l) * alpha * strength
x *= l, y *= l, z *= l
const b = sourceLinks / (sourceLinks + targetLinks)
target.vx -= x * b
target.vy -= y * b
dim === 3 && (target.vz -= z * b)
source.vx += x * (1 - b)
source.vy += y * (1 - b)
dim === 3 && (source.vz += z * (1 - b))
})
})
})
return null
}
================================================
FILE: src/layouts/force/forceManyBody.jsx
================================================
import { useCallback, useRef } from 'react'
import { useForce } from './layoutForce'
import { useGraph } from '../..'
import { is } from '../../utils'
import { useLayoutEffect } from 'react'
export const ForceManyBody = (props) => {
const {
strength = 1.0,
neighbors = 15,
updateValue = 0.75,
sampleValue = 0.25,
distanceMin = 1,
distanceMax = Infinity,
rand = () => Math.random()
} = props
const graph = useGraph()
const updates = Math.ceil(Math.pow(neighbors, updateValue))
const samples = Math.ceil(Math.pow(neighbors, sampleValue))
const dist2 = (s, t) => (s.x - t.x) ** 2 + (s.y - t.y) ** 2 + (s.z - t.z) ** 2
const distanceMax2 = distanceMax ** 2
const distanceMin2 = distanceMin ** 2
const multiplierRef = useRef(1)
const addRandomNeighbor = (node) => {
const n = graph.adjacency.length
if (n === 0) return
// Pick random node
const neighbor = graph.adjacency[Math.floor(rand() * n)]
// If neighbor already in the list
if (node.neighbors.indexOf(neighbor) >= 0) return
// If there's still place for neighbors
if (node.neighbors.length < neighbors) {
node.neighbors.push(neighbor)
} else {
// Find farthest neighbor
var farthestId = 0, farthestDist2 = -1
node.neighbors.forEach((curr, id) => {
const nodeCurrDist2 = dist2(curr, node)
if (nodeCurrDist2 > farthestDist2) {
farthestId = id
farthestDist2 = nodeCurrDist2
}
})
// Replace neighbor if closer
if (dist2(node, neighbor) < farthestDist2) {
node.neighbors[farthestId] = neighbor
}
}
}
const repulseRandom = (node, params) => {
const n = graph.adjacency.length
for (var i = 0; i < samples; i++) {
repulse(node, graph.adjacency[Math.floor(rand() * n)], params)
}
}
const repulseNeighbors = (node, params) => {
//addRandomNeighbor(node)
node.neighbors.forEach((neighbor) => {
repulse(node, neighbor, params)
})
}
const repulse = useCallback((node, other, params) => {
const { dim, alpha } = params
if (is.equ(node, other)) return
var x = node.x - other.x
var y = node.y - other.y
var z = node.z - other.z
var dist2 = x*x + y*y + z*z * (dim===3)
if (dist2 >= distanceMax2) return
if (x === 0) x = (rand() - 0.5) * 1e-6, dist2 += x * x;
if (y === 0) y = (rand() - 0.5) * 1e-6, dist2 += y * y;
if (z === 0) z = (rand() - 0.5) * 1e-6, dist2 += z * z;
if (dist2 < distanceMin2) dist2 = Math.sqrt(distanceMin2 * dist2);
const w = strength * alpha * multiplierRef.current / dist2;
node.vx += x * w;
node.vy += y * w;
node.vz += z * w * (dim === 3)
}, [multiplierRef, strength])
useLayoutEffect(() => {
const initNode = (node) => {
const n = graph.adjacency.length
node.neighbors = []
for (var i = 0; i < neighbors; i++) addRandomNeighbor(node)
multiplierRef.current = n < 100 ? 1 : n < 200 ? 3 : Math.sqrt(n);
}
graph.adjacency.forEach((node) => initNode(node))
return graph.subscribeChanges({ onBeforeAddNode: (node) => initNode(node) })
}, [])
const prevRef = useRef(0)
useForce((nodes, params) => {
const n = nodes.length
const prev = prevRef.current
const upper = prev + updates
var i = 0, j = prev
while (i < n || j < upper) {
if (j < upper) repulseRandom(nodes[j % n], params);
if (i < n) repulseNeighbors(nodes[i], params);
i++, j++
}
prevRef.current = upper % n;
})
return null
}
================================================
FILE: src/layouts/force/layoutForce.jsx
================================================
import React, {
useState,
useLayoutEffect,
useRef,
createContext,
useContext,
useCallback
} from 'react'
import { raf } from '@react-spring/rafz'
import { useGraph } from '../../graph'
import { is, jiggle } from '../../utils'
import { useUpdatedRef, useObserver } from '../../hooks'
const LayoutForceContext = createContext(null)
class LayoutForceState {
constructor() {
this.graph = null
this.subscribedForces = {}
this.params = {
onReady: null,
dim: null,
autoStart: true,
alpha: 1,
alphaMin: 0.001,
alphaDecay: 0.0227,
alphaTarget: 0,
velocityDecay: 0.6
}
this.initialized = false
}
start(alpha = 1.0) {
this.params.alpha = alpha
raf(() => this.tick())
}
stop() { this.params.alpha = 0 }
initNodeParams(node) {
node.vx = 0
node.vy = 0
node.vz = 0
}
updateParams(params) {
// Initialize params
Object.assign(this.params, params)
// First update
if (!this.initialized) {
this.initialized = true
this.params.autoStart && this.start()
this.params.onReady && this.params.onReady(this)
}
}
subscribeGraph(graph) {
this.graph = graph
this.graph.adjacency.forEach((node) => this.initNodeParams(node))
this.params.dim = graph.params.dim
return graph.subscribeChanges({
onBeforeAddNode: (node) => this.initNodeParams(node),
onParamsChange: ({ dim }) => this.params.dim = dim
})
}
tick(iterations = 1) {
var { alpha, alphaMin, alphaTarget, alphaDecay, velocityDecay } = this.params
if (alpha < alphaMin) return false
// We can manually tick more than one iteration if needed.
for (var i = 0; i < iterations; i++) {
// Update alpha
this.params.alpha += (alphaTarget - alpha) * alphaDecay
// Apply all forces on the graph
for (const uid of Object.keys(this.subscribedForces))
this.subscribedForces[uid].current(this.graph.adjacency, this.params)
// Update graph velocities & positions
this.graph.adjacency.forEach((node, id) => {
node.x += (node.vx *= velocityDecay)
node.y += (node.vy *= velocityDecay)
node.z += (node.vz *= velocityDecay)
// We don't update in-links since all nodes are iterated once.
this.graph.updateNode(node, null, false)
})
}
return true
}
subscribeForce(uid, callback) {
this.subscribedForces[uid] = callback
return () => delete this.subscribedForces[uid]
}
}
export const LayoutForce = (props) => {
const { children, ...rest } = props
const graph = useGraph()
const [layout] = useState(() => new LayoutForceState())
// Subscribe layout
useLayoutEffect(() => layout.subscribeGraph(graph), [layout, graph])
// Update params
useObserver((change) => layout.updateParams(change), rest)
return (
<LayoutForceContext.Provider value={layout}>
{children}
</LayoutForceContext.Provider>
)
}
export const useLayoutForce = () => {
const layout = useContext(LayoutForceContext)
if (!layout) throw 'Hooks must used inside LayoutForce'
return layout
}
let ids = 0
export const useForce = (callback) => {
const [id] = useState(() => ids++)
const layout = useLayoutForce()
const callbackRef = useUpdatedRef(callback)
useLayoutEffect(() => layout.subscribeForce(id, callbackRef), [layout, id, callbackRef])
}
================================================
FILE: src/layouts/index.jsx
================================================
export * from './force/layoutForce'
export * from './force/forceCenter'
export * from './force/forceDirection'
export * from './force/forceManyBody'
export * from './force/forceLink'
export * from './force/forceCollide'
//export * from './force/experimental/forceFMM'
export * from './layer/layoutLayer'
================================================
FILE: src/layouts/layer/layoutLayer.jsx
================================================
import React, {
useState,
useLayoutEffect,
createContext,
useContext
} from 'react'
import { useGraph } from '../../graph'
import { useObserver } from '../../hooks'
import { is, arr } from '../../utils'
const LayoutLayerContext = createContext(null)
class LayoutLayerState {
constructor() {
this.graph = null
this.params = {
dim: 2,
gaps: [10,10,10],
anchor: [0,0,0],
orientation: 'horizontal',
direction: 'ltr'
}
}
updateParams(params) {
Object.assign(this.params, params)
this.updateLayout()
}
updateLayout() {
const graph = this.graph.adjacency
const startNodes = graph.filter(node => node.linksFrom.length == 0)
let numLayers = 0
// Reset
graph.forEach(node => node.layer = undefined)
// Compute layers (assuming graph is DAG)
function DFS(node, layer) {
numLayers = Math.max(layer+1, numLayers)
node.layer = is.und(node.layer) ? layer : Math.max(node.layer, layer)
node.linksTo.forEach((link) => DFS(link.node, layer+1))
}
startNodes.forEach(node => DFS(node, 0));
// Store nodes by layer
let layers = arr.init2D(numLayers, 0)
graph.forEach(node => layers[node.layer].push(node))
// Evalute node positions
const heights = layers.map((layer) => layer.length)
const maxHeight = Math.max(...heights);
layers.forEach((layer, i) => {
const height = layer.length
layer.forEach((node, j) => {
node.x = i*this.params.gaps[0] + this.params.anchor[0]
node.y = j*this.params.gaps[1] + this.params.anchor[1]
this.graph.updateNode(node)
})
})
}
subscribeGraph(graph) {
this.graph = graph
this.updateLayout()
return graph.subscribeChanges({
onAddNode: () => { this.updateLayout() },
onRemoveNode: () => { this.updateLayout() },
onAddLink: () => { this.updateLayout() },
onRemoveLink: () => { this.updateLayout() }
})
}
}
export const LayoutLayer = (props) => {
const { children, ...rest } = props
const [layout] = useState(() => new LayoutLayerState())
const graph = useGraph()
// Subscribe layout
useLayoutEffect(() => layout.subscribeGraph(graph), [layout, graph])
// Update params
useObserver((change) => layout.updateParams(change), rest)
return (
<LayoutLayerContext.Provider value={layout}>
{children}
</LayoutLayerContext.Provider>
)
}
================================================
FILE: src/utils.js
================================================
export const is = {
obj: (a) => a === Object(a) && !is.arr(a) && typeof a !== 'function',
fun: (a) => typeof a === 'function',
str: (a) => typeof a === 'string',
num: (a) => typeof a === 'number',
und: (a) => a === void 0,
arr: (a) => Array.isArray(a),
equ(a, b) {
// Wrong type or one of the two undefined, doesn't match
if (typeof a !== typeof b || !!a !== !!b) return false
// Atomic, just compare a against b
if (is.str(a) || is.num(a) || is.obj(a)) return a === b
// Array, shallow compare first to see if it's a match
if (is.arr(a) && a == b) return true
// Last resort, go through keys
let i
for (i in a) if (!(i in b)) return false
for (i in b) if (a[i] !== b[i]) return false
return is.und(i) ? a === b : true
},
dequ(a, b, checkLength = false) {
// Deep object comparison
if (is.equ(a, b)) return true
else if (is.obj(a) && is.obj(b)) {
if (checkLength && Object.keys(a).length != Object.keys(b).length)
return false
for (var prop in a) {
if (b.hasOwnProperty(prop)) {
if (!is.dequ(a[prop], b[prop])) return false
} else return false
}
return true
} else return false
}
}
export const deepWrite = (source, target) => {
// writes
}
export const obj = {
// Adds defaults b to a if a is missing them, returns same reference as a.
default: (a, b) => Object.assign(a, Object.assign(b, a))
}
export const arr = {
remove: (arr, obj) => {
var index = arr.indexOf(obj);
if (index !== -1) arr.splice(index, 1)
},
removeByIndex: (arr, id) => {
arr.splice(id, 1)
},
init2D: (r, c, value = 0) => {
return Array(r).fill().map(() => Array(c).fill(value))
}
}
export const jiggle = () => Math.random()*1e-6
================================================
FILE: tsconfig.json
================================================
{
"compilerOptions": {
"module": "esnext",
"target": "es2018",
"allowSyntheticDefaultImports": true,
"jsx": "react",
"strict": true,
"preserveSymlinks": true,
"moduleResolution": "Node",
"esModuleInterop": true,
"declaration": true,
"declarationDir": "dist",
"skipLibCheck": true,
"removeComments": false,
"baseUrl": ".",
"allowJs": true
},
"include": ["src"]
}
gitextract_o4sk2iiy/ ├── .eslintrc.json ├── .gitignore ├── .npmignore ├── .prettierrc ├── .storybook/ │ ├── index.css │ ├── main.js │ ├── preview.js │ ├── public/ │ │ ├── tree.json │ │ └── treeLarge.json │ ├── stories/ │ │ ├── LayoutForceGraph.stories.tsx │ │ ├── LayoutForceParticles.stories.tsx │ │ ├── NoLayoutDragDropR3F.stories.tsx │ │ ├── NoLayoutDragDropSVG.stories.jsx │ │ └── useDrag.tsx │ └── tsconfig.json ├── LICENSE ├── README.md ├── package.json ├── rollup.config.js ├── src/ │ ├── graph.tsx │ ├── hooks.js │ ├── index.ts │ ├── layouts/ │ │ ├── force/ │ │ │ ├── forceCenter.jsx │ │ │ ├── forceCollide.jsx │ │ │ ├── forceDirection.jsx │ │ │ ├── forceLink.jsx │ │ │ ├── forceManyBody.jsx │ │ │ └── layoutForce.jsx │ │ ├── index.jsx │ │ └── layer/ │ │ └── layoutLayer.jsx │ └── utils.js └── tsconfig.json
SYMBOL INDEX (56 symbols across 9 files)
FILE: .storybook/stories/LayoutForceGraph.stories.tsx
function App (line 21) | function App() {
FILE: .storybook/stories/LayoutForceParticles.stories.tsx
function App (line 20) | function App() {
FILE: .storybook/stories/NoLayoutDragDropR3F.stories.tsx
function App (line 13) | function App() {
FILE: .storybook/stories/NoLayoutDragDropSVG.stories.jsx
function App (line 16) | function App() {
FILE: .storybook/stories/useDrag.tsx
function useDragSnap (line 6) | function useDragSnap(callback, plane, snap = {x: 0, y: 0}) {
FILE: src/graph.tsx
type UID (line 14) | type UID = number | string
type Position (line 15) | type Position = [number, number, number]
type CallbackNode (line 16) | type CallbackNode = (position: Position, node?: Node) => void
type RefCallbackNode (line 17) | type RefCallbackNode = RefObject<CallbackNode>
type ParamsNode (line 18) | interface ParamsNode {
type Node (line 27) | interface Node extends ParamsNode {
type CallbackLink (line 35) | type CallbackLink = (sourcePosition: Position, targetPosition: Position,...
type RefCallbackLink (line 36) | type RefCallbackLink = RefObject<CallbackLink>
type Link (line 37) | interface Link {
type LinkPair (line 41) | interface LinkPair {
type Subscriber (line 45) | interface Subscriber {
type Unsusbscribe (line 53) | type Unsusbscribe = () => void
type ParamsGraph (line 54) | interface ParamsGraph {
type GraphState (line 57) | interface GraphState {
method constructor (line 70) | constructor() {
method frame (line 77) | frame() {
method updateParams (line 82) | updateParams(params: ParamsGraph) {
method getNodeById (line 87) | getNodeById(id: UID, useUid: boolean = true) {
method addNode (line 91) | addNode(callback: RefCallbackNode): Node {
method removeNode (line 110) | removeNode(node: Node) {
method updateNode (line 127) | updateNode(node: Node, params: ParamsNode = {}, updateInLinks: boolean...
method notifyNode (line 149) | notifyNode(node: Node) {
method isLinkValid (line 153) | isLinkValid(source: Node, target: Node) {
method addLinkById (line 157) | addLinkById(callback: RefCallbackLink, sid: UID, tid: UID, useUid = fa...
method addLink (line 164) | addLink(callback: RefCallbackLink, source: Node, target: Node): LinkPa...
method removeLinkById (line 178) | removeLinkById(sid: UID, tid: UID, linkTo: Link, linkFrom: Link, useUi...
method removeLink (line 185) | removeLink(source: Node, target: Node, linkTo: Link, linkFrom: Link) {
method updateLink (line 192) | updateLink(to: Link, from: Link, params: ParamsLink) {
method notifyLink (line 196) | notifyLink(link: Link, source: Node, target: Node) {
method subscribeChanges (line 206) | subscribeChanges(callbacks: Subscriber) : Unsusbscribe {
method log (line 211) | log() {
method logNode (line 216) | logNode(node: Node) {
type ParamsLink (line 63) | type ParamsLink = { [key: string]: (string | number | ((fn: any) => any)...
class GraphState (line 68) | class GraphState {
method constructor (line 70) | constructor() {
method frame (line 77) | frame() {
method updateParams (line 82) | updateParams(params: ParamsGraph) {
method getNodeById (line 87) | getNodeById(id: UID, useUid: boolean = true) {
method addNode (line 91) | addNode(callback: RefCallbackNode): Node {
method removeNode (line 110) | removeNode(node: Node) {
method updateNode (line 127) | updateNode(node: Node, params: ParamsNode = {}, updateInLinks: boolean...
method notifyNode (line 149) | notifyNode(node: Node) {
method isLinkValid (line 153) | isLinkValid(source: Node, target: Node) {
method addLinkById (line 157) | addLinkById(callback: RefCallbackLink, sid: UID, tid: UID, useUid = fa...
method addLink (line 164) | addLink(callback: RefCallbackLink, source: Node, target: Node): LinkPa...
method removeLinkById (line 178) | removeLinkById(sid: UID, tid: UID, linkTo: Link, linkFrom: Link, useUi...
method removeLink (line 185) | removeLink(source: Node, target: Node, linkTo: Link, linkFrom: Link) {
method updateLink (line 192) | updateLink(to: Link, from: Link, params: ParamsLink) {
method notifyLink (line 196) | notifyLink(link: Link, source: Node, target: Node) {
method subscribeChanges (line 206) | subscribeChanges(callbacks: Subscriber) : Unsusbscribe {
method log (line 211) | log() {
method logNode (line 216) | logNode(node: Node) {
type PropsGraph (line 296) | interface PropsGraph extends ParamsGraph {
FILE: src/layouts/force/layoutForce.jsx
class LayoutForceState (line 16) | class LayoutForceState {
method constructor (line 17) | constructor() {
method start (line 33) | start(alpha = 1.0) {
method stop (line 38) | stop() { this.params.alpha = 0 }
method initNodeParams (line 40) | initNodeParams(node) {
method updateParams (line 46) | updateParams(params) {
method subscribeGraph (line 57) | subscribeGraph(graph) {
method tick (line 67) | tick(iterations = 1) {
method subscribeForce (line 89) | subscribeForce(uid, callback) {
FILE: src/layouts/layer/layoutLayer.jsx
class LayoutLayerState (line 13) | class LayoutLayerState {
method constructor (line 15) | constructor() {
method updateParams (line 26) | updateParams(params) {
method updateLayout (line 31) | updateLayout() {
method subscribeGraph (line 64) | subscribeGraph(graph) {
FILE: src/utils.js
method equ (line 8) | equ(a, b) {
method dequ (line 21) | dequ(a, b, checkLength = false) {
Condensed preview — 32 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (167K chars).
[
{
"path": ".eslintrc.json",
"chars": 2384,
"preview": "{\n \"env\": {\n \"browser\": true,\n \"es6\": true,\n \"node\": true\n },\n \"extends\": [\n \"prettier\",\n \"prettier/re"
},
{
"path": ".gitignore",
"chars": 630,
"preview": "# misc\n.DS_Store\n.env.local\n.env.development.local\n.env.test.local\n.env.production.local\n\n# Logs\nlogs\n*.log\nnpm-debug.lo"
},
{
"path": ".npmignore",
"chars": 28,
"preview": ".storybook\nstorybook-static\n"
},
{
"path": ".prettierrc",
"chars": 107,
"preview": "{\n \"semi\": false,\n \"trailingComma\": \"es5\",\n \"singleQuote\": true,\n \"tabWidth\": 2,\n \"printWidth\": 120\n}\n"
},
{
"path": ".storybook/index.css",
"chars": 158,
"preview": "html,\nbody,\n#root {\n width: 100%;\n height: 100%;\n margin: 0;\n padding: 0;\n overflow: hidden;\n background-color: #2"
},
{
"path": ".storybook/main.js",
"chars": 521,
"preview": "const path = require('path')\n\nmodule.exports = {\n stories: ['./stories/**/*.stories.{js,jsx,ts,tsx}'],\n addons: [\n "
},
{
"path": ".storybook/preview.js",
"chars": 76,
"preview": "import './index.css'\n\nexport const parameters = {\n layout: 'fullscreen',\n}\n"
},
{
"path": ".storybook/public/tree.json",
"chars": 28393,
"preview": "{\n \"nodes\": [\n { \"id\": 0 },\n { \"id\": 1 },\n { \"id\": 2 },\n { \"id\": 3 },\n { \"id\": 4 },\n { \"id\": 5 },\n "
},
{
"path": ".storybook/public/treeLarge.json",
"chars": 70698,
"preview": "{\"nodes\":[{\"id\":0},{\"id\":1},{\"id\":2},{\"id\":3},{\"id\":4},{\"id\":5},{\"id\":6},{\"id\":7},{\"id\":8},{\"id\":9},{\"id\":10},{\"id\":11},"
},
{
"path": ".storybook/stories/LayoutForceGraph.stories.tsx",
"chars": 2885,
"preview": "import * as React from 'react'\nimport { useState } from \"react\";\nimport { Canvas, useFrame } from \"@react-three/fiber\";\n"
},
{
"path": ".storybook/stories/LayoutForceParticles.stories.tsx",
"chars": 2024,
"preview": "import * as React from 'react'\nimport { useState } from \"react\";\nimport { Canvas, useFrame } from \"@react-three/fiber\";\n"
},
{
"path": ".storybook/stories/NoLayoutDragDropR3F.stories.tsx",
"chars": 2496,
"preview": "import * as React from 'react'\nimport { Canvas } from \"@react-three/fiber\";\nimport { Segment, Segments, OrbitControls } "
},
{
"path": ".storybook/stories/NoLayoutDragDropSVG.stories.jsx",
"chars": 2187,
"preview": "import * as React from 'react'\nimport { useState, useRef } from 'react'\nimport { useDrag } from '@use-gesture/react'\n// "
},
{
"path": ".storybook/stories/useDrag.tsx",
"chars": 748,
"preview": "import { useState } from \"react\";\nimport { useDrag } from \"@use-gesture/react\";\nimport { useThree } from \"@react-three/f"
},
{
"path": ".storybook/tsconfig.json",
"chars": 83,
"preview": "{\n \"extends\": \"../tsconfig\",\n \"exclude\": [],\n \"include\": [\"./stories/*\"]\n}"
},
{
"path": "LICENSE",
"chars": 1069,
"preview": "MIT License\n\nCopyright (c) 2020 react-spring\n\nPermission is hereby granted, free of charge, to any person obtaining a co"
},
{
"path": "README.md",
"chars": 4460,
"preview": "\n<img src=\"markdown/logo.png\">\n \n[]("
},
{
"path": "package.json",
"chars": 3084,
"preview": "{\n \"name\": \"graphire\",\n \"version\": \"0.0.0-beta.11\",\n \"description\": \"A unopinionated react graph library.\",\n \"keywor"
},
{
"path": "rollup.config.js",
"chars": 1502,
"preview": "import path from 'path'\nimport babel from '@rollup/plugin-babel'\nimport resolve from '@rollup/plugin-node-resolve'\n\ncons"
},
{
"path": "src/graph.tsx",
"chars": 8990,
"preview": "import * as React from 'react'\nimport {\n useState,\n useLayoutEffect,\n useRef,\n useContext,\n createContext,\n RefObj"
},
{
"path": "src/hooks.js",
"chars": 526,
"preview": "import { useRef, useLayoutEffect } from 'react'\nimport { is } from './utils'\n\nexport const useUpdatedRef = (params) => {"
},
{
"path": "src/index.ts",
"chars": 50,
"preview": "export * from './graph'\nexport * from './layouts'\n"
},
{
"path": "src/layouts/force/forceCenter.jsx",
"chars": 551,
"preview": "import { useForce } from './layoutForce'\n\nexport const ForceCenter = (props) => {\n const { strength = 1, x = 0, y = 0, "
},
{
"path": "src/layouts/force/forceCollide.jsx",
"chars": 1432,
"preview": "import { useForce } from './layoutForce'\nimport { is } from '../../utils'\n\nexport const ForceCollide = (props) => {\n co"
},
{
"path": "src/layouts/force/forceDirection.jsx",
"chars": 452,
"preview": "import { useForce } from './layoutForce'\nimport { is } from '../../utils'\n\nexport const ForceDirection = (props) => {\n "
},
{
"path": "src/layouts/force/forceLink.jsx",
"chars": 1121,
"preview": "import { useForce } from './layoutForce'\n\nexport const ForceLink = (props) => {\n const { strength = 1, distance = 50 } "
},
{
"path": "src/layouts/force/forceManyBody.jsx",
"chars": 3580,
"preview": "import { useCallback, useRef } from 'react'\nimport { useForce } from './layoutForce'\nimport { useGraph } from '../..'\nim"
},
{
"path": "src/layouts/force/layoutForce.jsx",
"chars": 3404,
"preview": "import React, {\n useState,\n useLayoutEffect,\n useRef,\n createContext,\n useContext,\n useCallback\n} from 'react'\nimp"
},
{
"path": "src/layouts/index.jsx",
"chars": 305,
"preview": "export * from './force/layoutForce'\nexport * from './force/forceCenter'\nexport * from './force/forceDirection'\nexport * "
},
{
"path": "src/layouts/layer/layoutLayer.jsx",
"chars": 2433,
"preview": "import React, {\n useState,\n useLayoutEffect,\n createContext,\n useContext\n} from 'react'\nimport { useGraph } from '.."
},
{
"path": "src/utils.js",
"chars": 1776,
"preview": "export const is = {\n obj: (a) => a === Object(a) && !is.arr(a) && typeof a !== 'function',\n fun: (a) => typeof a === '"
},
{
"path": "tsconfig.json",
"chars": 424,
"preview": "{\n \"compilerOptions\": {\n \"module\": \"esnext\",\n \"target\": \"es2018\",\n \"allowSyntheticDefaultImports\": true,\n \""
}
]
About this extraction
This page contains the full source code of the flavioschneider/graphire GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 32 files (145.1 KB), approximately 49.7k tokens, and a symbol index with 56 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.