# HG changeset patch # User Edouard Tisserant # Date 1728636406 -7200 # Node ID d9b772623fd9585d14add046d8c0089ca47a6da8 # Parent 59a331f80858e01aa20194e8ec7f39377d0984b5 SVGHMI update generated XSLT diff -r 59a331f80858 -r d9b772623fd9 svghmi/analyse_widget.xslt --- a/svghmi/analyse_widget.xslt Fri Oct 11 10:38:30 2024 +0200 +++ b/svghmi/analyse_widget.xslt Fri Oct 11 10:46:46 2024 +0200 @@ -245,23 +245,6 @@ - - - - - - AnimateRotation - DEPRECATED, do not use. - - Doesn't follow WYSIWYG principle, and forces user to add animateTransform tag in SVG (using inkscape XML editor for exemple) - - - - AnimateRotation - DEPRECATED - - - speed - - @@ -405,47 +388,6 @@ Value to display - - - - - - CircularSlider - DEPRECATED, to be replaced by PathSlider - - This widget moves "handle" labeled group along "range" labeled - - arc, according to value of the single accepted variable. - - - - If "min" a "max" labeled texts are provided, or if first and second - - argument are given, then they are used as respective minimum and maximum - - value. Otherwise, value is expected to be in between 0 and 100. - - - - If "value" labeled text is found, then its content is replaced by value. - - During drag, "setpoint" labeled group is moved to position defined by user - - while "handle" reflects current value from variable. - - - - CircularSlider - DEPRECATED - - - minimum value - - - maximum value - - - Value to display - - @@ -587,6 +529,12 @@ "ClassName:+/-number". + + + In case of "ClassName:offset", offset for first element is 1. + + + span widgets over a set of repeated HMI_NODEs @@ -938,27 +886,6 @@ visible - - - - - - Slider - DEPRECATED - use ScrollBar or PathSlider instead - - - - Slider - DEPRECATED - use ScrollBar instead - - - value - - - range - - - visible - - diff -r 59a331f80858 -r d9b772623fd9 svghmi/gen_index_xhtml.xslt --- a/svghmi/gen_index_xhtml.xslt Fri Oct 11 10:38:30 2024 +0200 +++ b/svghmi/gen_index_xhtml.xslt Fri Oct 11 10:46:46 2024 +0200 @@ -5,15 +5,6 @@ - - - HMI_PLC_STATUS - - - HMI_CURRENT_PAGE - - - @@ -121,35 +112,23 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + @@ -1929,7 +1908,7 @@ - sub(new_offset=0, relativeness, container_id){ + sub(new_offset, relativeness, container_id){ this.offset = new_offset; @@ -2561,193 +2540,6 @@ - - class - AnimateWidget - extends Widget{ - - frequency = 5; - - speed = 0; - - start = false; - - widget_center = undefined; - - - - dispatch(value) { - - this.speed = value / 5; - - - - //reconfigure animation - - this.request_animate(); - - } - - - - animate(){ - - // change animation properties - - for(let child of this.element.children){ - - if(child.nodeName.startsWith("animate")){ - - if(this.speed != 0 && !this.start){ - - this.start = true; - - this.element.beginElement(); - - } - - - - if(this.speed > 0){ - - child.setAttribute("dur", this.speed+"s"); - - } - - else if(this.speed < 0){ - - child.setAttribute("dur", (-1)*this.speed+"s"); - - } - - else{ - - this.start = false; - - this.element.endElement(); - - } - - } - - } - - } - - - - init() { - - let widget_pos = this.element.getBBox(); - - this.widget_center = [(widget_pos.x+widget_pos.width/2), (widget_pos.y+widget_pos.height/2)]; - - } - - } - - - - - - - - AnimateRotation - DEPRECATED, do not use. - - Doesn't follow WYSIWYG principle, and forces user to add animateTransform tag in SVG (using inkscape XML editor for exemple) - - - - AnimateRotation - DEPRECATED - - - speed - - - - class - AnimateRotationWidget - extends Widget{ - - frequency = 5; - - speed = 0; - - widget_center = undefined; - - - - dispatch(value) { - - this.speed = value / 5; - - - - //reconfigure animation - - this.request_animate(); - - } - - - - animate(){ - - // change animation properties - - // TODO : rewrite with proper es6 - - for(let child of this.element.children){ - - if(child.nodeName == "animateTransform"){ - - if(this.speed > 0){ - - child.setAttribute("dur", this.speed+"s"); - - child.setAttribute("from", "0 "+this.widget_center[0]+" "+this.widget_center[1]); - - child.setAttribute("to", "360 "+this.widget_center[0]+" "+this.widget_center[1]); - - } - - else if(this.speed < 0){ - - child.setAttribute("dur", (-1)*this.speed+"s"); - - child.setAttribute("from", "360 "+this.widget_center[0]+" "+this.widget_center[1]); - - child.setAttribute("to", "0 "+this.widget_center[0]+" "+this.widget_center[1]); - - } - - else{ - - child.setAttribute("from", "0 "+this.widget_center[0]+" "+this.widget_center[1]); - - child.setAttribute("to", "0 "+this.widget_center[0]+" "+this.widget_center[1]); - - } - - } - - } - - } - - - - init() { - - let widget_pos = this.element.getBBox(); - - this.widget_center = [(widget_pos.x+widget_pos.width/2), (widget_pos.y+widget_pos.height/2)]; - - } - - } - - @@ -3547,534 +3339,6 @@ - - - - - - CircularSlider - DEPRECATED, to be replaced by PathSlider - - This widget moves "handle" labeled group along "range" labeled - - arc, according to value of the single accepted variable. - - - - If "min" a "max" labeled texts are provided, or if first and second - - argument are given, then they are used as respective minimum and maximum - - value. Otherwise, value is expected to be in between 0 and 100. - - - - If "value" labeled text is found, then its content is replaced by value. - - During drag, "setpoint" labeled group is moved to position defined by user - - while "handle" reflects current value from variable. - - - - CircularSlider - DEPRECATED - - - minimum value - - - maximum value - - - Value to display - - - - class - CircularSliderWidget - extends Widget{ - - frequency = 5; - - range = undefined; - - circle = undefined; - - handle_pos = undefined; - - curr_value = 0; - - drag = false; - - enTimer = false; - - last_drag = false; - - - - dispatch(value) { - - let [min,max,start,totallength] = this.range; - - //save current value inside widget - - this.curr_value = value; - - - - //check if in range - - if (this.curr_value > max){ - - this.curr_value = max; - - this.apply_hmi_value(0, this.curr_value); - - } - - else if (this.curr_value < min){ - - this.curr_value = min; - - this.apply_hmi_value(0, this.curr_value); - - } - - - - if(this.value_elt) - - this.value_elt.textContent = String(value); - - - - //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,totalDistance] = this.range; - - let length = Math.max(0,Math.min((totalDistance),(Number(value)-min)/(max-min)*(totalDistance))); - - let tip = this.range_elt.getPointAtLength(length); - - elt.setAttribute('transform',"translate("+(tip.x-this.handle_pos.x)+","+(tip.y-this.handle_pos.y)+")"); - - - - // show or hide ghost if exists - - if(this.setpoint_elt != undefined){ - - if(this.last_drag!= this.drag){ - - if(this.drag){ - - this.setpoint_elt.setAttribute("style", this.setpoint_style); - - }else{ - - this.setpoint_elt.setAttribute("style", "display:none"); - - } - - this.last_drag = this.drag; - - } - - } - - } - - - - 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); - - } - - } - - - - update_position(evt){ - - if(this.drag && this.enTimer){ - - var svg_dist = 0; - - - - //calculate center of widget in html - - // --TODO maybe it would be better to bind this part to window change size event ??? - - let [xdest,ydest,svgWidth,svgHeight] = page_desc[current_visible_page].bbox; - - let [cX, cY,fiStart,fiEnd,minMax,x1,y1,width,height] = this.circle; - - let htmlCirc = this.range_elt.getBoundingClientRect(); - - let cxHtml = ((htmlCirc.right-htmlCirc.left)/(width)*(cX-x1))+htmlCirc.left; - - let cyHtml = ((htmlCirc.bottom-htmlCirc.top)/(height)*(cY-y1))+htmlCirc.top; - - - - - - //get mouse coordinates - - 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; - - } - - - - //calculate angle - - let fi = Math.atan2(cyHtml-mouseY, mouseX-cxHtml); - - - - // transform from 0 to 2PI - - if (fi > 0){ - - fi = 2*Math.PI-fi; - - } - - else{ - - fi = -fi; - - } - - - - //offset it to 0 - - fi = fi - fiStart; - - if (fi < 0){ - - fi = fi + 2*Math.PI; - - } - - - - //get handle distance from mouse position - - if(fi<fiEnd){ - - this.curr_value=(fi)/(fiEnd)*(this.range[1]-this.range[0]); - - } - - else if(fiEnd<fi && fi<fiEnd+minMax){ - - this.curr_value = this.range[1]; - - } - - else{ - - this.curr_value = this.range[0]; - - } - - - - //apply value to hmi - - this.apply_hmi_value(0, Math.ceil(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{ - - 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); - - - - //update postion on mouse press - - this.update_position(evt); - - - - //prevent next events - - evt.stopPropagation(); - - } - - - - init() { - - //get min max - - let min = this.min_elt ? - - Number(this.min_elt.textContent) : - - this.args.length >= 1 ? this.args[0] : 0; - - let max = this.max_elt ? - - Number(this.max_elt.textContent) : - - this.args.length >= 2 ? this.args[1] : 100; - - - - //fiStart ==> offset - - let fiStart = Number(this.range_elt.getAttribute('sodipodi:start')); - - let fiEnd = Number(this.range_elt.getAttribute('sodipodi:end')); - - fiEnd = fiEnd - fiStart; - - - - //fiEnd ==> size of angle - - if (fiEnd < 0){ - - fiEnd = 2*Math.PI + fiEnd; - - } - - - - //min max barrier angle - - let minMax = (2*Math.PI - fiEnd)/2; - - - - //get parameters from svg - - let cX = Number(this.range_elt.getAttribute('sodipodi:cx')); - - let cY = Number(this.range_elt.getAttribute('sodipodi:cy')); - - this.range_elt.style.strokeMiterlimit="0"; //eliminates some weird border around html object - - this.range = [min, max,this.range_elt.getTotalLength()]; - - let cPos = this.range_elt.getBBox(); - - this.handle_pos = this.range_elt.getPointAtLength(0); - - this.circle = [cX, cY,fiStart,fiEnd,minMax,cPos.x,cPos.y,cPos.width,cPos.height]; - - - - //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); - - //touch recognised as page drag without next command - - document.body.addEventListener("touchstart", function(e){}, false); - - - - //save ghost style - - //save ghost style - - if(this.setpoint_elt != undefined){ - - this.setpoint_style = this.setpoint_elt.getAttribute("style"); - - this.setpoint_elt.setAttribute("style", "display:none"); - - } - - - - } - - } - - - - - - - - - /disabled - - - - - - - - - - handle range - - - - - - value min max setpoint - - - - - - @@ -5174,6 +4438,12 @@ "ClassName:+/-number". + + + In case of "ClassName:offset", offset for first element is 1. + + + span widgets over a set of repeated HMI_NODEs @@ -5198,7 +4468,7 @@ - + ForEach widget @@ -5273,6 +4543,14 @@ + + + Duplicate item labeled + + in ForEach widget + + + @@ -5307,7 +4585,15 @@ }, - item_offset: 0, + range: + + , + + size: + + , + + position: 0, @@ -5315,18 +4601,26 @@ ForEachWidget extends Widget{ + items_subscribed = false; + unsub_items(){ - for(let item of this.items){ - - for(let widget of item) { - - widget.unsub(); + if(this.items_subscribed){ + + for(let item of this.items){ + + for(let widget of item) { + + widget.unsub(); + + } } + this.items_subscribed = false; + } } @@ -5335,45 +4629,47 @@ unsub(){ + super.unsub() + this.unsub_items(); - this.offset = 0; - - this.relativeness = undefined; - } sub_items(){ - for(let i = 0; i < this.items.length; i++) { - - let item = this.items[i]; - - let orig_item_index = this.index_pool[i]; - - let item_index = this.index_pool[i+this.item_offset]; - - let item_index_offset = item_index - orig_item_index; - - if(this.relativeness[0]) - - item_index_offset += this.offset; - - for(let widget of item) { - - /* all variables of all widgets in a ForEach are all relative. - - Really. - - - - TODO: allow absolute variables in ForEach widgets - - */ - - widget.sub(item_index_offset, widget.indexes.map(_=>true)); + if(!this.items_subscribed){ + + for(let i = 0; i < this.size; i++) { + + let item = this.items[i]; + + let orig_item_index = this.index_pool[i]; + + let item_index = this.index_pool[i+this.position]; + + let item_index_offset = item_index - orig_item_index; + + if(this.relativeness[0]) + + item_index_offset += this.offset; + + for(let widget of item) { + + /* all variables of all widgets in a ForEach are all relative. + + Really. + + + + TODO: allow absolute variables in ForEach widgets + + */ + + widget.sub(item_index_offset, widget.indexes.map(_=>true)); + + } } @@ -5383,68 +4679,136 @@ - sub(new_offset=0, relativeness=[]){ - - this.offset = new_offset; - - this.relativeness = relativeness; + sub(new_offset, relativeness, container_id){ + + let position_given = this.indexes.length > 2; + + + + // sub() will call apply_cache() and then dispatch() + + // undefining position forces dispatch() to call apply_position() + + if(position_given) + + this.position = undefined; + + + + super.sub(new_offset, relativeness, container_id); + + + + // if position isn't given as a variable + + // dispatch() to call apply_position() aren't called + + // and items must be subscibed now. + + if(!position_given) + + this.sub_items(); + + + + // as soon as subribed apply range and size once for all + + this.apply_hmi_value(1, this.range); + + this.apply_hmi_value(3, this.size); + + } + + + + apply_position(new_position){ + + let old_position = this.position; + + let limited_position = Math.round(Math.max(Math.min(new_position, this.range - this.size), 0)); + + if(this.position == limited_position){ + + return false; + + } + + this.unsub_items(); + + this.position = limited_position; this.sub_items(); + request_subscriptions_update(); + + jumps_need_update = true; + + this.request_animate(); + + return true; + } - apply_cache() { - - this.items.forEach(item=>item.forEach(widget=>widget.apply_cache())); + on_click(opstr, evt) { + + let new_position = eval(String(this.position)+opstr); + + if(new_position + this.size > this.range) { + + if(this.position + this.size == this.range) + + new_position = 0; + + else + + new_position = this.range - this.size; + + } else if(new_position < 0) { + + if(this.position == 0) + + new_position = this.range - this.size; + + else + + new_position = 0; + + } + + if(this.apply_position(new_position)){ + + this.apply_hmi_value(2, this.position); + + } } - on_click(opstr, evt) { - - let new_item_offset = eval(String(this.item_offset)+opstr); - - if(new_item_offset + this.items.length > this.index_pool.length) { - - if(this.item_offset + this.items.length == this.index_pool.length) - - new_item_offset = 0; - - else - - new_item_offset = this.index_pool.length - this.items.length; - - } else if(new_item_offset < 0) { - - if(this.item_offset == 0) - - new_item_offset = this.index_pool.length - this.items.length; - - else - - new_item_offset = 0; + dispatch(value, oldval, index) { + + // Only care about position, others are constants + + if(index == 2){ + + this.apply_position(value); + + if(this.position != value){ + + // widget refused or apply different value, force it back + + this.apply_hmi_value(2, this.position); + + } } - this.item_offset = new_item_offset; - - this.unsub_items(); - - this.sub_items(); - - update_subscriptions(); - - this.apply_cache(); - - jumps_need_update = true; - - requestHMIAnimation(); - } + + } @@ -7968,728 +7332,6 @@ }, - - - - - - Slider - DEPRECATED - use ScrollBar or PathSlider instead - - - - Slider - DEPRECATED - use ScrollBar instead - - - value - - - range - - - visible - - - - class - SliderWidget - extends Widget{ - - frequency = 5; - - range = undefined; - - handle_orig = undefined; - - scroll_size = undefined; - - scroll_range = 0; - - scroll_visible = 7; - - min_size = 0.07; - - fi = undefined; - - curr_value = 0; - - drag = false; - - enTimer = false; - - handle_click = undefined; - - last_drag = false; - - - - dispatch(value,oldval, index) { - - if (index == 0){ - - let [min,max,start,totallength] = this.range; - - //save current value inside widget - - this.curr_value = value; - - - - //check if in range - - if (this.curr_value > max){ - - this.curr_value = max; - - this.apply_hmi_value(0, this.curr_value); - - } - - else if (this.curr_value < min){ - - this.curr_value = min; - - this.apply_hmi_value(0, this.curr_value); - - } - - - - if(this.value_elt) - - this.value_elt.textContent = String(value); - - } - - else if(index == 1){ - - this.scroll_range = value; - - this.set_scroll(); - - } - - else if(index == 2){ - - this.scroll_visible = value; - - this.set_scroll(); - - } - - - - //don't update if draging and setpoint ghost doesn't exist - - if(!this.drag || (this.setpoint_elt != undefined)){ - - this.update_DOM(this.curr_value, this.handle_elt); - - } - - } - - - - set_scroll(){ - - //check if range is bigger than visible and set scroll size - - if(this.scroll_range > this.scroll_visible){ - - this.scroll_size = this.scroll_range - this.scroll_visible; - - this.range[0] = 0; - - this.range[1] = this.scroll_size; - - } - - else{ - - this.scroll_size = 1; - - this.range[0] = 0; - - this.range[1] = 1; - - } - - } - - - - update_DOM(value, elt){ - - let [min,max,start,totallength] = this.range; - - // 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){ - - this.setpoint_elt.setAttribute("style", this.setpoint_style); - - }else{ - - this.setpoint_elt.setAttribute("style", "display:none"); - - } - - this.last_drag = this.drag; - - } - - } - - } - - - - 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); - - } - - } - - - - 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 ); - - - - //get range and mouse coordinates - - var mouseX = undefined; - - var 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; - - } - - - - // 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 and apply - - 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{ - - 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); - - - - // 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; - - let max = this.max_elt ? - - 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); - - //touch recognised as page drag without next command - - document.body.addEventListener("touchstart", function(e){}, false); - - - - //save ghost style - - if(this.setpoint_elt != undefined){ - - this.setpoint_style = this.setpoint_elt.getAttribute("style"); - - this.setpoint_elt.setAttribute("style", "display:none"); - - } - - - - } - - } - - - - - - - - - /disabled - - - - - - - - - - handle range - - - - - - value min max setpoint - - - - @@ -11496,6 +10138,8 @@ let widget = hmi_widgets[id]; + if(widget.curr_value != undefined) return; + widget.do_init(); }); @@ -11750,7 +10394,7 @@ function send_blob(data) { - if(ws && data.length > 0) { + if(data.length > 0 && ws && ws.readyState == WebSocket.OPEN) { ws.send(new Blob([hmi_hash_u8].concat(data))); @@ -11820,6 +10464,8 @@ var subscriptions = []; + var subscriptions_update_requested = false; + function subscribers(index) { @@ -12088,7 +10734,13 @@ let delta = []; - if(!ws) + + + subscriptions_update_requested = false; + + + + if(!ws || ws.readyState != WebSocket.OPEN) // dont' change subscriptions if not connected @@ -12162,6 +10814,22 @@ + function request_subscriptions_update(){ + + if(!subscriptions_update_requested){ + + subscriptions_update_requested = true; + + Promise.resolve().then(update_subscriptions); + + } + + } + + + + + function send_hmi_value(index, value) { if(index > last_remote_index){ @@ -12490,7 +11158,7 @@ - update_subscriptions(); + request_subscriptions_update();