Module: Rubyvis::SvgScene

Includes:
REXML
Defined in:
lib/rubyvis/scene/svg_bar.rb,
lib/rubyvis/scene/svg_dot.rb,
lib/rubyvis/scene/svg_area.rb,
lib/rubyvis/scene/svg_line.rb,
lib/rubyvis/scene/svg_rule.rb,
lib/rubyvis/scene/svg_image.rb,
lib/rubyvis/scene/svg_label.rb,
lib/rubyvis/scene/svg_panel.rb,
lib/rubyvis/scene/svg_wedge.rb,
lib/rubyvis/scene/svg_scene.rb

Class Method Summary collapse

Class Method Details

.append(e, scenes, index) ⇒ Object



86
87
88
89
90
91
92
93
94
# File 'lib/rubyvis/scene/svg_scene.rb', line 86

def self.append(e,scenes,index)
  e._scene=OpenStruct.new({:scenes=>scenes, :index=>index})
  #e=self.title

  if(!e.parent)
    scenes._g.add_element(e)
  end
  return e.next_sibling_node
end

.area(scenes) ⇒ Object



3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
# File 'lib/rubyvis/scene/svg_area.rb', line 3

def self.area(scenes)
  e = scenes._g.elements[1]
  return e if scenes.size==0
  s=scenes[0]
  # segmented */
  return self.area_segment(scenes) if (s.segmented) 
  # visible
  # 
  return e if (!s.visible)
  
  fill = s.fill_style
  stroke = s.stroke_style
  
  return e if (fill.opacity==0 and stroke.opacity==0) 
  # /** @private Computes the straight path for the range [i, j]. */
  path=lambda {|ii,j|
    p1 = []
    p2 = [];
    k=j
    (ii..k).each {|i|
      si = scenes[i]
      sj = scenes[j]
      pi = "#{si.left},#{si.top}"
      pj = "#{(sj.left + sj.width)},#{(sj.top + sj.height)}"

      #/* interpolate */
      if (i < k) 
        sk = scenes[i + 1]
        sl = scenes[j - 1]
        case (s.interpolate) 
          when "step-before"
            pi = pi+"V#{sk.top}"
            pj = pj+"H#{sl.left + sl.width}"
          
          when "step-after"
            pi = pi+"H#{sk.left}"
            pj = pj+"V#{sl.top + sl.height}"
        end
      end

      p1.push(pi);
      p2.push(pj);
      j=j-1
    }
    (p1+p2).join("L");
  }
    
  # @private Computes the curved path for the range [i, j]. */
  path_curve=lambda {|ii, j|
    pointsT = []
    pointsB = []
    pathT=nil
    pathB=nil
    
    
    k=j
    (ii..k).each {|i|
      sj = scenes[j];
      pointsT.push(scenes[i])
      pointsB.push(OpenStruct.new({:left=> sj.left + sj.width, :top=> sj.top + sj.height}))
      j=j-1
    }

    if (s.interpolate == "basis") 
      pathT = Rubyvis.SvgScene.curve_basis(pointsT);
      pathB = Rubyvis.SvgScene.curve_basis(pointsB);
    elsif (s.interpolate == "cardinal") 
        pathT = Rubyvis.SvgScene.curve_cardinal(pointsT, s.tension);
        pathB = Rubyvis.SvgScene.curve_cardinal(pointsB, s.tension);
    elsif # monotone
      pathT = Rubyvis.SvgScene.curve_monotone(pointsT);
      pathB = Rubyvis.SvgScene.curve_monotone(pointsB);
    end

    "#{pointsT[0].left },#{ pointsT[0].top }#{ pathT }L#{ pointsB[0].left},#{pointsB[0].top}#{pathB}"
      }
    
      #/* points */
      d = []
      si=nil
      sj=nil
      i=0
      while(i<scenes.size) 
        si = scenes[i]
        continue if (si.width==0 and si.height==0)
        j=0
        (i+1).upto(scenes.size-1) {|jj|
          j=jj; sj = scenes[jj];
          break if (si.width==0 and si.height==0)
        }
        
        i=i-1 if (i!=0 and (s.interpolate != "step-after"))
        j=j+1 if ((j < scenes.size) and (s.interpolate != "step-before"))
        d.push(((j - i > 2 and (s.interpolate == "basis" or s.interpolate == "cardinal" or s.interpolate == "monotone")) ? path_curve : path).call(i, j - 1))
        i = j - 1
        i+=1
      end
      
      return e if d.size==0
    
      e = self.expect(e, "path", {
          "shape-rendering"=> s.antialias ? nil : "crispEdges",
          "pointer-events"=> s.events,
          "cursor"=> s.cursor,
          "d"=> "M" + d.join("ZM") + "Z",
          "fill"=> fill.color,
          "fill-opacity"=> fill.opacity==0 ? nil : fill.opacity,
          "stroke"=> stroke.color,
          "stroke-opacity"=> stroke.opacity==0 ? nil : stroke.opacity,
          "stroke-width"=> stroke.opacity!=0 ? s.line_width / self.scale : nil
        });
      return self.append(e, scenes, 0);
