nodalix 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,726 @@
1
+ # Nodalix
2
+
3
+ کتابخانهٔ React برای نمایش و تحلیل گراف‌های شبکه‌ای با **vis-network**. مناسب برای نمایش روابط بین موجودیت‌ها، جریان داده یا فرایند بین گره‌های اصلی و واسط، و نمایش اطلاعات یال‌ها (مقدار، زمان، متن تکمیلی و …) به‌صورت تعاملی.
4
+
5
+ **سازنده:** محمد صالحی
6
+
7
+ ---
8
+
9
+ ## فهرست
10
+
11
+ - [ویژگی‌ها](#ویژگی‌ها)
12
+ - [پیش‌نیازها](#پیش‌نیازها)
13
+ - [نصب](#نصب)
14
+ - [شروع سریع](#شروع-سریع)
15
+ - [ساختار داده](#ساختار-داده)
16
+ - [کامپوننت `Graph_Engine`](#کامپوننت-graph_engine)
17
+ - [پیکربندی داینامیک](#پیکربندی-داینامیک)
18
+ - [پیکربندی ابزارهای UI](#پیکربندی-ابزارهای-ui-گرید-جابه‌جایی-یال-زبان)
19
+ - [APIهای برنامه‌نویسی (Imperative)](#apiهای-برنامه‌نویسی-imperative)
20
+ - [ابزارهای داخلی UI](#ابزارهای-داخلی-ui)
21
+ - [منطق گراف و یال‌ها](#منطق-گراف-و-یال‌ها)
22
+ - [Exportها و ثابت‌ها](#exportها-و-ثابت‌ها)
23
+ - [ساخت و توسعه](#ساخت-و-توسعه)
24
+ - [نکات مهم](#نکات-مهم)
25
+
26
+ ---
27
+
28
+ ## ویژگی‌ها
29
+
30
+ - رندر گراف تعاملی (جابه‌جایی، زوم، انتخاب گره/یال)
31
+ - دو نوع گره: **main** (گره اصلی) و **sub** (گره واسط/میانی)
32
+ - نمایش اطلاعات یال روی گره‌های میانی (قابل تنظیم توسط کاربر یا ثابت توسط توسعه‌دهنده)
33
+ - گرید پس‌زمینه (قابل تغییر توسط کاربر یا ثابت توسط توسعه‌دهنده)
34
+ - جابه‌جایی گره‌های `main` (قابل تغییر توسط کاربر یا ثابت توسط توسعه‌دهنده)
35
+ - رابط فارسی/انگلیسی (دوزبانه یا تک‌زبانه با انتخاب توسعه‌دهنده)
36
+ - رنگ‌بندی border گره‌ها بر اساس **rate** و بازه‌های قابل تنظیم
37
+ - چیدمان خودکار گره‌ها (Auto Arrange)
38
+ - جستجوی زنده، هایلایت مسیر، رنگ‌آمیزی یال‌ها
39
+ - خروجی اسکرین‌شات و Excel
40
+ - افزودن گره از بیرون کامپوننت با `AddNewNode`
41
+ - پشتیبانی از تم روشن/تاریک (بر اساس کلاس `dark` روی `<html>`)
42
+
43
+ ---
44
+
45
+ ## پیش‌نیازها
46
+
47
+ | وابستگی | نسخه |
48
+ |---------|------|
49
+ | React | `>= 18` |
50
+ | React DOM | `>= 18` |
51
+
52
+ در پروژه‌های **Next.js** کامپوننت باید در فایل Client Component استفاده شود (`"use client"`).
53
+
54
+ ---
55
+
56
+ ## نصب
57
+
58
+ ### از مسیر محلی (توسعه)
59
+
60
+ ```bash
61
+ # ابتدا کتابخانه را بیلد کنید
62
+ cd nodalix
63
+ npm install
64
+ npm run build
65
+
66
+ # در پروژه مصرف‌کننده
67
+ npm install file:../nodalix
68
+ ```
69
+
70
+ ### از npm (پس از انتشار)
71
+
72
+ ```bash
73
+ npm install nodalix
74
+ ```
75
+
76
+ ---
77
+
78
+ ## شروع سریع
79
+
80
+ ```jsx
81
+ "use client";
82
+
83
+ import {
84
+ Graph_Engine,
85
+ NODE_TYPE,
86
+ EDGE_LABEL_FIELDS,
87
+ } from "nodalix";
88
+
89
+ const data = [
90
+ {
91
+ id: "node_a",
92
+ type: NODE_TYPE.MAIN,
93
+ text: "منبع A",
94
+ label: "گره مبدأ",
95
+ entity: { name: "تیم الف" },
96
+ rate: 12,
97
+ main: true,
98
+ metadata: null,
99
+ x: -420,
100
+ y: 0,
101
+ inputs: [],
102
+ outputs: [
103
+ {
104
+ id: "step_1",
105
+ value: 120,
106
+ subText: "واحد",
107
+ subValue: 4800,
108
+ time: 1717851000,
109
+ },
110
+ ],
111
+ },
112
+ {
113
+ id: "step_1",
114
+ type: NODE_TYPE.SUB,
115
+ text: "مرحله ۱",
116
+ label: null,
117
+ entity: null,
118
+ rate: null,
119
+ main: false,
120
+ metadata: null,
121
+ subText: "پردازش",
122
+ x: -210,
123
+ y: 0,
124
+ inputs: [
125
+ { id: "node_a", value: 120, subText: "واحد", subValue: 4800, time: 1717851000 },
126
+ ],
127
+ outputs: [
128
+ { id: "node_b", value: 120, subText: "واحد", subValue: 4800, time: 1717851000 },
129
+ ],
130
+ },
131
+ {
132
+ id: "node_b",
133
+ type: NODE_TYPE.MAIN,
134
+ text: "مقصد B",
135
+ label: "گره پایانی",
136
+ entity: null,
137
+ rate: 45,
138
+ main: false,
139
+ metadata: null,
140
+ x: 0,
141
+ y: 0,
142
+ inputs: [
143
+ { id: "step_1", value: 120, subText: "واحد", subValue: 4800, time: 1717851000 },
144
+ ],
145
+ outputs: [],
146
+ },
147
+ ];
148
+
149
+ export default function App() {
150
+ return (
151
+ <div style={{ width: "100%", height: "600px" }}>
152
+ <Graph_Engine
153
+ NewData={data}
154
+ onNodeClick={(node) => console.log("clicked:", node)}
155
+ edgeLabelFields={[
156
+ EDGE_LABEL_FIELDS.VALUE,
157
+ EDGE_LABEL_FIELDS.SUB_TEXT,
158
+ EDGE_LABEL_FIELDS.SUB_VALUE,
159
+ EDGE_LABEL_FIELDS.TIME,
160
+ ]}
161
+ rateColorRanges={[
162
+ { min: 70, max: Infinity, color: "red" },
163
+ { min: 50, max: 70, color: "orange" },
164
+ ]}
165
+ />
166
+ </div>
167
+ );
168
+ }
169
+ ```
170
+
171
+ > **نکته:** کانتینر والد باید ارتفاع مشخص داشته باشد تا گراف به‌درستی نمایش داده شود.
172
+
173
+ ---
174
+
175
+ ## ساختار داده
176
+
177
+ ### گره (`GraphNode`)
178
+
179
+ | فیلد | نوع | توضیح |
180
+ |------|-----|--------|
181
+ | `id` | `string` | شناسه یکتا (الزامی) |
182
+ | `type` | `"main"` \| `"sub"` | `main` = گره اصلی، `sub` = گره واسط/میانی |
183
+ | `text` | `string` | متن اصلی (شناسه داخلی یا توضیح کوتاه) |
184
+ | `label` | `string \| null` | برچسب نمایشی برای گره‌های `main` |
185
+ | `subText` | `string \| null` | برچسب نمایشی برای گره‌های `sub` |
186
+ | `entity` | `object \| null` | `{ name, image?, metadata? }` — اطلاعات موجودیت مرتبط |
187
+ | `rate` | `number \| null` | امتیاز عددی (مثلاً ۰–۱۰۰) — رنگ border را تعیین می‌کند |
188
+ | `main` | `boolean` | اگر `true` باشد فلش و استایل ویژه نمایش داده می‌شود |
189
+ | `metadata` | `string \| null` | اگر مقدار داشته باشد آیکون تکمیلی نمایش داده می‌شود |
190
+ | `x`, `y` | `number` | موقعیت اولیه در بوم |
191
+ | `inputs` | `EdgeRef[]` | اتصالات ورودی |
192
+ | `outputs` | `EdgeRef[]` | اتصالات خروجی |
193
+
194
+ ### مرجع یال (`EdgeRef` — داخل `inputs` / `outputs`)
195
+
196
+ | فیلد | نوع | توضیح |
197
+ |------|-----|--------|
198
+ | `id` | `string` | شناسه گره مقابل |
199
+ | `value` | `number` | مقدار اصلی |
200
+ | `subText` | `string` | متن تکمیلی (واحد، دسته، برچسب کوتاه و …) |
201
+ | `subValue` | `number` | مقدار ثانویه (مثلاً مقدار تبدیل‌شده یا مرجع) |
202
+ | `time` | `number` | زمان یونیکس (ثانیه) |
203
+
204
+ ### مثال کامل
205
+
206
+ ```js
207
+ {
208
+ id: "node_c",
209
+ type: "main",
210
+ text: "گره C-1042",
211
+ label: "انبار منطقه ۲",
212
+ entity: { name: "واحد لجستیک" },
213
+ rate: 55,
214
+ main: false,
215
+ metadata: "نیاز به بررسی",
216
+ x: 0,
217
+ y: 0,
218
+ inputs: [
219
+ { id: "step_2", value: 48, subText: "بسته", subValue: 960, time: 1717851200 },
220
+ ],
221
+ outputs: [
222
+ { id: "step_3", value: 48, subText: "بسته", subValue: 960, time: 1717851300 },
223
+ ],
224
+ }
225
+ ```
226
+
227
+ ---
228
+
229
+ ## کامپوننت `Graph_Engine`
230
+
231
+ کامپوننت اصلی و تنها نقطهٔ ورود UI کتابخانه.
232
+
233
+ ### Props
234
+
235
+ | Prop | نوع | پیش‌فرض | توضیح |
236
+ |------|-----|---------|--------|
237
+ | `NewData` | `GraphNode[]` | `[]` | آرایهٔ گره‌های گراف |
238
+ | `onNodeClick` | `(node) => void` | — | callback هنگام کلیک روی گره |
239
+ | `edgeLabelFields` | `string[]` | `["value","subText","time"]` | فیلدهایی که روی لیبل یال نمایش داده می‌شوند |
240
+ | `rateColorRanges` | `RateColorRange[]` | [پیش‌فرض زیر](#رنگ‌بندی-rate-ratecolorranges) | بازه‌های رنگ برای `rate` |
241
+ | `showEdgeHoverInfo` | `boolean` | `false` | نمایش اطلاعات یال هنگام هاور موس |
242
+ | `showHelpButton` | `boolean` | `true` | نمایش دکمهٔ راهنما در گوشهٔ گراف |
243
+ | `gridUserConfigurable` | `boolean` | `true` | اگر `false` باشد، کاربر نمی‌تواند گرید را تغییر دهد |
244
+ | `showGrid` | `boolean` | `true` | وضعیت گرید (ثابت یا مقدار اولیه وقتی کاربر قابل انتخاب است) |
245
+ | `nodesDraggableUserConfigurable` | `boolean` | `true` | اگر `false` باشد، کاربر نمی‌تواند جابه‌جایی گره را تغییر دهد |
246
+ | `nodesDraggable` | `boolean` | `true` | گره‌های main قابل جابه‌جایی باشند یا ثابت |
247
+ | `edgeInfoNodesUserConfigurable` | `boolean` | `true` | اگر `false` باشد، کاربر نمی‌تواند نمایش گره‌های میانی یال را تغییر دهد |
248
+ | `showEdgeInfoNodes` | `boolean` | `true` | نمایش گره‌های میانی اطلاعات یال |
249
+ | `languageUserConfigurable` | `boolean` | `true` | اگر `false` باشد، کاربر نمی‌تواند زبان را عوض کند |
250
+ | `language` | `"fa"` \| `"en"` | `"fa"` | زبان ثابت یا مقدار اولیه (`GRAPH_LANGUAGE.FA` / `GRAPH_LANGUAGE.EN`) |
251
+
252
+ ### نوع `RateColorRange`
253
+
254
+ ```ts
255
+ type RateColorRange = {
256
+ min: number; // حداقل بازه (شامل)
257
+ max: number; // حداکثر بازه (غیرشامل؛ برای آخرین بازه از Infinity استفاده کنید)
258
+ color: string; // نام یا کد رنگ CSS
259
+ };
260
+ ```
261
+
262
+ **پیش‌فرض:**
263
+
264
+ ```js
265
+ [
266
+ { min: 70, max: Infinity, color: "red" },
267
+ { min: 50, max: 70, color: "orange" },
268
+ ]
269
+ ```
270
+
271
+ گره‌هایی که `rate` ندارند یا در هیچ بازه‌ای نیفتند، رنگ border پیش‌فرض تم را می‌گیرند.
272
+
273
+ ---
274
+
275
+ ## پیکربندی داینامیک
276
+
277
+ ### فیلدهای لیبل یال (`edgeLabelFields`)
278
+
279
+ مقادیر مجاز (از `EDGE_LABEL_FIELDS`):
280
+
281
+ | کلید | مقدار | نمایش |
282
+ |------|-------|--------|
283
+ | `VALUE` | `"value"` | مقدار عددی اصلی |
284
+ | `SUB_TEXT` | `"subText"` | متن تکمیلی (در کنار value) |
285
+ | `SUB_VALUE` | `"subValue"` | مقدار ثانویه (با فرمت عددی در UI) |
286
+ | `TIME` | `"time"` | تاریخ و ساعت میلادی |
287
+
288
+ **مثال‌ها:**
289
+
290
+ ```jsx
291
+ // مقدار + متن تکمیلی + زمان (پیش‌فرض)
292
+ edgeLabelFields={["value", "subText", "time"]}
293
+
294
+ // فقط مقدار ثانویه و زمان
295
+ edgeLabelFields={["subValue", "time"]}
296
+
297
+ // همه فیلدها
298
+ edgeLabelFields={["value", "subText", "subValue", "time"]}
299
+ ```
300
+
301
+ ### رنگ‌بندی rate (`rateColorRanges`)
302
+
303
+ ```jsx
304
+ rateColorRanges={[
305
+ { min: 0, max: 30, color: "#22c55e" }, // امتیاز پایین
306
+ { min: 30, max: 60, color: "#eab308" }, // امتیاز متوسط
307
+ { min: 60, max: Infinity, color: "#ef4444" }, // امتیاز بالا
308
+ ]}
309
+ ```
310
+
311
+ بازه‌ها به ترتیب آرایه بررسی می‌شوند؛ اولین بازهٔ منطبق اعمال می‌شود.
312
+
313
+ ### هاور روی یال (`showEdgeHoverInfo`)
314
+
315
+ به‌صورت پیش‌فرض خاموش است. با فعال کردن آن، هنگام قرار دادن موس روی یال، شناسه مبدأ/مقصد و فیلدهای انتخاب‌شده در `edgeLabelFields` نمایش داده می‌شود:
316
+
317
+ ```jsx
318
+ <Graph_Engine
319
+ NewData={data}
320
+ showEdgeHoverInfo
321
+ edgeLabelFields={["value", "subText", "time"]}
322
+ />
323
+ ```
324
+
325
+ ### دکمهٔ راهنما (`showHelpButton`)
326
+
327
+ به‌صورت پیش‌فرض فعال است. دکمهٔ `?` در گوشهٔ پایین-راست گراف راهنمای استفاده را به زبان انتخاب‌شده در پنل ابزار (فارسی/انگلیسی) نشان می‌دهد:
328
+
329
+ ```jsx
330
+ <Graph_Engine NewData={data} showHelpButton />
331
+ ```
332
+
333
+ برای مخفی کردن: `showHelpButton={false}`
334
+
335
+ ---
336
+
337
+ ## پیکربندی ابزارهای UI (گرید، جابه‌جایی، یال، زبان)
338
+
339
+ چهار بخش از پنل **Graph Tools** را می‌توان از بیرون کنترل کرد. برای هر کدام دو حالت وجود دارد:
340
+
341
+ | حالت | `*UserConfigurable` | رفتار |
342
+ |------|---------------------|--------|
343
+ | **انتخاب کاربر** | `true` (پیش‌فرض) | سوئیچ/دکمه در پنل نمایش داده می‌شود و کاربر می‌تواند تغییر دهد |
344
+ | **ثابت توسعه‌دهنده** | `false` | سوئیچ مخفی است و مقدار از prop دوم اعمال می‌شود |
345
+
346
+ ### خلاصهٔ props
347
+
348
+ | ویژگی | انتخاب کاربر | مقدار ثابت / اولیه | پیش‌فرض |
349
+ |--------|----------------|---------------------|---------|
350
+ | گرید پس‌زمینه | `gridUserConfigurable` | `showGrid` | `true` / `true` |
351
+ | جابه‌جایی گره | `nodesDraggableUserConfigurable` | `nodesDraggable` | `true` / `true` |
352
+ | گره‌های میانی یال | `edgeInfoNodesUserConfigurable` | `showEdgeInfoNodes` | `true` / `true` |
353
+ | زبان UI | `languageUserConfigurable` | `language` (`"fa"` \| `"en"`) | `true` / `"fa"` |
354
+
355
+ > وقتی `*UserConfigurable={true}` است، prop دوم **مقدار اولیه** است (کاربر بعداً می‌تواند عوض کند).
356
+ > وقتی `*UserConfigurable={false}` است، prop دوم **مقدار ثابت** است.
357
+
358
+ ### گرید (`showGrid` / `gridUserConfigurable`)
359
+
360
+ شبکهٔ پس‌زمینه و snap گره‌ها هنگام جابه‌جایی و Auto Arrange به گرید وابسته است.
361
+
362
+ ```jsx
363
+ // کاربر می‌تواند گرید را روشن/خاموش کند (پیش‌فرض)
364
+ <Graph_Engine NewData={data} />
365
+
366
+ // گرید همیشه خاموش؛ بدون چک‌باکس در پنل
367
+ <Graph_Engine NewData={data} gridUserConfigurable={false} showGrid={false} />
368
+ ```
369
+
370
+ ### جابه‌جایی گره (`nodesDraggable` / `nodesDraggableUserConfigurable`)
371
+
372
+ فقط گره‌های `type: "main"` قابل جابه‌جایی هستند؛ گره‌های کمکی (`_Arrow`, `hotWallet`, `Tr…`) همیشه ثابت می‌مانند. Pan و Zoom تحت تأثیر این تنظیم نیستند.
373
+
374
+ ```jsx
375
+ // گره‌ها همیشه ثابت؛ کاربر نمی‌تواند جابه‌جا کند
376
+ <Graph_Engine NewData={data} nodesDraggableUserConfigurable={false} nodesDraggable={false} />
377
+
378
+ // پیش‌فرض: جابه‌جایی فعال و کاربر می‌تواند از پنل خاموش/روشن کند
379
+ <Graph_Engine NewData={data} nodesDraggableUserConfigurable nodesDraggable />
380
+ ```
381
+
382
+ ### گره‌های میانی یال (`showEdgeInfoNodes` / `edgeInfoNodesUserConfigurable`)
383
+
384
+ گره‌های کوچک روی یال‌ها که فیلدهای `edgeLabelFields` را نشان می‌دهند. این گزینه جدا از `showEdgeHoverInfo` است (هاور tooltip روی خود یال).
385
+
386
+ ```jsx
387
+ // اطلاعات یال همیشه نمایش داده می‌شود
388
+ <Graph_Engine NewData={data} edgeInfoNodesUserConfigurable={false} showEdgeInfoNodes />
389
+
390
+ // اطلاعات یال همیشه مخفی
391
+ <Graph_Engine NewData={data} edgeInfoNodesUserConfigurable={false} showEdgeInfoNodes={false} />
392
+ ```
393
+
394
+ ### زبان (`language` / `languageUserConfigurable`)
395
+
396
+ تمام متن‌های پنل ابزار، tooltipها و راهنما (`?`) به زبان انتخاب‌شده نمایش داده می‌شوند. برای مقدار ثابت از ثابت `GRAPH_LANGUAGE` استفاده کنید.
397
+
398
+ ```jsx
399
+ import { Graph_Engine, GRAPH_LANGUAGE } from "nodalix";
400
+
401
+ // فقط انگلیسی؛ بدون دکمهٔ تغییر زبان
402
+ <Graph_Engine
403
+ NewData={data}
404
+ languageUserConfigurable={false}
405
+ language={GRAPH_LANGUAGE.EN}
406
+ />
407
+
408
+ // دوزبانه؛ کاربر بین فارسی و انگلیسی انتخاب می‌کند (پیش‌فرض)
409
+ <Graph_Engine NewData={data} languageUserConfigurable language="fa" />
410
+ ```
411
+
412
+ ### مثال ترکیبی
413
+
414
+ ```jsx
415
+ import { Graph_Engine, GRAPH_LANGUAGE } from "nodalix";
416
+
417
+ <Graph_Engine
418
+ NewData={data}
419
+ gridUserConfigurable={false}
420
+ showGrid
421
+ nodesDraggableUserConfigurable
422
+ nodesDraggable
423
+ edgeInfoNodesUserConfigurable={false}
424
+ showEdgeInfoNodes={false}
425
+ languageUserConfigurable={false}
426
+ language={GRAPH_LANGUAGE.FA}
427
+ />
428
+ ```
429
+
430
+ در این مثال: گرید همیشه روشن، جابه‌جایی قابل تغییر توسط کاربر، گره‌های میانی یال همیشه مخفی، UI فقط فارسی.
431
+
432
+ ---
433
+
434
+ ## APIهای برنامه‌نویسی (Imperative)
435
+
436
+ این توابع خارج از درخت React و پس از mount شدن `Graph_Engine` قابل استفاده‌اند.
437
+
438
+ ### `AddNewNode(rawNode, options?)`
439
+
440
+ گره جدید را با اعتبارسنجی، محاسبه موقعیت امن، و همگام‌سازی دوطرفه `inputs`/`outputs` اضافه می‌کند.
441
+
442
+ ```js
443
+ import { AddNewNode, NODE_TYPE } from "nodalix";
444
+
445
+ const result = AddNewNode(
446
+ {
447
+ id: "node_new",
448
+ type: NODE_TYPE.MAIN,
449
+ text: "گره جدید",
450
+ label: "شعبه ۳",
451
+ entity: null,
452
+ rate: 25,
453
+ main: false,
454
+ metadata: null,
455
+ inputs: [
456
+ { id: "node_a", value: 30, subText: "قلم", subValue: 150, time: 1717851000 },
457
+ ],
458
+ outputs: [],
459
+ },
460
+ { minGap: 100 } // حداقل فاصله از سایر گره‌ها (پیکسل)
461
+ );
462
+
463
+ if (result.success) {
464
+ console.log(result.node); // گره با x,y محاسبه‌شده
465
+ console.log(result.data); // کل آرایه به‌روز
466
+ } else {
467
+ console.error(result.error);
468
+ }
469
+ ```
470
+
471
+ **پاسخ:**
472
+
473
+ ```ts
474
+ // موفق
475
+ { success: true, node: GraphNode, data: GraphNode[], length: number }
476
+
477
+ // ناموفق
478
+ { success: false, error: string }
479
+ ```
480
+
481
+ ### `GetSelectedNode()`
482
+
483
+ گره انتخاب‌شده فعلی را برمی‌گرداند (یا `null`).
484
+
485
+ ### `SetSelectedNode(node)`
486
+
487
+ گره انتخاب‌شده را از بیرون تنظیم می‌کند.
488
+
489
+ ```js
490
+ SetSelectedNode(null); // پاک کردن انتخاب
491
+ ```
492
+
493
+ ### `OnNodeClick(handler)`
494
+
495
+ ثبت callback سراسری برای کلیک روی گره (`handler` می‌تواند `null` باشد).
496
+
497
+ ### `getSafeNodePosition(params)`
498
+
499
+ موقعیت امن برای گره جدید را بدون افزودن به گراف محاسبه می‌کند.
500
+
501
+ ```js
502
+ const { x, y, width } = getSafeNodePosition({
503
+ node: rawNode,
504
+ nodes: existingNodes,
505
+ anchorIds: ["node_a", "node_b"], // گره‌های مرتبط
506
+ minGap: 100,
507
+ });
508
+ ```
509
+
510
+ ---
511
+
512
+ ## ابزارهای داخلی UI
513
+
514
+ پس از رندر گراف، پنل **Graph Panel** در دسترس است (بالا-چپ). دکمه‌های خروجی (اسکرین‌شات/اکسل) در نوار جداگانه بالا-راست قرار می‌گیرند. چهار مورد زیر می‌توانند توسط توسعه‌دهنده ثابت یا در اختیار کاربر گذاشته شوند (جزئیات در [پیکربندی ابزارهای UI](#پیکربندی-ابزارهای-ui-گرید-جابه‌جایی-یال-زبان)):
515
+
516
+ | ابزار | توضیح | props مرتبط |
517
+ |--------|--------|-------------|
518
+ | **زبان** | فارسی / انگلیسی | `languageUserConfigurable`, `language` |
519
+ | **جستجو** | هایلایت گره بر اساس ID یا Label | — |
520
+ | **نمایش اطلاعات یال** | گره‌های میانی روی یال‌ها | `edgeInfoNodesUserConfigurable`, `showEdgeInfoNodes` |
521
+ | **گرید** | شبکهٔ پس‌زمینه | `gridUserConfigurable`, `showGrid` |
522
+ | **جابه‌جایی گره** | drag گره‌های `main` | `nodesDraggableUserConfigurable`, `nodesDraggable` |
523
+ | **رنگ یال** | رنگ‌آمیزی یال‌های انتخاب‌شده | — |
524
+ | **مرتب‌سازی (Arrange)** | چیدمان خودکار گره‌ها | — |
525
+ | **اسکرین‌شات** | ذخیره تصویر کل گراف (نوار خروجی بالا-راست) | — |
526
+ | **خروجی Excel** | export به `.xlsx` (نوار خروجی بالا-راست) | — |
527
+ | **هایلایت مسیرها** | مسیرهای جهت‌دار بین دو ID | — |
528
+
529
+ **تعاملات:**
530
+
531
+ - **Drag** گره‌های `main` (قابل غیرفعال‌سازی با `nodesDraggable`)
532
+ - **Pan / Zoom** با ماوس (همیشه فعال)
533
+ - **Hover** برای tooltip اطلاعات گره؛ هاور یال با `showEdgeHoverInfo`
534
+ - **Multi-select** گره‌ها و یال‌ها
535
+
536
+ ---
537
+
538
+ ## منطق گراف و یال‌ها
539
+
540
+ ### انواع گره
541
+
542
+ ```
543
+ NODE_TYPE.MAIN → "main" گره اصلی (با تصویر/آیکون)
544
+ NODE_TYPE.SUB → "sub" گره واسط (نقطه کوچک)
545
+ ```
546
+
547
+ ### ساخت یال‌ها
548
+
549
+ یال‌های vis-network **فقط از گره‌های `type: "main"`** ساخته می‌شوند:
550
+
551
+ - هر آیتم در `outputs` → یال از این گره به `id` مقصد
552
+ - هر آیتم در `inputs` → یال از `id` مبدأ به این گره
553
+
554
+ گره‌های `sub` در توپولوژی نقش واسطه دارند؛ اتصال واقعی از طریق `inputs`/`outputs` گره‌های `main` تعریف می‌شود.
555
+
556
+ ### گره‌های کمکی (خودکار)
557
+
558
+ | پسوند ID | نقش |
559
+ |----------|-----|
560
+ | `Tr..._in` / `Tr..._out` | گره اطلاعات یال (لیبل میانی) |
561
+ | `hotWallet` | آیکون متادیتا |
562
+ | `_Arrow` | فلش برای گره‌های `main: true` |
563
+
564
+ ### برچسب نمایشی گره
565
+
566
+ | نوع | منبع برچسب |
567
+ |-----|------------|
568
+ | `sub` | `subText` |
569
+ | `main` | `label` → `entity.name` → `...` + ۷ کاراکتر اول `text` |
570
+
571
+ ---
572
+
573
+ ## Exportها و ثابت‌ها
574
+
575
+ ```js
576
+ import {
577
+ Graph_Engine,
578
+ AddNewNode,
579
+ GetSelectedNode,
580
+ SetSelectedNode,
581
+ OnNodeClick,
582
+ getSafeNodePosition,
583
+
584
+ // ثابت‌ها
585
+ NODE_TYPE,
586
+ EDGE_LABEL_FIELDS,
587
+ DEFAULT_EDGE_LABEL_FIELDS,
588
+ DEFAULT_RATE_COLOR_RANGES,
589
+ GRAPH_LANGUAGE,
590
+
591
+ // توابع کمکی
592
+ normalizeEdgeLabelFields,
593
+ normalizeRateColorRanges,
594
+ normalizeGraphLanguage,
595
+ getRateBorderColor,
596
+ buildEdgeInfoLabel,
597
+ getNodeDisplayLabel,
598
+ getNodeEntityImage,
599
+ getGraphGuide,
600
+
601
+ // edition و شمارش گره
602
+ NODALIX_EDITION,
603
+ NODALIX_MAX_NODES,
604
+ isBasicEdition,
605
+ isFullEdition,
606
+ hasNodeLimit,
607
+ countGraphNodes,
608
+ enforceNodeLimit,
609
+ } from "nodalix";
610
+ ```
611
+
612
+ ثابت‌های edition در بیلد فعلی:
613
+
614
+ ```js
615
+ NODALIX_EDITION; // "full"
616
+ NODALIX_MAX_NODES; // Infinity (بدون محدودیت تعداد گره)
617
+ ```
618
+
619
+ ثابت‌های زبان:
620
+
621
+ ```js
622
+ GRAPH_LANGUAGE.FA // "fa"
623
+ GRAPH_LANGUAGE.EN // "en"
624
+ ```
625
+
626
+ تابع `normalizeGraphLanguage(value)` مقدار ورودی را به `"fa"` یا `"en"` نرمال می‌کند.
627
+
628
+ ---
629
+
630
+ ## ساخت و توسعه
631
+
632
+ ```bash
633
+ # نصب وابستگی‌ها
634
+ npm install
635
+
636
+ # بیلد production (خروجی در dist/)
637
+ npm run build
638
+
639
+ # بیلد با watch
640
+ npm run dev
641
+
642
+ # اجرای تست‌ها
643
+ npm test
644
+ ```
645
+
646
+ ### TypeScript Support
647
+
648
+ پکیج خروجی دارای فایل type declaration است:
649
+
650
+ ```ts
651
+ import { Graph_Engine, type GraphNode, EDGE_LINE_STYLE } from "nodalix";
652
+ ```
653
+
654
+ در CI نیز build/test روی push و pull request اجرا می‌شود (فایل: `.github/workflows/ci.yml`).
655
+
656
+ ### ساختار پروژه
657
+
658
+ ```
659
+ nodalix/
660
+ ├── src/
661
+ │ ├── index.js # نقطه ورود و API عمومی
662
+ │ ├── edition.js # متادیتای edition بیلد
663
+ │ ├── graphNodeLimits.js # شمارش و محدودیت گره (ابزار داخلی)
664
+ │ ├── graphConfig.js # ثابت‌ها و helperهای پیکربندی
665
+ │ └── Components/
666
+ │ ├── Graph.js # موتور گراف و UI
667
+ │ ├── SetEdgesData.js # ساخت یال از inputs/outputs
668
+ │ ├── Options.js # تنظیمات vis-network
669
+ │ └── miladiCalendar.js # تبدیل timestamp به تاریخ
670
+ ├── dist/ # خروجی بیلد
671
+ ├── package.json
672
+ └── tsup.config.js
673
+ ```
674
+
675
+ در حال حاضر فقط یک بسته منتشر می‌شود: **nodalix** (نسخهٔ کامل، بدون محدودیت تعداد گره).
676
+
677
+ ```bash
678
+ npm run build # خروجی در dist/
679
+ ```
680
+
681
+ ---
682
+
683
+ ### پروژه تست
684
+
685
+ پوشهٔ `nodalix-test` (هم‌سطح) نمونهٔ استفاده از کتابخانه با Next.js است و شامل مثال پیکربندی ابزارهای UI (`gridUserConfigurable`, `nodesDraggable`, `showEdgeInfoNodes`, `language` و …) می‌شود.
686
+
687
+ ---
688
+
689
+ ## نکات مهم
690
+
691
+ ### تصاویر
692
+
693
+ گره‌های `main` از مسیرهای زیر استفاده می‌کنند. این فایل‌ها باید در `public/` پروژهٔ مصرف‌کننده باشند:
694
+
695
+ ```
696
+ /images/location.png — تصویر پیش‌فرض گره
697
+ /images/fire.png — آیکون متادیتا
698
+ ```
699
+
700
+ یا `entity.image` / `entity.metadata.image` را در داده تنظیم کنید.
701
+
702
+ ### Client Component
703
+
704
+ `Graph_Engine` با `"use client"` علامت‌گذاری شده. در Next.js App Router حتماً در کامپوننت کلاینت import کنید.
705
+
706
+ ### همگام‌سازی state
707
+
708
+ - `NewData` فقط در mount و تغییر prop همگام می‌شود.
709
+ - برای افزودن گره در runtime از `AddNewNode` استفاده کنید (state داخلی را خودش به‌روز می‌کند).
710
+ - اگر `NewData` را از والد تغییر دهید، state داخلی بازنویسی می‌شود.
711
+
712
+ ### تم تاریک
713
+
714
+ اگر روی `<html>` کلاس `dark` باشد، گراف به‌صورت خودکار تم تاریک می‌گیرد.
715
+
716
+ ### محدودیت‌ها
717
+
718
+ - فیزیک گراف همیشه خاموش است (چیدمان قطعی).
719
+ - `AddNewNode` و `GetSelectedNode` فقط وقتی `Graph_Engine` mount است کار می‌کنند.
720
+ - برای گراف‌های بسیار بزرگ (هزاران گره)، Auto Arrange ممکن است چند ثانیه طول بکشد.
721
+
722
+ ---
723
+
724
+ ## مجوز
725
+
726
+ MIT