Module: Rubyvis::SvgScene

Defined in:
lib/rubyvis/scene/svg_scene.rb,
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_curve.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

Overview

:nodoc:

Defined Under Namespace

Classes: PathBasis

Constant Summary collapse

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"}
}

Class Method Summary collapse

Class Method Details

.append(e, scenes, index) ⇒ Object



132
133
134
135
136
137
138
139
# File 'lib/rubyvis/scene/svg_scene.rb', line 132

def self.append(e,scenes,index)
  e._scene=OpenStruct.new({:scenes=>scenes, :index=>index})
  e=self.title(e, scenes[index])
  if(!e.parent)
    scenes._g.add_element(e)
  end
  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
116
117
118
119
120
121
122
123
124
125
126
127
128
# File 'lib/rubyvis/scene/svg_area.rb', line 3

def self.area(scenes)
  #e = scenes._g.elements[1]
  e=scenes._g.get_element(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)
  
  # 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)}"
      puts "#{i}:"+pi+","+pj if $DEBUG
      #/* 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
  # puts "Scenes:#{scenes.size}, interpolation:#{scenes[0].interpolate}"
  
  while(i < scenes.size)
    si = scenes[i]
    if (si.width==0 and si.height==0)
      i+=1
      next
    end
    
    j=i+1
    while(j<scenes.size) do
      sj=scenes[j]
      break if sj.width==0 and sj.height==0
      j+=1
    end
    
    puts "j:#{j}" if $DEBUG
    
    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
  })
  self.append(e, scenes, 0);
end

.area_segment(scenes) ⇒ Object



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
195
196
197
198
199
200
201
202
203
204
205
206
207
208
# File 'lib/rubyvis/scene/svg_area.rb', line 130

def self.area_segment(scenes)
  e=scenes._g.get_element(1)
  #e = scenes._g.elements[1]
  s = scenes[0]
  pathsT=nil
  pathsB=nil
  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") 
      pathsT = Rubyvis::SvgScene.curve_basis_segments(pointsT)
      pathsB = Rubyvis::SvgScene.curve_basis_segments(pointsB)
    elsif (s.interpolate == "cardinal")
        pathsT = Rubyvis::SvgScene.curve_cardinal_segments(pointsT, s.tension);
        pathsB = Rubyvis::SvgScene.curve_cardinal_segments(pointsB, s.tension);
    elsif # monotone
      pathsT = Rubyvis::SvgScene.curve_monotone_segments(pointsT)
      pathsB = 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 = s1.fill_style
    stroke = s1.stroke_style            
    next 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 ? nil : "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
30
# File 'lib/rubyvis/scene/svg_bar.rb', line 3

