Rajat Verma
Rajat Verma

Reputation: 460

How to make the victory native cursor container x and y axis line only intersect the point on the graph not on the touch point

How to make the victory native cursor container x and y axis line only intersect the point on the graph not on the touch point.Since by default the draggable cursor intersect the touch point but I want that the draggable cursor must intersect only at the point on the graph wherever I touch the graph it only show the nearest point on the graph corresponding to my touch point.

Please some on tell how to do it.

Upvotes: 0

Views: 3755

Answers (3)

Lsehovac
Lsehovac

Reputation: 191

In my instance, I only cared about showing the y value of my data, and please correct me if I'm wrong or oversimplified this - but this works exactly as needed for my case:

<VictoryChart
   containerComponent={
      <VictoryCursorContainer
          cursorDimension="x"
          cursorLabel={({datum}) => `${data[Math.round(datum.x) - 1]["y"]}`}
         />}
>

The cursorLabel component basically finds the closest x value of the chart pointer, converts it to an integer and we use this integer to index our data object. Of course we need to subtract 1 due to 0 indexing in our object whereas the charts positioning is not 0 indexing. Note that data is an array of objects such as [{x: a date, y: some value},]

Upvotes: 1

Simon
Simon

Reputation: 1

Echoing on @Rajat Verma's answer, Victory allows you to pass in a cursorComponent prop where you can use your own custom svg Line component (custom color, strokeWidth, etc.)

Additionally, it is useful to note that VictoryCursorContainer does not behave as it should in cases where you are also using the zoomDomain prop from VictoryZoomContainer (cursor will not match up with rendered line when zooming). A solution to this is taking out VictoryZoomContainer and manually filtering your original dataset to mimic the zoom. Hope it helps!

There is a typo in the accepted answer, use: const VictoryCursorVoronoiContainer = createContainer('cursor', 'voronoi'). And don't forget to use voronoiBlacklist prop to exclude items out of your voronoi diagram!

Upvotes: 0

Rajat Verma
Rajat Verma

Reputation: 460

Here is the solution:

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: 1

Related Questions