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.
@@ -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, (from_value, to_value)|
424
+ anim.animation_attributes.each do |anim_attr, values|
384
425
  attrs = {:attributeName => name_to_attribute(anim_attr),
385
426
  :attributeType => 'CSS'}
386
- attrs[:from] = from_value if from_value
387
- attrs[:to] = to_value
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.from.is_a?(Array)
403
- attrs[:from] = anim.from.join(',')
404
- elsif anim.from
405
- attrs[:from] = anim.from.to_s
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)
@@ -24,6 +24,8 @@
24
24
  base
25
25
  path
26
26
  marker
27
+ reused_shape
28
+ graphical_template
27
29
 
28
30
  ).each do |file_name|
29
31
  require File.join(File.dirname(__FILE__), 'shape', file_name)
@@ -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 a corner of the rectangle
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 the rectangle
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 rectangle
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