Public Documentation
  • Introduction
  • Getting started
    • Introduction
    • 1. Welcome Page
    • 2. Introduction (Beginner's Guide)
  • Portal Tools
    • Blocko
      • Ůvod do blocka
      • Flip-flop
      • REST-API bloček
    • Grid
      • Úvod do GRID
      • Základní Tlačítko (základy GRID)
      • vylepšený Přepínač (stylování a pokročilé možnosti GRID)
      • text generátor button (messeage type, two elements one widget)
      • graf (pokročilé funkce GRID)
      • Slider (User class v GRIDu)
      • Styly a jejich použití
  • Cloud
    • Cloud
    • Instancies
    • Rest-Api
  • General
    • What we plan
  • Hardware a programování
    • Úvod
      • Nahrání prvního programu
    • Konektivita
      • Specifikace zdroje internetu
      • GSM
      • 6LowPAN
      • Komunikace s portálem
      • Přepínání mezi servery
    • Hardware
      • Základní jednotky
        • IODAG3E
          • Rozhraní a periférie
          • Konektor X a Y
          • Napájení
          • Připojení zdroje k VBAT
          • Paměti
          • Technické specifikace
          • Schémata
        • IODAG3L
      • Rozšiřující moduly
        • GSM shield
        • LED shield
        • Relay shield
        • RFID shield
        • Ultrasonic shield
        • Meteo shield
        • Movement shield
        • PIR shield
        • RGB Displej shield
        • Serial shield
      • Ostatní
        • DevKitG3
          • Schéma
        • TK3G
          • Schéma
        • ZPPG3
          • Schéma
        • WEXP
    • Programování HW
      • Architektura FW
        • Aktualizace FW
        • Autobackup
      • Struktura programu
      • Byzance API
        • Vstupy a výstupy do Portálu
        • Callback Busy
        • Odložený restart
        • Callbacky připojení
        • Uživatelská makra
      • MBED API
        • Vstupy a výstupy
        • Komunikační rozhraní
        • Časování
        • RTOS
      • Knihovny
        • DHT
        • DS1820
        • Dali
        • EdgeStruct
        • I2CWrapper
        • Knock
        • MFRC522
        • MFRC522::MIFARE_Key
        • MPU9150
        • ms5637
        • OneWire
        • PCA9536
        • RGB_matrix
        • RollerDrive
        • SHT21
        • ST7565
        • Servo
        • TCA6424A
        • TLC59116
        • TripleSevenSeg
        • MFRC522::Uid
        • WS2812
        • WakeUp
      • Offline programování
        • Vlastní IDE
        • Upload kódu z GUI
        • Upload kódu z konzole
        • Upload kódu Drag&drop
    • Tutoriály
      • Datum a čas (RTC)
      • Komunikace po sériové lince (UART) s PC
        • Konfigurace sériové linky v PC
        • Programování sériové linky
      • Základní tutoriály
        • Digital Read
        • Analog Read/Write
        • PWM Fade
        • Timer/Ticker
        • State Change Detection
        • Ovládání LED modulu
        • BusOut
        • HC-SR04 Senzor
      • Pokročilé
    • Správa a diagnostika
      • Zdroj restartu
      • LED modul
      • Identifikace zařízení
      • Monitoring parametrů
      • Vytížení zařízení
      • Webové rozhraní
        • Základní přehled
        • Správce firmware
        • Vlákna
        • Definované vstupy
        • Konfigurace MQTT
        • Nastavení
      • Bootloader
        • Režimy bootloaderu
        • Command mód
        • Další vlastnosti bootloaderu
      • Webová konzole
      • Konfigurace zařízení
        • Confighash
      • Omezení konfigurace
        • Konfigurace
        • Binárky
        • Omezení MQTT
        • Lowpan
    • Knowledge base
      • Náhodná čísla
      • Watchdog
      • Paměť RAM
Powered by GitBook
On this page
  • Začátek třídy
  • Konstruktor třídy:
  • Mock funkce pro listenery:
  • Přidání Slideru do widgetu
  • přidání getterů a pokrytí základní funkčnosti
  • event listenery ve třídě:
  • přidání funkcí
  • doladění detailů
  • Nastavení vstupu/výstupu a konečné řešení
  1. Portal Tools
  2. Grid

Slider (User class v GRIDu)

Previousgraf (pokročilé funkce GRID)NextStyly a jejich použití

Last updated 7 years ago

Grid dokáže být až překvapivě tvárný a dají se v něm dělat i složitější věci, doslova od píky.

Co udělat horizontální slider, jako třeba tento?

Začátek třídy

Začneme tím, že si vytvoříme Widget a pojmenujeme si ho Hslider.

Vyjměčně nezačneme s context.addSizeProfiles ale s třídou Slider.

class Slider{


}

a přidáme do naší třídy několik promněných pro práci s ní:

class Slider {
    protected _emitter: WK.Emitter<WK.Event>;
    // slouží k tomu, abychom mohli přidat event.listener na tento objekt

    protected _rootView: WK.View; // main element, aby to všechno bylo na co dát (něco jako context.root) pro tuto třídu
    protected _backgroundElement: WK.View; // na celkové podbarvení panelu
    protected _valueElement: WK.Element; // na podbarvení vybrání pod tlačítkem
    protected _buttonElement: WK.Button; // na vytvoření kulatého tlačítka

    protected _reversed: boolean = false; // později budeme chtít možnost "invertovat graf" 
    protected _moving = false; 
    protected _movingOffset = 0; //je můžné, že tlačítko bude např. v půli grafu, zde si budeme ukládat aktuální posun tlačítka od 0 
    protected _value = 0; 

    constructor(){

    }

    }

Konstruktor třídy:

a v kontsruktoru je vytvoříme a nastylujeme. Samozřejmě pro vytvoření prvků potřebujeme context, proto si ho prřidáme do konstruktoru.

constructor(context: WidgetContext){
        this._emitter = new WK.Emitter<WK.Event>(); //inicializaace emitoru
        this._rootView = new WK.View(context); //inicializace našeho root.view

        //přidáme stylizaci
        this._rootView.style.padding = "22px"; // chceme, aby posuvník byl uprostřed 1 čtverečku
        this._rootView.style.background = "transparent"; // necheme pozadí, proto průhledná 


        this._backgroundElement = new WK.View(context); // inicializace
        this._backgroundElement.style.background = "#838383"; // nastaavíme šedou po celé délce
        this._backgroundElement.style.height = "10px"; // tímto z toho uděláme tenký proužek
        this._backgroundElement.style.y = "-3px"; // kvůli paddingu děláme drobnou korekturu
        this._backgroundElement.style.width = "100%"; // roztáhneme ho po celé šíři widgetu
        this._backgroundElement.style.radius = "5px"; //zakulatíme rohy
        this._rootView.add(this._backgroundElement);  //přidáme element na náš základní element

        this._valueElement = new WK.Element(context); // inicializace
        this._valueElement.style.background = "#2274ff";
        this._valueElement.style.height = "10px";
        this._valueElement.style.y = "0";
        this._valueElement.style.width = "0";
        this._valueElement.style.radius = "0";
        this._backgroundElement.add(this._valueElement);

        this._buttonElement = new WK.Button(context,"");// inicializace
        this._buttonElement.style.width = "30px"; //
        this._buttonElement.style.height = "30px"; // nastavíme velikosst tlačítka napevno
        this._buttonElement.style.x = "0"; 
        this._buttonElement.style.y = "2px";
        this._buttonElement.style.radius = "15px" //tímto tlačítko bude kulaté
        this._buttonElement.style.border = "#FFFFFF 5px"; //nastavíme hezký, velký zdobný okraj
        this._buttonElement.style.background = "#2274ff";
        this._buttonElement.style.shadow = "#000000 30px 0 0"; //vytvoříme stín, přímo pod tlačítkem
        this._buttonElement.style.originX = "0.5";
        this._buttonElement.style.originY = "0.5"; 
        this._rootView.add(this._buttonElement);
}

A nakonec přidáme několik listenerů do _constructor_u, abychom mohli manipulovat s posuvníkem

 this._buttonElement.listenEvent("mousedown",this.onButtonMouseDown); //reagování při kliknutí na button
 this._backgroundElement.listenEvent("mousedown",this.onBackgroundMouseDown); // reakce při kliknutí kamkoliv na posuvník
 context.root.listenEvent("appmouseup",this.onAppMouseUp); //ve chvíli kdy uživatel pustí tlačítko
 context.root.listenEvent("appmousemove",this.onAppMouseMove); //kvůli celemů posuvníku je třeba vyřešit co jak moc uživatel posunul

Mock funkce pro listenery:

Jistě jste si všimli, že místo kasického e => { foo.bar() }); voláme funkci, proto si rovno vytvoříme prázdé funkce, později se k ním vrátíme.

