svghmi/widget_slider.ysl2
branchsvghmi
changeset 3056 827bf284feec
parent 3045 f6d428330e04
child 3059 e0db3f6a5f39
--- a/svghmi/widget_slider.ysl2	Tue Aug 18 11:42:28 2020 +0200
+++ b/svghmi/widget_slider.ysl2	Wed Sep 16 09:41:52 2020 +0200
@@ -5,27 +5,85 @@
     class SliderWidget extends Widget{
         frequency = 5;
         range = undefined;
+        handle_orig = undefined;
+        scroll_size = 10;
+        min_size = 0.07;
         fi = undefined;
-        svg_dist = undefined;
+        curr_value = 0;
         drag = false;
         enTimer = false;
+        handle_click = undefined;
+        last_drag = false;
 
         dispatch(value) {
+            //save current value inside widget
+            this.curr_value = value;
+
             if(this.value_elt)
                 this.value_elt.textContent = String(value);
 
-            this.update_DOM(value, this.handle_elt);
-
-        }
-
-        last_drag = false;
+            //don't update if draging and setpoint ghost doesn't exist
+            if(!this.drag || (this.setpoint_elt != undefined)){
+                this.update_DOM(value, this.handle_elt);
+            }
+        }
 
         update_DOM(value, elt){
             let [min,max,start,totallength] = this.range;
-            let length = Math.max(0,Math.min(totallength,(Number(value)-min)*totallength/(max-min)));
-            let tip = this.range_elt.getPointAtLength(length);
-            elt.setAttribute('transform',"translate("+(tip.x-start.x)+","+(tip.y-start.y)+")");
-
+            // check if handle is resizeable
+            if (this.scroll_size != undefined){ //size changes
+                //get parameters
+                let length = Math.max(min,Math.min(max,(Number(value)-min)*max/(max-min)));
+                let tip = this.range_elt.getPointAtLength(length);
+                let handle_min = totallength*this.min_size;
+
+                let step = 1;
+                //check if range is bigger than  max displayed and recalculate step
+                if ((totallength/handle_min) < (max-min+1)){
+                    step = (max-min+1)/(totallength/handle_min-1);
+                }
+
+                let kx,ky,offseY,offseX = undefined;
+                //scale on x or y axes
+                if (this.fi > 0.75){
+                    //get scale factor
+                    if(step > 1){
+                        ky = handle_min/this.handle_orig.height;
+                    }
+                    else{
+                        ky = (totallength-handle_min*(max-min))/this.handle_orig.height;
+                    }
+                    kx = 1;
+                    //get 0 offset to stay inside range
+                    offseY = start.y - (this.handle_orig.height + this.handle_orig.y) * ky;
+                    offseX = 0;
+                    //get distance from value
+                    tip.y =this.range_elt.getPointAtLength(0).y - length/step *handle_min;
+                }
+                else{
+                    //get scale factor
+                    if(step > 1){
+                        kx = handle_min/this.handle_orig.width;
+                    }
+                    else{
+                        kx = (totallength-handle_min*(max-min))/this.handle_orig.width;
+                    }
+                    ky = 1;
+                    //get 0 offset to stay inside range
+                    offseX = start.x - (this.handle_orig.x * kx);
+                    offseY = 0;
+                    //get distance from value
+                    tip.x =this.range_elt.getPointAtLength(0).x + length/step *handle_min;
+                }
+                elt.setAttribute('transform',"matrix("+(kx)+" 0 0 "+(ky)+" "+(tip.x-start.x+offseX)+" "+(tip.y-start.y+offseY)+")");
+            }
+            else{ //size stays the same
+                let length = Math.max(0,Math.min(totallength,(Number(value)-min)*totallength/(max-min)));
+                let tip = this.range_elt.getPointAtLength(length);
+                elt.setAttribute('transform',"translate("+(tip.x-start.x)+","+(tip.y-start.y)+")");
+            }
+
+            // show or hide ghost if exists
             if(this.setpoint_elt != undefined){
                 if(this.last_drag!= this.drag){
                     if(this.drag){
@@ -39,22 +97,29 @@
         }
 
         on_release(evt) {
+            //unbind events
             window.removeEventListener("touchmove", this.on_bound_drag, true);
             window.removeEventListener("mousemove", this.on_bound_drag, true);
 
             window.removeEventListener("mouseup", this.bound_on_release, true)
             window.removeEventListener("touchend", this.bound_on_release, true);
             window.removeEventListener("touchcancel", this.bound_on_release, true);
+
+            //reset drag flag
             if(this.drag){
                 this.drag = false;
             }
+
+            // get final position
             this.update_position(evt);
-        }
-
+
+        }
 
         on_drag(evt){
+            //ignore drag event for X amount of time and if not selected
             if(this.enTimer && this.drag){
                 this.update_position(evt);
+
                 //reset timer
                 this.enTimer = false;
                 setTimeout("{hmi_widgets['"+this.element_id+"'].enTimer = true;}", 100);
@@ -63,11 +128,12 @@
 
         update_position(evt){
             var html_dist = 0;
+            let [min,max,start,totallength] = this.range;
 
             //calculate size of widget in html
             var range_borders = this.range_elt.getBoundingClientRect();
+            var [minX,minY,maxX,maxY] = [range_borders.left,range_borders.bottom,range_borders.right,range_borders.top];
             var range_length = Math.sqrt( range_borders.height*range_borders.height + range_borders.width*range_borders.width );
-            var [minX,minY,maxX,maxY] = [range_borders.left,range_borders.bottom,range_borders.right,range_borders.top];
 
             //get range and mouse coordinates
             var mouseX = undefined;
@@ -81,59 +147,123 @@
                 mouseY = evt.pageY;
             }
 
-            //get handle distance from mouse position
-            if (minX > mouseX && minY < mouseY){
-                html_dist = 0;
-            }
-            else if (maxX < mouseX && maxY > mouseY){
-                html_dist = range_length;
+            // calculate position
+            if (this.handle_click){ //if clicked on handle
+                let moveDist = 0, resizeAdd = 0;
+                let range_percent = 1;
+
+                //set paramters for resizeable handle
+                if (this.scroll_size != undefined){
+                    // add one more object to stay inside range
+                    resizeAdd = 1;
+
+                    //chack if range is bigger than display option and
+                    // calculate percent of range with out handle
+                    if(((max/(max*this.min_size)) < (max-min+1))){
+                        range_percent = 1-this.min_size;
+                    }
+                    else{
+                        range_percent = 1-(max-max*this.min_size*(max-min))/max;
+                    }
+                }
+
+                //calculate value difference on x or y axis
+                if(this.fi > 0.7){
+                    moveDist = ((max-min+resizeAdd)/(range_length*range_percent))*((this.handle_click[1]-mouseY)/Math.sin(this.fi));
+                }
+                else{
+                    moveDist = ((max-min+resizeAdd)/(range_length*range_percent))*((mouseX-this.handle_click[0])/Math.cos(this.fi));
+                }
+
+                this.curr_value = Math.ceil(this.handle_click[2] + moveDist);
+            }
+            else{ //if clicked on widget
+                //get handle distance from mouse position
+                if (minX > mouseX && minY < mouseY){
+                    html_dist = 0;
+                }
+                else if (maxX < mouseX && maxY > mouseY){
+                    html_dist = range_length;
+                }
+                else{
+                    if(this.fi > 0.7){
+                        html_dist = (minY - mouseY)/Math.sin(this.fi);
+                    }
+                    else{
+                        html_dist = (mouseX - minX)/Math.cos(this.fi);
+                    }
+                }
+                //calculate distance
+                this.curr_value=Math.ceil((html_dist/range_length)*(this.range[1]-this.range[0])+this.range[0]);
+            }
+
+            //check if in range
+            if (this.curr_value > max){
+                this.curr_value = max;
+            }
+            else if (this.curr_value < min){
+                this.curr_value = min;
+            }
+
+            this.apply_hmi_value(0, this.curr_value);
+
+            //redraw handle
+            this.request_animate();
+
+        }
+
+        animate(){
+            // redraw handle on screen refresh
+            // check if setpoint(ghost) handle exsist otherwise update main handle
+            if(this.setpoint_elt != undefined){
+                this.update_DOM(this.curr_value, this.setpoint_elt);
             }
             else{
-                // calculate distace
-                if(this.fi > 0.7){
-                    html_dist = (minY - mouseY)/Math.sin(this.fi);
-                }
-                else{
-                    html_dist = (mouseX - minX)/Math.cos(this.fi);
-                }
-
-                //check if in range
-                if (html_dist > range_length){
-                    html_dist = range_length;
-                }
-                else if (html_dist < 0){
-                    html_dist = 0;
-                }
-
-            }
-
-            this.svg_dist=Math.ceil((html_dist/range_length)*this.range[1]);
-
-            this.apply_hmi_value(0, this.svg_dist);
-
-            // update ghost cursor
-            if(this.setpoint_elt != undefined){
-                this.request_animate();
-            }
-        }
-
-        animate(){
-            this.update_DOM(this.svg_dist, this.setpoint_elt);
+                this.update_DOM(this.curr_value, this.handle_elt);
+            }
         }
 
         on_select(evt){
+            //enable drag flag and timer
             this.drag = true;
             this.enTimer = true;
+
+            //bind events
             window.addEventListener("touchmove", this.on_bound_drag, true);
             window.addEventListener("mousemove", this.on_bound_drag, true);
 
             window.addEventListener("mouseup", this.bound_on_release, true)
             window.addEventListener("touchend", this.bound_on_release, true);
             window.addEventListener("touchcancel", this.bound_on_release, true);
-            this.update_position(evt);
+
+            // check if handle was pressed
+            if (evt.currentTarget == this.handle_elt){
+                //get mouse position on the handle
+                let mouseX = undefined;
+                let mouseY = undefined;
+                if (evt.type.startsWith("touch")){
+                    mouseX = Math.ceil(evt.touches[0].clientX);
+                    mouseY = Math.ceil(evt.touches[0].clientY);
+                }
+                else{
+                    mouseX = evt.pageX;
+                    mouseY = evt.pageY;
+                }
+                //save coordinates and orig value
+                this.handle_click = [mouseX,mouseY,this.curr_value];
+            }
+            else{
+                // get new handle position and reset if handle was not pressed
+                this.handle_click = undefined;
+                this.update_position(evt);
+            }
+
+            //prevent next events
+            evt.stopPropagation();
         }
 
         init() {
+            //set min max value if not defined
             let min = this.min_elt ?
                         Number(this.min_elt.textContent) :
                         this.args.length >= 1 ? this.args[0] : 0;
@@ -141,15 +271,20 @@
                         Number(this.max_elt.textContent) :
                         this.args.length >= 2 ? this.args[1] : 100;
 
+            // save initial parameters
+            this.range_elt.style.strokeMiterlimit="0";
             this.range = [min, max, this.range_elt.getPointAtLength(0),this.range_elt.getTotalLength()];
             let start = this.range_elt.getPointAtLength(0);
             let end = this.range_elt.getPointAtLength(this.range_elt.getTotalLength());
             this.fi = Math.atan2(start.y-end.y, end.x-start.x);
-
+            this.handle_orig = this.handle_elt.getBBox();
+
+            //bind functions
             this.bound_on_select = this.on_select.bind(this);
             this.bound_on_release = this.on_release.bind(this);
             this.on_bound_drag = this.on_drag.bind(this);
 
+            this.handle_elt.addEventListener("mousedown", this.bound_on_select);
             this.element.addEventListener("mousedown", this.bound_on_select);
             this.element.addEventListener("touchstart", this.bound_on_select);