24-Hour Temperature Timeline with rain probability chart
Neste tutorial vamos usar os primeiros 8 itens do endpoint /forecast (24 horas, cada um com 3h de intervalo) para construir um grafico de linha de temperatura e barras de probabilidade de chuva. SVG puro, sem bibliotecas.
In this tutorial we'll use the first 8 items from the /forecast endpoint (24 hours, each 3h apart) to build a temperature line chart and rain probability bars. Pure SVG, no libraries.
O endpoint /forecast retorna uma lista de previsoes a cada 3 horas. Os primeiros 8 itens cobrem as proximas 24 horas.
The /forecast endpoint returns a list of forecasts every 3 hours. The first 8 items cover the next 24 hours.
const API_KEY = 'YOUR_API_KEY';
const BASE = 'https://weather.api.insyde.one';
async function fetchForecast(city) {
const qs = new URLSearchParams({ q: city, units: 'metric', key: API_KEY });
const res = await fetch(`${BASE}/forecast?${qs}`);
return res.json();
}
const data = await fetchForecast('São Paulo,BR');
// First 8 items = next 24 hours (3h intervals)
const next24h = data.list.slice(0, 8);
// Extract temperature and rain probability
const points = next24h.map(item => ({
time: item.dt_txt.slice(11, 16), // "06:00"
temp: Math.round(item.main.temp), // 22
pop: Math.round(item.pop * 100) // 10 (percentage)
}));
Para desenhar a linha de temperatura, mapeamos os valores de temp para coordenadas Y dentro de um viewBox SVG. Usamos <polyline> para conectar os pontos e um <linearGradient> para a area preenchida abaixo da linha.
To draw the temperature line, we map temp values to Y coordinates within an SVG viewBox. We use <polyline> to connect the points and a <linearGradient> for the filled area below the line.
const svgW = 700, svgH = 200;
const padL = 40, padR = 20, padT = 30, padB = 30;
const chartW = svgW - padL - padR;
const chartH = svgH - padT - padB;
// Find temp range for Y scaling
const temps = points.map(p => p.temp);
const minT = Math.floor(Math.min(...temps) / 4) * 4;
const maxT = Math.ceil(Math.max(...temps) / 4) * 4;
// Map data to SVG coordinates
function toX(i) { return padL + (i / 7) * chartW; }
function toY(temp) {
return padT + (1 - (temp - minT) / (maxT - minT)) * chartH;
}
// Build polyline points string
const linePoints = points
.map((p, i) => `${toX(i)},${toY(p.temp)}`)
.join(' ');
// Build filled area polygon (line + bottom corners)
const areaPoints = linePoints
+ ` ${toX(7)},${padT + chartH} ${toX(0)},${padT + chartH}`;
Abaixo do grafico SVG de temperatura, adicionamos barras horizontais para a probabilidade de chuva (pop). A altura e proporcional a porcentagem, e a opacidade do azul indica a intensidade.
Below the SVG temperature chart, we add bars for rain probability (pop). The height is proportional to the percentage, and the blue opacity indicates intensity.
function buildRainBars(points) {
const maxH = 60; // max bar height in px
return points.map(p => {
const h = (p.pop / 100) * maxH;
const opacity = 0.3 + (p.pop / 100) * 0.7;
return `<div class="rain-col">
<span class="rain-pct">${p.pop}%</span>
<div class="rain-bar" style="
height: ${h}px;
background: rgba(59,130,246,${opacity});
"></div>
<span class="rain-time">${p.time}</span>
</div>`;
}).join('');
}
Juntando tudo: buscamos a previsao, extraimos os 8 primeiros itens, desenhamos a polyline SVG para temperatura e as barras de chuva abaixo.
Putting it all together: fetch the forecast, extract the first 8 items, draw the SVG polyline for temperature and the rain bars below.
async function renderTimeline(city) {
const data = await fetchForecast(city);
const next24h = data.list.slice(0, 8);
const points = next24h.map(item => ({
time: item.dt_txt.slice(11, 16),
temp: Math.round(item.main.temp),
pop: Math.round(item.pop * 100)
}));
// Temperature range
const temps = points.map(p => p.temp);
const minT = Math.floor(Math.min(...temps) / 4) * 4;
const maxT = Math.ceil(Math.max(...temps) / 4) * 4;
const svgW = 700, svgH = 200;
const padL = 40, padR = 20, padT = 30, padB = 30;
const chartW = svgW - padL - padR;
const chartH = svgH - padT - padB;
function toX(i) { return padL + (i / 7) * chartW; }
function toY(t) { return padT + (1 - (t - minT) / (maxT - minT)) * chartH; }
const linePoints = points.map((p, i) =>
`${toX(i)},${toY(p.temp)}`
).join(' ');
const areaPoints = linePoints
+ ` ${toX(7)},${padT + chartH} ${toX(0)},${padT + chartH}`;
// Build SVG + rain bars HTML
const html = `...SVG and rain bars markup...`;
document.getElementById('content').innerHTML = html;
}
renderTimeline('São Paulo,BR');
O demo acima mostra o resultado final com dados reais de Sao Paulo. A linha azul conecta os 8 pontos de temperatura e a area preenchida com gradiente reforça a variacao termica. As barras de chuva abaixo usam opacidade variavel para indicar a intensidade.
The demo above shows the final result with realistic Sao Paulo data. The blue line connects the 8 temperature points and the gradient-filled area reinforces the thermal variation. The rain bars below use variable opacity to indicate intensity.