8.4.6 Extensions to SVG elements

While mapping from MetaEdit+ symbol elements to SVG elements is quite straightforward in general, a few exentensions are needed for MetaEdit+ specific details. These extensions appear as part of the usual SVG structures but are defined in the http://www.metacase.com/symbol namespace. An alias for the namespace may be declared as part of the overall GXL definition:
<gxl xmlns:sym="http://www.metacase.com/symbol">
This namespace prefix is then used when referring to extended attributes within an SVG tag:
<ellipse sym:startAngle="0.0e0" sym:sweepAngle="3.15e2">
For element level extensions, the default namespace must be changed with an attribute:
<metaInfo xmlns="http://www.metacase.com/symbol">
...
</metaInfo>

Common extensions

All SVG elements that represent MetaEdit+ symbol elements need to be extended with a metaInfo element. This element encapsulates all situational information needed when displaying the element. For the basic graphical elements, the metaInfo contains only the display condition (as illustrated below with an example of rectangle element):
<rect fill="rgb(255,255,255)" height="20" rx="0" ry="0"
    stroke="rgb(0,0,0)" stroke-width="1" width="30"
    x="90" y="70">
  <metaInfo xmlns="http://www.metacase.com/symbol">
    <displayCondition>...</displayCondition>
  </metaInfo>
</rect>
The displayCondition element is in the symbol namespace because of the xlmns attribute in its surrounding metaInfo element, and it defines three data entries:
A condition source based either on a property value or generator output. The source is defined as a piece of text within the displayCondition element (see the example below).
A conditionOperator to match the string value returned by the source. The possible condition operators are:
 
conditionOperator
Operation
=
Equal (exact matching)
=~
Equal (wildcard matching)
~=
Not equal (< >)
<
Smaller
>
Greater
<=
Small or equal
>=
Greater or equal
regexMatch:
Regex match true (=)
regexNonMatch:
Regex match false (< >)
 
A matchString to match the source string with.
Putting these together as a complete display condition definition results in an element like this:
<displayCondition conditionOperator="=" matchString="Red"
  xmlns="http://www.w3.org/2000/svg">
    PropertyTextSource:a1oyx6
</displayCondition>
In this example, the condition is based on the value of a property with slot id ‘a1oyx6’. If this value equals ‘Red’, the display condition evaluates to true, allowing the display of the associated graphical element. If the condition is false, the element is not shown.

The condition may also take its input from a generator. In that case the pattern is as follows:
<displayCondition conditionOperator="=~" 
  matchString="xxx*" xmlns="http://www.w3.org/2000/svg">
    ReportTextSource:
      foreach .() { 'x' }
</displayCondition>
Here we have a generator that outputs an x for each object in the current graph. The conditionOperator and matchString then define that this value will be tested to see if there are at least three x’s, and hence at least three objects. If this is true, the graphical element will be displayed, otherwise not.

For role symbol elements, the metaInfo also contains an extra attribute:
shouldRotate sets whether or not the element shape should rotate to match the roleline’s angle (accepted values “true” or “false”). See “Rotation” in Section 3.4.

Template

While most graphical elements found in MetaEdit+ symbols have their direct counterpart or something quite similar in SVG, the template elements are an exception. Due to their distinctive nature, we cannot adapt any existing SVG element type to substitute for them but have to present them as an element type of their own.