/*MIMO KONSTRUKTOR, ALE POŘÁD DO NAŠÍ TŘÍDY Slider*/

   protected onButtonMouseDown = (e) => { 
    }

   protected onBackgroundMouseDown = (e) => {      
    }

   protected onAppMouseUp = (e) => {
    }

   protected onAppMouseMove = (e: WK.MouseEvent) => { 
    }

Přidání Slideru do widgetu

pokud si chceme otestovat, že náš widget je nastylovaný správně, přidáme getter do naší třídy

  public get rootElement(): WK.View {
        return this._rootView;
    }

a poté úplně mimo třídu napíšeme

context.addSizeProfiles(3,1,50,1);

let slider = new Slider(context);
slider.rootElement.style.width = "100%";
slider.rootElement.style.height = "100%";
context.root.add(slider.rootElement); //přidáme slider.rootElement, na který jsme napojili všechny ty prvky dohromady

při testování dostaneme něco takového:

Můžeme trochu upravit pozice všech objektů.

přidání getterů a pokrytí základní funkčnosti

Upravíme naší třídu. Přidáme do ní ještě několik getterů

    public getButtonElement(): WK.Button {
        return this._buttonElement;
    }

    public getBackgroundElement(): WK.View {
        return this._backgroundElement;
    }

    public getValueBarElement(): WK.Element {
        return this._valueElement;
    }
      public get isMoving(): boolean {
        return this._moving;
    }