def self.bar(scenes)
  #e=scenes._g.elements[1]
  e=scenes._g.get_element(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 and stroke.opacity==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

.cardinal_tangents(points, tension) ⇒ Object

Computes the tangents for the given points needed for cardinal spline interpolation. Returns an array of tangent vectors. Note: that for n points only the n-2 well defined tangents are returned.

  • @param points the array of points.

  • @param tension the tension of hte cardinal spline.



214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
# File 'lib/rubyvis/scene/svg_curve.rb', line 214

def self.cardinal_tangents(points, tension) 
  tangents = []
  a = (1 - tension) / 2.0
  p0 = points[0]
  p1 = points[1]
  p2 = points[2]
  3.upto(points.size-1) {|i|
    tangents.push(OpenStruct.new({:x=> a * (p2.left - p0.left), :y=> a * (p2.top - p0.top)}))
    p0 = p1;
    p1 = p2;
    p2 = points[i];
  }

  tangents.push(OpenStruct.new({:x=> a * (p2.left - p0.left), :y=> a * (p2.top - p0.top)}))
  return tangents;
end

.create(type) ⇒ Object



114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
# File 'lib/rubyvis/scene/svg_scene.rb', line 114

def self.create(type)
  if Rubyvis.xml_engine==:nokogiri
    el=Rubyvis.nokogiri_document.create_element("#{type}")
    if type=='svg'
      el.add_namespace(nil, self.svg)
      el.add_namespace('xlink', self.xlink)
    end
  else
    el=REXML::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
  end
  el
end

.curve_basis(points) ⇒ Object

Interpolates the given points using the basis spline interpolation. Returns an SVG path without the leading M instruction to allow path appending.



65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
# File 'lib/rubyvis/scene/svg_curve.rb', line 65

def self.curve_basis(points) 
  return "" if (points.size <= 2)
  path = ""
  p0 = points[0]
  p1 = p0
  p2 = p0
  p3 = points[1]
  
  path += self.path_basis(p0, p1, p2, p3).to_s
  2.upto(points.size-1) {|i|
    p0 = p1
    p1 = p2
    p2 = p3
    p3 = points[i]
    path += self.path_basis(p0, p1, p2, p3).to_s
  }
  #  Cycle through to get the last point.
  path += self.path_basis(p1, p2, p3, p3).to_s
  path += self.path_basis(p2, p3, p3, p3).to_s
  path;
end

.curve_basis_segments(points) ⇒ Object

Interpolates the given points using the basis spline interpolation. If points.length == tangents.length then a regular Hermite interpolation is performed, if points.length == tangents.length + 2 then the first and last segments are filled in with cubic bazier segments. Returns an array of path strings.



93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
# File 'lib/rubyvis/scene/svg_curve.rb', line 93

def self.curve_basis_segments(points) 
  return "" if (points.size <= 2)
  paths = []
  p0 = points[0]
  p1 = p0
  p2 = p0
  p3 = points[1]
  firstPath = self.path_basis(p0, p1, p2, p3).segment
  p0 = p1;
  p1 = p2;
  p2 = p3;
  p3 = points[2];
  paths.push(firstPath + self.path_basis(p0, p1, p2, p3).to_s) # merge first & second path
  3.upto(points.size-1) {|i|
    p0 = p1;
    p1 = p2;
    p2 = p3;
    p3 = points[i];
    paths.push(path_basis(p0, p1, p2, p3).segment);
  }
  
  # merge last & second-to-last path
  paths.push(path_basis(p1, p2, p3, p3).segment + path_basis(p2, p3, p3, p3).to_s)
  paths
end

.curve_cardinal(points, tension) ⇒ Object

Interpolates the given points using cardinal spline interpolation. Returns an SVG path without the leading M instruction to allow path appending.

  • @param points the array of points.

  • @param tension the tension of hte cardinal spline.



238
239
240
241
# File 'lib/rubyvis/scene/svg_curve.rb', line 238

def self.curve_cardinal(points, tension)
  return "" if (points.size <= 2) 
  self.curve_hermite(points, self.cardinal_tangents(points, tension))
end

.curve_cardinal_segments(points, tension) ⇒ Object

Interpolates the given points using cardinal spline interpolation. Returns an array of path strings.

Parameters:

  • points

    the array of points.

  • tension

    the tension of hte cardinal spline.



247
248
249
250
# File 'lib/rubyvis/scene/svg_curve.rb', line 247

def self.curve_cardinal_segments(points, tension) 
  return "" if (points.size <= 2) 
  self.curve_hermite_segments(points, self.cardinal_tangents(points, tension))
end

.curve_hermite(points, tangents) ⇒ Object

Interpolates the given points with respective tangents using the cubic Hermite spline interpolation. If points.length == tangents.length then a regular Hermite interpolation is performed, if points.length == tangents.length + 2 then the first and last segments are filled in with cubic bazier segments. Returns an SVG path without the leading M instruction to allow path appending.

  • @param points the array of points.

  • @param tangents the array of tangent vectors.

/



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
# File 'lib/rubyvis/scene/svg_curve.rb', line 129

def self.curve_hermite(points, tangents)
  return "" if (tangents.size < 1 or (points.size != tangents.size and points.size != tangents.size + 2)) 
  quad = points.size != tangents.size
  path = ""
  p0 = points[0]
  p = points[1]
  t0 = tangents[0]
  t = t0
  pi = 1

  if (quad) 
      path += "Q#{(p.left - t0.x * 2 / 3)},#{(p.top - t0.y * 2 / 3)},#{p.left},#{p.top}"
      p0 = points[1];
      pi = 2;
  end

  if (tangents.length > 1) 
    t = tangents[1]
    p = points[pi]
    pi+=1
    path += "C#{(p0.left + t0.x)},#{(p0.top + t0.y) },#{(p.left - t.x) },#{(p.top - t.y)},#{p.left},#{p.top}"
    
    2.upto(tangents.size-1) {|i|
      p = points[pi];
      t = tangents[i];
      path += "S#{(p.left - t.x)},#{(p.top - t.y)},#{p.left},#{p.top}"
      pi+=1
    }
  end

  if (quad) 
  lp = points[pi];
  path += "Q#{(p.left + t.x * 2 / 3)},#{(p.top + t.y * 2 / 3)},#{lp.left},#{lp.top}"
  end

  path;
end

.curve_hermite_segments(points, tangents) ⇒ Object

Interpolates the given points with respective tangents using the cubic Hermite spline interpolation. Returns an array of path strings.

  • @param points the array of points.

  • @param tangents the array of tangent vectors.



171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
# File 'lib/rubyvis/scene/svg_curve.rb', line 171

def self.curve_hermite_segments(points, tangents)
  return [] if (tangents.size < 1 or  (points.size != tangents.size and points.size != tangents.size + 2)) 
  quad = points.size != tangents.size
  paths = []
  p0 = points[0]
  p = p0
  t0 = tangents[0]
  t = t0
  pi = 1
  
  if (quad) 
  p = points[1]
  paths.push("M#{p0.left},#{p0.top }Q#{(p.left - t.x * 2 / 3.0 )},#{(p.top - t.y * 2 / 3)},#{p.left},#{p.top}")
  pi = 2
  end
  
  1.upto(tangents.size-1) {|i|
  p0 = p;
  t0 = t;
  p = points[pi]
  t = tangents[i]
  paths.push("M#{p0.left },#{p0.top
    }C#{(p0.left + t0.x) },#{(p0.top + t0.y)
    },#{(p.left - t.x) },#{(p.top - t.y)
    },#{p.left },#{p.top}")
  pi+=1
  }
  
  if (quad) 
  lp = points[pi];
  paths.push("M#{p.left },#{p.top
      }Q#{(p.left + t.x * 2 / 3) },#{(p.top + t.y * 2 / 3) },#{lp.left },#{lp.top}")
  end
  
  paths