end

.area_segment(scenes) ⇒ Object



117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
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
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
# File 'lib/rubyvis/scene/svg_area.rb', line 117

def self.area_segment(scenes)
      
      e = scenes._g.elements[1]
      s = scenes[0]
      pathsT=[]
      pathsB=[]
      
      if (s.interpolate == "basis" or s.interpolate == "cardinal" or s.interpolate == "monotone") 
        pointsT = []
        pointsB = []
        n=scenes.size
        n.times {|i|
          sj = scenes[n - i - 1]
          pointsT.push(scenes[i])
          pointsB.push(OpenStruct.new({:left=> sj.left + sj.width, :top=> sj.top + sj.height}));
        }
    
        if (s.interpolate == "basis") 
          pathT = Rubyvis.SvgScene.curve_basis_segments(pointsT);
          pathB = Rubyvis.SvgScene.curve_basis_segments(pointsB);
        elsif (s.interpolate == "cardinal") 
            pathT = Rubyvis.SvgScene.curve_cardinal_segments(pointsT, s.tension);
            pathB = Rubyvis.SvgScene.curve_cardinal_segments(pointsB, s.tension);
        elsif # monotone
          pathT = Rubyvis.SvgScene.curve_monotone_segments(pointsT);
          pathB = Rubyvis.SvgScene.curve_monotone_segments(pointsB);
        end
      end
      n=scenes.size-1
      n.times {|i|
        
        s1 = scenes[i]
        s2 = scenes[i + 1]
    
        # /* visible */
        next if (!s1.visible or !s2.visible)
        
        fill = s.fill_style
        stroke = s.stroke_style            
        next e if (fill.opacity==0 and stroke.opacity==0) 
        d=nil
        if (pathsT) 
          pathT = pathsT[i]
          pb=pathsB[n - i - 1]
          pathB = "L" + pb[1,pb.size-1]
          d = pathT + pathB + "Z";
        else 
          #/* interpolate */
          si = s1
          sj = s2
          
          case (s1.interpolate) 
            when "step-before"
              si = s2
            when "step-after"
              sj = s1
          end
          
    
          #/* path */
          d = "M#{s1.left},#{si.top}L#{s2.left},#{sj.top }L#{s2.left + s2.width},#{sj.top + sj.height}L#{s1.left + s1.width},#{si.top + si.height}Z"
        end
    
        e = self.expect(e, "path", {
            "shape-rendering"=> s1.antialias ? null : "crispEdges",
            "pointer-events"=> s1.events,
            "cursor"=> s1.cursor,
            "d"=> d,
            "fill"=> fill.color,
            "fill-opacity"=> fill.opacity==0 ? nil : fill.opacity,
          "stroke"=> stroke.color,
          "stroke-opacity"=> stroke.opacity==0 ? nil : stroke.opacity,
          "stroke-width"=> stroke.opacity!=0 ? s1.line_width / self.scale : nil
          });
        e = self.append(e, scenes, i);
      }
      return e;
end

.bar(scenes) ⇒ Object



3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
# File 'lib/rubyvis/scene/svg_bar.rb', line 3

