diff --git a/App.js b/App.js index b5da49e..8d83f33 100644 --- a/App.js +++ b/App.js @@ -2,27 +2,12 @@ import React, {useState} from 'react'; import {TouchableOpacity} from 'react-native'; import {Alert} from 'react-native'; import {View, Text, StyleSheet} from 'react-native'; -import {BarChart, LineChart, PieChart} from './src'; +import {BarChart, LineChart} from './src'; const App = () => { - // const lineData = [ - // {value: 40, text: 'Jan', textShiftX: 8, textShiftY: -10}, - // {value: 80, text: 'Feb'}, - // {value: 170, text: 'Mar', textFontSize: 16, textColor: 'blue'}, - // {value: 90, text: 'Apr'}, - // {value: 190, text: 'May'}, - // ]; - // const lineData2 = [ - // {value: 30, text: 'Jan', textShiftX: 8}, - // {value: 40, text: 'Feb'}, - // {value: 60, text: 'Mar'}, - // {value: 70, text: 'Apr'}, - // {value: 100, text: 'May'}, - // ]; - const [toggle, setToggle] = useState(true); - const data = [ + const [data, setData] = useState([ {value: 15, label: 'Jan'}, { value: 40, @@ -34,16 +19,10 @@ const App = () => { { value: 10, label: 'Mar', - showDataPoint: true, - dataPointShape: 'rectangular', - dataPointHeight: 20, - dataPointWidth: 20, }, { value: 30, label: 'Apr', - // showVerticalLine: true, - showDataPoint: true, }, {value: 20, label: 'May'}, {value: 40, label: 'Jun'}, @@ -57,135 +36,15 @@ const App = () => { onPress: () => Alert.alert('Sales in Nov skyrocketed to $48 M'), }, {value: 30, label: 'Dec'}, - ]; + ]); - const stackData = [ - { - stacks: [ - {value: 10, color: 'orange'}, - {value: 20, color: '#4ABFF4', marginBottom: 2}, - ], - label: 'Jan', - }, - { - stacks: [ - {value: 10, color: '#4ABFF4'}, - {value: 11, color: 'orange', marginBottom: 2}, - {value: 15, color: '#28B2B3', marginBottom: 2}, - ], - label: 'Mar', - }, - { - stacks: [ - {value: 14, color: 'orange'}, - {value: 18, color: '#4ABFF4', marginBottom: 2}, - ], - label: 'Feb', - }, - { - stacks: [ - {value: 7, color: '#4ABFF4'}, - {value: 11, color: 'orange', marginBottom: 2}, - {value: 10, color: '#28B2B3', marginBottom: 2}, - ], - label: 'Mar', - }, - ]; - - const barData1 = [ - {value: 250, label: 'M'}, - {value: 500, label: 'T', frontColor: '#177AD5'}, - {value: 745, label: 'W', frontColor: '#177AD5'}, - {value: 320, label: 'T'}, - {value: 600, label: 'F', frontColor: '#177AD5'}, - {value: 256, label: 'S'}, - {value: 300, label: 'S'}, - ]; - - const lineData1 = [ - {value: 0, dataPointText: '0'}, - {value: 20, dataPointText: '20'}, - {value: 18, dataPointText: '18'}, - {value: 40, dataPointText: '40'}, - {value: 36, dataPointText: '36'}, - {value: 60, dataPointText: '60'}, - {value: 54, dataPointText: '54'}, - {value: 85, dataPointText: '85'}, - ]; - const ldata = [ - {value: 15, label: '15'}, - {value: 30, label: '30'}, - {value: 26, label: '26'}, - {value: 40, label: '40'}, - ]; - - // const MyComponent = () => { - // return ( - // - // Hello - // - // ); - // }; - - const barData = [ - {value: 230, label: 'Jan', frontColor: '#4ABFF4'}, - {value: 180, label: 'Feb', frontColor: '#79C3DB'}, - {value: 195, label: 'Mar', frontColor: '#28B2B3'}, - {value: 250, label: 'Apr', frontColor: '#4ADDBA'}, - {value: 320, label: 'May', frontColor: '#91E3E3'}, - ]; - // const lineData = [ - // {value: 0}, - // {value: 10}, - // {value: 8}, - // {value: 58}, - // {value: 56}, - // {value: 78}, - // {value: 74}, - // {value: 98}, - // ]; - // const lineData2 = [ - // {value: 0}, - // {value: 20}, - // {value: 18}, - // {value: 40}, - // {value: 36}, - // {value: 60}, - // {value: 54}, - // {value: 85}, - // ]; - const lineData = [ - {value: 0}, - {value: 20}, - {value: 18}, - {value: 40}, - {value: 36}, - {value: 60}, - {value: 54}, - {value: 85}, - ]; - const pieData = [ - {value: 70, color: '#177AD5' /*text: '54%'*/}, - {value: 30, color: 'lightgray' /*text: '30%'*/}, - // {value: 20, color: '#ED6665' /*text: '26%'*/}, - ]; return ( - {/* */} - - {/* { - return 70%; - }} - /> */} - {toggle ? ( + {!toggle ? ( { ) : ( { + console.log('index-->', index); + setData(data => { + item.dataPointColor = 'green'; + item.dataPointRadius = 6; + item.dataPointText = item.value; + // item.dataPointShape = 'rectangular'; + // item.dataPointWidth = 10; + // item.dataPointHeight = 10; + data[index] = item; + console.log('data------.....', data); + return data; + }); + }} + // disableScroll + pressEnabled + // showDataPointOnPress + showStripOnPress + showTextOnPress + textShiftY={-10} + textShiftX={-5} + textFontSize={18} + textColor={'green'} + stripWidth={1} + stripHeight={200} + // stripHeight={200} + stripOpacity={0.4} curved isAnimated - showGradient - cappedBars + animationDuration={2000} + // animationDuration={2000} + // dataPointsShape="rectangular" + // showGradient color={'rgb(78, 0, 142)'} yAxisColor={'rgb(78, 0, 142)'} xAxisColor={'rgb(78, 0, 142)'} dataPointsColor={'rgb(78, 0, 142)'} - dataPointsWidth={1} - dataPointsHeight={1} + dataPointsWidth={8} + dataPointsHeight={8} xAxisThickness={3} yAxisThickness={3} + dataPointsRadius={4} yAxisTextStyle={{color: 'rgb(78, 0, 142)'}} startFillColor={'rgb(200, 100, 244)'} startOpacity={0.9} @@ -299,210 +191,6 @@ const App = () => { style={{marginTop: 100, alignSelf: 'center'}}> Line Chart - - {/* */} - {/* */} - {/* */} - - {/* */} - - {/* */} - {/* - - */} - - {/* - - */} - - {/* */} - - {/* - - */} - - {/* Hello */} - {/* */} - {/* */} - {/* */} - {/* */} - {/* */} - {/* */} ); }; diff --git a/docs/LineChart/LineChartProps.md b/docs/LineChart/LineChartProps.md index 1eb3096..ad5cd03 100644 --- a/docs/LineChart/LineChartProps.md +++ b/docs/LineChart/LineChartProps.md @@ -177,6 +177,46 @@ type referenceConfigType = { --- +### onPress and strip related props + +Line or Area charts can be made interactive by allowing users to press on the chart and highlight that particular data point. For example- + +![focus points](../../demos/focusPoint.gif) + +To achieve this the `pressEnabled` props must be set to true. In addition, use below props to handle the press event. + +| Prop | Type | Description | Default value | +| -------------------- | ---------- | ---------------------------------------------------------------------------------------------------------- | --------------------------- | +| pressEnabled | Boolean | If set true, allows users to press on the chart (press event can be then handled using the `onPress` prop) | false | +| showDataPointOnPress | Boolean | If set true, it shows the data point corresponding to the pressed area of the chart | false | +| showStripOnPress | Boolean | If set true, it shows a vertical strip corresponding to the pressed area of the chart | false | +| showTextOnPress | Boolean | If set true, it shows the data point text corresponding to the pressed area of the chart | false | +| stripHeight | number | Height of the vertical strip that becomes visible on pressing the corresponding area of the chart | height of the data point | +| stripWidth | number | Width of the vertical strip that becomes visible on pressing the corresponding area of the chart | 2 | +| stripColor | ColorValue | Color of the vertical strip that becomes visible on pressing the corresponding area of the chart | color of the line | +| stripOpacity | number | Opacity of the vertical strip that becomes visible on pressing the corresponding area of the chart | (startOpacity+endOpacity)/2 | +| onPress | Function | The callback function that handles the press event. `item` and `index` are received as props | \_ | +| unFocusOnPressOut | Boolean | If set true, it unselects/unfocuses the focused/selected data point | true | +| delayBeforeUnFocus | number | Delay (in milliseconds) between the release of the press and ghe unfocusing of the data point | 300 | + +#### Example of onPress : + +```js +onPress={(item, index) => { + setData(data => { + item.dataPointColor = 'green'; + item.dataPointRadius = 6; + item.dataPointText = item.value; + data[index] = item; + return data; + }); +}} +``` + +Above code changes the pressed data point's color and radius. Since in this example, we are changing the data on th onPress event, the data must be a state variable. + +--- + ### Props for Area Chart | Prop | Type | Description | Default value | @@ -203,3 +243,7 @@ type referenceConfigType = { ``` ``` + +``` + +``` diff --git a/src/LineChart/index.tsx b/src/LineChart/index.tsx index c5ab2c7..8b6344f 100644 --- a/src/LineChart/index.tsx +++ b/src/LineChart/index.tsx @@ -50,6 +50,17 @@ type propTypes = { hideRules?: Boolean; rulesColor?: ColorValue; rulesThickness?: number; + pressEnabled?: Boolean; + showDataPointOnPress?: Boolean; + showStripOnPress?: Boolean; + showTextOnPress?: Boolean; + stripHeight?: number; + stripWidth?: number; + stripColor?: ColorValue | String | any; + stripOpacity?: number; + onPress?: Function; + unFocusOnPressOut?: Boolean; + delayBeforeUnFocus?: number; rulesType?: String; dashWidth?: number; @@ -201,6 +212,7 @@ export const LineChart = (props: propTypes) => { const [fillPoints, setFillPoints] = useState(''); const [fillPoints2, setFillPoints2] = useState(''); const [fillPoints3, setFillPoints3] = useState(''); + const [selectedIndex, setSelectedIndex] = useState(-1); const containerHeight = props.height || 200; const noOfSections = props.noOfSections || 10; const data = useMemo(() => props.data || [], [props.data]); @@ -701,6 +713,18 @@ export const LineChart = (props: propTypes) => { const dashWidth = props.dashWidth === 0 ? 0 : props.dashWidth || 4; const dashGap = props.dashGap === 0 ? 0 : props.dashGap || 8; + const pressEnabled = props.pressEnabled || false; + const showDataPointOnPress = props.showDataPointOnPress || false; + const showStripOnPress = props.showStripOnPress || false; + const showTextOnPress = props.showTextOnPress || false; + const stripHeight = props.stripHeight; + const stripWidth = props.stripWidth === 0 ? 0 : props.stripWidth || 2; + const stripColor = props.stripColor || color1; + const stripOpacity = props.stripOpacity || (startOpacity1 + endOpacity1) / 2; + const unFocusOnPressOut = props.unFocusOnPressOut === false ? false : true; + const delayBeforeUnFocus = + props.delayBeforeUnFocus === 0 ? 0 : props.delayBeforeUnFocus || 300; + const defaultReferenceConfig = { thickness: rulesThickness, width: (props.width || totalWidth) + 11, @@ -1086,85 +1110,190 @@ export const LineChart = (props: propTypes) => { }); }; + const onStripPress = (item, index) => { + setSelectedIndex(index); + if (props.onPress) { + props.onPress(item, index); + } + }; + const renderDataPoints = ( dataForRender, - dataPointsShape, - dataPointsWidth, - dataPointsHeight, - dataPointsColor, - dataPointsRadius, + dataPtsShape, + dataPtsWidth, + dataPtsHeight, + dataPtsColor, + dataPtsRadius, textColor, textFontSize, ) => { return dataForRender.map((item: itemType, index: number) => { + let dataPointsShape, + dataPointsWidth, + dataPointsHeight, + dataPointsColor, + dataPointsRadius, + text; + if (index === selectedIndex) { + dataPointsShape = item.dataPointShape || dataPtsShape; + dataPointsWidth = item.dataPointWidth || dataPtsWidth; + dataPointsHeight = item.dataPointHeight || dataPtsHeight; + dataPointsColor = item.dataPointColor || dataPtsColor; + dataPointsRadius = item.dataPointRadius || dataPtsRadius; + if (showTextOnPress) { + text = item.dataPointText; + } + } else { + dataPointsShape = dataPtsShape; + dataPointsWidth = dataPtsWidth; + dataPointsHeight = dataPtsHeight; + dataPointsColor = dataPtsColor; + dataPointsRadius = dataPtsRadius; + if (showTextOnPress) { + text = ''; + } + } // console.log('comes in'); - if (dataPointsShape === 'rectangular') { - return ( - - - {item.dataPointText && ( - + {pressEnabled ? ( + <> + {unFocusOnPressOut ? ( + onStripPress(item, index)} + onPressOut={() => + setTimeout(() => setSelectedIndex(-1), delayBeforeUnFocus) + } + x={initialSpacing + (spacing * index - spacing / 2)} + y={8} + width={spacing} + height={containerHeight - 0} + fill={'none'} + /> + ) : ( + onStripPress(item, index)} + x={initialSpacing + (spacing * index - spacing / 2)} + y={8} + width={spacing} + height={containerHeight - 0} + fill={'none'} + /> + )} + {index === selectedIndex && showStripOnPress ? ( + + ) : null} + + ) : null} + {dataPointsShape === 'rectangular' ? ( + + - {item.dataPointText} - - )} - - ); - } - return ( - - - {item.dataPointText && ( - - {item.dataPointText} - + (item.value * containerHeight) / maxValue + } + width={dataPointsWidth} + height={dataPointsHeight} + fill={ + showDataPointOnPress + ? index === selectedIndex + ? dataPointsColor + : 'none' + : dataPointsColor + } + /> + {text ? ( + !showTextOnPress || index === selectedIndex ? ( + + {text} + + ) : null + ) : null} + + ) : ( + + + {text ? ( + !showTextOnPress || index === selectedIndex ? ( + + {text} + + ) : null + ) : null} + )} );