Skip to content

Commit dd4868e

Browse files
authored
Add files via upload
1 parent b2d125e commit dd4868e

File tree

3 files changed

+229
-1
lines changed

3 files changed

+229
-1
lines changed

038-progressive-loading/index.html

Lines changed: 41 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,41 @@
1-
1+
<!DOCTYPE html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="UTF-8" />
5+
<!-- Ensures the layout scales correctly on mobile devices -->
6+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
7+
8+
<title>Progressive Loading</title>
9+
10+
<!-- Link to the CSS file -->
11+
<link rel="stylesheet" href="styles.css" />
12+
</head>
13+
<body>
14+
15+
<div class="container">
16+
<!-- Absolute full-screen background image -->
17+
<div class="background-image"></div>
18+
19+
<!-- Progress ring + text container -->
20+
<div class="progress-container">
21+
<div class="progress-ring">
22+
<!-- The SVG defines two circles:
23+
1) One for the background (light stroke).
24+
2) One for the progressive fill (white stroke). -->
25+
<svg class="ring" viewBox="0 0 120 120">
26+
<circle class="ring-bg" cx="60" cy="60" r="54"></circle>
27+
<circle class="ring-fill" cx="60" cy="60" r="54"></circle>
28+
</svg>
29+
<!-- Displays the current loading percentage in the center of the ring -->
30+
<div class="percent-display">0%</div>
31+
</div>
32+
33+
<!-- A small text message under the ring -->
34+
<p class="loading-message">Loading in progress...</p>
35+
</div>
36+
</div>
37+
38+
<!-- Link to the JS file (at the end for best practice) -->
39+
<script src="script.js"></script>
40+
</body>
41+
</html>

038-progressive-loading/script.js

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
/*******************************************************
2+
* 1) Grab references to all the elements we need:
3+
* - The percentage text inside the ring
4+
* - The circle that will fill up
5+
* - The background image that will transition
6+
*******************************************************/
7+
const percentDisplay = document.querySelector('.percent-display');
8+
const ringFill = document.querySelector('.ring-fill');
9+
const bgImage = document.querySelector('.background-image');
10+
11+
/********************************************
12+
* 2) Define our initial loading percentage:
13+
* We'll animate from 0 up to 100.
14+
********************************************/
15+
let loadValue = 0;
16+
17+
/******************************************************
18+
* 3) Use setInterval to increment the loading value
19+
* every 40ms (~25 times per second).
20+
******************************************************/
21+
const interval = setInterval(() => {
22+
loadValue++;
23+
24+
// Once loadValue exceeds 100, we stop the interval.
25+
if (loadValue > 100) {
26+
clearInterval(interval);
27+
return;
28+
}
29+
30+
// Update the text that displays the percentage
31+
percentDisplay.textContent = loadValue + '%';
32+
33+
/************************************************************
34+
* 4) Calculate the new stroke-dashoffset for the ring-fill:
35+
* - If we have a total circumference of 339.292,
36+
* at 0% we want strokeDashoffset = 339.292 (empty).
37+
* at 100% we want strokeDashoffset = 0 (full).
38+
************************************************************/
39+
const circumference = 339.292;
40+
// The fraction of the ring that should be filled
41+
const offset = circumference - (loadValue / 100) * circumference;
42+
ringFill.style.strokeDashoffset = offset;
43+
44+
/**************************************************************
45+
* 5) Modify the grayscale filter on the background image:
46+
* - mapRange() converts loadValue from [0..100] to [100..0].
47+
* - As loadValue goes up to 100, grayValue goes down to 0,
48+
* thus removing the grayscale effect.
49+
**************************************************************/
50+
const grayValue = mapRange(loadValue, 0, 100, 100, 0);
51+
bgImage.style.filter = `grayscale(${grayValue}%)`;
52+
53+
// Uncomment for debugging: see how values change in the console
54+
// console.log(`loadValue: ${loadValue}, grayValue: ${grayValue}`);
55+
}, 40);
56+
57+
58+
/*************************************************************************
59+
* 6) The mapRange() function:
60+
* - Takes 'num' within the range [inMin..inMax]
61+
* - Returns a corresponding value in [outMin..outMax]
62+
*************************************************************************/
63+
function mapRange(num, inMin, inMax, outMin, outMax) {
64+
return ((num - inMin) * (outMax - outMin)) / (inMax - inMin) + outMin;
65+
}