Abychom později mohli měnit detaily jako barvy, zaoblení rohu apod.

event listenery ve třídě:

Přidáme možnost poslouchat události ve třídě

public listenEvent(key: "valueChanged" , callback: (event: WK.Event) => void): WK.Listener<WK.Event> {
        return this._emitter.listenEvent(key, callback);
 }

Jedné, co děláme je, že vrátíme přesněji typovaný emmiter, ke kterému jsme přidali specifikovaný key a callback.

Napíšeme si kód, jenž bude posouvat posuvník, pro širší využití budeme pracovat v procentech (1 = 100%, 0.5 = 50%, 0.25 = 25%)

  protected internalSetValue(value: number) { 
         this._value = Math.min(Math.max(value, 0), 1); //podobně jako u grafu, jak jsme vybírali větší číslo

        this._valueElement.style.width = value * 100 + "%"; //šířka podbavení

        if (this._reversed) { //později přidáme i možnost mít posuvník z druhé strany, připravíme si tedy danou možnost předem
            this._buttonElement.style.x = (1 - value) * 100 + "%";// v případě že chceme invertovanou hodnotu
        } else {
            this._buttonElement.style.x = value * 100 + "%"; //posun tlačítka(posuvníku) na správnou pozici
        }
     }

Rovnou přidáme možnost umožnit mít posuvník "obráceně"

  public setReversed(reversed: boolean) {
        if (this._reversed != reversed) { //pokud se hodnoty, co aktuálně máme liší od té, co chceme
            this._reversed = reversed;

            if (this._reversed) {
                this._valueElement.style.originX = "1"; 
                this._valueElement.style.x = "100%"; //tímto "překlopíme" value.element, jenž podbarvuje posuvník 
            } else {
                this._valueElement.style.originX = "0";
                this._valueElement.style.x = "0";
            }
            this.internalSetValue(this._value); //aby se změny dostaly i k posuvníku
        }
    }