end

.curve_monotone(points) ⇒ Object

Interpolates the given points using Fritsch-Carlson Monotone cubic Hermite interpolation. Returns an SVG path without the leading M instruction to allow path appending.

  • @param points the array of points.



324
325
326
327
# File 'lib/rubyvis/scene/svg_curve.rb', line 324

def self.curve_monotone(points) 
   return "" if (points.length <= 2)
   return self.curve_hermite(points, self.monotone_tangents(points))
end

.curve_monotone_segments(points) ⇒ Object

Interpolates the given points using Fritsch-Carlson Monotone cubic Hermite interpolation. Returns an array of path strings.

  • @param points the array of points.

/



335
336
337
338
# File 'lib/rubyvis/scene/svg_curve.rb', line 335

def self.curve_monotone_segments(points) 
  return "" if (points.size <= 2)
   self.curve_hermite_segments(points, self.monotone_tangents(points))
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
65
# File 'lib/rubyvis/scene/svg_dot.rb', line 3

def self.dot(scenes)
  #e = scenes._g.elements[1]
  e=scenes._g.get_element(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



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
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
# File 'lib/rubyvis/scene/svg_scene.rb', line 169

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

  if (e)
    #e = e.elements[1] if (e.name == "a")
    e=e.get_element(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 == IMPLICIT[:svg][name])
    if (value.nil?)
      e.delete_attribute(name)
    else
      e.set_attributes(name=>value)
      #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==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(";")
      e.set_attributes('style'=> array_styles.map {|k,v| "#{k}:#{v}"}.join(";"))
    end
  end
  e
end

.fill(e, scenes, i) ⇒ Object



107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
# File 'lib/rubyvis/scene/svg_panel.rb', line 107

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]
  e=scenes._g.get_element(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.set_attributes("xlink:href"=>s.url);
    end
    e = self.append(e, scenes, i);
    
    #/* stroke */
    e = self.stroke(e, scenes, i);
  end
  e
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
52
53
# File 'lib/rubyvis/scene/svg_label.rb', line 3

def self.label(scenes)
  #e=scenes._g.elements[1]
  e=scenes._g.get_element(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.frozen? ? s.text.dup : 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
50
# File 'lib/rubyvis/scene/svg_line.rb', line 3

def self.line(scenes)
  #e=scenes._g.elements[1]
  e=scenes._g.get_element(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},#{s.top}"

  if (scenes.size > 2 and (['basis', 'cardinal', 'monotone'].include? s.interpolate))
    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. */



138
139
140
# File 'lib/rubyvis/scene/svg_line.rb', line 138

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



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
# File 'lib/rubyvis/scene/svg_line.rb', line 52

def self.line_segment(scenes)

  #e=scenes._g.elements[1]
  e=scenes._g.get_element(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

  (0...(scenes.size-1)).each {|i|

    s1 = scenes[i]
    s2 = scenes[i + 1];
    #p "#{s1.top} #{s1.left} #{s1.line_width} #{s1.interpolate} #{s1.line_join}"
    # visible 
    next if (!s1.visible or !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.line_join == "miter"))
      fill = stroke
      stroke = Rubyvis::Color.transparent
      s0=((i-1) < 0) ? nil : scenes[i-1]
      s3=((i+2) >= scenes.size) ? nil : scenes[i+2]
      
      d = path_join(s0, s1, s2, s3)
    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);
  }
  e
end

.monotone_tangents(points) ⇒ Object

Interpolates the given points using Fritsch-Carlson Monotone cubic Hermite interpolation. Returns an array of tangent vectors.

*@param points the array of points.



256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
# File 'lib/rubyvis/scene/svg_curve.rb', line 256

def self.monotone_tangents(points) 
  tangents = []
  d = []
  m = []
  dx = []
  #k=0
  
  #/* Compute the slopes of the secant lines between successive points. */
  
  
  0.upto(points.size-2) do |k| 
  
#    while(k < points.size-1) do 
    d[k] = (points[k+1].top - points[k].top) / (points[k+1].left - points[k].left).to_f
    k+=1
  end
  
  #/* Initialize the tangents at every point as the average of the secants. */
  m[0] = d[0]
  dx[0] = points[1].left - points[0].left
  
  
  1.upto(points.size-2) {|k|
    m[k] = (d[k-1]+d[k]) / 2.0
    dx[k] = (points[k+1].left - points[k-1].left) / 2.0
  }
  
  k=points.size-1
  
  m[k] = d[k-1];
  dx[k] = (points[k].left - points[k-1].left);
  
  # /* Step 3. Very important, step 3. Yep. Wouldn't miss it. */
  (points.size-1).times {|kk|
    if d[kk] == 0 
      m[ kk ] = 0;
      m[kk + 1] = 0;
    end
  }
  
  # /* Step 4 + 5. Out of 5 or more steps. */
  
  
  (points.size-1).times {|kk|
    next if ((m[kk].abs < 1e-5) or (m[kk+1].abs < 1e-5))
    akk = m[kk] / d[kk].to_f
    bkk = m[kk + 1] / d[kk].to_f
    s = akk * akk + bkk * bkk; # monotone constant (?)
    if (s > 9) 
      tkk = 3.0 / Math.sqrt(s)
      m[kk] = tkk * akk * d[kk]
      m[kk + 1] = tkk * bkk * d[kk]
    end
  }
  len=nil;
  points.size.times {|i|
    len = 1 + m[i] * m[i]; #// pv.vector(1, m[i]).norm().times(dx[i]/3)
    tangents.push(OpenStruct.new({:x=> dx[i] / 3.0 / len, :y=> m[i] * dx[i] / 3.0 / len}))
  }
  
  tangents;
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
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
# 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]
  e=(g.nil?) ? nil : g.get_element(1) 
  if g
    #e=g.elements[1]
    e=g.get_element(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]
        g=s.canvas.get_element(1)
        #e=(@g.nil?) ? nil : @g.elements[1]
        e=(@g.nil?) ? nil : @g.get_element(1)
      end
      if(!g)
        g=s.canvas.add_element(self.create('svg'))
        g.set_attributes(
          {
            'font-size'=>"10px",
            'font-family'=>'sans-serif',
            'fill'=>'none',
            'stroke'=>'none',
            'stroke-width'=>1.5
          }
        )
        e=g.get_element(1)
        # 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.set_attributes({
          'width'=>s.width+s.left+s.right,
          'height'=>s.height+s.top+s.bottom
      })
      #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=c.get_element(1)
      e=self.expect(e,'clipPath',{'id'=>id})
      #r=(e.elements[1]) ? e.elements[1] : e.add_element(self.create('rect'))
      r=(e.get_element(1)) ? e.get_element(1) : e.add_element(self.create('rect'))
      r.set_attributes({
          'x'=>s.left,
          'y'=>s.top,
          'width'=>s.width,
          'height'=>s.height
      })
      #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
    # fill
    e=self.fill(e,scenes, i)
    # transform
    k=self.scale
    t=s.transform
    x=s.left+t.x
    y=s.top+t.y
    SvgScene.scale=SvgScene.scale*t.k
    # children
    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
    }
    # transform (pop)
    SvgScene.scale=k
    # stroke
    e=SvgScene.stroke(e,scenes,i)
    # clip
    if (s.overflow=='hidden')
      scenes._g=g=c.parent
      e=c.next_sibling_node
    end
  end
  return e
  
