module Visualise.Dendogram ( Dendogram(Leaf,Branch) ,renderDendogram ) where import Graphics.Rendering.Cairo -- A binary tree with printable labels and leaves data Dendogram = Leaf String | Branch String Dendogram Dendogram deriving (Eq,Ord,Show) restorePos r = do (px,py) <- getCurrentPoint x <- r moveTo px py return x -- Text is drawn above the current point. This drops it down slightly so that the lines go through the center of the text -- Also return the texts width alignedText fontSize text = do (px,_) <- getCurrentPoint relMoveTo 0 (fontSize/4) showText text relMoveTo 0 (-fontSize/4) (px',_) <- getCurrentPoint return (px'-px) -- This is pretty messy. Basically drawDendogram renders the dendo and returns the coordinates of the drawing -- I think it can be done more legibly using translate etc drawDendogram :: Double -> Dendogram -> (Render Double, Double, Double) drawDendogram fontSize (Leaf leaf) = (r,fontSize/2,fontSize/2) where r = alignedText fontSize leaf drawDendogram fontSize (Branch label tbranch fbranch) = (r,(theight1+theight2),(fheight1+fheight2)) where (drawTBranch,theight1,theight2) = drawDendogram fontSize tbranch (drawFBranch,fheight1,fheight2) = drawDendogram fontSize fbranch r = restorePos $ do w <- alignedText fontSize label relLineTo fontSize 0 twidth <- restorePos $ do relCurveTo fontSize 0 0 (-theight2) fontSize (-theight2) drawTBranch fwidth <- restorePos $ do relCurveTo fontSize 0 0 fheight1 fontSize fheight1 drawFBranch return ((max twidth fwidth)+2*fontSize+w) -- Build and draw the tree -- The rendering function returns its size so that windows can resize themselves accordingly renderDendogram :: Double -> Dendogram -> Render (Double,Double) renderDendogram fontSize dendo = do setFontSize fontSize let (r,height1,height2) = drawDendogram fontSize dendo moveTo 0 (height1+fontSize) width <- r stroke return (height1+height2+fontSize,width+fontSize)