import * as d3 from 'd3' ; import React , { useEffect , useState } from 'react' ; import { VoterDisplayData , VoteType } from '../../proposalView' ; import { utils } from '@oyster/common' ; const { getExplorerUrl } = utils ; interface IVoterBubbleGraph { data : Array < VoterDisplayData > ; width : number ; height : number ; endpoint : string ; } const MAX_BUBBLE_AMOUNT = 50 ; export function VoterBubbleGraph ( props ) { const { data , width , height , endpoint } = props ; const [ ref , setRef ] = useState < any > ( ) ; const limitedData = data . slice ( 0 , MAX_BUBBLE_AMOUNT ) . map ( d => ( { ... d , name : d . name . slice ( 0 , 3 ) + '...' + d . name . slice ( d . name . length - 3 , d . name . length ) , } ) ) ; useEffect ( ( ) => { if ( ref ) { const format = d3 . format ( ',d' ) ; const color = d3 . scaleOrdinal ( ) . domain ( [ VoteType . Undecided , VoteType . Yes , VoteType . No ] ) . range ( [ 'grey' , 'green' , '#d32029' ] ) ; const pack = ( data ) => { return d3 . pack ( ) . size ( [ width - 2 , height - 2 ] ) . padding ( 3 ) ( d3 . hierarchy ( { children : data } ) . sum ( d => ( d . value ? d . value : 0 ) ) ) ; } ; ref . innerHTML = '' ; const root = pack ( limitedData ) ; const newSvg = d3 . select ( ref ) . append ( 'svg' ) . attr ( 'viewBox' , [ 0 , 0 , width , height ] ) . attr ( 'font-size' , 10 ) . attr ( 'font-family' , 'sans-serif' ) . attr ( 'text-anchor' , 'middle' ) ; const leaf = newSvg . selectAll ( 'g' ) . data ( root . leaves ( ) ) . join ( 'g' ) . attr ( 'transform' , d => `translate(${ d . x + 1 },${ d . y + 1 })` ) ; leaf . append ( 'circle' ) . attr ( 'id' , d => ( d . leafUid = { id : d . name } ) . id ) . attr ( 'r' , d => d . r ) . attr ( 'fill-opacity' , 0.7 ) . attr ( 'fill' , d => color ( d . data . group ) ) ; leaf . append ( 'clipPath' ) . attr ( 'id' , d => ( d . clipUid = { id : d . name , href : getExplorerUrl ( d . title , endpoint ) , } ) . id ) . append ( 'use' ) . attr ( 'xlink:href' , d => d . leafUid . href ) ; leaf . append ( 'svg:a' ) . attr ( 'xlink:href' , d => getExplorerUrl ( d . data . title , endpoint ) ) . append ( 'svg:text' ) . attr ( 'clip-path' , d => d . clipUid ) . selectAll ( 'tspan' ) . data ( d => d . data . name . split ( /(?=[A-Z][a-z])|\s+/g ) ) . join ( 'tspan' ) . attr ( 'x' , 0 ) . attr ( 'y' , ( d , i , nodes ) => `${ i - nodes . length / 2 + 0.8 }em` ) . attr ( 'fill' , 'white' ) . text ( d => d ) ; leaf . append ( 'title' ) . text ( d => `${ d . data . title === undefined ? '' : `${ d . data . title }
  ` }${ format ( d . value ) }` ) ; } } , [ ref , limitedData , height , width , endpoint ] ) ; return ( < div ref = { ref => { if ( ref ) setRef ( ref ) ; } } > < /div>); }