markmap-view-plus 0.0.2 → 0.0.4
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 +1 -1
- package/dist/browser/index.js +2061 -2112
- package/dist/index.js +1395 -1425
- package/package.json +3 -3
package/dist/browser/index.js
CHANGED
|
@@ -1,1059 +1,1094 @@
|
|
|
1
|
-
(function(exports,
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1
|
+
(function(exports, d3) {
|
|
2
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
3
|
+
var testPath = "npm2url/dist/index.cjs";
|
|
4
|
+
var defaultProviders = {
|
|
5
|
+
jsdelivr: (path) => `https://cdn.jsdelivr.net/npm/${path}`,
|
|
6
|
+
unpkg: (path) => `https://unpkg.com/${path}`
|
|
7
|
+
};
|
|
8
|
+
async function checkUrl(url, signal) {
|
|
9
|
+
const res = await fetch(url, { signal });
|
|
10
|
+
if (!res.ok) throw res;
|
|
11
|
+
await res.text();
|
|
12
|
+
}
|
|
13
|
+
var UrlBuilder = class {
|
|
14
|
+
constructor() {
|
|
15
|
+
this.providers = { ...defaultProviders };
|
|
16
|
+
this.provider = "jsdelivr";
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Get the fastest provider name.
|
|
20
|
+
* If none of the providers returns a valid response within `timeout`, an error will be thrown.
|
|
21
|
+
*/
|
|
22
|
+
async getFastestProvider(timeout = 5e3, path = testPath) {
|
|
23
|
+
const controller = new AbortController();
|
|
24
|
+
let timer = 0;
|
|
25
|
+
try {
|
|
26
|
+
return await new Promise((resolve, reject) => {
|
|
27
|
+
Promise.all(Object.entries(this.providers).map(async ([name, factory]) => {
|
|
28
|
+
try {
|
|
29
|
+
await checkUrl(factory(path), controller.signal);
|
|
30
|
+
resolve(name);
|
|
31
|
+
} catch {}
|
|
32
|
+
})).then(() => reject(/* @__PURE__ */ new Error("All providers failed")));
|
|
33
|
+
timer = setTimeout(reject, timeout, /* @__PURE__ */ new Error("Timed out"));
|
|
34
|
+
});
|
|
35
|
+
} finally {
|
|
36
|
+
controller.abort();
|
|
37
|
+
clearTimeout(timer);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Set the current provider to the fastest provider found by `getFastestProvider`.
|
|
42
|
+
*/
|
|
43
|
+
async findFastestProvider(timeout, path) {
|
|
44
|
+
this.provider = await this.getFastestProvider(timeout, path);
|
|
45
|
+
return this.provider;
|
|
46
|
+
}
|
|
47
|
+
setProvider(name, factory) {
|
|
48
|
+
if (factory) this.providers[name] = factory;
|
|
49
|
+
else delete this.providers[name];
|
|
50
|
+
}
|
|
51
|
+
getFullUrl(path, provider = this.provider) {
|
|
52
|
+
if (path.includes("://")) return path;
|
|
53
|
+
const factory = this.providers[provider];
|
|
54
|
+
if (!factory) throw new Error(`Provider ${provider} not found`);
|
|
55
|
+
return factory(path);
|
|
56
|
+
}
|
|
57
|
+
};
|
|
58
|
+
new UrlBuilder();
|
|
59
|
+
var Hook = class {
|
|
60
|
+
constructor() {
|
|
61
|
+
this.listeners = [];
|
|
62
|
+
}
|
|
63
|
+
tap(fn) {
|
|
64
|
+
this.listeners.push(fn);
|
|
65
|
+
return () => this.revoke(fn);
|
|
66
|
+
}
|
|
67
|
+
revoke(fn) {
|
|
68
|
+
const i = this.listeners.indexOf(fn);
|
|
69
|
+
if (i >= 0) this.listeners.splice(i, 1);
|
|
70
|
+
}
|
|
71
|
+
revokeAll() {
|
|
72
|
+
this.listeners.splice(0);
|
|
73
|
+
}
|
|
74
|
+
call(...args) {
|
|
75
|
+
for (const fn of this.listeners) fn(...args);
|
|
76
|
+
}
|
|
77
|
+
};
|
|
78
|
+
var uniqId = Math.random().toString(36).slice(2, 8);
|
|
79
|
+
var globalIndex = 0;
|
|
80
|
+
function getId() {
|
|
81
|
+
globalIndex += 1;
|
|
82
|
+
return `mm-${uniqId}-${globalIndex}`;
|
|
83
|
+
}
|
|
84
|
+
function noop() {}
|
|
85
|
+
function walkTree(tree, callback) {
|
|
86
|
+
const walk = (item, parent) => callback(item, () => {
|
|
87
|
+
var _a;
|
|
88
|
+
return (_a = item.children) == null ? void 0 : _a.map((child) => walk(child, item));
|
|
89
|
+
}, parent);
|
|
90
|
+
return walk(tree);
|
|
91
|
+
}
|
|
92
|
+
function addClass(className, ...rest) {
|
|
93
|
+
const classList = (className || "").split(" ").filter(Boolean);
|
|
94
|
+
rest.forEach((item) => {
|
|
95
|
+
if (item && classList.indexOf(item) < 0) classList.push(item);
|
|
96
|
+
});
|
|
97
|
+
return classList.join(" ");
|
|
98
|
+
}
|
|
99
|
+
function defer() {
|
|
100
|
+
const obj = {};
|
|
101
|
+
obj.promise = new Promise((resolve, reject) => {
|
|
102
|
+
obj.resolve = resolve;
|
|
103
|
+
obj.reject = reject;
|
|
104
|
+
});
|
|
105
|
+
return obj;
|
|
106
|
+
}
|
|
107
|
+
function memoize(fn) {
|
|
108
|
+
const cache = {};
|
|
109
|
+
return function memoized(...args) {
|
|
110
|
+
const key = `${args[0]}`;
|
|
111
|
+
let data = cache[key];
|
|
112
|
+
if (!data) {
|
|
113
|
+
data = { value: fn(...args) };
|
|
114
|
+
cache[key] = data;
|
|
115
|
+
}
|
|
116
|
+
return data.value;
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
function debounce(fn, time) {
|
|
120
|
+
const state = { timer: 0 };
|
|
121
|
+
function reset() {
|
|
122
|
+
if (state.timer) {
|
|
123
|
+
window.clearTimeout(state.timer);
|
|
124
|
+
state.timer = 0;
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
function run() {
|
|
128
|
+
reset();
|
|
129
|
+
if (state.args) state.result = fn(...state.args);
|
|
130
|
+
}
|
|
131
|
+
return function debounced(...args) {
|
|
132
|
+
reset();
|
|
133
|
+
state.args = args;
|
|
134
|
+
state.timer = window.setTimeout(run, time);
|
|
135
|
+
return state.result;
|
|
136
|
+
};
|
|
137
|
+
}
|
|
138
|
+
var VTYPE_ELEMENT = 1;
|
|
139
|
+
var VTYPE_FUNCTION = 2;
|
|
140
|
+
var SVG_NS = "http://www.w3.org/2000/svg";
|
|
141
|
+
var XLINK_NS = "http://www.w3.org/1999/xlink";
|
|
142
|
+
var NS_ATTRS = {
|
|
143
|
+
show: XLINK_NS,
|
|
144
|
+
actuate: XLINK_NS,
|
|
145
|
+
href: XLINK_NS
|
|
146
|
+
};
|
|
147
|
+
var isLeaf = (c) => typeof c === "string" || typeof c === "number";
|
|
148
|
+
var isElement = (c) => (c == null ? void 0 : c.vtype) === VTYPE_ELEMENT;
|
|
149
|
+
var isRenderFunction = (c) => (c == null ? void 0 : c.vtype) === VTYPE_FUNCTION;
|
|
150
|
+
function h(type, props, ...children) {
|
|
151
|
+
props = Object.assign({}, props, { children: children.length === 1 ? children[0] : children });
|
|
152
|
+
return jsx(type, props);
|
|
153
|
+
}
|
|
154
|
+
function jsx(type, props) {
|
|
155
|
+
let vtype;
|
|
156
|
+
if (typeof type === "string") vtype = VTYPE_ELEMENT;
|
|
157
|
+
else if (typeof type === "function") vtype = VTYPE_FUNCTION;
|
|
158
|
+
else throw new Error("Invalid VNode type");
|
|
159
|
+
return {
|
|
160
|
+
vtype,
|
|
161
|
+
type,
|
|
162
|
+
props
|
|
163
|
+
};
|
|
164
|
+
}
|
|
165
|
+
function Fragment(props) {
|
|
166
|
+
return props.children;
|
|
167
|
+
}
|
|
168
|
+
var DEFAULT_ENV = { isSvg: false };
|
|
169
|
+
function insertDom(parent, nodes) {
|
|
170
|
+
if (!Array.isArray(nodes)) nodes = [nodes];
|
|
171
|
+
nodes = nodes.filter(Boolean);
|
|
172
|
+
if (nodes.length) parent.append(...nodes);
|
|
173
|
+
}
|
|
174
|
+
function mountAttributes(domElement, props, env) {
|
|
175
|
+
for (const key in props) {
|
|
176
|
+
if (key === "key" || key === "children" || key === "ref") continue;
|
|
177
|
+
if (key === "dangerouslySetInnerHTML") domElement.innerHTML = props[key].__html;
|
|
178
|
+
else if (key === "innerHTML" || key === "textContent" || key === "innerText" || key === "value" && ["textarea", "select"].includes(domElement.tagName)) {
|
|
179
|
+
const value = props[key];
|
|
180
|
+
if (value != null) domElement[key] = value;
|
|
181
|
+
} else if (key.startsWith("on")) domElement[key.toLowerCase()] = props[key];
|
|
182
|
+
else setDOMAttribute(domElement, key, props[key], env.isSvg);
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
var attrMap = {
|
|
186
|
+
className: "class",
|
|
187
|
+
labelFor: "for"
|
|
188
|
+
};
|
|
189
|
+
function setDOMAttribute(el, attr, value, isSVG) {
|
|
190
|
+
attr = attrMap[attr] || attr;
|
|
191
|
+
if (value === true) el.setAttribute(attr, "");
|
|
192
|
+
else if (value === false) el.removeAttribute(attr);
|
|
193
|
+
else {
|
|
194
|
+
const namespace = isSVG ? NS_ATTRS[attr] : void 0;
|
|
195
|
+
if (namespace !== void 0) el.setAttributeNS(namespace, attr, value);
|
|
196
|
+
else el.setAttribute(attr, value);
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
function flatten(arr) {
|
|
200
|
+
return arr.reduce((prev, item) => prev.concat(item), []);
|
|
201
|
+
}
|
|
202
|
+
function mountChildren(children, env) {
|
|
203
|
+
return Array.isArray(children) ? flatten(children.map((child) => mountChildren(child, env))) : mount(children, env);
|
|
204
|
+
}
|
|
205
|
+
function mount(vnode, env = DEFAULT_ENV) {
|
|
206
|
+
if (vnode == null || typeof vnode === "boolean") return null;
|
|
207
|
+
if (vnode instanceof Node) return vnode;
|
|
208
|
+
if (isRenderFunction(vnode)) {
|
|
209
|
+
const { type, props } = vnode;
|
|
210
|
+
if (type === Fragment) {
|
|
211
|
+
const node = document.createDocumentFragment();
|
|
212
|
+
if (props.children) insertDom(node, mountChildren(props.children, env));
|
|
213
|
+
return node;
|
|
214
|
+
}
|
|
215
|
+
return mount(type(props), env);
|
|
216
|
+
}
|
|
217
|
+
if (isLeaf(vnode)) return document.createTextNode(`${vnode}`);
|
|
218
|
+
if (isElement(vnode)) {
|
|
219
|
+
let node;
|
|
220
|
+
const { type, props } = vnode;
|
|
221
|
+
if (!env.isSvg && type === "svg") env = Object.assign({}, env, { isSvg: true });
|
|
222
|
+
if (!env.isSvg) node = document.createElement(type);
|
|
223
|
+
else node = document.createElementNS(SVG_NS, type);
|
|
224
|
+
mountAttributes(node, props, env);
|
|
225
|
+
if (props.children) {
|
|
226
|
+
let childEnv = env;
|
|
227
|
+
if (env.isSvg && type === "foreignObject") childEnv = Object.assign({}, childEnv, { isSvg: false });
|
|
228
|
+
const children = mountChildren(props.children, childEnv);
|
|
229
|
+
if (children != null) insertDom(node, children);
|
|
230
|
+
}
|
|
231
|
+
const { ref } = props;
|
|
232
|
+
if (typeof ref === "function") ref(node);
|
|
233
|
+
return node;
|
|
234
|
+
}
|
|
235
|
+
throw new Error("mount: Invalid Vnode!");
|
|
236
|
+
}
|
|
237
|
+
function mountDom(vnode) {
|
|
238
|
+
return mount(vnode);
|
|
239
|
+
}
|
|
240
|
+
function hm(...args) {
|
|
241
|
+
return mountDom(h(...args));
|
|
242
|
+
}
|
|
243
|
+
var memoizedPreloadJS = memoize((url) => {
|
|
244
|
+
document.head.append(hm("link", {
|
|
245
|
+
rel: "preload",
|
|
246
|
+
as: "script",
|
|
247
|
+
href: url
|
|
248
|
+
}));
|
|
249
|
+
});
|
|
250
|
+
var jsCache = {};
|
|
251
|
+
var cssCache = {};
|
|
252
|
+
async function loadJSItem(item, context) {
|
|
253
|
+
var _a;
|
|
254
|
+
const src = item.type === "script" && ((_a = item.data) == null ? void 0 : _a.src) || "";
|
|
255
|
+
item.loaded || (item.loaded = jsCache[src]);
|
|
256
|
+
if (!item.loaded) {
|
|
257
|
+
const deferred = defer();
|
|
258
|
+
item.loaded = deferred.promise;
|
|
259
|
+
if (item.type === "script") {
|
|
260
|
+
document.head.append(hm("script", {
|
|
261
|
+
...item.data,
|
|
262
|
+
onLoad: () => deferred.resolve(),
|
|
263
|
+
onError: deferred.reject
|
|
264
|
+
}));
|
|
265
|
+
if (!src) deferred.resolve();
|
|
266
|
+
else jsCache[src] = item.loaded;
|
|
267
|
+
}
|
|
268
|
+
if (item.type === "iife") {
|
|
269
|
+
const { fn, getParams } = item.data;
|
|
270
|
+
fn(...(getParams == null ? void 0 : getParams(context)) || []);
|
|
271
|
+
deferred.resolve();
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
await item.loaded;
|
|
275
|
+
}
|
|
276
|
+
async function loadCSSItem(item) {
|
|
277
|
+
const url = item.type === "stylesheet" && item.data.href || "";
|
|
278
|
+
item.loaded || (item.loaded = cssCache[url]);
|
|
279
|
+
if (!item.loaded) {
|
|
280
|
+
const deferred = defer();
|
|
281
|
+
item.loaded = deferred.promise;
|
|
282
|
+
if (url) cssCache[url] = item.loaded;
|
|
283
|
+
if (item.type === "style") {
|
|
284
|
+
document.head.append(hm("style", { textContent: item.data }));
|
|
285
|
+
deferred.resolve();
|
|
286
|
+
} else if (url) {
|
|
287
|
+
document.head.append(hm("link", {
|
|
288
|
+
rel: "stylesheet",
|
|
289
|
+
...item.data
|
|
290
|
+
}));
|
|
291
|
+
fetch(url).then((res) => {
|
|
292
|
+
if (res.ok) return res.text();
|
|
293
|
+
throw res;
|
|
294
|
+
}).then(() => deferred.resolve(), deferred.reject);
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
await item.loaded;
|
|
298
|
+
}
|
|
299
|
+
async function loadJS(items, context) {
|
|
300
|
+
items.forEach((item) => {
|
|
301
|
+
var _a;
|
|
302
|
+
if (item.type === "script" && ((_a = item.data) == null ? void 0 : _a.src)) memoizedPreloadJS(item.data.src);
|
|
303
|
+
});
|
|
304
|
+
context = {
|
|
305
|
+
getMarkmap: () => window.markmap,
|
|
306
|
+
...context
|
|
307
|
+
};
|
|
308
|
+
for (const item of items) await loadJSItem(item, context);
|
|
309
|
+
}
|
|
310
|
+
async function loadCSS(items) {
|
|
311
|
+
await Promise.all(items.map((item) => loadCSSItem(item)));
|
|
312
|
+
}
|
|
313
|
+
const isMacintosh = typeof navigator !== "undefined" && navigator.userAgent.includes("Macintosh");
|
|
314
|
+
const defaultColorFn = (0, d3.scaleOrdinal)(d3.schemeCategory10);
|
|
315
|
+
const lineWidthFactory = (baseWidth = 1, deltaWidth = 3, k = 2) => (node) => baseWidth + deltaWidth / k ** node.state.depth;
|
|
316
|
+
const defaultOptions = {
|
|
317
|
+
autoFit: false,
|
|
318
|
+
duration: 500,
|
|
319
|
+
embedGlobalCSS: true,
|
|
320
|
+
fitRatio: .95,
|
|
321
|
+
maxInitialScale: 2,
|
|
322
|
+
scrollForPan: isMacintosh,
|
|
323
|
+
initialExpandLevel: -1,
|
|
324
|
+
zoom: true,
|
|
325
|
+
pan: true,
|
|
326
|
+
toggleRecursively: false,
|
|
327
|
+
editable: true,
|
|
328
|
+
addable: true,
|
|
329
|
+
deletable: true,
|
|
330
|
+
collapseOnHover: true,
|
|
331
|
+
hoverBorder: true,
|
|
332
|
+
clickBorder: true,
|
|
333
|
+
onNodeEdit: void 0,
|
|
334
|
+
onNodeAdd: void 0,
|
|
335
|
+
inputPlaceholder: "Enter text",
|
|
336
|
+
color: (node) => defaultColorFn(`${node.state?.path || ""}`),
|
|
337
|
+
lineWidth: lineWidthFactory(),
|
|
338
|
+
maxWidth: 0,
|
|
339
|
+
nodeMinHeight: 16,
|
|
340
|
+
paddingX: 8,
|
|
341
|
+
spacingHorizontal: 80,
|
|
342
|
+
spacingVertical: 5
|
|
343
|
+
};
|
|
344
|
+
function deriveOptions(jsonOptions) {
|
|
345
|
+
const derivedOptions = {};
|
|
346
|
+
const options = { ...jsonOptions };
|
|
347
|
+
const { color, colorFreezeLevel, lineWidth } = options;
|
|
348
|
+
if (color?.length === 1) {
|
|
349
|
+
const solidColor = color[0];
|
|
350
|
+
derivedOptions.color = () => solidColor;
|
|
351
|
+
} else if (color?.length) {
|
|
352
|
+
const colorFn = (0, d3.scaleOrdinal)(color);
|
|
353
|
+
derivedOptions.color = (node) => colorFn(`${node.state.path}`);
|
|
354
|
+
}
|
|
355
|
+
if (colorFreezeLevel) {
|
|
356
|
+
const color = derivedOptions.color || defaultOptions.color;
|
|
357
|
+
derivedOptions.color = (node) => {
|
|
358
|
+
node = {
|
|
359
|
+
...node,
|
|
360
|
+
state: {
|
|
361
|
+
...node.state,
|
|
362
|
+
path: node.state.path.split(".").slice(0, colorFreezeLevel).join(".")
|
|
363
|
+
}
|
|
364
|
+
};
|
|
365
|
+
return color(node);
|
|
366
|
+
};
|
|
367
|
+
}
|
|
368
|
+
if (lineWidth) derivedOptions.lineWidth = lineWidthFactory(...Array.isArray(lineWidth) ? lineWidth : [
|
|
369
|
+
lineWidth,
|
|
370
|
+
0,
|
|
371
|
+
1
|
|
372
|
+
]);
|
|
373
|
+
[
|
|
374
|
+
"duration",
|
|
375
|
+
"fitRatio",
|
|
376
|
+
"initialExpandLevel",
|
|
377
|
+
"maxInitialScale",
|
|
378
|
+
"maxWidth",
|
|
379
|
+
"nodeMinHeight",
|
|
380
|
+
"paddingX",
|
|
381
|
+
"spacingHorizontal",
|
|
382
|
+
"spacingVertical"
|
|
383
|
+
].forEach((key) => {
|
|
384
|
+
const value = options[key];
|
|
385
|
+
if (typeof value === "number") derivedOptions[key] = value;
|
|
386
|
+
});
|
|
387
|
+
["zoom", "pan"].forEach((key) => {
|
|
388
|
+
const value = options[key];
|
|
389
|
+
if (value != null) derivedOptions[key] = !!value;
|
|
390
|
+
});
|
|
391
|
+
return derivedOptions;
|
|
392
|
+
}
|
|
393
|
+
/**
|
|
394
|
+
* Credit: https://gist.github.com/jlevy/c246006675becc446360a798e2b2d781?permalink_comment_id=4738050#gistcomment-4738050
|
|
395
|
+
*/
|
|
396
|
+
function simpleHash(str) {
|
|
397
|
+
let hash = 0;
|
|
398
|
+
for (let i = 0; i < str.length; i++) hash = (hash << 5) - hash + str.charCodeAt(i) | 0;
|
|
399
|
+
return (hash >>> 0).toString(36);
|
|
400
|
+
}
|
|
401
|
+
function childSelector(filter) {
|
|
402
|
+
if (typeof filter === "string") {
|
|
403
|
+
const selector = filter;
|
|
404
|
+
filter = (el) => el.matches(selector);
|
|
405
|
+
}
|
|
406
|
+
const filterFn = filter;
|
|
407
|
+
return function selector() {
|
|
408
|
+
let nodes = Array.from(this.childNodes);
|
|
409
|
+
if (filterFn) nodes = nodes.filter((node) => filterFn(node));
|
|
410
|
+
return nodes;
|
|
411
|
+
};
|
|
412
|
+
}
|
|
413
|
+
function count(node) {
|
|
414
|
+
var sum = 0, children = node.children, i = children && children.length;
|
|
415
|
+
if (!i) sum = 1;
|
|
416
|
+
else while (--i >= 0) sum += children[i].value;
|
|
417
|
+
node.value = sum;
|
|
418
|
+
}
|
|
419
|
+
function count_default() {
|
|
420
|
+
return this.eachAfter(count);
|
|
421
|
+
}
|
|
422
|
+
function each_default(callback) {
|
|
423
|
+
var node = this, current, next = [node], children, i, n;
|
|
424
|
+
do {
|
|
425
|
+
current = next.reverse(), next = [];
|
|
426
|
+
while (node = current.pop()) {
|
|
427
|
+
callback(node), children = node.children;
|
|
428
|
+
if (children) for (i = 0, n = children.length; i < n; ++i) next.push(children[i]);
|
|
429
|
+
}
|
|
430
|
+
} while (next.length);
|
|
431
|
+
return this;
|
|
432
|
+
}
|
|
433
|
+
function eachBefore_default(callback) {
|
|
434
|
+
var node = this, nodes = [node], children, i;
|
|
435
|
+
while (node = nodes.pop()) {
|
|
436
|
+
callback(node), children = node.children;
|
|
437
|
+
if (children) for (i = children.length - 1; i >= 0; --i) nodes.push(children[i]);
|
|
438
|
+
}
|
|
439
|
+
return this;
|
|
440
|
+
}
|
|
441
|
+
function eachAfter_default(callback) {
|
|
442
|
+
var node = this, nodes = [node], next = [], children, i, n;
|
|
443
|
+
while (node = nodes.pop()) {
|
|
444
|
+
next.push(node), children = node.children;
|
|
445
|
+
if (children) for (i = 0, n = children.length; i < n; ++i) nodes.push(children[i]);
|
|
446
|
+
}
|
|
447
|
+
while (node = next.pop()) callback(node);
|
|
448
|
+
return this;
|
|
449
|
+
}
|
|
450
|
+
function sum_default(value) {
|
|
451
|
+
return this.eachAfter(function(node) {
|
|
452
|
+
var sum = +value(node.data) || 0, children = node.children, i = children && children.length;
|
|
453
|
+
while (--i >= 0) sum += children[i].value;
|
|
454
|
+
node.value = sum;
|
|
455
|
+
});
|
|
456
|
+
}
|
|
457
|
+
function sort_default(compare) {
|
|
458
|
+
return this.eachBefore(function(node) {
|
|
459
|
+
if (node.children) node.children.sort(compare);
|
|
460
|
+
});
|
|
461
|
+
}
|
|
462
|
+
function path_default(end) {
|
|
463
|
+
var start = this, ancestor = leastCommonAncestor(start, end), nodes = [start];
|
|
464
|
+
while (start !== ancestor) {
|
|
465
|
+
start = start.parent;
|
|
466
|
+
nodes.push(start);
|
|
467
|
+
}
|
|
468
|
+
var k = nodes.length;
|
|
469
|
+
while (end !== ancestor) {
|
|
470
|
+
nodes.splice(k, 0, end);
|
|
471
|
+
end = end.parent;
|
|
472
|
+
}
|
|
473
|
+
return nodes;
|
|
474
|
+
}
|
|
475
|
+
function leastCommonAncestor(a, b) {
|
|
476
|
+
if (a === b) return a;
|
|
477
|
+
var aNodes = a.ancestors(), bNodes = b.ancestors(), c = null;
|
|
478
|
+
a = aNodes.pop();
|
|
479
|
+
b = bNodes.pop();
|
|
480
|
+
while (a === b) {
|
|
481
|
+
c = a;
|
|
482
|
+
a = aNodes.pop();
|
|
483
|
+
b = bNodes.pop();
|
|
484
|
+
}
|
|
485
|
+
return c;
|
|
486
|
+
}
|
|
487
|
+
function ancestors_default() {
|
|
488
|
+
var node = this, nodes = [node];
|
|
489
|
+
while (node = node.parent) nodes.push(node);
|
|
490
|
+
return nodes;
|
|
491
|
+
}
|
|
492
|
+
function descendants_default() {
|
|
493
|
+
var nodes = [];
|
|
494
|
+
this.each(function(node) {
|
|
495
|
+
nodes.push(node);
|
|
496
|
+
});
|
|
497
|
+
return nodes;
|
|
498
|
+
}
|
|
499
|
+
function leaves_default() {
|
|
500
|
+
var leaves = [];
|
|
501
|
+
this.eachBefore(function(node) {
|
|
502
|
+
if (!node.children) leaves.push(node);
|
|
503
|
+
});
|
|
504
|
+
return leaves;
|
|
505
|
+
}
|
|
506
|
+
function links_default() {
|
|
507
|
+
var root = this, links = [];
|
|
508
|
+
root.each(function(node) {
|
|
509
|
+
if (node !== root) links.push({
|
|
510
|
+
source: node.parent,
|
|
511
|
+
target: node
|
|
512
|
+
});
|
|
513
|
+
});
|
|
514
|
+
return links;
|
|
515
|
+
}
|
|
516
|
+
function hierarchy(data, children) {
|
|
517
|
+
var root = new Node$1(data), valued = +data.value && (root.value = data.value), node, nodes = [root], child, childs, i, n;
|
|
518
|
+
if (children == null) children = defaultChildren;
|
|
519
|
+
while (node = nodes.pop()) {
|
|
520
|
+
if (valued) node.value = +node.data.value;
|
|
521
|
+
if ((childs = children(node.data)) && (n = childs.length)) {
|
|
522
|
+
node.children = new Array(n);
|
|
523
|
+
for (i = n - 1; i >= 0; --i) {
|
|
524
|
+
nodes.push(child = node.children[i] = new Node$1(childs[i]));
|
|
525
|
+
child.parent = node;
|
|
526
|
+
child.depth = node.depth + 1;
|
|
527
|
+
}
|
|
528
|
+
}
|
|
529
|
+
}
|
|
530
|
+
return root.eachBefore(computeHeight);
|
|
531
|
+
}
|
|
532
|
+
function node_copy() {
|
|
533
|
+
return hierarchy(this).eachBefore(copyData);
|
|
534
|
+
}
|
|
535
|
+
function defaultChildren(d) {
|
|
536
|
+
return d.children;
|
|
537
|
+
}
|
|
538
|
+
function copyData(node) {
|
|
539
|
+
node.data = node.data.data;
|
|
540
|
+
}
|
|
541
|
+
function computeHeight(node) {
|
|
542
|
+
var height = 0;
|
|
543
|
+
do
|
|
544
|
+
node.height = height;
|
|
545
|
+
while ((node = node.parent) && node.height < ++height);
|
|
546
|
+
}
|
|
547
|
+
function Node$1(data) {
|
|
548
|
+
this.data = data;
|
|
549
|
+
this.depth = this.height = 0;
|
|
550
|
+
this.parent = null;
|
|
551
|
+
}
|
|
552
|
+
Node$1.prototype = hierarchy.prototype = {
|
|
553
|
+
constructor: Node$1,
|
|
554
|
+
count: count_default,
|
|
555
|
+
each: each_default,
|
|
556
|
+
eachAfter: eachAfter_default,
|
|
557
|
+
eachBefore: eachBefore_default,
|
|
558
|
+
sum: sum_default,
|
|
559
|
+
sort: sort_default,
|
|
560
|
+
path: path_default,
|
|
561
|
+
ancestors: ancestors_default,
|
|
562
|
+
descendants: descendants_default,
|
|
563
|
+
leaves: leaves_default,
|
|
564
|
+
links: links_default,
|
|
565
|
+
copy: node_copy
|
|
566
|
+
};
|
|
567
|
+
const name = "d3-flextree";
|
|
568
|
+
const version$1 = "2.1.2";
|
|
569
|
+
const main = "build/d3-flextree.js";
|
|
570
|
+
const module = "index";
|
|
571
|
+
const author = {
|
|
572
|
+
"name": "Chris Maloney",
|
|
573
|
+
"url": "http://chrismaloney.org"
|
|
574
|
+
};
|
|
575
|
+
const description = "Flexible tree layout algorithm that allows for variable node sizes.";
|
|
576
|
+
const keywords = [
|
|
577
|
+
"d3",
|
|
578
|
+
"d3-module",
|
|
579
|
+
"layout",
|
|
580
|
+
"tree",
|
|
581
|
+
"hierarchy",
|
|
582
|
+
"d3-hierarchy",
|
|
583
|
+
"plugin",
|
|
584
|
+
"d3-plugin",
|
|
585
|
+
"infovis",
|
|
586
|
+
"visualization",
|
|
587
|
+
"2d"
|
|
588
|
+
];
|
|
589
|
+
const homepage = "https://github.com/klortho/d3-flextree";
|
|
590
|
+
const license = "WTFPL";
|
|
591
|
+
const repository = {
|
|
592
|
+
"type": "git",
|
|
593
|
+
"url": "https://github.com/klortho/d3-flextree.git"
|
|
594
|
+
};
|
|
595
|
+
const scripts = {
|
|
596
|
+
"clean": "rm -rf build demo test",
|
|
597
|
+
"build:demo": "rollup -c --environment BUILD:demo",
|
|
598
|
+
"build:dev": "rollup -c --environment BUILD:dev",
|
|
599
|
+
"build:prod": "rollup -c --environment BUILD:prod",
|
|
600
|
+
"build:test": "rollup -c --environment BUILD:test",
|
|
601
|
+
"build": "rollup -c",
|
|
602
|
+
"lint": "eslint index.js src",
|
|
603
|
+
"test:main": "node test/bundle.js",
|
|
604
|
+
"test:browser": "node test/browser-tests.js",
|
|
605
|
+
"test": "npm-run-all test:*",
|
|
606
|
+
"prepare": "npm-run-all clean build lint test"
|
|
607
|
+
};
|
|
608
|
+
const dependencies = { "d3-hierarchy": "^1.1.5" };
|
|
609
|
+
const devDependencies = {
|
|
610
|
+
"babel-plugin-external-helpers": "^6.22.0",
|
|
611
|
+
"babel-preset-es2015-rollup": "^3.0.0",
|
|
612
|
+
"d3": "^4.13.0",
|
|
613
|
+
"d3-selection-multi": "^1.0.1",
|
|
614
|
+
"eslint": "^4.19.1",
|
|
615
|
+
"jsdom": "^11.6.2",
|
|
616
|
+
"npm-run-all": "^4.1.2",
|
|
617
|
+
"rollup": "^0.55.3",
|
|
618
|
+
"rollup-plugin-babel": "^2.7.1",
|
|
619
|
+
"rollup-plugin-commonjs": "^8.0.2",
|
|
620
|
+
"rollup-plugin-copy": "^0.2.3",
|
|
621
|
+
"rollup-plugin-json": "^2.3.0",
|
|
622
|
+
"rollup-plugin-node-resolve": "^3.0.2",
|
|
623
|
+
"rollup-plugin-uglify": "^3.0.0",
|
|
624
|
+
"uglify-es": "^3.3.9"
|
|
625
|
+
};
|
|
626
|
+
var { version } = {
|
|
627
|
+
name,
|
|
628
|
+
version: version$1,
|
|
629
|
+
main,
|
|
630
|
+
module,
|
|
631
|
+
"jsnext:main": "index",
|
|
632
|
+
author,
|
|
633
|
+
description,
|
|
634
|
+
keywords,
|
|
635
|
+
homepage,
|
|
636
|
+
license,
|
|
637
|
+
repository,
|
|
638
|
+
scripts,
|
|
639
|
+
dependencies,
|
|
640
|
+
devDependencies
|
|
641
|
+
};
|
|
642
|
+
var defaults = Object.freeze({
|
|
643
|
+
children: (data) => data.children,
|
|
644
|
+
nodeSize: (node) => node.data.size,
|
|
645
|
+
spacing: 0
|
|
646
|
+
});
|
|
647
|
+
function flextree(options) {
|
|
648
|
+
const opts = Object.assign({}, defaults, options);
|
|
649
|
+
function accessor(name) {
|
|
650
|
+
const opt = opts[name];
|
|
651
|
+
return typeof opt === "function" ? opt : () => opt;
|
|
652
|
+
}
|
|
653
|
+
function layout(tree) {
|
|
654
|
+
const wtree = wrap(getWrapper(), tree, (node) => node.children);
|
|
655
|
+
wtree.update();
|
|
656
|
+
return wtree.data;
|
|
657
|
+
}
|
|
658
|
+
function getFlexNode() {
|
|
659
|
+
const nodeSize = accessor("nodeSize");
|
|
660
|
+
const spacing = accessor("spacing");
|
|
661
|
+
return class FlexNode extends hierarchy.prototype.constructor {
|
|
662
|
+
constructor(data) {
|
|
663
|
+
super(data);
|
|
664
|
+
}
|
|
665
|
+
copy() {
|
|
666
|
+
const c = wrap(this.constructor, this, (node) => node.children);
|
|
667
|
+
c.each((node) => node.data = node.data.data);
|
|
668
|
+
return c;
|
|
669
|
+
}
|
|
670
|
+
get size() {
|
|
671
|
+
return nodeSize(this);
|
|
672
|
+
}
|
|
673
|
+
spacing(oNode) {
|
|
674
|
+
return spacing(this, oNode);
|
|
675
|
+
}
|
|
676
|
+
get nodes() {
|
|
677
|
+
return this.descendants();
|
|
678
|
+
}
|
|
679
|
+
get xSize() {
|
|
680
|
+
return this.size[0];
|
|
681
|
+
}
|
|
682
|
+
get ySize() {
|
|
683
|
+
return this.size[1];
|
|
684
|
+
}
|
|
685
|
+
get top() {
|
|
686
|
+
return this.y;
|
|
687
|
+
}
|
|
688
|
+
get bottom() {
|
|
689
|
+
return this.y + this.ySize;
|
|
690
|
+
}
|
|
691
|
+
get left() {
|
|
692
|
+
return this.x - this.xSize / 2;
|
|
693
|
+
}
|
|
694
|
+
get right() {
|
|
695
|
+
return this.x + this.xSize / 2;
|
|
696
|
+
}
|
|
697
|
+
get root() {
|
|
698
|
+
const ancs = this.ancestors();
|
|
699
|
+
return ancs[ancs.length - 1];
|
|
700
|
+
}
|
|
701
|
+
get numChildren() {
|
|
702
|
+
return this.hasChildren ? this.children.length : 0;
|
|
703
|
+
}
|
|
704
|
+
get hasChildren() {
|
|
705
|
+
return !this.noChildren;
|
|
706
|
+
}
|
|
707
|
+
get noChildren() {
|
|
708
|
+
return this.children === null;
|
|
709
|
+
}
|
|
710
|
+
get firstChild() {
|
|
711
|
+
return this.hasChildren ? this.children[0] : null;
|
|
712
|
+
}
|
|
713
|
+
get lastChild() {
|
|
714
|
+
return this.hasChildren ? this.children[this.numChildren - 1] : null;
|
|
715
|
+
}
|
|
716
|
+
get extents() {
|
|
717
|
+
return (this.children || []).reduce((acc, kid) => FlexNode.maxExtents(acc, kid.extents), this.nodeExtents);
|
|
718
|
+
}
|
|
719
|
+
get nodeExtents() {
|
|
720
|
+
return {
|
|
721
|
+
top: this.top,
|
|
722
|
+
bottom: this.bottom,
|
|
723
|
+
left: this.left,
|
|
724
|
+
right: this.right
|
|
725
|
+
};
|
|
726
|
+
}
|
|
727
|
+
static maxExtents(e0, e1) {
|
|
728
|
+
return {
|
|
729
|
+
top: Math.min(e0.top, e1.top),
|
|
730
|
+
bottom: Math.max(e0.bottom, e1.bottom),
|
|
731
|
+
left: Math.min(e0.left, e1.left),
|
|
732
|
+
right: Math.max(e0.right, e1.right)
|
|
733
|
+
};
|
|
734
|
+
}
|
|
735
|
+
};
|
|
736
|
+
}
|
|
737
|
+
function getWrapper() {
|
|
738
|
+
const FlexNode = getFlexNode();
|
|
739
|
+
const nodeSize = accessor("nodeSize");
|
|
740
|
+
const spacing = accessor("spacing");
|
|
741
|
+
return class extends FlexNode {
|
|
742
|
+
constructor(data) {
|
|
743
|
+
super(data);
|
|
744
|
+
Object.assign(this, {
|
|
745
|
+
x: 0,
|
|
746
|
+
y: 0,
|
|
747
|
+
relX: 0,
|
|
748
|
+
prelim: 0,
|
|
749
|
+
shift: 0,
|
|
750
|
+
change: 0,
|
|
751
|
+
lExt: this,
|
|
752
|
+
lExtRelX: 0,
|
|
753
|
+
lThr: null,
|
|
754
|
+
rExt: this,
|
|
755
|
+
rExtRelX: 0,
|
|
756
|
+
rThr: null
|
|
757
|
+
});
|
|
758
|
+
}
|
|
759
|
+
get size() {
|
|
760
|
+
return nodeSize(this.data);
|
|
761
|
+
}
|
|
762
|
+
spacing(oNode) {
|
|
763
|
+
return spacing(this.data, oNode.data);
|
|
764
|
+
}
|
|
765
|
+
get x() {
|
|
766
|
+
return this.data.x;
|
|
767
|
+
}
|
|
768
|
+
set x(v) {
|
|
769
|
+
this.data.x = v;
|
|
770
|
+
}
|
|
771
|
+
get y() {
|
|
772
|
+
return this.data.y;
|
|
773
|
+
}
|
|
774
|
+
set y(v) {
|
|
775
|
+
this.data.y = v;
|
|
776
|
+
}
|
|
777
|
+
update() {
|
|
778
|
+
layoutChildren(this);
|
|
779
|
+
resolveX(this);
|
|
780
|
+
return this;
|
|
781
|
+
}
|
|
782
|
+
};
|
|
783
|
+
}
|
|
784
|
+
function wrap(FlexClass, treeData, children) {
|
|
785
|
+
const _wrap = (data, parent) => {
|
|
786
|
+
const node = new FlexClass(data);
|
|
787
|
+
Object.assign(node, {
|
|
788
|
+
parent,
|
|
789
|
+
depth: parent === null ? 0 : parent.depth + 1,
|
|
790
|
+
height: 0,
|
|
791
|
+
length: 1
|
|
792
|
+
});
|
|
793
|
+
const kidsData = children(data) || [];
|
|
794
|
+
node.children = kidsData.length === 0 ? null : kidsData.map((kd) => _wrap(kd, node));
|
|
795
|
+
if (node.children) Object.assign(node, node.children.reduce((hl, kid) => ({
|
|
796
|
+
height: Math.max(hl.height, kid.height + 1),
|
|
797
|
+
length: hl.length + kid.length
|
|
798
|
+
}), node));
|
|
799
|
+
return node;
|
|
800
|
+
};
|
|
801
|
+
return _wrap(treeData, null);
|
|
802
|
+
}
|
|
803
|
+
Object.assign(layout, {
|
|
804
|
+
nodeSize(arg) {
|
|
805
|
+
return arguments.length ? (opts.nodeSize = arg, layout) : opts.nodeSize;
|
|
806
|
+
},
|
|
807
|
+
spacing(arg) {
|
|
808
|
+
return arguments.length ? (opts.spacing = arg, layout) : opts.spacing;
|
|
809
|
+
},
|
|
810
|
+
children(arg) {
|
|
811
|
+
return arguments.length ? (opts.children = arg, layout) : opts.children;
|
|
812
|
+
},
|
|
813
|
+
hierarchy(treeData, children) {
|
|
814
|
+
const kids = typeof children === "undefined" ? opts.children : children;
|
|
815
|
+
return wrap(getFlexNode(), treeData, kids);
|
|
816
|
+
},
|
|
817
|
+
dump(tree) {
|
|
818
|
+
const nodeSize = accessor("nodeSize");
|
|
819
|
+
const _dump = (i0) => (node) => {
|
|
820
|
+
const i1 = i0 + " ";
|
|
821
|
+
const i2 = i0 + " ";
|
|
822
|
+
const { x, y } = node;
|
|
823
|
+
const size = nodeSize(node);
|
|
824
|
+
const kids = node.children || [];
|
|
825
|
+
const kdumps = kids.length === 0 ? " " : `,${i1}children: [${i2}${kids.map(_dump(i2)).join(i2)}${i1}],${i0}`;
|
|
826
|
+
return `{ size: [${size.join(", ")}],${i1}x: ${x}, y: ${y}${kdumps}},`;
|
|
827
|
+
};
|
|
828
|
+
return _dump("\n")(tree);
|
|
829
|
+
}
|
|
830
|
+
});
|
|
831
|
+
return layout;
|
|
832
|
+
}
|
|
833
|
+
flextree.version = version;
|
|
834
|
+
var layoutChildren = (w, y = 0) => {
|
|
835
|
+
w.y = y;
|
|
836
|
+
(w.children || []).reduce((acc, kid) => {
|
|
837
|
+
const [i, lastLows] = acc;
|
|
838
|
+
layoutChildren(kid, w.y + w.ySize);
|
|
839
|
+
const lowY = (i === 0 ? kid.lExt : kid.rExt).bottom;
|
|
840
|
+
if (i !== 0) separate(w, i, lastLows);
|
|
841
|
+
const lows = updateLows(lowY, i, lastLows);
|
|
842
|
+
return [i + 1, lows];
|
|
843
|
+
}, [0, null]);
|
|
844
|
+
shiftChange(w);
|
|
845
|
+
positionRoot(w);
|
|
846
|
+
return w;
|
|
847
|
+
};
|
|
848
|
+
var resolveX = (w, prevSum, parentX) => {
|
|
849
|
+
if (typeof prevSum === "undefined") {
|
|
850
|
+
prevSum = -w.relX - w.prelim;
|
|
851
|
+
parentX = 0;
|
|
852
|
+
}
|
|
853
|
+
const sum = prevSum + w.relX;
|
|
854
|
+
w.relX = sum + w.prelim - parentX;
|
|
855
|
+
w.prelim = 0;
|
|
856
|
+
w.x = parentX + w.relX;
|
|
857
|
+
(w.children || []).forEach((k) => resolveX(k, sum, w.x));
|
|
858
|
+
return w;
|
|
859
|
+
};
|
|
860
|
+
var shiftChange = (w) => {
|
|
861
|
+
(w.children || []).reduce((acc, child) => {
|
|
862
|
+
const [lastShiftSum, lastChangeSum] = acc;
|
|
863
|
+
const shiftSum = lastShiftSum + child.shift;
|
|
864
|
+
const changeSum = lastChangeSum + shiftSum + child.change;
|
|
865
|
+
child.relX += changeSum;
|
|
866
|
+
return [shiftSum, changeSum];
|
|
867
|
+
}, [0, 0]);
|
|
868
|
+
};
|
|
869
|
+
var separate = (w, i, lows) => {
|
|
870
|
+
const lSib = w.children[i - 1];
|
|
871
|
+
const curSubtree = w.children[i];
|
|
872
|
+
let rContour = lSib;
|
|
873
|
+
let rSumMods = lSib.relX;
|
|
874
|
+
let lContour = curSubtree;
|
|
875
|
+
let lSumMods = curSubtree.relX;
|
|
876
|
+
let isFirst = true;
|
|
877
|
+
while (rContour && lContour) {
|
|
878
|
+
if (rContour.bottom > lows.lowY) lows = lows.next;
|
|
879
|
+
const dist = rSumMods + rContour.prelim - (lSumMods + lContour.prelim) + rContour.xSize / 2 + lContour.xSize / 2 + rContour.spacing(lContour);
|
|
880
|
+
if (dist > 0 || dist < 0 && isFirst) {
|
|
881
|
+
lSumMods += dist;
|
|
882
|
+
moveSubtree(curSubtree, dist);
|
|
883
|
+
distributeExtra(w, i, lows.index, dist);
|
|
884
|
+
}
|
|
885
|
+
isFirst = false;
|
|
886
|
+
const rightBottom = rContour.bottom;
|
|
887
|
+
const leftBottom = lContour.bottom;
|
|
888
|
+
if (rightBottom <= leftBottom) {
|
|
889
|
+
rContour = nextRContour(rContour);
|
|
890
|
+
if (rContour) rSumMods += rContour.relX;
|
|
891
|
+
}
|
|
892
|
+
if (rightBottom >= leftBottom) {
|
|
893
|
+
lContour = nextLContour(lContour);
|
|
894
|
+
if (lContour) lSumMods += lContour.relX;
|
|
895
|
+
}
|
|
896
|
+
}
|
|
897
|
+
if (!rContour && lContour) setLThr(w, i, lContour, lSumMods);
|
|
898
|
+
else if (rContour && !lContour) setRThr(w, i, rContour, rSumMods);
|
|
899
|
+
};
|
|
900
|
+
var moveSubtree = (subtree, distance) => {
|
|
901
|
+
subtree.relX += distance;
|
|
902
|
+
subtree.lExtRelX += distance;
|
|
903
|
+
subtree.rExtRelX += distance;
|
|
904
|
+
};
|
|
905
|
+
var distributeExtra = (w, curSubtreeI, leftSibI, dist) => {
|
|
906
|
+
const curSubtree = w.children[curSubtreeI];
|
|
907
|
+
const n = curSubtreeI - leftSibI;
|
|
908
|
+
if (n > 1) {
|
|
909
|
+
const delta = dist / n;
|
|
910
|
+
w.children[leftSibI + 1].shift += delta;
|
|
911
|
+
curSubtree.shift -= delta;
|
|
912
|
+
curSubtree.change -= dist - delta;
|
|
913
|
+
}
|
|
914
|
+
};
|
|
915
|
+
var nextLContour = (w) => {
|
|
916
|
+
return w.hasChildren ? w.firstChild : w.lThr;
|
|
917
|
+
};
|
|
918
|
+
var nextRContour = (w) => {
|
|
919
|
+
return w.hasChildren ? w.lastChild : w.rThr;
|
|
920
|
+
};
|
|
921
|
+
var setLThr = (w, i, lContour, lSumMods) => {
|
|
922
|
+
const firstChild = w.firstChild;
|
|
923
|
+
const lExt = firstChild.lExt;
|
|
924
|
+
const curSubtree = w.children[i];
|
|
925
|
+
lExt.lThr = lContour;
|
|
926
|
+
const diff = lSumMods - lContour.relX - firstChild.lExtRelX;
|
|
927
|
+
lExt.relX += diff;
|
|
928
|
+
lExt.prelim -= diff;
|
|
929
|
+
firstChild.lExt = curSubtree.lExt;
|
|
930
|
+
firstChild.lExtRelX = curSubtree.lExtRelX;
|
|
931
|
+
};
|
|
932
|
+
var setRThr = (w, i, rContour, rSumMods) => {
|
|
933
|
+
const curSubtree = w.children[i];
|
|
934
|
+
const rExt = curSubtree.rExt;
|
|
935
|
+
const lSib = w.children[i - 1];
|
|
936
|
+
rExt.rThr = rContour;
|
|
937
|
+
const diff = rSumMods - rContour.relX - curSubtree.rExtRelX;
|
|
938
|
+
rExt.relX += diff;
|
|
939
|
+
rExt.prelim -= diff;
|
|
940
|
+
curSubtree.rExt = lSib.rExt;
|
|
941
|
+
curSubtree.rExtRelX = lSib.rExtRelX;
|
|
942
|
+
};
|
|
943
|
+
var positionRoot = (w) => {
|
|
944
|
+
if (w.hasChildren) {
|
|
945
|
+
const k0 = w.firstChild;
|
|
946
|
+
const kf = w.lastChild;
|
|
947
|
+
const prelim = (k0.prelim + k0.relX - k0.xSize / 2 + kf.relX + kf.prelim + kf.xSize / 2) / 2;
|
|
948
|
+
Object.assign(w, {
|
|
949
|
+
prelim,
|
|
950
|
+
lExt: k0.lExt,
|
|
951
|
+
lExtRelX: k0.lExtRelX,
|
|
952
|
+
rExt: kf.rExt,
|
|
953
|
+
rExtRelX: kf.rExtRelX
|
|
954
|
+
});
|
|
955
|
+
}
|
|
956
|
+
};
|
|
957
|
+
var updateLows = (lowY, index, lastLows) => {
|
|
958
|
+
while (lastLows !== null && lowY >= lastLows.lowY) lastLows = lastLows.next;
|
|
959
|
+
return {
|
|
960
|
+
lowY,
|
|
961
|
+
index,
|
|
962
|
+
next: lastLows
|
|
963
|
+
};
|
|
964
|
+
};
|
|
965
|
+
var style_default = ".markmap {\n --markmap-max-width: 9999px;\n --markmap-a-color: #0097e6;\n --markmap-a-hover-color: #00a8ff;\n --markmap-code-bg: #f0f0f0;\n --markmap-code-color: #555;\n --markmap-highlight-bg: #ffeaa7;\n --markmap-table-border: 1px solid currentColor;\n --markmap-font: 300 16px/20px sans-serif;\n --markmap-circle-open-bg: #fff;\n --markmap-text-color: #333;\n --markmap-highlight-node-bg: #ff02;\n\n font: var(--markmap-font);\n color: var(--markmap-text-color);\n}\n\n .markmap-link {\n fill: none;\n }\n\n .markmap-node > circle {\n cursor: pointer;\n }\n\n .markmap-node-hovered > foreignObject > div > div {\n padding: 2px 6px;\n border-radius: 14px;\n border: 2px solid #d9d9d9;\n }\n\n .markmap-selected > foreignObject > div > div,\n .markmap-selected.markmap-node-hovered > foreignObject > div > div {\n padding: 2px 6px;\n border-radius: 14px;\n border: 2px solid #b4b4b4;\n }\n\n .markmap-selected > circle {\n opacity: 0 !important;\n pointer-events: none;\n }\n\n .markmap-collapse-on-hover .markmap-node > circle {\n opacity: 0;\n transition: opacity 0.2s;\n }\n\n .markmap-collapse-on-hover .markmap-node:hover > circle {\n opacity: 1;\n }\n\n .markmap-foreign {\n display: inline-block;\n }\n\n .markmap-foreign > div > div {\n padding: 4px 6px;\n }\n\n .markmap-foreign .markmap-edit-wrapper {\n position: relative;\n width: 100%;\n padding: 4px;\n background: white;\n border-radius: 4px;\n box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);\n animation: fadeIn 0.2s ease-in;\n }\n\n .markmap-foreign .markmap-edit-input {\n width: 100%;\n padding: 8px 12px;\n border: 2px solid #4a90e2;\n border-radius: 4px;\n font-size: 14px;\n font-family: inherit;\n outline: none;\n background: #f8f9fa;\n transition: all 0.2s;\n }\n\n .markmap-foreign .markmap-edit-input:focus {\n border-color: #2d7dd2;\n background: white;\n box-shadow: 0 0 0 3px rgba(74, 144, 226, 0.1);\n }\n\n .markmap-foreign p {\n margin: 0;\n }\n\n .markmap-foreign a {\n color: var(--markmap-a-color);\n }\n\n .markmap-foreign a:hover {\n color: var(--markmap-a-hover-color);\n }\n\n .markmap-foreign code {\n padding: 0.25em;\n font-size: calc(1em - 2px);\n color: var(--markmap-code-color);\n background-color: var(--markmap-code-bg);\n border-radius: 2px;\n }\n\n .markmap-foreign pre {\n margin: 0;\n }\n\n .markmap-foreign pre > code {\n display: block;\n }\n\n .markmap-foreign del {\n text-decoration: line-through;\n }\n\n .markmap-foreign em {\n font-style: italic;\n }\n\n .markmap-foreign strong {\n font-weight: bold;\n }\n\n .markmap-foreign mark {\n background: var(--markmap-highlight-bg);\n }\n\n .markmap-foreign table,\n .markmap-foreign th,\n .markmap-foreign td {\n border-collapse: collapse;\n border: var(--markmap-table-border);\n }\n\n .markmap-foreign img {\n display: inline-block;\n }\n\n .markmap-foreign svg {\n fill: currentColor;\n }\n\n .markmap-foreign > div {\n width: var(--markmap-max-width);\n text-align: left;\n }\n\n .markmap-foreign > div > div {\n display: inline-block;\n max-width: var(--markmap-wrap-width, 30em);\n overflow-wrap: break-word;\n word-break: break-word;\n white-space: normal;\n }\n\n .markmap-highlight rect {\n fill: var(--markmap-highlight-node-bg);\n }\n\n.markmap-dark .markmap {\n --markmap-code-bg: #1a1b26;\n --markmap-code-color: #ddd;\n --markmap-circle-open-bg: #444;\n --markmap-text-color: #eee;\n}\n\n@keyframes fadeIn {\n from {\n opacity: 0;\n transform: scale(0.95);\n }\n to {\n opacity: 1;\n transform: scale(1);\n }\n}\n";
|
|
966
|
+
var SELECTOR_NODE$1 = "g.markmap-node";
|
|
967
|
+
/**
|
|
968
|
+
* Manages all node add / edit / delete actions and their associated UI overlays.
|
|
969
|
+
*
|
|
970
|
+
* Responsibilities:
|
|
971
|
+
* - Overlay lifecycle: + button, new-node input, edit input
|
|
972
|
+
* - Tree mutations: insert child, insert sibling, delete node
|
|
973
|
+
* - Selection state: editingNode, selectedNode
|
|
974
|
+
*
|
|
975
|
+
* view.ts creates one ActionManager per Markmap instance and delegates to it.
|
|
976
|
+
*/
|
|
977
|
+
var ActionManager = class {
|
|
978
|
+
constructor(ctx) {
|
|
979
|
+
this.ctx = ctx;
|
|
980
|
+
this.editingNode = null;
|
|
981
|
+
this.selectedNode = null;
|
|
982
|
+
}
|
|
983
|
+
_getNodeContentEl(node) {
|
|
984
|
+
const el = this.ctx.findElement(node);
|
|
985
|
+
if (!el) return null;
|
|
986
|
+
return (0, d3.select)(el.g).select("foreignObject").select("div").select("div").node() || null;
|
|
987
|
+
}
|
|
988
|
+
_getOverlayRoot() {
|
|
989
|
+
return this.ctx.svg.node()?.parentElement || document.body;
|
|
990
|
+
}
|
|
991
|
+
_positionOverlayToEl(wrap, targetEl, opts) {
|
|
992
|
+
const overlayRoot = this._getOverlayRoot();
|
|
993
|
+
if (window.getComputedStyle(overlayRoot).position === "static") overlayRoot.style.position = "relative";
|
|
994
|
+
const targetRect = targetEl.getBoundingClientRect();
|
|
995
|
+
const rootRect = overlayRoot.getBoundingClientRect();
|
|
996
|
+
const dx = opts?.dx ?? 0;
|
|
997
|
+
const dy = opts?.dy ?? 0;
|
|
998
|
+
const minW = opts?.minW ?? 0;
|
|
999
|
+
const minH = opts?.minH ?? 0;
|
|
1000
|
+
let left = targetRect.left - rootRect.left + dx;
|
|
1001
|
+
let top = targetRect.top - rootRect.top + dy;
|
|
1002
|
+
if (opts?.anchor === "br") {
|
|
1003
|
+
left = targetRect.right - rootRect.left + dx;
|
|
1004
|
+
top = targetRect.bottom - rootRect.top + dy;
|
|
1005
|
+
} else if (opts?.anchor === "r") {
|
|
1006
|
+
left = targetRect.right - rootRect.left + dx;
|
|
1007
|
+
top = targetRect.top - rootRect.top + dy;
|
|
1008
|
+
}
|
|
1009
|
+
wrap.style.left = `${left}px`;
|
|
1010
|
+
wrap.style.top = `${top}px`;
|
|
1011
|
+
if (minW) wrap.style.width = `${Math.max(minW, targetRect.width)}px`;
|
|
1012
|
+
if (minH) wrap.style.height = `${Math.max(minH, targetRect.height)}px`;
|
|
1013
|
+
}
|
|
1014
|
+
_safeRemoveEl(el) {
|
|
1015
|
+
try {
|
|
1016
|
+
if (el.parentNode) el.remove();
|
|
1017
|
+
} catch {}
|
|
1018
|
+
}
|
|
1019
|
+
_clearSelectionCss() {
|
|
1020
|
+
if (!this.ctx.options.clickBorder) return;
|
|
1021
|
+
this.ctx.g.selectAll(childSelector(SELECTOR_NODE$1)).classed("markmap-selected", false);
|
|
1022
|
+
}
|
|
1023
|
+
_findParent(target) {
|
|
1024
|
+
if (!this.ctx.state.data) return null;
|
|
1025
|
+
let result = null;
|
|
1026
|
+
walkTree(this.ctx.state.data, (item, next) => {
|
|
1027
|
+
if (result) return;
|
|
1028
|
+
const children = item.children || [];
|
|
1029
|
+
for (let i = 0; i < children.length; i++) if (children[i] === target) {
|
|
1030
|
+
result = {
|
|
1031
|
+
parent: item,
|
|
1032
|
+
index: i
|
|
1033
|
+
};
|
|
1034
|
+
return;
|
|
1035
|
+
}
|
|
1036
|
+
next();
|
|
1037
|
+
});
|
|
1038
|
+
return result;
|
|
1039
|
+
}
|
|
1040
|
+
/** Create a blank child INode and append it to parent.children. */
|
|
1041
|
+
_insertNewChildNode(parent) {
|
|
1042
|
+
let maxId = 0;
|
|
1043
|
+
walkTree(this.ctx.state.data, (item, next) => {
|
|
1044
|
+
if (item.state?.id > maxId) maxId = item.state.id;
|
|
1045
|
+
next();
|
|
1046
|
+
});
|
|
1047
|
+
const newId = maxId + 1;
|
|
1048
|
+
const depth = (parent.state?.depth ?? 0) + 1;
|
|
1049
|
+
const placeholder = " ";
|
|
1050
|
+
const node = {
|
|
1051
|
+
content: placeholder,
|
|
1052
|
+
children: [],
|
|
1053
|
+
payload: {},
|
|
1054
|
+
state: {
|
|
1055
|
+
id: newId,
|
|
1056
|
+
depth,
|
|
1057
|
+
key: `${parent.state?.id}.${newId}` + simpleHash(placeholder),
|
|
1058
|
+
path: [parent.state?.path, newId].filter(Boolean).join("."),
|
|
1059
|
+
rect: {
|
|
1060
|
+
x: 0,
|
|
1061
|
+
y: 0,
|
|
1062
|
+
width: 0,
|
|
1063
|
+
height: 0
|
|
1064
|
+
},
|
|
1065
|
+
size: [0, 0]
|
|
1066
|
+
}
|
|
1067
|
+
};
|
|
1068
|
+
parent.children = [...parent.children || [], node];
|
|
1069
|
+
this.ctx.options.color(node);
|
|
1070
|
+
return node;
|
|
1071
|
+
}
|
|
1072
|
+
/**
|
|
1073
|
+
* Core overlay builder shared by _editNewNode and handleEdit.
|
|
1074
|
+
*
|
|
1075
|
+
* @param node - The INode being edited (content will be mutated on save).
|
|
1076
|
+
* @param contentNode - The inner <div> whose position / style drives the overlay.
|
|
1077
|
+
* @param opts.initialValue - Starting text in the input ('': new node, textContent: existing).
|
|
1078
|
+
* @param opts.minWidth - Minimum overlay width in px.
|
|
1079
|
+
* @param opts.placeholder - Input placeholder (only shown when initialValue is empty).
|
|
1080
|
+
* @param opts.selectAll - Whether to select all text on focus (true for existing nodes).
|
|
1081
|
+
* @param opts.onSave - Called after the overlay is torn down on a successful save.
|
|
1082
|
+
* @param opts.onCancel - Called after the overlay is torn down on cancel / empty input.
|
|
1083
|
+
*/
|
|
1084
|
+
_openEditOverlay(node, contentNode, opts) {
|
|
1085
|
+
const overlayRoot = this._getOverlayRoot();
|
|
1086
|
+
if (window.getComputedStyle(overlayRoot).position === "static") overlayRoot.style.position = "relative";
|
|
1087
|
+
const targetRect = contentNode.getBoundingClientRect();
|
|
1088
|
+
const rootRect = overlayRoot.getBoundingClientRect();
|
|
1089
|
+
const wrap = document.createElement("div");
|
|
1090
|
+
wrap.className = "markmap-node-edit-overlay";
|
|
1091
|
+
wrap.style.cssText = `
|
|
1057
1092
|
position: absolute;
|
|
1058
1093
|
left: ${targetRect.left - rootRect.left}px;
|
|
1059
1094
|
top: ${targetRect.top - rootRect.top}px;
|
|
@@ -1062,15 +1097,15 @@
|
|
|
1062
1097
|
z-index: 9999;
|
|
1063
1098
|
pointer-events: auto;
|
|
1064
1099
|
`;
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1100
|
+
const computedStyle = window.getComputedStyle(contentNode);
|
|
1101
|
+
const input = document.createElement("input");
|
|
1102
|
+
input.type = "text";
|
|
1103
|
+
input.value = opts.initialValue;
|
|
1104
|
+
if (opts.placeholder) input.placeholder = opts.placeholder;
|
|
1105
|
+
input.autocomplete = "off";
|
|
1106
|
+
input.spellcheck = false;
|
|
1107
|
+
input.className = "markmap-node-edit-overlay-input";
|
|
1108
|
+
input.style.cssText = `
|
|
1074
1109
|
width: 100%;
|
|
1075
1110
|
height: 100%;
|
|
1076
1111
|
margin: 0;
|
|
@@ -1087,189 +1122,191 @@
|
|
|
1087
1122
|
letter-spacing: ${computedStyle.letterSpacing};
|
|
1088
1123
|
color: ${computedStyle.color};
|
|
1089
1124
|
`;
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
|
|
1180
|
-
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
|
|
1206
|
-
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
|
|
1217
|
-
|
|
1218
|
-
|
|
1219
|
-
|
|
1220
|
-
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
|
|
1244
|
-
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
|
-
|
|
1125
|
+
const prevVisibility = contentNode.style.visibility;
|
|
1126
|
+
contentNode.style.visibility = "hidden";
|
|
1127
|
+
wrap.appendChild(input);
|
|
1128
|
+
overlayRoot.appendChild(wrap);
|
|
1129
|
+
this.editOverlay = {
|
|
1130
|
+
wrap,
|
|
1131
|
+
input,
|
|
1132
|
+
contentEl: contentNode,
|
|
1133
|
+
prevVisibility
|
|
1134
|
+
};
|
|
1135
|
+
setTimeout(() => {
|
|
1136
|
+
input.focus();
|
|
1137
|
+
if (opts.selectAll) input.select();
|
|
1138
|
+
}, 0);
|
|
1139
|
+
const escapeHtml = (text) => text.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """);
|
|
1140
|
+
let cleanedUp = false;
|
|
1141
|
+
const cleanup = (cancel) => {
|
|
1142
|
+
if (cleanedUp) return;
|
|
1143
|
+
cleanedUp = true;
|
|
1144
|
+
input.removeEventListener("keydown", handleKeydown);
|
|
1145
|
+
input.removeEventListener("blur", handleBlur);
|
|
1146
|
+
if (this.editOverlay) {
|
|
1147
|
+
this.editOverlay.contentEl.style.visibility = this.editOverlay.prevVisibility;
|
|
1148
|
+
this.editOverlay.wrap.remove();
|
|
1149
|
+
this.editOverlay = void 0;
|
|
1150
|
+
} else {
|
|
1151
|
+
contentNode.style.visibility = prevVisibility;
|
|
1152
|
+
wrap.remove();
|
|
1153
|
+
}
|
|
1154
|
+
this.editingNode = null;
|
|
1155
|
+
if (cancel) opts.onCancel();
|
|
1156
|
+
else opts.onSave(escapeHtml(input.value.trim()));
|
|
1157
|
+
};
|
|
1158
|
+
const handleKeydown = (e) => {
|
|
1159
|
+
if (e.key === "Enter") {
|
|
1160
|
+
e.preventDefault();
|
|
1161
|
+
e.stopPropagation();
|
|
1162
|
+
const text = input.value.trim();
|
|
1163
|
+
if (text) {
|
|
1164
|
+
node.content = escapeHtml(text);
|
|
1165
|
+
cleanup(false);
|
|
1166
|
+
} else cleanup(true);
|
|
1167
|
+
} else if (e.key === "Escape") {
|
|
1168
|
+
e.preventDefault();
|
|
1169
|
+
e.stopPropagation();
|
|
1170
|
+
cleanup(true);
|
|
1171
|
+
}
|
|
1172
|
+
};
|
|
1173
|
+
const handleBlur = () => {
|
|
1174
|
+
setTimeout(() => {
|
|
1175
|
+
if (document.activeElement !== input) {
|
|
1176
|
+
const text = input.value.trim();
|
|
1177
|
+
if (text) {
|
|
1178
|
+
node.content = escapeHtml(text);
|
|
1179
|
+
cleanup(false);
|
|
1180
|
+
} else cleanup(true);
|
|
1181
|
+
}
|
|
1182
|
+
}, 100);
|
|
1183
|
+
};
|
|
1184
|
+
input.addEventListener("keydown", handleKeydown);
|
|
1185
|
+
input.addEventListener("blur", handleBlur);
|
|
1186
|
+
}
|
|
1187
|
+
/**
|
|
1188
|
+
* Open an edit overlay for a freshly-inserted node.
|
|
1189
|
+
* Empty input → confirm saves; blank input → cancels and removes the node from the tree.
|
|
1190
|
+
*/
|
|
1191
|
+
_editNewNode(node, parent) {
|
|
1192
|
+
const element = this.ctx.findElement(node);
|
|
1193
|
+
if (!element) return;
|
|
1194
|
+
this.editingNode = node;
|
|
1195
|
+
const contentNode = (0, d3.select)(element.g).select("foreignObject").select("div").select("div").node();
|
|
1196
|
+
if (!contentNode) return;
|
|
1197
|
+
this._openEditOverlay(node, contentNode, {
|
|
1198
|
+
initialValue: "",
|
|
1199
|
+
minWidth: 120,
|
|
1200
|
+
placeholder: this.ctx.options.inputPlaceholder,
|
|
1201
|
+
selectAll: false,
|
|
1202
|
+
onCancel: () => {
|
|
1203
|
+
parent.children = (parent.children || []).filter((c) => c !== node);
|
|
1204
|
+
this.hideAddUI();
|
|
1205
|
+
this.selectedNode = null;
|
|
1206
|
+
this._clearSelectionCss();
|
|
1207
|
+
this.ctx.renderData();
|
|
1208
|
+
},
|
|
1209
|
+
onSave: () => {
|
|
1210
|
+
this.ctx.options.onNodeAdd?.(parent, node);
|
|
1211
|
+
this.hideAddUI();
|
|
1212
|
+
this.ctx.renderData().then(() => {
|
|
1213
|
+
const showPlus = () => {
|
|
1214
|
+
this.selectedNode = node;
|
|
1215
|
+
if (this.ctx.options.clickBorder) this.ctx.g.selectAll(childSelector(SELECTOR_NODE$1)).classed("markmap-selected", (n) => n === node);
|
|
1216
|
+
this.showAddUI(node);
|
|
1217
|
+
};
|
|
1218
|
+
if (this.ctx.options.duration > 0) setTimeout(showPlus, this.ctx.options.duration);
|
|
1219
|
+
else showPlus();
|
|
1220
|
+
});
|
|
1221
|
+
}
|
|
1222
|
+
});
|
|
1223
|
+
}
|
|
1224
|
+
/** Reposition all active overlays after zoom / pan. */
|
|
1225
|
+
repositionOverlays() {
|
|
1226
|
+
if (this.addUI) {
|
|
1227
|
+
const contentEl = this._getNodeContentEl(this.addUI.node);
|
|
1228
|
+
if (contentEl) {
|
|
1229
|
+
const svgEl = this.ctx.svg.node();
|
|
1230
|
+
const scale = svgEl ? (0, d3.zoomTransform)(svgEl).k : 1;
|
|
1231
|
+
const btnSize = Math.round(16 * scale);
|
|
1232
|
+
const fontSize = Math.round(14 * scale);
|
|
1233
|
+
this.addUI.btn.style.width = `${btnSize}px`;
|
|
1234
|
+
this.addUI.btn.style.height = `${btnSize}px`;
|
|
1235
|
+
this.addUI.btn.style.fontSize = `${fontSize}px`;
|
|
1236
|
+
this._positionOverlayToEl(this.addUI.wrap, contentEl, {
|
|
1237
|
+
anchor: "br",
|
|
1238
|
+
dx: Math.round(14 * scale),
|
|
1239
|
+
dy: 0
|
|
1240
|
+
});
|
|
1241
|
+
}
|
|
1242
|
+
}
|
|
1243
|
+
if (this.addInputUI) {
|
|
1244
|
+
const contentEl = this._getNodeContentEl(this.addInputUI.node);
|
|
1245
|
+
if (contentEl) {
|
|
1246
|
+
this._positionOverlayToEl(this.addInputUI.wrap, contentEl, {
|
|
1247
|
+
anchor: "r",
|
|
1248
|
+
dx: 16,
|
|
1249
|
+
dy: 0
|
|
1250
|
+
});
|
|
1251
|
+
const inputH = 30;
|
|
1252
|
+
const nodeH = contentEl.getBoundingClientRect().height;
|
|
1253
|
+
const currentTop = parseFloat(this.addInputUI.wrap.style.top) || 0;
|
|
1254
|
+
this.addInputUI.wrap.style.top = `${currentTop + nodeH / 2 - inputH / 2}px`;
|
|
1255
|
+
}
|
|
1256
|
+
}
|
|
1257
|
+
if (this.editOverlay) {
|
|
1258
|
+
const overlayRoot = this._getOverlayRoot();
|
|
1259
|
+
const targetRect = this.editOverlay.contentEl.getBoundingClientRect();
|
|
1260
|
+
const rootRect = overlayRoot.getBoundingClientRect();
|
|
1261
|
+
this.editOverlay.wrap.style.left = `${targetRect.left - rootRect.left}px`;
|
|
1262
|
+
this.editOverlay.wrap.style.top = `${targetRect.top - rootRect.top}px`;
|
|
1263
|
+
this.editOverlay.wrap.style.width = `${Math.max(40, targetRect.width)}px`;
|
|
1264
|
+
this.editOverlay.wrap.style.height = `${Math.max(20, targetRect.height)}px`;
|
|
1265
|
+
}
|
|
1266
|
+
}
|
|
1267
|
+
/** Hide and destroy the + button and any associated input overlay. */
|
|
1268
|
+
hideAddUI() {
|
|
1269
|
+
if (this.addInputUI) {
|
|
1270
|
+
this._safeRemoveEl(this.addInputUI.wrap);
|
|
1271
|
+
this.addInputUI = void 0;
|
|
1272
|
+
}
|
|
1273
|
+
if (this.addUI) {
|
|
1274
|
+
this.addUI.cleanupDoc();
|
|
1275
|
+
this._safeRemoveEl(this.addUI.wrap);
|
|
1276
|
+
this.addUI = void 0;
|
|
1277
|
+
}
|
|
1278
|
+
}
|
|
1279
|
+
/** Show the + button anchored to the bottom-right corner of `node`. */
|
|
1280
|
+
showAddUI(node) {
|
|
1281
|
+
if (!this.ctx.options.addable) return;
|
|
1282
|
+
if (this.editingNode) return;
|
|
1283
|
+
const contentEl = this._getNodeContentEl(node);
|
|
1284
|
+
if (!contentEl) return;
|
|
1285
|
+
if (this.addUI?.node === node) {
|
|
1286
|
+
this._positionOverlayToEl(this.addUI.wrap, contentEl, {
|
|
1287
|
+
anchor: "br",
|
|
1288
|
+
dx: 14,
|
|
1289
|
+
dy: 0
|
|
1290
|
+
});
|
|
1291
|
+
return;
|
|
1292
|
+
}
|
|
1293
|
+
this.hideAddUI();
|
|
1294
|
+
const overlayRoot = this._getOverlayRoot();
|
|
1295
|
+
const wrap = document.createElement("div");
|
|
1296
|
+
wrap.style.cssText = `
|
|
1260
1297
|
position: absolute;
|
|
1261
1298
|
z-index: 9999;
|
|
1262
1299
|
pointer-events: auto;
|
|
1263
1300
|
`;
|
|
1264
|
-
|
|
1265
|
-
|
|
1266
|
-
|
|
1267
|
-
|
|
1268
|
-
|
|
1269
|
-
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
|
|
1301
|
+
const svgEl = this.ctx.svg.node();
|
|
1302
|
+
const scale = svgEl ? (0, d3.zoomTransform)(svgEl).k : 1;
|
|
1303
|
+
const btnSize = Math.round(16 * scale);
|
|
1304
|
+
const fontSize = Math.round(14 * scale);
|
|
1305
|
+
const btn = document.createElement("button");
|
|
1306
|
+
btn.type = "button";
|
|
1307
|
+
btn.className = "markmap-add-btn";
|
|
1308
|
+
btn.textContent = "+";
|
|
1309
|
+
btn.style.cssText = `
|
|
1273
1310
|
width: ${btnSize}px;
|
|
1274
1311
|
height: ${btnSize}px;
|
|
1275
1312
|
border-radius: 50%;
|
|
@@ -1288,872 +1325,784 @@
|
|
|
1288
1325
|
align-items: center;
|
|
1289
1326
|
justify-content: center;
|
|
1290
1327
|
`;
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
|
|
1300
|
-
|
|
1301
|
-
|
|
1302
|
-
|
|
1303
|
-
|
|
1304
|
-
|
|
1305
|
-
|
|
1306
|
-
|
|
1307
|
-
|
|
1308
|
-
|
|
1309
|
-
|
|
1310
|
-
|
|
1311
|
-
|
|
1312
|
-
|
|
1313
|
-
|
|
1314
|
-
|
|
1315
|
-
|
|
1316
|
-
|
|
1317
|
-
|
|
1318
|
-
|
|
1319
|
-
|
|
1320
|
-
|
|
1321
|
-
|
|
1322
|
-
|
|
1323
|
-
|
|
1324
|
-
|
|
1325
|
-
|
|
1326
|
-
|
|
1327
|
-
|
|
1328
|
-
|
|
1329
|
-
|
|
1330
|
-
|
|
1331
|
-
|
|
1332
|
-
|
|
1333
|
-
|
|
1334
|
-
|
|
1335
|
-
|
|
1336
|
-
|
|
1337
|
-
|
|
1338
|
-
|
|
1339
|
-
|
|
1340
|
-
|
|
1341
|
-
|
|
1342
|
-
|
|
1343
|
-
|
|
1344
|
-
|
|
1345
|
-
|
|
1346
|
-
|
|
1347
|
-
|
|
1348
|
-
|
|
1349
|
-
|
|
1350
|
-
|
|
1351
|
-
|
|
1352
|
-
|
|
1353
|
-
|
|
1354
|
-
|
|
1355
|
-
|
|
1356
|
-
|
|
1357
|
-
|
|
1358
|
-
|
|
1359
|
-
|
|
1360
|
-
|
|
1361
|
-
|
|
1362
|
-
|
|
1363
|
-
|
|
1364
|
-
|
|
1365
|
-
|
|
1366
|
-
|
|
1367
|
-
|
|
1368
|
-
|
|
1369
|
-
|
|
1370
|
-
|
|
1371
|
-
|
|
1372
|
-
|
|
1373
|
-
|
|
1374
|
-
|
|
1375
|
-
|
|
1376
|
-
|
|
1377
|
-
|
|
1378
|
-
|
|
1379
|
-
|
|
1380
|
-
|
|
1381
|
-
|
|
1382
|
-
|
|
1383
|
-
|
|
1384
|
-
|
|
1385
|
-
|
|
1386
|
-
|
|
1387
|
-
|
|
1388
|
-
|
|
1389
|
-
|
|
1390
|
-
|
|
1391
|
-
|
|
1392
|
-
|
|
1393
|
-
|
|
1394
|
-
|
|
1395
|
-
|
|
1396
|
-
|
|
1397
|
-
|
|
1398
|
-
|
|
1399
|
-
|
|
1400
|
-
|
|
1401
|
-
|
|
1402
|
-
|
|
1403
|
-
|
|
1404
|
-
|
|
1405
|
-
|
|
1406
|
-
|
|
1407
|
-
|
|
1408
|
-
|
|
1409
|
-
|
|
1410
|
-
|
|
1411
|
-
|
|
1412
|
-
|
|
1413
|
-
|
|
1414
|
-
|
|
1415
|
-
|
|
1416
|
-
|
|
1417
|
-
|
|
1418
|
-
|
|
1419
|
-
|
|
1420
|
-
|
|
1421
|
-
|
|
1422
|
-
|
|
1423
|
-
|
|
1424
|
-
|
|
1425
|
-
|
|
1426
|
-
|
|
1427
|
-
|
|
1428
|
-
|
|
1429
|
-
|
|
1430
|
-
|
|
1431
|
-
|
|
1432
|
-
|
|
1433
|
-
|
|
1434
|
-
|
|
1435
|
-
|
|
1436
|
-
|
|
1437
|
-
|
|
1438
|
-
|
|
1439
|
-
|
|
1440
|
-
|
|
1441
|
-
|
|
1442
|
-
|
|
1443
|
-
|
|
1444
|
-
|
|
1445
|
-
|
|
1446
|
-
|
|
1447
|
-
|
|
1448
|
-
|
|
1449
|
-
|
|
1450
|
-
|
|
1451
|
-
|
|
1452
|
-
|
|
1453
|
-
|
|
1454
|
-
|
|
1455
|
-
|
|
1456
|
-
|
|
1457
|
-
|
|
1458
|
-
|
|
1459
|
-
|
|
1460
|
-
|
|
1461
|
-
|
|
1462
|
-
|
|
1463
|
-
|
|
1464
|
-
|
|
1465
|
-
|
|
1466
|
-
|
|
1467
|
-
|
|
1468
|
-
|
|
1469
|
-
|
|
1470
|
-
|
|
1471
|
-
|
|
1472
|
-
|
|
1473
|
-
|
|
1474
|
-
|
|
1475
|
-
|
|
1476
|
-
|
|
1477
|
-
|
|
1478
|
-
|
|
1479
|
-
|
|
1480
|
-
|
|
1481
|
-
|
|
1482
|
-
|
|
1483
|
-
|
|
1484
|
-
|
|
1485
|
-
|
|
1486
|
-
|
|
1487
|
-
|
|
1488
|
-
|
|
1489
|
-
|
|
1490
|
-
|
|
1491
|
-
|
|
1492
|
-
|
|
1493
|
-
|
|
1494
|
-
|
|
1495
|
-
|
|
1496
|
-
|
|
1497
|
-
|
|
1498
|
-
|
|
1499
|
-
|
|
1500
|
-
|
|
1501
|
-
|
|
1502
|
-
|
|
1503
|
-
|
|
1504
|
-
|
|
1505
|
-
|
|
1506
|
-
|
|
1507
|
-
|
|
1508
|
-
|
|
1509
|
-
|
|
1510
|
-
|
|
1511
|
-
|
|
1512
|
-
|
|
1513
|
-
|
|
1514
|
-
|
|
1515
|
-
|
|
1516
|
-
|
|
1517
|
-
|
|
1518
|
-
|
|
1519
|
-
|
|
1520
|
-
|
|
1521
|
-
|
|
1522
|
-
|
|
1523
|
-
|
|
1524
|
-
|
|
1525
|
-
|
|
1526
|
-
|
|
1527
|
-
|
|
1528
|
-
|
|
1529
|
-
|
|
1530
|
-
|
|
1531
|
-
|
|
1532
|
-
|
|
1533
|
-
|
|
1534
|
-
|
|
1535
|
-
|
|
1536
|
-
|
|
1537
|
-
|
|
1538
|
-
|
|
1539
|
-
|
|
1540
|
-
|
|
1541
|
-
|
|
1542
|
-
|
|
1543
|
-
|
|
1544
|
-
|
|
1545
|
-
|
|
1546
|
-
|
|
1547
|
-
|
|
1548
|
-
|
|
1549
|
-
()
|
|
1550
|
-
|
|
1551
|
-
|
|
1552
|
-
|
|
1553
|
-
|
|
1554
|
-
|
|
1555
|
-
|
|
1556
|
-
|
|
1557
|
-
|
|
1558
|
-
|
|
1559
|
-
|
|
1560
|
-
|
|
1561
|
-
|
|
1562
|
-
|
|
1563
|
-
|
|
1564
|
-
|
|
1565
|
-
|
|
1566
|
-
|
|
1567
|
-
|
|
1568
|
-
|
|
1569
|
-
|
|
1570
|
-
|
|
1571
|
-
|
|
1572
|
-
|
|
1573
|
-
|
|
1574
|
-
|
|
1575
|
-
|
|
1576
|
-
|
|
1577
|
-
|
|
1578
|
-
|
|
1579
|
-
|
|
1580
|
-
|
|
1581
|
-
|
|
1582
|
-
|
|
1583
|
-
|
|
1584
|
-
|
|
1585
|
-
|
|
1586
|
-
|
|
1587
|
-
|
|
1588
|
-
|
|
1589
|
-
|
|
1590
|
-
|
|
1591
|
-
|
|
1592
|
-
|
|
1593
|
-
|
|
1594
|
-
|
|
1595
|
-
|
|
1596
|
-
|
|
1597
|
-
|
|
1598
|
-
|
|
1599
|
-
|
|
1600
|
-
|
|
1601
|
-
|
|
1602
|
-
|
|
1603
|
-
|
|
1604
|
-
|
|
1605
|
-
|
|
1606
|
-
|
|
1607
|
-
|
|
1608
|
-
|
|
1609
|
-
|
|
1610
|
-
|
|
1611
|
-
|
|
1612
|
-
|
|
1613
|
-
|
|
1614
|
-
|
|
1615
|
-
|
|
1616
|
-
|
|
1617
|
-
|
|
1618
|
-
|
|
1619
|
-
|
|
1620
|
-
|
|
1621
|
-
|
|
1622
|
-
|
|
1623
|
-
|
|
1624
|
-
|
|
1625
|
-
|
|
1626
|
-
|
|
1627
|
-
|
|
1628
|
-
|
|
1629
|
-
|
|
1630
|
-
|
|
1631
|
-
|
|
1632
|
-
|
|
1633
|
-
|
|
1634
|
-
|
|
1635
|
-
|
|
1636
|
-
|
|
1637
|
-
|
|
1638
|
-
|
|
1639
|
-
|
|
1640
|
-
|
|
1641
|
-
|
|
1642
|
-
|
|
1643
|
-
|
|
1644
|
-
|
|
1645
|
-
|
|
1646
|
-
|
|
1647
|
-
|
|
1648
|
-
|
|
1649
|
-
|
|
1650
|
-
|
|
1651
|
-
|
|
1652
|
-
|
|
1653
|
-
|
|
1654
|
-
|
|
1655
|
-
|
|
1656
|
-
|
|
1657
|
-
|
|
1658
|
-
|
|
1659
|
-
|
|
1660
|
-
|
|
1661
|
-
|
|
1662
|
-
|
|
1663
|
-
|
|
1664
|
-
|
|
1665
|
-
|
|
1666
|
-
|
|
1667
|
-
|
|
1668
|
-
|
|
1669
|
-
|
|
1670
|
-
|
|
1671
|
-
|
|
1672
|
-
|
|
1673
|
-
|
|
1674
|
-
|
|
1675
|
-
|
|
1676
|
-
|
|
1677
|
-
|
|
1678
|
-
|
|
1679
|
-
|
|
1680
|
-
|
|
1681
|
-
|
|
1682
|
-
|
|
1683
|
-
|
|
1684
|
-
|
|
1685
|
-
|
|
1686
|
-
|
|
1687
|
-
|
|
1688
|
-
|
|
1689
|
-
|
|
1690
|
-
|
|
1691
|
-
|
|
1692
|
-
|
|
1693
|
-
|
|
1694
|
-
|
|
1695
|
-
|
|
1696
|
-
|
|
1697
|
-
|
|
1698
|
-
|
|
1699
|
-
|
|
1700
|
-
|
|
1701
|
-
|
|
1702
|
-
|
|
1703
|
-
|
|
1704
|
-
|
|
1705
|
-
|
|
1706
|
-
|
|
1707
|
-
|
|
1708
|
-
|
|
1709
|
-
|
|
1710
|
-
|
|
1711
|
-
|
|
1712
|
-
|
|
1713
|
-
|
|
1714
|
-
|
|
1715
|
-
|
|
1716
|
-
|
|
1717
|
-
|
|
1718
|
-
|
|
1719
|
-
|
|
1720
|
-
|
|
1721
|
-
|
|
1722
|
-
|
|
1723
|
-
|
|
1724
|
-
|
|
1725
|
-
|
|
1726
|
-
|
|
1727
|
-
|
|
1728
|
-
|
|
1729
|
-
|
|
1730
|
-
|
|
1731
|
-
|
|
1732
|
-
|
|
1733
|
-
|
|
1734
|
-
|
|
1735
|
-
|
|
1736
|
-
|
|
1737
|
-
|
|
1738
|
-
|
|
1739
|
-
|
|
1740
|
-
|
|
1741
|
-
|
|
1742
|
-
|
|
1743
|
-
|
|
1744
|
-
|
|
1745
|
-
|
|
1746
|
-
|
|
1747
|
-
|
|
1748
|
-
|
|
1749
|
-
|
|
1750
|
-
|
|
1751
|
-
|
|
1752
|
-
|
|
1753
|
-
|
|
1754
|
-
|
|
1755
|
-
|
|
1756
|
-
|
|
1757
|
-
|
|
1758
|
-
|
|
1759
|
-
|
|
1760
|
-
|
|
1761
|
-
|
|
1762
|
-
|
|
1763
|
-
|
|
1764
|
-
|
|
1765
|
-
|
|
1766
|
-
|
|
1767
|
-
|
|
1768
|
-
|
|
1769
|
-
|
|
1770
|
-
|
|
1771
|
-
|
|
1772
|
-
|
|
1773
|
-
|
|
1774
|
-
|
|
1775
|
-
|
|
1776
|
-
|
|
1777
|
-
|
|
1778
|
-
|
|
1779
|
-
|
|
1780
|
-
|
|
1781
|
-
|
|
1782
|
-
|
|
1783
|
-
|
|
1784
|
-
|
|
1785
|
-
|
|
1786
|
-
|
|
1787
|
-
|
|
1788
|
-
|
|
1789
|
-
|
|
1790
|
-
|
|
1791
|
-
|
|
1792
|
-
|
|
1793
|
-
|
|
1794
|
-
|
|
1795
|
-
|
|
1796
|
-
|
|
1797
|
-
|
|
1798
|
-
|
|
1799
|
-
|
|
1800
|
-
|
|
1801
|
-
|
|
1802
|
-
|
|
1803
|
-
|
|
1804
|
-
|
|
1805
|
-
|
|
1806
|
-
|
|
1807
|
-
|
|
1808
|
-
|
|
1809
|
-
|
|
1810
|
-
|
|
1811
|
-
|
|
1812
|
-
|
|
1813
|
-
|
|
1814
|
-
|
|
1815
|
-
|
|
1816
|
-
|
|
1817
|
-
|
|
1818
|
-
|
|
1819
|
-
|
|
1820
|
-
|
|
1821
|
-
|
|
1822
|
-
|
|
1823
|
-
|
|
1824
|
-
|
|
1825
|
-
|
|
1826
|
-
|
|
1827
|
-
|
|
1828
|
-
|
|
1829
|
-
|
|
1830
|
-
|
|
1831
|
-
|
|
1832
|
-
|
|
1833
|
-
|
|
1834
|
-
|
|
1835
|
-
|
|
1836
|
-
|
|
1837
|
-
|
|
1838
|
-
|
|
1839
|
-
|
|
1840
|
-
|
|
1841
|
-
|
|
1842
|
-
|
|
1843
|
-
|
|
1844
|
-
|
|
1845
|
-
|
|
1846
|
-
|
|
1847
|
-
|
|
1848
|
-
|
|
1849
|
-
|
|
1850
|
-
|
|
1851
|
-
|
|
1852
|
-
|
|
1853
|
-
|
|
1854
|
-
|
|
1855
|
-
|
|
1856
|
-
|
|
1857
|
-
|
|
1858
|
-
|
|
1859
|
-
|
|
1860
|
-
|
|
1861
|
-
|
|
1862
|
-
|
|
1863
|
-
|
|
1864
|
-
|
|
1865
|
-
|
|
1866
|
-
|
|
1867
|
-
|
|
1868
|
-
|
|
1869
|
-
|
|
1870
|
-
|
|
1871
|
-
|
|
1872
|
-
|
|
1873
|
-
|
|
1874
|
-
|
|
1875
|
-
|
|
1876
|
-
|
|
1877
|
-
|
|
1878
|
-
|
|
1879
|
-
|
|
1880
|
-
|
|
1881
|
-
|
|
1882
|
-
|
|
1883
|
-
|
|
1884
|
-
|
|
1885
|
-
|
|
1886
|
-
|
|
1887
|
-
|
|
1888
|
-
|
|
1889
|
-
|
|
1890
|
-
|
|
1891
|
-
|
|
1892
|
-
|
|
1893
|
-
|
|
1894
|
-
|
|
1895
|
-
|
|
1896
|
-
|
|
1897
|
-
|
|
1898
|
-
|
|
1899
|
-
|
|
1900
|
-
|
|
1901
|
-
|
|
1902
|
-
|
|
1903
|
-
|
|
1904
|
-
|
|
1905
|
-
|
|
1906
|
-
|
|
1907
|
-
|
|
1908
|
-
|
|
1909
|
-
|
|
1910
|
-
|
|
1911
|
-
|
|
1912
|
-
|
|
1913
|
-
|
|
1914
|
-
|
|
1915
|
-
|
|
1916
|
-
|
|
1917
|
-
|
|
1918
|
-
|
|
1919
|
-
|
|
1920
|
-
|
|
1921
|
-
|
|
1922
|
-
|
|
1923
|
-
|
|
1924
|
-
|
|
1925
|
-
|
|
1926
|
-
|
|
1927
|
-
|
|
1928
|
-
|
|
1929
|
-
|
|
1930
|
-
|
|
1931
|
-
|
|
1932
|
-
|
|
1933
|
-
|
|
1934
|
-
|
|
1935
|
-
|
|
1936
|
-
|
|
1937
|
-
|
|
1938
|
-
|
|
1939
|
-
|
|
1940
|
-
|
|
1941
|
-
|
|
1942
|
-
|
|
1943
|
-
|
|
1944
|
-
|
|
1945
|
-
|
|
1946
|
-
|
|
1947
|
-
|
|
1948
|
-
|
|
1949
|
-
|
|
1950
|
-
|
|
1951
|
-
|
|
1952
|
-
|
|
1953
|
-
|
|
1954
|
-
|
|
1955
|
-
|
|
1956
|
-
|
|
1957
|
-
|
|
1958
|
-
|
|
1959
|
-
|
|
1960
|
-
|
|
1961
|
-
|
|
1962
|
-
|
|
1963
|
-
|
|
1964
|
-
|
|
1965
|
-
|
|
1966
|
-
|
|
1967
|
-
|
|
1968
|
-
|
|
1969
|
-
|
|
1970
|
-
|
|
1971
|
-
|
|
1972
|
-
|
|
1973
|
-
|
|
1974
|
-
|
|
1975
|
-
|
|
1976
|
-
|
|
1977
|
-
|
|
1978
|
-
|
|
1979
|
-
|
|
1980
|
-
|
|
1981
|
-
|
|
1982
|
-
|
|
1983
|
-
|
|
1984
|
-
|
|
1985
|
-
|
|
1986
|
-
|
|
1987
|
-
|
|
1988
|
-
|
|
1989
|
-
|
|
1990
|
-
|
|
1991
|
-
|
|
1992
|
-
|
|
1993
|
-
|
|
1994
|
-
|
|
1995
|
-
|
|
1996
|
-
|
|
1997
|
-
|
|
1998
|
-
|
|
1999
|
-
|
|
2000
|
-
|
|
2001
|
-
|
|
2002
|
-
|
|
2003
|
-
|
|
2004
|
-
|
|
2005
|
-
|
|
2006
|
-
|
|
2007
|
-
|
|
2008
|
-
|
|
2009
|
-
|
|
2010
|
-
|
|
2011
|
-
|
|
2012
|
-
|
|
2013
|
-
|
|
2014
|
-
|
|
2015
|
-
|
|
2016
|
-
|
|
2017
|
-
|
|
2018
|
-
|
|
2019
|
-
|
|
2020
|
-
|
|
2021
|
-
|
|
2022
|
-
|
|
2023
|
-
|
|
2024
|
-
|
|
2025
|
-
|
|
2026
|
-
|
|
2027
|
-
|
|
2028
|
-
|
|
2029
|
-
|
|
2030
|
-
|
|
2031
|
-
|
|
2032
|
-
|
|
2033
|
-
|
|
2034
|
-
|
|
2035
|
-
|
|
2036
|
-
|
|
2037
|
-
|
|
2038
|
-
|
|
2039
|
-
|
|
2040
|
-
|
|
2041
|
-
|
|
2042
|
-
|
|
2043
|
-
|
|
2044
|
-
|
|
2045
|
-
|
|
2046
|
-
|
|
2047
|
-
|
|
2048
|
-
|
|
2049
|
-
|
|
2050
|
-
|
|
2051
|
-
|
|
2052
|
-
|
|
2053
|
-
|
|
2054
|
-
|
|
2055
|
-
|
|
2056
|
-
|
|
2057
|
-
|
|
2058
|
-
|
|
2059
|
-
|
|
2060
|
-
|
|
2061
|
-
|
|
2062
|
-
|
|
2063
|
-
|
|
2064
|
-
|
|
2065
|
-
|
|
2066
|
-
|
|
2067
|
-
|
|
2068
|
-
|
|
2069
|
-
|
|
2070
|
-
|
|
2071
|
-
this._disposeList.forEach((fn) => {
|
|
2072
|
-
fn();
|
|
2073
|
-
});
|
|
2074
|
-
}
|
|
2075
|
-
static create(svg, opts, data = null) {
|
|
2076
|
-
const mm = new Markmap(svg, opts);
|
|
2077
|
-
if (data) {
|
|
2078
|
-
mm.setData(data).then(() => {
|
|
2079
|
-
mm.fit();
|
|
2080
|
-
});
|
|
2081
|
-
}
|
|
2082
|
-
return mm;
|
|
2083
|
-
}
|
|
2084
|
-
}
|
|
2085
|
-
function htmlInlineToMarkdown(html) {
|
|
2086
|
-
if (!html) return "";
|
|
2087
|
-
let md = html;
|
|
2088
|
-
md = md.replace(
|
|
2089
|
-
/<img(?=[^>]*?\bsrc="([^"]*)")(?=[^>]*?\balt="([^"]*)")(?=[^>]*?\btitle="([^"]*)")?[^>]*?\/?>/gi,
|
|
2090
|
-
(_, src, alt, title) => title ? `` : ``
|
|
2091
|
-
);
|
|
2092
|
-
md = md.replace(
|
|
2093
|
-
/<img\s[^>]*?\/?>/gi,
|
|
2094
|
-
(match) => {
|
|
2095
|
-
const src = (match.match(/\bsrc="([^"]*)"/) || [])[1] ?? "";
|
|
2096
|
-
const alt = (match.match(/\balt="([^"]*)"/) || [])[1] ?? "";
|
|
2097
|
-
const title = (match.match(/\btitle="([^"]*)"/) || [])[1];
|
|
2098
|
-
return title ? `` : ``;
|
|
2099
|
-
}
|
|
2100
|
-
);
|
|
2101
|
-
md = md.replace(
|
|
2102
|
-
/<a\s[^>]*?href="([^"]*)"[^>]*?>([\s\S]*?)<\/a>/gi,
|
|
2103
|
-
(_, href, inner) => {
|
|
2104
|
-
const title = (_.match(/\btitle="([^"]*)"/) || [])[1];
|
|
2105
|
-
const innerMd = htmlInlineToMarkdown(inner);
|
|
2106
|
-
return title ? `[${innerMd}](${href} "${title}")` : `[${innerMd}](${href})`;
|
|
2107
|
-
}
|
|
2108
|
-
);
|
|
2109
|
-
md = md.replace(/<strong>([\s\S]*?)<\/strong>/gi, (_, t) => `**${htmlInlineToMarkdown(t)}**`);
|
|
2110
|
-
md = md.replace(/<b>([\s\S]*?)<\/b>/gi, (_, t) => `**${htmlInlineToMarkdown(t)}**`);
|
|
2111
|
-
md = md.replace(/<em>([\s\S]*?)<\/em>/gi, (_, t) => `*${htmlInlineToMarkdown(t)}*`);
|
|
2112
|
-
md = md.replace(/<i>([\s\S]*?)<\/i>/gi, (_, t) => `*${htmlInlineToMarkdown(t)}*`);
|
|
2113
|
-
md = md.replace(/<(?:del|s)>([\s\S]*?)<\/(?:del|s)>/gi, (_, t) => `~~${htmlInlineToMarkdown(t)}~~`);
|
|
2114
|
-
md = md.replace(/<code>([\s\S]*?)<\/code>/gi, (_, t) => {
|
|
2115
|
-
const decoded = t.replace(/&#x([0-9a-f]+);/gi, (_2, hex) => String.fromCodePoint(parseInt(hex, 16))).replace(/&#([0-9]+);/g, (_2, dec) => String.fromCodePoint(parseInt(dec, 10))).replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, '"').replace(/'/g, "'");
|
|
2116
|
-
return "`" + decoded + "`";
|
|
2117
|
-
});
|
|
2118
|
-
md = md.replace(/<br\s*\/?>/gi, "\n");
|
|
2119
|
-
md = md.replace(/<[^>]+>/g, "");
|
|
2120
|
-
md = md.replace(/&#x([0-9a-f]+);/gi, (_, hex) => String.fromCodePoint(parseInt(hex, 16))).replace(/&#([0-9]+);/g, (_, dec) => String.fromCodePoint(parseInt(dec, 10))).replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, '"').replace(/'/g, "'").replace(/ /g, " ");
|
|
2121
|
-
return md;
|
|
2122
|
-
}
|
|
2123
|
-
function toMarkdown(root) {
|
|
2124
|
-
const lines = [];
|
|
2125
|
-
function walk(node, depth) {
|
|
2126
|
-
const text = htmlInlineToMarkdown(node.content).trim();
|
|
2127
|
-
if (text) {
|
|
2128
|
-
if (depth <= 2) {
|
|
2129
|
-
const hashes = "#".repeat(depth + 1);
|
|
2130
|
-
if (lines.length > 0) lines.push("");
|
|
2131
|
-
lines.push(`${hashes} ${text}`);
|
|
2132
|
-
} else {
|
|
2133
|
-
const indent = " ".repeat(depth - 3);
|
|
2134
|
-
lines.push(`${indent}- ${text}`);
|
|
2135
|
-
}
|
|
2136
|
-
}
|
|
2137
|
-
for (const child of node.children) {
|
|
2138
|
-
walk(child, depth + 1);
|
|
2139
|
-
}
|
|
2140
|
-
}
|
|
2141
|
-
walk(root, 0);
|
|
2142
|
-
return lines.join("\n").trimStart() + "\n";
|
|
2143
|
-
}
|
|
2144
|
-
exports.Markmap = Markmap;
|
|
2145
|
-
exports.childSelector = childSelector;
|
|
2146
|
-
exports.defaultColorFn = defaultColorFn;
|
|
2147
|
-
exports.defaultOptions = defaultOptions;
|
|
2148
|
-
exports.deriveOptions = deriveOptions;
|
|
2149
|
-
exports.globalCSS = globalCSS;
|
|
2150
|
-
exports.htmlInlineToMarkdown = htmlInlineToMarkdown;
|
|
2151
|
-
exports.isMacintosh = isMacintosh;
|
|
2152
|
-
exports.lineWidthFactory = lineWidthFactory;
|
|
2153
|
-
exports.loadCSS = loadCSS;
|
|
2154
|
-
exports.loadJS = loadJS;
|
|
2155
|
-
exports.refreshHook = refreshHook;
|
|
2156
|
-
exports.simpleHash = simpleHash;
|
|
2157
|
-
exports.toMarkdown = toMarkdown;
|
|
2158
|
-
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
1328
|
+
btn.addEventListener("click", (e) => {
|
|
1329
|
+
e.preventDefault();
|
|
1330
|
+
e.stopPropagation();
|
|
1331
|
+
this.showAddInput(node);
|
|
1332
|
+
});
|
|
1333
|
+
wrap.style.transform = "translate(-50%, -50%)";
|
|
1334
|
+
wrap.appendChild(btn);
|
|
1335
|
+
overlayRoot.appendChild(wrap);
|
|
1336
|
+
this._positionOverlayToEl(wrap, contentEl, {
|
|
1337
|
+
anchor: "br",
|
|
1338
|
+
dx: Math.round(14 * scale),
|
|
1339
|
+
dy: 0
|
|
1340
|
+
});
|
|
1341
|
+
const onDocDown = (ev) => {
|
|
1342
|
+
const t = ev.target;
|
|
1343
|
+
if (!t) return;
|
|
1344
|
+
if (wrap.contains(t)) return;
|
|
1345
|
+
if (this.addInputUI?.wrap.contains(t)) return;
|
|
1346
|
+
const nodeEl = this._getNodeContentEl(node);
|
|
1347
|
+
if (nodeEl && nodeEl.contains(t)) return;
|
|
1348
|
+
this.hideAddUI();
|
|
1349
|
+
};
|
|
1350
|
+
document.addEventListener("click", onDocDown, true);
|
|
1351
|
+
const cleanupDoc = () => document.removeEventListener("click", onDocDown, true);
|
|
1352
|
+
this.addUI = {
|
|
1353
|
+
node,
|
|
1354
|
+
btn,
|
|
1355
|
+
wrap,
|
|
1356
|
+
cleanupDoc
|
|
1357
|
+
};
|
|
1358
|
+
}
|
|
1359
|
+
/** Delete `node` from the tree and re-render. */
|
|
1360
|
+
deleteNode(node) {
|
|
1361
|
+
if (!this.ctx.options.deletable) return;
|
|
1362
|
+
if (!this.ctx.state.data) return;
|
|
1363
|
+
const found = this._findParent(node);
|
|
1364
|
+
if (!found) return;
|
|
1365
|
+
const { parent, index } = found;
|
|
1366
|
+
const children = [...parent.children || []];
|
|
1367
|
+
children.splice(index, 1);
|
|
1368
|
+
parent.children = children;
|
|
1369
|
+
this.selectedNode = null;
|
|
1370
|
+
this.hideAddUI();
|
|
1371
|
+
this._clearSelectionCss();
|
|
1372
|
+
this.ctx.renderData();
|
|
1373
|
+
}
|
|
1374
|
+
/**
|
|
1375
|
+
* Insert a new sibling node after `sibling`, render it, then open an edit overlay.
|
|
1376
|
+
* Called when the user presses Enter on a selected node.
|
|
1377
|
+
*/
|
|
1378
|
+
async showAddSiblingInput(sibling) {
|
|
1379
|
+
if (!this.ctx.state.data) return;
|
|
1380
|
+
const found = this._findParent(sibling);
|
|
1381
|
+
if (!found) return;
|
|
1382
|
+
const { parent, index } = found;
|
|
1383
|
+
this.hideAddUI();
|
|
1384
|
+
let maxId = 0;
|
|
1385
|
+
walkTree(this.ctx.state.data, (item, next) => {
|
|
1386
|
+
if (item.state?.id > maxId) maxId = item.state.id;
|
|
1387
|
+
next();
|
|
1388
|
+
});
|
|
1389
|
+
const newId = maxId + 1;
|
|
1390
|
+
const depth = sibling.state?.depth ?? 1;
|
|
1391
|
+
const placeholder = " ";
|
|
1392
|
+
const newNode = {
|
|
1393
|
+
content: placeholder,
|
|
1394
|
+
children: [],
|
|
1395
|
+
payload: {},
|
|
1396
|
+
state: {
|
|
1397
|
+
id: newId,
|
|
1398
|
+
depth,
|
|
1399
|
+
key: `${parent.state?.id}.${newId}` + simpleHash(placeholder),
|
|
1400
|
+
path: [parent.state?.path, newId].filter(Boolean).join("."),
|
|
1401
|
+
rect: {
|
|
1402
|
+
x: 0,
|
|
1403
|
+
y: 0,
|
|
1404
|
+
width: 0,
|
|
1405
|
+
height: 0
|
|
1406
|
+
},
|
|
1407
|
+
size: [0, 0]
|
|
1408
|
+
}
|
|
1409
|
+
};
|
|
1410
|
+
const children = [...parent.children || []];
|
|
1411
|
+
children.splice(index + 1, 0, newNode);
|
|
1412
|
+
parent.children = children;
|
|
1413
|
+
this.ctx.options.color(newNode);
|
|
1414
|
+
await this.ctx.renderData();
|
|
1415
|
+
if (this.ctx.options.duration > 0) await new Promise((resolve) => setTimeout(resolve, this.ctx.options.duration));
|
|
1416
|
+
this._editNewNode(newNode, parent);
|
|
1417
|
+
}
|
|
1418
|
+
/**
|
|
1419
|
+
* Insert a new child node under `node`, render it, then open an edit overlay.
|
|
1420
|
+
* Called when the user clicks the + button or presses Tab.
|
|
1421
|
+
*/
|
|
1422
|
+
async showAddInput(node) {
|
|
1423
|
+
if (!this.ctx.state.data) return;
|
|
1424
|
+
this.hideAddUI();
|
|
1425
|
+
const child = this._insertNewChildNode(node);
|
|
1426
|
+
await this.ctx.renderData();
|
|
1427
|
+
if (this.ctx.options.duration > 0) await new Promise((resolve) => setTimeout(resolve, this.ctx.options.duration));
|
|
1428
|
+
this._editNewNode(child, node);
|
|
1429
|
+
}
|
|
1430
|
+
/**
|
|
1431
|
+
* Open an edit overlay for an *existing* node.
|
|
1432
|
+
* Called on double-click. On confirm the node content is updated in-place.
|
|
1433
|
+
*/
|
|
1434
|
+
handleEdit(e, d) {
|
|
1435
|
+
if (!this.ctx.options.editable) return;
|
|
1436
|
+
e.preventDefault();
|
|
1437
|
+
e.stopPropagation();
|
|
1438
|
+
e.stopImmediatePropagation();
|
|
1439
|
+
if (this.editingNode) this.saveEdit();
|
|
1440
|
+
const element = this.ctx.findElement(d);
|
|
1441
|
+
if (!element) return;
|
|
1442
|
+
const contentNode = (0, d3.select)(element.g).select("foreignObject").select("div").select("div").node();
|
|
1443
|
+
if (!contentNode) return;
|
|
1444
|
+
if (this.editOverlay) {
|
|
1445
|
+
try {
|
|
1446
|
+
this.editOverlay.contentEl.style.visibility = this.editOverlay.prevVisibility;
|
|
1447
|
+
this.editOverlay.wrap.remove();
|
|
1448
|
+
} catch {}
|
|
1449
|
+
this.editOverlay = void 0;
|
|
1450
|
+
}
|
|
1451
|
+
const originalHtml = d.content;
|
|
1452
|
+
this.editingNode = d;
|
|
1453
|
+
this._openEditOverlay(d, contentNode, {
|
|
1454
|
+
initialValue: contentNode.textContent || "",
|
|
1455
|
+
minWidth: 40,
|
|
1456
|
+
selectAll: true,
|
|
1457
|
+
onCancel: () => {
|
|
1458
|
+
d.content = originalHtml;
|
|
1459
|
+
this.ctx.renderData();
|
|
1460
|
+
},
|
|
1461
|
+
onSave: (newHtml) => {
|
|
1462
|
+
this.ctx.options.onNodeEdit?.(d, newHtml);
|
|
1463
|
+
this.hideAddUI();
|
|
1464
|
+
this.ctx.renderData().then(() => {
|
|
1465
|
+
if (!this.ctx.options.addable) return;
|
|
1466
|
+
const showPlus = () => {
|
|
1467
|
+
this.selectedNode = d;
|
|
1468
|
+
if (this.ctx.options.clickBorder) this.ctx.g.selectAll(childSelector(SELECTOR_NODE$1)).classed("markmap-selected", (n) => n === d);
|
|
1469
|
+
this.showAddUI(d);
|
|
1470
|
+
};
|
|
1471
|
+
if (this.ctx.options.duration > 0) setTimeout(showPlus, this.ctx.options.duration);
|
|
1472
|
+
else showPlus();
|
|
1473
|
+
});
|
|
1474
|
+
}
|
|
1475
|
+
});
|
|
1476
|
+
}
|
|
1477
|
+
/** Immediately discard any in-progress edit overlay without saving. */
|
|
1478
|
+
saveEdit() {
|
|
1479
|
+
if (this.editOverlay) {
|
|
1480
|
+
const { input, contentEl, prevVisibility, wrap } = this.editOverlay;
|
|
1481
|
+
input.remove();
|
|
1482
|
+
contentEl.style.visibility = prevVisibility;
|
|
1483
|
+
wrap.remove();
|
|
1484
|
+
this.editOverlay = void 0;
|
|
1485
|
+
}
|
|
1486
|
+
if (this.editingNode) this.editingNode = null;
|
|
1487
|
+
}
|
|
1488
|
+
};
|
|
1489
|
+
const globalCSS = style_default;
|
|
1490
|
+
var SELECTOR_NODE = "g.markmap-node";
|
|
1491
|
+
var SELECTOR_LINK = "path.markmap-link";
|
|
1492
|
+
var SELECTOR_HIGHLIGHT = "g.markmap-highlight";
|
|
1493
|
+
var linkShape = (0, d3.linkHorizontal)();
|
|
1494
|
+
function minBy(numbers, by) {
|
|
1495
|
+
return numbers[(0, d3.minIndex)(numbers, by)];
|
|
1496
|
+
}
|
|
1497
|
+
function stopPropagation(e) {
|
|
1498
|
+
e.stopPropagation();
|
|
1499
|
+
}
|
|
1500
|
+
/**
|
|
1501
|
+
* A global hook to refresh all markmaps when called.
|
|
1502
|
+
*/
|
|
1503
|
+
const refreshHook = new Hook();
|
|
1504
|
+
var Markmap = class Markmap {
|
|
1505
|
+
constructor(svg, opts) {
|
|
1506
|
+
this.options = { ...defaultOptions };
|
|
1507
|
+
this._disposeList = [];
|
|
1508
|
+
this.handleZoom = (e) => {
|
|
1509
|
+
const { transform } = e;
|
|
1510
|
+
this.g.attr("transform", transform);
|
|
1511
|
+
this._actions.repositionOverlays();
|
|
1512
|
+
};
|
|
1513
|
+
this.handlePan = (e) => {
|
|
1514
|
+
e.preventDefault();
|
|
1515
|
+
const transform = (0, d3.zoomTransform)(this.svg.node());
|
|
1516
|
+
const newTransform = transform.translate(-e.deltaX / transform.k, -e.deltaY / transform.k);
|
|
1517
|
+
this.svg.call(this.zoom.transform, newTransform);
|
|
1518
|
+
};
|
|
1519
|
+
this.handleClick = (e, d) => {
|
|
1520
|
+
let recursive = this.options.toggleRecursively;
|
|
1521
|
+
if (isMacintosh ? e.metaKey : e.ctrlKey) recursive = !recursive;
|
|
1522
|
+
this.toggleNode(d, recursive);
|
|
1523
|
+
};
|
|
1524
|
+
this.ensureView = this.ensureVisible;
|
|
1525
|
+
this.svg = svg.datum ? svg : (0, d3.select)(svg);
|
|
1526
|
+
this.styleNode = this.svg.append("style");
|
|
1527
|
+
this.zoom = (0, d3.zoom)().filter((event) => {
|
|
1528
|
+
if (this.options.scrollForPan) {
|
|
1529
|
+
if (event.type === "wheel") return event.ctrlKey && !event.button;
|
|
1530
|
+
}
|
|
1531
|
+
return (!event.ctrlKey || event.type === "wheel") && !event.button;
|
|
1532
|
+
}).on("zoom", this.handleZoom);
|
|
1533
|
+
this.setOptions(opts);
|
|
1534
|
+
this.state = {
|
|
1535
|
+
id: this.options.id || this.svg.attr("id") || getId(),
|
|
1536
|
+
rect: {
|
|
1537
|
+
x1: 0,
|
|
1538
|
+
y1: 0,
|
|
1539
|
+
x2: 0,
|
|
1540
|
+
y2: 0
|
|
1541
|
+
}
|
|
1542
|
+
};
|
|
1543
|
+
this.g = this.svg.append("g");
|
|
1544
|
+
this.g.append("g").attr("class", "markmap-highlight");
|
|
1545
|
+
this._actions = new ActionManager(this);
|
|
1546
|
+
this.svg.on("click", () => {
|
|
1547
|
+
if (this._actions.selectedNode) {
|
|
1548
|
+
this._actions.selectedNode = null;
|
|
1549
|
+
if (this.options.clickBorder) this.g.selectAll(childSelector(SELECTOR_NODE)).classed("markmap-selected", false);
|
|
1550
|
+
this._actions.hideAddUI();
|
|
1551
|
+
}
|
|
1552
|
+
});
|
|
1553
|
+
const handleGlobalKeydown = (e) => {
|
|
1554
|
+
if (!this._actions.selectedNode) return;
|
|
1555
|
+
if (this._actions.editingNode || this._actions.editOverlay || this._actions.addInputUI) return;
|
|
1556
|
+
const tag = document.activeElement?.tagName;
|
|
1557
|
+
if (tag === "INPUT" || tag === "TEXTAREA") return;
|
|
1558
|
+
if (e.key === "Tab" && this.options.addable) {
|
|
1559
|
+
e.preventDefault();
|
|
1560
|
+
e.stopPropagation();
|
|
1561
|
+
this._actions.showAddInput(this._actions.selectedNode);
|
|
1562
|
+
} else if (e.key === "Enter" && this.options.addable) {
|
|
1563
|
+
e.preventDefault();
|
|
1564
|
+
e.stopPropagation();
|
|
1565
|
+
this._actions.showAddSiblingInput(this._actions.selectedNode);
|
|
1566
|
+
} else if ((e.key === "Delete" || e.key === "Backspace") && this.options.deletable) {
|
|
1567
|
+
e.preventDefault();
|
|
1568
|
+
e.stopPropagation();
|
|
1569
|
+
this._actions.deleteNode(this._actions.selectedNode);
|
|
1570
|
+
}
|
|
1571
|
+
};
|
|
1572
|
+
document.addEventListener("keydown", handleGlobalKeydown);
|
|
1573
|
+
this._disposeList.push(() => document.removeEventListener("keydown", handleGlobalKeydown));
|
|
1574
|
+
this._observer = new ResizeObserver(debounce(() => {
|
|
1575
|
+
if (this._actions.editingNode) return;
|
|
1576
|
+
this.renderData();
|
|
1577
|
+
}, 100));
|
|
1578
|
+
this._disposeList.push(refreshHook.tap(() => {
|
|
1579
|
+
this.setData();
|
|
1580
|
+
}), () => this._actions.hideAddUI(), () => this._observer.disconnect());
|
|
1581
|
+
}
|
|
1582
|
+
getStyleContent() {
|
|
1583
|
+
const { style } = this.options;
|
|
1584
|
+
const { id } = this.state;
|
|
1585
|
+
const styleText = typeof style === "function" ? style(id) : "";
|
|
1586
|
+
return [this.options.embedGlobalCSS && ".markmap {\n --markmap-max-width: 9999px;\n --markmap-a-color: #0097e6;\n --markmap-a-hover-color: #00a8ff;\n --markmap-code-bg: #f0f0f0;\n --markmap-code-color: #555;\n --markmap-highlight-bg: #ffeaa7;\n --markmap-table-border: 1px solid currentColor;\n --markmap-font: 300 16px/20px sans-serif;\n --markmap-circle-open-bg: #fff;\n --markmap-text-color: #333;\n --markmap-highlight-node-bg: #ff02;\n\n font: var(--markmap-font);\n color: var(--markmap-text-color);\n}\n\n .markmap-link {\n fill: none;\n }\n\n .markmap-node > circle {\n cursor: pointer;\n }\n\n .markmap-node-hovered > foreignObject > div > div {\n padding: 2px 6px;\n border-radius: 14px;\n border: 2px solid #d9d9d9;\n }\n\n .markmap-selected > foreignObject > div > div,\n .markmap-selected.markmap-node-hovered > foreignObject > div > div {\n padding: 2px 6px;\n border-radius: 14px;\n border: 2px solid #b4b4b4;\n }\n\n .markmap-selected > circle {\n opacity: 0 !important;\n pointer-events: none;\n }\n\n .markmap-collapse-on-hover .markmap-node > circle {\n opacity: 0;\n transition: opacity 0.2s;\n }\n\n .markmap-collapse-on-hover .markmap-node:hover > circle {\n opacity: 1;\n }\n\n .markmap-foreign {\n display: inline-block;\n }\n\n .markmap-foreign > div > div {\n padding: 4px 6px;\n }\n\n .markmap-foreign .markmap-edit-wrapper {\n position: relative;\n width: 100%;\n padding: 4px;\n background: white;\n border-radius: 4px;\n box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);\n animation: fadeIn 0.2s ease-in;\n }\n\n .markmap-foreign .markmap-edit-input {\n width: 100%;\n padding: 8px 12px;\n border: 2px solid #4a90e2;\n border-radius: 4px;\n font-size: 14px;\n font-family: inherit;\n outline: none;\n background: #f8f9fa;\n transition: all 0.2s;\n }\n\n .markmap-foreign .markmap-edit-input:focus {\n border-color: #2d7dd2;\n background: white;\n box-shadow: 0 0 0 3px rgba(74, 144, 226, 0.1);\n }\n\n .markmap-foreign p {\n margin: 0;\n }\n\n .markmap-foreign a {\n color: var(--markmap-a-color);\n }\n\n .markmap-foreign a:hover {\n color: var(--markmap-a-hover-color);\n }\n\n .markmap-foreign code {\n padding: 0.25em;\n font-size: calc(1em - 2px);\n color: var(--markmap-code-color);\n background-color: var(--markmap-code-bg);\n border-radius: 2px;\n }\n\n .markmap-foreign pre {\n margin: 0;\n }\n\n .markmap-foreign pre > code {\n display: block;\n }\n\n .markmap-foreign del {\n text-decoration: line-through;\n }\n\n .markmap-foreign em {\n font-style: italic;\n }\n\n .markmap-foreign strong {\n font-weight: bold;\n }\n\n .markmap-foreign mark {\n background: var(--markmap-highlight-bg);\n }\n\n .markmap-foreign table,\n .markmap-foreign th,\n .markmap-foreign td {\n border-collapse: collapse;\n border: var(--markmap-table-border);\n }\n\n .markmap-foreign img {\n display: inline-block;\n }\n\n .markmap-foreign svg {\n fill: currentColor;\n }\n\n .markmap-foreign > div {\n width: var(--markmap-max-width);\n text-align: left;\n }\n\n .markmap-foreign > div > div {\n display: inline-block;\n max-width: var(--markmap-wrap-width, 30em);\n overflow-wrap: break-word;\n word-break: break-word;\n white-space: normal;\n }\n\n .markmap-highlight rect {\n fill: var(--markmap-highlight-node-bg);\n }\n\n.markmap-dark .markmap {\n --markmap-code-bg: #1a1b26;\n --markmap-code-color: #ddd;\n --markmap-circle-open-bg: #444;\n --markmap-text-color: #eee;\n}\n\n@keyframes fadeIn {\n from {\n opacity: 0;\n transform: scale(0.95);\n }\n to {\n opacity: 1;\n transform: scale(1);\n }\n}\n", styleText].filter(Boolean).join("\n");
|
|
1587
|
+
}
|
|
1588
|
+
updateStyle() {
|
|
1589
|
+
const baseClass = addClass("", "markmap", this.state.id);
|
|
1590
|
+
const collapseClass = this.options.collapseOnHover ? "markmap-collapse-on-hover" : "";
|
|
1591
|
+
this.svg.attr("class", [baseClass, collapseClass].filter(Boolean).join(" "));
|
|
1592
|
+
const style = this.getStyleContent();
|
|
1593
|
+
this.styleNode.text(style);
|
|
1594
|
+
}
|
|
1595
|
+
async toggleNode(data, recursive = false) {
|
|
1596
|
+
const fold = data.payload?.fold ? 0 : 1;
|
|
1597
|
+
if (recursive) walkTree(data, (item, next) => {
|
|
1598
|
+
item.payload = {
|
|
1599
|
+
...item.payload,
|
|
1600
|
+
fold
|
|
1601
|
+
};
|
|
1602
|
+
next();
|
|
1603
|
+
});
|
|
1604
|
+
else data.payload = {
|
|
1605
|
+
...data.payload,
|
|
1606
|
+
fold: data.payload?.fold ? 0 : 1
|
|
1607
|
+
};
|
|
1608
|
+
await this.renderData(data);
|
|
1609
|
+
}
|
|
1610
|
+
_initializeData(node) {
|
|
1611
|
+
let nodeId = 0;
|
|
1612
|
+
const { color, initialExpandLevel } = this.options;
|
|
1613
|
+
let foldRecursively = 0;
|
|
1614
|
+
let depth = 0;
|
|
1615
|
+
walkTree(node, (item, next, parent) => {
|
|
1616
|
+
depth += 1;
|
|
1617
|
+
item.children = item.children?.map((child) => ({ ...child }));
|
|
1618
|
+
nodeId += 1;
|
|
1619
|
+
item.state = {
|
|
1620
|
+
...item.state,
|
|
1621
|
+
depth,
|
|
1622
|
+
id: nodeId,
|
|
1623
|
+
rect: {
|
|
1624
|
+
x: 0,
|
|
1625
|
+
y: 0,
|
|
1626
|
+
width: 0,
|
|
1627
|
+
height: 0
|
|
1628
|
+
},
|
|
1629
|
+
size: [0, 0]
|
|
1630
|
+
};
|
|
1631
|
+
item.state.key = [parent?.state?.id, item.state.id].filter(Boolean).join(".") + simpleHash(item.content);
|
|
1632
|
+
item.state.path = [parent?.state?.path, item.state.id].filter(Boolean).join(".");
|
|
1633
|
+
color(item);
|
|
1634
|
+
const isFoldRecursively = item.payload?.fold === 2;
|
|
1635
|
+
if (isFoldRecursively) foldRecursively += 1;
|
|
1636
|
+
else if (foldRecursively || initialExpandLevel >= 0 && item.state.depth >= initialExpandLevel) item.payload = {
|
|
1637
|
+
...item.payload,
|
|
1638
|
+
fold: 1
|
|
1639
|
+
};
|
|
1640
|
+
next();
|
|
1641
|
+
if (isFoldRecursively) foldRecursively -= 1;
|
|
1642
|
+
depth -= 1;
|
|
1643
|
+
});
|
|
1644
|
+
return node;
|
|
1645
|
+
}
|
|
1646
|
+
_relayout() {
|
|
1647
|
+
if (!this.state.data) return;
|
|
1648
|
+
this.g.selectAll(childSelector(SELECTOR_NODE)).selectAll(childSelector("foreignObject")).each(function(d) {
|
|
1649
|
+
const el = this.firstChild?.firstChild;
|
|
1650
|
+
const newSize = [el.scrollWidth, el.scrollHeight];
|
|
1651
|
+
d.state.size = newSize;
|
|
1652
|
+
});
|
|
1653
|
+
const { lineWidth, paddingX, spacingHorizontal, spacingVertical } = this.options;
|
|
1654
|
+
const getEffectiveSH = (node) => {
|
|
1655
|
+
if (node.payload?.fold) return spacingHorizontal;
|
|
1656
|
+
return (node.children || []).length === 1 ? Math.round(spacingHorizontal / 2) : spacingHorizontal;
|
|
1657
|
+
};
|
|
1658
|
+
const layout = flextree({}).children((d) => {
|
|
1659
|
+
if (!d.payload?.fold) return d.children;
|
|
1660
|
+
}).nodeSize((node) => {
|
|
1661
|
+
const [width, height] = node.data.state.size;
|
|
1662
|
+
const sh = getEffectiveSH(node.data);
|
|
1663
|
+
return [height, width + (width ? paddingX * 2 : 0) + sh];
|
|
1664
|
+
}).spacing((a, b) => {
|
|
1665
|
+
return (a.parent === b.parent ? spacingVertical : spacingVertical * 2) + lineWidth(a.data);
|
|
1666
|
+
});
|
|
1667
|
+
const tree = layout.hierarchy(this.state.data);
|
|
1668
|
+
layout(tree);
|
|
1669
|
+
const fnodes = tree.descendants();
|
|
1670
|
+
fnodes.forEach((fnode) => {
|
|
1671
|
+
const node = fnode.data;
|
|
1672
|
+
const sh = getEffectiveSH(node);
|
|
1673
|
+
node.state.rect = {
|
|
1674
|
+
x: fnode.y,
|
|
1675
|
+
y: fnode.x - fnode.xSize / 2,
|
|
1676
|
+
width: fnode.ySize - sh,
|
|
1677
|
+
height: fnode.xSize
|
|
1678
|
+
};
|
|
1679
|
+
});
|
|
1680
|
+
this.state.rect = {
|
|
1681
|
+
x1: (0, d3.min)(fnodes, (fnode) => fnode.data.state.rect.x) || 0,
|
|
1682
|
+
y1: (0, d3.min)(fnodes, (fnode) => fnode.data.state.rect.y) || 0,
|
|
1683
|
+
x2: (0, d3.max)(fnodes, (fnode) => fnode.data.state.rect.x + fnode.data.state.rect.width) || 0,
|
|
1684
|
+
y2: (0, d3.max)(fnodes, (fnode) => fnode.data.state.rect.y + fnode.data.state.rect.height) || 0
|
|
1685
|
+
};
|
|
1686
|
+
}
|
|
1687
|
+
setOptions(opts) {
|
|
1688
|
+
const modePreset = opts?.mode === "display" ? {
|
|
1689
|
+
editable: false,
|
|
1690
|
+
addable: false,
|
|
1691
|
+
deletable: false,
|
|
1692
|
+
collapseOnHover: false,
|
|
1693
|
+
hoverBorder: false,
|
|
1694
|
+
clickBorder: false
|
|
1695
|
+
} : opts?.mode === "editable" ? {
|
|
1696
|
+
editable: true,
|
|
1697
|
+
addable: true,
|
|
1698
|
+
deletable: true,
|
|
1699
|
+
collapseOnHover: true,
|
|
1700
|
+
hoverBorder: true,
|
|
1701
|
+
clickBorder: true
|
|
1702
|
+
} : {};
|
|
1703
|
+
this.options = {
|
|
1704
|
+
...this.options,
|
|
1705
|
+
...modePreset,
|
|
1706
|
+
...opts
|
|
1707
|
+
};
|
|
1708
|
+
if (this.options.zoom) this.svg.call(this.zoom);
|
|
1709
|
+
else this.svg.on(".zoom", null);
|
|
1710
|
+
if (this.options.pan) this.svg.on("wheel", this.handlePan);
|
|
1711
|
+
else this.svg.on("wheel", null);
|
|
1712
|
+
}
|
|
1713
|
+
async setData(data, opts) {
|
|
1714
|
+
if (opts) this.setOptions(opts);
|
|
1715
|
+
if (data) this.state.data = this._initializeData(data);
|
|
1716
|
+
if (!this.state.data) return;
|
|
1717
|
+
this.updateStyle();
|
|
1718
|
+
await this.renderData();
|
|
1719
|
+
}
|
|
1720
|
+
getData(pure) {
|
|
1721
|
+
const data = this.state.data;
|
|
1722
|
+
if (!data) return;
|
|
1723
|
+
if (!pure) return data;
|
|
1724
|
+
const toPure = (node) => ({
|
|
1725
|
+
content: node.content,
|
|
1726
|
+
payload: node.payload,
|
|
1727
|
+
children: (node.children || []).map(toPure)
|
|
1728
|
+
});
|
|
1729
|
+
return toPure(data);
|
|
1730
|
+
}
|
|
1731
|
+
async setHighlight(node) {
|
|
1732
|
+
this.state.highlight = node || void 0;
|
|
1733
|
+
await this.renderData();
|
|
1734
|
+
}
|
|
1735
|
+
_getHighlightRect(highlight) {
|
|
1736
|
+
const padding = 4 / (0, d3.zoomTransform)(this.svg.node()).k;
|
|
1737
|
+
const rect = { ...highlight.state.rect };
|
|
1738
|
+
rect.x -= padding;
|
|
1739
|
+
rect.y -= padding;
|
|
1740
|
+
rect.width += 2 * padding;
|
|
1741
|
+
rect.height += 2 * padding;
|
|
1742
|
+
return rect;
|
|
1743
|
+
}
|
|
1744
|
+
async renderData(originData) {
|
|
1745
|
+
const { paddingX, autoFit, color, maxWidth, lineWidth } = this.options;
|
|
1746
|
+
const rootNode = this.state.data;
|
|
1747
|
+
if (!rootNode) return;
|
|
1748
|
+
const nodeMap = {};
|
|
1749
|
+
const parentMap = {};
|
|
1750
|
+
const nodes = [];
|
|
1751
|
+
walkTree(rootNode, (item, next, parent) => {
|
|
1752
|
+
if (!item.payload?.fold) next();
|
|
1753
|
+
nodeMap[item.state.id] = item;
|
|
1754
|
+
if (parent) parentMap[item.state.id] = parent.state.id;
|
|
1755
|
+
nodes.push(item);
|
|
1756
|
+
});
|
|
1757
|
+
const originMap = {};
|
|
1758
|
+
const sourceRectMap = {};
|
|
1759
|
+
const setOriginNode = (originNode) => {
|
|
1760
|
+
if (!originNode || originMap[originNode.state.id]) return;
|
|
1761
|
+
walkTree(originNode, (item, next) => {
|
|
1762
|
+
originMap[item.state.id] = originNode.state.id;
|
|
1763
|
+
next();
|
|
1764
|
+
});
|
|
1765
|
+
};
|
|
1766
|
+
const getOriginSourceRect = (node) => {
|
|
1767
|
+
return sourceRectMap[originMap[node.state.id]] || rootNode.state.rect;
|
|
1768
|
+
};
|
|
1769
|
+
const getOriginTargetRect = (node) => (nodeMap[originMap[node.state.id]] || rootNode).state.rect;
|
|
1770
|
+
sourceRectMap[rootNode.state.id] = rootNode.state.rect;
|
|
1771
|
+
if (originData) setOriginNode(originData);
|
|
1772
|
+
let { highlight } = this.state;
|
|
1773
|
+
if (highlight && !nodeMap[highlight.state.id]) highlight = void 0;
|
|
1774
|
+
let highlightNodes = this.g.selectAll(childSelector(SELECTOR_HIGHLIGHT)).selectAll(childSelector("rect")).data(highlight ? [this._getHighlightRect(highlight)] : []).join("rect").attr("x", (d) => d.x).attr("y", (d) => d.y).attr("width", (d) => d.width).attr("height", (d) => d.height);
|
|
1775
|
+
const mmG = this.g.selectAll(childSelector(SELECTOR_NODE)).each((d) => {
|
|
1776
|
+
sourceRectMap[d.state.id] = d.state.rect;
|
|
1777
|
+
}).data(nodes, (d) => d.state.key);
|
|
1778
|
+
const mmGEnter = mmG.enter().append("g").attr("data-depth", (d) => d.state.depth).attr("data-path", (d) => d.state.path).each((d) => {
|
|
1779
|
+
setOriginNode(nodeMap[parentMap[d.state.id]]);
|
|
1780
|
+
});
|
|
1781
|
+
const mmGExit = mmG.exit().each((d) => {
|
|
1782
|
+
setOriginNode(nodeMap[parentMap[d.state.id]]);
|
|
1783
|
+
});
|
|
1784
|
+
const mmGMerge = mmG.merge(mmGEnter).attr("class", (d) => ["markmap-node", d.payload?.fold && "markmap-fold"].filter(Boolean).join(" "));
|
|
1785
|
+
const mmLine = mmGMerge.selectAll(childSelector("line")).data((d) => [d], (d) => d.state.key);
|
|
1786
|
+
const mmLineEnter = mmLine.enter().append("line").attr("stroke", (d) => color(d)).attr("stroke-width", 0);
|
|
1787
|
+
const mmLineMerge = mmLine.merge(mmLineEnter);
|
|
1788
|
+
const mmCircle = mmGMerge.selectAll(childSelector("circle")).data((d) => d.children?.length ? [d] : [], (d) => d.state.key);
|
|
1789
|
+
this.transition(mmCircle.exit()).attr("r", 0).attr("stroke-width", 0).remove();
|
|
1790
|
+
const mmCircleMerge = mmCircle.enter().append("circle").attr("stroke-width", 0).attr("r", 0).on("click", (e, d) => this.handleClick(e, d)).on("mousedown", stopPropagation).merge(mmCircle).attr("stroke", (d) => color(d)).attr("fill", (d) => d.payload?.fold && d.children ? color(d) : "var(--markmap-circle-open-bg)");
|
|
1791
|
+
const observer = this._observer;
|
|
1792
|
+
const mmFo = mmGMerge.selectAll(childSelector("foreignObject")).data((d) => [d], (d) => d.state.key);
|
|
1793
|
+
const mmFoEnter = mmFo.enter().append("foreignObject").attr("class", "markmap-foreign").attr("x", paddingX).attr("y", 0).style("opacity", 0).on("mousedown", stopPropagation).on("dblclick", (e, d) => {
|
|
1794
|
+
e.preventDefault();
|
|
1795
|
+
e.stopPropagation();
|
|
1796
|
+
e.stopImmediatePropagation();
|
|
1797
|
+
this._actions.handleEdit(e, d);
|
|
1798
|
+
});
|
|
1799
|
+
mmFoEnter.append("xhtml:div").append("xhtml:div").html((d) => d.content).attr("xmlns", "http://www.w3.org/1999/xhtml");
|
|
1800
|
+
mmFoEnter.each(function() {
|
|
1801
|
+
const el = this.firstChild?.firstChild;
|
|
1802
|
+
observer.observe(el);
|
|
1803
|
+
});
|
|
1804
|
+
const mmFoExit = mmGExit.selectAll(childSelector("foreignObject"));
|
|
1805
|
+
mmFoExit.each(function() {
|
|
1806
|
+
const el = this.firstChild?.firstChild;
|
|
1807
|
+
observer.unobserve(el);
|
|
1808
|
+
});
|
|
1809
|
+
const mmFoMerge = mmFoEnter.merge(mmFo);
|
|
1810
|
+
mmFoMerge.on("dblclick", (e, d) => {
|
|
1811
|
+
e.preventDefault();
|
|
1812
|
+
e.stopPropagation();
|
|
1813
|
+
e.stopImmediatePropagation();
|
|
1814
|
+
this._actions.handleEdit(e, d);
|
|
1815
|
+
});
|
|
1816
|
+
mmFoMerge.on("mouseenter", (e, d) => {
|
|
1817
|
+
if (!this.options.hoverBorder) return;
|
|
1818
|
+
const el = this.findElement(d);
|
|
1819
|
+
if (!el) return;
|
|
1820
|
+
const contentDiv = (0, d3.select)(el.g).select("foreignObject").node()?.firstChild?.firstChild;
|
|
1821
|
+
if (!contentDiv) return;
|
|
1822
|
+
const rect = contentDiv.getBoundingClientRect();
|
|
1823
|
+
if (e.clientX >= rect.left && e.clientX <= rect.right && e.clientY >= rect.top && e.clientY <= rect.bottom) (0, d3.select)(el.g).classed("markmap-node-hovered", true);
|
|
1824
|
+
});
|
|
1825
|
+
mmFoMerge.on("mousemove", (e, d) => {
|
|
1826
|
+
if (!this.options.hoverBorder) return;
|
|
1827
|
+
const el = this.findElement(d);
|
|
1828
|
+
if (!el) return;
|
|
1829
|
+
const contentDiv = (0, d3.select)(el.g).select("foreignObject").node()?.firstChild?.firstChild;
|
|
1830
|
+
if (!contentDiv) return;
|
|
1831
|
+
const rect = contentDiv.getBoundingClientRect();
|
|
1832
|
+
const inside = e.clientX >= rect.left && e.clientX <= rect.right && e.clientY >= rect.top && e.clientY <= rect.bottom;
|
|
1833
|
+
(0, d3.select)(el.g).classed("markmap-node-hovered", inside);
|
|
1834
|
+
});
|
|
1835
|
+
mmFoMerge.on("mouseleave", (_e, d) => {
|
|
1836
|
+
if (!this.options.hoverBorder) return;
|
|
1837
|
+
const el = this.findElement(d);
|
|
1838
|
+
if (el) (0, d3.select)(el.g).classed("markmap-node-hovered", false);
|
|
1839
|
+
});
|
|
1840
|
+
mmFoMerge.on("click", (e, d) => {
|
|
1841
|
+
if (this._actions.editingNode || this._actions.editOverlay) return;
|
|
1842
|
+
e.stopPropagation();
|
|
1843
|
+
const el = this.findElement(d);
|
|
1844
|
+
const contentDiv = el ? (0, d3.select)(el.g).select("foreignObject").node()?.firstChild?.firstChild : null;
|
|
1845
|
+
if (!(() => {
|
|
1846
|
+
if (!contentDiv) return false;
|
|
1847
|
+
const rect = contentDiv.getBoundingClientRect();
|
|
1848
|
+
return e.clientX >= rect.left && e.clientX <= rect.right && e.clientY >= rect.top && e.clientY <= rect.bottom;
|
|
1849
|
+
})()) return;
|
|
1850
|
+
this._actions.selectedNode = d;
|
|
1851
|
+
if (this.options.clickBorder) this.g.selectAll(childSelector(SELECTOR_NODE)).classed("markmap-selected", (n) => n === d);
|
|
1852
|
+
if (this.options.addable) this._actions.showAddUI(d);
|
|
1853
|
+
});
|
|
1854
|
+
mmFoMerge.select("div").select("div").html((d) => d.content);
|
|
1855
|
+
const links = nodes.flatMap((node) => node.payload?.fold ? [] : node.children.map((child) => ({
|
|
1856
|
+
source: node,
|
|
1857
|
+
target: child
|
|
1858
|
+
})));
|
|
1859
|
+
const mmPath = this.g.selectAll(childSelector(SELECTOR_LINK)).data(links, (d) => d.target.state.key);
|
|
1860
|
+
const mmPathExit = mmPath.exit();
|
|
1861
|
+
const mmPathMerge = mmPath.enter().insert("path", "g").attr("class", "markmap-link").attr("data-depth", (d) => d.target.state.depth).attr("data-path", (d) => d.target.state.path).attr("d", (d) => {
|
|
1862
|
+
const originRect = getOriginSourceRect(d.target);
|
|
1863
|
+
const pathOrigin = [originRect.x + originRect.width, originRect.y + originRect.height];
|
|
1864
|
+
return linkShape({
|
|
1865
|
+
source: pathOrigin,
|
|
1866
|
+
target: pathOrigin
|
|
1867
|
+
});
|
|
1868
|
+
}).attr("stroke-width", 0).merge(mmPath);
|
|
1869
|
+
this.svg.style("--markmap-max-width", maxWidth ? `${maxWidth}px` : null);
|
|
1870
|
+
await new Promise(requestAnimationFrame);
|
|
1871
|
+
this._relayout();
|
|
1872
|
+
highlightNodes = highlightNodes.data(highlight ? [this._getHighlightRect(highlight)] : []).join("rect");
|
|
1873
|
+
this.transition(highlightNodes).attr("x", (d) => d.x).attr("y", (d) => d.y).attr("width", (d) => d.width).attr("height", (d) => d.height);
|
|
1874
|
+
mmGEnter.attr("transform", (d) => {
|
|
1875
|
+
const originRect = getOriginSourceRect(d);
|
|
1876
|
+
return `translate(${originRect.x + originRect.width - d.state.rect.width},${originRect.y + originRect.height - d.state.rect.height})`;
|
|
1877
|
+
});
|
|
1878
|
+
this.transition(mmGExit).attr("transform", (d) => {
|
|
1879
|
+
const targetRect = getOriginTargetRect(d);
|
|
1880
|
+
return `translate(${targetRect.x + targetRect.width - d.state.rect.width},${targetRect.y + targetRect.height - d.state.rect.height})`;
|
|
1881
|
+
}).remove();
|
|
1882
|
+
this.transition(mmGMerge).attr("transform", (d) => `translate(${d.state.rect.x},${d.state.rect.y})`);
|
|
1883
|
+
const mmLineExit = mmGExit.selectAll(childSelector("line"));
|
|
1884
|
+
this.transition(mmLineExit).attr("x1", (d) => d.state.rect.width).attr("stroke-width", 0);
|
|
1885
|
+
mmLineEnter.attr("x1", (d) => d.state.rect.width).attr("x2", (d) => d.state.rect.width);
|
|
1886
|
+
mmLineMerge.attr("y1", (d) => d.state.rect.height + lineWidth(d) / 2).attr("y2", (d) => d.state.rect.height + lineWidth(d) / 2);
|
|
1887
|
+
this.transition(mmLineMerge).attr("x1", -1).attr("x2", (d) => d.state.rect.width + 2).attr("stroke", (d) => color(d)).attr("stroke-width", lineWidth);
|
|
1888
|
+
const mmCircleExit = mmGExit.selectAll(childSelector("circle"));
|
|
1889
|
+
this.transition(mmCircleExit).attr("r", 0).attr("stroke-width", 0);
|
|
1890
|
+
mmCircleMerge.attr("cx", (d) => d.state.rect.width + 4).attr("cy", (d) => d.state.rect.height + lineWidth(d) / 2);
|
|
1891
|
+
this.transition(mmCircleMerge).attr("r", 6).attr("stroke-width", 1.5);
|
|
1892
|
+
this.transition(mmFoExit).style("opacity", 0);
|
|
1893
|
+
mmFoMerge.attr("width", (d) => Math.max(0, d.state.rect.width - paddingX * 2 + 16)).attr("height", (d) => d.state.rect.height);
|
|
1894
|
+
this.transition(mmFoMerge).style("opacity", 1);
|
|
1895
|
+
this.transition(mmPathExit).attr("d", (d) => {
|
|
1896
|
+
const targetRect = getOriginTargetRect(d.target);
|
|
1897
|
+
const pathTarget = [targetRect.x + targetRect.width, targetRect.y + targetRect.height + lineWidth(d.target) / 2];
|
|
1898
|
+
return linkShape({
|
|
1899
|
+
source: pathTarget,
|
|
1900
|
+
target: pathTarget
|
|
1901
|
+
});
|
|
1902
|
+
}).attr("stroke-width", 0).remove();
|
|
1903
|
+
this.transition(mmPathMerge).attr("stroke", (d) => color(d.target)).attr("stroke-width", (d) => lineWidth(d.target)).attr("d", (d) => {
|
|
1904
|
+
const origSource = d.source;
|
|
1905
|
+
const origTarget = d.target;
|
|
1906
|
+
return linkShape({
|
|
1907
|
+
source: [origSource.state.rect.x + origSource.state.rect.width, origSource.state.rect.y + origSource.state.rect.height + lineWidth(origSource) / 2],
|
|
1908
|
+
target: [origTarget.state.rect.x, origTarget.state.rect.y + origTarget.state.rect.height + lineWidth(origTarget) / 2]
|
|
1909
|
+
});
|
|
1910
|
+
});
|
|
1911
|
+
if (autoFit) this.fit();
|
|
1912
|
+
}
|
|
1913
|
+
transition(sel) {
|
|
1914
|
+
const { duration } = this.options;
|
|
1915
|
+
return sel.transition().duration(duration);
|
|
1916
|
+
}
|
|
1917
|
+
/**
|
|
1918
|
+
* Fit the content to the viewport.
|
|
1919
|
+
*/
|
|
1920
|
+
async fit(maxScale = this.options.maxInitialScale) {
|
|
1921
|
+
const { width: offsetWidth, height: offsetHeight } = this.svg.node().getBoundingClientRect();
|
|
1922
|
+
const { fitRatio } = this.options;
|
|
1923
|
+
const { x1, y1, x2, y2 } = this.state.rect;
|
|
1924
|
+
const naturalWidth = x2 - x1;
|
|
1925
|
+
const naturalHeight = y2 - y1;
|
|
1926
|
+
const scale = Math.min(offsetWidth / naturalWidth * fitRatio, offsetHeight / naturalHeight * fitRatio, maxScale);
|
|
1927
|
+
const initialZoom = d3.zoomIdentity.translate((offsetWidth - naturalWidth * scale) / 2 - x1 * scale, (offsetHeight - naturalHeight * scale) / 2 - y1 * scale).scale(scale);
|
|
1928
|
+
return this.transition(this.svg).call(this.zoom.transform, initialZoom).end().catch(noop);
|
|
1929
|
+
}
|
|
1930
|
+
findElement(node) {
|
|
1931
|
+
let result;
|
|
1932
|
+
this.g.selectAll(childSelector(SELECTOR_NODE)).each(function walk(d) {
|
|
1933
|
+
if (d === node) result = {
|
|
1934
|
+
data: d,
|
|
1935
|
+
g: this
|
|
1936
|
+
};
|
|
1937
|
+
});
|
|
1938
|
+
return result;
|
|
1939
|
+
}
|
|
1940
|
+
/**
|
|
1941
|
+
* Pan the content to make the provided node visible in the viewport.
|
|
1942
|
+
*/
|
|
1943
|
+
async ensureVisible(node, padding) {
|
|
1944
|
+
const itemData = this.findElement(node)?.data;
|
|
1945
|
+
if (!itemData) return;
|
|
1946
|
+
const svgNode = this.svg.node();
|
|
1947
|
+
const relRect = svgNode.getBoundingClientRect();
|
|
1948
|
+
const transform = (0, d3.zoomTransform)(svgNode);
|
|
1949
|
+
const [left, right] = [itemData.state.rect.x, itemData.state.rect.x + itemData.state.rect.width + 2].map((x) => x * transform.k + transform.x);
|
|
1950
|
+
const [top, bottom] = [itemData.state.rect.y, itemData.state.rect.y + itemData.state.rect.height].map((y) => y * transform.k + transform.y);
|
|
1951
|
+
const pd = {
|
|
1952
|
+
left: 0,
|
|
1953
|
+
right: 0,
|
|
1954
|
+
top: 0,
|
|
1955
|
+
bottom: 0,
|
|
1956
|
+
...padding
|
|
1957
|
+
};
|
|
1958
|
+
const dxs = [pd.left - left, relRect.width - pd.right - right];
|
|
1959
|
+
const dys = [pd.top - top, relRect.height - pd.bottom - bottom];
|
|
1960
|
+
const dx = dxs[0] * dxs[1] > 0 ? minBy(dxs, Math.abs) / transform.k : 0;
|
|
1961
|
+
const dy = dys[0] * dys[1] > 0 ? minBy(dys, Math.abs) / transform.k : 0;
|
|
1962
|
+
if (dx || dy) {
|
|
1963
|
+
const newTransform = transform.translate(dx, dy);
|
|
1964
|
+
return this.transition(this.svg).call(this.zoom.transform, newTransform).end().catch(noop);
|
|
1965
|
+
}
|
|
1966
|
+
}
|
|
1967
|
+
async centerNode(node, padding) {
|
|
1968
|
+
const itemData = this.findElement(node)?.data;
|
|
1969
|
+
if (!itemData) return;
|
|
1970
|
+
const svgNode = this.svg.node();
|
|
1971
|
+
const relRect = svgNode.getBoundingClientRect();
|
|
1972
|
+
const transform = (0, d3.zoomTransform)(svgNode);
|
|
1973
|
+
const x = (itemData.state.rect.x + itemData.state.rect.width / 2) * transform.k + transform.x;
|
|
1974
|
+
const y = (itemData.state.rect.y + itemData.state.rect.height / 2) * transform.k + transform.y;
|
|
1975
|
+
const pd = {
|
|
1976
|
+
left: 0,
|
|
1977
|
+
right: 0,
|
|
1978
|
+
top: 0,
|
|
1979
|
+
bottom: 0,
|
|
1980
|
+
...padding
|
|
1981
|
+
};
|
|
1982
|
+
const cx = (pd.left + relRect.width - pd.right) / 2;
|
|
1983
|
+
const cy = (pd.top + relRect.height - pd.bottom) / 2;
|
|
1984
|
+
const dx = (cx - x) / transform.k;
|
|
1985
|
+
const dy = (cy - y) / transform.k;
|
|
1986
|
+
if (dx || dy) {
|
|
1987
|
+
const newTransform = transform.translate(dx, dy);
|
|
1988
|
+
return this.transition(this.svg).call(this.zoom.transform, newTransform).end().catch(noop);
|
|
1989
|
+
}
|
|
1990
|
+
}
|
|
1991
|
+
/**
|
|
1992
|
+
* Scale content with it pinned at the center of the viewport.
|
|
1993
|
+
*/
|
|
1994
|
+
async rescale(scale) {
|
|
1995
|
+
const svgNode = this.svg.node();
|
|
1996
|
+
const { width: offsetWidth, height: offsetHeight } = svgNode.getBoundingClientRect();
|
|
1997
|
+
const halfWidth = offsetWidth / 2;
|
|
1998
|
+
const halfHeight = offsetHeight / 2;
|
|
1999
|
+
const transform = (0, d3.zoomTransform)(svgNode);
|
|
2000
|
+
const newTransform = transform.translate((halfWidth - transform.x) * (1 - scale) / transform.k, (halfHeight - transform.y) * (1 - scale) / transform.k).scale(scale);
|
|
2001
|
+
return this.transition(this.svg).call(this.zoom.transform, newTransform).end().catch(noop);
|
|
2002
|
+
}
|
|
2003
|
+
destroy() {
|
|
2004
|
+
this.svg.on(".zoom", null);
|
|
2005
|
+
this.svg.html(null);
|
|
2006
|
+
this._disposeList.forEach((fn) => {
|
|
2007
|
+
fn();
|
|
2008
|
+
});
|
|
2009
|
+
}
|
|
2010
|
+
static create(svg, opts, data = null) {
|
|
2011
|
+
const mm = new Markmap(svg, opts);
|
|
2012
|
+
if (data) mm.setData(data).then(() => {
|
|
2013
|
+
mm.fit();
|
|
2014
|
+
});
|
|
2015
|
+
return mm;
|
|
2016
|
+
}
|
|
2017
|
+
};
|
|
2018
|
+
/**
|
|
2019
|
+
* Convert a single HTML inline-content string to Markdown text.
|
|
2020
|
+
* Handles common inline elements produced by markdown-it:
|
|
2021
|
+
* strong, em, del/s, code, a, img, br, and HTML entities.
|
|
2022
|
+
*/
|
|
2023
|
+
function htmlInlineToMarkdown(html) {
|
|
2024
|
+
if (!html) return "";
|
|
2025
|
+
let md = html;
|
|
2026
|
+
md = md.replace(/<img(?=[^>]*?\bsrc="([^"]*)")(?=[^>]*?\balt="([^"]*)")(?=[^>]*?\btitle="([^"]*)")?[^>]*?\/?>/gi, (_, src, alt, title) => title ? `` : ``);
|
|
2027
|
+
md = md.replace(/<img\s[^>]*?\/?>/gi, (match) => {
|
|
2028
|
+
const src = (match.match(/\bsrc="([^"]*)"/) || [])[1] ?? "";
|
|
2029
|
+
const alt = (match.match(/\balt="([^"]*)"/) || [])[1] ?? "";
|
|
2030
|
+
const title = (match.match(/\btitle="([^"]*)"/) || [])[1];
|
|
2031
|
+
return title ? `` : ``;
|
|
2032
|
+
});
|
|
2033
|
+
md = md.replace(/<a\s[^>]*?href="([^"]*)"[^>]*?>([\s\S]*?)<\/a>/gi, (_, href, inner) => {
|
|
2034
|
+
const title = (_.match(/\btitle="([^"]*)"/) || [])[1];
|
|
2035
|
+
const innerMd = htmlInlineToMarkdown(inner);
|
|
2036
|
+
return title ? `[${innerMd}](${href} "${title}")` : `[${innerMd}](${href})`;
|
|
2037
|
+
});
|
|
2038
|
+
md = md.replace(/<strong>([\s\S]*?)<\/strong>/gi, (_, t) => `**${htmlInlineToMarkdown(t)}**`);
|
|
2039
|
+
md = md.replace(/<b>([\s\S]*?)<\/b>/gi, (_, t) => `**${htmlInlineToMarkdown(t)}**`);
|
|
2040
|
+
md = md.replace(/<em>([\s\S]*?)<\/em>/gi, (_, t) => `*${htmlInlineToMarkdown(t)}*`);
|
|
2041
|
+
md = md.replace(/<i>([\s\S]*?)<\/i>/gi, (_, t) => `*${htmlInlineToMarkdown(t)}*`);
|
|
2042
|
+
md = md.replace(/<(?:del|s)>([\s\S]*?)<\/(?:del|s)>/gi, (_, t) => `~~${htmlInlineToMarkdown(t)}~~`);
|
|
2043
|
+
md = md.replace(/<code>([\s\S]*?)<\/code>/gi, (_, t) => {
|
|
2044
|
+
return "`" + t.replace(/&#x([0-9a-f]+);/gi, (_, hex) => String.fromCodePoint(parseInt(hex, 16))).replace(/&#([0-9]+);/g, (_, dec) => String.fromCodePoint(parseInt(dec, 10))).replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, "\"").replace(/'/g, "'") + "`";
|
|
2045
|
+
});
|
|
2046
|
+
md = md.replace(/<br\s*\/?>/gi, "\n");
|
|
2047
|
+
md = md.replace(/<[^>]+>/g, "");
|
|
2048
|
+
md = md.replace(/&#x([0-9a-f]+);/gi, (_, hex) => String.fromCodePoint(parseInt(hex, 16))).replace(/&#([0-9]+);/g, (_, dec) => String.fromCodePoint(parseInt(dec, 10))).replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, "\"").replace(/'/g, "'").replace(/ /g, " ");
|
|
2049
|
+
return md;
|
|
2050
|
+
}
|
|
2051
|
+
/**
|
|
2052
|
+
* Serialize an `IPureNode` tree back to a Markdown string.
|
|
2053
|
+
*
|
|
2054
|
+
* This is the conceptual inverse of `Transformer.transform()`.
|
|
2055
|
+
* The algorithm maps tree depth to Markdown heading levels:
|
|
2056
|
+
*
|
|
2057
|
+
* - depth 0 → `# text`
|
|
2058
|
+
* - depth 1 → `## text`
|
|
2059
|
+
* - depth 2 → `### text`
|
|
2060
|
+
* - depth 3+ → `- text` (indented list items, 2 spaces per extra level)
|
|
2061
|
+
*
|
|
2062
|
+
* A blank line is inserted between heading-level siblings to keep the
|
|
2063
|
+
* output readable and round-trip-stable through `transform()`.
|
|
2064
|
+
*
|
|
2065
|
+
* @param root Root node of the markmap tree (e.g. from `mm.getData(true)`).
|
|
2066
|
+
* @returns Markdown string.
|
|
2067
|
+
*
|
|
2068
|
+
* @example
|
|
2069
|
+
* ```ts
|
|
2070
|
+
* import { toMarkdown } from 'markmap-lib';
|
|
2071
|
+
*
|
|
2072
|
+
* const pureNode = mm.getData(true); // IPureNode
|
|
2073
|
+
* const markdown = toMarkdown(pureNode);
|
|
2074
|
+
* console.log(markdown);
|
|
2075
|
+
* ```
|
|
2076
|
+
*/
|
|
2077
|
+
function toMarkdown(root) {
|
|
2078
|
+
const lines = [];
|
|
2079
|
+
function walk(node, depth) {
|
|
2080
|
+
const text = htmlInlineToMarkdown(node.content).trim();
|
|
2081
|
+
if (text) if (depth <= 2) {
|
|
2082
|
+
const hashes = "#".repeat(depth + 1);
|
|
2083
|
+
if (lines.length > 0) lines.push("");
|
|
2084
|
+
lines.push(`${hashes} ${text}`);
|
|
2085
|
+
} else {
|
|
2086
|
+
const indent = " ".repeat(depth - 3);
|
|
2087
|
+
lines.push(`${indent}- ${text}`);
|
|
2088
|
+
}
|
|
2089
|
+
for (const child of node.children) walk(child, depth + 1);
|
|
2090
|
+
}
|
|
2091
|
+
walk(root, 0);
|
|
2092
|
+
return lines.join("\n").trimStart() + "\n";
|
|
2093
|
+
}
|
|
2094
|
+
exports.Markmap = Markmap;
|
|
2095
|
+
exports.childSelector = childSelector;
|
|
2096
|
+
exports.defaultColorFn = defaultColorFn;
|
|
2097
|
+
exports.defaultOptions = defaultOptions;
|
|
2098
|
+
exports.deriveOptions = deriveOptions;
|
|
2099
|
+
exports.globalCSS = globalCSS;
|
|
2100
|
+
exports.htmlInlineToMarkdown = htmlInlineToMarkdown;
|
|
2101
|
+
exports.isMacintosh = isMacintosh;
|
|
2102
|
+
exports.lineWidthFactory = lineWidthFactory;
|
|
2103
|
+
exports.loadCSS = loadCSS;
|
|
2104
|
+
exports.loadJS = loadJS;
|
|
2105
|
+
exports.refreshHook = refreshHook;
|
|
2106
|
+
exports.simpleHash = simpleHash;
|
|
2107
|
+
exports.toMarkdown = toMarkdown;
|
|
2159
2108
|
})(this.markmap = this.markmap || {}, d3);
|