React animate component when it render and when its state change - css

For animation i write the code like this but this code is not working for me. Whant to know this is a css problem or my code style needs update. or how to do animation on a component
render: function() {
var len = Object.keys(Interfaces.previewContainer.state.sourceImg).length;
var imgContainer = [];
for (var i = 0; i < len; i++) {
imgContainer.push(React.createElement(PreviewImgContainer, {
key: i,
flipParentClass: this.state.flipParentClass,
i_d: 'SelectedTemplate_' + i,
dataactionstring: 'selecttemplatetype-' + this.state.dataactionstring['src' + i],
sourceImg: this.state.sourceImg['src' + i],
ref: 'PreviewImgContainer',
alter: this.state.alter
}));
}
return (
React.createElement(
ReactCSSTransitionGroup, {
className:'flipParent',
transitionEnterTimeout: 250,
transitionLeaveTimeout: 250,
transitionName: 'flipped' // 'flipParent flipped' is a class name
},
React.createElement('div', {
className: 'previewContainer',
style: {
marginLeft: this.state.marginLeft
},
ref: 'previewContainer'
}, imgContainer)
)
);
}
please let me know where i am making a mistake or where i have to update the code
.flipParent {
height: 100%;
position: relative;
transform-style: preserve-3d;
transition: transform 0.5s ease 0s;
width: 100%;
}
/* .flipped is for flipping (x-axis) the element */
.flipped {
transform: rotateY(180deg);
}

Maybe you have to implement these
.flipped-enter
.flipped-enter.flipped-enter-active
.flipped-leave
.flipped-leave.flipped-leave-active
The below screenshot is from the official react guide

Related

How should I loop a 360 degree image in CSS for an Ionic App?

I have been asked to implement some of our companies 360 degree photos (panorama sort of things) on to our company app.
So far I have only been able to get the image to go across then back again which doesn't give the smooth endless photo loop we are after.
I am using Ionic 4.
Here is my current CSS code
#keyframes example {
from {
left: 0;
}
to {
left: -1350px;
}
}
.three-sixty {
max-width: none !important;
position: absolute;
height: 250px;
animation-name: example;
animation-duration: 10s;
animation-iteration-count: infinite;
animation-direction: alternate;
animation-timing-function: linear;
}
<ion-col>
<img class="three-sixty" [src]="mainImage">
</ion-col>
I am assuming I need multiple of the same image with timed animations to achieve the endless loop?
Extra Info:
The start of the image fits perfectly with the end of the image - so I need to make sure the image runs on smoothly from the last.
Any help would be greatly appreciated.
Please check the following component I implemented to view a 360 image in ionic (for web and mobile) in the latest version of ionic:
SCSS:
.rotatable-image {
display: flex;
justify-content: center;
align-items: center;
height: 300px;
background-color: lightgrey;
-webkit-user-select: none;
-khtml-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
-o-user-select: none;
user-select: none;
}
HTML:
<div
class="rotatable-image"
(mousedown)="handleMouseDown($event)"
(ondragstart)="preventDragHandler($event)"
>
<img
draggable="false"
class="rotatable-image"
alt=""
[src]="_dir + '/' + imageIndex + '.jpg'"
/>
<div style="font-size: 50px">
{{ imageIndex }}
</div>
</div>
TS:
import {
AfterViewInit,
Component,
Input,
OnChanges,
OnDestroy,
OnInit,
} from '#angular/core';
// You can play with this to adjust the sensitivity
// higher values make mouse less sensitive
const pixelsPerDegree = 3;
#Component({
selector: 'app-panoramic',
templateUrl: './panoramic.component.html',
styleUrls: ['./panoramic.component.scss'],
})
export class PanoramicComponent implements AfterViewInit, OnDestroy {
// tslint:disable-next-line: variable-name
_dir = '../../../assets/dummies/panoramic';
// tslint:disable-next-line: variable-name
_totalImages = 46;
#Input()
set dir(val: string) {
this._dir = val !== undefined && val !== null ? val : '';
}
#Input()
set totalImages(val: number) {
this._totalImages = val !== undefined && val !== null ? val : 0;
}
dragging = false;
dragStartIndex = 1;
dragStart?: any;
imageIndex = 1;
ngAfterViewInit() {
document.addEventListener(
'mousemove',
(evt: any) => {
this.handleMouseMove(evt);
},
false
);
document.addEventListener(
'mouseup',
() => {
this.handleMouseUp();
},
false
);
}
ngOnDestroy() {
document.removeEventListener(
'mousemove',
(evt: any) => {
this.handleMouseMove(evt);
},
false
);
document.removeEventListener(
'mouseup',
() => {
this.handleMouseUp();
},
false
);
}
handleMouseDown(e: any) {
this.dragging = true;
console.log(e.screenX);
this.dragStart = e.screenX;
this.dragStartIndex = this.imageIndex;
}
handleMouseUp() {
this.dragging = false;
}
updateImageIndex(currentPosition: any) {
const numImages = this._totalImages;
const pixelsPerImage = pixelsPerDegree * (360 / numImages);
// pixels moved
const dx = (currentPosition - this.dragStart) / pixelsPerImage;
let index = Math.floor(dx) % numImages;
if (index < 0) {
index = numImages + index - 1;
}
index = (index + this.dragStartIndex) % numImages;
if (index !== this.imageIndex) {
if (index === 0) {
index = 1;
}
this.imageIndex = index;
}
}
handleMouseMove(e: any) {
if (this.dragging) {
this.updateImageIndex(e.screenX);
}
}
preventDragHandler(e: any) {
e.preventDefault();
}
}

