import React, { useMemo, forwardRef } from 'react' import PropTypes from 'prop-types' import classnames from 'classnames' import { deepMerge,deepClone } from '../../datav/usefull/index' import useAutoResize from '../../datav/use/autoResize' import './style.less' const defaultConfig = { /** * @description Chart data * @type {Array} * @default data = [] */ data: [], /** * @description Chart img * @type {Array} * @default img = [] */ img: [], /** * @description Chart font size * @type {Number} * @default fontSize = 12 */ fontSize: 12, /** * @description Img side length * @type {Number} * @default imgSideLength = 30 */ imgSideLength: 30, /** * @description Column color * @type {String} * @default columnColor = 'rgba(0, 194, 255, 0.4)' */ columnColor: 'rgba(0, 194, 255, 0.4)', /** * @description Text color * @type {String} * @default textColor = '#fff' */ textColor: '#fff', /** * @description Show value * @type {Boolean} * @default showValue = false */ showValue: false } function getData(mergedConfig) { let { data } = mergedConfig data = deepClone(data, true) data.sort(({ value: a }, { value: b }) => { if (a > b) return -1 if (a < b) return 1 if (a === b) return 0 }) const max = data[0] ? data[0].value : 10 data = data.map(item => ({ ...item, percent: item.value / max })) return data } const ConicalColumnChart = forwardRef(({ config = {}, className, style }, ref) => { const { width, height, domRef } = useAutoResize(ref) const { mergedConfig, column } = useMemo(calcData, [config, width, height]) function calcData() { const mergedConfig = deepMerge(deepClone(defaultConfig, true), config || {}) mergedConfig.data = getData(mergedConfig) return { mergedConfig, column: getColumn(mergedConfig) } } function getColumn(mergedConfig) { const { imgSideLength, fontSize, data } = mergedConfig const itemNum = data.length const gap = width / (itemNum + 1) const useAbleHeight = height - imgSideLength - fontSize - 5 const svgBottom = height - fontSize - 5 return data.map((item, i) => { const { percent } = item const middleXPos = gap * (i + 1) const leftXPos = gap * i const rightXpos = gap * (i + 2) const middleYPos = svgBottom - useAbleHeight * percent const controlYPos = useAbleHeight * percent * 0.6 + middleYPos const d = ` M${leftXPos}, ${svgBottom} Q${middleXPos}, ${controlYPos} ${middleXPos},${middleYPos} M${middleXPos},${middleYPos} Q${middleXPos}, ${controlYPos} ${rightXpos},${svgBottom} L${leftXPos}, ${svgBottom} Z ` const textY = (svgBottom + middleYPos) / 2 + fontSize / 2 return { ...item, d, x: middleXPos, y: middleYPos, textY } }) } const classNames = useMemo( () => classnames('dv-conical-column-chart', className), [className] ) return (
{column.map((item, i) => ( {item.name} {!!mergedConfig.img.length && ( )} {mergedConfig.showValue && ( {item.value} )} ))}
) }) ConicalColumnChart.propTypes = { config: PropTypes.object, className: PropTypes.string, style: PropTypes.object } export default ConicalColumnChart