svghmi/inline_svg.ysl2
author Edouard Tisserant <edouard.tisserant@gmail.com>
Sun, 10 May 2020 17:01:09 +0200
branchsvghmi
changeset 2954 b5dccd0d99ac
parent 2941 ef13a4007538
child 2967 fc5fbf087b93
permissions -rw-r--r--
SVGHMI: clean up dead code, update generated xslt.
// 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 "preamble:inline-svg" {
    | let id = document.getElementById.bind(document);
    | var svg_root = id("«$svg/@id»");
}

emit "debug:clone-unlinking" {
    |
    | Unlinked :
    foreach "$to_unlink"{
        | «@id»
    }
}