import React, { useEffect, useState, useRef, useMemo } from 'react' import PropTypes from 'prop-types' import classnames from 'classnames' import { deepMerge,deepClone } from '../../datav/usefull/index' import { uuid } from '../../datav/util' import './style.less' const defaultConfig = { /** * @description Value * @type {Number} * @default value = 0 */ value: 0, /** * @description Colors (hex|rgb|rgba|color keywords) * @type {Array} * @default colors = ['#00BAFF', '#3DE7C9'] * @example colors = ['#000', 'rgb(0, 0, 0)', 'rgba(0, 0, 0, 1)', 'red'] */ colors: ['#3DE7C9', '#00BAFF'], /** * @description Border width * @type {Number} * @default borderWidth = 3 */ borderWidth: 3, /** * @description Gap between border and pond * @type {Number} * @default borderGap = 3 */ borderGap: 3, /** * @description Line dash * @type {Array} * @default lineDash = [5, 1] */ lineDash: [5, 1], /** * @description Text color * @type {String} * @default textColor = '#fff' */ textColor: '#fff', /** * @description Border radius * @type {Number} * @default borderRadius = 5 */ borderRadius: 5, /** * @description Local Gradient * @type {Boolean} * @default localGradient = false * @example localGradient = false | true */ localGradient: false, /** * @description Formatter * @type {String} * @default formatter = '{value}%' */ formatter: '{value}%' } const PercentPond = ({ config = {}, className, style }) => { const domRef = useRef(null) const { gradientId1, gradientId2 } = useRef({ gradientId1: `percent-pond-gradientId1-${uuid()}`, gradientId2: `percent-pond-gradientId2-${uuid()}` }).current const [{ width, height, mergedConfig }, setState] = useState({ width: 0, height: 0, mergedConfig: null }) const rectWidth = useMemo(() => { if (!mergedConfig) return 0 const { borderWidth } = mergedConfig return width - borderWidth }, [mergedConfig, width]) const rectHeight = useMemo(() => { if (!mergedConfig) return 0 const { borderWidth } = mergedConfig return height - borderWidth }, [mergedConfig, height]) const points = useMemo(() => { const halfHeight = height / 2 if (!mergedConfig) return `0, ${halfHeight} 0, ${halfHeight}` const { borderWidth, borderGap, value } = mergedConfig const polylineLength = ((width - (borderWidth + borderGap) * 2) / 100) * value return ` ${borderWidth + borderGap}, ${halfHeight} ${borderWidth + borderGap + polylineLength}, ${halfHeight + 0.001} ` }, [mergedConfig, width, height]) const polylineWidth = useMemo(() => { if (!mergedConfig) return 0 const { borderWidth, borderGap } = mergedConfig return height - (borderWidth + borderGap) * 2 }, [mergedConfig, height]) const linearGradient = useMemo(() => { if (!mergedConfig) return [] const { colors } = mergedConfig const colorNum = colors.length const colorOffsetGap = 100 / (colorNum - 1) return colors.map((c, i) => [colorOffsetGap * i, c]) }, [mergedConfig]) const polylineGradient = useMemo(() => { if (!mergedConfig) return gradientId2 if (mergedConfig.localGradient) return gradientId1 return gradientId2 }, [gradientId1, gradientId2, mergedConfig]) const gradient2XPos = useMemo(() => { if (!mergedConfig) return '100%' const { value } = mergedConfig return `${200 - value}%` }, [mergedConfig]) const details = useMemo(() => { if (!mergedConfig) return '' const { value, formatter } = mergedConfig return formatter.replace('{value}', value) }, [mergedConfig]) useEffect(() => { const { clientWidth: width, clientHeight: height } = domRef.current setState({ width, height, mergedConfig: deepMerge(deepClone(defaultConfig, true), config || {}) }) }, [config]) const classNames = useMemo(() => classnames('dv-percent-pond', className), [ className ]) return (
{linearGradient.map(lc => ( ))} {linearGradient.map(lc => ( ))} 0 ? rectWidth : 0} height={rectHeight > 0 ? rectHeight : 0} /> {details}
) } PercentPond.propTypes = { config: PropTypes.object, className: PropTypes.string, style: PropTypes.object } export default PercentPond