Rajat Verma
Rajat Verma

Reputation: 460

How to make draggable cursor in area chart in victory native

Note: I want a solution for react-native.I want to make a tooltip and a draggable cursor on the area chart in which there is a line which shows the datapoint of the area chart through draggable cursor. I just want to mark the datapoint which is from the data set only not the and y value of touch point of the screen, just only x and y value on the graph when touching on a screen it gives the nearest value of the data set corresponding to the screen.

I search on the internet I found something similar but it was for the react and used a scatter graph as I am very new to victory native library and react-native can someone tell how to make a react-native equivalent of it with the area chart. Here is the link where I was referring to see..

Click me

I just want to make a similar thing with the area chart in victory native with draggable cursor and tooltip which only mark the data point on the chart only not on the screen coordinates.

Can anyone provide me with the react-native code how to implement it as similar to the link provided above as per my requirement with a victory area chart? Also including react code which I want to convert to react-native. Please, someone, help me out.

/* Victory requires `react@^15.5.0` and `prop-types@^15.5.0` */
const {
    VictoryLine, VictoryChart, VictoryCursorContainer, VictoryLabel, VictoryScatter
} = Victory;
const { range, first, last } = _; // lodash
const mountNode = document.getElementById('app');

const allData = range(750).map((x) => ({x, y: x + 30 * Math.random()}));

const findClosestPointSorted = (data, value) => {
    // assumes 3 things:
  // 1. data is sorted by x
  // 2. data points are equally spaced
  // 3. the search is 1-dimentional (x, not x and y)
  if (value === null) return null;
    const start = first(data).x;
    const range = (last(data).x - start);
  const index = Math.round((value - start)/range * (data.length - 1));
  return data[index];
};

class App extends React.Component {
    constructor() {
    super();
    this.state = {
        activePoint: null
    };
  }
    handleCursorChange(value) {
    this.setState({
        activePoint: findClosestPointSorted(allData, value)
    });
  }
  render() {
    const { activePoint } = this.state;
    const point = activePoint ?
        <VictoryScatter data={[activePoint]} style={{data: {size: 100} }}/>
      : null;
    return (
      <div>
        <VictoryChart
          containerComponent={
            <VictoryCursorContainer
              dimension="x"
              onChange={this.handleCursorChange.bind(this)}
              cursorLabel={cursor => `${activePoint.x}, ${Math.round(activePoint.y)}`}
            />
          }
        >
          <VictoryLine data={allData} style={{data: {stroke: '#999'} }}/>
          {point}
        </VictoryChart>
      </div>
    );
  }
}

ReactDOM.render(
    <App/>,
  mountNode
);

Upvotes: 2

Views: 2903

Answers (1)

Rajat Verma
Rajat Verma

Reputation: 460

import React, { Component } from 'react'
import { Text, StyleSheet, View } from 'react-native'
import {VictoryArea,VictoryChart,createContainer,VictoryTooltip,VictoryScatter,VictoryLine } from 'victory-native';
import {range, first, last,maxBy } from 'lodash';
import Svg,{Line} from 'react-native-svg';

const VictoryZoomVoronoiContainer = createContainer( "cursor","voronoi");

const data = range(20,81).map((x) => ({x, y: x*x}));

const findClosestPointSorted = (data, value) => {  
  if (value === null) return null;
    const start = first(data).x;
    const range = (last(data).x - start);
  const index = Math.round((value - start)/range * (data.length - 1));
  return data[index];
};

export default class Chart extends Component {
    componentWillMount()
    {
        this.setState({ymax:maxBy(data,function(o) { return o.y; }).y})
    }

    state = {
        activePoint:null,
        data:data,
        ymax :0
    }
    handleCursorChange(value) {           

    this.setState({
        activePoint: findClosestPointSorted(data, value)
    });
  }

    render() {
        const { activePoint } = this.state;
        const point = activePoint ?
            <VictoryScatter name = "scatter" data={[activePoint]} style={{data: {size: 200,fill:'#ffffff',stroke:'#1bad53',strokeWidth:2} }}/>
          : null;

        return (
            <View>
                <VictoryChart
                    height={300}
                    width={350}
                    containerComponent={
                        <VictoryZoomVoronoiContainer
                        voronoiDimension="x"
                        cursorDimension="x"
                        voronoiBlacklist={["scatter"]}
                        labelComponent={<VictoryTooltip style={{fill:'red'}}  flyoutStyle={{
                        fill:  'rgba(52, 52, 52, 0.8)',}}/>}
                        onCursorChange={(value)=>{this.handleCursorChange(value)}}
                        labels={cursor => {

                            try {

                                return(activePoint.x?`${activePoint.x}, ${Math.round(activePoint.y)}\ndjh`:null)
                            } catch (error) {
                                console.log(error)
                            }
                        }}
                        />
                    }
                 >

            <VictoryArea
            name = "area"
            data={data}
            interpolation="cardinal"
            style={{
            data: { 
                fill: '#1bad53',
                stroke: '#05a543',
                strokeWidth: 2
            }
            }}
            />
             {point}

          {activePoint?<Line  x1= {50} x2="300" y1={250-(200/this.state.ymax)*activePoint.y} y2={250-(200/this.state.ymax)*activePoint.y} stroke="black" strokeWidth="1"/>:null}

        </VictoryChart>
            </View>
        )
    }
}

Upvotes: 2

Related Questions