038-progressive-loading/styles.css

Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
/* Import a sample font from Google Fonts */
2+
@import url("https://fonts.googleapis.com/css2?family=Open+Sans:wght@600&display=swap");
3+
4+
/* Reset box model and remove default margins/padding */
5+
* {
6+
box-sizing: border-box;
7+
margin: 0;
8+
padding: 0;
9+
}
10+
11+
/* The body occupies the full view height;
12+
we disable overflow to avoid scrollbars during the animation. */
13+
body {
14+
font-family: "Open Sans", sans-serif;
15+
width: 100%;
16+
height: 100vh;
17+
overflow: hidden;
18+
background: #111; /* Fallback background color */
19+
}
20+
21+
/* Main container fills the entire viewport */
22+
.container {
23+
position: relative;
24+
width: 100%;
25+
height: 100%;
26+
}
27+
28+
/* The background-image is positioned absolutely so it sits behind all other content. */
29+
.background-image {
30+
position: absolute;
31+
top: 0;
32+
left: 0;
33+
width: 100%;
34+
height: 100%;
35+
36+
/* Example image from Unsplash; adapt as needed */
37+
background: url("https://images.unsplash.com/photo-1474291102916-622af5ff18bb?q=80&w=2069&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D")
38+
no-repeat center center / cover;
39+
40+
/* Start at 100% grayscale, then gradually go to 0% via JavaScript. */
41+
filter: grayscale(100%);
42+
43+
/* Smooth transition for filter updates. */
44+
transition: filter 0.2s linear;
45+
46+
/* Ensure it stays below other elements. */
47+
z-index: 1;
48+
}
49+
50+
/* Container for the ring and the text inside it */
51+
.progress-container {
52+
position: absolute;
53+
top: 50%;
54+
left: 50%;
55+
transform: translate(-50%, -50%);
56+
text-align: center;
57+
color: #fff;
58+
z-index: 2; /* Above the background image */
59+
}
60+
61+
/* A wrapper for the SVG ring */
62+
.progress-ring {
63+
position: relative;
64+
width: 150px;
65+
height: 150px;
66+
margin: 0 auto 20px; /* Centers the ring and adds space below */
67+
}
68+
69+
/* Force the SVG to fill the container */
70+
.ring {
71+
width: 100%;
72+
height: 100%;
73+
}
74+
75+
/* Background circle with a light stroke,
76+
used as a reference behind the fill circle. */
77+
.ring-bg {
78+
fill: none;
79+
stroke: rgba(255, 255, 255, 0.2);
80+
stroke-width: 12;
81+
}
82+
83+
/* The circle that is progressively filled.
84+
We'll animate its stroke-dashoffset to simulate "filling." */
85+
.ring-fill {
86+
fill: none;
87+
stroke: #fff;
88+
stroke-width: 12;
89+
stroke-linecap: round;
90+
/* The circumference of the circle (r=54) -> 2 * pi * 54 ~ 339.292 */
91+
stroke-dasharray: 339.292;
92+
/* Start fully offset (which looks empty). */
93+
stroke-dashoffset: 339.292;
94+
/* Smooth animation for changes in stroke-dashoffset. */
95+
transition: stroke-dashoffset 0.2s ease-out;
96+
}
97+
98+
/* The text in the center of the ring (e.g., "50%") */
99+
.percent-display {
100+
position: absolute;
101+
top: 50%;
102+
left: 50%;
103+
transform: translate(-50%, -50%);
104+
font-size: 1.4rem;
105+
}
106+
107+
/* Subtitle or small message beneath the ring */
108+
.loading-message {
109+
font-size: 1.1rem;
110+
opacity: 0.7;
111+
}
112+
113+
/* Adjust sizes for very small screens */
114+
@media (max-width: 480px) {
115+
.progress-ring {
116+
width: 120px;
117+
height: 120px;
118+
}
119+
120+
.percent-display {
121+
font-size: 1.1rem;
122+
}
123+
}

0 commit comments

Comments
 (0)