end

.path_basis(p0, p1, p2, p3) ⇒ Object

Converts the specified b-spline curve segment to a bezier curve compatible with SVG ā€œCā€.

  • @param p0 the first control point.

  • @param p1 the second control point.

  • @param p2 the third control point.

  • @param p3 the fourth control point.



56
57
58
# File 'lib/rubyvis/scene/svg_curve.rb', line 56

def self.path_basis(p0,p1,p2,p3)
  PathBasis.new(p0,p1,p2,p3)
end

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

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



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
# File 'lib/rubyvis/scene/svg_line.rb', line 143

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.line_width / (2.0 * self.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 and 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

  d="M#{a.x},#{a.y}L#{b.x},#{b.y} #{c.x},#{c.y} #{d.x},#{d.y}"
  d
end

.path_segment(s1, s2) ⇒ Object

Returns the path segment for the specified points. */



114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
# File 'lib/rubyvis/scene/svg_line.rb', line 114

def self.path_segment(s1, s2) 
  l = 1; # sweep-flag
  l = 0 if s1.interpolate=='polar-reverse'
  
  if s1.interpolate=='polar' or s1.interpolate=='polar-reverse'
    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) or (e>1))
      return "A#{r},#{r} 0 0,#{l} #{s2.left},#{s2.top}"
    end
  end
  
  if s1.interpolate=="step-before"
    return "V#{s2.top}H#{s2.left}"
  elsif s1.interpolate=="step-after"
    return "H#{s2.left}V#{s2.top}"
  end
  
  return "L#{s2.left},#{s2.top}"
