SVGHMI: detach/re-attach elements required by pages on page switch svghmi
authorEdouard Tisserant <edouard.tisserant@gmail.com>
Mon, 02 Mar 2020 16:30:29 +0100
branchsvghmi
changeset 2850 e38654ec6281
parent 2849 bb89a2fbb4e0
child 2851 8d15c6238e62
SVGHMI: detach/re-attach elements required by pages on page switch

This is meant to optimize performances with large drawings leading to long restyle or reflow.
svghmi/gen_index_xhtml.xslt
svghmi/gen_index_xhtml.ysl2
svghmi/svghmi.js
--- a/svghmi/gen_index_xhtml.xslt	Mon Mar 02 16:25:35 2020 +0100
+++ b/svghmi/gen_index_xhtml.xslt	Mon Mar 02 16:30:29 2020 +0100
@@ -336,18 +336,18 @@
 </xsl:text>
     <xsl:for-each select="$hmi_elements">
       <xsl:variable name="widget" select="func:parselabel(@inkscape:label)/widget"/>
-      <xsl:text>"</xsl:text>
+      <xsl:text>    "</xsl:text>
       <xsl:value-of select="@id"/>
       <xsl:text>": {
 </xsl:text>
-      <xsl:text>    type: "</xsl:text>
+      <xsl:text>        type: "</xsl:text>
       <xsl:value-of select="$widget/@type"/>
       <xsl:text>",
 </xsl:text>
-      <xsl:text>    args: [
+      <xsl:text>        args: [
 </xsl:text>
       <xsl:for-each select="$widget/arg">
-        <xsl:text>        "</xsl:text>
+        <xsl:text>            "</xsl:text>
         <xsl:value-of select="@value"/>
         <xsl:text>"</xsl:text>
         <xsl:if test="position()!=last()">
@@ -356,9 +356,9 @@
         <xsl:text>
 </xsl:text>
       </xsl:for-each>
-      <xsl:text>    ],
-</xsl:text>
-      <xsl:text>    indexes: [
+      <xsl:text>        ],
+</xsl:text>
+      <xsl:text>        indexes: [
 </xsl:text>
       <xsl:for-each select="$widget/path">
         <xsl:variable name="hmipath" select="@value"/>
@@ -372,7 +372,7 @@
             </xsl:message>
           </xsl:when>
           <xsl:otherwise>
-            <xsl:text>        </xsl:text>
+            <xsl:text>            </xsl:text>
             <xsl:value-of select="$hmitree_match/@index"/>
             <xsl:if test="position()!=last()">
               <xsl:text>,</xsl:text>
@@ -382,16 +382,16 @@
           </xsl:otherwise>
         </xsl:choose>
       </xsl:for-each>
-      <xsl:text>    ],
-</xsl:text>
-      <xsl:text>    element: id("</xsl:text>
+      <xsl:text>        ],
+</xsl:text>
+      <xsl:text>        element: id("</xsl:text>
       <xsl:value-of select="@id"/>
       <xsl:text>"),
 </xsl:text>
       <xsl:apply-templates mode="widget_defs" select="$widget">
         <xsl:with-param name="hmi_element" select="."/>
       </xsl:apply-templates>
-      <xsl:text>}</xsl:text>
+      <xsl:text>    }</xsl:text>
       <xsl:if test="position()!=last()">
         <xsl:text>,</xsl:text>
       </xsl:if>
