dyi 0.0.2 → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/CHANGES +13 -0
- data/examples/animation.rb +28 -0
- data/examples/class_diagram.rb +1 -1
- data/examples/css.rb +34 -0
- data/examples/line_and_bar.rb +1 -2
- data/examples/line_chart.rb +5 -6
- data/examples/logo.rb +1 -1
- data/examples/pie_chart.rb +11 -4
- data/examples/simple_shapes.rb +1 -1
- data/lib/dyi.rb +8 -2
- data/lib/dyi/animation.rb +259 -0
- data/lib/dyi/canvas.rb +202 -0
- data/lib/dyi/chart.rb +2 -0
- data/lib/dyi/chart/array_reader.rb +112 -63
- data/lib/dyi/chart/axis_util.rb +298 -0
- data/lib/dyi/chart/base.rb +188 -466
- data/lib/dyi/chart/csv_reader.rb +0 -4
- data/lib/dyi/chart/legend.rb +82 -0
- data/lib/dyi/chart/line_chart.rb +31 -23
- data/lib/dyi/chart/pie_chart.rb +237 -30
- data/lib/dyi/color.rb +1 -1
- data/lib/dyi/drawing.rb +8 -1
- data/lib/dyi/drawing/clipping.rb +14 -1
- data/lib/dyi/drawing/pen.rb +12 -2
- data/lib/dyi/element.rb +167 -0
- data/lib/dyi/event.rb +148 -0
- data/lib/dyi/formatter/base.rb +43 -3
- data/lib/dyi/formatter/eps_formatter.rb +2 -2
- data/lib/dyi/formatter/svg_formatter.rb +430 -74
- data/lib/dyi/painting.rb +6 -1
- data/lib/dyi/script.rb +29 -0
- data/lib/dyi/script/ecmascript.rb +273 -0
- data/lib/dyi/script/simple_script.rb +94 -0
- data/lib/dyi/shape.rb +5 -1331
- data/lib/dyi/shape/base.rb +612 -0
- data/lib/dyi/shape/path.rb +902 -0
- data/lib/dyi/stylesheet.rb +86 -0
- data/lib/ironruby.rb +11 -11
- metadata +17 -4
- data/lib/dyi/drawing/canvas.rb +0 -100
@@ -64,13 +64,13 @@ module DYI #:nodoc:
|
|
64
64
|
|
65
65
|
def puts(io=$>)
|
66
66
|
StringFormat.set_default_formats(:color=>['%.3f %.3f %.3f', true], :length=>'0.### U', :coordinate=>'x y') {
|
67
|
-
if @canvas.
|
67
|
+
if @canvas.root_element?
|
68
68
|
io << header_comment
|
69
69
|
io << prolog
|
70
70
|
io << base_transform
|
71
71
|
end
|
72
72
|
@canvas.write_as(self, io)
|
73
|
-
if @canvas.
|
73
|
+
if @canvas.root_element?
|
74
74
|
io << footer_comment
|
75
75
|
end
|
76
76
|
}
|
@@ -25,11 +25,15 @@ module DYI #:nodoc:
|
|
25
25
|
module Formatter #:nodoc:
|
26
26
|
|
27
27
|
class SvgFormatter < XmlFormatter
|
28
|
+
include DYI::Script::EcmaScript::DomLevel2
|
28
29
|
|
29
30
|
def initialize(canvas, indent=0, level=0, version='1.1')
|
30
31
|
super(canvas, indent, level)
|
31
|
-
|
32
|
+
unless ['1.0', '1.1'].include?(@version = version.to_s)
|
33
|
+
raise ArgumentError, "version `#{version}' is unknown version"
|
34
|
+
end
|
32
35
|
@defs = {}
|
36
|
+
@text_border_elements = []
|
33
37
|
end
|
34
38
|
|
35
39
|
def declaration
|
@@ -47,21 +51,62 @@ module DYI #:nodoc:
|
|
47
51
|
|
48
52
|
def write_canvas(canvas, io)
|
49
53
|
@defs = {}
|
54
|
+
@xmlns = {:xmlns => "http://www.w3.org/2000/svg"}
|
55
|
+
pre_write
|
56
|
+
unless @text_border_elements.empty?
|
57
|
+
@canvas.add_initialize_script(draw_text_border(*@text_border_elements))
|
58
|
+
end
|
59
|
+
attrs = @xmlns.merge(:version => @version,
|
60
|
+
:width => canvas.real_width,
|
61
|
+
:height => canvas.real_height,
|
62
|
+
:viewBox => canvas.view_box,
|
63
|
+
:preserveAspectRatio => canvas.preserve_aspect_ratio)
|
64
|
+
attrs[:'pointer-events'] = 'none' if canvas.receive_event?
|
65
|
+
attrs[:class] = canvas.css_class if canvas.css_class
|
66
|
+
canvas.event_listeners.each do |event_name, listeners|
|
67
|
+
unless listeners.empty?
|
68
|
+
methods = listeners.map do |listener|
|
69
|
+
if listener.name
|
70
|
+
"#{listener.name}(#{listener.arguments.join(',')})"
|
71
|
+
end
|
72
|
+
end
|
73
|
+
attrs["on#{event_name}"] = methods.compact.join(';')
|
74
|
+
end
|
75
|
+
end
|
50
76
|
sio = StringIO.new
|
51
|
-
create_node(sio, 'svg',
|
52
|
-
:xmlns => "http://www.w3.org/2000/svg",
|
53
|
-
:version => @version,
|
54
|
-
:width => canvas.real_width,
|
55
|
-
:height => canvas.real_height,
|
56
|
-
:viewBox => canvas.view_box,
|
57
|
-
:preserveAspectRatio => canvas.preserve_aspect_ratio) {
|
77
|
+
create_node(sio, 'svg', attrs) {
|
58
78
|
@root_info = [sio.pos, @level]
|
79
|
+
i = 0
|
80
|
+
length = canvas.scripts.size
|
81
|
+
while i < length
|
82
|
+
script = canvas.scripts[i]
|
83
|
+
if script.include_external_file?
|
84
|
+
create_leaf_node(sio, 'script',
|
85
|
+
:'xlink:href' => script.href,
|
86
|
+
:type => script.content_type)
|
87
|
+
break if length <= (i += 1)
|
88
|
+
script = canvas.scripts[i]
|
89
|
+
else
|
90
|
+
content_type = script.content_type
|
91
|
+
create_cdata_node(sio, 'script',
|
92
|
+
:type => content_type) {
|
93
|
+
sio << script.body
|
94
|
+
if (i += 1) < length
|
95
|
+
script = canvas.scripts[i]
|
96
|
+
while !script.has_uri_reference? && content_type == script.content_type
|
97
|
+
sio << script.body
|
98
|
+
break if length <= (i += 1)
|
99
|
+
script = canvas.scripts[i]
|
100
|
+
end
|
101
|
+
end
|
102
|
+
}
|
103
|
+
end
|
104
|
+
end
|
59
105
|
canvas.child_elements.each do |element|
|
60
106
|
element.write_as(self, sio)
|
61
107
|
end
|
62
108
|
}
|
63
|
-
|
64
|
-
if @defs.empty?
|
109
|
+
if @defs.empty? && !@canvas.stylesheets.any?{|style| !style.include_external_file?}
|
65
110
|
io << sio.string
|
66
111
|
else
|
67
112
|
sio.rewind
|
@@ -70,6 +115,9 @@ module DYI #:nodoc:
|
|
70
115
|
_level = @level
|
71
116
|
@level = @root_info[1]
|
72
117
|
create_node(io, 'defs') {
|
118
|
+
@canvas.stylesheets.each do |stylesheet|
|
119
|
+
stylesheet.write_as(self, io)
|
120
|
+
end
|
73
121
|
@defs.each do |def_id, def_item|
|
74
122
|
def_item.write_as(self, io)
|
75
123
|
end
|
@@ -81,94 +129,198 @@ module DYI #:nodoc:
|
|
81
129
|
end
|
82
130
|
|
83
131
|
def write_rectangle(shape, io)
|
84
|
-
attrs = {:x=>shape.left,
|
132
|
+
attrs = {:x=>shape.left,
|
133
|
+
:y=>shape.top,
|
134
|
+
:width=>shape.width,
|
135
|
+
:height=>shape.height}
|
85
136
|
attrs.merge!(common_attributes(shape))
|
86
137
|
attrs[:rx] = shape.attributes[:rx] if shape.attributes[:rx]
|
87
138
|
attrs[:ry] = shape.attributes[:ry] if shape.attributes[:ry]
|
88
|
-
|
139
|
+
write_node(shape, io, attrs, 'rect')
|
89
140
|
end
|
90
141
|
|
91
142
|
def write_circle(shape, io)
|
92
143
|
attrs = {:cx=>shape.center.x, :cy=>shape.center.y, :r=>shape.radius}
|
93
144
|
attrs.merge!(common_attributes(shape))
|
94
|
-
|
145
|
+
write_node(shape, io, attrs, 'circle')
|
95
146
|
end
|
96
147
|
|
97
148
|
def write_ellipse(shape, io)
|
98
|
-
attrs = {:cx=>shape.center.x,
|
149
|
+
attrs = {:cx=>shape.center.x,
|
150
|
+
:cy=>shape.center.y,
|
151
|
+
:rx=>shape.radius_x,
|
152
|
+
:ry=>shape.radius_y}
|
99
153
|
attrs.merge!(common_attributes(shape))
|
100
|
-
|
154
|
+
write_node(shape, io, attrs, 'ellipse')
|
101
155
|
end
|
102
156
|
|
103
157
|
def write_line(shape, io)
|
104
|
-
attrs = {:x1 => shape.start_point.x,
|
158
|
+
attrs = {:x1 => shape.start_point.x,
|
159
|
+
:y1 => shape.start_point.y,
|
160
|
+
:x2 => shape.end_point.x,
|
161
|
+
:y2 => shape.end_point.y}
|
105
162
|
attrs.merge!(common_attributes(shape))
|
106
|
-
|
163
|
+
write_node(shape, io, attrs, 'line')
|
107
164
|
end
|
108
165
|
|
109
166
|
def write_polyline(shape, io)
|
110
167
|
attrs = {:points => shape.points.join(' ')}
|
111
168
|
attrs.merge!(common_attributes(shape))
|
112
|
-
|
169
|
+
write_node(shape, io, attrs, 'polyline')
|
113
170
|
end
|
114
171
|
|
115
172
|
def write_polygon(shape, io)
|
116
173
|
attrs = {:points => shape.points.join(' ')}
|
117
174
|
attrs.merge!(common_attributes(shape))
|
118
|
-
|
175
|
+
write_node(shape, io, attrs, 'polygon')
|
119
176
|
end
|
120
177
|
|
121
178
|
def write_path(shape, io)
|
122
179
|
attrs = {:d => shape.concise_path_data}
|
123
180
|
attrs.merge!(common_attributes(shape))
|
124
|
-
|
181
|
+
write_node(shape, io, attrs, 'path')
|
125
182
|
end
|
126
183
|
|
127
|
-
|
128
|
-
|
184
|
+
# @since 1.0.0
|
185
|
+
def write_image(shape, io)
|
186
|
+
attrs = {:x=>shape.left,
|
187
|
+
:y=>shape.top,
|
188
|
+
:width=>shape.width,
|
189
|
+
:height=>shape.height}
|
190
|
+
if shape.include_external_file?
|
191
|
+
attrs[:'xlink:href'] = shape.file_path
|
192
|
+
else
|
193
|
+
content_type = shape.attributes[:content_type].to_s
|
194
|
+
content_type = if content_type.empty?
|
195
|
+
shape.file_path =~ /\.([^\.]+)\z/
|
196
|
+
case $1
|
197
|
+
when 'png'
|
198
|
+
'image/png'
|
199
|
+
when 'jpg', 'jpeg'
|
200
|
+
'image/jpeg'
|
201
|
+
else
|
202
|
+
'image/svg+xml'
|
203
|
+
end
|
204
|
+
else
|
205
|
+
case content_type
|
206
|
+
when 'svg'
|
207
|
+
'image/svg+xml'
|
208
|
+
when 'png'
|
209
|
+
'image/png'
|
210
|
+
when 'jpeg'
|
211
|
+
'image/jpeg'
|
212
|
+
else
|
213
|
+
content_type
|
214
|
+
end
|
215
|
+
end
|
216
|
+
open(shape.file_path, 'rb') {|f|
|
217
|
+
content = f.read
|
218
|
+
attrs[:'xlink:href'] =
|
219
|
+
['data:', content_type, ";base64,\n", [content].pack('m')[0..-2]].join
|
220
|
+
}
|
221
|
+
end
|
129
222
|
attrs.merge!(common_attributes(shape))
|
130
|
-
attrs
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
attrs
|
139
|
-
|
140
|
-
|
223
|
+
attrs.reject! do |key, value|
|
224
|
+
key.to_s =~ /^(fill|stroke)/
|
225
|
+
end
|
226
|
+
attrs[:preserveAspectRatio] = shape.attributes[:preserve_aspect_ratio] || 'none'
|
227
|
+
write_node(shape, io, attrs, 'image')
|
228
|
+
end
|
229
|
+
|
230
|
+
def write_text(shape, io)
|
231
|
+
attrs = common_attributes(shape)
|
232
|
+
if shape.attributes[:text_decoration]
|
233
|
+
attrs[:"text-decoration"] = shape.attributes[:text_decoration]
|
234
|
+
end
|
235
|
+
if shape.attributes[:text_anchor]
|
236
|
+
attrs[:"text-anchor"] = shape.attributes[:text_anchor]
|
237
|
+
end
|
238
|
+
if shape.attributes[:writing_mode]
|
239
|
+
attrs[:"writing-mode"] = shape.attributes[:writing_mode]
|
240
|
+
end
|
241
|
+
if shape.attributes[:textLength]
|
242
|
+
attrs[:textLength] = shape.attributes[:textLength]
|
243
|
+
end
|
244
|
+
if shape.attributes[:lengthAdjust]
|
245
|
+
attrs[:lengthAdjust] = shape.attributes[:lengthAdjust]
|
246
|
+
end
|
247
|
+
|
141
248
|
text = shape.formated_text
|
142
|
-
if text =~ /(\r\n|\n|\r)/
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
249
|
+
if text =~ /(\r\n|\n|\r)/ || shape.animate? || shape.attributes[:show_border]
|
250
|
+
shape.publish_id if shape.attributes[:show_border]
|
251
|
+
create_text_group = proc {|tag_name, attrs|
|
252
|
+
create_node(io, tag_name, attrs) {
|
253
|
+
create_border_node(shape, io)
|
254
|
+
line_number = 0
|
255
|
+
txt_attrs = {:x => shape.point.x, :y => shape.point.y}
|
256
|
+
# FIXME: Implementation of baseline attribute are not suitable
|
257
|
+
case shape.attributes[:alignment_baseline]
|
258
|
+
when 'top' then txt_attrs[:y] += shape.font_height * 0.85
|
259
|
+
when 'middle' then txt_attrs[:y] += shape.font_height * 0.35
|
260
|
+
when 'bottom' then txt_attrs[:y] -= shape.font_height * 0.15
|
261
|
+
end
|
262
|
+
txt_attrs[:id] = shape.id + '_%02d' % line_number if shape.inner_id
|
263
|
+
current_line = $` || text
|
264
|
+
create_leaf_node(io, 'text', current_line.strip, txt_attrs)
|
265
|
+
$'.each_line do |line|
|
266
|
+
line_number += 1
|
267
|
+
txt_attrs = {:x => txt_attrs[:x], :y => txt_attrs[:y] + shape.dy}
|
268
|
+
txt_attrs[:id] = shape.id + '_%02d' % line_number if shape.inner_id
|
269
|
+
create_leaf_node(io, 'text', line.strip, txt_attrs)
|
270
|
+
end if $'
|
271
|
+
write_animations(shape, io)
|
272
|
+
}
|
148
273
|
}
|
274
|
+
if shape.anchor_href
|
275
|
+
attrs[:'xlink:href'] = shape.anchor_href
|
276
|
+
attrs[:target] = shape.anchor_target if shape.anchor_target
|
277
|
+
create_text_group.call('a', attrs)
|
278
|
+
else
|
279
|
+
create_text_group.call('g', attrs)
|
280
|
+
end
|
149
281
|
else
|
150
|
-
|
282
|
+
create_text_group = proc {
|
283
|
+
attrs.merge!(:x => shape.point.x, :y => shape.point.y)
|
284
|
+
# FIXME: Implementation of baseline attribute are not suitable
|
285
|
+
case shape.attributes[:alignment_baseline]
|
286
|
+
when 'top' then attrs[:y] += shape.font_height * 0.85
|
287
|
+
when 'middle' then attrs[:y] += shape.font_height * 0.35
|
288
|
+
when 'bottom' then attrs[:y] -= shape.font_height * 0.15
|
289
|
+
end
|
290
|
+
create_leaf_node(io, 'text', text, attrs)
|
291
|
+
}
|
292
|
+
if shape.anchor_href
|
293
|
+
link_attrs = {:'xlink:href' => shape.anchor_href}
|
294
|
+
link_attrs[:target] = shape.anchor_target if shape.anchor_target
|
295
|
+
create_node(io, 'a', link_attrs) {
|
296
|
+
create_text_group.call
|
297
|
+
}
|
298
|
+
else
|
299
|
+
create_text_group.call
|
300
|
+
end
|
151
301
|
end
|
152
302
|
end
|
153
303
|
|
154
304
|
def write_group(shape, io)
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
305
|
+
unless shape.child_elements.empty?
|
306
|
+
attrs = common_attributes(shape)
|
307
|
+
write_node(shape, io, attrs, 'g') {
|
308
|
+
shape.child_elements.each do |element|
|
309
|
+
element.write_as(self, io)
|
310
|
+
end
|
311
|
+
}
|
312
|
+
end
|
160
313
|
end
|
161
314
|
|
162
315
|
def write_linear_gradient(shape, io)
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
create_node(io, 'linearGradient', attr) {
|
316
|
+
attrs = {:id => @defs.find{|key, value| value==shape}[0],
|
317
|
+
:gradientUnit => 'objectBoundingBox',
|
318
|
+
:x1 => shape.start_point[0],
|
319
|
+
:y1 => shape.start_point[1],
|
320
|
+
:x2 => shape.stop_point[0],
|
321
|
+
:y2 => shape.stop_point[1]}
|
322
|
+
attrs[:"spreadMethod"] = shape.spread_method if shape.spread_method
|
323
|
+
create_node(io, 'linearGradient', attrs) {
|
172
324
|
shape.child_elements.each do |element|
|
173
325
|
element.write_as(self, io)
|
174
326
|
end
|
@@ -183,43 +335,232 @@ module DYI #:nodoc:
|
|
183
335
|
end
|
184
336
|
|
185
337
|
def write_clipping(clipping, io)
|
186
|
-
|
187
|
-
create_node(io, 'clipPath',
|
338
|
+
attrs = {:id => clipping.id}
|
339
|
+
create_node(io, 'clipPath', attrs) {
|
188
340
|
clipping.shapes.each_with_index do |shape, i|
|
189
341
|
shape.write_as(self, io)
|
190
342
|
end
|
191
343
|
}
|
192
344
|
end
|
193
345
|
|
346
|
+
# @since 1.0.0
|
347
|
+
def write_painting_animation(anim, shape, io)
|
348
|
+
anim.animation_attributes.each do |anim_attr, (from_value, to_value)|
|
349
|
+
attrs = {:attributeName => name_to_attribute(anim_attr),
|
350
|
+
:attributeType => 'CSS'}
|
351
|
+
attrs[:from] = from_value if from_value
|
352
|
+
attrs[:to] = to_value
|
353
|
+
merge_anim_attributes(anim, shape, attrs)
|
354
|
+
if anim.duration && anim.duration != 0
|
355
|
+
create_leaf_node(io, 'animate', attrs)
|
356
|
+
else
|
357
|
+
create_leaf_node(io, 'set', attrs)
|
358
|
+
end
|
359
|
+
end
|
360
|
+
end
|
361
|
+
|
362
|
+
# @since 1.0.0
|
363
|
+
def write_transform_animation(anim, shape, io)
|
364
|
+
attrs = {:attributeName => 'transform',
|
365
|
+
:attributeType => 'XML',
|
366
|
+
:type => anim.type}
|
367
|
+
if anim.from.is_a?(Array)
|
368
|
+
attrs[:from] = anim.from.join(',')
|
369
|
+
elsif anim.from
|
370
|
+
attrs[:from] = anim.from.to_s
|
371
|
+
end
|
372
|
+
attrs[:to] = anim.to.is_a?(Array) ? anim.to.join(',') : anim.to.to_s
|
373
|
+
merge_anim_attributes(anim, shape, attrs)
|
374
|
+
if anim.duration && anim.duration != 0
|
375
|
+
create_leaf_node(io, 'animateTransform', attrs)
|
376
|
+
else
|
377
|
+
create_leaf_node(io, 'set', attrs)
|
378
|
+
end
|
379
|
+
end
|
380
|
+
|
381
|
+
# @since 1.0.0
|
382
|
+
def write_script(script, io)
|
383
|
+
if script.include_external_file?
|
384
|
+
create_leaf_node(io, 'script',
|
385
|
+
:'xlink:href' => script.href,
|
386
|
+
:type => script.content_type)
|
387
|
+
else
|
388
|
+
io << script.body
|
389
|
+
end
|
390
|
+
end
|
391
|
+
|
392
|
+
# @since 1.0.0
|
393
|
+
def write_style(stylesheet, io)
|
394
|
+
unless stylesheet.include_external_file?
|
395
|
+
attrs = {:type => stylesheet.content_type}
|
396
|
+
attrs[:media] = stylesheet.media if stylesheet.media
|
397
|
+
attrs[:title] = stylesheet.title if stylesheet.title
|
398
|
+
create_cdata_node(io, 'style', attrs){
|
399
|
+
io << stylesheet.body
|
400
|
+
}
|
401
|
+
end
|
402
|
+
end
|
403
|
+
|
194
404
|
private
|
195
405
|
|
406
|
+
# @since 1.0.0
|
407
|
+
def write_node(shape, io, attrs, tag_name, &create_child_node)
|
408
|
+
if shape.anchor_href
|
409
|
+
link_attrs = {:'xlink:href' => shape.anchor_href}
|
410
|
+
link_attrs[:target] = shape.anchor_target if shape.anchor_target
|
411
|
+
create_node(io, 'a', link_attrs) {
|
412
|
+
write_shape_node(shape, io, attrs, tag_name, &create_child_node)
|
413
|
+
}
|
414
|
+
else
|
415
|
+
write_shape_node(shape, io, attrs, tag_name, &create_child_node)
|
416
|
+
end
|
417
|
+
end
|
418
|
+
|
419
|
+
# @since 1.0.0
|
420
|
+
def write_shape_node(shape, io, attrs, tag_name, &create_child_node)
|
421
|
+
if shape.animate? || block_given?
|
422
|
+
create_node(io, tag_name, attrs) {
|
423
|
+
yield if block_given?
|
424
|
+
write_animations(shape, io)
|
425
|
+
}
|
426
|
+
else
|
427
|
+
create_leaf_node(io, tag_name, attrs)
|
428
|
+
end
|
429
|
+
end
|
430
|
+
|
431
|
+
# @since 1.0.0
|
432
|
+
def write_animations(shape, io)
|
433
|
+
if shape.animate?
|
434
|
+
shape.animations.each do |anim|
|
435
|
+
anim.write_as(self, shape, io)
|
436
|
+
end
|
437
|
+
end
|
438
|
+
end
|
439
|
+
|
440
|
+
# @since 1.0.0
|
441
|
+
def create_border_node(shape, io)
|
442
|
+
if shape.attributes[:show_border]
|
443
|
+
attrs = {:id => shape.id + '_bd', :x => 0, :y => 0, :width => 0, :height => 0}
|
444
|
+
attrs[:rx] = shape.attributes[:border_rx] if shape.attributes[:border_rx]
|
445
|
+
attrs[:ry] = shape.attributes[:border_ry] if shape.attributes[:border_ry]
|
446
|
+
attrs[:fill] = shape.attributes[:background_color] || Color.new('white')
|
447
|
+
attrs[:stroke] = shape.attributes[:border_color] || Color.new('black')
|
448
|
+
attrs[:'stroke-width'] = shape.attributes[:border_width] || 1
|
449
|
+
create_leaf_node(io, 'rect', attrs)
|
450
|
+
end
|
451
|
+
end
|
452
|
+
|
453
|
+
# Examines the descendant elements of the canvas to collect the
|
454
|
+
# information of the elements.
|
455
|
+
# @return [void]
|
456
|
+
# @since 1.0.0
|
457
|
+
def pre_write
|
458
|
+
if @canvas.scripts.any?{|script| script.has_uri_reference?}
|
459
|
+
@xmlns[:'xmlns:xlink'] = "http://www.w3.org/1999/xlink"
|
460
|
+
end
|
461
|
+
examin_descendant_elements(@canvas)
|
462
|
+
end
|
463
|
+
|
464
|
+
# @since 1.0.0
|
465
|
+
def examin_descendant_elements(element)
|
466
|
+
if element.has_uri_reference?
|
467
|
+
@xmlns[:'xmlns:xlink'] = "http://www.w3.org/1999/xlink"
|
468
|
+
end
|
469
|
+
if element.respond_to?(:clipping) && element.clipping
|
470
|
+
unless @defs.value?(element.clipping)
|
471
|
+
def_id = element.clipping.id
|
472
|
+
@defs[def_id] = element.clipping
|
473
|
+
end
|
474
|
+
end
|
475
|
+
if element.respond_to?(:attributes) && element.attributes[:show_border]
|
476
|
+
@text_border_elements << element
|
477
|
+
end
|
478
|
+
element.child_elements.each do |child_element|
|
479
|
+
examin_descendant_elements(child_element)
|
480
|
+
end
|
481
|
+
end
|
482
|
+
|
483
|
+
# @since 1.0.0
|
484
|
+
def anim_duration(timecount)
|
485
|
+
return nil if timecount.nil? || timecount < 0
|
486
|
+
return '0s' if timecount == 0
|
487
|
+
timecount_ms = (timecount * 1000).to_i
|
488
|
+
if timecount_ms % (1000 * 60 * 60) == 0
|
489
|
+
'%ih' % (timecount_ms / (1000 * 60 * 60))
|
490
|
+
elsif timecount_ms % (1000 * 60) == 0
|
491
|
+
'%imin' % (timecount_ms / (1000 * 60))
|
492
|
+
elsif timecount_ms % 1000 == 0
|
493
|
+
'%is' % (timecount_ms / 1000)
|
494
|
+
else
|
495
|
+
'%ims' % timecount_ms
|
496
|
+
end
|
497
|
+
end
|
498
|
+
|
499
|
+
# @since 1.0.0
|
500
|
+
def amin_event(shape, event)
|
501
|
+
return nil unless event
|
502
|
+
if shape && shape == event.target
|
503
|
+
event.event_name.to_s
|
504
|
+
else
|
505
|
+
[event.target.id.gsub(/([\.\-\:])/, '\\\\\\1'), event.event_name.to_s].join('.')
|
506
|
+
end
|
507
|
+
end
|
508
|
+
|
509
|
+
# @since 1.0.0
|
510
|
+
def anim_period(shape, event, offset)
|
511
|
+
[amin_event(shape, event), anim_duration(offset)].compact.join('+')
|
512
|
+
end
|
513
|
+
|
514
|
+
# @return [void]
|
515
|
+
# @since 1.0.0
|
516
|
+
def merge_anim_attributes(anim, shape, attrs) #:nodoc:
|
517
|
+
attrs[:dur] = anim_duration(anim.duration) if anim.duration && anim.duration != 0
|
518
|
+
if anim.begin_event || anim.begin_offset
|
519
|
+
attrs[:begin] = anim_period(shape, anim.begin_event, anim.begin_offset)
|
520
|
+
else
|
521
|
+
attrs[:begin] = '0s'
|
522
|
+
end
|
523
|
+
if anim.end_event || anim.end_offset
|
524
|
+
attrs[:end] = anim_period(shape, anim.end_event, anim.end_offset)
|
525
|
+
end
|
526
|
+
attrs[:fill] = anim.fill if anim.fill
|
527
|
+
attrs[:additive] = anim.additive if anim.additive
|
528
|
+
attrs[:restart] = anim.restart if anim.restart
|
529
|
+
end
|
530
|
+
|
196
531
|
def name_to_attribute(name) #:nodoc:
|
197
532
|
name.to_s.gsub(/_/,'-').to_sym
|
198
533
|
end
|
199
534
|
|
200
535
|
def common_attributes(shape) #:nodoc:
|
201
536
|
attributes = {}
|
202
|
-
|
537
|
+
create_style(shape, attributes)
|
538
|
+
attributes[:class] = shape.css_class unless shape.css_class.empty?
|
203
539
|
transform = create_transform(shape)
|
204
|
-
clip_path = create_clip_path(shape)
|
205
|
-
attributes[:style] = style if style
|
206
540
|
attributes[:transform] = transform if transform
|
207
|
-
attributes[:'clip-path'] =
|
541
|
+
attributes[:'clip-path'] = "url(##{shape.clipping.id})" if shape.clipping
|
542
|
+
attributes[:id] = shape.id if shape.inner_id
|
543
|
+
attributes[:'pointer-events'] = 'all' if shape.event_target?
|
208
544
|
attributes
|
209
545
|
end
|
210
546
|
|
211
|
-
def create_style(shape) #:nodoc:
|
547
|
+
def create_style(shape, attributes) #:nodoc:
|
212
548
|
styles = {}
|
213
|
-
if shape.
|
549
|
+
if shape.font && !shape.font.empty?
|
214
550
|
styles.merge!(shape.font.attributes)
|
215
551
|
end
|
216
|
-
if shape.
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
552
|
+
if shape.painting && !shape.painting.empty?
|
553
|
+
painting_attrs = shape.painting.attributes
|
554
|
+
if painting_attrs.key?(:stroke_dasharray)
|
555
|
+
painting_attrs[:stroke_dasharray] =
|
556
|
+
painting_attrs[:stroke_dasharray].join(',')
|
557
|
+
end
|
558
|
+
painting_attrs[:fill] = 'none' unless painting_attrs.key?(:fill)
|
559
|
+
styles.merge!(painting_attrs)
|
560
|
+
end
|
561
|
+
styles.each do |key, value|
|
562
|
+
attributes[attribute_name(key)] = attribute_string(value)
|
221
563
|
end
|
222
|
-
styles.empty? ? nil : styles.map {|key, value| "#{attribute_name(key)}:#{attribute_string(value)}"}.join(';')
|
223
564
|
end
|
224
565
|
|
225
566
|
def attribute_string(value) #:nodoc:
|
@@ -232,12 +573,6 @@ module DYI #:nodoc:
|
|
232
573
|
end
|
233
574
|
end
|
234
575
|
|
235
|
-
def create_clip_path(shape) #:nodoc:
|
236
|
-
if shape.respond_to?(:clipping) && shape.clipping
|
237
|
-
"url(##{add_defs(shape.clipping)})"
|
238
|
-
end
|
239
|
-
end
|
240
|
-
|
241
576
|
def add_defs(value) #:nodoc:
|
242
577
|
@defs.each do |def_id, def_item|
|
243
578
|
return def_id if def_item == value
|
@@ -255,5 +590,26 @@ module DYI #:nodoc:
|
|
255
590
|
key.to_s.gsub(/_/,'-')
|
256
591
|
end
|
257
592
|
end
|
593
|
+
|
594
|
+
class PngFormatter
|
595
|
+
def save(file_name, options={})
|
596
|
+
tmp_svg_file = [file_name, Time.now.strftime('%Y%m%d%H%M%S'), 'tmp'].join('.')
|
597
|
+
@svg_formatter.save(tmp_svg_file, options)
|
598
|
+
`rsvg-convert -o #{file_name} #{tmp_svg_file}`
|
599
|
+
File.delete(tmp_svg_file)
|
600
|
+
end
|
601
|
+
|
602
|
+
def string
|
603
|
+
tmp_svg_file = [Time.now.strftime('%Y%m%d%H%M%S'), 'tmp'].join('.')
|
604
|
+
@svg_formatter.save(tmp_svg_file)
|
605
|
+
png_data = `rsvg-convert #{tmp_svg_file}`
|
606
|
+
File.delete(tmp_svg_file)
|
607
|
+
png_date
|
608
|
+
end
|
609
|
+
|
610
|
+
def initialize(*args)
|
611
|
+
@svg_formatter = SvgFormatter.new(*args)
|
612
|
+
end
|
613
|
+
end
|
258
614
|
end
|
259
615
|
end
|