import { callOrGetValue , CommonProps , Datum , ResponsiveWrapper , NumberAccessor , CommonAccessors , } from '@datalith/util' ; import * as React from 'react' ; import Tooltip from 'react-tooltip' ; interface Props extends CommonProps { /** Value Accessor */ value : NumberAccessor ; /** Center of the dataviz */ center ? : { x : number ; y : number ; } ; /** Spacing between points */ spacing ? : number ; param size return getSpiralCoords ? : ( size : { width : number ; height : number ; } ) => Array < { x : number ; y : number ; } > ; } interface CircleProps extends CommonAccessors { datum : Datum ; value : NumberAccessor ; x : number ; y : number ; index : number ; tooltip ? : ( d : Datum ) => string ; } function getDefaultSpiralCoords ( data , spacing ) { let angle = 0 ; const coords = [ ] ; for ( let i = 0 ; i < data . length ; i ++ ) { const radius = Math . pow ( angle , 2 ) ; const delta = ( - 2 * radius + Math . sqrt ( 4 * radius * radius + 20 * spacing ) ) / 4 ; coords . push ( { x : radius * Math . cos ( angle ) , y : radius * Math . sin ( angle ) , } ) ; angle += delta ; } return coords ; } const Circle = ( { datum , value : valueAccessor , index , x , y , fill , fillOpacity , stroke , strokeOpacity , tooltip , } ) => { const style = { fill : callOrGetValue ( fill , datum , index ) , fillOpacity : ! fill && ! fillOpacity ? 0.8 : callOrGetValue ( fillOpacity , datum , index ) , stroke : callOrGetValue ( stroke , datum , index ) , strokeOpacity : callOrGetValue ( strokeOpacity , datum , index ) , } ; const radius = callOrGetValue ( valueAccessor , datum , index ) ; return ( < g data - tip = { tooltip && tooltip ( datum ) } > < circle style = { style } cx = { x } cy = { y } r = { radius } / > < /g>); } ; export class SpiralComponent extends React . Component < Props > { static defaultProps = { value : d => d , } ; render ( ) { const { className , style , additionalElements , data , value , fill , fillOpacity , stroke , strokeOpacity , tooltip , getSpiralCoords , size : { width , height } , center = { x : width / 2 , y : height / 2 , } , } = this . props ; const { spacing = Math . min ( Math . min ( width , height ) , 2000 ) * 0.015 } = this . props ; const coords = getSpiralCoords ? getSpiralCoords ( { width , height } ) : getDefaultSpiralCoords ( data , spacing ) ; return ( < > < svg xmlns = "http://www.w3.org/2000/svg" className = { className } style = { style } width = { width } height = { height } > { additionalElements } < g transform = { `translate(${ center . x }, ${ center . y })` } > { data . map ( ( datum , i ) => ( < Circle key = { i } index = { i } datum = { datum } x = { coords [ i ] . x } y = { coords [ i ] . y } value = { value } fill = { fill } fillOpacity = { fillOpacity } stroke = { stroke } strokeOpacity = { strokeOpacity } tooltip = { tooltip } / > ) ) } < /g> < /svg> < Tooltip html / > < />); } } export const Spiral = ResponsiveWrapper ( SpiralComponent ) ;