2025. április 9., szerda

Laravel 12 -vel REST API - hajomenetrend feladat megoldása

laravel new hajomenetrend

none

mysql

npm rund build

yes

.env ->adatbázis nevet javítsd

php artisan make:model Menetrend

app/Models/Menetrend.php fájl tartalma:

<?php

 

namespace App\Models;

use Illuminate\Database\Eloquent\Model;

class Menetrend extends Model

{

    protected $table = 'menetrend';

    protected $primaryKey = 'azon';

    public $timestamps = false;

    protected $fillable = ['jarat', 'honnan', 'hova', 'indul', 'erkezik'];

}

php artisan make:controller MenetrendController –api

app/Http/Controllers/MenetrendController.php:

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;

use App\Models\Menetrend;

class MenetrendController extends Controller

{

    public function index()

    {

        return Menetrend::all();

    }

    public function store(Request $request)

    {

try {

        $menet = Menetrend::create($request->only(['jarat', 'honnan', 'hova', 'indul', 'erkezik']));

        return response()->json($menet, 201);

    } catch (\Exception $e) {

        return response()->json(['error' => $e->getMessage()], 500);

    }    }

 

    public function show($azon)

    {

        return Menetrend::findOrFail($azon);

    }

 

    public function update(Request $request, $azon)

    {

        $menetrend = Menetrend::findOrFail($azon);

        $menetrend->update($request->only(['jarat', 'honnan', 'hova', 'indul', 'erkezik']));

        return response()->json($menetrend);

    }

 

    public function destroy($azon)

    {

        Menetrend::destroy($azon);

        return response()->json(['message' => 'Törölve']);

    }

}

php artisan install:api

routes/api.php fájlba:

use App\Http\Controllers\MenetrendController;

Route::apiResource('menetrend', MenetrendController::class);

Teszt:

php artisan serve

GET /api/menetrend – összes hajójárat

GET /api/menetrend/1 – 1 járat

POST /api/menetrend – új járat

{

  "jarat": "B55",

  "honnan": "Tihany",

  "hova": "Balatonfüred",

  "indul": "12:00:00",

  "erkezik": "12:45:00"

}

PUT /api/menetrend/1 – módosítás

DELETE /api/menetrend/1 – törlés

a hajómenetrend táblához hozzá kell adni, mivel az azon nem auto increment

ALTER TABLE menetrend MODIFY COLUMN azon INT NOT NULL AUTO_INCREMENT;

Laravel 12 REST API - ez jó

norway_info adatbázishoz van elkészítve

Amire szükség van hozzá:

PHP >= 8.2

Node >= 18.18.2

NPM >= 9.8.1

Composer >= 2.8.6

Laravel Installer >= 5.12.2

ellenőrizd milyen verziód van : composer self-update

pl. Composer version 2.8.8 – ez jó

ha nem akkor :

composer global remove laravel/installer

composer global update

composer global require laravel/installer

mehet mindhárom parancs egyszerre, lefrissíti

hozd létre az új projektet:

laravel new laravel-12-rest-api

amikor választani kell, hogy none, react, vue, livewire, válaszd a none-t.

none

az adatbázisoknál a mysql-t

mysql

állítsd be a .env fájlban az adatbázisod nevét

php artisan make:model Content - -migration //másolásnál töröld vissza és írd be kézzel kötőjel-kötőjelmigration

Content.php-t egészítsd ki, mert ha kimarad akkor a post tesztelés nem fog működni:

namespace App\Models;

use Illuminate\Database\Eloquent\Model;

class Content extends Model
{
    protected $table = 'contents';

    protected $fillable = ['title', 'body', 'img'];

    public $timestamps = false;
}


állítsd be a database/migrations-ben a táblád adatait

$table->id();

$table->string('title');

$table->string('body');

$table->string('img');

$table->timestamps();

Jetstream helyett így tudjuk létrehozni az api.php-t:

php artisan install:api

Controllert létrehozása:

php artisan make:controller ContentController - -api //két kötőjel egymás után az api előtt, kézzel írd be

ahol szükséges egészítsd ki:

namespace App\Http\Controllers;

use App\Models\Content;

use Illuminate\Http\Request;

use App\Http\Controllers\Controller;

 

class ContentController extends Controller

{

    public function index()

    {

        //return response()->json(Content::all());

        $contents = Content::get();

        return response()->json($contents);

    }

 

    public function store(Request $request)

