Scrolling scrollable div freezes moving content - css

When I vertically scroll the moving div, some of the content freezes. I'm wondering how I would fix this. It isn't consistent either, as clicking the start/stop button sometimes fixes the issue for a few seconds. Very confused.
import { useEffect, useRef, useState } from "https://cdn.skypack.dev/react"
import ReactDOM from "https://cdn.skypack.dev/react-dom"
const Graph = ({ references: { trackerRef, wholeRef } }) => {
return (
<div
ref={wholeRef}
style={{
overflow: 'scroll',
height: '400px',
backgroundColor: '#333',
cursor: 'default',
userSelect: 'none'
}}
>
<div style={{ position: 'relative' }}>
<div>
{(() => {
const items = []
for (let i = 1; i < 100; i++) {
items.push(
<div
key={i}
style={{
position: 'absolute',
left: i * 1000,
height: '100%',
display: 'flex',
}}
>
<div
style={{
width: '1px',
backgroundColor: '#888',
}}
></div>
<div style={{ color: '#ddd', marginLeft: 8, fontSize: 14 }}>
{i}s
</div>
</div>
)
}
return items
})()}
{(() => {
const items = []
for (let i = 1; i < 1000; i++) {
if ((i * 100) % 1000 === 0) continue
items.push(
<div
key={i}
style={{
position: 'absolute',
left: i * 100,
height: '100%',
display: 'flex',
}}
>
<div
style={{
width: '1px',
backgroundColor: '#555',
}}
></div>
<div style={{ color: '#aaa', marginLeft: 5, fontSize: 10 }}>
{i * 100}ms
</div>
</div>
)
}
return items
})()}
<div
ref={trackerRef}
style={{
position: 'absolute',
height: '100%',
display: 'flex',
width: '1px',
backgroundColor: 'lightgreen',
}}
></div>
</div>
<div>
<div style={{ height: '2000px', width: '20px' }}></div>
</div>
</div>
</div>
)
}
const App = () => {
const trackerRef = useRef(null)
const wholeRef = useRef(null)
const [paused, setPaused] = useState(false)
const animationFrames = useRef([]).current
const intervals = useRef([]).current
const time = useRef(0)
useEffect(() => {
// Increase time when unpaused
intervals.push(setInterval(() => !paused && (time.current += 1), 1))
}, [paused])
useEffect(() => {
const refreshTrackbar = () => {
if (trackerRef.current && wholeRef.current && !paused) {
trackerRef.current.style.left = time.current + 'px'
wholeRef.current.scrollLeft = time.current - 100
requestAnimationFrame(refreshTrackbar)
}
}
animationFrames.push(requestAnimationFrame(refreshTrackbar))
}, [paused])
return (
<>
<h1>Scrollbug</h1>
<button
onClick={() => {
if (paused) {
setPaused(false)
} else {
setPaused(true)
animationFrames.forEach(frame => cancelAnimationFrame(frame))
intervals.forEach(interval => clearInterval(interval))
}
}}
>
{paused ? 'Start' : 'Stop'}
</button>
<br />
<br />
<Graph references={{ trackerRef, wholeRef }} />
</>
)
}
ReactDOM.render(<App />, document.getElementById("root"))
Here is a codepen to test the issue yourself
https://codepen.io/springer268/pen/PomjVvw
EDIT: So I tried this codepen on my mac, and the bug does not happen, which leads me to believe this is a Chrome version/platform specific issue, and not a me issue.

I'm not really sure how to make it stop freezing, but if you added an overflow:scroll; to your #root with a bigger height than your side-way scrolling div, you could scroll over it without freezing.
Making the side-way scrolling div a specific height and overflow-y: hidden; could help as well.
Kind of a workaround, but it works.

Related

How do I set a default scroll position for a component without scrolling the entire page in React?

