Projekat Logo kreator: generator logoa u JavaScript-u

Lekcija 16 od 17 · HTML, CSS i JavaScript

Srce sajta: strana na kojoj korisnik upiše naziv, izabere boju, oblik i font i odmah vidi svoj logo, a zatim ga preuzme kao sliku. Logo crtamo kao SVG – vektorsku sliku koja se pravi od HTML-olikih elemenata, pa je JavaScript menja isto kao ostatak stranice.

Pre nego što počneš: potrebno predznanje – stilovi naslovne strane, DOM i događaji.
Kako da učiš: zadatke na kraju prvo uradi sam/a u svom editoru; uputstvo i rešenje otvori tek posle toga. Svaki primer ima kod i živi rezultat ispod njega; kod prekucaj u svoj fajl i menjaj ga.

SVG: slika napisana kodom

<svg viewBox="0 0 300 120" width="300" style="border:1px solid #ccc">
  <circle cx="60" cy="60" r="45" fill="#dd0022" />                  <!-- krug: centar i poluprečnik -->
  <rect x="120" y="20" width="70" height="70" rx="12" fill="#1f5f91" /> <!-- pravougaonik, rx = zaobljenje -->
  <polygon points="250,15 290,60 250,105 210,60" fill="#2a9d5c" />   <!-- mnogougao: niz tačaka -->
  <text x="60" y="72" text-anchor="middle" font-size="32" font-weight="bold" fill="white">SP</text>
</svg>

Rezultat:

ElementAtributi
<svg viewBox="0 0 300 120">„platno“ od 300×120 jedinica; slika se uvećava bez gubitka oštrine
circlecx, cy – centar, r – poluprečnik
rectx, y – gornji levi ugao, width, height, rx
polygonpoints – parovi koordinata
textx, y, text-anchor="middle" – centriran oko x
fillboja popune

Koordinatni sistem je kao u matematici, ali y raste naniže – tačka (0, 0) je gornji levi ugao. Isti sistem koriste i Processing i Python turtle/pygame.

Strana generator.html

Levo je forma (Bootstrap), desno prazan div id="prikaz" u koji JavaScript crta logo:

<!DOCTYPE html>
<html lang="sr">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>Generator – Logo Kreator</title>
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css">
  <link rel="stylesheet" href="css/main.css">
</head>
<body class="bg-light">
  <div class="container py-4">
    <h1 class="h3 mb-4"><a href="naslovna.html" class="text-decoration-none">Logo Kreator</a> · generator</h1>
    <div class="row g-4">
      <!-- levo: izbor -->
      <form id="forma" class="col-md-5">
        <div class="mb-3">
          <label for="naziv" class="form-label">Naziv</label>
          <input id="naziv" class="form-control" maxlength="20" value="Logo">
        </div>
        <div class="mb-3">
          <label for="slogan" class="form-label">Slogan (nije obavezan)</label>
          <input id="slogan" class="form-control" maxlength="30">
        </div>
        <div class="row g-2 mb-3">
          <div class="col">
            <label for="boja" class="form-label">Boja</label>
            <input id="boja" type="color" class="form-control form-control-color w-100" value="#dd0022">
          </div>
          <div class="col">
            <label for="oblik" class="form-label">Oblik</label>
            <select id="oblik" class="form-select">
              <option value="krug">krug</option>
              <option value="kvadrat">kvadrat</option>
              <option value="romb">romb</option>
            </select>
          </div>
        </div>
        <div class="mb-3">
          <label for="font" class="form-label">Font</label>
          <select id="font" class="form-select">
            <option value="Arial, sans-serif">Arial</option>
            <option value="Georgia, serif">Georgia</option>
            <option value="'Courier New', monospace">Courier New</option>
          </select>
        </div>
        <button type="button" id="preuzmiSvg" class="btn btn-danger">Preuzmi SVG</button>
        <button type="button" id="preuzmiPng" class="btn btn-outline-danger">Preuzmi PNG</button>
      </form>
      <!-- desno: živi prikaz -->
      <div class="col-md-7 text-center">
        <div id="prikaz" class="p-3 bg-white rounded shadow-sm"></div>
      </div>
    </div>
  </div>
  <script src="js/generator.js"></script>
</body>
</html>

JavaScript: crtanje i živi prikaz

// ===== js/generator.js – Logo Kreator =====
const NS = "http://www.w3.org/2000/svg";       // SVG elementi se prave sa ovim "imenskim prostorom"
const polja = ["naziv", "slogan", "boja", "oblik", "font"].map(id => document.getElementById(id));
const [naziv, slogan, boja, oblik, font] = polja;
const prikaz = document.getElementById("prikaz");

