{-# LANGUAGE TypeFamilies
, MultiParamTypeClasses
, FlexibleInstances
, FlexibleContexts
, TypeSynonymInstances
, DeriveDataTypeable
#-}{-|
The SVG backend.
-}moduleDiagrams.Backend.SVG(SVG(..)-- rendering token,Options(..)-- for rendering options specific to SVG)where-- from baseimportData.TypeableimportControl.Monad.State-- from diagrams-libimportDiagrams.PreludeimportDiagrams.TwoD.Path(getClip)importDiagrams.TwoD.Adjust(adjustDia2D)importDiagrams.TwoD.Text-- from monoid-extrasimportData.Monoid.Split(Split(..))-- from blaze-svgimportqualifiedText.Blaze.Svg11asSimportText.Blaze.Svg11((!))-- from this packageimportqualifiedGraphics.Rendering.SVGasRdataSVG=SVGderiving(Show,Typeable)dataSvgRenderState=SvgRenderState{clipPathId::Int}initialSvgRenderState::SvgRenderStateinitialSvgRenderState=SvgRenderState0-- Monad to keep track of state when rendering an SVG.-- Currently just keeps a monotonically increasing counter-- for assiging unique clip path IDtypeSvgRenderM=StateSvgRenderStateS.SvgincrementClipPath::StateSvgRenderState()incrementClipPath=modify(\(SvgRenderStatex)->SvgRenderState(x+1))instanceMonoid(RenderSVGR2)wheremempty=R$returnmempty(Rr1)`mappend`(Rr2_)=R$dosvg1<-r1svg2<-r2_return(svg1`mappend`svg2)-- renders a <g> element with styles applied as attributes.renderStyledGroup::Stylev->(S.Svg->S.Svg)renderStyledGroups=S.g!R.renderStylessrenderSvgWithClipping::S.Svg-- Input SVG->Stylev-- Styles->Int-- Clip Path ID->TransformationR2-- Freeze transform->S.Svg-- Resulting svgrenderSvgWithClippingsvgsid_t=doR.renderClip(transform(invt)<$>getClip<$>getAttrs)id_-- Clipping if anysvg-- The diagraminstanceBackendSVGR2wheredataRenderSVGR2=RSvgRenderMtypeResultSVGR2=S.SvgdataOptionsSVGR2=SVGOptions{size::SizeSpec2D-- ^ The requested size.}-- Here the SVG backend is different from the other backends. We-- give a different definition of renderDia, where only the-- non-frozen transformation is applied to the primitives before-- they are passed to render. This means that withStyle is-- responsible for applying the frozen transformation to the-- primitives.withStyle_st(Rr)=R$doincrementClipPathclipPathId_<-getsclipPathIdsvg<-rletstyledSvg=renderStyledGroups!(R.renderClipPathIdsclipPathId_)$renderSvgWithClippingsvgsclipPathId_t-- This is where the frozen transformation is applied.return(R.renderTransformtstyledSvg)doRender_(SVGOptionssz)(Rr)=evalStatesvgOutputinitialSvgRenderStatewheresvgOutput=dosvg<-rlet(w,h)=caseszofWidthw'->(w',w')Heighth'->(h',h')Dimsw'h'->(w',h')Absolute->(100,100)return$R.svgHeaderwh$svgadjustDiacoptsd=adjustDia2DsizesetSvgSizecopts(d#reflectY#recommendFillColor(transparent::AlphaColourDouble))wheresetSvgSizeszo=o{size=sz}-- This implementation of renderDia is the same as the default one,-- except that it only applies the non-frozen transformation to the-- primitives before passing them to render.renderDiaSVGoptsd=doRenderSVGopts'.mconcat.maprenderOne.prims$d'where(opts',d')=adjustDiaSVGoptsdrenderOne::(PrimSVGR2,(Split(TransformationR2),StyleR2))->RenderSVGR2renderOne(p,(Mt,s))=withStyleSVGsmempty(renderSVG(transformtp))renderOne(p,(t1:|t2,s))-- Here is the difference from the default-- implementation: "t2" instead of "t1 <> t2".=withStyleSVGst1(renderSVG(transformt2p))instanceRenderable(SegmentR2)SVGwhererenderc=renderc.flipTrailFalse.(:[])instanceRenderable(TrailR2)SVGwhererenderct=renderc$Path[(p2(0,0),t)]instanceRenderable(PathR2)SVGwhererender_=R.return.R.renderPathinstanceRenderableTextSVGwhererender_=R.return.R.renderText-- TODO: instance Renderable Image SVG where