Latest Posts

Archives [+]

Categories [+]

Authors [+]

CRX Gems: Rendering content as HTML and SVG

A few days ago, I talked about how to "shred and store" a spreadsheet -- i.e., how to push rows of a spreadsheet into individual nodes in CRX (one node per row, with column data stored as properties). I also gave JavaScript code for doing this in an OpenOffice macro. For testing purposes, I used the CSV file a1-film.csv, representing 1741 movies catalogued by Georgia Tech's College of Computing.

After running my OpenOffice macro on the Georgia Tech CSV file, my CRX repository now contains movie data (Title, Director, Year, etc.) for 1741 films, each film with its own nt:unstructured node under the path /content/films/. In the CRX Content Explorer, a given node (in this case, the node at http://localhost:7402/content/films/terminator_2) looks something like this:

/content/ddc/blog/2010/07/crx_gems_rendering/jcr:content/par/image_0/file

Notice that the spreadsheet's column data now show up as properties (Actor, Actress, Director, etc.) with values like "Schwarzenegger, A.," "Hamilton, Linda," and so forth.

Notice also that I've included a property of sling:resourceType, with a value of "films," for every movie node. This is important, because it tells Sling to look under /apps/films/ for any runtime scripts that may need to be applied in order to render a particular node (such as http://localhost:7402/content/films/terminator_2).

Let's see how this works in practice. Suppose I want to render a movie node as HTML. I could put a file called html.esp under /apps/films/, containing the following markup:

<html>
<head>
<link rel="stylesheet" type="text/css" href="/apps/films/films.css" />
</head>
<body>

<img src="/apps/films/Film.png" width="95" height="92" />
<br/>

<span class="head"> <%= currentNode.Title %> </span><br/>

<span class="normal">Director:&nbsp;&nbsp;&nbsp;</span>
<span class="tdata"><%= currentNode.Director %></span><br/>

<span class="normal">Year:&nbsp;&nbsp;&nbsp;</span>
<span class="tdata"><%= currentNode.Year %></span><br/>

<span class="normal">Genre:&nbsp;&nbsp;&nbsp;</span>
<span class="tdata"><%= currentNode.Subject %></span><br/>

<span class="normal">Actor:&nbsp;&nbsp;&nbsp;</span>
<span class="tdata"><%= currentNode.Actor %></span><br/>

<span class="normal">Actress:&nbsp;&nbsp;&nbsp;</span>
<span class="tdata"><%= currentNode.Actress %></span><br/>

<span class="normal">Runtime:&nbsp;&nbsp;&nbsp;</span>
<span class="tdata"><%= currentNode.Length %> minutes</span><br/>

<span class="normal">Popularity:&nbsp;&nbsp;&nbsp;</span>
<span class="tdata"><%= currentNode.Popularity %></span><br/>

</body>
</html>

As it turns out, I've also got a small PNG graphic, Film.png, located under /apps/films/, as well as a CSS file called (what else?) films.css, which looks like:

.head {
font-family:Tahoma;
font-size:32pt;
fill:#990000;
color:#990000;
}

.normal {
font-family:Tahoma;
font-size:15pt;
fill:#444444;
}

.tdata {
font-family:Verdana;
font-size:15pt;
font-weight: bold;
fill:#992222;
color:#992222;
}

With these files in place, I can now direct my browser to go to http://localhost:7402/content/films/terminator_2.html, and Sling will automatically detect the need to use the html.esp script to render the node as HTML. The resulting rendition looks something like this:

/content/ddc/blog/2010/07/crx_gems_rendering/jcr:content/par/image_1/file























But suppose I want to be able to provide a Scalable Vector Graphics rendition, for browsers (like Firefox) that can render SVG. Not a problem: All I need to do is create a script called svg.esp and place it under /apps/films/. The svg.esp script might look something like this:

<?xml version="1.0" standalone="no"?>
<?xml-stylesheet type="text/css" href="/apps/films/films.css" ?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">

<svg width="100%" height="100%" version="1.1"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink">

<!--  Add a custom filter effect  -->
 <defs>
    <filter id="MyFilter" filterUnits="userSpaceOnUse" x="0" y="0" width="600" height="400">
      <feGaussianBlur in="SourceAlpha" stdDeviation="4" result="blur"/>
      <feOffset in="blur" dx="4" dy="4" result="offsetBlur"/>

      <feSpecularLighting in="blur" surfaceScale="5" specularConstant=".75"
   specularExponent="20" lighting-color="#992222"  
   result="specOut">
        <fePointLight x="-5000" y="-10000" z="20000"/>
      </feSpecularLighting>
      <feComposite in="specOut" in2="SourceAlpha" operator="in" result="specOut"/>
      <feComposite in="SourceGraphic" in2="specOut" operator="arithmetic"
   k1="0" k2="1" k3="1" k4="0" result="litPaint"/>
      <feMerge>
        <feMergeNode in="offsetBlur"/>
        <feMergeNode in="litPaint"/>
      </feMerge>

    </filter>
  </defs>

<image x="20" y="20" width="95" height="92" xlink:href="/apps/films/Film.png"/>

<!-- Apply the filter to Title -->
 <g filter="url(#MyFilter)" >
    <g  transform="matrix(1.15 0 0 1 0 0)"  >
      <text class="head" x="18" y="160" >
      <%= currentNode.Title %></text>      
    </g>
  </g>

<text class="normal" x="20" y="200" >Director</text>
<text class="tdata" x="200" y="200"><%= currentNode.Director %></text>

<text class="normal" x="20" y="230" >Genre</text>
<text x="200" y="230" class="tdata"><%= currentNode.Subject %></text>

<text class="normal" x="20" y="260" >Year</text>
<text x="200" y="260"  class="tdata"><%= currentNode.Year %></text>

<text class="normal" x="20" y="290" >Actor</text>
<text x="200" y="290" class="tdata"><%= currentNode.Actor %></text>

<text class="normal" x="20" y="320" >Actress</text>
<text x="200" y="320" class="tdata"><%= currentNode.Actress %></text>

<text class="normal" x="20" y="350" >Runtime</text>
<text x="200" y="350" class="tdata"><%= currentNode.Length %></text>

<text class="normal" x="20" y="380" >Popularity</text>
<text x="200" y="380" class="tdata"><%= currentNode.Popularity %></text>

</svg>

The big <defs> section near the beginning is an (optional) SVG filter effect, designed to provide a little extra visual appeal to the movie title by giving it a drop-shadow. The result (as rendered by Firefox) looks like this:

/content/ddc/blog/2010/07/crx_gems_rendering/jcr:content/par/image_2/file

























Of course, in a real-world component or application, you would have logic somewhere (whether on the server side or in client-side code) that detects the type of browser the user has and fetches the SVG rendition only if the user's browser is SVG-capable. 


 
(optional)
No comments yet