Is this an issue with React inline styling? I have a Crop component where I want to change the crop view based on the aspect ratio of the pic coming in.
When I pass the variables to Crop:
<Crop width={"200"} height={"100"}
I have in my Crop.js component:
<div style={{aspectRatio: `calc(${width}px / ${height}px)` }}>
</div>
But the changes don't show. However, when I write a regular aspect ratio with integers (i.e., 1/2) it does change. Is there a way to accomplish this the way I'm trying to? It'll help me with multiple components.
aspectRatio expect a value of type <ratio>, and you are giving it a calc. The example below works:
export default function App() {
const width = 200;
const height = 60;
return (
<div
style={{
aspectRatio: width / height,
background: "red"
}}
></div>
);
}
Also, pass them as numbers instead of strings:
<Crop width={200} height={100}
Related
I've designed and built an interactive Org Chart that allows users to view business organizations in a hierarchical format. By default only the first row below the root node of the chart is visible, but users can click to expand the chart further, thereby changing the size of the chart. Users can also drag and drop nodes to simulate a reorganization of the business.
I'm currently using react-zoom-pan-pinch to allow users to zoom and pan the chart. It works very well when the org chart has not been expanded too much, but becomes problematic at larger chart scales.
The problem is that the organizations being represented by the chart are very broad in comparison to their depth, meaning a fully expanded chart is a horizontal rectangle, not a square. react-zoom-pan-pinch will only allow me to zoom out to the maximum vertical extent of the chart, meaning users can't view a fully expanded organization without scrolling from side to side. This is not an acceptable behavior.
This is for work, so I cannot post code without violating numerous agreements. Instead I have linked to the react-zoom-pan-pinch documentation and will go over what I have tried changing.
The first place I looked was the TransformWrapper Props section of the documentation.
There I found the inititalScale, minScale, and maxScale props.
I can set the initialScale prop to a value of less than 1, and obtain something close to the result I want at first. Setting it to 0.5 results in the chart being zoomed out further than normally possible, but when I zoom in to a value of 1 I am unable to zoom back out. This was expected, as the minScale prop was still set to 1.
Having checked that the props indeed work, I went ahead and set minScale to 0.5, assuming I would be able to zoom back out to the initial view seen when initialScale is set to 0.5. This seemed like it should work, but it did not. Even with the minScale prop set to 0.5, I am unable to zoom back out after zooming in to a value of 1. This is very strange to me, as the acceptance of 0.5 as the initialScale prop and subsequent rendering of the chart indicates that values below 1 are acceptable.
I am now messing around with the rest of the props listed in the documentation, but have yet to achieve the desired result (infinite zoomout).
I believe the root of the issue is that react-zoom-pan-pinch is meant for images, not things that change size and aspect ratio, but it is a good package and I would prefer to keep using it.
Is anyone familiar enough with this package to know the settings I should be using to allow infinite zoom out, and if so what are those settings?
I discovered the answer to my own question. It turns out the minScale, maxScale, and other props were not being passed to the component properly. Once they are passed properly the package works very well. Here's my explanation/fix
The documentation suggests doing this:
import { TransformWrapper, TransformComponent } from "react-zoom-pan-pinch";
class Example extends Component {
render() {
return (
<TransformWrapper
initialScale={1}
minScale={0.5}
maxScale={7}
initialPositionX={200}
initialPositionY={100}
>
{({ zoomIn, zoomOut, resetTransform, ...rest }) => (
<React.Fragment>
<div className="tools">
<button onClick={() => zoomIn()}>+</button>
<button onClick={() => zoomOut()}>-</button>
<button onClick={() => resetTransform()}>x</button>
</div>
<TransformComponent>
<img src="image.jpg" alt="test" />
<div>Example text</div>
</TransformComponent>
</React.Fragment>
)}
</TransformWrapper>
);
}
}
The above doesn't work, and the minScale and maxScale props aren't passed to the component. If you open the React dev tools in your browser and go to TransformWrapper, you'll see the default values of 1 for minScale and 8 for maxScale, not the values you entered in your code.
You can solve the problem by creating an object:
const transformOptions = {
initialScale: 1,
minScale: 0.5,
maxScale: 2
}
Then setting an options prop inside the TransformWrapper component equal to the object, like so:
import { TransformWrapper, TransformComponent } from "react-zoom-pan-pinch";
class Example extends Component {
render() {
return (
<TransformWrapper
initialScale={1}
options={transformOptions}
initialPositionX={200}
initialPositionY={100}
>
{({ zoomIn, zoomOut, resetTransform, ...rest }) => (
<React.Fragment>
<div className="tools">
<button onClick={() => zoomIn()}>+</button>
<button onClick={() => zoomOut()}>-</button>
<button onClick={() => resetTransform()}>x</button>
</div>
<TransformComponent>
<img src="image.jpg" alt="test" />
<div>Example text</div>
</TransformComponent>
</React.Fragment>
)}
</TransformWrapper>
);
}
}
The same thing applies to pan, wheel, and zoom options. They don't work if set directly in the component as suggested by the documentation, but do work if you create objects like I did above.
I would like to calculate the current scroll percentage of my IonContent (it's an Ionic + React app)
The page layout looks like this:
<IonPage>
<IonHeader>
<IonToolbar>
<IonButtons slot="start">
<IonMenuButton />
</IonButtons>
<IonTitle>Page</IonTitle>
</IonToolbar>
</IonHeader>
<IonContentid="main-content"
scrollEvents={true}
onIonScroll={(ev) => {
// ToDo: calculate scroll percentage
console.log(ev.detail.scrollTop);
}}>
{// very long custom component
}
<IonFooter>
<IonLabel>Footer </IonLabel>
</IonFooter>
</IonContent>
</IonPage>
From the IonScroll event, I can read out the scrollTop which seems to be the current scroll position.
Now I need to get the maximal scrolling height of the IonContent.
Related questions are:
finding the maximum scroll position of a page
Cross-Browser Method to Determine Vertical Scroll Percentage in Javascript
how to calculate height of scroll content
The accepted answer from the first question seems to provide the most complete approach, by taking the max over a selection of scrolling height values:
var limit = Math.max( document.body.scrollHeight, document.body.offsetHeight,
document.documentElement.clientHeight, document.documentElement.scrollHeight, document.documentElement.offsetHeight );
I've extended this by also adding:
document.scrollingElement.scrollHeight
The problem:
In my scenario, the maximum over these values is around 660. But the logging output from ev.detail.scrollTop goes up to 680.76.
I've connected the debug inspector and tried scrolling from the console, to see what would happen for scroll value around 660. I can still see the content move when scrolling from 660 to 680:
document.getElementById('main-content').scrollToPoint(0, 680);
How can I find the maximum scrolling coordinates?
I think I found the solution:
onIonScroll={async (ev) => {
const elem = document.getElementById("ion-content-id");
// the ion content has its own associated scrollElement
const scrollElement = await ( elem as any).getScrollElement()
const scrollPosition = ev.detail.scrollTop;
const totalContentHeight = scrollElement.scrollHeight;
const viewportHeight = elem.offsetHeight;
const percentage = scrollPosition / (totalContentHeight - viewportHeight);
console.log(percentage);
}}
I don't understand why this incompatibility was introduced though. Wouldn't it be possible to connect the scrollElement of the IonContent with document.scrollingElement? The standard is still a draft but implemented in all major browsers (expect IE).
I have this example https://stackblitz.com/edit/react-sjyuej?file=Chart1.jsx
where I'm trying to make the the two charts in the left container share the height and respond to window resizing.
I've made the width responsive by setting overflow: hidden, forcing the charts to rescale as far as I understand, but I don't know how to get the same effect with the height.
Setting height='100%' in the Chart component doesn't help.
Use the highcharts-react-official package (>= 2.1) and set containerProps={{ style: { height: "100%" } }}.
This will make the chart dynamically resize to fill its parent div. You can then set up parent divs using flexbox to get your desired layout.
For example your render method would look like this:
render() {
return (
<HighchartsReact
containerProps={{ style: { height: "100%" } }}
highcharts={ Highcharts }
options={ options }
/>
);
}
Here is a live demo
Make sure you are on version >= 2.1 of highcharts-react-official (see this github issue)
After setting the height, you need to use chart.reflow() method:
componentDidMount(){
const container = this.chartComponent.current.container.current;
const table = document.getElementsByClassName('table')[0];
container.style.height = table.clientHeight + 'px';
this.chartComponent.current.chart.reflow();
}
API: https://api.highcharts.com/class-reference/Highcharts.Chart#reflow
Live demo: https://stackblitz.com/edit/react-3jwwvt?file=ChartOfficial.jsx
I have this ImageBackground tag in my React-Native App.
const{height,width} = Dimensions.get('window);
const navHeight = ExtraDimensions.get('SOFT_MENU_BAR_HEIGHT');
render(){
return(
<ImageBackground source={Images.bg} style={{width=width+48,height=height}}>
//content
</ImageBackground>
);
}
The number 48 is the height of the default Android navigation bar (the one contains BACK button). The navHeight is to detect the height of navigation bar on the device (refer here:https://github.com/Sunhat/react-native-extra-dimensions-android).
Since there are now devices with no navigation bar, i want to make a conditional styling in the ImageBackground style to take style={styles.bg1} when there is a value of navHeight and take style={styles.bg2} when there is no navHeight value.
May i know where and how should i implement the styling? thanks
My current wrong way of doing it is
<ImageBackground source={Images.bg} style={navHeight=0 ? styles.bg1 : styles.bg2}>
There is a syntatical error, for comparison you have to use ==.
Try this,
<ImageBackground source={Images.bg} style={ (navHeight==0) ? styles.bg1 : styles.bg2}>
Moreover, i would recommend you using Image tag and append a child component to it by using position="absolute". Because some styling props like borderRadius don't work in the case of ImageBackground tag.
I hope this helps you !
so I got some help in another question on making a table's height equal to the viewport's height. Meaning, if the user resizes the screen, the table height adjusts on-the-fly to occupy the entire height of the screen. My problem now is, this is a React App and I am having a hard time converting this jquery function to React.
My function looks like this:
$(document).ready(function() {
function setHeight() {
windowHeight = $(window).innerHeight();
$('.dynamicHeight').css('height', windowHeight + 'px');
};
setHeight();
$(window).resize(function() {
setHeight();
});
});
Here is a codepen showing the behavior
And here is a screen shot of what I am trying to do
How can I build this function in React? I'm assuming it will need some modification.
Thanks in advance
NOTE: this may look like another question I made, but it is not a duplicate. It's an entirely different question related to the same issue.
In the components lifecycle, you should add a componentDidMount method. In that method, simply add a resize handler
import React, { Component } from 'react';
class MyComponent extends Component {
constructor(props){
super(props);
this.state = {
width: $(window).width(),
height: $(window).height(),
}
this.resize = this.resize.bind(this);
}
resize(){
this.setState(() => {
return {
width: $(window).width(),
height: $(window).height()
}
});
}
componentDidMount(){
window.addEventListener('resize', this.resize);
}
render(){
return (
<div>
<MyComponent width={this.state.width} height={this.state.height} />
</div>
)
}
}
So what this does is, when your Component initializes, you set the state to the width and height of the viewport (using jQuery). Then you define a method to update the state, and when your component mounts you attach an resize event listener to it and call the resize method each time the screen resizes. This ensures that your state always contains the width and height of the viewport. Then you can define the width and height of your component by passing that state to your component as props and boom! All good, everytime you resize your screen your component will match it.
If you have any questions let me know. You might need to tinker with this to get it to work (specifically the lifecycle events might not update state as often as you need to) I just whipped it up and did not test it but in theory this is exactly what you need
edit: just a thought, if you want to change the style of your components I would use a style object. So in the child component, do something like this:
let style = {
width: this.props.width + 'px',
height: this.props.height + 'px'
}
And when you render that component
<ChildComponent style={style} />