I have a parent page that has to be scrollable. I have a calendar view withing that page that is also scrollable. However, I don't want the calendar to render and the view to have 1am at the top by default. I would like it to be scrolled about half way down and the user can scroll up or down in the component it self. However, everything I tried to do to solve this also scrolls the parent page. I think what is happening is it is scrolling the parent page and when that can no longer scroll anymore, it scrolls the component to where I want. Are there any ways to do this without scrolling the parent component?
I tried refs but but every time I did that the parent component would scroll
This is the code that I tried
export default function WeeklyCalendar({classes, clinicals, blockedTime, fileClinicalList}) {
const calendarRef = useRef(null);
useEffect(() => {
calendarRef.current.scrollTo(0, 500);
}, []);
return (
<div>
<div
style={{
position: 'sticky',
zIndex: '10',
backgroundColor: PlatformStyles.LogoNavyBlue,
width: '100%',
top: '0px',
left: '-10%',
right: '50px',
fontWeight: 'bold'
}}
>
{days.map((day , index) => {
let width = columnWidth
if (index === 0) {
width = '5%'
}
return (
<div
style={{
position: '',
display: 'inline-block',
zIndex: 11,
color: 'white'
width,
textAlign: 'center'
}}
>
{day}
</div>
)
})}
</div>
<div
ref={calendarRef}
style={{
scrollMarginTop: '1000px',
height: '700px',
position: 'relative',
marginLeft: '40px'
}}
>
{hours.map((hour) => {
let id = hour
if (hour === 6) {
id = 'scrollId'
}
return (
<div
key={hour}
id={id}
style={{
position: 'absolute',
top: `${(hour - 0.5) * multiplier + .51}%`,
bottom: `${100 - (hour + 1) * multiplier}%`,
left: '-2%',
right: '0%',
fontSize: '11px',
textAlign: 'left',
fontWeight: 'bold',
alignItems: 'center'
}}
>
{convertTime(hour)}
</div>
)
})}
{/* Adds line in the middle of the hour */}
{hours.map((hour) =>
<div
key={hour}
style={{
position: 'absolute',
top: `${hour * multiplier}%`,
bottom: `${100 - (hour + 1) * multiplier}%`,
left: '.5%',
right: '0%',
marginLeft: '22px',
borderBottom: '1px solid lightgray',
textAlign: 'left',
fontWeight: 'bold',
alignItems: 'center'
}}
>
</div>
)}
{events.map((event, index) =>
event.day.map((day) =>
<Event
key={`event-${index}-${day}`}
event={event}
day={day}
/>
)
)}
</div>
</div>
)
}
The following should produce a component that has an initial scroll-height of half it's scroll-length (minus half of it's height).
const ChildComponent = () => {
const ref = useRef(null);
useEffect(() => {
if (ref.current){
const elHeight = ref.current.offsetHeight / 2;
ref.current.scrollTop = ref.current.scrollHeight / 2 - elHeight;
}
}, [ref.current]);
return <div ref={ref}>...</div>
}
If you do not want it to be half the scroll-height, you can set it statically too:
const ChildComponent = () => {
const ref = useRef(null);
useEffect(() => {
if (ref.current){
ref.current.scrollTop = 200; // px
}
}, [ref.current]);
return <div ref={ref}>...</div>
}
Example: https://codesandbox.io/s/distracted-keldysh-03x0v5?file=/src/App.tsx

Covering 100% of available vertical space with video?