Do budoucna ještě pro posun tlačítka

   protected setButtonPosition(e: WK.MouseEvent) {
        const max = this._rootView.visibleRect.size.width; //zapamatujeme si max. šířku panelu
        let newX = Math.min( Math.max(e.mousePosition.x - this._movingOffset, 0), max); //tooto rozepíšu o kousek níže
        this._value = newX / max;

        if (this._reversed) { //kontrolujeme zda nescrollujeme z druhé strany
            this._value = 1 - this._value;
        }

        this.internalSetValue(this._value); //nastavíme novou "vnitřní" hodnotu
        this._emitter.emit(this, new WK.Event("valueChanged")); //vyšleme změny komukoliv,kdo je poslouchá
    }

zaměříme se na let newX = Math.min( Math.max(e.mousePosition.x - this._movingOffset, 0), max); nejedná se o nic složitého, jenom menší číslo, abychom nevyjeli z pole, ze dvou možných, kde ještě upravujeme, abychom se nedostali pod nulu. Nejdříve vyhodnotíme zda je pozice posuvíku (mínus offset pro správnou pozici) větší než nula a později, jestli nepřekračujeme nejvyšší možnou.

přidání funkcí

Když už jsme si konečně dopsali veškeré potřebné drobnosti pro barvení a posuv tlačítek, přidáme interaktivitu.

Přepíšeme původní prázdné funkce na:

protected onButtonMouseDown = (e) => {
        if (this._buttonElement.isHover) { //kontrolujeme, zda opravdu je kurzor nad tlačítkem
            this._moving = true; //potvrdíme že se hýbe s posuvníkem
            this._movingOffset = e.mousePosition.x - this._buttonElement.visibleRect.position.x; // uložíme si bokem offset, odkud se tlačítko posouvalo
        }
   }

Zde nám pouze stačí "přepnout" boolean na přesun, změnu hodnoty provedeme v "onAppMouseMove".

samozřejmě, kromada uživatelů spíše než tahem tlačítka preferuje klikání přímo na lištu posuvníku, proto přepíšeme interaktivitu k němu

protected onBackgroundMouseDown = (e) => {
        if (this._backgroundElement.isHover && !this._buttonElement.isHover) { //kontrolujeme, zda je myš na liště, ale né na tlačítku (pustili bychom tímto dvě funkce najednou)
            this._movingOffset = this._buttonElement.visibleRect.size.width / 2;
            this.setButtonPosition(e);
        }
    }

Všimněte si, že zde _moving neupravujeme. přednostně kvůli tomu, že ve chvíli co se klikne na danou pozici

Při puštění vypneme "moving" abychom neposouvali tačítko když nechceme

  protected onAppMouseUp = (e) => {
        this._moving = false;
    }

A samozřejmě, při posunu myší, pokud držíme posuvník

  protected onAppMouseMove = (e: WK.MouseEvent) => {
        if (this._moving) {
            this.setButtonPosition(e);
        }
    }

pokud klikneme na test, tlačítko by mělo býti posuvné a reagovat

Až na ten detail, že z něj nedostáváme žádné hodnoty, doděláme ještě pár drobností.

doladění detailů

Pro jednodušší práci si ještě přidáme několik "nastavovátek" na barvy, stíny a podobné

 public setReversed(reversed: boolean) {
        if (this._reversed != reversed) {
            this._reversed = reversed;

            if (this._reversed) {
                this._valueElement.style.originX = "1";
                this._valueElement.style.x = "100%";
            } else {
                this._valueElement.style.originX = "0";
                this._valueElement.style.x = "0";
            }
            this.internalSetValue(this._value);
        }
    }

