@ -29,7 +29,7 @@
v - btn . px - 5 ( value = 'rradial' )
v - icon ( left , : color = 'graphMode === `rradial` ? `primary` : `grey darken-3`' ) mdi - blur - radial
span . text - none Relational Radial
. admin - pages - visualize - svg .pa - 10 (ref = 'svgContainer ')
. admin - pages - visualize - svg (ref = 'svgContainer ', v - show = 'pages.length >= 1 ')
v - alert ( v - if = 'pages.length < 1' , outlined , type = 'warning' , style = 'max-width: 650px; margin: 0 auto;' ) Looks like there ' s no data yet to graph !
< / template >
@ -61,8 +61,14 @@ export default {
} ,
methods : {
goToPage ( d ) {
if ( _ . get ( d , 'data.id' , 0 ) > 0 ) {
this . $router . push ( ` ${ d . data . id } ` )
const id = d . data . id
if ( id ) {
if ( d3 . event . ctrlKey || d3 . event . metaKey ) {
const { href } = this . $router . resolve ( String ( id ) )
window . open ( href , '_blank' )
} else {
this . $router . push ( String ( id ) )
}
}
} ,
bilink ( root ) {
@ -86,41 +92,36 @@ export default {
}
return root
} ,
hierarchy ( data , rootOnly = false ) {
let result = [ ]
let level = { result }
const map = new Map ( data . map ( d => [ d . path , d ] ) )
data . forEach ( d => {
const pathParts = d . path . split ( '/' )
pathParts . reduce ( ( r , part , i ) => {
const curPath = _ . take ( pathParts , i + 1 ) . join ( '/' )
if ( ! r [ part ] ) {
r [ part ] = { result : [ ] }
const page = map . get ( curPath )
r . result . push ( page ? {
... d ,
children : r [ part ] . result
} : {
title : part ,
links : [ ] ,
path : curPath ,
children : r [ part ] . result
} )
hierarchy ( pages ) {
const map = new Map ( pages . map ( p => [ p . path , p ] ) )
const getPage = path => map . get ( path ) || {
path : path ,
title : path . split ( '/' ) . slice ( - 1 ) [ 0 ] ,
links : [ ]
}
return r [ part ]
} , level )
} )
return rootOnly ? _ . head ( result ) || { children : [ ] } : {
children : result
function recurse ( depth , [ parent , descendants ] ) {
const truncatePath = path => _ . take ( path . split ( '/' ) , depth ) . join ( '/' )
const descendantsByChild =
Object . entries ( _ . groupBy ( descendants , page => truncatePath ( page . path ) ) )
. map ( ( [ childPath , descendantsGroup ] ) => [ getPage ( childPath ) , descendantsGroup ] )
. map ( ( [ child , descendantsGroup ] ) =>
[ child , _ . filter ( descendantsGroup , d => d . path !== child . path ) ] )
return {
... parent ,
children : descendantsByChild . map ( _ . partial ( recurse , depth + 1 ) )
}
}
const root = { path : this . currentLocale , title : this . currentLocale , links : [ ] }
/ / s t a r t a t d e p t h = 2 b e c a u s e w e ' r e t a k i n g { l o c a l e } a s t h e r o o t a n d
/ / a l l p a t h s s t a r t w i t h { l o c a l e } /
return recurse ( 2 , [ root , pages ] )
} ,
/ * *
* Relational Radial
* /
drawRelations ( ) {
const data = this . hierarchy ( this . pages , true )
const data = this . hierarchy ( this . pages )
const line = d3 . lineRadial ( )
. curve ( d3 . curveBundle . beta ( 0.85 ) )
@ -136,7 +137,13 @@ export default {
const svg = d3 . create ( 'svg' )
. attr ( 'viewBox' , [ - this . width / 2 , - this . width / 2 , this . width , this . width ] )
const link = svg . append ( 'g' )
const g = svg . append ( 'g' )
svg . call ( d3 . zoom ( ) . on ( 'zoom' , function ( ) {
g . attr ( 'transform' , d3 . event . transform )
} ) )
const link = g . append ( 'g' )
. attr ( 'stroke' , '#CCC' )
. attr ( 'fill' , 'none' )
. selectAll ( 'path' )
@ -146,7 +153,7 @@ export default {
. attr ( 'd' , ( [ i , o ] ) => line ( i . path ( o ) ) )
. each ( function ( d ) { d . path = this } )
sv g. append ( 'g' )
g. append ( 'g' )
. attr ( 'font-family' , 'sans-serif' )
. attr ( 'font-size' , 10 )
. selectAll ( 'g' )
@ -195,7 +202,7 @@ export default {
* Hierarchical Tree
* /
drawTree ( ) {
const data = this . hierarchy ( this . pages , true )
const data = this . hierarchy ( this . pages )
const treeRoot = d3 . hierarchy ( data )
treeRoot . dx = 10
@ -212,7 +219,16 @@ export default {
const svg = d3 . create ( 'svg' )
. attr ( 'viewBox' , [ 0 , 0 , this . width , x1 - x0 + root . dx * 2 ] )
const g = svg . append ( 'g' )
/ / t h i s e x t r a l e v e l i s n e c e s s a r y b e c a u s e t h e e l e m e n t t h a t w e
/ / a p p l y t h e z o o m t r a n f o r m t o m u s t b e a b o v e t h e e l e m e n t w h e r e
/ / w e a p p l y t h e t r a n s l a t i o n ( ` g ` ) , o r e l s e z o o m i s w o n k y
const gZoom = svg . append ( 'g' )
svg . call ( d3 . zoom ( ) . on ( 'zoom' , function ( ) {
gZoom . attr ( 'transform' , d3 . event . transform )
} ) )
const g = gZoom . append ( 'g' )
. attr ( 'font-family' , 'sans-serif' )
. attr ( 'font-size' , 10 )
. attr ( 'transform' , ` translate( ${ root . dy / 3 } , ${ root . dx - x0 } ) ` )
@ -270,7 +286,14 @@ export default {
const svg = d3 . create ( 'svg' )
. style ( 'font' , '10px sans-serif' )
svg . append ( 'g' )
const g = svg . append ( 'g' )
svg . call ( d3 . zoom ( ) . on ( 'zoom' , function ( ) {
g . attr ( 'transform' , d3 . event . transform )
} ) )
/ / e s l i n t - d i s a b l e - n e x t - l i n e n o - u n u s e d - v a r s
const link = g . append ( 'g' )
. attr ( 'fill' , 'none' )
. attr ( 'stroke' , this . $vuetify . theme . dark ? 'white' : '#555' )
. attr ( 'stroke-opacity' , 0.4 )
@ -282,7 +305,7 @@ export default {
. angle ( d => d . x )
. radius ( d => d . y ) )
const node = sv g. append ( 'g' )
const node = g. append ( 'g' )
. attr ( 'stroke-linejoin' , 'round' )
. attr ( 'stroke-width' , 3 )
. selectAll ( 'g' )
@ -371,9 +394,12 @@ export default {
< style lang = 'scss' >
. admin - pages - visualize - svg {
text - align : center ;
/ / 1 0 0 v h - h e a d e r - t i t l e s e c t i o n - f o o t e r - c o n t e n t p a d d i n g
height : calc ( 100 vh - 64 px - 92 px - 32 px - 16 px ) ;
> svg {
height : 100 vh ;
height : 100 % ;
width : 100 % ;
}
}
< / style >