I'm trying to retrieve the width of my component using #rehooks/component-size which is meant to look something like this:
import { useRef } from 'react'
import useComponentSize from '#rehooks/component-size'
function MyComponent() {
let ref = useRef(null)
let { width } = useComponentSize(ref)
It worked for me before a refactor but now it just provides 0.
I'm trying to get the width of a linechart
<div className={styles.timeline}>
<Plot
{...baseChartSettings}
data={[{ x: time, y: groundSpeedData }]}
layout={{
xaxis: {
range: filters.byTime,
rangeslider: {
range: [0, data.maxTime],
},
},
}}
onUpdate={(
{
layout: {
xaxis: { range },
},
}: any // Figure, with 100% defined xaxis and yaxis atts
) => {
if (anyChangeInRange(filters.byTime, range)) {
filters.byTime = range;
setFilter({ ...filter });
}
}}
/>
</div>
edit: adding ref={ref} to the <div className={styles.timeline}> is what I was missing
Related
I'm making react app using gsap. I use scrolltrigger in timeline but it's not working. The scrolltrigger couldn't work.Can someone help me? Here is my code
gsap.registerPlugin(ScrollTrigger);
const el = useRef(null);
const q = gsap.utils.selector(el);
useEffect(() => {
let tl = gsap.timeline({
scrollTrigger: {
trigger: q(".scrollDist"),
start: "top top",
end: " bottom center",
scrub: 1,
markers: true,
},
});
tl.fromTo(
q(".header"),
{ y: 0, opacity: 1 },
{ y: -100, opacity: 0 }
).fromTo(".button_field", { y: 0 }, { y: -50 });
}, []);
A tad hard to pick up on what you're trying to achieve without a proper code snippet but I'll have a crack.
First glance it looks like you need to change the scrub: 1 config to scrub: true.
The other concern is it may not be querying for the elements properly, hard to tell without seeing the markup.
This is an assumption of the full code you have within your React component.
import React, { useEffect, useRef } from 'react'
import { gsap } from 'gsap'
import { ScrollTrigger } from 'gsap/all'
gsap.registerPlugin(ScrollTrigger);
const IndexPage = () => { {
const elementRef = useRef(null)
const q = gsap.utils.selector(elementRef)
useEffect(() => {
let tl = gsap.timeline(
{
scrollTrigger: {
trigger: q(".scrollDist"),
start: "top top",
end: "bottom center",
scrub: true, // scrub: 1
markers: true
}
}
);
tl
.fromTo(
q(".header"),
{ y: 0, opacity: 1 },
{ y: -100, opacity: 0 }
)
.fromTo(
".button_field",
{ y: 0 },
{ y: -50 }
);
}, [])
return (
<div ref={elementRef}>
<div className='scrollDist'></div>
<header className='header'>header</header>
<button className='button_field'>button</button>
</div>
)
}
export default IndexPage
I'm trying to implement a highChart using react and react-grid-layout. The chart should resize according to the react-grid-layout and for that, I need to pass chart.reflow() in the onResizeStop prop of ResponsiveGridLayout. I can get access to the chart in the callback prop of HighchartsReact but I'm not able to figure out how do I get access to the chart in the ResponsiveGridLayout component to pass it in the onResizeStop prop.
import { Responsive, WidthProvider } from 'react-grid-layout';
import Highcharts, { chart } from 'highcharts'
import HighchartsReact from 'highcharts-react-official'
import { useRef, useState } from "react"
import styles from './Blocks.module.css';
const ResponsiveGridLayout = WidthProvider(Responsive);
const options1 = {
title: {
text: 'My chart 1'
},
series: [{
type:'bar',
data: [1,2,3,4,5,6,7,1,2,3,4,5,6,7,1,2,3,4,5,6,7,1,2,3,4,5,6,7]
}],
}
const Blocks = (props) => {
const layout1 = [
{ i: "1", x: 0, y: 0, w: 8, h: 8 },
]
const handleResize = chart => {
chart.reflow()
}
return (
<div className={styles.blocks}>
<ResponsiveGridLayout
className="layout"
layouts={layout1}
autoSize={true}
allow-resize={true}
isDraggable
isRearrangeable
isResizable
onResizeStop={handleResize}
breakpoints={{lg: 1200, md: 996, sm: 768, xs: 480, xxs: 0}}
cols={{lg: 12, md: 10, sm: 6, xs: 4, xxs: 2}}
>
<div className={styles.container} key="1" >
<HighchartsReact
containerProps = {{ className: styles.chartContainer }}
highcharts = { Highcharts }
options = { options1 }
callback = { chart => chart}
/>
</div>
</ResponsiveGridLayout>
</div>
)
}
export default Blocks
You can get chart instance by using React useRef hook:
const chartComponent = useRef(null);
const handleResize = () => {
const chart = chartComponent.current?.chart;
if (chart) {
chart.reflow();
}
};
return (
<HighchartsReact
ref={chartComponent}
...
/>
);
Live demo: https://codesandbox.io/s/highcharts-react-demo-fork-n4y01?file=/demo.jsx
Docs: https://github.com/highcharts/highcharts-react#how-to-get-a-chart-instance
I'm using REACT-PLOTLY.JS to create a scatter graph. I've got everything working apart from the graph redrawing it self every-time I change a data point when using a list of objects in the array data prop. BUT... when I manually write the array and it's containing objects, my graph does not re-draw when I change a data point, which is how it should work. The 2nd solution is not dynamic and is unusable. Can anyone help please?
re-draws graph when data point changes.
<Plot
data={plotlyData}
does not re-draw graph when data point is changed but is not dynamic and therefore unusable.
<Plot
data={[plotlyData[0],plotlyData[1]]}
I'm using functional components.
How plotData is generated. I'm using an API to get the coordinates for the X and Y axis.
import { React, useState } from "react";
import Plot from "react-plotly.js";
import { useQuery } from "react-query";
import axios from "axios";
const PlotlyGraph = (props) => {
const [plot, setPlot] = useState([]);///not in use
const { datasets } = props;
const QueryUuid = datasets.map((d) => {
// console.log("Individual Dataset:", d);
return `${d.age}-${d.kmax}-${d.frontK}-${d.pachymetry}`;
});
const { error, isLoading, data } = useQuery(
`data-${QueryUuid.join("-")}`,
() =>
axios.post("/api/calculate_cxl", {
age_baseline: datasets.map((d) => d.age),
kmax: datasets.map((d) => d.kmax),
front_k1: datasets.map((d) => d.frontK),
tpt2: datasets.map((d) => d.pachymetry),
color: datasets.map((d) => d.color),
})
);
let plotlyData;
if (error !== null || isLoading === true) {
plotlyData = [];
} else {
plotlyData = data.data.map((d, i) => {
return {
x: d.x,
y: d.y,
type: "scatter",
mode: "lines",
marker: { color: datasets[i].color },
line: {
width: 3,
},
name: `Patient ${i + 1}`,
showlegend: true,
};
});
}
console.log("plot:", plotlyData);
//- Graph Configuration
const config = {
editable: false,
scrollZoom: true,
displayModeBar: true,
displaylogo: false,
};
return (
<>
<Plot
data={plotlyData}
layout={{
yaxis: { range: [0, 1] },
xaxis: { range: [0, 5] },
autoSize: "true",
title: "Patient Comparison",
}}
style={{ width: "100%", height: " 700px" }}
useResizeHandler={true}
config={config}
revision={0}
// onInitialized={plot}
// onUpdate={(plot) => setPlot(plotlyData)}
/>
</>
);
};
export default PlotlyGraph;
I had a similar issue and was able to figure out how to dynamically update my plot with new data after every API fetch (see State Management). Since I don't have access to the API you are using, I've included my own example.
From my API, I fetch an object that looks like this:
{
28AD7D49F6E13C0A: [69.36, 64.11, 68.69, 62.1, ...],
28DDC649F6003C1C: [69.59, 63.18, 60.63, 63.08, ...],
Time: ['20:50:15', '20:50:17', '20:50:19', '20:50:21', ...]
}
Every two seconds, that objects gets updated with a new item in each array. When the state data gets updated with setData, the state object gets updated, which then causes the plot to render with new data.
Full example:
import React, { useState, useEffect } from "react";
import Plot from "react-plotly.js";
function TemperatureGraph() {
const [data, setData] = useState({});
const state = {
data: [
{
x: data["Time"],
y: data["28AD7D49F6E13C0A"],
name: "28AD7D49F6E13C0A",
type: "scatter",
mode: "lines+markers",
marker: {
color: "red",
},
},
{
x: data["Time"],
y: data["28DDC649F6003C1C"],
name: "28DDC649F6003C1C",
type: "scatter",
mode: "lines+markers",
marker: {
color: "black",
},
},
],
layout: {
width: 800,
height: 500,
title: "",
xaxis: {
title: "Time",
},
yaxis: {
title: "Temperature (F)",
},
},
frames: [],
config: {},
};
useEffect(() => {
const timer = setInterval(() => {
fetch("/get-temperatures")
.then((response) => response.json())
.then((data) => setData(data));
}, 2000);
return () => clearInterval(timer);
}, []);
return (
<div>
<Plot data={state.data} layout={state.layout} />
</div>
);
}
export default TemperatureGraph;
How can I change the range slider to show the label text value instead of the value number from the marks data?
So instead of those numbers, I'd like to display different text values...
This is what I have right now :
import React, { useState } from "react";
import { makeStyles } from "#material-ui/core/styles";
import Slider from "#material-ui/core/Slider";
import { Tooltip } from "#material-ui/core";
// const useStyles = makeStyles((theme) => ({
// root: {
// width: 300,
// },
// margin: {
// height: theme.spacing(3),
// },
// }));
const marks = [
{
value: 0,
label: "None",
},
{
value: 33,
label: "Basic Style",
},
{
value: 66,
label: "Moderately Styled",
},
{
value: 99,
label: "Pro Styled",
},
];
function valuetext(value) {
return `${value}`;
}
const Slider3 = () => {
return (
<div className="container">
<Slider
defaultValue={33}
getAriaValueText={valuetext}
aria-labelledby="discrete-slider-always"
step={33}
marks={marks}
valueLabelDisplay="on"
/>
<div></div>
</div>
);
};
export default Slider3;
So I'm trying to display the label values from the marks constant inside that circle from the top, instead of the number values that is showing.
I am generating a chart using react-chartjs-2 and am pulling in "categories" from my API. The number of categories is dynamic (will be between 0 and approximately 20, but ultimately it is up to the user). What is the best way to generate a different color for each slice of a doughnut chart, all based off of my primary theme color (#3B73B4)? Would it be best to just do a gradient?
My graph component is as follows:
import React, { Component } from 'react';
import { Doughnut } from 'react-chartjs-2';
import colors from '../_styles/colors';
class CurrentPackGraph extends Component {
constructor(props) {
super(props);
this.state = {
categories: props.data.categories,
}
}
render() {
const data = {
labels: this.state.categories.map(c => c.name),
datasets: [{
data : this.state.categories.map(i => i.items.length),
backgroundColor : [
colors.darkPrimary,
'#36A2EB',
'#FFCE56',
],
hoverBackgroundColor: [
colors.darkPrimary,
'#36A2EB',
'#FFCE56',
],
}],
};
const chartOptions = {
maintainAspectRatio: false,
};
return (
<Doughnut
data={data}
options={chartOptions}
height={300}
/>
);
}
}
export default CurrentPackGraph;
You can use d3 scale library to achieve that:
import * as scale from "d3-scale";
// Set amount of categories
const length = 20;
// Generate color scale
const colors = scale
.scaleLinear()
.domain([0, length])
.range(["#fff", "#3B73B4"]);
// define some inline styles for illustration
const getBoxStyle = color => ({
margin: "20px",
backgroundColor: `${color}`
});
And then we simply use the generated scale:
function App() {
const squares = [];
for (let i = 0; i < length; i++) {
squares.push(
<div style={getBoxStyle(colors(i))} key={i}>
{colors(i)} {i}
</div>
);
}
return <div className="App">{squares}</div>;
}
Please see the working example here: https://codesandbox.io/s/p96vz6r5m0