I wanted to make a 3 x 3 map with dots as their location. when you click a dot then it will change the path that you are using, i.e the line will be changed to that route. This being the color of it as well as the line position does anyone know how? This is what I had already. Now im confused of how to make a function that would implement this functionality.
import React from "react";
import styled from 'styled-components';
import { scaleLinear } from "d3-scale";
var mapStyles = { position: "relative" };
var svgStyles = { position: "absolute", top: 0, left: 0, right: 0, bottom: 0 };
function Map({ width, height, nodes }) {
var xScale = scaleLinear()
.domain([0, 100])
.range([0, width]);
var yScale = scaleLinear()
.domain([0, 100])
.range([0, height]);
return (
<div id="map" style={mapStyles}>
<svg
style={svgStyles}
width={width}
height={height}
viewBox={`0 0 ${width} ${height}`}
>
{links.map((link, i) => (
<line
key={i}
x1={xScale(nodes[link.s].x)}
x2={xScale(nodes[link.d].x)}
y1={yScale(nodes[link.s].y)}
y2={yScale(nodes[link.d].y)}
strokeWidth={5}
stroke={
nodes[link.s].done === true && nodes[link.d].done
? "#CBFF5B"
: "grey"
}
/>
))}
{nodes.map((node, i) => (
<circle
key={i}
cx={xScale(node.x)}
cy={yScale(node.y)}
r="20"
fill={node.done === true ? "#CBFF5B" : "grey"}
/>
))}
</svg>
</div>
);
}
var nodes = [
{ x: 10, y: 10},
{ x: 10, y: 30, done: true },
{ x: 10, y: 50, done: true },
{ x: 50, y: 10, done: true},
{ x: 50, y: 30} ,
{ x: 50, y: 50 },
{ x: 90, y: 10 },
{ x: 90, y: 30 },
{ x: 90, y: 50 }
];
var links = [{ s: 3, d: 1 }, { s: 1, d: 2 }];
export const NodeMap = () => {
const avg = () => {
var elem = [ 0, 1, 2,]
var sum = 0;
for( var i = 0; i < elem.length; i++ ){
sum += parseInt( elem[i], 10 ); //don't forget to add the base
}
return sum/3;
}
return (
<Container>
<div className="App">
<Map width={666} height={1340} nodes={nodes} links={links} />
</div>
</Container>
);
};
Related
So currently I have this as my code for the victory line chat
import React from 'react';
import { View, StyleSheet } from 'react-native';
import { VictoryLine, VictoryChart } from 'victory-native'
let data = [
{
x: 1,
y: 0
},
{
x: 2,
y: 0
},
{
x: 3,
y: 0
},
{
x: 4,
y: 70
},
{
x: 5,
y: 73
},
{
x: 5,
y: 73
},
{
x: 5,
y: 73
},
{
x: 5,
y: 73
}
]
export default function Graph() {
return (
<VictoryLine style={styles.graph} height={150} width={350} data={data} style={{data: {stroke: 'orange', strokeWidth: 2.5}}} />
)
}
const styles = StyleSheet.create({
graph: {
marginRight: 0
}
})
which gives me a line chart that looks like this. Is there a way to:
A) Plot dotted point on the line for each data point
B) Just dot the last data point in the data list. Example image here of what I want to achieve
You can wrap your VictoryLine with an VictroyChart and hide the axis, like this sample
<View>
<VictoryChart polar={this.state.polar} height={390}>
<VictoryAxis style={{
axis: {stroke: "transparent"},
ticks: {stroke: "transparent"},
tickLabels: { fill:"transparent"}
}} />
<VictoryLine
interpolation={this.state.interpolation} data={data}
style={{ data: { stroke: "#c43a31" } }}
/>
<VictoryScatter data={[data[data.length-1]]}
size={5}
style={{ data: { fill: "#c43a31" } }}
/>
</VictoryChart>
</View>
import React, { FC } from "react";
import { G } from "react-native-svg";
import Animated, { useAnimatedProps, useDerivedValue, withSpring } from "react-native-reanimated";
import { CanvasControlledValuesProps } from "./helpers/types";
import { Candle } from "./Candle";
import { CANDLE_WIDTH } from "../../constants/sizes";
const AnimatedGroup = Animated.createAnimatedComponent(G);
export const Canvas: FC<CanvasControlledValuesProps> = ({
scaleY,
scaleX,
translateX,
offsetByY,
data,
initialDomain,
}) => {
const props = useAnimatedProps(() => {
return {
x: withSpring(translateX.value, {
damping: 20,
stiffness: 90,
}),
y: withSpring(offsetByY.value, {
damping: 20,
stiffness: 90,
}),
transform: { scale: [scaleX.value, scaleY.value] },
};
});
return (
<AnimatedGroup animatedProps={props}>
{data.map((candle, index) => (
<Candle key={index} width={CANDLE_WIDTH} {...{ candle, index }} domain={initialDomain} />
))}
</AnimatedGroup>
);
};
Good day! I need to increase or decrease the content of the AnimatedGroup, so I decided to use G but there was a problem: the scale is not applied for the AnimatedGroup, why it's like that? I have not used Aniamted.View since the quality of the Svg content, inside which the AnimatedGroup is located, will be lost.
const style = useAnimatedStyle(() => {
return {
transform: [
{
translateX: offsetByX.value,
},
{
translateX: withSpring(translateX.value, springConfig),
},
{
translateY: withSpring(adaptation.value.offsetByY, springConfig),
},
{
scaleX: scaleX.value,
},
{
scaleY: withSpring(adaptation.value.scaleY, springConfig),
},
],
};
});
return (
<AnimatedGroup style={style}>
{data.map((candle, index) => (
<Candle key={index} width={CANDLE_WIDTH} {...{ candle, index }} domain={initialDomain} />
))}
</AnimatedGroup>
);
The solution is to add animated styles for the Animated Group. Or you can use the matrix property like this:
const props = useAnimatedProps(() => {
return {
x: withSpring(translateX.value, {
damping: 20,
stiffness: 90,
}),
y: withSpring(offsetByY.value, {
damping: 20,
stiffness: 90,
}),
matrix: [scaleX.value, 0, 0, scaleY.value, 0, 0],
};
});
You can read about the work of matrix here https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/transform
I'm using Victory to render a data set:
class App extends React.Component {
render() {
return (
<div style={{ width: 600 }}>
<VictoryChart domainPadding={30}>
<VictoryAxis
dependentAxis={true}
style={{
grid: { stroke: "grey" }
}}
/>
<VictoryAxis />
<VictoryBar
barWidth={20}
style={{ data: { fill: "red" } }}
data={[
{ x: new Date("2019-01-01"), y: 2 },
{ x: new Date("2019-02-01"), y: 3 },
{ x: new Date("2019-03-01"), y: 5 },
{ x: new Date("2019-04-01"), y: 4 },
{ x: new Date("2019-05-01"), y: 8 },
{ x: new Date("2019-06-01"), y: 2 },
{ x: new Date("2019-07-01"), y: 3 },
{ x: new Date("2019-08-01"), y: 5 },
{ x: new Date("2019-09-01"), y: 9 },
{ x: new Date("2019-10-01"), y: 3 },
{ x: new Date("2019-11-01"), y: 5 },
{ x: new Date("2019-12-01"), y: 6 }
]}
/>
</VictoryChart>
</div>
);
}
}
How can I change the x-axis to render a tick for each month ("jan", "feb", "mar" etc.)? Further, I would like each bar to have a width of 40 px (barWidth=40), but when I do that all bars are just merged - I would like to control the margin/padding between the bars as well. How should this be solved?
An example is available in this sandbox:
https://codesandbox.io/s/victory-react-native-4t49q
You may show labels as x-axis ticks. Then to control margin/padding you may set container's width a bit wider to fit bolder bars.
import React from "react";
import { render } from "react-dom";
import { VictoryChart, VictoryBar, VictoryAxis, VictoryContainer, VictoryLabel } from "victory";
class App extends React.Component {
render() {
let month = new Array(12);
month[0] = "January";
month[1] = "February";
month[2] = "March";
month[3] = "April";
month[4] = "May";
month[5] = "June";
month[6] = "July";
month[7] = "August";
month[8] = "September";
month[9] = "October";
month[10] = "November";
month[11] = "December";
return (
<div style={{ width: 600 }}>
<VictoryChart domainPadding={30}
width={900}
containerComponent={<VictoryContainer responsive={false}/>}>
<VictoryAxis
dependentAxis={true}
style={{
grid: { stroke: "grey" }
}}
/>
<VictoryAxis
tickFormat={(x) => ``}
/>
<VictoryBar
barWidth={50}
padding={{ left: 20, right: 60 }}
style={{ data: { fill: "red" } }}
data={[
{ x: new Date("2019-01-01"), y: 2 },
{ x: new Date("2019-02-01"), y: 3 },
{ x: new Date("2019-03-01"), y: 5 },
{ x: new Date("2019-04-01"), y: 4 },
{ x: new Date("2019-05-01"), y: 8 },
{ x: new Date("2019-06-01"), y: 2 },
{ x: new Date("2019-07-01"), y: 3 },
{ x: new Date("2019-08-01"), y: 5 },
{ x: new Date("2019-09-01"), y: 9 },
{ x: new Date("2019-10-01"), y: 3 },
{ x: new Date("2019-11-01"), y: 5 },
{ x: new Date("2019-12-01"), y: 6 }
]}
labels={( datum ) => `${month[datum.x.getMonth()]}`}
labelComponent={<VictoryLabel y={250} verticalAnchor={"start"}/>}
/>
</VictoryChart>
</div>
);
}
}
render(<App />, document.getElementById("root"));
As a sandbox: link
You can try. Added comments where changes are Needed
class App extends React.Component {
render() {
return (
<div>
<VictoryChart
domainPadding={30}
width={700} // Width should be more as we are updating barWidth
>
<VictoryAxis
dependentAxis={true}
style={{
grid: { stroke: "grey" }
}}
/>
<VictoryAxis tickFormat={x => ''} /> // remove existing labels
<VictoryBar
barWidth={40}
style={{ data: { fill: "red" } }}
labels={( datum ) => { return `${datum.x.toLocaleString('default', { month: 'short' })}`}} // get labels as month name
labelComponent={
<VictoryLabel y={270}
verticalAnchor={"start"}
angle={90}
/>
}
data={[
{ x: new Date("2019-01-01"), y: 2 },
{ x: new Date("2019-02-01"), y: 3 },
{ x: new Date("2019-03-01"), y: 5 },
{ x: new Date("2019-04-01"), y: 4 },
{ x: new Date("2019-05-01"), y: 8 },
{ x: new Date("2019-06-01"), y: 2 },
{ x: new Date("2019-07-01"), y: 3 },
{ x: new Date("2019-08-01"), y: 5 },
{ x: new Date("2019-09-01"), y: 9 },
{ x: new Date("2019-10-01"), y: 3 },
{ x: new Date("2019-11-01"), y: 5 },
{ x: new Date("2019-12-01"), y: 6 }
]}
/>
</VictoryChart>
</div>
);
}
}
I am using PanResponder for a draggable box on the screen, but it can currently move off the screen. After reading the (very confusing) documentation with no examples, is there a way to constrain the box to not move off the screen?
Here's what I have:
componentWillMount () {
this.animatedValue = new Animated.ValueXY()
this.value = {x: 0, y: 0}
this.animatedValue.addListener(value => this.value = value)
this.panResponder = PanResponder.create({
onStartShouldSetPanResponder: (evt, gestureState) => true,
onMoveShouldSetPanResponder: (evt, gestureState) => {
return gestureState.dx !== 0 && gestureState.dy !== 0
},
onPanResponderGrant: (e, gestureState) => {
this.animatedValue.setOffset({
x: this.value.x,
y: this.value.y,
})
this.animatedValue.setValue({x: 0, y: 0})
},
onPanResponderMove: (e, gestureEvent) => {
this.pan(gestureEvent)
Animated.event([
null, {dx: this.animatedValue.x, dy: this.animatedValue.y}
])
},
onPanResponderRelease: (e, gestureState) => {
this.animatedValue.flattenOffset()
Animated.decay(this.animatedValue, {
velocity: {x: gestureState.vx, y: gestureState.vy}
}).start()
}
})
}
render () {
return (
<Animated.View
{...this.panResponder.panHandlers}
style={styles.box}
>
<Image source={{uri: 'uri'}} style={styles.imageDimensions} />
</Animated.View>
)
}
I made a basic code that can help you if you modify it. The Animated.View can not be moved to a negative position in the X coordinate.
import React from 'react';
import { View, Animated, PanResponder } from 'react-native';
let _value = {x: 0, y:0};
const _animatedValue = new Animated.ValueXY();
let xOffset = 0;
export default function App() {
React.useEffect(()=> {
const listener = _animatedValue.addListener(
(value) => _value = value
);
return () => {
_animatedValue.removeListener(listener);
}
}, []);
const panResponder = React.useMemo(() => PanResponder.create({
onStartShouldSetPanResponder: () => true,
onMoveShouldSetPanResponderCapture: () => true, // Same here, tell iOS that we allow dragging
onPanResponderGrant: (_, gesture) => {
xOffset= (xOffset + gesture.dx >= 0) ? _value.x : 0;
_animatedValue.setOffset({x: xOffset, y: _value.y});
_animatedValue.setValue({x: 0, y: 0});
},
onPanResponderMove: (_, gesture) => {
if (xOffset + gesture.dx >= 0) {
_animatedValue.setValue({ x: gesture.dx, y: 0 });
} else {
xOffset = 0;
_animatedValue.setOffset({x: 0, y: _value.y});
_animatedValue.setValue({ x: 0, y: 0 });
}
},
onPanResponderRelease: () => {
_animatedValue.flattenOffset();
}
}), []);
return <View
style={{
flex: 1,
alignItems: 'center',
alignContent: 'center'
}}
>
<View
style={{
width: 500,
height: 200,
position: 'relative',
}}
>
<View
style={{
width: 500,
height: 2,
backgroundColor: 'red',
top: 100,
position: 'absolute'
}}
>
<Animated.View
{...panResponder.panHandlers}
style={{
width: 10,
height: 10,
backgroundColor: 'blue',
borderRadius: 5,
position: 'absolute',
zIndex: 2,
transform: _animatedValue.getTranslateTransform()
}}
></Animated.View>
</View>
</View>
</View>
}
I'm trying to create a React component that is a Line and Scatter chart to look like this:
The React component for a single line with circles looks like this:
function Line ({ color, chartData }) {
return (
<VictoryGroup data={chartData}>
<VictoryLine
style={{ data: { stroke: color } }}
/>
<VictoryScatter
style={{
data: {
stroke: color,
fill: 'white',
strokeWidth: 3
}
}}
/>
</VictoryGroup>
);
}
I am trying to consume the component like so:
function MyCoolChart () {
return (
<VictoryChart>
<Line
color='#349CEE'
chartData={data1}
/>
<Line
color='#715EBD'
chartData={data2}
/>
</VictoryChart>
);
}
But the Line components aren't rendered. They're only rendered if I call them directly as a function, like so:
export default function MyCoolChart () {
return (
<VictoryChart>
{Line({ color: '#349CEE', chartData: data1 })}
{Line({ color: '#715EBD', chartData: data2 })}
</VictoryChart>
);
}
I'm trying to make a reusable component, so I'd rather not have to consume it as a function. I also want to understand why this is happening. Thanks!
For reference, the values of data1 and data2:
const data1 = [
{ x: 'M', y: 2 },
{ x: 'Tu', y: 3 },
{ x: 'W', y: 5 },
{ x: 'Th', y: 0 },
{ x: 'F', y: 7 }
];
const data2 = [
{ x: 'M', y: 1 },
{ x: 'Tu', y: 5 },
{ x: 'W', y: 5 },
{ x: 'Th', y: 7 },
{ x: 'F', y: 6 }
];
Thanks to #boygirl for responding to my github issue
Turns out Victory passes a few props down of its own that need to be passed along for things to be rendered correctly. Examples of this are domain and scale. Here's my updated component:
function Line ({ color, ...other }) {
return (
<VictoryGroup {...other}>
<VictoryLine
style={{ data: { stroke: color } }}
/>
<VictoryScatter
style={{
data: {
stroke: color,
fill: 'white',
strokeWidth: 3
}
}}
/>
</VictoryGroup>
);
}
And it is now consumed like so:
function MyCoolChart () {
return (
<VictoryChart>
<Line
color='#349CEE'
data={data1}
/>
<Line
color='#715EBD'
data={data2}
/>
</VictoryChart>
);
}