0%

🔌 JavaScript API & Bibliotēkas

JavaScript spēks izpaužas, kad to savieno ar ārējiem datiem un bibliotēkām. Šeit iepazīsim Chart.js vizualizāciju, publiskos REST API, kā arī praktiskus Fetch API piemērus, ko var izmantot jebkurā mājaslapā.

javascript

Kas ir REST API?

REST API (Representational State Transfer) ir veids, kā serveri komunicē — atbild uz HTTP pieprasījumiem ar JSON datiem. Tieši to izmanto Fetch API, ko mācījāmies iepriekšējā nodaļā.

Teksts
// Pamatprincips: nosūti HTTP pieprasījumu → saņem JSON atbildi
fetch("https://api.example.com/products")
    .then(res => res.json())
    .then(data => console.log(data));

// Tipiska JSON atbilde no REST API:
// {
//   "status": "success",
//   "data": [
//     { "id": 1, "name": "Produkts A", "price": 12.99 },
//     { "id": 2, "name": "Produkts B", "price": 8.50 }
//   ],
//   "total": 2
// }

Noderīgi bezmaksas publiskie API

Šie API ir pieejami bez reģistrācijas vai ar bezmaksas plānu — ideāli mācībām un nelieliem projektiem.

📡 Datu un satura API

  • OpenWeatherMap — laika prognoze pēc pilsētas vai koordinātām. Bezmaksas: 1000 pieprasījumi/dienā.
  • REST Countries — valstu dati (karogi, iedzīvotāji, valūta, valodas). Bez API atslēgas.
  • JSONPlaceholder — viltus REST API testēšanai (posts, users, todos). Bez atslēgas.
  • DummyJSON — produkti, lietotāji, receptes, komentāri. Pilnīgāks par JSONPlaceholder.
  • Quotable — gadījuma citāti. Ātri pieviest dinamisku saturu.
  • NewsAPI — jaunumi no 70 000+ avotiem. Bezmaksas izstrādātāja plāns.
  • ExchangeRate API — valūtas kursi reāllaikā. 1500 pieprasījumi/mēnesī bez maksas.
  • GIPHY — GIF meklēšana un iegūšana.

Chart.js — datu vizualizācija

Chart.js ir viena no populārākajām JS bibliotēkām grafikiem — viegla (~60KB), bez atkarībām, darbojas uz HTML <canvas> elementa.

Teksts
<!-- Iekļaut Chart.js no CDN -->
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
<canvas id="manis-grafiks" width="600" height="300"></canvas>

const ctx = document.getElementById("manis-grafiks").getContext("2d");

new Chart(ctx, {
    type: "bar",   // "bar" | "line" | "pie" | "doughnut" | "radar" | "polarArea"
    data: {
        labels: ["Jan", "Feb", "Mar", "Apr", "Mai", "Jun"],
        datasets: [{
            label: "Apmeklējumi",
            data: [1200, 1900, 1500, 2100, 1800, 2400],
            backgroundColor: [
                "rgba(220, 107, 47, 0.7)",   // Webpamati.lv oranžs
                "rgba(220, 107, 47, 0.6)",
                "rgba(220, 107, 47, 0.5)",
                "rgba(220, 107, 47, 0.8)",
                "rgba(220, 107, 47, 0.6)",
                "rgba(220, 107, 47, 0.9)",
            ],
            borderColor: "#dc6b2f",
            borderWidth: 2,
            borderRadius: 6,      // Noapaļoti stabiņi
        }]
    },
    options: {
        responsive: true,
        plugins: {
            legend: { position: "top" },
            title: {
                display: true,
                text: "Mājaslapas apmeklējumi 2025. gadā"
            }
        },
        scales: {
            y: { beginAtZero: true }
        }
    }
});

const ctx2 = document.getElementById("liniju-grafiks").getContext("2d");

