React: Set background image with props from another component - javascript

I hope I'm asking this question correctly (I'm still green with React).
I am writing a component that will set the background image (from a folder of jpgs) from props of another component. So let's say the component is "projects" then the background image would be set as "project.jpg" (and component "About" would have a background image of "about.jpg")
I've tried writing this and seems like I get close but not all the way there. Any React.js Gurus that could help me crack this code would have me singing praises of your screen name
My code
import React from 'react';
import styled from 'styled-components';
const pathToBgImages = require.context('../../../src/static', true);
const bgImages = [
'about.jpg',
'blog.jpg',
'contact.jpg',
'projects.jpg'
]
const getImages = () => bgImages.map(name => `<img src='${pathToBgImages(name, true)}'/>`);
const BgBackground = styled.div`
width: 100%;
&::after {
content: "";
background: url(${getImages});
background-size: cover;
opacity: 0.25;
height: 400px;
top: 0;
left: 0;
bottom: 0;
right: 0;
position: absolute;
z-index: -1;
}
`
class BgImage extends React.Component {
render() {
return (
<BgBackground />
);
}
}
export default BgImage;
I know there are some blanks in that component and not written correctly, I'm still trying to figure this out. Thank you in advance!

Related

Using Radix UI props does not work in React JS application

In my react Js application i am using Radix. I need to customizze toast component changing the position where the component should appear.
For this, the API provides the next way:
<ToastProvider swipeDirection="up">
So swipeDirection is responsible for this.
ISSUE: Using the above changes, the component stil appear at the bottom even with changed prop.
Question: How to make the component to appear at the top and why the prop does not work? demo: https://codesandbox.io/s/z688kv?module=App.js&file=/App.js:3909-3944
Sadly there is no "position" prop out of the box for this component. The swipeDirection="up" prop only specify that you can delete a toast by swiping it to the top. You can still specify where to place the toasts with pure css. Just update the styles of the ToastViewport component.
Default styles are:
position: fixed;
bottom: 0px;
right: 0px;
So to have the toasts in the top right corner for example just use:
<ToastViewport style={{ top: "0px" }} />
Adding on #johannchopin answer, if you want to position the toast to the left-bottom for example.
First, some changes to the slideIn animation:
const slideIn = keyframes({
from: { transform: `translateX(calc(-100% + ${VIEWPORT_PADDING}px))` },
to: { transform: "translateX(0)" }
});
const swipeOut = keyframes({
from: { transform: "translateX(var(--radix-toast-swipe-move-y))" },
to: { transform: `translateX(calc(-100% + ${VIEWPORT_PADDING}px))` }
});
notice the use of -100% instead of 100%
and a small change to the StyledViewport default position:
const StyledViewport = styled(ToastPrimitive.Viewport, {
position: "fixed",
bottom: 0,
left: 0,
//other styles removed to keep the code short
});

How to remove some portion of an image

I am trying to build a component, where it takes images and the first image will be shown while remaining images will be shown in a half circle.
Here I am trying to clip the image portion from second image by adding a class which is not working. I need to get the images as shown in the attached image below.
Images.js
const Images = ({ images = [] }) => {
return (
<div>
{images?.map((image, index) => {
const isFirst = index === 0;
return (
<img
src={image.url}
alt={image.title}
key={image.title}
className={isFirst ? "" : "semi-circle"}
/>
);
})}
</div>
);
};
export default Images;
style.css
img {
border-radius: 50%;
width: 100px;
height: 100px;
}
.semi-circle {
clip: rect(0px, 25px, 25px, 0px);
}
What am I doing wrong here.
Sandbox
See the image that illustrates what I'm trying to achieve:
this
You can use clip-path: path() to create custom shapes. This is now supported in modern browsers.
.semi-circle {
clip-path: path('m27.215 9.6962c70.511-13.195 81.235 89.479 4.948 82.882 16.494-5.773 43.709-54.43-4.948-82.882z');
}
Updated Sandbox
Clip-path Caniuse.com

Why does website cause most elements to be recalculated upon small change after being hosted?

