Fabric.js "digitális asztal" implementáció
Jocó - 2 évePCE rendszerről röviden
A koronavírus megjelenésével sorra zártak be az olyan helyek, ahol a létesítmény jellegéből adódóan több ember, kis helyen, nagy rotációban jelent meg: mozik, uszodák, éttermek. Ebbe a csoportba tartoznak a szabadulószobák is. A londoni clueQuest a kezdeti korlátozások után egy időre kénytelen volt bezárni kapuit a játékosok előtt.
Ebben az időben született meg a PCE, azaz a Print, Cut, Escape rendszer. Később ez aztán játékok jellege miatt véglegesen a Play At Home nevet kapta, ami sokkal jobban lefedi a célt. Az ötlet lényege, hogy otthoni környezetben egy nyomtató és egy olló segítségével papírra vetett feladványokat vagdoshatunk, hajtogathatunk majd a történet és a tálalás keretein belül egy online rendszerbe vihetjük fel a válaszainkat.
Ahogy telt az idő, úgy lett egyre bonyolultabb a rendszer. A kezdeti, egyszerű szöveges inputokból egyszerre megadott inputok validálása és beküldése lett, majd ahogy haladtunk tovább, megjelentek a bonyolultabb játékok is.
Példaként ott van a panoráma nézegető, ahol távcső szerűen tudunk 360 fokban egy képen körbeforogni, majd a megfelelő ponton megállítva a célkeresztet az adott pont koordinátáit be tudjuk küldeni megoldásként.
Egy nemrégiben épült modul pedig a digitális asztalunk, amire bármit rárakhatunk anélkül, hogy nyomtatni kéne vagy helyet csinálni a valós asztalunkon.
Oké, de ez mire jó?
Tegyük fel, hogy van 4 darab lapunk. A 4 darab lapot a megfelelő sorrendben és helyzetben kell összerakni, ahhoz, hogy le lehessen olvasni a megoldást.
Ezt nem lehetett volna papíron, rendesen kinyomtatva? De. Viszont mivel nincs mit vagdosni, pazarlás lenne 4 darab papírt egyszeri felhasználás miatt kinyomtatni majd eldobni. Egyrészt. Másrészt meg ezzel maga a felület is egy fokkal interaktívabb lett, hiszen nem csak válaszokat pötyögünk bele, hanem ténylegesen "játszani" is kell rajta, elemeket megfogni, arrébb rakni, sorba rendezni, forgatni, próbálgatni.
A rendszer lényege továbbra sem az, hogy 100%ban digitális legyen, de az ehhez hasonló modulokkal sikerült egy picivel izgalmasabbá tenni a feladványokat.
A megoldás
A modul építését hosszas kutatás előzte meg, próbáltuk több irányból is megközelíteni az egészet. Egy egyszerű javascriptes csodát talán még nem lett volna olyan bonyolult megírni, de a későbbi bővíthetőség és a támogatottság figyelembevételével nekiálltunk külső modulokat is nézegetni.
Több library átnézése és kipróbálása után a fabric.js-re esett a választás. Ez lényegében egy javascript alapú canvas library ami objektumok, formák, szöveg és képek felrajzolásán kívül még rengeteg dolgot ad a fejlesztő kezébe. Animálás, árnyékolás, cropolás és még sok egyéb apróság, valamit nagyobb dolgok is a csomag részei.
Kezdeti nehézségek
A rengeteg dologból mi igazából csak egy dolgot szerettünk volna használni, a képek megjelenítését. Ehhez adott egy loader, ami betölti a képeket majd rárakja őket egy canvasra. Korábban szerzett tapasztalatok alapján megépült a dinamikus, reszponzív canvas majd rádobáltuk a képeket. Azonnal előjöttek olyan problémák, ahol a layerek random sorrendben töltődnek be illetve egyik layer képes úgy lefedni a másikat, hogy nem lehet megfogni. Ezekre a fabric által támogatott eventek és utasítások megoldást jelentettek (object onclick -> bringtofront, set active) viszont a betöltési sorrendre saját, asynces megoldás készült ami megvárja az összes képet és csak utána rajzolja fel őket.
A forgatás, pozícionálás, lockolás, árnyék ki/be a rendszer részei, így az object propertyk setelése nem okozott problémát, viszont az, hogy a canvasról még véletlen se lehessen őket kihúzni, már igen. Ennek a problémának az elkerülése érdekében párhuzamosan készült egy reset gomb, ami visszaállítja, pontosabban újratölti (pontosabban újrarajzolja) az egész canvast, és egy olyan számolás, ami nem engedi kihúzni a canvasról az elemeket.
Mivel ez a funkcionalitás nem a fabric.js része, stacken és egyéb helyeken kutatva találtunk megoldást ami, mint később kiderült, csak félig meddig működik. A végső megoldást a ChatGPT-től kaptuk, ami nem csak szép de ténylegesen működő alapot adott amit aztán egy kis átalakítással a saját canvasunkhoz igazítottunk.
Okosítás
Digitális lapokat húzogatni a digitális asztalon tök menő, de mi lenne, ha segédlet helyett tényleges játékelemmé tudnánk ezt alakítani? Magyarul, tudunk-e valahogy adatokat kinyerni belőle? Adott például egy forgatós számzár, amit egy kör alapra lehelyezett számsor fölött egy pontban lyukas kör prezentál, meg tudjuk mondani, hogy melyik számon áll éppen, amikor megtörtént a forgatás?
Ezt konkrétan nem, de azt, hogy az adott object milyen szögben áll, igen. Itt jön a képbe a fabric getObjects() metódusa, ami visszaadja az objektumokat és azok adatait. Ezt egy eventtel bindolva (modified) fel lehet használni arra, hogy object áthelyezés, forgatás után visszaadjon egy értéket.
Jelenlegi állapotában ez úgy néz ki, hogy meg lehet mondani objektumonként, hogy melyik milyen adatot adjon vissza és akár osztani is tud, így a pontosságot csökkentve. Ez azért fontos, mert egy várt válasz esetén nem biztos, hogy adott elem pozícióját pixel pontosan meg akarom adni, így az 1442-ből tudok csinálni akár 144-et, de 14-et is.
A kód
Kódszinten egy typescript alapokon nyugvó npm-es projektről beszélünk, ami nyilván dependens a fabric.js libraryre. Maga a manager csak json alapú tömböt vár amiben megkap minden adatot: canvas méreteit, rajta lévő elemeket és azok propertijait, lehet-e adott objectet mozgatni X tengelyen vagy sem, ad-e választ vagy sem, scale, rotation, position és még sok minden más.
A tömböt aztán belül ő feldolgozza, így egy kiszervezhető, önálló komponensről beszélünk amit bármilyen projektbe belehúzva kapunk egy digitális asztalt, amit bárhova lerakhatunk és azt rakunk rá amit akarunk. A PCE rendszeren belül ehhez van egy builder, vagy konfigurátor, nem tudom pontosan minek nevezzem. Itt a fentebb említett paramétereket egy admin felületen csak össze kell kattintgatni és rámenteni, majd megnézni a végeredményt.
Felhasználási lehetőségek
A fentebb említett számzáras példán kívül még rengeteg ötletes dologra lehet használni. Mivel overlayt is támogat, akár egy célkeresztet felhúzva meg lehet célozni egy adott elem adott pontját. Vagy puzzle szerűen elemeket felrakva össze tudjuk őket igazgatni és validálni, hogy minden ott van ahol lennie kell. Működhet akár csak sima nézegetőként, amin képeket fogathatunk, nagyíthatunk, pakolgathatunk ahova szeretnénk.
Limitációk és hiányosságok
A fabric nagyon sok mindenre használható, viszont megvannak a saját kis problémái, pontosabban a megoldatlan kérdései. Ilyen például a touch gesture support, amivel elvileg érintős eszközökön lehetne több ujjas műveleteket kijelölés nélkül végezni. Ehhez viszont a saját custom builderét kell használni, majd a végterméket a már lehúzott npm-es packageben felülírni. Ezzel ugye az a probléma, hogy update esetén nem frissül vagy felülíródik. A másik probléma pedig az, hogy akárhogy probálkoztam, az istenért sem sikerült működésre bírnom ezt a custom buildet.
Összegzés
A fabric.js egy nagyon sokoldalú library ami kiválóan használható képek pakolására egy virtuális asztalon, prezentálásra vagy akár csak freehand rajzolgatásra. A demók között rengeteg ötletes dolgot találunk de ezeket ahogy néztem nem feltétlen támogatja beépített jelleggel, sok helyen egyszerűen megírták hozzá a számolásokat. Egyszerű dolgokra nagyon gyorsan fel lehet setupolni, de ahogy minden mást is, ezt is a végletekig lehet bonyolítani.
Fabric.js TypeScript Npm PCE