From da2f08799c614c1d9e3b17aca94ed9710a4fe4db Mon Sep 17 00:00:00 2001 From: Abhinandan-Kushwaha Date: Sat, 2 Jul 2022 21:56:09 +0530 Subject: [PATCH] Added arrow to Line and Area charts --- demos/arrowProps.png | Bin 0 -> 17863 bytes demos/lineArrow.png | Bin 0 -> 20747 bytes docs/BarChart/BarChartProps.md | 72 ++++ docs/LineChart/LineChartProps.md | 63 ++- package.json | 2 +- src/BarChart/index.tsx | 134 +++++- src/LineChart/index.tsx | 678 +++++++++++++++++++++++++++---- 7 files changed, 856 insertions(+), 93 deletions(-) create mode 100644 demos/arrowProps.png create mode 100644 demos/lineArrow.png diff --git a/demos/arrowProps.png b/demos/arrowProps.png new file mode 100644 index 0000000000000000000000000000000000000000..b294da274936b76a08d6c4bf7b5a1075320fc1ef GIT binary patch literal 17863 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 literal 0 HcmV?d00001 diff --git a/demos/lineArrow.png b/demos/lineArrow.png new file mode 100644 index 0000000000000000000000000000000000000000..c804392712145ccd0628046fe2301b85ae0930f3 GIT binary patch literal 20747 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 literal 0 HcmV?d00001 diff --git a/docs/BarChart/BarChartProps.md b/docs/BarChart/BarChartProps.md index 1d515c6..6cd7fc9 100644 --- a/docs/BarChart/BarChartProps.md +++ b/docs/BarChart/BarChartProps.md @@ -33,6 +33,78 @@ | leftShiftForTooltip | number | The distance by which the tooltip component should shift towards left | 0 | | leftShiftForLastIndexTooltip | number | The distance by which the tooltip component of the last bar should shift towards left | 0 | +#### lineConfig + +The lineConfig prop describes the properties of the line chart that is displayed when we set the showLine prop to true. The properties allowed by the lineConfig prop are- + +```js +type lineConfigType = { + initialSpacing?: number; + curved?: Boolean; + isAnimated?: Boolean; + delay?: number; + thickness?: number; + color?: ColorValue | String | any; + hideDataPoints?: Boolean; + dataPointsShape?: String; + dataPointsWidth?: number; + dataPointsHeight?: number; + dataPointsColor?: ColorValue | String | any; + dataPointsRadius?: number; + textColor?: ColorValue | String | any; + textFontSize?: number; + textShiftX?: number; + textShiftY?: number; + shiftY?: number; + startIndex?: number; + endIndex?: number; + showArrow?: boolean; + arrowConfig?: arrowType; +}; +type arrowType = { + length?: number; + width?: number; + strokeWidth?: number; + strokeColor?: string; + fillColor?: string; + showArrowBase?: boolean; +}; +``` + +The default value of the lineConfig object is - + +```js +defaultLineConfig = { + initialSpacing: initialSpacing, + curved: false, + isAnimated: false, + thickness: 1, + color: 'black', + hideDataPoints: false, + dataPointsShape: 'circular', + dataPointsWidth: 2, + dataPointsHeight: 2, + dataPointsColor: 'black', + dataPointsRadius: 3, + textColor: 'gray', + textFontSize: 10, + textShiftX: 0, + textShiftY: 0, + shiftY: 0, + delay: 0, + startIndex: 0, + endIndex: lineData.length - 1, + showArrow: false, + arrowConfig: { + length: 10, + width: 10, + strokeWidth: 1, + strokeColor: 'black', + fillColor: 'none', + showArrowBase: true, + }, + }; +``` --- **Alert!**\ diff --git a/docs/LineChart/LineChartProps.md b/docs/LineChart/LineChartProps.md index ff962e4..32c2fbe 100644 --- a/docs/LineChart/LineChartProps.md +++ b/docs/LineChart/LineChartProps.md @@ -181,6 +181,7 @@ type referenceConfigType = { | Prop | Type | Description | Default value | | ---------- | ---------- | ------------------------------------------------------------ | ---------------------- | +| curved | Boolean | To show curved line joining the data points | false | | color | ColorValue | Color of the lines joining the data points | black | | color1 | ColorValue | Color of the lines joining the first set of data points | color (from props) | | color2 | ColorValue | Color of the lines joining the second set of data points | color (from props) | @@ -211,12 +212,62 @@ type referenceConfigType = { | startIndex4 | number | Start index for data line 4 (used to display data lines having breaks) | 0 | | startIndex5 | number | Start index for data line 5 (used to display data lines having breaks) | 0 | | endIndex | number | End index for data line (used to display data lines having breaks) | data.length -1 | -| endIndex1 | number | End index for data line 1 (used to display data lines having breaks) | data.length -1 | -| endIndex2 | number | End index for data line 2 (used to display data lines having breaks) | data2.length -1 | -| endIndex3 | number | End index for data line 3 (used to display data lines having breaks) | data3.length -1 | -| endIndex4 | number | End index for data line 4 (used to display data lines having breaks) | data3.length -1 | -| endIndex5 | number | End index for data line 5 (used to display data lines having breaks) | data3.length -1 | -| curved | Boolean | To show curved line joining the data points | false | +| endIndex1 | number | End index for data line 1 (used to display data lines having breaks) | data.length -1 | +| endIndex2 | number | End index for data line 2 (used to display data lines having breaks) | data2.length -1 | +| endIndex3 | number | End index for data line 3 (used to display data lines having breaks) | data3.length -1 | +| endIndex4 | number | End index for data line 4 (used to display data lines having breaks) | data3.length -1 | +| endIndex5 | number | End index for data line 5 (used to display data lines having breaks) | data3.length -1 | + +## The arrow + +Some Line charts have an arrow at the end of the line. Here's an example- + + + +To display the arrrow at the end of the line, just pass the showArrows or showArrow{n} prop. +The properties of the arrow can controlled with the arrowConfig prop. +### Understanding the arrow- + + + +| showArrows | boolean | To show an arrow at the end of each data line | false | +| arrowConfig | arrowType | Object describing the properties of the arrows like length, width, strokeWidth, strokeColor, fillColor | defaultArrowConfig | +| showArrow1 | boolean | To show an arrow at the end of the first data line | false | +| arrowConfig1 | arrowType | Object describing the properties of the first arrow | defaultArrowConfig | +| showArrow2 | boolean | To show an arrow at the end of the second data line | false | +| arrowConfig2 | arrowType | Object describing the properties of the second arrow | defaultArrowConfig | +| showArrow3 | boolean | To show an arrow at the end of the third data line | false | +| arrowConfig3 | arrowType | Object describing the properties of the third arrow | defaultArrowConfig | +| showArrow4 | boolean | To show an arrow at the end of the fourth data line | false | +| arrowConfig4 | arrowType | Object describing the properties of the fourth arrow | defaultArrowConfig | +| showArrow5 | boolean | To show an arrow at the end of the fifth data line | false | +| arrowConfig5 | arrowType | Object describing the properties of the fifth arrow | defaultArrowConfig | + +The arrowConfig has the properties allowed by the arrowType- + +```js +type arrowType = { + length?: number; + width?: number; + strokeWidth?: number; + strokeColor?: string; + fillColor?: string; + showArrowBase?: boolean; +}; +``` + +The default values of these properties are- + +```js +defaultArrowConfig = { + length: 10, + width: 10, + strokeWidth: thickness1, + strokeColor: color1, + fillColor: 'none', + showArrowBase: true, + }; +``` --- diff --git a/package.json b/package.json index 8dfccbb..42db7cf 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "react-native-gifted-charts", - "version": "1.2.39", + "version": "1.2.40", "description": "The most complete library for Bar, Line, Area, Pie, Donut and Stacked Bar charts in React Native. Allows 2D, 3D, gradient, animations and live data updates.", "main": "src/index.tsx", "files": [ diff --git a/src/BarChart/index.tsx b/src/BarChart/index.tsx index e041209..631eb16 100644 --- a/src/BarChart/index.tsx +++ b/src/BarChart/index.tsx @@ -168,6 +168,16 @@ type lineConfigType = { shiftY?: number; startIndex?: number; endIndex?: number; + showArrow?: boolean; + arrowConfig?: arrowType; +}; +type arrowType = { + length?: number; + width?: number; + strokeWidth?: number; + strokeColor?: string; + fillColor?: string; + showArrowBase?: boolean; }; type referenceConfigType = { thickness: number; @@ -207,6 +217,7 @@ type itemType = { export const BarChart = (props: PropTypes) => { const scrollRef = useRef(); const [points, setPoints] = useState(''); + const [arrowPoints, setArrowPoints] = useState(''); const [selectedIndex, setSelectedIndex] = useState(-1); const showLine = props.showLine || false; const initialSpacing = @@ -244,6 +255,15 @@ export const BarChart = (props: PropTypes) => { delay: 0, startIndex: 0, endIndex: lineData.length - 1, + showArrow: false, + arrowConfig: { + length: 10, + width: 10, + strokeWidth: 1, + strokeColor: 'black', + fillColor: 'none', + showArrowBase: true, + }, }; const lineConfig = props.lineConfig ? { @@ -282,6 +302,32 @@ export const BarChart = (props: PropTypes) => { props.lineConfig.endIndex === 0 ? 0 : props.lineConfig.endIndex || defaultLineConfig.endIndex, + + showArrow: props.lineConfig.showArrow ?? defaultLineConfig.showArrow, + arrowConfig: { + length: + props.lineConfig.arrowConfig?.length ?? + defaultLineConfig.arrowConfig.length, + width: + props.lineConfig.arrowConfig?.width ?? + defaultLineConfig.arrowConfig.width, + + strokeWidth: + props.lineConfig.arrowConfig?.strokeWidth ?? + defaultLineConfig.arrowConfig.strokeWidth, + + strokeColor: + props.lineConfig.arrowConfig?.strokeColor ?? + defaultLineConfig.arrowConfig.strokeColor, + + fillColor: + props.lineConfig.arrowConfig?.fillColor ?? + defaultLineConfig.arrowConfig.fillColor, + + showArrowBase: + props.lineConfig.arrowConfig?.showArrowBase ?? + defaultLineConfig.arrowConfig.showArrowBase, + }, } : defaultLineConfig; const containerHeight = props.height || 200; @@ -465,6 +511,52 @@ export const BarChart = (props: PropTypes) => { }, [animationDuration, widthValue]); // console.log('olddata', oldData); + const getArrowPoints = ( + arrowTipX, + arrowTipY, + x1, + y1, + arrowLength, + arrowWidth, + showArrowBase, + ) => { + let dataLineSlope = (arrowTipY - y1) / (arrowTipX - x1); + let d = arrowLength; + let d2 = arrowWidth / 2; + let interSectionX = + arrowTipX - Math.sqrt((d * d) / (dataLineSlope * dataLineSlope + 1)); + let interSectionY = arrowTipY - dataLineSlope * (arrowTipX - interSectionX); + + let arrowBasex1, arrowBaseY1, arrowBaseX2, arrowBaseY2; + if (dataLineSlope === 0) { + arrowBasex1 = interSectionX; + arrowBaseY1 = interSectionY - d2; + arrowBaseX2 = interSectionX; + arrowBaseY2 = interSectionY + d2; + } else { + let arrowBaseSlope = -1 / dataLineSlope; + arrowBasex1 = + interSectionX - + Math.sqrt((d2 * d2) / (arrowBaseSlope * arrowBaseSlope + 1)); + arrowBaseY1 = + interSectionY - arrowBaseSlope * (interSectionX - arrowBasex1); + + arrowBaseX2 = + interSectionX + + Math.sqrt((d2 * d2) / (arrowBaseSlope * arrowBaseSlope + 1)); + arrowBaseY2 = + interSectionY + arrowBaseSlope * (interSectionX - arrowBasex1); + } + let arrowPoints = ` M${interSectionX} ${interSectionY}`; + arrowPoints += ` ${showArrowBase ? 'L' : 'M'}${arrowBasex1} ${arrowBaseY1}`; + arrowPoints += ` L${arrowTipX} ${arrowTipY}`; + arrowPoints += ` M${interSectionX} ${interSectionY}`; + arrowPoints += ` ${showArrowBase ? 'L' : 'M'}${arrowBaseX2} ${arrowBaseY2}`; + arrowPoints += ` L${arrowTipX} ${arrowTipY}`; + + return arrowPoints; + }; + useEffect(() => { if (showLine) { let pp = ''; @@ -488,6 +580,27 @@ export const BarChart = (props: PropTypes) => { ' '; } setPoints(pp.replace('L', 'M')); + if (lineData.length > 1 && lineConfig.showArrow) { + let ppArray = pp.trim().split(' '); + let arrowTipY = parseInt(ppArray[ppArray.length - 1]); + let arrowTipX = parseInt( + ppArray[ppArray.length - 2].replace('L', ''), + ); + let y1 = parseInt(ppArray[ppArray.length - 3]); + let x1 = parseInt(ppArray[ppArray.length - 4].replace('L', '')); + + let arrowPoints = getArrowPoints( + arrowTipX, + arrowTipY, + x1, + y1, + lineConfig.arrowConfig.length, + lineConfig.arrowConfig.width, + lineConfig.arrowConfig.showArrowBase, + ); + + setArrowPoints(arrowPoints); + } } else { let p1Array = []; for (let i = 0; i < lineData.length; i++) { @@ -532,11 +645,14 @@ export const BarChart = (props: PropTypes) => { lineConfig.startIndex, lineConfig.endIndex, maxValue, - // moveBar, props.barWidth, showLine, spacing, yAxisLabelWidth, + lineConfig.showArrow, + lineConfig.arrowConfig.length, + lineConfig.arrowConfig.width, + lineConfig.arrowConfig.showArrowBase, ]); const defaultReferenceConfig = { @@ -1334,6 +1450,14 @@ export const BarChart = (props: PropTypes) => { {!lineConfig.hideDataPoints ? renderDataPoints() : renderSpecificDataPoints(data)} + {lineConfig.showArrow && ( + + )} ); @@ -1362,6 +1486,14 @@ export const BarChart = (props: PropTypes) => { {!lineConfig.hideDataPoints ? renderDataPoints() : renderSpecificDataPoints(data)} + {lineConfig.showArrow && ( + + )} ); diff --git a/src/LineChart/index.tsx b/src/LineChart/index.tsx index 5e1830b..8ef5ecc 100644 --- a/src/LineChart/index.tsx +++ b/src/LineChart/index.tsx @@ -275,6 +275,26 @@ type propTypes = { labelsExtraHeight?: number; adjustToWidth?: Boolean; getPointerProps?: Function; + showArrows?: boolean; + arrowConfig?: arrowType; + showArrow1?: boolean; + arrowConfig1?: arrowType; + showArrow2?: boolean; + arrowConfig2?: arrowType; + showArrow3?: boolean; + arrowConfig3?: arrowType; + showArrow4?: boolean; + arrowConfig4?: arrowType; + showArrow5?: boolean; + arrowConfig5?: arrowType; +}; +type arrowType = { + length?: number; + width?: number; + strokeWidth?: number; + strokeColor?: string; + fillColor?: string; + showArrowBase?: boolean; }; type referenceConfigType = { thickness: number; @@ -374,6 +394,11 @@ type Pointer = { export const LineChart = (props: propTypes) => { const scrollRef = useRef(); const [scrollX, setScrollX] = useState(0); + const [arrow1Points, setArrow1Points] = useState(''); + const [arrow2Points, setArrow2Points] = useState(''); + const [arrow3Points, setArrow3Points] = useState(''); + const [arrow4Points, setArrow4Points] = useState(''); + const [arrow5Points, setArrow5Points] = useState(''); const [pointerIndex, setPointerIndex] = useState(-1); const [pointerX, setPointerX] = useState(0); const [pointerY, setPointerY] = useState(0); @@ -830,6 +855,270 @@ export const LineChart = (props: propTypes) => { labelsAppear, ]); + const thickness1 = + props.thickness1 === 0 ? 0 : props.thickness1 || props.thickness || 1; + const thickness2 = + props.thickness2 === 0 ? 0 : props.thickness2 || props.thickness || 1; + const thickness3 = + props.thickness3 === 0 ? 0 : props.thickness3 || props.thickness || 1; + const thickness4 = + props.thickness4 === 0 ? 0 : props.thickness4 || props.thickness || 1; + const thickness5 = + props.thickness5 === 0 ? 0 : props.thickness5 || props.thickness || 1; + + const zIndex1 = props.zIndex1 || 0; + const zIndex2 = props.zIndex2 || 0; + const zIndex3 = props.zIndex3 || 0; + const zIndex4 = props.zIndex4 || 0; + const zIndex5 = props.zIndex5 || 0; + + const strokeDashArray1 = props.strokeDashArray1 || props.strokeDashArray; + const strokeDashArray2 = props.strokeDashArray2 || props.strokeDashArray; + const strokeDashArray3 = props.strokeDashArray3 || props.strokeDashArray; + const strokeDashArray4 = props.strokeDashArray4 || props.strokeDashArray; + const strokeDashArray5 = props.strokeDashArray5 || props.strokeDashArray; + + const rotateLabel = props.rotateLabel || false; + const isAnimated = props.isAnimated || false; + const hideDataPoints1 = + props.hideDataPoints || props.hideDataPoints1 || false; + const hideDataPoints2 = + props.hideDataPoints || props.hideDataPoints2 || false; + const hideDataPoints3 = + props.hideDataPoints || props.hideDataPoints3 || false; + const hideDataPoints4 = + props.hideDataPoints || props.hideDataPoints4 || false; + const hideDataPoints5 = + props.hideDataPoints || props.hideDataPoints5 || false; + + const color1 = props.color1 || props.color || 'black'; + const color2 = props.color2 || props.color || 'black'; + const color3 = props.color3 || props.color || 'black'; + const color4 = props.color4 || props.color || 'black'; + const color5 = props.color5 || props.color || 'black'; + + const startFillColor1 = + props.startFillColor1 || props.startFillColor || 'gray'; + const endFillColor1 = props.endFillColor1 || props.endFillColor || 'white'; + const startOpacity = props.startOpacity === 0 ? 0 : props.startOpacity || 1; + const endOpacity = props.endOpacity === 0 ? 0 : props.endOpacity || 1; + const startOpacity1 = + props.startOpacity1 === 0 ? 0 : props.startOpacity1 || startOpacity; + const endOpacity1 = + props.endOpacity1 === 0 ? 0 : props.endOpacity1 || endOpacity; + + const startFillColor2 = + props.startFillColor2 || props.startFillColor || 'gray'; + const endFillColor2 = props.endFillColor2 || props.endFillColor || 'white'; + const startOpacity2 = + props.startOpacity2 === 0 ? 0 : props.startOpacity2 || startOpacity; + const endOpacity2 = + props.endOpacity2 === 0 ? 0 : props.endOpacity2 || endOpacity; + + const startFillColor3 = + props.startFillColor3 || props.startFillColor || 'gray'; + const endFillColor3 = props.endFillColor3 || props.endFillColor || 'white'; + const startOpacity3 = + props.startOpacity3 === 0 ? 0 : props.startOpacity3 || startOpacity; + const endOpacity3 = + props.endOpacity3 === 0 ? 0 : props.endOpacity3 || endOpacity; + + const startFillColor4 = + props.startFillColor4 || props.startFillColor || 'gray'; + const endFillColor4 = props.endFillColor4 || props.endFillColor || 'white'; + const startOpacity4 = + props.startOpacity4 === 0 ? 0 : props.startOpacity4 || startOpacity; + const endOpacity4 = + props.endOpacity4 === 0 ? 0 : props.endOpacity4 || endOpacity; + + const startFillColor5 = + props.startFillColor5 || props.startFillColor || 'gray'; + const endFillColor5 = props.endFillColor5 || props.endFillColor || 'white'; + const startOpacity5 = + props.startOpacity5 === 0 ? 0 : props.startOpacity5 || startOpacity; + const endOpacity5 = + props.endOpacity5 === 0 ? 0 : props.endOpacity5 || endOpacity; + + const defaultArrowConfig = { + length: 10, + width: 10, + strokeWidth: thickness1, + strokeColor: color1, + fillColor: 'none', + showArrowBase: true, + }; + + const arrowLength1 = + props.arrowConfig1?.length ?? + props.arrowConfig?.length ?? + defaultArrowConfig.length; + const arrowWidth1 = + props.arrowConfig1?.width ?? + props.arrowConfig?.width ?? + defaultArrowConfig.width; + const arrowStrokeWidth1 = + props.arrowConfig1?.strokeWidth ?? + props.arrowConfig?.strokeWidth ?? + defaultArrowConfig.strokeWidth; + const arrowStrokeColor1 = + props.arrowConfig1?.strokeColor ?? + props.arrowConfig?.strokeColor ?? + defaultArrowConfig.strokeColor; + const arrowFillColor1 = + props.arrowConfig1?.fillColor ?? + props.arrowConfig?.fillColor ?? + defaultArrowConfig.fillColor; + const showArrowBase1 = + props.arrowConfig1?.showArrowBase ?? + props.arrowConfig?.showArrowBase ?? + defaultArrowConfig.showArrowBase; + + const arrowLength2 = + props.arrowConfig2?.length ?? + props.arrowConfig?.length ?? + defaultArrowConfig.length; + const arrowWidth2 = + props.arrowConfig2?.width ?? + props.arrowConfig?.width ?? + defaultArrowConfig.width; + const arrowStrokeWidth2 = + props.arrowConfig2?.strokeWidth ?? + props.arrowConfig?.strokeWidth ?? + defaultArrowConfig.strokeWidth; + const arrowStrokeColor2 = + props.arrowConfig2?.strokeColor ?? + props.arrowConfig?.strokeColor ?? + defaultArrowConfig.strokeColor; + const arrowFillColor2 = + props.arrowConfig2?.fillColor ?? + props.arrowConfig?.fillColor ?? + defaultArrowConfig.fillColor; + const showArrowBase2 = + props.arrowConfig2?.showArrowBase ?? + props.arrowConfig?.showArrowBase ?? + defaultArrowConfig.showArrowBase; + + const arrowLength3 = + props.arrowConfig3?.length ?? + props.arrowConfig?.length ?? + defaultArrowConfig.length; + const arrowWidth3 = + props.arrowConfig3?.width ?? + props.arrowConfig?.width ?? + defaultArrowConfig.width; + const arrowStrokeWidth3 = + props.arrowConfig3?.strokeWidth ?? + props.arrowConfig?.strokeWidth ?? + defaultArrowConfig.strokeWidth; + const arrowStrokeColor3 = + props.arrowConfig3?.strokeColor ?? + props.arrowConfig?.strokeColor ?? + defaultArrowConfig.strokeColor; + const arrowFillColor3 = + props.arrowConfig3?.fillColor ?? + props.arrowConfig?.fillColor ?? + defaultArrowConfig.fillColor; + const showArrowBase3 = + props.arrowConfig3?.showArrowBase ?? + props.arrowConfig?.showArrowBase ?? + defaultArrowConfig.showArrowBase; + + const arrowLength4 = + props.arrowConfig4?.length ?? + props.arrowConfig?.length ?? + defaultArrowConfig.length; + const arrowWidth4 = + props.arrowConfig4?.width ?? + props.arrowConfig?.width ?? + defaultArrowConfig.width; + const arrowStrokeWidth4 = + props.arrowConfig4?.strokeWidth ?? + props.arrowConfig?.strokeWidth ?? + defaultArrowConfig.strokeWidth; + const arrowStrokeColor4 = + props.arrowConfig4?.strokeColor ?? + props.arrowConfig?.strokeColor ?? + defaultArrowConfig.strokeColor; + const arrowFillColor4 = + props.arrowConfig4?.fillColor ?? + props.arrowConfig?.fillColor ?? + defaultArrowConfig.fillColor; + const showArrowBase4 = + props.arrowConfig4?.showArrowBase ?? + props.arrowConfig?.showArrowBase ?? + defaultArrowConfig.showArrowBase; + + const arrowLength5 = + props.arrowConfig5?.length ?? + props.arrowConfig?.length ?? + defaultArrowConfig.length; + const arrowWidth5 = + props.arrowConfig5?.width ?? + props.arrowConfig?.width ?? + defaultArrowConfig.width; + const arrowStrokeWidth5 = + props.arrowConfig5?.strokeWidth ?? + props.arrowConfig?.strokeWidth ?? + defaultArrowConfig.strokeWidth; + const arrowStrokeColor5 = + props.arrowConfig5?.strokeColor ?? + props.arrowConfig?.strokeColor ?? + defaultArrowConfig.strokeColor; + const arrowFillColor5 = + props.arrowConfig5?.fillColor ?? + props.arrowConfig?.fillColor ?? + defaultArrowConfig.fillColor; + const showArrowBase5 = + props.arrowConfig5?.showArrowBase ?? + props.arrowConfig?.showArrowBase ?? + defaultArrowConfig.showArrowBase; + + const getArrowPoints = ( + arrowTipX, + arrowTipY, + x1, + y1, + arrowLength, + arrowWidth, + showArrowBase, + ) => { + let dataLineSlope = (arrowTipY - y1) / (arrowTipX - x1); + let d = arrowLength; + let d2 = arrowWidth / 2; + let interSectionX = + arrowTipX - Math.sqrt((d * d) / (dataLineSlope * dataLineSlope + 1)); + let interSectionY = arrowTipY - dataLineSlope * (arrowTipX - interSectionX); + + let arrowBasex1, arrowBaseY1, arrowBaseX2, arrowBaseY2; + if (dataLineSlope === 0) { + arrowBasex1 = interSectionX; + arrowBaseY1 = interSectionY - d2; + arrowBaseX2 = interSectionX; + arrowBaseY2 = interSectionY + d2; + } else { + let arrowBaseSlope = -1 / dataLineSlope; + arrowBasex1 = + interSectionX - + Math.sqrt((d2 * d2) / (arrowBaseSlope * arrowBaseSlope + 1)); + arrowBaseY1 = + interSectionY - arrowBaseSlope * (interSectionX - arrowBasex1); + + arrowBaseX2 = + interSectionX + + Math.sqrt((d2 * d2) / (arrowBaseSlope * arrowBaseSlope + 1)); + arrowBaseY2 = + interSectionY + arrowBaseSlope * (interSectionX - arrowBasex1); + } + let arrowPoints = ` M${interSectionX} ${interSectionY}`; + arrowPoints += ` ${showArrowBase ? 'L' : 'M'}${arrowBasex1} ${arrowBaseY1}`; + arrowPoints += ` L${arrowTipX} ${arrowTipY}`; + arrowPoints += ` M${interSectionX} ${interSectionY}`; + arrowPoints += ` ${showArrowBase ? 'L' : 'M'}${arrowBaseX2} ${arrowBaseY2}`; + arrowPoints += ` L${arrowTipX} ${arrowTipY}`; + + return arrowPoints; + }; + useEffect(() => { let pp = '', pp2 = '', @@ -847,7 +1136,7 @@ export const LineChart = (props: propTypes) => { 10 - (data[i].value * containerHeight) / maxValue) + ' '; - setPoints(pp.replace('L', 'M')); + // setPoints(pp.replace('L', 'M')); } if (data2.length && i >= startIndex2 && i <= endIndex2) { pp2 += @@ -895,6 +1184,108 @@ export const LineChart = (props: propTypes) => { setPoints4(pp4.replace('L', 'M')); setPoints5(pp5.replace('L', 'M')); + setPoints(pp.replace('L', 'M')); + + if (data.length > 1 && (props.showArrow1 || props.showArrows)) { + let ppArray = pp.trim().split(' '); + let arrowTipY = parseInt(ppArray[ppArray.length - 1]); + let arrowTipX = parseInt(ppArray[ppArray.length - 2].replace('L', '')); + let y1 = parseInt(ppArray[ppArray.length - 3]); + let x1 = parseInt(ppArray[ppArray.length - 4].replace('L', '')); + + let arrowPoints = getArrowPoints( + arrowTipX, + arrowTipY, + x1, + y1, + arrowLength1, + arrowWidth1, + showArrowBase1, + ); + + setArrow1Points(arrowPoints); + } + + if (data2.length > 1 && (props.showArrow2 || props.showArrows)) { + let ppArray = pp2.trim().split(' '); + let arrowTipY = parseInt(ppArray[ppArray.length - 1]); + let arrowTipX = parseInt(ppArray[ppArray.length - 2].replace('L', '')); + let y1 = parseInt(ppArray[ppArray.length - 3]); + let x1 = parseInt(ppArray[ppArray.length - 4].replace('L', '')); + + let arrowPoints = getArrowPoints( + arrowTipX, + arrowTipY, + x1, + y1, + arrowLength2, + arrowWidth2, + showArrowBase2, + ); + + setArrow2Points(arrowPoints); + } + + if (data3.length > 1 && (props.showArrow3 || props.showArrows)) { + let ppArray = pp3.trim().split(' '); + let arrowTipY = parseInt(ppArray[ppArray.length - 1]); + let arrowTipX = parseInt(ppArray[ppArray.length - 2].replace('L', '')); + let y1 = parseInt(ppArray[ppArray.length - 3]); + let x1 = parseInt(ppArray[ppArray.length - 4].replace('L', '')); + + let arrowPoints = getArrowPoints( + arrowTipX, + arrowTipY, + x1, + y1, + arrowLength3, + arrowWidth3, + showArrowBase3, + ); + + setArrow3Points(arrowPoints); + } + + if (data4.length > 1 && (props.showArrow4 || props.showArrows)) { + let ppArray = pp4.trim().split(' '); + let arrowTipY = parseInt(ppArray[ppArray.length - 1]); + let arrowTipX = parseInt(ppArray[ppArray.length - 2].replace('L', '')); + let y1 = parseInt(ppArray[ppArray.length - 3]); + let x1 = parseInt(ppArray[ppArray.length - 4].replace('L', '')); + + let arrowPoints = getArrowPoints( + arrowTipX, + arrowTipY, + x1, + y1, + arrowLength4, + arrowWidth4, + showArrowBase4, + ); + + setArrow4Points(arrowPoints); + } + + if (data5.length > 1 && (props.showArrow5 || props.showArrows)) { + let ppArray = pp5.trim().split(' '); + let arrowTipY = parseInt(ppArray[ppArray.length - 1]); + let arrowTipX = parseInt(ppArray[ppArray.length - 2].replace('L', '')); + let y1 = parseInt(ppArray[ppArray.length - 3]); + let x1 = parseInt(ppArray[ppArray.length - 4].replace('L', '')); + + let arrowPoints = getArrowPoints( + arrowTipX, + arrowTipY, + x1, + y1, + arrowLength5, + arrowWidth5, + showArrowBase5, + ); + + setArrow5Points(arrowPoints); + } + /*************************** For Area Charts *************************/ if (areaChart) { let ppp = '', @@ -1075,18 +1466,115 @@ export const LineChart = (props: propTypes) => { ]); } } + let xx = svgPath(p1Array, bezierCommand); let xx2 = svgPath(p2Array, bezierCommand); let xx3 = svgPath(p3Array, bezierCommand); let xx4 = svgPath(p4Array, bezierCommand); let xx5 = svgPath(p5Array, bezierCommand); // console.log('xx', xx); + setPoints(xx); setPoints2(xx2); setPoints3(xx3); setPoints4(xx4); setPoints5(xx5); + if (data.length > 1 && (props.showArrow1 || props.showArrows)) { + let arrowTipY = p1Array[p1Array.length - 1][1]; + let arrowTipX = p1Array[p1Array.length - 1][0]; + let y1 = p1Array[p1Array.length - 2][1]; + let x1 = p1Array[p1Array.length - 2][0]; + + let arrowPoints = getArrowPoints( + arrowTipX, + arrowTipY, + x1, + y1, + arrowLength1, + arrowWidth1, + showArrowBase1, + ); + + setArrow1Points(arrowPoints); + } + + if (data2.length > 1 && (props.showArrow2 || props.showArrows)) { + let arrowTipY = p2Array[p2Array.length - 1][1]; + let arrowTipX = p2Array[p2Array.length - 1][0]; + let y1 = p2Array[p2Array.length - 2][1]; + let x1 = p2Array[p2Array.length - 2][0]; + + let arrowPoints = getArrowPoints( + arrowTipX, + arrowTipY, + x1, + y1, + arrowLength2, + arrowWidth2, + showArrowBase2, + ); + + setArrow2Points(arrowPoints); + } + + if (data3.length > 1 && (props.showArrow3 || props.showArrows)) { + let arrowTipY = p3Array[p3Array.length - 1][1]; + let arrowTipX = p3Array[p3Array.length - 1][0]; + let y1 = p3Array[p3Array.length - 2][1]; + let x1 = p3Array[p3Array.length - 2][0]; + + let arrowPoints = getArrowPoints( + arrowTipX, + arrowTipY, + x1, + y1, + arrowLength3, + arrowWidth3, + showArrowBase3, + ); + + setArrow2Points(arrowPoints); + } + + if (data4.length > 1 && (props.showArrow4 || props.showArrows)) { + let arrowTipY = p4Array[p4Array.length - 1][1]; + let arrowTipX = p4Array[p4Array.length - 1][0]; + let y1 = p4Array[p4Array.length - 2][1]; + let x1 = p4Array[p4Array.length - 2][0]; + + let arrowPoints = getArrowPoints( + arrowTipX, + arrowTipY, + x1, + y1, + arrowLength4, + arrowWidth4, + showArrowBase4, + ); + + setArrow2Points(arrowPoints); + } + + if (data5.length > 1 && (props.showArrow5 || props.showArrows)) { + let arrowTipY = p5Array[p5Array.length - 1][1]; + let arrowTipX = p5Array[p5Array.length - 1][0]; + let y1 = p5Array[p5Array.length - 2][1]; + let x1 = p5Array[p5Array.length - 2][0]; + + let arrowPoints = getArrowPoints( + arrowTipX, + arrowTipY, + x1, + y1, + arrowLength5, + arrowWidth5, + showArrowBase5, + ); + + setArrow2Points(arrowPoints); + } + /*************************** For Area Charts *************************/ // console.log('xx---->>>', xx) @@ -1279,6 +1767,27 @@ export const LineChart = (props: propTypes) => { endIndex4, startIndex5, endIndex5, + arrowLength1, + arrowWidth1, + showArrowBase1, + props.showArrow1, + props.showArrows, + props.showArrow2, + props.showArrow3, + props.showArrow4, + props.showArrow5, + arrowLength2, + arrowWidth2, + showArrowBase2, + arrowLength3, + arrowWidth3, + showArrowBase3, + arrowLength4, + arrowWidth4, + showArrowBase4, + arrowLength5, + arrowWidth5, + showArrowBase5, ]); const horizSections = [{value: '0'}]; @@ -1287,90 +1796,6 @@ export const LineChart = (props: propTypes) => { const stepValue = props.stepValue || maxValue / noOfSections; const noOfSectionsBelowXAxis = props.noOfSectionsBelowXAxis || -minValue / stepValue; - const thickness1 = - props.thickness1 === 0 ? 0 : props.thickness1 || props.thickness || 1; - const thickness2 = - props.thickness2 === 0 ? 0 : props.thickness2 || props.thickness || 1; - const thickness3 = - props.thickness3 === 0 ? 0 : props.thickness3 || props.thickness || 1; - const thickness4 = - props.thickness4 === 0 ? 0 : props.thickness4 || props.thickness || 1; - const thickness5 = - props.thickness5 === 0 ? 0 : props.thickness5 || props.thickness || 1; - - const zIndex1 = props.zIndex1 || 0; - const zIndex2 = props.zIndex2 || 0; - const zIndex3 = props.zIndex3 || 0; - const zIndex4 = props.zIndex4 || 0; - const zIndex5 = props.zIndex5 || 0; - - const strokeDashArray1 = props.strokeDashArray1 || props.strokeDashArray; - const strokeDashArray2 = props.strokeDashArray2 || props.strokeDashArray; - const strokeDashArray3 = props.strokeDashArray3 || props.strokeDashArray; - const strokeDashArray4 = props.strokeDashArray4 || props.strokeDashArray; - const strokeDashArray5 = props.strokeDashArray5 || props.strokeDashArray; - - const rotateLabel = props.rotateLabel || false; - const isAnimated = props.isAnimated || false; - const hideDataPoints1 = - props.hideDataPoints || props.hideDataPoints1 || false; - const hideDataPoints2 = - props.hideDataPoints || props.hideDataPoints2 || false; - const hideDataPoints3 = - props.hideDataPoints || props.hideDataPoints3 || false; - const hideDataPoints4 = - props.hideDataPoints || props.hideDataPoints4 || false; - const hideDataPoints5 = - props.hideDataPoints || props.hideDataPoints5 || false; - - const color1 = props.color1 || props.color || 'black'; - const color2 = props.color2 || props.color || 'black'; - const color3 = props.color3 || props.color || 'black'; - const color4 = props.color4 || props.color || 'black'; - const color5 = props.color5 || props.color || 'black'; - - const startFillColor1 = - props.startFillColor1 || props.startFillColor || 'gray'; - const endFillColor1 = props.endFillColor1 || props.endFillColor || 'white'; - const startOpacity = props.startOpacity === 0 ? 0 : props.startOpacity || 1; - const endOpacity = props.endOpacity === 0 ? 0 : props.endOpacity || 1; - const startOpacity1 = - props.startOpacity1 === 0 ? 0 : props.startOpacity1 || startOpacity; - const endOpacity1 = - props.endOpacity1 === 0 ? 0 : props.endOpacity1 || endOpacity; - - const startFillColor2 = - props.startFillColor2 || props.startFillColor || 'gray'; - const endFillColor2 = props.endFillColor2 || props.endFillColor || 'white'; - const startOpacity2 = - props.startOpacity2 === 0 ? 0 : props.startOpacity2 || startOpacity; - const endOpacity2 = - props.endOpacity2 === 0 ? 0 : props.endOpacity2 || endOpacity; - - const startFillColor3 = - props.startFillColor3 || props.startFillColor || 'gray'; - const endFillColor3 = props.endFillColor3 || props.endFillColor || 'white'; - const startOpacity3 = - props.startOpacity3 === 0 ? 0 : props.startOpacity3 || startOpacity; - const endOpacity3 = - props.endOpacity3 === 0 ? 0 : props.endOpacity3 || endOpacity; - - const startFillColor4 = - props.startFillColor4 || props.startFillColor || 'gray'; - const endFillColor4 = props.endFillColor4 || props.endFillColor || 'white'; - const startOpacity4 = - props.startOpacity4 === 0 ? 0 : props.startOpacity4 || startOpacity; - const endOpacity4 = - props.endOpacity4 === 0 ? 0 : props.endOpacity4 || endOpacity; - - const startFillColor5 = - props.startFillColor5 || props.startFillColor || 'gray'; - const endFillColor5 = props.endFillColor5 || props.endFillColor || 'white'; - const startOpacity5 = - props.startOpacity5 === 0 ? 0 : props.startOpacity5 || startOpacity; - const endOpacity5 = - props.endOpacity5 === 0 ? 0 : props.endOpacity5 || endOpacity; - const rulesThickness = props.rulesThickness === 0 ? 0 : props.rulesThickness || 1; const rulesLength = props.rulesLength; @@ -2683,6 +3108,11 @@ export const LineChart = (props: propTypes) => { startOpacity: number, endOpacity: number, strokeDashArray: Array | undefined | null, + showArrow: boolean, + arrowPoints, + arrowStrokeWidth, + arrowStrokeColor, + arrowFillColor, ) => { return ( @@ -2815,6 +3245,14 @@ export const LineChart = (props: propTypes) => { endIndex5, ) : null} + {showArrow && ( + + )} ); }; @@ -2830,6 +3268,11 @@ export const LineChart = (props: propTypes) => { startOpacity: number, endOpacity: number, strokeDashArray: Array | undefined | null, + showArrow, + arrowPoints, + arrowStrokeWidth, + arrowStrokeColor, + arrowFillColor, ) => { return ( { startOpacity, endOpacity, strokeDashArray, + showArrow, + arrowPoints, + arrowStrokeWidth, + arrowStrokeColor, + arrowFillColor, )} ); @@ -3055,6 +3503,11 @@ export const LineChart = (props: propTypes) => { startOpacity: number, endOpacity: number, strokeDashArray: Array | undefined | null, + showArrow, + arrowPoints, + arrowStrokeWidth, + arrowStrokeColor, + arrowFillColor, ) => { // console.log('animatedWidth is-------->', animatedWidth); return ( @@ -3264,6 +3717,11 @@ export const LineChart = (props: propTypes) => { startOpacity, endOpacity, strokeDashArray, + showArrow, + arrowPoints, + arrowStrokeWidth, + arrowStrokeColor, + arrowFillColor, )} ); @@ -3389,6 +3847,11 @@ export const LineChart = (props: propTypes) => { startOpacity1, endOpacity1, strokeDashArray1, + props.showArrow1 || props.showArrows, + arrow1Points, + arrowStrokeWidth1, + arrowStrokeColor1, + arrowFillColor1, ) : renderLine( zIndex1, @@ -3401,6 +3864,11 @@ export const LineChart = (props: propTypes) => { startOpacity1, endOpacity1, strokeDashArray1, + props.showArrow1 || props.showArrows, + arrow1Points, + arrowStrokeWidth1, + arrowStrokeColor1, + arrowFillColor1, )} {points2 ? isAnimated @@ -3416,6 +3884,11 @@ export const LineChart = (props: propTypes) => { startOpacity2, endOpacity2, strokeDashArray2, + props.showArrow2 || props.showArrows, + arrow2Points, + arrowStrokeWidth2, + arrowStrokeColor2, + arrowFillColor2, ) : renderLine( zIndex2, @@ -3428,6 +3901,11 @@ export const LineChart = (props: propTypes) => { startOpacity2, endOpacity2, strokeDashArray2, + props.showArrow2 || props.showArrows, + arrow2Points, + arrowStrokeWidth2, + arrowStrokeColor2, + arrowFillColor2, ) : null} {points3 @@ -3444,6 +3922,11 @@ export const LineChart = (props: propTypes) => { startOpacity3, endOpacity3, strokeDashArray3, + props.showArrow3 || props.showArrows, + arrow3Points, + arrowStrokeWidth3, + arrowStrokeColor3, + arrowFillColor3, ) : renderLine( zIndex3, @@ -3456,6 +3939,11 @@ export const LineChart = (props: propTypes) => { startOpacity3, endOpacity3, strokeDashArray3, + props.showArrow3 || props.showArrows, + arrow3Points, + arrowStrokeWidth3, + arrowStrokeColor3, + arrowFillColor3, ) : null} {points4 @@ -3472,6 +3960,11 @@ export const LineChart = (props: propTypes) => { startOpacity4, endOpacity4, strokeDashArray4, + props.showArrow4 || props.showArrows, + arrow4Points, + arrowStrokeWidth4, + arrowStrokeColor4, + arrowFillColor4, ) : renderLine( zIndex4, @@ -3484,6 +3977,11 @@ export const LineChart = (props: propTypes) => { startOpacity4, endOpacity4, strokeDashArray4, + props.showArrow4 || props.showArrows, + arrow4Points, + arrowStrokeWidth4, + arrowStrokeColor4, + arrowFillColor4, ) : null} {points5 @@ -3500,6 +3998,11 @@ export const LineChart = (props: propTypes) => { startOpacity5, endOpacity5, strokeDashArray5, + props.showArrow5 || props.showArrows, + arrow5Points, + arrowStrokeWidth5, + arrowStrokeColor5, + arrowFillColor5, ) : renderLine( zIndex5, @@ -3512,6 +4015,11 @@ export const LineChart = (props: propTypes) => { startOpacity5, endOpacity5, strokeDashArray5, + props.showArrow5 || props.showArrows, + arrow5Points, + arrowStrokeWidth5, + arrowStrokeColor5, + arrowFillColor5, ) : null} {pointerX > 0 ? (