// Dati no API — piemēram, no sava PHP backend
async function ieladeGrafiku() {
    const resp = await fetch("/api/statistika?gads=2025");
    const json = await resp.json();

    new Chart(ctx2, {
        type: "line",
        data: {
            labels: json.menesi,   // ["Jan", "Feb", ...]
            datasets: [
                {
                    label: "Jauni lietotāji",
                    data: json.jaunie,
                    borderColor: "#3b82f6",
                    backgroundColor: "rgba(59,130,246,0.1)",
                    tension: 0.4,   // Izliekta līnija
                    fill: true,
                },
                {
                    label: "Atgriežošies",
                    data: json.atgriesosies,
                    borderColor: "#dc6b2f",
                    backgroundColor: "rgba(220,107,47,0.1)",
                    tension: 0.4,
                    fill: true,
                }
            ]
        },
        options: {
            responsive: true,
            interaction: {
                mode: "index",        // Parāda visus datus uz hover
                intersect: false
            }
        }
    });
}

ieladeGrafiku();

new Chart(document.getElementById("pirags").getContext("2d"), {
    type: "doughnut",
    data: {
        labels: ["PHP", "JavaScript", "Python", "MySQL"],
        datasets: [{
            data: [35, 28, 22, 15],
            backgroundColor: ["#f97316", "#eab308", "#3b82f6", "#22c55e"],
            hoverOffset: 8
        }]
    },
    options: {
        plugins: {
            legend: { position: "right" },
            title: { display: true, text: "Populārākās valodas Webpamati.lv" }
        }
    }
});

// Grafiku var atjaunināt reāllaikā bez pārlādēšanas
const grafiks = new Chart(ctx, { type: "bar", data: { labels: [], datasets: [{ data: [] }] } });

function pievieno_punktu(label, vertiba) {
    grafiks.data.labels.push(label);
    grafiks.data.datasets[0].data.push(vertiba);

    // Maksimāli rāda 10 vērtības
    if (grafiks.data.labels.length > 10) {
        grafiks.data.labels.shift();
        grafiks.data.datasets[0].data.shift();
    }

    grafiks.update();   // Animēts atjauninājums
}

// Simulēt reāllaika datus
setInterval(() => {
    const tagad = new Date().toLocaleTimeString("lv");
    pievieno_punktu(tagad, Math.floor(Math.random() * 100));
}, 1000);

OpenWeatherMap API — laika apgabals

Teksts
// 1. Reģistrēties: openweathermap.org → bezmaksas API atslēga
// 2. Pieprasījuma URL:
//    https://api.openweathermap.org/data/2.5/weather?q=Riga&appid=TAVA_ATSLEGA&units=metric&lang=lv

async function iegutLaiku(pilseta) {
    const API_ATSLEGA = "tava_api_atslega_seit";   // Nekad neglabā frontendā publiskā projektā!
    const url = `https://api.openweathermap.org/data/2.5/weather?q=${pilseta}&appid=${API_ATSLEGA}&units=metric&lang=lv`;

    try {
        const atbilde = await fetch(url);
        if (!atbilde.ok) throw new Error(`HTTP kļūda: ${atbilde.status}`);

        const dati = await atbilde.json();

        return {
            pilseta:     dati.name,
            temp:        Math.round(dati.main.temp),
            juta_ka:     Math.round(dati.main.feels_like),
            mitrums:     dati.main.humidity,
            apraksts:    dati.weather[0].description,
            ikona:       `https://openweathermap.org/img/wn/${dati.weather[0].icon}@2x.png`,
            vejs:        dati.wind.speed,
        };
    } catch (kludas) {
        console.error("Laika datu kļūda:", kludas);
        return null;
    }
}

// Lietošana
iegutLaiku("Riga").then(laiks => {
    if (!laiks) return;

    document.getElementById("laika-bloks").innerHTML = `
        <img src="${laiks.ikona}" alt="${laiks.apraksts}">
        <h3>${laiks.pilseta}: ${laiks.temp}°C</h3>
        <p>${laiks.apraksts} · Jūtas kā ${laiks.juta_ka}°C</p>
        <p>💧 ${laiks.mitrums}% · 💨 ${laiks.vejs} m/s</p>
    `;
});

REST Countries — valstu dati

Bez API atslēgas — ideāli karodziņu izvēlnēm, valūtas konvertētājiem, ģeogrāfiskiem filtriem.