@@ -411,7 +411,7 @@
     <xsl:text>var hmitree_types = [
 </xsl:text>
     <xsl:for-each select="$indexed_hmitree/*">
-      <xsl:text>/* </xsl:text>
+      <xsl:text>    /* </xsl:text>
       <xsl:value-of select="@index"/>
       <xsl:text>  </xsl:text>
       <xsl:value-of select="@hmipath"/>
@@ -433,11 +433,11 @@
     <xsl:for-each select="$detachable_elements">
       <xsl:text>    "</xsl:text>
       <xsl:value-of select="@id"/>
-      <xsl:text>" : {element: id("</xsl:text>
+      <xsl:text>":[id("</xsl:text>
       <xsl:value-of select="@id"/>
-      <xsl:text>"), parent:id("</xsl:text>
+      <xsl:text>"), id("</xsl:text>
       <xsl:value-of select="../@id"/>
-      <xsl:text>")}</xsl:text>
+      <xsl:text>")]</xsl:text>
       <xsl:if test="position()!=last()">
         <xsl:text>,</xsl:text>
       </xsl:if>
@@ -964,114 +964,110 @@
 </xsl:text>
     <xsl:text>function prepare_svg() {
 </xsl:text>
-    <xsl:text>    /* set everybody hidden initially for better performance */
-</xsl:text>
-    <xsl:text>    for(let widget in hmi_widgets){
-</xsl:text>
-    <xsl:text>        if(widget.element != undefined)
-</xsl:text>
-    <xsl:text>            widget.element.style.display = "none";
+    <xsl:text>    for(let eltid in detachable_elements){
+</xsl:text>
+    <xsl:text>        let [element,parent] = detachable_elements[eltid];
+</xsl:text>
+    <xsl:text>        parent.removeChild(element);
 </xsl:text>
     <xsl:text>    }
 </xsl:text>
-    <xsl:text>        /*for(let name in page_desc){
-</xsl:text>
-    <xsl:text>            if(name != new_desc){
-</xsl:text>
-    <xsl:text>                page_desc[name].widget.element.style.display = "none";
+    <xsl:text>};
+</xsl:text>
+    <xsl:text>
+</xsl:text>
+    <xsl:text>function switch_page(page_name) {
+</xsl:text>
+    <xsl:text>    let old_desc = page_desc[current_page];
+</xsl:text>
+    <xsl:text>    let new_desc = page_desc[page_name];
+</xsl:text>
+    <xsl:text>
+</xsl:text>
+    <xsl:text>    if(new_desc == undefined){
+</xsl:text>
+    <xsl:text>        /* TODO LOG ERROR */
+</xsl:text>
+    <xsl:text>        return;
+</xsl:text>
+    <xsl:text>    }
+</xsl:text>
+    <xsl:text>
+</xsl:text>
+    <xsl:text>    if(old_desc){
+</xsl:text>
+    <xsl:text>        for(let widget of old_desc.widgets){
+</xsl:text>
+    <xsl:text>            /* remove subsribers */
+</xsl:text>
+    <xsl:text>            for(let index of widget.indexes){
+</xsl:text>
+    <xsl:text>                subscribers[index].delete(widget);
 </xsl:text>
     <xsl:text>            }
 </xsl:text>
-    <xsl:text>        }*/
-</xsl:text>
-    <xsl:text>};
-</xsl:text>
-    <xsl:text>
-</xsl:text>
-    <xsl:text>function switch_page(page_name) {
-</xsl:text>
-    <xsl:text>    let old_desc = page_desc[current_page];
-</xsl:text>
-    <xsl:text>    let new_desc = page_desc[page_name];
-</xsl:text>
-    <xsl:text>
-</xsl:text>
-    <xsl:text>    if(new_desc == undefined){
-</xsl:text>
-    <xsl:text>        /* TODO LOG ERROR */
-</xsl:text>
-    <xsl:text>        return;
+    <xsl:text>        }
+</xsl:text>
+    <xsl:text>        for(let eltid in old_desc.required_detachables){
+</xsl:text>
+    <xsl:text>            if(!(eltid in new_desc.required_detachables)){
+</xsl:text>
+    <xsl:text>                let [element, parent] = old_desc.required_detachables[eltid];
+</xsl:text>
+    <xsl:text>                parent.removeChild(element);
+</xsl:text>
+    <xsl:text>            }
+</xsl:text>
+    <xsl:text>        }
+</xsl:text>
+    <xsl:text>        for(let eltid in new_desc.required_detachables){
+</xsl:text>
+    <xsl:text>            if(!(eltid in old_desc.required_detachables)){
+</xsl:text>
+    <xsl:text>                let [element, parent] = new_desc.required_detachables[eltid];
+</xsl:text>
+    <xsl:text>                parent.appendChild(element);
+</xsl:text>
+    <xsl:text>            }
+</xsl:text>
+    <xsl:text>        }
+</xsl:text>
+    <xsl:text>    }else{
+</xsl:text>
+    <xsl:text>        for(let eltid in new_desc.required_detachables){
+</xsl:text>
+    <xsl:text>            let [element, parent] = new_desc.required_detachables[eltid];
+</xsl:text>
+    <xsl:text>            parent.appendChild(element);
+</xsl:text>
+    <xsl:text>        }
 </xsl:text>
     <xsl:text>    }
 </xsl:text>
     <xsl:text>
 </xsl:text>
-    <xsl:text>    if(old_desc){
-</xsl:text>
-    <xsl:text>        for(let widget of old_desc.widgets){
-</xsl:text>
-    <xsl:text>
-</xsl:text>
-    <xsl:text>            /* hide widget */
-</xsl:text>
-    <xsl:text>            if(widget.element != undefined)
-</xsl:text>
-    <xsl:text>                widget.element.style.display = "none";
-</xsl:text>
-    <xsl:text>
-</xsl:text>
-    <xsl:text>            /* remove subsribers */
-</xsl:text>
-    <xsl:text>            for(let index of widget.indexes){
-</xsl:text>
-    <xsl:text>                subscribers[index].delete(widget);
-</xsl:text>
-    <xsl:text>            }
+    <xsl:text>    for(let widget of new_desc.widgets){
+</xsl:text>
+    <xsl:text>        /* add widget's subsribers */
+</xsl:text>
+    <xsl:text>        for(let index of widget.indexes){
+</xsl:text>
+    <xsl:text>            subscribers[index].add(widget);
+</xsl:text>
+    <xsl:text>            /* dispatch current cache in newly opened page widgets */
+</xsl:text>
+    <xsl:text>            let cached_val = cache[index];
+</xsl:text>
+    <xsl:text>            if(cached_val != undefined)
+</xsl:text>
+    <xsl:text>                dispatch_value_to_widget(widget, index, cached_val, cached_val);
 </xsl:text>
     <xsl:text>        }
 </xsl:text>
-    <xsl:text>        old_desc.widget.element.style.display = "none";
-</xsl:text>
     <xsl:text>    }
 </xsl:text>
     <xsl:text>
 </xsl:text>
-    <xsl:text>    for(let widget of new_desc.widgets){
-</xsl:text>
-    <xsl:text>
-</xsl:text>
-    <xsl:text>        /* unhide widget */
-</xsl:text>
-    <xsl:text>        if(widget.element != undefined)
-</xsl:text>
-    <xsl:text>            widget.element.style.display = "inline";
-</xsl:text>
-    <xsl:text>
-</xsl:text>
-    <xsl:text>        /* add widget's subsribers */
-</xsl:text>
-    <xsl:text>        for(let index of widget.indexes){
-</xsl:text>
-    <xsl:text>            subscribers[index].add(widget);
-</xsl:text>
-    <xsl:text>            /* dispatch current cache in newly opened page widgets */
-</xsl:text>
-    <xsl:text>            let cached_val = cache[index];
-</xsl:text>
-    <xsl:text>            if(cached_val != undefined)
-</xsl:text>
-    <xsl:text>                dispatch_value_to_widget(widget, index, cached_val, cached_val);
-</xsl:text>
-    <xsl:text>        }
-</xsl:text>
-    <xsl:text>    }
-</xsl:text>
-    <xsl:text>
-</xsl:text>
-    <xsl:text>    new_desc.widget.element.style.display = "inline";
-</xsl:text>
-    <xsl:text>
-</xsl:text>
     <xsl:text>    svg_root.setAttribute('viewBox',new_desc.bbox.join(" "));
 </xsl:text>
     <xsl:text>    current_page = page_name;
--- a/svghmi/gen_index_xhtml.ysl2	Mon Mar 02 16:25:35 2020 +0100
+++ b/svghmi/gen_index_xhtml.ysl2	Mon Mar 02 16:30:29 2020 +0100
@@ -523,7 +523,7 @@
 
         | var detachable_elements = {
         foreach "$detachable_elements"{
-        |     "«@id»" : {element: id("«@id»"), parent:id("«../@id»")}`if "position()!=last()" > ,`
+        |     "«@id»":[id("«@id»"), id("«../@id»")]`if "position()!=last()" > ,`
         }
         | }
 
--- a/svghmi/svghmi.js	Mon Mar 02 16:25:35 2020 +0100
+++ b/svghmi/svghmi.js	Mon Mar 02 16:30:29 2020 +0100
@@ -218,16 +218,10 @@
 var current_page;
 
 function prepare_svg() {
-    /* set everybody hidden initially for better performance */
-    for(let widget in hmi_widgets){
-        if(widget.element != undefined)
-            widget.element.style.display = "none";
-    }
-        /*for(let name in page_desc){
-            if(name != new_desc){
-                page_desc[name].widget.element.style.display = "none";
-            }
-        }*/
+    for(let eltid in detachable_elements){
+        let [element,parent] = detachable_elements[eltid];
+        parent.removeChild(element);
+    }
 };
 
 function switch_page(page_name) {
@@ -241,25 +235,31 @@
 
     if(old_desc){
         for(let widget of old_desc.widgets){
-
-            /* hide widget */
-            if(widget.element != undefined)
-                widget.element.style.display = "none";
-
             /* remove subsribers */
             for(let index of widget.indexes){
                 subscribers[index].delete(widget);
             }
         }
-        old_desc.widget.element.style.display = "none";
+        for(let eltid in old_desc.required_detachables){
+            if(!(eltid in new_desc.required_detachables)){
+                let [element, parent] = old_desc.required_detachables[eltid];
+                parent.removeChild(element);
+            }
+        }
+        for(let eltid in new_desc.required_detachables){
+            if(!(eltid in old_desc.required_detachables)){
+                let [element, parent] = new_desc.required_detachables[eltid];
+                parent.appendChild(element);
+            }
+        }
+    }else{
+        for(let eltid in new_desc.required_detachables){
+            let [element, parent] = new_desc.required_detachables[eltid];
+            parent.appendChild(element);
+        }
     }
 
     for(let widget of new_desc.widgets){
-
-        /* unhide widget */
-        if(widget.element != undefined)
-            widget.element.style.display = "inline";
-
         /* add widget's subsribers */
         for(let index of widget.indexes){
             subscribers[index].add(widget);
@@ -270,8 +270,6 @@
         }
     }
 
-    new_desc.widget.element.style.display = "inline";
-
     svg_root.setAttribute('viewBox',new_desc.bbox.join(" "));
     current_page = page_name;