BF Summer sales
Pouze tento týden sleva až 80 % na HTML & CSS a JavaScript
80 % bodů zdarma na online výuku díky naší Letní akci!

Navrhujeme doplněk webu v JavaScriptu

V tomto článku si zkusíme naprogramovat doplněk pro interaktivní stránky v JavaScriptu. Náš doplněk bude fungovat plně automaticky, tvořit budeme kulatý progress bar. K vykreslování použijeme canvas s data-* atributy. V tomto článku to nebudu uvádět step-by-step postupem, jak jste asi zvyklí, ale vždy vás pouze nakopnu (snad) správným směrem. Stejně tak článek počítá s tím, že jste studijní typy a dokážete použít google. I kdybyste nechtěli tvořit celý komplet, tak si můžete stáhnout přiložený zdrojový kód (dole pod článkem) a upravit ho tak, aby byl lepší a dokonalejší.

Někde se začít musí

Většina lidí začíná tím, že si představí výsledek. To je sice fajn, ale když pak začínají psát, pořád mají tu představu. Začněte jinak, představte si svůj výsledek, když jste jej ořezali na minimum. Toto se vám bude dělat mnohem lépe a té první představy dosáhnete mnohem rychleji. Stejně tak je dobré začít právě tím základem. Jestliže začnete vykreslováním textu doprostřed, při dodělávání samotného progress baru zjistíte, že to není až zas tak snadné a přitom je.

Začneme samotným skriptem, který bude obsluhovat každý canvas s atributem data-procent. K tomuto účelu nám dobře poslouží metoda document.query­SelectorAll(), která v parametru dostává CSS selektor a vrátí nám pole elementů, které by ovlivnil tento selektor. Pro vybrání všech canvasů s atributem data-procent použijeme selektor canvas[data-procent], po načtení stránky tedy projdeme pomocí querySelectorA­ll("canvas[da­ta-procent]"), který nám vrátí přesně ty canvasy co potřebujeme.

Nyní si vytvoříme objekt, který bude zastupovat náš kulatý progress bar. Objekty jsou v JavaScriptu jeden velký kámen úrazu. Definují se totiž konstruktorem, což je jednak už od pohledu divné, špatně se v tom orientuje a tím se nám občas i změní docela jasné proměnné i nabobtná pomocný kód. Nicméně se na objekty v JavaScriptu podívejme z té druhé stránky, jakmile by se naše progressbary rozrostly, projekt by se automaticky stal natolik složitý, že bez dobrého návrhu bychom se dříve nebo později dostali do bodu, kdy jsme na dosavadním projektu víceméně pouze ztratili čas. Ačkoli tedy s objekty ze začátku budeme zápasit, nebudeme se jim za žádnou cenu vyhýbat.

Objekt v JavaScriptu definujeme ve funkci, tam načteme všechny vlastnosti. Metody se definují přes prototype této třídy. Vlastnosti ukládáme přes klíčové slovo this. Jako jednoduchou ukázku kódu použijeme třídu pro osoby, na které to lze všechno docela pěkně vidět.

function Clovek(jmeno, vek) {
        this.jmeno = jmeno;
        this.vek = vek;

        Clovek.prototype.Pozdrav = function () {
                alert("Jmenuji se " + this.jmeno + " a je mi " + this.vek + " let.");
        }
}

var karel = new Clovek("Karel", 34)
karel.Pozdrav();
Tento výukový obsah pomáhají rozvíjet následující firmy, které dost možná hledají právě tebe!

Zde vytváříme 34 letého Karla a necháme ho, aby nás pozdravil. V našem doplňku nám bude stačit jen jeden objekt, ten bude reprezentovat právě náš Progressbar. Objekt by mohl mít metody pro aktualizaci stavu a vykreslení, případně by mohl obsahovat metody pro vykreslování jednotlivých částí, čímž se kód zpřehlední. Jednotlivé metody a celkový kód nezapomeňte zdokumentovat, velmi vám to pomůže vyznat se v už tak dost nepřehledných objektech. Pro dokumentaci můžete použít třeba nějakou syntaxi, je jich hodně, můžete použít třeba JSdoc. Zápis JS doc se příliš neliší od dokumentace používané v Javě, naši metodu Pozdrav v člověkovi bychom mohli zdokumentovat následovně:

/**
 * @author Misaz
 * Představí člověka
*/
Clovek.prototype.Pozdrav = function () {
        alert("Jmenuji se " + this.jmeno + " a je mi " + this.vek + " let.");
}

