# HG changeset patch # User Edouard Tisserant # Date 1598607078 -7200 # Node ID c113904f0e62558358568e46b38d82b808b43a10 # Parent d1bb0c09e412d938e76230d9c8baeb94bc62a6d1# Parent f6d428330e0471cbb7c4f75a4c8edf7785f3cd4f Merged diff -r d1bb0c09e412 -r c113904f0e62 svghmi/gen_index_xhtml.xslt --- a/svghmi/gen_index_xhtml.xslt Fri Aug 28 11:27:07 2020 +0200 +++ b/svghmi/gen_index_xhtml.xslt Fri Aug 28 11:31:18 2020 +0200 @@ -1583,10 +1583,98 @@ <xsl:text> </xsl:text> </xsl:template> + <xsl:template mode="widget_class" match="widget[@type='CircularBar']"> + <xsl:text>class CircularBarWidget extends Widget{ +</xsl:text> + <xsl:text> frequency = 10; +</xsl:text> + <xsl:text> range = undefined; +</xsl:text> + <xsl:text> +</xsl:text> + <xsl:text> dispatch(value) { +</xsl:text> + <xsl:text> if(this.value_elt) +</xsl:text> + <xsl:text> this.value_elt.textContent = String(value); +</xsl:text> + <xsl:text> let [min,max,start,end] = this.range; +</xsl:text> + <xsl:text> let [cx,cy] = this.center; +</xsl:text> + <xsl:text> let [rx,ry] = this.proportions; +</xsl:text> + <xsl:text> let tip = start + (end-start)*Number(value)/(max-min); +</xsl:text> + <xsl:text> let size = 0; +</xsl:text> + <xsl:text> if (tip-start > Math.PI) { +</xsl:text> + <xsl:text> size = 1; +</xsl:text> + <xsl:text> } else { +</xsl:text> + <xsl:text> size = 0; +</xsl:text> + <xsl:text> } +</xsl:text> + <xsl:text> this.path_elt.setAttribute('d', "M "+(cx+rx*Math.cos(start))+","+(cy+ry*Math.sin(start))+" A "+rx+","+ry+" 0 "+size+" 1 "+(cx+rx*Math.cos(tip))+","+(cy+ry*Math.sin(tip))); +</xsl:text> + <xsl:text> } +</xsl:text> + <xsl:text> +</xsl:text> + <xsl:text> init() { +</xsl:text> + <xsl:text> let start = Number(this.path_elt.getAttribute('sodipodi:start')); +</xsl:text> + <xsl:text> let end = Number(this.path_elt.getAttribute('sodipodi:end')); +</xsl:text> + <xsl:text> let cx = Number(this.path_elt.getAttribute('sodipodi:cx')); +</xsl:text> + <xsl:text> let cy = Number(this.path_elt.getAttribute('sodipodi:cy')); +</xsl:text> + <xsl:text> let rx = Number(this.path_elt.getAttribute('sodipodi:rx')); +</xsl:text> + <xsl:text> let ry = Number(this.path_elt.getAttribute('sodipodi:ry')); +</xsl:text> + <xsl:text> if (ry == 0) { +</xsl:text> + <xsl:text> ry = rx; +</xsl:text> + <xsl:text> } +</xsl:text> + <xsl:text> if (start > end) { +</xsl:text> + <xsl:text> end = end + 2*Math.PI; +</xsl:text> + <xsl:text> } +</xsl:text> + <xsl:text> let min = this.min_elt ? +</xsl:text> + <xsl:text> Number(this.min_elt.textContent) : +</xsl:text> + <xsl:text> this.args.length >= 1 ? this.args[0] : 0; +</xsl:text> + <xsl:text> let max = this.max_elt ? +</xsl:text> + <xsl:text> Number(this.max_elt.textContent) : +</xsl:text> + <xsl:text> this.args.length >= 2 ? this.args[1] : 100; +</xsl:text> + <xsl:text> this.range = [min, max, start, end]; +</xsl:text> + <xsl:text> this.center = [cx, cy]; +</xsl:text> + <xsl:text> this.proportions = [rx, ry]; +</xsl:text> + <xsl:text> } +</xsl:text> + <xsl:text>} +</xsl:text> + </xsl:template> <xsl:template mode="widget_defs" match="widget[@type='CircularBar']"> <xsl:param name="hmi_element"/> - <xsl:text>frequency: 10, -</xsl:text> <xsl:call-template name="defs_by_labels"> <xsl:with-param name="hmi_element" select="$hmi_element"/> <xsl:with-param name="labels"> @@ -1600,83 +1688,7 @@ </xsl:with-param> <xsl:with-param name="mandatory" select="'no'"/> </xsl:call-template> - <xsl:text>dispatch: function(value) { -</xsl:text> - <xsl:text> if(this.value_elt) -</xsl:text> - <xsl:text> this.value_elt.textContent = String(value); -</xsl:text> - <xsl:text> let [min,max,start,end] = this.range; -</xsl:text> - <xsl:text> let [cx,cy] = this.center; -</xsl:text> - <xsl:text> let [rx,ry] = this.proportions; -</xsl:text> - <xsl:text> let tip = start + (end-start)*Number(value)/(max-min); -</xsl:text> - <xsl:text> let size = 0; -</xsl:text> - <xsl:text> if (tip-start > Math.PI) { -</xsl:text> - <xsl:text> size = 1; -</xsl:text> - <xsl:text> } else { -</xsl:text> - <xsl:text> size = 0; -</xsl:text> - <xsl:text> } -</xsl:text> - <xsl:text> this.path_elt.setAttribute('d', "M "+(cx+rx*Math.cos(start))+","+(cy+ry*Math.sin(start))+" A "+rx+","+ry+" 0 "+size+" 1 "+(cx+rx*Math.cos(tip))+","+(cy+ry*Math.sin(tip))); -</xsl:text> - <xsl:text>}, -</xsl:text> - <xsl:text>range: undefined, -</xsl:text> - <xsl:text>init: function() { -</xsl:text> - <xsl:text> let start = Number(this.path_elt.getAttribute('sodipodi:start')); -</xsl:text> - <xsl:text> let end = Number(this.path_elt.getAttribute('sodipodi:end')); -</xsl:text> - <xsl:text> let cx = Number(this.path_elt.getAttribute('sodipodi:cx')); -</xsl:text> - <xsl:text> let cy = Number(this.path_elt.getAttribute('sodipodi:cy')); -</xsl:text> - <xsl:text> let rx = Number(this.path_elt.getAttribute('sodipodi:rx')); -</xsl:text> - <xsl:text> let ry = Number(this.path_elt.getAttribute('sodipodi:ry')); -</xsl:text> - <xsl:text> if (ry == 0) { -</xsl:text> - <xsl:text> ry = rx; -</xsl:text> - <xsl:text> } -</xsl:text> - <xsl:text> if (start > end) { -</xsl:text> - <xsl:text> end = end + 2*Math.PI; -</xsl:text> - <xsl:text> } -</xsl:text> - <xsl:text> let min = this.min_elt ? -</xsl:text> - <xsl:text> Number(this.min_elt.textContent) : -</xsl:text> - <xsl:text> this.args.length >= 1 ? this.args[0] : 0; -</xsl:text> - <xsl:text> let max = this.max_elt ? -</xsl:text> - <xsl:text> Number(this.max_elt.textContent) : -</xsl:text> - <xsl:text> this.args.length >= 2 ? this.args[1] : 100; -</xsl:text> - <xsl:text> this.range = [min, max, start, end]; -</xsl:text> - <xsl:text> this.center = [cx, cy]; -</xsl:text> - <xsl:text> this.proportions = [rx, ry]; -</xsl:text> - <xsl:text>}, + <xsl:text> </xsl:text> </xsl:template> <xsl:template mode="widget_class" match="widget[@type='CircularSlider']"> @@ -1690,23 +1702,59 @@ </xsl:text> <xsl:text> handle_pos = undefined; </xsl:text> + <xsl:text> svg_dist = undefined; +</xsl:text> <xsl:text> drag = false; </xsl:text> <xsl:text> enTimer = false; </xsl:text> + <xsl:text> last_drag = false; +</xsl:text> <xsl:text> </xsl:text> <xsl:text> dispatch(value) { </xsl:text> - <xsl:text> if(!this.drag){ -</xsl:text> - <xsl:text> if(this.value_elt) -</xsl:text> - <xsl:text> this.value_elt.textContent = String(value); -</xsl:text> - <xsl:text> -</xsl:text> - <xsl:text> this.handle_position(value); + <xsl:text> if(this.value_elt) +</xsl:text> + <xsl:text> this.value_elt.textContent = String(value); +</xsl:text> + <xsl:text> +</xsl:text> + <xsl:text> this.update_DOM(value, this.handle_elt); +</xsl:text> + <xsl:text> } +</xsl:text> + <xsl:text> +</xsl:text> + <xsl:text> update_DOM(value, elt){ +</xsl:text> + <xsl:text> let [min,max,totalDistance] = this.range; +</xsl:text> + <xsl:text> let length = Math.max(0,Math.min((totalDistance),(Number(value)-min)/(max-min)*(totalDistance))); +</xsl:text> + <xsl:text> let tip = this.range_elt.getPointAtLength(length); +</xsl:text> + <xsl:text> elt.setAttribute('transform',"translate("+(tip.x-this.handle_pos.x)+","+(tip.y-this.handle_pos.y)+")"); +</xsl:text> + <xsl:text> +</xsl:text> + <xsl:text> if(this.setpoint_elt != undefined){ +</xsl:text> + <xsl:text> if(this.last_drag!= this.drag){ +</xsl:text> + <xsl:text> if(this.drag){ +</xsl:text> + <xsl:text> this.setpoint_elt.setAttribute("style", this.setpoint_style); +</xsl:text> + <xsl:text> }else{ +</xsl:text> + <xsl:text> this.setpoint_elt.setAttribute("style", "display:none"); +</xsl:text> + <xsl:text> } +</xsl:text> + <xsl:text> this.last_drag = this.drag; +</xsl:text> + <xsl:text> } </xsl:text> <xsl:text> } </xsl:text> @@ -1714,28 +1762,46 @@ </xsl:text> <xsl:text> </xsl:text> - <xsl:text> handle_position(value){ -</xsl:text> - <xsl:text> let [min,max,totalDistance] = this.range; -</xsl:text> - <xsl:text> let length = Math.max(0,Math.min((totalDistance),(Number(value)-min)/(max-min)*(totalDistance))); -</xsl:text> - <xsl:text> let tip = this.range_elt.getPointAtLength(length); -</xsl:text> - <xsl:text> this.handle_elt.setAttribute('transform',"translate("+(tip.x-this.handle_pos.x)+","+(tip.y-this.handle_pos.y)+")"); -</xsl:text> - <xsl:text> } -</xsl:text> - <xsl:text> -</xsl:text> <xsl:text> on_release(evt) { </xsl:text> + <xsl:text> window.removeEventListener("touchmove", this.on_bound_drag, true); +</xsl:text> + <xsl:text> window.removeEventListener("mousemove", this.on_bound_drag, true); +</xsl:text> + <xsl:text> +</xsl:text> + <xsl:text> window.removeEventListener("mouseup", this.bound_on_release, true) +</xsl:text> + <xsl:text> window.removeEventListener("touchend", this.bound_on_release, true); +</xsl:text> + <xsl:text> window.removeEventListener("touchcancel", this.bound_on_release, true); +</xsl:text> <xsl:text> if(this.drag){ </xsl:text> <xsl:text> this.drag = false; </xsl:text> <xsl:text> } </xsl:text> + <xsl:text> this.update_position(evt); +</xsl:text> + <xsl:text> } +</xsl:text> + <xsl:text> +</xsl:text> + <xsl:text> on_drag(evt){ +</xsl:text> + <xsl:text> if(this.enTimer && this.drag){ +</xsl:text> + <xsl:text> this.update_position(evt); +</xsl:text> + <xsl:text> //reset timer +</xsl:text> + <xsl:text> this.enTimer = false; +</xsl:text> + <xsl:text> setTimeout("{hmi_widgets['"+this.element_id+"'].enTimer = true;}", 100); +</xsl:text> + <xsl:text> } +</xsl:text> <xsl:text> } </xsl:text> <xsl:text> @@ -1828,41 +1894,37 @@ </xsl:text> <xsl:text> if(fi<fiEnd){ </xsl:text> - <xsl:text> svg_dist=(fi)/(fiEnd)*(this.range[1]-this.range[0]); + <xsl:text> this.svg_dist=(fi)/(fiEnd)*(this.range[1]-this.range[0]); </xsl:text> <xsl:text> } </xsl:text> <xsl:text> else if(fiEnd<fi && fi<fiEnd+minMax){ </xsl:text> - <xsl:text> svg_dist = this.range[1]; + <xsl:text> this.svg_dist = this.range[1]; </xsl:text> <xsl:text> } </xsl:text> <xsl:text> else{ </xsl:text> - <xsl:text> svg_dist = this.range[0]; + <xsl:text> this.svg_dist = this.range[0]; </xsl:text> <xsl:text> } </xsl:text> <xsl:text> </xsl:text> - <xsl:text> //redraw handle --TODO is it fast enough if I just call change_hmi_value??? -</xsl:text> - <xsl:text> this.handle_position(svg_dist); -</xsl:text> - <xsl:text> if(this.value_elt) -</xsl:text> - <xsl:text> this.value_elt.textContent = String(Math.ceil(svg_dist)); -</xsl:text> - <xsl:text> this.apply_hmi_value(0, Math.ceil(svg_dist)); -</xsl:text> - <xsl:text> -</xsl:text> - <xsl:text> //reset timer -</xsl:text> - <xsl:text> this.enTimer = false; -</xsl:text> - <xsl:text> setTimeout("{hmi_widgets['"+this.element_id+"'].enTimer = true;}", 100); + <xsl:text> +</xsl:text> + <xsl:text> this.apply_hmi_value(0, Math.ceil(this.svg_dist)); +</xsl:text> + <xsl:text> +</xsl:text> + <xsl:text> // update ghost cursor +</xsl:text> + <xsl:text> if(this.setpoint_elt != undefined){ +</xsl:text> + <xsl:text> this.request_animate(); +</xsl:text> + <xsl:text> } </xsl:text> <xsl:text> } </xsl:text> @@ -1872,12 +1934,32 @@ </xsl:text> <xsl:text> </xsl:text> + <xsl:text> animate(){ +</xsl:text> + <xsl:text> this.update_DOM(this.svg_dist, this.setpoint_elt); +</xsl:text> + <xsl:text> } +</xsl:text> + <xsl:text> +</xsl:text> <xsl:text> on_select(evt){ </xsl:text> <xsl:text> this.drag = true; </xsl:text> <xsl:text> this.enTimer = true; </xsl:text> + <xsl:text> window.addEventListener("touchmove", this.on_bound_drag, true); +</xsl:text> + <xsl:text> window.addEventListener("mousemove", this.on_bound_drag, true); +</xsl:text> + <xsl:text> +</xsl:text> + <xsl:text> window.addEventListener("mouseup", this.bound_on_release, true) +</xsl:text> + <xsl:text> window.addEventListener("touchend", this.bound_on_release, true); +</xsl:text> + <xsl:text> window.addEventListener("touchcancel", this.bound_on_release, true); +</xsl:text> <xsl:text> this.update_position(evt); </xsl:text> <xsl:text> } @@ -1946,13 +2028,33 @@ </xsl:text> <xsl:text> </xsl:text> + <xsl:text> //bind functions +</xsl:text> + <xsl:text> this.bound_on_select = this.on_select.bind(this); +</xsl:text> + <xsl:text> this.bound_on_release = this.on_release.bind(this); +</xsl:text> + <xsl:text> this.on_bound_drag = this.on_drag.bind(this); +</xsl:text> + <xsl:text> +</xsl:text> <xsl:text> //init events </xsl:text> - <xsl:text> this.handle_elt.addEventListener("touchstart", hmi_widgets[this.element_id].on_select.bind(this)); -</xsl:text> - <xsl:text> this.handle_elt.addEventListener("mousedown", hmi_widgets[this.element_id].on_select.bind(this)); -</xsl:text> - <xsl:text> this.element.addEventListener("mousedown", hmi_widgets[this.element_id].on_select.bind(this)); + <xsl:text> this.element.addEventListener("mousedown", this.bound_on_select); +</xsl:text> + <xsl:text> this.element.addEventListener("touchstart", this.bound_on_select); +</xsl:text> + <xsl:text> +</xsl:text> + <xsl:text> if(this.setpoint_elt != undefined){ +</xsl:text> + <xsl:text> this.setpoint_style = this.setpoint_elt.getAttribute("style"); +</xsl:text> + <xsl:text> this.setpoint_elt.setAttribute("style", "display:none"); +</xsl:text> + <xsl:text> } +</xsl:text> + <xsl:text> </xsl:text> <xsl:text> </xsl:text> @@ -3973,7 +4075,7 @@ </xsl:text> <xsl:text> moving = undefined; </xsl:text> - <xsl:text> enTimer = undefined; + <xsl:text> click = undefined; </xsl:text> <xsl:text> offset = undefined; </xsl:text> @@ -3983,7 +4085,21 @@ </xsl:text> <xsl:text> this.moving = true; </xsl:text> - <xsl:text> this.enTimer = true; + <xsl:text> +</xsl:text> + <xsl:text> // chatch window events +</xsl:text> + <xsl:text> window.addEventListener("touchmove", this.bound_on_drag, true); +</xsl:text> + <xsl:text> window.addEventListener("mousemove", this.bound_on_drag, true); +</xsl:text> + <xsl:text> +</xsl:text> + <xsl:text> window.addEventListener("mouseup", this.bound_on_release, true) +</xsl:text> + <xsl:text> window.addEventListener("touchend", this.bound_on_release, true); +</xsl:text> + <xsl:text> window.addEventListener("touchcancel", this.bound_on_release, true); </xsl:text> <xsl:text> </xsl:text> @@ -4017,7 +4133,23 @@ </xsl:text> <xsl:text> </xsl:text> - <xsl:text> off_position_click(evt) { + <xsl:text> on_release(evt) { +</xsl:text> + <xsl:text> //relase binds +</xsl:text> + <xsl:text> window.removeEventListener("touchmove", this.bound_on_drag, true); +</xsl:text> + <xsl:text> window.removeEventListener("mousemove", this.bound_on_drag, true); +</xsl:text> + <xsl:text> +</xsl:text> + <xsl:text> window.removeEventListener("mouseup", this.bound_on_release, true) +</xsl:text> + <xsl:text> window.removeEventListener("touchend", this.bound_on_release, true); +</xsl:text> + <xsl:text> window.removeEventListener("touchcancel", this.bound_on_release, true); +</xsl:text> + <xsl:text> </xsl:text> <xsl:text> if(this.moving) </xsl:text> @@ -4027,63 +4159,65 @@ </xsl:text> <xsl:text> </xsl:text> - <xsl:text> on_move(evt) { -</xsl:text> - <xsl:text> if(this.moving && this.enTimer){ -</xsl:text> - <xsl:text> //get keyboard pos in html -</xsl:text> - <xsl:text> let [eltid, tmpgrp] = current_modal; -</xsl:text> - <xsl:text> let [xcoord,ycoord] = this.coordinates; -</xsl:text> - <xsl:text> let [xdest,ydest,svgWidth,svgHeight] = page_desc[current_visible_page].bbox; -</xsl:text> - <xsl:text> -</xsl:text> - <xsl:text> //get mouse coordinates -</xsl:text> - <xsl:text> var clickX = undefined; -</xsl:text> - <xsl:text> var clickY = undefined; -</xsl:text> - <xsl:text> if (evt.type == "touchmove"){ -</xsl:text> - <xsl:text> clickX = Math.ceil(evt.touches[0].clientX); -</xsl:text> - <xsl:text> clickY = Math.ceil(evt.touches[0].clientY); -</xsl:text> - <xsl:text> } -</xsl:text> - <xsl:text> else{ -</xsl:text> - <xsl:text> clickX = evt.pageX; -</xsl:text> - <xsl:text> clickY = evt.pageY; -</xsl:text> - <xsl:text> } -</xsl:text> - <xsl:text> -</xsl:text> - <xsl:text> //translate keyboard position -</xsl:text> - <xsl:text> let mouseX = ((clickX-this.offset[0])/window.innerWidth)*svgWidth; -</xsl:text> - <xsl:text> let mouseY = ((clickY-this.offset[1])/window.innerHeight)*svgHeight; -</xsl:text> - <xsl:text> tmpgrp.setAttribute("transform","translate("+String(xdest-xcoord+mouseX)+","+String(ydest-ycoord+mouseY)+")"); -</xsl:text> - <xsl:text> -</xsl:text> - <xsl:text> //reset timer -</xsl:text> - <xsl:text> this.enTimer = false; -</xsl:text> - <xsl:text> setTimeout("{hmi_widgets['"+this.element_id+"'].enTimer = true;}", 100); -</xsl:text> - <xsl:text> } -</xsl:text> - <xsl:text> + <xsl:text> on_drag(evt) { +</xsl:text> + <xsl:text> if(this.moving) +</xsl:text> + <xsl:text> //get mouse coordinates +</xsl:text> + <xsl:text> var clickX = undefined; +</xsl:text> + <xsl:text> var clickY = undefined; +</xsl:text> + <xsl:text> if (evt.type == "touchmove"){ +</xsl:text> + <xsl:text> clickX = Math.ceil(evt.touches[0].clientX); +</xsl:text> + <xsl:text> clickY = Math.ceil(evt.touches[0].clientY); +</xsl:text> + <xsl:text> } +</xsl:text> + <xsl:text> else{ +</xsl:text> + <xsl:text> clickX = evt.pageX; +</xsl:text> + <xsl:text> clickY = evt.pageY; +</xsl:text> + <xsl:text> } +</xsl:text> + <xsl:text> this.click = [clickX,clickY] +</xsl:text> + <xsl:text> +</xsl:text> + <xsl:text> //requeset redraw +</xsl:text> + <xsl:text> this.request_animate(); +</xsl:text> + <xsl:text> } +</xsl:text> + <xsl:text> +</xsl:text> + <xsl:text> animate(){ +</xsl:text> + <xsl:text> //get keyboard pos in html +</xsl:text> + <xsl:text> let [eltid, tmpgrp] = current_modal; +</xsl:text> + <xsl:text> let [xcoord,ycoord] = this.coordinates; +</xsl:text> + <xsl:text> let [clickX,clickY] = this.click; +</xsl:text> + <xsl:text> let [xdest,ydest,svgWidth,svgHeight] = page_desc[current_visible_page].bbox; +</xsl:text> + <xsl:text> +</xsl:text> + <xsl:text> //translate keyboard position +</xsl:text> + <xsl:text> let mouseX = ((clickX-this.offset[0])/window.innerWidth)*svgWidth; +</xsl:text> + <xsl:text> let mouseY = ((clickY-this.offset[1])/window.innerHeight)*svgHeight; +</xsl:text> + <xsl:text> tmpgrp.setAttribute("transform","translate("+String(xdest-xcoord+mouseX)+","+String(ydest-ycoord+mouseY)+")"); </xsl:text> <xsl:text> } </xsl:text> @@ -4329,20 +4463,16 @@ </xsl:for-each> <xsl:text> if(this.position_elt){ </xsl:text> + <xsl:text> this.bound_on_release = this.on_release.bind(this); +</xsl:text> + <xsl:text> this.bound_on_drag = this.on_drag.bind(this); +</xsl:text> + <xsl:text> +</xsl:text> <xsl:text> this.position_elt.setAttribute("onmousedown", "hmi_widgets['"+this.element_id+"'].on_position_click(evt)"); </xsl:text> <xsl:text> this.position_elt.setAttribute("ontouchstart", "hmi_widgets['"+this.element_id+"'].on_position_click(evt)"); </xsl:text> - <xsl:text> window.addEventListener("mouseup", hmi_widgets[this.element_id].off_position_click.bind(this)); -</xsl:text> - <xsl:text> window.addEventListener("touchend", hmi_widgets[this.element_id].off_position_click.bind(this)); -</xsl:text> - <xsl:text> window.addEventListener("touchcancel", hmi_widgets[this.element_id].off_position_click.bind(this)); -</xsl:text> - <xsl:text> window.addEventListener("mousemove", hmi_widgets[this.element_id].on_move.bind(this)); -</xsl:text> - <xsl:text> window.addEventListener("touchmove", hmi_widgets[this.element_id].on_move.bind(this)); -</xsl:text> <xsl:text> } </xsl:text> <xsl:text> }, @@ -4388,10 +4518,62 @@ <xsl:text> }, </xsl:text> </xsl:template> + <xsl:template mode="widget_class" match="widget[@type='Meter']"> + <xsl:text>class MeterWidget extends Widget{ +</xsl:text> + <xsl:text> frequency = 10; +</xsl:text> + <xsl:text> origin = undefined; +</xsl:text> + <xsl:text> range = undefined; +</xsl:text> + <xsl:text> +</xsl:text> + <xsl:text> dispatch(value) { +</xsl:text> + <xsl:text> if(this.value_elt) +</xsl:text> + <xsl:text> this.value_elt.textContent = String(value); +</xsl:text> + <xsl:text> let [min,max,totallength] = this.range; +</xsl:text> + <xsl:text> let length = Math.max(0,Math.min(totallength,(Number(value)-min)*totallength/(max-min))); +</xsl:text> + <xsl:text> let tip = this.range_elt.getPointAtLength(length); +</xsl:text> + <xsl:text> this.needle_elt.setAttribute('d', "M "+this.origin.x+","+this.origin.y+" "+tip.x+","+tip.y); +</xsl:text> + <xsl:text> } +</xsl:text> + <xsl:text> +</xsl:text> + <xsl:text> init() { +</xsl:text> + <xsl:text> let min = this.min_elt ? +</xsl:text> + <xsl:text> Number(this.min_elt.textContent) : +</xsl:text> + <xsl:text> this.args.length >= 1 ? this.args[0] : 0; +</xsl:text> + <xsl:text> let max = this.max_elt ? +</xsl:text> + <xsl:text> Number(this.max_elt.textContent) : +</xsl:text> + <xsl:text> this.args.length >= 2 ? this.args[1] : 100; +</xsl:text> + <xsl:text> this.range = [min, max, this.range_elt.getTotalLength()] +</xsl:text> + <xsl:text> this.origin = this.needle_elt.getPointAtLength(0); +</xsl:text> + <xsl:text> } +</xsl:text> + <xsl:text> +</xsl:text> + <xsl:text>} +</xsl:text> + </xsl:template> <xsl:template mode="widget_defs" match="widget[@type='Meter']"> <xsl:param name="hmi_element"/> - <xsl:text> frequency: 10, -</xsl:text> <xsl:call-template name="defs_by_labels"> <xsl:with-param name="hmi_element" select="$hmi_element"/> <xsl:with-param name="labels"> @@ -4405,45 +4587,7 @@ </xsl:with-param> <xsl:with-param name="mandatory" select="'no'"/> </xsl:call-template> - <xsl:text> dispatch: function(value) { -</xsl:text> - <xsl:text> if(this.value_elt) -</xsl:text> - <xsl:text> this.value_elt.textContent = String(value); -</xsl:text> - <xsl:text> let [min,max,totallength] = this.range; -</xsl:text> - <xsl:text> let length = Math.max(0,Math.min(totallength,(Number(value)-min)*totallength/(max-min))); -</xsl:text> - <xsl:text> let tip = this.range_elt.getPointAtLength(length); -</xsl:text> - <xsl:text> this.needle_elt.setAttribute('d', "M "+this.origin.x+","+this.origin.y+" "+tip.x+","+tip.y); -</xsl:text> - <xsl:text> }, -</xsl:text> - <xsl:text> origin: undefined, -</xsl:text> - <xsl:text> range: undefined, -</xsl:text> - <xsl:text> init: function() { -</xsl:text> - <xsl:text> let min = this.min_elt ? -</xsl:text> - <xsl:text> Number(this.min_elt.textContent) : -</xsl:text> - <xsl:text> this.args.length >= 1 ? this.args[0] : 0; -</xsl:text> - <xsl:text> let max = this.max_elt ? -</xsl:text> - <xsl:text> Number(this.max_elt.textContent) : -</xsl:text> - <xsl:text> this.args.length >= 2 ? this.args[1] : 100; -</xsl:text> - <xsl:text> this.range = [min, max, this.range_elt.getTotalLength()] -</xsl:text> - <xsl:text> this.origin = this.needle_elt.getPointAtLength(0); -</xsl:text> - <xsl:text> }, + <xsl:text> </xsl:text> </xsl:template> <xsl:template mode="widget_class" match="widget[@type='MultiState']"> @@ -4568,6 +4712,8 @@ </xsl:text> <xsl:text> fi = undefined; </xsl:text> + <xsl:text> svg_dist = undefined; +</xsl:text> <xsl:text> drag = false; </xsl:text> <xsl:text> enTimer = false; diff -r d1bb0c09e412 -r c113904f0e62 svghmi/widget_circularbar.ysl2 --- a/svghmi/widget_circularbar.ysl2 Fri Aug 28 11:27:07 2020 +0200 +++ b/svghmi/widget_circularbar.ysl2 Fri Aug 28 11:31:18 2020 +0200 @@ -1,48 +1,57 @@ // widget_circularbar.ysl2 +template "widget[@type='CircularBar']", mode="widget_class"{ + || + class CircularBarWidget extends Widget{ + frequency = 10; + range = undefined; + + dispatch(value) { + if(this.value_elt) + this.value_elt.textContent = String(value); + let [min,max,start,end] = this.range; + let [cx,cy] = this.center; + let [rx,ry] = this.proportions; + let tip = start + (end-start)*Number(value)/(max-min); + let size = 0; + if (tip-start > Math.PI) { + size = 1; + } else { + size = 0; + } + this.path_elt.setAttribute('d', "M "+(cx+rx*Math.cos(start))+","+(cy+ry*Math.sin(start))+" A "+rx+","+ry+" 0 "+size+" 1 "+(cx+rx*Math.cos(tip))+","+(cy+ry*Math.sin(tip))); + } + + init() { + let start = Number(this.path_elt.getAttribute('sodipodi:start')); + let end = Number(this.path_elt.getAttribute('sodipodi:end')); + let cx = Number(this.path_elt.getAttribute('sodipodi:cx')); + let cy = Number(this.path_elt.getAttribute('sodipodi:cy')); + let rx = Number(this.path_elt.getAttribute('sodipodi:rx')); + let ry = Number(this.path_elt.getAttribute('sodipodi:ry')); + if (ry == 0) { + ry = rx; + } + if (start > end) { + end = end + 2*Math.PI; + } + 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; + this.range = [min, max, start, end]; + this.center = [cx, cy]; + this.proportions = [rx, ry]; + } + } + || +} template "widget[@type='CircularBar']", mode="widget_defs" { param "hmi_element"; - | frequency: 10, labels("path"); optional_labels("value min max"); - | dispatch: function(value) { - | if(this.value_elt) - | this.value_elt.textContent = String(value); - | let [min,max,start,end] = this.range; - | let [cx,cy] = this.center; - | let [rx,ry] = this.proportions; - | let tip = start + (end-start)*Number(value)/(max-min); - | let size = 0; - | if (tip-start > Math.PI) { - | size = 1; - | } else { - | size = 0; - | } - | this.path_elt.setAttribute('d', "M "+(cx+rx*Math.cos(start))+","+(cy+ry*Math.sin(start))+" A "+rx+","+ry+" 0 "+size+" 1 "+(cx+rx*Math.cos(tip))+","+(cy+ry*Math.sin(tip))); - | }, - | range: undefined, - | init: function() { - | let start = Number(this.path_elt.getAttribute('sodipodi:start')); - | let end = Number(this.path_elt.getAttribute('sodipodi:end')); - | let cx = Number(this.path_elt.getAttribute('sodipodi:cx')); - | let cy = Number(this.path_elt.getAttribute('sodipodi:cy')); - | let rx = Number(this.path_elt.getAttribute('sodipodi:rx')); - | let ry = Number(this.path_elt.getAttribute('sodipodi:ry')); - | if (ry == 0) { - | ry = rx; - | } - | if (start > end) { - | end = end + 2*Math.PI; - | } - | 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; - | this.range = [min, max, start, end]; - | this.center = [cx, cy]; - | this.proportions = [rx, ry]; - | }, + |, } \ No newline at end of file diff -r d1bb0c09e412 -r c113904f0e62 svghmi/widget_circularslider.ysl2 --- a/svghmi/widget_circularslider.ysl2 Fri Aug 28 11:27:07 2020 +0200 +++ b/svghmi/widget_circularslider.ysl2 Fri Aug 28 11:31:18 2020 +0200 @@ -7,29 +7,56 @@ range = undefined; circle = undefined; handle_pos = undefined; + svg_dist = undefined; drag = false; enTimer = false; + last_drag = false; dispatch(value) { - if(!this.drag){ - if(this.value_elt) - this.value_elt.textContent = String(value); - - this.handle_position(value); - } - } - - handle_position(value){ + if(this.value_elt) + this.value_elt.textContent = String(value); + + 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); - this.handle_elt.setAttribute('transform',"translate("+(tip.x-this.handle_pos.x)+","+(tip.y-this.handle_pos.y)+")"); + elt.setAttribute('transform',"translate("+(tip.x-this.handle_pos.x)+","+(tip.y-this.handle_pos.y)+")"); + + 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) { + 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); if(this.drag){ this.drag = false; } + this.update_position(evt); + } + + on_drag(evt){ + 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){ @@ -76,31 +103,39 @@ //get handle distance from mouse position if(fi<fiEnd){ - svg_dist=(fi)/(fiEnd)*(this.range[1]-this.range[0]); + this.svg_dist=(fi)/(fiEnd)*(this.range[1]-this.range[0]); } else if(fiEnd<fi && fi<fiEnd+minMax){ - svg_dist = this.range[1]; + this.svg_dist = this.range[1]; } else{ - svg_dist = this.range[0]; - } - - //redraw handle --TODO is it fast enough if I just call change_hmi_value??? - this.handle_position(svg_dist); - if(this.value_elt) - this.value_elt.textContent = String(Math.ceil(svg_dist)); - this.apply_hmi_value(0, Math.ceil(svg_dist)); - - //reset timer - this.enTimer = false; - setTimeout("{hmi_widgets['"+this.element_id+"'].enTimer = true;}", 100); - } - + this.svg_dist = this.range[0]; + } + + + this.apply_hmi_value(0, Math.ceil(this.svg_dist)); + + // update ghost cursor + if(this.setpoint_elt != undefined){ + this.request_animate(); + } + } + + } + + animate(){ + this.update_DOM(this.svg_dist, this.setpoint_elt); } on_select(evt){ this.drag = true; this.enTimer = true; + 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); } @@ -135,10 +170,20 @@ 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); + //init events - this.handle_elt.addEventListener("touchstart", hmi_widgets[this.element_id].on_select.bind(this)); - this.handle_elt.addEventListener("mousedown", hmi_widgets[this.element_id].on_select.bind(this)); - this.element.addEventListener("mousedown", hmi_widgets[this.element_id].on_select.bind(this)); + this.element.addEventListener("mousedown", this.bound_on_select); + this.element.addEventListener("touchstart", this.bound_on_select); + + if(this.setpoint_elt != undefined){ + this.setpoint_style = this.setpoint_elt.getAttribute("style"); + this.setpoint_elt.setAttribute("style", "display:none"); + } + window.addEventListener("touchmove", hmi_widgets[this.element_id].update_position.bind(this)); window.addEventListener("mousemove", hmi_widgets[this.element_id].update_position.bind(this)); diff -r d1bb0c09e412 -r c113904f0e62 svghmi/widget_keypad.ysl2 --- a/svghmi/widget_keypad.ysl2 Fri Aug 28 11:27:07 2020 +0200 +++ b/svghmi/widget_keypad.ysl2 Fri Aug 28 11:31:18 2020 +0200 @@ -17,12 +17,19 @@ || class KeypadWidget extends Widget{ moving = undefined; - enTimer = undefined; + click = undefined; offset = undefined; on_position_click(evt) { this.moving = true; - this.enTimer = true; + + // chatch window events + window.addEventListener("touchmove", this.bound_on_drag, true); + window.addEventListener("mousemove", this.bound_on_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); // get click position offset from widget x,y and save it to variable var keypad_borders = this.position_elt.getBoundingClientRect(); @@ -39,40 +46,49 @@ this.offset=[clickX-keypad_borders.left,clickY-keypad_borders.top] } - off_position_click(evt) { + on_release(evt) { + //relase binds + window.removeEventListener("touchmove", this.bound_on_drag, true); + window.removeEventListener("mousemove", this.bound_on_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); + if(this.moving) this.moving = false; } - on_move(evt) { - if(this.moving && this.enTimer){ - //get keyboard pos in html - let [eltid, tmpgrp] = current_modal; - let [xcoord,ycoord] = this.coordinates; - let [xdest,ydest,svgWidth,svgHeight] = page_desc[current_visible_page].bbox; - - //get mouse coordinates - var clickX = undefined; - var clickY = undefined; - if (evt.type == "touchmove"){ - clickX = Math.ceil(evt.touches[0].clientX); - clickY = Math.ceil(evt.touches[0].clientY); - } - else{ - clickX = evt.pageX; - clickY = evt.pageY; - } - - //translate keyboard position - let mouseX = ((clickX-this.offset[0])/window.innerWidth)*svgWidth; - let mouseY = ((clickY-this.offset[1])/window.innerHeight)*svgHeight; - tmpgrp.setAttribute("transform","translate("+String(xdest-xcoord+mouseX)+","+String(ydest-ycoord+mouseY)+")"); - - //reset timer - this.enTimer = false; - setTimeout("{hmi_widgets['"+this.element_id+"'].enTimer = true;}", 100); - } - + on_drag(evt) { + if(this.moving) + //get mouse coordinates + var clickX = undefined; + var clickY = undefined; + if (evt.type == "touchmove"){ + clickX = Math.ceil(evt.touches[0].clientX); + clickY = Math.ceil(evt.touches[0].clientY); + } + else{ + clickX = evt.pageX; + clickY = evt.pageY; + } + this.click = [clickX,clickY] + + //requeset redraw + this.request_animate(); + } + + animate(){ + //get keyboard pos in html + let [eltid, tmpgrp] = current_modal; + let [xcoord,ycoord] = this.coordinates; + let [clickX,clickY] = this.click; + let [xdest,ydest,svgWidth,svgHeight] = page_desc[current_visible_page].bbox; + + //translate keyboard position + let mouseX = ((clickX-this.offset[0])/window.innerWidth)*svgWidth; + let mouseY = ((clickY-this.offset[1])/window.innerHeight)*svgHeight; + tmpgrp.setAttribute("transform","translate("+String(xdest-xcoord+mouseX)+","+String(ydest-ycoord+mouseY)+")"); } on_key_click(symbols) { @@ -185,15 +201,11 @@ | this.«.»_elt.setAttribute("onclick", "hmi_widgets['«$hmi_element/@id»'].on_«.»_click()"); } | if(this.position_elt){ + | this.bound_on_release = this.on_release.bind(this); + | this.bound_on_drag = this.on_drag.bind(this); + | | this.position_elt.setAttribute("onmousedown", "hmi_widgets['"+this.element_id+"'].on_position_click(evt)"); | this.position_elt.setAttribute("ontouchstart", "hmi_widgets['"+this.element_id+"'].on_position_click(evt)"); - - | window.addEventListener("mouseup", hmi_widgets[this.element_id].off_position_click.bind(this)); - | window.addEventListener("touchend", hmi_widgets[this.element_id].off_position_click.bind(this)); - | window.addEventListener("touchcancel", hmi_widgets[this.element_id].off_position_click.bind(this)); - - | window.addEventListener("mousemove", hmi_widgets[this.element_id].on_move.bind(this)); - | window.addEventListener("touchmove", hmi_widgets[this.element_id].on_move.bind(this)); | } | }, | diff -r d1bb0c09e412 -r c113904f0e62 svghmi/widget_meter.ysl2 --- a/svghmi/widget_meter.ysl2 Fri Aug 28 11:27:07 2020 +0200 +++ b/svghmi/widget_meter.ysl2 Fri Aug 28 11:31:18 2020 +0200 @@ -1,31 +1,41 @@ // widget_meter.ysl2 +template "widget[@type='Meter']", mode="widget_class"{ + || + class MeterWidget extends Widget{ + frequency = 10; + origin = undefined; + range = undefined; + + dispatch(value) { + if(this.value_elt) + this.value_elt.textContent = String(value); + let [min,max,totallength] = this.range; + let length = Math.max(0,Math.min(totallength,(Number(value)-min)*totallength/(max-min))); + let tip = this.range_elt.getPointAtLength(length); + this.needle_elt.setAttribute('d', "M "+this.origin.x+","+this.origin.y+" "+tip.x+","+tip.y); + } + + init() { + 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; + this.range = [min, max, this.range_elt.getTotalLength()] + this.origin = this.needle_elt.getPointAtLength(0); + } + + } + || +} template "widget[@type='Meter']", mode="widget_defs" { param "hmi_element"; - | frequency: 10, labels("needle range"); optional_labels("value min max"); - | dispatch: function(value) { - | if(this.value_elt) - | this.value_elt.textContent = String(value); - | let [min,max,totallength] = this.range; - | let length = Math.max(0,Math.min(totallength,(Number(value)-min)*totallength/(max-min))); - | let tip = this.range_elt.getPointAtLength(length); - | this.needle_elt.setAttribute('d', "M "+this.origin.x+","+this.origin.y+" "+tip.x+","+tip.y); - | }, - | origin: undefined, - | range: undefined, - | init: function() { - | 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; - | this.range = [min, max, this.range_elt.getTotalLength()] - | this.origin = this.needle_elt.getPointAtLength(0); - | }, + |, } diff -r d1bb0c09e412 -r c113904f0e62 svghmi/widget_slider.ysl2 --- a/svghmi/widget_slider.ysl2 Fri Aug 28 11:27:07 2020 +0200 +++ b/svghmi/widget_slider.ysl2 Fri Aug 28 11:31:18 2020 +0200 @@ -6,6 +6,7 @@ frequency = 5; range = undefined; fi = undefined; + svg_dist = undefined; drag = false; enTimer = false;