    {

        /*$content = Content::create($request->only(['title', 'body', 'img']));

        return response()->json($content, 201);*/

 

        $content = new Content();

        $content->title = $request->title;

        $content->body = $request->body;

        $content->img = $request->img;

        $content->save();

        return response()->json($content);

    }

 

    public function show(string $id)

    {

        $content = Content::findOrFail($id);

        return response()->json($content);

 

       

    }

 

    public function update(Request $request, string $id)

    {

        $content = Content::findOrFail($id);

        $content->update($request->only(['title', 'body', 'img']));

        return response()->json($content);

    }

 

    public function destroy(string $id)

    {

        Content::destroy($id);

        return response()->json(['message' => 'Törölve']);

    }

}

egészítsük ki az routes/api.php fájlunkat:

use Illuminate\Http\Request;

use Illuminate\Support\Facades\Route;

use App\Http\Controllers\ContentController;

Route::get('/user', function (Request $request) {

    return $request->user();

})->middleware('auth:sanctum');

Route::apiResource('contents', ContentController::class);

mehet a tesztelés:

php artisan serve

link /api/contents 

php artisan route:list -> útvonalak végpontok

REST API PHP

 Procedurális módszerrel:

<?php

// Adatbázis kapcsolat beállításai

$host = 'localhost';

$user = 'root';

$password = '';

$dbname = 'norway_info';

 

// Kapcsolat létrehozása

$conn = new mysqli($host, $user, $password, $dbname);

 

// Kapcsolat ellenőrzése

if ($conn->connect_error) {

    die("Sikertelen kapcsolat: " . $conn->connect_error);

}

 

// Karakterkódolás beállítása

$conn->set_charset("utf8mb4");

header('Content-Type: application/json; charset=utf-8');

 

$method = $_SERVER['REQUEST_METHOD'];

$id = isset($_GET['id']) ? intval($_GET['id']) : null;

 

// JSON input feldolgozása

$inputJSON = file_get_contents('php://input');

$input = json_decode($inputJSON, true);

 

// fallback ha nem JSON jött

if (!is_array($input)) {

    $input = $_POST;

}

 

switch ($method) {

    case 'GET':

        if ($id) {

            $stmt = mysqli_prepare($conn, "SELECT * FROM contents WHERE id = ?");

            mysqli_stmt_bind_param($stmt, "i", $id);

            mysqli_stmt_execute($stmt);

            $result = mysqli_stmt_get_result($stmt);

            $data = mysqli_fetch_assoc($result);

        } else {

            $result = mysqli_query($conn, "SELECT * FROM contents");

            $data = mysqli_fetch_all($result, MYSQLI_ASSOC);

        }

        echo json_encode($data, JSON_UNESCAPED_UNICODE);

        break;

 

    case 'POST':

        if (!isset($input['title']) || !isset($input['body'])) {

            http_response_code(400);

            echo json_encode(['error' => 'title és body mező kötelező']);

            exit;

        }

        $title = $input['title'];

        $body = $input['body'];

        $img = isset($input['img']) ? $input['img'] : '';

 

        $stmt = mysqli_prepare($conn, "INSERT INTO contents (title, body, img) VALUES (?, ?, ?)");

        mysqli_stmt_bind_param($stmt, "sss", $title, $body, $img);

        mysqli_stmt_execute($stmt);

        echo json_encode(['id' => mysqli_insert_id($conn)]);

        break;

 

    case 'PUT':

        if (!$id) {

            http_response_code(400);

            echo json_encode(['error' => 'ID szükséges']);

            exit;

        }

        if (!isset($input['title']) || !isset($input['body'])) {

            http_response_code(400);

            echo json_encode(['error' => 'title és body mező kötelező']);

            exit;

        }

        $title = $input['title'];

        $body = $input['body'];

        $img = isset($input['img']) ? $input['img'] : '';

 

        $stmt = mysqli_prepare($conn, "UPDATE contents SET title=?, body=?, img=? WHERE id=?");

        mysqli_stmt_bind_param($stmt, "sssi", $title, $body, $img, $id);

        mysqli_stmt_execute($stmt);

        echo json_encode(['updated' => mysqli_stmt_affected_rows($stmt)]);

        break;

 

    case 'DELETE':

        if (!$id) {

            http_response_code(400);

            echo json_encode(['error' => 'ID szükséges']);

            exit;

        }

 

        $stmt = mysqli_prepare($conn, "DELETE FROM contents WHERE id=?");

        mysqli_stmt_bind_param($stmt, "i", $id);

        mysqli_stmt_execute($stmt);

        echo json_encode(['deleted' => mysqli_stmt_affected_rows($stmt)]);

        break;

 

    default:

        http_response_code(405);

        echo json_encode(['error' => 'Nem támogatott HTTP metódus']);

}

