[Widget] Dynamic Slider avec Icon

Bonjour, Ci-dessous mon widget perso sur l’action slider
(code fait à partir de l’excellent travail de @Salvialf et les astuces de @F_yann)

<div class="tooltips cmd cmd-widget" data-type="action" data-subtype="slider" data-cmd_id="#id#" data-cmd_uid="#uid#" data-version="#version#" data-eqLogic_id="#eqLogic_id#">
  <div class="title #hide_name#">
    <div class="cmdName">#name_display#</div>
  </div>
  <div id="switch_3_ways_v2#uid#" class="switch_3_ways_v2#uid#">
  </div>
  <span class="timeCmd#uid# timeCmd label label-default"></span>
<style>
 .mode_lib{
  color: white;

  border:none;
  padding:6px 8px 8px 8px;
  border-radius:4px;
  box-shadow: 0px 0px 1px 1px rgba(255,255,255,0.5);
  font:bold 25px Arial;
  vertical-align: middle;
  width:110px;
}

   .button_thp i.fa, .button i.fas, .button i.fab {
     line-height:54px
     color: grey;
   }

   .button_thp {
     box-sizing: border-box;
     border: 3px solid grey;
     color: grey;
     width: 60px;
     height: 60px;
     display: block;
     text-align: center;
     cursor: pointer;
     font-size: 30px;
     margin: 0;
     font-weight:400;
   }			
.mode_lib_small{
  color: white;

  border:none;
  padding:1px 1px 1px 1px;
  border-radius:2px;
  box-shadow: 0px 0px 2px 2px rgba(255,255,255,0.5);
  font:bold 12px Arial;
  vertical-align: middle;
  
}  
  
.switch_3_ways_v2#uid#{
  margin:5px 10px 10px 10px;
  color:#D0D0D0;
  font-size:1em;
  font-weight:bold;
  position:relative;
  display:block;
  vertical-align: middle;
  
}

.switch2#uid#.blockX#uid#{
  text-align:center;
  position:relative;
  width:0;
  -webkit-transition: 100ms ease-out;
  -moz-transition: 100ms ease-out;
  transition: 100ms ease-out;
  color:white;
  vertical-align: middle;
  margin-right: 20px;

}
.selector#uid#{
  text-align:center;
  position:absolute;
  width:0;
  
  -webkit-transition: 100ms ease-out;
  -moz-transition: 100ms ease-out;
  transition: 100ms ease-out;
  color:white;
}
</style>
  
<script>
  function hexToRgbA(hex,opacite){
    var c;
    if(/^#([A-Fa-f0-9]{3}){1,2}$/.test(hex)){
        c= hex.substring(1).split('');
        if(c.length== 3){
            c= [c[0], c[0], c[1], c[1], c[2], c[2]];
        }
        c= '0x'+c.join('');
        return 'rgba('+[(c>>16)&255, (c>>8)&255, c&255].join(',')+','+opacite+')';
    }
    throw new Error('Bad Hex '+hex);
}

  function setTitleBoxColor(myTitleSelector,texte,bgColor,textFont,textColor)
  { 
    myTitleSelector.innerHTML = texte;
    myTitleSelector.style.boxShadow ="0px 0px 1px 1px " + hexToRgbA(bgColor,0.3);
    
    myTitleSelector.style.backgroundColor =bgColor;
    myTitleSelector.style.color =textColor;
    myTitleSelector.style.font = "bold "+textFont+"px Arial";
    
  }	

   function setTitleBox(myTitleBox,texte,color,textFont)
  {
        myTitleBox.innerHTML =texte;
    	myTitleBox.style.color = color;
    	myTitleBox.style.font = "bold "+textFont+"px Arial";
        myTitleBox.style.boxShadow ="none"; 
  }				
  function setButton(myButton,myIcone,iconName,color,buttonSize,borderSize,iconSize,arrondi)
  {
    
	 myButton.css("border", borderSize+"px solid "+color);
     if(arrondi==1)
     {
       myButton.css("border-radius", buttonSize+"px");
     }
     myButton.css("color", color);
     myButton.css("width", buttonSize+"px");
     myButton.css("height", buttonSize+"px");
     myButton.css("font-size", iconSize +"px");
     
     var lineheight = buttonSize - borderSize - borderSize;
     myIcone.css("line-height",lineheight+"px");
     myIcone.css("color",color); 
	 myIcone.removeClass().addClass(iconName);
  }
  
  
  function addBlockButton(switch_3_ways_v2,numBlock,texte,textBoxSize,buttonSize,isSelector,textBoxHeight)
  {
    var divBlock = document.createElement('div');
    var divTitle = document.createElement('div');
    var divTitleBox = document.createElement('div');
    var divButton = document.createElement('div');
    var divButtonThp = document.createElement('div');
    var divIcon = document.createElement('i');
    
    //creation des tags
    if(isSelector == 1)
    {
      divBlock.id = "selector#uid#";
      divBlock.className = "selector#uid#";   
    }
    else
    {
      divBlock.id = 'block'+numBlock+"#uid#";
      divBlock.className = "switch2#uid# blockX#uid#";
      
    }
    
    divTitle.style.paddingLeft = (buttonSize-textBoxSize)/2 + "px";
    divTitleBox.id = "titlebox"+numBlock+"#uid#";
    divTitleBox.className ="mode_lib_small";
    divTitleBox.style.width = textBoxSize +"px";
    divTitle.id = 'title'+numBlock+"#uid#";
    divTitle.style.height = textBoxHeight+"px"; 
    divButton.id = 'button'+numBlock+"-#uid#";
    divButtonThp.className = "button_thp";
    divIcon.id = 'icon'+numBlock+"-#uid#";
    divIcon.className = "fa fa-lock";
    
    //append des tags
    divButtonThp.appendChild(divIcon);
    divButton.appendChild(divButtonThp);
    divTitle.appendChild(divTitleBox);
    divBlock.appendChild(divTitle);
    divBlock.appendChild(divButton);
    
    switch_3_ways_v2.appendChild(divBlock);
  }
  
    jeedom.cmd.update['#id#'] = function(_options){
    
    var buttonSize = ('#taille#' !='#'+'taille#') ? "#taille#":60;
    var borderSize = ('#taille_bordure#' !='#'+'taille_bordure#') ? "#taille_bordure#":3;
    var iconSize = ('#taille_icone#' !='#'+'taille_icone#') ? "#taille_icone#":30;
    var arrondi = ('#arrondi#' !='#'+'arrondi#') ? "#arrondi#":1;
    var textBoxSize = ('#textBoxSize#' !='#'+'textBoxSize#') ? "#textBoxSize#":50;
    var textFont = ('#textFont#' !='#'+'textFont#') ? "#textFont#":12;
    var textBoxHeight = ('#textBoxHeight#' !='#'+'textBoxHeight#') ? "#textBoxHeight#":20;
    var separateur = ('#Separateur#'!='#'+'Separateur#') ? "#Separateur#" : ' ';
    var icones = ('#Icones#'!='#'+'Icones#') ? "#Icones#" : 'Erreur ajouter otpion Icones';
	var textes = ('#Textes#'!='#'+'Textes#') ? "#Textes#" : 'Erreur ajouter otpion Textes';
    var colors = ('#Couleurs#'!='#'+'Couleurs#') ? "#Couleurs#" : 'Erreur ajouter otpion Couleurs';
    var enables = ('#Enables#'!='#'+'Enables#') ? "#Enables#" : 'Erreur ajouter otpion Enables';
    var cmdIds = ('#CmdIds#'!='#'+'CmdIds#') ? "#CmdIds#" : '#id#';
    var textColors = ('#texteCouleurs#'!='#'+'texteCouleurs#') ? "#texteCouleurs#" : '#FFFFFF';
    var blockSize = ('#blockSize#' !='#'+'blockSize#') ? "#blockSize#":60;
    var distanceBlock = ('#distanceBlock#' !='#'+'distanceBlock#') ? "#distanceBlock#":20;
  	var nbBlock = ('#nbBlock#' !='#'+'nbBlock#') ? "#nbBlock#":3;
    var showText = ('#showText#' !='#'+'showText#') ? "#showText#":0;
    var switch_3_ways_v2 = document.getElementById("switch_3_ways_v2#uid#");
    var commande = ('#CommandeExt#' !='#'+'CommandeExt#') ? "#CommandeExt#":0;
    
    var arrayValue =icones.split(separateur);
    var arrayTexte =textes.split(separateur);
    var arrayColor =colors.split(separateur);
    var arrayEnable=enables.split(separateur);
    var arrayCmdId =cmdIds.split(separateur);
    var arrayTexteColor = textColors.split(separateur);
    
    
    var selectedValue = _options.display_value;
    
    for (let i = 0; i < nbBlock; i++) {
      if(arrayValue[i] == null || arrayValue[i] == ""){
        arrayValue[i] = "fas fa-lock";
      }
      if(arrayTexte[i] == null || arrayTexte[i] == ""){
        arrayTexte[i] = "texte"+i;
      }
      if(arrayColor[i] == null || arrayColor[i] == ""){
        arrayColor[i] = "#FFFFFF";
      }
      if(arrayEnable[i] == null || arrayEnable[i] == ""){
        arrayEnable[i] = 1;
      }
      if(arrayTexteColor[i] == null || arrayTexteColor[i] == ""){
        arrayTexteColor[i] = "#FFFFFF";
      }
      
      if(arrayCmdId[i] == null || arrayCmdId[i] == ""){
        arrayCmdId[i] = '#id#';
      }
      
      if (document.getElementById('block'+i+"#uid#")==null)
      {
        
      	addBlockButton(switch_3_ways_v2,i,arrayTexte[i],textBoxSize,buttonSize,0,textBoxHeight);
        setButton($("#button"+i+"-#uid# .button_thp"),$("#button"+i+"-#uid# .button_thp i"),arrayValue[i],'grey',buttonSize,borderSize,iconSize,arrondi);
        setTitleBox(document.getElementById("titlebox"+i+"#uid#"),arrayTexte[i],'grey',textFont);
      }
	}
    if (document.getElementById("selector#uid#")==null)
    {
      	addBlockButton(switch_3_ways_v2,'','',textBoxSize,buttonSize,1,textBoxHeight);
    }
    
    var selector = document.getElementById("selector#uid#");
  	var titleSelector = document.getElementById("titlebox#uid#");
    
    if(selectedValue>=nbBlock)
    {
      selector.style.display ="none";
    }
    else
    {
      selector.style.display = "block";
    }
    
    if(showText == 0 )
    {
      	for (let i = 0; i < nbBlock; i++) {
       	 	$("#title"+i+"#uid#").css('display','none');
      	}
      	$("#title#uid#").css('display','none');	
    }
        
    if ('#vertical#' == "1"){
		$('.switch2#uid#').css('margin-bottom',distanceBlock+'px');
      
    	$('.switch2#uid#').css('width',blockSize+'px');
        if(showText == 0 )
    	{
          selector.style.top = (parseInt(buttonSize) + parseInt(distanceBlock))*selectedValue +"px" ;
        }else {  
    		selector.style.top = (parseInt(buttonSize)+parseInt(textBoxHeight)+parseInt(distanceBlock))*selectedValue +"px" ;
        }
    	selector.style.width = blockSize+'px';
        if(selectedValue<nbBlock)
    	{
    		setButton($("#button-#uid# .button_thp"),$("#button-#uid# .button_thp i"),arrayValue[selectedValue],arrayColor[selectedValue],buttonSize,borderSize,iconSize,arrondi);
if(borderSize>0){
    		$("#button-#uid# .button_thp").css("box-shadow","0px 0px 2px 2px "+ hexToRgbA(arrayColor[selectedValue],0.7));
}
    		setTitleBoxColor(titleSelector,arrayTexte[selectedValue],arrayColor[selectedValue],textFont,arrayTexteColor[selectedValue]);
        }
   	}
    else 
    {
    	$('.switch2#uid#').css('float','left');
    	$('.switch2#uid#').css('width',blockSize+'px');
    	$('.switch2#uid#').css('margin-right',distanceBlock+'px');
      	selector.style.left = (parseInt(blockSize)+parseInt(distanceBlock))*selectedValue +"px" ;
      	selector.style.width = blockSize+'px';
        if(selectedValue<nbBlock)
    	{
      		setButton($("#button-#uid# .button_thp"),$("#button-#uid# .button_thp i"),arrayValue[selectedValue],arrayColor[selectedValue],buttonSize,borderSize,iconSize,arrondi);
if(borderSize>0){
      		$("#button-#uid# .button_thp").css("box-shadow","0px 0px 2px 2px "+ hexToRgbA(arrayColor[selectedValue],0.7));
}
      		setTitleBoxColor(titleSelector,arrayTexte[selectedValue],arrayColor[selectedValue],textFont,arrayTexteColor[selectedValue] );
        }
    }
    
    for (let i = 0; i < nbBlock; i++) 
    {
    	if(arrayEnable[i]==1){
          
          if(commande==0 || arrayCmdId[i].toString() == '#id#')
            document.getElementById('block'+i+"#uid#").onclick = function(){jeedom.cmd.execute({id: '#id#', value:(i.toString())});   };
          else
          	document.getElementById('block'+i+"#uid#").onclick = function(){jeedom.cmd.execute({id: arrayCmdId[i].toString(), value:(i.toString())}); jeedom.cmd.execute({id: '#id#', value:(i.toString())});   };
            
        }
    }
    
	if ('#time#' == 'duree') {  
        jeedom.cmd.displayDuration(_options.valueDate,  $('.cmd[data-cmd_id=#id#] .timeCmd'));
          }
      else if ('#time#' == 'date') {
      	var date = new Date(_options.valueDate);
		var format = $.datepicker.formatDate('D dd/mm', date);
		var time = "à "+date.getHours()+":"+(date.getMinutes()<10?'0':'')+date.getMinutes();
        $('.cmd[data-cmd_id=#id#] .timeCmd').html(format+'<br>'+time);
      	}
      else if ('#time#' == 'heure') {
        var date = new Date(_options.valueDate);
        var time = "à "+date.getHours()+":"+(date.getMinutes()<10?'0':'')+date.getMinutes()+":"+(date.getSeconds()<10?'0':'')+date.getSeconds()+"";
        $('.cmd[data-cmd_id=#id#] .timeCmd').html(time);
      	}
		}
      	jeedom.cmd.update['#id#']({display_value:'#state#',valueDate:'#valueDate#',collectDate:'#collectDate#',alertLevel:'#alertLevel#'})
  </script>
</div>

Définition :
Un bloc contient un zone de texte et un bouton, un bouton contient une icone.

L’utilisation :

  • vertical :1/0 widget en vertical ou horizontal, par défaut 0
  • nbBlock : le nombre de bloc
  • Separateur : séparateurs des champs, par exemple | ou ; (valeur par défaut |)
  • Textes : textes à afficher sur les icones, par exemple texte0|texte1|texte2 , valeur par défaut : « texte »+position
  • Couleurs : couleurs de chaque bouton sélectionné, en HEX
  • Icones : Icones de chaque bouton
  • Enables : définir si le bouton est cliquable ou non, par exemple 1|0|1|1
  • CommandeExt : pouvoir générer les commandes extérieures ( 0 par défaut)
  • CmdIds : liste des id des commandes extérieures : par exemple 234|333|878
  • texteCouleurs : couleurs des textes (white par défaut); et #000 pour transparente
  • distanceBlock : distance entre deux bloc
  • blockSize : taille du bloc
  • taille : taille du bouton
  • taille_bordure : taille de la bordure du bouton
  • arrondi : bouton en forme rond ou carré
  • taille_icone : taille de l’icone
  • showText : 1/0 : activer/désactiver la zone de texte
  • textBoxSize : largeur de la zone de texte
  • textBoxHeight : hauteur de la zone de texte
  • textFont : taille/police de la zone de texte