end

.remove_siblings(e) ⇒ Object



107
108
109
110
111
112
113
# File 'lib/rubyvis/scene/svg_scene.rb', line 107

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
27
# File 'lib/rubyvis/scene/svg_rule.rb', line 3

def self.rule(scenes)
  #e=scenes._g.elements[1]
  e=scenes._g.get_element(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



77
78
79
# File 'lib/rubyvis/scene/svg_scene.rb', line 77

def self.scale
  @scale
end

.scale=(v) ⇒ Object



80
81
82
# File 'lib/rubyvis/scene/svg_scene.rb', line 80

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

.stroke(e, scenes, i) ⇒ Object



129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
# File 'lib/rubyvis/scene/svg_panel.rb', line 129

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

include REXML



64
65
66
# File 'lib/rubyvis/scene/svg_scene.rb', line 64

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

.title(e, s) ⇒ Object

Applies a title tooltip to the specified element e, using the title property of the specified scene node s. Note that this implementation does not create an SVG title element as a child of e; although this is the recommended standard, it is only supported in Opera. Instead, an anchor element is created around the element e, and the xlink:title attribute is set accordingly.

Parameters:

  • e

    an SVG element.

  • s

    a scene node.



151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
# File 'lib/rubyvis/scene/svg_scene.rb', line 151

def self.title(e,s)
  a = e.parent
  a=nil if (a and (a.name != "a"))
  if (s.title) 
    if (!a) 
      a = self.create("a")
      e.parent.replace_child(a, e) if (e.parent)
      a.add_element(e)
    end
    #a.add_attribute('xlink:title',s.title)
    a.set_attributes('xlink:title' => s.title)

    return a;
  end
  a.parent_node.replace_child(e, a) if (a) 
  e
end

.update_all(scenes) ⇒ Object



100
101
102
103
104
105
106
# File 'lib/rubyvis/scene/svg_scene.rb', line 100

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
55
56
# File 'lib/rubyvis/scene/svg_wedge.rb', line 3

def self.wedge(scenes)
  #e=scenes._g.elements[1]
  e=scenes._g.get_element(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!=0) 
        _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!=0)
        _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



73
74
75
# File 'lib/rubyvis/scene/svg_scene.rb', line 73

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


70
71
72
# File 'lib/rubyvis/scene/svg_scene.rb', line 70

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

.xmlnsObject



67
68
69
# File 'lib/rubyvis/scene/svg_scene.rb', line 67

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