Dec 052011
 

Concerto 2 is going to be a technical marvel if I have anything to say about it.  We’re going to be using SVG when possible as alternatives to server-size RMagick work when we need to generate simple graphics.  In theory this will save a few ms of processing time (returning text > processing an image file) and reduce our cache size if enough people support svg images.  We’ll still fall back to PNG / JPEGs for people with outdated browsers, and you probably should too; there’s a lot of folks out there who don’t have SVG support… optimistically this will be the minority.

One of the things that Concerto does it return a small preview of a template when you’re modifying it.  A template is essentially a high-res background image (often 1920×1080) and an accompanying set of transparent boxes (positions) that content get displayed in and the preview is really important to help see where those invisible boxes are.  This turned out to be really easy to implement in <svg> using the <rect> element.  Just like I’d draw div elements on a screen’s dom, I can draw rectangles positioned relative to the svg image to recreate the exact same layout but in a more graphical fashion.  The background image was quickly added in using svg’s image element, setting it’s width and height to 100% and the x and y coords to 0,0.

<image id="background" xlink:href="/media/19" height="100%" width="100%" x="0" y="0" />

I found that this almost scaled the template appropriately.  By default the aspect ratio was constraining it to the image’s aspect ratio, so the width and height of 100 was really width = 100% or height = 100% depending what was smaller.  Quick fix for small stretching issue was to add preserveAspectRatio=”none”.

<image id="background" xlink:href="/media/19" height="100%" width="100%" x="0" y="0"
       preserveAspectRatio="none" />

This was working wonderfully, and with my rectangles overlaying the positions it was a near pixel perfect replica of the code that I had already used to generate the PNG / JPEG images.  The only subtle differences were in the text / font rendering, and I don’t really care too much about that.

One problem left: resizing the svg / resizing the window.

Despite using relative sizes with percentages, the image wasn’t getting resized when the window was resizing like all the other objects were.  This meant that you needed to refresh the page to see the correct box placement over the image if you ever dragged thing, and that’s not a very desirable outcome.  I didn’t have much luck figuring out why this behavior was happening, but it seems like the image object is a special case in SVG-land that isn’t handled the same as drawable graphic elements like text or images.

To work around this I ended up writing some very short emcascript (aka JavaScript) and embedding it in the SVG.  I’ve tested the resulting behavior in Chrome and Safari and will assume it works in Firefox too.  Every time the svg get’s resized the onresize event is triggered, just like in JavaScript’s and we fire a callback to resize the image element… really just reminding it to fill the screen.

 
<svg xmlns="http://www.w3.org/2000/svg"
     xmlns:xlink="http://www.w3.org/1999/xlink" height="100%" width="100%"
     onresize="resize(evt)">
  <script type="text/ecmascript"><![CDATA[
    function resize(evt){
      var background = document.getElementById('background');
      background.setAttribute("width", "100%");
      background.setAttribute("height", "100%");
    }
  ]]></script>
  <g>
    <image id="background" xlink:href="/media/19" height="100%" width="100%" x="0" y="0"
           preserveAspectRatio="none" />
    <g>
      <rect x="2.5%" y="2.6%"
            width="56.7%" height="77.0%" 
            style="fill:grey; stroke:none; fill-opacity:0.6;"
            id="position_25" />
      <text y="45.1%" x="30.85%" 
            style="fill:black; stroke:black;" font-size="300%" text-anchor="middle">
        Graphics
      </text>
    </g>
    <g>
      <rect x="22.1%" y="88.5%"
            width="75.4%" height="10.0%" 
            style="fill:grey; stroke:none; fill-opacity:0.6;"
            id="position_26" />
      <text y="97.5%" x="59.8%" 
            style="fill:black; stroke:black;" font-size="300%" text-anchor="middle">
        Ticker
      </text>
    </g>
  </g>
</svg>

If you’re particularly curious, you can see this code in Concerto 2 here or by appending “.svg” to a template preview link in a Concerto 2 install to force the svg image.

May 042011
 

I’m trying to integrate testing as much as possible into the development of Concerto 2.  We’re building in Ruby on Rails, so testing is built into the framework and language, the trick is just getting the team on board and writing tests (and not breaking them as we develop).  To help facilitate testing, I setup BigTuna to run a continuous integration server, automatically testing each version that gets pushed to our GitHub repository.

Since people could be using Ruby 1.8.7 or 1.9.2, we use RVM on testing environment to run tests in both versions.  If you’re looking to replicate our setup which updates git submodules, refreshes the bundle, migrates the database, and finally runs the tests, this set of steps might work for you.

In our setup, we have a database.yml.sample located in our project directory (in our case /bigtuna/builds/concerto) which gets copied over to each build.

rvm 1.8.7 exec bundle install --path=%project_dir%/bundle --deployment
cp %project_dir%/database.yml.sample %build_dir%/config/database.yml
git submodule init &amp;&amp; git submodule update
rvm 1.8.7 exec env RAILS_ENV=test bundle exec rake db:migrate --trace
rvm 1.8.7 exec env RAILS_ENV=test bundle exec rake

and for our 1.9.2 tests..

rvm 1.9.2 exec bundle install --path=%project_dir%/bundle --deployment
cp %project_dir%/database.yml.sample %build_dir%/config/database.yml
git submodule init &amp;&amp; git submodule update
rvm 1.9.2 exec env RAILS_ENV=test bundle exec rake db:migrate --trace
rvm 1.9.2 exec env RAILS_ENV=test bundle exec rake

Getting the rvm portion of the setup working has been the hardest bit, getting the right ruby environment and bundle of gems to the apps was tough.  The above config was written for rvm 1.2.8 and Bundler 1.0.12, otherwise I don’t believe there are any server-specific configuration parameters at play here.

Best of luck if you’re going the continuous integration route, hopefully you can keep your build green!