Class: XRVG::SVGRender

Inherits:
Render
  • Object
show all
Defined in:
lib/render.rb

Overview

SVG Render class

In charge of generating a svg output file from different object passed to it

Use

Canonical use of the class

render = SVGRender[ :filename, "essai.svg" ]
render.add( Circle[] )
render.end

Improvements

Allows also the “with” syntax

Attributes

attribute :filename, "", String
attribute :imagesize, "2cm", String
attribute :background, Color.white, [Color, String]

Instance Attribute Summary collapse

Attributes inherited from Render

#height, #width

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(*args, &block) ⇒ SVGRender

:nodoc:



55
56
57
58
59
60
61
62
63
64
# File 'lib/render.rb', line 55

def initialize ( *args, &block ) #:nodoc:
  super( *args )
  @layers  = {}
  @defs    = ""
  @ngradients = 0
  if @filename.length == 0
    @filename = $0.split(".")[0..-2].join(".") + ".svg"
    Trace("filename is #{filename}")
  end
end

Instance Attribute Details

#viewboxObject (readonly)

:nodoc:



141
142
143
# File 'lib/render.rb', line 141

def viewbox
  @viewbox
end

Class Method Details

.[](*args, &block) ⇒ Object

SVGRender builder

Allows to pass a block, to avoid using .end

SVGRender.[] do |render|
  render.add( Circle[] )
end


45
46
47
48
49
50
51
52
# File 'lib/render.rb', line 45

def SVGRender.[](*args,&block)
  result = self.new( *args )
  if block
    yield result
    result.end
  end
  return result
end

Instance Method Details

#add(object, style = nil, layer = 0, type = :object) ⇒ Object

render fundamental method

used to render an object, with a particular style, on an optional layer.

render.add( Circle[], Style[ :fill, Color.black ], 1 )

If style is not provided, render asked to object its default_style, if any



106
107
108
109
# File 'lib/render.rb', line 106

def add(object, style=nil, layer=0, type=:object)
  add_content( render( object, style ), layer)
  refresh_viewbox( object )
end

#add_content(string, layer) ⇒ Object

:nodoc:



73
74
75
76
77
78
# File 'lib/render.rb', line 73

def add_content (string, layer) #:nodoc:
  if not @layers.key? layer
    @layers[ layer ] = ""
  end
  @layers[ layer ] += string
end

#add_def(object) ⇒ Object

:nodoc:



90
91
92
# File 'lib/render.rb', line 90

def add_def (object) #:nodoc:
  @defs += object
end

#add_gradient(gradient) ⇒ Object

:nodoc:



94
95
96
97
98
99
# File 'lib/render.rb', line 94

def add_gradient( gradient ) #:nodoc:
  id = "gradient#{@ngradients}"
  add_def( gradient.svgdef.subreplace( {"%ID%" => id} ) )
  @ngradients += 1
  return id
end

#contentObject

:nodoc:



232
233
234
235
# File 'lib/render.rb', line 232

def content #:nodoc:
  keys = @sortlayers ? @sortlayers : @layers.keys.sort
  return keys.inject("") {|result,key| result += @layers[key]}
end

#endObject

:nodoc:



241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
# File 'lib/render.rb', line 241

def end () #:nodoc:
  svgcontent    = content()
  svgviewbox    = get_viewbox_svg()
  svgbackground = get_background_svg()

  content = svg_template().subreplace( {"%VIEWBOX%"    => svgviewbox,
			  "%SIZE%"       => @imagesize,
			  "%DEFS%"       => svgdef,
			  "%BACKGROUND%" => svgbackground,
			  "%CONTENT%"    => svgcontent})
  
  File.open(filename(), "w") do |f|
    f << content
  end
 
  puts "render #{filename()} OK"; # necessary for Emacs to get output name !!!!
end

#get_background_svgObject

:nodoc:



177
178
179
180
181
182
183
184
185
186
187
188
189
# File 'lib/render.rb', line 177

def get_background_svg #:nodoc:
  xmin, ymin, width, height = get_carre_viewbox( get_final_viewbox() )
  template = '<rect x="%x%" y="%y%" width="%width%" height="%height%" fill="%fill%"/>' 
  bg = self.background
  if bg.respond_to? :svg
    bg = bg.svg
  end
  return template.subreplace( {"%x%"      => xmin,
		 "%y%"      => ymin,
		 "%width%"  => width,
		 "%height%" => height,
		 "%fill%"   => bg} )
end

#get_carre_viewbox(viewbox) ⇒ Object

:nodoc:



219
220
221
222
223
224
225
# File 'lib/render.rb', line 219

