diff -r f6d428330e04 -r 827bf284feec svghmi/widget_slider.ysl2 --- 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);