Zapínání/vypínání stínu

    public enableShadow(enabled: boolean) {
        if (!enabled) {
            this.getButtonElement().style.shadow = "none";
        } else {
            this.getButtonElement().style.shadow = "#000000 30px 0 0";
        }
    }

kulatost hran

    public enableRadius(enabled: boolean) {
        if (!enabled) {
            this.getBackgroundElement().style.radius = "0";
            this.getButtonElement().style.radius = "0";
        } else {
            this.getBackgroundElement().style.radius = "5px";
            this.getButtonElement().style.radius = "15px";
        }
    }

možnost nastavit pozadí jaké cheme my

    public setBackgroundColor(color: string) {
        this.getBackgroundElement().style.background = color;
    }

včetně "value" barvy

    public setFrontColor(color: string) {
        this.getValueBarElement().style.background = color;
        this.getButtonElement().style.background = color;
    }

a bavy okraje

    public setBorder(color: string, width: number) {
        if (width == 0) {
            this.getButtonElement().style.border = "none";
        } else {
            this.getButtonElement().style.border = color + " " + width + "px";
        }
    }

Rovnou přidáme i Setter na value (abychom mohli nastavit námi požadovanou hodnotu při vytvoření např.)

    public set value(value: number) {
        this.internalSetValue(value);
        this._emitter.emit(this, new WK.Event("valueChanged"));
    }

a tímto máme celou Slider class hotovou.

Nastavení vstupu/výstupu a konečné řešení

Mimo naší třídu, nejlépe tam, kde jsme nastavovali conext.addProfilepřidáme Vstup a výstup

let input = context.inputs.add("ain","analog","Analog input");
let output = context.outputs.add("aout","analog","Analog output");

a můžeme využít možnosti nastavit prakticky cokoliv v naší třídě

let backgroundColorProperty = context.configProperties.add('backgroundColor','color', 'Color of background', '#838383');
let frontColorProperty = context.configProperties.add('frontColor','color', 'Color of front', '#2274ff');
let outlineColorProperty = context.configProperties.add('outlineColor','color', 'Color of border', '#FFFFFF');
let outlineWidthProperty = context.configProperties.add('outlineWidth','integer', 'Size of border', 5);
let radiusProperty = context.configProperties.add('radius','boolean', 'Enable border radius', true);
let shadowProperty = context.configProperties.add('shadow','boolean', 'Enable shadow', true);
let reversedProperty = context.configProperties.add('reversed','boolean', 'Reversed', false);

přidáme tyto dva pojistné řádky (Widget by je měl automaticky povolovat, ale tímto se ujistíme, že vše funguje jak má)

context.enableGlobalMouseEvents(); //povolí globální mouse.event
context.root.style.background = "transparent"; //nastaví root. componentu průhlednou

napíšeme si funkci na to, že pokud se stane změna v "configuration", tak změníme i slider

function setupSliderFromProperties() {
    slider.enableRadius(radiusProperty.value);
    slider.setBackgroundColor(backgroundColorProperty.value);
    slider.setFrontColor(frontColorProperty.value);
    slider.setBorder(outlineColorProperty.value, outlineWidthProperty.value);
    slider.enableShadow(shadowProperty.value);
    slider.setReversed(reversedProperty.value);
}

a hned si funkci zavoláme pro počáteční nastavení

setupSliderFromProperties();

a nakonec jenom napíšeme listenery na náš slider:

slider.listenEvent("valueChanged", function(e) { //posloucháme a pošleme veškeré .emit změny. 
    output.value = (<Slider>e.target).value; // upravujeme typ objektů aby vše fungovalo. jak má
});

input.listenEvent("valueChanged", function(e) { //pokud nám příjde z input nějaká hodnota, prostě jí dosadíme do slideru
    if (!slider.isMoving) {
        slider.value = input.value;
    }
});


context.configProperties.listenEvent("valueChanged", setupSliderFromProperties); //nastavování změn

a můžeme finálně otestovat