rasem icon indicating copy to clipboard operation
rasem copied to clipboard

rasem is a pure ruby gem that allows you to describe your SVG images in ruby code

= Rasem

rasem is a pure ruby gem that allows you to describe your SVG images in ruby code.

== Why Rasem

  • Did you ever want to visualize some data in a nice image?
  • Do you want to draw a complex image that is easier to describe using a code?
  • Would you like to power your HTML 5 site with nicely drawn SVG images?
  • Do you need to generate nice images from your ruby code?
  • Are you fed up with using DIVs and Javascript to draw simple graphs?
  • Is your server overwhelmed with sending PNG images that can be described in a few bytes using SVG?

Rasem allows you to generate SVG images that can be easily exported to other formats and embed in an HTML 5 page.

== Features

  • Draw basic elements: line, rectangle, rouned rectangle, circle, ellipse, polygon and polyline.
  • Use SVG styles such as stroke-width, opacity and fill.
  • Use SVG transformations such as translate, scale, rotate, skewX/Y and matrix
  • Create SVG groups for better editing in SVG editors.
  • Create SVG paths using ruby blocks
  • Use definitions to create shapes and reuse them in your image
  • Create SVG gradients Coming features:
  • Include all SVG standard elements such as filters
  • Create default rake and thor tasks to convert your .rasem files to .svg.
  • Embed other images in your SVG image
  • Output to more formats such as PNG.

Rasem is still in alpha release. Please report your bugs so that we can work on it. You are welcome to contribute to the project by adding more features and fixing bugs. The end goal of the project is to fully support SVG standard and make it easy to use.

== Installation gem install rasem

== Usage There are two main methods to generate images with Rasem.

=== Command line Create a file with extension .rasem. Here is a sample file test.rasem self.width = 100 self.height = 100 circle 20, 20, 5 circle 50, 50, 5 line 20, 20, 50, 50

Save this file and execute the command rasem test.rasem

A file test.svg will be generated.

=== Ruby code You can generate the image from your ruby code. This has several uses such as sending the image on the fly from a Rails application.

Here is a simple example require 'rasem' img = Rasem::SVGImage.new(:width=>100, :height=>100) do circle 20, 20, 5 circle 50, 50, 5 line 20, 20, 50, 50 end

puts img.output

img.output is the SVG code generated for this images.

== More Examples The following examples are for .rasem files. These are actually ruby scripts that are executed to generate the image. So, you can write arbitrary ruby code in .rasem files as you will see.

simple_graph.rasem nodes = [[10,10], [20,20], [10,20]] radius = 3 with_style :fill=>"white", :stroke=>"black" do for node in nodes circle node.first, node.last, radius end end

line nodes[0].first, nodes[0].last, nodes[1].first, nodes[1].last, :stroke=>"blue"

Here is a more sophisticated example.

tictactoe.rasem self.width = 150 self.height = 150 board = [['x', 'o', 'x'], ['o', '-', 'o'], ['x', 'o', 'x']] def draw_x(x,y) group :stroke=>"red" do line x-20, y-20, x+20, y+20 line x-20, y+20, x+20, y-20 end end

def draw_o(x,y) circle x, y, 20, :stroke=>"blue", :fill=>"white" end

group :stroke=>"black" do
rectangle 0, 0, 150, 150, :stroke_width=>2, :fill=>"white" line 50, 0, 50, 150 line 100, 0, 100, 150 line 0, 50, 150, 50 line 0, 100, 150, 100 end

board.each_with_index do |row, row_index| row.each_with_index do |cell, column_index| if cell == "x" draw_x row_index * 50 + 25, column_index * 50 + 25 elsif cell == "o" draw_o row_index * 50 + 25, column_index * 50 + 25 end end end

Here are some examples that show how you can generate images from your ruby code.

You can generate SVG and store it to file img = Rasem::SVGImage.new(:width => 100, :height => 100) img.line(0, 0, 100, 100)

File.open("test.svg", w") do |f| img.write(f) end

You can use pass a block to SVGImage.new to make things more compact img = Rasem::SVGImage.new(100, 100) do line(0, 0, 100, 100) end

Image is closed automatically

Write to file

You can make your code even more compact by passing the file as a last argument to SVGImage.new File.open("test.svg", "w") do |f| Rasem::SVGImage.new({:width => 100, :height => 100}, f) do line(0, 0, 100, 100) end end

You can use transformations on created objects (translate, scale, rotate, skew, matrix)

img = Rasem::SVGImage.new(:width => 100, :height => 100) do circle(0, 0, 10).translate(50, 50).scale(2, 1.5) end

Here is an example showing how to generate a path using ruby code.

require 'rasem'

width = 100 height = 200

img = Rasem::SVGImage.new(:width => width, :height => height) do path("stroke" => "black") do moveToA(0, height / 2.0) vlineTo(height / 2.0 - 50) curveTo(50, 40, 0, 0, 50, 0) curveTo(-30, -50, 0, 0, 10, -30) vlineTo(-(height / 2.0 - 60)) end end

File.open("path.svg", "w") do |f| img.write(f) end

Using definitions and reuse them later

img = Rasem::SVGImage.new(:width => 100, :height => 100) do defs do group(:id => "group1") do circle(0, 0, 20) text(0, 5, :fill => "red") { raw "hi!" } end end

use("group1", :x => 50, :y => 25)
use("group1", :x => 50, :y => 75, :fill => "blue")

end

Ruby method def_group to use definitions. It create a group inside 'defs' with the given id and populate it using the block. The second optional argument controls the behaviour if the id is already in use, you can :fail, :update the existing element (and return the new one), or :skip the new one (effectively skipping the block, and returning the existing element).

img = Rasem::SVGImage.new(:width => 100, :height => 100) do

g = def_group("group1") do
  circle(0, 0, 20)
end


g = def_group("group1", :update) do
  circle(0, 0, 20)
  text(0, 5, :fill => "red") { raw "hi!" }
end
  

use(g, :x => 50, :y => 25)
use(g, :x => 50, :y => 75, :fill => "blue")

end

An example of gradients usage

img = Rasem::SVGImage.new(:width => 100, :height => 100) do

r1 = radialGradient("rgrad1") do
  stop("0%", "green", 1)
  stop("100%", "blue", 1)
end

r2 = radialGradient("rgrad2") do
  stop("0%", "yellow", 1)
  stop("100%", "red", 1)
end

r2 = radialGradient("rgrad2", {}, :skip) do
  stop("0%", "blue", 1)
  stop("100%", "red", 1)
end


circle(50, 25, 20, :fill => r1.fill)
circle(50, 75, 20, :fill => r2.fill)

end

== Contributing to rasem

  • Check out the latest master to make sure the feature hasn't been implemented or the bug hasn't been fixed yet
  • Check out the issue tracker to make sure someone already hasn't requested it and/or contributed it
  • Fork the project
  • Start a feature/bugfix branch
  • Commit and push until you are happy with your contribution
  • Make sure to add tests for it. This is important so I don't break it in a future version unintentionally.
  • Please try not to mess with the Rakefile, version, or history. If you want to have your own version, or is otherwise necessary, that is fine, but please isolate to its own commit so I can cherry-pick around it.

== Copyright

Copyright (c) 2011 Ahmed Eldawy. See LICENSE.txt for further details.