@dynect/base 0.1.0 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/src/runtime/assets/svg/app/asset.svg +8 -0
- package/src/runtime/assets/svg/app/crm.svg +8 -0
- package/src/runtime/assets/svg/app/dark/asset.svg +6 -0
- package/src/runtime/assets/svg/app/dark/crm.svg +6 -0
- package/src/runtime/assets/svg/app/dark/erp.svg +5 -0
- package/src/runtime/assets/svg/app/dark/hrms.svg +8 -0
- package/src/runtime/assets/svg/app/dark/investment.svg +10 -0
- package/src/runtime/assets/svg/app/dark/pos.svg +5 -0
- package/src/runtime/assets/svg/app/dark/project.svg +8 -0
- package/src/runtime/assets/svg/app/dark/retail.svg +9 -0
- package/src/runtime/assets/svg/app/erp.svg +5 -0
- package/src/runtime/assets/svg/app/hrms.svg +10 -0
- package/src/runtime/assets/svg/app/investment.svg +12 -0
- package/src/runtime/assets/svg/app/outline/asset.svg +5 -0
- package/src/runtime/assets/svg/app/outline/crm.svg +6 -0
- package/src/runtime/assets/svg/app/outline/erp.svg +5 -0
- package/src/runtime/assets/svg/app/outline/hrms.svg +7 -0
- package/src/runtime/assets/svg/app/outline/investment.svg +9 -0
- package/src/runtime/assets/svg/app/outline/pos.svg +5 -0
- package/src/runtime/assets/svg/app/outline/project.svg +8 -0
- package/src/runtime/assets/svg/app/outline/retail.svg +9 -0
- package/src/runtime/assets/svg/app/pos.svg +7 -0
- package/src/runtime/assets/svg/app/project.svg +10 -0
- package/src/runtime/assets/svg/app/retail.svg +11 -0
- package/src/runtime/assets/svg/flags/ad.svg +150 -0
- package/src/runtime/assets/svg/flags/ae.svg +6 -0
- package/src/runtime/assets/svg/flags/af.svg +81 -0
- package/src/runtime/assets/svg/flags/ag.svg +14 -0
- package/src/runtime/assets/svg/flags/ai.svg +29 -0
- package/src/runtime/assets/svg/flags/al.svg +5 -0
- package/src/runtime/assets/svg/flags/am.svg +5 -0
- package/src/runtime/assets/svg/flags/ao.svg +13 -0
- package/src/runtime/assets/svg/flags/aq.svg +5 -0
- package/src/runtime/assets/svg/flags/ar.svg +32 -0
- package/src/runtime/assets/svg/flags/arab.svg +109 -0
- package/src/runtime/assets/svg/flags/as.svg +72 -0
- package/src/runtime/assets/svg/flags/asean.svg +13 -0
- package/src/runtime/assets/svg/flags/at.svg +4 -0
- package/src/runtime/assets/svg/flags/au.svg +8 -0
- package/src/runtime/assets/svg/flags/aw.svg +186 -0
- package/src/runtime/assets/svg/flags/ax.svg +18 -0
- package/src/runtime/assets/svg/flags/az.svg +8 -0
- package/src/runtime/assets/svg/flags/ba.svg +12 -0
- package/src/runtime/assets/svg/flags/bb.svg +6 -0
- package/src/runtime/assets/svg/flags/bd.svg +4 -0
- package/src/runtime/assets/svg/flags/be.svg +7 -0
- package/src/runtime/assets/svg/flags/bf.svg +7 -0
- package/src/runtime/assets/svg/flags/bg.svg +5 -0
- package/src/runtime/assets/svg/flags/bh.svg +4 -0
- package/src/runtime/assets/svg/flags/bi.svg +15 -0
- package/src/runtime/assets/svg/flags/bj.svg +14 -0
- package/src/runtime/assets/svg/flags/bl.svg +5 -0
- package/src/runtime/assets/svg/flags/bm.svg +97 -0
- package/src/runtime/assets/svg/flags/bn.svg +36 -0
- package/src/runtime/assets/svg/flags/bo.svg +673 -0
- package/src/runtime/assets/svg/flags/bq.svg +5 -0
- package/src/runtime/assets/svg/flags/br.svg +45 -0
- package/src/runtime/assets/svg/flags/bs.svg +13 -0
- package/src/runtime/assets/svg/flags/bt.svg +89 -0
- package/src/runtime/assets/svg/flags/bv.svg +13 -0
- package/src/runtime/assets/svg/flags/bw.svg +7 -0
- package/src/runtime/assets/svg/flags/by.svg +18 -0
- package/src/runtime/assets/svg/flags/bz.svg +145 -0
- package/src/runtime/assets/svg/flags/ca.svg +4 -0
- package/src/runtime/assets/svg/flags/cc.svg +19 -0
- package/src/runtime/assets/svg/flags/cd.svg +5 -0
- package/src/runtime/assets/svg/flags/cefta.svg +13 -0
- package/src/runtime/assets/svg/flags/cf.svg +15 -0
- package/src/runtime/assets/svg/flags/cg.svg +12 -0
- package/src/runtime/assets/svg/flags/ch.svg +9 -0
- package/src/runtime/assets/svg/flags/ci.svg +7 -0
- package/src/runtime/assets/svg/flags/ck.svg +9 -0
- package/src/runtime/assets/svg/flags/cl.svg +13 -0
- package/src/runtime/assets/svg/flags/cm.svg +15 -0
- package/src/runtime/assets/svg/flags/cn.svg +11 -0
- package/src/runtime/assets/svg/flags/co.svg +7 -0
- package/src/runtime/assets/svg/flags/cp.svg +7 -0
- package/src/runtime/assets/svg/flags/cr.svg +7 -0
- package/src/runtime/assets/svg/flags/cu.svg +13 -0
- package/src/runtime/assets/svg/flags/cv.svg +13 -0
- package/src/runtime/assets/svg/flags/cw.svg +14 -0
- package/src/runtime/assets/svg/flags/cx.svg +15 -0
- package/src/runtime/assets/svg/flags/cy.svg +6 -0
- package/src/runtime/assets/svg/flags/cz.svg +5 -0
- package/src/runtime/assets/svg/flags/de.svg +5 -0
- package/src/runtime/assets/svg/flags/dg.svg +130 -0
- package/src/runtime/assets/svg/flags/dj.svg +13 -0
- package/src/runtime/assets/svg/flags/dk.svg +5 -0
- package/src/runtime/assets/svg/flags/dm.svg +152 -0
- package/src/runtime/assets/svg/flags/do.svg +121 -0
- package/src/runtime/assets/svg/flags/dz.svg +5 -0
- package/src/runtime/assets/svg/flags/eac.svg +48 -0
- package/src/runtime/assets/svg/flags/ec.svg +138 -0
- package/src/runtime/assets/svg/flags/ee.svg +5 -0
- package/src/runtime/assets/svg/flags/eg.svg +38 -0
- package/src/runtime/assets/svg/flags/eh.svg +16 -0
- package/src/runtime/assets/svg/flags/er.svg +8 -0
- package/src/runtime/assets/svg/flags/es-ct.svg +4 -0
- package/src/runtime/assets/svg/flags/es-ga.svg +187 -0
- package/src/runtime/assets/svg/flags/es-pv.svg +5 -0
- package/src/runtime/assets/svg/flags/es.svg +544 -0
- package/src/runtime/assets/svg/flags/et.svg +14 -0
- package/src/runtime/assets/svg/flags/eu.svg +28 -0
- package/src/runtime/assets/svg/flags/fi.svg +5 -0
- package/src/runtime/assets/svg/flags/fj.svg +120 -0
- package/src/runtime/assets/svg/flags/fk.svg +90 -0
- package/src/runtime/assets/svg/flags/fm.svg +11 -0
- package/src/runtime/assets/svg/flags/fo.svg +12 -0
- package/src/runtime/assets/svg/flags/fr.svg +5 -0
- package/src/runtime/assets/svg/flags/ga.svg +7 -0
- package/src/runtime/assets/svg/flags/gb-eng.svg +5 -0
- package/src/runtime/assets/svg/flags/gb-nir.svg +132 -0
- package/src/runtime/assets/svg/flags/gb-sct.svg +4 -0
- package/src/runtime/assets/svg/flags/gb-wls.svg +9 -0
- package/src/runtime/assets/svg/flags/gb.svg +7 -0
- package/src/runtime/assets/svg/flags/gd.svg +27 -0
- package/src/runtime/assets/svg/flags/ge.svg +6 -0
- package/src/runtime/assets/svg/flags/gf.svg +5 -0
- package/src/runtime/assets/svg/flags/gg.svg +9 -0
- package/src/runtime/assets/svg/flags/gh.svg +6 -0
- package/src/runtime/assets/svg/flags/gi.svg +32 -0
- package/src/runtime/assets/svg/flags/gl.svg +4 -0
- package/src/runtime/assets/svg/flags/gm.svg +14 -0
- package/src/runtime/assets/svg/flags/gn.svg +7 -0
- package/src/runtime/assets/svg/flags/gp.svg +5 -0
- package/src/runtime/assets/svg/flags/gq.svg +23 -0
- package/src/runtime/assets/svg/flags/gr.svg +16 -0
- package/src/runtime/assets/svg/flags/gs.svg +133 -0
- package/src/runtime/assets/svg/flags/gt.svg +204 -0
- package/src/runtime/assets/svg/flags/gu.svg +19 -0
- package/src/runtime/assets/svg/flags/gw.svg +13 -0
- package/src/runtime/assets/svg/flags/gy.svg +9 -0
- package/src/runtime/assets/svg/flags/hk.svg +8 -0
- package/src/runtime/assets/svg/flags/hm.svg +8 -0
- package/src/runtime/assets/svg/flags/hn.svg +18 -0
- package/src/runtime/assets/svg/flags/hr.svg +58 -0
- package/src/runtime/assets/svg/flags/ht.svg +116 -0
- package/src/runtime/assets/svg/flags/hu.svg +7 -0
- package/src/runtime/assets/svg/flags/ic.svg +7 -0
- package/src/runtime/assets/svg/flags/id.svg +4 -0
- package/src/runtime/assets/svg/flags/ie.svg +7 -0
- package/src/runtime/assets/svg/flags/il.svg +14 -0
- package/src/runtime/assets/svg/flags/im.svg +36 -0
- package/src/runtime/assets/svg/flags/in.svg +25 -0
- package/src/runtime/assets/svg/flags/io.svg +130 -0
- package/src/runtime/assets/svg/flags/iq.svg +10 -0
- package/src/runtime/assets/svg/flags/ir.svg +219 -0
- package/src/runtime/assets/svg/flags/is.svg +12 -0
- package/src/runtime/assets/svg/flags/it.svg +7 -0
- package/src/runtime/assets/svg/flags/je.svg +62 -0
- package/src/runtime/assets/svg/flags/jm.svg +8 -0
- package/src/runtime/assets/svg/flags/jo.svg +16 -0
- package/src/runtime/assets/svg/flags/jp.svg +11 -0
- package/src/runtime/assets/svg/flags/ke.svg +23 -0
- package/src/runtime/assets/svg/flags/kg.svg +4 -0
- package/src/runtime/assets/svg/flags/kh.svg +61 -0
- package/src/runtime/assets/svg/flags/ki.svg +36 -0
- package/src/runtime/assets/svg/flags/km.svg +16 -0
- package/src/runtime/assets/svg/flags/kn.svg +14 -0
- package/src/runtime/assets/svg/flags/kp.svg +15 -0
- package/src/runtime/assets/svg/flags/kr.svg +24 -0
- package/src/runtime/assets/svg/flags/kw.svg +13 -0
- package/src/runtime/assets/svg/flags/ky.svg +103 -0
- package/src/runtime/assets/svg/flags/kz.svg +36 -0
- package/src/runtime/assets/svg/flags/la.svg +12 -0
- package/src/runtime/assets/svg/flags/lb.svg +15 -0
- package/src/runtime/assets/svg/flags/lc.svg +8 -0
- package/src/runtime/assets/svg/flags/li.svg +43 -0
- package/src/runtime/assets/svg/flags/lk.svg +22 -0
- package/src/runtime/assets/svg/flags/lr.svg +14 -0
- package/src/runtime/assets/svg/flags/ls.svg +8 -0
- package/src/runtime/assets/svg/flags/lt.svg +7 -0
- package/src/runtime/assets/svg/flags/lu.svg +5 -0
- package/src/runtime/assets/svg/flags/lv.svg +6 -0
- package/src/runtime/assets/svg/flags/ly.svg +13 -0
- package/src/runtime/assets/svg/flags/ma.svg +4 -0
- package/src/runtime/assets/svg/flags/mc.svg +6 -0
- package/src/runtime/assets/svg/flags/md.svg +70 -0
- package/src/runtime/assets/svg/flags/me.svg +116 -0
- package/src/runtime/assets/svg/flags/mf.svg +5 -0
- package/src/runtime/assets/svg/flags/mg.svg +7 -0
- package/src/runtime/assets/svg/flags/mh.svg +7 -0
- package/src/runtime/assets/svg/flags/mk.svg +5 -0
- package/src/runtime/assets/svg/flags/ml.svg +7 -0
- package/src/runtime/assets/svg/flags/mm.svg +12 -0
- package/src/runtime/assets/svg/flags/mn.svg +14 -0
- package/src/runtime/assets/svg/flags/mo.svg +9 -0
- package/src/runtime/assets/svg/flags/mp.svg +86 -0
- package/src/runtime/assets/svg/flags/mq.svg +5 -0
- package/src/runtime/assets/svg/flags/mr.svg +6 -0
- package/src/runtime/assets/svg/flags/ms.svg +29 -0
- package/src/runtime/assets/svg/flags/mt.svg +58 -0
- package/src/runtime/assets/svg/flags/mu.svg +8 -0
- package/src/runtime/assets/svg/flags/mv.svg +6 -0
- package/src/runtime/assets/svg/flags/mw.svg +10 -0
- package/src/runtime/assets/svg/flags/mx.svg +382 -0
- package/src/runtime/assets/svg/flags/my.svg +26 -0
- package/src/runtime/assets/svg/flags/mz.svg +21 -0
- package/src/runtime/assets/svg/flags/na.svg +16 -0
- package/src/runtime/assets/svg/flags/nc.svg +13 -0
- package/src/runtime/assets/svg/flags/ne.svg +6 -0
- package/src/runtime/assets/svg/flags/nf.svg +9 -0
- package/src/runtime/assets/svg/flags/ng.svg +6 -0
- package/src/runtime/assets/svg/flags/ni.svg +129 -0
- package/src/runtime/assets/svg/flags/nl.svg +5 -0
- package/src/runtime/assets/svg/flags/no.svg +7 -0
- package/src/runtime/assets/svg/flags/np.svg +13 -0
- package/src/runtime/assets/svg/flags/nr.svg +12 -0
- package/src/runtime/assets/svg/flags/nu.svg +10 -0
- package/src/runtime/assets/svg/flags/nz.svg +36 -0
- package/src/runtime/assets/svg/flags/om.svg +115 -0
- package/src/runtime/assets/svg/flags/pa.svg +14 -0
- package/src/runtime/assets/svg/flags/pc.svg +33 -0
- package/src/runtime/assets/svg/flags/pe.svg +4 -0
- package/src/runtime/assets/svg/flags/pf.svg +19 -0
- package/src/runtime/assets/svg/flags/pg.svg +9 -0
- package/src/runtime/assets/svg/flags/ph.svg +6 -0
- package/src/runtime/assets/svg/flags/pk.svg +15 -0
- package/src/runtime/assets/svg/flags/pl.svg +6 -0
- package/src/runtime/assets/svg/flags/pm.svg +5 -0
- package/src/runtime/assets/svg/flags/pn.svg +53 -0
- package/src/runtime/assets/svg/flags/pr.svg +13 -0
- package/src/runtime/assets/svg/flags/ps.svg +15 -0
- package/src/runtime/assets/svg/flags/pt.svg +57 -0
- package/src/runtime/assets/svg/flags/pw.svg +11 -0
- package/src/runtime/assets/svg/flags/py.svg +157 -0
- package/src/runtime/assets/svg/flags/qa.svg +4 -0
- package/src/runtime/assets/svg/flags/re.svg +5 -0
- package/src/runtime/assets/svg/flags/ro.svg +7 -0
- package/src/runtime/assets/svg/flags/rs.svg +292 -0
- package/src/runtime/assets/svg/flags/ru.svg +5 -0
- package/src/runtime/assets/svg/flags/rw.svg +13 -0
- package/src/runtime/assets/svg/flags/sa.svg +25 -0
- package/src/runtime/assets/svg/flags/sb.svg +13 -0
- package/src/runtime/assets/svg/flags/sc.svg +7 -0
- package/src/runtime/assets/svg/flags/sd.svg +13 -0
- package/src/runtime/assets/svg/flags/se.svg +4 -0
- package/src/runtime/assets/svg/flags/sg.svg +13 -0
- package/src/runtime/assets/svg/flags/sh-ac.svg +689 -0
- package/src/runtime/assets/svg/flags/sh-hl.svg +164 -0
- package/src/runtime/assets/svg/flags/sh-ta.svg +76 -0
- package/src/runtime/assets/svg/flags/sh.svg +7 -0
- package/src/runtime/assets/svg/flags/si.svg +18 -0
- package/src/runtime/assets/svg/flags/sj.svg +7 -0
- package/src/runtime/assets/svg/flags/sk.svg +9 -0
- package/src/runtime/assets/svg/flags/sl.svg +7 -0
- package/src/runtime/assets/svg/flags/sm.svg +75 -0
- package/src/runtime/assets/svg/flags/sn.svg +8 -0
- package/src/runtime/assets/svg/flags/so.svg +11 -0
- package/src/runtime/assets/svg/flags/sr.svg +6 -0
- package/src/runtime/assets/svg/flags/ss.svg +8 -0
- package/src/runtime/assets/svg/flags/st.svg +16 -0
- package/src/runtime/assets/svg/flags/state/ft.svg +5503 -0
- package/src/runtime/assets/svg/flags/state/johor.svg +59 -0
- package/src/runtime/assets/svg/flags/state/kedah.svg +246 -0
- package/src/runtime/assets/svg/flags/state/kelantan.svg +84 -0
- package/src/runtime/assets/svg/flags/state/kuala_lumpur.svg +9 -0
- package/src/runtime/assets/svg/flags/state/labuan.svg +10 -0
- package/src/runtime/assets/svg/flags/state/melaka.svg +56 -0
- package/src/runtime/assets/svg/flags/state/negeri_sembilan.svg +5 -0
- package/src/runtime/assets/svg/flags/state/pahang.svg +5 -0
- package/src/runtime/assets/svg/flags/state/penang.svg +514 -0
- package/src/runtime/assets/svg/flags/state/perak.svg +5 -0
- package/src/runtime/assets/svg/flags/state/perlis.svg +5 -0
- package/src/runtime/assets/svg/flags/state/putrajaya.svg +2631 -0
- package/src/runtime/assets/svg/flags/state/sabah.svg +8 -0
- package/src/runtime/assets/svg/flags/state/sarawak.svg +18 -0
- package/src/runtime/assets/svg/flags/state/selangor.svg +20 -0
- package/src/runtime/assets/svg/flags/state/terengganu.svg +6 -0
- package/src/runtime/assets/svg/flags/sv.svg +593 -0
- package/src/runtime/assets/svg/flags/sx.svg +56 -0
- package/src/runtime/assets/svg/flags/sy.svg +6 -0
- package/src/runtime/assets/svg/flags/sz.svg +34 -0
- package/src/runtime/assets/svg/flags/tc.svg +50 -0
- package/src/runtime/assets/svg/flags/td.svg +7 -0
- package/src/runtime/assets/svg/flags/tf.svg +15 -0
- package/src/runtime/assets/svg/flags/tg.svg +14 -0
- package/src/runtime/assets/svg/flags/th.svg +7 -0
- package/src/runtime/assets/svg/flags/tj.svg +22 -0
- package/src/runtime/assets/svg/flags/tk.svg +5 -0
- package/src/runtime/assets/svg/flags/tl.svg +13 -0
- package/src/runtime/assets/svg/flags/tm.svg +204 -0
- package/src/runtime/assets/svg/flags/tn.svg +4 -0
- package/src/runtime/assets/svg/flags/to.svg +10 -0
- package/src/runtime/assets/svg/flags/tr.svg +8 -0
- package/src/runtime/assets/svg/flags/tt.svg +5 -0
- package/src/runtime/assets/svg/flags/tv.svg +9 -0
- package/src/runtime/assets/svg/flags/tw.svg +34 -0
- package/src/runtime/assets/svg/flags/tz.svg +13 -0
- package/src/runtime/assets/svg/flags/ua.svg +6 -0
- package/src/runtime/assets/svg/flags/ug.svg +30 -0
- package/src/runtime/assets/svg/flags/um.svg +9 -0
- package/src/runtime/assets/svg/flags/un.svg +16 -0
- package/src/runtime/assets/svg/flags/us.svg +9 -0
- package/src/runtime/assets/svg/flags/uy.svg +28 -0
- package/src/runtime/assets/svg/flags/uz.svg +30 -0
- package/src/runtime/assets/svg/flags/va.svg +190 -0
- package/src/runtime/assets/svg/flags/vc.svg +8 -0
- package/src/runtime/assets/svg/flags/ve.svg +26 -0
- package/src/runtime/assets/svg/flags/vg.svg +59 -0
- package/src/runtime/assets/svg/flags/vi.svg +28 -0
- package/src/runtime/assets/svg/flags/vn.svg +11 -0
- package/src/runtime/assets/svg/flags/vu.svg +21 -0
- package/src/runtime/assets/svg/flags/wf.svg +5 -0
- package/src/runtime/assets/svg/flags/ws.svg +7 -0
- package/src/runtime/assets/svg/flags/xk.svg +5 -0
- package/src/runtime/assets/svg/flags/xx.svg +4 -0
- package/src/runtime/assets/svg/flags/ye.svg +7 -0
- package/src/runtime/assets/svg/flags/yt.svg +5 -0
- package/src/runtime/assets/svg/flags/za.svg +17 -0
- package/src/runtime/assets/svg/flags/zm.svg +27 -0
- package/src/runtime/assets/svg/flags/zw.svg +21 -0
- package/src/runtime/assets/svg/icon/activity.svg +4 -0
- package/src/runtime/assets/svg/icon/arrow-left.svg +3 -0
- package/src/runtime/assets/svg/icon/arrow-right.svg +3 -0
- package/src/runtime/assets/svg/icon/building-07.svg +4 -0
- package/src/runtime/assets/svg/icon/car-01.svg +4 -0
- package/src/runtime/assets/svg/icon/cash.svg +3 -0
- package/src/runtime/assets/svg/icon/clipboard-check.svg +3 -0
- package/src/runtime/assets/svg/icon/cog.svg +3 -0
- package/src/runtime/assets/svg/icon/colapse-sidebar.svg +3 -0
- package/src/runtime/assets/svg/icon/file-chart-bar.svg +3 -0
- package/src/runtime/assets/svg/icon/frame.svg +3 -0
- package/src/runtime/assets/svg/icon/gift-09.svg +7 -0
- package/src/runtime/assets/svg/icon/grid.svg +227 -0
- package/src/runtime/assets/svg/icon/layers.svg +3 -0
- package/src/runtime/assets/svg/icon/medical-cross.svg +3 -0
- package/src/runtime/assets/svg/icon/minimise-sidebar.svg +3 -0
- package/src/runtime/assets/svg/icon/rocket.svg +3 -0
- package/src/runtime/assets/svg/icon/speedometer-04.svg +5 -0
- package/src/runtime/assets/svg/icon/user-headset.svg +3 -0
- package/src/runtime/assets/svg/icon/users-group.svg +3 -0
- package/src/runtime/assets/svg/icon/users.svg +3 -0
- package/src/runtime/assets/svg/images/document-folders.svg +86 -0
- package/src/runtime/assets/svg/images/error-404.svg +56 -0
- package/src/runtime/assets/svg/images/error-500.svg +243 -0
- package/src/runtime/assets/svg/images/login-right-content.svg +272 -0
- package/src/runtime/assets/svg/images/man-question-mark.svg +130 -0
- package/src/runtime/assets/svg/logo/logomark.svg +4 -0
- package/src/runtime/assets/svg/logo/logotext.svg +10 -0
- package/src/runtime/components/base/event-calendar/AgendaView.vue +92 -0
- package/src/runtime/components/base/event-calendar/ColorManager.vue +149 -0
- package/src/runtime/components/base/event-calendar/DayEventsOverflowPopup.vue +41 -0
- package/src/runtime/components/base/event-calendar/DayView.vue +254 -0
- package/src/runtime/components/base/event-calendar/DragDropVisualFeedback.vue +97 -0
- package/src/runtime/components/base/event-calendar/EventCalendar.md +203 -0
- package/src/runtime/components/base/event-calendar/EventCalendar.vue +414 -0
- package/src/runtime/components/base/event-calendar/EventModal.vue +573 -0
- package/src/runtime/components/base/event-calendar/EventResizeHandle.vue +284 -0
- package/src/runtime/components/base/event-calendar/ExternalCalendarSettings.vue +138 -0
- package/src/runtime/components/base/event-calendar/LocationDisplay.vue +62 -0
- package/src/runtime/components/base/event-calendar/MonthView.vue +272 -0
- package/src/runtime/components/base/event-calendar/WeekView.vue +329 -0
- package/src/runtime/components/base/event-calendar/composables/useAdvancedValidation.ts +557 -0
- package/src/runtime/components/base/event-calendar/composables/useCalendarUtils.ts +70 -0
- package/src/runtime/components/base/event-calendar/composables/useColorManager.ts +244 -0
- package/src/runtime/components/base/event-calendar/composables/useCompatibility.ts +318 -0
- package/src/runtime/components/base/event-calendar/composables/useDragAndDrop.ts +481 -0
- package/src/runtime/components/base/event-calendar/composables/useEventFiltering.ts +116 -0
- package/src/runtime/components/base/event-calendar/composables/useEventStatus.ts +108 -0
- package/src/runtime/components/base/event-calendar/composables/useEventStore.ts +325 -0
- package/src/runtime/components/base/event-calendar/composables/useExternalCalendar.ts +340 -0
- package/src/runtime/components/base/event-calendar/composables/useKeyboardNavigation.ts +95 -0
- package/src/runtime/components/base/event-calendar/composables/useMonitoring.ts +433 -0
- package/src/runtime/components/base/event-calendar/composables/useMultiDayLayout.ts +131 -0
- package/src/runtime/components/base/event-calendar/composables/usePerformanceCache.ts +134 -0
- package/src/runtime/components/base/event-calendar/composables/useRecurringEvents.ts +291 -0
- package/src/runtime/components/base/event-calendar/composables/useResilientErrorHandling.ts +480 -0
- package/src/runtime/components/base/event-calendar/composables/useSecurity.ts +425 -0
- package/src/runtime/components/base/event-calendar/composables/useTimezone.ts +256 -0
- package/src/runtime/components/base/event-calendar/constants.ts +18 -0
- package/src/runtime/components/base/event-calendar/eventModal.schema.ts +32 -0
- package/src/runtime/components/base/event-calendar/types.ts +96 -0
- package/src/runtime/components/base/org-chart/index.vue +359 -0
- package/src/runtime/components/base/org-chart/main.ts +2372 -0
- package/src/runtime/components/base/org-chart/svg-icons.ts +58 -0
- package/src/runtime/components/base/org-chart/types.ts +492 -0
- package/src/runtime/components/base/signature/index.vue +218 -0
- package/src/runtime/components/base/toast/Toast.vue +396 -0
- package/src/runtime/components/base/toast/Toaster.vue +1241 -0
- package/src/runtime/components/base/toast/assets/CloseIcon.vue +3 -0
- package/src/runtime/components/base/toast/assets/ErrorIcon.vue +7 -0
- package/src/runtime/components/base/toast/assets/IconWrapper.vue +13 -0
- package/src/runtime/components/base/toast/assets/InfoIcon.vue +7 -0
- package/src/runtime/components/base/toast/assets/Loader.vue +18 -0
- package/src/runtime/components/base/toast/assets/SuccessIcon.vue +7 -0
- package/src/runtime/components/base/toast/assets/WarningIcon.vue +7 -0
- package/src/runtime/components/base/toast/constant.ts +30 -0
- package/src/runtime/components/base/toast/hooks.ts +114 -0
- package/src/runtime/components/base/toast/state.ts +317 -0
- package/src/runtime/components/base/toast/types.ts +201 -0
- package/src/runtime/components/chart/Bar.vue +175 -0
- package/src/runtime/components/chart/Line.vue +149 -0
- package/src/runtime/components/chart/Pie.vue +115 -0
- package/src/runtime/components/chart/Radar.vue +167 -0
- package/src/runtime/components/dynect/Accordion.vue +152 -0
- package/src/runtime/components/dynect/Alert.vue +194 -0
- package/src/runtime/components/dynect/Autocomplete.vue +404 -0
- package/src/runtime/components/dynect/Avatar.vue +132 -0
- package/src/runtime/components/dynect/AvatarGroup.vue +56 -0
- package/src/runtime/components/dynect/AvatarLabel.vue +82 -0
- package/src/runtime/components/dynect/Badge.vue +101 -0
- package/src/runtime/components/dynect/Button.vue +36 -0
- package/src/runtime/components/dynect/Checkbox.vue +80 -0
- package/src/runtime/components/dynect/DatePicker.vue +180 -0
- package/src/runtime/components/dynect/DateRange.vue +217 -0
- package/src/runtime/components/dynect/Dropzone.vue +355 -0
- package/src/runtime/components/dynect/EventCalendar.vue +66 -0
- package/src/runtime/components/dynect/Filters.vue +162 -0
- package/src/runtime/components/dynect/FormDescription.vue +20 -0
- package/src/runtime/components/dynect/FormError.vue +20 -0
- package/src/runtime/components/dynect/FormField.vue +45 -0
- package/src/runtime/components/dynect/FormLabel.vue +40 -0
- package/src/runtime/components/dynect/Gantt.vue +231 -0
- package/src/runtime/components/dynect/Input.vue +234 -0
- package/src/runtime/components/dynect/Kanban.vue +128 -0
- package/src/runtime/components/dynect/Modal.vue +118 -0
- package/src/runtime/components/dynect/OtpInput.vue +148 -0
- package/src/runtime/components/dynect/Pagination.vue +57 -0
- package/src/runtime/components/dynect/PermissionGuard.vue +50 -0
- package/src/runtime/components/dynect/Progress.vue +102 -0
- package/src/runtime/components/dynect/Radio.vue +90 -0
- package/src/runtime/components/dynect/Select.vue +190 -0
- package/src/runtime/components/dynect/SelectMultiple.vue +259 -0
- package/src/runtime/components/dynect/Sheet.vue +80 -0
- package/src/runtime/components/dynect/Signature.vue +135 -0
- package/src/runtime/components/dynect/SwitchColor.vue +14 -0
- package/src/runtime/components/dynect/SwitchLanguage.vue +39 -0
- package/src/runtime/components/dynect/Table.vue +488 -0
- package/src/runtime/components/dynect/TagsInput.vue +388 -0
- package/src/runtime/components/dynect/Telephone.vue +651 -0
- package/src/runtime/components/dynect/TextEditor.vue +94 -0
- package/src/runtime/components/dynect/Textarea.vue +108 -0
- package/src/runtime/components/dynect/TimePicker.vue +275 -0
- package/src/runtime/components/dynect/Timeline.vue +301 -0
- package/src/runtime/components/dynect/Toggle.vue +100 -0
- package/src/runtime/components/ui/accordion/Accordion.vue +15 -0
- package/src/runtime/components/ui/accordion/AccordionContent.vue +19 -0
- package/src/runtime/components/ui/accordion/AccordionItem.vue +19 -0
- package/src/runtime/components/ui/accordion/AccordionTrigger.vue +32 -0
- package/src/runtime/components/ui/accordion/index.ts +4 -0
- package/src/runtime/components/ui/alert/Alert.vue +17 -0
- package/src/runtime/components/ui/alert/AlertDescription.vue +14 -0
- package/src/runtime/components/ui/alert/AlertTitle.vue +14 -0
- package/src/runtime/components/ui/alert/index.ts +20 -0
- package/src/runtime/components/ui/alert-dialog/AlertDialog.vue +15 -0
- package/src/runtime/components/ui/alert-dialog/AlertDialogAction.vue +18 -0
- package/src/runtime/components/ui/alert-dialog/AlertDialogCancel.vue +18 -0
- package/src/runtime/components/ui/alert-dialog/AlertDialogContent.vue +36 -0
- package/src/runtime/components/ui/alert-dialog/AlertDialogDescription.vue +17 -0
- package/src/runtime/components/ui/alert-dialog/AlertDialogFooter.vue +14 -0
- package/src/runtime/components/ui/alert-dialog/AlertDialogHeader.vue +14 -0
- package/src/runtime/components/ui/alert-dialog/AlertDialogTitle.vue +17 -0
- package/src/runtime/components/ui/alert-dialog/AlertDialogTrigger.vue +12 -0
- package/src/runtime/components/ui/alert-dialog/index.ts +9 -0
- package/src/runtime/components/ui/aspect-ratio/AspectRatio.vue +12 -0
- package/src/runtime/components/ui/aspect-ratio/index.ts +1 -0
- package/src/runtime/components/ui/avatar/Avatar.vue +15 -0
- package/src/runtime/components/ui/avatar/AvatarFallback.vue +17 -0
- package/src/runtime/components/ui/avatar/AvatarImage.vue +12 -0
- package/src/runtime/components/ui/avatar/index.ts +3 -0
- package/src/runtime/components/ui/badge/Badge.vue +24 -0
- package/src/runtime/components/ui/badge/index.ts +22 -0
- package/src/runtime/components/ui/breadcrumb/Breadcrumb.vue +13 -0
- package/src/runtime/components/ui/breadcrumb/BreadcrumbEllipsis.vue +18 -0
- package/src/runtime/components/ui/breadcrumb/BreadcrumbItem.vue +14 -0
- package/src/runtime/components/ui/breadcrumb/BreadcrumbLink.vue +16 -0
- package/src/runtime/components/ui/breadcrumb/BreadcrumbList.vue +14 -0
- package/src/runtime/components/ui/breadcrumb/BreadcrumbPage.vue +14 -0
- package/src/runtime/components/ui/breadcrumb/BreadcrumbSeparator.vue +17 -0
- package/src/runtime/components/ui/breadcrumb/index.ts +7 -0
- package/src/runtime/components/ui/button/Button.vue +38 -0
- package/src/runtime/components/ui/button/index.ts +51 -0
- package/src/runtime/components/ui/button-group/ButtonGroup.vue +17 -0
- package/src/runtime/components/ui/button-group/ButtonGroupSeparator.vue +16 -0
- package/src/runtime/components/ui/button-group/ButtonGroupText.vue +22 -0
- package/src/runtime/components/ui/button-group/index.ts +23 -0
- package/src/runtime/components/ui/calendar/Calendar.vue +163 -0
- package/src/runtime/components/ui/calendar/CalendarCell.vue +19 -0
- package/src/runtime/components/ui/calendar/CalendarCellTrigger.vue +47 -0
- package/src/runtime/components/ui/calendar/CalendarGrid.vue +19 -0
- package/src/runtime/components/ui/calendar/CalendarGridBody.vue +12 -0
- package/src/runtime/components/ui/calendar/CalendarGridHead.vue +13 -0
- package/src/runtime/components/ui/calendar/CalendarGridRow.vue +19 -0
- package/src/runtime/components/ui/calendar/CalendarHeadCell.vue +19 -0
- package/src/runtime/components/ui/calendar/CalendarHeader.vue +19 -0
- package/src/runtime/components/ui/calendar/CalendarHeading.vue +25 -0
- package/src/runtime/components/ui/calendar/CalendarNextButton.vue +22 -0
- package/src/runtime/components/ui/calendar/CalendarPrevButton.vue +22 -0
- package/src/runtime/components/ui/calendar/index.ts +14 -0
- package/src/runtime/components/ui/card/Card.vue +14 -0
- package/src/runtime/components/ui/card/CardAction.vue +14 -0
- package/src/runtime/components/ui/card/CardContent.vue +14 -0
- package/src/runtime/components/ui/card/CardDescription.vue +14 -0
- package/src/runtime/components/ui/card/CardFooter.vue +14 -0
- package/src/runtime/components/ui/card/CardHeader.vue +14 -0
- package/src/runtime/components/ui/card/CardTitle.vue +14 -0
- package/src/runtime/components/ui/card/index.ts +7 -0
- package/src/runtime/components/ui/carousel/Carousel.vue +46 -0
- package/src/runtime/components/ui/carousel/CarouselContent.vue +21 -0
- package/src/runtime/components/ui/carousel/CarouselItem.vue +15 -0
- package/src/runtime/components/ui/carousel/CarouselNext.vue +32 -0
- package/src/runtime/components/ui/carousel/CarouselPrevious.vue +32 -0
- package/src/runtime/components/ui/carousel/index.ts +8 -0
- package/src/runtime/components/ui/carousel/interface.ts +22 -0
- package/src/runtime/components/ui/carousel/useCarousel.ts +51 -0
- package/src/runtime/components/ui/chart/ChartContainer.vue +61 -0
- package/src/runtime/components/ui/chart/ChartLegendContent.vue +52 -0
- package/src/runtime/components/ui/chart/ChartStyle.vue +37 -0
- package/src/runtime/components/ui/chart/ChartTooltipContent.vue +92 -0
- package/src/runtime/components/ui/chart/index.ts +26 -0
- package/src/runtime/components/ui/chart/utils.ts +45 -0
- package/src/runtime/components/ui/checkbox/Checkbox.vue +34 -0
- package/src/runtime/components/ui/checkbox/index.ts +1 -0
- package/src/runtime/components/ui/collapsible/Collapsible.vue +15 -0
- package/src/runtime/components/ui/collapsible/CollapsibleContent.vue +12 -0
- package/src/runtime/components/ui/collapsible/CollapsibleTrigger.vue +12 -0
- package/src/runtime/components/ui/collapsible/index.ts +3 -0
- package/src/runtime/components/ui/combobox/Combobox.vue +15 -0
- package/src/runtime/components/ui/combobox/ComboboxAnchor.vue +19 -0
- package/src/runtime/components/ui/combobox/ComboboxEmpty.vue +17 -0
- package/src/runtime/components/ui/combobox/ComboboxGroup.vue +25 -0
- package/src/runtime/components/ui/combobox/ComboboxInput.vue +33 -0
- package/src/runtime/components/ui/combobox/ComboboxItem.vue +29 -0
- package/src/runtime/components/ui/combobox/ComboboxItemIndicator.vue +19 -0
- package/src/runtime/components/ui/combobox/ComboboxList.vue +38 -0
- package/src/runtime/components/ui/combobox/ComboboxSeparator.vue +17 -0
- package/src/runtime/components/ui/combobox/ComboboxTrigger.vue +19 -0
- package/src/runtime/components/ui/combobox/ComboboxViewport.vue +19 -0
- package/src/runtime/components/ui/combobox/index.ts +12 -0
- package/src/runtime/components/ui/command/Command.vue +85 -0
- package/src/runtime/components/ui/command/CommandDialog.vue +36 -0
- package/src/runtime/components/ui/command/CommandEmpty.vue +22 -0
- package/src/runtime/components/ui/command/CommandGroup.vue +40 -0
- package/src/runtime/components/ui/command/CommandInput.vue +38 -0
- package/src/runtime/components/ui/command/CommandItem.vue +80 -0
- package/src/runtime/components/ui/command/CommandList.vue +21 -0
- package/src/runtime/components/ui/command/CommandSeparator.vue +17 -0
- package/src/runtime/components/ui/command/CommandShortcut.vue +14 -0
- package/src/runtime/components/ui/command/index.ts +25 -0
- package/src/runtime/components/ui/context-menu/ContextMenu.vue +15 -0
- package/src/runtime/components/ui/context-menu/ContextMenuCheckboxItem.vue +37 -0
- package/src/runtime/components/ui/context-menu/ContextMenuContent.vue +35 -0
- package/src/runtime/components/ui/context-menu/ContextMenuGroup.vue +12 -0
- package/src/runtime/components/ui/context-menu/ContextMenuItem.vue +42 -0
- package/src/runtime/components/ui/context-menu/ContextMenuLabel.vue +17 -0
- package/src/runtime/components/ui/context-menu/ContextMenuPortal.vue +12 -0
- package/src/runtime/components/ui/context-menu/ContextMenuRadioGroup.vue +15 -0
- package/src/runtime/components/ui/context-menu/ContextMenuRadioItem.vue +37 -0
- package/src/runtime/components/ui/context-menu/ContextMenuSeparator.vue +15 -0
- package/src/runtime/components/ui/context-menu/ContextMenuShortcut.vue +14 -0
- package/src/runtime/components/ui/context-menu/ContextMenuSub.vue +15 -0
- package/src/runtime/components/ui/context-menu/ContextMenuSubContent.vue +29 -0
- package/src/runtime/components/ui/context-menu/ContextMenuSubTrigger.vue +31 -0
- package/src/runtime/components/ui/context-menu/ContextMenuTrigger.vue +14 -0
- package/src/runtime/components/ui/context-menu/index.ts +14 -0
- package/src/runtime/components/ui/dialog/Dialog.vue +15 -0
- package/src/runtime/components/ui/dialog/DialogClose.vue +12 -0
- package/src/runtime/components/ui/dialog/DialogContent.vue +49 -0
- package/src/runtime/components/ui/dialog/DialogDescription.vue +19 -0
- package/src/runtime/components/ui/dialog/DialogFooter.vue +25 -0
- package/src/runtime/components/ui/dialog/DialogHeader.vue +14 -0
- package/src/runtime/components/ui/dialog/DialogOverlay.vue +17 -0
- package/src/runtime/components/ui/dialog/DialogScrollContent.vue +46 -0
- package/src/runtime/components/ui/dialog/DialogTitle.vue +19 -0
- package/src/runtime/components/ui/dialog/DialogTrigger.vue +12 -0
- package/src/runtime/components/ui/dialog/index.ts +10 -0
- package/src/runtime/components/ui/drawer/Drawer.vue +19 -0
- package/src/runtime/components/ui/drawer/DrawerClose.vue +12 -0
- package/src/runtime/components/ui/drawer/DrawerContent.vue +40 -0
- package/src/runtime/components/ui/drawer/DrawerDescription.vue +17 -0
- package/src/runtime/components/ui/drawer/DrawerFooter.vue +14 -0
- package/src/runtime/components/ui/drawer/DrawerHeader.vue +14 -0
- package/src/runtime/components/ui/drawer/DrawerOverlay.vue +15 -0
- package/src/runtime/components/ui/drawer/DrawerTitle.vue +17 -0
- package/src/runtime/components/ui/drawer/DrawerTrigger.vue +12 -0
- package/src/runtime/components/ui/drawer/index.ts +9 -0
- package/src/runtime/components/ui/dropdown-menu/DropdownMenu.vue +15 -0
- package/src/runtime/components/ui/dropdown-menu/DropdownMenuCheckboxItem.vue +37 -0
- package/src/runtime/components/ui/dropdown-menu/DropdownMenuContent.vue +37 -0
- package/src/runtime/components/ui/dropdown-menu/DropdownMenuGroup.vue +12 -0
- package/src/runtime/components/ui/dropdown-menu/DropdownMenuItem.vue +41 -0
- package/src/runtime/components/ui/dropdown-menu/DropdownMenuLabel.vue +18 -0
- package/src/runtime/components/ui/dropdown-menu/DropdownMenuRadioGroup.vue +15 -0
- package/src/runtime/components/ui/dropdown-menu/DropdownMenuRadioItem.vue +38 -0
- package/src/runtime/components/ui/dropdown-menu/DropdownMenuSeparator.vue +19 -0
- package/src/runtime/components/ui/dropdown-menu/DropdownMenuShortcut.vue +14 -0
- package/src/runtime/components/ui/dropdown-menu/DropdownMenuSub.vue +15 -0
- package/src/runtime/components/ui/dropdown-menu/DropdownMenuSubContent.vue +29 -0
- package/src/runtime/components/ui/dropdown-menu/DropdownMenuSubTrigger.vue +30 -0
- package/src/runtime/components/ui/dropdown-menu/DropdownMenuTrigger.vue +14 -0
- package/src/runtime/components/ui/dropdown-menu/index.ts +16 -0
- package/src/runtime/components/ui/empty/Empty.vue +14 -0
- package/src/runtime/components/ui/empty/EmptyContent.vue +14 -0
- package/src/runtime/components/ui/empty/EmptyDescription.vue +14 -0
- package/src/runtime/components/ui/empty/EmptyHeader.vue +14 -0
- package/src/runtime/components/ui/empty/EmptyMedia.vue +17 -0
- package/src/runtime/components/ui/empty/EmptyTitle.vue +14 -0
- package/src/runtime/components/ui/empty/index.ts +23 -0
- package/src/runtime/components/ui/field/Field.vue +17 -0
- package/src/runtime/components/ui/field/FieldContent.vue +14 -0
- package/src/runtime/components/ui/field/FieldDescription.vue +17 -0
- package/src/runtime/components/ui/field/FieldError.vue +45 -0
- package/src/runtime/components/ui/field/FieldGroup.vue +14 -0
- package/src/runtime/components/ui/field/FieldLabel.vue +31 -0
- package/src/runtime/components/ui/field/FieldLegend.vue +15 -0
- package/src/runtime/components/ui/field/FieldSeparator.vue +18 -0
- package/src/runtime/components/ui/field/FieldSet.vue +14 -0
- package/src/runtime/components/ui/field/FieldTitle.vue +14 -0
- package/src/runtime/components/ui/field/index.ts +32 -0
- package/src/runtime/components/ui/form/FormControl.vue +12 -0
- package/src/runtime/components/ui/form/FormDescription.vue +17 -0
- package/src/runtime/components/ui/form/FormItem.vue +20 -0
- package/src/runtime/components/ui/form/FormLabel.vue +17 -0
- package/src/runtime/components/ui/form/FormMessage.vue +17 -0
- package/src/runtime/components/ui/form/index.ts +7 -0
- package/src/runtime/components/ui/form/injectionKeys.ts +3 -0
- package/src/runtime/components/ui/form/useFormField.ts +29 -0
- package/src/runtime/components/ui/gantt/Gantt.vue +108 -0
- package/src/runtime/components/ui/gantt/GanttCreateMarkerTrigger.vue +44 -0
- package/src/runtime/components/ui/gantt/GanttFeatureItem.vue +303 -0
- package/src/runtime/components/ui/gantt/GanttFeatureList.vue +16 -0
- package/src/runtime/components/ui/gantt/GanttFeatureListGroup.vue +20 -0
- package/src/runtime/components/ui/gantt/GanttHeader.vue +197 -0
- package/src/runtime/components/ui/gantt/GanttMarker.vue +133 -0
- package/src/runtime/components/ui/gantt/GanttSidebar.vue +65 -0
- package/src/runtime/components/ui/gantt/GanttSidebarGroup.vue +25 -0
- package/src/runtime/components/ui/gantt/GanttSidebarItem.vue +32 -0
- package/src/runtime/components/ui/gantt/GanttTimeline.vue +179 -0
- package/src/runtime/components/ui/gantt/GanttToday.vue +52 -0
- package/src/runtime/components/ui/gantt/GanttZoomControls.vue +49 -0
- package/src/runtime/components/ui/gantt/README.md +356 -0
- package/src/runtime/components/ui/gantt/index.ts +18 -0
- package/src/runtime/components/ui/gantt/meta.json +96 -0
- package/src/runtime/components/ui/hover-card/HoverCard.vue +15 -0
- package/src/runtime/components/ui/hover-card/HoverCardContent.vue +36 -0
- package/src/runtime/components/ui/hover-card/HoverCardTrigger.vue +12 -0
- package/src/runtime/components/ui/hover-card/index.ts +3 -0
- package/src/runtime/components/ui/inline-editable-input/InlineEditableInput.vue +126 -0
- package/src/runtime/components/ui/inline-editable-input/index.ts +1 -0
- package/src/runtime/components/ui/input/Input.vue +35 -0
- package/src/runtime/components/ui/input/index.ts +1 -0
- package/src/runtime/components/ui/input-group/InputGroup.vue +37 -0
- package/src/runtime/components/ui/input-group/InputGroupAddon.vue +33 -0
- package/src/runtime/components/ui/input-group/InputGroupButton.vue +25 -0
- package/src/runtime/components/ui/input-group/InputGroupInput.vue +13 -0
- package/src/runtime/components/ui/input-group/InputGroupText.vue +14 -0
- package/src/runtime/components/ui/input-group/InputGroupTextarea.vue +13 -0
- package/src/runtime/components/ui/input-group/index.ts +41 -0
- package/src/runtime/components/ui/input-otp/InputOTP.vue +22 -0
- package/src/runtime/components/ui/input-otp/InputOTPGroup.vue +18 -0
- package/src/runtime/components/ui/input-otp/InputOTPSeparator.vue +17 -0
- package/src/runtime/components/ui/input-otp/InputOTPSlot.vue +37 -0
- package/src/runtime/components/ui/input-otp/index.ts +4 -0
- package/src/runtime/components/ui/item/Item.vue +27 -0
- package/src/runtime/components/ui/item/ItemActions.vue +14 -0
- package/src/runtime/components/ui/item/ItemContent.vue +14 -0
- package/src/runtime/components/ui/item/ItemDescription.vue +14 -0
- package/src/runtime/components/ui/item/ItemFooter.vue +14 -0
- package/src/runtime/components/ui/item/ItemGroup.vue +14 -0
- package/src/runtime/components/ui/item/ItemHeader.vue +14 -0
- package/src/runtime/components/ui/item/ItemMedia.vue +17 -0
- package/src/runtime/components/ui/item/ItemSeparator.vue +12 -0
- package/src/runtime/components/ui/item/ItemTitle.vue +14 -0
- package/src/runtime/components/ui/item/index.ts +47 -0
- package/src/runtime/components/ui/kanban/Kanban.vue +42 -0
- package/src/runtime/components/ui/kanban/KanbanBoard.vue +75 -0
- package/src/runtime/components/ui/kanban/KanbanCard.vue +59 -0
- package/src/runtime/components/ui/kanban/KanbanCards.vue +27 -0
- package/src/runtime/components/ui/kanban/KanbanHeader.vue +15 -0
- package/src/runtime/components/ui/kanban/README.md +184 -0
- package/src/runtime/components/ui/kanban/index.ts +8 -0
- package/src/runtime/components/ui/kbd/Kbd.vue +23 -0
- package/src/runtime/components/ui/kbd/KbdGroup.vue +14 -0
- package/src/runtime/components/ui/kbd/index.ts +2 -0
- package/src/runtime/components/ui/label/Label.vue +30 -0
- package/src/runtime/components/ui/label/index.ts +1 -0
- package/src/runtime/components/ui/menubar/Menubar.vue +20 -0
- package/src/runtime/components/ui/menubar/MenubarCheckboxItem.vue +37 -0
- package/src/runtime/components/ui/menubar/MenubarContent.vue +38 -0
- package/src/runtime/components/ui/menubar/MenubarGroup.vue +12 -0
- package/src/runtime/components/ui/menubar/MenubarItem.vue +37 -0
- package/src/runtime/components/ui/menubar/MenubarLabel.vue +16 -0
- package/src/runtime/components/ui/menubar/MenubarMenu.vue +12 -0
- package/src/runtime/components/ui/menubar/MenubarRadioGroup.vue +15 -0
- package/src/runtime/components/ui/menubar/MenubarRadioItem.vue +37 -0
- package/src/runtime/components/ui/menubar/MenubarSeparator.vue +17 -0
- package/src/runtime/components/ui/menubar/MenubarShortcut.vue +14 -0
- package/src/runtime/components/ui/menubar/MenubarSub.vue +20 -0
- package/src/runtime/components/ui/menubar/MenubarSubContent.vue +35 -0
- package/src/runtime/components/ui/menubar/MenubarSubTrigger.vue +25 -0
- package/src/runtime/components/ui/menubar/MenubarTrigger.vue +19 -0
- package/src/runtime/components/ui/menubar/index.ts +15 -0
- package/src/runtime/components/ui/native-select/NativeSelect.vue +45 -0
- package/src/runtime/components/ui/native-select/NativeSelectOptGroup.vue +15 -0
- package/src/runtime/components/ui/native-select/NativeSelectOption.vue +15 -0
- package/src/runtime/components/ui/native-select/index.ts +3 -0
- package/src/runtime/components/ui/navigation-menu/NavigationMenu.vue +31 -0
- package/src/runtime/components/ui/navigation-menu/NavigationMenuContent.vue +30 -0
- package/src/runtime/components/ui/navigation-menu/NavigationMenuIndicator.vue +23 -0
- package/src/runtime/components/ui/navigation-menu/NavigationMenuItem.vue +17 -0
- package/src/runtime/components/ui/navigation-menu/NavigationMenuLink.vue +28 -0
- package/src/runtime/components/ui/navigation-menu/NavigationMenuList.vue +19 -0
- package/src/runtime/components/ui/navigation-menu/NavigationMenuTrigger.vue +22 -0
- package/src/runtime/components/ui/navigation-menu/NavigationMenuViewport.vue +28 -0
- package/src/runtime/components/ui/navigation-menu/index.ts +14 -0
- package/src/runtime/components/ui/number-field/NumberField.vue +20 -0
- package/src/runtime/components/ui/number-field/NumberFieldContent.vue +14 -0
- package/src/runtime/components/ui/number-field/NumberFieldDecrement.vue +22 -0
- package/src/runtime/components/ui/number-field/NumberFieldIncrement.vue +22 -0
- package/src/runtime/components/ui/number-field/NumberFieldInput.vue +16 -0
- package/src/runtime/components/ui/number-field/index.ts +5 -0
- package/src/runtime/components/ui/pagination/Pagination.vue +23 -0
- package/src/runtime/components/ui/pagination/PaginationContent.vue +17 -0
- package/src/runtime/components/ui/pagination/PaginationEllipsis.vue +21 -0
- package/src/runtime/components/ui/pagination/PaginationFirst.vue +34 -0
- package/src/runtime/components/ui/pagination/PaginationItem.vue +44 -0
- package/src/runtime/components/ui/pagination/PaginationLast.vue +33 -0
- package/src/runtime/components/ui/pagination/PaginationNext.vue +33 -0
- package/src/runtime/components/ui/pagination/PaginationPrevious.vue +33 -0
- package/src/runtime/components/ui/pagination/index.ts +8 -0
- package/src/runtime/components/ui/pin-input/PinInput.vue +22 -0
- package/src/runtime/components/ui/pin-input/PinInputGroup.vue +17 -0
- package/src/runtime/components/ui/pin-input/PinInputSeparator.vue +16 -0
- package/src/runtime/components/ui/pin-input/PinInputSlot.vue +26 -0
- package/src/runtime/components/ui/pin-input/index.ts +4 -0
- package/src/runtime/components/ui/popover/Popover.vue +15 -0
- package/src/runtime/components/ui/popover/PopoverAnchor.vue +12 -0
- package/src/runtime/components/ui/popover/PopoverContent.vue +38 -0
- package/src/runtime/components/ui/popover/PopoverTrigger.vue +12 -0
- package/src/runtime/components/ui/popover/index.ts +4 -0
- package/src/runtime/components/ui/progress/Progress.vue +19 -0
- package/src/runtime/components/ui/progress/index.ts +1 -0
- package/src/runtime/components/ui/radio-group/RadioGroup.vue +20 -0
- package/src/runtime/components/ui/radio-group/RadioGroupItem.vue +33 -0
- package/src/runtime/components/ui/radio-group/index.ts +2 -0
- package/src/runtime/components/ui/range-calendar/RangeCalendar.vue +61 -0
- package/src/runtime/components/ui/range-calendar/RangeCalendarCell.vue +32 -0
- package/src/runtime/components/ui/range-calendar/RangeCalendarCellTrigger.vue +46 -0
- package/src/runtime/components/ui/range-calendar/RangeCalendarGrid.vue +19 -0
- package/src/runtime/components/ui/range-calendar/RangeCalendarGridBody.vue +12 -0
- package/src/runtime/components/ui/range-calendar/RangeCalendarGridHead.vue +12 -0
- package/src/runtime/components/ui/range-calendar/RangeCalendarGridRow.vue +19 -0
- package/src/runtime/components/ui/range-calendar/RangeCalendarHeadCell.vue +19 -0
- package/src/runtime/components/ui/range-calendar/RangeCalendarHeader.vue +19 -0
- package/src/runtime/components/ui/range-calendar/RangeCalendarHeading.vue +25 -0
- package/src/runtime/components/ui/range-calendar/RangeCalendarNextButton.vue +22 -0
- package/src/runtime/components/ui/range-calendar/RangeCalendarPrevButton.vue +22 -0
- package/src/runtime/components/ui/range-calendar/index.ts +12 -0
- package/src/runtime/components/ui/resizable/ResizableHandle.vue +35 -0
- package/src/runtime/components/ui/resizable/ResizablePanel.vue +16 -0
- package/src/runtime/components/ui/resizable/ResizablePanelGroup.vue +20 -0
- package/src/runtime/components/ui/resizable/index.ts +3 -0
- package/src/runtime/components/ui/scroll-area/ScrollArea.vue +22 -0
- package/src/runtime/components/ui/scroll-area/ScrollBar.vue +19 -0
- package/src/runtime/components/ui/scroll-area/index.ts +2 -0
- package/src/runtime/components/ui/select/Select.vue +15 -0
- package/src/runtime/components/ui/select/SelectContent.vue +43 -0
- package/src/runtime/components/ui/select/SelectGroup.vue +12 -0
- package/src/runtime/components/ui/select/SelectItem.vue +39 -0
- package/src/runtime/components/ui/select/SelectItemText.vue +12 -0
- package/src/runtime/components/ui/select/SelectLabel.vue +14 -0
- package/src/runtime/components/ui/select/SelectScrollDownButton.vue +22 -0
- package/src/runtime/components/ui/select/SelectScrollUpButton.vue +22 -0
- package/src/runtime/components/ui/select/SelectSeparator.vue +15 -0
- package/src/runtime/components/ui/select/SelectTrigger.vue +32 -0
- package/src/runtime/components/ui/select/SelectValue.vue +12 -0
- package/src/runtime/components/ui/select/index.ts +11 -0
- package/src/runtime/components/ui/separator/Separator.vue +18 -0
- package/src/runtime/components/ui/separator/index.ts +1 -0
- package/src/runtime/components/ui/sheet/Sheet.vue +15 -0
- package/src/runtime/components/ui/sheet/SheetClose.vue +12 -0
- package/src/runtime/components/ui/sheet/SheetContent.vue +54 -0
- package/src/runtime/components/ui/sheet/SheetDescription.vue +17 -0
- package/src/runtime/components/ui/sheet/SheetFooter.vue +12 -0
- package/src/runtime/components/ui/sheet/SheetHeader.vue +12 -0
- package/src/runtime/components/ui/sheet/SheetOverlay.vue +17 -0
- package/src/runtime/components/ui/sheet/SheetTitle.vue +17 -0
- package/src/runtime/components/ui/sheet/SheetTrigger.vue +12 -0
- package/src/runtime/components/ui/sheet/index.ts +8 -0
- package/src/runtime/components/ui/sidebar/Sidebar.vue +78 -0
- package/src/runtime/components/ui/sidebar/SidebarContent.vue +14 -0
- package/src/runtime/components/ui/sidebar/SidebarFooter.vue +14 -0
- package/src/runtime/components/ui/sidebar/SidebarGroup.vue +14 -0
- package/src/runtime/components/ui/sidebar/SidebarGroupAction.vue +31 -0
- package/src/runtime/components/ui/sidebar/SidebarGroupContent.vue +14 -0
- package/src/runtime/components/ui/sidebar/SidebarGroupLabel.vue +30 -0
- package/src/runtime/components/ui/sidebar/SidebarHeader.vue +14 -0
- package/src/runtime/components/ui/sidebar/SidebarInput.vue +15 -0
- package/src/runtime/components/ui/sidebar/SidebarInset.vue +24 -0
- package/src/runtime/components/ui/sidebar/SidebarMenu.vue +14 -0
- package/src/runtime/components/ui/sidebar/SidebarMenuAction.vue +41 -0
- package/src/runtime/components/ui/sidebar/SidebarMenuBadge.vue +28 -0
- package/src/runtime/components/ui/sidebar/SidebarMenuButton.vue +49 -0
- package/src/runtime/components/ui/sidebar/SidebarMenuButtonChild.vue +27 -0
- package/src/runtime/components/ui/sidebar/SidebarMenuItem.vue +14 -0
- package/src/runtime/components/ui/sidebar/SidebarMenuSkeleton.vue +23 -0
- package/src/runtime/components/ui/sidebar/SidebarMenuSub.vue +14 -0
- package/src/runtime/components/ui/sidebar/SidebarMenuSubButton.vue +43 -0
- package/src/runtime/components/ui/sidebar/SidebarMenuSubItem.vue +14 -0
- package/src/runtime/components/ui/sidebar/SidebarProvider.vue +89 -0
- package/src/runtime/components/ui/sidebar/SidebarRail.vue +35 -0
- package/src/runtime/components/ui/sidebar/SidebarSeparator.vue +15 -0
- package/src/runtime/components/ui/sidebar/SidebarTrigger.vue +19 -0
- package/src/runtime/components/ui/sidebar/index.ts +59 -0
- package/src/runtime/components/ui/sidebar/utils.ts +19 -0
- package/src/runtime/components/ui/skeleton/Skeleton.vue +14 -0
- package/src/runtime/components/ui/skeleton/index.ts +1 -0
- package/src/runtime/components/ui/slider/Slider.vue +34 -0
- package/src/runtime/components/ui/slider/index.ts +1 -0
- package/src/runtime/components/ui/spinner/Spinner.vue +13 -0
- package/src/runtime/components/ui/spinner/index.ts +1 -0
- package/src/runtime/components/ui/stepper/Stepper.vue +20 -0
- package/src/runtime/components/ui/stepper/StepperDescription.vue +19 -0
- package/src/runtime/components/ui/stepper/StepperIndicator.vue +34 -0
- package/src/runtime/components/ui/stepper/StepperItem.vue +19 -0
- package/src/runtime/components/ui/stepper/StepperSeparator.vue +29 -0
- package/src/runtime/components/ui/stepper/StepperTitle.vue +19 -0
- package/src/runtime/components/ui/stepper/StepperTrigger.vue +19 -0
- package/src/runtime/components/ui/stepper/index.ts +7 -0
- package/src/runtime/components/ui/switch/Switch.vue +36 -0
- package/src/runtime/components/ui/switch/index.ts +1 -0
- package/src/runtime/components/ui/table/Table.vue +16 -0
- package/src/runtime/components/ui/table/TableBody.vue +14 -0
- package/src/runtime/components/ui/table/TableCaption.vue +14 -0
- package/src/runtime/components/ui/table/TableCell.vue +14 -0
- package/src/runtime/components/ui/table/TableEmpty.vue +29 -0
- package/src/runtime/components/ui/table/TableFooter.vue +14 -0
- package/src/runtime/components/ui/table/TableHead.vue +14 -0
- package/src/runtime/components/ui/table/TableHeader.vue +14 -0
- package/src/runtime/components/ui/table/TableRow.vue +14 -0
- package/src/runtime/components/ui/table/index.ts +9 -0
- package/src/runtime/components/ui/table/utils.ts +8 -0
- package/src/runtime/components/ui/tabs/Tabs.vue +23 -0
- package/src/runtime/components/ui/tabs/TabsContent.vue +17 -0
- package/src/runtime/components/ui/tabs/TabsList.vue +17 -0
- package/src/runtime/components/ui/tabs/TabsTrigger.vue +28 -0
- package/src/runtime/components/ui/tabs/index.ts +4 -0
- package/src/runtime/components/ui/tags-input/TagsInput.vue +20 -0
- package/src/runtime/components/ui/tags-input/TagsInputInput.vue +17 -0
- package/src/runtime/components/ui/tags-input/TagsInputItem.vue +20 -0
- package/src/runtime/components/ui/tags-input/TagsInputItemDelete.vue +22 -0
- package/src/runtime/components/ui/tags-input/TagsInputItemText.vue +19 -0
- package/src/runtime/components/ui/tags-input/index.ts +5 -0
- package/src/runtime/components/ui/textarea/Textarea.vue +31 -0
- package/src/runtime/components/ui/textarea/index.ts +1 -0
- package/src/runtime/components/ui/tiptap/TiptapContent.vue +154 -0
- package/src/runtime/components/ui/tiptap/TiptapEditor.vue +37 -0
- package/src/runtime/components/ui/tiptap/TiptapIcon.vue +141 -0
- package/src/runtime/components/ui/tiptap/TiptapKeyboardShortcuts.vue +25 -0
- package/src/runtime/components/ui/tiptap/TiptapMobileToolbar.vue +148 -0
- package/src/runtime/components/ui/tiptap/TiptapProvider.vue +407 -0
- package/src/runtime/components/ui/tiptap/TiptapSlotPanel.vue +112 -0
- package/src/runtime/components/ui/tiptap/TiptapStatusBar.vue +83 -0
- package/src/runtime/components/ui/tiptap/TiptapTableToolbar.vue +176 -0
- package/src/runtime/components/ui/tiptap/TiptapToolbar.vue +223 -0
- package/src/runtime/components/ui/tiptap/TiptapTreeItem.vue +210 -0
- package/src/runtime/components/ui/tiptap/TiptapTreeStructure.vue +133 -0
- package/src/runtime/components/ui/tiptap/index.ts +49 -0
- package/src/runtime/components/ui/tiptap/tiptapTreeUtils.ts +137 -0
- package/src/runtime/components/ui/toggle/Toggle.vue +35 -0
- package/src/runtime/components/ui/toggle/index.ts +27 -0
- package/src/runtime/components/ui/toggle-group/ToggleGroup.vue +54 -0
- package/src/runtime/components/ui/toggle-group/ToggleGroupItem.vue +51 -0
- package/src/runtime/components/ui/toggle-group/index.ts +2 -0
- package/src/runtime/components/ui/tooltip/Tooltip.vue +15 -0
- package/src/runtime/components/ui/tooltip/TooltipContent.vue +39 -0
- package/src/runtime/components/ui/tooltip/TooltipProvider.vue +14 -0
- package/src/runtime/components/ui/tooltip/TooltipTrigger.vue +12 -0
- package/src/runtime/components/ui/tooltip/index.ts +4 -0
|
@@ -0,0 +1,2372 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @description Org Chart component — contains the OrgChart class and all rendering/configuration
|
|
3
|
+
* logic for visualising hierarchical data. Built on top of D3.js with support for
|
|
4
|
+
* compact layouts, zoom/pan, custom node content, Vue h() render functions, and
|
|
5
|
+
* multiple layout directions (top / right / bottom / left).
|
|
6
|
+
* @author Amirul Apex
|
|
7
|
+
* @created Jan 2026
|
|
8
|
+
* @project Dynect
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import { flextree } from 'd3-flextree';
|
|
12
|
+
import 'd3-transition';
|
|
13
|
+
import { selection, select, max, min, sum, cumsum, tree, stratify, linkHorizontal, zoom, zoomIdentity, zoomTransform, type D3ZoomEvent } from 'd3';
|
|
14
|
+
import { createApp } from 'vue';
|
|
15
|
+
import { createIconSVG, getLayoutIcon } from './svg-icons';
|
|
16
|
+
import type {
|
|
17
|
+
OrgChartAttrs,
|
|
18
|
+
OrgChartNode,
|
|
19
|
+
OrgChartNodeData,
|
|
20
|
+
Connection,
|
|
21
|
+
LayoutType,
|
|
22
|
+
Point,
|
|
23
|
+
UpdateParams,
|
|
24
|
+
ExportImageParams,
|
|
25
|
+
DownloadImageParams,
|
|
26
|
+
FitParams,
|
|
27
|
+
ZoomToBoundsParams,
|
|
28
|
+
TextMeasurementParams,
|
|
29
|
+
CalcProperties,
|
|
30
|
+
NodeAccessor,
|
|
31
|
+
DataAccessor,
|
|
32
|
+
NodeContentCallback,
|
|
33
|
+
ButtonContentCallback,
|
|
34
|
+
PagingButtonCallback,
|
|
35
|
+
NodeClickCallback,
|
|
36
|
+
NodeExpandCollapseCallback,
|
|
37
|
+
ZoomCallback,
|
|
38
|
+
NodeUpdateCallback,
|
|
39
|
+
NodeEnterCallback,
|
|
40
|
+
NodeExitCallback,
|
|
41
|
+
LinkUpdateCallback,
|
|
42
|
+
DefsCallback,
|
|
43
|
+
ConnectionsUpdateCallback,
|
|
44
|
+
} from './types';
|
|
45
|
+
|
|
46
|
+
function vnodeToHTML(result: unknown): string {
|
|
47
|
+
if (result !== null && typeof result === 'object' && (result as any).__v_isVNode) {
|
|
48
|
+
const container = document.createElement('div');
|
|
49
|
+
const app = createApp({ render: () => result as any });
|
|
50
|
+
app.mount(container);
|
|
51
|
+
const html = container.innerHTML;
|
|
52
|
+
app.unmount();
|
|
53
|
+
return html;
|
|
54
|
+
}
|
|
55
|
+
return result as string;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
const d3 = {
|
|
59
|
+
selection,
|
|
60
|
+
select,
|
|
61
|
+
max,
|
|
62
|
+
min,
|
|
63
|
+
sum,
|
|
64
|
+
cumsum,
|
|
65
|
+
tree,
|
|
66
|
+
stratify,
|
|
67
|
+
zoom,
|
|
68
|
+
zoomIdentity,
|
|
69
|
+
zoomTransform,
|
|
70
|
+
linkHorizontal,
|
|
71
|
+
flextree,
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
// Interface untuk method overloading (untuk IDE autocomplete)
|
|
75
|
+
export interface IOrgChart<Datum = any> {
|
|
76
|
+
// Configuration Methods
|
|
77
|
+
container(): string | HTMLElement;
|
|
78
|
+
container(value: string | HTMLElement): this;
|
|
79
|
+
data(): Datum[] | null;
|
|
80
|
+
data(value: Datum[]): this;
|
|
81
|
+
svgWidth(): number;
|
|
82
|
+
svgWidth(value: number): this;
|
|
83
|
+
svgHeight(): number;
|
|
84
|
+
svgHeight(value: number): this;
|
|
85
|
+
compact(): boolean;
|
|
86
|
+
compact(value: boolean): this;
|
|
87
|
+
layout(): LayoutType;
|
|
88
|
+
layout(value: LayoutType): this;
|
|
89
|
+
duration(): number;
|
|
90
|
+
duration(value: number): this;
|
|
91
|
+
connections(): Connection<Datum>[];
|
|
92
|
+
connections(value: Connection<Datum>[]): this;
|
|
93
|
+
rootMargin(): number;
|
|
94
|
+
rootMargin(value: number): this;
|
|
95
|
+
setActiveNodeCentered(): boolean;
|
|
96
|
+
setActiveNodeCentered(value: boolean): this;
|
|
97
|
+
scaleExtent(): [number, number];
|
|
98
|
+
scaleExtent(value: [number, number]): this;
|
|
99
|
+
defaultFont(): string;
|
|
100
|
+
defaultFont(value: string): this;
|
|
101
|
+
imageName(): string;
|
|
102
|
+
imageName(value: string): this;
|
|
103
|
+
linkYOffset(): number;
|
|
104
|
+
linkYOffset(value: number): this;
|
|
105
|
+
|
|
106
|
+
// Accessor Methods
|
|
107
|
+
nodeId(): DataAccessor<string | number, Datum>;
|
|
108
|
+
nodeId(value: DataAccessor<string | number, Datum>): this;
|
|
109
|
+
parentNodeId(): DataAccessor<string | number, Datum>;
|
|
110
|
+
parentNodeId(value: DataAccessor<string | number, Datum>): this;
|
|
111
|
+
nodeWidth(): NodeAccessor<number, Datum>;
|
|
112
|
+
nodeWidth(value: NodeAccessor<number, Datum>): this;
|
|
113
|
+
nodeHeight(): NodeAccessor<number, Datum>;
|
|
114
|
+
nodeHeight(value: NodeAccessor<number, Datum>): this;
|
|
115
|
+
siblingsMargin(): NodeAccessor<number, Datum>;
|
|
116
|
+
siblingsMargin(value: NodeAccessor<number, Datum>): this;
|
|
117
|
+
childrenMargin(): NodeAccessor<number, Datum>;
|
|
118
|
+
childrenMargin(value: NodeAccessor<number, Datum>): this;
|
|
119
|
+
neighbourMargin(): (node1: OrgChartNode<Datum>, node2: OrgChartNode<Datum>) => number;
|
|
120
|
+
neighbourMargin(value: (node1: OrgChartNode<Datum>, node2: OrgChartNode<Datum>) => number): this;
|
|
121
|
+
compactMarginPair(): NodeAccessor<number, Datum>;
|
|
122
|
+
compactMarginPair(value: NodeAccessor<number, Datum>): this;
|
|
123
|
+
compactMarginBetween(): NodeAccessor<number, Datum>;
|
|
124
|
+
compactMarginBetween(value: NodeAccessor<number, Datum>): this;
|
|
125
|
+
initialExpandLevel(): number;
|
|
126
|
+
initialExpandLevel(value: number): this;
|
|
127
|
+
nodeButtonWidth(): NodeAccessor<number, Datum>;
|
|
128
|
+
nodeButtonWidth(value: NodeAccessor<number, Datum>): this;
|
|
129
|
+
nodeButtonHeight(): NodeAccessor<number, Datum>;
|
|
130
|
+
nodeButtonHeight(value: NodeAccessor<number, Datum>): this;
|
|
131
|
+
nodeButtonX(): NodeAccessor<number, Datum>;
|
|
132
|
+
nodeButtonX(value: NodeAccessor<number, Datum>): this;
|
|
133
|
+
nodeButtonY(): NodeAccessor<number, Datum>;
|
|
134
|
+
nodeButtonY(value: NodeAccessor<number, Datum>): this;
|
|
135
|
+
pagingStep(): NodeAccessor<number, Datum>;
|
|
136
|
+
pagingStep(value: NodeAccessor<number, Datum>): this;
|
|
137
|
+
minPagingVisibleNodes(): NodeAccessor<number, Datum>;
|
|
138
|
+
minPagingVisibleNodes(value: NodeAccessor<number, Datum>): this;
|
|
139
|
+
|
|
140
|
+
// Callback Methods
|
|
141
|
+
nodeContent(): NodeContentCallback<Datum>;
|
|
142
|
+
nodeContent(value: NodeContentCallback<Datum>): this;
|
|
143
|
+
buttonContent(): ButtonContentCallback<Datum>;
|
|
144
|
+
buttonContent(value: ButtonContentCallback<Datum>): this;
|
|
145
|
+
pagingButton(): PagingButtonCallback<Datum>;
|
|
146
|
+
pagingButton(value: PagingButtonCallback<Datum>): this;
|
|
147
|
+
onNodeClick(): NodeClickCallback<Datum>;
|
|
148
|
+
onNodeClick(value: NodeClickCallback<Datum>): this;
|
|
149
|
+
onExpandOrCollapse(): NodeExpandCollapseCallback<Datum>;
|
|
150
|
+
onExpandOrCollapse(value: NodeExpandCollapseCallback<Datum>): this;
|
|
151
|
+
onZoomStart(): ZoomCallback<Datum>;
|
|
152
|
+
onZoomStart(value: ZoomCallback<Datum>): this;
|
|
153
|
+
onZoom(): ZoomCallback<Datum>;
|
|
154
|
+
onZoom(value: ZoomCallback<Datum>): this;
|
|
155
|
+
onZoomEnd(): ZoomCallback<Datum>;
|
|
156
|
+
onZoomEnd(value: ZoomCallback<Datum>): this;
|
|
157
|
+
nodeUpdate(): NodeUpdateCallback<Datum>;
|
|
158
|
+
nodeUpdate(value: NodeUpdateCallback<Datum>): this;
|
|
159
|
+
nodeEnter(): NodeEnterCallback<Datum>;
|
|
160
|
+
nodeEnter(value: NodeEnterCallback<Datum>): this;
|
|
161
|
+
nodeExit(): NodeExitCallback<Datum>;
|
|
162
|
+
nodeExit(value: NodeExitCallback<Datum>): this;
|
|
163
|
+
linkUpdate(): LinkUpdateCallback<Datum>;
|
|
164
|
+
linkUpdate(value: LinkUpdateCallback<Datum>): this;
|
|
165
|
+
connectionsUpdate(): ConnectionsUpdateCallback<Datum>;
|
|
166
|
+
connectionsUpdate(value: ConnectionsUpdateCallback<Datum>): this;
|
|
167
|
+
defs(): DefsCallback<Datum>;
|
|
168
|
+
defs(value: DefsCallback<Datum>): this;
|
|
169
|
+
lastTransform(): { x: number; y: number; k: number };
|
|
170
|
+
lastTransform(value: { x: number; y: number; k: number }): this;
|
|
171
|
+
|
|
172
|
+
// Utility Methods
|
|
173
|
+
groupBy<T, K extends string | number>(array: T[], accessor: (item: T) => K, aggregator: (group: T[]) => any): [string, any][];
|
|
174
|
+
calculateCompactFlexDimensions(root: OrgChartNode<Datum>): void;
|
|
175
|
+
calculateCompactFlexPositions(root: OrgChartNode<Datum>): void;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
export class OrgChart<Datum = any> implements IOrgChart<Datum> {
|
|
179
|
+
private readonly attrs: OrgChartAttrs<Datum>;
|
|
180
|
+
|
|
181
|
+
// Public getter for accessing chart state
|
|
182
|
+
getChartState: () => OrgChartAttrs<Datum>;
|
|
183
|
+
|
|
184
|
+
// Dynamic properties (added via getter/setter pattern)
|
|
185
|
+
[key: string]: any;
|
|
186
|
+
|
|
187
|
+
constructor() {
|
|
188
|
+
// Exposed variables test test
|
|
189
|
+
const attrs: OrgChartAttrs<Datum> = {
|
|
190
|
+
/* NOT INTENDED FOR PUBLIC OVERRIDE */
|
|
191
|
+
|
|
192
|
+
id: `ID${crypto.randomUUID()}`, // Id for event handlings
|
|
193
|
+
firstDraw: true, // Whether chart is drawn for the first time
|
|
194
|
+
ctx: document.createElement('canvas').getContext('2d'),
|
|
195
|
+
initialExpandLevel: 1,
|
|
196
|
+
nodeDefaultBackground: 'none',
|
|
197
|
+
lastTransform: { x: 0, y: 0, k: 1 }, // Panning and zooming values
|
|
198
|
+
allowedNodesCount: {},
|
|
199
|
+
zoomBehavior: null,
|
|
200
|
+
generateRoot: null,
|
|
201
|
+
|
|
202
|
+
/* INTENDED FOR PUBLIC OVERRIDE */
|
|
203
|
+
|
|
204
|
+
svgWidth: 800, // Configure svg width
|
|
205
|
+
svgHeight: window.innerHeight - 100, // Configure svg height
|
|
206
|
+
container: 'body', // Set parent container, either CSS style selector or DOM element
|
|
207
|
+
data: null, // Set data, it must be an array of objects, where hierarchy is clearly defined via id and parent ID (property names are configurable)
|
|
208
|
+
connections: [], // Sets connection data, array of objects, SAMPLE: [{from:"145",to:"201",label:"Conflicts of interest"}]
|
|
209
|
+
defaultFont: 'Helvetica', // Set default font
|
|
210
|
+
nodeId: (d: Datum) => (d as any).nodeId || (d as any).id, // Configure accessor for node id, default is either odeId or id
|
|
211
|
+
parentNodeId: (d: Datum) => (d as any).parentNodeId || (d as any).parentId, // Configure accessor for parent node id, default is either parentNodeId or parentId
|
|
212
|
+
rootMargin: 40, // Configure how much root node is offset from top
|
|
213
|
+
nodeWidth: (_) => 250, // Configure each node width, use with caution, it is better to have the same value set for all nodes
|
|
214
|
+
nodeHeight: (_) => 150, // Configure each node height, use with caution, it is better to have the same value set for all nodes
|
|
215
|
+
neighbourMargin: (_, __) => 80, // Configure margin between two nodes, use with caution, it is better to have the same value set for all nodes
|
|
216
|
+
siblingsMargin: (_) => 40, // Configure margin between two siblings, use with caution, it is better to have the same value set for all nodes
|
|
217
|
+
childrenMargin: (_) => 60, // Configure margin between parent and children, use with caution, it is better to have the same value set for all nodes
|
|
218
|
+
compactMarginPair: (_) => 100, // Configure margin between two nodes in compact mode, use with caution, it is better to have the same value set for all nodes
|
|
219
|
+
compactMarginBetween: (_) => 40, // Configure margin between two nodes in compact mode, use with caution, it is better to have the same value set for all nodes
|
|
220
|
+
nodeButtonWidth: (_) => 40, // Configure expand & collapse button width
|
|
221
|
+
nodeButtonHeight: (_) => 40, // Configure expand & collapse button height
|
|
222
|
+
nodeButtonX: (_) => -20, // Configure expand & collapse button x position
|
|
223
|
+
nodeButtonY: (_) => -20, // Configure expand & collapse button y position
|
|
224
|
+
linkYOffset: 10, // When correcting links which is not working for safari
|
|
225
|
+
pagingStep: (_) => 5, // Configure how many nodes to show when making new nodes appear
|
|
226
|
+
minPagingVisibleNodes: (_) => 2000, // Configure minimum number of visible nodes , after which paging button appears
|
|
227
|
+
scaleExtent: [0.001, 20], // Configure zoom scale extent , if you don't want any kind of zooming, set it to [1,1]
|
|
228
|
+
duration: 400, // Configure duration of transitions
|
|
229
|
+
imageName: 'Chart', // Configure exported PNG and SVG image name
|
|
230
|
+
setActiveNodeCentered: true, // Configure if active node should be centered when expanded and collapsed
|
|
231
|
+
layout: 'top', // Configure layout direction , possible values are "top", "left", "right", "bottom"
|
|
232
|
+
compact: true, // Configure if compact mode is enabled , when enabled, nodes are shown in compact positions, instead of horizontal spread
|
|
233
|
+
createZoom: (_) => d3.zoom(),
|
|
234
|
+
onZoomStart: (_) => {}, // Callback for zoom & panning start
|
|
235
|
+
onZoom: (_) => {}, // Callback for zoom & panning
|
|
236
|
+
onZoomEnd: (_) => {}, // Callback for zoom & panning end
|
|
237
|
+
onNodeClick: (d) => d, // Callback for node click
|
|
238
|
+
onExpandOrCollapse: (d) => d, // Callback for node expand or collapse
|
|
239
|
+
|
|
240
|
+
/*
|
|
241
|
+
* Node HTML content generation , remember that you can access some helper methods:
|
|
242
|
+
|
|
243
|
+
* node=> node.data - to access node's original data
|
|
244
|
+
* node=> node.leaves() - to access node's leaves
|
|
245
|
+
* node=> node.descendants() - to access node's descendants
|
|
246
|
+
* node=> node.children - to access node's children
|
|
247
|
+
* node=> node.parent - to access node's parent
|
|
248
|
+
* node=> node.depth - to access node's depth
|
|
249
|
+
* node=> node.hierarchyHeight - to access node's hierarchy height ( Height, which d3 assigns to hierarchy nodes)
|
|
250
|
+
* node=> node.height - to access node's height
|
|
251
|
+
* node=> node.width - to access node's width
|
|
252
|
+
*
|
|
253
|
+
* You can also access additional properties to style your node:
|
|
254
|
+
*
|
|
255
|
+
* d=>d.data._centeredWithDescendants - when node is centered with descendants
|
|
256
|
+
* d=>d.data._directSubordinatesPaging - subordinates count in paging mode
|
|
257
|
+
* d=>d.data._directSubordinates - subordinates count
|
|
258
|
+
* d=>d.data._totalSubordinates - total subordinates count
|
|
259
|
+
* d=>d._highlighted - when node is highlighted
|
|
260
|
+
* d=>d._upToTheRootHighlighted - when node is highlighted up to the root
|
|
261
|
+
* d=>d._expanded - when node is expanded
|
|
262
|
+
* d=>d.data._centered - when node is centered
|
|
263
|
+
*/
|
|
264
|
+
nodeContent: (d: OrgChartNode<Datum>) => `<div style="padding:5px;font-size:10px;">Sample Node(id=${(d.data as any).id}), override using <br/>
|
|
265
|
+
<code>chart.nodeContent({data}=>{ <br/>
|
|
266
|
+
return '' // Custom HTML <br/>
|
|
267
|
+
})</code>
|
|
268
|
+
</div>`,
|
|
269
|
+
|
|
270
|
+
/* Node expand & collapse button content and styling. You can access same helper methods as above */
|
|
271
|
+
buttonContent: ({ node, state }: { node: OrgChartNode<Datum>; state: OrgChartAttrs<Datum> }) => {
|
|
272
|
+
const iconPath = getLayoutIcon(state.layout, !!node.children);
|
|
273
|
+
const marginLeft = state.layout === 'bottom' || state.layout === 'top' ? '1px' : '0';
|
|
274
|
+
const iconHTML = createIconSVG(iconPath, node.data._directSubordinatesPaging || 0, marginLeft);
|
|
275
|
+
return `<div style="border:1px solid #E4E2E9;border-radius:3px;padding:3px;font-size:9px;margin:auto auto;background-color:white"> ${iconHTML} </div>`;
|
|
276
|
+
},
|
|
277
|
+
/* Node paging button content and styling. You can access same helper methods as above. */
|
|
278
|
+
pagingButton: (d: OrgChartNode<Datum>, _i: number, _arr: OrgChartNode<Datum>[], state: OrgChartAttrs<Datum>) => {
|
|
279
|
+
const step = state.pagingStep(d.parent!);
|
|
280
|
+
const currentIndex = d.parent!.data._pagingStep;
|
|
281
|
+
const diff = d.parent!.data._directSubordinatesPaging! - currentIndex!;
|
|
282
|
+
const min = Math.min(diff, step);
|
|
283
|
+
return `
|
|
284
|
+
<div style="margin-top:90px;">
|
|
285
|
+
<div style="display:flex;width:170px;border-radius:20px;padding:5px 15px; padding-bottom:4px;;background-color:#E5E9F2">
|
|
286
|
+
<div><svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
287
|
+
<path d="M5.59 7.41L10.18 12L5.59 16.59L7 18L13 12L7 6L5.59 7.41ZM16 6H18V18H16V6Z" fill="#716E7B" stroke="#716E7B"/>
|
|
288
|
+
</svg>
|
|
289
|
+
</div><div style="line-height:2"> Show next ${min} nodes </div></div>
|
|
290
|
+
</div>
|
|
291
|
+
`;
|
|
292
|
+
},
|
|
293
|
+
/* You can access and modify actual node DOM element in runtime using this method. */
|
|
294
|
+
nodeUpdate: function (this: SVGGElement, d: OrgChartNode<Datum>, _i: number, _arr: SVGGElement[] | ArrayLike<SVGGElement>) {
|
|
295
|
+
d3.select(this)
|
|
296
|
+
.select('.node-rect')
|
|
297
|
+
.attr('stroke', () => (d.data._highlighted || d.data._upToTheRootHighlighted ? '#E27396' : 'none'))
|
|
298
|
+
.attr('stroke-width', d.data._highlighted || d.data._upToTheRootHighlighted ? 10 : 2);
|
|
299
|
+
},
|
|
300
|
+
nodeEnter: (d: OrgChartNode<Datum>) => d, // Custom handling of node update
|
|
301
|
+
nodeExit: (d: OrgChartNode<Datum>) => d, // Custom handling of exit node
|
|
302
|
+
/* You can access and modify actual link DOM element in runtime using this method. */
|
|
303
|
+
linkUpdate: function (this: SVGPathElement, d: OrgChartNode<Datum>, _i: number, _arr: SVGPathElement[] | ArrayLike<SVGPathElement>) {
|
|
304
|
+
d3.select(this)
|
|
305
|
+
.attr('stroke', () => (d.data._upToTheRootHighlighted ? '#E27396' : '#E4E2E9'))
|
|
306
|
+
.attr('stroke-width', () => (d.data._upToTheRootHighlighted ? 5 : 1));
|
|
307
|
+
|
|
308
|
+
if (d.data._upToTheRootHighlighted) {
|
|
309
|
+
d3.select(this).raise();
|
|
310
|
+
}
|
|
311
|
+
},
|
|
312
|
+
/* Horizontal diagonal generation algorithm - https://observablehq.com/@bumbeishvili/curved-edges-compact-horizontal */
|
|
313
|
+
hdiagonal: function (s: Point, t: Point, m?: Point | null) {
|
|
314
|
+
// Define source and target x,y coordinates
|
|
315
|
+
const x = s.x;
|
|
316
|
+
const y = s.y;
|
|
317
|
+
const ex = t.x;
|
|
318
|
+
const ey = t.y;
|
|
319
|
+
|
|
320
|
+
const mx = m?.x ?? x; // This is a changed line
|
|
321
|
+
const my = m?.y ?? y; // This also is a changed line
|
|
322
|
+
|
|
323
|
+
// Values in case of top reversed and left reversed diagonals
|
|
324
|
+
const xrvs = ex - x < 0 ? -1 : 1;
|
|
325
|
+
const yrvs = ey - y < 0 ? -1 : 1;
|
|
326
|
+
|
|
327
|
+
// Define preferred curve radius
|
|
328
|
+
const rdef = 35;
|
|
329
|
+
|
|
330
|
+
// Reduce curve radius, if source-target x space is smaller
|
|
331
|
+
let r = Math.min(Math.abs(ex - x) / 2, rdef);
|
|
332
|
+
|
|
333
|
+
// Further reduce curve radius, is y space is more small
|
|
334
|
+
r = Math.min(Math.abs(ey - y) / 2, r);
|
|
335
|
+
|
|
336
|
+
// Defin width and height of link, excluding radius
|
|
337
|
+
// let h = Math.abs(ey - y) / 2 - r;
|
|
338
|
+
const w = Math.abs(ex - x) / 2 - r;
|
|
339
|
+
|
|
340
|
+
// Build and return custom arc command
|
|
341
|
+
return `
|
|
342
|
+
M ${mx} ${my}
|
|
343
|
+
L ${mx} ${y}
|
|
344
|
+
L ${x} ${y}
|
|
345
|
+
L ${x + w * xrvs} ${y}
|
|
346
|
+
C ${x + w * xrvs + r * xrvs} ${y}
|
|
347
|
+
${x + w * xrvs + r * xrvs} ${y}
|
|
348
|
+
${x + w * xrvs + r * xrvs} ${y + r * yrvs}
|
|
349
|
+
L ${x + w * xrvs + r * xrvs} ${ey - r * yrvs}
|
|
350
|
+
C ${x + w * xrvs + r * xrvs} ${ey}
|
|
351
|
+
${x + w * xrvs + r * xrvs} ${ey}
|
|
352
|
+
${ex - w * xrvs} ${ey}
|
|
353
|
+
L ${ex} ${ey}
|
|
354
|
+
`;
|
|
355
|
+
},
|
|
356
|
+
/* Vertical diagonal generation algorithm - https://observablehq.com/@bumbeishvili/curved-edges-compacty-vertical */
|
|
357
|
+
diagonal: function (s: Point, t: Point, m?: Point | null, offsets: { sy?: number; ty?: number } = { sy: 0 }) {
|
|
358
|
+
const x = s.x;
|
|
359
|
+
let y = s.y;
|
|
360
|
+
|
|
361
|
+
const ex = t.x;
|
|
362
|
+
const ey = t.y;
|
|
363
|
+
|
|
364
|
+
const mx = m?.x ?? x; // This is a changed line
|
|
365
|
+
const my = m?.y ?? y; // This also is a changed line
|
|
366
|
+
|
|
367
|
+
const xrvs = ex - x < 0 ? -1 : 1;
|
|
368
|
+
const yrvs = ey - y < 0 ? -1 : 1;
|
|
369
|
+
|
|
370
|
+
y += offsets.sy || 0;
|
|
371
|
+
|
|
372
|
+
const rdef = 35;
|
|
373
|
+
let r = Math.min(Math.abs(ex - x) / 2, rdef);
|
|
374
|
+
|
|
375
|
+
r = Math.min(Math.abs(ey - y) / 2, r);
|
|
376
|
+
|
|
377
|
+
const h = Math.abs(ey - y) / 2 - r;
|
|
378
|
+
const w = Math.abs(ex - x) - r * 2;
|
|
379
|
+
const path = `
|
|
380
|
+
M ${mx} ${my}
|
|
381
|
+
L ${x} ${my}
|
|
382
|
+
L ${x} ${y}
|
|
383
|
+
L ${x} ${y + h * yrvs}
|
|
384
|
+
C ${x} ${y + h * yrvs + r * yrvs} ${x} ${y + h * yrvs + r * yrvs} ${x + r * xrvs} ${y + h * yrvs + r * yrvs}
|
|
385
|
+
L ${x + w * xrvs + r * xrvs} ${y + h * yrvs + r * yrvs}
|
|
386
|
+
C ${ex} ${y + h * yrvs + r * yrvs} ${ex} ${y + h * yrvs + r * yrvs} ${ex} ${ey - h * yrvs}
|
|
387
|
+
L ${ex} ${ey}
|
|
388
|
+
`;
|
|
389
|
+
return path;
|
|
390
|
+
},
|
|
391
|
+
// Defining arrows with markers for connections
|
|
392
|
+
defs: function (_state: OrgChartAttrs<Datum>, visibleConnections: Connection<Datum>[]) {
|
|
393
|
+
return `<defs>
|
|
394
|
+
${visibleConnections
|
|
395
|
+
.map((conn) => {
|
|
396
|
+
const labelWidth = 0; // Placeholder, will be calculated in actual rendering
|
|
397
|
+
return `
|
|
398
|
+
<marker id="${conn.from + '_' + conn.to}" refX="${conn._source!.x < conn._target!.x ? -7 : 7}" refY="5" markerWidth="500" markerHeight="500" orient="${conn._source!.x < conn._target!.x ? 'auto' : 'auto-start-reverse'}" >
|
|
399
|
+
<rect rx=0.5 width=${conn.label ? labelWidth + 3 : 0} height=3 y=1 fill="#E27396"></rect>
|
|
400
|
+
<text font-size="2px" x=1 fill="white" y=3>${conn.label || ''}</text>
|
|
401
|
+
</marker>
|
|
402
|
+
|
|
403
|
+
<marker id="arrow-${conn.from + '_' + conn.to}" markerWidth="500" markerHeight="500" refY="2" refX="1" orient="${conn._source!.x < conn._target!.x ? 'auto' : 'auto-start-reverse'}" >
|
|
404
|
+
<path transform="translate(0)" d='M0,0 V4 L2,2 Z' fill='#E27396' />
|
|
405
|
+
</marker>
|
|
406
|
+
`;
|
|
407
|
+
})
|
|
408
|
+
.join('')}
|
|
409
|
+
</defs>
|
|
410
|
+
`;
|
|
411
|
+
},
|
|
412
|
+
/* You can update connections with custom styling using this function */
|
|
413
|
+
connectionsUpdate: function (this: SVGPathElement, d: Connection<Datum>, _i: number, _arr: SVGPathElement[] | ArrayLike<SVGPathElement>) {
|
|
414
|
+
d3.select(this)
|
|
415
|
+
.attr('stroke', () => '#E27396')
|
|
416
|
+
.attr('stroke-linecap', 'round')
|
|
417
|
+
.attr('stroke-width', () => '5')
|
|
418
|
+
.attr('pointer-events', 'none')
|
|
419
|
+
.attr('marker-start', () => `url(#${d.from + '_' + d.to})`)
|
|
420
|
+
.attr('marker-end', () => `url(#arrow-${d.from + '_' + d.to})`);
|
|
421
|
+
},
|
|
422
|
+
// Link generator for connections
|
|
423
|
+
linkGroupArc: d3
|
|
424
|
+
.linkHorizontal()
|
|
425
|
+
.x((d) => d[0])
|
|
426
|
+
.y((d) => d[1]),
|
|
427
|
+
|
|
428
|
+
/*
|
|
429
|
+
* You can customize/offset positions for each node and link by overriding these functions
|
|
430
|
+
* For example, suppose you want to move link y position 30 px bellow in top layout. You can do it like this:
|
|
431
|
+
* ```javascript
|
|
432
|
+
* const layout = chart.layoutBindings();
|
|
433
|
+
* layout.top.linkY = node => node.y + 30;
|
|
434
|
+
* chart.layoutBindings(layout);
|
|
435
|
+
* ```
|
|
436
|
+
*/
|
|
437
|
+
layoutBindings: {
|
|
438
|
+
left: {
|
|
439
|
+
nodeLeftX: (_) => 0,
|
|
440
|
+
nodeRightX: (node) => node.width,
|
|
441
|
+
nodeTopY: (node) => -node.height / 2,
|
|
442
|
+
nodeBottomY: (node) => node.height / 2,
|
|
443
|
+
nodeJoinX: (node) => node.x + node.width,
|
|
444
|
+
nodeJoinY: (node) => node.y - node.height / 2,
|
|
445
|
+
linkJoinX: (node) => node.x + node.width,
|
|
446
|
+
linkJoinY: (node) => node.y,
|
|
447
|
+
linkX: (node) => node.x,
|
|
448
|
+
linkY: (node) => node.y,
|
|
449
|
+
linkCompactXStart: (node) => node.x + node.width / 2, //node.x + (node.compactEven ? node.width / 2 : -node.width / 2),
|
|
450
|
+
linkCompactYStart: (node) => node.y + (node.compactEven ? node.height / 2 : -node.height / 2),
|
|
451
|
+
compactLinkMidX: (node, _) => node.firstCompactNode!.x, // node.firstCompactNode.x + node.firstCompactNode.flexCompactDim[0] / 4 + state.compactMarginPair(node) / 4,
|
|
452
|
+
compactLinkMidY: (node, state) => node.firstCompactNode!.y + (node.firstCompactNode!.flexCompactDim ? node.firstCompactNode!.flexCompactDim[0] / 4 : 0) + state.compactMarginPair(node) / 4,
|
|
453
|
+
linkParentX: (node) => node.parent!.x + node.parent!.width,
|
|
454
|
+
linkParentY: (node) => node.parent!.y,
|
|
455
|
+
buttonX: (node) => node.width,
|
|
456
|
+
buttonY: (node) => node.height / 2,
|
|
457
|
+
centerTransform: ({ rootMargin, centerY, scale }: { root: OrgChartNode<Datum>; rootMargin: number; scale: number; centerX: number; centerY: number }) => `translate(${rootMargin},${centerY}) scale(${scale})`,
|
|
458
|
+
compactDimension: {
|
|
459
|
+
sizeColumn: (node) => node.height,
|
|
460
|
+
sizeRow: (node) => node.width,
|
|
461
|
+
reverse: (arr) => arr.slice().reverse(),
|
|
462
|
+
},
|
|
463
|
+
nodeFlexSize: ({ height, width, siblingsMargin, childrenMargin, state, node }) => {
|
|
464
|
+
if (state.compact && node.flexCompactDim) {
|
|
465
|
+
const result: [number, number] = [node.flexCompactDim[0], node.flexCompactDim[1]];
|
|
466
|
+
return result;
|
|
467
|
+
}
|
|
468
|
+
const result: [number, number] = [height + siblingsMargin, width + childrenMargin];
|
|
469
|
+
return result;
|
|
470
|
+
},
|
|
471
|
+
zoomTransform: ({ x, y, k }: { x: number; y: number; k: number }) => `translate(${x},${y}) scale(${k})`,
|
|
472
|
+
diagonal: this.hdiagonal.bind(this),
|
|
473
|
+
swap: (d) => {
|
|
474
|
+
const x = d.x;
|
|
475
|
+
d.x = d.y;
|
|
476
|
+
d.y = x;
|
|
477
|
+
},
|
|
478
|
+
nodeUpdateTransform: ({ x, y, height }) => `translate(${x},${y - height / 2})`,
|
|
479
|
+
},
|
|
480
|
+
top: {
|
|
481
|
+
nodeLeftX: (node) => -node.width / 2,
|
|
482
|
+
nodeRightX: (node) => node.width / 2,
|
|
483
|
+
nodeTopY: (_) => 0,
|
|
484
|
+
nodeBottomY: (node) => node.height,
|
|
485
|
+
nodeJoinX: (node) => node.x - node.width / 2,
|
|
486
|
+
nodeJoinY: (node) => node.y + node.height,
|
|
487
|
+
linkJoinX: (node) => node.x,
|
|
488
|
+
linkJoinY: (node) => node.y + node.height,
|
|
489
|
+
linkCompactXStart: (node) => node.x + (node.compactEven ? node.width / 2 : -node.width / 2),
|
|
490
|
+
linkCompactYStart: (node) => node.y + node.height / 2,
|
|
491
|
+
compactLinkMidX: (node, state) => node.firstCompactNode!.x + (node.firstCompactNode!.flexCompactDim ? node.firstCompactNode!.flexCompactDim[0] / 4 : 0) + state.compactMarginPair(node) / 4,
|
|
492
|
+
compactLinkMidY: (node) => node.firstCompactNode!.y,
|
|
493
|
+
compactDimension: {
|
|
494
|
+
sizeColumn: (node) => node.width,
|
|
495
|
+
sizeRow: (node) => node.height,
|
|
496
|
+
reverse: (arr) => arr,
|
|
497
|
+
},
|
|
498
|
+
linkX: (node) => node.x,
|
|
499
|
+
linkY: (node) => node.y,
|
|
500
|
+
linkParentX: (node) => node.parent!.x,
|
|
501
|
+
linkParentY: (node) => node.parent!.y + node.parent!.height,
|
|
502
|
+
buttonX: (node) => node.width / 2,
|
|
503
|
+
buttonY: (node) => node.height,
|
|
504
|
+
centerTransform: ({ rootMargin, scale, centerX }: { root: OrgChartNode<Datum>; rootMargin: number; scale: number; centerX: number; centerY: number }) => `translate(${centerX},${rootMargin}) scale(${scale})`,
|
|
505
|
+
nodeFlexSize: ({ height, width, siblingsMargin, childrenMargin, state, node }) => {
|
|
506
|
+
if (state.compact && node.flexCompactDim) {
|
|
507
|
+
const result: [number, number] = [node.flexCompactDim[0], node.flexCompactDim[1]];
|
|
508
|
+
return result;
|
|
509
|
+
}
|
|
510
|
+
const result: [number, number] = [width + siblingsMargin, height + childrenMargin];
|
|
511
|
+
return result;
|
|
512
|
+
},
|
|
513
|
+
zoomTransform: ({ x, y, k }: { x: number; y: number; k: number }) => `translate(${x},${y}) scale(${k})`,
|
|
514
|
+
diagonal: this.diagonal.bind(this),
|
|
515
|
+
swap: (_d: any) => {},
|
|
516
|
+
nodeUpdateTransform: ({ x, y, width }: { x: number; y: number; width: number }) => `translate(${x - width / 2},${y})`,
|
|
517
|
+
},
|
|
518
|
+
bottom: {
|
|
519
|
+
nodeLeftX: (node) => -node.width / 2,
|
|
520
|
+
nodeRightX: (node) => node.width / 2,
|
|
521
|
+
nodeTopY: (node) => -node.height,
|
|
522
|
+
nodeBottomY: (_) => 0,
|
|
523
|
+
nodeJoinX: (node) => node.x - node.width / 2,
|
|
524
|
+
nodeJoinY: (node) => node.y - node.height - node.height,
|
|
525
|
+
linkJoinX: (node) => node.x,
|
|
526
|
+
linkJoinY: (node) => node.y - node.height,
|
|
527
|
+
linkCompactXStart: (node) => node.x + (node.compactEven ? node.width / 2 : -node.width / 2),
|
|
528
|
+
linkCompactYStart: (node) => node.y - node.height / 2,
|
|
529
|
+
compactLinkMidX: (node, state) => node.firstCompactNode!.x + (node.firstCompactNode!.flexCompactDim ? node.firstCompactNode!.flexCompactDim[0] / 4 : 0) + state.compactMarginPair(node) / 4,
|
|
530
|
+
compactLinkMidY: (node) => node.firstCompactNode!.y,
|
|
531
|
+
linkX: (node) => node.x,
|
|
532
|
+
linkY: (node) => node.y,
|
|
533
|
+
compactDimension: {
|
|
534
|
+
sizeColumn: (node) => node.width,
|
|
535
|
+
sizeRow: (node) => node.height,
|
|
536
|
+
reverse: (arr) => arr,
|
|
537
|
+
},
|
|
538
|
+
linkParentX: (node) => node.parent!.x,
|
|
539
|
+
linkParentY: (node) => node.parent!.y - node.parent!.height,
|
|
540
|
+
buttonX: (node) => node.width / 2,
|
|
541
|
+
buttonY: (_) => 0,
|
|
542
|
+
centerTransform: ({ rootMargin, scale, centerX }: { root: OrgChartNode<Datum>; rootMargin: number; scale: number; centerX: number; centerY: number; chartHeight?: number; chartWidth?: number }) => {
|
|
543
|
+
const attrs = this.getChartState();
|
|
544
|
+
return `translate(${centerX},${attrs.calc!.chartHeight - rootMargin}) scale(${scale})`;
|
|
545
|
+
},
|
|
546
|
+
nodeFlexSize: ({ height, width, siblingsMargin, childrenMargin, state, node }) => {
|
|
547
|
+
if (state.compact && node.flexCompactDim) {
|
|
548
|
+
const result: [number, number] = [node.flexCompactDim[0], node.flexCompactDim[1]];
|
|
549
|
+
return result;
|
|
550
|
+
}
|
|
551
|
+
const result: [number, number] = [width + siblingsMargin, height + childrenMargin];
|
|
552
|
+
return result;
|
|
553
|
+
},
|
|
554
|
+
zoomTransform: ({ x, y, k }: { x: number; y: number; k: number }) => `translate(${x},${y}) scale(${k})`,
|
|
555
|
+
diagonal: this.diagonal.bind(this),
|
|
556
|
+
swap: (d) => {
|
|
557
|
+
d.y = -d.y;
|
|
558
|
+
},
|
|
559
|
+
nodeUpdateTransform: ({ x, y, width, height }) => `translate(${x - width / 2},${y - height})`,
|
|
560
|
+
},
|
|
561
|
+
right: {
|
|
562
|
+
nodeLeftX: (node) => -node.width,
|
|
563
|
+
nodeRightX: (_) => 0,
|
|
564
|
+
nodeTopY: (node) => -node.height / 2,
|
|
565
|
+
nodeBottomY: (node) => node.height / 2,
|
|
566
|
+
nodeJoinX: (node) => node.x - node.width - node.width,
|
|
567
|
+
nodeJoinY: (node) => node.y - node.height / 2,
|
|
568
|
+
linkJoinX: (node) => node.x - node.width,
|
|
569
|
+
linkJoinY: (node) => node.y,
|
|
570
|
+
linkX: (node) => node.x,
|
|
571
|
+
linkY: (node) => node.y,
|
|
572
|
+
linkParentX: (node) => node.parent!.x - node.parent!.width,
|
|
573
|
+
linkParentY: (node) => node.parent!.y,
|
|
574
|
+
buttonX: (_) => 0,
|
|
575
|
+
buttonY: (node) => node.height / 2,
|
|
576
|
+
linkCompactXStart: (node) => node.x - node.width / 2, //node.x + (node.compactEven ? node.width / 2 : -node.width / 2),
|
|
577
|
+
linkCompactYStart: (node) => node.y + (node.compactEven ? node.height / 2 : -node.height / 2),
|
|
578
|
+
compactLinkMidX: (node, _) => node.firstCompactNode!.x, // node.firstCompactNode.x + node.firstCompactNode.flexCompactDim[0] / 4 + state.compactMarginPair(node) / 4,
|
|
579
|
+
compactLinkMidY: (node, state) => node.firstCompactNode!.y + (node.firstCompactNode!.flexCompactDim ? node.firstCompactNode!.flexCompactDim[0] / 4 : 0) + state.compactMarginPair(node) / 4,
|
|
580
|
+
centerTransform: ({ rootMargin, centerY, scale }: { root: OrgChartNode<Datum>; rootMargin: number; scale: number; centerX: number; centerY: number; chartWidth?: number; chartHeight?: number }) => {
|
|
581
|
+
const attrs = this.getChartState();
|
|
582
|
+
return `translate(${attrs.calc!.chartWidth - rootMargin},${centerY}) scale(${scale})`;
|
|
583
|
+
},
|
|
584
|
+
nodeFlexSize: ({ height, width, siblingsMargin, childrenMargin, state, node }) => {
|
|
585
|
+
if (state.compact && node.flexCompactDim) {
|
|
586
|
+
const result: [number, number] = [node.flexCompactDim[0], node.flexCompactDim[1]];
|
|
587
|
+
return result;
|
|
588
|
+
}
|
|
589
|
+
const result: [number, number] = [height + siblingsMargin, width + childrenMargin];
|
|
590
|
+
return result;
|
|
591
|
+
},
|
|
592
|
+
compactDimension: {
|
|
593
|
+
sizeColumn: (node) => node.height,
|
|
594
|
+
sizeRow: (node) => node.width,
|
|
595
|
+
reverse: (arr) => arr.slice().reverse(),
|
|
596
|
+
},
|
|
597
|
+
zoomTransform: ({ x, y, k }: { x: number; y: number; k: number }) => `translate(${x},${y}) scale(${k})`,
|
|
598
|
+
diagonal: this.hdiagonal.bind(this),
|
|
599
|
+
swap: (d) => {
|
|
600
|
+
const x = d.x;
|
|
601
|
+
d.x = -d.y;
|
|
602
|
+
d.y = x;
|
|
603
|
+
},
|
|
604
|
+
nodeUpdateTransform: ({ x, y, width, height }) => `translate(${x - width},${y - height / 2})`,
|
|
605
|
+
},
|
|
606
|
+
},
|
|
607
|
+
} as OrgChartAttrs<Datum>;
|
|
608
|
+
|
|
609
|
+
// Assign attrs to instance property
|
|
610
|
+
this.attrs = attrs;
|
|
611
|
+
|
|
612
|
+
// Assign getChartState method
|
|
613
|
+
this.getChartState = () => this.attrs;
|
|
614
|
+
|
|
615
|
+
this.initializeEnterExitUpdatePattern();
|
|
616
|
+
}
|
|
617
|
+
|
|
618
|
+
initializeEnterExitUpdatePattern(): void {
|
|
619
|
+
//Adding custom patternify method to d3.selection prototype
|
|
620
|
+
d3.selection.prototype.patternify = function (params: { selector: string; tag: string; data?: any[] | ((d: any) => any[]) }) {
|
|
621
|
+
const selector = params.selector;
|
|
622
|
+
const elementTag = params.tag;
|
|
623
|
+
const data = params.data || [selector];
|
|
624
|
+
|
|
625
|
+
// Pattern in action
|
|
626
|
+
let selection = this.selectAll('.' + selector).data(data, (d: any, i: number) => {
|
|
627
|
+
if (typeof d === 'object') {
|
|
628
|
+
if (d.id) {
|
|
629
|
+
return d.id;
|
|
630
|
+
}
|
|
631
|
+
}
|
|
632
|
+
return i;
|
|
633
|
+
});
|
|
634
|
+
selection.exit().remove();
|
|
635
|
+
selection = selection.enter().append(elementTag).merge(selection);
|
|
636
|
+
selection.attr('class', selector);
|
|
637
|
+
return selection;
|
|
638
|
+
};
|
|
639
|
+
}
|
|
640
|
+
|
|
641
|
+
// Configuration Methods
|
|
642
|
+
container(value?: string | HTMLElement): any {
|
|
643
|
+
if (arguments.length === 0) return this.attrs.container;
|
|
644
|
+
this.attrs.container = value!;
|
|
645
|
+
return this;
|
|
646
|
+
}
|
|
647
|
+
data(value?: Datum[]): any {
|
|
648
|
+
if (arguments.length === 0) return this.attrs.data;
|
|
649
|
+
this.attrs.data = value!;
|
|
650
|
+
return this;
|
|
651
|
+
}
|
|
652
|
+
svgWidth(value?: number): any {
|
|
653
|
+
if (arguments.length === 0) return this.attrs.svgWidth;
|
|
654
|
+
this.attrs.svgWidth = value!;
|
|
655
|
+
return this;
|
|
656
|
+
}
|
|
657
|
+
svgHeight(value?: number): any {
|
|
658
|
+
if (arguments.length === 0) return this.attrs.svgHeight;
|
|
659
|
+
this.attrs.svgHeight = value!;
|
|
660
|
+
return this;
|
|
661
|
+
}
|
|
662
|
+
compact(value?: boolean): any {
|
|
663
|
+
if (arguments.length === 0) return this.attrs.compact;
|
|
664
|
+
this.attrs.compact = value!;
|
|
665
|
+
return this;
|
|
666
|
+
}
|
|
667
|
+
layout(value?: LayoutType): any {
|
|
668
|
+
if (arguments.length === 0) return this.attrs.layout;
|
|
669
|
+
this.attrs.layout = value!;
|
|
670
|
+
return this;
|
|
671
|
+
}
|
|
672
|
+
duration(value?: number): any {
|
|
673
|
+
if (arguments.length === 0) return this.attrs.duration;
|
|
674
|
+
this.attrs.duration = value!;
|
|
675
|
+
return this;
|
|
676
|
+
}
|
|
677
|
+
connections(value?: Connection<Datum>[]): any {
|
|
678
|
+
if (arguments.length === 0) return this.attrs.connections;
|
|
679
|
+
this.attrs.connections = value!;
|
|
680
|
+
return this;
|
|
681
|
+
}
|
|
682
|
+
rootMargin(value?: number): any {
|
|
683
|
+
if (arguments.length === 0) return this.attrs.rootMargin;
|
|
684
|
+
this.attrs.rootMargin = value!;
|
|
685
|
+
return this;
|
|
686
|
+
}
|
|
687
|
+
setActiveNodeCentered(value?: boolean): any {
|
|
688
|
+
if (arguments.length === 0) return this.attrs.setActiveNodeCentered;
|
|
689
|
+
this.attrs.setActiveNodeCentered = value!;
|
|
690
|
+
return this;
|
|
691
|
+
}
|
|
692
|
+
scaleExtent(value?: [number, number]): any {
|
|
693
|
+
if (arguments.length === 0) return this.attrs.scaleExtent;
|
|
694
|
+
this.attrs.scaleExtent = value!;
|
|
695
|
+
return this;
|
|
696
|
+
}
|
|
697
|
+
defaultFont(value?: string): any {
|
|
698
|
+
if (arguments.length === 0) return this.attrs.defaultFont;
|
|
699
|
+
this.attrs.defaultFont = value!;
|
|
700
|
+
return this;
|
|
701
|
+
}
|
|
702
|
+
imageName(value?: string): any {
|
|
703
|
+
if (arguments.length === 0) return this.attrs.imageName;
|
|
704
|
+
this.attrs.imageName = value!;
|
|
705
|
+
return this;
|
|
706
|
+
}
|
|
707
|
+
linkYOffset(value?: number): any {
|
|
708
|
+
if (arguments.length === 0) return this.attrs.linkYOffset;
|
|
709
|
+
this.attrs.linkYOffset = value!;
|
|
710
|
+
return this;
|
|
711
|
+
}
|
|
712
|
+
|
|
713
|
+
// Accessor Methods
|
|
714
|
+
nodeId(value?: DataAccessor<string | number, Datum>): any {
|
|
715
|
+
if (arguments.length === 0) return this.attrs.nodeId;
|
|
716
|
+
this.attrs.nodeId = value!;
|
|
717
|
+
return this;
|
|
718
|
+
}
|
|
719
|
+
parentNodeId(value?: DataAccessor<string | number, Datum>): any {
|
|
720
|
+
if (arguments.length === 0) return this.attrs.parentNodeId;
|
|
721
|
+
this.attrs.parentNodeId = value!;
|
|
722
|
+
return this;
|
|
723
|
+
}
|
|
724
|
+
nodeWidth(value?: NodeAccessor<number, Datum>): any {
|
|
725
|
+
if (arguments.length === 0) return this.attrs.nodeWidth;
|
|
726
|
+
this.attrs.nodeWidth = value!;
|
|
727
|
+
return this;
|
|
728
|
+
}
|
|
729
|
+
nodeHeight(value?: NodeAccessor<number, Datum>): any {
|
|
730
|
+
if (arguments.length === 0) return this.attrs.nodeHeight;
|
|
731
|
+
this.attrs.nodeHeight = value!;
|
|
732
|
+
return this;
|
|
733
|
+
}
|
|
734
|
+
siblingsMargin(value?: NodeAccessor<number, Datum>): any {
|
|
735
|
+
if (arguments.length === 0) return this.attrs.siblingsMargin;
|
|
736
|
+
this.attrs.siblingsMargin = value!;
|
|
737
|
+
return this;
|
|
738
|
+
}
|
|
739
|
+
childrenMargin(value?: NodeAccessor<number, Datum>): any {
|
|
740
|
+
if (arguments.length === 0) return this.attrs.childrenMargin;
|
|
741
|
+
this.attrs.childrenMargin = value!;
|
|
742
|
+
return this;
|
|
743
|
+
}
|
|
744
|
+
neighbourMargin(value?: (node1: OrgChartNode<Datum>, node2: OrgChartNode<Datum>) => number): any {
|
|
745
|
+
if (arguments.length === 0) return this.attrs.neighbourMargin;
|
|
746
|
+
this.attrs.neighbourMargin = value!;
|
|
747
|
+
return this;
|
|
748
|
+
}
|
|
749
|
+
compactMarginPair(value?: NodeAccessor<number, Datum>): any {
|
|
750
|
+
if (arguments.length === 0) return this.attrs.compactMarginPair;
|
|
751
|
+
this.attrs.compactMarginPair = value!;
|
|
752
|
+
return this;
|
|
753
|
+
}
|
|
754
|
+
compactMarginBetween(value?: NodeAccessor<number, Datum>): any {
|
|
755
|
+
if (arguments.length === 0) return this.attrs.compactMarginBetween;
|
|
756
|
+
this.attrs.compactMarginBetween = value!;
|
|
757
|
+
return this;
|
|
758
|
+
}
|
|
759
|
+
initialExpandLevel(value?: number): any {
|
|
760
|
+
if (arguments.length === 0) return this.attrs.initialExpandLevel;
|
|
761
|
+
this.attrs.initialExpandLevel = value!;
|
|
762
|
+
return this;
|
|
763
|
+
}
|
|
764
|
+
nodeButtonWidth(value?: NodeAccessor<number, Datum>): any {
|
|
765
|
+
if (arguments.length === 0) return this.attrs.nodeButtonWidth;
|
|
766
|
+
this.attrs.nodeButtonWidth = value!;
|
|
767
|
+
return this;
|
|
768
|
+
}
|
|
769
|
+
nodeButtonHeight(value?: NodeAccessor<number, Datum>): any {
|
|
770
|
+
if (arguments.length === 0) return this.attrs.nodeButtonHeight;
|
|
771
|
+
this.attrs.nodeButtonHeight = value!;
|
|
772
|
+
return this;
|
|
773
|
+
}
|
|
774
|
+
nodeButtonX(value?: NodeAccessor<number, Datum>): any {
|
|
775
|
+
if (arguments.length === 0) return this.attrs.nodeButtonX;
|
|
776
|
+
this.attrs.nodeButtonX = value!;
|
|
777
|
+
return this;
|
|
778
|
+
}
|
|
779
|
+
nodeButtonY(value?: NodeAccessor<number, Datum>): any {
|
|
780
|
+
if (arguments.length === 0) return this.attrs.nodeButtonY;
|
|
781
|
+
this.attrs.nodeButtonY = value!;
|
|
782
|
+
return this;
|
|
783
|
+
}
|
|
784
|
+
pagingStep(value?: NodeAccessor<number, Datum>): any {
|
|
785
|
+
if (arguments.length === 0) return this.attrs.pagingStep;
|
|
786
|
+
this.attrs.pagingStep = value!;
|
|
787
|
+
return this;
|
|
788
|
+
}
|
|
789
|
+
minPagingVisibleNodes(value?: NodeAccessor<number, Datum>): any {
|
|
790
|
+
if (arguments.length === 0) return this.attrs.minPagingVisibleNodes;
|
|
791
|
+
this.attrs.minPagingVisibleNodes = value!;
|
|
792
|
+
return this;
|
|
793
|
+
}
|
|
794
|
+
|
|
795
|
+
// Callback Methods
|
|
796
|
+
nodeContent(value?: NodeContentCallback<Datum>): any {
|
|
797
|
+
if (arguments.length === 0) return this.attrs.nodeContent;
|
|
798
|
+
this.attrs.nodeContent = value!;
|
|
799
|
+
return this;
|
|
800
|
+
}
|
|
801
|
+
buttonContent(value?: ButtonContentCallback<Datum>): any {
|
|
802
|
+
if (arguments.length === 0) return this.attrs.buttonContent;
|
|
803
|
+
this.attrs.buttonContent = value!;
|
|
804
|
+
return this;
|
|
805
|
+
}
|
|
806
|
+
pagingButton(value?: PagingButtonCallback<Datum>): any {
|
|
807
|
+
if (arguments.length === 0) return this.attrs.pagingButton;
|
|
808
|
+
this.attrs.pagingButton = value!;
|
|
809
|
+
return this;
|
|
810
|
+
}
|
|
811
|
+
onNodeClick(value?: NodeClickCallback<Datum>): any {
|
|
812
|
+
if (arguments.length === 0) return this.attrs.onNodeClick;
|
|
813
|
+
this.attrs.onNodeClick = value!;
|
|
814
|
+
return this;
|
|
815
|
+
}
|
|
816
|
+
onExpandOrCollapse(value?: NodeExpandCollapseCallback<Datum>): any {
|
|
817
|
+
if (arguments.length === 0) return this.attrs.onExpandOrCollapse;
|
|
818
|
+
this.attrs.onExpandOrCollapse = value!;
|
|
819
|
+
return this;
|
|
820
|
+
}
|
|
821
|
+
onZoomStart(value?: ZoomCallback<Datum>): any {
|
|
822
|
+
if (arguments.length === 0) return this.attrs.onZoomStart;
|
|
823
|
+
this.attrs.onZoomStart = value!;
|
|
824
|
+
return this;
|
|
825
|
+
}
|
|
826
|
+
onZoom(value?: ZoomCallback<Datum>): any {
|
|
827
|
+
if (arguments.length === 0) return this.attrs.onZoom;
|
|
828
|
+
this.attrs.onZoom = value!;
|
|
829
|
+
return this;
|
|
830
|
+
}
|
|
831
|
+
onZoomEnd(value?: ZoomCallback<Datum>): any {
|
|
832
|
+
if (arguments.length === 0) return this.attrs.onZoomEnd;
|
|
833
|
+
this.attrs.onZoomEnd = value!;
|
|
834
|
+
return this;
|
|
835
|
+
}
|
|
836
|
+
nodeUpdate(value?: NodeUpdateCallback<Datum>): any {
|
|
837
|
+
if (arguments.length === 0) return this.attrs.nodeUpdate;
|
|
838
|
+
this.attrs.nodeUpdate = value!;
|
|
839
|
+
return this;
|
|
840
|
+
}
|
|
841
|
+
nodeEnter(value?: NodeEnterCallback<Datum>): any {
|
|
842
|
+
if (arguments.length === 0) return this.attrs.nodeEnter;
|
|
843
|
+
this.attrs.nodeEnter = value!;
|
|
844
|
+
return this;
|
|
845
|
+
}
|
|
846
|
+
nodeExit(value?: NodeExitCallback<Datum>): any {
|
|
847
|
+
if (arguments.length === 0) return this.attrs.nodeExit;
|
|
848
|
+
this.attrs.nodeExit = value!;
|
|
849
|
+
return this;
|
|
850
|
+
}
|
|
851
|
+
linkUpdate(value?: LinkUpdateCallback<Datum>): any {
|
|
852
|
+
if (arguments.length === 0) return this.attrs.linkUpdate;
|
|
853
|
+
this.attrs.linkUpdate = value!;
|
|
854
|
+
return this;
|
|
855
|
+
}
|
|
856
|
+
connectionsUpdate(value?: ConnectionsUpdateCallback<Datum>): any {
|
|
857
|
+
if (arguments.length === 0) return this.attrs.connectionsUpdate;
|
|
858
|
+
this.attrs.connectionsUpdate = value!;
|
|
859
|
+
return this;
|
|
860
|
+
}
|
|
861
|
+
defs(value?: DefsCallback<Datum>): any {
|
|
862
|
+
if (arguments.length === 0) return this.attrs.defs;
|
|
863
|
+
this.attrs.defs = value!;
|
|
864
|
+
return this;
|
|
865
|
+
}
|
|
866
|
+
lastTransform(value?: { x: number; y: number; k: number }): any {
|
|
867
|
+
if (arguments.length === 0) return this.attrs.lastTransform;
|
|
868
|
+
this.attrs.lastTransform = value!;
|
|
869
|
+
return this;
|
|
870
|
+
}
|
|
871
|
+
|
|
872
|
+
// This method retrieves passed node's children IDs (including node)
|
|
873
|
+
getNodeChildren({ data, children, _children }: { data: Datum; children?: OrgChartNode<Datum>[]; _children?: OrgChartNode<Datum>[] }, nodeStore: Datum[] = []): Datum[] {
|
|
874
|
+
// Store current node ID
|
|
875
|
+
nodeStore.push(data);
|
|
876
|
+
|
|
877
|
+
// Loop over children and recursively store descendants id (expanded nodes)
|
|
878
|
+
if (children) {
|
|
879
|
+
children.forEach((d) => {
|
|
880
|
+
this.getNodeChildren(d, nodeStore);
|
|
881
|
+
});
|
|
882
|
+
}
|
|
883
|
+
|
|
884
|
+
// Loop over _children and recursively store descendants id (collapsed nodes)
|
|
885
|
+
if (_children) {
|
|
886
|
+
_children.forEach((d) => {
|
|
887
|
+
this.getNodeChildren(d, nodeStore);
|
|
888
|
+
});
|
|
889
|
+
}
|
|
890
|
+
|
|
891
|
+
// Return result
|
|
892
|
+
return nodeStore;
|
|
893
|
+
}
|
|
894
|
+
|
|
895
|
+
// This method can be invoked via chart.setZoomFactor API, it zooms to particulat scale
|
|
896
|
+
initialZoom(zoomLevel: number): this {
|
|
897
|
+
const attrs = this.getChartState();
|
|
898
|
+
attrs.lastTransform.k = zoomLevel;
|
|
899
|
+
return this;
|
|
900
|
+
}
|
|
901
|
+
|
|
902
|
+
render(): this {
|
|
903
|
+
//InnerFunctions which will update visuals
|
|
904
|
+
const attrs: any = this.getChartState();
|
|
905
|
+
if (!attrs.data || attrs.data.length == 0) {
|
|
906
|
+
console.log('ORG CHART - Data is empty');
|
|
907
|
+
if (attrs.container) {
|
|
908
|
+
(select as any)(attrs.container).select('.nodes-wrapper').remove();
|
|
909
|
+
(select as any)(attrs.container).select('.links-wrapper').remove();
|
|
910
|
+
(select as any)(attrs.container).select('.connections-wrapper').remove();
|
|
911
|
+
}
|
|
912
|
+
return this;
|
|
913
|
+
}
|
|
914
|
+
|
|
915
|
+
//Drawing containers
|
|
916
|
+
const container = (d3.select as any)(attrs.container);
|
|
917
|
+
const containerNode = container.node();
|
|
918
|
+
if (containerNode && 'getBoundingClientRect' in containerNode) {
|
|
919
|
+
const containerRect = (containerNode as HTMLElement).getBoundingClientRect();
|
|
920
|
+
if (containerRect.width > 0) attrs.svgWidth = containerRect.width;
|
|
921
|
+
}
|
|
922
|
+
|
|
923
|
+
//Calculated properties
|
|
924
|
+
const calc: CalcProperties = {
|
|
925
|
+
id: `ID${crypto.randomUUID()}`, // id for event handlings,
|
|
926
|
+
chartWidth: attrs.svgWidth,
|
|
927
|
+
chartHeight: attrs.svgHeight,
|
|
928
|
+
centerX: attrs.svgWidth / 2,
|
|
929
|
+
centerY: attrs.svgHeight / 2,
|
|
930
|
+
};
|
|
931
|
+
attrs.calc = calc;
|
|
932
|
+
|
|
933
|
+
// ******************* BEHAVIORS **********************
|
|
934
|
+
if (attrs.firstDraw) {
|
|
935
|
+
const behaviors: any = {
|
|
936
|
+
zoom: null,
|
|
937
|
+
};
|
|
938
|
+
|
|
939
|
+
// Get zooming function
|
|
940
|
+
behaviors.zoom = attrs
|
|
941
|
+
.createZoom(attrs.root!)
|
|
942
|
+
.clickDistance(10)
|
|
943
|
+
.wheelDelta((event: any) => {
|
|
944
|
+
if (event.ctrlKey) {
|
|
945
|
+
event.preventDefault();
|
|
946
|
+
|
|
947
|
+
const isPinchGesture = event.ctrlKey && event.deltaMode === 0 && Math.abs(event.deltaY) < 50;
|
|
948
|
+
const isCtrlScrollReal = event.ctrlKey && Math.abs(event.deltaY) >= 50;
|
|
949
|
+
return -event.deltaY * (event.deltaMode === 1 ? 0.05 : event.deltaMode ? 1 : 0.002) * (isPinchGesture ? 10 : isCtrlScrollReal ? 1 : 1);
|
|
950
|
+
}
|
|
951
|
+
|
|
952
|
+
return 0;
|
|
953
|
+
})
|
|
954
|
+
.on('start', (event: any, _d: any) => attrs.onZoomStart(event))
|
|
955
|
+
.on('end', (event: any, _d: any) => attrs.onZoomEnd(event))
|
|
956
|
+
.on('zoom', (event: any, d: any) => {
|
|
957
|
+
attrs.onZoom(event);
|
|
958
|
+
this.zoomed(event, d);
|
|
959
|
+
})
|
|
960
|
+
.scaleExtent(attrs.scaleExtent);
|
|
961
|
+
attrs.zoomBehavior = behaviors.zoom;
|
|
962
|
+
}
|
|
963
|
+
|
|
964
|
+
//****************** ROOT node work ************************
|
|
965
|
+
|
|
966
|
+
attrs.flexTreeLayout = flextree<Datum>({
|
|
967
|
+
nodeSize: (node: any) => {
|
|
968
|
+
const width = attrs.nodeWidth(node);
|
|
969
|
+
const height = attrs.nodeHeight(node);
|
|
970
|
+
const siblingsMargin = attrs.siblingsMargin(node);
|
|
971
|
+
const childrenMargin = attrs.childrenMargin(node);
|
|
972
|
+
return attrs.layoutBindings[attrs.layout].nodeFlexSize({
|
|
973
|
+
state: attrs,
|
|
974
|
+
node: node as OrgChartNode<Datum>,
|
|
975
|
+
width,
|
|
976
|
+
height,
|
|
977
|
+
siblingsMargin,
|
|
978
|
+
childrenMargin,
|
|
979
|
+
});
|
|
980
|
+
},
|
|
981
|
+
}).spacing((nodeA: any, nodeB: any) => (nodeA.parent == nodeB.parent ? 0 : attrs.neighbourMargin(nodeA as OrgChartNode<Datum>, nodeB as OrgChartNode<Datum>)));
|
|
982
|
+
|
|
983
|
+
this.setLayouts({ expandNodesFirst: false });
|
|
984
|
+
|
|
985
|
+
// ************************* DRAWING **************************
|
|
986
|
+
//Add svg
|
|
987
|
+
const svg = container
|
|
988
|
+
.patternify({
|
|
989
|
+
tag: 'svg',
|
|
990
|
+
selector: 'svg-chart-container',
|
|
991
|
+
})
|
|
992
|
+
.attr('width', attrs.svgWidth)
|
|
993
|
+
.attr('height', attrs.svgHeight)
|
|
994
|
+
.attr('font-family', attrs.defaultFont);
|
|
995
|
+
|
|
996
|
+
if (attrs.firstDraw) {
|
|
997
|
+
svg.call(attrs.zoomBehavior)
|
|
998
|
+
.on('dblclick.zoom', null)
|
|
999
|
+
.on(
|
|
1000
|
+
'wheel',
|
|
1001
|
+
(event: any) => {
|
|
1002
|
+
const t = d3.zoomTransform(svg.node());
|
|
1003
|
+
const k = t.k;
|
|
1004
|
+
|
|
1005
|
+
if (event.ctrlKey) {
|
|
1006
|
+
event.preventDefault();
|
|
1007
|
+
return;
|
|
1008
|
+
}
|
|
1009
|
+
|
|
1010
|
+
event.preventDefault();
|
|
1011
|
+
if (attrs.zoomBehavior) {
|
|
1012
|
+
svg.call(attrs.zoomBehavior.transform, d3.zoomIdentity.translate(t.x - event.deltaX, t.y - event.deltaY).scale(k));
|
|
1013
|
+
}
|
|
1014
|
+
},
|
|
1015
|
+
{ passive: false }
|
|
1016
|
+
)
|
|
1017
|
+
.attr('cursor', 'move');
|
|
1018
|
+
}
|
|
1019
|
+
|
|
1020
|
+
attrs.svg = svg;
|
|
1021
|
+
|
|
1022
|
+
//Add container g element
|
|
1023
|
+
const chart = svg.patternify({
|
|
1024
|
+
tag: 'g',
|
|
1025
|
+
selector: 'chart',
|
|
1026
|
+
});
|
|
1027
|
+
|
|
1028
|
+
// Add one more container g element, for better positioning controls
|
|
1029
|
+
attrs.centerG = chart.patternify({
|
|
1030
|
+
tag: 'g',
|
|
1031
|
+
selector: 'center-group',
|
|
1032
|
+
});
|
|
1033
|
+
|
|
1034
|
+
attrs.linksWrapper = attrs.centerG!.patternify({
|
|
1035
|
+
tag: 'g',
|
|
1036
|
+
selector: 'links-wrapper',
|
|
1037
|
+
});
|
|
1038
|
+
|
|
1039
|
+
attrs.nodesWrapper = attrs.centerG!.patternify({
|
|
1040
|
+
tag: 'g',
|
|
1041
|
+
selector: 'nodes-wrapper',
|
|
1042
|
+
});
|
|
1043
|
+
|
|
1044
|
+
attrs.connectionsWrapper = attrs.centerG!.patternify({
|
|
1045
|
+
tag: 'g',
|
|
1046
|
+
selector: 'connections-wrapper',
|
|
1047
|
+
});
|
|
1048
|
+
|
|
1049
|
+
attrs.defsWrapper = svg.patternify({
|
|
1050
|
+
tag: 'g',
|
|
1051
|
+
selector: 'defs-wrapper',
|
|
1052
|
+
});
|
|
1053
|
+
|
|
1054
|
+
if (attrs.firstDraw) {
|
|
1055
|
+
attrs.centerG!.attr('transform', () => {
|
|
1056
|
+
return attrs.layoutBindings[attrs.layout].centerTransform({
|
|
1057
|
+
centerX: calc.centerX,
|
|
1058
|
+
centerY: calc.centerY,
|
|
1059
|
+
scale: attrs.lastTransform.k,
|
|
1060
|
+
rootMargin: attrs.rootMargin,
|
|
1061
|
+
root: attrs.root!,
|
|
1062
|
+
});
|
|
1063
|
+
});
|
|
1064
|
+
}
|
|
1065
|
+
|
|
1066
|
+
attrs.chart = chart;
|
|
1067
|
+
|
|
1068
|
+
// Display tree contenrs
|
|
1069
|
+
this.update(attrs.root!);
|
|
1070
|
+
|
|
1071
|
+
//######################################### UTIL FUNCS ##################################
|
|
1072
|
+
// This function restyles foreign object elements ()
|
|
1073
|
+
|
|
1074
|
+
d3.select(window).on(`resize.${attrs.id}`, () => {
|
|
1075
|
+
const containerNode = (d3.select as any)(attrs.container).node();
|
|
1076
|
+
if (containerNode && 'getBoundingClientRect' in containerNode) {
|
|
1077
|
+
const containerRect = (containerNode as HTMLElement).getBoundingClientRect();
|
|
1078
|
+
attrs.svg!.attr('width', containerRect.width);
|
|
1079
|
+
}
|
|
1080
|
+
});
|
|
1081
|
+
|
|
1082
|
+
if (attrs.firstDraw) {
|
|
1083
|
+
attrs.firstDraw = false;
|
|
1084
|
+
}
|
|
1085
|
+
|
|
1086
|
+
return this;
|
|
1087
|
+
}
|
|
1088
|
+
|
|
1089
|
+
// This function can be invoked via chart.addNode API, and it adds node in tree at runtime
|
|
1090
|
+
addNode(obj: Datum): this {
|
|
1091
|
+
const attrs = this.getChartState();
|
|
1092
|
+
if (obj && (attrs.parentNodeId(obj) == null || attrs.parentNodeId(obj) == attrs.nodeId(obj)) && (attrs.data?.length || 0) == 0) {
|
|
1093
|
+
attrs.data!.push(obj);
|
|
1094
|
+
this.render();
|
|
1095
|
+
return this;
|
|
1096
|
+
}
|
|
1097
|
+
const root = attrs.generateRoot!(attrs.data || []);
|
|
1098
|
+
const descendants = root.descendants();
|
|
1099
|
+
const nodeFound = descendants.filter(({ data }) => attrs.nodeId(data).toString() === attrs.nodeId(obj).toString())[0];
|
|
1100
|
+
if (nodeFound) {
|
|
1101
|
+
console.log(`ORG CHART - ADD - Node with id "${attrs.nodeId(obj)}" already exists in tree`);
|
|
1102
|
+
return this;
|
|
1103
|
+
}
|
|
1104
|
+
|
|
1105
|
+
if ((obj as any)._centered && !(obj as any)._expanded) (obj as any)._expanded = true;
|
|
1106
|
+
attrs.data!.push(obj);
|
|
1107
|
+
|
|
1108
|
+
// Update state of nodes and redraw graph
|
|
1109
|
+
this.updateNodesState();
|
|
1110
|
+
|
|
1111
|
+
return this;
|
|
1112
|
+
}
|
|
1113
|
+
|
|
1114
|
+
// This function can be invoked via chart.removeNode API, and it removes node from tree at runtime
|
|
1115
|
+
removeNode(nodeId: string | number): this {
|
|
1116
|
+
const attrs = this.getChartState();
|
|
1117
|
+
const root = attrs.generateRoot!(attrs.data || []);
|
|
1118
|
+
const descendants = root.descendants();
|
|
1119
|
+
const node = descendants.find(({ data }) => attrs.nodeId(data) == nodeId);
|
|
1120
|
+
|
|
1121
|
+
if (!node) {
|
|
1122
|
+
console.log(`ORG CHART - REMOVE - Node with id "${nodeId}" not found in the tree`);
|
|
1123
|
+
return this;
|
|
1124
|
+
}
|
|
1125
|
+
|
|
1126
|
+
// Get all node descendants
|
|
1127
|
+
const nodeDescendants = node.descendants();
|
|
1128
|
+
|
|
1129
|
+
// Mark all node children and node itself for removal
|
|
1130
|
+
nodeDescendants.forEach((d) => ((d.data as any)._filteredOut = true));
|
|
1131
|
+
|
|
1132
|
+
// Filter out retrieved nodes and reassign data
|
|
1133
|
+
attrs.data = attrs.data!.filter((d) => !(d as any)._filteredOut);
|
|
1134
|
+
|
|
1135
|
+
if ((attrs.data?.length || 0) == 0) {
|
|
1136
|
+
this.render();
|
|
1137
|
+
} else {
|
|
1138
|
+
const updateNodesState = this.updateNodesState.bind(this);
|
|
1139
|
+
// Update state of nodes and redraw graph
|
|
1140
|
+
updateNodesState();
|
|
1141
|
+
}
|
|
1142
|
+
return this;
|
|
1143
|
+
}
|
|
1144
|
+
|
|
1145
|
+
groupBy<T, K extends string | number>(array: T[], accessor: (item: T) => K, aggregator: (group: T[]) => any): [string, any][] {
|
|
1146
|
+
const grouped: Record<string, T[]> = {};
|
|
1147
|
+
array.forEach((item) => {
|
|
1148
|
+
const key = String(accessor(item));
|
|
1149
|
+
grouped[key] ??= [];
|
|
1150
|
+
grouped[key].push(item);
|
|
1151
|
+
});
|
|
1152
|
+
|
|
1153
|
+
Object.keys(grouped).forEach((key) => {
|
|
1154
|
+
grouped[key] = aggregator(grouped[key] as any);
|
|
1155
|
+
});
|
|
1156
|
+
return Object.entries(grouped);
|
|
1157
|
+
}
|
|
1158
|
+
|
|
1159
|
+
calculateCompactFlexDimensions(root: OrgChartNode<Datum>): void {
|
|
1160
|
+
const attrs = this.getChartState();
|
|
1161
|
+
root.eachBefore((node) => {
|
|
1162
|
+
node.firstCompact = undefined;
|
|
1163
|
+
node.compactEven = undefined;
|
|
1164
|
+
node.flexCompactDim = undefined;
|
|
1165
|
+
node.firstCompactNode = undefined;
|
|
1166
|
+
});
|
|
1167
|
+
root.eachBefore((node) => {
|
|
1168
|
+
if (node.children && node.children.length > 1) {
|
|
1169
|
+
const compactChildren = node.children.filter((d) => !d.children);
|
|
1170
|
+
|
|
1171
|
+
if (compactChildren.length < 2) return;
|
|
1172
|
+
compactChildren.forEach((child, i) => {
|
|
1173
|
+
if (!i) child.firstCompact = true;
|
|
1174
|
+
if (i % 2) child.compactEven = false;
|
|
1175
|
+
else child.compactEven = true;
|
|
1176
|
+
child.row = Math.floor(i / 2);
|
|
1177
|
+
});
|
|
1178
|
+
const evenMaxColumnDimension =
|
|
1179
|
+
d3.max(
|
|
1180
|
+
compactChildren.filter((d) => d.compactEven),
|
|
1181
|
+
attrs.layoutBindings[attrs.layout].compactDimension.sizeColumn
|
|
1182
|
+
) || 0;
|
|
1183
|
+
const oddMaxColumnDimension =
|
|
1184
|
+
d3.max(
|
|
1185
|
+
compactChildren.filter((d) => !d.compactEven),
|
|
1186
|
+
attrs.layoutBindings[attrs.layout].compactDimension.sizeColumn
|
|
1187
|
+
) || 0;
|
|
1188
|
+
const columnSize = Math.max(evenMaxColumnDimension, oddMaxColumnDimension) * 2;
|
|
1189
|
+
const rowsMapNew = this.groupBy(
|
|
1190
|
+
compactChildren,
|
|
1191
|
+
(d) => d.row || 0,
|
|
1192
|
+
(reducedGroup) => d3.max(reducedGroup, (d) => attrs.layoutBindings[attrs.layout].compactDimension.sizeRow(d) + attrs.compactMarginBetween(d))
|
|
1193
|
+
);
|
|
1194
|
+
const rowSize = d3.sum(rowsMapNew.map((v) => v[1]));
|
|
1195
|
+
compactChildren.forEach((node) => {
|
|
1196
|
+
node.firstCompactNode = compactChildren[0];
|
|
1197
|
+
if (node.firstCompact) {
|
|
1198
|
+
node.flexCompactDim = [columnSize + attrs.compactMarginPair(node), rowSize - attrs.compactMarginBetween(node)];
|
|
1199
|
+
} else {
|
|
1200
|
+
node.flexCompactDim = [0, 0];
|
|
1201
|
+
}
|
|
1202
|
+
});
|
|
1203
|
+
node.flexCompactDim = undefined;
|
|
1204
|
+
}
|
|
1205
|
+
});
|
|
1206
|
+
}
|
|
1207
|
+
|
|
1208
|
+
calculateCompactFlexPositions(root: OrgChartNode<Datum>): void {
|
|
1209
|
+
const attrs = this.getChartState();
|
|
1210
|
+
root.eachBefore((node) => {
|
|
1211
|
+
if (node.children) {
|
|
1212
|
+
const compactChildren = node.children.filter((d) => d.flexCompactDim);
|
|
1213
|
+
const fch = compactChildren[0];
|
|
1214
|
+
if (!fch?.flexCompactDim) return;
|
|
1215
|
+
compactChildren.forEach((child, i, _arr) => {
|
|
1216
|
+
if (i == 0 && fch.flexCompactDim) fch.x -= fch.flexCompactDim[0] / 2;
|
|
1217
|
+
if (fch.flexCompactDim && i & ((i % 2) - 1)) child.x = fch.x + fch.flexCompactDim[0] * 0.25 - attrs.compactMarginPair(child) / 4;
|
|
1218
|
+
else if (i && fch.flexCompactDim) child.x = fch.x + fch.flexCompactDim[0] * 0.75 + attrs.compactMarginPair(child) / 4;
|
|
1219
|
+
});
|
|
1220
|
+
if (!fch.flexCompactDim) return;
|
|
1221
|
+
const centerX = fch.x + fch.flexCompactDim[0] * 0.5;
|
|
1222
|
+
fch.x = fch.x + fch.flexCompactDim[0] * 0.25 - attrs.compactMarginPair(fch) / 4;
|
|
1223
|
+
const offsetX = node.x - centerX;
|
|
1224
|
+
if (Math.abs(offsetX) < 10) {
|
|
1225
|
+
compactChildren.forEach((d) => (d.x += offsetX));
|
|
1226
|
+
}
|
|
1227
|
+
|
|
1228
|
+
const rowsMapNew = this.groupBy(
|
|
1229
|
+
compactChildren,
|
|
1230
|
+
(d) => d.row || 0,
|
|
1231
|
+
(reducedGroup) => d3.max(reducedGroup, (d) => attrs.layoutBindings[attrs.layout].compactDimension.sizeRow(d))
|
|
1232
|
+
);
|
|
1233
|
+
const cumSum = d3.cumsum(rowsMapNew.map((d) => d[1] + attrs.compactMarginBetween(fch)));
|
|
1234
|
+
compactChildren.forEach((node, _i) => {
|
|
1235
|
+
if (node.row) {
|
|
1236
|
+
const cumulativeValue = cumSum[(node.row ?? 0) - 1];
|
|
1237
|
+
node.y = fch.y + (cumulativeValue ?? 0);
|
|
1238
|
+
} else {
|
|
1239
|
+
node.y = fch.y;
|
|
1240
|
+
}
|
|
1241
|
+
});
|
|
1242
|
+
}
|
|
1243
|
+
});
|
|
1244
|
+
}
|
|
1245
|
+
|
|
1246
|
+
// This function basically redraws visible graph, based on nodes state
|
|
1247
|
+
update({ x0, y0, x = 0, y = 0, width, height }: UpdateParams): this {
|
|
1248
|
+
const attrs = this.getChartState();
|
|
1249
|
+
|
|
1250
|
+
// Paging
|
|
1251
|
+
if (attrs.compact) {
|
|
1252
|
+
this.calculateCompactFlexDimensions(attrs.root!);
|
|
1253
|
+
}
|
|
1254
|
+
|
|
1255
|
+
// Assigns the x and y position for the nodes
|
|
1256
|
+
const treeData = attrs.flexTreeLayout!(attrs.root! as any);
|
|
1257
|
+
|
|
1258
|
+
// Reassigns the x and y position for the based on the compact layout
|
|
1259
|
+
if (attrs.compact) {
|
|
1260
|
+
this.calculateCompactFlexPositions(attrs.root!);
|
|
1261
|
+
}
|
|
1262
|
+
|
|
1263
|
+
const nodes = treeData.descendants() as unknown as OrgChartNode<Datum>[];
|
|
1264
|
+
|
|
1265
|
+
// console.table(nodes.map(d => ({ x: d.x, y: d.y, width: d.width, height: d.height, flexCompactDim: d.flexCompactDim + "" })))
|
|
1266
|
+
|
|
1267
|
+
// Get all links
|
|
1268
|
+
const links = treeData.descendants().slice(1);
|
|
1269
|
+
nodes.forEach((element) => {
|
|
1270
|
+
return attrs.layoutBindings[attrs.layout].swap(element);
|
|
1271
|
+
});
|
|
1272
|
+
|
|
1273
|
+
// Connections
|
|
1274
|
+
const connections = attrs.connections;
|
|
1275
|
+
const allNodesMap: any = {};
|
|
1276
|
+
attrs.allNodes!.forEach((d) => (allNodesMap[attrs.nodeId(d.data)] = d));
|
|
1277
|
+
|
|
1278
|
+
const visibleNodesMap: any = {};
|
|
1279
|
+
nodes.forEach((d) => (visibleNodesMap[attrs.nodeId(d.data)] = d));
|
|
1280
|
+
|
|
1281
|
+
connections.forEach((connection) => {
|
|
1282
|
+
const source = allNodesMap[connection.from];
|
|
1283
|
+
const target = allNodesMap[connection.to];
|
|
1284
|
+
connection._source = source;
|
|
1285
|
+
connection._target = target;
|
|
1286
|
+
});
|
|
1287
|
+
const visibleConnections = connections.filter((d) => visibleNodesMap[d.from] && visibleNodesMap[d.to]);
|
|
1288
|
+
const defsString = attrs.defs.bind(this)(attrs, visibleConnections);
|
|
1289
|
+
const existingString = attrs.defsWrapper!.html();
|
|
1290
|
+
if (defsString !== existingString) {
|
|
1291
|
+
attrs.defsWrapper!.html(defsString);
|
|
1292
|
+
}
|
|
1293
|
+
|
|
1294
|
+
// -------------------------- LINKS ----------------------
|
|
1295
|
+
// Get links selection
|
|
1296
|
+
const linkSelection = attrs.linksWrapper!.selectAll('path.link').data(links, (d: any) => attrs.nodeId(d.data));
|
|
1297
|
+
|
|
1298
|
+
// Enter any new links at the parent's previous position.
|
|
1299
|
+
const linkEnter = linkSelection
|
|
1300
|
+
.enter()
|
|
1301
|
+
.insert('path', 'g')
|
|
1302
|
+
.attr('class', 'link')
|
|
1303
|
+
.attr('d', (_d: any) => {
|
|
1304
|
+
const xo = attrs.layoutBindings[attrs.layout].linkJoinX({ x: x0, y: y0, width, height });
|
|
1305
|
+
const yo = attrs.layoutBindings[attrs.layout].linkJoinY({ x: x0, y: y0, width, height });
|
|
1306
|
+
const o = { x: xo, y: yo };
|
|
1307
|
+
return attrs.layoutBindings[attrs.layout].diagonal(o, o, o);
|
|
1308
|
+
});
|
|
1309
|
+
|
|
1310
|
+
// Get links update selection
|
|
1311
|
+
const linkUpdate = (linkEnter as any).merge(linkSelection);
|
|
1312
|
+
|
|
1313
|
+
// Styling links
|
|
1314
|
+
linkUpdate.attr('fill', 'none');
|
|
1315
|
+
|
|
1316
|
+
if (this.isEdge()) {
|
|
1317
|
+
linkUpdate.style('display', (d: any) => {
|
|
1318
|
+
const display = d.data._pagingButton ? 'none' : 'auto';
|
|
1319
|
+
return display;
|
|
1320
|
+
});
|
|
1321
|
+
} else {
|
|
1322
|
+
linkUpdate.attr('display', (d: any) => {
|
|
1323
|
+
const display = d.data._pagingButton ? 'none' : 'auto';
|
|
1324
|
+
return display;
|
|
1325
|
+
});
|
|
1326
|
+
}
|
|
1327
|
+
|
|
1328
|
+
// Allow external modifications
|
|
1329
|
+
linkUpdate.each(attrs.linkUpdate as any);
|
|
1330
|
+
|
|
1331
|
+
// Transition back to the parent element position
|
|
1332
|
+
linkUpdate
|
|
1333
|
+
.transition()
|
|
1334
|
+
.duration(attrs.duration)
|
|
1335
|
+
.attr('d', (d: any) => {
|
|
1336
|
+
const n =
|
|
1337
|
+
attrs.compact && d.flexCompactDim
|
|
1338
|
+
? {
|
|
1339
|
+
x: attrs.layoutBindings[attrs.layout].compactLinkMidX(d, attrs),
|
|
1340
|
+
y: attrs.layoutBindings[attrs.layout].compactLinkMidY(d, attrs),
|
|
1341
|
+
}
|
|
1342
|
+
: {
|
|
1343
|
+
x: attrs.layoutBindings[attrs.layout].linkX(d),
|
|
1344
|
+
y: attrs.layoutBindings[attrs.layout].linkY(d),
|
|
1345
|
+
};
|
|
1346
|
+
|
|
1347
|
+
const p = {
|
|
1348
|
+
x: attrs.layoutBindings[attrs.layout].linkParentX(d),
|
|
1349
|
+
y: attrs.layoutBindings[attrs.layout].linkParentY(d),
|
|
1350
|
+
};
|
|
1351
|
+
|
|
1352
|
+
const m =
|
|
1353
|
+
attrs.compact && d.flexCompactDim
|
|
1354
|
+
? {
|
|
1355
|
+
x: attrs.layoutBindings[attrs.layout].linkCompactXStart(d),
|
|
1356
|
+
y: attrs.layoutBindings[attrs.layout].linkCompactYStart(d),
|
|
1357
|
+
}
|
|
1358
|
+
: n;
|
|
1359
|
+
return attrs.layoutBindings[attrs.layout].diagonal(n, p, m, { sy: attrs.linkYOffset });
|
|
1360
|
+
});
|
|
1361
|
+
|
|
1362
|
+
// Remove any links which is exiting after animation
|
|
1363
|
+
linkSelection
|
|
1364
|
+
.exit()
|
|
1365
|
+
.transition()
|
|
1366
|
+
.duration(attrs.duration)
|
|
1367
|
+
.attr('d', (_d: any) => {
|
|
1368
|
+
const xo = attrs.layoutBindings[attrs.layout].linkJoinX({ x, y, width, height });
|
|
1369
|
+
const yo = attrs.layoutBindings[attrs.layout].linkJoinY({ x, y, width, height });
|
|
1370
|
+
const o = { x: xo, y: yo };
|
|
1371
|
+
return attrs.layoutBindings[attrs.layout].diagonal(o, o, null, { sy: attrs.linkYOffset });
|
|
1372
|
+
})
|
|
1373
|
+
.remove();
|
|
1374
|
+
|
|
1375
|
+
// -------------------------- CONNECTIONS ----------------------
|
|
1376
|
+
|
|
1377
|
+
const connectionsSel = attrs.connectionsWrapper!.selectAll('path.connection').data(visibleConnections);
|
|
1378
|
+
|
|
1379
|
+
// Enter any new connections at the parent's previous position.
|
|
1380
|
+
const connEnter = connectionsSel
|
|
1381
|
+
.enter()
|
|
1382
|
+
.insert('path', 'g')
|
|
1383
|
+
.attr('class', 'connection')
|
|
1384
|
+
.attr('d', (_d: any) => {
|
|
1385
|
+
const xo = attrs.layoutBindings[attrs.layout].linkJoinX({ x: x0, y: y0, width, height });
|
|
1386
|
+
const yo = attrs.layoutBindings[attrs.layout].linkJoinY({ x: x0, y: y0, width, height });
|
|
1387
|
+
const o = { x: xo, y: yo };
|
|
1388
|
+
return attrs.layoutBindings[attrs.layout].diagonal(o, o, null, { sy: attrs.linkYOffset });
|
|
1389
|
+
});
|
|
1390
|
+
|
|
1391
|
+
// Get connections update selection
|
|
1392
|
+
const connUpdate = (connEnter as any).merge(connectionsSel);
|
|
1393
|
+
|
|
1394
|
+
// Styling connections
|
|
1395
|
+
(connUpdate as any).attr('fill', 'none');
|
|
1396
|
+
|
|
1397
|
+
// Transition back to the parent element position
|
|
1398
|
+
connUpdate
|
|
1399
|
+
.transition()
|
|
1400
|
+
.duration(attrs.duration)
|
|
1401
|
+
.attr('d', (d: any) => {
|
|
1402
|
+
const xs = attrs.layoutBindings[attrs.layout].linkX({ x: d._source.x, y: d._source.y, width: d._source.width, height: d._source.height } as any);
|
|
1403
|
+
const ys = attrs.layoutBindings[attrs.layout].linkY({ x: d._source.x, y: d._source.y, width: d._source.width, height: d._source.height } as any);
|
|
1404
|
+
const xt = attrs.layoutBindings[attrs.layout].linkJoinX({ x: d._target.x, y: d._target.y, width: d._target.width, height: d._target.height } as any);
|
|
1405
|
+
const yt = attrs.layoutBindings[attrs.layout].linkJoinY({ x: d._target.x, y: d._target.y, width: d._target.width, height: d._target.height } as any);
|
|
1406
|
+
return attrs.linkGroupArc({ source: { x: xs, y: ys }, target: { x: xt, y: yt } });
|
|
1407
|
+
});
|
|
1408
|
+
|
|
1409
|
+
// Allow external modifications
|
|
1410
|
+
connUpdate.each(attrs.connectionsUpdate);
|
|
1411
|
+
|
|
1412
|
+
// Remove any links which is exiting after animation
|
|
1413
|
+
connectionsSel.exit().transition().duration(attrs.duration).attr('opacity', 0).remove();
|
|
1414
|
+
|
|
1415
|
+
// -------------------------- NODES ----------------------
|
|
1416
|
+
// Get nodes selection
|
|
1417
|
+
const nodesSelection = attrs.nodesWrapper!.selectAll('g.node').data(nodes, (d: any) => attrs.nodeId(d.data));
|
|
1418
|
+
|
|
1419
|
+
// Enter any new nodes at the parent's previous position.
|
|
1420
|
+
const nodeEnter: any = nodesSelection
|
|
1421
|
+
.enter()
|
|
1422
|
+
.append('g')
|
|
1423
|
+
.attr('class', 'node')
|
|
1424
|
+
.attr('transform', (d: any) => {
|
|
1425
|
+
if (d == attrs.root) return `translate(${x0},${y0})`;
|
|
1426
|
+
const xj = attrs.layoutBindings[attrs.layout].nodeJoinX({ x: x0, y: y0, width, height });
|
|
1427
|
+
const yj = attrs.layoutBindings[attrs.layout].nodeJoinY({ x: x0, y: y0, width, height });
|
|
1428
|
+
return `translate(${xj},${yj})`;
|
|
1429
|
+
})
|
|
1430
|
+
.attr('cursor', 'pointer')
|
|
1431
|
+
.on('click.node', (event: any, node: any) => {
|
|
1432
|
+
const { data } = node;
|
|
1433
|
+
if ([...event.srcElement.classList].includes('node-button-foreign-object')) {
|
|
1434
|
+
return;
|
|
1435
|
+
}
|
|
1436
|
+
if ([...event.srcElement.classList].includes('paging-button-wrapper')) {
|
|
1437
|
+
this.loadPagingNodes(node);
|
|
1438
|
+
return;
|
|
1439
|
+
}
|
|
1440
|
+
if (!data._pagingButton) {
|
|
1441
|
+
attrs.onNodeClick(node);
|
|
1442
|
+
}
|
|
1443
|
+
})
|
|
1444
|
+
// Event handler to the expand button
|
|
1445
|
+
.on('keydown.node', (event, node) => {
|
|
1446
|
+
const { data: _data } = node;
|
|
1447
|
+
if (event.key === 'Enter' || event.key === ' ' || event.key === 'Spacebar') {
|
|
1448
|
+
if ([...event.srcElement.classList].includes('node-button-foreign-object')) {
|
|
1449
|
+
return;
|
|
1450
|
+
}
|
|
1451
|
+
if ([...event.srcElement.classList].includes('paging-button-wrapper')) {
|
|
1452
|
+
this.loadPagingNodes(node);
|
|
1453
|
+
return;
|
|
1454
|
+
}
|
|
1455
|
+
if (event.key === 'Enter' || event.key === ' ' || event.key === 'Spacebar') {
|
|
1456
|
+
this.onButtonClick(event, node);
|
|
1457
|
+
}
|
|
1458
|
+
}
|
|
1459
|
+
});
|
|
1460
|
+
nodeEnter.each(attrs.nodeEnter);
|
|
1461
|
+
|
|
1462
|
+
// Add background rectangle for the nodes
|
|
1463
|
+
nodeEnter.patternify({
|
|
1464
|
+
tag: 'rect',
|
|
1465
|
+
selector: 'node-rect',
|
|
1466
|
+
data: ((d: any) => [d]) as any,
|
|
1467
|
+
});
|
|
1468
|
+
|
|
1469
|
+
// Node update styles
|
|
1470
|
+
const nodeUpdate = nodeEnter.merge(nodesSelection).style('font', '12px sans-serif');
|
|
1471
|
+
|
|
1472
|
+
// Add foreignObject element inside rectangle
|
|
1473
|
+
const fo = nodeUpdate
|
|
1474
|
+
.patternify({
|
|
1475
|
+
tag: 'foreignObject',
|
|
1476
|
+
selector: 'node-foreign-object',
|
|
1477
|
+
data: (d: any) => [d],
|
|
1478
|
+
})
|
|
1479
|
+
.style('overflow', 'visible');
|
|
1480
|
+
|
|
1481
|
+
// Add foreign object
|
|
1482
|
+
fo.patternify({
|
|
1483
|
+
tag: 'xhtml:div',
|
|
1484
|
+
selector: 'node-foreign-object-div',
|
|
1485
|
+
data: (d: any) => [d],
|
|
1486
|
+
});
|
|
1487
|
+
|
|
1488
|
+
this.restyleForeignObjectElements();
|
|
1489
|
+
|
|
1490
|
+
// Add Node button circle's group (expand-collapse button)
|
|
1491
|
+
const nodeButtonGroups = nodeEnter
|
|
1492
|
+
.patternify({
|
|
1493
|
+
tag: 'g',
|
|
1494
|
+
selector: 'node-button-g',
|
|
1495
|
+
data: (d: any) => [d],
|
|
1496
|
+
})
|
|
1497
|
+
.on('click', (event: any, d: OrgChartNode<Datum>) => this.onButtonClick(event, d))
|
|
1498
|
+
.on('keydown', (event: { key: string }, d: OrgChartNode<Datum>) => {
|
|
1499
|
+
if (event.key === 'Enter' || event.key === ' ' || event.key === 'Spacebar') {
|
|
1500
|
+
this.onButtonClick(event, d);
|
|
1501
|
+
}
|
|
1502
|
+
});
|
|
1503
|
+
|
|
1504
|
+
nodeButtonGroups
|
|
1505
|
+
.patternify({
|
|
1506
|
+
tag: 'rect',
|
|
1507
|
+
selector: 'node-button-rect',
|
|
1508
|
+
data: ((d: any) => [d]) as any,
|
|
1509
|
+
})
|
|
1510
|
+
.attr('opacity', 0)
|
|
1511
|
+
.attr('pointer-events', 'all')
|
|
1512
|
+
.attr('width', (d: any) => attrs.nodeButtonWidth(d))
|
|
1513
|
+
.attr('height', (d: any) => attrs.nodeButtonHeight(d))
|
|
1514
|
+
.attr('x', (d: any) => attrs.nodeButtonX(d))
|
|
1515
|
+
.attr('y', (d: any) => attrs.nodeButtonY(d));
|
|
1516
|
+
|
|
1517
|
+
// Add expand collapse button content
|
|
1518
|
+
nodeButtonGroups
|
|
1519
|
+
.patternify({
|
|
1520
|
+
tag: 'foreignObject',
|
|
1521
|
+
selector: 'node-button-foreign-object',
|
|
1522
|
+
data: (d: any) => [d],
|
|
1523
|
+
})
|
|
1524
|
+
.attr('width', (d: any) => attrs.nodeButtonWidth(d))
|
|
1525
|
+
.attr('height', (d: any) => attrs.nodeButtonHeight(d))
|
|
1526
|
+
.attr('x', (d: any) => attrs.nodeButtonX(d))
|
|
1527
|
+
.attr('y', (d: any) => attrs.nodeButtonY(d))
|
|
1528
|
+
.style('overflow', 'visible')
|
|
1529
|
+
.patternify({
|
|
1530
|
+
tag: 'xhtml:div',
|
|
1531
|
+
selector: 'node-button-div',
|
|
1532
|
+
data: ((d: any) => [d]) as any,
|
|
1533
|
+
})
|
|
1534
|
+
.style('pointer-events', 'none')
|
|
1535
|
+
.style('display', 'flex')
|
|
1536
|
+
.style('width', '100%')
|
|
1537
|
+
.style('height', '100%');
|
|
1538
|
+
|
|
1539
|
+
// Transition to the proper position for the node
|
|
1540
|
+
nodeUpdate
|
|
1541
|
+
.transition()
|
|
1542
|
+
.attr('opacity', 0)
|
|
1543
|
+
.duration(attrs.duration)
|
|
1544
|
+
.attr('transform', ({ x, y, width, height }: { x: any; y: any; width: any; height: any }) => {
|
|
1545
|
+
return attrs.layoutBindings[attrs.layout].nodeUpdateTransform({ x, y, width, height } as any, attrs);
|
|
1546
|
+
})
|
|
1547
|
+
.attr('opacity', 1);
|
|
1548
|
+
|
|
1549
|
+
// Style node rectangles
|
|
1550
|
+
nodeUpdate
|
|
1551
|
+
.select('.node-rect')
|
|
1552
|
+
.attr('width', (d: any) => d.width)
|
|
1553
|
+
.attr('height', (d: any) => d.height)
|
|
1554
|
+
.attr('x', (_d: any) => 0)
|
|
1555
|
+
.attr('y', (_d: any) => 0)
|
|
1556
|
+
.attr('cursor', 'pointer')
|
|
1557
|
+
.attr('rx', 3)
|
|
1558
|
+
.attr('fill', attrs.nodeDefaultBackground);
|
|
1559
|
+
|
|
1560
|
+
nodeUpdate
|
|
1561
|
+
.select('.node-button-g')
|
|
1562
|
+
.attr('transform', (d: any) => {
|
|
1563
|
+
const x = attrs.layoutBindings[attrs.layout].buttonX(d);
|
|
1564
|
+
const y = attrs.layoutBindings[attrs.layout].buttonY(d);
|
|
1565
|
+
return `translate(${x},${y})`;
|
|
1566
|
+
})
|
|
1567
|
+
.attr('display', ({ data }: { data: any }) => {
|
|
1568
|
+
return data._directSubordinates > 0 ? null : 'none';
|
|
1569
|
+
})
|
|
1570
|
+
.attr('opacity', (d: any) => {
|
|
1571
|
+
if (d.data._pagingButton) {
|
|
1572
|
+
return 0;
|
|
1573
|
+
}
|
|
1574
|
+
if (d.children || d._children) {
|
|
1575
|
+
return 1;
|
|
1576
|
+
}
|
|
1577
|
+
return 0;
|
|
1578
|
+
});
|
|
1579
|
+
|
|
1580
|
+
// Restyle node button circle
|
|
1581
|
+
nodeUpdate.select('.node-button-foreign-object .node-button-div').html((node: any) => {
|
|
1582
|
+
return attrs.buttonContent({ node, state: attrs });
|
|
1583
|
+
});
|
|
1584
|
+
|
|
1585
|
+
// Restyle button texts
|
|
1586
|
+
nodeUpdate
|
|
1587
|
+
.select('.node-button-text')
|
|
1588
|
+
.attr('text-anchor', 'middle')
|
|
1589
|
+
.attr('alignment-baseline', 'middle')
|
|
1590
|
+
.attr('font-size', ({ children }: { children: any }) => {
|
|
1591
|
+
if (children) return 40;
|
|
1592
|
+
return 26;
|
|
1593
|
+
})
|
|
1594
|
+
.text(({ children }: { children: any }) => {
|
|
1595
|
+
if (children) return '-';
|
|
1596
|
+
return '+';
|
|
1597
|
+
})
|
|
1598
|
+
.attr('y', this.isEdge() ? 10 : 0);
|
|
1599
|
+
|
|
1600
|
+
nodeUpdate.each(attrs.nodeUpdate as any);
|
|
1601
|
+
|
|
1602
|
+
// Remove any exiting nodes after transition
|
|
1603
|
+
const nodeExitTransition = nodesSelection.exit();
|
|
1604
|
+
nodeExitTransition.each(attrs.nodeExit as any);
|
|
1605
|
+
|
|
1606
|
+
const maxDepthNode: any = nodeExitTransition.data().reduce((a: any, b: any) => (a.depth < b.depth ? a : b), { depth: Infinity });
|
|
1607
|
+
|
|
1608
|
+
nodeExitTransition
|
|
1609
|
+
.attr('opacity', 1)
|
|
1610
|
+
.transition()
|
|
1611
|
+
.duration(attrs.duration)
|
|
1612
|
+
.attr('transform', (_d: any) => {
|
|
1613
|
+
const { x, y, width, height } = maxDepthNode.parent || {};
|
|
1614
|
+
const ex = attrs.layoutBindings[attrs.layout].nodeJoinX({ x, y, width, height } as any);
|
|
1615
|
+
const ey = attrs.layoutBindings[attrs.layout].nodeJoinY({ x, y, width, height } as any);
|
|
1616
|
+
return `translate(${ex},${ey})`;
|
|
1617
|
+
})
|
|
1618
|
+
.on('end', function () {
|
|
1619
|
+
d3.select(this).remove();
|
|
1620
|
+
})
|
|
1621
|
+
.attr('opacity', 0);
|
|
1622
|
+
|
|
1623
|
+
// Store the old positions for transition.
|
|
1624
|
+
nodes.forEach((d: any) => {
|
|
1625
|
+
d.x0 = d.x;
|
|
1626
|
+
d.y0 = d.y;
|
|
1627
|
+
});
|
|
1628
|
+
|
|
1629
|
+
// CHECK FOR CENTERING
|
|
1630
|
+
const centeredNode = attrs.allNodes!.find((d) => d.data._centered);
|
|
1631
|
+
if (centeredNode) {
|
|
1632
|
+
let centeredNodes = [centeredNode];
|
|
1633
|
+
if (centeredNode.data._centeredWithDescendants) {
|
|
1634
|
+
if (attrs.compact) {
|
|
1635
|
+
centeredNodes = centeredNode.descendants().filter((_, i) => i < 7);
|
|
1636
|
+
} else {
|
|
1637
|
+
centeredNodes = centeredNode.descendants().filter((_, i, arr) => {
|
|
1638
|
+
const h = Math.round(arr.length / 2);
|
|
1639
|
+
const spread = 2;
|
|
1640
|
+
if (arr.length % 2) {
|
|
1641
|
+
return i > h - spread && i < h + spread - 1;
|
|
1642
|
+
}
|
|
1643
|
+
|
|
1644
|
+
return i > h - spread && i < h + spread;
|
|
1645
|
+
});
|
|
1646
|
+
}
|
|
1647
|
+
}
|
|
1648
|
+
centeredNode.data._centeredWithDescendants = undefined;
|
|
1649
|
+
centeredNode.data._centered = undefined;
|
|
1650
|
+
this.fit({
|
|
1651
|
+
animate: true,
|
|
1652
|
+
scale: false,
|
|
1653
|
+
nodes: centeredNodes,
|
|
1654
|
+
});
|
|
1655
|
+
}
|
|
1656
|
+
|
|
1657
|
+
return this;
|
|
1658
|
+
}
|
|
1659
|
+
|
|
1660
|
+
// This function detects whether current browser is edge
|
|
1661
|
+
isEdge(): boolean {
|
|
1662
|
+
return globalThis.navigator.userAgent.includes('Edge');
|
|
1663
|
+
}
|
|
1664
|
+
|
|
1665
|
+
// Generate horizontal diagonal - play with it here - https://observablehq.com/@bumbeishvili/curved-edges-horizontal-d3-v3-v4-v5-v6
|
|
1666
|
+
hdiagonal(s: Point, t: Point, m?: Point | null, offsets?: any): string {
|
|
1667
|
+
const state = this.getChartState();
|
|
1668
|
+
return state.hdiagonal!(s, t, m, offsets);
|
|
1669
|
+
}
|
|
1670
|
+
|
|
1671
|
+
// Generate custom diagonal - play with it here - https://observablehiq.com/@bumbeishvili/curved-edges
|
|
1672
|
+
diagonal(s: Point, t: Point, m?: Point | null, offsets?: any): string {
|
|
1673
|
+
const state = this.getChartState();
|
|
1674
|
+
return state.diagonal!(s, t, m, offsets);
|
|
1675
|
+
}
|
|
1676
|
+
|
|
1677
|
+
restyleForeignObjectElements(): void {
|
|
1678
|
+
const attrs = this.getChartState();
|
|
1679
|
+
|
|
1680
|
+
attrs
|
|
1681
|
+
.svg!.selectAll('.node-foreign-object')
|
|
1682
|
+
.attr('width', (d: any) => d.width)
|
|
1683
|
+
.attr('height', (d: any) => d.height)
|
|
1684
|
+
.attr('x', (_d: any) => 0)
|
|
1685
|
+
.attr('y', (_d: any) => 0);
|
|
1686
|
+
attrs
|
|
1687
|
+
.svg!.selectAll('.node-foreign-object-div')
|
|
1688
|
+
.style('width', (d: any) => `${d.width}px`)
|
|
1689
|
+
.style('height', (d: any) => `${d.height}px`)
|
|
1690
|
+
.html(function (this: any, d: any, i: number, arr: any) {
|
|
1691
|
+
if (d.data._pagingButton) {
|
|
1692
|
+
return `<div class="paging-button-wrapper"><div style="pointer-events:none">${attrs.pagingButton(d, i, arr, attrs)}</div></div>`;
|
|
1693
|
+
}
|
|
1694
|
+
return vnodeToHTML(attrs.nodeContent.bind(this)(d));
|
|
1695
|
+
});
|
|
1696
|
+
}
|
|
1697
|
+
|
|
1698
|
+
// Toggle children on click.
|
|
1699
|
+
onButtonClick(event: any, d: OrgChartNode<Datum>): void {
|
|
1700
|
+
const attrs = this.getChartState();
|
|
1701
|
+
if (d.data._pagingButton) {
|
|
1702
|
+
return;
|
|
1703
|
+
}
|
|
1704
|
+
if (attrs.setActiveNodeCentered) {
|
|
1705
|
+
(d.data as any)._centered = true;
|
|
1706
|
+
(d.data as any)._centeredWithDescendants = true;
|
|
1707
|
+
}
|
|
1708
|
+
|
|
1709
|
+
// If childrens are expanded
|
|
1710
|
+
if (d.children) {
|
|
1711
|
+
//Collapse them
|
|
1712
|
+
d._children = d.children;
|
|
1713
|
+
d.children = undefined;
|
|
1714
|
+
|
|
1715
|
+
// Set descendants expanded property to false
|
|
1716
|
+
this.setExpansionFlagToChildren(d, false);
|
|
1717
|
+
} else {
|
|
1718
|
+
// Expand children
|
|
1719
|
+
d.children = d._children;
|
|
1720
|
+
d._children = undefined;
|
|
1721
|
+
|
|
1722
|
+
// Set each children as expanded
|
|
1723
|
+
if (d.children) {
|
|
1724
|
+
d.children.forEach(({ data }) => ((data as any)._expanded = true));
|
|
1725
|
+
}
|
|
1726
|
+
}
|
|
1727
|
+
|
|
1728
|
+
// Redraw Graph
|
|
1729
|
+
this.update({ x0: d.x0 || 0, y0: d.y0 || 0, width: d.width, height: d.height });
|
|
1730
|
+
event.stopPropagation();
|
|
1731
|
+
|
|
1732
|
+
// Trigger callback
|
|
1733
|
+
attrs.onExpandOrCollapse(d);
|
|
1734
|
+
}
|
|
1735
|
+
|
|
1736
|
+
// This function changes `expanded` property to descendants
|
|
1737
|
+
setExpansionFlagToChildren({ data, children, _children }: OrgChartNode<Datum>, flag: boolean): void {
|
|
1738
|
+
// Set flag to the current property
|
|
1739
|
+
(data as any)._expanded = flag;
|
|
1740
|
+
|
|
1741
|
+
// Loop over and recursively update expanded children's descendants
|
|
1742
|
+
if (children) {
|
|
1743
|
+
children.forEach((d) => {
|
|
1744
|
+
this.setExpansionFlagToChildren(d, flag);
|
|
1745
|
+
});
|
|
1746
|
+
}
|
|
1747
|
+
|
|
1748
|
+
// Loop over and recursively update collapsed children's descendants
|
|
1749
|
+
if (_children) {
|
|
1750
|
+
_children.forEach((d) => {
|
|
1751
|
+
this.setExpansionFlagToChildren(d, flag);
|
|
1752
|
+
});
|
|
1753
|
+
}
|
|
1754
|
+
}
|
|
1755
|
+
|
|
1756
|
+
// Method which only expands nodes, which have property set "expanded=true"
|
|
1757
|
+
expandSomeNodes(d: OrgChartNode<Datum>): void {
|
|
1758
|
+
// If node has expanded property set
|
|
1759
|
+
if ((d.data as any)._expanded) {
|
|
1760
|
+
// Retrieve node's parent
|
|
1761
|
+
let parent = d.parent;
|
|
1762
|
+
|
|
1763
|
+
// While we can go up
|
|
1764
|
+
while (parent && parent._children) {
|
|
1765
|
+
// Expand all current parent's children
|
|
1766
|
+
parent.children = parent._children;
|
|
1767
|
+
parent._children = undefined;
|
|
1768
|
+
// Replace current parent holding object
|
|
1769
|
+
parent = parent.parent;
|
|
1770
|
+
}
|
|
1771
|
+
}
|
|
1772
|
+
|
|
1773
|
+
// Recursively do the same for collapsed nodes
|
|
1774
|
+
if (d._children) {
|
|
1775
|
+
d._children.forEach((ch) => this.expandSomeNodes(ch));
|
|
1776
|
+
}
|
|
1777
|
+
|
|
1778
|
+
// Recursively do the same for expanded nodes
|
|
1779
|
+
if (d.children) {
|
|
1780
|
+
d.children.forEach((ch) => this.expandSomeNodes(ch));
|
|
1781
|
+
}
|
|
1782
|
+
}
|
|
1783
|
+
|
|
1784
|
+
// This function updates nodes state and redraws graph, usually after data change
|
|
1785
|
+
updateNodesState(): void {
|
|
1786
|
+
const attrs = this.getChartState();
|
|
1787
|
+
|
|
1788
|
+
this.setLayouts({ expandNodesFirst: true });
|
|
1789
|
+
|
|
1790
|
+
// Redraw Graphs
|
|
1791
|
+
const root = attrs.root!;
|
|
1792
|
+
this.update({ x0: root.x0 || 0, y0: root.y0 || 0, width: root.width, height: root.height });
|
|
1793
|
+
}
|
|
1794
|
+
|
|
1795
|
+
setLayouts({ expandNodesFirst = true }: { expandNodesFirst?: boolean }): void {
|
|
1796
|
+
const attrs = this.getChartState();
|
|
1797
|
+
// Store new root by converting flat data to hierarchy
|
|
1798
|
+
|
|
1799
|
+
const stratify = d3
|
|
1800
|
+
.stratify<Datum>()
|
|
1801
|
+
.id((d) => attrs.nodeId(d as any) as string)
|
|
1802
|
+
.parentId((d) => attrs.parentNodeId(d as any) as string);
|
|
1803
|
+
|
|
1804
|
+
attrs.generateRoot = (data: Datum[]) => stratify(data as any) as any as OrgChartNode<Datum>;
|
|
1805
|
+
attrs.root = attrs.generateRoot(attrs.data || []);
|
|
1806
|
+
|
|
1807
|
+
const descendantsBefore = attrs.root.descendants();
|
|
1808
|
+
if (attrs.initialExpandLevel > 1 && descendantsBefore.length > 0) {
|
|
1809
|
+
descendantsBefore.forEach((d) => {
|
|
1810
|
+
if (d.depth <= attrs.initialExpandLevel) {
|
|
1811
|
+
(d.data as any)._expanded = true;
|
|
1812
|
+
}
|
|
1813
|
+
});
|
|
1814
|
+
attrs.initialExpandLevel = 1;
|
|
1815
|
+
}
|
|
1816
|
+
|
|
1817
|
+
const hiddenNodesMap: Record<string, boolean> = {};
|
|
1818
|
+
attrs.root
|
|
1819
|
+
.descendants()
|
|
1820
|
+
.filter((node) => node.children)
|
|
1821
|
+
.filter((node) => !node.data._pagingStep)
|
|
1822
|
+
.forEach((node) => {
|
|
1823
|
+
node.data._pagingStep = attrs.minPagingVisibleNodes(node);
|
|
1824
|
+
});
|
|
1825
|
+
|
|
1826
|
+
attrs.root.eachBefore((node: OrgChartNode, _i: number) => {
|
|
1827
|
+
node.data._directSubordinatesPaging = node.children ? node.children.length : 0;
|
|
1828
|
+
if (node.children) {
|
|
1829
|
+
node.children.forEach((child: OrgChartNode, j: number) => {
|
|
1830
|
+
child.data._pagingButton = false;
|
|
1831
|
+
if (j > node.data._pagingStep!) {
|
|
1832
|
+
hiddenNodesMap[child.id as string] = true;
|
|
1833
|
+
}
|
|
1834
|
+
if (j === node.data._pagingStep && node.children!.length - 1 > node.data._pagingStep!) {
|
|
1835
|
+
child.data._pagingButton = true;
|
|
1836
|
+
}
|
|
1837
|
+
if (child.parent && hiddenNodesMap[child.parent.id as string]) {
|
|
1838
|
+
hiddenNodesMap[child.id as string] = true;
|
|
1839
|
+
}
|
|
1840
|
+
if (child.data._expanded || child.data._centered || child.data._highlighted || child.data._upToTheRootHighlighted) {
|
|
1841
|
+
let localNode: OrgChartNode | null = child;
|
|
1842
|
+
while (localNode && (hiddenNodesMap[localNode.id as string] || localNode.data._pagingButton)) {
|
|
1843
|
+
hiddenNodesMap[localNode.id as string] = false;
|
|
1844
|
+
if (localNode.data._pagingButton) {
|
|
1845
|
+
localNode.data._pagingButton = false;
|
|
1846
|
+
localNode.parent?.children?.forEach((ch: OrgChartNode) => {
|
|
1847
|
+
ch.data._expanded = true;
|
|
1848
|
+
hiddenNodesMap[ch.id as string] = false;
|
|
1849
|
+
});
|
|
1850
|
+
}
|
|
1851
|
+
localNode = localNode.parent;
|
|
1852
|
+
}
|
|
1853
|
+
}
|
|
1854
|
+
});
|
|
1855
|
+
}
|
|
1856
|
+
});
|
|
1857
|
+
|
|
1858
|
+
attrs.root = d3
|
|
1859
|
+
.stratify<Datum>()
|
|
1860
|
+
.id((d) => attrs.nodeId(d as any) as string)
|
|
1861
|
+
.parentId((d) => attrs.parentNodeId(d as any) as string)(attrs.data!.filter((d) => hiddenNodesMap[attrs.nodeId(d as any) as string] !== true) as any) as any as OrgChartNode<Datum>;
|
|
1862
|
+
|
|
1863
|
+
attrs.root.each((node: OrgChartNode, _i: number, _thisNode: OrgChartNode) => {
|
|
1864
|
+
const _hierarchyHeight = (node as any)._hierarchyHeight || node.height;
|
|
1865
|
+
const width = attrs.nodeWidth(node);
|
|
1866
|
+
const height = attrs.nodeHeight(node);
|
|
1867
|
+
Object.assign(node, { width, height, _hierarchyHeight });
|
|
1868
|
+
});
|
|
1869
|
+
|
|
1870
|
+
// Store positions, where children appear during their enter animation
|
|
1871
|
+
attrs.root.x0 = 0;
|
|
1872
|
+
attrs.root.y0 = 0;
|
|
1873
|
+
attrs.allNodes = attrs.root.descendants();
|
|
1874
|
+
|
|
1875
|
+
// Store direct and total descendants count
|
|
1876
|
+
attrs.allNodes.forEach((d) => {
|
|
1877
|
+
Object.assign(d.data, {
|
|
1878
|
+
_directSubordinates: d.children ? d.children.length : 0,
|
|
1879
|
+
_totalSubordinates: d.descendants().length - 1,
|
|
1880
|
+
});
|
|
1881
|
+
});
|
|
1882
|
+
|
|
1883
|
+
if (attrs.root.children) {
|
|
1884
|
+
if (expandNodesFirst) {
|
|
1885
|
+
// Expand all nodes first
|
|
1886
|
+
attrs.root.children.forEach(this.expand);
|
|
1887
|
+
}
|
|
1888
|
+
// Then collapse them all
|
|
1889
|
+
attrs.root.children.forEach((d) => this.collapse(d));
|
|
1890
|
+
|
|
1891
|
+
// Collapse root if level is 0
|
|
1892
|
+
if (attrs.initialExpandLevel == 0) {
|
|
1893
|
+
attrs.root._children = attrs.root.children;
|
|
1894
|
+
attrs.root.children = undefined;
|
|
1895
|
+
}
|
|
1896
|
+
|
|
1897
|
+
// Then only expand nodes, which have expanded property set to true
|
|
1898
|
+
if (attrs.root) {
|
|
1899
|
+
[attrs.root].forEach((ch) => this.expandSomeNodes(ch));
|
|
1900
|
+
}
|
|
1901
|
+
}
|
|
1902
|
+
}
|
|
1903
|
+
|
|
1904
|
+
// Function which collapses passed node and it's descendants
|
|
1905
|
+
collapse(d: OrgChartNode): this {
|
|
1906
|
+
if (d.children) {
|
|
1907
|
+
d._children = d.children;
|
|
1908
|
+
d._children.forEach((ch) => this.collapse(ch));
|
|
1909
|
+
d.children = undefined;
|
|
1910
|
+
}
|
|
1911
|
+
return this;
|
|
1912
|
+
}
|
|
1913
|
+
|
|
1914
|
+
// Function which expands passed node and it's descendants
|
|
1915
|
+
expand(d: OrgChartNode): this {
|
|
1916
|
+
if (d._children) {
|
|
1917
|
+
d.children = d._children;
|
|
1918
|
+
d.children.forEach((ch) => this.expand(ch));
|
|
1919
|
+
d._children = undefined;
|
|
1920
|
+
}
|
|
1921
|
+
return this;
|
|
1922
|
+
}
|
|
1923
|
+
|
|
1924
|
+
// Zoom handler function
|
|
1925
|
+
zoomed(event: D3ZoomEvent<SVGSVGElement, OrgChartNodeData>, _d?: OrgChartNode): void {
|
|
1926
|
+
const attrs = this.getChartState();
|
|
1927
|
+
const chart = attrs.chart!;
|
|
1928
|
+
|
|
1929
|
+
// Get d3 event's transform object
|
|
1930
|
+
const transform = event.transform;
|
|
1931
|
+
|
|
1932
|
+
// Store it
|
|
1933
|
+
attrs.lastTransform = transform;
|
|
1934
|
+
|
|
1935
|
+
// Reposition and rescale chart accordingly
|
|
1936
|
+
chart.attr('transform', transform.toString());
|
|
1937
|
+
|
|
1938
|
+
// Apply new styles to the foreign object element
|
|
1939
|
+
if (this.isEdge()) {
|
|
1940
|
+
this.restyleForeignObjectElements();
|
|
1941
|
+
}
|
|
1942
|
+
}
|
|
1943
|
+
|
|
1944
|
+
zoomTreeBounds({ x0, x1, y0, y1, params = { animate: true, scale: true, onCompleted: () => {} } }: ZoomToBoundsParams): void {
|
|
1945
|
+
const { centerG, svgWidth: w, svgHeight: h, svg, zoomBehavior, duration, lastTransform } = this.getChartState();
|
|
1946
|
+
const scaleVal = Math.min(8, 0.9 / Math.max((x1 - x0) / w, (y1 - y0) / h));
|
|
1947
|
+
let identity = d3.zoomIdentity.translate(w / 2, h / 2);
|
|
1948
|
+
identity = identity.scale(params?.scale ? scaleVal : lastTransform.k);
|
|
1949
|
+
|
|
1950
|
+
identity = identity.translate(-(x0 + x1) / 2, -(y0 + y1) / 2);
|
|
1951
|
+
// Transition zoom wrapper component into specified bounds
|
|
1952
|
+
(svg!.transition().duration(params?.animate ? duration : 0) as any).call(zoomBehavior!.transform, identity);
|
|
1953
|
+
centerG!
|
|
1954
|
+
.transition()
|
|
1955
|
+
.duration(params?.animate ? duration : 0)
|
|
1956
|
+
.attr('transform', 'translate(0,0)')
|
|
1957
|
+
.on('end', function () {
|
|
1958
|
+
if (params?.onCompleted) {
|
|
1959
|
+
params.onCompleted();
|
|
1960
|
+
}
|
|
1961
|
+
});
|
|
1962
|
+
}
|
|
1963
|
+
|
|
1964
|
+
fit({ animate = true, nodes, scale = true, onCompleted = () => {} }: FitParams = {}): this {
|
|
1965
|
+
const attrs = this.getChartState();
|
|
1966
|
+
const { root } = attrs;
|
|
1967
|
+
const descendants = nodes ?? root!.descendants();
|
|
1968
|
+
const minX = d3.min(descendants, (d) => d.x + attrs.layoutBindings[attrs.layout].nodeLeftX(d)) || 0;
|
|
1969
|
+
const maxX = d3.max(descendants, (d) => d.x + attrs.layoutBindings[attrs.layout].nodeRightX(d)) || 0;
|
|
1970
|
+
const minY = d3.min(descendants, (d) => d.y + attrs.layoutBindings[attrs.layout].nodeTopY(d)) || 0;
|
|
1971
|
+
const maxY = d3.max(descendants, (d) => d.y + attrs.layoutBindings[attrs.layout].nodeBottomY(d)) || 0;
|
|
1972
|
+
|
|
1973
|
+
this.zoomTreeBounds({
|
|
1974
|
+
params: { animate: animate, scale, onCompleted },
|
|
1975
|
+
x0: minX - 50,
|
|
1976
|
+
x1: maxX + 50,
|
|
1977
|
+
y0: minY - 50,
|
|
1978
|
+
y1: maxY + 50,
|
|
1979
|
+
});
|
|
1980
|
+
return this;
|
|
1981
|
+
}
|
|
1982
|
+
|
|
1983
|
+
// Load Paging Nodes
|
|
1984
|
+
loadPagingNodes(node: OrgChartNode): void {
|
|
1985
|
+
const attrs = this.getChartState();
|
|
1986
|
+
node.data._pagingButton = false;
|
|
1987
|
+
const current = node.parent!.data._pagingStep!;
|
|
1988
|
+
const step = attrs.pagingStep(node.parent!);
|
|
1989
|
+
const newPagingIndex = current + step;
|
|
1990
|
+
node.parent!.data._pagingStep = newPagingIndex;
|
|
1991
|
+
this.updateNodesState();
|
|
1992
|
+
}
|
|
1993
|
+
|
|
1994
|
+
// This function can be invoked via chart.setExpanded API, it expands or collapses particular node
|
|
1995
|
+
setExpanded(id: string | number, expandedFlag: boolean = true): this {
|
|
1996
|
+
const attrs = this.getChartState();
|
|
1997
|
+
// Retrieve node by node Id
|
|
1998
|
+
const node = attrs.allNodes!.find(({ data }) => attrs.nodeId(data) == id);
|
|
1999
|
+
|
|
2000
|
+
if (!node) {
|
|
2001
|
+
console.log(`ORG CHART - ${expandedFlag ? 'EXPAND' : 'COLLAPSE'} - Node with id (${id}) not found in the tree`);
|
|
2002
|
+
return this;
|
|
2003
|
+
}
|
|
2004
|
+
node.data._expanded = expandedFlag;
|
|
2005
|
+
if (!expandedFlag) {
|
|
2006
|
+
const parent = node.parent || { descendants: () => [] };
|
|
2007
|
+
const descendants = parent.descendants().filter((d) => d != parent);
|
|
2008
|
+
descendants.forEach((d) => (d.data._expanded = false));
|
|
2009
|
+
}
|
|
2010
|
+
|
|
2011
|
+
return this;
|
|
2012
|
+
}
|
|
2013
|
+
|
|
2014
|
+
setCentered(nodeId: string | number): this {
|
|
2015
|
+
const attrs = this.getChartState();
|
|
2016
|
+
// this.setExpanded(nodeId)
|
|
2017
|
+
const root = attrs.generateRoot!(attrs.data || []);
|
|
2018
|
+
const descendants = root.descendants();
|
|
2019
|
+
const node = descendants.find(({ data }) => attrs.nodeId(data).toString() == nodeId.toString());
|
|
2020
|
+
if (!node) {
|
|
2021
|
+
console.log(`ORG CHART - CENTER - Node with id (${nodeId}) not found in the tree`);
|
|
2022
|
+
return this;
|
|
2023
|
+
}
|
|
2024
|
+
const ancestors = node.ancestors();
|
|
2025
|
+
ancestors.forEach((d) => (d.data._expanded = true));
|
|
2026
|
+
node.data._centered = true;
|
|
2027
|
+
node.data._expanded = true;
|
|
2028
|
+
return this;
|
|
2029
|
+
}
|
|
2030
|
+
|
|
2031
|
+
setHighlighted(nodeId: string | number | null): this {
|
|
2032
|
+
const attrs = this.getChartState();
|
|
2033
|
+
const root = attrs.generateRoot!(attrs.data || []);
|
|
2034
|
+
const descendants = root.descendants();
|
|
2035
|
+
const node = nodeId ? descendants.find((d) => attrs.nodeId(d.data).toString() === nodeId.toString()) : null;
|
|
2036
|
+
if (!node) {
|
|
2037
|
+
console.log(`ORG CHART - HIGHLIGHT - Node with id (${nodeId}) not found in the tree`);
|
|
2038
|
+
return this;
|
|
2039
|
+
}
|
|
2040
|
+
const ancestors = node.ancestors();
|
|
2041
|
+
ancestors.forEach((d) => (d.data._expanded = true));
|
|
2042
|
+
node.data._highlighted = true;
|
|
2043
|
+
node.data._expanded = true;
|
|
2044
|
+
node.data._centered = true;
|
|
2045
|
+
return this;
|
|
2046
|
+
}
|
|
2047
|
+
|
|
2048
|
+
setUpToTheRootHighlighted(nodeId: string | number | null): this {
|
|
2049
|
+
const attrs = this.getChartState();
|
|
2050
|
+
const root = attrs.generateRoot!(attrs.data || []);
|
|
2051
|
+
const descendants = root.descendants();
|
|
2052
|
+
const node = nodeId ? descendants.find((d) => attrs.nodeId(d.data).toString() === nodeId.toString()) : null;
|
|
2053
|
+
if (!node) {
|
|
2054
|
+
console.log(`ORG CHART - HIGHLIGHTROOT - Node with id (${nodeId}) not found in the tree`);
|
|
2055
|
+
return this;
|
|
2056
|
+
}
|
|
2057
|
+
const ancestors = node.ancestors();
|
|
2058
|
+
ancestors.forEach((d) => (d.data._expanded = true));
|
|
2059
|
+
node.data._upToTheRootHighlighted = true;
|
|
2060
|
+
node.data._expanded = true;
|
|
2061
|
+
node.ancestors().forEach((d) => (d.data._upToTheRootHighlighted = true));
|
|
2062
|
+
return this;
|
|
2063
|
+
}
|
|
2064
|
+
|
|
2065
|
+
clearHighlighting(): this {
|
|
2066
|
+
const attrs = this.getChartState();
|
|
2067
|
+
attrs.allNodes!.forEach((d) => {
|
|
2068
|
+
d.data._highlighted = false;
|
|
2069
|
+
d.data._upToTheRootHighlighted = false;
|
|
2070
|
+
});
|
|
2071
|
+
const root = attrs.root!;
|
|
2072
|
+
this.update({ x0: root.x0 || 0, y0: root.y0 || 0, width: root.width, height: root.height });
|
|
2073
|
+
return this;
|
|
2074
|
+
}
|
|
2075
|
+
|
|
2076
|
+
// It can take selector which would go fullscreen
|
|
2077
|
+
fullscreen(elem?: HTMLElement): void {
|
|
2078
|
+
const attrs = this.getChartState();
|
|
2079
|
+
const el = (elem ? d3.select(elem as any) : d3.select(attrs.container as any)).node() as any;
|
|
2080
|
+
|
|
2081
|
+
d3.select(document).on('fullscreenchange.' + attrs.id, function (_d: any) {
|
|
2082
|
+
const fsElement = (document as any).fullscreenElement || (document as any).mozFullscreenElement || (document as any).webkitFullscreenElement;
|
|
2083
|
+
if (fsElement == el) {
|
|
2084
|
+
setTimeout((_d: any) => {
|
|
2085
|
+
attrs.svg!.attr('height', window.innerHeight - 40);
|
|
2086
|
+
}, 500);
|
|
2087
|
+
} else {
|
|
2088
|
+
attrs.svg!.attr('height', attrs.svgHeight);
|
|
2089
|
+
}
|
|
2090
|
+
});
|
|
2091
|
+
|
|
2092
|
+
if (el.requestFullscreen) {
|
|
2093
|
+
el.requestFullscreen();
|
|
2094
|
+
} else if (el.mozRequestFullScreen) {
|
|
2095
|
+
el.mozRequestFullScreen();
|
|
2096
|
+
} else if (el.webkitRequestFullscreen) {
|
|
2097
|
+
el.webkitRequestFullscreen();
|
|
2098
|
+
} else if (el.msRequestFullscreen) {
|
|
2099
|
+
el.msRequestFullscreen();
|
|
2100
|
+
}
|
|
2101
|
+
}
|
|
2102
|
+
|
|
2103
|
+
// Zoom in exposed method
|
|
2104
|
+
zoomIn(): this {
|
|
2105
|
+
const { svg, zoomBehavior } = this.getChartState();
|
|
2106
|
+
(svg as any).transition().call(zoomBehavior!.scaleBy, 1.3);
|
|
2107
|
+
return this;
|
|
2108
|
+
}
|
|
2109
|
+
|
|
2110
|
+
// Zoom out exposed method
|
|
2111
|
+
zoomOut(): this {
|
|
2112
|
+
const { svg, zoomBehavior } = this.getChartState();
|
|
2113
|
+
(svg as any).transition().call(zoomBehavior!.scaleBy, 0.78);
|
|
2114
|
+
return this;
|
|
2115
|
+
}
|
|
2116
|
+
|
|
2117
|
+
toDataURL(url: string, callback: (result: string | ArrayBuffer | null) => void): void {
|
|
2118
|
+
const xhr = new XMLHttpRequest();
|
|
2119
|
+
xhr.onload = function () {
|
|
2120
|
+
if (xhr.status >= 200 && xhr.status < 300) {
|
|
2121
|
+
const reader = new FileReader();
|
|
2122
|
+
reader.onloadend = function () {
|
|
2123
|
+
callback(reader.result);
|
|
2124
|
+
};
|
|
2125
|
+
reader.readAsDataURL(xhr.response);
|
|
2126
|
+
} else {
|
|
2127
|
+
callback(null);
|
|
2128
|
+
}
|
|
2129
|
+
};
|
|
2130
|
+
xhr.onerror = function () {
|
|
2131
|
+
callback(null);
|
|
2132
|
+
};
|
|
2133
|
+
xhr.open('GET', url);
|
|
2134
|
+
xhr.responseType = 'blob';
|
|
2135
|
+
xhr.send();
|
|
2136
|
+
}
|
|
2137
|
+
|
|
2138
|
+
exportImg({ full = false, scale = 3, onLoad = (_d: any) => _d, save = true, backgroundColor = '#FAFAFA' }: ExportImageParams = {}): void {
|
|
2139
|
+
const attrs = this.getChartState();
|
|
2140
|
+
const { svg: svgImg } = attrs;
|
|
2141
|
+
let count = 0;
|
|
2142
|
+
const selection = svgImg!.selectAll('img');
|
|
2143
|
+
const total = selection.size();
|
|
2144
|
+
|
|
2145
|
+
const exportImage = () => {
|
|
2146
|
+
const duration = this.duration();
|
|
2147
|
+
if (full) {
|
|
2148
|
+
this.fit();
|
|
2149
|
+
}
|
|
2150
|
+
const { svg } = this.getChartState();
|
|
2151
|
+
|
|
2152
|
+
setTimeout(
|
|
2153
|
+
(_d: any) => {
|
|
2154
|
+
this.downloadImage({
|
|
2155
|
+
node: svg!.node()!,
|
|
2156
|
+
scale,
|
|
2157
|
+
isSvg: false,
|
|
2158
|
+
backgroundColor,
|
|
2159
|
+
onAlreadySerialized: (_d: any) => {
|
|
2160
|
+
const root = this.getChartState().root!;
|
|
2161
|
+
this.update({ x0: root.x0 || 0, y0: root.y0 || 0, width: root.width, height: root.height });
|
|
2162
|
+
},
|
|
2163
|
+
imageName: attrs.imageName,
|
|
2164
|
+
onLoad: onLoad,
|
|
2165
|
+
save,
|
|
2166
|
+
});
|
|
2167
|
+
},
|
|
2168
|
+
full ? duration + 10 : 0
|
|
2169
|
+
);
|
|
2170
|
+
};
|
|
2171
|
+
|
|
2172
|
+
if (total > 0) {
|
|
2173
|
+
const imgNodes = selection.nodes() as HTMLImageElement[];
|
|
2174
|
+
imgNodes.forEach((imgElement) => {
|
|
2175
|
+
this.toDataURL(imgElement.src, (dataUrl) => {
|
|
2176
|
+
if (dataUrl) imgElement.src = dataUrl as string;
|
|
2177
|
+
if (++count === total) {
|
|
2178
|
+
exportImage();
|
|
2179
|
+
}
|
|
2180
|
+
});
|
|
2181
|
+
});
|
|
2182
|
+
} else {
|
|
2183
|
+
exportImage();
|
|
2184
|
+
}
|
|
2185
|
+
}
|
|
2186
|
+
|
|
2187
|
+
exportSvg(): this {
|
|
2188
|
+
const { svg, imageName } = this.getChartState();
|
|
2189
|
+
this.downloadImage({ imageName: imageName, node: svg!.node()!, scale: 3, isSvg: true });
|
|
2190
|
+
return this;
|
|
2191
|
+
}
|
|
2192
|
+
|
|
2193
|
+
expandAll(): this {
|
|
2194
|
+
const { data } = this.getChartState();
|
|
2195
|
+
data!.forEach((d) => ((d as any)._expanded = true));
|
|
2196
|
+
this.render();
|
|
2197
|
+
return this;
|
|
2198
|
+
}
|
|
2199
|
+
|
|
2200
|
+
collapseAll(): this {
|
|
2201
|
+
const { allNodes } = this.getChartState();
|
|
2202
|
+
allNodes!.forEach((d) => (d.data._expanded = false));
|
|
2203
|
+
this.initialExpandLevel(0);
|
|
2204
|
+
this.render();
|
|
2205
|
+
return this;
|
|
2206
|
+
}
|
|
2207
|
+
|
|
2208
|
+
downloadImage({ node, scale = 2, imageName = 'graph', isSvg = false, save = true, backgroundColor = '#FAFAFA', onAlreadySerialized = (_d: any) => {}, onLoad = (_d: any) => {} }: DownloadImageParams): void {
|
|
2209
|
+
// Retrieve svg node
|
|
2210
|
+
const svgNode = node as SVGSVGElement;
|
|
2211
|
+
|
|
2212
|
+
function saveAs(uri: string, filename: string): void {
|
|
2213
|
+
// create link
|
|
2214
|
+
const link = document.createElement('a');
|
|
2215
|
+
if (typeof link.download === 'string') {
|
|
2216
|
+
document.body.appendChild(link); // Firefox requires the link to be in the body
|
|
2217
|
+
link.download = filename;
|
|
2218
|
+
link.href = uri;
|
|
2219
|
+
link.click();
|
|
2220
|
+
link.remove(); // remove the link when done
|
|
2221
|
+
} else {
|
|
2222
|
+
location.replace(uri);
|
|
2223
|
+
}
|
|
2224
|
+
}
|
|
2225
|
+
// This function serializes SVG and sets all necessary attributes
|
|
2226
|
+
function serializeString(svg: any) {
|
|
2227
|
+
const xmlns = 'http://www.w3.org/2000/xmlns/';
|
|
2228
|
+
const xlinkns = 'http://www.w3.org/1999/xlink';
|
|
2229
|
+
const svgns = 'http://www.w3.org/2000/svg';
|
|
2230
|
+
|
|
2231
|
+
// Clone the SVG
|
|
2232
|
+
const clonedSvg = svg.cloneNode(true);
|
|
2233
|
+
|
|
2234
|
+
// Copy computed styles from original to cloned elements
|
|
2235
|
+
const originalWalker = document.createTreeWalker(svg, NodeFilter.SHOW_ELEMENT);
|
|
2236
|
+
const clonedWalker = document.createTreeWalker(clonedSvg, NodeFilter.SHOW_ELEMENT);
|
|
2237
|
+
|
|
2238
|
+
// Process root SVG element
|
|
2239
|
+
copyComputedStyle(svg, clonedSvg);
|
|
2240
|
+
|
|
2241
|
+
// Process all child elements
|
|
2242
|
+
while (originalWalker.nextNode() && clonedWalker.nextNode()) {
|
|
2243
|
+
const originalNode = originalWalker.currentNode as Element;
|
|
2244
|
+
const clonedNode = clonedWalker.currentNode as Element;
|
|
2245
|
+
|
|
2246
|
+
// Copy computed styles
|
|
2247
|
+
copyComputedStyle(originalNode, clonedNode);
|
|
2248
|
+
|
|
2249
|
+
// Fix fragment references
|
|
2250
|
+
for (const attr of Array.from(clonedNode.attributes)) {
|
|
2251
|
+
if (attr.value.includes(globalThis.location.href + '#')) {
|
|
2252
|
+
attr.value = attr.value.replace(globalThis.location.href + '#', '#');
|
|
2253
|
+
}
|
|
2254
|
+
}
|
|
2255
|
+
}
|
|
2256
|
+
|
|
2257
|
+
clonedSvg.setAttributeNS(xmlns, 'xmlns', svgns);
|
|
2258
|
+
clonedSvg.setAttributeNS(xmlns, 'xmlns:xlink', xlinkns);
|
|
2259
|
+
const serializer = new XMLSerializer();
|
|
2260
|
+
const string = serializer.serializeToString(clonedSvg);
|
|
2261
|
+
return string;
|
|
2262
|
+
}
|
|
2263
|
+
|
|
2264
|
+
// Helper function to copy computed styles
|
|
2265
|
+
function copyComputedStyle(source: Element, target: Element) {
|
|
2266
|
+
const computedStyle = globalThis.getComputedStyle(source);
|
|
2267
|
+
|
|
2268
|
+
// List of CSS properties to copy
|
|
2269
|
+
const propertiesToCopy = [
|
|
2270
|
+
'font-family',
|
|
2271
|
+
'font-size',
|
|
2272
|
+
'font-weight',
|
|
2273
|
+
'font-style',
|
|
2274
|
+
'fill',
|
|
2275
|
+
'stroke',
|
|
2276
|
+
'stroke-width',
|
|
2277
|
+
'stroke-dasharray',
|
|
2278
|
+
'stroke-linecap',
|
|
2279
|
+
'stroke-linejoin',
|
|
2280
|
+
'opacity',
|
|
2281
|
+
'color',
|
|
2282
|
+
'text-anchor',
|
|
2283
|
+
'dominant-baseline',
|
|
2284
|
+
'alignment-baseline',
|
|
2285
|
+
'display',
|
|
2286
|
+
'visibility',
|
|
2287
|
+
'transform',
|
|
2288
|
+
'transform-origin',
|
|
2289
|
+
'background',
|
|
2290
|
+
'background-color',
|
|
2291
|
+
'border',
|
|
2292
|
+
'border-width',
|
|
2293
|
+
'border-color',
|
|
2294
|
+
'border-style',
|
|
2295
|
+
'border-radius',
|
|
2296
|
+
'padding',
|
|
2297
|
+
'margin',
|
|
2298
|
+
'width',
|
|
2299
|
+
'height',
|
|
2300
|
+
'overflow',
|
|
2301
|
+
];
|
|
2302
|
+
|
|
2303
|
+
// Apply computed styles as inline styles
|
|
2304
|
+
propertiesToCopy.forEach((property) => {
|
|
2305
|
+
const value = computedStyle.getPropertyValue(property);
|
|
2306
|
+
if (value && value !== '' && value !== 'none') {
|
|
2307
|
+
(target as HTMLElement).style.setProperty(property, value);
|
|
2308
|
+
}
|
|
2309
|
+
});
|
|
2310
|
+
}
|
|
2311
|
+
|
|
2312
|
+
if (isSvg) {
|
|
2313
|
+
let source = serializeString(svgNode);
|
|
2314
|
+
//add xml declaration
|
|
2315
|
+
source = '<?xml version="1.0" standalone="no"?>\r\n' + source;
|
|
2316
|
+
//convert svg source to URI data scheme.
|
|
2317
|
+
const url = 'data:image/svg+xml;charset=utf-8,' + encodeURIComponent(source);
|
|
2318
|
+
saveAs(url, imageName + '.svg');
|
|
2319
|
+
onAlreadySerialized?.(source);
|
|
2320
|
+
return;
|
|
2321
|
+
}
|
|
2322
|
+
// Get image quality index (basically, index you can zoom in)
|
|
2323
|
+
const quality = scale;
|
|
2324
|
+
// Create image
|
|
2325
|
+
const image = document.createElement('img');
|
|
2326
|
+
image.onload = function () {
|
|
2327
|
+
// Create image canvas
|
|
2328
|
+
const canvas = document.createElement('canvas');
|
|
2329
|
+
// Set width and height based on SVG node
|
|
2330
|
+
const rect = svgNode.getBoundingClientRect();
|
|
2331
|
+
canvas.width = rect.width * quality;
|
|
2332
|
+
canvas.height = rect.height * quality;
|
|
2333
|
+
// Draw background
|
|
2334
|
+
const context = canvas.getContext('2d');
|
|
2335
|
+
context!.fillStyle = backgroundColor;
|
|
2336
|
+
context!.fillRect(0, 0, rect.width * quality, rect.height * quality);
|
|
2337
|
+
context!.drawImage(image, 0, 0, rect.width * quality, rect.height * quality);
|
|
2338
|
+
// Set some image metadata
|
|
2339
|
+
const dt = canvas.toDataURL('image/png');
|
|
2340
|
+
if (onLoad) {
|
|
2341
|
+
const img = new Image();
|
|
2342
|
+
img.src = dt;
|
|
2343
|
+
onLoad(img);
|
|
2344
|
+
}
|
|
2345
|
+
if (save) {
|
|
2346
|
+
// Invoke saving function
|
|
2347
|
+
saveAs(dt, imageName + '.png');
|
|
2348
|
+
}
|
|
2349
|
+
};
|
|
2350
|
+
|
|
2351
|
+
const url = 'data:image/svg+xml; charset=utf8, ' + encodeURIComponent(serializeString(svgNode));
|
|
2352
|
+
|
|
2353
|
+
onAlreadySerialized?.(serializeString(svgNode));
|
|
2354
|
+
|
|
2355
|
+
image.src = url; // URL.createObjectURL(blob);
|
|
2356
|
+
// This function invokes save window
|
|
2357
|
+
}
|
|
2358
|
+
|
|
2359
|
+
// Calculate what size text will take
|
|
2360
|
+
getTextWidth(text: string, { fontSize = 14, fontWeight = '400', defaultFont = 'Helvetice', ctx }: Partial<TextMeasurementParams>): number {
|
|
2361
|
+
ctx!.font = `${fontWeight || ''} ${fontSize}px ${defaultFont} `;
|
|
2362
|
+
const measurement = ctx!.measureText(text);
|
|
2363
|
+
return measurement.width;
|
|
2364
|
+
}
|
|
2365
|
+
|
|
2366
|
+
// Clear after moving off from the page
|
|
2367
|
+
clear(): void {
|
|
2368
|
+
const attrs = this.getChartState();
|
|
2369
|
+
d3.select(window).on(`resize.${attrs.id}`, null);
|
|
2370
|
+
attrs.svg?.selectAll('*').remove();
|
|
2371
|
+
}
|
|
2372
|
+
}
|