Přidat článek mezi oblíbenéZasílat nové komentáře e-mailem Naučte HTML novým trikům (II)

Dnes si ukážeme, jak vytvořit nový HTML tag, reprezentující SVG prvek, který se zobrazí jako sedmisegmentovka (jedna číslice). Použijeme ho např. takhle: <svg-segment x=“20“ y=“30“ value=“6“ color=“blue“></svg-segment>

Článek volně navazuje na předchozí: Naučte HTML novým trikům.

Pozn.: Je mi jasné, že daný úkol lze realizovat mnoha způsoby, jistě jsou i elegantnější než moje řešení :-)

Sedmisegmentovka

Jedná se hojně rozšířený způsob zobrazení čílic 0 – 9 (popřípadě 0 – F v šestnáctkové soustavě). Může vypadat např. takhle:
[http://pc.poradna.net/file/view/21476-7segmentovka            -popis-png]
Každý segment má svoje označení (a – g), číslice zobrazíme tak, že příslušný segment buď rozsvítíme, nebo zhasneme.
Pro zobrazení číslice 3 rozsvítíme segmenty: a, b, c, d, g.
[http://pc.poradna.net/file/view/21477-7segmentovka            -cislice-3-png]

Direktiva v Angularu

Pomocí javascriptové knihovny AngularJS můžeme definovat nový tag, který potom využijeme v HTML kódu webové stránky. Naše direktiva se jmenuje svgSegment a v HTML kódu ji použijeme jako <svg-segment></svg-segment>.
Může vypadat takto:

app.directive('svgSegment', function(){
    return {
    restrict: 'E',
    replace: true,
    scope: {
        x:'@',
        y: '@',
        min: '@',
        max: '@',
        value: '=value',
        error: '@',
        errorColor: '@',
        color: '@'
    },
    templateNamespace: "svg",
    template: '<g transform="translate({{x}}, {{y}})">\n\
                    <polyline id="segm_a" stroke-width="1" points="11, 14 17, 8 47, 8 53, 14 47, 20 17, 20 11, 14 17, 8" stroke-linejoin="miter" ng-attr-fill="{{a}}" />\n\
                    <polyline id="segm_g" stroke-width="1" points="11, 65 17, 59 47, 59 53, 65 47, 71 17, 71 10, 65 17, 59" stroke-linejoin="miter"  ng-attr-fill="{{g}}" />\n\
                    <polyline id="segm_d" stroke-width="1" points="11, 114 17, 108 47, 108 53, 114 47, 120 17, 120 11, 114 17, 108" stroke-linejoin="miter"  ng-attr-fill="{{d}}" />\n\
                    <polyline id="segm_f" stroke-width="1" points="8, 19 14, 25 14, 55 8, 61 2, 55 2, 25 8, 19 14, 25" stroke-linejoin="miter" ng-attr-fill="{{f}}" />\n\
                    <polyline id="segm_b" stroke-width="1" points="56, 19 62, 25 62, 55 56, 61 50, 55 50, 25 56, 19 62, 25" stroke-linejoin="miter"  ng-attr-fill="{{b}}" />\n\
                    <polyline id="segm_c" stroke-width="1" points="56, 69 62, 75 62, 105 56, 111 50, 105 50, 75 56, 69 62, 75" stroke-linejoin="miter" ng-attr-fill="{{c}}" />\n\
                    <polyline id="segm_e" stroke-width="1" points="8, 69 14, 75 14, 105 8, 111 2, 105 2, 75 8, 69 14, 75" stroke-linejoin="miter" ng-attr-fill="{{e}}" />\n\
                    \n\</g>',

controller: function ($scope){
         
        $scope.getColors = function(){
            var val = $scope.value;
            if (!$scope.isError) {
                $scope.a = (val === 0 || val === 2 || val === 3 || val === 5 || val === 6 || val === 7 || val === 8 || val === 9) ? $scope.color : 'none';
                $scope.b = (val === 0 || val === 1 || val === 2 || val === 3 || val === 4 || val === 7 || val === 8 || val === 9) ? $scope.color : 'none';
                $scope.c = (val === 0 || val === 1 || val === 3 || val === 4 || val === 5 || val === 6|| val === 7 || val === 8 || val === 9) ? $scope.color : 'none';
                $scope.d = (val === 0 || val === 2 || val === 3 || val === 5 || val === 6 || val === 8) ? $scope.color : 'none';
                $scope.e = (val === 0 || val === 2 || val === 6 || val === 8 ) ? $scope.color : 'none';
                $scope.f = (val === 0 || val === 4 || val === 5 || val === 6 || val === 8 || val === 9) ? $scope.color : 'none';
                $scope.g = (val === 2 || val === 3 || val === 4 || val === 5 || val === 6 || val === 8 || val === 9) ? $scope.color : 'none';                
            }
            else {
                if ($scope.error === "E") {
                    $scope.a = $scope.f = $scope.g = $scope.e = $scope.d = $scope.errorColor;
                    $scope.b = $scope.c = 'none';
                }
                else {
                    $scope.g = $scope.errorColor;
                    $scope.a = $scope.b = $scope.c = $scope.d = $scope.e = $scope.f = 'none';
                }
            }             
        };
        
        $scope.checkError = function(){
            $scope.isError = false;
            $scope.isError = !( ($scope.value === parseInt($scope.value)) && ($scope.value >= $scope.min) && ($scope.value <= $scope.max) );
        };
         
         
        $scope.min = ($scope.min === parseInt($scope.min)) ? $scope.min : 0;
        $scope.max = ($scope.max === parseInt($scope.max)) ? $scope.max : 9;
         
        $scope.color = $scope.color || 'black';
        $scope.errorColor = $scope.errorColor || 'red';
        $scope.error = ( ($scope.error === '-') || ($scope.error === 'E') ) ? $scope.error : 'E';

$scope.$watch('value', function(newVal){
            $scope.value = newVal;
            $scope.checkError();
            $scope.getColors();
        });
    }
    }; 
});

Direktiva vrací objekt, jehož vlastnost:
restrict: 'E' říká, že vytvoříme nový tag = element
replace: true značí, že (níže uvedená) vlastnost template nahradí náš tag <svg-element></svg-element> zápisem uvedeným v template
scope je další objekt, pomocí kterého ovlivníme chování tagu <svg-element></svg-element> z HTML kódu použitím atributů
x, y jsou souřadnice, kde se nám sedmisegmentovka vykreslí
min, max umožní definovat minimální a maximální číslici, kterou sedmisegmentovka zobrazí
value je hodnota, kterou chceme zobrazit
error je znak, který se má zobrazit v případě chyby (např. číslo mimo rozsah min-max), může být buď „-„ nebo „E“
errorColor je barva, kterou se zobrazí chyba
color je barva rozsvíceného segmentu

templateNamespace: "svg" je tu proto, aby direktiva fungovala uvnitř SVG
template obsahuje kód, který se vloží místo tagu <svg-element></svg-element>
na prvním řádku je případné posunutí segmentovky o x pixelů doprava a o y pixelů dolů (klasický způsob v SVG)
na dalších řádcích jsou pak definovány jednotlivé segmenty ag pomocí tagu <polyline />, je to běžný zápis v SVG až na poslední atribut ng-attr-fill, který určuje barvu každého segmentu (podle toho, zda je rozsvícený nebo zhasnutý)

controller popisuje chování direktivy a provádí některé manipulace
funkce $scope.getColors() na základě hodnoty value nastaví barvu těm segmentům, které se mají rozsvítit, zhasnuté segmenty se vůbec nevykreslí; v případě chyby se zobrazí buď znak „-„ nebo znak „E“

funkce $scope.checkError() ověří, zda je zadána celočíselná hodnota value a zda je v intervalu min-max, v opačném případě nastaví proměnnou $scope.isError na true

poslední fukce $scope.$watch() by tu být nemusela v případě, že nepotřebujeme update sedmisegmentovky a stačilo by nám jen jednou nastavit její číselnou hodnotu, která se má zobrazit; pokud ale chceme, aby segmentovka reagovala na změnu atributu value, hodí se nám tato funkce

Použití tagu <svg-segment></svg-segment> v HTML

Direktiva definuje několik atributů pro tag (element) <svg-segment></svg-segment> zapsaný v HTML. Atributy jsou:
x, y, min, max, value, error, errorColor, color

Příklad použití:

<svg>
<svg-segment x=“20“ y=“30“ value=“6“ color=“blue“></svg-segment>
</svg>

Co se stane v případě, že některý z atributů vynecháme? Každý atribut má svoji implicitní hodnotu (která se použije). Souřadnice x, y ji sice nemají implicitně uvedenu, ale pokud je vynecháme, zobrazí se sedmisegmentovka na pozici 0, 0. Ostatní implicitní hodnoty jsou definovány v controlleru, např. minimum:
$scope.min = ($scope.min === parseInt($scope.min)) ? $scope.min : 0;
Zdálo by se, že vynecháním nejpodstatnějšího atributu value nebude zřejmé, co se vlastně má zobrazit, nicméně zobrazí se chyba (znak „-„ nebo „E“), to zařídí funkce $scope.checkError(), v jejíž první části podmínky se ověří, zda platí $scope.value === parseInt($scope.value), tj. zda je atribut value celé číslo. Tím, že atribut value úplně vynecháme, podmínka splněna není a je nastaven příznak chyby a proměnná $scope.isError má hodnotu true.

Na závěr

Jsem si vědom toho, že daný úkol se dá řešit mnoha způsoby, z nichž některé jsou jistě elegantnější než moje řešení. Pro experty: Také vím, že v direktivách existují funkce link a compile…

Direktiva by šla ještě rozšířit o atribut type s hodnotami „bin“, „dec“, „hex“ a s příslušně upraveným controllorem by se pak dala použít na zobrazování dvojkových, desítkových a šestnáctkových číslic.

Pokud někomu nevyhovuje velikost sedmisegmentovky, nemusí nic upravovat v kódu, ale stačí obalit segmentovku tagy <g> a </g> a nastavit příslušnou hodnotu scale, např:

<svg>
<g transform=“scale(0.5)“>
<svg-segment x=“20“ y=“30“ value=“6“ color=“blue“></svg-segment>	
</g>
</svg>
Předmět Autor Datum
Pozn.: Je mi jasné, že daný úkol lze realizovat mnoha způsoby, jistě jsou i elegantnější než moje ř…
LeguanOS 03.02.2015 10:09
LeguanOS
Na takové hračičky je Angular pěkný, ale na větším komerčním projektu už bych ho nenasazoval, použil…
MaSo 03.02.2015 10:41
MaSo
Pěkné. Když jsem ale testoval HTML5 inputy, některé prohlížeže to nezvládaly a tak dělám stále posta…
Kráťa 03.02.2015 14:12
Kráťa
Kráťa • Proc nenapises o tech "HTML5 input" naké clanek? (pripadne mi to zajimavejsi s rozsahlejsim…
CoCoChanel 03.02.2015 14:41
CoCoChanel
Já testoval pouze tento input "date". Na článek by to jednak nebylo a druhak se necítím být natolik…
Kráťa 03.02.2015 21:57
Kráťa
V Konqueroru je to ještě vtipnější. Je tam sice cvakátko-klikátko na vytažení roletky, leč nejde zma…
Rce 05.02.2015 03:22
Rce
To nemá chybu! :-) poslední
Kráťa 05.02.2015 10:34
Kráťa

Pozn.: Je mi jasné, že daný úkol lze realizovat mnoha způsoby, jistě jsou i elegantnější než moje řešení :-)

Tak proč pises članek?

Článek o HTML bez řadku 'html' dobry vtip, :-D Chtělo by to víc praxe a techniky před napsaním članku (malé A4), nebo upozornit ze se jen učíš ;-)
Jinak hezké :-)

Na takové hračičky je Angular pěkný, ale na větším komerčním projektu už bych ho nenasazoval, použil něco jiného (React) nebo počkal bych na verzi 2, která bude podle všeho postavená úplně jinak a dořeší neduhy jedičky...

Pěkné. Když jsem ale testoval HTML5 inputy, některé prohlížeže to nezvládaly a tak dělám stále postaru.
Teď jsem se tam podíval
input-date
a Firefox to stále neumí.

Kráťa

• Proc nenapises o tech "HTML5 input" naké clanek? (pripadne mi to zajimavejsi s rozsahlejsim vyuzitim)
• Jako clanek o <HTML> se mi to zda jako zajimavejsi koncept nez Angular .

Zpět na články Přidat komentář k článku Nahoru