def self.bar(scenes)
  e=scenes._g.elements[1]
  scenes.each_with_index do |s,i|
    next unless s.visible
    fill=s.fill_style
    stroke=s.stroke_style
    next if(fill.opacity==0.0 and stroke.opacity==0.0)
    e=SvgScene.expect(e,'rect', {
      "shape-rendering"=> s.antialias ? nil : "crispEdges",
      "pointer-events"=> s.events,
      "cursor"=> s.cursor,
      "x"=> s.left,
      "y"=> s.top,
      "width"=> [1E-10, s.width].max,
      "height"=> [1E-10, s.height].max,
      "fill"=> fill.color,
      "fill-opacity"=> (fill.opacity==0) ? nil : fill.opacity,
      "stroke"=> stroke.color,
      "stroke-opacity"=> (stroke.opacity==0) ? nil : stroke.opacity,
      "stroke-width"=> stroke.opacity ? s.line_width / SvgScene.scale.to_f : nil
    })

    e=SvgScene.append(e,scenes,i)

  end
  e
end

.create(type) ⇒ Object



76
77
78
79
80
81
82
83
84
# File 'lib/rubyvis/scene/svg_scene.rb', line 76

def self.create(type)
  el=Element.new "#{type}"
  if type=='svg'
    el.add_namespace(self.svg)
    #el.add_namespace("xmlns:xmlns", self.xmlns)
    el.add_namespace("xmlns:xlink", self.xlink)
  end
  el
end

.dot(scenes) ⇒ Object



3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
# File 'lib/rubyvis/scene/svg_dot.rb', line 3

def self.dot(scenes)
  e = scenes._g.elements[1]
  scenes.each_with_index {|s,i|
  s = scenes[i];
  
  # visible */
  next if !s.visible
  fill = s.fill_style
  stroke = s.stroke_style
  next if (fill.opacity==0 and stroke.opacity==0)
  
  #/* points */
  radius = s.shape_radius
  path = nil
  case s.shape
  when 'cross'
    path = "M#{-radius},#{-radius}L#{radius},#{radius}M#{radius},#{ -radius}L#{ -radius},#{radius}"
  when "triangle"
    h = radius
    w = radius * 1.1547; # // 2 / Math.sqrt(3)
    path = "M0,#{h}L#{w},#{-h} #{-w},#{-h}Z"
  when  "diamond"
    radius=radius* Math::sqrt(2)
    path = "M0,#{-radius}L#{radius},0 0,#{radius} #{-radius},0Z";
  when  "square"
    path = "M#{-radius},#{-radius}L#{radius},#{-radius} #{radius},#{radius} #{-radius},#{radius}Z"
  when  "tick"
    path = "M0,0L0,#{-s.shapeSize}"
  when  "bar"
    path = "M0,#{s.shape_size / 2.0}L0,#{-(s.shapeSize / 2.0)}"

  end
  
  #/* Use <circle> for circles, <path> for everything else. */
  svg = {
  "shape-rendering"=> s.antialias ? nil : "crispEdges",
  "pointer-events"=> s.events,
  "cursor"=> s.cursor,
  "fill"=> fill.color,
  "fill-opacity"=> (fill.opacity==0) ? nil :fill.opacity,
  "stroke"=> stroke.color,
  "stroke-opacity"=> (stroke.opacity==0) ? nil : stroke.opacity,
  "stroke-width"=> (stroke.opacity!=0) ? s.line_width / self.scale : nil
  }
  
  if (path) 
      svg["transform"] = "translate(#{s.left},#{s.top})"
      if (s.shape_angle) 
        svg["transform"] += " rotate(#{180 * s.shape_angle / Math.PI})";
      end
    svg["d"] = path
    e = self.expect(e, "path", svg);
  else 
    svg["cx"] = s.left;
    svg["cy"] = s.top;
    svg["r"] = radius;
    e = self.expect(e, "circle", svg);
  end
  e = self.append(e, scenes, i);
  }
  return e
end

.expect(e, type, attributes, style = nil) ⇒ Object



96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
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/rubyvis/scene/svg_scene.rb', line 96

