Javascript-форум (https://javascript.ru/forum/)
-   Javascript под браузер (https://javascript.ru/forum/css-html/)
-   -   Срабатывания счетчика цифр при иностранном формате чисел (https://javascript.ru/forum/css-html/85729-srabatyvaniya-schetchika-cifr-pri-inostrannom-formate-chisel.html)

NastyaVs 28.01.2024 18:26

Срабатывания счетчика цифр при иностранном формате чисел
 
Добрый день, уважаемые специалисты JS.
Прошу Вас помочь в доработке кода на JS для счетчика цифр, который позволял бы:

- перелистывать значения которые находятся в иностранной разрядности цифр (сейчас у меня значения в обычном формате 2800, 1700, 106, 720. А нужно чтобы эти же значения код смог перелистывать когда они находятся в формате с иностранной разрядностью, а именно (2,800, 1,700, 106, 720))

- значения начинали пересвистываться когда при скроле страницы они достигали данного блока с этими значениями.

- и все значения до конечного результата останавливались синхронно.

Это то что я смога реализовать самостоятельно:

<!DOCTYPE html>
<html lang="en">

<head>
	<meta charset="UTF-8">
	<meta name="viewport" content="width=device-width, initial-scale=1.0">
	<meta name="robots" content="noindex, nofollow">
	<link rel="stylesheet" href="css/style.css">
	<title>Values</title>
</head>

<body>
	<div class="wrapper">
		<main>
			<div class="block js-counter-numbers-wrapper">
				<div class="block__container">
					<div class="block__grid">
						<div class="block__item_grid block__item_grid--info-mod">
							<div class="block__row">
								<div class="block__col">
									<div data-number="2800" class="block__numbers js-counter-numbers">
										<div class="block__number_sizer">2800</div>
										<div class="block__number js-counter-number">0</div>
									</div>
									<div class="block__text">
										<p>Projects</p>
									</div>
								</div>
								<div class="block__col">
									<div data-number="106" class="block__numbers js-counter-numbers">
										<div class="block__number_sizer">1060</div>
										<div class="block__number js-counter-number">0</div>
									</div>
									<div class="block__text">
										<p>Years</p>
									</div>
								</div>
							</div>
							<div class="block__row">
								<div class="block__col">
									<div data-number="1700" class="block__numbers js-counter-numbers">
										<div class="block__number_sizer">106</div>
										<div class="block__number js-counter-number">0</div>
									</div>
									<div class="block__text">
										<p>Clients</p>
									</div>
								</div>
								<div class="block__col">
									<div data-number="720" class="block__numbers js-counter-numbers">
										<div class="block__number_sizer">1670</div>
										<div class="block__number js-counter-number">0</div>
									</div>
									<div class="block__text">
										<p>Directions</p>
									</div>
								</div>
							</div>
						</div>
					</div>
				</div>
			</div>
		</main>
	</div>
	<script src="js/app.js"></script>
</body>

</html>


function counterNumbers() {
	const SELECTORS = {
		wrapper: ".js-counter-numbers-wrapper",
		numbers: ".js-counter-numbers",
		number: ".js-counter-number",
	};

	const $wrappers = document.querySelectorAll(SELECTORS.wrapper);

	if (!$wrappers.length) return;

	const BASE_DELAY = 200;

	$wrappers.forEach(($wrapper) => {
		const $numbers = $wrapper.querySelectorAll(SELECTORS.numbers);

		if (!$numbers.length) return;

		$numbers.forEach(($numberWrapper) => {
			const $number = $numberWrapper.querySelector(SELECTORS.number);
			const endValue = parseInt($numberWrapper.dataset.number);

			if (!endValue) return;

			const delay = Math.floor(BASE_DELAY / endValue);

			const interval = setInterval(() => {
				const currentNum = parseInt($number.innerText);

				if (currentNum >= endValue) clearInterval(interval);
				else $number.innerText = currentNum + 1;
			}, delay);
		});
	});
}

window.addEventListener("load", () => {
	counterNumbers();
});

voraa 28.01.2024 20:35

Чего то я не понял про "иностранную разрядность".

Цитата:

Сообщение от NastyaVs
- значения начинали пересвистываться когда при скроле страницы они достигали данного блока с этими значениями.

- и все значения до конечного результата останавливались синхронно.

Как они могут останавливаться синхронно, если начинаются в разное время (когда появятся при скролле)?

NastyaVs 28.01.2024 21:25

Цитата:

Сообщение от voraa (Сообщение 554608)
Чего то я не понял про "иностранную разрядность".

voraa, Обычный формат чисел в тысячах - пишутся 1800 или число 1700
В некоторых странах при разрядности тысячей они отделяются запятой - то есть 1800 пишется как 1,800 или число 1700 пишется как 1,700

NastyaVs 28.01.2024 21:27

Цитата:

Сообщение от voraa (Сообщение 554608)
Как они могут останавливаться синхронно, если начинаются в разное время (когда появятся при скролле)?

voraa, Они же находятся в одном блоке. Вот как это выглядит в коде:
https://codepen.io/AlmUA/pen/xxBpOmp

voraa 28.01.2024 22:48

Цитата:

Сообщение от NastyaVs
некоторых странах при разрядности тысячей они отделяются запятой - то есть 1800 пишется как 1,800 или число 1700 пишется как 1,700

Ну это не сложно
https://developer.mozilla.org/ru/doc...l/NumberFormat

Что такое BASE_DELAY?
Это максимальное время, через которое должен завершиться отсчет?
(по программе это так, судя по
const delay = Math.floor(BASE_DELAY / endValue);
)

Или это все таки интервал, между прибавлениями 1 для max endValue? Тогда все время отсчета будет BASE_DELAY * max endValue в миллисекундах.

NastyaVs 29.01.2024 00:59

Цитата:

Сообщение от voraa (Сообщение 554611)

Я сама не смогу. Пыталась

Цитата:

Что такое BASE_DELAY?
Это максимальное время, через которое должен завершиться отсчет?
(по программе это так, судя по
const delay = Math.floor(BASE_DELAY / endValue);
)
Да

voraa 29.01.2024 08:15

Что бы одновременно останавливались и выводились числа с учетом языковой настройки такой код

function counterNumbers() {
    const SELECTORS = {
        wrapper: ".js-counter-numbers-wrapper",
        numbers: ".js-counter-numbers",
        number: ".js-counter-number",
    };
 
    const $wrappers = document.querySelectorAll(SELECTORS.wrapper);
 
    if (!$wrappers.length) return;

    const TIME_COUNT = 6000;  // Время счета

    function counter ($wrapper, timeCount) {
        const $numbers = $wrapper.querySelectorAll(SELECTORS.numbers);
        if (!$numbers.length) return;

        const $numbersText = $wrapper.querySelectorAll(SELECTORS.number);
        
        const endValues = [];
         
        $numbers.forEach(($numberWrapper) => {
            const endValue = parseInt($numberWrapper.dataset.number);
            endValues.push (endValue);
        })

        const timeStart = performance.now();
        
        const form = new Intl.NumberFormat();
        
        function showNumbers (currentTime) {
            let part = (currentTime - timeStart) / timeCount;
            if (part > 1) part = 1;
            for (let i = 0; i < $numbersText.length; i++) {
                const value = Math.round( part * endValues[i]);
                $numbersText[i].textContent = form.format(value);
            }
            if (part < 1) requestAnimationFrame(showNumbers);
        }
        
        requestAnimationFrame(showNumbers);
    }
 
    $wrappers.forEach(($wrapper) => {
        counter ($wrapper, TIME_COUNT);
    });
}

NastyaVs 29.01.2024 12:00

Цитата:

Сообщение от voraa (Сообщение 554615)
Что бы одновременно останавливались и выводились числа с учетом языковой настройки такой код

Не срабатыват

voraa 29.01.2024 16:27

Цитата:

Сообщение от NastyaVs
Не срабатыват

У меня CSS нет, поэтому так смотрите. Все работает
https://jsfiddle.net/013sf5w9/

NastyaVs 29.01.2024 17:56

voraa,
Сработало.
Но как добиться того чтобы разделитель в тысячных числах был не через пробел:
2 800
а через запятую
2,800

То есть как бы по факту работа счетчика (отсчета) нужна: Чтобы значения которые идут в тысячах отделялись не через пробел как сейчас, а через запятую 2,800. Можно пожалуйста так так сделать?

https://dropmefiles.com/PHIbt - вот на видео сейчас тысячи счетчик отчитывает через пробел нижние числа, а верхние как бы хотелось через запятую.

voraa 29.01.2024 18:21

Цитата:

Сообщение от NastyaVs
Но как добиться того чтобы разделитель в тысячных числах был не через пробел:

Пробел или запятая или еще что зависит от настроек браузера, сайта или элемента.
Например можно задавать, через атрибут lang в самом html или в конкретном элементе. Брать значение этого атрибута и указывать.
Например
const form = new Intl.NumberFormat('en-En');
или
const form = new Intl.NumberFormat('ru');

https://jsfiddle.net/fa64prL0/

Я там для элемента, который на 1700 поставил lang="en-En"

NastyaVs 29.01.2024 19:05

Цитата:

Сообщение от voraa (Сообщение 554628)
Я там для элемента, который на 1700 поставил lang="en-En"

Теперь поняла. Спасибо Вам большое за уделенное время

NastyaVs 29.01.2024 19:58

voraa,
К вашему варианту еще решила добавить такую процедуру чтобы счетчик срабатывал только тогда когда при скролле достигнет этого блока, но так понимаю он не сработает:

const check = new IntersectionObserver(
	(entries) => {
		entries.forEach((entry) => {
			if (entry.isIntersecting) {
				check.disconnect();
				counterNumbers();
			}
		});
	},
	{
		root: null, // viewport, для отслеживания в пределах другого элемента (указать в этом месте)
		rootMargin: "0px", // margin вокруг root
		threshold: 1, // пороговое значение для отображения (100% для элемента)
	}
);

check.observe(document.querySelector(".block__item_grid"));

voraa 29.01.2024 20:28

Что такое check.disconnect(); ?

А так может и сработает. Пробовать надо.
Сам не могу не имея полного кода с CSS.

Только надо понять, а что дальше. Ну сработал обсервер, начали циферки
тикать. А пользователь дальше мышью крутит туда-сюда. Когда элемент появится снова опять надо считать или хватит одного первого раза.
А если опять считать, когда еще предыдущий не закончился, то все равно начинать снова с 0, или дать закончиться предыдущему циклу.

Все эти вопросы надо продумывать.

NastyaVs 29.01.2024 22:14

Цитата:

Сообщение от voraa (Сообщение 554631)
Что такое check.disconnect(); ?

voraa, Точно не скажу. Решение нашла.

if (entry.isIntersecting) {
	            // сработает когда элемент будет виден на 90%
	            observer.disconnect();
	            startProgress();


По моему в ней и крылась ошибка. Я ее исключила и вроде бы как заработало. Я пробовала, посмотрите, пожалуйста: https://codepen.io/NastyaVs/pen/vYPpvXP

Только не очень корректно срабатывает у меня когда возврат к блоку происходит при скролле

Цитата:

Сообщение от voraa (Сообщение 554631)
Только надо понять, а что дальше. Ну сработал обсервер, начали циферки тикать. А пользователь дальше мышью крутит туда-сюда. Когда элемент появится снова опять надо считать или хватит одного первого раза.

voraa, Вроде бы в этом решении все реализовано.

Цитата:

Сообщение от voraa (Сообщение 554631)
А если опять считать, когда еще предыдущий не закончился, то все равно начинать снова с 0, или дать закончиться предыдущему циклу.

voraa, Решение делает просчет счетчика цифр, сначала когда при скролле пользователь возвращается в данному блоку

voraa 29.01.2024 23:12

Цитата:

Сообщение от NastyaVs
Решение делает просчет счетчика цифр, сначала когда при скролле пользователь возвращается в данному блоку

Если так и задумывалось, то вроде работает
Цитата:

Сообщение от NastyaVs
Только не очень корректно срабатывает у меня когда возврат к блоку происходит при скролле

А в чем некорректность?

NastyaVs 29.01.2024 23:31

Цитата:

Сообщение от voraa (Сообщение 554633)
А в чем некорректность?

В принципе так и задумывалось. Но такое ощущение если возвращаться к блоку и скроллить очень медленно и когда только видишь краешек блока заметные старые значения. А если блок уже существенную часть видно уже на экране то отсчет идет сначала как и задумывалось.


Вот только мои Progress Bar ведут себя абсолютно безобразно при таком решении.

1. Первый Progress Bar - при первом обращении все корректно показывает. Но при возврате к нему обратно при скролле счетчик чисел считает бесконечно значения, а сам зеленый бар замкнулся и не все.

2. Второй Progress Bar - при первом обращении счетчик цифр отрабатывает очень быстро не успеваешь к нему даже дойти чтобы увидеть как пролистываются цифры. При этом зеленый бар при первом подходе отображается как надо. Но уже при повторном возврате ко всему Progress Bar он абсолютно не осуществляет повторно никаких действий. Можете посмотреть в чем ошибка:
https://codepen.io/NastyaVs/pen/qBvpgLb

voraa 30.01.2024 08:24

А вы сами эти коды пишете? Или надергиваете где то не думая?
Что у вас означает clearInterval();? (встречается 2 раза)
Какой именно таймер надо сбросить?

Почему 2 раза вызывается startProgress(); и еще один раз вызываются без счетчики без функции?

Я уже показывал, как делать анимацию с помощью requestAnimationFrame. А вы опять setInterval городите.
Хотите, что бы опять все кто то переделывал?

NastyaVs 30.01.2024 11:22

Цитата:

Сообщение от voraa (Сообщение 554635)
А вы сами эти коды пишете? Или надергиваете где то не думая?

Сама учусь, смотря материал на Youtube. Понимаю что очень много ошибок

Цитата:

Сообщение от voraa (Сообщение 554635)
Что у вас означает clearInterval();? (встречается 2 раза)
Какой именно таймер надо сбросить?

Пример реализации брала здесь https://www.youtube.com/watch?v=mSfsGTIQlxg&t=486s

NastyaVs 30.01.2024 11:26

Цитата:

Сообщение от voraa (Сообщение 554635)
Почему 2 раза вызывается startProgress(); и еще один раз вызываются без счетчики без функции?

Подсмотрела на форуме. Подумала так и должно быть

NastyaVs 30.01.2024 11:27

Цитата:

Сообщение от voraa (Сообщение 554635)
Хотите, что бы опять все кто то переделывал?

Я прошу предметно помочь чтобы я могла разобраться в дальнейшем :(

NastyaVs 30.01.2024 11:32

Цитата:

Сообщение от voraa (Сообщение 554635)
Хотите, что бы опять все кто то переделывал?

Если Вам тяжело помочь, или считаете что я очень надоедлива то прошу прощения, что я Вас побеспокоила

NastyaVs 30.01.2024 11:58

Цитата:

Сообщение от voraa (Сообщение 554635)
Хотите, что бы опять все кто то переделывал?

Я попыталась переделать сама у меня получилось так: https://codepen.io/NastyaVs/pen/qBvpgLb

Но добиться чтобы в Варианте #2 когда доходишь скроллом до него видно как счетчик цифр срабатывает, а срабатывает анимация для зеленых Bar-ров.

И при повторном возврате к блокам в Варианте 1 и Варианте 2 при скролле страницы вверх или вниз чтобы зеленые Bar-ы и цифры заново прокручивались и анимироваались Я НЕ СМОГЛА РЕАЛИЗОВАТЬ :(

рони 30.01.2024 12:39

NastyaVs,
на всякий случай, пример из далёкого прошлого )))
https://javascript.ru/forum/showthre...397#post485397

NastyaVs 30.01.2024 12:51

рони,
Спасибо Вам огромное за пример, но здесь подключения плагинов мне пока будет трудно в этом разбираться. Я еле свое пока могу реализовать

voraa 30.01.2024 13:38

<!DOCTYPE html>
<html lang="en">

<head>
	<meta charset="UTF-8">
	<meta name="viewport" content="width=device-width, initial-scale=1.0">
	<title>test</title>
	<style>
.wrapper {
	overflow: clip;
	min-height: 100%;
	display: flex;
	flex-direction: column;
}

.wrapper > main {
	flex-grow: 1;
}

.main {
	font-family: "Poppins", sans-serif;
	color: #fff;
	background-color: #37393f;
}

/* !Убрать после тестов*/
.main__section {
	padding-top: 1200px;
	margin-bottom: 1250px;
}

h3{
	text-align: center;
}

h3:not(:last-child){
	margin-bottom: 20px;
}
/* !Убрать после тестов */

.main__section > *:not(:last-child) {
	margin-bottom: 150px;
}

/* ?Вариант #1 (Progress Bar) */
.progress-bar__block-bar {
	max-width: 640px;
	margin: 0 auto;
	padding: 0 15px;
	display: flex;
	flex-wrap: wrap;
	gap: 15px;
}

.block-bar__clients,
.block-bar__project {
	background-color: #2e2f34;
	padding: 27px 30px;
	flex: 1 1 auto;
}

.clients-bar__wrap,
.project-bar__wrap {
	display: flex;
	flex-wrap: wrap;
	gap: 12px;
	align-items: center;
}
.clients-bar__circular,
.project-bar__circular {
	position: relative;
	width: 80px;
	height: 80px;
	border-radius: 50%;
	background: conic-gradient(#40ddb6 3.7deg, #37393f 0deg);
	display: flex;
	align-items: center;
	justify-content: center;
}

.clients-bar__circular::before,
.project-bar__circular::before {
	content: "";
	position: absolute;
	top: 5px;
	left: 5px;
	width: 70px;
	height: 70px;
	border-radius: 50%;
	background: #37393f;
}
.clients-bar__value,
.project-bar__value {
	font-size: 20px;
	font-weight: 600;
	line-height: 0.8;
	z-index: 2;
}

.text-block__paragraph {
	text-transform: capitalize;
	font-family: "Inter", sans-serif;
	line-height: 1.4;
}

.text-block__paragraph:not(:last-child) {
	margin-bottom: 1px;
}
.text-block__subtitle {
	text-transform: capitalize;
	font-size: 18px;
	font-weight: 600;
	line-height: 0.9;
}

[class*="-bar__value"] {
	font-family: "Poppins", sans-serif;
	font-size: 20px;
	font-weight: 600;
	line-height: 0.8;
}
/* !Вариант #1 (Progress Bar) */

/* ?Вариант #2 (Progress Bar) */
.circular-bar__block {
	max-width: 640px;
	margin: 0 auto;
	padding: 0 15px;
	display: flex;
	flex-wrap: wrap;
	gap: 15px;
}

.decs__paragraph {
	text-transform: capitalize;
	font-family: "Inter", sans-serif;
	line-height: 1.4;
}

.decs__subcaption {
	text-transform: capitalize;
	font-size: 18px;
	font-weight: 600;
	line-height: 0.9;
}

.block-circular__products-inner,
.block-circular__clients-inner {
	background-color: #2e2f34;
	padding: 27px 28px;
	display: flex;
	gap: 15px;
	flex-wrap: wrap;
	align-items: center;
}

.bar-products__outer-item,
.bar-clients__outer-item {
	height: 80px;
	width: 80px;
	border-radius: 50%;
	background-color: #37393f;
	display: flex;
	justify-content: center;
	align-items: center;
	position: relative;
}

.bar-products__inner-item,
.bar-clients__inner-item {
	position: absolute;
	top: 4px;
	left: 4px;
	height: 70px;
	width: 70px;
	border-radius: 50%;
	display: flex;
	justify-content: center;
	align-items: center;
}

#bar-products__value,
#bar-clients__value {
	font-size: 20px;
	font-weight: 600;
	line-height: 0.8;
	z-index: 2;
}

.circular-bar__anim.circular-bar__products.circular-bar__active {
	fill: #37393F;
	stroke: #40ddb6;
	stroke-width: 5px;
	stroke-dasharray: 226; /* параметр для создания полноценной окружности */
	stroke-dashoffset: 226; /* параметр для начальной точки отсчета */
	animation: sircle-products 1s linear forwards;
}

.circular-bar__anim.circular-bar__clients.circular-bar__active {
	fill: #37393F;
	stroke: #40ddb6;
	stroke-width: 5px;
	stroke-dasharray: 226; /* параметр для создания полноценной окружности */
	stroke-dashoffset: 226; /* параметр для начальной точки отсчета */
	animation: sircle-clients 1s linear forwards;
}

.circular-bar__products, .circular-bar__clients {
	transform: rotate(-84deg);
}

@keyframes sircle-products {
	100% {
		stroke-dashoffset: 11;
	}
}

@keyframes sircle-clients {
	100% {
		stroke-dashoffset: 20;
	}
}
	
	</style>
</head>

<body>
	<div class="wrapper">


		<header class="header">
			<div class="header__section section">
			</div>
		</header>


		<main class="main">
			<div class="main__section section">
				<!-- ?Вариант #1 -->
				<div class="progress-bar">
					<h3>Вариант #1</h3>
					<div class="progress-bar__block-bar block-bar">

						<div class="block-bar__clients clients-bar">
							<div class="clients-bar__wrap">
								<div class="clients-bar__circular">
									<span class="clients-bar__value">95%</span>
								</div>

								<div class="clients-bar__text-block text-block">
									<div class="text-block__paragraph">clients</div>
									<h4 class="text-block__subtitle">quick response</h4>
								</div>
							</div>
						</div>
						<div class="block-bar__project project-bar">
							<div class="project-bar__wrap">
								<div class="project-bar__circular">
									<span class="project-bar__value">85%</span>
								</div>

								<div class="products-bar__text-block text-block">
									<div class="text-block__paragraph">project</div>
									<h4 class="text-block__subtitle">finished jobs</h4>
								</div>
							</div>
						</div>
					</div>
				</div>

			</div>
		</main>


		<footer class="footer">
			<div class="footer__section section"></div>
		</footer>
	</div>
	<script>
let barProducts = document.querySelector(".clients-bar__circular"),
		productsCount = document.querySelector(".clients-bar__value"),
		barClients = document.querySelector(".project-bar__circular"),
		clientsCount = document.querySelector(".project-bar__value");
 
let productsStart = 0,
		productsEndValue = 95,
		clientsStartValue = 0,
		clientsEndValue = 85;


let productsInterval = false;
let clientsInterval = false;

const COUNT_TIME = 5000;
 
const startProgress = (timeCount) => {

    const endValues = [95, 85];
    const elementsBar = [barProducts, barClients];
    const elementsCount = [productsCount, clientsCount];
    
    const timeStart = performance.now();
               
     function show (currentTime) {
        let part = (currentTime - timeStart) / timeCount;
        if (part > 1) part = 1;
        for (let i = 0; i < endValues.length; i++) {
            const percent = Math.round( part * endValues[i]);
            const degree = part * endValues[i] * 3.6;
            elementsBar[i].style.background = `conic-gradient(#40DDB6 ${degree}deg, #37393F 0deg)`;
            elementsCount[i].innerHTML = `${percent}%`;
        }
        if (part < 1) requestAnimationFrame(show);
    }
        
    requestAnimationFrame(show);
}
    
	
 
//TODO Вариант #1 (Progress Bar) - скролл страницы
 
const observer = new IntersectionObserver(
    (entries) => {
        entries.forEach((entry) => {
            if (entry.isIntersecting) {
                startProgress(COUNT_TIME);
            }
        });
    },
    {
        root: null,
        rootMargin: "0px",
        threshold: 0.9,
    }
);
 
observer.observe(document.querySelector(".progress-bar__block-bar"));
	</script>
</body>

</html>

NastyaVs 30.01.2024 16:48

voraa,
Спасибо Вам огромное за объяснение


Часовой пояс GMT +3, время: 09:03.