// 1. naziv iz adrese: generator.html?naziv=Sekcija+Pupin (šalje ga forma sa naslovne)
const izAdrese = new URLSearchParams(location.search).get("naziv");
if (izAdrese) naziv.value = izAdrese.slice(0, 20);

// pomoćna funkcija: napravi SVG element sa atributima
function el(ime, atributi) {
  const e = document.createElementNS(NS, ime);
  for (const [k, v] of Object.entries(atributi)) e.setAttribute(k, v);
  return e;
}

// inicijali: "Sekcija Pupin" -> "SP", "Logo" -> "LO"
function inicijali(tekst) {
  const reci = tekst.trim().split(/\s+/).filter(r => r.length > 0);
  if (reci.length === 0) return "?";
  if (reci.length === 1) return reci[0].slice(0, 2).toUpperCase();
  return (reci[0][0] + reci[1][0]).toUpperCase();
}

// 2. nacrtaj logo iz trenutnih vrednosti polja
function nacrtaj() {
  const svg = el("svg", { xmlns: NS, viewBox: "0 0 400 200", width: "100%" });
  svg.id = "logo";
  const b = boja.value;

  // znak (levo)
  if (oblik.value === "krug") svg.append(el("circle", { cx: 100, cy: 100, r: 70, fill: b }));
  else if (oblik.value === "kvadrat") svg.append(el("rect", { x: 30, y: 30, width: 140, height: 140, rx: 24, fill: b }));
  else svg.append(el("polygon", { points: "100,25 175,100 100,175 25,100", fill: b }));

  const slova = el("text", { x: 100, y: 116, "text-anchor": "middle", "font-size": 46, "font-weight": "bold",
                             "font-family": font.value, fill: "#fff" });
  slova.textContent = inicijali(naziv.value);
  svg.append(slova);

  // naziv i slogan (desno)
  // veličina slova se smanjuje za duži naziv, da stane u preostalih ~200 jedinica širine
  const velicina = Math.min(34, Math.floor(200 / (0.6 * Math.max(naziv.value.length, 1))));
  const ime = el("text", { x: 195, y: slogan.value ? 100 : 112, "font-size": velicina, "font-weight": "bold",
                           "font-family": font.value, fill: "#222" });
  ime.textContent = naziv.value || "Logo";
  svg.append(ime);
  if (slogan.value) {
    const s = el("text", { x: 197, y: 132, "font-family": font.value, fill: b,
                           "font-size": Math.min(18, Math.floor(200 / (0.55 * slogan.value.length))) });
    s.textContent = slogan.value;
    svg.append(s);
  }

  prikaz.replaceChildren(svg);   // zameni stari logo novim
}

// 3. svaka promena u bilo kom polju odmah ponovo crta logo
for (const p of polja) p.addEventListener("input", nacrtaj);
nacrtaj();
IdejaGde u kodu
naziv sa naslovne strane stiže u adresi (?naziv=...) i čita se sa URLSearchParamskorak 1
SVG elementi se prave sa createElementNS (obični createElement ne radi za SVG)funkcija el
sav izgled zavisi od vrednosti polja – funkcija nacrtaj svaki put pravi logo iz početkakorak 2
događaj input na svim poljima → logo se menja dok kucaš ili biraš bojukorak 3
tekst se upisuje sa textContent – bezbedno (lekcija DOM i događaji)slova, ime, s

Preuzimanje slike: SVG i PNG

// 4. preuzimanje
function imeFajla(ekstenzija) {
  return (naziv.value.trim() || "logo").toLowerCase().replace(/[^a-z0-9]+/g, "_") + "." + ekstenzija;
}

function preuzmi(url, ime) {                 // privremeni link koji "kliknemo" iz koda
  const a = document.createElement("a");
  a.href = url;
  a.download = ime;
  a.click();
}

function svgTekst() {
  return new XMLSerializer().serializeToString(document.getElementById("logo"));
}

document.getElementById("preuzmiSvg").addEventListener("click", () => {
  const blob = new Blob([svgTekst()], { type: "image/svg+xml" });
  const url = URL.createObjectURL(blob);
  preuzmi(url, imeFajla("svg"));
  URL.revokeObjectURL(url);
});