def self.expect(e, type, attributes, style=nil)

  if (e)
    e = e.elements[1] if (e.name == "a")
    if (e.name != type)
      n = self.create(type);
      e.parent.replace_child(e, n);
      e = n
    end
  else
    e = self.create(type)
  end
  attributes.each {|name,value|
    value = nil if (value == self.implicit[:svg][name])
    if (value.nil?)
      e.delete_attribute(name)
    else
      e.attributes[name]=value
    end
  }
  
  if(style)
    base_style=e.attributes['style']
    base_style||=""
    array_styles={}
    base_style.split(";").each {|v|
      v=~/\s*(.+)\s*:\s*(.+)/
      array_styles[$1]=$2
    }
    style.each {|name,value|
      value=nil if value==self.implicit[:css][name]
      if (value.nil?)
        array_styles.delete(name)
      else
        
        array_styles[name]=value
      end
    }
    if array_styles.size>0
      e.attributes["style"]=array_styles.map {|k,v| "#{k}:#{v}"}.join(";")
    end
  end
  e
end

.fill(e, scenes, i) ⇒ Object



79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
# File 'lib/rubyvis/scene/svg_panel.rb', line 79

def self.fill(e,scenes,i)
  s=scenes[i]
  fill=s.fill_style
  if(fill.opacity>0 or s.events=='all')
    e=SvgScene.expect(e,'rect', {
      "shape-rendering"=> s.antialias ? nil : "crispEdges",
      "pointer-events"=> s.events,
      "cursor"=> s.cursor,
      "x"=> s.left,
      "y"=> s.top,
      "width"=> s.width,
      "height"=> s.height,
      "fill"=> fill.color,
      "fill-opacity"=> fill.opacity,
      "stroke"=> nil
    })
    e=SvgScene.append(e,scenes, i)
  end
  e
end

.image(scenes) ⇒ Object



3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
# File 'lib/rubyvis/scene/svg_image.rb', line 3

def self.image(scenes)
  e=scenes._g.elements[1]
  scenes.each_with_index do |s,i|
    next unless s.visible
    e=self.fill(e,scenes,i)
    if s.image
      raise "Not implemented yet"
    else
      e = self.expect(e, "image", {
      "preserveAspectRatio"=> "none",
      "cursor"=> s.cursor,
      "x"=> s.left,
      "y"=> s.top,
      "width"=> s.width,
      "height"=> s.height
      })
      
      e.add_attribute("xlink:href", s.url);
    end
    e = self.append(e, scenes, i);
    
    #/* stroke */
    e = self.stroke(e, scenes, i);
  end
  e
end

.implicitObject



40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
# File 'lib/rubyvis/scene/svg_scene.rb', line 40

def self.implicit
  svg={
    "shape-rendering"=> "auto",
    "pointer-events"=> "painted",
    "x"=> 0,
    "y"=> 0,
    "dy"=> 0,
    "text-anchor"=> "start",
    "transform"=> "translate(0,0)",
    #"fill"=> "none",
    "fill-opacity"=> 1,
    "stroke"=> "none",
    "stroke-opacity"=> 1,
    "stroke-width"=> 1.5,
    "stroke-linejoin"=> "miter"
  }
  css={"font"=>"10px sans-serif"}

  {:svg=>svg,:css=>css}
end

.label(scenes) ⇒ Object



3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
# File 'lib/rubyvis/scene/svg_label.rb', line 3

def self.label(scenes)
  e=scenes._g.elements[1]
  scenes.each_with_index do |s,i|
    next unless s.visible
    fill=s.text_style
    next if(fill.opacity==0 or s.text.nil?)
    x=0
    y=0
    dy=0
    anchor='start'
    case s.text_baseline
      when 'middle'
        dy=".35em"
      when "top"
        dy = ".71em"
        y = s.text_margin
      when "bottom"
        y = "-" + s.text_margin.to_s
    end
    
    case s.text_align
      when 'right'
        anchor = "end"
        x = "-" + s.text_margin.to_s
      when "center"
        anchor = "middle"
      when "left"
        x = s.text_margin
    end
    e=SvgScene.expect(e,'text', {
      "pointer-events"=> s.events,
      "cursor"=> s.cursor,
      "x"=> x,
      "y"=> y,
      "dy"=> dy,
      "transform"=> "translate(#{s.left},#{s.top})" + (s.text_angle!=0 ? " rotate(" + (180 * s.text_angle / Math::PI).to_s + ")" : "") + (self.scale != 1 ? " scale(" + 1 / self.scale + ")" : ""),
      "fill"=> fill.color,
      "fill-opacity"=> fill.opacity==0 ? nil : fill.opacity,
      "text-anchor"=> anchor
    }, {
    "font"=> s.font, "text-shadow"=> s.text_shadow, "text-decoration"=> s.text_decoration      })
    e.text=s.text


    e=SvgScene.append(e,scenes,i)

  end
  e
