Update react state from touchhandler
See original GitHub issueI am trying to indicate which bar is selected and when doing so change a react state which also updates the bars color. The issue I am facing is that it only works as soon as I add a console.log() inside the touch handler, which then somehow makes it trigger correctly. I tried multiple ways of doing it but never got it to work like intented.
import { useTheme } from '@emotion/react';
import {
Canvas,
Group,
Paint,
Path,
Skia,
useDerivedValue,
useTouchHandler,
useValue,
} from '@shopify/react-native-skia';
import PropTypes from 'prop-types';
import React, { useState } from 'react';
import Axis from '../charts/barchart/Axis';
import Orientation from '../charts/barchart/Constants';
import NewLegend from '../charts/barchart/NewLegend';
import { scaleBand, scaleLinear, scaleOrdinal } from 'd3-scale';
import { max } from 'd3-arrays';
import { line as d3Line } from 'd3-shape';
import { View } from 'react-native';
const createLinePath = (data, xMax, yMax, xBarScale, yLineScale) => {
const line = d3Line()
.x((d) => xBarScale(d.name) + xBarScale.bandwidth() / 2)
.y((d) => yLineScale(d.performance));
return Skia.Path.MakeFromSVGString(line(data));
};
const insideBounds = (rect, x, y) => {
return x >= rect.x && x <= rect.x + rect.width && y >= rect.y && y <= rect.y + rect.height;
};
const HistoryChart = ({
data,
xAccessor,
yAccessor,
width = 200,
height = 200,
offset = 8,
lineCount = 6,
verticalMargin = 8,
margin = { top: 20, right: 40, bottom: 20, left: 40 },
selected,
setSelected,
y,
children,
}) => {
if (!data) {
throw Error('No data set!');
} else if (!xAccessor) {
throw Error('No xAccessor set!');
} else if (!yAccessor) {
throw Error('No yAccessor set!');
}
const theme = useTheme();
const yMax = height - margin.bottom - margin.top;
const xMax = width - margin.left - margin.right;
const xBarScale = scaleBand()
.domain(data.map((val) => xAccessor(val)))
.range([0, xMax])
.paddingInner(0.2)
.paddingOuter(0.2)
.round(false);
const yBarScale = scaleLinear()
.domain([0, max(data, (d) => yAccessor(d))])
.range([yMax, 0])
.nice();
const yLineScale = scaleLinear()
// .domain(d3.extent(data, (d) => d.performance))
.domain([0, max(data, (d) => d.performance)])
.range([yMax, 0])
.nice();
const legendScale = scaleOrdinal()
.domain(['Plant TCH (t/ha)', 'Ratoon TCH (t/ha)', 'Perfomance Ration (%)'])
.range(['#377eb8', '#4daf4a', '#ff7f00']);
const touchHandler = useTouchHandler(
{
onStart: ({ x, y }) => {
data.forEach((d) => {
const name = xAccessor(d);
const barWidth = xBarScale.bandwidth();
const barHeight = yMax - (yBarScale(yAccessor(d)) ?? 0);
const barX = xBarScale(name);
const barY = yMax - barHeight;
const rect = {
x: barX + margin.left,
y: barY + margin.top,
width: barWidth,
height: barHeight,
};
if (insideBounds(rect, x, y)) {
setSelected(d.seasonName);
}
});
},
},
[setSelected, selected],
);
return (
<View style={{ flexDirection: 'column', alignItems: 'center' }}>
<NewLegend
round
scale={legendScale}
style={{
marginHorizontal: 8,
justifyContent: 'center',
}}
/>
<View style={{ width, height }}>
<Canvas style={{ flex: 1 }} onTouch={touchHandler}>
<Group
origin={{ x: 128, y: 128 }}
transform={[{ translateY: margin.top }, { translateX: margin.left }]}>
{data.map((d, index) => {
const path = Skia.Path.Make();
const name = xAccessor(d);
const barWidth = xBarScale.bandwidth();
const barHeight = yMax - (yBarScale(yAccessor(d)) ?? 0);
const barX = xBarScale(name);
const barY = yMax - barHeight;
const rect = {
x: barX,
y: barY,
width: barWidth,
height: barHeight,
};
path.addRect(rect, false);
path.close();
return (
<Path
key={`bar-${name}`}
path={path}
color={
d.seasonName === selected ? '#4ea0a3' : d.ratoon === 0 ? '#377eb8' : '#4daf4a'
}
/>
);
})}
<Path
path={createLinePath(data, xMax, yMax, xBarScale, yLineScale)}
color={'#ff7f00'}
style={'stroke'}
strokeWidth={2}
/>
<Axis
scale={yBarScale}
orientation={Orientation.left}
strokeColor={theme.colors.text}
textColor={theme.colors.text}
label="(t/ha)"
/>
<Axis
scale={xBarScale}
top={yMax}
orientation={Orientation.bottom}
strokeColor={theme.colors.text}
textColor={theme.colors.text}
/>
<Axis
scale={yLineScale}
orientation={Orientation.right}
left={xMax}
strokeColor={theme.colors.text}
textColor={theme.colors.text}
label="(%)"
/>
</Group>
</Canvas>
</View>
</View>
);
};
HistoryChart.propTypes = {
data: PropTypes.array,
colors: PropTypes.array,
width: PropTypes.number,
height: PropTypes.number,
offset: PropTypes.number,
valueExtractor: PropTypes.func,
nameExtractor: PropTypes.func,
children: PropTypes.any,
};
export default HistoryChart;
Issue Analytics
- State:
- Created a year ago
- Comments:9
Top Results From Across the Web
Updating Objects in State - React Docs
State can hold any kind of JavaScript value, including objects. But you shouldn't change objects that you hold in the React state directly....
Read more >Touch handler not called with React Native - Stack Overflow
I just started learning React Native and ran into this: I've created a component ... setState(prevState => ({ age: prevState.age + 1 })) ......
Read more >Updating State with Events - LearnHowToProgram.com
In this lesson, we'll handle our first event in a React application. We've handled many events before — every time we use functions...
Read more >Handling touchscreen or mouse events: Simple Touch Handler
The Simple Touch Handler can be configured to react to particular touch or mouse ... Handler object manages several variables reflecting its current...
Read more >Handling Touches - React Native
Users interact with mobile apps mainly through touch. They can use a combination of gestures, such as tapping on a button, scrolling a...
Read more >
Top Related Medium Post
No results found
Top Related StackOverflow Question
No results found
Troubleshoot Live Code
Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free
Top Related Reddit Thread
No results found
Top Related Hackernoon Post
No results found
Top Related Tweet
No results found
Top Related Dev.to Post
No results found
Top Related Hashnode Post
No results found
Yea thx. Really enjoying the library so far.
Yes doing so now.