I decided to make a Pac-Man game and after I did it and everything was working somewhat fine on local document I pushed my website on Github pages and decrease in fps was enormous. It turned out page was making recalculation for hundreds elements which caused 20ms+ delay.
Here's a small part of the code that still has performance difference between local and github-pages hosted website.
const gameBoard = document.getElementById("game-board");
const root = document.documentElement.style;
let elements;
let characterNode;
let position = 658;
makeLevel();
function makeLevel() {
for (let i = 0; i < 868; i++) {
const element = document.createElement("DIV");
element.style.backgroundPosition = `0 0`;
let character = document.createElement("DIV");
character.className = "yellow";
element.append(character);
gameBoard.append(element);
}
elements = Array.from(gameBoard.children);
characterNode = elements[658].children[0];
changePosition();
}
function changePosition() {
root.setProperty(`--yellow-sprite-y`, `-32px`);
characterNode.style.transform = `translateX(-20px)`;
setTimeout(() => {
characterNode.style.transform = "";
characterNode.classList.remove(`yellow-visible`);
position = position - 1;
characterNode = elements[position].children[0];
characterNode.classList.add(`yellow-visible`);
changePosition()
}, 200)
}
:root {
--yellow-sprite-y: -32px;
}
#game-board {
width: 560px;
height: 620px;
display: grid;
grid-template-columns: repeat(28, 20px);
background-color: #000000;
}
#game-board > * {
position: relative;
width: 20px;
height: 20px;
}
.yellow {
position: absolute;
top: -4px;
left: -5.5px;
width: 30px;
height: 28px;
z-index: 10;
}
.yellow-visible {
background-image: url("https://i.imgur.com/SphNpH6.png");
background-position: -32px var(--yellow-sprite-y);
transition: transform 200ms linear;
}
<div id="game-board">
</div>
The exact problem in this code is line 29 which on local document performs like this:
while after hosting it on Github performs this way:
Why is it working this way and what can I do to lessen the performance decrease on hosted page?
Amazingly everything works well and bug doesn't exist on CodePen, yet on Github it still persists.
After getting some feedback that my site works well for other users I shared it on CodePen and it also worked fine, day later somebody said there could be an extension that could do something like that and indeed Adblocker Ultimate caused the slow performance.

Changing background-image property causes a flicker in Firefox