end

.line(scenes) ⇒ Object



3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
# File 'lib/rubyvis/scene/svg_line.rb', line 3

def self.line(scenes)
  e=scenes._g.elements[1]
  return e if (scenes.size < 2)
  s = scenes[0]
  # segmented */
  return self.line_segment(scenes) if (s.segmented)

  #/* visible */
  return e if (!s.visible)
  fill = s.fill_style
  stroke = s.stroke_style

  return e if (fill.opacity==0.0 and  stroke.opacity==0.0)
  #/* points */

  d = "M" + s.left.to_s + "," + s.top.to_s

  if (scenes.size > 2 and (s.interpolate == "basis" or s.interpolate == "cardinal" or s.interpolate == "monotone"))
    case (s.interpolate)
    when "basis"
      d = d+ curve_basis(scenes)
    when "cardinal"
      d = d+curve_cardinal(scenes, s.tension)
    when "monotone"
      d = d+curve_monotone(scenes)
    end

  else
    (1...scenes.size).each {|i|
      d+= path_segment(scenes[i-1],scenes[i])
    }
  end

  e = SvgScene.expect(e, "path", {
    "shape-rendering"=> s.antialias ? nil : "crispEdges",
    "pointer-events"=> s.events,
    "cursor"=> s.cursor,
    "d"=> d,
    "fill"=> fill.color,
    "fill-opacity"=> (fill.opacity==0.0) ? nil : fill.opacity,
    "stroke"=> stroke.color,
    "stroke-opacity"=> (stroke.opacity==0.0) ? nil : stroke.opacity,
    "stroke-width"=> (stroke.opacity>0) ? s.line_width / self.scale : nil,
    "stroke-linejoin"=> s.line_join
  });
  return SvgScene.append(e, scenes, 0);
end

.line_intersect(o1, d1, o2, d2) ⇒ Object

/** @private Line-line intersection, per Akenine-Moller 16.16.1. */



132
133
134
# File 'lib/rubyvis/scene/svg_line.rb', line 132

def self.line_intersect(o1, d1, o2, d2)
  return o1.plus(d1.times(o2.minus(o1).dot(d2.perp()) / d1.dot(d2.perp())));
end

.line_segment(scenes) ⇒ Object



51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
# File 'lib/rubyvis/scene/svg_line.rb', line 51

def self.line_segment(scenes)

  e=scenes._g.elements[1]

  s = scenes[0];
  paths=nil
  case s.interpolate
  when "basis"
    paths = curve_basis_segments(scenes)
  when "cardinal"
    paths=curve_cardinal_segments(scenes, s.tension)
  when "monotone"
    paths = curve_monotone_segments(scenes)
  end

  (scenes.length-1).times {|i|

    s1 = scenes[i]
    s2 = scenes[i + 1];

    #/* visible */
    next if (!s1.visible and !s2.visible)

    stroke = s1.stroke_style
    fill = Rubyvis.Color.transparent

    next if stroke.opacity==0.0

    #/* interpolate */
    d=nil
    if ((s1.interpolate == "linear") and (s1.lineJoin == "miter"))
      fill = stroke;
      stroke = Rubyvis.Color.transparent;
      d = path_join(scenes[i - 1], s1, s2, scenes[i + 2]);
    elsif(paths)
      d = paths[i];
    else
      d = "M" + s1.left + "," + s1.top + path_segment(s1, s2);
    end

    e = SvgScene.expect(e, "path", {
      "shape-rendering"=> s1.antialias ? nil : "crispEdges",
      "pointer-events"=> s1.events,
      "cursor"=> s1.cursor,
      "d"=> d,
      "fill"=> fill.color,
      "fill-opacity"=> (fill.opacity==0.0) ? nil : fill.opacity,
      "stroke"=> stroke.color,
      "stroke-opacity"=> (stroke.opacity==0.0) ? nil : stroke.opacity,
      "stroke-width"=> stroke.opacity>0 ? s1.line_width / self.scale : nil,
      "stroke-linejoin"=> s1.line_join
    });
    e = SvgScene.append(e, scenes, i);
  }
  return e