document.getElementById("preuzmiPng").addEventListener("click", () => {
  const slika = new Image();
  slika.onload = () => {
    const platno = document.createElement("canvas");   // SVG -> crtež na platnu -> PNG
    platno.width = 800;
    platno.height = 400;
    const ctx = platno.getContext("2d");
    ctx.fillStyle = "#fff";
    ctx.fillRect(0, 0, 800, 400);
    ctx.drawImage(slika, 0, 0, 800, 400);
    preuzmi(platno.toDataURL("image/png"), imeFajla("png"));
  };
  slika.src = "data:image/svg+xml;charset=utf-8," + encodeURIComponent(svgTekst());
});
FormatKako nastajeKada
SVGtekst SVG elementa (XMLSerializer) → Blob (fajl u memoriji) → link sa atributom downloadza štampu i velike formate – oštar u svakoj veličini
PNGSVG se učita kao slika, nacrta na canvas dvostruke veličine i pretvori u PNGza profilnu sliku, dokumente, društvene mreže

Ime fajla nastaje iz naziva: mala slova, a sve što nije slovo ili cifra postaje _ („Sekcija Pupin“ → sekcija_pupin.png).

Probaj generator

Ceo generator (HTML + JavaScript) radi u okviru ispod. Promeni naziv, slogan, boju, oblik i font. Preuzimanje u ovom okviru je zbog bezbednosti isključeno – radi kada stranu otvoriš kao svoj fajl.

<!DOCTYPE html>
<html lang="sr">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>Generator – Logo Kreator</title>
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css">
  <link rel="stylesheet" href="css/main.css">
</head>
<body class="bg-light">
  <div class="container py-4">
    <h1 class="h3 mb-4"><a href="naslovna.html" class="text-decoration-none">Logo Kreator</a> · generator</h1>
    <div class="row g-4">
      <!-- levo: izbor -->
      <form id="forma" class="col-md-5">
        <div class="mb-3">
          <label for="naziv" class="form-label">Naziv</label>
          <input id="naziv" class="form-control" maxlength="20" value="Logo">
        </div>
        <div class="mb-3">
          <label for="slogan" class="form-label">Slogan (nije obavezan)</label>
          <input id="slogan" class="form-control" maxlength="30">
        </div>
        <div class="row g-2 mb-3">
          <div class="col">
            <label for="boja" class="form-label">Boja</label>
            <input id="boja" type="color" class="form-control form-control-color w-100" value="#dd0022">
          </div>
          <div class="col">
            <label for="oblik" class="form-label">Oblik</label>
            <select id="oblik" class="form-select">
              <option value="krug">krug</option>
              <option value="kvadrat">kvadrat</option>
              <option value="romb">romb</option>
            </select>
          </div>
        </div>
        <div class="mb-3">
          <label for="font" class="form-label">Font</label>
          <select id="font" class="form-select">
            <option value="Arial, sans-serif">Arial</option>
            <option value="Georgia, serif">Georgia</option>
            <option value="'Courier New', monospace">Courier New</option>
          </select>
        </div>
        <button type="button" id="preuzmiSvg" class="btn btn-danger">Preuzmi SVG</button>
        <button type="button" id="preuzmiPng" class="btn btn-outline-danger">Preuzmi PNG</button>
      </form>
      <!-- desno: živi prikaz -->
      <div class="col-md-7 text-center">
        <div id="prikaz" class="p-3 bg-white rounded shadow-sm"></div>
      </div>
    </div>
  </div>
  <script>
// ===== js/generator.js – Logo Kreator =====
const NS = "http://www.w3.org/2000/svg";       // SVG elementi se prave sa ovim "imenskim prostorom"
const polja = ["naziv", "slogan", "boja", "oblik", "font"].map(id => document.getElementById(id));
const [naziv, slogan, boja, oblik, font] = polja;
const prikaz = document.getElementById("prikaz");

// 1. naziv iz adrese: generator.html?naziv=Sekcija+Pupin (šalje ga forma sa naslovne)
const izAdrese = new URLSearchParams(location.search).get("naziv");
if (izAdrese) naziv.value = izAdrese.slice(0, 20);

// pomoćna funkcija: napravi SVG element sa atributima
function el(ime, atributi) {
  const e = document.createElementNS(NS, ime);
  for (const [k, v] of Object.entries(atributi)) e.setAttribute(k, v);
  return e;
}

// inicijali: "Sekcija Pupin" -> "SP", "Logo" -> "LO"
function inicijali(tekst) {
  const reci = tekst.trim().split(/\s+/).filter(r => r.length > 0);
  if (reci.length === 0) return "?";
  if (reci.length === 1) return reci[0].slice(0, 2).toUpperCase();
  return (reci[0][0] + reci[1][0]).toUpperCase();
}