Egy másik megoldással:

$method = $_SERVER['REQUEST_METHOD'];

 

// PUT és DELETE esetén a nyers input feldolgozása

parse_str(file_get_contents("php://input"), $input);

 

$id = $_GET['id'] ?? null;

 

switch ($method) {

    case 'GET':

        if ($id) {

            $stmt = $conn->prepare("SELECT * FROM contents WHERE id = ?");

            $stmt->bind_param("i", $id);

        } else {

            $stmt = $conn->prepare("SELECT * FROM contents");

        }

        $stmt->execute();

        $result = $stmt->get_result();

        $data = $id ? $result->fetch_assoc() : $result->fetch_all(MYSQLI_ASSOC);

        echo json_encode($data, JSON_UNESCAPED_UNICODE);

        break;

 

    case 'POST':

        $title = $_POST['title'] ?? '';

        $body = $_POST['body'] ?? '';

        $img = $_POST['img'] ?? '';

        $stmt = $conn->prepare("INSERT INTO contents (title, body, img) VALUES (?, ?, ?)");

        $stmt->bind_param("sss", $title, $body, $img);

        $stmt->execute();

        echo json_encode(['id' => $stmt->insert_id]);

        break;

 

    case 'PUT':

        if (!$id) {

            http_response_code(400);

            echo json_encode(['error' => 'ID szükséges']);

            exit;

        }

        $title = $input['title'] ?? '';

        $body = $input['body'] ?? '';

        $img = $input['img'] ?? '';

        $stmt = $conn->prepare("UPDATE contents SET title=?, body=?, img=? WHERE id=?");

        $stmt->bind_param("sssi", $title, $body, $img, $id);

        $stmt->execute();

        echo json_encode(['updated' => $stmt->affected_rows]);

        break;

 

    case 'DELETE':

        if (!$id) {

            http_response_code(400);

            echo json_encode(['error' => 'ID szükséges']);

            exit;

        }

        $stmt = $conn->prepare("DELETE FROM contents WHERE id=?");

        $stmt->bind_param("i", $id);

        $stmt->execute();

        echo json_encode(['deleted' => $stmt->affected_rows]);

        break;

 

    default:

        http_response_code(405);

        echo json_encode(['error' => 'Nem támogatott metódus']);

}

2025. április 7., hétfő

Norway_info Laravel REST API Jetstreammel (Livewire + MySQL)

Készítsünk egy olyan Laravel REST API-t, amely egy contents nevű adatbázistábla adatait kezeli (Create, Read, Update, Delete), és amelyet Postmanből, vagy ECHO API-val lehet tesztelni autentikáció vagyis bejelentkezés nélkül.

Jetstream ajánlott, mert automatikusan létrehozza az api.php fájlt, és beállítja a projektet fejlesztésre. Ha nem szeretnél bejelentkezést, azt egyszerűen kihagyjuk a kódodból.

Telepíts egy új projektet: laravel new norway_info

válaszd ki a jetstream, livewire, mysql, és migrálás lehetőségeket. Ha valamit kihagysz utólag is telepítheted: 

cd norway_info

composer require laravel/jetstream

php artisan jetstream:install livewire

npm install && npm run dev

php artisan migrate

Jetstream + Livewire beállítja az alapstruktúrát, de az autentikációs middleware-t nem fogjuk használni az API route-oknál, mert az nem feladat jelen esetben.

Adatmodell létrehozása: 

php artisan make:model Content

A modellbe engedélyezzük a mezők tömeges kitöltését:

// app/Models/Content.php

protected $fillable = ['title', 'body', 'img'];

API Resource létrehozása:

php artisan make:resource ContentResource

A resource formázza az adatokat JSON-válaszként:

// app/Http/Resources/ContentResource.php

namespace App\Http\Resources;

use Illuminate\Http\Request;

use Illuminate\Http\Resources\Json\JsonResource;

class ContentResource extends JsonResource

{

    public function toArray(Request $request): array

    {

        return [

            'id'         => $this->id,

            'title'      => $this->title,

            'body'       => $this->body,

            'img'        => $this->img,

            'created_at' => $this->created_at,

        ];

    }

}

Controller létrehozása REST API-hoz:

php artisan make:controller ContentController - -api

// app/Http/Controllers/ContentController.php

namespace App\Http\Controllers;

use App\Models\Content;

use Illuminate\Http\Request;

use App\Http\Resources\ContentResource;

class ContentController extends Controller

{

    // 🟢 READ – Összes tartalom lekérdezése

    public function index()

    {

        return ContentResource::collection(Content::all());

    }

    // 🟢 CREATE – Új tartalom létrehozása

    public function store(Request $request)

    {

        $validated = $request->validate([

            'title' => 'required|string|max:255',

            'body'  => 'required|string',

            'img'   => 'nullable|string|max:255',

        ]);

        $content = Content::create($validated);

        return new ContentResource($content);

    }

    // 🟢 READ – Egy adott tartalom lekérdezése

    public function show($id)

    {

        return new ContentResource(Content::findOrFail($id));

    }

    // 🟡 UPDATE – Tartalom frissítése

    public function update(Request $request, $id)

    {

        $content = Content::findOrFail($id);

        $validated = $request->validate([

            'title' => 'sometimes|required|string|max:255',

            'body'  => 'sometimes|required|string',

            'img'   => 'nullable|string|max:255',

        ]);

        $content->update($validated);

        return new ContentResource($content);

    }

    // 🔴 DELETE – Tartalom törlése

    public function destroy($id)

    {

        $content = Content::findOrFail($id);

        $content->delete();

        return response()->json(['message' => 'Deleted successfully']);

    }

}

API útvonal hozzáadása (route)

// routes/api.php

use Illuminate\Support\Facades\Route;

use App\Http\Controllers\ContentController;

Route::apiResource('contents', ContentController::class);

Szerver indítás:

php artisan serve

URL: http://127.0.0.1:8000/api/contents

Post teszthez:

{

  "title": "Norvég Oktatás",

  "body": "Az oktatási rendszer ingyenes és magas színvonalú.",

  "img": "education.jpg"

}

Mi van, ha sessions hibát kapok?
Állítsd .env fájlban: SESSION_DRIVER=file
Majd: php artisan config:clear

Nem jön létre api.php?
Hozd létre kézzel: routes/api.php
Laravel automatikusan betölti.

MűveletHTTPVégpont
ListázásGET/api/contents
Egy lekérdezésGET/api/contents/{id}
LétrehozásPOST/api/contents
MódosításPUT/api/contents/{id}
TörlésDELETE/api/contents/{id}

2025. március 30., vasárnap

Norvég feladat

A feladathoz szükséges képek, minta és adatbázis elérhetősége:

https://github.com/latiza/norv-gfeladat/



2025. március 27., csütörtök

Akadálymentesített weboldalak

13.B2 - gondoljátok át, van e esetleg értelme a meglévő projektetekbe még beépíteni. Mint pl itt a Nebih oldalán is lehet látni: https://portal.nebih.gov.hu/rszkf 

12B. Feladat a lap alján, olvasd végig :-) 



az ikonra kattintás után:

nem keverendő össze a dark móddal.

Akadálymentesítés alatt azt értjük, amikor egy weboldalt úgy tervezünk meg és alakítunk ki, hogy azt mindenki – beleértve a fogyatékossággal élőket is – használni tudja.

Kiemelt célcsoport:

  • Vak felhasználók: képernyőolvasó szoftvert használnak pl. NVDA, JAWS.  Két barátom is használ felolvasó programot, ezek a felolvasó programok olyan gyorsan olvassák fel a szöveget, hogy én nem is értettem mit mond, ők „fordították le nekem” mit olvasott fel nekik a szoftver. Persze be lehet állítani a sebességet és fokozatosan szoktak hozzá.
  • Gyengénlátók: nagyítással, színkontraszttal vagy saját betűtípussal olvasnak.

A WCAG (Web Content Accessibility Guidelines) irányelvei alapján a weboldalaknak a következő négy elvnek kell megfelelniük:

Elv

Jelentés

Észlelhetőség

A tartalom érzékelhető legyen látás nélkül is (pl. hang vagy leírás formájában).

Működtethetőség

A felhasználó vezérelhessen mindent billentyűzettel is.

Érthetőség

A tartalom és navigáció legyen egyszerű és logikus.

Robusztusság

A tartalom különféle segítő technológiákkal is működjön.

A vak felhasználók gyakran fejből tanulják meg az oldal szerkezetét. Ezért is fontos a következetes elrendezés és a logikus sorrend.

