Button, ToggleButton and slider updated. Error to warning when building
Button fixed so it doesn't release until it gets feedback from plc
Toggle button changed so it makes changes instantly. There was too big delay if we waited for feedback.
Slider added new features need some changes for final version.
--- a/svghmi/widget_button.ysl2 Tue Aug 18 11:42:28 2020 +0200
+++ b/svghmi/widget_button.ysl2 Wed Sep 16 09:41:52 2020 +0200
@@ -5,23 +5,40 @@
class ButtonWidget extends Widget{
frequency = 5;
state = 0;
+ plc_lock = false;
active_style = undefined;
inactive_style = undefined;
+ dispatch(value) {
+ if(value){
+ this.button_release();
+ }
+ }
+
on_mouse_down(evt) {
if (this.active_style && this.inactive_style) {
this.active_elt.setAttribute("style", this.active_style);
this.inactive_elt.setAttribute("style", "display:none");
}
this.apply_hmi_value(0, 1);
+ this.plc_lock = false;
}
on_mouse_up(evt) {
- if (this.active_style && this.inactive_style) {
- this.active_elt.setAttribute("style", "display:none");
- this.inactive_elt.setAttribute("style", this.inactive_style);
- }
- this.apply_hmi_value(0, 0);
+ this.button_release();
+ }
+
+ button_release(){
+ if(!this.plc_lock){
+ this.plc_lock = true;
+ }
+ else{
+ if (this.active_style && this.inactive_style) {
+ this.active_elt.setAttribute("style", "display:none");
+ this.inactive_elt.setAttribute("style", this.inactive_style);
+ }
+ this.apply_hmi_value(0, 0);
+ }
}
init() {
--- 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);
--- a/svghmi/widget_tooglebutton.ysl2 Tue Aug 18 11:42:28 2020 +0200
+++ b/svghmi/widget_tooglebutton.ysl2 Wed Sep 16 09:41:52 2020 +0200
@@ -10,19 +10,28 @@
inactive_style = undefined;
dispatch(value) {
- this.state = value;
- if (this.state) {
- this.active_elt.setAttribute("style", this.active_style);
- this.inactive_elt.setAttribute("style", "display:none");
- this.state = 0;
- } else {
- this.inactive_elt.setAttribute("style", this.inactive_style);
- this.active_elt.setAttribute("style", "display:none");
- this.state = 1;
+ if(this.state != value){
+ this.state = value;
+ if (this.state) {
+ this.active_elt.setAttribute("style", this.active_style);
+ this.inactive_elt.setAttribute("style", "display:none");
+ } else {
+ this.inactive_elt.setAttribute("style", this.inactive_style);
+ this.active_elt.setAttribute("style", "display:none");
+ }
}
}
on_click(evt) {
+ if (this.state) {
+ this.inactive_elt.setAttribute("style", this.inactive_style);
+ this.active_elt.setAttribute("style", "display:none");
+ this.state = 0;
+ } else {
+ this.active_elt.setAttribute("style", this.active_style);
+ this.inactive_elt.setAttribute("style", "display:none");
+ this.state = 1;
+ }
this.apply_hmi_value(0, this.state);
}
@@ -30,6 +39,8 @@
this.active_style = this.active_elt.style.cssText;
this.inactive_style = this.inactive_elt.style.cssText;
this.element.setAttribute("onclick", "hmi_widgets['"+this.element_id+"'].on_click(evt)");
+ this.inactive_elt.setAttribute("style", this.inactive_style);
+ this.active_elt.setAttribute("style", "display:none");
}
}
||
--- a/svghmi/widgets_common.ysl2 Tue Aug 18 11:42:28 2020 +0200
+++ b/svghmi/widgets_common.ysl2 Wed Sep 16 09:41:52 2020 +0200
@@ -30,7 +30,7 @@
when "not(@index)" {
choose {
when "not(@type)"
- error > Widget «$widget/@type» id="«$eltid»" : No match for path "«@value»" in HMI tree
+ warning > Widget «$widget/@type» id="«$eltid»" : No match for path "«@value»" in HMI tree
when "@type = 'PAGE_LOCAL'"
> "«@value»"`if "position()!=last()" > ,`
when "@type = 'HMI_LOCAL'"