Teksts
// Visas valstis
const atbilde = await fetch("https://restcountries.com/v3.1/all?fields=name,flags,population,currencies,languages");
const valstis = await atbilde.json();

// Meklēt pēc nosaukuma
const latvija = await fetch("https://restcountries.com/v3.1/name/latvia");
const [lv] = await latvija.json();

console.log(lv.name.common);          // "Latvia"
console.log(lv.name.official);        // "Republic of Latvia"
console.log(lv.flags.svg);            // URL uz karodziņu
console.log(lv.population);           // 1850651
console.log(lv.currencies);           // { EUR: { name: "Euro", symbol: "€" } }

// Renderēt karodzīnu izvēlni
async function izveidoValstu­sarakstu(containerId) {
    const resp    = await fetch("https://restcountries.com/v3.1/all?fields=name,flags,cca2");
    const valstis = await resp.json();

    valstis.sort((a, b) => a.name.common.localeCompare(b.name.common));

    const izvele = document.getElementById(containerId);
    valstis.forEach(v => {
        const option = document.createElement("option");
        option.value = v.cca2;                          // "LV"
        option.textContent = `${v.flags.emoji} ${v.name.common}`;
        izvele.appendChild(option);
    });
}

izveidoValstu­sarakstu("valsts-izvele");

ExchangeRate API — valūtas kursi

Teksts
// https://api.exchangerate-api.com/v4/latest/EUR  ← bez atslēgas (older endpoint)
// Vai reģistrēties exchangerate-api.com priekš jaunākā versijas

async function konvertet(summa, no, uz) {
    const resp  = await fetch(`https://api.exchangerate-api.com/v4/latest/${no}`);
    const dati  = await resp.json();
    const kurss = dati.rates[uz];
    return (summa * kurss).toFixed(2);
}

// Lietošana
const rezultats = await konvertet(100, "EUR", "USD");
console.log(`100 EUR = ${rezultats} USD`);

// Valūtas konvertētāja forma
document.getElementById("konvertacijas-forma").addEventListener("submit", async (e) => {
    e.preventDefault();
    const summa = parseFloat(document.getElementById("summa").value);
    const no    = document.getElementById("no-valutas").value;    // "EUR"
    const uz    = document.getElementById("uz-valutas").value;    // "GBP"

    const rezultats = await konvertet(summa, no, uz);
    document.getElementById("rezultats").textContent = `${summa} ${no} = ${rezultats} ${uz}`;
});

Pārlūka iebūvētie API

Papildu ārējiem servisiem, pārlūks pats nodrošina vairākus noderīgus API — bez interneta savienojuma.

Teksts
// ── 1. localStorage — datu glabāšana pārlūkā (paliek pēc aizvēršanas) ──
localStorage.setItem("tēma", "dark");
const tema = localStorage.getItem("tēma");   // "dark"
localStorage.removeItem("tēma");
localStorage.clear();

// Glabāt objektu (jāserializē)
const lietotajs = { vards: "Anna", valoda: "lv" };
localStorage.setItem("lietotajs", JSON.stringify(lietotajs));
const atguts = JSON.parse(localStorage.getItem("lietotajs"));

// ── 2. Geolocation API — lietotāja atrašanās vieta ──
if ("geolocation" in navigator) {
    navigator.geolocation.getCurrentPosition(
        (pozicija) => {
            const { latitude, longitude } = pozicija.coords;
            console.log(`Lat: ${latitude}, Lon: ${longitude}`);
            // Apvienot ar laika API: iegutLaiku uz koordinātām
        },
        (kludas) => console.error("Ģeolokācija liegta:", kludas.message)
    );
}

// ── 3. Clipboard API — kopēšana programmatiski ──
async function kopet(teksts) {
    try {
        await navigator.clipboard.writeText(teksts);
        console.log("Nokopēts!");
    } catch {
        console.error("Clipboard piekļuve liegta");
    }
}