I'm trying to create a page with a header that takes up the top 15% of the vertical page, a footer that takes up the bottom 10%, and a video in the middle that takes up the rest of the vertical space.
This is the code I'm using, but it looks completely wrong. Any ideas what my mistake is here?
import React, { useState } from "react"
import Header from "./header"
import Footer from "./footer"
import VideoFile from "../../resources/my_video.mp4"
const Index = () => {
const [nav, showNav] = useState(false)
return (
<div>
<Header>
</Header >
<video preload='auto' loop autoPlay muted height="400vh" objectFit="cover" display="block" margin="0 auto">
<source src={VideoFile} type="video/mp4" />
</video>
<Footer>
</Footer>
</div>
)
}
export default Index
Then here's my header.
import React, { useState } from "react"
import styled, { createGlobalStyle } from "styled-components"
import { Link } from "gatsby"
import logo_image from "../../static/logo_white_trans.png"
const Header = () => {
const [nav, showNav] = useState(false)
return (
<div id='header' style={{ height: '100%', backgroundColor: 'blue', display: 'grid', gridTemplateColumns: '20% 60% 20%' }}>
<div id='logo' style={{ width: '100%', backgroundColor: 'orange' }} >
<img alt='logo' src={logo_image} style={{ maxHeight: '15vh', maxWidth: '100%', width: 'auto !important' }} />
</div>
<div id='title' style={{ backgroundColor: 'lime', textAlign: 'center', color: 'white' }}>
Ellephant
</div>
<div id='menu' style={{ width: '100%', backgroundColor: 'coral' }}>
<MenuIcon nav={nav} onClick={() => showNav(!nav)}>
<div />
<div />
<div />
</MenuIcon>
<MenuLinks nav={nav}>
</MenuLinks>
</div>
</div>
)
}
export default Header
And the footer.
import React from "react"
import fb_icon_image from "../../static/fb_icon.png"
import ig_icon_image from "../../static/ig_icon.png"
import yt_icon_image from "../../static/yt_icon.png"
const Footer = () => {
return (
<div id='footer' style={{ height: '10vh', backgroundColor: 'grey', textAlign: 'center', marginTop: '0.25rem', marginBottom: '0.25rem', position: 'absolute', bottom: 0, left: 50, right: 50 }}>
<img src={fb_icon_image} style={{ height: '90%', display: 'inline-block' }} />
<img src={ig_icon_image} style={{ height: '90%', display: 'inline-block', marginLeft: '1rem', marginRight: '1rem' }} />
<img src={yt_icon_image} style={{ height: '90%', display: 'inline-block' }} />
</div>
)
}
export default Footer

Trying to enable Google AMP with Nextjs but getting parent tag of tag error

I'm trying to implement google AMP to the project but I keep getting error messages related to tags errors, I'm using Next.js for frontend and Laravel for backend
This is my code in Next.js
export const config = { amp: true }
const useStyles = makeStyles(() => ({
container: {
maxWidth: 1120,
margin: '0 auto',
padding: '0 4vw'
},
content: {
margin: '0 auto'
},
postFeatureImage: {
'&>img': {
margin: '0 0 3vw',
width: '100%',
objectFit: 'contain',
overflow: 'hidden',
height: '100%'
}
},
postFullContent: {
maxwidth: 720,
margin: '0 auto',
background: '#fff',
fontFamily: "'tahoma'",
},
contentTitle: {
margin: '0 0 0.8em'
/* font-size: 5rem; */
},
contentBody: {
display: 'flex',
flexDirection: 'column',
fontFamily: `var(--font-serif)`,
'&> .kg-card.kg-image-card': {
// width: '100%',
justifyContent: 'center',
display: 'flex',
flexDirection: 'column',
alignItems: 'center',
'&>img': {
maxWidth: '80%'
}
},
}
}))
const Blog = ({ data }) => {
if (router.isFallback) {
return <div>Loading...</div>
}
const post = data && data.posts[0]
return (
<headers>
<SEO
title={post.meta_title}
image={post.feature_image}
url={`https://automart.ph/blog/${post.slug}`}
description={post.meta_description}
/>
<div className={classes.container}>
<article className={classes.content}>
{post.feature_image ?
<figure className={classes.postFeatureImage}>
<img className={classes.featureImage} src={post.feature_image} alt={post.title} />
</figure> : null}
<section className={classes.postFullContent}>
<h1 className={classes.contentTitle}>{post.title}</h1>
{/* The main post content */}
<section
className={classes.contentBody + ' load-external-scripts'}
dangerouslySetInnerHTML={{ __html: post.html }}
/>
</section>
</article>
</div>
</headers>
)
}
export default Blog
But I'm getting these errors in the console:
How can I solve this? P.S I don't have these tags mentioned in the error in the code above.

How to position tooltip on the top of a barchart in rechart?

