Visual indicator of page progress while scrolling
Mint
// ==UserScript==
// @license MIT
// @name Scroll Page Progress
// @namespace http://tampermonkey.net/
// @version 1.4
// @description Visual indicator of page progress while scrolling
// @author You
// @match *://*/*
// @icon data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==
// @grant none
// ==/UserScript==
(function() {
'use strict';
let globalShadow
function once(fn, context) {
var result;
return function() {
if(fn) {
result = fn.apply(context || this, arguments);
fn = null;
}
return result;
};
}
function insertCirculaProgressBarEl() {
const shadowHost = document.createElement('div')
const shadow = shadowHost.attachShadow({ mode: "closed" });
const circularProgressBar = document.createElement('div')
const title = document.createElement('div')
const overlay = document.createElement('div')
const leftSide = document.createElement('div')
const rightSide = document.createElement('div')
globalShadow = shadow
circularProgressBar.classList.add('circular-progress-bar')
title.classList.add('title');
overlay.classList.add('overlay');
leftSide.classList.add('left-side');
rightSide.classList.add('right-side');
shadowHost.id = 'host-shwadow-circular-progress'
title.innerText = '-%';
[title, overlay, leftSide, rightSide].forEach(childEl => circularProgressBar.appendChild(childEl))
shadow.appendChild(circularProgressBar)
document.body.appendChild(shadowHost)
}
function addCSS() {
const styleSheet = document.createElement('style');
styleSheet.textContent = `
* {
box-sizing: border-box;
padding: 0;
margin: 0;
}
.circular-progress-bar {
--backgroundColor: #424242;
--left-side-angle: 180deg;
--barColor:orangered;
width: 60px;
height: 60px;
color: #fff;
border-radius: 50%;
overflow: hidden;
position: fixed;
z-index: 999999999;
background: var(--backgroundColor);
border: 5px solid white;
box-shadow:
0 1px 1px hsl(0deg 0% 0% / 0.075),
0 2px 2px hsl(0deg 0% 0% / 0.075),
0 4px 4px hsl(0deg 0% 0% / 0.075),
0 8px 8px hsl(0deg 0% 0% / 0.075),
0 16px 16px hsl(0deg 0% 0% / 0.075);
text-align: center;
}
.circular-progress-bar .overlay {
width: 50%;
height: 100%;
position: absolute;
top: 0;
left: 0;
z-index: 1;
background-color: var(--backgroundColor);
}
.circular-progress-bar .title {
font-size: 15px;
font-weight: bold;
position:relative;
height: 100%;
display:flex;
justify-content:center;
align-items: center;
z-index: 100;
}
.circular-progress-bar .left-side,
.circular-progress-bar .right-side {
width: 50%;
height: 100%;
position: absolute;
top: 0;
left: 0;
border: 5px solid var(--barColor);
border-radius: 100px 0px 0px 100px;
border-right: 0;
transform-origin: right;
}
.circular-progress-bar .left-side {
transform: rotate(var(--left-side-angle));
z-index: var(--zindex);
}
.circular-progress-bar .right-side {
transform: rotate(var(--right-side-angle));
}
`
globalShadow.appendChild(styleSheet)
}
insertCirculaProgressBarEl()
addCSS()
const currentState = {
deg: 0,
progress: 0,
zIndex: 0
}
function setAngle(deg) {
const progressBar = globalShadow.querySelector('.circular-progress-bar')
const leftSide = globalShadow.querySelector('.left-side')
const rightSide = globalShadow.querySelector('.right-side')
leftSide.style.opacity = "0"
const zIndex = deg > 180 ? 100 : 0
const rightSideAngle = deg < 180 ? deg : 180
const leftSideAngle = deg
const zIndexChangedToPositive = currentState.zIndex === 0 && zIndex === 100
if (deg > 180) {
leftSide.style.opacity = "1"
progressBar.style.setProperty('--left-side-angle', `${leftSideAngle}deg`);
progressBar.style.setProperty('--zindex', zIndex);
}
progressBar.style.setProperty('--right-side-angle', `${rightSideAngle}deg`);
currentState.deg = deg
/*if (zIndex === 100 && zIndexChangedToPositive) {
setUnsetOpacity()
}*/
}
function percentageToAngle (percentageNumber) {
if (percentageNumber > 100) {
return 360
}
if (percentageNumber < 0) {
return 0
}
return (360 * percentageNumber)/100
}
function setPercentage(percentageNumber) {
const angle = percentageToAngle(percentageNumber)
setAngle(angle)
}
function debounce(callback, wait) {
let timerId;
return (...args) => {
clearTimeout(timerId);
timerId = setTimeout(() => {
callback(...args);
}, wait);
};
}
const progressBar = globalShadow.querySelector('.circular-progress-bar')
const body = document.body;
let offsetX = 0, offsetY = 0, isDragging = false;
progressBar.addEventListener("mousedown", (e) => {
e.preventDefault()
offsetX = e.clientX - progressBar.offsetLeft;
offsetY = e.clientY - progressBar.offsetTop;
isDragging = true;
progressBar.style.cursor = "grabbing";
});
document.addEventListener("mousemove", (e) => {
if (isDragging) {
e.preventDefault();
const left = e.clientX - offsetX;
const top = e.clientY - offsetY;
progressBar.style.left = `${left}px`;
progressBar.style.top = `${top}px`;
savePosition(left, top); // Guardar la posición cada vez que se mueve
}
});
document.addEventListener("mouseup", () => {
isDragging = false;
progressBar.style.cursor = "grab";
});
function savePosition(left, top) {
const position = { left, top };
localStorage.setItem("elementPosition", JSON.stringify(position));
}
function loadPosition() {
const savedPosition = localStorage.getItem("elementPosition");
if (savedPosition) {
const { left, top } = JSON.parse(savedPosition);
progressBar.style.left = `${left}px`;
progressBar.style.top = `${top}px`;
} else {
progressBar.style.right = `10px`;
progressBar.style.top = `10px`;
}
}
function getCurrentScrollProgress() {
const winScroll = document.body.scrollTop || document.documentElement.scrollTop;
const height = document.documentElement.scrollHeight - document.documentElement.clientHeight;
const progress = (winScroll / height) * 100;
return Math.trunc(progress);
}
const progressBarTitle = globalShadow.querySelector('.title')
document.onreadystatechange = function () {
if (document.readyState == "complete") {
loadPosition()
document.addEventListener('scroll', debounce(() => {
setPercentage(getCurrentScrollProgress())
progressBarTitle.innerText = getCurrentScrollProgress() + '%'
console.log(progressBarTitle, getCurrentScrollProgress())
currentState.progress = getCurrentScrollProgress()
currentState.deg = percentageToAngle(getCurrentScrollProgress())
}, 50))
}
}
})();