I want to create a component where the size of the chart automatically adjusts with resize events of the container holding the graph. It would be great if someone can help me with an example. Here si the link to the library. react-rnd library
E.x somehting like this but using highcharts codebox react-rnd with googlecharts
const Highchart = () => {
return (
<rnd>
<div>
<HightchartsReact highcharts={Highcharts} constructorType={'chart'} options={option} />
</div>
</rnd>
)
}
You need to call chart.reflow method in onResizeStop event callback function.
return (
<Rnd
...
onResizeStop={(e, direction, ref, delta, position) => {
const chart = this.chartComponent.current?.chart;
if (chart) {
chart.reflow();
}
...
}}
>
...
</Rnd>
);
From Highcharts API:
reflow( [e])
Reflows the chart to its container. By default, the chart reflows
automatically to its container following a window.resize event, as per
the chart.reflow option. However, there are no reliable events for div
resize, so if the container is resized without a window resize event,
this must be called explicitly.
Live demo: https://codesandbox.io/s/cranky-hoover-cz-czw5k?file=/src/index.js
API Reference: https://api.highcharts.com/class-reference/Highcharts.Chart#reflow
Related
I need to know how to assign a function to an expo-av Video component's onPress event, or how to make a useRef reference trigger an onPress event on an expo-av Video component.
I have a lot of requirements for a React Native video component and I am trying to work out how to best achieve them all. The main issue is the user needs to be able to double-tap the video and have an animation fire. We have a Pressable component that renders over the video that handles a double tap. The animation works fine. But the problem is there's also a requirement that the video uses native controls, and the Pressable blocks those controls.
I have two strategies but I haven't been able to achieve either. Plan A, someone on StackOverflow tells me that expo-av Video components have some kind of onPress function not listed in their docs, and all I have to do is trigger the double tap animation using that function. So far I've tried onPress, onTouchEnd, onTouchStart, and onClick, and all are undefined and not listed in the docs. No dice.
Plan B, I can create a Pressable component that renders over the Video component that is short enough not to block the native controls, but tall enough to catch all other taps. Then, when a user double-taps the Pressable, the animation fires and everything's good. This is what I initially submitted as a solution, but our QA folks said they need the native controls to show on the first press. Normally the native controls are not visible and the expo-av Video shows them on any press, but the Pressable blocks those presses, and I cannot find anything in the docs that allows you to referentially trigger the expo-av press event. I have a useRef() working and have tried videoRef.current.press, videoRef.current.click, and videoRef.current.setStatusAsync({ progressUpdateIntervalMillis: 0 }). No dice. I just need the control buttons to show up like they normally do on a tap, nothing else.
So in summary, does anyone A: Know how to assign a function to the expo-av Video component's onPress event? or B: Know how to make a useRef reference trigger an onPress event on an expo-av Video component? or C: Some other solution I haven't thought of?
Here are some code snippets if it helps:
The Video instantiation:
<Video
ref={(video) => videoRef.current = video}
style={[styles.postMedia, { width: videoDimensions.width, height: videoDimensions.height }]}
source={{ uri: videoUrl }}
rate={1.0}
volume={1.0}
isMuted={isMuted}
resizeMode={Video.RESIZE_MODE_CONTAIN}
shouldPlay={shouldPlay || screenIsFocussed && (keyInView === _id)}
isLooping
useNativeControls
onError={(e) => setVideoUrl(`${getS3BaseUrl(video.s3Bucket)}/${video.url}`)}
onReadyForDisplay={(response) => {
const { width, height } = response.naturalSize;
if (width >= height) return setVideoDimensions({ width: screenWidth, height: screenWidth * height / width });
if (height > width) return setVideoDimensions({ height: screenWidth, width: screenWidth * width / height });
}}
/>
The handleDoubleTap function:
let lastTap = null;
const handleDoubleTap = () => {
const now = Date.now();
const DOUBLE_PRESS_DELAY = 300;
if (lastTap && (now - lastTap) < DOUBLE_PRESS_DELAY) {
toggleLike();
} else {
if (videoRef) videoRef.current.setStatusAsync({ progressUpdateIntervalMillis: 0 }); // <-- insert something that actually works here
lastTap = now;
}
};
The Pressable component instantiation:
{(video || image) && (
<Pressable
onPress={handleDoubleTap}
style={video ? {
...styles.videoLikePostFromFeedPressable,
height: IS_IOS ? DEVICE_WIDTH * 0.75 : DEVICE_WIDTH * 0.66,
} : {
...styles.likePostFromFeedPressable,
height: DEVICE_WIDTH,
}}
>
{renderOverlay()} {/* <-- This is just the animation render, works fine */}
</Pressable>
)}
I'm trying to update the scene background dynamically using a npm package that's called 'react-colorful'.
So far it works great, debugging the color picker with console.log() returns desired colors but Three.js doesn't seem to update it when I change it using the hooks from React.
So my goal is to dynamically update the scene.background color when using the color picker. The color picker has no issues, returns everything dynamically when I debugged it.
Here is what I tried so far, if you need more information, feel free to ask.
My code is heavily based on this CodePen
const ThreePromoKitAnim = () => {
const [currBackground, setBackground] = useState('#ff0000')
const mount = useRef()
useEffect(() => {
// initialization of scene, camera
mount.current.appendChild(renderer.domElement)
}, [])
// value = returned color value from the color picker
const handleBackgroundChange = (value) => {
setBackground(value)
scene.background = new THREE.Color(currBackground)
}
return (
<>
<HexColorPicker
color={currBackground}
onChange={handleBackgroundChange}
/>
<div className='threejs' ref={mount} />
</>
)
}
Also, I've noticed that when React auto updates the page (when saving code) and I set another value of the background color using the color picker it does work but not dynamically.
Am I missing something? Why doesn't the background change dynamically? How can I use hooks to dynamically change the background? Is there another workaround to dynamically change the color?
Many thanks in advance.
The following code works for me, I just had to re-render the scene.
const handleBackgroundChange = useCallback((value) => {
setBackground(value)
scene.background = new THREE.Color(value)
renderer.render(scene, camera)
}, [scene])
I am trying to handle React components in popup outer windows, I am using FlexLayout, ag-Grid React and SyncFusion React and I managed to handle the outer window with FlexLayout by using const currentDocument = this.selfRef.current.ownerDocument; -check Floating Tabs (Popouts) in FlexLayout- and pass this currentDocument to getDocument() callback in ag-Grid and now I wanted to do the same with SyncFusion, but I found no method/property in SyncFusion to pass the currentDocument to it.
So, is there anyway to pass the outer window document to the SyncFusion component which will be re-rendered after going in outer window and leave the origin document?
Attached a screenshot for the issue when not passing the currentDocument (new outer window) to SyncFusion components I have pressed the Date Picker button in the outer window (on the right), but the DatePicker component rendered in the original window (on the left)!
SyncFusion DatePicker Issue Screenshot
You can align the popup position relate to input element by setting X and Y position in the open event of DateTimePicker popup as mentioned in the below code example.
this.onOpen = (args) => {
args.popup.position = { X: "left", Y: "bottom" };
};
The possible values for popup position are left, right, top and bottom. Try specifying the all possible combination of values to align the popup based on your viewport.
Also, you can set the offsetX and offsetY value in number (Provide the x and y value by imaging x and y axis) to align the DateTimePicker popup relate to the input element. Here, we have provided the offsetX and offsetY value based on the desktop mode. You can customize it based on the view port.
this.onOpen = (args) => {
args.popup.offsetX= 1000;
args.popup.offsetY= 1000;
};
Sample Link: https://stackblitz.com/edit/react-yhgq4y-w2avy2?file=index.js
Provide more details about your query, if the solution suggested above does not help you.
You can customize the DatePicker popup’s in the desired position using the appendTo method in the open event argument. Kindly refer the below code,
render() {
return (
<div className="control-pane">
<div className="control-section">
<div className="datepicker-control-section">
<DatePickerComponent open={this.onOpen.bind(this)} />
</div>
</div>
<div id="target" />
</div>
);
}
onOpen(args) {
args.appendTo = document.body.querySelector("#target");
}
Please find the sample below,
Sample link: https://stackblitz.com/edit/react-eekdsn?file=index.js
I haven't seen a thread that handles this, at least not for React.
My case: I want to conditionally render a back to top button only when scrolling is an option. It makes no sense to have such a feature if it can't affect the page.
The only solutions I can find are in jQuery. I'm using react-scroll but couldn't find any functionality there for this.
When a scrollbar is visible then window.visualViewport.width < window.Width.
var buttonIsVisible = window.visualViewport.width < window.Width;
To check if scrollbar is visible in vertical appearance.
document.body.clientHeight > window.innerHeight
I added this code in a useEffect.
useEffect(() => {
if (document.body.clientHeight > window.innerHeight) {
something()
}
}, [state]);
Luke.
By "scrolling is an option" I am assuming here that you mean "when the scrollbar is visible."
As far as I am aware, there is not any way to check for scrollbar visibility using the React API. There is the DOM boolean window.scrollbars.visible; however, I have not had luck with this. It seems to always return true whether a scrollbar is visible or not. The following approach may work for you:
You could set an event listener for onScroll and check window.scrollY. If window.scrollY > 0, then you could conditionally render the button. If window.scrollY is 0, then the page is already scrolled to the top and there is no need to display the button.
Depending on the design of your web app, checking once for scrollbar visibility (e.g., on componentDidMount) may not be the best option, since some DOM elements may continue to load after the component initially mounts and the height of the page may change.
I hope this is helpful.
If you have a wrapper around the element that has the scroll you can detect the width difference.
<div className="wrapper">
<div className="scrollingContent">
Very long content here
</div>
</div>
const scrollBarWidth = this.wrapper.clientWidth - this.scrollingContent.clientWidth;
this.setState({ scrollBarWidth });
Most of the time (depending on edge cases where elements are sized differently). You can use an element ref to check if the scrollWidth is greater than the current width (or height for vertical scroll). The ref might not update scroll properties with useEffect hence why you need state in the dependencies array. Plus you will likely want to add a window resize event listener to run the same code.
const ref = useRef(null);
const [hasScrollBar, setHasScrollBar] = useState(false);
useEffect(() => {
function updateState() {
const el = ref.current;
el && setHasScrollBar(el.scrollWidth > el.getBoundingClientRect().width);
}
updateState();
window.addEventListener('resize', updateState);
return () => window.removeEventListener('resize', updateState);
}, [state]);
<div ref={ref} style={{ overflowX: 'auto' }}>
{state}
</div>
A new update to SwipeableViews allows for each Tab in the MaterialUI Tabs Component to have their own height. Let me back up a little. Before, MaterialUI Tabs component will show all tabs in the height of the longest tab. This created unnecessary scrolling on tabs that didn't need it. SwipeableViews recently fixed this by adding this to their component
<SwipeableViews
action={actions => {this.swipeableActions = actions;}}>
<div>{'slide n°1'}</div>
<div>{'slide n°2'}</div>
<div>{'slide n°3'}</div>
</SwipeableViews>
and
componentDidUpdate() {
this.swipeableActions.updateHeight();
}
That fixed the height issue across tabs on their loaded state. But when items are hidden and shown with a click event, the height persists and shown items do not show (being cut off from view)
See image (imgur failed to load the image) see the image link instead
image
You need to add:
animateHeight
to the SwipeableViews component.
You may also have to pass a function down to child components in order to update the height when a child modifies the view.
UpdateSwipeableViewHeight = () => {
if (this.swipeableActions) this.swipeableActions.updateHeight()
};
<SwipeableViews
id="searchTabsSwipeableView"
axis={theme.direction === 'rtl' ? 'x-reverse' : 'x'}
index={activeTabIndex}
onChangeIndex={index => {
this.handleChange(null, index);
this.UpdateSwipeableViewHeight();
}
}
action={actions => (this.swipeableActions = actions)}
animateHeight
>
<div className={classes.swipableViewsComponent}>
<ChildComponent updateHeight={this.UpdateSwipeableViewHeight} />
</div>