Coder Social home page Coder Social logo

diagrams-svg's Introduction

diagrams-svg Hackage Build Status)

diagrams-svg is a an SVG backend for diagrams. Diagrams is a powerful, flexible, declarative domain-specific language for creating vector graphics, using the Haskell programming language.

diagrams-svg is the default out-of-the box backend that comes with the diagrams framework, and supports most features defined in diagrams-lib.

Installation

cabal update && cabal install diagrams-svg

Usage

A simple example that uses diagrams-svg to draw a square.

import Diagrams.Prelude
import Diagrams.Backend.SVG.CmdLine

b1 :: Diagram B
b1 = square 20 # lw 0.002

main = mainWith (pad 1.1 b1)

Save this to file named Square.hs and compile this program:

ghc --make Square.hs

This will generate an executable which, when run produces an SVG file. Run the executable with the --help option to find out more about how to call it.

$ ./Square --help
./Square

Usage: ./Square [-w|--width WIDTH] [-h|--height HEIGHT] [-o|--output OUTPUT] [--loop] [-s|--src ARG] [-i|--interval INTERVAL]
  Command-line diagram generation.

Available options:
  -?,--help                Show this help text
  -w,--width WIDTH         Desired WIDTH of the output image
  -h,--height HEIGHT       Desired HEIGHT of the output image
  -o,--output OUTPUT       OUTPUT file
  -l,--loop                Run in a self-recompiling loop
  -s,--src ARG             Source file to watch
  -i,--interval INTERVAL   When running in a loop, check for changes every INTERVAL seconds.
  -p,--pretty              Pretty print the SVG output

You must pass an output file name with a .svg extension to generate the SVG file.

$ ./Square -o square.svg

The command above generates the SVG file:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
    "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="22.0" height="22.0" viewBox="0 0 22 22">
  <g>
    <g stroke="rgb(0,0,0)" stroke-opacity="1.0" fill="rgb(0,0,0)" fill-opacity="0.0" stroke-width="2.0e-3">
       <path d="M 21.0,21.0 l -2.220446049250313e-15,-20.0 h -20.0 l -2.220446049250313e-15,20.0 Z" />
    </g>
  </g>
</svg>

diagrams-svg's People

Contributors

andrewthad avatar bergey avatar bgamari avatar byorgey avatar cchalmers avatar deech avatar deepakjois avatar duairc avatar fryguybob avatar fumieval avatar ggreif avatar gleachkr avatar igormoreno avatar jeffreyrosenbluth avatar jhrcek avatar larskuhtz avatar mchav avatar meteficha avatar mgsloan avatar michaelt avatar misterbeebee avatar ocharles avatar phadej avatar ryanglscott avatar sergv avatar sid-kap avatar taruti avatar tdox avatar tvh avatar vaibhavsagar avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

diagrams-svg's Issues

Font size not applied properly in composite diagram

Applying fontSize to a composite diagram doesn't render properly:

rightSize = square 3 <> text "hi" # fontSizeL 2
wrongSize = (square 3 <> text "hi") # fontSizeL 2

Inspecting the SVG output shows the correct size is applied in an outer group but the Recommended size is used in an inner group and that's what gets shown. I suspect this is from the recent changes to Measure. It doesn't happen in the rasterific or pgf backends.

SVG backend fills lines again

Consider:

dia = pentagon 1 # strokeLine # fc green

This should produce an empty pentagon, but it produces a green one.

I'm guessing this was introduced during the conversion to use RTree?

Allow xml references

When I have a green circle and want to duplicate it to many translated positions, then the circle's svg source will get textually duplicated. When the duplicand has a lot of source this can get very verbose. Any chance to use xml references optionally to refer to the original?

Gradient is not applied to text

Using a linear gradient to fill some text does not work.

This is specific for the SVG backend as it works for the rasterific backend. Here is a minimal working example:

{-# LANGUAGE NoMonomorphismRestriction #-}

import Diagrams.Prelude
import Diagrams.Backend.SVG.CmdLine

stops = mkStops [(gray, 0, 1), (white, 0.5, 1), (purple, 1, 1)]
gradient = mkLinearGradient stops ((-0.5) ^& 0) (0.5 ^& 0) GradPad

text1 :: Diagram B 
text1 = rect 20 8 <> text "Hello" # fontSize (local 4) # fillTexture  gradient

main = mainWith text1

Replacing GradPad with GradRepeat shows a gradient applied to the text though.

Fill color needs to be explicitly specified for text nodes

diagrams-svg uses a transparent fill color by default. diagrams text primitives use only fills, and set the <stroke> attribute to none to get around some other rendering issues. This leads to a situation where if we do not set a fill color explicitly, a lot of times there is no visible output.

Line width not handled properly by some browsers

{-# LANGUAGE NoMonomorphismRestriction #-}

import Diagrams.Prelude
import Diagrams.Backend.SVG.CmdLine

illustrateBezier c0 c1 c2 c3 x2 x3
    = endpt  # translate x3
    <> l3a
    <> fromSegments [bezier3 c3 c0 x3, bezier3 c1 c2 x2]
  where
    dashed  = dashing [0.1,0.1] 0
    endpt   = circle 0.05 # fc red  # lw 0
    l3a     = fromOffsets [r2 (1, 2)] # translate (r2 (1, 1)) # dashed

x2      = r2 (3,-1) :: R2         -- endpoint
x3      = r2 (1, 1) :: R2         -- endpoint
[c0,c1,c2,c3,c4] = map r2 [(-1, -3), (1,2), (2,0), (-3,0), (-1, -2)]   -- control points

example = illustrateBezier c0 c1 c2 (-c2) x2 x3

main = defaultMain example

Replacing SVG.CmdLine by Cairo.CmdLine produces what I would expect but SVG gives extremely wide lines as you can see in the diagrams.
screen shot 2013-07-14 at 12 03 50

Drawing a circle produes a path and not a circle.

I'm doing the tutorial and the first example of drawing a circle produces an svg file which represents a circle as a path, instead of representing a circle as a circle element.

I would like to be leveraging the compactness of svg, and drawing a path for a circle seems to negate the inherent efficiency of the svg format.

(Viewing the circle in the browser the path of the circle is noticeably imperfect.)

feature idea: on mouseover support

i've noticed that svg's have an on mouseover operation that can be supported,
this might be worth supporting in diagrams-svg (would that entail adding it to blaze svg?)

i've not dug around to see what needs to be changed to add this (if feasible), but i figured that this might be interesting for other folks too, so I'm adding it here

Add function of type FilePath -> SizeSpec2D -> Diagram -> IO ()

That is, something you could just call from ghci or from within some other program to write out a diagram to a file, instead of creating a standalone executable with defaultMain.

(Note, something like this should probably go in diagrams-cairo as well.)

Freezing does not appear to work with the SVG backend

(Reported by Derrick Lin, moved here from http://code.google.com/p/diagrams/issues/detail?id=89)

What steps will reproduce the problem?

  1. Install diagrams with the SVG backend
  2. Do the diagrams tutorial
  3. Be puzzled when you hit the Freezing section

What is the expected output? What do you see instead?
"On the left is an untransformed circle drawn with a line 0.1 units thick. The next circle is a scaled version of the first: notice how the line thickness is the same. The third circle was produced by first freezing, then scaling the first circle, resulting in a line twice as thick. The last two circles illustrate a non-uniform scale applied to an unfrozen circle (which is drawn with a uniform line) and to a frozen one (in which the line gets thicker and thinner according to the non-uniform scale)."

Sadly the line thickness is the same between the frozen and unfrozen versions.

What version of the product are you using? On what operating system?
OSX Snow Leopard (10.6), newest diagrams (0.5).

Please provide any additional information below.
Discovered at hac-phi.

SVG backend doesn't fill loops if they occur in the same subtree as a line

It looks like #42 was a bit more subtle than I thought. See the last line of http://projects.haskell.org/diagrams/backend-tests/all-index.html .

The problem is that a style node may occur at the root of a subtree which contains both lines and loops. In that case it seems that the only possible solution is to actually split the style node and push fill attributes down until they are over a subtree which contains only loops.

In fact, perhaps we even ought to do this as a compilation pass, in diagrams-core. We could make sure that fill attributes are only ever at the root of subtrees containing all loops. Then backends wouldn't have to worry about it at all, but could simply issue a fill attribute when they see it.

Data type for command line options need to be exported

Data types for command line options need to be exported for the Mainable instance to be composed with other Mainable instances. There might be some other nice things to have like Default instances where applicable. Also didn't we merge the changes that let us remove CPP from CmdLine?

Font scaling uses "em" units.

I'm not sure why, but font-scale attributes have "em" units. This renders as expected for me in Chrome, but not in Inkscape. I think the Inkscape rendering makes more sense but I haven't thought it through completely. If I manually remove all the "em"s Chrome and Inkscape look the same.

Option to not XML-escape text

It would be nice if there was an option to not XML-escape text, so that special characters could be used, as in alignedText 0 0 "Jack&amp;Jill had 5&minus;4 pancakes". Currently this renders as <text ...>Jack&amp;amp;Jill had 5&amp;minus;4 pancakes</text>.

I tracked down what happens to the string that is put into alignedText during rendering. Graphics.Rendering.SVG.renderText sends the string (in a Text object) to Graphics.SVG.Core.toElement, part of the svg-builder package, which runs it through Blaze.ByteString.Builder.Html.Utf8.fromHtmlEscapedString, which is the culprit.

I'm not sure what could be done to get around this. For now my workaround is to run the svg output through sed -i "s/\&amp;/\&/g".

SVG backend has broken text fusion

I just started playing with diagrams again, and it's pretty great!

However, I'm running into speed issues. I have an example project here. This thing builds up maybe 900 circles, and does some transformations on them.

It takes about 9 seconds to run on my machine, even with -O2. This is too slow for any kind of live coding experience, so I decided to do some profiling. The results are here:

COST CENTRE            MODULE                             SRC                                             %time %alloc  ticks     bytes

toText                 Graphics.Svg.Path                  src/Graphics/Svg/Path.hs:26:1-63                 19.3   24.7   2600 1931550016
fmap                   Linear.V2                          src/Linear/V2.hs:131:3-34                        12.8   12.1   1719 946285224
atParam                Diagrams.Segment                   src/Diagrams/Segment.hs:(232,3)-(236,18)         10.5   10.4   1411 813761968
getEnvelope.\          Diagrams.Segment                   src/Diagrams/Segment.hs:(295,5)-(301,36)         10.2    7.7   1376 600342736

and the cost centers:

                                                                                                                                                                                        individual      inherited
COST CENTRE                                                          MODULE                               SRC                                                      no.       entries  %time %alloc   %time %alloc  ticks     bytes

MAIN                                                                 MAIN                                 <built-in>                                               13590          0    0.0    0.0   100.0  100.0      2     67600
                   withTrail                                         Diagrams.Trail                       src/Diagrams/Trail.hs:811:1-54                           44663        924    0.0    0.0    21.6   30.1      0         0
                    withTrail'                                       Diagrams.Trail                       src/Diagrams/Trail.hs:(417,1)-(418,40)                   44664        924    0.0    0.0    21.6   30.1      1         0
                     renderTrail.renderLoop                          Graphics.Rendering.SVG               src/Graphics/Rendering/SVG.hs:(113,5)-(120,10)           44665        924    0.9    3.6    21.6   30.1    119 282848416
                      renderSeg                                      Graphics.Rendering.SVG               src/Graphics/Rendering/SVG.hs:(123,1)-(128,67)           44737      52234    0.0    0.0    20.4   26.3      5       240
                       cR                                            Graphics.Svg.Path                    src/Graphics/Svg/Path.hs:(68,1)-(70,53)                  44856      52230    1.2    1.7    20.3   26.3    160 133733280
                        toText                                       Graphics.Svg.Path                    src/Graphics/Svg/Path.hs:26:1-63                         44858     313380   19.1   24.6    19.1   24.6   2578 1918235944

Dang! Looks like text fusion is broken. The implementation of toText suggests why:

toText :: RealFloat a => a -> Text
toText = toStrict . toLazyText . formatRealFloat Fixed (Just 4)

formatRealFloat returns a Data.Text.Lazy.Builder, but then the builder is immediately forced. Later, every other function in this module just Text.concats them together! But all of these are strict texts! No wonder we're missing out on fusion and everything is allocating super hard!

The fix as best I can tell is to make toText return a Builder, and then replace each instance of T.concat in Graphics.SVG.Path with toStrict . toLazy . mconcat. Or better yet, to use this same builder all the way through the SVG generation.

diagrams-svg doesn't build under directory-1.2 (and hence GHC-7.6)

See http://haskell.1045720.n5.nabble.com/getModificationTime-and-directory-1-2-td5717458.html. Probably the right thing to do is to switch from ClockTime to UTCTime, and add some CPP directives to insert some additional code to do the conversion from ClockTime to UTCTime when compiling under older versions of directory.

Of course, the same change will be needed in diagrams-cairo, which once again points out the need for abstracting this looped recompilation stuff out into a separate package.

diagrams-svg-1.4.3.1 requires diagrams-lib-1.4.5

Building library for diagrams-svg-1.4.3.1..
[1 of 3] Compiling Graphics.Rendering.SVG ( src/Graphics/Rendering/SVG.hs, /codetmp/diagrams-lib/diagrams-svg-1.4.3.1/.dist-newstyle-trustee/c8310e23749e36eec7b572efa1ee26bc640a99c16cea4b4a6563693e59ba04f6bc1ac514dfcc29aceefe8838770cdde2c65732f9d953a21b8d805b61a78c45f9/build/x86_64-linux/ghc-9.0.1/diagrams-svg-1.4.3.1/noopt/build/Graphics/Rendering/SVG.o, /codetmp/diagrams-lib/diagrams-svg-1.4.3.1/.dist-newstyle-trustee/c8310e23749e36eec7b572efa1ee26bc640a99c16cea4b4a6563693e59ba04f6bc1ac514dfcc29aceefe8838770cdde2c65732f9d953a21b8d805b61a78c45f9/build/x86_64-linux/ghc-9.0.1/diagrams-svg-1.4.3.1/noopt/build/Graphics/Rendering/SVG.dyn_o )
[2 of 3] Compiling Diagrams.Backend.SVG ( src/Diagrams/Backend/SVG.hs, /codetmp/diagrams-lib/diagrams-svg-1.4.3.1/.dist-newstyle-trustee/c8310e23749e36eec7b572efa1ee26bc640a99c16cea4b4a6563693e59ba04f6bc1ac514dfcc29aceefe8838770cdde2c65732f9d953a21b8d805b61a78c45f9/build/x86_64-linux/ghc-9.0.1/diagrams-svg-1.4.3.1/noopt/build/Diagrams/Backend/SVG.o, /codetmp/diagrams-lib/diagrams-svg-1.4.3.1/.dist-newstyle-trustee/c8310e23749e36eec7b572efa1ee26bc640a99c16cea4b4a6563693e59ba04f6bc1ac514dfcc29aceefe8838770cdde2c65732f9d953a21b8d805b61a78c45f9/build/x86_64-linux/ghc-9.0.1/diagrams-svg-1.4.3.1/noopt/build/Diagrams/Backend/SVG.dyn_o )


src/Diagrams/Backend/SVG.hs:260:14: error:
    • No instance for (Eq (SizeSpec V2 n))
        arising from the first field of ‘SVGOptions’ (type ‘SizeSpec V2 n’)
      Possible fix:
        use a standalone 'deriving instance' declaration,
          so you can specify the instance context yourself
    • When deriving the instance for (Eq (Options SVG V2 n))
    |
260 |     deriving Eq

See also diagrams/diagrams-postscript#34

I made a corresponding revision: https://hackage.haskell.org/package/diagrams-svg-1.4.3.1/revisions/

Embedded font definitions

I'm trying to update Chart-diagrams to diagrams-svg-1.3, but I'm not sure how to deal with embedded font definitions. Previously, SVGFonts was used to produce some markup that was passed to the SVGOptions record via its second parameter. That parameter is now a list of Attributes. Is there a way to go from the output of makeSvgFont to something I can stuff into a value of type [Attribute]?

Embedding JPEG images without repacking

I wanted to embed JPEG images without repacking them (and thus losing quality) or using PNG (huge images). I ended up with taruti@9a9a911

That solves the issue by adding a new

loadImageSVG :: FilePath -> IO (Diagram SVG R2)

to Diagrams.Backend.SVG.

Using Embedded DImages does not work since that would imply repacking and a loss of quality.

Using External DImages does not work since SVG backend does not have IO and thus one cannot read the image data for the embed in the rendering function.

This requires a git version of diagrams-lib (at least 2014-06-23).

clipping broken

Tested with diagrams-svg-1.1.0.4, test case:

import Diagrams.Prelude
import Diagrams.Backend.SVG.CmdLine (defaultMain)
-- import Diagrams.Backend.Cairo.CmdLine (defaultMain)

clipBy' p d = d # clipBy p # withEnvelope p

shape c = square 2 # fc c # clipBy' (circle 0.5)

main = defaultMain $
  ((shape red  ||| shape yellow)
   ===
   (shape blue ||| shape green)
  ) # bg white

Correct output with cairo backend, using -w 1024 -o bug.svg:
clipping-bug-cairo-backend

Bad output with svg backend, using -w 1024 -o bug.svg:
clipping-bug-svg-backend

SVG converted to PNG using rsvg -w 128 bug.svg -o bug.png

$ rsvg --version
rsvg-convert version 2.36.1

Improve Haddock documentation

See the diagrams-cairo Haddocks for an example. There needs to be a bunch more information about how to make use of the backend, since a lot of information is actually buried in type class instances.

Spaces not preserved in text

By default, SVG does not preserve spaces in text. This is explained in the SVG spec:

‘xml:space’ is an inheritable attribute which can have one of two values:

'default'
(The initial/default value for ‘xml:space’.) When xml:space="default", the SVG user agent will do the following using a copy of the original character data content. First, it will remove all newline characters. Then it will convert all tab characters into space characters. Then, it will strip off all leading and trailing space characters. Then, all contiguous space characters will be consolidated.

'preserve'
When xml:space="preserve", the SVG user agent will do the following using a copy of the original character data content. It will convert all newline and tab characters into space characters. Then, it will draw all space characters, including leading, trailing and multiple contiguous space characters. Thus, when drawn with xml:space="preserve", the string "a b" (three spaces between "a" and "b") will produce a larger separation between "a" and "b" than "a b" (one space between "a" and "b").

I am working on a visual representation of Haskell rendered using diagrams (Glance), so of course I want to preserve spaces for string literals and comments.

As a workaround, I made a customized version of renderSVG that adds the attribute bindAttr XmlSpace_ (pack "preserve")

customRenderSVG outputFilename size = renderSVG' outputFilename svgOptions where
  -- This xml:space=preserve attribute preserves the spaces in the svg text.
  attributes = [bindAttr XmlSpace_ (pack "preserve")]
  svgOptions = SVGOptions size Nothing (pack "") attributes True

Embed SVG images

Right now it is possible to embed raster images (PNG, JPG, ...) but not other SVG images, although the SVG format itself supports embedded SVGs perfectly well, either via a nested <svg> tag or via an <image ... xlink:href="..."> tag (corresponding to the existing embedded/external distinction in diagrams).

While researching the best way to support this I'm realizing that diagrams' whole system of support for images is very much biased towards raster images. The SVG backend has an instance for DImage Embedded which definitely represents a raster image; it also has a special loadImageSVG which goes via ImageNative, but it also only supports PNG or JPEG, and ends up embedding them in a base64-encoded data URI. I think trying to shoehorn embedded SVG into this is going to be annoying.

Instead, I think the simplest approach is to simply add a new kind of embedded SVG primitive, specific to the SVG backend. It would be easiest to have it work via the xlink approach but inlining the contents of another SVG should be possible too.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.