A Pen by Tamio Honma on CodePen.
Last active
March 31, 2020 00:45
-
-
Save IOIO72/d283030bf0614014eba88be59cc7acff to your computer and use it in GitHub Desktop.
Clock [WIP]
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<div id="root"></div> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
const {useState, useCallback, useEffect, useRef } = React; | |
const DebugClock = props => ( | |
<table className="debug-clock"> | |
{Object.entries(props).map(item => ( | |
<tr key={item[0]} className="debug-clock__property"> | |
<td className="debug-clock__key">{item[0]}</td> | |
<td className="debug-clock__value">{item[1]}</td> | |
</tr> | |
))} | |
</table> | |
); | |
const Hand = ({type = 'hours', degrees}) => ( | |
<div className={`hand hand--${type}`} style={{ | |
transform: `rotateZ(${degrees}deg)` | |
}} /> | |
); | |
const AnalogClock = ({hrs,mr,mrs,srs,sr,smoothMinutes=false,smoothSeconds=false}) => { | |
return ( | |
<div className="analog-clock"> | |
<div className="analog-clock__face"> | |
<Hand type="hours" degrees={hrs} /> | |
<Hand type="minutes" degrees={smoothMinutes ? mrs : mr} /> | |
<Hand type="seconds" degrees={smoothSeconds ? srs : sr} /> | |
</div> | |
</div> | |
); | |
} | |
const DigitalClock = ({h0,h024,m0,s0,ampm,mode24=false,blink=false,lcd=false}) => ( | |
<time className={`digital-clock digital-clock--${lcd ? 'lcd' : 'text' }`}> | |
<span className="digital-clock__hours">{mode24 ? h024 : h0}</span> | |
<span className={`digital-clock__divider digital-clock__divider--${blink ? 'blink' : 'static'}`}>:</span> | |
<span className="digital-clock__minutes">{m0}</span> | |
<span className={`digital-clock__divider digital-clock__divider--${blink ? 'blink' : 'static'}`}>:</span> | |
<span className="digital-clock__seconds">{s0}</span> | |
{!mode24 && ( | |
<span className="digital-clock__ampm">{ampm}</span> | |
)} | |
</time> | |
) | |
const Clock = ({ | |
type = 'digital', | |
scale = 1, | |
delay = 250, | |
className = '', | |
...otherProps | |
}) => { | |
const clockElement = useRef(null); | |
const [time, setTime] = useState({h:0,h24:0,m:0,s:0,ms:0,h0:'00',h024:'00',m0:'00',s0:'00',hr:0,hr24:0,mr:0,sr:0,hrs:0,hrs24:0,mrs:0,srs:0,ampm:'',}); | |
const getTwoDigits = num => `${num < 10 ? '0' : ''}${num}`; | |
const getRotationValue = (units, value, smoothDegrees = false) => { | |
const degrees = 360 / units; | |
const rotation = value * degrees; | |
const smoothRotation = smoothDegrees === false | |
? 0 | |
: smoothDegrees / 360 * degrees; | |
return rotation + smoothRotation; | |
} | |
const ts = new Date(); | |
const currentTime = useCallback(() => { | |
const hours24 = ts.getHours(); | |
const hours = hours24 % 12; | |
const minutes = ts.getMinutes(); | |
const seconds = ts.getSeconds(); | |
const milliseconds = ts.getMilliseconds(); | |
setTime({ | |
h: hours, | |
h24: hours24, | |
h0: getTwoDigits(hours), | |
h024: getTwoDigits(hours24), | |
hr: getRotationValue(12, hours), | |
hrs: getRotationValue(12, hours, getRotationValue(60, minutes)), | |
hr24: getRotationValue(24, hours24), | |
hrs24: getRotationValue(24, hours24, getRotationValue(60, minutes)), | |
m: minutes, | |
m0: getTwoDigits(minutes), | |
mr: getRotationValue(60, minutes), | |
mrs: getRotationValue(60, minutes, getRotationValue(60, seconds)), | |
s: seconds, | |
s0: getTwoDigits(seconds), | |
sr: getRotationValue(60, seconds), | |
srs: getRotationValue(60, seconds, getRotationValue(1000, milliseconds)), | |
ms: milliseconds, | |
ampm: hours24 > 11 ? 'pm' : 'am', | |
}); | |
}, [ts, setTime, getTwoDigits, getRotationValue]); | |
useEffect(() => { | |
const interval = setInterval(() => { | |
currentTime(); | |
}, delay); | |
return () => clearInterval(interval); | |
}, [currentTime, delay]); | |
useEffect(() => { | |
if (clockElement.current && scale && scale !== 1) { | |
clockElement.current.setAttribute("style", ` | |
width: ${clockElement.current.offsetWidth * scale}px; | |
height: ${clockElement.current.offsetHeight * scale}px; | |
transform: scale(${scale}); | |
`); | |
} | |
}, [scale, clockElement]); | |
return ( | |
<div ref={clockElement} className={`clock ${className}`}> | |
{type === 'digital' && <DigitalClock {...time} {...otherProps} />} | |
{type === 'analog' && <AnalogClock {...time} {...otherProps} />} | |
{type === 'debug' && <DebugClock {...time} {...otherProps} />} | |
</div> | |
); | |
}; | |
const App = () => ( | |
<> | |
<Clock type="digital" /> | |
<Clock type="digital" mode24 blink /> | |
<Clock type="digital" scale={2.5} lcd blink className="color__blue" /><br /> | |
<Clock type="analog" /> | |
<Clock type="analog" delay={50} smoothMinutes smoothSeconds /> | |
<Clock type="analog" scale={0.25} delay={200} smoothSeconds /> | |
<Clock type="debug" delay={200} /> | |
</> | |
); | |
ReactDOM.render( | |
<App />, | |
document.getElementById('root') | |
); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.13.1/umd/react.production.min.js"></script> | |
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.13.1/umd/react-dom.production.min.js"></script> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
@import url(https://db.onlinewebfonts.com/c/1cb7c6ea746ff369304a02b0538ce0f1?family=LCD); | |
@font-face {font-family: "LCD"; src: url("https://db.onlinewebfonts.com/t/1cb7c6ea746ff369304a02b0538ce0f1.eot"); src: url("https://db.onlinewebfonts.com/t/1cb7c6ea746ff369304a02b0538ce0f1.eot?#iefix") format("embedded-opentype"), url("https://db.onlinewebfonts.com/t/1cb7c6ea746ff369304a02b0538ce0f1.woff2") format("woff2"), url("https://db.onlinewebfonts.com/t/1cb7c6ea746ff369304a02b0538ce0f1.woff") format("woff"), url("https://db.onlinewebfonts.com/t/1cb7c6ea746ff369304a02b0538ce0f1.ttf") format("truetype"), url("https://db.onlinewebfonts.com/t/1cb7c6ea746ff369304a02b0538ce0f1.svg#LCD") format("svg"); } | |
$analog: ( | |
size: 32rem, | |
hub: 3rem, | |
hand-color: #05134f, | |
hand-accent-color: #bd0000, | |
hours-width: 1.625rem, | |
hours-height: 9.625rem, | |
minutes-width: 1.25rem, | |
minutes-height: 14.75rem, | |
seconds-width: 0.5rem, | |
seconds-height: 15.125rem, | |
); | |
@keyframes blink { | |
0% {opacity:0;} | |
50% {opacity:1;} | |
100% {opacity:0;} | |
} | |
.clock { | |
display: inline-block; | |
transform-origin: left top; | |
} | |
.debug-clock { | |
font-family: monospace; | |
background-color: black; | |
color: white; | |
&__key { | |
color: cyan; | |
text-align: right; | |
} | |
&__value { | |
color: lime; | |
text-align: left; | |
} | |
} | |
.digital-clock { | |
display: inline-block; | |
padding: 0.5rem; | |
font-family: monospace; | |
&--lcd { | |
font-family: LCD, monospace; | |
text-transform: uppercase; | |
} | |
&__divider { | |
opacity: 1; | |
&--blink { | |
animation: { | |
name: blink; | |
duration: 1s; | |
iteration-count: infinite; | |
}; | |
} | |
} | |
&__ampm { | |
margin-left: 0.25rem; | |
} | |
} | |
.analog-clock { | |
display: inline-block; | |
&__face { | |
width: map-get($analog, size); | |
height: map-get($analog, size); | |
position: relative; | |
display: flex; | |
justify-content: center; | |
border-radius: 50%; | |
background-color: lightgray; | |
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='512' height='512' viewBox='0 0 5120 5120'%3E%3Cg fill='%23061350'%3E%3Cpath d='M2297 4963c-44-4-48-6-44-26 3-12 9-61 13-109l7-88h31c17 0 42 3 55 7 23 6 23 7 17 92-8 95-15 132-25 129-3-1-28-3-54-5zM2460 4590v-380h200v760h-200v-380zM2756 4946c-3-12-8-60-12-107-6-85-6-86 17-92 13-4 38-7 55-7h30l11 108c6 59 10 108 9 108 0 1-24 4-53 6-46 4-52 3-57-16zM2047 4923c-37-6-41-20-27-90 29-144 28-143 101-123l37 10-22 103c-24 110-24 110-89 100zM3006 4918c-3-7-14-55-24-105l-20-93 37-10c60-17 69-13 80 28 22 84 33 164 25 172-5 4-28 11-51 15-32 5-44 3-47-7zM1805 4855c-31-9-39-17-37-31 7-34 54-179 61-187 10-10 101 22 101 36 0 29-63 197-73 196-7-1-30-7-52-14zM3221 4777c-17-50-31-97-31-104 0-14 91-46 101-36 7 8 54 153 61 187 2 14-7 21-42 32-25 8-48 14-52 14-3 0-20-42-37-93zM1577 4768c-26-11-47-24-47-28s19-50 43-103l44-96 51 24 51 24-43 96c-24 52-45 97-47 100-2 2-26-6-52-17zM3481 4768c-5-13-25-58-45-101l-35-78 51-24 51-24 44 96c48 107 48 109 31 116-7 3-30 12-51 21-37 16-38 16-46-6zM1350 4651c-47-27-84-53-83-58 4-21 302-528 311-531 8-2 140 66 180 93 5 4-310 545-317 545-3 0-44-22-91-49zM3516 4429c-86-150-155-273-154-274 40-27 172-95 180-93 9 3 307 510 311 531 2 8-159 107-174 107-4 0-77-122-163-271zM1137 4513c-20-14-37-29-37-33 0-11 119-170 128-170 16 0 83 52 80 62-8 23-114 167-123 168-6 0-27-12-48-27zM3870 4458c-33-45-60-85-60-89 0-9 70-59 82-59 9 0 128 159 128 170 0 8-72 60-83 60-4 0-34-37-67-82zM946 4359c-20-17-36-36-36-41 0-13 130-158 141-158 5 0 26 15 46 34l37 34-62 69c-90 102-84 99-126 62zM4059 4309l-73-81 37-34c20-19 41-34 46-34 11 0 141 145 141 158 0 9-65 72-74 72-2 0-37-37-77-81zM761 4175c-17-20-31-37-31-39s37-37 81-77l81-73 34 37c19 20 34 41 34 46 0 11-145 141-158 141-5 0-24-16-41-35zM4231 4142c-81-74-82-80-27-131l25-24 81 73c44 40 80 74 80 76 0 10-64 74-74 74-6-1-44-31-85-68zM604 3979l-29-42 33-27c79-66 142-103 155-91 17 13 53 79 47 84-35 27-154 109-164 113-7 3-26-14-42-37zM4405 3969c-39-27-77-54-85-59-13-8-13-13 4-45 33-60 40-62 100-20 30 20 69 50 88 65l33 27-29 42c-16 22-32 41-35 41-4 0-38-23-76-51zM482 3793c-59-102-65-114-55-123 13-12 536-311 538-308 26 39 95 172 93 179-2 6-105 69-228 141-124 71-244 140-267 154l-42 24-39-67zM4330 3705c-145-84-266-158-268-163-2-8 67-141 93-180 3-3 525 296 539 309 8 7-54 130-86 171-12 15-38 2-278-137zM357 3553c-9-21-18-44-19-51-2-7 38-31 95-57l98-44 24 51 24 51-96 44c-53 24-99 43-103 43s-14-17-23-37zM4633 3546l-92-42 24-52 24-51 98 44c57 26 97 50 95 57-7 33-36 88-46 87-6 0-52-20-103-43zM275 3347c-2-7-8-27-14-46s-11-37-11-42c0-7 175-69 197-69 8 0 43 77 43 97 0 5-35 18-129 46-58 18-83 22-86 14zM4740 3328c-52-16-98-33-103-37-10-10 22-101 37-101 13 0 187 57 193 64 5 5-18 88-26 97-3 4-49-7-101-23zM205 3098c-3-7-6-31-8-52l-2-40 102-22 103-22 10 37c20 73 23 70-98 96-89 18-101 19-107 3zM4820 3098c-131-28-130-27-110-99l10-37 103 22 102 22-2 40c-5 70-10 72-103 52zM158 2818c-2-29-3-55-1-57 5-8 203-25 209-18 4 4 9 28 12 55l4 49-88 7c-49 4-99 10-110 12-20 5-22 1-26-48zM4836 2857l-98-10 4-49c3-27 8-51 12-55 6-7 204 10 209 18 9 12-6 109-16 107-7 0-56-6-111-11zM150 2560v-100h760v200H150v-100zM4210 2560v-100h760v200h-760v-100zM217 2370c-32-4-59-9-60-11-2-2-1-28 1-57 4-49 6-53 26-48 11 2 60 8 109 12l87 7v31c0 66-8 76-59 75-25-1-72-5-104-9zM4747 2359c-4-13-7-38-7-55v-30l108-11c59-6 108-10 108-9 1 0 4 24 6 53 6 60 10 58-123 69-85 6-86 6-92-17zM295 2135l-100-21 3-45c2-24 7-48 12-53 8-8 88 3 174 25 38 10 38 11 32 51-11 67-10 67-121 43zM4710 2121c-17-60-13-69 28-80 84-22 164-33 172-25 5 5 10 29 12 53l3 45-102 22-103 22-10-37zM341 1899c-46-16-86-30-88-33-2-2 2-26 10-52 11-39 18-48 33-46 34 7 179 54 187 61 13 13-23 101-41 100-10 0-55-14-101-30zM4646 1883c-9-26-13-50-9-54 8-7 153-54 187-61 14-2 21 7 32 42 8 25 14 48 14 52 0 7-176 68-197 68-6 0-18-21-27-47zM692 1606c-144-85-265-156-268-159-6-6 62-135 88-169 12-15 38-2 278 137 145 84 266 158 268 163 3 11-89 182-98 181-3 0-123-69-268-153zM4107 1674c-26-47-47-90-45-96 2-5 123-79 268-163 240-139 266-152 278-137 32 41 94 164 86 171-9 8-534 311-537 311-1 0-24-39-50-86zM430 1674c-55-25-94-49-92-56 5-26 35-88 42-88 4 0 50 19 103 43l96 44-24 51c-13 29-25 52-27 51-2 0-46-21-98-45zM4565 1668l-24-51 96-44c53-24 99-43 103-43 7 0 37 62 42 88 2 7-38 31-95 57l-98 44-24-51zM662 1250c-45-33-82-63-82-67 0-11 52-83 60-83 11 0 170 119 170 128 0 12-50 82-59 82-4 0-44-27-89-60zM4335 1273c-14-21-25-41-25-45 0-9 159-128 170-128 8 0 60 72 60 83 0 9-160 127-171 127-5 0-20-17-34-37zM806 1057l-79-73 33-37c17-20 37-37 42-37 13 0 158 130 158 141 0 10-60 79-69 79-3 0-42-33-85-73zM4191 1095c-17-20-31-39-31-44 0-11 145-141 158-141 5 0 25 17 42 37l33 37-79 73c-43 40-82 73-85 73-4 0-21-16-38-35zM1567 1053c-85-145-299-519-300-526-2-8 159-107 174-107 7 0 322 541 317 545-28 19-170 95-177 95-5 0-12-3-14-7zM3450 1015c-41-25-79-46-83-48-7-2 281-515 304-541 7-8 130 54 171 86 15 12 2 38-137 278-84 146-159 266-167 267-7 1-47-18-88-42zM976 886c-36-41-66-78-66-84 0-9 65-72 74-72 2 0 37 37 77 81l73 81-37 34c-20 19-41 34-46 34s-38-33-75-74zM4023 926l-37-34 73-81c40-44 75-81 77-81 9 0 74 63 74 72 0 13-130 158-141 158-5 0-26-15-46-34zM2460 530V150h200v760h-200V530zM1160 728c-33-45-60-85-60-88 0-8 72-60 83-60 9 0 127 160 127 171 0 9-70 59-82 59-5 0-35-37-68-82zM3847 785c-20-14-37-29-37-34 0-11 118-171 127-171 11 0 83 52 83 60 0 11-119 170-128 170-4 0-24-11-45-25zM1572 481c-23-53-42-99-42-102 0-6 64-36 88-41 7-2 31 38 56 95l45 97-30 15c-75 39-70 42-117-64zM3452 555l-51-24 44-98c26-57 50-97 57-95 26 5 88 35 88 42 0 4-19 50-43 103l-44 96-51-24zM1821 467c-34-88-59-188-48-192 7-2 27-8 46-14s37-11 42-11c7 0 69 175 69 197 0 6-21 18-47 27-57 20-52 20-62-7zM3233 473c-24-8-43-20-43-26 0-21 61-197 68-197 4 0 27 6 52 14 37 11 44 17 42 34-6 40-58 186-68 188-5 1-28-4-51-13zM2041 383c-22-85-33-165-25-173 5-5 29-10 53-12l45-3 22 102 22 103-37 10c-60 17-69 13-80-27zM2994 409l-32-9 22-102 22-103 45 3c24 2 48 7 53 12 8 8-3 88-25 173-11 40-23 44-85 26zM2263 273c-6-60-10-109-9-109 0-1 24-4 53-6 60-6 58-10 69 123 6 85 6 86-17 92-13 4-38 7-55 7h-30l-11-107zM2756 373c-17-5-18-12-12-91 11-134 9-130 69-124 29 2 53 5 53 6 1 0-3 49-9 109l-11 107-35-1c-20-1-44-3-55-6z'/%3E%3C/g%3E%3C/svg%3E"); | |
background-size: cover; | |
background-repeat: no-repeat; | |
&::after { | |
width: map-get($analog, hub); | |
height: map-get($analog, hub); | |
background-color: map-get($analog, hand-color); | |
position: absolute; | |
display: inline-block; | |
content: ''; | |
border-radius: 50%; | |
top: 50%; | |
transform: translateY(-50%); | |
} | |
} | |
} | |
%hand-shadow { | |
box-shadow: 0 0 8px -1px black; | |
} | |
%hand-shadow-in { | |
box-shadow: inset 0 0 6px -1px black, 0 0 6px -1px black; | |
} | |
.hand { | |
@extend %hand-shadow; | |
width: map-get($analog, hours-width); | |
height: map-get($analog, hours-height); | |
background-color: map-get($analog, hand-color); | |
position: absolute; | |
display: flex; | |
justify-content: center; | |
bottom: 50%; | |
transform-origin: bottom center; | |
&--hours { | |
width: map-get($analog, hours-width); | |
height: map-get($analog, hours-height); | |
} | |
&--minutes { | |
width: map-get($analog, minutes-width); | |
height: map-get($analog, minutes-height); | |
} | |
&--seconds { | |
width: map-get($analog, seconds-width); | |
height: map-get($analog, seconds-height) * 0.4; | |
background-color: map-get($analog, hand-accent-color); | |
&::before { | |
@extend %hand-shadow-in; | |
border: map-get($analog, seconds-width) * 0.9 solid map-get($analog, hand-accent-color); | |
width: map-get($analog, hub); | |
height: map-get($analog, hub); | |
position: absolute; | |
display: inline-block; | |
content: ''; | |
border-radius: 50%; | |
background-color: transparent; | |
left: 50%; | |
top: 0; | |
transform: translate(-50%, -100%); | |
} | |
&::after { | |
@extend %hand-shadow; | |
width: map-get($analog, seconds-width) * 0.8; | |
height: map-get($analog, seconds-height) * 0.3 + map-get($analog, seconds-width) * 1.2; | |
top: (map-get($analog, seconds-height) * 0.4 + map-get($analog, hub)) * -1; | |
background-color: map-get($analog, hand-accent-color); | |
position: absolute; | |
display: inline-block; | |
content: ''; | |
} | |
} | |
} | |
.color { | |
&__black { | |
color: #000000; | |
} | |
&__white { | |
color: #ffffff; | |
} | |
&__red { | |
color: #bd0000; | |
} | |
&__blue { | |
color: #0513af; | |
&--dark { | |
color: #05134f; | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment