fileOverview import React , { PureComponent , SVGProps } from 'react' ; import _ from 'lodash' ; import { symbol as shapeSymbol , symbolCircle , symbolCross , symbolDiamond , symbolSquare , symbolStar , symbolTriangle , symbolWye , SymbolType as D3SymbolType , } from 'd3-shape' ; import classNames from 'classnames' ; import { SymbolType , filterProps } from '../util/types' ; type SizeType = 'area' | 'diameter' ; interface SymbolFactory { [ type ] : D3SymbolType ; } const symbolFactories = { symbolCircle , symbolCross , symbolDiamond , symbolSquare , symbolStar , symbolTriangle , symbolWye , } ; const RADIAN = Math . PI / 180 ; const getSymbolFactory = ( type ) => { const name = `symbol${ _ . upperFirst ( type ) }` ; return symbolFactories [ name ] || symbolCircle ; } ; const calculateAreaSize = ( size , sizeType , type ) => { if ( sizeType === 'area' ) { return size ; } switch ( type ) { case 'cross' : return ( 5 * size * size ) / 9 ; case 'diamond' : return ( 0.5 * size * size ) / Math . sqrt ( 3 ) ; case 'square' : return size * size ; case 'star' : { const angle = 18 * RADIAN ; return 1.25 * size * size * ( Math . tan ( angle ) - Math . tan ( angle * 2 ) * Math . tan ( angle ) ** 2 ) ; } case 'triangle' : return ( Math . sqrt ( 3 ) * size * size ) / 4 ; case 'wye' : return ( ( 21 - 10 * Math . sqrt ( 3 ) ) * size * size ) / 8 ; default : return ( Math . PI * size * size ) / 4 ; } } ; interface SymbolsProp { className ? : string ; type : SymbolType ; cx ? : number ; cy ? : number ; size ? : number ; sizeType ? : SizeType ; } export type Props = SVGProps < SVGPathElement > & SymbolsProp ; export class Symbols extends PureComponent < Props > { static defaultProps = { type : 'circle' , size : 64 , sizeType : 'area' , } ; static registerSymbol = ( key , factory ) => { symbolFactories [ `symbol${ _ . upperFirst ( key ) }` ] = factory ; } ; return { String } getPath ( ) { const { size , sizeType , type } = this . props ; const symbolFactory = getSymbolFactory ( type ) ; const symbol = shapeSymbol ( ) . type ( symbolFactory ) . size ( calculateAreaSize ( size , sizeType , type ) ) ; return symbol ( ) ; } render ( ) { const { className , cx , cy , size } = this . props ; if ( cx === + cx && cy === + cy && size === + size ) { return ( < path { ... filterProps ( this . props , true ) } className = { classNames ( 'recharts-symbols' , className ) } transform = { `translate(${ cx }, ${ cy })` } d = { this . getPath ( ) } / > ) ; } return null ; } }