// ── 4. Notification API — pārlūka paziņojumi ──
async function paziņot(virsraksts, teksts) {
    const atlauja = await Notification.requestPermission();
    if (atlauja === "granted") {
        new Notification(virsraksts, {
            body: teksts,
            icon: "/favicon.ico"
        });
    }
}

// ── 5. IntersectionObserver — elements ir redzamajā laukā ──
// Izmanto: lazy loading, animācijas uz scroll, infinite scroll

const novērotājs = new IntersectionObserver((ieraksti) => {
    ieraksti.forEach(ieraksts => {
        if (ieraksts.isIntersecting) {
            ieraksts.target.classList.add("redzams");   // Pievieno CSS klasi
            novērotājs.unobserve(ieraksts.target);      // Pārtraukt novērošanu
        }
    });
}, { threshold: 0.2 });   // 20% elementa jābūt redzamiem

// Novērot visas kartītes
document.querySelectorAll(".topic-card").forEach(el => novērotājs.observe(el));

// ── 6. Web Workers — fona aprēķini (neblocks UI) ──
// worker.js (atsevišķs fails):
// self.onmessage = (e) => {
//     const rezultats = laikietilpigs_apreklinat(e.data);
//     self.postMessage(rezultats);
// };

const workers = new Worker("worker.js");
workers.postMessage({ dati: [1, 2, 3, 4, 5] });
workers.onmessage = (e) => console.log("Rezultāts:", e.data);

Pilns piemērs: laika sīkrīks

Apvienojam OpenWeatherMap API, Geolocation API un Chart.js vienā funkcionālā komponentā.

Teksts
<div id="laika-sikriks">
  <p id="laika-stavoklis">Notiek lokācijas noteikšana...</p>
  <div id="laika-info" hidden></div>
  <canvas id="temp-grafiks" width="400" height="150" hidden></canvas>
</div>

const API_KEY = "tava_api_atslega";

async function ieladeLatika() {
    const statuss = document.getElementById("laika-stavoklis");
    statuss.textContent = "Notiek lokācijas noteikšana...";

    // 1. Iegūt koordinātas
    const pozicija = await new Promise((resolve, reject) =>
        navigator.geolocation.getCurrentPosition(resolve, reject)
    );

    const { latitude: lat, longitude: lon } = pozicija.coords;
    statuss.textContent = "Ielādē laika datus...";

    // 2. Iegūt tagadējo laiku
    const [laiksResp, prognozeResp] = await Promise.all([
        fetch(`https://api.openweathermap.org/data/2.5/weather?lat=${lat}&lon=${lon}&appid=${API_KEY}&units=metric&lang=lv`),
        fetch(`https://api.openweathermap.org/data/2.5/forecast?lat=${lat}&lon=${lon}&appid=${API_KEY}&units=metric&cnt=8`)
    ]);

    const laiks    = await laiksResp.json();
    const prognoze = await prognozeResp.json();

    // 3. Renderēt pašreizējo laiku
    document.getElementById("laika-info").innerHTML = `
        <h3>📍 ${laiks.name}: ${Math.round(laiks.main.temp)}°C</h3>
        <p>${laiks.weather[0].description}</p>
    `;
    document.getElementById("laika-info").hidden = false;
    statuss.hidden = true;

    // 4. Renderēt 24h temperatūras grafiku ar Chart.js
    const canvas = document.getElementById("temp-grafiks");
    canvas.hidden = false;

    new Chart(canvas.getContext("2d"), {
        type: "line",
        data: {
            labels: prognoze.list.map(p =>
                new Date(p.dt * 1000).toLocaleTimeString("lv", { hour: "2-digit", minute: "2-digit" })
            ),
            datasets: [{
                label: "Temperatūra (°C)",
                data: prognoze.list.map(p => Math.round(p.main.temp)),
                borderColor: "#dc6b2f",
                backgroundColor: "rgba(220,107,47,0.1)",
                tension: 0.4,
                fill: true
            }]
        },
        options: { responsive: true, plugins: { legend: { display: false } } }
    });
}

ieladeLatika().catch(err => {
    document.getElementById("laika-stavoklis").textContent = `Kļūda: ${err.message}`;
});