Referenced Parameter Variables in SVG

Often, users may wish to create a single resource, and reuse it several times with specified variations. This is is currently possible by the use of script access to URL parameters or the <param> element in the HTML <object> element.

Passing Values to SVG Files

Passing Values via object param

Using the <object> element, you can pass parameters by the use of child <param> elements. Each <param> element should have name/value pairs with the 'name' and 'value' attributes; these will be exposed to the embedded SVG document via script.

HTML:

  <object type="image/svg+xml" data="button.svg">
    <param name="param1" value="value1" />
    <param name="param2" value="value2" />
  </object>

SVG Javascript:

  // get param elements from referencing object element 
  var params = document.defaultView.frameElement.getElementsByTagName("param");
  // get attribute values of param @name and @value
  ...
  // find elements that need to be changed, then set values to to param @value
  ...

Passing Values via URL Parameters

With the <object>, <iframe>, and <embed> elements, you can pass parameters via the URL. The URL query syntax allows you to pass sets of name/value pairs separated by an ampersand (&); as with object params, these will be exposed to the embedded SVG document via script.

HTML:

  <object type="image/svg+xml" data="button.svg?param1=value1&param2=value2">
  </object>

SVG Javascript:

  // get param elements from referencing object element 
  var params = document.defaultView.location.href.split("?")[1].split("&");
  // split name/value pairs
  ...
  // find elements that need to be changed, then set values to to parameter value
  ...

Use Cases and Requirements

The script-based approach is useful, but has several drawbacks:

To overcome these issues, this document examines some of the requirements and use cases involved in this issue, and proposes a solution for a declarative extension to SVG to fulfill these requirements. (Note: This issue is orthogonal to the CSS Variables proposal.)

For the sake of simplicity in this document, referenced parameter variables will be called variables in the general case, or <ref> elements in the specific case of a proposed solution.

Requirements

  1. variables must be allowed as text content or attribute values for any attribute (and possibly properties, if the CSS WG agrees)
  2. variables must be able to get their values from URL parameters, or from mechanisms such as the <param> element in the HTML <object> element
  3. must be smooth, consistent, and clear inheritance when used through other mechanisms, such as stylesheets
  4. it must be possible for an author to specify a default value for a variable
  5. variable references with no matching parameter and no specified default value will be treated as if they have the default or lacuna value
  6. must share common functionality and syntax for both declarative and scripted solutions
  7. must not require, but may permit, the use of script
  8. may have an API (including a way to get elements with an idref to the target id, getElementsByIdRef? can you do this with SelectorsAPI?)
  9. existing parameter keywords, such as those defined in WICD, must not be overridable (requires a registry?)

Use Cases

Edge Cases and Tests

Proposal

The proposed solution is to specify a new SVG element, the <ref> element. This element would have a 'param' attribute which matches the parameter name, a 'default' attribute which provides a default value, and which is referenced by its 'id' attribute like any paint server. This differs from a paint server in that it can also be used to provide text content for a <tref> element.

Proposed Syntax

My current proposal is to add a new element, the <ref> element. This would have three main attributes, 'param' (for matching incoming parameters from either the <param> element or URL query string), 'default' (an optional value for setting a default value if there is no parameter provided), and 'id' (for referencing with an IDREF attribute like 'xlink:href' or the 'url(#foo)' syntax). Additionally, the element could have child element content, which acts as a default value if there is no 'default' attribute. This element would act much as the various paint servers in SVG (<linearGradient>, <radialGradient>, <solidColor>, etc.), in that it can be referenced to provide a value to an element's attribute. It would also serve as the target for a <tref> reference, for text values.

The various values in the code examples are color-coded as follows:

HTML:

  <object type="image/svg+xml" data="button.svg">
    <param name="color" value="red" />
    <param name="text-label" value="stop" />
  </object>

SVG:

  <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
       viewBox="0 0 110 40" width="100%" height="100%">

    <title>Reusable Button</title>
    <desc>Takes parameters from parent document's embedding element.</desc>

    <defs>
      <ref id="paramFill" param="color" default="blue"/>
      <ref id="paramText" param="text-label">button</ref>
      <ref id="paramStroke" param="outline" default="navy"/>
    </defs>

    <g>
      <rect id="button_rect" x="5" y="5" width="100" height="30" rx="15" ry="15" 
        fill="url(#paramFill)" stroke="url(#paramStroke)" />
      <text id="button_label" x="55" y="30" text-anchor="middle" 
        font-size="25" fill="black" font-family="Verdana">
        <tref xlink:href="#paramText" />
      </text>
    </g>

  </svg>

Examples

These examples show how this proposal would work in practice, by use of a prototyping script, ref.js. Obviously, this wouldn't be needed in a working native implementation.

Note that the text parameter aspects of these examples don't quite work in Firefox, since it doesn't support the <tref> element yet (14-04-2009). They could be made to work with only a little extra script, by directly inserting the text strings into the relevant text element, but the whole point is that it makes use of SVG's IDREF architecture. All other aspects should work in Opera, Firefox, and Safari, and maybe others (Chrome? Plugins?).

No Parameters

  <object type="image/svg+xml" data="button.svg">
  </object>

Object Parameters

  <object type="image/svg+xml" data="button.svg">
    <param name="color" value="red" />
    <param name="text-label" value="stop" />
  </object>

URL Parameters

  <object type="image/svg+xml" data="button.svg?color=cornflowerblue&text-label=fnord">
  </object>

URL and Object Parameters

  <object type="image/svg+xml" data="button.svg?color=cornflowerblue&text-label=fnord">
    <param name="color" value="purple" />
    <param name="text-label" value="override" />
  </object>

Parameterizing Position

  <object type="image/svg+xml" data="map.svg">
    <param name="x" value="125" />
    <param name="y" value="108" />
  </object>
  <object type="image/svg+xml" data="map.svg?y=103&x=523">
  </object>
  <ref id="paramX" param="x" default="-10"/>
  <ref id="paramY" param="y" default="-10"/>

  <circle id="coord" cx="url(#paramX)" cy="url(#paramY)" r="5" fill="tan" stroke="brown" stroke-width="3" />

Parameterizing Links

  <object type="image/svg+xml" data="ad.svg">
    <param name="buylink" value="http://example.com/shop" />
  </object>
  <object type="image/svg+xml" data="ad.svg?buylink=http%3A%2F%2Fexample.com%2Fbargains">
  </object>
  <ref id="targetURL" param="buylink" default="/"/>

  <a xlink:href="url(#targetURL)" target="_new">...</>

Fallback Values

Open Questions

Comments and questions may be sent to schepers@w3.org. Some open questions and details are: