svghmi/widget_circularslider.ysl2
branchsvghmi
changeset 3018 22b969b409b0
parent 3013 0ea6b4f435de
child 3045 f6d428330e04
equal deleted inserted replaced
3008:dabad70db1bf 3018:22b969b409b0
       
     1 // widget_circuralslider.ysl2
       
     2 
       
     3 template "widget[@type='CircularSlider']", mode="widget_class"
       
     4     ||
       
     5     class CircularSliderWidget extends Widget{
       
     6         frequency = 5;
       
     7         range = undefined;
       
     8         circle = undefined;
       
     9         handle_pos = undefined;
       
    10         drag = false;
       
    11         enTimer = false;
       
    12 
       
    13         dispatch(value) {
       
    14             if(!this.drag){
       
    15                 if(this.value_elt)
       
    16                     this.value_elt.textContent = String(value);
       
    17 
       
    18                 this.handle_position(value);
       
    19             }
       
    20         }
       
    21 
       
    22         handle_position(value){
       
    23             let [min,max,totalDistance] = this.range;
       
    24             let length = Math.max(0,Math.min((totalDistance),(Number(value)-min)/(max-min)*(totalDistance)));
       
    25             let tip = this.range_elt.getPointAtLength(length);
       
    26             this.handle_elt.setAttribute('transform',"translate("+(tip.x-this.handle_pos.x)+","+(tip.y-this.handle_pos.y)+")");
       
    27         }
       
    28 
       
    29         on_release(evt) {
       
    30             if(this.drag){
       
    31                 this.drag = false;
       
    32             }
       
    33         }
       
    34 
       
    35         update_position(evt){
       
    36             if(this.drag && this.enTimer){
       
    37                 var svg_dist = 0;
       
    38 
       
    39                 //calculate center of widget in html
       
    40                 // --TODO maybe it would be better to bind this part to window change size event ???
       
    41                 let [xdest,ydest,svgWidth,svgHeight] = page_desc[current_visible_page].bbox;
       
    42                 let [cX, cY,fiStart,fiEnd,minMax,x1,y1,width,height] = this.circle;
       
    43                 let htmlCirc = this.range_elt.getBoundingClientRect();
       
    44                 let cxHtml = ((htmlCirc.right-htmlCirc.left)/(width)*(cX-x1))+htmlCirc.left;
       
    45                 let cyHtml = ((htmlCirc.bottom-htmlCirc.top)/(height)*(cY-y1))+htmlCirc.top;
       
    46 
       
    47 
       
    48                 //get mouse coordinates
       
    49                 let mouseX = undefined;
       
    50                 let mouseY = undefined;
       
    51                 if (evt.type.startsWith("touch")){
       
    52                     mouseX = Math.ceil(evt.touches[0].clientX);
       
    53                     mouseY = Math.ceil(evt.touches[0].clientY);
       
    54                 }
       
    55                 else{
       
    56                     mouseX = evt.pageX;
       
    57                     mouseY = evt.pageY;
       
    58                 }
       
    59 
       
    60                 //calculate angle
       
    61                 let fi = Math.atan2(cyHtml-mouseY, mouseX-cxHtml);
       
    62 
       
    63                 // transform from 0 to 2PI
       
    64                 if (fi > 0){
       
    65                     fi = 2*Math.PI-fi;
       
    66                 }
       
    67                 else{
       
    68                     fi = -fi;
       
    69                 }
       
    70 
       
    71                 //offset it to 0
       
    72                 fi = fi - fiStart;
       
    73                 if (fi < 0){
       
    74                     fi = fi + 2*Math.PI;
       
    75                 }
       
    76 
       
    77                 //get handle distance from mouse position
       
    78                 if(fi<fiEnd){
       
    79                     svg_dist=(fi)/(fiEnd)*(this.range[1]-this.range[0]);
       
    80                 }
       
    81                 else if(fiEnd<fi && fi<fiEnd+minMax){
       
    82                     svg_dist = this.range[1];
       
    83                 }
       
    84                 else{
       
    85                     svg_dist = this.range[0];
       
    86                 }
       
    87 
       
    88                 //redraw handle --TODO is it fast enough if I just call change_hmi_value???
       
    89                 this.handle_position(svg_dist);
       
    90                 if(this.value_elt)
       
    91                     this.value_elt.textContent = String(Math.ceil(svg_dist));
       
    92                 this.apply_hmi_value(0, Math.ceil(svg_dist));
       
    93 
       
    94                 //reset timer
       
    95                 this.enTimer = false;
       
    96                 setTimeout("{hmi_widgets['"+this.element_id+"'].enTimer = true;}", 100);
       
    97             }
       
    98 
       
    99         }
       
   100 
       
   101         on_select(evt){
       
   102             this.drag = true;
       
   103             this.enTimer = true;
       
   104             this.update_position(evt);
       
   105         }
       
   106 
       
   107         init() {
       
   108             //get min max
       
   109             let min = this.min_elt ?
       
   110                         Number(this.min_elt.textContent) :
       
   111                         this.args.length >= 1 ? this.args[0] : 0;
       
   112             let max = this.max_elt ?
       
   113                         Number(this.max_elt.textContent) :
       
   114                         this.args.length >= 2 ? this.args[1] : 100;
       
   115 
       
   116             //fiStart ==> offset
       
   117             let fiStart = Number(this.range_elt.getAttribute('sodipodi:start'));
       
   118             let fiEnd = Number(this.range_elt.getAttribute('sodipodi:end'));
       
   119             fiEnd = fiEnd - fiStart;
       
   120 
       
   121             //fiEnd ==> size of angle
       
   122             if (fiEnd < 0){
       
   123                 fiEnd = 2*Math.PI + fiEnd;
       
   124             }
       
   125 
       
   126             //min max barrier angle
       
   127             let minMax = (2*Math.PI - fiEnd)/2;
       
   128 
       
   129             //get parameters from svg
       
   130             let cX = Number(this.range_elt.getAttribute('sodipodi:cx'));
       
   131             let cY = Number(this.range_elt.getAttribute('sodipodi:cy'));
       
   132             this.range_elt.style.strokeMiterlimit="0"; //eliminates some weird border around html object
       
   133             this.range = [min, max,this.range_elt.getTotalLength()];
       
   134             let cPos = this.range_elt.getBBox();
       
   135             this.handle_pos = this.range_elt.getPointAtLength(0);
       
   136             this.circle = [cX, cY,fiStart,fiEnd,minMax,cPos.x,cPos.y,cPos.width,cPos.height];
       
   137 
       
   138             //init events
       
   139             this.handle_elt.addEventListener("touchstart", hmi_widgets[this.element_id].on_select.bind(this));
       
   140             this.handle_elt.addEventListener("mousedown", hmi_widgets[this.element_id].on_select.bind(this));
       
   141             this.element.addEventListener("mousedown", hmi_widgets[this.element_id].on_select.bind(this));
       
   142 
       
   143             window.addEventListener("touchmove", hmi_widgets[this.element_id].update_position.bind(this));
       
   144             window.addEventListener("mousemove", hmi_widgets[this.element_id].update_position.bind(this));
       
   145 
       
   146             window.addEventListener("mouseup", hmi_widgets[this.element_id].on_release.bind(this))
       
   147             window.addEventListener("touchend", hmi_widgets[this.element_id].on_release.bind(this));
       
   148             window.addEventListener("touchcancel", hmi_widgets[this.element_id].on_release.bind(this));
       
   149 
       
   150         }
       
   151     }
       
   152     ||
       
   153 
       
   154 template "widget[@type='CircularSlider']", mode="widget_defs" {
       
   155     param "hmi_element";
       
   156     labels("handle range");
       
   157     optional_labels("value min max");
       
   158     |,
       
   159 }