További infók:

Lehetőségek:

Használj megfelelő, beszédes, leíró alternatív szöveget (alt) a képeknél:

<img src="kutyus.jpg" alt="Fehér labrador kutya egy parkban ül">

A képernyőolvasók ezt a szöveget olvassák fel!

Strukturált HTML, szemantikus elemek használata:

·       Használj szemantikus elemeket, header, nav, main, aside, footer, section, article.

·       Használj helyes címsorokat (<h1>, <h2>, stb.), listákat, űrlap elemekhez címkéket (<label>), táblázatokhoz scope attribútumot.

Navigációs elemeket ne képekkel oldd meg:

·       Használj szöveges gombokat, vagy gondoskodj arról, hogy a képnek is legyen alternatív leírása.

Ne csak vizuális utalás legyen:

·       Kerüld a „Kattints a piros gombra!” típusú utasításokat. Írd inkább: „Kattints a ‘Tovább’ feliratú gombra!”

Billentyűzet-navigáció biztosítása:

  • Ne csak egérrel legyenek elérhetők a menüpontok!
  • Használj tabindex, accesskey attribútumokat, ha szükséges.

Kontrasztarány:

A szöveg és a háttér közti kontraszt legyen legalább 4.5:1.

  • Világosszürke szöveg fehér alapon (gyenge kontraszt)
  • Sötétkék szöveg világos háttéren (jó kontraszt)

Reszponzív és nagyítható betűméret:

·       Használj relatív mértékegységeket (em, %, rem) a betűmérethez, ne px-et fixen.

Saját betűtípus beállításának lehetősége:

·       Ne tiltsd le a böngésző betűtípusainak módosítását !important utasításokkal.

·       Ne villogjon, ne mozogjon gyorsan:

·       Az animációk és villogó elemek (pl. reklámok) zavaróak lehetnek.

Tesztelő eszközök:

  • WAVE
  • axe DevTools
  • Google Chrome „Accessibility” panel (Fejlesztői eszközökben)

Gyakorlati feladat

Feladat: Hozz létre egy weboldalt, amely bemutat egy állatot, és tartalmaz:

  • Egy képet alt szöveggel
  • Egy címet és bekezdést logikus címsor struktúrával
  • Egy űrlapot név bekérésére (label használatával)
  • A HTML legyen teljesen billentyűzet-navigálható

Tedd akadálymentessé az oldalt.

Használd az akadálymentesítés ikonját:


Ha van komolyabb kész projektetek, amin szintén érdemes lenne alkalmazni, adjátok hozzá szintén az akadálymentesítési funkciót. 


UI: Régebben is találkoztam ezzel a témával, de azt, hogy mennyire fontos, akkor értettem meg igazán, amikor egy szlovén túrára 2 gyengén látó utas érkezett. Nem voltak teljesen vakok, alakokat láttak. Csak annyit kértek mutassam, meg mi merre van a hotelben, étteremben, és ők utána már kiválóan fognak tudni tájékozódni. A vacsoránál szembesültem vele, hogy azért ez nem teljesen így van, amikor hallottam, hogy beszélgetnek, hogy nem sikerült a büfé asztaltól csirkét választani. Innentől kezdve, felajánlottam menjünk együtt válogatni, és akkor nem lesz ilyen kellemetlenség. Így amikor már a városnéző programra mentünk, tudtam, hogy „akadálymentesen” kell bemutatnom a várost. Amikor egy épületről beszéltem, azt is elmondtam mit látunk pontosan. Először kicsit aggódtam, mit fog szólni a többi utas, de örömmel tapasztaltam, hogy mindenkiben tudatosult, van két gyengén látó útitársunk, és onnantól kezdve, mindenki nagyon segítőkész és figyelmes volt velük. J Így alap volt, hogy a haverom cégének a weboldalába elve beépítem az akadálymentes funkciót: https://balatonbusz.hu/




2025. március 25., kedd

Feladat: Találd ki a megyeszékhely helyét! Webalapú földrajzi kvíz Leaflet.js és AngularJS használatával

Készíts egy interaktív weboldalt, amelyen a felhasználónak az a feladata, hogy megjelölje Magyarország térképén a rendszer által véletlenszerűen kiválasztott megyeszékhely helyét. A weboldal:

  • térképet jelenít meg Leaflet segítségével,
  • adatokat olvas be egy JSON fájlból,
  • véletlenszerűen kiválaszt egy várost,
  • a felhasználó kattintásával tippet ad,
  • megmutatja az eltérés távolságát,
  • és új kérdést ad.