I'm working on a component that rotates a series of background images in a banner on my page. The problem I'm running into is that when the background-image properties url is changed via state it seems to cause a flash of white. This flashing doesn't seem to happen all the time in Chrome, but does happen consistently in Firefox and sometimes Safari. For additional context I'm using Mac OSX.
At first I assumed this was because the images are being retrieved by the browser when they are requested, but to avoid this I've made some considerations for pre-fetching by rendering a hidden image tag with the resource.
{this.props.items.map(item => (
<img src={item} style={{ display: "none" }} />
))}
I've also tried creating a new image in the rotate method that pre-fetches the next rotation item ahead of the transition, but neither seem to work.
const img = new Image();
img.src = this.props.items[index + 1];
Where am I going wrong here? I've attached an example of the component below. Any help would be appreciated.
class Cats extends React.Component {
constructor(props) {
super(props);
this.state = {
background: props.items[0],
index: 0
};
this.rotate = this.rotate.bind(this);
}
// Let's you see when the component has updated.
componentDidMount() {
this.interval = setInterval(() => this.rotate(), 5000);
}
componentDidUnmount() {
clearInterval(this.interval);
}
rotate() {
const maximum = this.props.items.length - 1;
const index = this.state.index === maximum ? 0 : this.state.index + 1;
this.setState({
background: this.props.items[index],
index
});
}
render() {
return (
<div
className="background"
style={{ backgroundImage: `url(${this.state.background})` }}
>
{this.props.items.map(item => (
<img src={item} style={{ display: "none" }} />
))}
</div>
);
}
}
ReactDOM.render(
<Cats
items={[
"https://preview.redd.it/8lt2w3du0zb31.jpg?width=640&crop=smart&auto=webp&s=58d0eb6771296b3016d85ee1828d1c26833fd022",
"https://preview.redd.it/120qmpjmg1c31.jpg?width=640&crop=smart&auto=webp&s=1b01fc0c3f20098e6bb1f4126c3c2a54b7bc2b8e",
"https://preview.redd.it/guprqpenoxb31.jpg?width=640&crop=smart&auto=webp&s=ace24e96764bb40a01e7d167a88d35298db76a1c",
"https://preview.redd.it/mlzq0x1o0xb31.jpg?width=640&crop=smart&auto=webp&s=b3fd159069f45b6c354de975daffde21f04c3ad5"
]}
/>,
document.querySelector(".wrapper")
);
html, body, .wrapper {
width: 100%;
height: 100%;
}
.background {
position: static;
background-size: cover;
height: 100%;
width: 100%;
transition: background-image 1s ease-in-out;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.6.1/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/15.6.1/react-dom.min.js"></script>
<div class="wrapper"></div>
Unfortunately, it seems like this flicker is a known bug in Firefox caused by its image decoder, which won't decode an image until it's displayed for the first time. In the snippet below, I created overlapping divs, one which loads the next image slightly earlier and sits behind the other. This way when the other "flickers," the proper image is already displayed behind, rather than a white background.
You could also theoretically display all the images in the hidden div really quickly, then set it back to white, since the images only need to be displayed once for the decoder to work.
Depending on the long-term goal for this project, the most proper way around this problem may be to use a <canvas> to render your images. The canvas element uses a different decoder which won't cause a flicker.
class Cats extends React.Component {
constructor(props) {
super(props);
this.props.items.forEach((item) => {
const img = new Image(640, 640);
img.src = item;
});
this.state = {
background: props.items[0],
preloadBackground: props.items[1],
index: 0
};
this.rotate = this.rotate.bind(this);
}
// Let's you see when the component has updated.
componentDidMount() {
this.interval = setInterval(() => this.rotate(), 5000);
}
componentDidUnmount() {
clearInterval(this.interval);
}
rotate() {
const maximum = this.props.items.length - 1;
const index = this.state.index === maximum ? 0 : this.state.index + 1;
this.setState({
preloadBackground: this.props.items[index],
index
});
setTimeout(() => {
this.setState({
background: this.props.items[index],
});
}, 100);
}
render() {
return (
<div className="pane">
<div
className="preload-background"
style={{ backgroundImage: `url(${this.state.preloadBackground})` }}
>
</div>
<div
className="background"
style={{ backgroundImage: `url(${this.state.background})` }}
>
</div>
</div>
);
}
}
ReactDOM.render(
<Cats
items={[
"https://preview.redd.it/8lt2w3du0zb31.jpg?width=640&crop=smart&auto=webp&s=58d0eb6771296b3016d85ee1828d1c26833fd022",
"https://preview.redd.it/120qmpjmg1c31.jpg?width=640&crop=smart&auto=webp&s=1b01fc0c3f20098e6bb1f4126c3c2a54b7bc2b8e",
"https://preview.redd.it/guprqpenoxb31.jpg?width=640&crop=smart&auto=webp&s=ace24e96764bb40a01e7d167a88d35298db76a1c",
"https://preview.redd.it/mlzq0x1o0xb31.jpg?width=640&crop=smart&auto=webp&s=b3fd159069f45b6c354de975daffde21f04c3ad5"
]}
/>,
document.querySelector(".wrapper")
);
html, body, .wrapper, .pane {
width: 100%;
height: 100%;
}
.background {
position: static;
background-size: cover;
height: 100%;
width: 100%;
transition: background-image 1s ease-in-out;
}
.preload-background {
position: absolute;
background-size: cover;
height: 100%;
width: 100%;
z-index: -1;
transition: background-image 1s ease-in-out;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.6.1/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/15.6.1/react-dom.min.js"></script>
<div class="wrapper"></div>
You can use decode() method that will let you know when image is decoded and ready to be used.
https://developer.mozilla.org/en-US/docs/Web/API/HTMLImageElement/decode
In your case:
const img = new Image();
img.src = this.props.items[index + 1];
img.decode()
.then(() => {
// image is decoded and ready to use
})
.catch((encodingError) => {
// do something with the error.
})

how to animate image in react when image change after some interval?

I am trying to make a image slider in react in which a image is change after 5000 second.
I checked from here http://mumbaimirror.indiatimes.com/ .where this website implement that functionality .
I tried to implement same this in react .I am able to make that , but my image is not slide(from right to left) in other words image not showing animation when second image show n view
here is my code
https://codesandbox.io/s/YrO0LvAA
constructor(){
super();
this.pre=this.pre.bind(this);
this.next=this.next.bind(this);
this.state ={
currentSlide :0
}
setInterval(()=>{
var current = this.state.currentSlide;
var next = current + 1;
if (next > this.props.stories.items.length - 1) {
next = 0;
}
this.setState({ currentSlide: next });
}, 5000);
}
One way to do this is to always have the future image (next image) be ready on the right side so you can transition it to the left, at the same time you transition the current one to the left. So they both move together.
In React this would mean that you would need to store the Index of both the current image and your next image, and each X seconds you need to move them both to the left (or the right depending on your action)
Here's a proof of concept:
https://codepen.io/nashio/pen/xLKepZ
const pics = [
'https://cdn.pixabay.com/photo/2017/06/19/07/12/water-lily-2418339__480.jpg',
'https://cdn.pixabay.com/photo/2017/07/18/18/24/dove-2516641__480.jpg',
'https://cdn.pixabay.com/photo/2017/07/14/17/44/frog-2504507__480.jpg',
'https://cdn.pixabay.com/photo/2016/09/04/13/08/bread-1643951__480.jpg',
];
class App extends React.Component {
constructor(props) {
super(props);
const idxStart = 0;
this.state = {
index: idxStart,
next: this.getNextIndex(idxStart),
move: false,
};
}
getNextIndex(idx) {
if (idx >= pics.length - 1) {
return 0;
}
return idx + 1;
}
setIndexes(idx) {
this.setState({
index: idx,
next: this.getNextIndex(idx)
});
}
componentDidMount() {
setInterval(() => {
// on
this.setState({
move: true
});
// off
setTimeout(() => {
this.setState({
move: false
});
this.setIndexes(this.getNextIndex(this.state.index));
}, 500); // same delay as in the css transition here
}, 2000); // next slide delay
}
render() {
const move = this.state.move ? 'move' : '';
if (this.state.move) {
}
return (
<div className="mask">
<div className="pic-wrapper">
<div className={`current pic ${move}`}>
{this.state.index}
<img src={pics[this.state.index]} alt="" />
</div>
<div className={`next pic ${move}`}>
{this.state.next}
<img src={pics[this.state.next]} alt="" />
</div>
</div>
</div>
);
}
}
React.render(<App />, document.getElementById('root'));
// CSS
.pic {
display: inline-block;
width: 100px;
height: 100px;
position: absolute;
img {
width: 100px;
height: 100px;
}
}
.current {
left: 100px;
}
.current.move {
left: 0;
transition: all .5s ease;
}
.next {
left: 200px;
}
.next.move {
left: 100px;
transition: all .5s ease;
}
.pic-wrapper {
background: lightgray;
left: -100px;
position: absolute;
}
.mask {
left: 50px;
overflow: hidden;
width: 100px;
height: 120px;
position: absolute;
}
EDIT: Updated the POC a bit to handle left and right navigation, see full thing HERE
This is by no means an elegant solution, but it does slide the image in from the left when it first appears: https://codesandbox.io/s/xWyEN9Yz
I think that the issue you're having is because you are only rendering the current story, but much of your code seemed to assume that there would be a rolling carousel of stories which you could animate along, like a reel.
With the rolling carousel approach it would be as simple as animating the left CSS property, and adjusting this based on the currently visible story. I.e. maintain some state in your component which is the current index, and then set the 'left' style property of your stories container to a multiple of that index. E.g:
const getLeftForIndex = index => ((index*325) + 'px');
<div className="ImageSlider" style={{ left: getLeftForIndex(currentStory) }}>
<Stories />
</div>

Categories