Problem:
I have created a bar chart with a custom tooltip. Now What I need is to position tooltip on top of the bar not within the area of the chart. Like in this picture.
This is how It looks like now.
Here I am providing how I organize my code.
import React, { Component } from "react";
import {
BarChart,
Tooltip,
Bar,
Legend,
ResponsiveContainer,
Cell
} from "recharts";
import { Card, CardTitle, CardBody } from "reactstrap";
import "./SessionDuration.css";
const colors = ["#26a0a7", "#79d69f", "#f9ec86", "#ec983d"];
const data = [
{
name: "Page A",
pv: 2400,
amt: 2400
},
{
name: "Page B",
pv: 1398,
amt: 2210
},
{
name: "Page C",
pv: 9800,
amt: 2290
},
{
name: "Page D",
pv: 3908,
amt: 2000
}
];
const getTitleOfTooltip = (label) =>{
if (label === 0) {
return "<=5 min";
}
if (label === 1) {
return "5-30 min";
}
if (label === 2) {
return "30-60 min";
}
if (label === 3) {
return ">60";
}
}
const getIntroOfPage = label => {
if (label === 0) {
return "Page A is about men's clothing";
}
if (label === 1) {
return "Page B is about women's dress";
}
if (label === 2) {
return "Page C is about women's bag";
}
if (label === 3) {
return "Page D is about household goods";
}
};
class SessionDuration extends Component {
render() {
return (
<Card className="session-duration-card">
<CardTitle className="session-duration-card-header">
Session Duration
</CardTitle>
<CardBody>
<ResponsiveContainer width="100%" height="100%" aspect={4.0 / 5.5}>
<BarChart
data={data}
margin={{
top: 3,
right: 5,
left: 5,
bottom: 13
}}
barGap={10}
>
<Tooltip
coordinate={{ x: 0, y: 150 }}
content={<CustomTooltip />}
/>
<Bar dataKey="pv" fill="#8884d8">
{data.map((entry, index) => (
<Cell key={`cell-${index + 1}`} fill={colors[index]} />
))}
</Bar>
</BarChart>
</ResponsiveContainer>
</CardBody>
</Card>
);
}
}
export default SessionDuration;
const CustomTooltip = ({ active, payload, label }) => {
if (active) {
return (
<div className="session-duration-tooltip">
<p className="session-duration-tooltip-label">{getTitleOfTooltip(label)}</p>
<p className="session-duration-tooltip-intro">
{getIntroOfPage(label)}
</p>
<p className="session-duration-tooltip-desc">
Anything you want can be displayed here.
</p>
</div>
);
}
return null;
};
Here I am providing my CSS file.
#media only screen and (min-width: 1024px) {
.session-duration-card {
margin-top: 14.5%;
margin-left: -44%;
width: 190% !important;
border-radius: none !important;
height: 86%
}
.session-duration-card-header {
font-weight: 700;
text-align: left;
padding-left: 6%
}
.session-duration-tooltip {
width: 210%;
}
.session-duration-tooltip-label {
font-weight: 700;
font-size: 11px;
}
}
#media only screen and (min-width: 308px) and (max-width: 1024px) {
.session-duration-card {
margin-top: 5%;
margin-left: 3.2%;
width: 94.5%;
border-radius: none !important;
}
.session-duration-card-header {
font-weight: 700;
text-align: center;
}
}
#media only screen and (min-width: 1666px) {
.session-duration-card {
margin-top: 11%;
margin-left: -13%;
width: 190% !important;
height: 97%;
border-radius: none !important;
}
.session-duration-card-header {
font-weight: 700;
text-align: center;
}
}
I tried a lot to find a solution for my problem but I was unable to get it done can someone help me by modifying my code to get this work done. Thank you very much.
To solve this problem, will need to get the height and width of each bar and tooltip.
Need two functions onMouseMove and onMouseOut to get the height
and width of the Bar component.
Using useState to get and keep the height and width to the state, also place extra boolean to the state, to handle when the mouse is outside of the Bar. (So, to function we add object with two paramets data and boolean ).
In the Tooltip component, set the position object for static values X, Y and using the state values, set the height and width.
Using useEffect, to find the .recharts-tooltip-wrapper class, to define the height and width of the DOM element.
Set styles for .recharts-tooltip-wrapper. (Rechart. js in .recharts-tooltip-wrapper has its own generated style, we need to keep some static style of the .recharts-tooltip-wrapper and add our).
SessionDuration.js
import React, { useState, useEffect } from 'react';
import { BarChart, Tooltip, Bar, ResponsiveContainer, Cell } from 'recharts';
import { Card, CardTitle, CardBody } from 'reactstrap';
import './SessionDuration.css';
const colors = ['#26a0a7', '#79d69f', '#f9ec86', '#ec983d'];
const data = [
{
name: 'Page A',
pv: 2400,
amt: 2400,
},
{
name: 'Page B',
pv: 1398,
amt: 2210,
},
{
name: 'Page C',
pv: 9800,
amt: 2290,
},
{
name: 'Page D',
pv: 3908,
amt: 2000,
},
];
const getTitleOfTooltip = label => {
if (label === 0) {
return '<=5 min';
}
if (label === 1) {
return '5-30 min';
}
if (label === 2) {
return '30-60 min';
}
if (label === 3) {
return '>60';
}
};
const getIntroOfPage = label => {
if (label === 0) {
return "Page A is about men's clothing";
}
if (label === 1) {
return "Page B is about women's dress";
}
if (label === 2) {
return "Page C is about women's bag";
}
if (label === 3) {
return 'Page D is about household goods';
}
};
export const SessionDuration = () => {
const [position, setPosition] = useState(null);
useEffect(() => {
const tooltip = document.querySelector('.recharts-tooltip-wrapper');
if (!tooltip) return;
// Init tooltip values
const tooltipHeight = tooltip.getBoundingClientRect().height;
const tooltipWidth = tooltip.getBoundingClientRect().width;
const spaceForLittleTriangle = 10;
// Rewrite tooltip styles
tooltip.style = `
transform: translate(${position?.data.x}px, ${position?.data.y}px);
pointer-events: none; position: absolute;
top: -${tooltipHeight + spaceForLittleTriangle}px;
left: -${tooltipWidth / 2 - position?.data.width / 2}px;
opacity: ${position?.show ? '1' : 0};
transition: all 400ms ease 0s;
`;
}, [position]);
return (
<>
<Card className="session-duration-card">
<CardTitle className="session-duration-card-header">
Session Duration
</CardTitle>
<CardBody>
<ResponsiveContainer width="100%" height="100%" aspect={4.0 / 5.5}>
<BarChart
data={data}
margin={{
top: 100, // for tooltip visibility
right: 5,
left: 5,
bottom: 13,
}}
barGap={10}
>
<Tooltip
cursor={false} // hide hover effect 'grey rectangle'
position={{
// Static position
x: position?.data.x ?? 0,
y: position?.data.y ?? 0,
}}
content={<CustomTooltip />}
/>
<Bar
dataKey="pv"
fill="#8884d8"
// Handlers
onMouseMove={data => setPosition({ data: data, show: true })}
onMouseOut={data => setPosition({ data: data, show: false })}
>
{data.map((entry, index) => (
<Cell key={`cell-${index + 1}`} fill={colors[index]} />
))}
</Bar>
</BarChart>
</ResponsiveContainer>
</CardBody>
</Card>
</>
);
};
export default SessionDuration;
const CustomTooltip = ({ active, payload, label }) => {
if (active) {
return (
<div className="session-duration-tooltip">
<p className="session-duration-tooltip-label">
{getTitleOfTooltip(label)}
</p>
<p className="session-duration-tooltip-intro">
{getIntroOfPage(label)}
</p>
<p className="session-duration-tooltip-desc">
Anything you want can be displayed here.
</p>
</div>
);
}
return null;
};
SessionDuration.css
:root {
--bg-color: hsl(270 3% 29% / 0.9);
}
.session-duration-tooltip {
max-width: 250px;
position: relative;
padding: 0.5em;
border-radius: 5px;
background-color: var(--bg-color);
color: aliceblue;
}
.session-duration-tooltip::after {
content: '';
height: 0;
width: 0;
position: absolute;
bottom: -10px;
left: 50%;
transform: translateX(-50%);
border-style: solid;
border-width: 10px 10px 0 10px;
border-color: var(--bg-color) transparent transparent transparent;
}
A lot of people asking for this feature here https://github.com/recharts/recharts/issues/222 and here https://github.com/recharts/recharts/issues/488. I came up with
Third working solution (with great help from #ЖнецЪ answer)
Unfortunately the problem with that answer is that you still have to hover the "bars" themselves, and mine are quite narrow, so I wanted it to show up regardless of if you are hovering the bar or the "cursor area", this solution allows the latter.
Basically:
Get the active tooltip index from the full barchart (changes on the cursor area and not the specific bar)
a useEffect hook grabs all the bars using the bar class ".recharts-bar-rectangle" and grabs the current active one using the toolTipIndex, get's the height, and sets that to the tooltip Y-position.
As before the tooltip is controlled by the internal x position but the y position is the height +/- some offset.
export default function BarChartCard(props) {
const [activeBarIndex, setActiveBarIndex] = useState();
const [toolTipYPosition, setToolTipYPosition] = useState({});
useEffect(() => {
const barCharts = document.querySelectorAll(".recharts-bar-rectangle");
if (!barCharts || !activeBarIndex) return;
// Init tooltip values
const barChart = barCharts[activeBarIndex];
setToolTipYPosition(barChart.getBoundingClientRect().height);
}, [activeBarIndex]);
return (
<BaseCard>
<Grid container spacing={2}>
<Grid item xs={12}>
<Typography variant="h2">{props.title}</Typography>
</Grid>
</Grid>
<ResponsiveContainer width={"100%"} height={300}>
<BarChart
barGap={0}
data={props.data}
margin={{
top: 5,
right: 30,
left: 20,
bottom: 5,
}}
onMouseMove={(e) => {
setActiveBarIndex(e.activeTooltipIndex);
}}
>
<Tooltip
content={<CustomTooltip />}
cursor={false}
position={{ y: 170 - toolTipYPosition }}
offset={-60}
allowEscapeViewBox={{ x: true, y: true }}
/>
<XAxis
style={{
fontSize: "1.125rem",
fontFamily: "Cairo",
fontWeight: 600,
}}
axisLine={false}
tickLine={false}
dataKey="date"
tickFormatter={ReformatDateShortDayName}
/>
<YAxis
allowDecimals={false}
style={{
fontSize: "1.125rem",
fontFamily: "Cairo",
fontWeight: 600,
}}
dataKey="value"
axisLine={false}
tickLine={false}
/>
<Legend
style={{
fontSize: "1.125rem",
fontFamily: "Cairo",
fontWeight: 600,
}}
iconType="circle"
iconSize={6}
align="right"
verticalAlign="top"
height={36}
formatter={(value) => (
<span
style={{
color: "#CCC",
fontSize: "1.125rem",
fontWeight: 600,
fontFamily: "Cairo",
}}
>
{value}
</span>
)}
/>
<Bar
barSize={10}
dataKey="value"
name={props.legendText}
fill="#EFC92B"
/>
</BarChart>
</ResponsiveContainer>
</BaseCard>
);
}
A hacky solution
based on some other implementation and answers out there:
const [barGraphData, setBarGraphData] = useState({})
return (
<BarChart barGap={0} data={props.data} margin={{
top: 5,
right: 30,
left: 20,
bottom: 5
}}>
<Tooltip content={<CustomTooltip />}
cursor={{ fill: 'transparent' }}
position={{ y: barGraphData.height + 40}}
offset={-60}
/>
<XAxis />
<YAxis />
<Legend />
<Bar
barSize={10}
dataKey="value"
fill="#EFC92B"
onMouseOver={(data)=> {
setBarGraphData(data)
}}
onMouseLeave={(data) => {
setBarGraphData(data)
}}
/>
</BarChart>
)
So basically:
Have a static y-value, in this case I'm doing the height of the bar + some offset (at least I think it's the height of the bar). But this one could be static as well.
Add an offset to the tooltip, I had to do this otherwise it would not be on top of the bar but right shifted 60 pixels.
Let the x coordinate be handled by recharts.
As you can see from my code, I used a custom tooltip according to the recharts documentation
const CustomTooltip = ({ active, payload, label }) => {
const classes = useStyles();
return (
<Fragment>
{active && payload?.length >= 1 &&
<Card className={classes.toolTip}>
<CardContent className={classes.toolTipContent}>
<Typography className={classes.toolTipLabel}>{label}</Typography>
<Typography className={classes.toolTipValue}>{payload[0].payload.value}</Typography>
</CardContent>
</Card>
}
</Fragment>
)
}
But this is just for formatting / style, it should work with the default one as well.
Unfortunately this only seems to work when you hover the actual "Bar" and not the full area as defined by the "cursor".
Second hacky solution, which works for the full cursor area
This led me to a second solution which unfortunately gives an warning
Warning: Cannot update a component (`BarChartCard`) while rendering a different component (`label`). To locate the bad setState() call inside `label`, follow the stack trace as described in ...
The code to create get it going is here, any comment on how to make this work would be awesome!
export default function BarChartCard(props) {
const [barGraphData, setBarGraphData] = useState({});
const [activeBarIndex, setActiveBarIndex] = useState({});
const [toolTipYPosition, setToolTipYPosition] = useState({});
return (
<BaseCard>
<Grid container spacing={2}>
<Grid item xs={12}>
<Typography variant="h2">{props.title}</Typography>
</Grid>
</Grid>
<ResponsiveContainer
width={"100%"}
height={300}
>
<BarChart
barGap={0}
data={props.data}
margin={{
top: 5,
right: 30,
left: 20,
bottom: 5,
}}
onMouseMove={(e) => {
setActiveBarIndex(e.activeTooltipIndex)
}}
>
<Tooltip
content={<CustomTooltip />}
cursor={false}
position={{ y: -toolTipYPosition + 170}}
offset={-60}
allowEscapeViewBox={{ x: true, y: true }}
/>
<XAxis
style={{
fontSize: "1.125rem",
fontFamily: "Cairo",
fontWeight: 600,
}}
axisLine={false}
tickLine={false}
dataKey="date"
tickFormatter={ReformatDateShortDayName}
/>
<YAxis
allowDecimals={false}
style={{
fontSize: "1.125rem",
fontFamily: "Cairo",
fontWeight: 600,
}}
dataKey="value"
axisLine={false}
tickLine={false}
/>
<Legend
style={{
fontSize: "1.125rem",
fontFamily: "Cairo",
fontWeight: 600,
}}
iconType="circle"
iconSize={6}
align="right"
verticalAlign="top"
height={36}
formatter={(value) => (
<span
style={{
color: "#CCC",
fontSize: "1.125rem",
fontWeight: 600,
fontFamily: "Cairo",
}}
>
{value}
</span>
)}
/>
<Bar
label={(e) => {
if(e.index === activeBarIndex){
setToolTipYPosition(e.height)
}
return null;
}}
barSize={10}
dataKey="value"
name={props.legendText}
fill="#EFC92B"
onMouseOver={(data) => {
setBarGraphData(data);
}}
onMouseLeave={(data) => {
setBarGraphData(data);
}}
/>
</BarChart>
</ResponsiveContainer>
</BaseCard>
);
}