// 2. nacrtaj logo iz trenutnih vrednosti polja
function nacrtaj() {
  const svg = el("svg", { xmlns: NS, viewBox: "0 0 400 200", width: "100%" });
  svg.id = "logo";
  const b = boja.value;

  // znak (levo)
  if (oblik.value === "krug") svg.append(el("circle", { cx: 100, cy: 100, r: 70, fill: b }));
  else if (oblik.value === "kvadrat") svg.append(el("rect", { x: 30, y: 30, width: 140, height: 140, rx: 24, fill: b }));
  else svg.append(el("polygon", { points: "100,25 175,100 100,175 25,100", fill: b }));

  const slova = el("text", { x: 100, y: 116, "text-anchor": "middle", "font-size": 46, "font-weight": "bold",
                             "font-family": font.value, fill: "#fff" });
  slova.textContent = inicijali(naziv.value);
  svg.append(slova);

  // naziv i slogan (desno)
  // veličina slova se smanjuje za duži naziv, da stane u preostalih ~200 jedinica širine
  const velicina = Math.min(34, Math.floor(200 / (0.6 * Math.max(naziv.value.length, 1))));
  const ime = el("text", { x: 195, y: slogan.value ? 100 : 112, "font-size": velicina, "font-weight": "bold",
                           "font-family": font.value, fill: "#222" });
  ime.textContent = naziv.value || "Logo";
  svg.append(ime);
  if (slogan.value) {
    const s = el("text", { x: 197, y: 132, "font-family": font.value, fill: b,
                           "font-size": Math.min(18, Math.floor(200 / (0.55 * slogan.value.length))) });
    s.textContent = slogan.value;
    svg.append(s);
  }

  prikaz.replaceChildren(svg);   // zameni stari logo novim
}

// 3. svaka promena u bilo kom polju odmah ponovo crta logo
for (const p of polja) p.addEventListener("input", nacrtaj);
nacrtaj();

// 4. preuzimanje
function imeFajla(ekstenzija) {
  return (naziv.value.trim() || "logo").toLowerCase().replace(/[^a-z0-9]+/g, "_") + "." + ekstenzija;
}

function preuzmi(url, ime) {                 // privremeni link koji "kliknemo" iz koda
  const a = document.createElement("a");
  a.href = url;
  a.download = ime;
  a.click();
}

function svgTekst() {
  return new XMLSerializer().serializeToString(document.getElementById("logo"));
}

document.getElementById("preuzmiSvg").addEventListener("click", () => {
  const blob = new Blob([svgTekst()], { type: "image/svg+xml" });
  const url = URL.createObjectURL(blob);
  preuzmi(url, imeFajla("svg"));
  URL.revokeObjectURL(url);
});

document.getElementById("preuzmiPng").addEventListener("click", () => {
  const slika = new Image();
  slika.onload = () => {
    const platno = document.createElement("canvas");   // SVG -> crtež na platnu -> PNG
    platno.width = 800;
    platno.height = 400;
    const ctx = platno.getContext("2d");
    ctx.fillStyle = "#fff";
    ctx.fillRect(0, 0, 800, 400);
    ctx.drawImage(slika, 0, 0, 800, 400);
    preuzmi(platno.toDataURL("image/png"), imeFajla("png"));
  };
  slika.src = "data:image/svg+xml;charset=utf-8," + encodeURIComponent(svgTekst());
});
</script>
</body>
</html>

Rezultat:

Zadaci za vežbu

Za svaki zadatak postoji primer, uputstvo i rešenje. Rešenja su provereno ispravna u pregledaču.

ZADATAK 01Težina: srednje

Novi oblik: šestougao

Dodaj u generator oblik „šestougao“: novu opciju u padajućoj listi i crtanje pravilnog šestougla sa centrom u (100, 100) i poluprečnikom 72.

ZADATAK 02Težina: lako

Dugme „Iznenadi me“

Dodaj dugme koje bira nasumičnu boju, oblik i font i ponovo crta logo.

Česte greške i saveti
  • SVG elementi se prave sa document.createElementNS("http://www.w3.org/2000/svg", ...) – sa običnim createElement se ne prikazuju.
  • U SVG-u y osa raste naniže.
  • Kada JavaScript promeni vrednost polja, događaj input se ne desi – zato se posle toga ručno poziva nacrtaj().
  • Fontovi u preuzetom SVG-u zavise od računara koji ga otvara; za stalan izgled koristi PNG.

Proveri znanje

Otvori kviz

Generator logoa

1. Kako generator saznaje naziv upisan na naslovnoj strani?




2. Kojom metodom se prave SVG elementi u JavaScript-u?




3. Gde je tačka (0, 0) u SVG-u?




4. Zašto se logo ponovo crta pri svakom događaju input?