A template is a complex element that is made of the following obligatory sub-parts:
Layout defines the polyline(s) along which the subobjects are distributed.
Subobject source sets where the subobjects are retrieved from.
Subsymbol source sets where the symbol representation for each subobject comes from.
Layout is defined with a pair of pathLayout and layoutPath elements that share a set of similar kinds of attributes:
points is a collection of points that defines the base polyline for the template.
allocation sets the direction subobjects are allocated in and from where on the path to Allocate from (possible values are “start”, “middle” or “end”).
startDistance defines the distance Before first subobject, from the allocation starting point along the layout path
layoutDistance sets the Interval between subobjects along the layout path
lineSegmentTable defines the active and inactive polyline segments. If there is only one element in the points collection, the value of lineSegmentTable must be empty (as there are no line segments, just one point). Each point pair in the points collection defines a line segment and the respective true/false value in lineSegmentTable sets if this segment is active or not (i.e. if our points collection is "0,0 50,50 100,100, 150,150" and lineSegmentTable is "true,false,true", it means that the first segment (0,0 to 50,50) is active, the second segment (50,50 to 100,100) is inactive and the final segment (100,100 to 150,150) is again active).
So why do we need two similar-looking nested elements to define a path? The catch here is the possibility to clone the layout path. Consided the following layout that has Use clone path turned on:

Figure 8–2. Cloned layout path.

The blue lines define the layout path which we will see the objects distributed along. Even if we see multiple blue lines, they all are derived as offset duplicates of the same canonical layoutPath element that looks like this:
<layoutPath points="0,0 100,0" allocation="start"
  startDistance="10" layoutDistance="30"
  lineSegmentTable="true"></layoutPath>
The point collection defining the underlying polyline for the path assumes 0,0 as its starting point. When we are cloning the layout paths, each new clone will translate this point along the cloning path defined by the green line shown in Figure 8–2. This translation follows the similar kinds of rules as those that define the distribution of the actual subobjects. So, the blue layout path’s layoutPath element is embedded inside the pathLayout element that defines the green cloning path:
<pathLayout points="70,50 70,150" allocation="start"
    startDistance="0" layoutDistance="30"
    lineSegmentTable="true">
  <layoutPath points="0,0 100,0" allocation="start"
    startDistance="10" layoutDistance="30"
    lineSegmentTable="true"></layoutPath>
</pathLayout>
This structure is used even if we have a non-cloning layout: in that case, the cloning path just consists of one point, resulting in only one instance of the layout path. With cloning turned off, the example above would results in the following pathLayout and layoutPath pair:
<pathLayout points="70,50" allocation="start"
    startDistance="0" layoutDistance="0"
    lineSegmentTable="">
  <layoutPath points="0,0 100,0" allocation="start"
    startDistance="10" layoutDistance="30"
    lineSegmentTable="true"></layoutPath>
</pathLayout>
Having the layout characteristics sorted out, we will now see how to define the source where the actual subobjects are fetched from. As explained in section 3.2.9, there are five possible source element types:
noneNPSource: Returns the hosting object itself. As this source type does not need any definition attributes, it is basically represented by an empty tag pair:
<noneNPSource></noneNPSource>
 
propertyNPSource: Returns the object attached to a single property. This source type requires the slot id of the hosting property and it is represented by an attribute called source:
<propertyNPSource source="a34po"></propertyNPSource>
 
collectionPropertyNPSource: Returns a collection of objects from a collection property. Similar to propertyNPSource, this element type also has an attribute source whose value is the collection property’s slot id:
<collectionPropertyNPSource source="a378r">
</collectionPropertyNPSource>
 
subgraphNPSource: Returns objects of a specific type from the hosting object’s subgraph of the specified type. Two attributes are required – source that defines the subgraph type and nonProperty that defines the type of the objects to fetch (both use the longer internal type names):
<subgraphNPSource
  source="Graph_MyGraph_sysadmin_3572690290"
  nonProperty="Object_MyObject_sysadmin_3572690265">
</subgraphNPSource>
 
generatorNPSource: Returns the set of objects retrieved by a generator. This element type does not have any attributes but has the generator definition as the element content:
<generatorNPSource>
  do decompositions { foreach .() { id }}
</generatorNPSource>
In addition to layout and subsymbol source, a template also needs a definition of the subsymbol source. There are two possible element types for representing subsymbol sources:
npSubsymbolSource for using the subobject’s own symbol. This does not require any element content or attributes, and hence is defined as an empty tag pair:
<npSubsymbolSource></npSubsymbolSource>
 