How to align the two buttons to the center of a div of 'position:absolute' using flexbox? [duplicate]

This question already has answers here:
How can I vertically center a div element for all browsers using CSS?
(48 answers)
Flexbox: center horizontally and vertically
(14 answers)
How to center a "position: absolute" element
(31 answers)
How can I horizontally center an element?
(133 answers)
How can I center an absolutely positioned element in a div?
(37 answers)
Closed 4 years ago.
This is the outcome of my code so far:
What I actually want to achieve is to move the two button to the center horizontally. But at the moment they are aligned to the left.
This is the result I want to achieve:
I have tried alignItems but it has no effect. I don't want to use any margin because the container size may vary.
Here is my code:
const H = "540px";
const W = "720px";
const ContentView = ({ width, height }) => (
<div style={{ width, height, border: "1 solid red" }}>Hello! Alt View!</div>
);
const ControlView = ({ width, height, onReveal, onCopy }) => {
const container = {
width,
height,
position: "relative"
};
const controlsContainer = {
width,
height,
position: "absolute",
left: 0,
top: 0,
border: "5px solid green",
display: "flex"
};
return (
<div style={container}>
<img style={{ width, height }} src="https://i.imgur.com/MQcuk3n.jpg" />
<div style={controlsContainer}>
<div
style={{
display: "flex",
flexDirection: "column",
alignItems: "center",
justifyContent: "center"
}}
>
<div>
<button
style={{
width: "400px",
height: "60px",
minWidth: "200px",
display: "block"
}}
onClick={onReveal}
>
Reveal
</button>
</div>
<div>
<button
style={{ width: "400px", height: "60px", minWidth: "200px" }}
onClick={onCopy}
>
Copy Meta
</button>
</div>
</div>
</div>
</div>
);
};
class App extends React.Component {
constructor(props) {
super(props);
this.state = { playing: false };
}
_onReveal() {
this.setState({ playing: true });
}
_onCopy() {
window.alert("Meta data copied");
}
renderAltView() {
return <AltView />;
}
render() {
const { width, height } = this.props;
if (!this.state.playing) {
return (
<div>
<h2>Controls</h2>
<ControlView
width={width}
height={height}
onReveal={() => this._onReveal()}
onCopy={() => this._onCopy()}
/>
</div>
);
}
return (
<div>
<ContentView />
</div>
);
}
}
ReactDOM.render(<App width={W} height={H} />, document.getElementById("app"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="app"></div>
Unfortunately I cannot get it to work in SO code snippet. A working version is here at codepen https://codepen.io/kongakong/pen/EpRKPx
What flex directive I can use to position the buttons as I want?
You also need to center all the child elements in the parent div. So in your case you need to set the flexbox properties to the controlsContainer.
const controlsContainer = {
width,
height,
position: 'absolute',
left: 0,
top: 0,
border: '5px solid green',
display: 'flex',
flexDirection: 'column',
alignItems: 'center',
justifyContent: 'center'
};
Working example:
const H="540px";
const W="720px";
const ContentView = ({width, height}) => (
<div style={{width, height, border: '1 solid red'}}>Hello! Alt View!</div>
)
const ControlView = ({width, height, onReveal, onCopy}) => {
const container = {
width,
height,
position: 'relative',
};
const controlsContainer = {
width,
height,
position: 'absolute',
left: 0,
top: 0,
border: '5px solid green',
display: 'flex',
flexDirection: 'column',
alignItems: 'center',
justifyContent: 'center'
};
return (
<div style={container} >
<img style={{width, height}} src="https://i.imgur.com/MQcuk3n.jpg" ></img>
<div style={controlsContainer}>
<div style={{display: 'flex', flexDirection: 'column', alignItems: 'center', justifyContent: 'center'}}>
<div>
<button style={{ width: '400px', height: '60px', minWidth: '200px', display:'block'}}
onClick={onReveal}>Reveal</button>
</div>
<div >
<button style={{width: '400px', height: '60px', minWidth: '200px'}}
onClick={onCopy}>Copy Meta</button>
</div>
</div>
</div>
</div>
)
}
class App extends React.Component{
constructor(props){
super(props);
this.state = {playing: false};
}
_onReveal() {
this.setState({playing: true})
}
_onCopy() {
window.alert('Meta data copied')
}
renderAltView() {
return (
<AltView />
)
}
render(){
const { width, height } = this.props;
if (!this.state.playing){
return (
<div>
<h2>Controls</h2>
<ControlView width={width} height={height}
onReveal={() => this._onReveal()}
onCopy={() => this._onCopy()}
/>
</div>);
}
return (<div><ContentView /></div>);
}
}
ReactDOM.render(<App width={W} height={H}/>, document.getElementById('app'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="app"></div>
Add justify-content: center; to the absolute positioned DIV (controlsContainer)

Resources