beremiz

SVGHMI: JsonTable now use intermediate variables again to address JSON data without duplicating code or referencing. Using intermediate variables also alows to check for availability of data and stop evaluating early if data is missing. Finally added complete roundtrip example to illustrate use of JSonTable to display "alarms" collected in python from changes on PLC boolean variables.
// widget_keypad.ysl2
emit "declarations:keypad" {
|
| var keypads = {
foreach "$keypads_descs"{
const "keypad_id","@id";
foreach "arg"{
const "g", "$geometry[@Id = $keypad_id]";
| "«@value»":["«$keypad_id»", «$g/@x», «$g/@y»],
}
}
| }
}
template "widget[@type='Keypad']", mode="widget_class"
||
class KeypadWidget extends Widget{
moving = undefined;
enTimer = undefined;
offset = undefined;
on_position_click(evt) {
this.moving = true;
this.enTimer = true;
// get click position offset from widget x,y and save it to variable
var keypad_borders = this.position_elt.getBoundingClientRect();
var clickX = undefined;
var clickY = undefined;
if (evt.type == "touchstart"){
clickX = Math.ceil(evt.touches[0].clientX);
clickY = Math.ceil(evt.touches[0].clientY);
}
else{
clickX = evt.pageX;
clickY = evt.pageY;
}
this.offset=[clickX-keypad_borders.left,clickY-keypad_borders.top]
}
off_position_click(evt) {
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_key_click(symbols) {
var syms = symbols.split(" ");
this.shift |= this.caps;
this.editstr += syms[this.shift?syms.length-1:0];
this.shift = false;
this.update();
}
on_Esc_click() {
end_modal.call(this);
}
on_Enter_click() {
let coercedval = (typeof this.initial) == "number" ? Number(this.editstr) : this.editstr;
if(isNaN(coercedval)){
this.editstr = String(this.initial);
this.update();
} else { // revert to initial so it explicitely shows input was ignored
let callback_obj = this.result_callback_obj;
end_modal.call(this);
callback_obj.edit_callback(coercedval);
}
}
on_BackSpace_click() {
this.editstr = this.editstr.slice(0,this.editstr.length-1);
this.update();
}
on_Sign_click() {
if(this.editstr[0] == "-")
this.editstr = this.editstr.slice(1,this.editstr.length);
else
this.editstr = "-" + this.editstr;
this.update();
}
on_NumDot_click() {
if(this.editstr.indexOf(".") == "-1"){
this.editstr += ".";
this.update();
}
}
on_Space_click() {
this.editstr += " ";
this.update();
}
caps = false;
_caps = undefined;
on_CapsLock_click() {
this.caps = !this.caps;
this.update();
}
shift = false;
_shift = undefined;
on_Shift_click() {
this.shift = !this.shift;
this.caps = false;
this.update();
}
editstr = "";
_editstr = undefined;
result_callback_obj = undefined;
start_edit(info, valuetype, callback_obj, initial,size) {
show_modal.call(this,size);
this.editstr = String(initial);
this.result_callback_obj = callback_obj;
this.Info_elt.textContent = info;
this.shift = false;
this.caps = false;
this.initial = initial;
this.update();
}
update() {
if(this.editstr != this._editstr){
this._editstr = this.editstr;
this.Value_elt.textContent = this.editstr;
}
if(this.shift != this._shift){
this._shift = this.shift;
(this.shift?widget_active_activable:widget_inactive_activable)(this.Shift_sub);
}
if(this.caps != this._caps){
this._caps = this.caps;
(this.caps?widget_active_activable:widget_inactive_activable)(this.CapsLock_sub);
}
}
}
||
template "widget[@type='Keypad']", mode="widget_defs" {
param "hmi_element";
labels("Esc Enter BackSpace Keys Info Value");
optional_labels("Sign Space NumDot position");
activable_labels("CapsLock Shift");
| init: function() {
foreach "$hmi_element/*[@inkscape:label = 'Keys']/*" {
| id("«@id»").setAttribute("onclick", "hmi_widgets['«$hmi_element/@id»'].on_key_click('«func:escape_quotes(@inkscape:label)»')");
}
foreach "str:split('Esc Enter BackSpace Sign Space NumDot CapsLock Shift')" {
| if(this.«.»_elt)
| this.«.»_elt.setAttribute("onclick", "hmi_widgets['«$hmi_element/@id»'].on_«.»_click()");
}
| if(this.position_elt){
| 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));
| }
| },
|
const "g", "$geometry[@Id = $hmi_element/@id]";
| coordinates: [«$g/@x», «$g/@y»],
}