// inline_svg.ysl2 // // Produce Inline SVG element of resulting XHTML page. // Since stylesheet output namespace is xhtml, templates that output svg have to be explicitely declared as such in xsl decl svgtmpl(match, xmlns="http://www.w3.org/2000/svg") alias template; in xsl decl svgfunc(name, xmlns="http://www.w3.org/2000/svg") alias template; // Identity template : // - copy every attributes // - copy every sub-elements template "@* | node()", mode="inline_svg" { // use real xsl:copy instead copy-of alias from yslt.yml2 if "not(@id = $discardable_elements/@id)" xsl:copy apply "@* | node()", mode="inline_svg"; } // replaces inkscape's height and width hints. forces fit template "svg:svg/@width", mode="inline_svg"; template "svg:svg/@height", mode="inline_svg"; svgtmpl "svg:svg", mode="inline_svg" svg { attrib "preserveAspectRatio" > none attrib "height" > 100vh attrib "width" > 100vw apply "@* | node()", mode="inline_svg"; } // ensure that coordinate in CSV file generated by inkscape are in default reference frame template "svg:svg[@viewBox!=concat('0 0 ', @width, ' ', @height)]", mode="inline_svg" { error > ViewBox settings other than X=0, Y=0 and Scale=1 are not supported } // ensure that coordinate in CSV file generated by inkscape match svg default unit template "sodipodi:namedview[@units!='px' or @inkscape:document-units!='px']", mode="inline_svg" { error > All units must be set to "px" in Inkscape's document properties } //////////////// Clone Unlinking // svg:use (inkscape's clones) inside a widgets are // replaced by real elements they refer in order to : // - allow finding "needle" element in "meter" widget, // even if "needle" is in a group refered by a svg use. // - if "needle" is visible through a svg:use for // each instance of the widget, then needle would show // the same position in all instances // // For now, clone unlinkink applies to descendants of all widget except HMI:Page // TODO: narrow application of clone unlinking to active elements, // while keeping static decoration cloned const "to_unlink", "$hmi_elements[not(@id = $hmi_pages)]//svg:use"; svgtmpl "svg:use", mode="inline_svg" { choose { when "@id = $to_unlink/@id" call "unlink_clone"; otherwise xsl:copy apply "@* | node()", mode="inline_svg"; } } // to unlink a clone, an group containing a copy of target element is created // that way, style and transforms can be preserved const "_excluded_use_attrs" { name > href name > width name > height name > x name > y } const "excluded_use_attrs","exsl:node-set($_excluded_use_attrs)"; svgfunc "unlink_clone"{ g{ // include non excluded attributes foreach "@*[not(local-name() = $excluded_use_attrs/name)]" attrib "{name()}" > «.» const "targetid","substring-after(@xlink:href,'#')"; apply "//svg:*[@id = $targetid]", mode="unlink_clone"{ with "seed","@id"; } } } // clone unlinking is really similar to deep-copy // all nodes are sytematically copied svgtmpl "@id", mode="unlink_clone" { param "seed"; attrib "id" > «$seed»_«.» } svgtmpl "@*", mode="unlink_clone" xsl:copy; // copying widgets would have unwanted effect // instead widget is refered through a svg:use. svgtmpl "svg:*", mode="unlink_clone" { param "seed"; choose { // node recursive copy ends when finding a widget when "@id = $hmi_elements/@id" { // place a clone instead of copying use{ attrib "xlink:href" > «concat('#',@id)» } } otherwise { xsl:copy apply "@* | node()", mode="unlink_clone" { with "seed","$seed"; } } } } const "result_svg" apply "/", mode="inline_svg"; const "result_svg_ns", "exsl:node-set($result_svg)"; emit "debug:inline-svg" { | Unlinked : foreach "$to_unlink"{ | «@id» } }