--- 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);