svghmi/svghmi.js
changeset 3648 ff42600fddd7
parent 3645 82882a9f91ce
child 3650 9256c344c2da
equal deleted inserted replaced
3647:7c427418396f 3648:ff42600fddd7
    20     });
    20     });
    21 };
    21 };
    22 
    22 
    23 // Open WebSocket to relative "/ws" address
    23 // Open WebSocket to relative "/ws" address
    24 var has_watchdog = window.location.hash == "#watchdog";
    24 var has_watchdog = window.location.hash == "#watchdog";
    25 
       
    26 var ws_url =
       
    27     window.location.href.replace(/^http(s?:\/\/[^\/]*)\/.*$/, 'ws$1/ws')
       
    28     + '?mode=' + (has_watchdog ? "watchdog" : "multiclient");
       
    29 
       
    30 var ws = new WebSocket(ws_url);
       
    31 ws.binaryType = 'arraybuffer';
       
    32 
    25 
    33 const dvgetters = {
    26 const dvgetters = {
    34     INT: (dv,offset) => [dv.getInt16(offset, true), 2],
    27     INT: (dv,offset) => [dv.getInt16(offset, true), 2],
    35     BOOL: (dv,offset) => [dv.getInt8(offset, true), 1],
    28     BOOL: (dv,offset) => [dv.getInt8(offset, true), 1],
    36     NODE: (dv,offset) => [dv.getInt8(offset, true), 1],
    29     NODE: (dv,offset) => [dv.getInt8(offset, true), 1],
    96 }
    89 }
    97 
    90 
    98 // Message reception handler
    91 // Message reception handler
    99 // Hash is verified and HMI values updates resulting from binary parsing
    92 // Hash is verified and HMI values updates resulting from binary parsing
   100 // are stored until browser can compute next frame, DOM is left untouched
    93 // are stored until browser can compute next frame, DOM is left untouched
   101 ws.onmessage = function (evt) {
    94 function ws_onmessage(evt) {
   102 
    95 
   103     let data = evt.data;
    96     let data = evt.data;
   104     let dv = new DataView(data);
    97     let dv = new DataView(data);
   105     let i = 0;
    98     let i = 0;
   106     try {
    99     try {
   138     }
   131     }
   139 };
   132 };
   140 
   133 
   141 hmi_hash_u8 = new Uint8Array(hmi_hash);
   134 hmi_hash_u8 = new Uint8Array(hmi_hash);
   142 
   135 
       
   136 var ws = null;
       
   137 
   143 function send_blob(data) {
   138 function send_blob(data) {
   144     if(data.length > 0) {
   139     if(ws && data.length > 0) {
   145         ws.send(new Blob([hmi_hash_u8].concat(data)));
   140         ws.send(new Blob([hmi_hash_u8].concat(data)));
   146     };
   141     };
   147 };
   142 };
   148 
   143 
   149 const typedarray_types = {
   144 const typedarray_types = {
   197     } else {
   192     } else {
   198         entry[1] = period;
   193         entry[1] = period;
   199     }
   194     }
   200 }
   195 }
   201 
   196 
       
   197 function reset_subscription_periods() {
       
   198     for(let index in subscriptions)
       
   199         subscriptions[index][1] = 0;
       
   200 }
       
   201 
   202 if(has_watchdog){
   202 if(has_watchdog){
   203     // artificially subscribe the watchdog widget to "/heartbeat" hmi variable
   203     // artificially subscribe the watchdog widget to "/heartbeat" hmi variable
   204     // Since dispatch directly calls change_hmi_value,
   204     // Since dispatch directly calls change_hmi_value,
   205     // PLC will periodically send variable at given frequency
   205     // PLC will periodically send variable at given frequency
   206     subscribers(heartbeat_index).add({
   206     subscribers(heartbeat_index).add({
   296 
   296 
   297 setup_lang();
   297 setup_lang();
   298 
   298 
   299 function update_subscriptions() {
   299 function update_subscriptions() {
   300     let delta = [];
   300     let delta = [];
       
   301     if(!ws)
       
   302         // dont' change subscriptions if not connected
       
   303         return;
       
   304 
   301     for(let index in subscriptions){
   305     for(let index in subscriptions){
   302         let widgets = subscribers(index);
   306         let widgets = subscribers(index);
   303 
   307 
   304         // periods are in ms
   308         // periods are in ms
   305         let previous_period = get_subscription_period(index);
   309         let previous_period = get_subscription_period(index);
   416   } else {
   420   } else {
   417     document.exitFullscreen();
   421     document.exitFullscreen();
   418   }
   422   }
   419 }
   423 }
   420 
   424 
   421 function prepare_svg() {
   425 // prevents context menu from appearing on right click and long touch
   422     // prevents context menu from appearing on right click and long touch
   426 document.body.addEventListener('contextmenu', e => {
   423     document.body.addEventListener('contextmenu', e => {
   427     toggleFullscreen();
   424         toggleFullscreen();
   428     e.preventDefault();
   425         e.preventDefault();
   429 });
   426     });
   430 
       
   431 function detach_detachables() {
   427 
   432 
   428     for(let eltid in detachable_elements){
   433     for(let eltid in detachable_elements){
   429         let [element,parent] = detachable_elements[eltid];
   434         let [element,parent] = detachable_elements[eltid];
   430         parent.removeChild(element);
   435         parent.removeChild(element);
   431     }
   436     }
   570         group.transform.baseVal.appendItem(transform);
   575         group.transform.baseVal.appendItem(transform);
   571         ["x", "y"].forEach((axis) => group.removeAttribute("svghmi_"+axis+"_offset"));
   576         ["x", "y"].forEach((axis) => group.removeAttribute("svghmi_"+axis+"_offset"));
   572     });
   577     });
   573 }
   578 }
   574 
   579 
       
   580 // prepare SVG
       
   581 apply_reference_frames();
       
   582 init_widgets();
       
   583 detach_detachables();
       
   584 
       
   585 // show main page
       
   586 switch_page(default_page);
       
   587 
       
   588 var reconnect_delay = 0;
       
   589 // var periodic_reconnect_timer;
       
   590 
   575 // Once connection established
   591 // Once connection established
   576 ws.onopen = function (evt) {
   592 function ws_onopen(evt) {
   577     apply_reference_frames();
   593     /* 
   578     init_widgets();
   594     // to force reconnect every hour
       
   595     if(periodic_reconnect_timer){
       
   596         window.clearTimeout(periodic_reconnect_timer);
       
   597     }
       
   598     periodic_reconnect_timer = window.setTimeout(() => {
       
   599         ws.close();
       
   600         periodic_reconnect_timer = null;
       
   601     }, 3600*1000);
       
   602     */
       
   603 
       
   604     // forget subscriptions remotely
   579     send_reset();
   605     send_reset();
   580     // show main page
   606 
   581     prepare_svg();
   607     // forget earlier subscriptions locally
   582     switch_page(default_page);
   608     reset_subscription_periods();
   583 };
   609 
   584 
   610     // update PLC about subscriptions and current page
   585 ws.onclose = function (evt) {
   611     switch_page();
       
   612 
       
   613     // at first try reconnect immediately
       
   614     reconnect_delay = 1;
       
   615 };
       
   616 
       
   617 function ws_onclose(evt) {
       
   618     console.log("Connection closed. code:"+evt.code+" reason:"+evt.reason+" wasClean:"+evt.wasClean+" Reload in "+reconnect_delay+"ms.");
       
   619     ws = null;
       
   620     // reconect
   586     // TODO : add visible notification while waiting for reload
   621     // TODO : add visible notification while waiting for reload
   587     console.log("Connection closed. code:"+evt.code+" reason:"+evt.reason+" wasClean:"+evt.wasClean+" Reload in 10s.");
   622     window.setTimeout(create_ws, reconnect_delay);
   588     // TODO : re-enable auto reload when not in debug
   623     reconnect_delay += 500;
   589     //window.setTimeout(() => location.reload(true), 10000);
   624 };
   590     alert("Connection closed. code:"+evt.code+" reason:"+evt.reason+" wasClean:"+evt.wasClean+".");
   625 
   591 
   626 var ws_url =
   592 };
   627     window.location.href.replace(/^http(s?:\/\/[^\/]*)\/.*$/, 'ws$1/ws')
       
   628     + '?mode=' + (has_watchdog ? "watchdog" : "multiclient");
       
   629 
       
   630 function create_ws(){
       
   631     ws = new WebSocket(ws_url);
       
   632     ws.binaryType = 'arraybuffer';
       
   633     ws.onmessage = ws_onmessage;
       
   634     ws.onclose = ws_onclose;
       
   635     ws.onopen = ws_onopen;
       
   636 }
       
   637 
       
   638 create_ws()
   593 
   639 
   594 const xmlns = "http://www.w3.org/2000/svg";
   640 const xmlns = "http://www.w3.org/2000/svg";
   595 var edit_callback;
   641 var edit_callback;
   596 const localtypes = {"PAGE_LOCAL":null, "HMI_LOCAL":null}
   642 const localtypes = {"PAGE_LOCAL":null, "HMI_LOCAL":null}
   597 function edit_value(path, valuetype, callback, initial) {
   643 function edit_value(path, valuetype, callback, initial) {