librarySubsymbolSource for using a symbol fetched from the symbol library. The content of this element specifies how to get the name of the symbol to be retrieved. There are three different ways to get the name. The first option is simply to give the name:
<librarySubsymbolSource>MyLibrarySymbol</librarySubsymbolSource>
 The second option is to use a property value as the name. In this case we need to start the content text with a keyword PropertyTextSource: and follow it with the slot id of the property carrying the name:
<librarySubsymbolSource>PropertyTextSource:a06awh</librarySubsymbolSource>
 The third option is to create the name with a generator. This requires us to use ReportTextSource: keyword at the beginning of the content text and then provide the generator definition:
<librarySubsymbolSource>
  ReportTextSource:id
</librarySubsymbolSource>
To complete the template definition we still need to augment it with a few attribute definitions:
revealConnectables specifies whether or not the connectables are revealed as ports (accepted value “true” or “false”), i.e. Use subobjects as ports.
subsymbolExtentX is the horizontal dimension of the subsymbol slot (the blue boxes with dashed outlines in Figure 8–2), i.e. Max. width.
subsymbolExtentY is the vertical dimension of the subsymbol slot, i.e. Max. height.
scaleFilter sets how we allow the template to scale, and is made up of the Allow X scaling and Allow Y scaling settings, with 1 for true and 0 for false. “1,1” thus means that the subsymbol slot scales with the host symbol both horizontally and vertically, whereas “1,0” scales the slot only horizontally and “0,0” stops the slot scaling at all.
useTargetpoint specifies Targetpoint alignment: whether to align the subsymbol so that its default connectable’s target point will be in that point around which the subsymbol slot is aligned (“true”), or allow MetaEdit+ to align the subsymbol in the slot according to the alignmentPoint (“false”).
alignmentPointX specifies the Before point setting: the fraction of the subsymbol slot that is before its allocated point. It is ignored if useTargetpoint is false.
alignmentPointY specifies the Left of path setting: the fraction of the subsymbol slot that is to the left of its allocated point, when moving in the direction of its arrowhead. It is ignored if useTargetpoint is false.
isMovable defines whether or not it is allowed to move subobjects when they appear as ports (accepted value “true” or “false”), i.e. Allow moving of ports.
rotation is an internal value that must always be “false”.
width is the Weight of the template, which is interpreted as the width of the outline of the subsymbol slot, avoiding clipping for wide lines along the slot edge in subsymbols.
Putting these attributes and the layout and subobject/subsymbol elements together will now bring us the complete template element, as shown in an example below:
<template revealConnectables="true" subsymbolExtentX="20"
  subsymbolExtentY="20" scaleFilter="0,0"
  useTargetpoint="false" aligmentPointX="0.5"
  aligmentPointY="0.5" isMovable="false" rotation="false"
  width="1" xmlns="http://www.metacase.com/symbol">
  <pathLayout points="70,50 70,150" allocation="start"
    startDistance="0" layoutDistance="30"
    lineSegmentTable="true">
    <layoutPath points="0,0 100,0" allocation="start"
      startDistance="10" layoutDistance="30"
      lineSegmentTable="true"></layoutPath>
  </pathLayout>
  <collectionPropertyNPSource source="a378r">
  </collectionPropertyNPSource>
  <npSubsymbolSource></npSubsymbolSource>
</template>

Path

There are no corresponding SVG elements for representing MetaEdit+’s Bezier and spline elements. Therefore we need to use SVG’s path element to substitute for these. The catch here is that SVG stores the path data as a sequence of drawing commands while MetaEdit+’s elements are stored as an array of breakpoints. As there is no way for us to reconstruct the breakpoints from the SVG path data, we need an additional attribute controlPoints to store them in the SVG path element:
<path d="..." fill="none" stroke="rgb(0,0,0)"
  sym:controlPoints="40,80 60,50 90,70 120,30 150,70">

Text and textArea

