svghmi/widget_circularslider.ysl2
changeset 4027 59a331f80858
parent 4026 a3cf9f635952
child 4028 d9b772623fd9
equal deleted inserted replaced
4026:a3cf9f635952 4027:59a331f80858
     1 // widget_circuralslider.ysl2
       
     2 
       
     3 widget_desc("CircularSlider") {
       
     4     longdesc
       
     5     ||
       
     6     CircularSlider - DEPRECATED, to be replaced by PathSlider
       
     7     This widget moves "handle" labeled group along "range" labeled
       
     8     arc, according to value of the single accepted variable.
       
     9 
       
    10     If "min" a "max" labeled texts are provided, or if first and second
       
    11     argument are given, then they are used as respective minimum and maximum
       
    12     value. Otherwise, value is expected to be in between 0 and 100.
       
    13 
       
    14     If "value" labeled text is found, then its content is replaced by value.
       
    15     During drag, "setpoint" labeled group is moved to position defined by user
       
    16     while "handle" reflects current value from variable.
       
    17     ||
       
    18 
       
    19     shortdesc > CircularSlider - DEPRECATED
       
    20 
       
    21     arg name="min" count="optional" accepts="int,real" > minimum value
       
    22 
       
    23     arg name="min" count="optional" accepts="int,real" > maximum value
       
    24 
       
    25     // TODO: add printf-like format
       
    26 
       
    27     path name="value" accepts="HMI_INT,HMI_REAL" > Value to display
       
    28     
       
    29 }
       
    30 
       
    31 widget_class("CircularSlider")
       
    32     ||
       
    33         frequency = 5;
       
    34         range = undefined;
       
    35         circle = undefined;
       
    36         handle_pos = undefined;
       
    37         curr_value = 0;
       
    38         drag = false;
       
    39         enTimer = false;
       
    40         last_drag = false;
       
    41 
       
    42         dispatch(value) {
       
    43             let [min,max,start,totallength] = this.range;
       
    44             //save current value inside widget
       
    45             this.curr_value = value;
       
    46 
       
    47             //check if in range
       
    48             if (this.curr_value > max){
       
    49                 this.curr_value = max;
       
    50                 this.apply_hmi_value(0, this.curr_value);
       
    51             }
       
    52             else if (this.curr_value < min){
       
    53                 this.curr_value = min;
       
    54                 this.apply_hmi_value(0, this.curr_value);
       
    55             }
       
    56 
       
    57             if(this.value_elt)
       
    58                 this.value_elt.textContent = String(value);
       
    59 
       
    60             //don't update if draging and setpoint ghost doesn't exist
       
    61             if(!this.drag || (this.setpoint_elt != undefined)){
       
    62                 this.update_DOM(value, this.handle_elt);
       
    63             }
       
    64         }
       
    65 
       
    66         update_DOM(value, elt){
       
    67             let [min,max,totalDistance] = this.range;
       
    68             let length = Math.max(0,Math.min((totalDistance),(Number(value)-min)/(max-min)*(totalDistance)));
       
    69             let tip = this.range_elt.getPointAtLength(length);
       
    70             elt.setAttribute('transform',"translate("+(tip.x-this.handle_pos.x)+","+(tip.y-this.handle_pos.y)+")");
       
    71 
       
    72             // show or hide ghost if exists
       
    73             if(this.setpoint_elt != undefined){
       
    74                 if(this.last_drag!= this.drag){
       
    75                     if(this.drag){
       
    76                         this.setpoint_elt.setAttribute("style", this.setpoint_style);
       
    77                     }else{
       
    78                         this.setpoint_elt.setAttribute("style", "display:none");
       
    79                     }
       
    80                     this.last_drag = this.drag;
       
    81                 }
       
    82             }
       
    83         }
       
    84 
       
    85         on_release(evt) {
       
    86             //unbind events
       
    87             window.removeEventListener("touchmove", this.on_bound_drag, true);
       
    88             window.removeEventListener("mousemove", this.on_bound_drag, true);
       
    89 
       
    90             window.removeEventListener("mouseup", this.bound_on_release, true)
       
    91             window.removeEventListener("touchend", this.bound_on_release, true);
       
    92             window.removeEventListener("touchcancel", this.bound_on_release, true);
       
    93 
       
    94             //reset drag flag
       
    95             if(this.drag){
       
    96                 this.drag = false;
       
    97             }
       
    98 
       
    99             // get final position
       
   100             this.update_position(evt);
       
   101         }
       
   102 
       
   103         on_drag(evt){
       
   104             //ignore drag event for X amount of time and if not selected
       
   105             if(this.enTimer && this.drag){
       
   106                 this.update_position(evt);
       
   107 
       
   108                 //reset timer
       
   109                 this.enTimer = false;
       
   110                 setTimeout("{hmi_widgets['"+this.element_id+"'].enTimer = true;}", 100);
       
   111             }
       
   112         }
       
   113 
       
   114         update_position(evt){
       
   115             if(this.drag && this.enTimer){
       
   116                 var svg_dist = 0;
       
   117 
       
   118                 //calculate center of widget in html
       
   119                 // --TODO maybe it would be better to bind this part to window change size event ???
       
   120                 let [xdest,ydest,svgWidth,svgHeight] = page_desc[current_visible_page].bbox;
       
   121                 let [cX, cY,fiStart,fiEnd,minMax,x1,y1,width,height] = this.circle;
       
   122                 let htmlCirc = this.range_elt.getBoundingClientRect();
       
   123                 let cxHtml = ((htmlCirc.right-htmlCirc.left)/(width)*(cX-x1))+htmlCirc.left;
       
   124                 let cyHtml = ((htmlCirc.bottom-htmlCirc.top)/(height)*(cY-y1))+htmlCirc.top;
       
   125 
       
   126 
       
   127                 //get mouse coordinates
       
   128                 let mouseX = undefined;
       
   129                 let mouseY = undefined;
       
   130                 if (evt.type.startsWith("touch")){
       
   131                     mouseX = Math.ceil(evt.touches[0].clientX);
       
   132                     mouseY = Math.ceil(evt.touches[0].clientY);
       
   133                 }
       
   134                 else{
       
   135                     mouseX = evt.pageX;
       
   136                     mouseY = evt.pageY;
       
   137                 }
       
   138 
       
   139                 //calculate angle
       
   140                 let fi = Math.atan2(cyHtml-mouseY, mouseX-cxHtml);
       
   141 
       
   142                 // transform from 0 to 2PI
       
   143                 if (fi > 0){
       
   144                     fi = 2*Math.PI-fi;
       
   145                 }
       
   146                 else{
       
   147                     fi = -fi;
       
   148                 }
       
   149 
       
   150                 //offset it to 0
       
   151                 fi = fi - fiStart;
       
   152                 if (fi < 0){
       
   153                     fi = fi + 2*Math.PI;
       
   154                 }
       
   155 
       
   156                 //get handle distance from mouse position
       
   157                 if(fi<fiEnd){
       
   158                    this.curr_value=(fi)/(fiEnd)*(this.range[1]-this.range[0]);
       
   159                 }
       
   160                 else if(fiEnd<fi && fi<fiEnd+minMax){
       
   161                     this.curr_value = this.range[1];
       
   162                 }
       
   163                 else{
       
   164                     this.curr_value = this.range[0];
       
   165                 }
       
   166 
       
   167                 //apply value to hmi
       
   168                 this.apply_hmi_value(0, Math.ceil(this.curr_value));
       
   169 
       
   170                 //redraw handle
       
   171                 this.request_animate();
       
   172 
       
   173             }
       
   174 
       
   175         }
       
   176 
       
   177         animate(){
       
   178             // redraw handle on screen refresh
       
   179             // check if setpoint(ghost) handle exsist otherwise update main handle
       
   180             if(this.setpoint_elt != undefined){
       
   181                 this.update_DOM(this.curr_value, this.setpoint_elt);
       
   182             }
       
   183             else{
       
   184                 this.update_DOM(this.curr_value, this.handle_elt);
       
   185             }
       
   186         }
       
   187 
       
   188         on_select(evt){
       
   189             //enable drag flag and timer
       
   190             this.drag = true;
       
   191             this.enTimer = true;
       
   192 
       
   193             //bind events
       
   194             window.addEventListener("touchmove", this.on_bound_drag, true);
       
   195             window.addEventListener("mousemove", this.on_bound_drag, true);
       
   196 
       
   197             window.addEventListener("mouseup", this.bound_on_release, true);
       
   198             window.addEventListener("touchend", this.bound_on_release, true);
       
   199             window.addEventListener("touchcancel", this.bound_on_release, true);
       
   200 
       
   201             //update postion on mouse press
       
   202             this.update_position(evt);
       
   203 
       
   204             //prevent next events
       
   205             evt.stopPropagation();
       
   206         }
       
   207 
       
   208         init() {
       
   209             //get min max
       
   210             let min = this.min_elt ?
       
   211                         Number(this.min_elt.textContent) :
       
   212                         this.args.length >= 1 ? this.args[0] : 0;
       
   213             let max = this.max_elt ?
       
   214                         Number(this.max_elt.textContent) :
       
   215                         this.args.length >= 2 ? this.args[1] : 100;
       
   216 
       
   217             //fiStart ==> offset
       
   218             let fiStart = Number(this.range_elt.getAttribute('sodipodi:start'));
       
   219             let fiEnd = Number(this.range_elt.getAttribute('sodipodi:end'));
       
   220             fiEnd = fiEnd - fiStart;
       
   221 
       
   222             //fiEnd ==> size of angle
       
   223             if (fiEnd < 0){
       
   224                 fiEnd = 2*Math.PI + fiEnd;
       
   225             }
       
   226 
       
   227             //min max barrier angle
       
   228             let minMax = (2*Math.PI - fiEnd)/2;
       
   229 
       
   230             //get parameters from svg
       
   231             let cX = Number(this.range_elt.getAttribute('sodipodi:cx'));
       
   232             let cY = Number(this.range_elt.getAttribute('sodipodi:cy'));
       
   233             this.range_elt.style.strokeMiterlimit="0"; //eliminates some weird border around html object
       
   234             this.range = [min, max,this.range_elt.getTotalLength()];
       
   235             let cPos = this.range_elt.getBBox();
       
   236             this.handle_pos = this.range_elt.getPointAtLength(0);
       
   237             this.circle = [cX, cY,fiStart,fiEnd,minMax,cPos.x,cPos.y,cPos.width,cPos.height];
       
   238 
       
   239             //bind functions
       
   240             this.bound_on_select = this.on_select.bind(this);
       
   241             this.bound_on_release = this.on_release.bind(this);
       
   242             this.on_bound_drag = this.on_drag.bind(this);
       
   243 
       
   244             this.handle_elt.addEventListener("mousedown", this.bound_on_select);
       
   245             this.element.addEventListener("mousedown", this.bound_on_select);
       
   246             this.element.addEventListener("touchstart", this.bound_on_select);
       
   247             //touch recognised as page drag without next command
       
   248             document.body.addEventListener("touchstart", function(e){}, false);
       
   249 
       
   250             //save ghost style
       
   251             //save ghost style
       
   252             if(this.setpoint_elt != undefined){
       
   253                 this.setpoint_style = this.setpoint_elt.getAttribute("style");
       
   254                 this.setpoint_elt.setAttribute("style", "display:none");
       
   255             }
       
   256 
       
   257         }
       
   258     ||
       
   259 
       
   260 widget_defs("CircularSlider") {
       
   261     labels("handle range");
       
   262     optional_labels("value min max setpoint");
       
   263     |,
       
   264 }