def get_carre_viewbox( viewbox ) #:nodoc:
  xmin, ymin, width, height = viewbox
  xcenter = xmin + width  / 2.0
  ycenter = ymin + height / 2.0
  maxsize = width < height ? height : width
  return [xcenter - maxsize/2.0, ycenter - maxsize/2.0, maxsize, maxsize]
end

#get_final_viewboxObject

:nodoc:



191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
# File 'lib/render.rb', line 191

def get_final_viewbox #:nodoc:
  marginfactor = 0.2
  xmin, ymin, xmax, ymax = viewbox()
  width, height          = size()
  
  xcenter = (xmin + xmax)/2.0
  ycenter = (ymin + ymax)/2.0
  
  width  *= 1.0 + marginfactor
  height *= 1.0 + marginfactor
  
  if width == 0.0
    width = 1.0
  end
  if height == 0.0
    height = 1.0
  end

  xmin = xcenter - width  / 2.0
  ymin = ycenter - height / 2.0
							
  return xmin, ymin, width, height
end

#get_viewbox_svgObject

:nodoc:



215
216
217
# File 'lib/render.rb', line 215

def get_viewbox_svg #:nodoc:
  return viewbox_svg( get_final_viewbox() )
end

#layers=(backtofront) ⇒ Object

:nodoc:



66
67
68
69
70
71
# File 'lib/render.rb', line 66

def layers=( backtofront ) #:nodoc:
  @sortlayers = backtofront
  @sortlayers.each do |key|
    @layers[ key ] = ""
  end
end

#rasterObject

:nodoc:



259
260
261
262
263
264
# File 'lib/render.rb', line 259

def raster () #:nodoc:
  # bg = background.format255

  # Kernel.system( "ruby", "svg2png.rb", filename(), "2.0" )
  # Kernel.system( "i_view32", filename().subreplace( ".svg" => ".png" ), "/fs" )
end

#refresh_viewbox(object) ⇒ Object

:nodoc:



150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
# File 'lib/render.rb', line 150

def refresh_viewbox (object) #:nodoc:
  newviewbox = object.viewbox
  if newviewbox.length > 0
    if @viewbox == nil
	@viewbox = newviewbox
    else
	newxmin, newymin, newxmax, newymax = newviewbox
	xmin, ymin, xmax, ymax = viewbox
	
	if newxmin < xmin 
 xmin = newxmin
	end
	if newymin < ymin 
 ymin = newymin
	end
	if newxmax > xmax
 xmax = newxmax
	end
	if newymax > ymax
 ymax = newymax
	end

	@viewbox = [xmin, ymin, xmax, ymax]
    end
  end
end

#render(object, style = nil) ⇒ Object

:nodoc:



111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
# File 'lib/render.rb', line 111

def render (object, style=nil) #:nodoc:
  owidth, oheight = object.size

  res     = 0.0000001
  if owidth < res and oheight < res
    return ""
  end

  if not style
    style = object.default_style
  end

  result  = "<g #{style.svgline}>\n"
  result += object.svg + "\n"
  result += "</g>\n"

  # puts "result #{result}"

  if style.fill.is_a? Gradient
    gradientID = add_gradient( style.fill )
    result = result.subreplace( {"%fillgradient%" => "url(##{gradientID})"} )
  end
  
  if style.stroke.is_a? Gradient
    gradientID = add_gradient( style.stroke )
    result = result.subreplace( {"%strokegradient%" => "url(##{gradientID})"} )
  end
  return result
end

#sizeObject

:nodoc:



145
146
147
148
# File 'lib/render.rb', line 145

def size #:nodoc:
  xmin, ymin, xmax, ymax  = viewbox
  return [xmax - xmin, ymax - ymin]
end

#svg_templateObject

:nodoc:



80
81
82
83
84
85
86
87
88
# File 'lib/render.rb', line 80

def svg_template #:nodoc:
  return '<?xml version="1.0" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg width="%SIZE%" height="%SIZE%" %VIEWBOX% version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
  %DEFS%
  %BACKGROUND%
  %CONTENT%
</svg>'
end

#svgdefObject

:nodoc:



237
238
239
# File 'lib/render.rb', line 237

def svgdef #:nodoc:
  return "<defs>\n#{@defs}\n</defs>\n"
end

#viewbox_svg(viewbox) ⇒ Object

:nodoc:



227
228
229
230
# File 'lib/render.rb', line 227

def viewbox_svg( viewbox ) #:nodoc:
  xmin, ymin, width, height = viewbox
  return "viewBox=\"#{xmin} #{ymin} #{width} #{height}\""
end