Resize grid items on scroll react - javascript

I need to do animation where my grid items will shrink and expand on scroll like this https://k72.ca/en/work, I have no progress for now can anyone give me a hint or help me to find package for it or tell me how should it be done?
my list looks like this:
{projects?.map((projectData) => {
const project = tData(projectData)
const slug = toKebabCase(
`${projectData.en?.client}-${projectData.en?.project}`
)
return (
<div
key={projectData.id}
className="projects-grid-item"
style={{
backgroundImage: `url(${project?.mainImage})`,
}}
>
<div className="project-content-wrapper">
<div className="nox-h-4">
<Link href={`${PROJECTS_ROUTE}/${slug}`}>
<a>
{project?.client} - {project?.project}
</a>
</Link>
</div>
<div className="additional-info-wrapper nox-body-1">
<div className="services">
{project?.services}
</div>
<div>{project?.year}</div>
</div>
</div>
</div>
)}

A good first step would be looking into the Intersection Observer API. It provides a way to track elements captured in the current viewport.
A second step might be to use an observer instance to change classes of elements in order to trigger the transitions that you're looking to implement.

Related

Card flip with Onclick with cards randered from Json Data

I have a json list which i used to populate a list of react cards which has two sides. I want to flip to the info side when a button is clicked but I can only get it to flip all the cards. i can achieve it with hover within the css then only card hovered over flips.
Below is my card code
<MDBRow class="row">
<ul className="ulWidth">
<li className="liWidth"> {this.state.infos.map(post => {
return (
<div key={post.id} id="menu">
<MDBCol lg="4" className=" mb-3 column flip-card" id="myEltId">
<MDBCard className="card colCardinfoHeightImg flip-card-inner">
<img className="img-fluid infoImage" src={require('../../images/infoImage.png')} />
<MDBCardBody>
<MDBCardTitle className="CardTitle text-uppercase text-bold">{post.infoName}</MDBCardTitle>
<MDBCardText>
<strong>Data Example 1:</strong> {post.jsonData1}<br/>
<strong>Data Example 2:</strong> {post.jsonData2}<br/>
<strong>Data Example 3:</strong> {post.jsonData3}<br/>
</MDBCardText>
</MDBCardBody>
<div class="flip-card-back">
<MDBCard className=" colCardinfoHeight">
<MDBCardBody>
<MDBCardTitle>{post.infoName}</MDBCardTitle>
<MDBCardText>
<p><strong>Data Example 3:</strong>{post.jsonData4}<br/>
<strong>Data Example 3:</strong> {post.jsonData5}
</p>
<hr/>
<p><strong>Data Example 3:</strong> {post.jsonData6}<br/>
</MDBCardText>
<MDBBtn className="infoButton" color="orange" size="lg" onClick={this.clickFlipFunction}>Switch Today</MDBBtn>
</MDBCardBody>
</MDBCard>
</div>
</MDBCard>
</MDBCol>
</div>
);
})}
</li>
</ul>
</MDBRow>
this is the flip function i have attempted at the minute but it flips all the cards that are rendered.
onFlipCard(){
$(document).ready(function(){
$(".flip-card").css("transform", " rotateY(180deg)");
$(".flip-card-inner").css("transform", " rotateY(180deg)");
});
}
it works when i input the above css in the css file with the hover tag used and when the user hovers over it flips only the right card but i need it to be a clickable function.
Create an onClick event handler for the card.
Track whether the card is flipped or not within the component using something like an isCardFlipped state variable.
Whenever onClick is called, toggle the isCardFlipped state value.
Assign dynamic classnames using classnames , to show either flip-card or flip-card-inner based on the value in isCardFlipped
Edit : I would advice against the use of jquery, or to perform direct DOM manipulation. The major benefit of using React, which you might have missed out on, is to be able to update the DOM indirectly via React's internal working : in a gist, this allows only those DOM elements to be updated which have changed versus redrawing the entire DOM altogether. Read more on this here
Right now your event handler is getting all elements with the class "flip-card". That's what this part is doing:
$(".flip-card")
What you'll need instead is to use a reference to the specific element that was clicked, something like:
$(".flip-card").click(function(e){
$(e.target).css("transform", " rotateY(180deg)");
});
Event.target reference

moving "pieces" around the board with React

I am working on a "simple" board game using create-react-app. I have a board component built from tiles. I want to move a pawn around the board in correlation to each player's position (position is saved and updated in each player's state object). Each of the tiles has a unique id. Essentially I want to make some kind of comparison check between the userPosition and the tile id, and render the user's pawn on the matching tile.
I had thought of 2 ways to do this, both cumbersome, and neither quite working:
Have a pawn for each user set inside each tile, and use CSS to toggle if they are visible or not.
Run a switch checking the userPosition, and updating the CSS position property accordingly.
The problem with both those methods is that I need to be able to target DOM elements: in the 1st option I need to be able to check the id of each tile. In the 2nd option I need to be able to target the element in order to change it's CSS position. using "regular" DOM methods like:
let myElement = document.getElementById("p1");
doesn't work.
I've been reading that maybe I need to be using a ref method, however I am using functional react with hooks, so I don't have a class to extend this to?
Also, I am totally open to other ideas as to how to visually move a pawn around the board, those are just 2 ideas I came up with.
some code:
the grid:
function Board () {
return (
<div className="boardContainer">
<div className="row">
<div className="col tile" id="1">
*
</div>
<div className="col tile" id="2" >
*
</div>
<div className="col tile" id="3">
*
</div>
<div className="col tile" id="4">
*
</div>
<div className="col tile" id="5">
*
</div>
</div>
the pawns:
<span className="dot1" id="p1"></span>
<span className="dot2"></span>
<span className="dot3"></span>
<span className="dot4"></span>
There are a lot of ways to do this without direct DOM manipulation.
You could have a <Tile> component that accepts a boolean value if a player is there and renders differently if one is:
function Tile({hasPlayer}) {
return <div className="col tile">
{hasPlayer ? <span className="dot1" /> : '*'}
</div>
}
Now you could create a row like:
<div className="row">
{[1,2,3,4,5].map(tileId => (
<Tile hasPlayer={tileId === playerPosition} />
)}
</div>
Or you could set the inline styles of the pawn to position the pawn absolutely.
CSS:
.pawn {
position: absolute;
transition: left 0.5s, top 0.5s; // smoothly move the pawn
}
If you knew the tiles were a certain size, say 50 pixels, you could then:
<span
className="pawn"
style={{
left: playerPosition.x * 50,
top: playerPosition.y * 50,
}}
/>
In general, think about your game as pure data. You just have state that allows you to know about what happening in the game. Then you simply render that state.
Don't think of moving things on the web page. Simply update the data that records the game state, and then just render it.

Vuetify on mouseover toggle data object within array list

I am trying to implement a functionality which will toggle a Vuetify badge element for each array object within the list when the containing div has been hovered over.
I am able to create a hover like functionality within v-for array list using css, which is fairly simple but how can I achieve similar outcome using vuetify components? As I have not found any questions discussing this or demonstrating it, assume it is possible. Have looked into
First Link
Second Link
Second Link
And much more but have not found similar enough example of what I desire.
I have added codepen example of what I currently have.
The badge should only appear on the element which is currently being hovered, however all badge elements are being executed when any element has been hovered on.
CodePen Link
Maybe I have missed out something obvious
HTML Part
<template>
<div id="app">
<div>My favourite fruit is <b>{{favouriteFruit}}</b></div> <br>
<div v-for="(dataArray, index) in testArray" #click="setCurrent(dataArray.name)">
<v-badge
:color="computedFavFruitColor[index]"
right
v-model="show"
>
<template v-slot:badge>
<span><v-icon color="#ECF0FF">{{computedFavFruit[index]}}</v-icon></span>
</template>
<div #mouseover="show = true" #mouseleave="show = false">
{{dataArray.name}}
</div>
</v-badge>
</div>
</div>
</template>
Any further help of suggestions regarding this manner would be appreciated.
While the show property is global, it counts for every item you hover. You want to target the element you hover. So I suggest to keep track of the index of the item you hover like this: https://codepen.io/reijnemans/pen/JjPrayp?editors=1010
<div v-for="(dataArray, index) in testArray" #click="setCurrent(dataArray.name)">
<v-badge
:color="computedFavFruitColor[index]"
right
>
<template v-slot:badge>
<span v-if="show == index"><v-icon color="#ECF0FF">{{computedFavFruit[index]}}</v-icon></span>
</template>
<div #mouseenter="show = index" #mouseleave="show = null">
{{dataArray.name}}
</div>
</v-badge>
</div>
And show = null ipv show = true in data block of vue

onclick on img that would link to a particular section on another page

so currently I'm trying to link a particular section of another component page to an img when the image is clicked. Right now i'm doing this in the below component which takes me to the questions/1234 page but not to the exact section of questions/1234
handleClick(event) {
this.props.history.push('/questions/1234')
}
render() {
<img src={"/public/123"} onClick= {event =>
this.handleImageClick(event)} className="thumbnail"/>
/>
}
The component I'm linking the image to when clicked is
render() {
<div id="one">
1
</div>
<div id="two">
2
</div>
<div id="three">
3
</div>
}
And i would like to make it so that when I click on the image in the first component, this would lead me to the div "two" of the other component. How can I do this? Please Remember this is React
If I understand your question correctly then this should be possible by specifying a hash in the path of the page being navigated to.
If the hash value matches an element id in the page being navigated to, then the browser should automatically scroll to that element to ensure it's visible:
handleClick(event) {
/*
Adding #two causes browser to ensure that <div id="two"> is visible
after navigation
*/
this.props.history.push('/questions/1234#two');
}
Your sample code looks like reactjs, hence this answer.
What I have had to do in the past is use a library called react-scrollable-anchor. Check it out here
So in your case it'll probably look like so:
import ScrollableAnchor from 'react-scrollable-anchor';
// your other stuffs...
render() {
return <ScrollableAnchor id="one">
<div>
1
</div>
</ScrollableAnchor>
<ScrollableAnchor id="two">
<div>
2
</div>
</ScrollableAnchor>
<ScrollableAnchor id="three">
<div>
3
</div>
</ScrollableAnchor>
}
Note: Your render methods look weird without a return.
In the off chance that you're using Angular, which I know very little about, you may check out this library https://www.npmjs.com/package/ng2-page-scroll
Also, for something as simple as this you'll expect not to use another library on top of the routing library you already have, guess it's not that simple. Check these github thread out for:
react (using react-router) => https://github.com/ReactTraining/react-router/issues/394#issuecomment-220221604
angular => https://github.com/angular/angular/issues/14245
Additionally, your use of onClick event on the img tag feels a bit forced (js overuse) to me. Is there reason you're not doing as #John Rudell suggested in his/her/their comment? i.e wrapping your image in an anchor like so:
handleClick(event) {
// Not today we're just going to use an anchor for this
// this.props.history.push('/questions/1234')
}
render() {
<a href="/questions/1234#two >
<img src={"/public/123"} className="thumbnail" />
</a>
}
Note: technically, there's talk that the above is not a valid html as per dom nesting rules. Nesting an inline-block inside of an inline element. There are solutions to this. I just didn't want to distract from the simple idea of using the right tools.
In case OP or anyone else is wondering, a solution might be:
render() {
<div style={{ position: "relative" }} >
<img src={"/public/123"} className="thumbnail" />
<a
href="/questions/1234#two
style={{
position: "absolute",
top: 0,
bottom: 0,
width: "100%"
/>
</div>
}
Hope it helps.

React on screen doesn't work when I use it with React full-screen component

When I scroll down within the full page react's slides, though the page on the viewport of the screen the background color of the div does not change, I use react-on-screen npm package withing the full page react component but when I use the react-on-screen without full page react component it works great, I think when I scrolldown within the full-page-react slides the viewport don't think the new slides are new pages so the div background color doesn't change. Plus I tried to resize the window when the div in the last page is on the screen then the background is changed. Can you help me about this problem?
render() {
const { height } = this.state;
return (
<Layout>
<ReactFullpage
refresh
keyboardScrolling
lazyLoading
scrollOverflowReset={false}
slidesNavigation={deger}
onLeave={this.onLeave}
render={({ state, fullpageApi }) => {
return (
<ReactFullpage.Wrapper>
<React.Fragment>
<div className="section">
<p>Section 1</p>
</div>
<div className="section">
<div className="Index_LogoWrapper" style={{ height }}>
<LogoImage />
<div className="Index_ContactUsWrapper">
<div className="Index_ContactUs">
For more information contact us at
info#mail.io
</div>
</div>
</div>
</div>
<div className="section">
<TrackVisibility>
<ComponentToTrack />
</TrackVisibility>
</div>
</React.Fragment>
</ReactFullpage.Wrapper>
);
}}
/>
</Layout>
);
}
If the component you use to change the color relies on the scrolling position then you'll have to use the option scrollBar of fullPage.js in your react-fullpage component.
Otherwise I would encourage you to use the fullpage.js callbacks such as afterLoad or onLeave or even use the fullpage.js state classes that get added to the body element.
See one of my video tutorials about how to perform CSS 3 animations with fullpage.js state classes:
https://www.youtube.com/watch?v=qiCVPpI9l3M

Categories