# HG changeset patch # User Edouard Tisserant # Date 1582805664 -3600 # Node ID 94696b3f69fb6554df7946279babf36fff9d7441 # Parent 2f73f001955a248e6f1a7c5fb33b35f9f164e904 SVGHMI : still trying to optimize. Added xslt code to identitfy minimum set of elements needed by a particular page. Plan is to remove unseen/unused elements from the DOM, and re-appending them later when used, on page switch. Disabled previous optimization. diff -r 2f73f001955a -r 94696b3f69fb svghmi/gen_index_xhtml.xslt --- a/svghmi/gen_index_xhtml.xslt Fri Feb 21 16:22:44 2020 +0100 +++ b/svghmi/gen_index_xhtml.xslt Thu Feb 27 13:14:24 2020 +0100 @@ -126,40 +126,6 @@ <xsl:text>All units must be set to "px" in Inkscape's document properties</xsl:text> </xsl:message> </xsl:template> - <xsl:template xmlns="http://www.w3.org/2000/svg" mode="inline_svg" match="svg:use"> - <g> - <xsl:attribute name="style"> - <xsl:value-of select="@style"/> - </xsl:attribute> - <xsl:attribute name="transform"> - <xsl:value-of select="@transform"/> - </xsl:attribute> - <xsl:attribute name="id"> - <xsl:value-of select="@id"/> - </xsl:attribute> - <xsl:variable name="targetid" select="substring-after(@xlink:href,'#')"/> - <xsl:apply-templates mode="unlink_clone" select="//svg:*[@id = $targetid]"/> - </g> - </xsl:template> - <xsl:template xmlns="http://www.w3.org/2000/svg" mode="unlink_clone" match="@*"> - <xsl:copy/> - </xsl:template> - <xsl:template xmlns="http://www.w3.org/2000/svg" mode="unlink_clone" match="svg:*"> - <xsl:choose> - <xsl:when test="@id = $hmi_elements/@id"> - <use> - <xsl:attribute name="xlink:href"> - <xsl:value-of select="concat('#',@id)"/> - </xsl:attribute> - </use> - </xsl:when> - <xsl:otherwise> - <xsl:copy> - <xsl:apply-templates mode="unlink_clone" select="@* | node()"/> - </xsl:copy> - </xsl:otherwise> - </xsl:choose> - </xsl:template> <xsl:template match="/"> <xsl:comment> <xsl:text>Made with SVGHMI. https://beremiz.org</xsl:text> @@ -238,17 +204,35 @@ <xsl:param name="elems"/> <xsl:variable name="descend" select="$elems/descendant-or-self::svg:*"/> <xsl:variable name="clones" select="$descend[self::svg:use]"/> - <xsl:variable name="reals" select="$descend[not(self::svg:use)]"/> <xsl:variable name="originals" select="//svg:*[concat('#',@id) = $clones/@xlink:href]"/> <xsl:choose> <xsl:when test="$originals"> - <func:result select="$reals | func:refered_elements($originals)"/> + <func:result select="$descend | func:refered_elements($originals)"/> </xsl:when> <xsl:otherwise> - <func:result select="$reals"/> + <func:result select="$descend"/> </xsl:otherwise> </xsl:choose> </func:function> + <func:function name="func:included_geometry"> + <xsl:param name="elt"/> + <xsl:variable name="g" select="$geometry[@Id = $elt/@id]"/> + <func:result select="$geometry[@Id != $elt/@id and @x >= $g/@x and @y >= $g/@y and @x+@w <= $g/@x+$g/@w and @y+@h <= $g/@y+$g/@h]"/> + </func:function> + <func:function name="func:sumarized_elements"> + <xsl:param name="elements"/> + <xsl:variable name="short_list" select="$elements[not(ancestor::*/@id = $elements/@id)]"/> + <xsl:variable name="filled_groups" select="$short_list/parent::svg:*[not(descendant::*[not(self::svg:g)][not(@id = $short_list/descendant-or-self::*[not(self::svg:g)]/@id)])]"/> + <xsl:variable name="groups_to_add" select="$filled_groups[not(ancestor::*/@id = $filled_groups/@id)]"/> + <func:result select="$groups_to_add | $short_list[not(ancestor::svg:g/@id = $filled_groups/@id)]"/> + </func:function> + <func:function name="func:all_related_elements"> + <xsl:param name="page"/> + <xsl:variable name="page_included_geometry" select="func:included_geometry($page)"/> + <xsl:variable name="page_sub_elements" select="func:refered_elements($page)"/> + <xsl:variable name="page_included_elements" select="//svg:*[@id = $page_included_geometry/@Id]"/> + <func:result select="$page_sub_elements | $page_included_elements"/> + </func:function> <xsl:template name="scripts"> <xsl:text>//(function(){ </xsl:text> @@ -359,10 +343,10 @@ <xsl:for-each select="$hmi_pages"> <xsl:variable name="desc" select="func:parselabel(@inkscape:label)/widget"/> <xsl:variable name="page" select="."/> - <xsl:variable name="p" select="$hmi_geometry[@Id = $page/@id]"/> - <xsl:variable name="page_ids" select="$hmi_geometry[@Id != $page/@id and @x >= $p/@x and @y >= $p/@y and @x+@w <= $p/@x+$p/@w and @y+@h <= $p/@y+$p/@h]/@Id"/> - <xsl:variable name="page_sub_ids" select="func:refered_elements($page)[@id = $hmi_elements/@id]/@id"/> - <xsl:variable name="all_page_ids" select="$page_ids | $page_sub_ids[not(. = $page_ids)]"/> + <xsl:variable name="p" select="$geometry[@Id = $page/@id]"/> + <xsl:variable name="page_all_elements" select="func:all_related_elements($page)"/> + <xsl:variable name="all_page_ids" select="$page_all_elements[@id = $hmi_elements/@id and @id != $page/@id]/@id"/> + <xsl:variable name="shorter_list" select="func:sumarized_elements($page_all_elements)"/> <xsl:text> "</xsl:text> <xsl:value-of select="$desc/arg[1]/@value"/> <xsl:text>": { @@ -395,6 +379,16 @@ </xsl:for-each> <xsl:text> ] </xsl:text> + <xsl:text> required_elements: [ +</xsl:text> + <xsl:for-each select="$shorter_list"> + <xsl:text> "</xsl:text> + <xsl:value-of select="@id"/> + <xsl:text>", +</xsl:text> + </xsl:for-each> + <xsl:text> ] +</xsl:text> <xsl:text> }</xsl:text> <xsl:if test="position()!=last()"> <xsl:text>,</xsl:text> @@ -852,6 +846,32 @@ </xsl:text> <xsl:text> </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> + <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> + <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]; @@ -862,18 +882,30 @@ </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> /* remove subsribers of previous page if any */ -</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); @@ -884,17 +916,35 @@ </xsl:text> <xsl:text> old_desc.widget.element.style.display = "none"; </xsl:text> - <xsl:text> } else { -</xsl:text> - <xsl:text> /* initial page switch : set everybody hidden */ -</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> +</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> @@ -902,28 +952,6 @@ </xsl:text> <xsl:text> </xsl:text> - <xsl:text> /* add new subsribers if any */ -</xsl:text> - <xsl:text> for(let widget of new_desc.widgets){ -</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> @@ -952,6 +980,8 @@ </xsl:text> <xsl:text> // show main page </xsl:text> + <xsl:text> prepare_svg(); +</xsl:text> <xsl:text> switch_page(default_page); </xsl:text> <xsl:text>}; diff -r 2f73f001955a -r 94696b3f69fb svghmi/gen_index_xhtml.ysl2 --- a/svghmi/gen_index_xhtml.ysl2 Fri Feb 21 16:22:44 2020 +0100 +++ b/svghmi/gen_index_xhtml.ysl2 Thu Feb 27 13:14:24 2020 +0100 @@ -72,6 +72,10 @@ const "_indexed_hmitree" apply "$hmitree", mode="index"; const "indexed_hmitree", "exsl:node-set($_indexed_hmitree)"; + + // TODO globally discardable elements, not (used by | ancestor of) any page + + template "*", mode="index" { param "index", "0"; param "parentpath", "''"; @@ -113,6 +117,7 @@ template "@* | node()", mode="inline_svg" { /* use real xsl:copy instead copy-of alias from yslt.yml2 */ xsl:copy apply "@* | node()", mode="inline_svg"; + /* TODO filter out globally discardable elements */ } /* replaces inkscape's height and width hints. forces fit */ @@ -133,32 +138,35 @@ error > All units must be set to "px" in Inkscape's document properties } - /* clone unlinkink until widget for better perf with webkit */ - svgtmpl "svg:use", mode="inline_svg" - { - g{ - attrib "style" > «@style» - attrib "transform" > «@transform» - /* keep same id and label in case it is a widget */ - //attrib "inkscape:label","@inkscape:label"; - attrib "id" > «@id» - const "targetid","substring-after(@xlink:href,'#')"; - apply "//svg:*[@id = $targetid]", mode="unlink_clone"; - } - } - svgtmpl "@*", mode="unlink_clone" xsl:copy; - svgtmpl "svg:*", mode="unlink_clone" { - choose { - when "@id = $hmi_elements/@id" { - use{ - attrib "xlink:href" > «concat('#',@id)» - } - } - otherwise { - xsl:copy apply "@* | node()", mode="unlink_clone"; - } - } - } + + //// Commented out before implementing runtime DOM remove/append on page switch - would have side effect + //// + //// /* clone unlinkink until widget for better perf with webkit */ + //// svgtmpl "svg:use", mode="inline_svg" + //// { + //// g{ + //// attrib "style" > «@style» + //// attrib "transform" > «@transform» + //// /* keep same id and label in case it is a widget */ + //// //attrib "inkscape:label","@inkscape:label"; + //// attrib "id" > «@id» + //// const "targetid","substring-after(@xlink:href,'#')"; + //// apply "//svg:*[@id = $targetid]", mode="unlink_clone"; + //// } + //// } + //// svgtmpl "@*", mode="unlink_clone" xsl:copy; + //// svgtmpl "svg:*", mode="unlink_clone" { + //// choose { + //// when "@id = $hmi_elements/@id" { + //// use{ + //// attrib "xlink:href" > «concat('#',@id)» + //// } + //// } + //// otherwise { + //// xsl:copy apply "@* | node()", mode="unlink_clone"; + //// } + //// } + //// } // template "svg:use/@style", mode="inline_svg"{ // attrib "style" > all:initial; @@ -212,7 +220,7 @@ } */ - func:function name="func:parselabel" { + def "func:parselabel" { param "label"; const "description", "substring-after($label,'HMI:')"; @@ -243,22 +251,49 @@ } } - func:result select="exsl:node-set($ast)" + result "exsl:node-set($ast)"; } // returns all directly or indirectly refered elements - func:function name="func:refered_elements" { + def "func:refered_elements" { param "elems"; const "descend", "$elems/descendant-or-self::svg:*"; const "clones", "$descend[self::svg:use]"; - const "reals", "$descend[not(self::svg:use)]"; const "originals", "//svg:*[concat('#',@id) = $clones/@xlink:href]"; choose { when "$originals" - func:result select="$reals | func:refered_elements($originals)"; + result "$descend | func:refered_elements($originals)"; otherwise - func:result select="$reals"; - } + result "$descend"; + } + } + + // return included geometry a given element + def "func:included_geometry" { + param "elt"; + const "g", "$geometry[@Id = $elt/@id]"; + result """$geometry[@Id != $elt/@id and + @x >= $g/@x and @y >= $g/@y and + @x+@w <= $g/@x+$g/@w and @y+@h <= $g/@y+$g/@h]"""; + + } + + def "func:sumarized_elements" { + param "elements"; + const "short_list", "$elements[not(ancestor::*/@id = $elements/@id)]"; + /* TODO exclude globally discardable elements from group fulfillment check */ + const "filled_groups", "$short_list/parent::svg:*[not(descendant::*[not(self::svg:g)][not(@id = $short_list/descendant-or-self::*[not(self::svg:g)]/@id)])]"; + const "groups_to_add", "$filled_groups[not(ancestor::*/@id = $filled_groups/@id)]"; + result "$groups_to_add | $short_list[not(ancestor::svg:g/@id = $filled_groups/@id)]"; + } + + def "func:all_related_elements" { + param "page"; + const "page_included_geometry", "func:included_geometry($page)"; + const "page_sub_elements", "func:refered_elements($page)"; + + const "page_included_elements", "//svg:*[@id = $page_included_geometry/@Id]"; + result "$page_sub_elements | $page_included_elements"; } function "scripts" @@ -324,17 +359,20 @@ | ] | + | var page_desc = { foreach "$hmi_pages" { const "desc", "func:parselabel(@inkscape:label)/widget"; - const "page", "."; - const "p", "$hmi_geometry[@Id = $page/@id]"; - const "page_ids","""$hmi_geometry[@Id != $page/@id and - @x >= $p/@x and @y >= $p/@y and - @x+@w <= $p/@x+$p/@w and @y+@h <= $p/@y+$p/@h]/@Id"""; - const "page_sub_ids", "func:refered_elements($page)[@id = $hmi_elements/@id]/@id"; - const "all_page_ids","$page_ids | $page_sub_ids[not(. = $page_ids)]"; + const "page", "."; + const "p", "$geometry[@Id = $page/@id]"; + + const "page_all_elements", "func:all_related_elements($page)"; + + const "all_page_ids","$page_all_elements[@id = $hmi_elements/@id and @id != $page/@id]/@id"; + + const "shorter_list", "func:sumarized_elements($page_all_elements)"; + | "«$desc/arg[1]/@value»": { | widget: hmi_widgets["«@id»"], | bbox: [«$p/@x», «$p/@y», «$p/@w», «$p/@h»], @@ -343,6 +381,11 @@ | hmi_widgets["«.»"]`if "position()!=last()" > ,` } | ] + | required_elements: [ + foreach "$shorter_list" { + | "«@id»", + } + | ] | }`if "position()!=last()" > ,` } | } diff -r 2f73f001955a -r 94696b3f69fb svghmi/svghmi.js --- a/svghmi/svghmi.js Fri Feb 21 16:22:44 2020 +0100 +++ b/svghmi/svghmi.js Thu Feb 27 13:14:24 2020 +0100 @@ -217,33 +217,50 @@ 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"; + } + }*/ +}; + function switch_page(page_name) { let old_desc = page_desc[current_page]; let new_desc = page_desc[page_name]; if(new_desc == undefined){ + /* TODO LOG ERROR */ return; } - /* remove subsribers of previous page if any */ 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"; - } else { - /* initial page switch : set everybody hidden */ - for(let name in page_desc){ - if(name != new_desc){ - page_desc[name].widget.element.style.display = "none"; - } - } - } - - /* add new subsribers if any */ + } + 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); /* dispatch current cache in newly opened page widgets */ @@ -267,6 +284,7 @@ init_widgets(); send_reset(); // show main page + prepare_svg(); switch_page(default_page); };