44 < meta charset ="UTF-8 ">
55 < meta name ="viewport " content ="width=device-width, initial-scale=1.0 ">
66 < title > DB AutoOrgChart</ title >
7- < script src =" https://cdnjs.cloudflare.com/ajax/libs/d3/7.8.5/d3. min.js" > </ script >
7+ < script src =' /static/d3. min.js' > </ script >
88 < style >
99 * {
1010 margin : 0 ;
139139 min-height : calc (100vh - 180px );
140140 }
141141
142+ .layout-toggle {
143+ position : absolute;
144+ top : 20px ;
145+ left : 20px ;
146+ z-index : 10 ;
147+ background : white;
148+ border : 1px solid # ddd ;
149+ border-radius : 4px ;
150+ display : flex;
151+ box-shadow : 0 2px 4px rgba (0 , 0 , 0 , 0.1 );
152+ overflow : hidden;
153+ }
154+
155+ .layout-btn {
156+ padding : 8px 12px ;
157+ background : white;
158+ border : none;
159+ cursor : pointer;
160+ font-size : 12px ;
161+ transition : all 0.3s ease;
162+ display : flex;
163+ align-items : center;
164+ gap : 4px ;
165+ white-space : nowrap;
166+ }
167+
168+ .layout-btn : first-child {
169+ border-right : 1px solid # ddd ;
170+ }
171+
172+ .layout-btn : hover {
173+ background : # f5f5f5 ;
174+ }
175+
176+ .layout-btn .active {
177+ background : # 0078d4 ;
178+ color : white;
179+ }
180+
181+ .layout-icon {
182+ width : 16px ;
183+ height : 16px ;
184+ display : flex;
185+ align-items : center;
186+ justify-content : center;
187+ }
188+
142189 .controls {
143190 position : absolute;
144191 top : 20px ;
222269 padding : 6px 10px ;
223270 font-size : 11px ;
224271 }
272+
273+ .layout-toggle {
274+ top : 10px ;
275+ left : 10px ;
276+ }
277+
278+ .layout-btn {
279+ padding : 6px 10px ;
280+ font-size : 11px ;
281+ }
225282 }
226283
227284 .detail-header {
@@ -533,9 +590,19 @@ <h1>Organization Chart</h1>
533590
534591 < div class ="main-content ">
535592 < div class ="org-chart-container " id ="orgChart ">
593+ < div class ="layout-toggle ">
594+ < button class ="layout-btn active " onclick ="setLayoutOrientation('vertical') ">
595+ < span class ="layout-icon "> ↓</ span >
596+ Vertical
597+ </ button >
598+ < button class ="layout-btn " onclick ="setLayoutOrientation('horizontal') ">
599+ < span class ="layout-icon "> →</ span >
600+ Horizontal
601+ </ button >
602+ </ div >
536603 < div class ="controls ">
537- < button class ="control-btn " onclick ="zoomIn() "> Zoom In +</ button >
538- < button class ="control-btn " onclick ="zoomOut() "> Zoom Out -</ button >
604+ < button class ="control-btn " onclick ="zoomIn() "> +</ button >
605+ < button class ="control-btn " onclick ="zoomOut() "> -</ button >
539606 < button class ="control-btn " onclick ="resetZoom() "> Reset Zoom</ button >
540607 < button class ="control-btn " onclick ="fitToScreen() "> Fit to Screen</ button >
541608 < button class ="control-btn " onclick ="expandAll() "> Expand All</ button >
@@ -566,6 +633,7 @@ <h1>Organization Chart</h1>
566633 let g = null ;
567634 let zoom = null ;
568635 let appSettings = { } ;
636+ let currentLayout = 'vertical' ; // Default layout
569637
570638 const API_BASE_URL = window . location . origin ;
571639 const nodeWidth = 220 ;
@@ -624,6 +692,22 @@ <h1>Organization Chart</h1>
624692 return `${ h12 } :${ minutes } ${ suffix } ` ;
625693 }
626694
695+ function setLayoutOrientation ( orientation ) {
696+ currentLayout = orientation ;
697+
698+ // Update button states
699+ document . querySelectorAll ( '.layout-btn' ) . forEach ( btn => {
700+ btn . classList . remove ( 'active' ) ;
701+ } ) ;
702+ event . target . closest ( '.layout-btn' ) . classList . add ( 'active' ) ;
703+
704+ // Re-render the chart with new orientation
705+ if ( root ) {
706+ update ( root ) ;
707+ fitToScreen ( ) ;
708+ }
709+ }
710+
627711 async function init ( ) {
628712 await loadSettings ( ) ;
629713
@@ -687,7 +771,7 @@ <h1>Organization Chart</h1>
687771
688772 root = d3 . hierarchy ( data ) ;
689773
690- root . x0 = 0 ;
774+ root . x0 = 0 ;
691775 root . y0 = 0 ;
692776
693777 const treeLayout = d3 . tree ( )
@@ -709,12 +793,23 @@ <h1>Organization Chart</h1>
709793
710794 function update ( source ) {
711795 const treeLayout = d3 . tree ( )
712- . nodeSize ( [ nodeWidth + 20 , levelHeight ] ) ;
796+ . nodeSize ( currentLayout === 'vertical'
797+ ? [ nodeWidth + 20 , levelHeight ]
798+ : [ levelHeight , nodeWidth + 20 ] ) ;
713799
714800 const treeData = treeLayout ( root ) ;
715801 const nodes = treeData . descendants ( ) ;
716802 const links = treeData . links ( ) ;
717803
804+ // Swap x and y coordinates for horizontal layout
805+ if ( currentLayout === 'horizontal' ) {
806+ nodes . forEach ( d => {
807+ const temp = d . x ;
808+ d . x = d . y ;
809+ d . y = temp ;
810+ } ) ;
811+ }
812+
718813 const link = g . selectAll ( '.link' )
719814 . data ( links , d => d . target . data . id ) ;
720815
@@ -878,12 +973,14 @@ <h1>Organization Chart</h1>
878973
879974 expandBtn . append ( 'circle' )
880975 . attr ( 'class' , 'expand-btn' )
881- . attr ( 'cy' , nodeHeight / 2 + 10 )
976+ . attr ( 'cy' , currentLayout === 'vertical' ? nodeHeight / 2 + 10 : 0 )
977+ . attr ( 'cx' , currentLayout === 'horizontal' ? nodeWidth / 2 + 10 : 0 )
882978 . attr ( 'r' , 10 ) ;
883979
884980 expandBtn . append ( 'text' )
885981 . attr ( 'class' , 'expand-text' )
886- . attr ( 'y' , nodeHeight / 2 + 15 )
982+ . attr ( 'y' , currentLayout === 'vertical' ? nodeHeight / 2 + 15 : 4 )
983+ . attr ( 'x' , currentLayout === 'horizontal' ? nodeWidth / 2 + 10 : 0 )
887984 . attr ( 'text-anchor' , 'middle' )
888985 . text ( d => d . _children ?. length ? '+' : '-' ) ;
889986
@@ -916,7 +1013,13 @@ <h1>Organization Chart</h1>
9161013 . attr ( 'transform' , d => `translate(${ d . x } , ${ d . y } )` ) ;
9171014
9181015 nodeUpdate . select ( '.expand-text' )
919- . text ( d => d . _children ?. length ? '+' : '-' ) ;
1016+ . text ( d => d . _children ?. length ? '+' : '-' )
1017+ . attr ( 'y' , currentLayout === 'vertical' ? nodeHeight / 2 + 15 : 4 )
1018+ . attr ( 'x' , currentLayout === 'horizontal' ? nodeWidth / 2 + 10 : 0 ) ;
1019+
1020+ nodeUpdate . select ( '.expand-btn' )
1021+ . attr ( 'cy' , currentLayout === 'vertical' ? nodeHeight / 2 + 10 : 0 )
1022+ . attr ( 'cx' , currentLayout === 'horizontal' ? nodeWidth / 2 + 10 : 0 ) ;
9201023
9211024 nodeUpdate . select ( '.expand-group' )
9221025 . style ( 'display' , d => ( d . _children ?. length || d . children ?. length ) ? 'block' : 'none' ) ;
@@ -948,12 +1051,19 @@ <h1>Organization Chart</h1>
9481051 }
9491052
9501053 function diagonal ( s , d ) {
951- const midY = ( s . y + d . y ) / 2 ;
952-
953- return `M ${ s . x } ${ s . y + nodeHeight / 2 }
954- L ${ s . x } ${ midY }
955- L ${ d . x } ${ midY }
956- L ${ d . x } ${ d . y - nodeHeight / 2 } ` ;
1054+ if ( currentLayout === 'vertical' ) {
1055+ const midY = ( s . y + d . y ) / 2 ;
1056+ return `M ${ s . x } ${ s . y + nodeHeight / 2 }
1057+ L ${ s . x } ${ midY }
1058+ L ${ d . x } ${ midY }
1059+ L ${ d . x } ${ d . y - nodeHeight / 2 } ` ;
1060+ } else {
1061+ const midX = ( s . x + d . x ) / 2 ;
1062+ return `M ${ s . x + nodeWidth / 2 } ${ s . y }
1063+ L ${ midX } ${ s . y }
1064+ L ${ midX } ${ d . y }
1065+ L ${ d . x - nodeWidth / 2 } ${ d . y } ` ;
1066+ }
9571067 }
9581068
9591069 function toggle ( d ) {
0 commit comments