svghmi/widget_slider.ysl2
changeset 3302 c89fc366bebd
parent 3283 71ae6f02a7ff
equal deleted inserted replaced
2744:577118ebd179 3302:c89fc366bebd
       
     1 // widget_slider.ysl2
       
     2 
       
     3 widget_desc("Slider") {
       
     4     longdesc
       
     5     || 
       
     6     Slider - DEPRECATED - use ScrollBar or PathSlider instead
       
     7     ||
       
     8 
       
     9     shortdesc > Slider - DEPRECATED - use ScrollBar instead
       
    10 
       
    11     path name="value" accepts="HMI_INT" > value
       
    12     path name="range" accepts="HMI_INT" > range
       
    13     path name="visible" accepts="HMI_INT" > visible
       
    14     
       
    15 }
       
    16 
       
    17 widget_class("Slider")
       
    18     ||
       
    19         frequency = 5;
       
    20         range = undefined;
       
    21         handle_orig = undefined;
       
    22         scroll_size = undefined;
       
    23         scroll_range = 0;
       
    24         scroll_visible = 7;
       
    25         min_size = 0.07;
       
    26         fi = undefined;
       
    27         curr_value = 0;
       
    28         drag = false;
       
    29         enTimer = false;
       
    30         handle_click = undefined;
       
    31         last_drag = false;
       
    32 
       
    33         dispatch(value,oldval, index) {
       
    34             if (index == 0){
       
    35                 let [min,max,start,totallength] = this.range;
       
    36                 //save current value inside widget
       
    37                 this.curr_value = value;
       
    38 
       
    39                 //check if in range
       
    40                 if (this.curr_value > max){
       
    41                     this.curr_value = max;
       
    42                     this.apply_hmi_value(0, this.curr_value);
       
    43                 }
       
    44                 else if (this.curr_value < min){
       
    45                     this.curr_value = min;
       
    46                     this.apply_hmi_value(0, this.curr_value);
       
    47                 }
       
    48 
       
    49                 if(this.value_elt)
       
    50                     this.value_elt.textContent = String(value);
       
    51             }
       
    52             else if(index == 1){
       
    53                 this.scroll_range = value;
       
    54                 this.set_scroll();
       
    55             }
       
    56             else if(index == 2){
       
    57                 this.scroll_visible = value;
       
    58                 this.set_scroll();
       
    59             }
       
    60 
       
    61             //don't update if draging and setpoint ghost doesn't exist
       
    62             if(!this.drag || (this.setpoint_elt != undefined)){
       
    63                 this.update_DOM(this.curr_value, this.handle_elt);
       
    64             }
       
    65         }
       
    66 
       
    67         set_scroll(){
       
    68             //check if range is bigger than visible and set scroll size
       
    69             if(this.scroll_range > this.scroll_visible){
       
    70                 this.scroll_size = this.scroll_range - this.scroll_visible;
       
    71                 this.range[0] = 0;
       
    72                 this.range[1] = this.scroll_size;
       
    73             }
       
    74             else{
       
    75                 this.scroll_size = 1;
       
    76                 this.range[0] = 0;
       
    77                 this.range[1] = 1;
       
    78             }
       
    79         }
       
    80 
       
    81         update_DOM(value, elt){
       
    82             let [min,max,start,totallength] = this.range;
       
    83             // check if handle is resizeable
       
    84             if (this.scroll_size != undefined){ //size changes
       
    85                 //get parameters
       
    86                 let length = Math.max(min,Math.min(max,(Number(value)-min)*max/(max-min)));
       
    87                 let tip = this.range_elt.getPointAtLength(length);
       
    88                 let handle_min = totallength*this.min_size;
       
    89 
       
    90                 let step = 1;
       
    91                 //check if range is bigger than  max displayed and recalculate step
       
    92                 if ((totallength/handle_min) < (max-min+1)){
       
    93                     step = (max-min+1)/(totallength/handle_min-1);
       
    94                 }
       
    95 
       
    96                 let kx,ky,offseY,offseX = undefined;
       
    97                 //scale on x or y axes
       
    98                 if (this.fi > 0.75){
       
    99                     //get scale factor
       
   100                     if(step > 1){
       
   101                         ky = handle_min/this.handle_orig.height;
       
   102                     }
       
   103                     else{
       
   104                         ky = (totallength-handle_min*(max-min))/this.handle_orig.height;
       
   105                     }
       
   106                     kx = 1;
       
   107                     //get 0 offset to stay inside range
       
   108                     offseY = start.y - (this.handle_orig.height + this.handle_orig.y) * ky;
       
   109                     offseX = 0;
       
   110                     //get distance from value
       
   111                     tip.y =this.range_elt.getPointAtLength(0).y - length/step *handle_min;
       
   112                 }
       
   113                 else{
       
   114                     //get scale factor
       
   115                     if(step > 1){
       
   116                         kx = handle_min/this.handle_orig.width;
       
   117                     }
       
   118                     else{
       
   119                         kx = (totallength-handle_min*(max-min))/this.handle_orig.width;
       
   120                     }
       
   121                     ky = 1;
       
   122                     //get 0 offset to stay inside range
       
   123                     offseX = start.x - (this.handle_orig.x * kx);
       
   124                     offseY = 0;
       
   125                     //get distance from value
       
   126                     tip.x =this.range_elt.getPointAtLength(0).x + length/step *handle_min;
       
   127                 }
       
   128                 elt.setAttribute('transform',"matrix("+(kx)+" 0 0 "+(ky)+" "+(tip.x-start.x+offseX)+" "+(tip.y-start.y+offseY)+")");
       
   129             }
       
   130             else{ //size stays the same
       
   131                 let length = Math.max(0,Math.min(totallength,(Number(value)-min)*totallength/(max-min)));
       
   132                 let tip = this.range_elt.getPointAtLength(length);
       
   133                 elt.setAttribute('transform',"translate("+(tip.x-start.x)+","+(tip.y-start.y)+")");
       
   134             }
       
   135 
       
   136             // show or hide ghost if exists
       
   137             if(this.setpoint_elt != undefined){
       
   138                 if(this.last_drag!= this.drag){
       
   139                     if(this.drag){
       
   140                         this.setpoint_elt.setAttribute("style", this.setpoint_style);
       
   141                     }else{
       
   142                         this.setpoint_elt.setAttribute("style", "display:none");
       
   143                     }
       
   144                     this.last_drag = this.drag;
       
   145                 }
       
   146             }
       
   147         }
       
   148 
       
   149         on_release(evt) {
       
   150             //unbind events
       
   151             window.removeEventListener("touchmove", this.on_bound_drag, true);
       
   152             window.removeEventListener("mousemove", this.on_bound_drag, true);
       
   153 
       
   154             window.removeEventListener("mouseup", this.bound_on_release, true);
       
   155             window.removeEventListener("touchend", this.bound_on_release, true);
       
   156             window.removeEventListener("touchcancel", this.bound_on_release, true);
       
   157 
       
   158             //reset drag flag
       
   159             if(this.drag){
       
   160                 this.drag = false;
       
   161             }
       
   162 
       
   163             // get final position
       
   164             this.update_position(evt);
       
   165 
       
   166         }
       
   167 
       
   168         on_drag(evt){
       
   169             //ignore drag event for X amount of time and if not selected
       
   170             if(this.enTimer && this.drag){
       
   171                 this.update_position(evt);
       
   172 
       
   173                 //reset timer
       
   174                 this.enTimer = false;
       
   175                 setTimeout("{hmi_widgets['"+this.element_id+"'].enTimer = true;}", 100);
       
   176             }
       
   177         }
       
   178 
       
   179         update_position(evt){
       
   180             var html_dist = 0;
       
   181             let [min,max,start,totallength] = this.range;
       
   182 
       
   183             //calculate size of widget in html
       
   184             var range_borders = this.range_elt.getBoundingClientRect();
       
   185             var [minX,minY,maxX,maxY] = [range_borders.left,range_borders.bottom,range_borders.right,range_borders.top];
       
   186             var range_length = Math.sqrt( range_borders.height*range_borders.height + range_borders.width*range_borders.width );
       
   187 
       
   188             //get range and mouse coordinates
       
   189             var mouseX = undefined;
       
   190             var mouseY = undefined;
       
   191             if (evt.type.startsWith("touch")){
       
   192                 mouseX = Math.ceil(evt.touches[0].clientX);
       
   193                 mouseY = Math.ceil(evt.touches[0].clientY);
       
   194             }
       
   195             else{
       
   196                 mouseX = evt.pageX;
       
   197                 mouseY = evt.pageY;
       
   198             }
       
   199 
       
   200             // calculate position
       
   201             if (this.handle_click){ //if clicked on handle
       
   202                 let moveDist = 0, resizeAdd = 0;
       
   203                 let range_percent = 1;
       
   204 
       
   205                 //set paramters for resizeable handle
       
   206                 if (this.scroll_size != undefined){
       
   207                     // add one more object to stay inside range
       
   208                     resizeAdd = 1;
       
   209 
       
   210                     //chack if range is bigger than display option and
       
   211                     // calculate percent of range with out handle
       
   212                     if(((max/(max*this.min_size)) < (max-min+1))){
       
   213                         range_percent = 1-this.min_size;
       
   214                     }
       
   215                     else{
       
   216                         range_percent = 1-(max-max*this.min_size*(max-min))/max;
       
   217                     }
       
   218                 }
       
   219 
       
   220                 //calculate value difference on x or y axis
       
   221                 if(this.fi > 0.7){
       
   222                     moveDist = ((max-min+resizeAdd)/(range_length*range_percent))*((this.handle_click[1]-mouseY)/Math.sin(this.fi));
       
   223                 }
       
   224                 else{
       
   225                     moveDist = ((max-min+resizeAdd)/(range_length*range_percent))*((mouseX-this.handle_click[0])/Math.cos(this.fi));
       
   226                 }
       
   227 
       
   228                 this.curr_value = Math.ceil(this.handle_click[2] + moveDist);
       
   229             }
       
   230             else{ //if clicked on widget
       
   231                 //get handle distance from mouse position
       
   232                 if (minX > mouseX && minY < mouseY){
       
   233                     html_dist = 0;
       
   234                 }
       
   235                 else if (maxX < mouseX && maxY > mouseY){
       
   236                     html_dist = range_length;
       
   237                 }
       
   238                 else{
       
   239                     if(this.fi > 0.7){
       
   240                         html_dist = (minY - mouseY)/Math.sin(this.fi);
       
   241                     }
       
   242                     else{
       
   243                         html_dist = (mouseX - minX)/Math.cos(this.fi);
       
   244                     }
       
   245                 }
       
   246                 //calculate distance
       
   247                 this.curr_value=Math.ceil((html_dist/range_length)*(this.range[1]-this.range[0])+this.range[0]);
       
   248             }
       
   249 
       
   250             //check if in range and apply
       
   251             if (this.curr_value > max){
       
   252                 this.curr_value = max;
       
   253             }
       
   254             else if (this.curr_value < min){
       
   255                 this.curr_value = min;
       
   256             }
       
   257             this.apply_hmi_value(0, this.curr_value);
       
   258 
       
   259             //redraw handle
       
   260             this.request_animate();
       
   261 
       
   262         }
       
   263 
       
   264         animate(){
       
   265             // redraw handle on screen refresh
       
   266             // check if setpoint(ghost) handle exsist otherwise update main handle
       
   267             if(this.setpoint_elt != undefined){
       
   268                 this.update_DOM(this.curr_value, this.setpoint_elt);
       
   269             }
       
   270             else{
       
   271                 this.update_DOM(this.curr_value, this.handle_elt);
       
   272             }
       
   273         }
       
   274 
       
   275         on_select(evt){
       
   276             //enable drag flag and timer
       
   277             this.drag = true;
       
   278             this.enTimer = true;
       
   279 
       
   280             //bind events
       
   281             window.addEventListener("touchmove", this.on_bound_drag, true);
       
   282             window.addEventListener("mousemove", this.on_bound_drag, true);
       
   283 
       
   284             window.addEventListener("mouseup", this.bound_on_release, true);
       
   285             window.addEventListener("touchend", this.bound_on_release, true);
       
   286             window.addEventListener("touchcancel", this.bound_on_release, true);
       
   287 
       
   288             // check if handle was pressed
       
   289             if (evt.currentTarget == this.handle_elt){
       
   290                 //get mouse position on the handle
       
   291                 let mouseX = undefined;
       
   292                 let mouseY = undefined;
       
   293                 if (evt.type.startsWith("touch")){
       
   294                     mouseX = Math.ceil(evt.touches[0].clientX);
       
   295                     mouseY = Math.ceil(evt.touches[0].clientY);
       
   296                 }
       
   297                 else{
       
   298                     mouseX = evt.pageX;
       
   299                     mouseY = evt.pageY;
       
   300                 }
       
   301                 //save coordinates and orig value
       
   302                 this.handle_click = [mouseX,mouseY,this.curr_value];
       
   303             }
       
   304             else{
       
   305                 // get new handle position and reset if handle was not pressed
       
   306                 this.handle_click = undefined;
       
   307                 this.update_position(evt);
       
   308             }
       
   309 
       
   310             //prevent next events
       
   311             evt.stopPropagation();
       
   312 
       
   313         }
       
   314 
       
   315 
       
   316         init() {
       
   317             //set min max value if not defined
       
   318             let min = this.min_elt ?
       
   319                         Number(this.min_elt.textContent) :
       
   320                         this.args.length >= 1 ? this.args[0] : 0;
       
   321             let max = this.max_elt ?
       
   322                         Number(this.max_elt.textContent) :
       
   323                         this.args.length >= 2 ? this.args[1] : 100;
       
   324 
       
   325 
       
   326             // save initial parameters
       
   327             this.range_elt.style.strokeMiterlimit="0";
       
   328             this.range = [min, max, this.range_elt.getPointAtLength(0),this.range_elt.getTotalLength()];
       
   329             let start = this.range_elt.getPointAtLength(0);
       
   330             let end = this.range_elt.getPointAtLength(this.range_elt.getTotalLength());
       
   331             this.fi = Math.atan2(start.y-end.y, end.x-start.x);
       
   332             this.handle_orig = this.handle_elt.getBBox();
       
   333 
       
   334             //bind functions
       
   335             this.bound_on_select = this.on_select.bind(this);
       
   336             this.bound_on_release = this.on_release.bind(this);
       
   337             this.on_bound_drag = this.on_drag.bind(this);
       
   338 
       
   339             this.handle_elt.addEventListener("mousedown", this.bound_on_select);
       
   340             this.element.addEventListener("mousedown", this.bound_on_select);
       
   341             this.element.addEventListener("touchstart", this.bound_on_select);
       
   342             //touch recognised as page drag without next command
       
   343             document.body.addEventListener("touchstart", function(e){}, false);
       
   344 
       
   345             //save ghost style
       
   346             if(this.setpoint_elt != undefined){
       
   347                 this.setpoint_style = this.setpoint_elt.getAttribute("style");
       
   348                 this.setpoint_elt.setAttribute("style", "display:none");
       
   349             }
       
   350 
       
   351         }
       
   352     ||
       
   353 
       
   354 widget_defs("Slider") {
       
   355     labels("handle range");
       
   356     optional_labels("value min max setpoint");
       
   357 }