Szükséges technológiák

  • HTML
  • AngularJS (1.x)
  • Leaflet.js
  • OpenStreetMap
  • Alapvető JavaScript és JSON kezelés

A megye.json fájl

Hozz létre egy megye.json fájlt, amely tartalmazza a megyeszékhelyeket és azok koordinátáit:

[

    { "title": "Budapest", "coordinates": { "lat": 47.4979, "lng": 19.0402 } },

    { "title": "Debrecen", "coordinates": { "lat": 47.5316, "lng": 21.6273 } },

    { "title": "Szeged", "coordinates": { "lat": 46.2530, "lng": 20.1414 } },

    { "title": "Miskolc", "coordinates": { "lat": 48.1030, "lng": 20.7784 } },

    { "title": "Pécs", "coordinates": { "lat": 46.0727, "lng": 18.2323 } },

    { "title": "Győr", "coordinates": { "lat": 47.6875, "lng": 17.6504 } },

    { "title": "Nyíregyháza", "coordinates": { "lat": 47.9554, "lng": 21.7167 } },

    { "title": "Kecskemét", "coordinates": { "lat": 46.9062, "lng": 19.6913 } },

    { "title": "Székesfehérvár", "coordinates": { "lat": 47.1860, "lng": 18.4221 } },

    { "title": "Szombathely", "coordinates": { "lat": 47.2307, "lng": 16.6218 } },

    { "title": "Eger", "coordinates": { "lat": 47.9025, "lng": 20.3772 } },

    { "title": "Zalaegerszeg", "coordinates": { "lat": 46.8416, "lng": 16.8465 } },

    { "title": "Salgótarján", "coordinates": { "lat": 48.0982, "lng": 19.8032 } },

    { "title": "Tatabánya", "coordinates": { "lat": 47.5847, "lng": 18.3933 } },

    { "title": "Szekszárd", "coordinates": { "lat": 46.3481, "lng": 18.7045 } },

    { "title": "Békéscsaba", "coordinates": { "lat": 46.6791, "lng": 21.0877 } },

    { "title": "Veszprém", "coordinates": { "lat": 47.0933, "lng": 17.9115 } },

    { "title": "Kaposvár", "coordinates": { "lat": 46.3593, "lng": 17.7969 } }

  ]

HTML váz (index.html)

  1. Használd az alábbi könyvtárakat a <head> szakaszban:

<!-- Leaflet CSS + JS -->

<link rel="stylesheet" href="https://unpkg.com/leaflet/dist/leaflet.css" />

<script src="https://unpkg.com/leaflet/dist/leaflet.js"></script>

 

<!-- AngularJS -->

<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.8.2/angular.min.js"></script>

  1. Készíts egy alap HTML szerkezetet, amely tartalmaz:
  • adj hozzá egy .container osztályú elemet, aminek a szélessége 900px legyen, és helyezd el középen az oldalon, adhatsz hozzá keretet vagy boksz árnyékot, hogylásd sikerült e.
  • egy #map elemet a térképnek, 500px magas legyen.
  • egy gombot az új kérdéshez
  • egy szöveget a feladványhoz és eredményhez
  • ne pánikolj, mert lépésről lépésre leírok mindent, mit kell csinálnod!

AngularJS alkalmazás létrehozása

  • Készítsd el az AngularJS modult és kontrollert (quizApp, QuizController -> két paramétert kell hozzá adnod a $scope, és $http)

A függvényen belül először hozd létre a szükséges változókat:

  • Hozd létre a következő js változókat, let kulcsszóval: map, userMarker, realMarker, line
  • Hozz létre egy üres tömböt és tárold el a $scope.places változóba,
  • Hozd létre a $scope.result változót, inicializáld egy üres stringgel,
  • Hozz létre egy üres objektumot $scope.currentPlace néven.

calcDistance() függvény létrehozása:

·       A controller függvényen belül hozz létre egy új (sima) javascript függvényt calcDistance néven. Két paramétert adj neki: latlng1, latlng2.

·       A függvény visszatérési értéke latlng1.distanceTo(latlng2) legyen amit el osztasz 1000-el.

Mindkettő Leaflet LatLng objektum típusú (vagyis olyan objektum, amely tartalmaz lat és lng értékeket, pl. egy marker helyzetét).

A latlng1 és latlng2 a két pont (tipikusan L.latLng(...) objektumok).

