Navigation

    Logo
    • Register
    • Login
    • Search
    • Recent
    • Tags
    • Unread
    • Categories
    • Unreplied
    • Popular
    • GitHub
    • Docu
    • Hilfe
    1. Home
    2. Deutsch
    3. Visualisierung
    4. Bestes Widget ?

    NEWS

    • Neuer Blog: Fotos und Eindrücke aus Solingen

    • ioBroker@Smart Living Forum Solingen, 14.06. - Agenda added

    • ioBroker goes Matter ... Matter Adapter in Stable

    Bestes Widget ?

    This topic has been deleted. Only users with topic management privileges can see it.
    • OliverIO
      OliverIO @OliverIO last edited by OliverIO

      @oliverio

      so nach dem letzten Post habe ich mich auchmal noch versucht.
      Der folgenden Code kann die folgenden Ereignisse abdecken und dann in einen Datenpunkt schreiben

      Click
      DoubleClick
      Longpress

      Bei Longpress kann man die minimale Zeit und maximale Zeit noch angeben.
      Der Code für das Tag kann noch optimiert werden, so das man eigentlich nur ein ereignis (mousedown) definieren müsste, aber jetzt erstmal mit diesem code probieren.

      das kommt in ein html widget

      <div style="width:100%;height:50%"
        onClick="func(event,'0_userdata.0.test2');" 
        onMousedown="func(event,'0_userdata.0.test2');"
        onmouseup="func(event,'0_userdata.0.test2');"
        ondblclick="func(event,'0_userdata.0.test2');" 
      >xxx</div>
      <div style="width:100%;height:50%"
        onClick="func(event,'0_userdata.0.test3');" 
        onMousedown="func(event,'0_userdata.0.test3');"
        onmouseup="func(event,'0_userdata.0.test3');"
        ondblclick="func(event,'0_userdata.0.test3');" 
      >xxx</div>
      

      Das kommt in den Reiter "Skripte" der view

      var minPressDelay=1000;
      var maxPressDelay=5000;
      var eventDebounceDelay = 200;
      
      function func(e,dp) {
          var element = e.currentTarget;
          var diff=0;
          var etype="";
      
          if ($(element).data("time")) diff = e.timeStamp - $(element).data("time");
          if (e.type=="mousedown") $(element).data("time", e.timeStamp);
          if (e.type=="mouseup") $(element).data("time", 0);
          if (diff>minPressDelay && diff<maxPressDelay) etype="longpress";
          if (e.type=="click") etype="click";
          if (e.type=="dblclick") etype="dblclick";
          if (etype) {
              if (etype=="click" && $(element).data("lastevent")=="longpress") return;
              $(element).data("lastevent",etype);
              var oldTimer = $(element).data("timer");
              clearTimeout(oldTimer);
              var newTimer = setTimeout(function(){
                  console.log("Event: " + etype + " for datapoint " + dp);
                  vis.setValue(dp,etype);
                  $(element).removeData("lastevent");
                  $(element).removeData("timer");
               
                       },200);
              $(element).data("timer",newTimer);
          }
      }
      

      Es gibt hier 3 konfigurierbare Werte, wie schon erwähnt
      minPressDelay und maxPressDelay
      longpress wird nur erkannt, wenn es zwischen diesen beiden Werten in Millisekunden liegt
      eventDebounceDelay muss je nach Hardware eingestellt werden, wie schnell die reagiert und läuft. Einfach mal probieren. Da während dem ganzen Klicken und drücken diverse Ereignisse erzeugt werden, müssen diese weggepuffert werden.
      Beispiel für ein einfaches Click werden die folgenden Ereignisse der Reihe nach erzeugt

      mousedown mouseup click
      

      oder für doubleclick

      mousedown mouseup click mousedown mouseup click dblclick
      

      damit nicht ganz wild der datenpunkt befeuert wird, wird eine gewisse zeit gewartet wird (bspw um das letzte click vom eigentlichen dblclick zu unterscheiden.

      bitte beachtet die width und height angaben des divs anzupassen, so das das element auch den ganzen Raum ausfüllt.

      OliverIO 1 Reply Last reply Reply Quote 1
      • S
        seek1338 @OliverIO last edited by

        @oliverio

        Wow erstmal vielen Dank für die Antworten und den Tipp mit dem vergessenen "clearTimeout(timer);", ich hab den nun in der Funktion "function revert(objID,visObjID)" ergänzt.

        Aber es hat auch davor funktioniert, nacheinander, abwechselt long und short?? Das Mit dem Doubleklick hatte ich auch drin aber ich hab wegen einer möglichen falschen Klick/Doubleklick unterscheidung am Touch die finger davon gelassen.

        Ich hab mir auch ein bisschen deine Links und Skripte angeschaut und muss sagen es übersteigt "etwas" meine JS-Fähigkeiten 🤕 .... bin erstmal froh das es so funktioniert, verbesserungen werden aber bestimmt mit der Zeit folgen - Danke!

        Zu deiner Frage wieso ich zuerst den Status auslese:
        Wenn das Licht aktuell an ist, wird es beim Click ausgeschaltet und wenn es aus ist, wird es beim Click eingeschaltet. So eine Art schnelle On/Off Funktion fürs licht beim Single Click. Soweit ich das kenne muss man dafür vorab den Status abrufen.

        Zu meiner unverstandenen Frage:
        Es gibt im VIS ein Widget das Nennt sich "Filter - dropdown", in diesem kann man "Tags" definieren, die man anzeigen lassen möchte und alle Widgets die nicht dieses Tag haben werden deaktiviert. Das Widget ist im Standard Projekt drin wenn man ein neues anlegt, von daher kenn ich es auch.

        Ich würde gerne die Funktion im Skript beim Longpress abbilden und die Widgets die Angezeigt oder Ausgeblendet werden pro Zimmer via "Tags" dann über die VIS steuern und nicht wie jetzt, über ein Datenpunkt im Iobroker und der Sichtbarkeits Objekt ID im VIS z.b. wie ich mir das vorstelle im code:

        function makeChange(objID,tag)
        {
            if(timer)
            clearTimeout(timer);
            
            if(istrue)
            {
                //Longpress Event
                istrue =false;
                vis.showTag(tag);
            }
        }
        

        aber ich habe keine Funktion gefunden die diese Tags aktiviert oder deaktiviert. ich weiß auch nicht in wie fern die Sichtbarkeit eines Widget, welche über eine Objekt ID gesteuert wird in JS verwendung findet (JS getElement by ID und Ocupacy = 0?) oder dergleichen....

        ich hoffe ich habe mich nun verständlicher ausgedrückt 😊

        mfg,
        Seek

        OliverIO 1 Reply Last reply Reply Quote 0
        • OliverIO
          OliverIO @seek1338 last edited by

          @seek1338

          das kannst du erreichen, indem du per programm in der selectbox einen wert auswählst.
          Mit jquery ist es relativ einfach

          $('#w00000 select').val("Name deiner View bzw. Filterworts")
          

          Mit jQuery sucht man über sogenannte css selectoren ein oder mehrere Elemente und kann dann funktionen daran ausführen. In meinem Skript verwende ich diverse dieser Befehle.
          jquery wird in vis automatisch schon mitgeladen.

          Der angegebene Selektor '#w00000 select' bedeutet
          suche nach ID w00000 und innerhalb dieses Elements nach dem Select-Tag
          https://kulturbanause.de/blog/css-selektoren/

          Es ist der selbe Mechanismus, mit dem man mit CSS Elemente formatieren kann.

          Mit dem Unterbefehl .val("Wert") kannst du die Auswahl bestimmen.
          https://api.jquery.com/val/
          Ich habe das jetzt selbst nicht in diesem Kontext ausprobiert.

          1 Reply Last reply Reply Quote 1
          • OliverIO
            OliverIO @OliverIO last edited by

            @oliverio

            Hier noch zur Vollständigkeit und für die Nachwelt
            Ich habe das obige Skript von der Anwendung nochmals vereinfacht, so das man nur noch einmal die Funktion im Tag angeben muss

            Hier der Inhalt für das html widget

            <div style="width:100%;height:50%"
              onMousedown="func(event,'0_userdata.0.test2');"
            >xxx</div>
            <div style="width:100%;height:50%"
              onMousedown="func(event,'0_userdata.0.test3');"
            >xxx</div>
            
            

            Hier das Skript, welches in den Skripte-Reiter der jeweiligen view muss

            var minPressDelay=1000;
            var maxPressDelay=5000;
            var eventDebounceDelay = 200;
             
            function func(e,dp) {
                var element = e.currentTarget;
                var diff=0;
                var etype="";
                $(element).off(".longpress");
                $(element).on("mouseup.longpress",function(dp,event){func(event,dp)}.bind(this,dp));
                $(element).on("click.longpress",function(dp,event){func(event,dp)}.bind(this,dp));
                $(element).on("dblclick.longpress",function(dp,event){func(event,dp)}.bind(this,dp));
                if ($(element).data("time")) diff = e.timeStamp - $(element).data("time");
                if (e.type=="mousedown") $(element).data("time", e.timeStamp);
                if (e.type=="mouseup") $(element).data("time", 0);
                if (diff>minPressDelay && diff<maxPressDelay) etype="longpress";
                if (e.type=="click") etype="click";
                if (e.type=="dblclick") etype="dblclick";
                if (etype) {
                    if (etype=="click" && $(element).data("lastevent")=="longpress") return;
                    $(element).data("lastevent",etype);
                    var oldTimer = $(element).data("timer");
                    clearTimeout(oldTimer);
                    var newTimer = setTimeout(function(){
                        console.log("Event: " + etype + " for datapoint " + dp);
                        vis.setValue(dp,etype);
                        $(element).removeData("lastevent");
                        $(element).removeData("timer");
                    },200);
                    $(element).data("timer",newTimer);
                }
            }
            
            

            Dieses Skript erzeugt nun seine noch fehlenden Ereignishandler selber,
            so dass nur noch onmousedown angegeben werden muss.
            Die Erklärung der restlichen parameter steht im Vorgängerpost

            S 1 Reply Last reply Reply Quote 0
            • S
              seek1338 @OliverIO last edited by

              @oliverio danke für den jquery tipp ich muss mich da einlessen ich habe das noch nie verwendet bzw. wie man dann daten setzten kann.

              ich hab mein input auch umbauen müssen auf onpointerdown/onpointerup weils am touch nicht funktioniert hat nur mit der maus am pc 🙂

              <input style="height: 100%;width: 100%" type="button" onpointerdown="func('hm-rpc.0.OEQ0236727.3.STATE','0_userdata.0.VIS.buero')" onpointerup="revert('hm-rpc.0.OEQ0236727.3.STATE','0_userdata.0.VIS.buero')" value="foo"/>
              

              ich hab auch dein Skript getestet - wenn auch nicht verstanden, aber ich blick nicht so ganz durch und wenn man so periodisch alle 0,5 Sek drauf drückt erkennt er mal short und longpress (laut console) ? Wollt dich nur drauf aufmerksam machen.

              mfg,
              Seek

              OliverIO 1 Reply Last reply Reply Quote 0
              • OliverIO
                OliverIO @seek1338 last edited by OliverIO

                @seek1338

                dann musst du mit der eventDebounceDelay wahrscheinlich verlängern.
                Eigentlich müsste die exakt auf der Zeit liegen, die das Betriebssystem als Zeit für ein doubleclick vorgesehen hat. Die kenn ich aber nicht.

                Short? welches short?

                Welche Zeile/Zeilen verstehst du nicht.
                Wenn du sehr allgemein fragst kann man nicht antworten.

                Ok,Eventhandling im browser ist schon etwas fortgeschritteneres.
                Es hilft da auch mal mit dem debugger reinzugehen. Allerdings bitte nicht in die tiefen von jquery absteigen. das ist megaoptimiert, das verstehe ich auch manchmal nicht mehr.

                Die Befehle mit off und on löschen oder definieren die ereignisbehandlung für das betroffene element
                Die komplette Logik für alle ereignisse wurden in dieser einen Funktion untergebracht

                Die if-Abfragen fragen ab, für welches Event die Funktion gerade aufgerufen wurde und übernehmen für die relevanten ereignisse click, dblclick die werte.

                Bei mousedown merkt er sich die Zeit und bei mouseup setzt er den zeitzähler wieder zurück

                wenn die Zeit lang genug war bei mouseup, erkennt er den etype longpress

                Alles was innerhalb des Abschnitts mit if (etype) {
                statt findet ist das entprellen der vielen Ereignisse, so das nur die relevanten Ereignisse das schreiben eines States auslösen..

                Hier ist noch eine Sonderbehandlung für click und longpress drin, da das click ereignis nicht abgebrochen werden kann. daher muss er sich das jeweils letzte ereignis merken. nur wenn click auf longpress folgt, dann wird click unterdrückt.
                Wenn der State dann geschrieben wurde, wird timer und lastevent wieder aufgeräumt

                S 1 Reply Last reply Reply Quote 0
                • S
                  seek1338 @OliverIO last edited by seek1338

                  @oliverio

                  ok ich glaub ich verstehe was du meins, du setzt mit var element = e.currentTarget; ein pointer auf das element und fragst bzw generierst via "$(element).on(" die events direkt im skript ab und brauchst dann nicht mehr im div/input feld mehrfach einträge.

                  Im gesamten verstehe ich dein skript jedoch nicht zu 100%, weil ich diese schreibweise mit element und data nicht kenne und die checks sowie die abhängigkeiten im vergleich zu meinem Skript komplizierter (für mich) geschrieben sind (js noob).

                  Nachdem ich kurz mit jQuery herumexperimetiert habe (wer das auch immer erfunden hat war auf drogen), hab ich einen anderen weg gesucht und im quelltext der VIS gefunden:
                  https://github.com/ioBroker/ioBroker.vis/blob/master/www/widgets/basic.html

                  //ab Zeile 488
                  $this.find('select').change(function () {
                            vis.changeFilter(null, $this.find('select option:selected').val(), hideEffect, hideDuration, showEffect, showDuration);
                  });
                  

                  dann im eigentlichen vis file nachgeschaut:
                  https://github.com/ioBroker/ioBroker.vis/blob/master/www/js/vis.js

                  ab Zeile 1092 fa läuft die funktion... auch nciht viel verstanden aber jquery unter andem gefudnen und auch folgenden hinweis:

                  if (widgets[widget] && widgets[widget].data && widgets[widget].data.filterkey) {
                         $('#' + widget).show(showEffect, null, parseInt(showDuration));
                  }
                  

                  sieht für mich so aus als würde jquery alleine nicht helfen sondern die Tags ein bestands element vom Widget.data sind.

                  also ein bisschen gespielt und nach ein paar fehlern folgendes zum funktionieren gebracht:

                  vis.changeFilter(null, "buero_detail", null, null, null, 3000); //zeigt widgets mit dem TAG buero_detail an
                  vis.changeFilter(null, "all", null, null, null, 3000); //widgets mit anderen tags verschwinden wieder
                  

                  die widgets mit tags, die man einblenden und ausblenen lassen möchte, müssen sichtbarkeit haben und das Prüfelement muss gegen ein false Objekt immer beim starten auf unsichtbar sein (so hab ichs gelöst, vielleicht geht es auch eleganter).

                  muss jetzt nur noch ein weg finden wie ich die tags an die jeweiligen input felder binde (eventuell value vom inputfeld) und dann mit einem true/false jeweils eins der befehle zum anzeigen oder ausblenden bewege.

                  wenn ich ein weg gefunden habe poste ich das gesammelte nochmal rein

                  mfg,
                  Seek

                  BananaJoe 1 Reply Last reply Reply Quote 0
                  • BananaJoe
                    BananaJoe Most Active @seek1338 last edited by BananaJoe

                    @seek1338 ich habe das einfach mit dem "Basic - Bulb (on/off)" gemacht,
                    Als Overlay arbeite ich wie folgt:

                    • Hintergrund mit Licht aus
                    • Off einfach ein Transparentes .png
                    • On dann ein .png mit Licht an

                    So kann ich einfach einmal auf den Raum drauftippen.
                    cde38f1f-9dea-4846-8967-cf11e3b3b175-image.png
                    b494fef5-a9c4-4bd2-96e9-3426c7ffab10-image.png

                    Aber am Thema vorbei, du wolltest ja Alternativmenüs - die habe ich bei mir mit den sichtbaren extra-Buttons gelöst.
                    Alternativ über dasObjekt einen weiteren Bulb legen und im Z-Index weiter nach oben setzen.
                    Und dann z.B. ein Popup-Menü aufrufen lassen

                    S 1 Reply Last reply Reply Quote 0
                    • S
                      seek1338 @BananaJoe last edited by

                      @bananajoe danke... das mit dem Overlay funktioniert schon lange, war auc ham einfachsten... mir gehts drum dieses Extrabutton zu vermeiden.
                      Click = Licht An/Aus
                      Longpress (0,5Sek) = Extramenü (mit den weiteren Raum Optionen oder vll eine Raumansicht im neuen View, bin noch unentschlossen)

                      Aber ich habs fast 😵 😬

                      1 Reply Last reply Reply Quote 0
                      • S
                        seek1338 last edited by

                        so nachdem nun endlich das Skript so ist wie ich es mir gewünscht habe, danke an alle die mir geholfen haben und/oder mich am richtigen weg gebraucht haben 😊

                        Was das Ziel war:
                        Unsichtbares HTML Overlay über ein Zimmer

                        • bei Click geht das Licht An oder Aus, je nach aktuellem Status
                        • bei long Press am Zimmer tauchen Widgets auf welche zu vor mit einem entsprechenden Filterwort versehen wurden (werden nach x Sekunden wieder ausgeblendet)

                        Vorraussetzung:
                        .) Dieses Skript funktioniert nur sofern aktuell keine anderen Widgets oder Navigationen mit Filterwörter verwendet werden!
                        .) Alle Widgets welche mit Filterwort genutzt werden sollen, müssen beim Starten unsichtbar sein. Hierfür im Sichtbarkeits Objekt Verlinkung einen manuell erstelten Datenpunkt auswählen welcher imer auf fals steht (z.b. 0_userdata.0.VIS.false_state = false) eventuell kann man das schöner lösen ich weiß es nicht

                        HTML Overlay - HTML Code:

                        <input id="buero" style="height: 100%;width: 100%" type="button" onpointerdown="func('hm-rpc.0.OEQ0236727.3.STATE','buero_detail')" onpointerup="revert('hm-rpc.0.OEQ0236727.3.STATE','buero_detail')"/>
                        

                        Wobei:
                        "hm-rpc.0.OEQ0236727.3.STATE" - muss mit deinem IoBroker Objekt Pfad zu deinem licht getauscht werden
                        "buero_detail" - ist das Filterwort das die für das Zimmer Relevanten Widgets haben müssen

                        Vis JS-Skript:

                        var timer;
                        var hidetimer;
                        var istrue = true;
                        var filterVisible = [];
                        var delay = 500; // after delay Click = Longpress
                        var showTime = 5; // sek after hide shown Tag-Widgets
                        
                         //objID    = Objekt ID from Device z.b. hm-rpc.0.OEQ0236727.3.STATE
                        //visObjID = Widget Tag
                        function func(objID,visObjID)
                        {
                            istrue = true;
                            timer = setTimeout(function(){ makeChange(objID,visObjID);},delay);
                        }
                        
                        function makeChange(objID,visObjID)
                        {
                            if(timer) clearTimeout(timer);
                            if(hidetimer) clearTimeout(hidetimer);
                            
                            if(istrue) 
                            { //Longpress Event Start
                                istrue = false;
                                
                                //IF visObjID is not set!
                                if(typeof filterVisible[visObjID] === 'undefined') 
                                {   
                                    //Show Widget with Tags = visObjID
                                    vis.changeFilter(null, visObjID, null, null, null, null);
                                    
                                    clearArray(filterVisible);      //Clear other visObjID entrys
                                    filterVisible = [];             //Set back to Array
                                    filterVisible[visObjID] = true; //set status for this visObjID
                                    
                                    //Hide after (showTime) Sek the Tags-Widgets
                                    hidetimer = setTimeout(function(){ 
                                        //Hide Back Widgets with Tags = visObjID
                                        vis.changeFilter(null, "TagNotExists", null, null, null, null);
                                        
                                        clearArray(filterVisible);  //clear 
                                        filterVisible = [];         //Set back to Array
                                    }, showTime*1000)
                                } 
                                //if the same visObjID and visObjID = true
                                else
                                {
                                    //Hide Back Widgets with Tags = visObjID
                                    vis.changeFilter(null, "TagNotExists", null, null, null, null);
                                    
                                    clearArray(filterVisible);  //clear 
                                    filterVisible = [];         //Set back to Array
                                }    
                            }
                        }
                        
                        function revert(objID,visObjID)
                        {
                            if(timer && istrue) 
                            { //Click Event
                                clearTimeout(timer);
                                istrue = false;
                        
                                //Get ObjektID Status (Bool) and set oposide (Light On/Off)
                                servConn._socket.emit('getStates', objID, (error, states) => {
                                    servConn._socket.emit('setState', objID, !states[objID].val);
                                });
                            }
                        }
                        
                        function clearArray(array) {
                            while (array.length) {
                                array.pop();
                            }
                        }
                        

                        Wobei:
                        var delay = zeit in ms, welche mindestens für ein Longpress vergehen muss (bitte testet das auf euer system)
                        var showTime = zeit in sekunden, nach welcher die eingeblendeten widgets wieder ausgeblendet werden

                        Wichtig:
                        Solltet Ihr Lichter haben welche andere Werte als false oder true vorraussetzen funktioniert dieses Skript ohne umbau nicht!! Bitte hierfür den Bereich in der revert Funktion bearbeiten z.b.: (ungetestet):

                        servConn._socket.emit('getStates', objID, (error, states) => {
                        	if(states[objID].val == 0) 
                        		servConn._socket.emit('setState', objID, 1);
                        	else 
                        		servConn._socket.emit('setState', objID, 0);
                        });
                        

                        Hat mich echt was an Zeit gekostet und ich denke das JS-Skript geht auch besser, aber es funktioniert und macht was es soll 😉

                        danke nochmals besonder @oliverio für den tiefen einblick 👍

                        mfg,
                        Seek

                        1 Reply Last reply Reply Quote 1
                        • First post
                          Last post

                        Support us

                        ioBroker
                        Community Adapters
                        Donate

                        926
                        Online

                        31.9k
                        Users

                        80.1k
                        Topics

                        1.3m
                        Posts

                        4
                        20
                        1815
                        Loading More Posts
                        • Oldest to Newest
                        • Newest to Oldest
                        • Most Votes
                        Reply
                        • Reply as topic
                        Log in to reply
                        Community
                        Impressum | Datenschutz-Bestimmungen | Nutzungsbedingungen
                        The ioBroker Community 2014-2023
                        logo