npm i d3 -- save
< template> < div class = "d3" > < div : id= "id"  class = "d3-content" > < / div> < / div> 
< / template> 
< script> 
import  *  as  d3 from  "d3" ; export  default  { props :  { data :  Object, nodeWidth :  { type :  Number, default :  340 , } , nodeHeight :  { type :  Number, default :  40 , } , active :  { type :  String, default :  "" , } , } , data ( )  { return  { id :  "TreeMap"  +  randomString ( 4 ) , deep :  0 , treeData :  null , show :  true , demoData :  { label :  "中国" , url :  "https://baike.baidu.com/item/%E4%B8%AD%E5%9B%BD/1122445?fr=aladdin" , children :  [ { label :  "浙江45468761321" , disabled :  true , children :  [ {  label :  "杭州999999999"  } , {  label :  "宁波"  } , {  label :  "温州"  } , {  label :  "绍兴"  } , ] , } , { label :  "广西" , children :  [ { label :  "桂林56465465465464" , children :  [ {  label :  "秀峰区"  } , {  label :  "叠彩区"  } , {  label :  "象山区"  } , {  label :  "七星区"  } , ] , } , {  label :  "南宁"  } , {  label :  "柳州"  } , {  label :  "防城港"  } , ] , } , ] , } , } ; } , mounted ( )  { this . $nextTick ( ( )  =>  { this . drawMap ( ) ; window. handleCustom= this . handleCustom; } ) ; } , methods :  { drawMap ( )  { let  that =  this ; let  data =  { } ; if  ( this . data &&  JSON . stringify ( this . data)  !==  "{}" )  { data =  this . data; }  else  { data =  this . demoData; } if  ( ! this . treeData)  { this . treeData =  data; }  else  { d3. select ( "#"  +  this . id) . selectAll ( "svg" ) . remove ( ) ; } let  leafList =  [ ] ; getTreeLeaf ( data,  leafList) ; let  leafNum =  leafList. length; let  TreeDeep =  getDepth ( data) ; let  mapPaddingLR =  10 ; let  mapPaddingTB =  0 ; let  mapWidth =  this . nodeWidth *  TreeDeep +  mapPaddingLR *  2 ; let  mapHeight =  ( this . nodeHeight -  4 )  *  leafNum +  mapPaddingTB *  2 ; let  svgMap =  d3. select ( "#"  +  this . id) . append ( "svg" ) . attr ( "width" ,  mapWidth) . attr ( "height" ,  mapHeight) . style ( "margin" ,  "0px" ) ; let  treeMap =  svgMap. append ( "g" ) . attr ( "transform" , "translate("  + mapPaddingLR + ","  + ( mapHeight /  2  -  mapPaddingTB)  + ")" ) ; let  treeData =  d3. tree ( ) . nodeSize ( [ this . nodeHeight,  this . nodeWidth] ) . separation ( function  ( a,  b )  { let  rate = ( a. parent ==  b. parent?  b. children?  b. children. length /  2 :  1 :  2 )  /  a. depth; if  ( rate <  0.7 )  { rate =  0.7 ; } return  rate; } ) ( d3. hierarchy ( data) . sum ( function  ( node )  { return  node. value; } ) ) ; let  B ézier_curve_generator =  d3. linkHorizontal ( ) . x ( function  ( d )  { return  d. y; } ) . y ( function  ( d )  { return  d. x; } ) ; treeMap. selectAll ( "path" ) . data ( treeData. links ( ) ) . enter ( ) . append ( "path" ) . attr ( "d" ,  function  ( d )  { var  start =  { x :  d. source. x, y : d. source. y + 10  + ( d. source. data. link ?  getPXwidth ( d. source. data. link)  +  10  :  0 )  + getPXwidth ( d. source. data. label)  + ( ! d. source. data. children? 82 : 0 )  + 20 , } ; var  end =  {  x :  d. target. x,  y :  d. target. y } ; return  B ézier_curve_generator ( {  source :  start,  target :  end } ) ; } ) . attr ( "fill" ,  "none" ) . attr ( "stroke" ,  "#00AB6B" ) . attr ( "stroke-width" ,  1 ) ; let  groups =  treeMap. selectAll ( "g" ) . data ( treeData. descendants ( ) ) . enter ( ) . append ( "g" ) . attr ( "transform" ,  function  ( d )  { var  cx =  d. x; var  cy =  d. y; return  "translate("  +  cy +  ","  +  cx +  ")" ; } ) ; groups. append ( "circle" ) . on ( "click" ,  function  ( event,  node )  { let  data =  node. data; if  ( data. children)  { data. childrenTemp =  data. children; data. children =  null ; }  else  { data. children =  data. childrenTemp; data. childrenTemp =  null ; } that. drawMap ( ) ; } ) . attr ( "cursor" ,  "pointer" ) . attr ( "r" ,  4 ) . attr ( "fill" ,  function  ( d )  { if  ( d. data. childrenTemp)  { return  "#00AB6B" ; }  else  { return  "white" ; } } ) . attr ( "stroke" ,  "#00AB6B" ) . attr ( "stroke-width" ,  1 ) ; groups. append ( "rect" ) . attr ( "x" ,  8 ) . attr ( "y" ,  - 10 ) . attr ( "width" ,  function  ( d )  { return  d. data. link ?  getPXwidth ( d. data. link)  +  10  :  0 ; } ) . attr ( "height" ,  22 ) . attr ( "fill" ,  "red" ) . attr ( "border" ,  "blue" ) . attr ( "rx" ,  4 ) ; groups. append ( "text" ) . attr ( "x" ,  12 ) . attr ( "y" ,  - 5 ) . attr ( "dy" ,  10 ) . attr ( "fill" ,  "white" ) . attr ( "font-size" ,  12 ) . text ( function  ( d )  { return  d. data. link; } ) ; groups. append ( "text" ) . on ( "click" ,  function  ( event,  node )  { let  data =  node. data; if  ( data. disabled)  { return ; } if  ( data. url)  { window. open ( data. url) ; that. $emit ( "activeChange" ,  "map" ) ; return ; } if  ( data. dicType)  { that. $emit ( "dicTypeChange" ,  data. dicType) ; } if  ( data. prop)  { that. $emit ( "activeChange" ,  data. prop) ; } } ) . attr ( "x" ,  function  ( d )  { return  12  +  ( d. data. link ?  getPXwidth ( d. data. link)  +  10  :  0 ) ; } ) . attr ( "fill" ,  function  ( d )  { if  ( d. data. prop ===  that. active)  { return  "#409EFF" ; } } ) . attr ( "font-weight" ,  function  ( d )  { if  ( d. data. prop ===  that. active)  { return  "bold" ; } } ) . attr ( "font-size" ,  14 ) . attr ( "cursor" ,  function  ( d )  { if  ( d. data. disabled)  { return  "not-allowed" ; }  else  { return  "pointer" ; } } ) . attr ( "y" ,  - 5 ) . attr ( "dy" ,  10 ) . attr ( "slot" ,  function  ( d )  { return  d. data. prop; } ) ; groups. append ( "foreignObject" ) . attr ( "width" ,  ( d )  =>  { return  getPXwidth ( d. data. label)  +  22  +  ( ! d. data. children? 82 : 0 ) ; } ) . attr ( "height" ,  100 ) . attr ( "x" ,  function  ( d )  { return  12  +  ( d. data. link ?  getPXwidth ( d. data. link)  +  10  :  0 ) ; } ) . on ( "click" ,  function  ( event,  node )  { } ) . attr ( "y" ,  - 10 ) . append ( "xhtml:div" ) . style ( "font" ,  '14px "Helvetica Neue"' ) . html ( ( d )  =>  { let  _html =  ` <div class="custom-html"><div> ${ d. data. label} </div></div> ` ; if ( ! d. data. children) { _html =  ` <div class="custom-html"><div> ${ d. data. label} </div><div οnclick="handleCustom( ${ 1 } )"><i class="iconfont"></i>视频课</div></div> ` ; } return  _html} ) ; } , handleCustom ( data ) { debugger } } , 
} ; 
function  getDepth ( json )  { var  arr =  [ ] ; arr. push ( json) ; var  depth =  0 ; while  ( arr. length >  0 )  { var  temp =  [ ] ; for  ( var  i =  0 ;  i <  arr. length;  i++ )  { temp. push ( arr[ i] ) ; } arr =  [ ] ; for  ( var  i =  0 ;  i <  temp. length;  i++ )  { if  ( temp[ i] . children &&  temp[ i] . children. length >  0 )  { for  ( var  j =  0 ;  j <  temp[ i] . children. length;  j++ )  { arr. push ( temp[ i] . children[ j] ) ; } } } if  ( arr. length >=  0 )  { depth++ ; } } return  depth; 
} 
function  getTreeLeaf ( treeData,  leafList )  { if  ( Array. isArray ( treeData) )  { treeData. forEach ( ( item )  =>  { if  ( item. children &&  item. children. length >  0 )  { getTreeLeaf ( item. children,  leafList) ; }  else  { leafList. push ( item) ; } } ) ; }  else  { if  ( treeData. children &&  treeData. children. length >  0 )  { getTreeLeaf ( treeData. children,  leafList) ; }  else  { leafList. push ( treeData) ; } } 
} 
function  getStringSizeLength ( string )  { return  string. replace ( / [\u0391-\uFFE5] / g ,  "aa" ) . length; 
} 
function  randomString ( strLength )  { strLength =  strLength ||  32 ; let  strLib =  "ABCDEFGHJKMNPQRSTWXYZabcdefhijkmnprstwxyz" ; let  n =  "" ; for  ( let  i =  0 ;  i <  strLength;  i++ )  { n +=  strLib. charAt ( Math. floor ( Math. random ( )  *  strLib. length) ) ; } return  n; 
} 
function  getPXwidth ( str,  fontSize =  "12px" ,  fontFamily =  "Microsoft YaHei" )  { var  span =  document. createElement ( "span" ) ; var  result =  { } ; result. width =  span. offsetWidth; result. height =  span. offsetHeight; span. style. visibility =  "hidden" ; span. style. fontSize =  fontSize; span. style. fontFamily =  fontFamily; span. style. display =  "inline-block" ; document. body. appendChild ( span) ; if  ( typeof  span. textContent !=  "undefined" )  { span. textContent =  str; }  else  { span. innerText =  str; } result. width =  parseFloat ( window. getComputedStyle ( span) . width)  -  result. width; return  result. width; 
} 
< / script> 
< style lang= "scss"  scoped> 
. d3 { position :  relative; overflow :  hidden; width :  calc ( 100 % ) ; min- height:  500px; overflow- x:  scroll; . d3- content { position :  absolute; width :  max- content; : : v- deep . custom- html { display :  flex; div { i { font- size:  12px; margin- right:  4px; } & : nth- child ( 2 )  { margin- left:  10px; background :  #f2faf7; border :  0 . 5px solid #c3e7da; border- radius:  4px; color :  #00ab6b; font- size:  12px; padding :  0  4px; height :  20px; cursor :  pointer; } } } } 
} 
< / style>