A latlng1.distanceTo(latlng2) – ez egy Leaflet beépített metódus, amely visszaadja a két pont közötti távolságot méterben. Mivel méterben fogod megkapni, ezért kell elosztanod 1000-el, hogy kilométer értéket kapj vissza.

nextPlace() függvény

·       Hozz létre egy AngularJs függvényt, nextPlace néven, paramétert nem kell adni neki.

·       Ezt a függvényt hívd meg a html-ből az ng-click direktívával ha a user kattint a „Következő hely tippelése” gombra.

·       A függvényen belül add hozzá a $scope.result változót újra, és inicializáld üres értékkel, ez a lépés fogja a result változó előző tartalmát alaphelyzetbe állítani.

·       A böngészőben, amikor a user keresgél a térképen lehet el fogja húzni, jobbra vagy balra, és amikor új feladatot kérünk akkor jó lenne, ha vissza állna középre. Ezért egy if elágazással nézzük meg létezik e a map és ha igen akkor a map.setView([47.1625, 19.5033], 7); értékkel térjen vissza. Else ág nem kell.

Ø  Ez azt ellenőrzi, hogy a map (Leaflet térkép) már létezik-e.

Ø  Ha igen, visszaállítja a térkép nézetét Magyarország közepére:

Ø  47.1625 – Magyarország földrajzi szélessége

Ø  19.5033 – földrajzi hosszúsága

Ø  7 – a zoom szint (ez elég nagy ahhoz, hogy az egész ország látszódjon)

·       Ez fontos, mert a felhasználó elmozgathatta a térképet, és így mindig ugyanarról az alapállásból indul az új kérdés.

·       Ha létezik userMarker (a játékos tippjének a jelölője)- itt írd meg az elágazást - , azt távolítsd el a térképről: map.removeLayer(userMarker)

·       Ha létezik a valódi helyet jelölő marker, azt is távolítsd el, úgy mint az előzőt, mert új kérdés jön: map.removeLayer(realMarker);

·       Ha volt korábban piros vonal (ami a két pont közti eltérést mutatta), azt is töröld: map.removeLayer(line);

·       $scope.currentPlace változót iniciáld a következő értékekkel:

Ø  $scope.places[] tartalmazza a megyeszékhelyeket (azokat, amiket a JSON fájlból betöltöttünk).

Ø  Math.random() → ad egy véletlenszámot 0 és 1 között

Ø  Math.floor(...) → kerekíti lefelé, így egész szám lesz;

·       Ez alapján véletlenszerűen kiválasztunk egy új megyeszékhelyet, és ezt elmentjük a $scope.currentPlace változóba.

Ez lesz a következő kérdés, amit a játékosnak ki kell találnia a térképen! Tehát a A nextPlace():

·       Törli a korábbi játék nyomait (jelölők, vonal, eredmény),

·       Visszaállítja a térképet alaphelyzetbe,

·       Új véletlenszerű várost választ,

·       Előkészíti a következő kört.

Oké, jöhet a következő függvény, és innentől kezdve mindent ebbe adsz meg.

$http.get()

·       A get metódussal kérd le az adatokat a megye.json fájlból.

·       A választ tárold el a $scope.places változóba.

·       Hívd meg a $scope.nextPlace() függvényt.

·       Az előzetesen létrehozott map változónak adjuk meg értékként Magyarország közepét:

map = L.map('map').setView([47.1625, 19.5033], 7);

Ezt követően a következőket kell megadnod a függvényen belül a következőket kell hozzáadnod:

Térképréteg betöltése – OpenStreetMap

L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
    attribution: '&copy; OpenStreetMap contributors'
}).addTo(map);

Mit csinál ez?

  • A tileLayer az, ami megjeleníti a térkép csempéit (tile-jait).
  • Az https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png egy OpenStreetMap sablon URL, ahol a {z} a zoom-szintet, {x} és {y} a csempe koordinátáit jelöli.
  • Az attribution fontos: ez a jogi nyilatkozat, ami megjelenik a térképen, hogy tudjuk, ki a térkép forrása (OpenStreetMap).

addTo(map) hozzáadja ezt a réteget a map nevű Leaflet térképhez.

2. Kattintás esemény kezelése