Seuls les paramètres Separateur,Textes,Icones,Couleurs,Enables sont obligatoires…

Exemple :

image

image

Rendu final : j’utilise pour changer le mode de mes thermostats (un slider virtuel avec scénarios pour synchroniser avec le thermostat)

Screen_Recording_20201207-005447_Chrome_1 (1)

Screen Shot 12-09-20 at 04.30 PM

Screen Shot 12-09-20 at 04.31 PM

Dans ce design: j’ai ajouté :

  • Le slider avec mon widget perso :slight_smile:
  • La commande thermostat avec le widget de @Salvialf
  • La commande température
  • Le statut du thermostat (Chauffage/Arrete) avec un widget perso qui change l’icone selon le statut

En bonus : les scénarios qui synchronise le slider et le thermostat

(si vous ne l’utilisez pas l’option commandeExt)
Screen Shot 12-08-20 at 01.38 PM 001

Screen Shot 12-08-20 at 01.38 PM

EDIT : je viens d’ajouter l’option permettant associer une commande simple à chaque bouton, donc, il n’est plus nécessaire de faire des scénario pour associer une action à un bouton :slight_smile: :slight_smile:

10 J'aimes

Il est vraiment magnifique.
Merci pour le partage, il n y’a plus qu’à essayer de copier l’original