Vykreslování

Vykreslování na plátno je zprostředkováno kontextem, na kterém se volají jednotlivé metody pro vykreslování. Budou vám bohatě stačit metoda arc(), která bere různé parametry a vykreslí část kruhu. Pozor si dávejte na to, že všechny úhly nejsou ve stupních, ale v radiánech. Vzorec pro převod stupňů na radiány je

Radiany = PI / 180 * stupně

Pokud převod budete používat častěji, vložte si to do funkce někde mimo. Velmi zajímavé je si tu funkci vložit přímo do interních Math. V JavaScriptu je to snadné, prostě přiřadíte do požadovaného názvu v Math (vytvoříte si nový, nic nepřepisujete) onu funkci. Tímto zakomponujete vaši funkci do již existujících a čistota kódu je zachována.

Math.deg2rad = function (degrades) {
        return Math.PI / 180 * degrades
}

Aby metoda arc() fungovala podle vašich potřeb, je potřeba si pohrát s cestami. Cestu otevřete metodou beginPath(), ukončíte closePath() a vykreslíte přes fill(). Ta vyplní uzavřenou cestu a stroke vykreslí pouze obrys.

Animace

Abyste docílili efektu animace, musíte v určitém intervalu volat vykreslování a aktualizaci stavu. K tomu můžete použít dvě varianty. Můžete nastavit interval nebo odpočet s tím, že odpočet byste pak museli v každém kroku nastavit nový. Na první pohled se může zdát, že interval je tedy lepší, ale opak je pravdou. Interval běží stále, i když není potřeba – animace přeci nebude nekonečná. Toto sice na běžném moderním počítači s obvykle 2 a více jádrovým procesorem nejde poznat, ale na mobilu se to výrazně negativně projeví na výdrži baterie (v dnešní době velký problém) a u některých telefonů i přehřívání (ale toho se většinou nevyhnete tak či tak). Osobně vám tedy s ohledem ke koncovému uživateli doporučuji metodu odpočtu, nastavíte ji metodou setTimeout(). Pokud jste se i přesto rozhodli pro interval, tak ten nastavíte přes metodu setInterval(). I pro interval je tu ještě jedna možnost, která by řešila problém zbytečných aktualizací a to návratovou hodnotu si někam uložit a v okamžiku konce animace zavolat clearIterval(), do parametru předáte právě proměnnou. Ve výsledku to může vyjít na stejno a je jen na vás, která varianta se vám více líbí.

Pokud jste animace v JavaScriptu nikdy nedělali a nejste v tom zběhlí, tak se vám možná budou na úvod hodit jednoduché tipy pro jejich tvorbu. Jestliže by se měl progressbar animovat, tak se bude hodnota většinu času pohybovat někde uvnitř. Nejprve to bude 0, pak 1, 2, 3 a nakonec to bude třeba 75 uložených v attributu data-procent (ten který jsme ověřovali selektorem). K zařazení této pohybující se proměnné do aplikace máte opět dvě varianty. První varianta je ta, že to budete celou dobu animace předávat v parametru, ta druhá, že si vytvoříte pomocnou proměnnou (osobně je pro přehlednost označuji tím, že začínají podtržítkem). Druhá mi osobně přijde o trochu lepší, protože dělali byste animaci, která může přibývat nebo ubývat (možná si říkáte na co ubývání, to proto, že jakmile implementuje obsluhu události pro změnu parametru, tak uživatel může zadat hodnotu menší než je dosavadní), tak musíte použít buď inkrementaci, nebo dekrementaci, ačkoliv to jde udělat všechno i v parametru přijde mi hezčí varianta pracovat s vlastností.

DOMsubtreeModified

Abychom mohli nějak za běhu kontrolovat změny parametrů, tak máme (jako už asi již tradičně) dvě možnosti. Ta první je, že budeme v určitém časovém intervalu kontrolovat každou hodnotu anebo si odchytíme událost DOMsubtreeModified. Ta se vyvolá vždy v okamžiku, když se cokoliv změní v stromu DOM. Ačkoli by tuto událost měli správně zpracovat všechny prohlížeče, zjistil jsem, že v Google Chrome nefunguje. Neustálá kontrola atributů je jednak asi mírně složitější, kód je méně přehlednější, jelikož tam je kolem toho spousta pomocného kódu a jak již jsem zmiňoval v odstavci o animacích, pro mobilní zařízení to není to pravé ořechové. Proto si odchyťte DOMsubtreeModified a obslužte si to podle libosti.