SVG provides two element types for representing text – text and textArea – where as MetaEdit+ has only one. Both kinds of SVG text elements will be imported as the sole MetaEdit+ type, and this translation is done automatically during import. When exporting, MetaEdit+ will use textArea, extending it with a few attributes of its own. Some of those attributes can also be used on text elements when importing.

characterBackgroundFill defines the text background color, for both text and textArea. Please note that this is separate from the fill color of the text box itself.
<text sym:characterBackgroundFill="none">
The text’s content follows the normal SVG text pattern for simple fixed text content, in both both text and textArea:
<text>Some text here</text>
However, in MetaEdit+’s case the text can be derived also from a property or a generator. These can be defined within the text or textArea tag in a similar manner to how property and generator sources are defined as part of displayConditions, as explained in the section above discussing the common extensions. If the text element shows a property value, the definition will look like this:
<text>PropertyTextSource:a1oyx6</text>
This simply states that the text is fetched from a property with slot id ‘a1oyx’.

If the text element shows the output of a generator, the definition will look like this:
<text>ReportTextSource:foreach .() { id }</text>
Here we have a key word ReportTextSource:, followed by the generator definition.

The textArea element requires extra attributes to store the data required by MetaEdit+’s text element. The additional attributes are:
wordWrap that sets the word wrapping on or off (accepted values “true” and “false”)
textboxFill that defines the fill color for the containing text box
textboxStroke that defines the line color for the containing text box
textboxStroke-width that sets the width of the text box perimeter line
textboxStroke-dasharray that defines the dash pattern for dashed text box lines (as a pattern of sequential dash and interval pixel lengths, i.e. “1,1” reads “1px dash followed by 1px interval” and “4,2” reads “4px dash followed by 2px interval”).
A textArea definition with these extension attributes will look like this:
<textArea sym:characterBackgroundFill="none"
    sym:wordWrap="true" sym:textboxFill="none"
    sym:textboxStroke="rgb(255,255,255)"
    sym:textboxStroke-width="1"
    sym:textboxStroke-dasharray="1,1">
  Some text here
</textArea>

Ellipse

Unlike SVG, MetaEdit+’s ellipse elements provide the option for drawing open elliptical arcs, and therefore we need to extend the SVG ellipse element with two additional attributes:
startAngle that defines the start angle of elliptical arc
sweepAngle to deinfe the stop angle of the arc
These attributes will appear as part of the SVG ellipse element itself:
<ellipse cx="100" cy="60" fill="rgb(255,255,255)" rx="20"
  ry="20" stroke="rgb(0,0,0)" stroke-width="1"
  sym:startAngle="0.0e0" sym:sweepAngle="3.15e2">

Image

For an SVG image element, an extra attribute of scale is needed to define the horizontal and vertical scaling factors of the image in the symbol, i.e. how much it has been scaled in the Symbol Editor after Symbol | Import Bitmap:
<image sym:scale="1,2">

Group

For element groups, MetaEdit+ needs to cache the position and dimensions of the group, hence the following extra attributes are needed:
x as the x coordinate of the group
y as the y coordinate of the group
width that defines the horizontal dimension of the group
height that defines the vertical dimension of the group
This is how the attributes appear as part of the group element definition:
<g sym:x="100" sym:y="50" sym:width="60" sym:height="70">
...
</g>

Gradients

The way MetaEdit+ handles the gradient fills requires some extensions in SVG’s gradient fill elements. Both SVG’s linearGradient and radialGradient elements need to be augmented with correctGamma attribute that defines whether or not the gamma correction is active (accepted attribute values “true” or “false”):
<linearGradient sym:correctGamma="true"></linearGradient>
The radialGradient elements also need an extra fillType attribute that tells MetaEdit+ which one of its internal radial gradient implementations to use (the possible values are “RadialFill”, “PathFill” and “SquareFill”; currently, Cairo draws all these as RadialFill):
<radialGradient sym:fillType="RadialFill">
</radialGradient>