33
loading...
This website collects cookies to deliver better user experience
npx create-react-app Speedometer
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
ReactDOM.render(
<React.StrictMode>
<App />
</React.StrictMode>,
document.getElementById('root')
);
function App() {
return (
<div>
Hello World
</div>
);
}
export default App;
yarn add styled-components
import styled from 'styled-components';
export const Wrapper = styled.div`
width: 100%;
max-width: 100vw;
height: 100vh;
display: flex;
justify-content: center;
align-items: center;
background: #fff;
`
import styled from 'styled-components';
export const StyledSpeedometer = styled.div`
width: 100%;
max-width: 450px;
margin-top: 3rem;
.guage_body {
width: 100%;
height: 0;
padding-bottom: 50%;
background: #000;
border-top-left-radius: 100% 200%;
border-top-right-radius: 100% 200%;
position: relative;
overflow: hidden;
}
`
import React from 'react'
import { StyledSpeedometer } from '../styles/SpeedometerStyle.style'
import { Wrapper } from '../styles/Wrapper.style'
const Speedometer = () => {
return (
<Wrapper>
<StyledSpeedometer>
<div className="guage_body"></div>
</StyledSpeedometer>
</Wrapper>
)
}
export default Speedometer
import Speedometer from "./components/Speedometer";
function App() {
return (
<Speedometer />
);
}
export default App;
<div className="guage_body_cover">
<div className="guage_indicator_slider" />
</div>
<div className="guage_indicator" />
.guage_body_fill {
position: absolute;
top: 100%;
left: 0;
width: inherit;
height: 100%;
background: #000;
transform-origin: center top;
transform: rotate(0turn);
transition: transform 0.2s ease-in-out;
}
.guage_indicator {
position: absolute;
width: 225px;
height: 225px;
top: 125%;
left: 50%;
transform: translate(-50%, -50%);
transform-origin: center top;
transform: rotate(0.3turn);
border-radius: 50%;
background: #000;
z-index: 7;
&::before {
}
}
.guage_indicator_slider {
width: 4px;
height: 22rem;
background-color: #000;
transform-origin: center;
transform: rotate(0.3turn);
margin-bottom: 1rem;
}
.guage_body_cover {
width: 97%;
height: 200%;
border-radius: 50%;
background: #fff;
position: absolute;
top: 3%;
left: 50%;
transform: translateX(-50%);
display: flex;
justify-content: center;
align-items: center;
}
<div className="text_content">
<h3>100</h3>
<p>Mbps</p>
</div>
.text_content {
position: absolute;
top: 0;
background-color: #000;
top: 80%;
left: 50%;
transform: translate(-50%, -50%);
z-index: 55;
h3 {
font-size: 2.25rem;
font-weight: 400;
color: #fff;
margin: 0;
padding: 0;
text-align: center;
}
p {
font-size: 1rem;
font-weight: 300;
color: #fff;
text-align: center;
padding: 0;
margin: 0;
}
}
// create a state to store the speed
const [speed, setSpeed] = useState(0)
// generates a random number between 0 and 35 every second
useEffect(() => {
setInterval(function(){
setSpeed(Math.floor((Math.random()*35)+1));
}, 1000);
}, [])
const turnRef = React.useRef(null)
const sliderRef = React.useRef(null)
<div className="guage_body_fill" ref={turnRef} />
<div className="guage_body_cover">
<div className="guage_indicator_slider" ref={sliderRef} />
</div>
useEffect(() => {
const turn = speed >= 37.5 ? ((12.5 + 37.5) / 100) : ((12.5 + speed) / 100)
turnRef.current.style.transform = `rotate(${turn}turn)`
sliderRef.current.style.transform = `rotate(${turn + 0.25}turn)`
}, [speed])