chart in range of time react native svg charts - react-native

I'm working on chart with react-native-svg-charts library, and seems like it is very flexible and cool, but I faced the issue. I need to build 24 hours timeline for xAxis and can not understand how to do it.
So I have a chart it looks like this
and the code of the chart is next:
<>
<View style={{flex: 1}} {...panResponder.current.panHandlers}>
<AreaChart
animate
style={{flex: 1}}
data={glucoseValues}
yMin={0}
yMax={180}
curve={shape.curveNatural}
contentInset={{...verticalContentInset}}
svg={{fill: 'url(#gradient)'}}>
<CustomLine/>
<Tooltip/>
</AreaChart>
<SafeArea/>
</View>
<YAxis
style={{width: apx(44)}}
data={[...Array(19).fill(1).map((el, i) => el + i * 10)]}
contentInset={verticalContentInset}
svg={{fontSize: apx(20), fill: '#617485'}}
/>
<XAxis
style={{
alignSelf: 'stretch',
width: apx(INIT_WIDTH),
height: apx(40),
}}
data={[...Array(24).fill(1)]}
formatLabel={(value, i) => {
return i === 0 ? '00:00' :
i % 4 === 0 ? moment().startOf('day').add(i, 'hours').format('HH:mm') :
i === 23 ? '23:59' : '';
}}
contentInset={{
left: 20,
right: 20,
}}
svg={{
fontSize: apx(20),
fill: '#617485',
alignmentBaseline: 'center',
textAnchor: 'middle',
y: apx(10),
}}
/>
</>
So as you see XAxis is kinda shows timeline but it is not applied. If it would, before and after the chart, we should see empty space like on this picture.
My question is next. How can I set up domain for xAxis that will work as on picture above?
For chart I user array of values for Y and array of timestamps for X. Maybe I should point somehow xMax, xMin properties for AreaChart. Any ideas?

Related

How to apply gradient shadow color in StackedAreaChart of "#rainbow-me/animated-charts" library?

I'm using this library to make a StackedAreaChart. It's currently working but I need to change the colors to gradients.Only I am able to plot points using the data,I want the gradient colors to be applied in the plotted chart area.
I have attached the code and screenshot for this.
<ChartPathProvider
data={{
points: chartData.map((data) => ({
x: toTimestamp(data.fiscal_year),
y:
data.close_price != null
? parseFloat(data.close_price).toFixed(
instrumentData.digit
)
: 0,
})),
smoothingStrategy: "bezier",
}}
>
<View>
<ChartPath
height={moderateScale(280)}
stroke="green"
strokeWidth={3}
width={screenWidth}
/>
<ChartDot>
<View
style={{
position: "absolute",
left: moderateScale(-35),
width: moderateScale(80),
alignItems: "center",
backgroundColor: "rgba(0, 0, 0, 0.4)",
}}
>
</View>
{/* Chart x & y axis */}
<ChartXLabel
format={toStringDate}
style={[
styles.M12_FW600_LH19_LS02,
styles.whiteColor,
]}
/>
<ChartYLabel
format={formatPrice}
style={[
styles.M12_FW600_LH19_LS02,
styles.whiteColor,
]}
/>
</View>
</ChartDot>
</View>
</ChartPathProvider>
Currently this charts
[1]: https://i.stack.imgur.com/jYptt.png
This is required
[2]: https://i.stack.imgur.com/pr270.png

Victory Charts cuts off tick labels when angled

(Edit: I also tried putting overflow: 'visible' in various locations to no avail.)
I'm using a date for the x-axis tick labels so I would like them to be at an angle to prevent overlap. The issue is that they are not being cut off at the bottom, as seen here (the colors are there to show different component edges):
Here is my code:
<View style={{ backgroundColor: 'red', paddingBottom: 50 }}>
<VictoryChart
theme={chartTheme}
width={screenWidth - 10}
animate={{
onLoad: { duration: 100 },
duration: 500,
}}
containerComponent={<VictoryContainer style={{ backgroundColor: 'blue', paddingBottom: 50 }} />} >
<VictoryAxis
label={plotText.xLabel}
style={{ // adding padding here does nothing
tickLabels: { angle: -45, textAnchor: 'end' } // adding padding here does nothing
}}
tickValues={dispRSHistData.ticks}
tickFormat={(t) => getFormattedDate(t)}
/>
<VictoryAxis
dependentAxis
label={plotText.yLabel} />
<VictoryLine
data={dispRSHistData.data}
x="timestamp"
y="percentSuccess"
style={{ data: { stroke: "tomato" } }}
size={10} />
</VictoryChart>
</View>
I've tried setting various heights manually but nothing seems to give space to show the full tick labels.
I didnt find an automatic solution to your problem
but mannualy adding "padding" prop to the chart worked for me
btw this solution is for VictoryNative on react native but I guess something similar works on react.js version too
check the 'padding' prop here
<VictoryChart width={400} theme={VictoryTheme.material}
padding={{bottom:100,right:50,left:50}}
>
<VictoryAxis //the x axis
// axisLabelComponent={<VictoryLabel angle={-90}/>}
tickLabelComponent={<VictoryLabel angle={-90} dy={-7}
textAnchor='end'
// labelPlacement="perpendicular"
/>}
/>
<VictoryAxis dependentAxis //the y axis
/>