Merci pour ce super Widget il est top !

Petite question… est il possible de modifier la couleur de l’icône qui n’est pas active ?
D’origine elle est grise « clair » j’aimerais qu’elle soit plus foncée… une idée ?

Merci

salut, le mot « grey » doit etre quelque part dans le code :), à toi de jouer.

1 J'aime

Bonjour,
Bravo pour ton travail !
Je cherchais une idée de présentation de les thermostats et je crois avoir trouvé !
Benoit

1 J'aime

Mis à jour chez moi, c’est nickel !

Concernant le widget consigne thermostat. est celui de @Salvialf ?
J’ai cru comprendre en lisant ses fils que le sien n’avait pas les boutons + et - colorés.
De plus quand je passe la couleur du texte en blanc dans le design, ça flingue la couleur du thermometre ;-(

Oui, légèrement customisé :

 <div class="title #hide_name#">
    <div class="cmdName">#name_display#</div>
  </div>
  <span id="thermo_icon"></span>
  <p id="displayConsigne" class="text-center text-white">
    	<span id="valeur#id#"></span>&#8451;
   </p>
   <div id="boutons">
     <a class="btn-sm bt_minus"><i class="fas fa-3x fa-minus-square icon_blue"></i></a>
    <a class="btn-sm bt_plus"><i class="fas fa-3x fa-plus-square icon_red"></i></a>
    
   </div>

Une pettite proposition !
L’icone à l’intérieur d’un bloc est coloré. Nickel
En revanche dans un desgin, si on force la couleur du texte. L’icone prend la couleur du texte et ne garde pas sa couleur initiale.
Une solution pourrait peut etre comme pour ton paramètre « Couleurs », faire un paramètre « CouleurIcones » .
Oui mieux, forcer les clouleurs déjà définies mais je sais pas comment on fait.
Ou alors bien avoir un « CouleurTextes » pour ne pas avoir à forcer la couleur dans le design. Ce qui à mon sens serait peut etre la plus souple solution
Qu’en penses tu ?
Voici ce que ça donne actuellement chez moi :
Capture

Bonjour @theone_811
je pense être pas trop loin, juste avec un virtuel.Pas aussi beau que le tiens mais ça rend assez bien.
cuisine

1 J'aime

Oui, ce n’est pas très dur à faire, je regarderai peut etre ce weekend… là je suis écrasé sous les réunions interminables…
Déjà, tu peux remplacer les mots « grey » par « white » dans le code si tu veux que le texte par défaut soit blanc, sans toucher au paramètres du design.

Bonjour,

Effectivement, il est vraiment très beau. J’ai une petite question. Ne serait-il pas possible de rajouter un tableau d’Id correspond au Id des commandes actions associés à chaque icône ? Peut-être en ajoutant un execute supplémentaire dans la fonction onClick ? Cela éviterai de passer par les scénario.

En tout cas merci pour tout ces partages !

Salut Theone_811,

Le widget est vraiment terrible sur les design c’est juste parfait. Bravo encore pour le boulot !
J’observe un bug d’après moi lorsque je passe en vertical la couleur est décalée…

Je n’ai pas le soucis en horizontale.
Une idée ?

Merci

heu, j’avoue que je n’ai pas testé le mode vertical sans texte…

Oui c’est exact cela vient de l’affichage ou non du texte.

J’ai mis à jour le code, tu peux essayer stp ?

Au top ça fonctionne parfaitement merci pour ta rapidité :slight_smile:

Pas mal @domoggvad tes cozytouch avec l icone etat native!
Comment geres tu des differents mode avec le cozytouch ?
Pas simple a faire la gestion des modes du coup avec les scenarios et les commandes programmation et mode des cozytouch. Ils ont un peu mélangés a mon sens les 2 commandes et les differents etats

Ne serait-il pas possible de rajouter un tableau d’Id correspond au Id des commandes actions associés à chaque icône

Hello, oui, c’est dans les tuyaux :slight_smile:

1 J'aime

Done :slight_smile:
j’ai mis à jour le code, peux tu essayer stp ?

Capture d’écran 2020-12-12 à 03.28.03

Comme évoqué ensemble, juste de simple icone et non des cozytouch (therme que je ne connaissais pas)