Posted on: June 05, 2025 08:21 PM
Posted by: Renato
Views: 140
Frente fria - vista do espaço
Imagens de uma frente fria vista do espaço.
A imagem representa uma formação de nuvens bastante característica, conhecida como frente fria ou linha de instabilidade, geralmente associada a sistemas meteorológicos frontais. A imagem mostra claramente uma longa faixa de nuvens se estendendo de norte a sul sobre a América do Sul, mais precisamente sobre a Argentina, com o Brasil à direita da imagem.
A formação é típica de frentes frias, onde o ar frio (à esquerda) empurra o ar quente (à direita), forçando o ar quente a subir. Esse movimento gera condensação e, consequentemente, essa faixa contínua de nuvens densas.
A formação de nuvens é linear e se alinha com a borda dos Andes, o que é comum devido à topografia que canaliza os ventos e intensifica o contraste térmico entre as massas de ar. Essa imagem é um exemplo impressionante da interação entre clima e geografia terrestre.
- Existe alguma api que posso consumir para ver previsao do tempo e como posso fazer sito com laravel?
🌤️ APIs para Previsão do Tempo
-
OpenWeatherMap
-
Tem plano gratuito com limites razoáveis.
-
Fornece previsão atual, por hora e por 7 dias, além de mapas climáticos.
-
Necessário registrar e obter uma
API Key.
-
WeatherAPI
-
Fornece previsão atual, histórica, futura, e dados astronômicos.
-
Climacell (Tomorrow.io)
-
Site: https://www.tomorrow.io
-
Oferece insights hiperlocais (útil para previsão em regiões específicas, como a borda dos Andes).
-
🚀 Exemplo de Integração no Laravel com OpenWeatherMap
1. Instale o HTTP Client (Laravel 7+ já vem com Http):
composer require guzzlehttp/guzzle
2. No .env, adicione:
OPENWEATHER_API_KEY=your_api_key_aqui
3. Crie um Controller:
php artisan make:controller WeatherController
4. Código no controller:
use Illuminate\Support\Facades\Http;
class WeatherController extends Controller
{
public function getWeather($city = 'Buenos Aires')
{
$apiKey = env('OPENWEATHER_API_KEY');
$response = Http::get("https://api.openweathermap.org/data/2.5/weather", [
'q' => $city,
'appid' => $apiKey,
'units' => 'metric',
'lang' => 'pt_br',
]);
if ($response->successful()) {
return response()->json($response->json());
}
return response()->json(['error' => 'Erro ao obter dados meteorológicos'], 500);
}
}
5. Rota em web.php ou api.php:
Route::get('/weather/{city?}', [WeatherController::class, 'getWeather']);
📌 Resultado
Acesse:
http://localhost:8000/weather/São%20Paulo
E receba uma resposta como:
{
"main": {
"temp": 21.6,
"humidity": 78
},
"weather": [
{
"description": "nuvens dispersas"
}
]
}
Ótimo! Vamos mostrar a previsão do tempo em uma view Blade, com Laravel (pode ser usado com Livewire depois, se quiser reatividade).
✅ Etapas para exibir previsão do tempo em uma view Blade
1. 🔧 Controller: ajustar para enviar os dados para a view
Atualize seu WeatherController para:
use Illuminate\Support\Facades\Http;
class WeatherController extends Controller
{
public function show($city = 'Buenos Aires')
{
$apiKey = env('OPENWEATHER_API_KEY');
$response = Http::get("https://api.openweathermap.org/data/2.5/weather", [
'q' => $city,
'appid' => $apiKey,
'units' => 'metric',
'lang' => 'pt_br',
]);
if ($response->successful()) {
$weather = $response->json();
return view('weather.show', compact('weather', 'city'));
}
return view('weather.show', ['weather' => null, 'city' => $city]);
}
}
2. 🛣️ Rota (em web.php)
Route::get('/previsao/{city?}', [WeatherController::class, 'show']);
3. 🖼️ Criar a view Blade: resources/views/weather/show.blade.php
@extends('layouts.app')
@section('content')
<div class="max-w-md mx-auto mt-10 bg-white shadow-xl rounded-xl p-6 text-center">
<h1 class="text-2xl font-bold mb-4">Previsão do Tempo</h1>
<form method="GET" action="{{ url('/previsao') }}" class="mb-4">
<input type="text" name="city" placeholder="Digite a cidade"
value="{{ old('city', $city) }}"
class="border px-3 py-2 rounded w-full mb-2" />
<button type="submit" class="bg-blue-500 text-white px-4 py-2 rounded">
Buscar
</button>
</form>
@if ($weather)
<h2 class="text-xl font-semibold">{{ $city }}</h2>
<p class="text-gray-700 text-lg">🌡️ {{ $weather['main']['temp'] }}°C</p>
<p class="text-gray-500 capitalize">☁️ {{ $weather['weather'][0]['description'] }}</p>
<p class="text-gray-500">💧 Umidade: {{ $weather['main']['humidity'] }}%</p>
@else
<p class="text-red-500">Não foi possível obter a previsão para "{{ $city }}"</p>
@endif
</div>
@endsection
4. 💡 Exemplo de layout base (caso não tenha um)
Crie resources/views/layouts/app.blade.php se ainda não existir:
<!DOCTYPE html>
<html lang="pt-BR">
<head>
<meta charset="UTF-8">
<title>Previsão do Tempo</title>
<link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/tailwind.min.css" rel="stylesheet">
</head>
<body class="bg-gray-100">
@yield('content')
</body>
</html>
🔁 Livewire (opcional)
Perfeito! Vamos transformar a busca em reativa com Livewire, além de adicionar ícones meteorológicos, previsão por hora, e um mapa com a localização. Aqui está o passo a passo:
✅ Etapas completas com Livewire + ícones + previsão por hora + mapa
1. 📦 Instale o Livewire (caso ainda não tenha)
composer require livewire/livewire
php artisan livewire:publish
2. 🧠 Crie o componente Livewire
php artisan make:livewire WeatherForecast
3. ✍️ Código do componente app/Livewire/WeatherForecast.php
namespace App\Livewire;
use Livewire\Component;
use Illuminate\Support\Facades\Http;
class WeatherForecast extends Component
{
public $city = 'Buenos Aires';
public $weather;
public $hourly;
public function mount()
{
$this->fetchWeather();
}
public function updatedCity()
{
$this->fetchWeather();
}
public function fetchWeather()
{
$apiKey = env('OPENWEATHER_API_KEY');
// Get coordinates first
$geo = Http::get('http://api.openweathermap.org/geo/1.0/direct', [
'q' => $this->city,
'limit' => 1,
'appid' => $apiKey,
])->json();
if (empty($geo)) {
$this->weather = null;
$this->hourly = [];
return;
}
$lat = $geo[0]['lat'];
$lon = $geo[0]['lon'];
$response = Http::get("https://api.openweathermap.org/data/2.5/onecall", [
'lat' => $lat,
'lon' => $lon,
'exclude' => 'minutely,daily,alerts',
'units' => 'metric',
'appid' => $apiKey,
'lang' => 'pt_br',
]);
if ($response->successful()) {
$data = $response->json();
$this->weather = $data['current'];
$this->hourly = array_slice($data['hourly'], 0, 6); // próximas 6 horas
} else {
$this->weather = null;
$this->hourly = [];
}
}
public function render()
{
return view('livewire.weather-forecast');
}
}
4. 🖼️ View do componente: resources/views/livewire/weather-forecast.blade.php
<div class="max-w-xl mx-auto mt-10 p-6 bg-white rounded-lg shadow-md text-center">
<h1 class="text-2xl font-bold mb-4">Previsão do Tempo</h1>
<input type="text" wire:model.debounce.1000ms="city"
placeholder="Digite a cidade"
class="border px-4 py-2 rounded w-full mb-4" />
@if ($weather)
<h2 class="text-xl font-semibold">{{ $city }}</h2>
<div class="flex flex-col items-center">
<img src="https://openweathermap.org/img/wn/{{ $weather['weather'][0]['icon'] }}@2x.png" alt="icone clima">
<p class="text-lg font-bold">🌡️ {{ round($weather['temp']) }}°C</p>
<p class="capitalize text-gray-600">☁️ {{ $weather['weather'][0]['description'] }}</p>
<p class="text-sm text-gray-500">💧 Umidade: {{ $weather['humidity'] }}%</p>
</div>
<h3 class="mt-6 text-lg font-bold">Próximas horas</h3>
<div class="grid grid-cols-3 gap-4 mt-3 text-sm">
@foreach ($hourly as $hour)
<div class="bg-gray-100 rounded p-2">
<p>{{ \Carbon\Carbon::createFromTimestamp($hour['dt'])->format('H:i') }}</p>
<img src="https://openweathermap.org/img/wn/{{ $hour['weather'][0]['icon'] }}.png" class="mx-auto">
<p>{{ round($hour['temp']) }}°C</p>
</div>
@endforeach
</div>
<h3 class="mt-6 text-lg font-bold">📍 Mapa</h3>
<iframe
width="100%"
height="250"
class="rounded mt-2"
frameborder="0"
scrolling="no"
marginheight="0"
marginwidth="0"
src="https://maps.google.com/maps?q={{ urlencode($city) }}&t=&z=10&ie=UTF8&iwloc=&output=embed">
</iframe>
@else
<p class="text-red-500">Não foi possível obter a previsão para "{{ $city }}"</p>
@endif
</div>
5. 🛣️ Use o componente em uma página Blade
Crie resources/views/weather.blade.php:
@extends('layouts.app')
@section('content')
@livewire('weather-forecast')
@endsection
6. 📄 Adicione a rota
Em routes/web.php:
Route::get('/clima', function () {
return view('weather');
});
7. 🧩 Inclua Livewire no layout base (layouts/app.blade.php)
No <head>:
@livewireStyles
Antes de fechar </body>:
@livewireScripts
✅ Pronto! Agora:
-
A previsão do tempo é atualizada reativamente ao digitar a cidade.
-
Mostra ícone do clima atual, previsão para 6 horas e mapa da cidade.
-
Pode ser expandido para incluir previsão diária, radar, alertas, etc.
Ótimo! Vamos criar uma versão mais avançada e estilizada do componente com:
✅ Recursos adicionais:
-
Previsão para os próximos 5 dias
-
Livewire reativo (sem recarregar a página)
-
Ícones de clima
-
Gráfico simples (temperatura máxima/mínima por dia)
-
Estilo com Tailwind CSS
-
Mapa da cidade
🧠 Atualização do componente Livewire
app/Livewire/WeatherForecast.php
Atualize o componente para buscar também a previsão diária:
namespace App\Livewire;
use Livewire\Component;
use Illuminate\Support\Facades\Http;
class WeatherForecast extends Component
{
public $city = 'São Paulo';
public $weather;
public $daily = [];
public function mount()
{
$this->fetchWeather();
}
public function updatedCity()
{
$this->fetchWeather();
}
public function fetchWeather()
{
$apiKey = env('OPENWEATHER_API_KEY');
$geo = Http::get('http://api.openweathermap.org/geo/1.0/direct', [
'q' => $this->city,
'limit' => 1,
'appid' => $apiKey,
])->json();
if (empty($geo)) {
$this->weather = null;
$this->daily = [];
return;
}
$lat = $geo[0]['lat'];
$lon = $geo[0]['lon'];
$response = Http::get("https://api.openweathermap.org/data/2.5/onecall", [
'lat' => $lat,
'lon' => $lon,
'exclude' => 'minutely,hourly,alerts',
'units' => 'metric',
'appid' => $apiKey,
'lang' => 'pt_br',
]);
if ($response->successful()) {
$data = $response->json();
$this->weather = $data['current'];
$this->daily = array_slice($data['daily'], 0, 5);
} else {
$this->weather = null;
$this->daily = [];
}
}
public function render()
{
return view('livewire.weather-forecast');
}
}
🖼️ View com Estilo + Gráfico
resources/views/livewire/weather-forecast.blade.php
<div class="max-w-3xl mx-auto mt-10 p-6 bg-white shadow-lg rounded-xl">
<h1 class="text-3xl font-bold text-center mb-6">🌤️ Previsão do Tempo</h1>
<input type="text" wire:model.debounce.1000ms="city"
placeholder="Digite a cidade"
class="border border-gray-300 px-4 py-2 rounded w-full mb-4 shadow-sm focus:ring focus:ring-blue-200" />
@if ($weather)
<div class="text-center">
<h2 class="text-2xl font-semibold">{{ $city }}</h2>
<img src="https://openweathermap.org/img/wn/{{ $weather['weather'][0]['icon'] }}@2x.png" class="mx-auto">
<p class="text-lg font-bold">🌡️ {{ round($weather['temp']) }}°C</p>
<p class="capitalize text-gray-600">☁️ {{ $weather['weather'][0]['description'] }}</p>
<p class="text-sm text-gray-500">💧 Umidade: {{ $weather['humidity'] }}%</p>
</div>
<div class="mt-6">
<h3 class="text-xl font-bold mb-2">🗓️ Previsão para os próximos 5 dias</h3>
<div class="grid grid-cols-1 md:grid-cols-5 gap-4 text-center">
@foreach ($daily as $day)
<div class="bg-blue-50 rounded-lg p-3 shadow-sm">
<p class="font-medium">{{ \Carbon\Carbon::createFromTimestamp($day['dt'])->translatedFormat('D d/M') }}</p>
<img src="https://openweathermap.org/img/wn/{{ $day['weather'][0]['icon'] }}.png" class="mx-auto">
<p class="text-sm capitalize">{{ $day['weather'][0]['description'] }}</p>
<p class="text-sm">🌡️ Máx: {{ round($day['temp']['max']) }}°C</p>
<p class="text-sm">🌡️ Mín: {{ round($day['temp']['min']) }}°C</p>
</div>
@endforeach
</div>
</div>
<div class="mt-8">
<h3 class="text-xl font-bold mb-2">📍 Localização</h3>
<iframe
width="100%"
height="250"
class="rounded-lg shadow"
frameborder="0"
scrolling="no"
marginheight="0"
marginwidth="0"
src="https://maps.google.com/maps?q={{ urlencode($city) }}&t=&z=10&ie=UTF8&iwloc=&output=embed">
</iframe>
</div>
@elseif(strlen($city) > 2)
<p class="text-red-500 text-center">❌ Não foi possível encontrar "{{ $city }}"</p>
@endif
</div>
🎯 Resultado:
-
⚡ Reativo: digite o nome da cidade → tudo se atualiza automaticamente
-
📅 Previsão diária (5 dias)
-
🌐 Mapa do Google Maps
-
☁️ Ícones climáticos + descrições
-
🎨 Layout bonito com Tailwind
Perfeito! Vamos adicionar agora um gráfico interativo de temperatura (máx e mín) para os próximos 5 dias usando Chart.js, integrado com Livewire.
🎯 Objetivo
-
Mostrar a temperatura máxima e mínima por dia em um gráfico de linha usando Chart.js
-
O gráfico será atualizado automaticamente ao trocar a cidade
🧩 Passos
1. 📦 Adicione Chart.js
No seu Blade principal (ex: resources/views/layouts/app.blade.php ou diretamente no componente), inclua:
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
2. 🧠 Atualize o componente Blade
resources/views/livewire/weather-forecast.blade.php (adicione isso após a previsão de 5 dias)
<div class="mt-10">
<h3 class="text-xl font-bold mb-2">📊 Gráfico de Temperaturas</h3>
<canvas id="tempChart" height="150"></canvas>
</div>
@push('scripts')
<script>
document.addEventListener('livewire:load', () => {
let chart;
Livewire.hook('message.processed', (message, component) => {
const daily = @json($daily);
const labels = daily.map(d => {
const date = new Date(d.dt * 1000);
return date.toLocaleDateString('pt-BR', { weekday: 'short', day: 'numeric' });
});
const maxTemps = daily.map(d => d.temp.max);
const minTemps = daily.map(d => d.temp.min);
const data = {
labels: labels,
datasets: [
{
label: 'Máxima °C',
data: maxTemps,
borderColor: 'rgb(255, 99, 132)',
fill: false,
tension: 0.2
},
{
label: 'Mínima °C',
data: minTemps,
borderColor: 'rgb(54, 162, 235)',
fill: false,
tension: 0.2
}
]
};
const config = {
type: 'line',
data: data,
options: {
responsive: true,
plugins: {
legend: {
position: 'top'
},
title: {
display: false
}
}
},
};
// destrói gráfico antigo se houver
if (chart) chart.destroy();
const ctx = document.getElementById('tempChart').getContext('2d');
chart = new Chart(ctx, config);
});
});
</script>
@endpush
Resultado 🎉
Você verá:
-
✅ Previsão detalhada em cards
-
✅ Google Maps embutido
-
✅ Gráfico de temperatura com linhas suaves e cores distintas
-
✅ Atualização automática via Livewire
Fim e boa sorte!
Donate to Site
Renato
Developer