react native wheel picker (IOS) is not stay on selected value?

this works absolutely fine on android but not on IOS (not displaying value which user select from wheel picker). Check this Link.
https://drive.google.com/file/d/1y_ULGQuvPlzZj2V2zr1RAynrZKpme4Uc/view?usp=sharing
<Picker
style={{ width: 100, height: 80 }}
selectedValue={this.state.selectedHour}
itemStyle={{ color: "black", fontSize: 20 }}
onValueChange={index => this.onPickerHourSelect(index)}
>
{this.state.hourList.map((value, i) => (
<PickerItem label={value} value={i} key={"money" + value} />
))}
onPickerHourSelect(index) {
var hour = this.state.hourList[index];
this.setState({
selectedHour: hour,
}) }
Please suggest me another component or package of picker(Like Spinner Or Wheel Picker)
I've had the same problem! I solved it using selectedValue instead of selectedItem and passing the pickerItem's value.
This is my code:
<Picker style={{flex: 1, width: 150, height: 180}}
itemStyle={{color: 'black', fontSize: 26}}
selectedValue={this.state.minutes[this.state.indexSelected]}
onValueChange={(index) => {this.setState({indexSelected: index})}}>
{this.state.minutes.map((value, i) => (<PickerItem label={value} value={i} key={i}/>))}
</Picker>

react-native-svg-charts Areachart renders an extra bottom line

I am using react-native-svg-charts to render some charts. In my case i use area chart (see image below). When the last data entries have same values, there is a bottom line appearing
Here is how i render the area chart
<AreaChart style = {{height: '100%', width: '100%' }} data = {Object.values(chartData)} curve={shape.curveBasis}
svg={{ fill: 'url(#gradient)', stroke: 'blue', fillOpacity: 0.8, scale: 1.002, strokeWidth: 0 }}
contentInset={{ top: scaleHeight(10), bottom: scaleHeight(10) }} animate >
<Gradient/>
</AreaChart>
The code for Gradient is as follows
const Gradient = ({ index }) => (
<Defs key={index}>
<LinearGradient id={'gradient'} x1={'0%'} y={'0%'} x2={'0%'} y2={'100%'}>
<Stop offset={'0%'} stopColor="blue" stopOpacity={1}/>
<Stop offset={'100%'} stopColor="white" stopOpacity={1}/>
</LinearGradient>
</Defs>
)

React Native FlatList with columns, Last item width

