{"id":465821,"date":"2025-07-03T09:25:19","date_gmt":"2025-07-03T09:25:19","guid":{"rendered":"http:\/\/savepearlharbor.com\/?p=465821"},"modified":"-0001-11-30T00:00:00","modified_gmt":"-0001-11-29T21:00:00","slug":"","status":"publish","type":"post","link":"https:\/\/savepearlharbor.com\/?p=465821","title":{"rendered":"<span>Code Tutorials \u2014 React: \u0440\u0438\u0441\u0443\u0435\u043c \u0434\u0432\u0443\u043c\u0435\u0440\u043d\u044b\u0439 \u0433\u0440\u0430\u0444<\/span>"},"content":{"rendered":"<div><!--[--><!--]--><\/div>\n<div id=\"post-content-body\">\n<div>\n<div class=\"article-formatted-body article-formatted-body article-formatted-body_version-1\">\n<div xmlns=\"http:\/\/www.w3.org\/1999\/xhtml\"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/webt\/ma\/po\/lv\/mapolvqq4uunxfqoaviv3g9km9y.jpeg\" sizes=\"(max-width: 780px) 100vw, 50vw\" srcset=\"https:\/\/habrastorage.org\/r\/w780\/webt\/ma\/po\/lv\/mapolvqq4uunxfqoaviv3g9km9y.jpeg 780w,&#10;       https:\/\/habrastorage.org\/r\/w1560\/webt\/ma\/po\/lv\/mapolvqq4uunxfqoaviv3g9km9y.jpeg 781w\" loading=\"lazy\" decode=\"async\"\/> <\/p>\n<p> <\/p>\n<p> <\/p>\n<p>\u041f\u0440\u0438\u0432\u0435\u0442, \u0434\u0440\u0443\u0437\u044c\u044f!<\/p>\n<p> <\/p>\n<p>\u0412 \u044d\u0442\u043e\u0439 \u0441\u0435\u0440\u0438\u0438 \u0441\u0442\u0430\u0442\u0435\u0439 \u044f \u0434\u0435\u043b\u044e\u0441\u044c \u0441 \u0432\u0430\u043c\u0438 \u0441\u0432\u043e\u0438\u043c \u043e\u043f\u044b\u0442\u043e\u043c \u0440\u0435\u0448\u0435\u043d\u0438\u044f \u0440\u0430\u0437\u043b\u0438\u0447\u043d\u044b\u0445 \u0437\u0430\u0434\u0430\u0447 \u0438\u0437 \u043e\u0431\u043b\u0430\u0441\u0442\u0438 \u0432\u0435\u0431-\u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u0438 \u043d\u0435 \u0442\u043e\u043b\u044c\u043a\u043e.<\/p>\n<p> <\/p>\n<p>\u0412 \u044d\u0442\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0435 \u043c\u044b \u0438\u0437\u0443\u0447\u0438\u043c \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0443 <a href=\"https:\/\/github.com\/vasturiano\/react-force-graph\">react-force-graph-2d<\/a> \u0434\u043b\u044f \u0440\u0438\u0441\u043e\u0432\u0430\u043d\u0438\u044f \u0434\u0432\u0443\u043c\u0435\u0440\u043d\u044b\u0445 \u0433\u0440\u0430\u0444\u043e\u0432.<\/p>\n<p> <\/p>\n<p>\u0414\u0435\u043c\u043e \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f:<\/p>\n<p> <\/p>\n<div class=\"oembed\"><a href=\"https:\/\/react-graph.netlify.app\/\">https:\/\/react-graph.netlify.app\/<\/a><\/div>\n<p> <\/p>\n<p>\u041b\u043e\u043a\u0430\u043b\u044c\u043d\u044b\u0439 \u0437\u0430\u043f\u0443\u0441\u043a \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f:<\/p>\n<p> <\/p>\n<pre><code class=\"bash\">git clone https:\/\/github.com\/harryheman\/react-graph.git cd react-graph npm i npm run dev<\/code><\/pre>\n<p> <\/p>\n<p>\u0418\u043d\u0442\u0435\u0440\u0435\u0441\u043d\u043e? \u0422\u043e\u0433\u0434\u0430 \u043f\u0440\u043e\u0448\u0443 \u043f\u043e\u0434 \u043a\u0430\u0442.<\/p>\n<p><a name=\"habracut\"><\/a> <\/p>\n<h2 id=\"-sozdanie-proekta-i-ustanovka-zavisimostey\">\u276f \u0421\u043e\u0437\u0434\u0430\u043d\u0438\u0435 \u043f\u0440\u043e\u0435\u043a\u0442\u0430 \u0438 \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0430 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0435\u0439<\/h2>\n<p> <\/p>\n<p>\u0421\u043e\u0437\u0434\u0430\u0435\u043c \u0447\u0438\u0441\u0442\u044b\u0439 React+Typescript \u043f\u0440\u043e\u0435\u043a\u0442 \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e <a href=\"https:\/\/vite.dev\/\">Vite<\/a>:<\/p>\n<p> <\/p>\n<pre><code class=\"bash\">npm create vite react-graph --template react-ts<\/code><\/pre>\n<p> <\/p>\n<p>\u041f\u0435\u0440\u0435\u0445\u043e\u0434\u0438\u043c \u0432 \u0441\u043e\u0437\u0434\u0430\u043d\u043d\u0443\u044e \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u044e \u0438 \u0443\u0441\u0442\u0430\u043d\u0430\u0432\u043b\u0438\u0432\u0430\u0435\u043c \u0438\u043d\u0442\u0435\u0440\u0435\u0441\u0443\u044e\u0449\u0443\u044e \u043d\u0430\u0441 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0443:<\/p>\n<p> <\/p>\n<pre><code class=\"bash\">cd react-graph # \u0412\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u0435 \u044d\u0442\u043e\u0439 \u043a\u043e\u043c\u0430\u043d\u0434\u044b \u0442\u0430\u043a\u0436\u0435 \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442 \u043e\u0441\u043d\u043e\u0432\u043d\u044b\u0435 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438 \u043f\u0440\u043e\u0435\u043a\u0442\u0430 npm i react-force-graph-2d<\/code><\/pre>\n<p> <\/p>\n<p>\u0414\u0430\u043b\u0435\u0435 \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u043c \u0432 \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u0438 <code>src<\/code>.<\/p>\n<p> <\/p>\n<p>\u0423\u0434\u0430\u043b\u044f\u0435\u043c \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u044e <code>assets<\/code> \u0438 \u0444\u0430\u0439\u043b <code>App.css<\/code> \u0438 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u0435\u043c \u043c\u0438\u043d\u0438\u043c\u0430\u043b\u044c\u043d\u044b\u0435 \u0441\u0442\u0438\u043b\u0438 \u0432 <code>index.css<\/code>:<\/p>\n<p> <\/p>\n<pre><code class=\"css\">html, body, #root {   min-height: 100%; }  body {   margin: 0; }  #root {   display: flex;   justify-content: center;   align-items: center; }  h3 {   margin: 0; }  hr {   width: 100%; }<\/code><\/pre>\n<p> <\/p>\n<p>\u0421\u043e\u0437\u0434\u0430\u0435\u043c \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u044e <code>components<\/code>.<\/p>\n<p> <\/p>\n<p>\u041e\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u0435\u043c \u043d\u0435\u0431\u043e\u043b\u044c\u0448\u043e\u0439 \u0432\u0441\u043f\u043e\u043c\u043e\u0433\u0430\u0442\u0435\u043b\u044c\u043d\u044b\u0439 \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440 \u0432 <code>components\/Flex.tsx<\/code>:<\/p>\n<p> <\/p>\n<pre><code class=\"javascript\">import { forwardRef, type CSSProperties, type PropsWithChildren } from 'react'  export const Flex = forwardRef&lt;   HTMLDivElement,   PropsWithChildren&lt;CSSProperties&gt; &gt;(({ children, ...styles }, ref) =&gt; {   return (     &lt;div       ref={ref}       style={{         display: 'flex',         ...styles,       }}     &gt;       {children}     &lt;\/div&gt;   ) })<\/code><\/pre>\n<p> <\/p>\n<p>\u0421\u043e\u0437\u0434\u0430\u0435\u043c \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u044e <code>components\/Graph<\/code> \u0434\u043b\u044f \u0433\u0440\u0430\u0444\u043e\u0432.<\/p>\n<p> <\/p>\n<p>\u041d\u0430\u043c \u043f\u043e\u0442\u0440\u0435\u0431\u0443\u0435\u0442\u0441\u044f \u0444\u0443\u043d\u043a\u0446\u0438\u044f \u0434\u043b\u044f \u0433\u0435\u043d\u0435\u0440\u0430\u0446\u0438\u0438 \u0444\u0438\u043a\u0442\u0438\u0432\u043d\u044b\u0445 \u0434\u0430\u043d\u043d\u044b\u0445. \u041e\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u0435\u043c \u0435\u0435 \u0432 <code>Graph\/utils.ts<\/code>:<\/p>\n<p> <\/p>\n<pre><code class=\"javascript\">import type { LinkObject, NodeObject } from 'react-force-graph-2d'  export function generateGraphData(   n = 10,   reverse = false, ): {   nodes: (NodeObject &amp; {     neighbors?: NodeObject[]     links?: LinkObject[]   })[]   links: LinkObject[] } {   return {     \/\/ \u0423\u0437\u0435\u043b \u0434\u043e\u043b\u0436\u0435\u043d \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u0442\u044c \u0445\u043e\u0442\u044f \u0431\u044b `id`     nodes: [...Array(n).keys()].map((i) =&gt; ({       id: i,       name: `node ${i + 1}`,       neighbors: [],       links: [],     })),     \/\/ \u0420\u0435\u0431\u0440\u043e \u0434\u043e\u043b\u0436\u043d\u043e \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u0442\u044c \u0445\u043e\u0442\u044f \u0431\u044b `source` \u0438 `target`     links: [...Array(n).keys()]       .filter((id) =&gt; id)       .map((id) =&gt; ({         [reverse ? 'target' : 'source']: id,         [reverse ? 'source' : 'target']: Math.round(Math.random() * (id - 1)),         name: `link ${id}`,       })),   } }<\/code><\/pre>\n<p> <\/p>\n<h2 id=\"-api\">\u276f API<\/h2>\n<p> <\/p>\n<p>\u0420\u0430\u0441\u0441\u043c\u043e\u0442\u0440\u0438\u043c \u043e\u0441\u043d\u043e\u0432\u043d\u043e\u0439 API, \u043f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u043c\u044b\u0439 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u043e\u0439.<\/p>\n<p> <\/p>\n<h3 id=\"dannye\">\u0414\u0430\u043d\u043d\u044b\u0435<\/h3>\n<p> <\/p>\n<div class=\"scrollable-table\">\n<table>\n<thead>\n<tr>\n<th>\u0421\u0432\u043e\u0439\u0441\u0442\u0432\u043e<\/th>\n<th>\u041e\u043f\u0438\u0441\u0430\u043d\u0438\u0435<\/th>\n<th>\u0422\u0438\u043f<\/th>\n<th>\u041f\u043e \u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044e<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td><code>graphData<\/code><\/td>\n<td>\u0414\u0430\u043d\u043d\u044b\u0435<\/td>\n<td><code>{ nodes: NodeObject[], links: LinkObject[] }<\/code><\/td>\n<td><code>{ nodes: [], links: [] }<\/code><\/td>\n<\/tr>\n<tr>\n<td><code>nodeId<\/code><\/td>\n<td>\u0418\u0434\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0442\u043e\u0440 \u0432\u0435\u0440\u0448\u0438\u043d\u044b<\/td>\n<td><code>string<\/code><\/td>\n<td><code>id<\/code><\/td>\n<\/tr>\n<tr>\n<td><code>linkSource<\/code><\/td>\n<td>\u0418\u0434\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0442\u043e\u0440 \u0432\u0435\u0440\u0448\u0438\u043d\u044b-\u0438\u0441\u0442\u043e\u0447\u043d\u0438\u043a\u0430<\/td>\n<td><code>string<\/code><\/td>\n<td><code>source<\/code><\/td>\n<\/tr>\n<tr>\n<td><code>linkTarget<\/code><\/td>\n<td>\u0418\u0434\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0442\u043e\u0440 \u0432\u0435\u0440\u0448\u0438\u043d\u044b-\u0446\u0435\u043b\u0438<\/td>\n<td><code>string<\/code><\/td>\n<td><code>target<\/code><\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<\/div>\n<p> <\/p>\n<h3 id=\"konteyner\">\u041a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440<\/h3>\n<p> <\/p>\n<div class=\"scrollable-table\">\n<table>\n<thead>\n<tr>\n<th>\u0421\u0432\u043e\u0439\u0441\u0442\u0432\u043e<\/th>\n<th>\u041e\u043f\u0438\u0441\u0430\u043d\u0438\u0435<\/th>\n<th>\u0422\u0438\u043f<\/th>\n<th>\u041f\u043e \u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044e<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td><code>width<\/code><\/td>\n<td>\u0428\u0438\u0440\u0438\u043d\u0430 \u0445\u043e\u043b\u0441\u0442\u0430 \u0432 \u043f\u0438\u043a\u0441\u0435\u043b\u044f\u0445<\/td>\n<td><code>number<\/code><\/td>\n<td>\u0428\u0438\u0440\u0438\u043d\u0430 \u043e\u0431\u043b\u0430\u0441\u0442\u0438 \u043f\u0440\u043e\u0441\u043c\u043e\u0442\u0440\u0430<\/td>\n<\/tr>\n<tr>\n<td><code>height<\/code><\/td>\n<td>\u0412\u044b\u0441\u043e\u0442\u0430 \u0445\u043e\u043b\u0441\u0442\u0430 \u0432 \u043f\u0438\u043a\u0441\u0435\u043b\u044f\u0445<\/td>\n<td><code>number<\/code><\/td>\n<td>\u0412\u044b\u0441\u043e\u0442\u0430 \u043e\u0431\u043b\u0430\u0441\u0442\u0438 \u043f\u0440\u043e\u0441\u043c\u043e\u0442\u0440\u0430<\/td>\n<\/tr>\n<tr>\n<td><code>backgroundColor<\/code><\/td>\n<td>\u0426\u0432\u0435\u0442 \u0444\u043e\u043d\u0430<\/td>\n<td><code>string<\/code><\/td>\n<td><code>undefined<\/code><\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<\/div>\n<p> <\/p>\n<h3 id=\"vershina\">\u0412\u0435\u0440\u0448\u0438\u043d\u0430<\/h3>\n<p> <\/p>\n<div class=\"scrollable-table\">\n<table>\n<thead>\n<tr>\n<th>\u0421\u0432\u043e\u0439\u0441\u0442\u0432\u043e<\/th>\n<th>\u041e\u043f\u0438\u0441\u0430\u043d\u0438\u0435<\/th>\n<th>\u0422\u0438\u043f<\/th>\n<th>\u041f\u043e \u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044e<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td><code>nodeRelSize<\/code><\/td>\n<td>\u0421\u043e\u043e\u0442\u043d\u043e\u0448\u0435\u043d\u0438\u0435 \u043f\u043b\u043e\u0449\u0430\u0434\u0438 \u043e\u043a\u0440\u0443\u0436\u043d\u043e\u0441\u0442\u0438 \u0432\u0435\u0440\u0448\u0438\u043d\u044b \u043d\u0430 \u0435\u0434\u0438\u043d\u0438\u0446\u0443 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f<\/td>\n<td><code>number<\/code><\/td>\n<td><code>4<\/code><\/td>\n<\/tr>\n<tr>\n<td><code>nodeVal<\/code><\/td>\n<td>\u0420\u0430\u0437\u043c\u0435\u0440 \u0432\u0435\u0440\u0448\u0438\u043d\u044b<\/td>\n<td><code>number \\| string \\| function<\/code><\/td>\n<td><code>val<\/code><\/td>\n<\/tr>\n<tr>\n<td><code>nodeLabel<\/code><\/td>\n<td>\u041f\u043e\u0434\u043f\u0438\u0441\u044c \u0432\u0435\u0440\u0448\u0438\u043d\u044b<\/td>\n<td><code>string \\| function<\/code><\/td>\n<td><code>name<\/code><\/td>\n<\/tr>\n<tr>\n<td><code>nodeVisibility<\/code><\/td>\n<td>\u0412\u0438\u0434\u0438\u043c\u043e\u0441\u0442\u044c \u0432\u0435\u0440\u0448\u0438\u043d\u044b<\/td>\n<td><code>boolean \\| string \\| function<\/code><\/td>\n<td><code>true<\/code><\/td>\n<\/tr>\n<tr>\n<td><code>nodeColor<\/code><\/td>\n<td>\u0426\u0432\u0435\u0442 \u0432\u0435\u0440\u0448\u0438\u043d\u044b<\/td>\n<td><code>string \\| function<\/code><\/td>\n<td><code>color<\/code><\/td>\n<\/tr>\n<tr>\n<td><code>nodeAutoColorBy<\/code><\/td>\n<td>\u0413\u0440\u0443\u043f\u043f\u0438\u0440\u043e\u0432\u043a\u0430 \u0446\u0432\u0435\u0442\u043e\u0432<\/td>\n<td><code>string \\| function<\/code><\/td>\n<td><code>undefined<\/code><\/td>\n<\/tr>\n<tr>\n<td><code>nodeCanvasObject<\/code><\/td>\n<td>\u0424\u0443\u043d\u043a\u0446\u0438\u044f \u0440\u0438\u0441\u043e\u0432\u0430\u043d\u0438\u044f \u0432\u0435\u0440\u0448\u0438\u043d\u044b<\/td>\n<td><code>function<\/code><\/td>\n<td>\u041a\u0440\u0443\u0433 \u0440\u0430\u0437\u043c\u0435\u0440\u043e\u043c <code>val<\/code> \u0438 \u0446\u0432\u0435\u0442\u043e\u043c <code>color<\/code><\/td>\n<\/tr>\n<tr>\n<td><code>nodeCanvasObjectMode<\/code><\/td>\n<td>\u0421\u0442\u0440\u043e\u043a\u0430 \u0438\u043b\u0438 \u0444\u0443\u043d\u043a\u0446\u0438\u044f, \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u044e\u0449\u0430\u044f \u0440\u0435\u0436\u0438\u043c \u0440\u0438\u0441\u043e\u0432\u0430\u043d\u0438\u044f \u0432\u0435\u0440\u0448\u0438\u043d\u044b (\u0441\u043c. \u043d\u0438\u0436\u0435)<\/td>\n<td><code>string \\| function<\/code><\/td>\n<td><code>() =&gt; 'replace'<\/code><\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<\/div>\n<p> <\/p>\n<p> <\/p>\n<p> <\/p>\n<p><code>nodeCanvasObjectMode<\/code> \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f \u0432 \u0441\u043e\u0447\u0435\u0442\u0430\u043d\u0438\u0438 \u0441 <code>nodeCanvasObject<\/code> \u0434\u043b\u044f \u043a\u0430\u0441\u0442\u043e\u043c\u0438\u0437\u0430\u0446\u0438\u0438 \u0440\u0438\u0441\u043e\u0432\u0430\u043d\u0438\u044f \u0432\u0435\u0440\u0448\u0438\u043d. \u0412\u043e\u0437\u043c\u043e\u0436\u043d\u044b\u0435 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f:<\/p>\n<p> <\/p>\n<ul>\n<li><code>replace<\/code> \u2014 \u0432\u0435\u0440\u0448\u0438\u043d\u0430 \u0440\u0438\u0441\u0443\u0435\u0442\u0441\u044f \u0442\u043e\u043b\u044c\u043a\u043e \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e <code>nodeCanvasObject<\/code><\/li>\n<li><code>before<\/code> \u2014 \u0441\u043d\u0430\u0447\u0430\u043b\u0430 \u0432\u0435\u0440\u0448\u0438\u043d\u0430 \u0440\u0438\u0441\u0443\u0435\u0442\u0441\u044f \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e <code>nodeCanvasObject<\/code>, \u0437\u0430\u0442\u0435\u043c \u0440\u0438\u0441\u0443\u0435\u0442\u0441\u044f \u0434\u0435\u0444\u043e\u043b\u0442\u043d\u0430\u044f \u0432\u0435\u0440\u0448\u0438\u043d\u0430<\/li>\n<li><code>after<\/code> \u2014 \u0441\u043d\u0430\u0447\u0430\u043b\u0430 \u0440\u0438\u0441\u0443\u0435\u0442\u0441\u044f \u0432\u0435\u0440\u0448\u0438\u043d\u0430 \u043f\u043e \u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044e, \u0437\u0430\u0442\u0435\u043c \u0432\u044b\u0437\u044b\u0432\u0430\u0435\u0442\u0441\u044f <code>nodeCanvasObject<\/code><\/li>\n<\/ul>\n<p> <\/p>\n<h3 id=\"rebro\">\u0420\u0435\u0431\u0440\u043e<\/h3>\n<p> <\/p>\n<div class=\"scrollable-table\">\n<table>\n<thead>\n<tr>\n<th>\u0421\u0432\u043e\u0439\u0441\u0442\u0432\u043e<\/th>\n<th>\u041e\u043f\u0438\u0441\u0430\u043d\u0438\u0435<\/th>\n<th>\u0422\u0438\u043f<\/th>\n<th>\u041f\u043e \u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044e<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td><code>linkLabel<\/code><\/td>\n<td>\u041f\u043e\u0434\u043f\u0438\u0441\u044c \u0440\u0435\u0431\u0440\u0430<\/td>\n<td><code>string \\| function<\/code><\/td>\n<td><code>name<\/code><\/td>\n<\/tr>\n<tr>\n<td><code>linkVisibility<\/code><\/td>\n<td>\u0412\u0438\u0434\u0438\u043c\u043e\u0441\u0442\u044c \u0440\u0435\u0431\u0440\u0430<\/td>\n<td><code>boolean \\| string \\| function<\/code><\/td>\n<td><code>val<\/code><\/td>\n<\/tr>\n<tr>\n<td><code>linkColor<\/code><\/td>\n<td>\u0426\u0432\u0435\u0442 \u0440\u0435\u0431\u0440\u0430<\/td>\n<td><code>string \\| function<\/code><\/td>\n<td><code>color<\/code><\/td>\n<\/tr>\n<tr>\n<td><code>linkAutoColorBy<\/code><\/td>\n<td>\u0413\u0440\u0443\u043f\u043f\u0438\u0440\u043e\u0432\u043a\u0430 \u0446\u0432\u0435\u0442\u043e\u0432<\/td>\n<td><code>string \\| function<\/code><\/td>\n<td><code>undefined<\/code><\/td>\n<\/tr>\n<tr>\n<td><code>linkLineDash<\/code><\/td>\n<td>\u041c\u0430\u0441\u0441\u0438\u0432 \u0447\u0438\u0441\u0435\u043b, \u0441\u0442\u0440\u043e\u043a\u0430 \u0438\u043b\u0438 \u0444\u0443\u043d\u043a\u0446\u0438\u044f \u0440\u0438\u0441\u043e\u0432\u0430\u043d\u0438\u044f \u043f\u0440\u0435\u0440\u044b\u0432\u0438\u0441\u0442\u043e\u0439 \u043b\u0438\u043d\u0438\u0438<\/td>\n<td><code>number[] \\| string \\| function<\/code><\/td>\n<td><code>undefined<\/code><\/td>\n<\/tr>\n<tr>\n<td><code>linkWidth<\/code><\/td>\n<td>\u0428\u0438\u0440\u0438\u043d\u0430 \u043b\u0438\u043d\u0438\u0438<\/td>\n<td><code>number \\| string \\| function<\/code><\/td>\n<td><code>1<\/code><\/td>\n<\/tr>\n<tr>\n<td><code>linkCurvature<\/code><\/td>\n<td>\u0420\u0430\u0434\u0438\u0443\u0441 \u043a\u0440\u0438\u0432\u0438\u0437\u043d\u044b \u043b\u0438\u043d\u0438\u0438<\/td>\n<td><code>number \\| string \\| function<\/code><\/td>\n<td><code>0<\/code><\/td>\n<\/tr>\n<tr>\n<td><code>linkCanvasObject<\/code><\/td>\n<td>\u0424\u0443\u043d\u043a\u0446\u0438\u044f \u0440\u0438\u0441\u043e\u0432\u0430\u043d\u0438\u044f \u0440\u0435\u0431\u0440\u0430<\/td>\n<td><code>function<\/code><\/td>\n<td>\u041b\u0438\u043d\u0438\u044f \u0448\u0438\u0440\u0438\u043d\u043e\u0439 <code>width<\/code> \u0438 \u0446\u0432\u0435\u0442\u043e\u043c <code>color<\/code><\/td>\n<\/tr>\n<tr>\n<td><code>linkCanvasObjectMode<\/code><\/td>\n<td>\u0421\u0442\u0440\u043e\u043a\u0430 \u0438\u043b\u0438 \u0444\u0443\u043d\u043a\u0446\u0438\u044f, \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u044e\u0449\u0430\u044f \u0440\u0435\u0436\u0438\u043c \u0440\u0438\u0441\u043e\u0432\u0430\u043d\u0438\u044f \u0440\u0435\u0431\u0440\u0430 (\u0441\u043c. \u043d\u0438\u0436\u0435)<\/td>\n<td><code>string \\| function<\/code><\/td>\n<td><code>() =&gt; 'replace'<\/code><\/td>\n<\/tr>\n<tr>\n<td><code>linkDirectionalArrowLength<\/code><\/td>\n<td>\u0428\u0438\u0440\u0438\u043d\u0430 \u0441\u0442\u0440\u0435\u043b\u043a\u0438<\/td>\n<td><code>number \\| string \\| function<\/code><\/td>\n<td><code>0<\/code><\/td>\n<\/tr>\n<tr>\n<td><code>linkDirectionalArrowColor<\/code><\/td>\n<td>\u0426\u0432\u0435\u0442 \u0441\u0442\u0440\u0435\u043b\u043a\u0438<\/td>\n<td><code>string \\| function<\/code><\/td>\n<td><code>color<\/code><\/td>\n<\/tr>\n<tr>\n<td><code>linkDirectionalArrowRelPos<\/code><\/td>\n<td>\u041f\u043e\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u0441\u0442\u0440\u0435\u043b\u043a\u0438 (\u043e\u0442 <code>0<\/code> \u0434\u043e <code>1<\/code>)<\/td>\n<td><code>number \\| string \\| function<\/code><\/td>\n<td><code>0.5<\/code> (\u0441\u0442\u0440\u0435\u043b\u043a\u0430 \u0440\u0438\u0441\u0443\u0435\u0442\u0441\u044f \u043f\u043e\u0441\u0435\u0440\u0435\u0434\u0438\u043d\u0435)<\/td>\n<\/tr>\n<tr>\n<td><code>linkDirectionalParticles<\/code><\/td>\n<td>\u0410\u043d\u0438\u043c\u0438\u0440\u0443\u0435\u043c\u044b\u0435 \u0447\u0430\u0441\u0442\u0438\u0446\u044b (\u043c\u0430\u043b\u0435\u043d\u044c\u043a\u0438\u0435 \u043a\u0440\u0443\u0433\u0438) \u043f\u043e\u0432\u0435\u0440\u0445 \u0440\u0435\u0431\u0440\u0430<\/td>\n<td><code>number \\| string \\| function<\/code><\/td>\n<td><code>0<\/code><\/td>\n<\/tr>\n<tr>\n<td><code>linkDirectionalParticleSpeed<\/code><\/td>\n<td>\u0421\u043a\u043e\u0440\u043e\u0441\u0442\u044c \u0430\u043d\u0438\u043c\u0430\u0446\u0438\u0438 \u0447\u0430\u0441\u0442\u0438\u0446<\/td>\n<td><code>number \\| string \\| function<\/code><\/td>\n<td><code>0.01<\/code><\/td>\n<\/tr>\n<tr>\n<td><code>linkDirectionalParticleWidth<\/code><\/td>\n<td>\u0428\u0438\u0440\u0438\u043d\u0430 \u0447\u0430\u0441\u0442\u0438\u0446\u044b<\/td>\n<td><code>number \\| string \\| function<\/code><\/td>\n<td><code>0.5<\/code><\/td>\n<\/tr>\n<tr>\n<td><code>linkDirectionalParticleColor<\/code><\/td>\n<td>\u0426\u0432\u0435\u0442 \u0447\u0430\u0441\u0442\u0438\u0446\u044b<\/td>\n<td><code>string \\| function<\/code><\/td>\n<td><code>color<\/code><\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<\/div>\n<p> <\/p>\n<p> <\/p>\n<p> <\/p>\n<p><code>linkCanvasObjectMode<\/code> \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f \u0432 \u0441\u043e\u0447\u0435\u0442\u0430\u043d\u0438\u0438 \u0441 <code>linkCanvasObject<\/code> \u0434\u043b\u044f \u043a\u0430\u0441\u0442\u043e\u043c\u0438\u0437\u0430\u0446\u0438\u0438 \u0440\u0438\u0441\u043e\u0432\u0430\u043d\u0438\u044f \u0440\u0435\u0431\u0435\u0440. \u0412\u043e\u0437\u043c\u043e\u0436\u043d\u044b\u0435 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f:<\/p>\n<p> <\/p>\n<ul>\n<li><code>replace<\/code> \u2014 \u0440\u0435\u0431\u0440\u043e \u0440\u0438\u0441\u0443\u0435\u0442\u0441\u044f \u0442\u043e\u043b\u044c\u043a\u043e \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e <code>linkCanvasObject<\/code><\/li>\n<li><code>before<\/code> \u2014 \u0441\u043d\u0430\u0447\u0430\u043b\u0430 \u0440\u0435\u0431\u0440\u043e \u0440\u0438\u0441\u0443\u0435\u0442\u0441\u044f \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e <code>linkCanvasObject<\/code>, \u0437\u0430\u0442\u0435\u043c \u0440\u0438\u0441\u0443\u0435\u0442\u0441\u044f \u0434\u0435\u0444\u043e\u043b\u0442\u043d\u043e\u0435 \u0440\u0435\u0431\u0440\u043e<\/li>\n<li><code>after<\/code> \u2014 \u0441\u043d\u0430\u0447\u0430\u043b\u0430 \u0440\u0438\u0441\u0443\u0435\u0442\u0441\u044f \u0440\u0435\u0431\u0440\u043e \u043f\u043e \u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044e, \u0437\u0430\u0442\u0435\u043c \u0432\u044b\u0437\u044b\u0432\u0430\u0435\u0442\u0441\u044f <code>linkCanvasObject<\/code><\/li>\n<\/ul>\n<p> <\/p>\n<h3 id=\"upravlenie-renderingom\">\u0423\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u0440\u0435\u043d\u0434\u0435\u0440\u0438\u043d\u0433\u043e\u043c<\/h3>\n<p> <\/p>\n<div class=\"scrollable-table\">\n<table>\n<thead>\n<tr>\n<th>\u0421\u0432\u043e\u0439\u0441\u0442\u0432\u043e<\/th>\n<th>\u041e\u043f\u0438\u0441\u0430\u043d\u0438\u0435<\/th>\n<th>\u0422\u0438\u043f<\/th>\n<th>\u041f\u043e \u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044e<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td><code>autoPauseRedraw<\/code><\/td>\n<td>\u0418\u043d\u0434\u0438\u043a\u0430\u0442\u043e\u0440 \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u043e\u0439 \u043f\u0435\u0440\u0435\u0440\u0438\u0441\u043e\u0432\u043a\u0438 \u0445\u043e\u043b\u0441\u0442\u0430 \u043d\u0430 \u043a\u0430\u0436\u0434\u043e\u043c \u043a\u0430\u0434\u0440\u0435 \u0430\u043d\u0438\u043c\u0430\u0446\u0438\u0438<\/td>\n<td><code>boolean<\/code><\/td>\n<td><code>true<\/code><\/td>\n<\/tr>\n<tr>\n<td><code>minZoom<\/code><\/td>\n<td>\u041c\u0438\u043d\u0438\u043c\u0430\u043b\u044c\u043d\u044b\u0439 \u043c\u0430\u0441\u0448\u0442\u0430\u0431<\/td>\n<td><code>number<\/code><\/td>\n<td><code>0.01<\/code><\/td>\n<\/tr>\n<tr>\n<td><code>maxZoom<\/code><\/td>\n<td>\u041c\u0430\u043a\u0441\u0438\u043c\u0430\u043b\u044c\u043d\u044b\u0439 \u043c\u0430\u0441\u0448\u0442\u0430\u0431<\/td>\n<td><code>number<\/code><\/td>\n<td><code>1000<\/code><\/td>\n<\/tr>\n<tr>\n<td><code>onRenderFramePre<\/code><\/td>\n<td>\u0424\u0443\u043d\u043a\u0446\u0438\u044f, \u0432\u044b\u0437\u044b\u0432\u0430\u0435\u043c\u0430\u044f \u043d\u0430 \u043a\u0430\u0436\u0434\u043e\u043c \u043a\u0430\u0434\u0440\u0435 \u043f\u0435\u0440\u0435\u0434 \u043e\u0442\u0440\u0438\u0441\u043e\u0432\u043a\u043e\u0439 \u0432\u0435\u0440\u0448\u0438\u043d\u044b\/\u0440\u0435\u0431\u0440\u0430<\/td>\n<td><code>function<\/code><\/td>\n<td><code>undefined<\/code><\/td>\n<\/tr>\n<tr>\n<td><code>onRenderFramePost<\/code><\/td>\n<td>\u0424\u0443\u043d\u043a\u0446\u0438\u044f, \u0432\u044b\u0437\u044b\u0432\u0430\u0435\u043c\u0430\u044f \u043d\u0430 \u043a\u0430\u0436\u0434\u043e\u043c \u043a\u0430\u0434\u0440\u0435 \u043f\u043e\u0441\u043b\u0435 \u043e\u0442\u0440\u0438\u0441\u043e\u0432\u043a\u0438 \u0432\u0435\u0440\u0448\u0438\u043d\u044b\/\u0440\u0435\u0431\u0440\u0430<\/td>\n<td><code>function<\/code><\/td>\n<td><code>undefined<\/code><\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<\/div>\n<p> <\/p>\n<h4 id=\"metody\">\u041c\u0435\u0442\u043e\u0434\u044b<\/h4>\n<p> <\/p>\n<div class=\"scrollable-table\">\n<table>\n<thead>\n<tr>\n<th>\u041c\u0435\u0442\u043e\u0434<\/th>\n<th>\u0410\u0440\u0433\u0443\u043c\u0435\u043d\u0442\u044b<\/th>\n<th>\u041e\u043f\u0438\u0441\u0430\u043d\u0438\u0435<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td><code>pauseAnimation<\/code><\/td>\n<td>&#8212;<\/td>\n<td>\u041f\u0440\u0438\u043e\u0441\u0442\u0430\u043d\u0430\u0432\u043b\u0438\u0432\u0430\u0435\u0442 \u0440\u0435\u043d\u0434\u0435\u0440\u0438\u043d\u0433 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u0430, &#171;\u0437\u0430\u043c\u043e\u0440\u0430\u0436\u0438\u0432\u0430\u044f&#187; \u0442\u0435\u043a\u0443\u0449\u0435\u0435 \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u0435 \u0438 \u043e\u0442\u043a\u043b\u044e\u0447\u0430\u044f \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u0441\u043a\u0438\u0435 \u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044f<\/td>\n<\/tr>\n<tr>\n<td><code>resumeAnimation<\/code><\/td>\n<td>&#8212;<\/td>\n<td>\u0412\u043e\u0437\u043e\u0431\u043d\u043e\u0432\u043b\u044f\u0435\u0442 \u0440\u0435\u043d\u0434\u0435\u0440\u0438\u043d\u0433 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u0430<\/td>\n<\/tr>\n<tr>\n<td><code>centerAt<\/code><\/td>\n<td><code>(x?, y?, ms?)<\/code><\/td>\n<td>\u0423\u0441\u0442\u0430\u043d\u0430\u0432\u043b\u0438\u0432\u0430\u0435\u0442 \u043a\u043e\u043e\u0440\u0434\u0438\u043d\u0430\u0442\u044b \u0446\u0435\u043d\u0442\u0440\u0430 \u043e\u0431\u043b\u0430\u0441\u0442\u0438 \u043f\u0440\u043e\u0441\u043c\u043e\u0442\u0440\u0430<\/td>\n<\/tr>\n<tr>\n<td><code>zoom<\/code><\/td>\n<td><code>(number?, ms?)<\/code><\/td>\n<td>\u0423\u0441\u0442\u0430\u043d\u0430\u0432\u043b\u0438\u0432\u0430\u0435\u0442 \u043c\u0430\u0441\u0448\u0442\u0430\u0431 \u0445\u043e\u043b\u0441\u0442\u0430<\/td>\n<\/tr>\n<tr>\n<td><code>zoomToFit<\/code><\/td>\n<td><code>(ms?, px?, nodeFilterFn?)<\/code><\/td>\n<td>\u041c\u0430\u0441\u0448\u0442\u0430\u0431\u0438\u0440\u0443\u0435\u0442 \u0433\u0440\u0430\u0444 \u0434\u043e \u0440\u0430\u0437\u043c\u0435\u0440\u043e\u0432 \u043e\u0431\u043b\u0430\u0441\u0442\u0438 \u043f\u0440\u043e\u0441\u043c\u043e\u0442\u0440\u0430<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<\/div>\n<p> <\/p>\n<h3 id=\"polzovatelskie-vzaimodeystviya\">\u041f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u0441\u043a\u0438\u0435 \u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044f<\/h3>\n<p> <\/p>\n<div class=\"scrollable-table\">\n<table>\n<thead>\n<tr>\n<th>\u0421\u0432\u043e\u0439\u0441\u0442\u0432\u043e<\/th>\n<th>\u041e\u043f\u0438\u0441\u0430\u043d\u0438\u0435<\/th>\n<th>\u0422\u0438\u043f<\/th>\n<th>\u041f\u043e \u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044e<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td><code>onNodeClick<\/code><\/td>\n<td>\u041e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a \u043a\u043b\u0438\u043a\u0430 \u043f\u043e \u0432\u0435\u0440\u0448\u0438\u043d\u0435<\/td>\n<td><code>function<\/code><\/td>\n<td><code>undefined<\/code><\/td>\n<\/tr>\n<tr>\n<td><code>onNodeRightClick<\/code><\/td>\n<td>\u041e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a \u043a\u043b\u0438\u043a\u0430 \u043f\u043e \u0432\u0435\u0440\u0448\u0438\u043d\u0435 \u043f\u0440\u0430\u0432\u043e\u0439 \u043a\u043d\u043e\u043f\u043a\u043e\u0439 \u043c\u044b\u0448\u0438<\/td>\n<td><code>function<\/code><\/td>\n<td><code>undefined<\/code><\/td>\n<\/tr>\n<tr>\n<td><code>onNodeHover<\/code><\/td>\n<td>\u041e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a \u043d\u0430\u0432\u0435\u0434\u0435\u043d\u0438\u044f \u043a\u0443\u0440\u0441\u043e\u0440\u0430 \u043d\u0430 \u0432\u0435\u0440\u0448\u0438\u043d\u0443<\/td>\n<td><code>function<\/code><\/td>\n<td><code>undefined<\/code><\/td>\n<\/tr>\n<tr>\n<td><code>onNodeDrag<\/code><\/td>\n<td>\u041e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a \u043f\u0435\u0440\u0435\u0442\u0430\u0441\u043a\u0438\u0432\u0430\u043d\u0438\u044f \u0432\u0435\u0440\u0448\u0438\u043d\u044b<\/td>\n<td><code>function<\/code><\/td>\n<td><code>undefined<\/code><\/td>\n<\/tr>\n<tr>\n<td><code>onNodeDragEnd<\/code><\/td>\n<td>\u041e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a \u0437\u0430\u0432\u0435\u0440\u0448\u0435\u043d\u0438\u044f \u043f\u0435\u0440\u0435\u0442\u0430\u0441\u043a\u0438\u0432\u0430\u043d\u0438\u044f \u0432\u0435\u0440\u0448\u0438\u043d\u044b<\/td>\n<td><code>function<\/code><\/td>\n<td><code>undefined<\/code><\/td>\n<\/tr>\n<tr>\n<td><code>onLinkClick<\/code><\/td>\n<td>\u041e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a \u043a\u043b\u0438\u043a\u0430 \u043f\u043e \u0440\u0435\u0431\u0440\u0443<\/td>\n<td><code>function<\/code><\/td>\n<td><code>undefined<\/code><\/td>\n<\/tr>\n<tr>\n<td><code>onLinkRightClick<\/code><\/td>\n<td>\u041e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a \u043a\u043b\u0438\u043a\u0430 \u043f\u043e \u0440\u0435\u0431\u0440\u0443 \u043f\u0440\u0430\u0432\u043e\u0439 \u043a\u043d\u043e\u043f\u043a\u043e\u0439 \u043c\u044b\u0448\u0438<\/td>\n<td><code>function<\/code><\/td>\n<td><code>undefined<\/code><\/td>\n<\/tr>\n<tr>\n<td><code>onLinkHover<\/code><\/td>\n<td>\u041e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a \u043d\u0430\u0432\u0435\u0434\u0435\u043d\u0438\u044f \u043a\u0443\u0440\u0441\u043e\u0440\u0430 \u043d\u0430 \u0440\u0435\u0431\u0440\u043e<\/td>\n<td><code>function<\/code><\/td>\n<td><code>undefined<\/code><\/td>\n<\/tr>\n<tr>\n<td><code>onBackgroundClick<\/code><\/td>\n<td>\u041e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a \u043a\u043b\u0438\u043a\u0430 \u043f\u043e \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440\u0443 \u0433\u0440\u0430\u0444\u0430<\/td>\n<td><code>function<\/code><\/td>\n<td><code>undefined<\/code><\/td>\n<\/tr>\n<tr>\n<td><code>onBackgroundRightClick<\/code><\/td>\n<td>\u041e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a \u043a\u043b\u0438\u043a\u0430 \u043f\u043e \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440\u0443 \u0433\u0440\u0430\u0444\u0430 \u043f\u0440\u0430\u0432\u043e\u0439 \u043a\u043d\u043e\u043f\u043a\u043e\u0439 \u043c\u044b\u0448\u0438<\/td>\n<td><code>function<\/code><\/td>\n<td><code>undefined<\/code><\/td>\n<\/tr>\n<tr>\n<td><code>linkHoverPrecision<\/code><\/td>\n<td>\u0422\u043e\u0447\u043d\u043e\u0441\u0442\u044c \u043d\u0430\u0432\u0435\u0434\u0435\u043d\u0438\u044f \u043a\u0443\u0440\u0441\u043e\u0440\u0430 \u043d\u0430 \u0440\u0435\u0431\u0440\u043e, \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u044e\u0449\u0430\u044f \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u0435 \u043f\u043e\u0434\u043f\u0438\u0441\u0438<\/td>\n<td><code>number<\/code><\/td>\n<td><code>4<\/code><\/td>\n<\/tr>\n<tr>\n<td><code>onZoom<\/code><\/td>\n<td>\u041e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a \u043c\u0430\u0441\u0448\u0442\u0430\u0431\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f<\/td>\n<td><code>function<\/code><\/td>\n<td><code>undefined<\/code><\/td>\n<\/tr>\n<tr>\n<td><code>onZoomEnd<\/code><\/td>\n<td>\u041e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a \u0437\u0430\u0432\u0435\u0440\u0448\u0435\u043d\u0438\u044f \u043c\u0430\u0441\u0448\u0442\u0430\u0431\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f<\/td>\n<td><code>function<\/code><\/td>\n<td><code>undefined<\/code><\/td>\n<\/tr>\n<tr>\n<td><code>enableZoomInteraction<\/code><\/td>\n<td>\u0418\u043d\u0434\u0438\u043a\u0430\u0442\u043e\u0440 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u0438 \u043c\u0430\u0441\u0448\u0442\u0430\u0431\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f<\/td>\n<td><code>boolean<\/code><\/td>\n<td><code>true<\/code><\/td>\n<\/tr>\n<tr>\n<td><code>enablePanInteraction<\/code><\/td>\n<td>\u0418\u043d\u0434\u0438\u043a\u0430\u0442\u043e\u0440 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u0438 \u043f\u0435\u0440\u0435\u0442\u0430\u0441\u043a\u0438\u0432\u0430\u043d\u0438\u044f \u0433\u0440\u0430\u0444\u0430<\/td>\n<td><code>boolean<\/code><\/td>\n<td><code>true<\/code><\/td>\n<\/tr>\n<tr>\n<td><code>enablePointerInteraction<\/code><\/td>\n<td>\u0418\u043d\u0434\u0438\u043a\u0430\u0442\u043e\u0440 \u043e\u0442\u0441\u043b\u0435\u0436\u0438\u0432\u0430\u043d\u0438\u044f \u0441\u043e\u0431\u044b\u0442\u0438\u0439 \u0443\u043a\u0430\u0437\u0430\u0442\u0435\u043b\u044f (\u043a\u043b\u0438\u043a, \u043d\u0430\u0432\u0435\u0434\u0435\u043d\u0438\u0435 \u043a\u0443\u0440\u0441\u043e\u0440\u0430 \u0438 \u0434\u0440.)<\/td>\n<td><code>boolean<\/code><\/td>\n<td><code>true<\/code><\/td>\n<\/tr>\n<tr>\n<td><code>enableNodeDrag<\/code><\/td>\n<td>\u0418\u043d\u0434\u0438\u043a\u0430\u0442\u043e\u0440 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u0438 \u043f\u0435\u0440\u0435\u0442\u0430\u0441\u043a\u0438\u0432\u0430\u043d\u0438\u044f \u0432\u0435\u0440\u0448\u0438\u043d<\/td>\n<td><code>boolean<\/code><\/td>\n<td><code>true<\/code><\/td>\n<\/tr>\n<tr>\n<td><code>nodePointerAreaPaint<\/code><\/td>\n<td>\u0424\u0443\u043d\u043a\u0446\u0438\u044f \u0440\u0438\u0441\u043e\u0432\u0430\u043d\u0438\u044f \u043e\u0431\u043b\u0430\u0441\u0442\u0438 \u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044f \u0432\u0435\u0440\u0448\u0438\u043d\u044b<\/td>\n<td><code>function<\/code><\/td>\n<td>\u041a\u0440\u0443\u0433 \u0440\u0430\u0437\u043c\u0435\u0440\u043e\u043c \u0441 \u0432\u0435\u0440\u0448\u0438\u043d\u0443<\/td>\n<\/tr>\n<tr>\n<td><code>linkPointerAreaPaint<\/code><\/td>\n<td>\u0424\u0443\u043d\u043a\u0446\u0438\u044f \u0440\u0438\u0441\u043e\u0432\u0430\u043d\u0438\u044f \u043e\u0431\u043b\u0430\u0441\u0442\u0438 \u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044f \u0440\u0435\u0431\u0440\u0430<\/td>\n<td><code>function<\/code><\/td>\n<td>\u041f\u0440\u044f\u043c\u0430\u044f \u043b\u0438\u043d\u0438\u044f \u043c\u0435\u0436\u0434\u0443 \u0432\u0435\u0440\u0448\u0438\u043d\u0430\u043c\u0438<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<\/div>\n<p> <\/p>\n<h2 id=\"-komponenty\">\u276f \u041a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u044b<\/h2>\n<p> <\/p>\n<p>\u0420\u0435\u0430\u043b\u0438\u0437\u0443\u0435\u043c \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0432\u0430\u0440\u0438\u0430\u043d\u0442\u043e\u0432 \u0433\u0440\u0430\u0444\u0430.<\/p>\n<p> <\/p>\n<h3 id=\"bazovyy-variant\">\u0411\u0430\u0437\u043e\u0432\u044b\u0439 \u0432\u0430\u0440\u0438\u0430\u043d\u0442<\/h3>\n<p> <\/p>\n<p>\u041f\u043e \u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044e \u0433\u0440\u0430\u0444 \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u043c\u0430\u0441\u0448\u0442\u0430\u0431\u0438\u0440\u0443\u0435\u043c\u044b\u043c, \u043f\u0435\u0440\u0435\u0442\u0430\u0441\u043a\u0438\u0432\u0430\u0435\u043c\u044b\u043c (\u0441\u0430\u043c \u0433\u0440\u0430\u0444 \u0438 \u0443\u0437\u043b\u044b) \u0438 \u0440\u0435\u0430\u0433\u0438\u0440\u0443\u044e\u0449\u0438\u043c \u043d\u0430 \u0441\u043e\u0431\u044b\u0442\u0438\u044f \u0443\u043a\u0430\u0437\u0430\u0442\u0435\u043b\u044f (\u043d\u0430\u0432\u0435\u0434\u0435\u043d\u0438\u0435 \u043a\u0443\u0440\u0441\u043e\u0440\u0430, \u043a\u043b\u0438\u043a \u043f\u043e \u0443\u0437\u043b\u0443\/\u0432\u0435\u0440\u0448\u0438\u043d\u0435 \u0438 \u0442.\u043f.). \u041f\u043e \u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044e \u0433\u0440\u0430\u0444 \u043f\u0440\u0438\u043d\u0438\u043c\u0430\u0435\u0442 \u0440\u0430\u0437\u043c\u0435\u0440 \u043e\u0431\u043b\u0430\u0441\u0442\u0438 \u043f\u0440\u043e\u0441\u043c\u043e\u0442\u0440\u0430. \u041f\u0440\u0438 \u043d\u0430\u0432\u0435\u0434\u0435\u043d\u0438\u0438 \u043a\u0443\u0440\u0441\u043e\u0440\u0430 \u043d\u0430 \u0443\u0437\u0435\u043b\/\u0433\u0440\u0430\u0444 \u043f\u043e \u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044e \u0440\u0435\u043d\u0434\u0435\u0440\u0438\u0442\u0441\u044f \u0442\u0443\u043b\u0442\u0438\u043f \u0441 \u0435\u0433\u043e \u043d\u0430\u0437\u0432\u0430\u043d\u0438\u0435\u043c (\u043f\u043e \u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044e \u043f\u043e\u043b\u0435 <code>name<\/code> \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u044e\u0449\u0435\u0433\u043e \u043e\u0431\u044a\u0435\u043a\u0442\u0430, \u043a\u0430\u0441\u0442\u043e\u043c\u0438\u0437\u0438\u0440\u0443\u0435\u0442\u0441\u044f \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u043f\u0440\u043e\u043f\u043e\u0432 <code>nodeLabel<\/code> \u0438 <code>linkLabel<\/code>).<\/p>\n<p> <\/p>\n<pre><code class=\"javascript\">\/\/ Graph\/Basic.tsx import { useState } from 'react' import ForceGraph from 'react-force-graph-2d' import { Flex } from '..\/Flex' import { generateGraphData } from '.\/utils'  const graphData = generateGraphData()  function Basic() {   \/\/ \u041c\u0430\u0441\u0448\u0442\u0430\u0431\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435   const [enableZoomInteraction, setEnableZoomInteraction] = useState(true)   \/\/ \u041f\u0435\u0440\u0435\u0442\u0430\u0441\u043a\u0438\u0432\u0430\u043d\u0438\u0435 \u0433\u0440\u0430\u0444\u0430   const [enablePanInteraction, setEnablePanInteraction] = useState(true)   \/\/ \u041f\u0435\u0440\u0435\u0442\u0430\u0441\u043a\u0438\u0432\u0430\u043d\u0438\u0435 \u0443\u0437\u043b\u043e\u0432   const [enableNodeDrag, setEnableNodeDrag] = useState(true)   \/\/ \u0421\u043e\u0431\u044b\u0442\u0438\u044f \u0443\u043a\u0430\u0437\u0430\u0442\u0435\u043b\u044f   const [enablePointerInteraction, setEnablePointerInteraction] = useState(true)    return (     &lt;Flex flexDirection='column' gap={12}&gt;       &lt;h3&gt;\u0411\u0430\u0437\u043e\u0432\u044b\u0439 \u0432\u0430\u0440\u0438\u0430\u043d\u0442&lt;\/h3&gt;       &lt;fieldset&gt;         &lt;legend&gt;\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438&lt;\/legend&gt;         &lt;Flex flexDirection='column' gap={8}&gt;           &lt;label&gt;             &lt;input               type='checkbox'               checked={enableZoomInteraction}               onChange={(e) =&gt; setEnableZoomInteraction(e.target.checked)}             \/&gt;{' '}             \u041c\u0430\u0441\u0448\u0442\u0430\u0431\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u0433\u0440\u0430\u0444\u0430           &lt;\/label&gt;           &lt;label&gt;             &lt;input               type='checkbox'               checked={enablePanInteraction}               onChange={(e) =&gt; setEnablePanInteraction(e.target.checked)}             \/&gt;{' '}             \u041f\u0435\u0440\u0435\u0442\u0430\u0441\u043a\u0438\u0432\u0430\u043d\u0438\u0435 \u0433\u0440\u0430\u0444\u0430           &lt;\/label&gt;           &lt;label&gt;             &lt;input               type='checkbox'               checked={enableNodeDrag}               onChange={(e) =&gt; setEnableNodeDrag(e.target.checked)}             \/&gt;{' '}             \u041f\u0435\u0440\u0435\u0442\u0430\u0441\u043a\u0438\u0432\u0430\u043d\u0438\u0435 \u0432\u0435\u0440\u0448\u0438\u043d           &lt;\/label&gt;           &lt;label&gt;             &lt;input               type='checkbox'               checked={enablePointerInteraction}               onChange={(e) =&gt; setEnablePointerInteraction(e.target.checked)}             \/&gt;{' '}             \u0421\u043e\u0431\u044b\u0442\u0438\u044f \u0443\u043a\u0430\u0437\u0430\u0442\u0435\u043b\u044f           &lt;\/label&gt;         &lt;\/Flex&gt;       &lt;\/fieldset&gt;       &lt;Flex width={768} height={480} border='1px dashed rgba(0,0,0,0.25)'&gt;         &lt;ForceGraph           width={768}           height={480}           graphData={graphData}           enableZoomInteraction={enableZoomInteraction}           enablePanInteraction={enablePanInteraction}           enableNodeDrag={enableNodeDrag}           enablePointerInteraction={enablePointerInteraction}         \/&gt;       &lt;\/Flex&gt;     &lt;\/Flex&gt;   ) }  export default Basic<\/code><\/pre>\n<p> <\/p>\n<h3 id=\"kastomizaciya-vershin\">\u041a\u0430\u0441\u0442\u043e\u043c\u0438\u0437\u0430\u0446\u0438\u044f \u0432\u0435\u0440\u0448\u0438\u043d<\/h3>\n<p> <\/p>\n<pre><code class=\"javascript\">\/\/ Graph\/Node.tsx import { useState } from 'react' import ForceGraph from 'react-force-graph-2d' import { Flex } from '..\/Flex' import { generateGraphData } from '.\/utils'  const graphData = generateGraphData()  function Node() {   \/\/ \u0412\u0438\u0434\u0438\u043c\u043e\u0441\u0442\u044c \u0432\u0435\u0440\u0448\u0438\u043d   const [nodeVisibility, setNodeVisibility] = useState(true)   \/\/ \u0420\u0430\u0437\u043c\u0435\u0440 \u0432\u0435\u0440\u0448\u0438\u043d   const [nodeRelSize, setNodeRelSize] = useState(4)   \/\/ \u0426\u0432\u0435\u0442 \u0432\u0435\u0440\u0448\u0438\u043d   const [nodeColor, setNodeColor] = useState('deepskyblue')    return (     &lt;Flex flexDirection='column' gap={12}&gt;       &lt;h3&gt;\u041a\u0430\u0441\u0442\u043e\u043c\u0438\u0437\u0430\u0446\u0438\u044f \u0432\u0435\u0440\u0448\u0438\u043d&lt;\/h3&gt;       &lt;fieldset&gt;         &lt;legend&gt;\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438&lt;\/legend&gt;         &lt;Flex flexDirection='column' gap={8}&gt;           &lt;label&gt;             &lt;input               type='checkbox'               checked={nodeVisibility}               onChange={(e) =&gt; setNodeVisibility(e.target.checked)}             \/&gt;{' '}             \u0412\u0438\u0434\u0438\u043c\u043e\u0441\u0442\u044c \u0432\u0435\u0440\u0448\u0438\u043d           &lt;\/label&gt;           &lt;label&gt;             \u0420\u0430\u0437\u043c\u0435\u0440 \u0432\u0435\u0440\u0448\u0438\u043d{' '}             &lt;input               type='number'               value={nodeRelSize}               onChange={(e) =&gt; setNodeRelSize(Number(e.target.value))}               min={4}               max={12}             \/&gt;           &lt;\/label&gt;           &lt;Flex gap={8} alignItems='center'&gt;             &lt;label&gt;\u0426\u0432\u0435\u0442 \u0432\u0435\u0440\u0448\u0438\u043d&lt;\/label&gt;             &lt;input               type='color'               value={nodeColor}               onChange={(e) =&gt; setNodeColor(e.target.value)}             \/&gt;              &lt;button onClick={() =&gt; setNodeColor('deepskyblue')}&gt;\u0421\u0431\u0440\u043e\u0441&lt;\/button&gt;           &lt;\/Flex&gt;         &lt;\/Flex&gt;       &lt;\/fieldset&gt;       &lt;Flex         width={768}         height={480}         border='1px dashed rgba(0,0,0,0.25)'         justifyContent='center'         alignItems='center'       &gt;         &lt;ForceGraph           width={768}           height={480}           graphData={graphData}           nodeVisibility={nodeVisibility}           nodeRelSize={nodeRelSize}           nodeColor={() =&gt; nodeColor}         \/&gt;       &lt;\/Flex&gt;     &lt;\/Flex&gt;   ) }  export default Node<\/code><\/pre>\n<p> <\/p>\n<p>\u0420\u0430\u0437\u043c\u0435\u0440 \u0432\u0435\u0440\u0448\u0438\u043d\u044b \u043c\u043e\u0436\u0435\u0442 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u0442\u044c\u0441\u044f \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u043f\u043e\u043b\u044f <code>val<\/code>, \u0430 \u0446\u0432\u0435\u0442 \u2014 \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u043f\u043e\u043b\u044f <code>color<\/code>.<\/p>\n<p> <\/p>\n<h3 id=\"kastomizaciya-reber\">\u041a\u0430\u0441\u0442\u043e\u043c\u0438\u0437\u0430\u0446\u0438\u044f \u0440\u0435\u0431\u0435\u0440<\/h3>\n<p> <\/p>\n<pre><code class=\"javascript\">\/\/ Graph\/Link.tsx import { useEffect, useState } from 'react' import ForceGraph from 'react-force-graph-2d' import { Flex } from '..\/Flex' import { generateGraphData } from '.\/utils'  const initialGraphData = generateGraphData()  function Link() {   const [graphData, setGraphData] = useState(initialGraphData)    \/\/ \u0412\u0438\u0434\u0438\u043c\u043e\u0441\u0442\u044c \u0440\u0435\u0431\u0435\u0440   const [linkVisibility, setLinkVisibility] = useState(true)   \/\/ \u0426\u0432\u0435\u0442 \u0440\u0435\u0431\u0435\u0440   const [linkColor, setLinkColor] = useState('deepskyblue')   \/\/ \u0428\u0438\u0440\u0438\u043d\u0430 \u0440\u0435\u0431\u0435\u0440   const [linkWidth, setLinkWidth] = useState(1)   \/\/ \u041f\u0440\u0435\u0440\u044b\u0432\u0438\u0441\u0442\u043e\u0441\u0442\u044c \u043b\u0438\u043d\u0438\u0438   const [linkLineDash, setLinkLineDash] = useState(false)   \/\/ \u041a\u0440\u0438\u0432\u0438\u0437\u043d\u0430 \u043b\u0438\u043d\u0438\u0438   const [linkCurvature, setLinkCurvature] = useState(false)   \/\/ \u0414\u043b\u0438\u043d\u0430 \u0441\u0442\u0440\u0435\u043b\u043a\u0438   const [linkDirectionalArrowLength, setLinkDirectionalArrowLength] =     useState(0)   \/\/ \u041f\u043e\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u0441\u0442\u0440\u0435\u043b\u043a\u0438   const [linkDirectionalArrowRelPos, setLinkDirectionalArrowRelPos] =     useState(0.5)   \/\/ \u0414\u0432\u043e\u0438\u0306\u043d\u044b\u0435 \u0441\u0442\u0440\u0435\u043b\u043a\u0438   const [doubleArrows, setDoubleArrows] = useState(false)    useEffect(() =&gt; {     if (doubleArrows) {       \/\/ \u0423\u0434\u0432\u0430\u0438\u0432\u0430\u0435\u043c \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u043e \u0440\u0435\u0431\u0435\u0440       const links = [...initialGraphData.links]       const reversedLinks = links.map((link, i) =&gt; {         return {           id: links.length + i + 1,           source: link.target,           target: link.source,         }       })       const allLinks = links.concat(reversedLinks)       const newGraphData = {         nodes: [...initialGraphData.nodes],         links: allLinks,       }       setGraphData(newGraphData)     } else {       setGraphData(initialGraphData)     }   }, [doubleArrows])    return (     &lt;Flex flexDirection='column' gap={12}&gt;       &lt;h3&gt;\u041a\u0430\u0441\u0442\u043e\u043c\u0438\u0437\u0430\u0446\u0438\u044f \u0440\u0435\u0431\u0435\u0440&lt;\/h3&gt;       &lt;fieldset&gt;         &lt;legend&gt;\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438&lt;\/legend&gt;         &lt;Flex flexDirection='column' gap={8}&gt;           &lt;label&gt;             &lt;input               type='checkbox'               checked={linkVisibility}               onChange={(e) =&gt; setLinkVisibility(e.target.checked)}             \/&gt;{' '}             \u0412\u0438\u0434\u0438\u043c\u043e\u0441\u0442\u044c \u0432\u0435\u0440\u0448\u0438\u043d           &lt;\/label&gt;           &lt;label&gt;             \u0428\u0438\u0440\u0438\u043d\u0430 \u0440\u0435\u0431\u0435\u0440{' '}             &lt;input               type='number'               value={linkWidth}               onChange={(e) =&gt; setLinkWidth(Number(e.target.value))}               min={1}               max={4}             \/&gt;           &lt;\/label&gt;           &lt;Flex gap={8} alignItems='center'&gt;             &lt;label&gt;\u0426\u0432\u0435\u0442 \u0440\u0435\u0431\u0435\u0440&lt;\/label&gt;             &lt;input               type='color'               value={linkColor}               onChange={(e) =&gt; setLinkColor(e.target.value)}             \/&gt;              &lt;button onClick={() =&gt; setLinkColor('deepskyblue')}&gt;\u0421\u0431\u0440\u043e\u0441&lt;\/button&gt;           &lt;\/Flex&gt;           &lt;label&gt;             &lt;input               type='checkbox'               checked={linkLineDash}               onChange={(e) =&gt; setLinkLineDash(e.target.checked)}             \/&gt;{' '}             \u041f\u0440\u0435\u0440\u044b\u0432\u0438\u0441\u0442\u0430\u044f \u043b\u0438\u043d\u0438\u044f           &lt;\/label&gt;           &lt;label&gt;             &lt;input               type='checkbox'               checked={linkCurvature}               onChange={(e) =&gt; setLinkCurvature(e.target.checked)}             \/&gt;{' '}             \u041a\u0440\u0438\u0432\u0430\u044f \u043b\u0438\u043d\u0438\u044f           &lt;\/label&gt;           &lt;label&gt;             \u0414\u043b\u0438\u043d\u0430 \u0441\u0442\u0440\u0435\u043b\u043a\u0438{' '}             &lt;input               type='number'               value={linkDirectionalArrowLength}               onChange={(e) =&gt;                 setLinkDirectionalArrowLength(Number(e.target.value))               }               min={0}               max={8}             \/&gt;           &lt;\/label&gt;           &lt;label&gt;             \u041f\u043e\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u0441\u0442\u0440\u0435\u043b\u043a\u0438{' '}             &lt;input               type='number'               value={linkDirectionalArrowRelPos}               onChange={(e) =&gt;                 setLinkDirectionalArrowRelPos(Number(e.target.value))               }               min={0}               max={1}               step={0.1}             \/&gt;           &lt;\/label&gt;           &lt;label&gt;             &lt;input               type='checkbox'               checked={doubleArrows}               onChange={(e) =&gt; setDoubleArrows(e.target.checked)}             \/&gt;{' '}             \u0414\u0432\u043e\u0439\u043d\u044b\u0435 \u0441\u0442\u0440\u0435\u043b\u043a\u0438           &lt;\/label&gt;         &lt;\/Flex&gt;       &lt;\/fieldset&gt;       &lt;Flex width={768} height={480} border='1px dashed rgba(0,0,0,0.25)'&gt;         &lt;ForceGraph           width={768}           height={480}           graphData={graphData}           linkVisibility={linkVisibility}           linkColor={() =&gt; linkColor}           linkWidth={linkWidth}           \/\/ [\u0448\u0438\u0440\u0438\u043d\u0430 \u043b\u0438\u043d\u0438\u0438, \u0448\u0438\u0440\u0438\u043d\u0430 \u043e\u0442\u0441\u0442\u0443\u043f\u0430]           linkLineDash={linkLineDash ? [4, 2] : undefined}           \/\/ \u043e\u0442 0 \u0434\u043e 1           linkCurvature={linkCurvature ? 1 : undefined}           linkDirectionalArrowColor={() =&gt; linkColor}           linkDirectionalArrowLength={linkDirectionalArrowLength}           linkDirectionalArrowRelPos={linkDirectionalArrowRelPos}         \/&gt;       &lt;\/Flex&gt;     &lt;\/Flex&gt;   ) }  export default Link<\/code><\/pre>\n<p> <\/p>\n<p>\u0426\u0432\u0435\u0442 \u0432\u0435\u0440\u0448\u0438\u043d\u044b \u043c\u043e\u0436\u0435\u0442 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u0442\u044c\u0441\u044f \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u043f\u043e\u043b\u044f <code>color<\/code>.<\/p>\n<p> <\/p>\n<h3 id=\"ikonka-v-uzle\">\u0418\u043a\u043e\u043d\u043a\u0430 \u0432 \u0443\u0437\u043b\u0435<\/h3>\n<p> <\/p>\n<p>\u0414\u043b\u044f \u0440\u0438\u0441\u043e\u0432\u0430\u043d\u0438\u044f \u0438\u043a\u043e\u043d\u043a\u0438 \u043f\u043e\u0432\u0435\u0440\u0445 \u0443\u0437\u043b\u0430 \u043d\u0430\u043c \u043f\u043e\u0442\u0440\u0435\u0431\u0443\u0435\u0442\u0441\u044f \u0441\u043f\u0435\u0446\u0438\u0430\u043b\u044c\u043d\u0430\u044f \u0444\u0443\u043d\u043a\u0446\u0438\u044f. \u041e\u043f\u0440\u0435\u0434\u0435\u043b\u0438\u043c \u0435\u0435 \u0432 <code>Graph\/utils.ts<\/code>:<\/p>\n<p> <\/p>\n<pre><code class=\"javascript\">export type DrawNodeImageProps = {   \/\/ \u0423\u0437\u0435\u043b   node: NodeObject   \/\/ \u041a\u043e\u043d\u0442\u0435\u043a\u0441\u0442 \u0440\u0438\u0441\u043e\u0432\u0430\u043d\u0438\u044f   ctx: CanvasRenderingContext2D   \/\/ \u0418\u0437\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u0435   image: CanvasImageSource | OffscreenCanvas }  \/\/ \u0414\u0435\u0444\u043e\u043b\u0442\u043d\u044b\u0438\u0306 \u0440\u0430\u0437\u043c\u0435\u0440 \u0443\u0437\u043b\u0430 const defaultNodeSize = 4  export const drawNodeImage = ({ node, ctx, image }: DrawNodeImageProps) =&gt; {   if (!image) return    \/\/ \u041d\u0430\u0447\u0430\u043b\u044c\u043d\u044b\u0435 \u043a\u043e\u043e\u0440\u0434\u0438\u043d\u0430\u0442\u044b \u0438 \u0440\u0430\u0437\u043c\u0435\u0440 \u0443\u0437\u043b\u0430   const nodeX = node.x || 0   const nodeY = node.y || 0   const nodeSize = Number(node.val) || defaultNodeSize    \/\/ \u0420\u0438\u0441\u0443\u0435\u043c \u0438\u0437\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u0435   ctx.drawImage(     image,     nodeX - nodeSize,     nodeY - nodeSize,     nodeSize * 2,     nodeSize * 2,   ) }<\/code><\/pre>\n<p> <\/p>\n<p>\u041f\u0440\u0438\u043c\u0435\u043d\u044f\u0435\u043c \u044d\u0442\u0443 \u0444\u0443\u043d\u043a\u0446\u0438\u044e \u0432 \u043f\u0440\u043e\u043f\u0435 <code>nodeCanvasObject<\/code>:<\/p>\n<p> <\/p>\n<pre><code class=\"javascript\">\/\/ Graph\/NodeIcon.tsx import { useEffect, useRef, useState } from 'react' import ForceGraph from 'react-force-graph-2d' import { Flex } from '..\/Flex' import { drawNodeImage, generateGraphData } from '.\/utils'  const graphData = generateGraphData()  function NodeIcon() {   const spanRef = useRef&lt;HTMLSpanElement&gt;(null)   const [images, setImages] = useState&lt;HTMLImageElement[]&gt;([])    useEffect(() =&gt; {     if (!spanRef.current) return     const images = [...spanRef.current.querySelectorAll('img')]     setImages(images)   }, [])    return (     &lt;Flex flexDirection='column' gap={12}&gt;       &lt;h3&gt;\u0423\u0437\u0435\u043b \u0441 \u0438\u043a\u043e\u043d\u043a\u043e\u0439&lt;\/h3&gt;       {\/* \u041d\u0435\u0431\u043e\u043b\u044c\u0448\u043e\u0439 \u0445\u0430\u043a *\/}       &lt;span         ref={spanRef}         style={{           display: 'none',         }}       &gt;         {\/* \u0418\u0437\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u044f \u043b\u0435\u0436\u0430\u0442 \u0432 \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u0438 `public\/graph` *\/}         &lt;img src='\/graph\/briefcase.svg' alt='' \/&gt;         &lt;img src='\/graph\/folder.svg' alt='' \/&gt;         &lt;img src='\/graph\/font.svg' alt='' \/&gt;         &lt;img src='\/graph\/paste.svg' alt='' \/&gt;         &lt;img src='\/graph\/user.svg' alt='' \/&gt;       &lt;\/span&gt;       &lt;Flex width={768} height={480} border='1px dashed rgba(0,0,0,0.25'&gt;         &lt;ForceGraph           width={768}           height={480}           graphData={graphData}           nodeRelSize={6}           nodeCanvasObject={(node, ctx) =&gt; {             \/\/ \u0412\u044b\u0431\u0438\u0440\u0430\u0435\u043c \u0438\u0437\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u0435             const image = images[Number(node.id) % 5]              \/\/ \u0420\u0438\u0441\u0443\u0435\u043c \u0435\u0433\u043e             drawNodeImage({ node, ctx, image })           }}           \/\/ \u0421\u043d\u0430\u0447\u0430\u043b\u0430 \u0440\u0438\u0441\u0443\u0435\u043c \u0434\u0435\u0444\u043e\u043b\u0442\u043d\u044b\u0439 \u0443\u0437\u0435\u043b, \u0437\u0430\u0442\u0435\u043c - \u0438\u043a\u043e\u043d\u043a\u0443           nodeCanvasObjectMode={() =&gt; 'after'}         \/&gt;       &lt;\/Flex&gt;     &lt;\/Flex&gt;   ) }  export default NodeIcon<\/code><\/pre>\n<p> <\/p>\n<h3 id=\"uzel-s-podpisyu\">\u0423\u0437\u0435\u043b \u0441 \u043f\u043e\u0434\u043f\u0438\u0441\u044c\u044e<\/h3>\n<p> <\/p>\n<p>\u0427\u0442\u043e \u0435\u0441\u043b\u0438 \u043c\u044b \u0445\u043e\u0442\u0438\u043c, \u0447\u0442\u043e\u0431\u044b \u043d\u0430\u0437\u0432\u0430\u043d\u0438\u044f \u0443\u0437\u043b\u043e\u0432 \u0440\u0435\u043d\u0434\u0435\u0440\u0438\u043b\u0438\u0441\u044c \u043d\u0435 \u0432 \u0442\u0443\u043b\u0442\u0438\u043f\u0435, \u0430 \u043f\u043e\u0434 \u0443\u0437\u043b\u0430\u043c\u0438? \u0414\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u043d\u0430\u043c \u0442\u0430\u043a\u0436\u0435 \u043f\u043e\u0442\u0440\u0435\u0431\u0443\u044e\u0442\u0441\u044f \u0441\u043f\u0435\u0446\u0438\u0430\u043b\u044c\u043d\u044b\u0435 \u0444\u0443\u043d\u043a\u0446\u0438\u0438. \u041e\u043f\u0440\u0435\u0434\u0435\u043b\u0438\u043c \u0438\u0445 \u0432 <code>Graph\/utils.ts<\/code>:<\/p>\n<p> <\/p>\n<pre><code class=\"javascript\">export type DrawNodeLabelProps = {   \/\/ \u0423\u0437\u0435\u043b   node: NodeObject   \/\/ \u041a\u043e\u043d\u0442\u0435\u043a\u0441\u0442 \u0440\u0438\u0441\u043e\u0432\u0430\u043d\u0438\u044f   ctx: CanvasRenderingContext2D   \/\/ \u0413\u043b\u043e\u0431\u0430\u043b\u044c\u043d\u044b\u0438\u0306 \u043c\u0430\u0441\u0448\u0442\u0430\u0431   globalScale?: number   \/\/ \u0420\u0430\u0437\u043c\u0435\u0440 \u0448\u0440\u0438\u0444\u0442\u0430   fontSize?: number   \/\/ \u041e\u0442\u0441\u0442\u0443\u043f \u043e\u0442 \u0443\u0437\u043b\u0430   offset?: number   \/\/ \u0423\u0437\u043b\u044b \u0432 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0438 hover   hoverNodes?: (NodeObject | null)[]   \/\/ \u0412\u044b\u0431\u0440\u0430\u043d\u043d\u044b\u0435 \u0443\u0437\u043b\u044b   clickNodes?: (NodeObject | null)[]   \/\/ \u0420\u0435\u0436\u0438\u043c \u043e\u0442\u043b\u0430\u0434\u043a\u0438   debug?: boolean }  \/\/ \u0414\u0435\u0444\u043e\u043b\u0442\u043d\u044b\u0435 \u0446\u0432\u0435\u0442\u0430 export const defaultColors = {   nodeColor: '#827e7e',   activeNodeColor: '#1d75db',   labelColor: '#1a1818',   tooltipColor: '#f7ebeb', }  export const drawNodeLabel = ({   node,   ctx,   globalScale = 1,   fontSize = 6,   offset = 4,   hoverNodes = [],   clickNodes = [],   debug, }: DrawNodeLabelProps) =&gt; {   const { activeNodeColor, labelColor } = defaultColors    const nodeX = node.x || 0   const nodeY = node.y || 0   const nodeSize = Number(node.size) || defaultNodeSize    \/\/ \u0420\u0438\u0441\u0443\u0435\u043c \u0442\u0435\u043a\u0441\u0442   const label = String(node.name) || ''   const _fontSize = fontSize \/ globalScale   ctx.font = `${_fontSize}px sans-serif`   ctx.textAlign = 'center'   ctx.textBaseline = 'middle'   const _labelColor = node.labelColor || labelColor   const labelActiveColor = node.labelActiveColor || activeNodeColor   \/\/ \u0426\u0432\u0435\u0442 \u043f\u043e\u0434\u043f\u0438\u0441\u0438 \u0437\u0430\u0432\u0438\u0441\u0438\u0442 \u043e\u0442 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f \u0443\u0437\u043b\u0430   ctx.fillStyle =     hoverNodes.includes(node) || clickNodes.includes(node)       ? labelActiveColor       : _labelColor   ctx.fillText(label, nodeX, nodeY + nodeSize + offset)    \/\/ \u0412\u044b\u0447\u0438\u0441\u043b\u044f\u0435\u043c \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f \u0434\u043b\u044f \u043e\u0431\u043b\u0430\u0441\u0442\u0438 \u0432\u044b\u0434\u0435\u043b\u0435\u043d\u0438\u044f\/\u043a\u043b\u0438\u043a\u0430   const textWidth = ctx.measureText(label).width   const pointerArea = {     x: nodeX - textWidth \/ 2,     y: nodeY - nodeSize \/ 2 - offset \/ 2,     width: textWidth,     height: nodeSize + fontSize + offset,   }    \/\/ \u0415\u0441\u043b\u0438 \u0432\u043a\u043b\u044e\u0447\u0435\u043d \u0440\u0435\u0436\u0438\u043c \u043e\u0442\u043b\u0430\u0434\u043a\u0438   if (debug) {     \/\/ \u0420\u0438\u0441\u0443\u0435\u043c \u043e\u0431\u043b\u0430\u0441\u0442\u044c \u0432\u044b\u0434\u0435\u043b\u0435\u043d\u0438\u044f\/\u043a\u043b\u0438\u043a\u0430     ctx.fillStyle = 'rgba(0, 0, 0, 0.25)'     ctx.fillRect(       pointerArea.x,       pointerArea.y,       pointerArea.width,       pointerArea.height,     )   }    \/\/ \u0414\u043b\u044f \u043f\u043e\u0432\u0442\u043e\u0440\u043d\u043e\u0433\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u044f \u0432 `drawNodePointerArea`   node.pointerArea = pointerArea }  export type NodePointerArea = {   x: number   y: number   width: number   height: number }  export type DrawNodePointerAreaProps = {   \/\/ \u0423\u0437\u0435\u043b   node: NodeObject   \/\/ \u0426\u0432\u0435\u0442   color: string   \/\/ \u041a\u043e\u043d\u0442\u0435\u043a\u0441\u0442 \u0440\u0438\u0441\u043e\u0432\u0430\u043d\u0438\u044f   ctx: CanvasRenderingContext2D }  export const drawNodePointerArea = ({   node,   color,   ctx, }: DrawNodePointerAreaProps) =&gt; {   ctx.fillStyle = color   const pointerArea: NodePointerArea = node.pointerArea   pointerArea &amp;&amp;     ctx.fillRect(       pointerArea.x,       pointerArea.y,       pointerArea.width,       pointerArea.height,     ) }<\/code><\/pre>\n<p> <\/p>\n<p>\u041f\u0440\u0438\u043c\u0435\u043d\u044f\u0435\u043c \u0438\u0445 \u0432 \u043f\u0440\u043e\u043f\u0435 <code>nodeCanvasObject<\/code>:<\/p>\n<p> <\/p>\n<pre><code class=\"javascript\">\/\/ Graph\/NodeWithLabel.tsx import ForceGraph from 'react-force-graph-2d' import { Flex } from '..\/Flex' import { drawNodeLabel, drawNodePointerArea, generateGraphData } from '.\/utils'  const graphData = generateGraphData()  function NodeWithLabel() {   return (     &lt;Flex flexDirection='column' gap={12}&gt;       &lt;h3&gt;\u0423\u0437\u0435\u043b \u0441 \u043f\u043e\u0434\u043f\u0438\u0441\u044c\u044e&lt;\/h3&gt;       &lt;Flex width={768} height={480} border='1px dashed rgba(0,0,0,0.25)'&gt;         &lt;ForceGraph           width={768}           height={480}           graphData={graphData}           \/\/ \u0420\u0438\u0441\u0443\u0435\u043c \u043f\u043e\u0434\u043f\u0438\u0441\u044c           nodeCanvasObject={(node, ctx) =&gt;             drawNodeLabel({               node,               ctx,             })           }           \/\/ \u0421\u043d\u0430\u0447\u0430\u043b\u0430 \u0440\u0438\u0441\u0443\u0435\u043c \u0434\u0435\u0444\u043e\u043b\u0442\u043d\u044b\u0439 \u0443\u0437\u0435\u043b, \u0437\u0430\u0442\u0435\u043c - \u043f\u043e\u0434\u043f\u0438\u0441\u044c           nodeCanvasObjectMode={() =&gt; 'after'}           \/\/ \u0420\u0438\u0441\u0443\u0435\u043c \u043e\u0431\u043b\u0430\u0441\u0442\u044c \u0432\u044b\u0434\u0435\u043b\u0435\u043d\u0438\u044f\/\u043a\u043b\u0438\u043a\u0430           nodePointerAreaPaint={(node, color, ctx) =&gt;             drawNodePointerArea({ node, color, ctx })           }           \/\/ \u041e\u0442\u043a\u043b\u044e\u0447\u0430\u0435\u043c \u0442\u0443\u043b\u0442\u0438\u043f\u044b           nodeLabel='label'           linkLabel='label'         \/&gt;       &lt;\/Flex&gt;     &lt;\/Flex&gt;   ) }  export default NodeWithLabel<\/code><\/pre>\n<p> <\/p>\n<h3 id=\"uzel-v-sostoyanii-hover\">\u0423\u0437\u0435\u043b \u0432 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0438 hover<\/h3>\n<p> <\/p>\n<p>\u0420\u0435\u0430\u043b\u0438\u0437\u0443\u0435\u043c \u0433\u0440\u0430\u0444 \u0441 \u0443\u0437\u043b\u0430\u043c\u0438 \u0438 \u0440\u0435\u0431\u0440\u0430\u043c\u0438, \u0432\u044b\u0434\u0435\u043b\u044f\u0435\u043c\u044b\u043c\u0438 \u0446\u0432\u0435\u0442\u043e\u043c \u043f\u0440\u0438 \u043d\u0430\u0432\u0435\u0434\u0435\u043d\u0438\u0438. \u041f\u0440\u0438 \u044d\u0442\u043e\u043c, \u043c\u044b \u0445\u043e\u0442\u0438\u043c \u0438\u043c\u0435\u0442\u044c \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c \u0432\u044b\u0434\u0435\u043b\u044f\u0442\u044c \u043d\u0435 \u0442\u043e\u043b\u044c\u043a\u043e \u0441\u0430\u043c \u0443\u0437\u0435\u043b, \u043d\u043e \u0442\u0430\u043a\u0436\u0435 \u0435\u0433\u043e \u0441\u043e\u0441\u0435\u0434\u0435\u0439 \u0438 \u0440\u0435\u0431\u0440\u0430. \u0422\u0430\u043a\u0436\u0435 \u043c\u044b \u0445\u043e\u0442\u0438\u043c \u0438\u043c\u0435\u0442\u044c \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c \u0432\u044b\u0434\u0435\u043b\u044f\u0442\u044c \u043d\u0435 \u0442\u043e\u043b\u044c\u043a\u043e \u0441\u0430\u043c\u043e \u0440\u0435\u0431\u0440\u043e, \u043d\u043e \u0442\u0430\u043a\u0436\u0435 \u0435\u0433\u043e \u0438\u0441\u0442\u043e\u0447\u043d\u0438\u043a \u0438 \u0446\u0435\u043b\u044c (\u0432\u0435\u0440\u0448\u0438\u043d\u044b).<\/p>\n<p> <\/p>\n<pre><code class=\"javascript\">\/\/ Graph\/Hover.tsx import { useState } from 'react' import ForceGraph, {   type LinkObject,   type NodeObject, } from 'react-force-graph-2d' import { Flex } from '..\/Flex' import { defaultColors, generateGraphData } from '.\/utils'  const graphData = generateGraphData() \/\/ \u041c\u044b \u0445\u043e\u0442\u0438\u043c \u0438\u043c\u0435\u0442\u044c \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c \u0432\u044b\u0434\u0435\u043b\u044f\u0442\u044c \u043d\u0435 \u0442\u043e\u043b\u044c\u043a\u043e \u0443\u0437\u0435\u043b, \u043d\u043e \u0442\u0430\u043a\u0436\u0435 \u0435\u0433\u043e \u0441\u043e\u0441\u0435\u0434\u0435\u0439 \u0438 \u0440\u0435\u0431\u0440\u0430 graphData.links.forEach((link) =&gt; {   if (typeof link.source === 'undefined' || typeof link.target === 'undefined')     return   const a = graphData.nodes[link.source as number]   const b = graphData.nodes[link.target as number]    if (!a || !b) return   \/\/ \u0421\u043e\u0441\u0435\u0434\u0438 \u0443\u0437\u043b\u0430   !a.neighbors &amp;&amp; (a.neighbors = [])   !b.neighbors &amp;&amp; (b.neighbors = [])   a.neighbors.push(b)   b.neighbors.push(a)    \/\/ \u0420\u0435\u0431\u0440\u0430 \u0443\u0437\u043b\u0430   !a.links &amp;&amp; (a.links = [])   !b.links &amp;&amp; (b.links = [])   a.links.push(link)   b.links.push(link) })  function Hover() {   \/\/ \u0423\u0437\u043b\u044b \u0432 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0438 hover   const [hoverNodes, setHoverNodes] = useState&lt;(NodeObject | null)[]&gt;([])   \/\/ \u0420\u0435\u0431\u0440\u0430 \u0432 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0438 hover   const [hoverLinks, setHoverLinks] = useState&lt;(LinkObject | null)[]&gt;([])   \/\/ \u0412\u044b\u0434\u0435\u043b\u0435\u043d\u0438\u0435 \u0440\u0435\u0431\u0435\u0440 \u0443\u0437\u043b\u0430   const [links, setLinks] = useState(false)   \/\/ \u0412\u044b\u0434\u0435\u043b\u0435\u043d\u0438\u0435 \u0441\u043e\u0441\u0435\u0434\u0435\u0438\u0306 \u0443\u0437\u043b\u0430   const [neighbors, setNeighbors] = useState(false)   \/\/ \u0412\u044b\u0434\u0435\u043b\u0435\u043d\u0438\u0435 \u0438\u0441\u0442\u043e\u0447\u043d\u0438\u043a\u0430 \u0438 \u0446\u0435\u043b\u0438 \u0440\u0435\u0431\u0440\u0430   const [nodes, setNodes] = useState(false)    const { nodeColor, activeNodeColor } = defaultColors    return (     &lt;Flex flexDirection='column' gap={12}&gt;       &lt;h3&gt;\u0423\u0437\u0435\u043b \u0432 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0438 hover&lt;\/h3&gt;       &lt;Flex gap='$4' flexDirection='column'&gt;         &lt;fieldset&gt;           &lt;legend&gt;\u0412\u0435\u0440\u0448\u0438\u043d\u0430&lt;\/legend&gt;           &lt;Flex flexDirection='column' gap={8}&gt;             &lt;label&gt;               &lt;input                 type='checkbox'                 checked={links}                 onChange={(e) =&gt; setLinks(e.target.checked)}               \/&gt;{' '}               \u0420\u0435\u0431\u0440\u0430             &lt;\/label&gt;             &lt;label&gt;               &lt;input                 type='checkbox'                 checked={neighbors}                 onChange={(e) =&gt; setNeighbors(e.target.checked)}               \/&gt;{' '}               \u0421\u043e\u0441\u0435\u0434\u0438             &lt;\/label&gt;           &lt;\/Flex&gt;         &lt;\/fieldset&gt;         &lt;fieldset&gt;           &lt;legend&gt;\u0420\u0435\u0431\u0440\u043e&lt;\/legend&gt;           &lt;label&gt;             &lt;input               type='checkbox'               checked={nodes}               onChange={(e) =&gt; setNodes(e.target.checked)}             \/&gt;{' '}             \u0418\u0441\u0442\u043e\u0447\u043d\u0438\u043a \u0438 \u0446\u0435\u043b\u044c           &lt;\/label&gt;         &lt;\/fieldset&gt;       &lt;\/Flex&gt;        &lt;Flex width={768} height={480} border='1px dashed rgba(0,0,0,0.25)'&gt;         &lt;ForceGraph           width={768}           height={480}           graphData={graphData}           onNodeHover={(node) =&gt; {             const newHoverNodes = [node]             const newHoverLinks: LinkObject[] = []             if (node) {               \/\/ \u0412\u044b\u0434\u0435\u043b\u0435\u043d\u0438\u0435 \u0440\u0435\u0431\u0435\u0440 \u0443\u0437\u043b\u0430               if (links) {                 newHoverLinks.push(...(node.links as LinkObject[]))               }               \/\/ \u0412\u044b\u0434\u0435\u043b\u0435\u043d\u0438\u0435 \u0441\u043e\u0441\u0435\u0434\u0435\u0439 \u0443\u0437\u043b\u0430               if (neighbors) {                 newHoverNodes.push(...(node.neighbors as NodeObject[]))               }             }             setHoverLinks(newHoverLinks)             setHoverNodes(newHoverNodes)           }}           onLinkHover={(link) =&gt; {             const newHoverLinks = [link]             const newHoverNodes: NodeObject[] = []             if (link) {               \/\/ \u0412\u044b\u0434\u0435\u043b\u0435\u043d\u0438\u0435 \u0443\u0437\u043b\u043e\u0432 \u0440\u0435\u0431\u0440\u0430               if (nodes) {                 newHoverNodes.push(                   link.source as NodeObject,                   link.target as NodeObject,                 )               }             }             setHoverLinks(newHoverLinks)             setHoverNodes(newHoverNodes)           }}           nodeColor={(node) =&gt;             hoverNodes.includes(node) ? activeNodeColor : nodeColor           }           linkColor={(link) =&gt;             hoverLinks.includes(link) ? activeNodeColor : nodeColor           }           linkDirectionalArrowColor={(link) =&gt;             hoverLinks.includes(link) ? activeNodeColor : nodeColor           }         \/&gt;       &lt;\/Flex&gt;     &lt;\/Flex&gt;   ) }  export default Hover<\/code><\/pre>\n<p> <\/p>\n<h3 id=\"uzel-s-podpisyu-i-tultipom\">\u0423\u0437\u0435\u043b \u0441 \u043f\u043e\u0434\u043f\u0438\u0441\u044c\u044e \u0438 \u0442\u0443\u043b\u0442\u0438\u043f\u043e\u043c<\/h3>\n<p> <\/p>\n<p>\u0427\u0442\u043e \u0435\u0441\u043b\u0438 \u0432 \u0434\u043e\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u0435 \u043a \u043f\u043e\u0434\u043f\u0438\u0441\u0438 \u043c\u044b \u0445\u043e\u0442\u0438\u043c \u0440\u0435\u043d\u0434\u0435\u0440\u0438\u0442\u044c \u0441\u043e\u0431\u0441\u0442\u0432\u0435\u043d\u043d\u044b\u0439 \u0442\u0443\u043b\u0442\u0438\u043f \u043f\u0440\u0438 \u043d\u0430\u0432\u0435\u0434\u0435\u043d\u0438\u0438 \u043d\u0430 \u0443\u0437\u0435\u043b? \u0414\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u043d\u0430\u043c \u043f\u043e\u0442\u0440\u0435\u0431\u0443\u0435\u0442\u0441\u044f \u0441\u043f\u0435\u0446\u0438\u0430\u043b\u044c\u043d\u0430\u044f \u0444\u0443\u043d\u043a\u0446\u0438\u044f. \u041e\u043f\u0440\u0435\u0434\u0435\u043b\u0438\u043c \u0435\u0435 \u0432 <code>Graph\/utils.ts<\/code>:<\/p>\n<p> <\/p>\n<pre><code class=\"javascript\">export type DrawNodeTooltipProps = {   \/\/ \u0423\u0437\u0435\u043b   node: NodeObject   \/\/ \u041a\u043e\u043d\u0442\u0435\u043a\u0441\u0442 \u0440\u0438\u0441\u043e\u0432\u0430\u043d\u0438\u044f   ctx: CanvasRenderingContext2D   \/\/ \u041f\u043e\u0434\u0441\u043a\u0430\u0437\u043a\u0430   tooltip: string   \/\/ \u0413\u043b\u043e\u0431\u0430\u043b\u044c\u043d\u044b\u0438\u0306 \u043c\u0430\u0441\u0448\u0442\u0430\u0431   globalScale?: number   \/\/ \u0420\u0430\u0437\u043c\u0435\u0440 \u0448\u0440\u0438\u0444\u0442\u0430   fontSize?: number   \/\/ \u041e\u0442\u0441\u0442\u0443\u043f \u043e\u0442 \u0443\u0437\u043b\u0430   offset?: number   \/\/ \u0413\u043e\u0440\u0438\u0437\u043e\u043d\u0442\u0430\u043b\u044c\u043d\u044b\u0438\u0306 \u043e\u0442\u0441\u0442\u0443\u043f   horizontalPadding?: number   \/\/ \u0412\u0435\u0440\u0442\u0438\u043a\u0430\u043b\u044c\u043d\u044b\u0438\u0306 \u043e\u0442\u0441\u0442\u0443\u043f   verticalPadding?: number }  export const drawNodeTooltip = ({   node,   ctx,   tooltip,   globalScale = 1,   fontSize = 5,   offset = 7,   horizontalPadding = 8,   verticalPadding = 6, }: DrawNodeTooltipProps) =&gt; {   const { tooltipColor, labelColor } = defaultColors    const nodeX = node.x || 0   const nodeY = node.y || 0   const nodeSize = Number(node.size) || defaultNodeSize    \/\/ \u041d\u0430\u0441\u0442\u0440\u0430\u0438\u0432\u0430\u0435\u043c \u0442\u0435\u043a\u0441\u0442   const _fontSize = fontSize \/ globalScale   ctx.font = `${_fontSize}px sans-serif`   ctx.textAlign = 'center'   ctx.textBaseline = 'middle'    \/\/ \u0420\u0438\u0441\u0443\u0435\u043c \u043f\u0440\u044f\u043c\u043e\u0443\u0433\u043e\u043b\u044c\u043d\u0438\u043a   const textWidth = ctx.measureText(tooltip).width   const tooltipContainerColor = node.labelColor || labelColor   ctx.fillStyle = tooltipContainerColor   ctx.fillRect(     nodeX - textWidth \/ 2 - horizontalPadding \/ 2,     nodeY - nodeSize - offset - verticalPadding \/ 2 - fontSize \/ 2,     textWidth + horizontalPadding,     fontSize + verticalPadding,   )    \/\/ \u0420\u0438\u0441\u0443\u0435\u043c \u0442\u0435\u043a\u0441\u0442   const _tooltipColor = node.tooltipColor || tooltipColor   ctx.fillStyle = _tooltipColor   ctx.fillText(tooltip, nodeX, nodeY - nodeSize - offset) }<\/code><\/pre>\n<p> <\/p>\n<p>\u041f\u0440\u0438\u043c\u0435\u043d\u044f\u0435\u043c \u0435\u0435 \u0432 \u043f\u0440\u043e\u043f\u0435 <code>nodeCanvasObject<\/code>:<\/p>\n<p> <\/p>\n<pre><code class=\"javascript\">\/\/ Graph\/NodeWithLabelAndTooltip.tsx import { useState } from 'react' import ForceGraph, { type NodeObject } from 'react-force-graph-2d' import { Flex } from '..\/Flex' import {   defaultColors,   drawNodeLabel,   drawNodePointerArea,   drawNodeTooltip,   generateGraphData, } from '.\/utils'  const graphData = generateGraphData()  function NodeWithLabelAndTooltip() {   \/\/ \u0423\u0437\u0435\u043b \u0432 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0438 hover   const [hoverNode, setHoverNode] = useState&lt;NodeObject | null&gt;(null)    const { nodeColor, activeNodeColor } = defaultColors    return (     &lt;Flex flexDirection='column' gap={12}&gt;       &lt;h3&gt;\u0423\u0437\u0435\u043b \u0441 \u043f\u043e\u0434\u043f\u0438\u0441\u044c\u044e \u0438 \u0442\u0443\u043b\u0442\u0438\u043f\u043e\u043c&lt;\/h3&gt;       &lt;Flex width={768} height={480} border='1px dashed rgba(0,0,0,0.25)'&gt;         &lt;ForceGraph           width={768}           height={480}           graphData={graphData}           onNodeHover={(node) =&gt; {             setHoverNode(node)           }}           nodeCanvasObject={(node, ctx) =&gt; {             \/\/ \u0420\u0438\u0441\u0443\u0435\u043c \u043f\u043e\u0434\u043f\u0438\u0441\u044c             drawNodeLabel({               node,               ctx,               hoverNodes: [hoverNode],             })             \/\/ \u0415\u0441\u043b\u0438 \u0443\u0437\u0435\u043b \u043d\u0430\u0445\u043e\u0434\u0438\u0442\u0441\u044f \u0432 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0438 hover             if (node === hoverNode) {               \/\/ \u0420\u0438\u0441\u0443\u0435\u043c \u0442\u0443\u043b\u0442\u0438\u043f               drawNodeTooltip({                 node,                 ctx,                 tooltip: `\u041f\u043e\u0434\u0441\u043a\u0430\u0437\u043a\u0430 \u043a ${node.name}`,               })             }           }}           \/\/ \u0421\u043d\u0430\u0447\u0430\u043b\u0430 \u0440\u0438\u0441\u0443\u0435\u043c \u0434\u0435\u0444\u043e\u043b\u0442\u043d\u044b\u0439 \u0443\u0437\u0435\u043b, \u0437\u0430\u0442\u0435\u043c - \u043f\u043e\u0434\u043f\u0438\u0441\u044c \u0438 \u0442\u0443\u043b\u0442\u0438\u043f           \/\/ (\u0434\u043b\u044f \u0443\u0437\u043b\u0430, \u043d\u0430\u0445\u043e\u0434\u044f\u0449\u0435\u0433\u043e\u0441\u044f \u0432 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0438 hover)           nodeCanvasObjectMode={() =&gt; 'after'}           \/\/ \u0420\u0438\u0441\u0443\u0435\u043c \u043e\u0431\u043b\u0430\u0441\u0442\u044c \u0432\u044b\u0434\u0435\u043b\u0435\u043d\u0438\u044f\/\u043a\u043b\u0438\u043a\u0430           nodePointerAreaPaint={(node, color, ctx) =&gt;             drawNodePointerArea({ node, color, ctx })           }           \/\/ \u0426\u0432\u0435\u0442 \u0443\u0437\u043b\u0430 \u0437\u0430\u0432\u0438\u0441\u0438\u0442 \u043e\u0442 \u0435\u0433\u043e \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f           nodeColor={(node) =&gt;             node === hoverNode ? activeNodeColor : nodeColor           }           \/\/ \u041e\u0442\u043a\u043b\u044e\u0447\u0430\u0435\u043c \u0432\u0441\u0442\u0440\u043e\u0435\u043d\u043d\u044b\u0435 \u0442\u0443\u043b\u0442\u0438\u043f\u044b           nodeLabel='label'           linkLabel='label'         \/&gt;       &lt;\/Flex&gt;     &lt;\/Flex&gt;   ) }  export default NodeWithLabelAndTooltip<\/code><\/pre>\n<p> <\/p>\n<h3 id=\"vydelenie-uzlov\">\u0412\u044b\u0434\u0435\u043b\u0435\u043d\u0438\u0435 \u0443\u0437\u043b\u043e\u0432<\/h3>\n<p> <\/p>\n<p>\u0420\u0435\u0430\u043b\u0438\u0437\u0443\u0435\u043c \u0433\u0440\u0430\u0444 \u0441 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c \u0432\u044b\u0431\u043e\u0440\u0430 \u0443\u0437\u043b\u043e\u0432. \u041c\u044b \u0445\u043e\u0442\u0438\u043c, \u0447\u0442\u043e\u0431\u044b \u0432\u044b\u0431\u0440\u0430\u043d\u043d\u044b\u0435 \u0443\u0437\u043b\u044b \u0438 \u0438\u0445 \u043f\u043e\u0434\u043f\u0438\u0441\u0438 \u0432\u044b\u0434\u0435\u043b\u044f\u043b\u0438\u0441\u044c \u0446\u0432\u0435\u0442\u043e\u043c, \u0430 \u0442\u0430\u043a\u0436\u0435 \u0446\u0432\u0435\u0442\u043d\u044b\u043c \u043a\u043e\u043b\u044c\u0446\u043e\u043c \u0432\u043e\u043a\u0440\u0443\u0433 \u0443\u0437\u043b\u0430. \u0414\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u043d\u0430\u043c \u043f\u043e\u0442\u0440\u0435\u0431\u0443\u0435\u0442\u0441\u044f \u0441\u043f\u0435\u0446\u0438\u0430\u043b\u044c\u043d\u0430\u044f \u0444\u0443\u043d\u043a\u0446\u0438\u044f. \u041e\u043f\u0440\u0435\u0434\u0435\u043b\u0438\u043c \u0435\u0435 \u0432 <code>Graph\/utils.ts<\/code>:<\/p>\n<p> <\/p>\n<pre><code class=\"javascript\">export type DrawNodeRingProps = {   \/\/ \u0423\u0437\u0435\u043b   node: NodeObject   \/\/ \u041a\u043e\u043d\u0442\u0435\u043a\u0441\u0442 \u0440\u0438\u0441\u043e\u0432\u0430\u043d\u0438\u044f   ctx: CanvasRenderingContext2D   \/\/ \u041e\u0442\u0441\u0442\u0443\u043f \u043e\u0442 \u0443\u0437\u043b\u0430   offset?: number   \/\/ \u0428\u0438\u0440\u0438\u043d\u0430 \u043b\u0438\u043d\u0438\u0438   lineWidth?: number }  export const drawNodeRing = ({   node,   ctx,   offset = 5,   lineWidth = 1, }: DrawNodeRingProps) =&gt; {   const { activeNodeColor } = defaultColors   const nodeX = node.x || 0   const nodeY = node.y || 0   const nodeSize = Number(node.size) || defaultNodeSize   ctx.beginPath()   ctx.arc(nodeX, nodeY, nodeSize + offset, 0, 2 * Math.PI)   ctx.lineWidth = lineWidth   const ringColor = node.activeColor || activeNodeColor   ctx.strokeStyle = ringColor   ctx.stroke() }<\/code><\/pre>\n<p> <\/p>\n<p>\u041f\u0440\u0438\u043c\u0435\u043d\u044f\u0435\u043c \u0435\u0435 \u0432 \u043f\u0440\u043e\u043f\u0435 <code>nodeCanvasObject<\/code>:<\/p>\n<p> <\/p>\n<pre><code class=\"javascript\">\/\/ Graph\/Click.tsx import { useCallback, useState } from 'react' import ForceGraph, { type NodeObject } from 'react-force-graph-2d' import { Flex } from '..\/Flex' import { defaultColors, drawNodeRing, generateGraphData } from '.\/utils'  const graphData = generateGraphData()  function Click() {   \/\/ \u0412\u044b\u0434\u0435\u043b\u0435\u043d\u043d\u044b\u0435 \u0443\u0437\u043b\u044b   const [clickNodes, setClickNodes] = useState&lt;(NodeObject | null)[]&gt;([])   \/\/ \u0418\u043d\u0434\u0438\u043a\u0430\u0442\u043e\u0440 \u0432\u044b\u0434\u0435\u043b\u0435\u043d\u0438\u044f \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u0438\u0445 \u0443\u0437\u043b\u043e\u0432   const [multiple, setMultiple] = useState(false)    const handleNodeClick = useCallback(     (node: NodeObject) =&gt; {       if (!multiple) {         setClickNodes([node])         return       }       let newClickNodes = [...clickNodes]       if (newClickNodes.includes(node)) {         newClickNodes = newClickNodes.filter((n) =&gt; n !== node)       } else {         newClickNodes.push(node)       }       setClickNodes(newClickNodes)     },     [clickNodes, multiple],   )    const { nodeColor, activeNodeColor } = defaultColors    return (     &lt;Flex flexDirection='column' gap={12}&gt;       &lt;h3&gt;\u0412\u044b\u0434\u0435\u043b\u0435\u043d\u0438\u0435 \u0443\u0437\u043b\u043e\u0432&lt;\/h3&gt;       &lt;fieldset&gt;         &lt;legend&gt;\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438&lt;\/legend&gt;         &lt;label&gt;           &lt;input             type='checkbox'             checked={multiple}             onChange={(e) =&gt; setMultiple(e.target.checked)}           \/&gt;{' '}           \u0412\u044b\u0434\u0435\u043b\u0435\u043d\u0438\u0435 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u0438\u0445 \u0432\u0435\u0440\u0448\u0438\u043d         &lt;\/label&gt;       &lt;\/fieldset&gt;       &lt;Flex width={768} height={480} border='1px dashed rgba(0,0,0,0.25)'&gt;         &lt;ForceGraph           width={768}           height={480}           graphData={graphData}           onNodeClick={handleNodeClick}           nodeCanvasObject={(node, ctx) =&gt; drawNodeRing({ node, ctx })}           \/\/ \u0420\u0438\u0441\u0443\u0435\u043c \u043a\u043e\u043b\u044c\u0446\u043e \u0432\u043e\u043a\u0440\u0443\u0433 \u0432\u044b\u0434\u0435\u043b\u0435\u043d\u043d\u044b\u0445 \u0443\u0437\u043b\u043e\u0432           nodeCanvasObjectMode={(node) =&gt;             clickNodes.includes(node) ? 'before' : undefined           }           \/\/ \u041f\u0440\u0438 \u043a\u043b\u0438\u043a\u0435 \u043f\u043e \u0444\u043e\u043d\u0443 \u043e\u0447\u0438\u0449\u0430\u0435\u043c \u0432\u044b\u0434\u0435\u043b\u0435\u043d\u043d\u044b\u0435 \u0443\u0437\u043b\u044b           onBackgroundClick={() =&gt; {             setClickNodes([])           }}           nodeColor={(node) =&gt;             clickNodes.includes(node) ? activeNodeColor : nodeColor           }           \/\/ \u041e\u0442\u043a\u043b\u044e\u0447\u0430\u0435\u043c \u043f\u0435\u0440\u0435\u0442\u0430\u0441\u043a\u0438\u0432\u0430\u043d\u0438\u0435 \u0443\u0437\u043b\u043e\u0432           enableNodeDrag={false}         \/&gt;       &lt;\/Flex&gt;     &lt;\/Flex&gt;   ) }  export default Click<\/code><\/pre>\n<p> <\/p>\n<h3 id=\"vlozhennye-uzly\">\u0412\u043b\u043e\u0436\u0435\u043d\u043d\u044b\u0435 \u0443\u0437\u043b\u044b<\/h3>\n<p> <\/p>\n<p>\u041c\u044b \u0445\u043e\u0442\u0438\u043c, \u0447\u0442\u043e\u0431\u044b \u0443\u0437\u043b\u044b, \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u0449\u0438\u0435 \u0434\u0440\u0443\u0433\u0438\u0435 \u0443\u0437\u043b\u044b, \u043a\u0430\u043a-\u0442\u043e \u043e\u0431\u043e\u0437\u043d\u0430\u0447\u0430\u043b\u0438\u0441\u044c. \u041d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u0432 \u0437\u0430\u043a\u0440\u044b\u0442\u043e\u043c \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0438 \u043e\u043d\u0438 \u043c\u043e\u0433\u0443\u0442 \u043e\u0431\u043e\u0437\u043d\u0430\u0447\u0430\u0442\u044c\u0441\u044f \u0438\u043a\u043e\u043d\u043a\u043e\u0439 \u043f\u043b\u044e\u0441\u0430, \u0430 \u0432 \u0440\u0430\u0441\u043a\u0440\u044b\u0442\u043e\u043c \u2014 \u0438\u043a\u043e\u043d\u043a\u043e\u0439 \u043c\u0438\u043d\u0443\u0441\u0430.<\/p>\n<p> <\/p>\n<pre><code class=\"javascript\">\/\/ Graph\/Children.tsx import { useCallback, useEffect, useRef, useState } from 'react' import ForceGraph, {   type LinkObject,   type NodeObject, } from 'react-force-graph-2d' import { Flex } from '..\/Flex' import { drawNodeImage } from '.\/utils'  type NodeObjectWithChildren = NodeObject &amp; {   children?: NodeObject[] }  const initialGraphData: {   nodes: NodeObjectWithChildren[]   links: LinkObject[] } = {   nodes: [     {       id: 0,       name: 'node 0',     },     {       id: 1,       name: 'node 1',       children: [         {           id: 5,           name: 'node 5',         },         {           id: 6,           name: 'node 6',         },         {           id: 7,           name: 'node 7',         },       ],     },     {       id: 2,       name: 'node 2',     },     {       id: 3,       name: 'node 3',       children: [         {           id: 8,           name: 'node 8',         },         {           id: 9,           name: 'node 9',         },       ],     },     {       id: 4,       name: 'node 4',     },   ],   links: [     {       source: 1,       target: 0,       name: 'link 1',     },     {       source: 2,       target: 0,       name: 'link 2',     },     {       source: 3,       target: 1,       name: 'link 3',     },     {       source: 4,       target: 3,       name: 'link 4',     },   ], }  function Children() {   const spanRef = useRef&lt;HTMLSpanElement&gt;(null)   const [images, setImages] = useState&lt;HTMLImageElement[]&gt;([])    const [graphData, setGraphData] = useState(initialGraphData)   \/\/ \u0420\u0430\u0441\u043a\u0440\u044b\u0442\u044b\u0435 \u0443\u0437\u043b\u044b   const [expandedNodes, setExpandedNodes] = useState&lt;NodeObject[]&gt;([])    useEffect(() =&gt; {     if (!spanRef.current) return     const images = [...spanRef.current.querySelectorAll('img')]     setImages(images)   }, [])    const handleNodeClick = useCallback(     (node: NodeObject) =&gt; {       if (!node.children) return       \/\/ \u041e\u0442\u0441\u043b\u0435\u0436\u0438\u0432\u0430\u0435\u043c \u0440\u0430\u0441\u043a\u0440\u044b\u0442\u044b\u0435 \u0443\u0437\u043b\u044b       let newExpandedNodes = [...expandedNodes]       if (!expandedNodes.includes(node)) {         newExpandedNodes.push(node)       } else {         newExpandedNodes = newExpandedNodes.filter((n) =&gt; n !== node)       }       setExpandedNodes(newExpandedNodes)       \/\/ \u0414\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u043c\/\u0443\u0434\u0430\u043b\u044f\u0435\u043c \u0432\u043b\u043e\u0436\u0435\u043d\u043d\u044b\u0435 \u0432\u0435\u0440\u0448\u0438\u043d\u044b \u0438 \u0440\u0435\u0431\u0440\u0430       let nodes = [...graphData.nodes]       let links = [...graphData.links]       const children: NodeObjectWithChildren[] = node.children       const childIds = children.map((n) =&gt; n.id)       if (!expandedNodes.includes(node)) {         nodes.push(...children)         const newLinks = children.map((n, i) =&gt; ({           id: links.length + i + 1,           source: n.id,           target: node.id,         }))         links.push(...newLinks)       } else {         nodes = nodes.filter((n) =&gt; !childIds.includes(n.id))         links = links.filter((l) =&gt; {           const sourceId = typeof l.source === 'object' ? l.source.id : l.source           return !childIds.includes(sourceId)         })       }       setGraphData({ nodes, links })     },     [expandedNodes, graphData],   )    return (     &lt;Flex flexDirection='column' gap={12}&gt;       {\/* \u041d\u0435\u0431\u043e\u043b\u044c\u0448\u043e\u0439 \u0445\u0430\u043a *\/}       &lt;span         ref={spanRef}         style={{           display: 'none',         }}       &gt;         {\/* \u0418\u0437\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u044f \u043b\u0435\u0436\u0430\u0442 \u0432 \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u0438 `public\/graph` *\/}         &lt;img src='\/graph\/plus.svg' alt='' \/&gt;         &lt;img src='\/graph\/minus.svg' alt='' \/&gt;       &lt;\/span&gt;       &lt;Flex width={768} height={480} border='1px dashed rgba(0,0,0,0.25)'&gt;         &lt;ForceGraph           width={768}           height={480}           graphData={graphData}           nodeRelSize={6}           nodeCanvasObject={(node, ctx) =&gt; {             \/\/ \u041d\u0430\u0441 \u0438\u043d\u0442\u0435\u0440\u0435\u0441\u0443\u044e\u0442 \u0442\u043e\u043b\u044c\u043a\u043e \u0443\u0437\u043b\u044b \u0441 \u043f\u043e\u0442\u043e\u043c\u043a\u0430\u043c\u0438             if (node.children) {               \/\/ images[1] - \u0438\u043a\u043e\u043d\u043a\u0430 \u043c\u0438\u043d\u0443\u0441\u0430, images[0] - \u0438\u043a\u043e\u043d\u043a\u0430 \u043f\u043b\u044e\u0441\u0430               const image = expandedNodes.includes(node) ? images[1] : images[0]                drawNodeImage({ node, ctx, image })             }           }}           \/\/ \u0421\u043d\u0430\u0447\u0430\u043b\u0430 \u0440\u0438\u0441\u0443\u0435\u043c \u0434\u0435\u0444\u043e\u043b\u0442\u043d\u044b\u0439 \u0443\u0437\u0435\u043b, \u0437\u0430\u0442\u0435\u043c - \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u044e\u0449\u0443\u044e \u0438\u043a\u043e\u043d\u043a\u0443           nodeCanvasObjectMode={() =&gt; 'after'}           onNodeClick={handleNodeClick}         \/&gt;       &lt;\/Flex&gt;     &lt;\/Flex&gt;   ) }  export default Children<\/code><\/pre>\n<p> <\/p>\n<h3 id=\"panel-upravleniya\">\u041f\u0430\u043d\u0435\u043b\u044c \u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u044f<\/h3>\n<p> <\/p>\n<p>\u0420\u0435\u0430\u043b\u0438\u0437\u0443\u0435\u043c \u0433\u0440\u0430\u0444 \u0441 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c\u044e \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u043d\u043e\u0433\u043e \u043c\u0430\u0441\u0448\u0442\u0430\u0431\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u0438 \u0446\u0435\u043d\u0442\u0440\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f.<\/p>\n<p> <\/p>\n<pre><code class=\"javascript\">\/\/ Graph\/Toolkit.tsx import { useEffect, useRef, useState } from 'react' import ForceGraph, {   type ForceGraphMethods,   type LinkObject,   type NodeObject, } from 'react-force-graph-2d' import { Flex } from '..\/Flex' import { generateGraphData } from '.\/utils'  const graphData = generateGraphData()  type NodeType = (typeof graphData.nodes)[number] type LinkType = (typeof graphData.links)[number]  function Toolkit() {   \/\/ \u0422\u0435\u043a\u0443\u0449\u0438\u0439 \u043c\u0430\u0441\u0448\u0442\u0430\u0431   const [currentZoom, setCurrentZoom] = useState(1)    const graphRef = useRef&lt;     | ForceGraphMethods&lt;NodeObject&lt;NodeType&gt;, LinkObject&lt;NodeType, LinkType&gt;&gt;     | undefined   &gt;()    \/\/ \u042d\u0444\u0444\u0435\u043a\u0442 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f \u043c\u0430\u0441\u0448\u0442\u0430\u0431\u0430   useEffect(() =&gt; {     if (!graphRef.current) return     graphRef.current.zoom(currentZoom)   }, [currentZoom])    return (     &lt;Flex flexDirection='column' gap={12}&gt;       &lt;h3&gt;\u041f\u0430\u043d\u0435\u043b\u044c \u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u044f&lt;\/h3&gt;        &lt;Flex         width={768}         height={480}         border='1px dashed rgba(0,0,0,0.25)'         position='relative'       &gt;         &lt;Flex           position='absolute'           top='50%'           transform='translateY(-50%)'           right={12}           zIndex={1}           flexDirection='column'           gap={8}           backgroundColor='gray'           padding={8}         &gt;           &lt;button             onClick={() =&gt; setCurrentZoom((currentZoom) =&gt; currentZoom + 0.5)}           &gt;             \u0423\u0432\u0435\u043b\u0438\u0447\u0438\u0442\u044c &lt;br \/&gt;             \u043c\u0430\u0441\u0448\u0442\u0430\u0431           &lt;\/button&gt;           &lt;button             onClick={() =&gt; setCurrentZoom((currentZoom) =&gt; currentZoom - 0.5)}           &gt;             \u0423\u043c\u0435\u043d\u044c\u0448\u0438\u0442\u044c &lt;br \/&gt;             \u043c\u0430\u0441\u0448\u0442\u0430\u0431           &lt;\/button&gt;           &lt;button onClick={() =&gt; graphRef.current?.zoomToFit()}&gt;             \u0423\u0432\u0435\u043b\u0438\u0447\u0438\u0442\u044c &lt;br \/&gt;             \u0434\u043e \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440\u0430           &lt;\/button&gt;           &lt;button onClick={() =&gt; graphRef.current?.centerAt(0, 0)}&gt;             \u0412\u044b\u0440\u043e\u0432\u043d\u044f\u0442\u044c &lt;br \/&gt;             \u043f\u043e \u0446\u0435\u043d\u0442\u0440\u0443           &lt;\/button&gt;         &lt;\/Flex&gt;         &lt;ForceGraph           ref={graphRef}           width={768}           height={480}           graphData={graphData}           \/\/ \u041f\u043e\u0441\u043b\u0435 \u043d\u0430\u0447\u0430\u043b\u044c\u043d\u043e\u0433\u043e \u043c\u0430\u0441\u0448\u0442\u0430\u0431\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f (\u043f\u043e\u0441\u043b\u0435 \u043f\u0435\u0440\u0432\u043e\u0433\u043e \u0440\u0435\u043d\u0434\u0435\u0440\u0438\u043d\u0433\u0430),           \/\/ \u0430 \u0442\u0430\u043a\u0436\u0435 \u043f\u043e\u0441\u043b\u0435 \u043c\u0430\u0441\u0448\u0442\u0430\u0431\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u0434\u043e \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440\u0430,           \/\/ \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u043e\u0431\u043d\u043e\u0432\u0438\u0442\u044c \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435 \u0442\u0435\u043a\u0443\u0449\u0435\u0433\u043e \u043c\u0430\u0441\u0448\u0442\u0430\u0431\u0430           onZoomEnd={({ k }) =&gt; {             if (k !== currentZoom) {               setCurrentZoom(k)             }           }}           \/\/ \u041e\u0442\u043a\u043b\u044e\u0447\u0430\u0435\u043c \u043c\u0430\u0441\u0448\u0442\u0430\u0431\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u043f\u0440\u043e\u043a\u0440\u0443\u0442\u043a\u043e\u0439           enableZoomInteraction={false}         \/&gt;       &lt;\/Flex&gt;     &lt;\/Flex&gt;   ) }  export default Toolkit<\/code><\/pre>\n<p> <\/p>\n<h3 id=\"poisk\">\u041f\u043e\u0438\u0441\u043a<\/h3>\n<p> <\/p>\n<p>\u0420\u0435\u0430\u043b\u0438\u0437\u0443\u0435\u043c \u0433\u0440\u0430\u0444 \u0441 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c\u044e \u0444\u0438\u043b\u044c\u0442\u0440\u0430\u0446\u0438\u0438 \u0443\u0437\u043b\u043e\u0432 \u0438 \u0440\u0435\u0431\u0435\u0440 \u043f\u043e \u043d\u0430\u0437\u0432\u0430\u043d\u0438\u044f\u043c \u0443\u0437\u043b\u043e\u0432.<\/p>\n<p> <\/p>\n<pre><code class=\"javascript\">\/\/ Graph\/Search.tsx import { useEffect, useMemo, useState } from 'react' import ForceGraph from 'react-force-graph-2d' import { Flex } from '..\/Flex' import { drawNodeLabel, drawNodePointerArea, generateGraphData } from '.\/utils'  const { nodes, links } = generateGraphData(25)  const Search = () =&gt; {   \/\/ \u041e\u0442\u0444\u0438\u043b\u044c\u0442\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0435 \u0443\u0437\u043b\u044b   const [filteredNodes, setFilteredNodes] = useState(nodes)   \/\/ \u041e\u0442\u0444\u0438\u043b\u044c\u0442\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0435 \u0440\u0435\u0431\u0440\u0430   const [filteredLinks, setFilteredLinks] = useState(links)   \/\/ \u0421\u0442\u0440\u043e\u043a\u0430 \u043f\u043e\u0438\u0441\u043a\u0430   const [searchQuery, setSearchQuery] = useState('')   \/\/ \u0417\u043d\u0430\u0447\u0435\u043d\u0438\u0435 \u0438\u043d\u043f\u0443\u0442\u0430   const [value, setValue] = useState('')    const onSubmit = (e: React.FormEvent&lt;HTMLFormElement&gt;) =&gt; {     e.preventDefault()     const query = value.trim().toLowerCase()     setSearchQuery(query)   }    useEffect(() =&gt; {     if (value === '') {       setSearchQuery('')     }   }, [value])    useEffect(() =&gt; {     if (!searchQuery) {       setFilteredLinks(links)       setFilteredNodes(nodes)       return     }      \/\/ \u0424\u0438\u043b\u044c\u0442\u0440\u0443\u0435\u043c \u0443\u0437\u043b\u044b     const _nodes = nodes.filter((n) =&gt; {       const label = n.name as string       return label.toLowerCase().includes(searchQuery)     })     const nodeIds = _nodes.map((n) =&gt; String(n.id))     \/\/ \u0424\u0438\u043b\u044c\u0442\u0440\u0443\u0435\u043c \u0440\u0435\u0431\u0440\u0430     const _links = links.filter((l) =&gt; {       const sourceId = typeof l.source === 'object' ? l.source.id : l.source       const targetId = typeof l.target === 'object' ? l.target.id : l.target        return (         nodeIds.includes(String(sourceId)) &amp;&amp; nodeIds.includes(String(targetId))       )     })     setFilteredLinks(_links)     setFilteredNodes(_nodes)   }, [searchQuery])    const graphData = useMemo(     () =&gt; ({       nodes: filteredNodes,       links: filteredLinks,     }),     [filteredNodes, filteredLinks],   )    return (     &lt;Flex flexDirection='column' gap={12}&gt;       &lt;h3&gt;\u041f\u043e\u0438\u0441\u043a&lt;\/h3&gt;        &lt;form         onSubmit={onSubmit}         style={{           display: 'flex',           alignSelf: 'center',         }}       &gt;         &lt;input           value={value}           onChange={(e) =&gt; setValue(e.target.value)}           placeholder='\u041f\u043e\u0438\u0441\u043a...'         \/&gt;{' '}         &lt;button&gt;\u041f\u043e\u0438\u0441\u043a&lt;\/button&gt;       &lt;\/form&gt;       &lt;Flex width={768} height={768} border='1px dashed rgba(0,0,0,0.25)'&gt;         &lt;ForceGraph           width={768}           height={768}           graphData={graphData}           nodeCanvasObject={(node, ctx) =&gt;             drawNodeLabel({               node,               ctx,             })           }           nodeCanvasObjectMode={() =&gt; 'after'}           nodePointerAreaPaint={(node, color, ctx) =&gt;             drawNodePointerArea({ node, color, ctx })           }           \/\/ \u041e\u0442\u043a\u043b\u044e\u0447\u0430\u0435\u043c \u0442\u0443\u043b\u0442\u0438\u043f\u044b           nodeLabel='label'           linkLabel='label'         \/&gt;       &lt;\/Flex&gt;     &lt;\/Flex&gt;   ) }  export default Search<\/code><\/pre>\n<p> <\/p>\n<h2 id=\"-zaklyuchenie\">\u276f \u0417\u0430\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435<\/h2>\n<p> <\/p>\n<p>\u041c\u044b \u0441 \u0432\u0430\u043c\u0438 \u0440\u0430\u0441\u0441\u043c\u043e\u0442\u0440\u0435\u043b\u0438 \u043d\u0435 \u0432\u0441\u0435 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u0438, \u043f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u043c\u044b\u0435 <a href=\"https:\/\/github.com\/vasturiano\/react-force-graph\">react-force-graph-2d<\/a>, \u043d\u043e \u0434\u0443\u043c\u0430\u044e, \u0432\u044b \u043f\u043e\u043b\u0443\u0447\u0438\u043b\u0438 \u0434\u043e\u0432\u043e\u043b\u044c\u043d\u043e \u043f\u043e\u043b\u043d\u043e\u0435 \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u043e \u0442\u043e\u043c, \u0447\u0442\u043e \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u0434\u0435\u043b\u0430\u0442\u044c \u044d\u0442\u0430 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0430. \u041e\u0431\u0440\u0430\u0442\u0438\u0442\u0435 \u0432\u043d\u0438\u043c\u0430\u043d\u0438\u0435, \u0447\u0442\u043e <code>react-force-graph-2d<\/code> \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u0447\u0430\u0441\u0442\u044c\u044e \u0431\u043e\u043b\u0435\u0435 \u0448\u0438\u0440\u043e\u043a\u043e\u0433\u043e \u043d\u0430\u0431\u043e\u0440\u0430 \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442\u043e\u0432 \u0434\u043b\u044f \u0440\u0438\u0441\u043e\u0432\u0430\u043d\u0438\u044f \u0433\u0440\u0430\u0444\u043e\u0432, \u0432\u043a\u043b\u044e\u0447\u0430\u044f \u0442\u0440\u0435\u0445\u043c\u0435\u0440\u043d\u044b\u0435 \u0438 VR\/AR \u0432\u0430\u0440\u0438\u0430\u043d\u0442\u044b.<\/p>\n<p> <\/p>\n<p>\u0414\u0435\u043c\u043e \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f:<\/p>\n<p> <\/p>\n<div class=\"oembed\"><a href=\"https:\/\/react-graph.netlify.app\/\">https:\/\/react-graph.netlify.app\/<\/a><\/div>\n<p> <\/p>\n<p>\u041b\u043e\u043a\u0430\u043b\u044c\u043d\u044b\u0439 \u0437\u0430\u043f\u0443\u0441\u043a \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f:<\/p>\n<p> <\/p>\n<pre><code class=\"bash\">git clone https:\/\/github.com\/harryheman\/react-graph.git cd react-graph npm i npm run dev<\/code><\/pre>\n<p> <\/p>\n<p>Happy coding!<\/p>\n<p> <\/p>\n<hr\/>\n<p> <\/p>\n<blockquote><p><a href=\"https:\/\/t.me\/timewebru\"><b>\u041d\u043e\u0432\u043e\u0441\u0442\u0438, \u043e\u0431\u0437\u043e\u0440\u044b \u043f\u0440\u043e\u0434\u0443\u043a\u0442\u043e\u0432 \u0438 \u043a\u043e\u043d\u043a\u0443\u0440\u0441\u044b \u043e\u0442 \u043a\u043e\u043c\u0430\u043d\u0434\u044b Timeweb.Cloud \u2014 \u0432 \u043d\u0430\u0448\u0435\u043c Telegram-\u043a\u0430\u043d\u0430\u043b\u0435<\/b><\/a> <b>\u21a9<\/b><\/p><\/blockquote>\n<p><a href=\"https:\/\/timeweb.cloud\/?utm_source=habr&amp;utm_medium=banner&amp;utm_campaign=promo\"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/webt\/6r\/9j\/sr\/6r9jsrljpzsgcfyj1jjupubij5e.png\" sizes=\"(max-width: 780px) 100vw, 50vw\" srcset=\"https:\/\/habrastorage.org\/r\/w780\/webt\/6r\/9j\/sr\/6r9jsrljpzsgcfyj1jjupubij5e.png 780w,&#10;       https:\/\/habrastorage.org\/r\/w1560\/webt\/6r\/9j\/sr\/6r9jsrljpzsgcfyj1jjupubij5e.png 781w\" loading=\"lazy\" decode=\"async\"\/><\/a><\/p>\n<\/div>\n<\/div>\n<\/div>\n<p><!----><!----><\/div>\n<p><!----><!----><br \/> \u0441\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 \u043e\u0440\u0438\u0433\u0438\u043d\u0430\u043b \u0441\u0442\u0430\u0442\u044c\u0438 <a href=\"https:\/\/habr.com\/ru\/articles\/917064\/\"> https:\/\/habr.com\/ru\/articles\/917064\/<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<div><!--[--><!--]--><\/div>\n<div id=\"post-content-body\">\n<div>\n<div class=\"article-formatted-body article-formatted-body article-formatted-body_version-1\">\n<div xmlns=\"http:\/\/www.w3.org\/1999\/xhtml\"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/webt\/ma\/po\/lv\/mapolvqq4uunxfqoaviv3g9km9y.jpeg\" sizes=\"(max-width: 780px) 100vw, 50vw\" srcset=\"https:\/\/habrastorage.org\/r\/w780\/webt\/ma\/po\/lv\/mapolvqq4uunxfqoaviv3g9km9y.jpeg 780w,&#10;       https:\/\/habrastorage.org\/r\/w1560\/webt\/ma\/po\/lv\/mapolvqq4uunxfqoaviv3g9km9y.jpeg 781w\" loading=\"lazy\" decode=\"async\"\/> <\/p>\n<p> <\/p>\n<p> <\/p>\n<p>\u041f\u0440\u0438\u0432\u0435\u0442, \u0434\u0440\u0443\u0437\u044c\u044f!<\/p>\n<p> <\/p>\n<p>\u0412 \u044d\u0442\u043e\u0439 \u0441\u0435\u0440\u0438\u0438 \u0441\u0442\u0430\u0442\u0435\u0439 \u044f \u0434\u0435\u043b\u044e\u0441\u044c \u0441 \u0432\u0430\u043c\u0438 \u0441\u0432\u043e\u0438\u043c \u043e\u043f\u044b\u0442\u043e\u043c \u0440\u0435\u0448\u0435\u043d\u0438\u044f \u0440\u0430\u0437\u043b\u0438\u0447\u043d\u044b\u0445 \u0437\u0430\u0434\u0430\u0447 \u0438\u0437 \u043e\u0431\u043b\u0430\u0441\u0442\u0438 \u0432\u0435\u0431-\u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u0438 \u043d\u0435 \u0442\u043e\u043b\u044c\u043a\u043e.<\/p>\n<p> <\/p>\n<p>\u0412 \u044d\u0442\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0435 \u043c\u044b \u0438\u0437\u0443\u0447\u0438\u043c \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0443 <a href=\"https:\/\/github.com\/vasturiano\/react-force-graph\">react-force-graph-2d<\/a> \u0434\u043b\u044f \u0440\u0438\u0441\u043e\u0432\u0430\u043d\u0438\u044f \u0434\u0432\u0443\u043c\u0435\u0440\u043d\u044b\u0445 \u0433\u0440\u0430\u0444\u043e\u0432.<\/p>\n<p> <\/p>\n<p>\u0414\u0435\u043c\u043e \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f:<\/p>\n<p> <\/p>\n<div class=\"oembed\"><a href=\"https:\/\/react-graph.netlify.app\/\">https:\/\/react-graph.netlify.app\/<\/a><\/div>\n<p> <\/p>\n<p>\u041b\u043e\u043a\u0430\u043b\u044c\u043d\u044b\u0439 \u0437\u0430\u043f\u0443\u0441\u043a \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f:<\/p>\n<p> <\/p>\n<pre><code class=\"bash\">git clone https:\/\/github.com\/harryheman\/react-graph.git cd react-graph npm i npm run dev<\/code><\/pre>\n<p> <\/p>\n<p>\u0418\u043d\u0442\u0435\u0440\u0435\u0441\u043d\u043e? \u0422\u043e\u0433\u0434\u0430 \u043f\u0440\u043e\u0448\u0443 \u043f\u043e\u0434 \u043a\u0430\u0442.<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[],"tags":[],"class_list":["post-465821","post","type-post","status-publish","format-standard","hentry"],"_links":{"self":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/465821","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=465821"}],"version-history":[{"count":0,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/465821\/revisions"}],"wp:attachment":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=465821"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=465821"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=465821"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}