├── LICENSE ├── README.md ├── bg-desktop.webp ├── graficos ├── common.js ├── informacoesGlobais.js ├── quantidadeUsuarios.js └── scripts.js ├── index.html └── style.css /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2024 Rafael Assis Santos 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Ciencia de dados criando graficos dinamicos com JavaScript 2 | @rasinformática 3 | 4 | 5 | https://www.youtube.com/watch?v=ZNNDuNZhkkc&t=11s 6 | -------------------------------------------------------------------------------- /bg-desktop.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/professor-rafael/Ciencia-de-dados-criando-graficos-dinamicos-com-JavaScript/84db615c722ee6a3981263630571e3df06d8f079/bg-desktop.webp -------------------------------------------------------------------------------- /graficos/common.js: -------------------------------------------------------------------------------- 1 | const getCSS = (variavel) => { 2 | const bodyStyles = getComputedStyle(document.body) 3 | return bodyStyles.getPropertyValue(variavel) 4 | } 5 | 6 | const tickConfig = { 7 | family: getCSS('--font'), 8 | size: 16, 9 | color: getCSS('--primary-color') 10 | } 11 | 12 | export {getCSS, tickConfig} 13 | -------------------------------------------------------------------------------- /graficos/informacoesGlobais.js: -------------------------------------------------------------------------------- 1 | const url = 'https://raw.githubusercontent.com/guilhermeonrails/api/main/dados-globais.json' 2 | 3 | async function vizualizarInformacoesGlobais() { 4 | const res = await fetch(url) 5 | const dados = await res.json() 6 | const pessoasConectadas = (dados.total_pessoas_conectadas / 1e9) 7 | const pessoasNoMundo = (dados.total_pessoas_mundo / 1e9) 8 | const horas = parseInt(dados.tempo_medio) 9 | const minutos = Math.round((dados.tempo_medio - horas) * 100) 10 | const porcentagemConectada = ((pessoasConectadas / pessoasNoMundo ) * 100).toFixed(2) 11 | 12 | const paragrafo = document.createElement('p') 13 | paragrafo.classList.add('graficos-container__texto') 14 | paragrafo.innerHTML = `Você sabia que o mundo tem ${pessoasNoMundo} bilhões de pessoas e que aproximadamente ${pessoasConectadas} bilhões estão conectadas em alguma rede social e passam em média ${horas} horas e ${minutos} minutos conectadas.
Isso significa que aproximadamente ${porcentagemConectada}% de pessoas estão conectadas em alguma rede social.` 15 | 16 | const container = document.getElementById('graficos-container') 17 | container.appendChild(paragrafo) 18 | } 19 | 20 | vizualizarInformacoesGlobais() 21 | -------------------------------------------------------------------------------- /graficos/quantidadeUsuarios.js: -------------------------------------------------------------------------------- 1 | import { getCSS, tickConfig } from "./common.js" 2 | 3 | async function quantidadeUsuariosPorRede() { 4 | const url = 'https://raw.githubusercontent.com/guilhermeonrails/api/main/numero-usuarios.json' 5 | const res = await fetch(url) 6 | const dados = await res.json() 7 | const nomeDasRedes = Object.keys(dados) 8 | const quantidadeDeUsuarios = Object.values(dados) 9 | 10 | const data = [ 11 | { 12 | x: nomeDasRedes, 13 | y: quantidadeDeUsuarios, 14 | type: 'bar', 15 | marker: { 16 | color: getCSS('--primary-color') 17 | } 18 | } 19 | ] 20 | 21 | const laytout = { 22 | plot_bgcolor: getCSS('--bg-color'), 23 | paper_bgcolor: getCSS('--bg-color'), 24 | title: { 25 | text: 'Redes sociais com mais usuários', 26 | x: 0, 27 | font: { 28 | color: getCSS('--primary-color'), 29 | size: 30, 30 | font: getCSS('--font') 31 | } 32 | }, 33 | xaxis: { 34 | tickfont: tickConfig, 35 | title: { 36 | text: 'Nome das redes', 37 | font: { 38 | color: getCSS('--secondary-color') 39 | } 40 | } 41 | }, 42 | yaxis: { 43 | tickfont: tickConfig, 44 | title: { 45 | text: 'Bilhões de usuários ativos', 46 | font: { 47 | color: getCSS('--secondary-color') 48 | } 49 | } 50 | } 51 | } 52 | 53 | const grafico = document.createElement('div') 54 | grafico.className = 'grafico' 55 | document.getElementById('graficos-container').appendChild(grafico) 56 | Plotly.newPlot(grafico, data, laytout) 57 | } 58 | 59 | quantidadeUsuariosPorRede() -------------------------------------------------------------------------------- /graficos/scripts.js: -------------------------------------------------------------------------------- 1 | 2 | const selecaoVoz = document.querySelector("#selecao-voz"); 3 | const entradaTexto = document.querySelector("#entrada-de-texto"); 4 | const botaoOuvir = document.querySelector("#ouvir-btn"); 5 | const botoaBaixarTexto = document.querySelector("#baixar-texto-btn"); 6 | const uplaodArquivo = document.querySelector("#upload-arquivo"); 7 | 8 | 9 | const fala = new SpeechSynthesisUtterance(); 10 | 11 | let vozesDisponiveis = []; 12 | 13 | 14 | const atualizarValores = () => { 15 | vozesDisponiveis = window.speechSynthesis.getVoices(); 16 | 17 | fala.voice = vozesDisponiveis[0]; 18 | 19 | console.log(vozesDisponiveis); 20 | 21 | vozesDisponiveis.forEach((voz, index) => { 22 | const opcao = document.createElement("option"); 23 | opcao.value = index; 24 | opcao.textContent = voz.name; 25 | selecaoVoz.appendChild(opcao); 26 | }); 27 | }; 28 | 29 | window.speechSynthesis.onvoiceschanged = atualizarValores; 30 | 31 | 32 | selecaoVoz.addEventListener("change", () => { 33 | fala.voice = vozesDisponiveis[selecaoVoz.value]; 34 | }); 35 | 36 | botaoOuvir.addEventListener("click", () => { 37 | fala.text = entradaTexto.value; 38 | 39 | window.speechSynthesis.speak(fala); 40 | }); 41 | 42 | 43 | botoaBaixarTexto.addEventListener("click", () => { 44 | const texto = entradaTexto.value; 45 | 46 | const blob = new Blob([texto], { type: "text/plain" }); 47 | 48 | const url = URL.createObjectURL(blob); 49 | 50 | const a = document.createElement("a"); 51 | 52 | a.href = url; 53 | 54 | a.download = "texto.txt"; 55 | 56 | a.click(); 57 | 58 | URL.revokeObjectURL(url); 59 | }); 60 | 61 | 62 | uplaodArquivo.addEventListener("change", (event) => { 63 | const arquivo = event.target.files[0]; 64 | 65 | if (arquivo) { 66 | const leitor = new FileReader(); 67 | 68 | leitor.onload = (e) => { 69 | entradaTexto.value = e.target.result; 70 | }; 71 | 72 | leitor.readAsText(arquivo); 73 | } 74 | }); 75 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Redes Sociais 7 | 8 | 9 | 10 | 11 |
12 |

Relatório das redes sociais

13 | 17 |
18 |
19 |
20 | 21 |
22 |
23 | 26 | 27 | 28 | 29 | 30 |
31 |
32 |
33 |

Conversor de Texto para Fala

34 |

Digite um texto ou envie algum arquivo para ser lido:

35 |
36 | 40 |
41 | 42 | 43 |
44 |
45 |
46 |
47 |

Selecione a voz:

48 | 49 |
50 |
51 |

Clique para ouvir:

52 | 53 |
54 |
55 |

Obtenha um arquivo do conteúdo:

56 | 57 |
58 |
59 |
60 | 150 | 151 |
152 | 153 | 154 | -------------------------------------------------------------------------------- /style.css: -------------------------------------------------------------------------------- 1 | @import url('https://fonts.googleapis.com/css2?family=Nunito+Sans:ital,opsz,wght@0,6..12,200..1000;1,6..12,200..1000&display=swap'); 2 | 3 | :root { 4 | --bg-color: black; 5 | --primary-color: green; 6 | --secondary-color: green; 7 | --font: American Typewriter, serif; 8 | } 9 | 10 | body { 11 | background-color: var(--bg-color); 12 | color: var(--primary-color); 13 | font-family: var(--font); 14 | height: 100vh; 15 | margin: 0; 16 | background: url('bg-desktop.webp'); 17 | } 18 | 19 | header { 20 | background-color: var(--primary-color); 21 | text-align: center; 22 | padding: 1px; 23 | } 24 | 25 | h1 { 26 | font-size: 2rem; 27 | color: var(--bg-color); 28 | font-weight: 700; 29 | font-weight: bolder; 30 | } 31 | 32 | nav { 33 | display: flex; 34 | justify-content: center; 35 | font-weight: 400; 36 | font-weight: bolder; 37 | } 38 | 39 | nav a { 40 | text-decoration: none; 41 | color: var(--bg-color); 42 | margin: 0 2rem 1rem 0rem; 43 | font-size: 1.2rem; 44 | } 45 | 46 | nav a:hover { 47 | text-decoration: none; 48 | transform: scale(0.90); 49 | transition: transform 0.1s; 50 | font: bold; 51 | font-family: 22px; 52 | } 53 | 54 | .graficos-container { 55 | margin: 5rem; 56 | filter: drop-shadow(1px 1px 20px rgb(1, 13, 4)); 57 | border-radius: 10px; 58 | 59 | } 60 | 61 | .grafico { 62 | margin-top: 3rem; 63 | filter: box-shadow(1px 1px 20px rgb(186, 206, 192)); 64 | border: 8px green double; 65 | } 66 | 67 | .graficos-container__texto { 68 | font-size: 1.3rem; 69 | text-align: center; 70 | padding: 2rem; 71 | border: var(--secondary-color) solid 2px; 72 | } 73 | 74 | span { 75 | font-weight: bold; 76 | color: var(--secondary-color); 77 | } 78 | 79 | footer { 80 | display: flex; 81 | align-items: center; 82 | justify-content: center; 83 | background-color: var(--primary-color); 84 | color: var(--bg-color); 85 | width: 100%; 86 | height: 3rem; 87 | margin-top: 2rem; 88 | filter: drop-shadow(1px 1px 20px rgb(164, 211, 179)); 89 | border-radius: 10px; 90 | } 91 | 92 | p { 93 | color: grey; 94 | text-decoration: none; 95 | font-size: larger; 96 | font-size: 38px; 97 | font-weight: bolder; 98 | } 99 | 100 | 101 | ul { 102 | list-style: none; 103 | } 104 | 105 | .example-2 { 106 | display: flex; 107 | justify-content: center; 108 | align-items: center; 109 | } 110 | .example-2 .icon-content { 111 | margin: 0 10px; 112 | position: relative; 113 | } 114 | .example-2 .icon-content .tooltip { 115 | position: absolute; 116 | top: -30px; 117 | left: 50%; 118 | transform: translateX(-50%); 119 | color: #390909; 120 | padding: 6px 10px; 121 | border-radius: 5px; 122 | opacity: 0; 123 | visibility: hidden; 124 | font-size: 14px; 125 | transition: all 0.3s ease; 126 | } 127 | .example-2 .icon-content:hover .tooltip { 128 | opacity: 1; 129 | visibility: visible; 130 | top: -50px; 131 | } 132 | .example-2 .icon-content a { 133 | position: relative; 134 | overflow: hidden; 135 | display: flex; 136 | justify-content: center; 137 | align-items: center; 138 | width: 50px; 139 | height: 50px; 140 | border-radius: 50%; 141 | color: #4d4d4d; 142 | background-color: c29090; 143 | transition: all 0.3s ease-in-out; 144 | } 145 | .example-2 .icon-content a:hover { 146 | box-shadow: 3px 2px 45px 0px rgb(0 0 0 / 12%); 147 | } 148 | .example-2 .icon-content a svg { 149 | position: relative; 150 | z-index: 1; 151 | width: 30px; 152 | height: 30px; 153 | } 154 | .example-2 .icon-content a:hover { 155 | color: rgb(54, 20, 20); 156 | } 157 | .example-2 .icon-content a .filled { 158 | position: absolute; 159 | top: auto; 160 | bottom: 0; 161 | left: 0; 162 | width: 100%; 163 | height: 0; 164 | background-color: #000; 165 | transition: all 0.3s ease-in-out; 166 | } 167 | .example-2 .icon-content a:hover .filled { 168 | height: 100%; 169 | } 170 | 171 | .example-2 .icon-content a[data-social="linkedin"] .filled, 172 | .example-2 .icon-content a[data-social="linkedin"] ~ .tooltip { 173 | background-color: #0274b3; 174 | } 175 | 176 | .example-2 .icon-content a[data-social="github"] .filled, 177 | .example-2 .icon-content a[data-social="github"] ~ .tooltip { 178 | background-color: #24262a; 179 | } 180 | .example-2 .icon-content a[data-social="instagram"] .filled, 181 | .example-2 .icon-content a[data-social="instagram"] ~ .tooltip { 182 | background: linear-gradient( 183 | 45deg, 184 | #405de6, 185 | #5b51db, 186 | #b33ab4, 187 | #c135b4, 188 | #e1306c, 189 | #fd1f1f 190 | ); 191 | } 192 | .example-2 .icon-content a[data-social="youtube"] .filled, 193 | .example-2 .icon-content a[data-social="youtube"] ~ .tooltip { 194 | background-color: #ff0000; 195 | } 196 | 197 | 198 | 199 | .container { 200 | width: 100%; 201 | min-height: 100vh; 202 | display: flex; 203 | align-items: center; 204 | justify-content: center; 205 | flex-direction: column; 206 | color: greenyellow; 207 | text-align: center; 208 | gap: 20px; 209 | } 210 | 211 | .container h1 { 212 | font-size: 42px; 213 | font-weight: bold; 214 | } 215 | 216 | .container h1 span { 217 | color: greenyellow; 218 | } 219 | 220 | #entrada-de-conteudo { 221 | display: flex; 222 | width: 80%; 223 | gap: 20px; 224 | align-items: center; 225 | } 226 | 227 | #entrada-de-conteudo textarea { 228 | width: 80%; 229 | height: 150px; 230 | border: none; 231 | border-radius: 5px; 232 | font-size: 16px; 233 | outline: none; 234 | padding: 15px; 235 | } 236 | 237 | input[type="file"] { 238 | display: none; 239 | } 240 | 241 | .acoes { 242 | display: flex; 243 | align-items: center; 244 | gap: 10px; 245 | width: 80%; 246 | } 247 | 248 | .acao-box { 249 | padding: 15px; 250 | gap: 15px; 251 | flex: 1; 252 | } 253 | 254 | .acoes select, 255 | .acoes button, 256 | #arquivo-label { 257 | margin: 10px 0; 258 | padding: 10px; 259 | border: none; 260 | border-radius: 5px; 261 | font-size: 16px; 262 | width: 50%; 263 | font-weight: bold; 264 | cursor: pointer; 265 | } 266 | 267 | #selecao-voz { 268 | width: 100%; 269 | } 270 | 271 | .acoes button { 272 | background-color:green; 273 | color: black; 274 | 275 | transition: 0.3s; 276 | } 277 | 278 | #arquivo-label { 279 | font-size: 20px; 280 | padding: 15px; 281 | background-color: green; 282 | } 283 | 284 | .acoes button:hover, 285 | #arquivo-label:hover { 286 | background-color: black; 287 | border: double purple; 288 | } 289 | 290 | --------------------------------------------------------------------------------