We are facing for some time problem with LabelList which is displayed over the elements of Scatter chart. If user is hovering over them, Tooltip is not displayed.
Code:
const {ScatterChart, Scatter, XAxis, YAxis, CartesianGrid, LabelList, Tooltip, Legend} = Recharts;
const data = [{x: 100, y: 200, z: 200}, {x: 120, y: 100, z: 260},
{x: 170, y: 300, z: 400}, {x: 140, y: 250, z: 280},
{x: 150, y: 400, z: 500}, {x: 110, y: 280, z: 200}]
const SimpleScatterChart = React.createClass({
render () {
return (
<ScatterChart width={400} height={400} margin={{top: 20, right: 20, bottom: 20, left: 20}}>
<XAxis type="number" dataKey={'x'} name='stature' unit='cm'/>
<YAxis type="number" dataKey={'y'} name='weight' unit='kg'/>
<CartesianGrid />
<Tooltip cursor={{strokeDasharray: '3 3'}}/>
<Legend onMouseEnter={this.handleMouseEnter} onMouseLeave={this.handleMouseLeave} />
<Scatter name='A school' data={data} fill='#8884d8'>
<LabelList dataKey="x" />
</Scatter>
</ScatterChart>
);
}
})
ReactDOM.render(
<SimpleScatterChart />,
document.getElementById('container')
);
Example: https://jsfiddle.net/alidingling/gvsspn0h/
Once you will remove LabelList, it is working fine:
const {ScatterChart, Scatter, XAxis, YAxis, CartesianGrid, LabelList, Tooltip, Legend} = Recharts;
const data = [{x: 100, y: 200, z: 200}, {x: 120, y: 100, z: 260},
{x: 170, y: 300, z: 400}, {x: 140, y: 250, z: 280},
{x: 150, y: 400, z: 500}, {x: 110, y: 280, z: 200}]
const SimpleScatterChart = React.createClass({
render () {
return (
<ScatterChart width={400} height={400} margin={{top: 20, right: 20, bottom: 20, left: 20}}>
<XAxis type="number" dataKey={'x'} name='stature' unit='cm'/>
<YAxis type="number" dataKey={'y'} name='weight' unit='kg'/>
<CartesianGrid />
<Tooltip cursor={{strokeDasharray: '3 3'}}/>
<Legend onMouseEnter={this.handleMouseEnter} onMouseLeave={this.handleMouseLeave} />
<Scatter name='A school' data={data} fill='#8884d8'>
</Scatter>
</ScatterChart>
);
}
})
ReactDOM.render(
<SimpleScatterChart />,
document.getElementById('container')
);
Example: https://jsfiddle.net/gt0uy92a/2/
Problem is, we need LabelList displayed as it is in a first example, we can't change the position, but Tooltip must be working properly.
<LabelList
dataKey="x"
style={{pointerEvents: 'none'}}
/>
will work for you.you can bind onMouseEnter event to LabelList component as well.
Solution was not so simple, it was little bit tricky, but still logical. If we can't do anything with way how is SVG rendering elements, can't use z-index, we still can set them opacity.
const CustomizedCircle = props => {
const {
cx, cy, fill, size, z,
} = props;
const radius = size / 70;
const value = z;
return (
<svg width={radius} height={radius} style={{overflow: 'visible'}}>
<text style={{fontWeight: FONT_WEIGHT, fontSize: FONT_SIZE}} x={cx} y={cy + 5} textAnchor="middle">{value}</text>
<circle style={{opacity: OPACITY}} cx={cx} cy={cy} r={radius} fill={fill} />
</svg>
);
};
So we are first rendering the text, then we render the circle and to see text beneath the circle we are setting the circle some kind of opacity.
Related
I'm using react-native-svg to render a chart, which contain a gradient, work perfectly on web, but when use the same code on react-native it won't work
Here is the react-native code
const data = [
{x: new Date(2000, 3, 2), y: 100},
{x: new Date(2003, 4, 3), y: 120},
{x: new Date(2002, 5, 4), y: 140},
{x: new Date(2005, 6, 5), y: 150},
{x: new Date(2006, 7, 6), y: 130},
{x: new Date(2007, 8, 7), y: 120},
{x: new Date(2008, 9, 8), y: 150},
];
export default function Chart4() {
const dateData = data.map(i => i.x);
return (
<Svg>
<Defs>
<LinearGradient id="myGradient" x1="0" y1="0" x2="0" y2="1.3">
<Stop offset="0%" stopColor="#86CD9B" stop-opacity={1} />
<Stop offset="100%" stopColor="white" stop-opacity={1} />
</LinearGradient>
</Defs>
<VictoryChart scale={{x: 'time', y: 'linear'}}>
<VictoryAxis dependentAxis />
<VictoryAxis
tickValues={dateData}
tickFormat={x => {
return x.toLocaleString('vn-vn', {
month: 'short',
day: 'numeric',
});
}}
/>
<VictoryArea
data={data}
style={{
data: {fill: 'url(#myGradient)'},
}}
/>
<VictoryScatter
data={data}
style={{
data: {
stroke: '#86CD9B',
fill: 'white',
strokeWidth: 1,
fillOpacity: 1,
},
}}
labels={({datum}) =>
`x: ${datum.x.toLocaleString('vn-vn', {
month: 'short',
day: 'numeric',
})} \n y:${datum.y}`
}
labelComponent={
<VictoryTooltip
renderInPortal={false}
dy={0}
centerOffset={{x: 25}}
/>
}
/>
</VictoryChart>
</Svg>
);
}
And it show nothing
But on web ( react ) , it work perfectly, here is codesanbbox for that https://codesandbox.io/s/chart-blood-glucose-031dn?file=/src/App.js
What going on, please help, thank a lots
I am using react-vis library for one of my projects. I copied the source code of a sample chart from one of their examples on the site. I copied the example directly but still the chart does not look as expected.
import React from 'react';
import {curveCatmullRom} from 'd3-shape';
import {
XYPlot,
XAxis,
YAxis,
HorizontalGridLines,
VerticalGridLines,
LineSeries
} from 'index';
export default function Example(props) {
return (
<XYPlot width={300} height={300}>
<HorizontalGridLines style={{stroke: '#B7E9ED'}} />
<VerticalGridLines style={{stroke: '#B7E9ED'}} />
<XAxis
title="X Axis"
style={{
line: {stroke: '#ADDDE1'},
ticks: {stroke: '#ADDDE1'},
text: {stroke: 'none', fill: '#6b6b76', fontWeight: 600}
}}
/>
<YAxis title="Y Axis" />
<LineSeries
className="first-series"
data={[{x: 1, y: 3}, {x: 2, y: 5}, {x: 3, y: 15}, {x: 4, y: 12}]}
style={{
strokeLinejoin: 'round',
strokeWidth: 4
}}
/>
<LineSeries className="second-series" data={null} />
<LineSeries
className="third-series"
curve={'curveMonotoneX'}
data={[{x: 1, y: 10}, {x: 2, y: 4}, {x: 3, y: 2}, {x: 4, y: 15}]}
strokeDasharray="7, 3"
/>
<LineSeries
className="fourth-series"
curve={curveCatmullRom.alpha(0.5)}
data={[{x: 1, y: 7}, {x: 2, y: 11}, {x: 3, y: 9}, {x: 4, y: 2}]}
/>
</XYPlot>
);
}
For this issue, you can import style.css from react-vis in your component like below,
import "react-vis/dist/style.css";
Working Code :- https://codesandbox.io/s/musing-yonath-bgg1i?file=/src/App.js
What I am trying to do is the following:
But I can't manage to get it working. I was able to get the data to read in from 2 different data sources but it somehow does not render the second line properly on the x-axis.
Here is the example code:
import React from "react";
import { render } from "react-dom";
import { LineChart, Line, XAxis, YAxis, ReferenceLine } from "recharts";
const styles = {
fontFamily: "sans-serif",
textAlign: "center"
};
const data = [];
const maxBudget = 300;
for (let i = 0; i < 20; i++) {
let d = {
day: i,
value: Math.random() * (maxBudget + 50) + 100
};
data.push(d);
}
const testline = [{ x: 0, y: 300 }, { x: 20, y: 0 }]
const App = () => (
<div style={styles}>
<LineChart
width={500}
height={300}
margin={{ top: 5, right: 20, bottom: 5, left: 0 }}
>
<Line type="monotone" data={data} dataKey="value" stroke="#8884d8" dot={false} />
<Line type="linear" data={testline} dataKey="y" stroke="#FF3333" dot={false} strokeWidth={2} />
<XAxis dataKey="day" type="number" tickCount={11} />
<YAxis />
<ReferenceLine
y={maxBudget}
label={{
position: "center",
value: "Max budget"
}}
strokeDasharray="5 5"
/>
</LineChart>
</div>
);
render(<App />, document.getElementById("root"));
ok I m stupid. I just found it out by myself. Sometimes you don't see the wood for the trees for days :(.
The x value must be the same as defined in the XAxis so I had to change x:0 to day:0:
const testline = [{ day: 0, y: 300 }, { day: 20, y: 0 }]
Now it works
I'm using rechart , in that I've one problem. I'm using scatter chart. If the value of scatter chart is 0 scatter is displaying on top of x-axis(Y value 0), I don't want to display scatter when value is "0"
How can I do that , Some one please help.
Code:
const {ScatterChart, Scatter, XAxis, YAxis, ZAxis, CartesianGrid, Tooltip, Legend} = Recharts;
const data01 = [{x: 100, y: 200}, {x: 120, y: 0},
];
const ThreeDimScatterChart = React.createClass({
render () {
return (
<ScatterChart width={400} height={400} margin={{top: 20, right: 20, bottom: 20, left: 20}}>
<XAxis type="number" dataKey={'x'} name='stature' unit='cm'/>
<YAxis type="number" dataKey={'y'} name='weight' unit='kg'/>
<CartesianGrid />
<Tooltip cursor={{strokeDasharray: '3 3'}}/>
<Legend />
<Scatter name='A school' data={data01} fill='#8884d8' shape="star"/>
</ScatterChart>
);
}
})
ReactDOM.render(
<ThreeDimScatterChart />,
document.getElementById('container')
);
Output:
So in this image for 2nd scatter x value is 120 and y value is 0, So if y value is 0 . I don't want to diaplay scatter at all.
Please help me in this
Thanks
Background:
I am trying to add a tooltip to a react-native-svg chart following this tutorial.
The link to the tutorial: Link
Current Code Implementation:
import React, {useState} from 'react';
import {View, Text, Dimensions} from 'react-native';
import {LineChart} from 'react-native-chart-kit';
import {Rect, Text as TextSVG, Svg} from 'react-native-svg';
const Charts = () => {
let [tooltipPos, setTooltipPos] = useState({
x: 0,
y: 0,
visible: false,
value: 0,
});
return (
<View>
<LineChart
data={{
labels: ['January', 'February', 'March', 'April', 'May', 'June'],
datasets: [
{
data: [100, 110, 90, 130, 80, 103],
},
],
}}
width={Dimensions.get('window').width}
height={250}
yAxisLabel="$"
yAxisSuffix="k"
yAxisInterval={1}
chartConfig={{
backgroundColor: 'white',
backgroundGradientFrom: '#fbfbfb',
backgroundGradientTo: '#fbfbfb',
decimalPlaces: 2,
color: (opacity = 1) => `rgba(0, 0, 0, ${opacity})`,
labelColor: (opacity = 1) => `rgba(0, 0, 0, ${opacity})`,
style: {
borderRadius: 0,
},
propsForDots: {
r: '6',
strokeWidth: '0',
stroke: '#fbfbfb',
},
}}
bezier
style={{
marginVertical: 8,
borderRadius: 6,
}}
decorator={() => {
return tooltipPos.visible ? (
<View>
<Svg>
<Rect
x={tooltipPos.x - 15}
y={tooltipPos.y + 10}
width="40"
height="30"
fill="black"
/>
<MaterialCommunityIcons
name="run"
size={32}
color="rgb(67, 67, 67)"
/>
<TextSVG
x={tooltipPos.x + 5}
y={tooltipPos.y + 30}
fill="white"
fontSize="16"
fontWeight="bold"
textAnchor="middle">
{tooltipPos.value}
</TextSVG>
</Svg>
</View>
) : null;
}}
onDataPointClick={(data) => {
let isSamePoint = tooltipPos.x === data.x && tooltipPos.y === data.y;
isSamePoint
? setTooltipPos((previousState) => {
return {
...previousState,
value: data.value,
visible: !previousState.visible,
};
})
: setTooltipPos({
x: data.x,
value: data.value,
y: data.y,
visible: true,
});
}}
/>
</View>
);
};
Question:
I want to add the icon(Running icon) as seen on the image above, to be next to the tool-tip text.
The Icon, then the text inside the rectangle filled in Black. When I try to position it,, it shows up on the extreme top left for some reason. How do I position it?
You can use the ForeignObject component from react-native-svg and change your decorator to something like this:
decorator={() => {
return tooltipPos.visible ? (
<ForeignObject x={tooltipPos.x} y={tooltipPos.y}>
<View
style={{
width: 70,
flexDirection: 'row',
backgroundColor: 'black',
}}>
<MaterialCommunityIcons
name="run"
size={32}
color="rgb(67, 67, 67)"
/>
<Text
style={{
color: 'white',
fontSize: 16,
fontWeight: 'bold',
textAnchor: 'middle',
}}>
{tooltipPos.value}
</Text>
</View>
</ForeignObject>
) : null;
}}
The problem with what you had before is that the react-native-svg Text and Rect components use x and y coordinates and your icon doesn't, so the positioning will be off.
The benefit of the approach shown above is that you only have to specify the x and y props of the ForeignObject. Everything inside the ForeignObject can be regular views, positioned as you normally would (https://github.com/react-native-community/react-native-svg#foreignobject).
I've chosen the tooltipPos.x and tooltipPos.y for the x and y prop values of the ForeignObject respectively, but you could add an offset if necessary.
Be sure to import ForeignObject from react-native-svg.