Comparing SVG: Under the Hood
In this example we take a technical look at how changes to XML-encoded W3C Scalable Vector Graphic (SVG) images can be detected, recorded and manipulated using DeltaXML.
Simple Example
For the first example we have created two very simple SVG rectangles. If you have an SVG viewer, as discussed in our notes on requirements, you can view the source files, rectangle-1.svg and rectangle-2.svg. These files have the following XML contents:
<svg width="12cm" height="4cm" viewBox="0 0 1200 400" xmlns="http://www.w3.org/2000/svg" version="1.1"> <desc>Nested rectangles SVG example</desc> <rect x="1" y="1" width="1198" height="398" fill="none" stroke="blue" stroke-width="2"/> <rect x="400" y="100" width="400" height="200" fill="yellow" stroke="navy" stroke-width="10"/> </svg>
and
<svg width="12cm" height="4cm" viewBox="0 0 1200 400" xmlns="http://www.w3.org/2000/svg" version="1.1"> <desc>Nested rectangles SVG example</desc> <rect x="1" y="1" width="1198" height="398" fill="none" stroke="blue" stroke-width="2"/> <rect x="400" y="100" width="400" height="200" fill="orange" stroke="purple" stroke-width="10"/> </svg>
The only difference between the two pairs of nested rectangle is that the colors of the inner one change.
The file rectangles.xml shows the result of comparing the two files with DeltaXML. By applying an output filter to this file we can create an animated SVG that switches between the two representations every 5 seconds.
Crouching Tiger
A more realistic set of SVG images has been used in our Crouching Tiger, Hidden Changes demonstrations. There are three aspects to this demonstration:
- The use of the delta file to show the effects of changes by animating the alterations.
- The use of DeltaXML to merge changes made to different versions, creating a composite image.
- The use of the DeltaXML Sync API to synchronize multiple sets of files to allow changes to be propagated from one image to another.
Finding the Changes
Using DeltaXML, we can compare the two versions of the tiger to find where there are changes. The result is that the following graphical items are identified as having been deleted:
<g deltaxml:delta="delete" style="fill: #99cc32">
<path d="M47 36.514C40.128 36.514 31.755 32.649 31.755
26.4C31.755 20.152 40.128 13.887 47 13.887C53.874 13.887 59.446
18.952 59.446 25.2C59.446 31.449 53.874 36.514 47 36.514z"/>
</g>
<g deltaxml:delta="delete" style="fill: #99cc32">
<path d="M-71.4 3.8C-71.4 3.8 -62.422 5.274 -61.4 8C-60.8
9.6 -60.137 17.908 -65.6 19C-70.152 19.911 -72.382 9.69 -71.4 3.8z"/>
< /g>
<g deltaxml:delta="delete" style="fill: #ffffff; stroke:#000000; stroke-width:0.1">
<path d="M-18.038 119.793C-18.038 119.793 -19.115 121.079 -17.162 120.825C-6.916 119.493
14.489 78.222 58.928 83.301C58.928 83.301 26.962 68.955 -18.038
119.793z"/>
</g>
and
<g deltaxml:delta="delete" style="fill: #cccccc">
<path d="M301.5 191.5L284 179.5C284 179.5 303 196.5 303.5
200.5L301.5 191.5z"/>
</g>
The first two are the green eyes, the third is a whisker and the fourth is one of the small grey marks on the right of the tiger.
Two items have been added:
<g deltaxml:delta="add" style="fill: #ffff00">
<path d="M47 36.514C40.128 36.514 31.755 32.649 31.755
26.4C31.755 20.152 40.128 13.887 47 13.887C53.874 13.887 59.446
18.952 59.446 25.2C59.446 31.449 53.874 36.514 47 36.514z"/>
</g>
and
<g deltaxml:delta="add" style="fill: #ffff00">
<path d="M-71.4 3.8C-71.4 3.8 -62.422 5.274 -61.4 8C-60.8
9.6 -60.137 17.908 -65.6 19C-70.152 19.911 -72.382 9.69 -71.4 3.8z"/>
</g>
These represent the yellow eyes.
Animating the Changes
Once we have found the changes, we can proceed to animate them. The DeltaXML delta file is in XML, so all we need to do is to process this XML file using XSLT. In this case, we decide that in order to show the changes we will add animation to a deleted element so that it appears and disappears, thus drawing our attention to it. This is achieved by adding an <animate> element to the <g> element whenwe find a deltaxml:delta="delete" attribute.
Thus we transform:
<g deltaxml:delta="delete" style="fill: #ffffff; stroke:#000000; stroke-width:0.1">
<path d="M-18.038
119.793C-18.038 119.793 -19.115 121.079 -17.162 120.825C-6.916 119.493
14.489 78.222 58.928 83.301C58.928 83.301 26.962 68.955 -18.038
119.793z"/>
</g>
into:
<g deltaxml:delta="delete" style="fill: #ffffff;
stroke:#000000; stroke-width:0.1">
<path d="M-18.038
119.793C-18.038 119.793 -19.115 121.079 -17.162 120.825C-6.916 119.493
14.489 78.222 58.928 83.301C58.928 83.301 26.962 68.955 -18.038
119.793z"/>
<animate attributeType="CSS" attributeName="opacity" from="1" to="0"
dur="1s" repeatCount="indefinite" />
</g>
the following XSLT template will achieve this:
<!-- Add animation to deleted <g> elements -->
<xsl:template match="g[@deltaxml:delta='delete']">
<xsl:copy>
<xsl:apply-templates select="@*"/>
<xsl:apply-templates/>
<animate attributeType="CSS" attributeName="opacity"
from="1" to="0" dur="1s" repeatCount="indefinite" />
</xsl:copy>
</xsl:template>
In a similar way, we can animate the additions using the following template:
<xsl:template match="g[@deltaxml:delta='add']">
<xsl:copy>
<xsl:apply-templates select="@*"/>
<xsl:apply-templates/>
<animate attributeType="CSS" attributeName="opacity"
from="0" to="1" dur="1s" repeatCount="indefinite" />
</xsl:copy>
</xsl:template>
This causes the added and deleted elements to fade in and out so the changes are apparent.
The DeltaXML full context delta provides both the changed and unchanged elements in a single XML file. By processing this delta file as illustrated above, we can convert it back into a pure SVG file, adding animation to show the changes. In this simple example we show only how to animate deletion and addition of <g> elements, but clearly this could be extended.