1/* ============================================================ 2 Cinquentômetro â contador estimado da população 50+ no Brasil 3 Portal Viva · layoutV2 4 5 Método PRÃPRIO do projeto. NÃO consome IBGE, censo nem API externa: 6 é uma PROJEÃÃO client-side a partir de um valor de referência que 7 cresce de forma constante ao longo do tempo. 8 9 valor = inicial + incremento * floor( segundos_decorridos / intervalo ) 10 11 Config via data-* no elemento #cinquentometro: 12 data-inicial valor de referência (ex.: 62234770) 13 data-base data em que o valor de referência valia (ISO, ex.: 2026-08-03) 14 data-seg intervalo em segundos entre incrementos (ex.: 20) 15 data-incremento quanto soma a cada incremento (opcional, padrão 1) 16 17 Renderiza cada algarismo como <span class="portalviva_contador__digito"> e 18 cada separador de milhar como <span class="portalviva_contador__sep">. 19 20 ANIMAÃÃO (pedido do cliente): cada quadro (dÃgito) que muda gira de baixo p/ 21 cima (flip). Se muda só a última casa, gira só ela; se mudam 2, 3, ⦠giram 22 todas as que mudaram. Anima Sà os dÃgitos alterados, via Web Animations API 23 (re-dispara limpo, sem classes; funciona em Chrome/Firefox/Safari-iOS). 24 O limiar CASAS_MIN_ANIMACAO controla a partir de quantas casas anima (padrão 1). 25 A perspectiva 3D vai no próprio transform (perspective(...) aqui no animar()); 26 o CSS só define transform-origin (centro) e backface-visibility. 27 ============================================================ */ 28(function () { 29 'use strict'; 30 31 // Anima CADA quadro (dÃgito) que muda. 1 = anima sempre que um dÃgito é 32 // atualizado â inclusive quando só a última casa muda (comportamento pedido). 33 // Aumente p/ só animar quando N+ casas mudarem juntas. 34 var CASAS_MIN_ANIMACAO = 1; 35 36 function initCinquentometro() { 37 var el = document.getElementById('cinquentometro'); 38 if (!el) return; 39 40 var inicial = parseInt(el.getAttribute('data-inicial'), 10); 41 var base = Date.parse(el.getAttribute('data-base') + 'T00:00:00Z'); 42 var intervalo = parseInt(el.getAttribute('data-seg'), 10); 43 var incremento = parseInt(el.getAttribute('data-incremento'), 10); 44 if (isNaN(incremento) || incremento <= 0) incremento = 1; 45 46 // sem config válida, não renderiza nada (evita "NaN" na tela) 47 if (isNaN(inicial) || isNaN(base) || isNaN(intervalo) || intervalo <= 0) return; 48 49 var spans = []; // 1 <span> por caractere (dÃgitos e separadores) 50 var ultimoTxt = null; // string formatada anterior (ex.: "62.234.770") 51 var ultimoValor = null; 52 53 function valorAtual() { 54 var decorridos = Math.floor((Date.now() - base) / 1000); 55 if (decorridos < 0) decorridos = 0; // data de referência no futuro â mostra o inicial 56 return inicial + incremento * Math.floor(decorridos / intervalo); 57 } 58 59 // (re)constrói toda a estrutura de spans a partir do texto 60 function construir(txt) { 61 el.textContent = ''; 62 spans = []; 63 var frag = document.createDocumentFragment(); 64 for (var i = 0; i < txt.length; i++) { 65 var ch = txt.charAt(i); 66 var span = document.createElement('span'); 67 if (ch >= '0' && ch <= '9') { 68 span.className = 'portalviva_contador__digito'; 69 span.textContent = ch; 70 } else { 71 span.className = 'portalviva_contador__sep'; 72 span.setAttribute('aria-hidden', 'true'); 73 } 74 frag.appendChild(span); 75 spans.push(span); 76 } 77 el.appendChild(frag); 78 } 79 80 // giro de baixo p/ cima do dÃgito (WAAPI). Sem suporte â só troca o número. 81 function animar(span) { 82 if (typeof span.animate !== 'function') return; 83 // perspective() DENTRO do transform â ponto de fuga próprio de cada dÃgito 84 // (giro 3D vertical em torno do centro, sem escorregar pro lado). 85 span.animate( 86 [ 87 { transform: 'perspective(320px) rotateX(-90deg)', opacity: 0 }, 88 { transform: 'perspective(320px) rotateX(0deg)', opacity: 1 } 89 ], 90 { duration: 650, easing: 'cubic-bezier(.2,.7,.3,1)' } 91 ); 92 } 93 94 function render() { 95 var valor = valorAtual(); 96 if (valor === ultimoValor) return; // só mexe quando o número muda 97 ultimoValor = valor; 98
99 var txt = valor.toLocaleString('pt-BR'); 100 101 // 1º render ou mudança de estrutura (nº de casas/separadores) â reconstrói 102 if (ultimoTxt === null || txt.length !== ultimoTxt.length) { 103 construir(txt); 104 ultimoTxt = txt; 105 return; 106 } 107 108 // mesma estrutura: acha as posições que mudaram (são sempre dÃgitos) 109 var mudaram = []; 110 for (var i = 0; i < txt.length; i++) { 111 if (txt.charAt(i) !== ultimoTxt.charAt(i)) mudaram.push(i); 112 } 113 114 // atualiza o texto dos dÃgitos que mudaram 115 for (var j = 0; j < mudaram.length; j++) { 116 spans[mudaram[j]].textContent = txt.charAt(mudaram[j]); 117 } 118 119 // anima só se >= CASAS_MIN_ANIMACAO casas mudaram de uma vez 120 if (mudaram.length >= CASAS_MIN_ANIMACAO) { 121 for (var k = 0; k < mudaram.length; k++) { 122 animar(spans[mudaram[k]]); 123 } 124 } 125 126 ultimoTxt = txt; 127 } 128 129 render(); 130 setInterval(render, 1000); 131 } 132 133 if (document.readyState === 'loading') { 134 document.addEventListener('DOMContentLoaded', initCinquentometro); 135 } else { 136 initCinquentometro(); 137 } 138})();
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.