dyi 1.2.1 → 1.3.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 +11 -0
- data/README +2 -3
- data/examples/animation.rb +104 -28
- data/examples/clock.rb +152 -0
- data/examples/data/money.csv +13 -12
- data/examples/external_files/asian_map.png +0 -0
- data/examples/external_files/xslt.xsl +71 -0
- data/examples/letter.rb +125 -0
- data/examples/line_and_bar.rb +32 -19
- data/examples/logo.rb +1 -62
- data/examples/map.rb +30705 -0
- data/examples/panther.rb +1602 -0
- data/examples/pie_chart.rb +27 -20
- data/examples/rainbow.rb +31 -0
- data/examples/simple_animation.rb +28 -0
- data/examples/thumbnail.rb +73 -0
- data/examples/xslt.rb +9 -0
- data/lib/dyi.rb +71 -2
- data/lib/dyi/animation.rb +270 -79
- data/lib/dyi/canvas.rb +10 -1
- data/lib/dyi/chart/line_chart.rb +75 -27
- data/lib/dyi/drawing/color_effect.rb +117 -0
- data/lib/dyi/drawing/pen.rb +6 -2
- data/lib/dyi/element.rb +11 -10
- data/lib/dyi/event.rb +3 -3
- data/lib/dyi/formatter/svg_formatter.rb +113 -25
- data/lib/dyi/shape.rb +2 -0
- data/lib/dyi/shape/base.rb +42 -3
- data/lib/dyi/shape/graphical_template.rb +106 -0
- data/lib/dyi/shape/reused_shape.rb +99 -0
- metadata +14 -3
- data/examples/class_diagram.rb +0 -154
@@ -62,13 +62,13 @@ module DYI
|
|
62
62
|
@canvas.add_initialize_script(Script::EcmaScript::DomLevel2.draw_text_border(*@text_border_elements))
|
63
63
|
end
|
64
64
|
attrs = @xmlns.merge(:version => @version,
|
65
|
-
:width => canvas.real_width,
|
66
|
-
:height => canvas.real_height,
|
67
|
-
:viewBox => canvas.view_box,
|
68
|
-
:preserveAspectRatio => canvas.preserve_aspect_ratio)
|
69
|
-
attrs[:'pointer-events'] = 'none' if canvas.receive_event?
|
70
|
-
attrs[:class] = canvas.css_class if canvas.css_class
|
71
|
-
canvas.event_listeners.each do |event_name, listeners|
|
65
|
+
:width => @canvas.real_width,
|
66
|
+
:height => @canvas.real_height,
|
67
|
+
:viewBox => @canvas.view_box,
|
68
|
+
:preserveAspectRatio => @canvas.preserve_aspect_ratio)
|
69
|
+
attrs[:'pointer-events'] = 'none' if @canvas.receive_event?
|
70
|
+
attrs[:class] = @canvas.css_class if @canvas.css_class
|
71
|
+
@canvas.event_listeners.each do |event_name, listeners|
|
72
72
|
unless listeners.empty?
|
73
73
|
methods = listeners.map do |listener|
|
74
74
|
if listener.name
|
@@ -81,43 +81,42 @@ module DYI
|
|
81
81
|
end
|
82
82
|
sio = StringIO.new
|
83
83
|
create_node(sio, 'svg', attrs) {
|
84
|
-
create_leaf_node(sio, 'title', canvas.title) if canvas.title
|
85
|
-
create_leaf_node(sio, 'desc', canvas.description) if canvas.description
|
86
|
-
if canvas.metadata
|
84
|
+
create_leaf_node(sio, 'title', @canvas.title) if @canvas.title
|
85
|
+
create_leaf_node(sio, 'desc', @canvas.description) if @canvas.description
|
86
|
+
if @canvas.metadata
|
87
87
|
create_cdata_node(sio, 'metadata'){
|
88
88
|
puts_line(sio) {
|
89
|
-
write_metadata(canvas.metadata, sio)
|
89
|
+
write_metadata(@canvas.metadata, sio)
|
90
90
|
}
|
91
91
|
}
|
92
92
|
end
|
93
93
|
@root_info = [sio.pos, @level]
|
94
94
|
i = 0
|
95
|
-
length = canvas.scripts.size
|
95
|
+
length = @canvas.scripts.size
|
96
96
|
while i < length
|
97
|
-
script = canvas.scripts[i]
|
97
|
+
script = @canvas.scripts[i]
|
98
98
|
if script.include_external_file?
|
99
99
|
create_leaf_node(sio, 'script',
|
100
100
|
:'xlink:href' => script.href,
|
101
101
|
:type => script.content_type)
|
102
102
|
break if length <= (i += 1)
|
103
|
-
script = canvas.scripts[i]
|
104
103
|
else
|
105
104
|
content_type = script.content_type
|
106
105
|
create_cdata_node(sio, 'script',
|
107
106
|
:type => content_type) {
|
108
107
|
sio << script.contents
|
109
108
|
if (i += 1) < length
|
110
|
-
script = canvas.scripts[i]
|
109
|
+
script = @canvas.scripts[i]
|
111
110
|
while !script.has_uri_reference? && content_type == script.content_type
|
112
111
|
sio << script.contents
|
113
112
|
break if length <= (i += 1)
|
114
|
-
script = canvas.scripts[i]
|
113
|
+
script = @canvas.scripts[i]
|
115
114
|
end
|
116
115
|
end
|
117
116
|
}
|
118
117
|
end
|
119
118
|
end
|
120
|
-
canvas.child_elements.each do |element|
|
119
|
+
@canvas.child_elements.each do |element|
|
121
120
|
element.write_as(self, sio)
|
122
121
|
end
|
123
122
|
}
|
@@ -330,6 +329,31 @@ module DYI
|
|
330
329
|
end
|
331
330
|
end
|
332
331
|
|
332
|
+
# @since 1.3.0
|
333
|
+
def write_template(shape, io)
|
334
|
+
unless shape.child_elements.empty?
|
335
|
+
attrs = {:viewBox => shape.view_box,
|
336
|
+
:preserveAspectRatio => shape.preserve_aspect_ratio}
|
337
|
+
attrs.merge!(common_attributes(shape))
|
338
|
+
write_node(shape, io, attrs, 'symbol') {
|
339
|
+
shape.child_elements.each do |element|
|
340
|
+
element.write_as(self, io)
|
341
|
+
end
|
342
|
+
}
|
343
|
+
end
|
344
|
+
end
|
345
|
+
|
346
|
+
# @since 1.3.0
|
347
|
+
def write_reused_shape(shape, io)
|
348
|
+
attrs = {:x=>shape.left,
|
349
|
+
:y=>shape.top,
|
350
|
+
:'xlink:href'=>"##{shape.source_element.id}"}
|
351
|
+
attrs[:width] = shape.width if shape.width
|
352
|
+
attrs[:height] = shape.height if shape.height
|
353
|
+
attrs.merge!(common_attributes(shape))
|
354
|
+
write_node(shape, io, attrs, 'use')
|
355
|
+
end
|
356
|
+
|
333
357
|
def write_linear_gradient(shape, io)
|
334
358
|
attrs = {:id => @defs.find{|key, value| value==shape}[0],
|
335
359
|
:gradientUnit => 'objectBoundingBox',
|
@@ -345,6 +369,23 @@ module DYI
|
|
345
369
|
}
|
346
370
|
end
|
347
371
|
|
372
|
+
# @since 1.3.0
|
373
|
+
def write_radial_gradient(shape, io)
|
374
|
+
attrs = {:id => @defs.find{|key, value| value==shape}[0],
|
375
|
+
:gradientUnit => 'objectBoundingBox',
|
376
|
+
:cx => shape.center_point.x,
|
377
|
+
:cy => shape.center_point.y,
|
378
|
+
:r => shape.radius,
|
379
|
+
:fx => shape.focal_point.x,
|
380
|
+
:fy => shape.focal_point.y}
|
381
|
+
attrs[:"spreadMethod"] = shape.spread_method if shape.spread_method
|
382
|
+
create_node(io, 'radialGradient', attrs) {
|
383
|
+
shape.child_elements.each do |element|
|
384
|
+
element.write_as(self, io)
|
385
|
+
end
|
386
|
+
}
|
387
|
+
end
|
388
|
+
|
348
389
|
def write_gradient_stop(shape, io)
|
349
390
|
attrs = {:offset=>shape.offset}
|
350
391
|
attrs[:"stop-color"] = shape.color if shape.color
|
@@ -380,11 +421,24 @@ module DYI
|
|
380
421
|
|
381
422
|
# @since 1.0.0
|
382
423
|
def write_painting_animation(anim, shape, io)
|
383
|
-
anim.animation_attributes.each do |anim_attr,
|
424
|
+
anim.animation_attributes.each do |anim_attr, values|
|
384
425
|
attrs = {:attributeName => name_to_attribute(anim_attr),
|
385
426
|
:attributeType => 'CSS'}
|
386
|
-
|
387
|
-
|
427
|
+
if values.size == 2
|
428
|
+
attrs[:from] = values[0] if values[0]
|
429
|
+
attrs[:to] = values[1]
|
430
|
+
else
|
431
|
+
attrs[:values] = values.join(';')
|
432
|
+
key_times = [0].push(*anim.relay_times[0, anim.relays.size])
|
433
|
+
if anim.relay_times.size < anim.relays.size
|
434
|
+
step = (1.0 - key_times.last) / (anim.relays.size - anim.relay_times.size + 1)
|
435
|
+
(anim.relays.size - anim.relay_times.size).times do |i|
|
436
|
+
key_times << key_times.last + step
|
437
|
+
end
|
438
|
+
end
|
439
|
+
key_times << 1
|
440
|
+
attrs[:keyTimes] = key_times.map{|num| num.strfnum('0.###')}.join(';')
|
441
|
+
end
|
388
442
|
merge_anim_attributes(anim, shape, attrs)
|
389
443
|
if anim.duration && anim.duration != 0
|
390
444
|
create_leaf_node(io, 'animate', attrs)
|
@@ -399,12 +453,26 @@ module DYI
|
|
399
453
|
attrs = {:attributeName => 'transform',
|
400
454
|
:attributeType => 'XML',
|
401
455
|
:type => anim.type}
|
402
|
-
if anim.
|
403
|
-
|
404
|
-
|
405
|
-
|
456
|
+
if anim.relays.empty?
|
457
|
+
if anim.from.is_a?(Array)
|
458
|
+
attrs[:from] = anim.from.join(',')
|
459
|
+
elsif anim.from
|
460
|
+
attrs[:from] = anim.from.to_s
|
461
|
+
end
|
462
|
+
attrs[:to] = anim.to.is_a?(Array) ? anim.to.join(',') : anim.to.to_s
|
463
|
+
else
|
464
|
+
values = [anim.from].push(*anim.relays).push(anim.to)
|
465
|
+
attrs[:values] = values.map{|v| v.is_a?(Array) ? v.join(',') : v.to_s}.join(';')
|
466
|
+
key_times = [0].push(*anim.relay_times[0, anim.relays.size])
|
467
|
+
if anim.relay_times.size < anim.relays.size
|
468
|
+
step = (1.0 - key_times.last) / (anim.relays.size - anim.relay_times.size + 1)
|
469
|
+
(anim.relays.size - anim.relay_times.size).times do |i|
|
470
|
+
key_times << key_times.last + step
|
471
|
+
end
|
472
|
+
end
|
473
|
+
key_times << 1
|
474
|
+
attrs[:keyTimes] = key_times.map{|num| num.strfnum('0.###')}.join(';')
|
406
475
|
end
|
407
|
-
attrs[:to] = anim.to.is_a?(Array) ? anim.to.join(',') : anim.to.to_s
|
408
476
|
merge_anim_attributes(anim, shape, attrs)
|
409
477
|
if anim.duration && anim.duration != 0
|
410
478
|
create_leaf_node(io, 'animateTransform', attrs)
|
@@ -586,6 +654,13 @@ module DYI
|
|
586
654
|
end
|
587
655
|
end
|
588
656
|
end
|
657
|
+
if element.respond_to?(:source_element) && element.source_element
|
658
|
+
source_element = element.source_element
|
659
|
+
unless source_element.canvas == @canvas || @defs.value?(source_element)
|
660
|
+
def_id = source_element.id || (source_element.id = @canvas.publish_shape_id)
|
661
|
+
@defs[def_id] = source_element
|
662
|
+
end
|
663
|
+
end
|
589
664
|
element.child_elements.each do |child_element|
|
590
665
|
examin_descendant_elements(child_element)
|
591
666
|
end
|
@@ -636,6 +711,19 @@ module DYI
|
|
636
711
|
attrs[:fill] = anim.fill if anim.fill
|
637
712
|
attrs[:additive] = anim.additive if anim.additive
|
638
713
|
attrs[:restart] = anim.restart if anim.restart
|
714
|
+
attrs[:calcMode] = anim.calc_mode if anim.calc_mode
|
715
|
+
if anim.repeat_count
|
716
|
+
count = anim.repeat_count
|
717
|
+
attrs[:repeatCount] =
|
718
|
+
if count.zero? || count.infinite?
|
719
|
+
'indefinite'
|
720
|
+
else
|
721
|
+
anim.repeat_count
|
722
|
+
end
|
723
|
+
end
|
724
|
+
if anim.key_splines && !anim.key_splines.empty?
|
725
|
+
attrs[:keySplines] = anim.key_splines.each_slice(4).map{|nums| nums.join(' ')}.join(';')
|
726
|
+
end
|
639
727
|
end
|
640
728
|
|
641
729
|
def name_to_attribute(name)
|
data/lib/dyi/shape.rb
CHANGED
data/lib/dyi/shape/base.rb
CHANGED
@@ -390,6 +390,8 @@ module DYI
|
|
390
390
|
@anchor_target = options.delete(:anchor_target)
|
391
391
|
self.css_class = options.delete(:css_class)
|
392
392
|
self.id = options.delete(:id) if options[:id]
|
393
|
+
self.description = options.delete(:description) if options[:description]
|
394
|
+
self.title = options.delete(:title) if options[:title]
|
393
395
|
options
|
394
396
|
end
|
395
397
|
end
|
@@ -404,14 +406,16 @@ module DYI
|
|
404
406
|
# Returns heigth of the rectangle.
|
405
407
|
attr_length :height
|
406
408
|
|
407
|
-
# @param [Coordinate] left_top a coordinate of
|
409
|
+
# @param [Coordinate] left_top a left-top coordinate of the rectangle
|
408
410
|
# @param [Length] width width of the rectangle
|
409
411
|
# @param [Length] heigth heigth of the rectangle
|
410
|
-
# @option options [Painting] :painting painting status of
|
412
|
+
# @option options [Painting] :painting painting status of this shape
|
411
413
|
# @option options [Length] :rx the x-axis radius of the ellipse for
|
412
414
|
# rounded the rectangle
|
413
415
|
# @option options [Length] :ry the y-axis radius of the ellipse for
|
414
416
|
# rounded the rectangle
|
417
|
+
# @option options [String] :description the description of this shape
|
418
|
+
# @option options [String] :title the title of this shape
|
415
419
|
def initialize(left_top, width, height, options={})
|
416
420
|
width = Length.new(width)
|
417
421
|
height = Length.new(height)
|
@@ -468,7 +472,7 @@ module DYI
|
|
468
472
|
# @param [Coordinate] left_top a coordinate of a corner of the rectangle
|
469
473
|
# @param [Length] width width of the rectangle
|
470
474
|
# @param [Length] heigth heigth of the rectangle
|
471
|
-
# @option options [Painting] :painting painting status of the
|
475
|
+
# @option options [Painting] :painting painting status of the shape
|
472
476
|
# @option options [Length] :rx the x-axis radius of the ellipse for
|
473
477
|
# rounded the rectangle
|
474
478
|
# @option options [Length] :ry the y-axis radius of the ellipse for
|
@@ -508,6 +512,11 @@ module DYI
|
|
508
512
|
# Returns a radius of the circle.
|
509
513
|
attr_length :radius
|
510
514
|
|
515
|
+
# @param [Coordinate] center a center coordinate of the circle
|
516
|
+
# @param [Length] radius a radius length of the circle
|
517
|
+
# @option options [Painting] :painting painting status of this shape
|
518
|
+
# @option options [String] :description the description of this shape
|
519
|
+
# @option options [String] :title the title of this shape
|
511
520
|
def initialize(center, radius, options={})
|
512
521
|
@center = Coordinate.new(center)
|
513
522
|
@radius = Length.new(radius).abs
|
@@ -556,6 +565,12 @@ module DYI
|
|
556
565
|
attr_coordinate :center
|
557
566
|
attr_length :radius_x, :radius_y
|
558
567
|
|
568
|
+
# @param [Coordinate] center a center coordinate of the ellipse
|
569
|
+
# @param [Length] radius_x an x-axis radius of the ellipse
|
570
|
+
# @param [Length] radius_y a y-axis radius of the ellipse
|
571
|
+
# @option options [Painting] :painting painting status of this shape
|
572
|
+
# @option options [String] :description the description of this shape
|
573
|
+
# @option options [String] :title the title of this shape
|
559
574
|
def initialize(center, radius_x, radius_y, options={})
|
560
575
|
@center = Coordinate.new(center)
|
561
576
|
@radius_x = Length.new(radius_x).abs
|
@@ -605,6 +620,11 @@ module DYI
|
|
605
620
|
include Markable
|
606
621
|
attr_coordinate :start_point, :end_point
|
607
622
|
|
623
|
+
# @param [Coordinate] start_point a start coordinate of the line
|
624
|
+
# @param [Coordinate] end_point an end coordinate of the line
|
625
|
+
# @option options [Painting] :painting painting status of this shape
|
626
|
+
# @option options [String] :description the description of this shape
|
627
|
+
# @option options [String] :title the title of this shape
|
608
628
|
def initialize(start_point, end_point, options={})
|
609
629
|
@start_point = Coordinate.new(start_point)
|
610
630
|
@end_point = Coordinate.new(end_point)
|
@@ -651,6 +671,10 @@ module DYI
|
|
651
671
|
class Polyline < Base
|
652
672
|
include Markable
|
653
673
|
|
674
|
+
# @param [Coordinate] start_point a start coordinate of the shape
|
675
|
+
# @option options [Painting] :painting painting status of this shape
|
676
|
+
# @option options [String] :description the description of this shape
|
677
|
+
# @option options [String] :title the title of this shape
|
654
678
|
def initialize(start_point, options={})
|
655
679
|
@points = [Coordinate.new(start_point)]
|
656
680
|
@attributes = init_attributes(options)
|
@@ -715,6 +739,13 @@ module DYI
|
|
715
739
|
class Image < Rectangle
|
716
740
|
attr_reader :file_path
|
717
741
|
|
742
|
+
# @param [Coordinate] left_top a left-top coordinate of the image
|
743
|
+
# @param [Length] width width of the image
|
744
|
+
# @param [Length] heigth heigth of the image
|
745
|
+
# @param [String] file_path a file path of the image
|
746
|
+
# @option options [Painting] :painting painting status of this shape
|
747
|
+
# @option options [String] :description the description of this shape
|
748
|
+
# @option options [String] :title the title of this shape
|
718
749
|
def initialize(left_top, width, height, file_path, options={})
|
719
750
|
super(left_top, width, height, options)
|
720
751
|
@file_path = file_path
|
@@ -745,6 +776,12 @@ module DYI
|
|
745
776
|
attr_accessor :text
|
746
777
|
attr_reader :format
|
747
778
|
|
779
|
+
# @param [Coordinate] point a start coordinate of the text
|
780
|
+
# @param [String] text a text that is displayed
|
781
|
+
# @option options [Painting] :painting painting status of the shape
|
782
|
+
# @option options [Font] :font font status of the text
|
783
|
+
# @option options [String] :description the description of this shape
|
784
|
+
# @option options [String] :title the title of this shape
|
748
785
|
def initialize(point, text=nil, options={})
|
749
786
|
@point = Coordinate.new(point || [0,0])
|
750
787
|
@text = text
|
@@ -796,6 +833,8 @@ module DYI
|
|
796
833
|
class ShapeGroup < Base
|
797
834
|
attr_reader :child_elements
|
798
835
|
|
836
|
+
# @option options [String] :description the description of this group
|
837
|
+
# @option options [String] :title the title of this group
|
799
838
|
def initialize(options={})
|
800
839
|
@attributes = init_attributes(options)
|
801
840
|
@child_elements = []
|
@@ -0,0 +1,106 @@
|
|
1
|
+
# -*- encoding: UTF-8 -*-
|
2
|
+
|
3
|
+
# Copyright (c) 2009-2012 Sound-F Co., Ltd. All rights reserved.
|
4
|
+
#
|
5
|
+
# Author:: Mamoru Yuo
|
6
|
+
#
|
7
|
+
# This file is part of DYI.
|
8
|
+
#
|
9
|
+
# DYI is free software: you can redistribute it and/or modify it
|
10
|
+
# under the terms of the GNU General Public License as published by
|
11
|
+
# the Free Software Foundation, either version 3 of the License, or
|
12
|
+
# (at your option) any later version.
|
13
|
+
#
|
14
|
+
# DYI is distributed in the hope that it will be useful,
|
15
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
16
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
17
|
+
# GNU General Public License for more details.
|
18
|
+
#
|
19
|
+
# You should have received a copy of the GNU General Public License
|
20
|
+
# along with DYI. If not, see <http://www.gnu.org/licenses/>.
|
21
|
+
|
22
|
+
#
|
23
|
+
module DYI
|
24
|
+
|
25
|
+
module Shape
|
26
|
+
|
27
|
+
# The body of Vector-Image. This class is a container for all graphical
|
28
|
+
# elements that make up the image.
|
29
|
+
# @since 1.3.0
|
30
|
+
class GraphicalTemplate < Base
|
31
|
+
|
32
|
+
# @private
|
33
|
+
IMPLEMENT_ATTRIBUTES = [:view_box, :preserve_aspect_ratio]
|
34
|
+
|
35
|
+
# Returns width of the vector-image on user unit.
|
36
|
+
attr_length :width
|
37
|
+
|
38
|
+
# Returns heigth of the vector-image on user unit.
|
39
|
+
attr_length :height
|
40
|
+
|
41
|
+
# @attribute view_box
|
42
|
+
# Returns the value of the view_box.
|
43
|
+
# @return [String]
|
44
|
+
#+++
|
45
|
+
# @attribute preserve_aspect_ratio
|
46
|
+
# Returns the value of the preserve_aspect_ratio.
|
47
|
+
# @return [String] the value of preserve_aspect_ratio
|
48
|
+
attr_reader *IMPLEMENT_ATTRIBUTES
|
49
|
+
|
50
|
+
# Returns an array of child elements.
|
51
|
+
# @return [Array<Element>] an array of child elements
|
52
|
+
attr_reader :child_elements
|
53
|
+
|
54
|
+
# Returns a metadata object that the image has.
|
55
|
+
# @return [Object] a metadata object that the image has.
|
56
|
+
attr_accessor :metadata
|
57
|
+
|
58
|
+
# @param [Length] width width of the canvas on user unit
|
59
|
+
# @param [Length] height height of the canvas on user unit
|
60
|
+
# @param [Length] real_width width of the image. When this value
|
61
|
+
# is nil, uses a value that equals value of width parameter.
|
62
|
+
# @param [Length] real_height height of the image. When this value
|
63
|
+
# is nil, uses a value that equals value of height parameter.
|
64
|
+
# @param [String] preserve_aspect_ratio value that indicates
|
65
|
+
# whether or not to force uniform scaling
|
66
|
+
# @option options [String] :css_class CSS class of body element
|
67
|
+
def initialize(width, height,
|
68
|
+
preserve_aspect_ratio='none', options={})
|
69
|
+
self.width = width
|
70
|
+
self.height = height
|
71
|
+
@view_box = "0 0 #{width} #{height}"
|
72
|
+
@preserve_aspect_ratio = preserve_aspect_ratio
|
73
|
+
@child_elements = []
|
74
|
+
self.css_class = options[:css_class]
|
75
|
+
end
|
76
|
+
|
77
|
+
# Returns whether this instance is root element of the shape.
|
78
|
+
# @return [Boolean] always true.
|
79
|
+
def root_element?
|
80
|
+
false
|
81
|
+
end
|
82
|
+
|
83
|
+
# Writes image on io object.
|
84
|
+
# @param [Formatter::Base] formatter an object that defines the image format
|
85
|
+
# @param [IO] io an io to be written
|
86
|
+
def write_as(formatter, io=$>)
|
87
|
+
formatter.write_template(self, io)
|
88
|
+
end
|
89
|
+
|
90
|
+
def instantiate_on(parent, left_top, options={})
|
91
|
+
Shape::ReusedShape.new(self, left_top, options).draw_on(parent)
|
92
|
+
end
|
93
|
+
|
94
|
+
# Returns optional attributes.
|
95
|
+
# @return [Hash] optional attributes
|
96
|
+
def attributes
|
97
|
+
IMPLEMENT_ATTRIBUTES.inject({}) do |hash, attribute|
|
98
|
+
variable_name = '@' + attribute.to_s.split(/(?=[A-Z])/).map{|str| str.downcase}.join('_')
|
99
|
+
value = instance_variable_get(variable_name)
|
100
|
+
hash[attribute] = value.to_s if value
|
101
|
+
hash
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|