Možná vylepšení

Tímto byste měli mít progreessbary hotové a můžete se pustit do implementace dalších vylepšení, dbejte vždy na dobrý návrh, přemýšlejte a věřte, že přepisovat kód na pětkrát je zcela normální, někdy si to ani neuvědomujete. Nakonec vám vypíši, co byste mohli doimplementovat.

  • Volitelné animace, dejte možnost i neanimované verze, můžete použít attrbtu data-*
  • Možnost nastavování různých barev pro pozadí i samotný progress
  • Umožnit nastavení startovního úhlu, u některých aplikací se hodí víc když pregress začíná třeba v 3/5.
  • Podpora různé výšky šířky. Můžete třeba vycentrovat obsah, k tomu se dobře hodí možnost posunutí kontextu u plátna.

Doufám že se vám tento článek líbil, něco jste se přiučili, ale hlavně doufám že byl pro vás přínosný a vaše nadcházející výsledky v JavaScriptu budou zase o trochu lepší.

Doporučuji se zkoušet zapojovat do zdejších minisoutěží Machr na JavaScript. Trénujete nejen JavaScrit, ale i schopnost řešit určitou úlohu rychle a celý projekt stihnout dokončit do deadline. V Machru na JS se nehodnotí jenom výsledek, ale i zdrojový kód. A právě tento článek vás měl navést správnou cestou a dát vám některé tipy k správnému návrhu a psaní hezkého a dobře čitelného kódu. Právě kulatý progressbar je úloha jednoho předchozího machra. :)


 

Stáhnout

Staženo 519x (2.36 kB)
Aplikace je včetně zdrojových kódů v jazyce JavaScript

 

Všechny články v sekci
Objektově orientované programování v JavaScriptu
Článek pro vás napsal Michal Žůrek - misaz
Avatar
Jak se ti líbí článek?
6 hlasů
Autor se věnuje tvorbě aplikací pro počítače, mobilní telefony, mikroprocesory a tvorbě webových stránek a webových aplikací. Nejraději programuje ve Visual Basicu a TypeScript. Ovládá HTML, CSS, JavaScript, TypeScript, C# a Visual Basic.
Aktivity (1)

 

 

Komentáře

Avatar
David Čápka
Tým ITnetwork
Avatar
David Čápka:17.2.2014 18:44

Přijde mi lepší učit raději step by step, tvoje metoda je sice zajímavá, ale myslím, že neznalého to spíše odradí.

Odpovědět
17.2.2014 18:44
Jsem moc rád, že jsi na síti, a přeji ti top IT kariéru, ať jako zaměstnanec nebo podnikatel. Máš na to! :)
Avatar
Odpovídá na David Čápka
Michal Žůrek - misaz:17.2.2014 18:53

no to je právě pro znalé, když jsem se díval na ty dva poslední machry, tak mi přišlo že technicky to měli vymakané dobře, ale nemám slov, když někdo složitější HTML dělá přes innerHTML. A právě proto tohle - jednoduše jsem je ankopl k začátku a když tak ať použijí google, to je při programování velmi důležitá schopnost.

 
Odpovědět
17.2.2014 18:53
Avatar
1Pupik1989
Neregistrovaný
Avatar
1Pupik1989:17.2.2014 18:59
function Clovek(jmeno, vek) {
        this.jmeno = jmeno;
        this.vek = vek;

        Clovek.prototype.Pozdrav = function () {
                alert("Jmenuji se " + this.jmeno + " a je mi " + this.vek + " let.");
        }
}

Tohle ještě chce opravit. Správně má být prototype v kódu za konstruktorem.

function Clovek(jmeno, vek) {
  this.jmeno  = jmeno;
  this.vek    = vek;
};

Clovek.prototype.pozdrav = function(){
  alert("Jmenuji se " + this.jmeno + " a je mi " + this.vek + " let.");
};
 
Odpovědět
17.2.2014 18:59
Avatar
Odpovídá na 1Pupik1989
Michal Žůrek - misaz:17.2.2014 19:07

dík, opraveno, čeká na schválení.

 
Odpovědět
17.2.2014 19:07
Avatar
Pavel Vosyka
Člen
Avatar
Pavel Vosyka:23.2.2014 13:49