end

.panel(scenes) ⇒ Object



3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
# File 'lib/rubyvis/scene/svg_panel.rb', line 3

def self.panel(scenes)
  puts " -> panel: #{scenes.inspect}" if $DEBUG
  g=scenes._g
  e=(g.nil?) ? nil : g.elements[1]
  if g
    e=g.elements[1]
  end
  scenes.each_with_index do |s,i|
    next unless s.visible

    if(!scenes.parent)
      if g and g.parent!=s.canvas
        g=s.canvas.elements[1]
        e=(@g.nil?) ? nil : @g.elements[1]
      end
      if(!g)
        g=s.canvas.add_element(self.create('svg'))
        g.attributes["font-size"]="10px"
        g.attributes["font-family"]="sans-serif"
        g.attributes["fill"]="none"
        g.attributes["stroke"]="none"
        g.attributes["stroke-width"]=1.5
        e=g.elements[1]
      end
      scenes._g=g
      #p s
      g.attributes['width']=s.width+s.left+s.right
      g.attributes['height']=s.height+s.top+s.bottom
    end
    if s.overflow=='hidden'
      id=Rubyvis.id.to_s(36)
      c=self.expect(e,'g',{'clip-path'=>'url(#'+id+')'});
      g.add_element(c) if(!c.parent)
      scenes._g=g=c
      e=c.elements[1]
      e=self.expect(e,'clipPath',{'id'=>id})
      r=(e.elements[1]) ? e.elements[1] : e.add_element(self.create('rect'))
      r.attributes['x']=s.left
      r.attributes['y']=s.top
      r.attributes['width']=s.width
      r.attributes['height']=s.height
      g.add_element(e) if !e.parent
      e=e.next_sibling_node

    end
    e=self.fill(e,scenes, i)
    k=self.scale
    t=s.transform

    x=s.left+t.x
    y=s.top+t.y


    SvgScene.scale=SvgScene.scale*t.k

    s.children.each_with_index {|child, i2|
      child._g=e=SvgScene.expect(e, "g", {
        "transform"=> "translate(" + x.to_s + "," + y.to_s + ")" + (t.k != 1 ? " scale(" + t.k.to_s + ")" : "")
      })
      SvgScene.update_all(child)
      g.add_element(e) if(!e.parent)
      e=e.next_sibling_node
    }
    SvgScene.scale=k
    e=SvgScene.stroke(e,scenes,i)
    if (s.overflow=='hidden')
      scenes._g=g=c.parent
      e=c.next_sibling_node
    end
  end
  return e
  
end

.path_join(s0, s1, s2, s3) ⇒ Object

/** @private Returns the miter join path for the specified points. */



137
138
139
140
141
142
143
144
145
146
147
148
149
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
176
177
178
179
180
181
# File 'lib/rubyvis/scene/svg_line.rb', line 137

