I am using ReactJs. I want to change a position of the image dynamically.
I am trying to set up style like described here:
My sprite.js:
'use strict';
import '../res/my_css.css'
const React = require('react');
const ReactDOM = require('react-dom');
class Sprite extends React.Component {
render() {
var left = 5000 + 'px';
var top = 5000 + 'px';
var padding = 5000 + 'px';
return (
<div id="bird" style={{padding:padding, left: left, top:top}}/>
)
}
}
export default Sprite;
ReactDOM.render(
<Sprite />,
document.getElementById('sprite')
)
My css contains:
#bird {
background:url('../res/bird.png');
background-repeat: no-repeat;
}
I see the image, but style={{padding:padding, left: left, top:top}} does not applied.
If I look to the source code in Chrome, I see the style padding:5000px, left:5000px, top:5000px. But my image is in the left top corner.
How can I dinamically change the position of the div element (image in my case) in ReactJs?
Try like this.You have not included position:absolute
class Sprite extends React.Component {
render() {
var left = 5000 + 'px';
var top = 5000 + 'px';
var padding = 5000 + 'px';
return (
<div id="bird" style={{padding, left, top,position:'absolute'}}/>
)
}
}
To play with left and top add position like this
<div id="bird" style={{position: 'relative', padding, left, top}}/>
Related
I simply want to create infinitely moving object with javascript.
I integrate it with react just for exploration but the idea is to make it infinite
I have an issue that the result eventually is not quiet what I wanted to.
The issue is it goes correctly infinite to the left direction but not to the right, when moving to the right, it only moves 2 iteration, and then no more objects appearing
scroll --> is smooth scrolling factor
Here is the link to the code playground:
https://codesandbox.io/s/infinite-loop-scrolling-c2iq0c
here is my code:
import { useRef, useEffect } from "react";
import Physics from "./Physics";
import { useStateValue } from "./StateProvider";
export function App() {
return (
<>
<Boxes />
<Physics />
</>
);
}
const totalbox = 16;
export const Boxes = () => {
return (
<>
{Array(totalbox)
.fill(totalbox)
.map((num, i) => (
<BoxDetail key={i} keyindex={i} />
))}
</>
);
};
const BoxDetail = ({ keyindex }) => {
const [{ pos: scroll }] = useStateValue();
const boxRef = useRef();
//infinite
// total box * ( width + margin )
const margin = 50;
const width = 50;
const WHOLEWIDTH = totalbox * (margin + width);
function calcPos(_scroll, _position) {
const temp =
((_scroll + _position + margin + width + WHOLEWIDTH) % WHOLEWIDTH) - margin - width;
return temp;
}
useEffect(() => {
const boxPos = 100 * keyindex;
boxRef.current.style.left = `${calcPos(scroll, boxPos)}px`;
}, [scroll, calcPos]);
return (
<>
<div
ref={boxRef}
style={{
border: '1px solid red',
position: 'absolute',
color: 'blue',
margin: '0px',
width: '50px',
height: '50px',
}}
>
box {keyindex}
</div>
</>
);
};
the picture below shows -> going to right direction
the picture below shows -> going to left direction
Any idea where the problem is ?
The problem is in your method of wrapping around
You are using % WHOLEWIDTH, which is perfectly appropriate, for situations of scrolling one way. This is because, for example, if WHOLEWIDTH is 1500, then 1700 % WHOLEWIDTH is 200, and 30050 % WHOLEWIDTH is 50.
The problem is when you scroll in the other direction. -300 % WHOLEWIDTH will not automatically become 1200. You have a good mitigation, which is to add WHOLEWIDTH, before doing the % WHOLEWIDTH.
However that only deals with numbers in the range -1500 to 0. If the number goes more negative than -1500, the result will be negative, which is not what you want.
Solution
The simplest solution is to add not just one WHOLEWIDTH, but many. For example, try changing this line:
const temp =
((_scroll + _position + margin + width + WHOLEWIDTH) % WHOLEWIDTH) - margin - width;
to this:
const temp =
((_scroll + _position + margin + width + 10000*WHOLEWIDTH) % WHOLEWIDTH) - margin - width;
That will allow you to scroll the boxes to wrap round 10000 times in the negative direction and still have them all display.
I am trying to copy an open curtain animation like in the following where the side divs expand horizontally on the background image on scroll.
I have a working example with the following code
import { useState, useEffect, useRef, useCallback } from "react";
import "./styles.css";
export default function App() {
// check window scroll direction
const [y, setY] = useState(null);
const [scrollDirection, setScrollDirection] = useState("");
const boxTwo = useRef(null);
const boxTwoLeft = useRef(null);
const boxTwoRight = useRef(null);
const countRefTranslateX = useRef(0);
// check window scroll direction https://stackoverflow.com/questions/62497110/detect-scroll-direction-in-react-js
const handleScrollDirection = useCallback(
(e) => {
const window = e.currentTarget;
if (y > window.scrollY) {
setScrollDirection("up");
} else if (y < window.scrollY) {
setScrollDirection("down");
}
setY(window.scrollY);
},
[y]
);
const handleScroll = useCallback(() => {
if (boxTwo.current) {
let position = boxTwo.current.getBoundingClientRect();
// checking for partial visibility and if 50 pixels of the element is visible in viewport
if (
position.top + 50 < window.innerHeight &&
position.bottom >= 0 &&
scrollDirection === "down"
) {
countRefTranslateX.current = countRefTranslateX.current + 3;
boxTwoLeft.current.style.transform = `translateX(-${countRefTranslateX.current}px)`;
boxTwoRight.current.style.transform = `translateX(${countRefTranslateX.current}px)`;
} else if (
position.top + 50 < window.innerHeight &&
position.bottom >= 0 &&
scrollDirection === "up"
) {
countRefTranslateX.current = countRefTranslateX.current - 3;
boxTwoLeft.current.style.transform = `translateX(-${countRefTranslateX.current}px)`;
boxTwoRight.current.style.transform = `translateX(${countRefTranslateX.current}px)`;
} else {
countRefTranslateX.current = 0;
boxTwoLeft.current.style.transform = `translateX(-${countRefTranslateX.current}px)`;
boxTwoRight.current.style.transform = `translateX(${countRefTranslateX.current}px)`;
}
}
}, [scrollDirection]);
useEffect(() => {
window.addEventListener("scroll", handleScroll);
return () => {
window.removeEventListener("scroll", handleScroll);
};
}, [handleScroll]);
useEffect(() => {
setY(window.scrollY);
window.addEventListener("scroll", handleScrollDirection);
return () => {
window.removeEventListener("scroll", handleScrollDirection);
};
}, [handleScrollDirection]);
return (
<div className="App">
<div className="boxOne"></div>
<div ref={boxTwo} className="boxTwo">
<div ref={boxTwoLeft} className="boxTwoLeft"></div>
<div ref={boxTwoRight} className="boxTwoRight"></div>
</div>
<div className="boxThree"></div>
</div>
);
}
I have two issues.
My right white div keeps going to the left while I scroll up
I cannot get a fixed vertical window breakpoint. My animation continues after the window has scrolled after the point I want to start/stop moving the divs
How can I resolve these issues?
My codesandbox
I've looked over what you've done but it's way too complicated.
All you want is to place two curtains (panels) on top of your content.
The container should have position:relative and the curtains should have position: absolute.
You then declare the scrollLimits in between which they should move. In the example below, 0 is the starting point and window.innerHeight the end point. Replace those values with whatever makes sense for your section, considering its vertical position in the page. You could use the section's current offsetTop and clientHeight to set the limits dynamically, based on current window size.
You then get the current scroll position and calculate the scroll percentage relative to the limits.
You then apply the percentage/2 + 50% to each curtain's transform: translateX() the left one with negative value, the right one with positive value.
Done.
document.addEventListener('scroll', revealSection);
/* function revealSection() {
const scrollLimits = [0, window.innerHeight];
const currentScroll = window.scrollY;
const percent = Math.min(currentScroll * 100 / (scrollLimits[1] - scrollLimits[0]), 100);
document.querySelector('.l-panel').style.transform = `translateX(-${percent/2 + 50}%)`;
document.querySelector('.r-panel').style.transform = `translateX(${percent/2 + 50}%)`;
} */
function revealSection() {
const top = document.querySelector('section').getBoundingClientRect().top;
const percent = Math.min(Math.max(0, (window.innerHeight - top) / window.innerHeight * 100), 100);
document.querySelector('.l-panel').style.transform = `translateX(-${percent/2 + 50}%)`;
document.querySelector('.r-panel').style.transform = `translateX(${percent/2 + 50}%)`;
}
body {
margin: 0;
}
section {
background-image: url('https://static.toss.im/assets/homepage/new tossim/section2_4_big.jpg');
background-repeat: no-repeat;
background-position: center;
background-size: cover;
width: 100%;
height: 100vh;
margin: 100vh 0;
position: relative;
overflow: hidden;
}
.l-panel, .r-panel{
position: absolute;
height: 100%;
width: 100%;
content: '';
top: 0;
background-color: white;
left: 0;
}
<section>
<div class="l-panel"></div>
<div class="r-panel"></div>
</section>
Note: change the CSS selectors so the styles apply to your section only.
Edit: I've come up with a more generic way to set the scroll interval, using the section's getBoundingClientRect().top and window.innerHeight. It's probably more useful, as you no longer have to worry about the section's position in page.
I've left the previous version in, for reference and/or for anyone who prefers it.
I'm trying to scroll my div horizontally with arrows by changing the margin of the div as using scrollLeft property needs me to set overflow as hidden on the div, which doesn't go well with my hover effects.
But I can't figure out how to set it in a way that the div while scrolling horizontally perfectly aligns with the window on both left and right sides of the div, on both pc and mobile.
I managed to make the left arrow stop working initially when the margin is zero by calculating the actual margin set with css('margin-left'). But I can't figure out how to do the same for the right arrow i.e when the div reaches the end of scrolling.
Here is what the div looks like (the ones below the large grid, with multiple items) - https://netflix-clone-by-shivam.herokuapp.com/
import $ from "jquery";
export const LeftArrow = node => {
var move = node.current;
var margin = parseInt($(move).css('margin-left'));
console.log(margin)
if(margin < 0) {
$(move).animate(
{
marginLeft: "+=330px"
},
"slow"
);
}
};
export const RightArrow = node => {
var move = node.current;
var margin = parseInt($(move).css('margin-left'));
console.log(margin)
$(move).animate(
{
marginLeft: "-=330px"
},
"slow"
);
};
I think you need to calculate all the images together, minus the last one.
var images = $(move).find('.movie-image');
var width = 0;
for(var i = 0; i < (images.length -1); i++){
width += images.eq(i).width();
}
Then only animate if the margin is smaller than the width.
if(margin < width){
$(move).animate({
marginLeft: "-=330px"
}, "slow");
}
Edit: Yeah dont answer my question that works too!
I placed getBoundingClientRect() in both componentDidMount and componentDidUpdate and they both return the same values.
When I use getBoundingClientRect it returns a random value like 330 which is completely way off because it's less than than the window viewport size.
Chrome's getBoundingClientRect:
ClientRect
bottom
:
346.4270935058594
height
:
0
left
:
0
right
:
394
top
:
346.4270935058594
width
:
394
Also, side note: When I use this function in Microsoft Edge the values like height and top are more accurate
Microsoft Edge:
{bottom: 1150.919921875, height: 513.05993652...", left: 0, right: 390, top: 637.85998535...", width: 390}
class Hoop extends React.Component {
state = {
rect: {},
offsetY: 0
}
componentDidMount() {
const { documentElement, body } = document;
//remember: window.innerHeight and window.pageYOffset are in the global
//scope as innerHeight and pageYOffset anyway, because window is the global object.
const scrollTop = pageYOffset || documentElement.scrollTop || body.scrollTop;
const rect = ReactDOM
.findDOMNode(this.targetHoopRef)
.getBoundingClientRect();
// const offsetY = rect.top + scrollTop + pageYOffset;
const offsetY = 0;
this.setState({ rect, offsetY });
}
componentDidUpdate() {
const rect = ReactDOM
.findDOMNode(this.targetHoopRef)
.getBoundingClientRect();
// console.log(rect);
}
render() {
const { projectname, projectdate, projecttools, projectdescript, droptargetname } = this.props;
const { rect, offsetY } = this.state;
return (
<Card className="column" id="hoop" ref="test">
<TargetHoop isOver=""
projectname={projectname}
droptargetname={droptargetname}
cardRect={rect}
offsetY={offsetY}
ref={ref => this.targetHoopRef = ref} />
<extrastuff/>
);
}
}
I have a problem with dynamically added div's and adjusting parent's height according to dynamically added content.
So, I have a div called #full-content-wrap and it's width divided with two child elements. These element's are called .doubled-wrap-content-left and .doubled-wrap-content-right (let's call it left wrap and right wrap). So, then, I have a two links (or buttons, or whatever) so when I click on one of these links, javascript add a element .doubled-table dynamically to left or right wrap (according which link i clicked). So, but I have a bit problem with setting height of #full-content-wrap or left/right wrap.
When I set a full-cont-wrap's height to auto, and l-r wrap's height to auto too, it's still 0px. When I set 100% - auto it's still 100% and added elements are overflowing off the parent element. So I've done it this way. I have created a function that adjusts height of full-cont-wrap to biggest height of it's content (left or right wrap) and when it's empty, to window.innerHeight. But, it's kinda uncomfortable and it has two minuses. The first one is that when I change size of my browser, then I reload page and maximize window, the height is smaller than innerHeight of maximized window (this happens when I open inspect element function). The second one is as you can realise, it's unnecessary JS counting and setting of height.
Question is: How to do this simply in CSS without JS?
Things like: Divs are floating etc. I know and I have tried set display to every value.
Additional questions comment please :/
<div id="full-content-wrap">
<div id="section-name">
<span>Dashboard</span>
<span class="section-subname">statistics and more</span>
</div>
<div id="doubled-wrap-content">
<div id="doubled-wrap-content-left">
<div class="doubled-table">
<div class="table-header">
<div class="caption">
<span class="fa fa-cogs"></span>
<span class="caption-content">Server Control</span>
</div>
<div class="tools">
<div class="picon-collapse"></div>
<div class="picon-remove"></div>
</div>
</div>
<div class="table-body"></div>
</div>
</div>
<div id="doubled-wrap-content-right">
</div>
</div>
function setContentWrap () {
/* Set width for full-wrap-content */
var width = screen.width;
width -= 220;
var percent = ((width * 100) / screen.width);
$("#full-content-wrap").css({ width: percent + '%' });
/* Set height for full-wrap-content */
var left = $('#doubled-wrap-content-left')[0].offsetHeight;
var right = $('#doubled-wrap-content-right')[0].offsetHeight;
var sidePanel = $('.side-panel-menu')[0].offsetHeight;
var side = false;
var bigger = 0, b = "";
if (left > right) { bigger = left; b = "left"; }
else if (right > left) { bigger = right; b = "right"; }
else if (right == left) { bigger = right || left; }
if (bigger < sidePanel) {
bigger = sidePanel;
side = true;
}
var height = 0, j = 0;
$('#full-content-wrap').each(function () {
var n = this.children;
var length = this.children.length;
for ( var i = 0; i < length; i++ ) {
if (n[i].id == 'doubled-wrap-content') break;
height += n[i].style.height || n[i].offsetHeight;
j++;
}
});
var more = 0;
$('#doubled-wrap-content').each(function () {
if ( more < this.children.length ) {
more = this.children.length;
}
});
if (side == false) {
height += bigger + (more * 60);
} else {
height = window.innerHeight;
}
$('#full-content-wrap').css({ minHeight: height + 'px' });
var setTo = window.innerHeight;
if (parseInt($('#full-content-wrap').css('minHeight'), 10) < window.innerHeight) {
$('#full-content-wrap').css({ height: setTo + 'px' });
//$('#full-content-wrap').css({ height: '100%' });
}
}
Hope it's all. Because those spaces here are ....ooh