map.on('click', function (e) {

Ez a rész akkor fut le, amikor a felhasználó rákattint a térképre.

3. Megakadályozás, ha már van eredmény

if ($scope.result) return;

Ha már volt egy tipp és kiszámolták az eltérést, akkor ne engedje újra kattintani. Új kérdésig nincs új kattintás.

4. Tippelt pozíció mentése

const guessed = e.latlng;
  • e.latlng a Leaflet által adott objektum, amely a kattintás helyének GPS-koordinátáit tartalmazza.
  • Példa: {lat: 47.5, lng: 19.1}

5. Valódi hely pozíciója

const actual = L.latLng($scope.currentPlace.coordinates.lat, $scope.currentPlace.coordinates.lng);
  • Ez átalakítja az aktuális megyeszékhely (currentPlace) koordinátáit Leaflet-értelmezhető formátumra.
  • Így a distanceTo() később működni fog.

6. Távolság kiszámítása

const distance = calcDistance(guessed, actual).toFixed(2);
  • Meghívja az előzőleg létrehozott calcDistance() függvényt, ami a két pont közötti távolságot méri km-ben.
  • .toFixed(2) → két tizedesjegyre kerekíti, pl. 124.37

7. Játékos tippjének megjelenítése

userMarker = L.marker(guessed).addTo(map).bindPopup("Tipped: ").openPopup();
  • Elhelyez egy markert oda, ahová a játékos kattintott.
  • Megnyit egy buborékot: „Tipped: ” (akár bővítheted: „Tipped: itt gondoltad, hogy a város van”).

8. Valódi hely marker ikonja és popup

realMarker = L.marker(actual, {
    icon: L.icon({
        iconUrl: 'https://cdn-icons-png.flaticon.com/512/149/149059.png',
        iconSize: [30, 30],
        iconAnchor: [15, 30]
    })
}).addTo(map).bindPopup(`Helyes válasz: ${$scope.currentPlace.title}`).openPopup();
  • Elhelyez egy markert a helyes megyeszékhelyre
  • Speciális ikont használ (iconUrl)
  • A popupban megjeleníti: „Helyes válasz: Eger” – vagy bármelyik város

9. Vonal a két pont között

line = L.polyline([guessed, actual], {color: 'red'}).addTo(map);
  • L.polyline([...]) rajzol egy piros vonalat a két pont közé:

Ø  A játékos tippje

Ø  A valódi megyeszékhely

  • Ez látványosan mutatja az eltérést.

10. Eltérés kiírása

$scope.result = `Eltérés: ${distance} km`;
$scope.$apply();
  • Ezzel elmentjük az eltérés szövegét az Angular modellbe
  • A {{result}} szöveg a HTML-ben frissül
  • A $scope.$apply() arra kell, hogy az Angular figyelje meg a változást és frissítse a DOM-ot (mivel a változás egy külső eseményből – Leaflet – indult el)

Mit kell beadni?

  • A teljes projektmappa:

Ø  index.html

Ø  megye.json

  • Minden fájl működjön helyi szerveren (Live Server, XAMPP stb.)
  • A térkép és a kvíz funkció legyen tesztelhető és hibamentes

Tesztelés

  • Nyisd meg a projektet Live Serverrel
  • Próbálj meg 3-4 választ adni
  • Ellenőrizd: marker megjelenik? távolság jól számolódik? új kérdés működik?

Ha valami nem működik, ne pánikolj, ne add fel:

  • Ellenőrizd a konzolt (F12 → Console)
  • Nézd meg, valóban betöltődött-e a megye.json fájl
  • Használj console.log(...)-ot a változók értékének megtekintéséhez

Minta:


user tippje után eredmény: 




IKT Projekt feladat:

Kedves Csapat tudom szívesen játszátok a találd ki hol van játékot. Ennek a feladatnak nyomán készítsetek saját játékot. ChatGpt-vel írassatok különböző országokra, vagy földrészekre JSON fájlt, és készítsétek el hozzá a saját játékotokat. Ezt követően lehet majd tovább gondolni, regisztrációval, pont számlálóval, esetleges jövőbeni projekt dolgozatnak. A csoporton belül, beszéljétek meg, melyik csapat melyik földrészre vonatkozóan készíti el a játékot. Ezt követően össze lehet fűzni az összes oldalt, úgy hogy egy fő oldalon, a user ki tudja választani egy select-ből, hogy melyik földrészen szeretne játszani.

Tanfolyami jelentkezés – HTML űrlap készítése, adatok feldolgozása PHP-val, validációval és formázással

  HTML űrlap (jelentkezes.html) Készíts egy HTML oldalt, amely egy tanfolyamra történő jelentkezési űrlapot jelenít meg. Az űrlap legyen ...