def self.path_join(s0, s1, s2, s3)
  #
  # P1-P2 is the current line segment. V is a vector that is perpendicular to
  # the line segment, and has length lineWidth / 2. ABCD forms the initial
  # bounding box of the line segment (i.e., the line segment if we were to do
  # no joins).
  #

  p1 = Rubyvis.vector(s1.left, s1.top)

  p2 = Rubyvis.vector(s2.left, s2.top)

  p = p2.minus(p1)

  v = p.perp().norm()

  w = v.times(s1.lineWidth / (2 * this.scale))

  a = p1.plus(w)
  b = p2.plus(w)
  c = p2.minus(w)
  d = p1.minus(w)

  #/*
  # * Start join. P0 is the previous line segment's start point. We define the
  # * cutting plane as the average of the vector perpendicular to P0-P1, and
  # * the vector perpendicular to P1-P2. This insures that the cross-section of
  # * the line on the cutting plane is equal if the line-width is unchanged.
  # * Note that we don't implement miter limits, so these can get wild.
  # */
  if (s0 and s0.visible)
    v1 = p1.minus(s0.left, s0.top).perp().norm().plus(v);
    d = line_intersect(p1, v1, d, p);
    a = line_intersect(p1, v1, a, p);
  end

  #/* Similarly, for end join. */
  if (s3 && s3.visible)
    v2 = Rubyvis.vector(s3.left, s3.top).minus(p2).perp().norm().plus(v);
    c = line_intersect(p2, v2, c, p);
    b = line_intersect(p2, v2, b, p);
  end

  return "M" + a.x + "," + a.y+ "L" + b.x + "," + b.y+ " " + c.x + "," + c.y+ " " + d.x + "," + d.y
end

.path_segment(s1, s2) ⇒ Object

/** @private Returns the path segment for the specified points. */



110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
# File 'lib/rubyvis/scene/svg_line.rb', line 110

def self.path_segment(s1, s2)
  l = 1; # sweep-flag
  case (s1.interpolate)
  when "polar-reverse"
    l = 0;
  when "polar"
    dx = s2.left - s1.left,
    dy = s2.top - s1.top
    e = 1 - s1.eccentricity
    r = Math.sqrt(dx * dx + dy * dy) / (2 * e)
    if !((e<=0) and (e>1))
      return "A#{r},#{r} 0 0,#{l} #{s2.left},#{s2.top}"
    end
  when "step-before"
    return "V#{s2.top}H#{s2.left}"
  when "step-after"
    return "H#{s2.left}V#{s2.top}"
  end
  return "L#{s2.left},#{s2.top}"
end

.remove_siblings(e) ⇒ Object



69
70
71
72
73
74
75
# File 'lib/rubyvis/scene/svg_scene.rb', line 69

def self.remove_siblings(e)
  while(e)
    n=e.next_sibling_node
    e.remove
    e=n
  end
end

.rule(scenes) ⇒ Object



3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
# File 'lib/rubyvis/scene/svg_rule.rb', line 3

def self.rule(scenes)
  e=scenes._g.elements[1]
  scenes.each_with_index do |s,i|
    next unless s.visible
    stroke=s.stroke_style
    next if(stroke.opacity==0.0)
    e=SvgScene.expect(e,'line', {
      "shape-rendering"=> s.antialias ? nil : "crispEdges",
      "pointer-events"=> s.events,
      "cursor"=> s.cursor,
      "x1"=> s.left,
      "y1"=> s.top,
      'x2'=> s.left+s.width,
      'y2'=>s.top+s.height,
      "stroke"=> stroke.color,
      "stroke-opacity"=> stroke.opacity,
      "stroke-width"=> s.line_width / self.scale
    })

    e=SvgScene.append(e,scenes,i)

  end
  e
end

.scaleObject



34
35
36
# File 'lib/rubyvis/scene/svg_scene.rb', line 34

def self.scale
  @scale
end

.scale=(v) ⇒ Object



37
38
39
# File 'lib/rubyvis/scene/svg_scene.rb', line 37

def self.scale=(v)
  @scale=v
end

.stroke(e, scenes, i) ⇒ Object



101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
# File 'lib/rubyvis/scene/svg_panel.rb', line 101

def self.stroke(e, scenes, i)
  s = scenes[i]
  stroke = s.stroke_style
  if (stroke.opacity>0 or s.events == "all")
    e = self.expect(e, "rect", {
      "shape-rendering"=> s.antialias ? nil : "crispEdges",
      "pointer-events"=> s.events == "all" ? "stroke" : s.events,
      "cursor"=> s.cursor,
      "x"=> s.left,
      "y"=> s.top,
      "width"=> [1E-10, s.width].max,
      "height"=>[1E-10, s.height].max,
      "fill"=>"none",
      "stroke"=> stroke.color,
      "stroke-opacity"=> stroke.opacity,
      "stroke-width"=> s.line_width / self.scale.to_f
    });
    e = self.append(e, scenes, i);
  end
  return e