How to create a smooth background image transition in React?

I have a header, whose className changes depending on State. Each class has a different background image, specified in the CSS. Everything works fine, but the transitions are quite abrupt without a fade-in effect.
I wrote:
.jumbotron-img-1{
background-image: url("/images/myImg1.jpg");
transition: all 1s ease-in-out;
It works, but it's ugly. There is a zoom, and a distortion of the image before it shows up in its final form. I've watched some tutorials on Google, but nothing was simple and to the point for background-image transition in pure CSS or React.
Any help would be greatly appreciated, thanks!
background-image is not an animatable property. I feel what best serves your purpose is to render multiple headers with all the classnames available stacked over each other with position: absolute; relative to common parent and make only one of them visible using opacity property based on which classname is active in your state and use transition on opacity
Sample working code:
render() {
const {imgClassList} = this.props;
const {activeimgClass} = this.state;
return (
<div className="header-container">
{imgClassList.map(imgClass => {
return (
<div
className={`header ${imgClass} ${(imgClass === activeimgClass)? 'active' : ''}`}
/>)
})}
</div>
)
}
And css be something like:
.header-container {
position: relative;
}
.header{
position: absolute;
top: 0;
left: 0;
opacity: 0
transition: opacity 1s ease-in-out;
}
.header.active {
opacity: 1
}
.img-1 {
background:url('images/img-1')
}
.img-2 {
background: url('images/img-2')
} ... and so on
There's no good way to transition a background image using CSS because it's not an animatable property, per the CSS spec. One way to do this is to just have multiple images on top of one another, each containing a different one of the images you'd like to display, and then cycle through them by transitioning them to opacity: 0 and changing their z-index order.
I made a quick demo showing how you can achieve smooth changes by manipulating opacity and z-index. In pure Javascript, this is done by simply adjusting the styles with DOM manipulation and using setTimeout().
Of course in React you don't want to be doing DOM manipulation, so you can experiment with multiple classes with different opacity levels and transitions to accomplish this. There also seems to be a React component that enables all types of transitions: https://reactcommunity.org/react-transition-group/css-transition
Check out the Javascript solution demo to see how changing the opacity can get a crossfade effect on images:
function backgroundScheduler_1() {
setTimeout(() => {
document.querySelector(".img1").style.opacity = 0;
document.querySelector(".img2").style.opacity = 1;
document.querySelector(".img3").style.opacity = 1;
order(["-3", "-1", "-2"], () => { backgroundScheduler_2() }, 1000);
}, 3000);
}
function backgroundScheduler_2() {
setTimeout(() => {
document.querySelector(".img1").style.opacity = 1;
document.querySelector(".img2").style.opacity = 0;
document.querySelector(".img3").style.opacity = 1;
order(["-2", "-3", "-1"], () => { backgroundScheduler_3() }, 1000);
}, 3000);
}
function backgroundScheduler_3() {
setTimeout(() => {
document.querySelector(".img1").style.opacity = 1;
document.querySelector(".img2").style.opacity = 1;
document.querySelector(".img3").style.opacity = 0;
order(["-1", "-2", "-3"], () => { backgroundScheduler_1() }, 1000);
}, 3000);
}
function order(array, callback, time) {
setTimeout(() => {
document.querySelector(".img1").style.zIndex = array[0];
document.querySelector(".img2").style.zIndex = array[1];
document.querySelector(".img3").style.zIndex = array[2];
callback();
}, time);
}
backgroundScheduler_1();
.background-image {
position: absolute;
top: 0;
left: 0;
opacity: 1;
transition: 1s;
}
.img1 {
z-index: -1;
}
.img2 {
z-index: -2;
}
.img3 {
z-index: -3;
}
<div class="background-container">
<img class="background-image img1" src="https://placeimg.com/640/640/nature"></img>
<img class="background-image img2" src="https://placeimg.com/640/640/animals"></img>
<img class="background-image img3" src="https://placeimg.com/640/640/tech"></img>
<h2 style="color: white;">WOW!</h2>
</div>
I checked NPM momentarily and didn't see anything that promises this exact functionality. Hope this helps!

How can I update transition-delay value via ReactJS Component?

I am writing a ReactJS component for the first time. I have a tooltip which needs to have a dynamic delay value on mouseenter and mouseleave events. I am currently using a hover approach in CSS with transition-delay. This solution is working for me however, I need to be able to setState and update each of the transition-delay (see below) through my component. I need to be able to accomplish this with pure ReactJS/Javascript (no JQuery etc).
Here is a sample of my code:
.tooltip .tooltiptext {
visibility: hidden;
width: 120px;
background-color: #555;
color: #fff;
text-align: center;
border-radius: 6px;
padding: 5px 0;
position: absolute;
z-index: 1;
bottom: 125%;
left: 50%;
margin-left: -60px;
opacity: 0;
transition-delay: 2s;
}
.tooltip:hover .tooltiptext {
visibility: visible;
opacity: 1;
transition-delay: 1s;
}
How can I access each of these transition-delay properties from the component and change the value with setState?
Thanks for your help
Update: I have figured out how to update the CSS property through JS. I now need to be able to reset the state. Please see my comment from below.
Here is some additional code:
constructor(props) {
super(props);
this.state = {
userInput: '',
transitionDelay: '0s'
}
handleMouseEnterDelay() {
var mouseIn = document.getElementById('tooltip');
var delayIn = mouseIn.style.transitionDelay = '0s';
this.setState({
transitionDelay: {delayIn}
})
}
handleMouseLeaveDelay() {
var mouseLeave = document.getElementById('tooltiptext');
var delayLeave = mouseLeave.style.transitionDelay = '4s';
this.setState({
transitionDelay: {delayLeave}
})
So what I need is that after each hover event i need transitionDelay to take the values defined in the function. I.e. after first mouseenter/leave event it stays to 4s, so the second time I go to hover(enter) then it is a 4s delay for both enter and leave. I need the enter delay to go back to 0s as defined in the handleMouseEnterDelay function.
Is there a way which I can have two 'transitionDelay' values in setState? I tried a nested object i.e. in:{transitionDelay}, out:{transitionDelay} but i couldn't access it while setting state.
Maybe something like...
constructor() {
this.state = {
style: {
transitionDelay: '1s'
}
};
this.toggleDelay = this.toggleDelay.bind(this);
}
toggleDelay(state) {
this.setState({ style: { transitionDelay: state ? '2s' : '1s' } });
}
...
render() {
return (
<div className="tooltip" style={this.state.style} onMouseEnter={() => this.toggleDelay(true)} onMouseLeave={() => this.toggleDelay(false)}>
.....
</div>
);
}

React sexy transition: Animate new text on keypress

I'm looking to scroll through a story, but let the user press (space) for the next phrase. I think it could be a beautiful optional intro on a website.
Already done: I've managed to scroll through an array of strings as the user presses (space):
CodePen: https://codepen.io/anon/pen/PbRLdp
React / JS:
var strings = ["Hi","it's not easy finding a freelancer, is it?", "referrals don't always come", "you need to know it'll get done", "I get it.", "perhaps we should connect"];
var i = 0;
var hitElement = document.querySelector( '.storylines' );
document.body.onkeyup = function(e) {
if( e.keyCode == 32 ) {
addHit();
}
}
var addHit = function() {
if ( i+2 <= strings.length) {
i++
renderStories();
}
}
var renderStories = function() {
hitElement.innerHTML = strings[i];
}
HTML:
<span class="storylines">press (spacebar)</span>
My question: How can I use React to create a transition between phrases? I'm thinking of translating / fading the current span downwards, and fading the new span in (without translating it).
I tried to change your question as little as possible since I'm not that familiar with reactJS.
I would do it only by css. This will allow you to change what each transition focuses on without too much code added (opacity vs. opacity and placement).
var strings = ["Hi", "it's not easy finding a freelancer, is it?", "referrals don't always come", "you need to know it'll get done", "I get it.", "perhaps we should connect"];
var i = 0;
var hitElement = document.querySelector('.storylines');
document.body.onkeyup = function(e) {
if (e.keyCode == 32) {
addHit();
}
}
var addHit = function() {
if (i + 2 <= strings.length) {
i++
renderStories();
}
}
var renderStories = function() {
hitElement.classList.remove('enter');
hitElement.classList.add('hide');
setTimeout(function() {
hitElement.innerHTML = strings[i];
hitElement.classList.remove('hide');
hitElement.classList.add('enter');
}, 250);
}
.storylines {
display: inline-block;
transition: opacity 250ms linear 150ms;
opacity: 0;
}
.storylines.hide {
transition: all 250ms linear;
transform: translateY(15px);
opacity: 0;
}
.storylines.enter {
opacity: 1;
}
<span class="storylines enter">press (spacebar)</span>
NOTICE: click on Expand snippet to not have the spacebar scroll the stackoverflow page :-)
This is the logic flow:
The page starts with the storylines class and the enter class.
This is to have the 1st element already shown.
When the change occurs, remove the enter class, and add the hide class to make the class leave.
hide will make sure the element disappears and moves down. enter is removed so it won't override the opacity of the element.
Also, hide contains a different transition that will animate all changes. This allows the transform to also move the element on exit.
After a timeout, add the enter class and remove the hide class
Here, since we remove the hide class, the transition changes to animate only opacity. So, the element appears in place instead of moving up or down.
NOTICE that the enter animation as a delay value added, so it won't happen in the same time as the hide animation.
transition: opacity 250ms linear 150ms;
Also, you can change the animations using css only, which I think is a good separation of roles.
Try this on your last function:
var renderStories = function() {
hitElement.style.opacity = 0;
setTimeout(function(){
hitElement.innerHTML = strings[i];
hitElement.style.opacity = 1;
}, 600);
}
An this in your CSS:
.storylines {
transition: all 0.6s;
opacity: 1;
}
The JS timeout should be exactly the transition time for your CSS element.
EDIT: With translate
var renderStories = function() {
hitElement.style.opacity = 0;
hitElement.style.transform = "translateY(-100%)";
setTimeout(function(){
hitElement.innerHTML = strings[i];
hitElement.style.opacity = 1;
hitElement.style.transform = "translateY(0%)";
}, 600);
}
CSS
.storylines {
transition: all 0.6s;
opacity: 1;
display: block; /* the element needs to be seen as solid */
}
EDIT 2: Changed the location so the new line appears in the same place:
var renderStories = function() {
hitElement.style.opacity = 0;
hitElement.style.transform = "translateY(-100%)";
setTimeout(function(){
hitElement.style.trasition = "opacity 0.3s, transform 0s"
hitElement.style.transform = "translateY(0%)";
}, 300);
setTimeout(function(){
hitElement.innerHTML = strings[i];
hitElement.style.opacity = 1;
hitElement.style.trasition = "opacity 0.3s, transform 0.3s"
}, 600);
}
CSS:
.storylines {
transition: opacity 0.3s, transform 0.3s;
opacity: 1;
display: block; /* the element needs to be seen as solid */
}
If you want it slower make sure that the 600 is the double of 0.3 or 300 with whatever value you're changing.

Can I get a two-way transition speed with CSS for open and close?

I have a full-screen overlay menu.
.overlay {
height: 0%;
width: 100%;
position: fixed;
z-index: 70;
top: 0;
right: 0;
background-color:#415566;
overflow-y: hidden;
transition: 2.0s;
}
<div id="menuActive">☰</div>
×
I have JS to call it to open and close:
function openNav() {
document.getElementById("navBar").style.height = "100%";
}
function closeNav() {
document.getElementById("navBar").style.height = "0%";
}
Is it possible to have a different transition time for openNav() and closeNav()? At present, I am only able to control both.
You could add an extra class to your .overlay to modify the transition:
function openNav() {
var navBar = document.getElementById("navBar");
navBar.style.height = "100%";
setTimeout(function(){
navBar.classList.add("opened");
}, 2000)
}
function closeNav() {
var navBar = document.getElementById("navBar");
navBar.style.height = "0%";
setTimeout(function(){
navBar.classList.remove("opened");
}, 300)
}
and the CSS for this class could be:
.opened {
transition: height 300ms; /* The duration you want... */
}
Also, take the good advice given by skobaljic in the question's comments about using JS to just add/remove classes for this kind of interaction.
Here we go.
function openNav() {
$("#navBar").show(1000);
}
function closeNav() {
$("#navBar").hide();
}

Resources