Sep 09 2008
Laying diagrams over background images
I’ve had a cracking evening so I thought I’d take a few minutes to show you what I’ve been up to. It’s been a mixture of learning and supplementing the Diagrams package as before.
I’ve started a new repository at http://dougalstanton.net/code/diagrams-examples to store the test material I’m using. That way I can make it public without cluttering up the package with unnecessary files and commits.
First, I would like to introduce my brother. He will be helping us this evening, in the manner of Debbie McGee. (He will survive, in one piece. It’s just magic folks…) One of the additions I have made to the package is the ability to save on top of another image. Instead of a plain white background, you can load something from disk and put your diagram onto that.
We’ll see it all in action here, with the help of my brother (as mentioned). Excuse me if the code is a bit sloppy. As mentioned this is my scratch pad for developing features, so it’s quite a crufty place to work!
module Main where import Graphics.Rendering.Diagrams import Control.Arrow ((***)) main = renderOverPNG "alasdair.png" "bubble.png" dia
This loads alasdair.png and saves as bubble.png with the rendered diagram pasted onto it. I’m a wee bit uncomfortable about the fact that it’s not obvious which file is the input and which is the output. But I chose the standard copy/move semantics — source followed by destination.
para sz = vcatA left . map (text sz) underlay a b = a `withSize` b ## b atop a b = vcatA hcenter [(a `withSize` b), b]
These are just some helper functions. para is used to typeset a left-justified paragraph, constructed by taking a list of lines and aligning them one above the other.
The other two are for arranging objects around each other, using a new layout function called withSize. It lets you construct one object using the current dimensions of the other. (This may ring a bell. I have done this before, by other means. But this has proven to be a more flexible approach.)
And this next bit shows the flexibility I mean: simple construction of text in bubbles!
{{lang:haskell}
plainbubble strs = bubble `underlay` writing
where writing = para 12 strs
bubble w h = fc white $ lc white $ roundrect (w*1.2) (h*1.2)
It seems to be an unfortunate fact of the Diagrams package that objects can be positioned in some local co-ordinate system, but not relative to a background. So I cheated here and created an empty object in the top left corner, for all other objects to relate to. Then I can position them by assigning co-ordinates which map neatly to pixels on the background PNG I’m loading…
dia = position [((0,0),nil), ((450,280), alitalk), ((230,300),plea)] where alitalk = bubbletail left top `atop` plainbubble quote plea = bubbletail right top `atop` plainbubble ["help!"] quote = ["Come join me!" ,"" ,"We shall drink mead and tell" ,"tales of our ancestors!"] bubbletail ha va w h = fc white $ lc white $ curved 0 $ pathFromVertices pts where (w',h') = (w/3,h/2) scaleWH = map (\(x,y) -> (x*w',y*h')) pts = scaleWH $ map (if ha==left then id else negate *** if va==top then id else negate) upleft upleft = [(-0.25,0),(-1,-1),(0.25,0)]
After all that, it’s my brother’s turn for the lime light.