Tenhle styl psaní se mi líbí. Taky to, že je to v čistém javascriptu. Akorát mě zamrzela ta nepodpora "DOMsubtreeMo­dified" v chrome :(

Pěkný výsledek.

Odpovědět
23.2.2014 13:49
"nikdy nepiš nic 2x"
Avatar
Odpovídá na Pavel Vosyka
Michal Žůrek - misaz:23.2.2014 13:56

ani verze 33 to neumí, reportoval jsem jim bug, tak uvidíme jestli to čtou a jestli to do verze 34 vyřeší.

 
Odpovědět
23.2.2014 13:56
Avatar
1Pupik1989
Člen
Avatar
1Pupik1989:9.3.2014 23:17

Koukám, že to opravování nedopadlo. Pokud si to někdo přečte, tak nebude mít zrovna 2x dobrý základ. Bude z něj horší kodér než jsou lepičové. Opravdu by to chtělo opravit.

 
Odpovědět
9.3.2014 23:17
Avatar
1Pupik1989
Člen
Avatar
1Pupik1989:10.3.2014 1:08

Jen dodám, pro pokročilejší uživatele, co honí každé fps a každou ms ať už ve 2D nebo pseudo 3D. Nedělejte funkci deg2rad, ale uložte si prostě vlastnost k objektu.

Math.PIOver180 = Math.PI/180

A pak stačí jen násobit. Násobení je několikrát rychlejší než zavolání funkce. To už je ale jen performance tip.

 
Odpovědět
10.3.2014 1:08
Avatar
Odpovídá na 1Pupik1989
Michal Žůrek - misaz:10.3.2014 15:12

Možná je to rychlejší (až si najdu čas schválně otestuji), ale rozhodně kód takhle není přehledný a na toto článek cílil.

 
Odpovědět
10.3.2014 15:12
Avatar
1Pupik1989
Člen
Avatar
Odpovídá na Michal Žůrek - misaz
1Pupik1989:10.3.2014 16:36

Nepřipadá mi, že by se tím kód nějak znepřehlednil. Jediné co se změní, že bez volání funkce ubude jedna operace, čili to 100% bude rychlejší. Samozřejmě úplně nejlepší řešení je používat vždy radiány a ne stupně. Do budoucna to ušetří spoustu práce a kódu. Podle mě ale u toho kódu to bude nejspíš jedno, protože při každém zavolání funkci vytvoří 4 další funkce. Lepší by se to řešilo v OOP.

new RadialProgressBar(elements[i])

To by chtělo ještě opravit na:

RadialProgressBar(elements[i])

Doufám že jsem nezněl jako blb. To jsou jen postřehy, nic už nikdy nikomu vyčítat nebudu, ať si každý píše jak chce. :D

 
Odpovědět
10.3.2014 16:36
Avatar
1Pupik1989
Člen
Avatar
Odpovídá na Michal Žůrek - misaz
1Pupik1989:11.3.2014 23:49

Promiň, ale když koukám na kód, tak si jim ani svým zápisem na přehlednosti moc nepomohl. Tohle je příklad, kde by šla oddělit logika od vykreslení a přitom opravdu použít prototype. Rozdělil bych to na metody jako jsem měl v objektu v soutěži já. "drawBackground", "drawProgress" a zde přidat i "drawText". Tohle je vlastně takové půl closure. Sice to má vnořené funkce, nicméně to není objekt a nic to nevrací. Nechci nějak radit, ale tohle bych se opravdu odnaučil. V pár případech je to dobrá věc, ale co se týče objektového psaní je to zlo. Jak jsem psal, operátor "new" ztrácí smysl. Vytvoří zbytečně objekt, který nic nepoužívá, čili to zabere paměť úplně k ničemu. Přesně takto jsem začínal a trvalo mi, než jsem logiku javascriptu pochopil a dozvěděl se, co se mu nejvíc líbí. Opravdu je prototype rychlejší a hlavně přehlednější.

Jen hrubý návrh, nějak jsem se tím nezabýval (15 min než jsem šel na pivo). Určitě by v closure nemusel být celý objekt, ale jen to co využívá vedlejší funkce. Ty by se ale daly napsat přímo do metod objektu.

http://www.itnetwork.cz/dev-lighter/318

 
Odpovědět
11.3.2014 23:49
Avatar
Odpovídá na 1Pupik1989
Michal Žůrek - misaz:12.3.2014 6:22

to je schválně, hned na začátek je že ti co to nechocou psát celé sami si mohou stáhnout zdrojáky a upravit je aby to bylo lepší, proto to není prototypované atd. Za deg2rad si stojím, nějaké násobení s pioverbuhvico mě nepřesvědčí, že je přehlednější, nehledě na to že si pořád musím pamatovat jak přesně funguje ten vzorec. Mám to tím číslem dělit? násobit? mocnit? odmocnit?

new Neco() volám když vytvářím instanci a Neco() když volám funkci, takhle to rozlišuje. Však každý si to přece může dělat po svém.

Editováno 12.3.2014 6:24
 
Odpovědět
12.3.2014 6:22
Avatar
1Pupik1989
Člen
Avatar
1Pupik1989:12.3.2014 11:41

V tomto případě ale vytvoříš instanci a nijak jí nevyužiješ. Vlastně je to funkce, která obsahuje lokální proměnné a funkce. K tomu není třeba instance, ale postačí funkci pustit s parametrem.

V matematice je potřeba si pamatovat hodně vzorců. Výběr funkce nebo proměnné už je na jedinci. Já mám všechny proměnné tak, abych násobil. Mám zafixováno, že násobení je rychlejší než dělení. Teď už to asi pravda moc nebude.

deg2rad jsem měl také jako funkci, ale časem si toho pamatuji víc a při honění rychlosti ji nemělo cenu používat. Vůbec když jsem přestal používat stupně úplně.

 
Odpovědět
12.3.2014 11:41
Avatar
Michal Žůrek - misaz:11.4.2014 19:02

Chrome 24 a DOMSUbtreeModified jim stále nic neříká

 
Odpovědět
11.4.2014 19:02
Tento výukový obsah pomáhají rozvíjet následující firmy, které dost možná hledají právě tebe!
Avatar
1Pupik1989
Člen
Avatar
1Pupik1989:11.4.2014 21:13

DOMSubtreeModified jde celkem dobře simulovat bez časování. Stačí u všech DOM elementům upravit metody na manipulaci.

 
Odpovědět
11.4.2014 21:13
Avatar
Odpovídá na 1Pupik1989
Michal Žůrek - misaz:11.4.2014 21:16

jasně, ale to už není tak hezké.

 
Odpovědět
11.4.2014 21:16
Avatar
1Pupik1989
Člen
Avatar
1Pupik1989:11.4.2014 21:28

Nicméně funkční. Třeba Opera zrovna tu metodu také moc nepodporuje.

Editováno 11.4.2014 21:29
 
Odpovědět
11.4.2014 21:28
Avatar
Odpovídá na 1Pupik1989
Michal Žůrek - misaz:15.4.2014 8:48

to není metoda, je to událost.

 
Odpovědět
15.4.2014 8:48
Avatar
1Pupik1989
Člen
Avatar
1Pupik1989:15.4.2014 12:32

To nic nemění na tom, že to simulovat jde, když to tak nutně potřebuješ. Nicméně jsem moc nepochopil význam té události.

 
Odpovědět
15.4.2014 12:32
Avatar
šíma
Člen
Avatar
šíma:16.12.2018 13:18

nefunguje to :-(

Odpovědět
16.12.2018 13:18
šíma = programátor !!!
Avatar
Patrik Pastor:17.4.2019 21:13

co to jako je??

<canvas width="100" height="100"
data-procent="45"
data-animovane
data-barva="#FF0000"
data-pismo="calibri"
data-popisek="Down"
data-startovni-uhel="225"></­canvas>
<canvas width="100" height="100"
data-procent="10"
data-animovane
data-barva="#FF0000"
data-pismo="'Segoe UI symbol'"
data-popisek=""
data-startovni-uhel="225"></­canvas>

<canvas width="100" height="100"
data-procent="85"
data-popisek="HTML\numím na\n%%%%"></canvas>

<canvas width="200" height="200" id="hrajtesi"
data-procent="45"
data-animovane
data-barva="rgb(66, 177, 10)"
data-barva-pozadi="#B1F100"
data-pismo="calibri"
data-popisek="Hrajte\n si!"></canvas>

Jak mam vedet za mam takhle zacit, predstavil jsem si jeden canvas pro progres bar (jeste sem si hledal co to vlastne je), ale clanek pokracoval, vyberem VSECHNY canvasy..... Proc je tam vice kanvasu? (nema prece plnit funkci dalsich procent prave ten jeden kanvas - to "nacitani" nebo proc tam jsou random canvasy pro random procenta? (myslim, 10, 45, 75, 100 - tak nejak to tam myslim bylo), ja jsem si teda nepredstavil, ze bych progress bar zacinal se 4 canvasy pro 4 random procenta, vubec sem nepochopil autora na zacatku, mohl by to psat trochu lepe srozumitelneji.

 
Odpovědět
17.4.2019 21:13
Avatar
Odpovídá na Patrik Pastor
Michal Žůrek - misaz:18.4.2019 0:06

Je to ze soutěže, jejiž cílem bylo udělat jednu komponentu, která může být na stránce vícekrát. Tento článek není step-by-step tutorial. Prostě si ho přečti a zkus to naprogramovat sám, bez ohledu na to jak vypadá moje řešení. (tvoje řešení bude nejspíš diametrálně odlišné, ale to vůbec nevadí). Klidně si to udělej jako jeden canvas, když ti to víc vyhovuje.

 
Odpovědět
18.4.2019 0:06
Avatar
Odpovídá na Michal Žůrek - misaz
Patrik Pastor:18.4.2019 13:54

aha chapu, je to ze souteze, ale potom by bylo dobre uvest i podminky (nebo cile, jak jsi zminil) k teto soutezi, tedy ze se maji vykrslit vice canvasu, takhle ten clanek pusobi nedodelany a muze nekoho zmast, kdyz zacnes psat jakoby z prostredka (kor kdyz to neni prave step-by-step), stacilo pouze par informaci k okolnosti vzniku. dik

Editováno 18.4.2019 13:54
 
Odpovědět
18.4.2019 13:54
Avatar
Odpovídá na Patrik Pastor
Michal Žůrek - misaz:19.4.2019 10:50

ta soutěž už byla. To co si můžeš stáhnou je jedno z řešení.

 
Odpovědět
19.4.2019 10:50
Avatar
Odpovídá na Michal Žůrek - misaz
Patrik Pastor:19.4.2019 21:59

o soutez vubec nejde ale o informaci ke clanku. Pokud se CLANEK tyka souteze, a v ni jsou napriklad pravidla (za ma byt vice canvasu) tak by bylo dobre to zminit i ve clanku, kde se snazis napovedet k reseni, ale stejne zacnes z prostredka, takze ctenar je potom zmateny. Ze soutez probehla, je uplne putna. Jde o informaci ke clanku, protoze ten ctu, zadnou soutez.

 
Odpovědět
19.4.2019 21:59
Avatar
Odpovídá na Patrik Pastor
Michal Žůrek - misaz:20.4.2019 22:20

Tady tyto soutěže (okolo roku 2014) fungovali tak, že se na fóru (teré tehdy nebylo striktně omezeno na dotazy, ale využívalo se i všelijak jinak) byl zadán každý týden úkol a kdo to vyřešil nejlíp, tak dostal placku (takovou tu třeba na batoh) takovou jako je na obrázku dole v článku.

Podmínkou získání placky bylo, že to ešení tu bude na věky věků zveřejněno jako článek a to je v tomto případě tento článek.

Zadání (a průběhú) je zde: https://www.itnetwork.cz/…2e7da4c2e544

Pomocí vyhledávače jdou najít i další soutěže, které se historicky řešili. Každý má v profilu placky, které získal, takže si můžeš rozkliknout můj profil a tam bude 12 placek, které jsem získal, můžeš si zkusit ty programy naprogramovat taky.

 
Odpovědět
20.4.2019 22:20
Avatar
David Čápka
Tým ITnetwork
Avatar
Odpovídá na Michal Žůrek - misaz
David Čápka:21.4.2019 13:29

Ony byly pokusy je oživit ještě poměrně nedávno. Měl bych tu teď mít výrazně více času než předtím, možná by se s tím dalo zas něco zkusit.

Odpovědět
21.4.2019 13:29
Jsem moc rád, že jsi na síti, a přeji ti top IT kariéru, ať jako zaměstnanec nebo podnikatel. Máš na to! :)
Děláme co je v našich silách, aby byly zdejší diskuze co nejkvalitnější. Proto do nich také mohou přispívat pouze registrovaní členové. Pro zapojení do diskuze se přihlas. Pokud ještě nemáš účet, zaregistruj se, je to zdarma.

Zobrazeno 28 zpráv z 28.