JesperLekland / react-native-svg-charts

📈 One library to rule all charts for React Native 📊
MIT License
2.36k stars 410 forks source link

Vertical Grid doesn't display with time series data #232

Open fredlemieux opened 6 years ago

fredlemieux commented 6 years ago

What is the problem?

This is probably a lack of understanding from my side rather than an issue with "react-native-svg-charts", but perhaps others are having a similar issue and it'll be worth having the solution here. I can't get vertical gridlines to display correctly when using time series data, the only vertical gridline shown is the Y-Axis of the chart.

There isn't much documentation on how the custom grid works, so it is hard to know where I'm going wrong with this. If I use the index (rather than value) of the data.map function in the custom grid I don't even get the vertical line in the Y-Axis. What am I doing wrong?

Platform

React Native version: "dependencies": { "axios": "^0.18.0", "expo": "^30.0.1", "react": "16.3.1", "react-native": "https://github.com/expo/react-native/archive/sdk-30.0.0.tar.gz", "react-native-svg": "^7.0.2", "react-native-svg-charts": "^5.2.0", "react-navigation": "^2.14.2", }

Code below:

import React from 'react';
import {Dimensions, StyleSheet, View} from 'react-native';

import {LineChart, YAxis, XAxis} from 'react-native-svg-charts'
import {G, Line} from "react-native-svg";
import * as shape from 'd3-shape';
import * as scale from 'd3-scale';
import moment from "moment";

const data = [
    {
        value: 50,
        date: new Date(2018, 0, 1, 2),
    },
    {
        value: 10,
        date: new Date(2018, 0, 1, 9),
    },
    {
        value: 150,
        date: new Date(2018, 0, 1, 10),
    },
    {
        value: 10,
        date: new Date(2018, 0, 1, 13),
    },
    {
        value: 100,
        date: new Date(2018, 0, 1, 21),
    },
    {
        value: 20,
        date: new Date(2018, 0, 2, 0),
    },
    {
        value: 115,
        date: new Date(2018, 0, 2, 8),
    },
    {
        value: 75,
        date: new Date(2018, 0, 2, 10),
    },
    {
        value: 25,
        date: new Date(2018, 0, 2, 16),
    },
    {
        value: 125,
        date: new Date(2018, 0, 2, 17),
    },
    {
        value: 66,
        date: new Date(2018, 0, 2, 19),
    },
    {
        value: 85,
        date: new Date(2018, 0, 2, 23),
    },
];

export default class ChartTest extends React.Component {
    renderChart(){
        const xAxisHeight = 30;
        const verticalContentInset = {top: 10, bottom: 10};

        const CustomGrid = ({x, y, data, ticks}) => (
            <G>
                {
                    // Horizontal grid
                    ticks.map(tick => (
                        <Line
                            key={tick}
                            x1={'0%'}
                            x2={'100%'}
                            y1={y(tick)}
                            y2={y(tick)}
                            stroke={'rgba(0,0,0,0.2)'}
                        />
                    ))
                }
                {
                    // Vertical grid
                    data.map((value, index) => (
                        <Line
                            key={index}
                            y1={'0%'}
                            y2={'100%'}
                            x1={x(value)}
                            x2={x(value)}
                            stroke={'red'}
                        />
                    ))
                }
            </G>
        );

        return (
            <View style={{ height: 250, padding: 20, width: '90%', flexDirection: 'row' }}>
                <YAxis
                    style={{ marginBottom: xAxisHeight }}
                    data={data}
                    contentInset={verticalContentInset}
                    yAccessor={({item}) => item.value}
                    xAccessor={({item}) => item.date}
                    svg={{
                        fill: '#FFFFFF',
                    }}
                    numberOfTicks={5}
                    formatLabel={value => `${value} ºC`}
                />
                <View style={{ flex: 1, marginLeft: 10 }}>
                    <LineChart
                        style={ { flex: 1 } }
                        data={ data }
                        contentInset={verticalContentInset}
                        yAccessor={({ item }) => item.value}
                        xAccessor={({ item }) => item.date}
                        svg={ {
                            stroke: '#81B0C0',
                        } }
                        scale={scale.scaleTime}
                        numberOfTicks={10}
                    >
                        <CustomGrid belowChart={true}/>
                    </LineChart>
                    <XAxis
                        data={data}
                        svg={{
                            fill: '#FFFFFF',
                            fontSize: 8,
                            fontWeight: 'bold',
                            rotation: 20,
                            originY: 30,
                            y: 5,
                        }}
                        xAccessor={({ item }) => item.date}
                        scale={scale.scaleTime}
                        numberOfTicks={10}
                        style={{ marginHorizontal: -10, height: xAxisHeight }}
                        contentInset={verticalContentInset}
                        formatLabel={(value) => moment(value).format('HH:mm')}
                    />
                </View>
            </View>)
    }
    render() {
        return (
            <View style={styles.container}>
                {this.renderChart()}
            </View>
        );
    }
}

const styles = StyleSheet.create({
    container: {
        flex: 1,
        backgroundColor: '#343334',
        alignItems: 'center',
        justifyContent: 'center',
    }
});
jcurtis commented 5 years ago

Looking at the CustomGridExample in the storybook examples helped me resolve this:

https://github.com/JesperLekland/react-native-svg-charts/blob/dev/storybook/stories/decorators/custom-grid.js#L34

// Vertical grid
                    data.map((_, index) => (
                        <Line
                            key={ index }
                            y1={ '0%' }
                            y2={ '100%' }
                            x1={ x(index) }
                            x2={ x(index) }
                            stroke={ 'rgba(0,0,0,0.2)' }
                        />
))

Notice x1 & x2 are set to x(index) and not x(tick). This might be something we could fix in the Grid component itself but I'm not sure how that would affect using it with other components.

manueljtejada commented 5 years ago

Were you able to resolve this? Doing x1={ x(index) } x2={ x(index) } is not working for me because x(index) returns very low numbers (e.g., -7240355.0000433875).

My dataset looks similar to yours. I have an array of items with date (as the xAccessor) and value (yAccessor).

purplegamba commented 4 years ago

It seems from my experimenting that the xAccessor isn't passed down to the child (the Grid). So if you use x(value), the value isn't correct - it's not the date. I don't know if that's deliberate, or a bug. This solution works for me:

// Vertical grid data.map((value, index) => ( <Line key={index} y1={'0%'} y2={'100%'} x1={x( data[ index ].date )} x2={x( data[ index ].date )} stroke={'red'} /> ))

ctohster commented 4 years ago

I did the same but not working for me. Can't get decorators to work on the time series either.

purplegamba commented 4 years ago

I did the same but not working for me. Can't get decorators to work on the time series either.

Did you see my solution above for the vertical grid? I've been able to get decorators working the same way. If you want to share your code I'll be happy to help you figure it out.

ctohster commented 4 years ago

got it working thanks. My issue was a combination of this and I actually had a conflicting component called Line to draw the custom Path haha.