end

.svgObject



21
22
23
# File 'lib/rubyvis/scene/svg_scene.rb', line 21

def self.svg
  "http://www.w3.org/2000/svg"
end

.update_all(scenes) ⇒ Object



61
62
63
64
65
66
67
68
# File 'lib/rubyvis/scene/svg_scene.rb', line 61

def self.update_all(scenes)
  puts "update_all: #{scenes.inspect}" if $DEBUG
  if (scenes.size>0 and scenes[0].reverse and scenes.type!='line' and scenes.type!='area')
    scenes=scenes.reverse
  end
  
  self.remove_siblings(self.send(scenes.type, scenes))
end

.wedge(scenes) ⇒ Object



3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
# File 'lib/rubyvis/scene/svg_wedge.rb', line 3

def self.wedge(scenes)
  e=scenes._g.elements[1]
  scenes.each_with_index do |s,i|
    next unless s.visible
    fill=s.fill_style
    stroke=s.stroke_style
    next if(fill.opacity==0.0 and stroke.opacity==0.0)
    # /* points */
    
    r1 = s.inner_radius
    r2 = s.outer_radius
    a = (s.angle).abs
    _p=nil
    
    if (a >= 2 * Math::PI) 
      if (r1) 
        _p = "M0,#{r2 }A#{r2},#{r2} 0 1,1 0,#{-r2}A#{r2 },#{r2 } 0 1,1 0,#{r2}M0,#{r1}A#{r1},#{r1} 0 1,1 0,#{-r1}A#{r1},#{r1} 0 1,1 0,#{r1 }Z"
      else 
        _p = "M0,#{r2}A#{r2},#{r2} 0 1,1 0,#{-r2}A#{r2},#{r2} 0 1,1 0,#{r2 }Z"
      end
    else 
      sa = [s.start_angle, s.end_angle].min
      ea = [s.start_angle, s.end_angle].max
      c1 = Math.cos(sa)
      c2 = Math.cos(ea)
      s1 = Math.sin(sa)
      s2 = Math.sin(ea)
      if (r1)
        _p = "M#{r2 * c1},#{r2 * s1}A#{r2},#{r2} 0 #{((a < Math::PI) ? "0" : "1")},1 #{r2 * c2},#{r2 * s2}L#{r1 * c2},#{r1 * s2}A#{r1},#{r1} 0 #{((a < Math::PI) ? "0" : "1")},0 #{r1 * c1},#{r1 * s1}Z"
      else 
        _p = "M#{r2 * c1},#{r2 * s1}A#{r2},#{r2} 0 #{((a < Math.PI) ? "0" : "1")},1 #{r2 * c2},#{r2 * s2}L0,0Z"
      end
    end
    
    e = self.expect(e, "path", {
      "shape-rendering"=> s.antialias ? nil : "crispEdges",
      "pointer-events"=> s.events,
      "cursor"=> s.cursor,
      "transform"=> "translate(#{s.left},#{s.top})",
      "d"=> _p,
      "fill"=> fill.color,
      "fill-rule"=> "evenodd",
      "fill-opacity"=>  (fill.opacity==0) ? nil : fill.opacity,
      "stroke"=> stroke.color,
      "stroke-opacity"=> (stroke.opacity==0) ? nil : stroke.opacity,
      "stroke-width"=> stroke.opacity>0 ? s.line_width / self.scale.to_f : nil
    });
    e=SvgScene.append(e,scenes,i)

  end
  e
end

.xhtmlObject



30
31
32
# File 'lib/rubyvis/scene/svg_scene.rb', line 30

def self.xhtml
  "http://www.w3.org/1999/xhtml"
end


27
28
29
# File 'lib/rubyvis/scene/svg_scene.rb', line 27

def self.xlink
  "http://www.w3.org/1999/xlink"
end

.xmlnsObject



24
25
26
# File 'lib/rubyvis/scene/svg_scene.rb', line 24

def self.xmlns
  "http://www.w3.org/2000/xmlns"
end