I'm using a FlatList to show a list of items in two columns
<FlatList style={{margin:5}}
data={this.state.items}
numColumns={2}
keyExtractor={(item, index) => item.id }
renderItem={(item) => <Card image={item.item.gallery_image_url} text={item.item.name}/> }
/>
The card component is just a view with some styles:
<View style={{ flex: 1, margin: 5, backgroundColor: '#ddd', height: 130}} ></View>
It is working fine, but if the number of items is odd, the last row only contains one item and that item stretches to the full width of the screen.
How can I set the item to the same width of the others?
for your case use flex: 1/2
therefore: Your item should have flex of 1/(number of columns) if you have 3 columns your item should have flex:1/3
Theres a few things you can try here.
A) Setting a pre-defined width for the card ( Maybe equal to the height you've set? ). Then you can use alignItems in order to have the card positioned in the middle or on the left - Unsure as to which you wanted here.
B) If there are an even number of cards, you could add an empty View at the end in order to fill this space. I find this method pretty clunky but useful when trying to leave space for future elements.
C) Simply use alignItems: 'space-between, i like to use this to center items, but you would have to define the width, or use something like flex:0.5
I suggest researching more into flexbox to help you with this, as it is hard to tell the context of this situation. I'm assuming the above methods will help, but if not, here are some links for you to look at -
A Complete Guide to Flexbox (CSS Tricks)
Layout with Flexbox (React Native)
Video Tutorial (Youtube) Link Broken
Hope this helps. If you need any further clarification - just ask
This is the cleanest way to style a FlatList with columns and spaced evenly:
<FlatList style={{margin:5}}
numColumns={2} // set number of columns
columnWrapperStyle={style.row} // space them out evenly
data={this.state.items}
keyExtractor={(item, index) => item.id }
renderItem={(item) => <Card image={item.item.gallery_image_url} text={item.item.name}/> }
/>
const style = StyleSheet.create({
row: {
flex: 1,
justifyContent: "space-around"
}
});
You can try to get the current width of the device via Dimensions, do some math based on the number of columns you want to render, minus off the margins and set that as the minWidth and maxWidth.
For example:
const {height, width} = Dimensions.get('window');
const itemWidth = (width - 15) / 2;
<View style={{ flex: 1, margin: 5, backgroundColor: '#ddd', minWidth: {this.itemWidth}, maxWidth: {this.itemWidth}, height: 130}} ></View>
The reason for it is your Card have style flex: 1, so it will try to expand all the space remain.
You can fix it by add maxWidth: '50%' to your Card style
<View style={{ flex: 1, margin: 5, backgroundColor: '#ddd', height: 130, maxWidth: '50%'}} ></View>
#Emilius Mfuruki suggestion is good, but if you have text with varying length it doesn't work perfectly. Then use this width inside your item view:
const {height, width} = Dimensions.get('window');
const itemWidth = (width - (MarginFromTheSide * 2 + MarginInBetween * (n-1))) / n;
In FlatList use:
columnWrapperStyle={{
flex: 1,
justifyContent: 'space-evenly',
}}
Works perfectly.
The simplest solution is do the math.
Imagine we have 2 View for each Row and we want to give 10 margin to every side it will look something like that:
As you see in the image above each View have 2 margins in horizontal. (inside of red rectangle)
So we have to subtract the product of margin, number of column and 2 from the width.
import { Dimensions } from 'react-native';
const {width} = Dimensions.get("window")
const column = 2
const margin = 10
const SIZE = (width - (margin * column * 2)) / column
<View style={{ margin: 10, width: SIZE }} ></View>
I tried some of the solutions above but I still had some problems with the margins on the last item (2 columns list).
My solution was simply wrapping the item into a parent container, leaving the original container with flex: 1 and the parent container of the item with flex: 0.5 so it would take the margin correctly.
itemContainer: {
flex: 0.5,
},
itemSubContainer: {
flex: 1,
marginHorizontal: margin,
},
A simple way with flex
<FlatList style={{margin:5}}
data={this.state.items}
numColumns={2}
keyExtractor={(item, index) => item.id }
renderItem={({item, index}) => {
const lastItem = index === this.state.items.length - 1;
return (
<View style={{flex: lastItem ? 1 / 2 : 1 }}>
<Card image={item.gallery_image_url} text={item.name}/>
</View>
)}}
/>
You can use ListFooterComponent={this.renderFooter}
None of the above answers have worked perfectly for me so I post my own answer:
works with padding and margins
the last element will always have the correct size
<FlatList
data={data}
numColumns={2}
renderItem={({item, index}) => {
const lastItem = index === data.length - 1;
return (
<View style={{flex: 1, padding: 8, maxWidth: lastItem ? '50%' : '100%' }}>
...
</View>
)}}
/>
Note: change maxWidth according to number of columns
Result:
just use flex:0.5 and width:'50%'
Create an array with odd number of images in it, like:
const images = [
require('./../...jpg'),
require('./../...jpg'),
require('./../...jpg'),
require('./../...jpg'),
require('./../...jpg'),
];
And then, use the code given below,
const App = () => {
const _renderItem = ({ item, index }) => (
<Image
source={item}
style={{
width: '50%',
height: 200,
}}
resizeMode="cover"
/>
);
return (
<View style={{flex: 1, marginHorizontal: 10,}}>
<FlatList
columnWrapperStyle={{ justifyContent: 'space-between' }}
keyExtractor={(_, index)=> index.toString()}
data={images}
numColumns={2}
renderItem={_renderItem}
/>
</View>
)
};
export default App;
Working Example