rsvgr 0.0.2 → 0.0.3

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.
Files changed (4) hide show
  1. checksums.yaml +4 -4
  2. data/examples/chart.rb +2 -2
  3. data/lib/rsvgr.rb +402 -366
  4. metadata +2 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 57ae7236d7ad70541c443a79ff46b350b329a18b
4
- data.tar.gz: 3b2b17d2b27be8fe4902585000716a469e759c1f
3
+ metadata.gz: 81287bc178329e0d715c02f1734862ae9a795385
4
+ data.tar.gz: 8ccea10d7969f32ef4ccdf3b91617a2cda41acb9
5
5
  SHA512:
6
- metadata.gz: aa6b1014cad2b629d67bce579080339a6159b962e8b77043a610c79f66272f4c6e312466966e313f9d66ea38c2dcd18f95c492deb74543f5a543917a437d9669
7
- data.tar.gz: 879debc0e25101c7bccbcf4912379d2a972bba407c9a9f2b721adca70e18a6974f3f82d736490fef5bea3a7b9f1847b03b3bbe7283e466025f029ef1cfd424bb
6
+ metadata.gz: c38662bfa2eba97e20b3165320b242ce8ddb0753b3841f15e76ca1c95545f42767759bcf0933c0141dc41d86268f27bc69279118c8b6c3d9258d093e16a7149d
7
+ data.tar.gz: 85f1b0f25c6d4de989d85b3678b1ba56c175d0a63c91690daf6b8b0cd922154299cee8adbf54e7a0d95840cdfa77c2300a5cef5fcd187f4fab9460ecf9acfbe3
@@ -1,4 +1,4 @@
1
- require_relative "../rsvgr"
1
+ require_relative File.join "..", "lib", "rsvgr.rb"
2
2
  include RSVGR
3
3
 
4
4
  world = {
@@ -25,4 +25,4 @@ svg = Root.new << plot = Samples::Plot.new(ticks_x:ticks_x)
25
25
  plot.add_line(title: "население Земли", data_pairs: world)\
26
26
  .add_line(title: "население Азии", data_pairs: asia)
27
27
 
28
- svg.cat.save.open_with "Chromium"
28
+ svg.cat.save#.open_with "Chromium"
@@ -1,400 +1,436 @@
1
- # I don't use any xml library, because I just don't really need it here
2
-
3
1
  # http://www.w3.org/TR/SVGTiny12/single-page.html
4
2
 
5
3
 
6
4
  module RSVGR
7
5
 
8
- UNSUPPORTED = ->{ raise "not supported currently" }
6
+ UNSUPPORTED = ->{ raise "not supported currently" }
9
7
 
10
- DEFAULT_SIZE = 100.0 # if we use such small value as 1.0 vertical text alignment goes mad
8
+ DEFAULT_SIZE = 1000.0 # if we use such small value as 1.0 vertical text alignment goes mad
11
9
 
12
- class Node
13
- def initialize args = {}
14
- args[:x1] ||= 0
15
- args[:y1] ||= 0
16
- args[:x2] ||= DEFAULT_SIZE
17
- args[:y2] ||= DEFAULT_SIZE
18
- args.each{ |k,v| instance_variable_set "@#{k}",v }
19
- end
20
- def to_s
21
- raise "you had to override me, while ascending from #{self.class.name} class"
22
- end
10
+ node = Class.new do
11
+ def initialize args = {}
12
+ # args[:x1] ||= 0
13
+ # args[:y1] ||= 0
14
+ # args[:x2] ||= 1
15
+ # args[:y2] ||= 1
16
+ args.each{ |k,v| instance_variable_set "@#{k}",v }
23
17
  end
24
-
25
- class CanIHazChildren < Node
26
- def initialize args = {}
27
- @children = []
28
- super
29
- end
30
- def << x
31
- @children << x
32
- self
33
- end
34
- def to_s_children additional_child = []
35
- [*@children, *additional_child].map{ |child|
36
- child.to_s.gsub(/.+/, ' \0')
37
- }.join
38
- end
39
- def save_as what, where
40
- File.open(where, "w"){ |f| f.puts what }
41
- self
42
- end
18
+ def to_s
19
+ raise "you have to override me, if inheriting from #{self.class} class"
43
20
  end
21
+ # def save where = "temp.svg"
22
+ # File.write where, self
23
+ # puts "saved as #{where}"
24
+ # self
25
+ # end
26
+ # def save_html
27
+ # UNSUPPORTED
28
+ # save_as to_html, "temp.html"
29
+ # end
30
+ end
44
31
 
45
- class Group < CanIHazChildren
46
- def to_s additional_child = []
47
- "<g transform=\"" \
48
- "#{"translate(#{@x || 0},#{@y || 0}) " if @x || @y}" \
49
- "#{"scale(#{@scale_x || @scale || 1},#{@scale_y || @scale || 1}) " if @scale_x || @scale_y || @scale}" \
50
- "#{"rotate(#{@rotate})" if @rotate}\"" \
51
- "#{" id=\"#{@id}\"" if @id}" \
52
- "#{" fill=\"#{@fill_color}\"" if @fill_color}" \
53
- "#{" stroke-width=\"#{@stroke_width}\"" if @stroke_width}" \
54
- "#{" stroke=\"#{@stroke_color}\"" if @stroke_color}" \
55
- ">\n" + to_s_children(additional_child) + "</g>\n"
56
- end
57
- # def []= k,v
58
- # instance_variable_set "@#{k}",v
59
- # end
32
+ class Line < node
33
+ def initialize *args
34
+ @x1 = 0
35
+ @y1 = 0
36
+ @x2 = 1
37
+ @y2 = 1
38
+ super
39
+ end
40
+ def to_s
41
+ "<line" +
42
+ " x1=\"#{DEFAULT_SIZE * @x1}\"" +
43
+ " x2=\"#{DEFAULT_SIZE * @x2}\"" +
44
+ " y1=\"#{DEFAULT_SIZE * @y1}\"" +
45
+ " y2=\"#{DEFAULT_SIZE * @y2}\"" +
46
+ "#{" stroke=\"#{@stroke_color}\"" if @stroke_color}" +
47
+ "/>\n"
60
48
  end
49
+ end
61
50
 
62
- class Root < CanIHazChildren
63
- def initialize args = {}
64
- @fill_color = "silver"
65
- @stroke_color = "black"
66
- @stroke_width = DEFAULT_SIZE*0.01
67
- @stroke_linecap = "round"
68
- super
69
- end
70
- def to_s
71
- "<?xml version=\"1.0\"?>\n" \
72
- "<svg xmlns=\"http://www.w3.org/2000/svg\" version=\"1.2\" baseProfile=\"tiny\"" \
73
- " viewBox=\"#{[@x1, @y1, @x2, @y2].join " "}\"" \
74
- " fill=\"#{@fill_color}\"" \
75
- " stroke=\"#{@stroke_color}\"" \
76
- " stroke-width=\"#{@stroke_width}\"" \
77
- " stroke-linecap=\"#{@stroke_linecap}\"" \
78
- " preserveAspectRatio=\"xMidYMid meet\"" \
79
- ">\n <title>Generated by RubySVGmakeR v0.1 (c) Nakilon</title>\n" +
80
- to_s_children + "</svg>\n"
81
- end
82
- def to_html
83
- "<html xmlns=\"http://www.w3.org/1999/xhtml\">\n" \
84
- " <head>\n" \
85
- " <title>#{Time.now}</title>\n" \
86
- " <style type=\"text/css\" media=\"screen\">\n" \
87
- " body {\n" \
88
- " background:lightgrey;\n" \
89
- " margin:0;\n" \
90
- " }\n" \
91
- " svg {\n" \
92
- " display:block;\n" \
93
- " border:2px solid grey;\n" \
94
- " position:absolute;\n" \
95
- " top:3%;\n" \
96
- " left:3%;\n" \
97
- " width:94%;\n" \
98
- " height:94%;\n" \
99
- " background:white;\n" \
100
- " }\n" \
101
- " </style>\n" \
102
- " </head>\n" \
103
- " <body>\n" + to_s + " </body>\n</html>\n"
104
- end
105
- def cat
106
- puts self.to_s
107
- self
108
- end
109
- def save
110
- save_as to_s, "temp.svg"
111
- end
112
- def save_html
113
- UNSUPPORTED
114
- save_as to_html, "temp.html"
115
- end
116
- def save_as what, where
117
- UNSUPPORTED
118
- File.open(where, "w"){ |f| f.puts what }
119
- self
120
- end
121
- def open_with app
122
- RUBY_PLATFORM["mingw"] ? `#{app} temp.svg` : `open -a #{app} temp.svg`
123
- end
51
+ class Path < node
52
+ def initialize args = {}
53
+ @fill_color = "none"
54
+ super
124
55
  end
56
+ def to_s
57
+ "<path" +
58
+ " d=\"#{@d || "M " + @points.map{ |x, y|
59
+ "#{DEFAULT_SIZE * x} #{DEFAULT_SIZE * y}"
60
+ }.join(" L ")}\"" +
61
+ "#{" stroke=\"#{@stroke_color}\"" if @stroke_color}" +
62
+ "#{" stroke-width=\"#{@stroke_width}\"" if @stroke_width}" +
63
+ " fill=\"#{@fill_color}\"" +
64
+ "/>\n"
65
+ end
66
+ end
125
67
 
68
+ class Circle < node
69
+ def initialize *args
70
+ @cx = 0.5
71
+ @cy = 0.5
72
+ @r = 0.5
73
+ super
74
+ end
75
+ def to_s
76
+ "<circle" +
77
+ " cx=\"#{DEFAULT_SIZE * @cx}\"" +
78
+ " cy=\"#{DEFAULT_SIZE * @cy}\"" +
79
+ " r=\"#{DEFAULT_SIZE * @r}\"" +
80
+ "#{" fill=\"#{@fill_color}\"" if @fill_color}" +
81
+ "#{" stroke=\"#{@stroke_color}\"" if @stroke_color}" +
82
+ "#{" stroke-width=\"#{@stroke_width}\"" if @stroke_width}" +
83
+ "#{" onmousemove=\"#{@onmousemove}\"" if @onmousemove}" +
84
+ "#{" onmouseout=\"#{@onmouseout}\"" if @onmouseout}" +
85
+ "/>\n"
86
+ end
87
+ end
126
88
 
127
- class Script < CanIHazChildren
128
- def to_s
129
- "<script" \
130
- " type=\"text/ecmascript\"" \
131
- "#{" id=\"#{@id}\"" if @id}" \
132
- "><![CDATA[\n" + to_s_children + "]]></script>\n"
133
- end
89
+ class Rect < node
90
+ def initialize *args
91
+ @x = 0
92
+ @y = 0
93
+ @width = 1
94
+ @height = 1
95
+ super
96
+ end
97
+ def to_s
98
+ "<rect" +
99
+ " x=\"#{DEFAULT_SIZE * @x}\"" +
100
+ " y=\"#{DEFAULT_SIZE * @y}\"" +
101
+ " width=\"#{DEFAULT_SIZE * @width}\"" +
102
+ " height=\"#{DEFAULT_SIZE * @height}\"" +
103
+ "#{" stroke=\"#{@stroke_color}\"" if @stroke_color}" +
104
+ "#{" stroke-width=\"#{@stroke_width}\"" if @stroke_width}" +
105
+ "#{" fill=\"#{@fill_color}\"" if @fill_color}" +
106
+ "/>\n"
134
107
  end
108
+ end
135
109
 
136
- class Text < CanIHazChildren
137
- def initialize args = {}
138
- args[:x] ||= DEFAULT_SIZE/2
139
- args[:y] ||= DEFAULT_SIZE/2
140
- args[:size] ||= DEFAULT_SIZE*0.8
141
- args[:anchor] ||= "middle"
142
- args[:baseline] ||= "central"
143
- args[:fill_color] ||= "black"
144
- super
145
- end
146
- def to_s
147
- "<text" \
148
- "#{" id=\"#{@id}\"" if @id}" \
149
- "#{" visibility=\"#{@visibility}\"" if @visibility}" \
150
- " x=\"#{@x}\"" \
151
- " y=\"#{@y}\"" \
152
- " font-size=\"#{@size}\"" \
153
- " text-anchor=\"#{@anchor}\"" \
154
- " dominant-baseline=\"#{@baseline}\"" \
155
- " fill=\"#{@fill_color}\"" \
156
- "#{" stroke=\"#{@stroke_color}\"" if @stroke_color}" \
157
- "#{" style=\"#{@style}\"" if @style}" \
158
- ">\n" + to_s_children + "</text>\n"
159
- end
110
+ canIHazChildren = Class.new node do
111
+ def << x
112
+ children << x
113
+ self
160
114
  end
115
+ # def to_s_children additional_child = []
116
+ # [*@children, *additional_child].map{ |child|
117
+ def to_s_children
118
+ children.map{ |child| child.to_s.gsub /.+/, ' \0' }.join
119
+ end
120
+ private
121
+ def children
122
+ @children ||= []
123
+ end
124
+ end
161
125
 
162
- class Line < Node
163
- def to_s
164
- "<line " \
165
- "x1=\"#{@x1}\" " \
166
- "x2=\"#{@x2}\" " \
167
- "y1=\"#{@y1}\" " \
168
- "y2=\"#{@y2}\" " \
169
- "#{"stroke=\"#{@stroke_color}\" " if @stroke_color}" \
170
- "/>\n"
171
- end
126
+ class Group < canIHazChildren
127
+ # def to_s additional_child = []
128
+ def to_s
129
+ "<g transform=\"" +
130
+ "#{" translate(#{DEFAULT_SIZE * (@x || 0)},#{DEFAULT_SIZE * (@y || 0)})" if @x || @y}" +
131
+ "#{" scale(#{@scale_x || @scale || 1},#{@scale_y || @scale || 1})" if @scale_x || @scale_y || @scale}" +
132
+ "#{" rotate(#{@rotate})" if @rotate}\"" +
133
+ # "#{" id=\"#{@id}\"" if @id}" +
134
+ "#{" fill=\"#{@fill_color}\"" if @fill_color}" +
135
+ "#{" stroke-width=\"#{@stroke_width}\"" if @stroke_width}" +
136
+ "#{" stroke=\"#{@stroke_color}\"" if @stroke_color}" +
137
+ ">\n" + to_s_children + "</g>\n"
138
+ # ">\n" + to_s_children(additional_child) + "</g>\n"
172
139
  end
140
+ # def []= k,v
141
+ # instance_variable_set "@#{k}",v
142
+ # end
143
+ end
173
144
 
174
- class Path < Node
175
- def initialize args = {}
176
- args[:d] = "M " + args[:points].map{ |x, y| "#{x} #{y}" }.join(" L ")
177
- args[:fill_color] ||= "none"
178
- super
179
- end
180
- def to_s
181
- "<path" \
182
- " d=\"#{@d}\"" \
183
- "#{" stroke=\"#{@stroke_color}\"" if @stroke_color}" \
184
- " fill=\"#{@fill_color}\"" \
185
- "/>\n"
186
- end
145
+ class Root < canIHazChildren
146
+ def initialize *args
147
+ @x1 = 0
148
+ @y1 = 0
149
+ @x2 = 1
150
+ @y2 = 1
151
+ @fill_color = "silver"
152
+ @stroke_color = "black"
153
+ # @stroke_width = 0.005
154
+ # @stroke_linecap = "round"
155
+ super
187
156
  end
157
+ def to_s
158
+ "<?xml version=\"1.0\"?>\n" +
159
+ "<svg xmlns=\"http://www.w3.org/2000/svg\" version=\"1.2\" baseProfile=\"tiny\"" +
160
+ " viewBox=\"#{[@x1, @y1, @x2, @y2].map{ |i| DEFAULT_SIZE * i }.join " "}\"" +
161
+ " preserveAspectRatio=\"xMidYMid meet\"" +
162
+ " fill=\"#{@fill_color}\"" +
163
+ " stroke=\"#{@stroke_color}\"" +
164
+ # " stroke-width=\"#{@stroke_width}\"" +
165
+ # " stroke-linecap=\"#{@stroke_linecap}\"" +
166
+ ">\n <title>Generated by RubySVGmakeR (c) Nakilon</title>\n" + to_s_children + "</svg>\n"
167
+ end
168
+ # def to_html
169
+ # "<html xmlns=\"http://www.w3.org/1999/xhtml\">\n" \
170
+ # " <head>\n" \
171
+ # " <title>#{Time.now}</title>\n" \
172
+ # " <style type=\"text/css\" media=\"screen\">\n" \
173
+ # " body {\n" \
174
+ # " background:lightgrey;\n" \
175
+ # " margin:0;\n" \
176
+ # " }\n" \
177
+ # " svg {\n" \
178
+ # " display:block;\n" \
179
+ # " border:2px solid grey;\n" \
180
+ # " position:absolute;\n" \
181
+ # " top:3%;\n" \
182
+ # " left:3%;\n" \
183
+ # " width:94%;\n" \
184
+ # " height:94%;\n" \
185
+ # " background:white;\n" \
186
+ # " }\n" \
187
+ # " </style>\n" \
188
+ # " </head>\n" \
189
+ # " <body>\n" + to_s + " </body>\n</html>\n"
190
+ # end
191
+ def cat
192
+ self.tap &method(:puts)
193
+ end
194
+ # def open_with app
195
+ # RUBY_PLATFORM["mingw"] ? `#{app} temp.svg` : `open -a #{app} temp.svg`
196
+ # end
197
+ end
188
198
 
189
- class Circle < Node
190
- def initialize args = {}
191
- args[:r] ||= DEFAULT_SIZE*0.5
192
- super
193
- end
194
- def to_s
195
- "<circle" \
196
- "#{" cx=\"#{@x}\"" if @x}" \
197
- "#{" cy=\"#{@y}\"" if @y}" \
198
- " r=\"#{@r}\"" \
199
- "#{" fill=\"#{@fill_color}\"" if @fill_color}" \
200
- "#{" stroke=\"#{@stroke_color}\"" if @stroke_color}" \
201
- "#{" onmousemove=\"#{@onmousemove}\"" if @onmousemove}" \
202
- "#{" onmouseout=\"#{@onmouseout}\"" if @onmouseout}" \
203
- "/>\n"
204
- end
199
+
200
+ class Script < canIHazChildren
201
+ def to_s
202
+ "<script type=\"text/ecmascript\"" +
203
+ "#{" id=\"#{@id}\"" if @id}" +
204
+ "><![CDATA[\n" + to_s_children + "]]></script>\n"
205
205
  end
206
+ end
206
207
 
207
- class Rect < Node
208
- def initialize args = {}
209
- args[:width] ||= DEFAULT_SIZE
210
- args[:height] ||= DEFAULT_SIZE
211
- super
212
- end
213
- def to_s
214
- "<rect" \
215
- "#{" x=\"#{@x1}\"" if @x1}" \
216
- "#{" y=\"#{@y1}\"" if @y1}" \
217
- " width=\"#{@width}\"" \
218
- " height=\"#{@height}\"" \
219
- "#{" stroke=\"#{@stroke_color}\"" if @stroke_color}" \
220
- "#{" stroke-width=\"#{@stroke_width}\"" if @stroke_width}" \
221
- "#{" fill=\"#{@fill_color}\"" if @fill_color}" \
222
- "/>\n"
223
- end
208
+ class Text < canIHazChildren
209
+ def initialize *args
210
+ @x = 0.5
211
+ @y = 0.5
212
+ @size = 0.8
213
+ @anchor = "middle"
214
+ @baseline = "central"
215
+ @fill_color = "black"
216
+ @stroke_color = "none"
217
+ super
218
+ end
219
+ def to_s
220
+ "<text" +
221
+ "#{" id=\"#{@id}\"" if @id}" +
222
+ "#{" visibility=\"#{@visibility}\"" if @visibility}" +
223
+ " x=\"#{DEFAULT_SIZE * @x}\"" +
224
+ " y=\"#{DEFAULT_SIZE * @y}\"" +
225
+ " font-size=\"#{DEFAULT_SIZE * @size}\"" +
226
+ " text-anchor=\"#{@anchor}\"" +
227
+ " dominant-baseline=\"#{@baseline}\"" +
228
+ " fill=\"#{@fill_color}\"" +
229
+ " stroke=\"#{@stroke_color}\"" +
230
+ # "#{" style=\"#{@style}\"" if @style}" +
231
+ ">\n" + to_s_children + "</text>\n"
224
232
  end
233
+ end
225
234
 
226
235
 
227
- module Samples
228
- def self.face args = {}
229
- args[:scale_x] = args[:scale_y] = args[:size]/DEFAULT_SIZE if args[:size]
230
- args[:fill_color] = "yellow"
231
- args[:x] = DEFAULT_SIZE/2
232
- args[:y] = DEFAULT_SIZE/2
233
- args[:stroke_width] = DEFAULT_SIZE/10
234
- args[:stroke_color] = :black
235
- Group.new(args) <<
236
- Circle.new <<
237
- Circle.new(x:-0.2*DEFAULT_SIZE, y:-0.2*DEFAULT_SIZE, r:0.1*DEFAULT_SIZE) <<
238
- Circle.new(x:+0.2*DEFAULT_SIZE, y:-0.2*DEFAULT_SIZE, r:0.1*DEFAULT_SIZE) <<
239
- Line.new(x1:-0.2*DEFAULT_SIZE, y1:+0.2*DEFAULT_SIZE, x2:+0.2*DEFAULT_SIZE, y2:+0.2*DEFAULT_SIZE)
236
+ module Samples
237
+ def self.face args = {}
238
+ args[:scale_x] = args[:scale_y] = args[:size] if args[:size]
239
+ args[:fill_color] = "yellow"
240
+ args[:x] = 0.5
241
+ args[:y] = 0.5
242
+ args[:stroke_width] = 0.1
243
+ args[:stroke_color] = :black
244
+ Group.new(args) <<
245
+ Circle.new <<
246
+ Circle.new(x:-0.2, y:-0.2, r:0.1) <<
247
+ Circle.new(x:+0.2, y:-0.2, r:0.1) <<
248
+ Line.new(x1:-0.2, y1:+0.2, x2:+0.2, y2:+0.2)
249
+ end
250
+ class Grid < Group
251
+ def initialize args = {}
252
+ args[:fill_color] = "white"
253
+ super
254
+ if @xn*(@y2-@y1) > (@x2-@x1)*@yn
255
+ y = (@x2-@x1)*@yn/@xn
256
+ @y1 = (1-y)/2
257
+ @y2 = (1+y)/2
258
+ else
259
+ x = (@y2-@y1)*@xn/@yn
260
+ @x1 = (1-x)/2
261
+ @x2 = (1+x)/2
262
+ end
263
+ w = (@x2 - @x1)/@xn
264
+ h = (@y2 - @y1)/@yn
265
+ [*0...@yn].product([*0...@xn]) do |i,j|
266
+ self << cell = Group.new(
267
+ x: @x1+j*w,
268
+ y: @y1+i*h,
269
+ scale_x: w,
270
+ scale_y: h,
271
+ )
272
+ cell << Rect.new(stroke_color:"silver", stroke_width:0.1) if args[:grid]
273
+ cell << inside = Group.new(
274
+ x: 0.1,
275
+ y: 0.1,
276
+ scale_x: 0.8,
277
+ scale_y: 0.8,
278
+ )
279
+ yield inside,i,j if block_given?
280
+ end
281
+ end
282
+ end
283
+ class Plot < Group
284
+ def initialize *args
285
+ # @stroke_width = 0.002
286
+ # @fill_color = "white"
287
+ super
288
+ end
289
+ def to_s
290
+ return @to_s_cached if @to_s_cached
291
+ # maybe start all #to_s with "super \" and implement caching crutch in Node#to_s
292
+ left = 0.2
293
+ text_size = 0.03
294
+ self << field = Group.new(id:"TODOfield", x: left, y: 0.05, scale: 0.7)
295
+ field << Rect.new(fill_color: "none")
296
+ ticks = lambda do |values, forced_ticks = nil|
297
+ if values.all?{ |i| i.is_a? Numeric }
298
+ min, max = values.minmax
299
+ @log ? [
300
+ forced_ticks || [min, *(1...8).map{ |i| Math.exp(Math.log(min - min + 1) + (Math.log(max - min + 1) - Math.log(min - min + 1)) * i * 0.125) + min - 1 }, max],
301
+ -> x { (Math.log(x - min + 1) - Math.log(min - min + 1)) * 1.0 / (Math.log(max - min + 1) - Math.log(min - min + 1)) }
302
+ ] : [
303
+ forced_ticks || [min, *(1...8).map{ |i| min + ( max - min ) * i * 0.125 }, max],
304
+ -> x { ( x - min ) * 1.0 / ( max - min ) }
305
+ ]
306
+ else
307
+ unique_values = forced_ticks || values.uniq
308
+ [
309
+ unique_values,
310
+ -> x { unique_values.index(x) * 1.0 / (unique_values.size - 1) }
311
+ ]
312
+ end
240
313
  end
241
- class Grid < Group
242
- def initialize args = {}
243
- args[:fill_color] = "white"
244
- super
245
- if @xn*(@y2-@y1) > (@x2-@x1)*@yn
246
- y = (@x2-@x1)*@yn/@xn
247
- @y1 = (DEFAULT_SIZE-y)/2
248
- @y2 = (DEFAULT_SIZE+y)/2
249
- else
250
- x = (@y2-@y1)*@xn/@yn
251
- @x1 = (DEFAULT_SIZE-x)/2
252
- @x2 = (DEFAULT_SIZE+x)/2
253
- end
254
- w = (@x2 - @x1)/@xn
255
- h = (@y2 - @y1)/@yn
256
- [*0...@yn].product([*0...@xn]) do |i,j|
257
- self << cell = Group.new(
258
- x: @x1+j*w,
259
- y: @y1+i*h,
260
- scale_x: w/DEFAULT_SIZE,
261
- scale_y: h/DEFAULT_SIZE,
262
- )
263
- cell << Rect.new(stroke_color:"silver", stroke_width:DEFAULT_SIZE/10) if args[:grid]
264
- cell << inside = Group.new(
265
- x: DEFAULT_SIZE*0.1,
266
- y: DEFAULT_SIZE*0.1,
267
- scale_x: 0.8,
268
- scale_y: 0.8,
269
- )
270
- yield inside,i,j if block_given?
271
- end
272
- end
314
+ ticks_x, f_x = ticks[ arrays.flat_map{ |array| array[:data].transpose[0] }, @ticks_x ]
315
+ ticks_y, f_y = ticks[ arrays.flat_map{ |array| array[:data].transpose[1] }, @ticks_y ]
316
+ ticks_x.each do |tick|
317
+ field << Line.new(
318
+ y1: 1.025, x1: f_x[tick], x2: f_x[tick]
319
+ ) << Line.new(
320
+ x1: f_x[tick], x2: f_x[tick], stroke_color: "silver"
321
+ ) << (Group.new(
322
+ y: 1.025, x: f_x[tick], rotate: 90
323
+ ) << (Text.new(x: 0, y: 0, size: text_size,
324
+ #baseline: "text-before-edge",
325
+ anchor: "begin",
326
+ #style: "writing-mode: tb;",
327
+ ) << tick.to_s)
328
+ )
273
329
  end
274
- class Plot < Group
275
- def initialize args = {}
276
- args[:stroke_width] = DEFAULT_SIZE * 0.002
277
- args[:fill_color] = "white"
278
- super
279
- @lines = []
280
- end
281
- def add_line args = {}
282
- args[:data_pairs] = Hash[args[:data_pairs].to_a]
283
- @lines << args
284
- self
285
- end
286
- def to_s
287
- return @to_s_cached if @to_s_cached
288
- ticks = lambda do |basics|
289
- if basics.any?{ |i| ! i.is_a? Integer }
290
- [
291
- basics.uniq,
292
- -> x { DEFAULT_SIZE * basics.index(x) / (basics.size-1) }
293
- ]
294
- else
295
- min, max = basics.minmax
296
- [
297
- [min, *(1...8).map{ |i| (max-min)*i/8 }, max],
298
- -> x { DEFAULT_SIZE * (x - min) / (max - min) }
299
- ]
300
- end
301
- end
302
- ticks_x, f_x = ticks[ @ticks_x || @lines.flat_map{ |line| line[:data_pairs].keys } ]
303
- ticks_y, f_y = ticks[ @lines.flat_map{ |line| line[:data_pairs].values } ]
304
- top, left, scale = 0.05, 0.1
305
- size = DEFAULT_SIZE * 0.03
306
- self << field = Group.new(id:"TODOfield", x: DEFAULT_SIZE * left, y: DEFAULT_SIZE * top, scale: 0.7)
307
- hsv2rgb = lambda do |h,s,v|
308
- vmin = (100-s)*v/100
309
- a = (v - vmin)*(h % 60)/60.0
310
- vinc = vmin + a
311
- vdec = v - a
312
- case h/60
313
- when 0 ; [v, vinc, vmin]
314
- when 1 ; [vdec, v, vmin]
315
- when 2 ; [vmin, v, vinc]
316
- when 3 ; [vmin, vdec, v]
317
- when 4 ; [vinc, vmin, v]
318
- when 5 ; [v, vmin, vdec]
319
- end.map{ |i| (2.55 * i).floor }
320
- end
321
- colors = (0...@lines.size).map{ |i| ?# + hsv2rgb[i*360/@lines.size, 100, 100].pack("C*").unpack("H*").first }
322
- @lines.zip(colors).each_with_index do |(line, color), i|
323
- #@@id = defined?(@@id) ? @@id + 1 : 0
324
- field << (Text.new(
325
- #id: @@id,
326
- fill_color: "black",# color.tr("0123456789abcdef", "fedcba9876543210"),
327
- stroke_color: "none",
328
- size: DEFAULT_SIZE * 0.03,
329
- x: DEFAULT_SIZE * 0.12,
330
- y: DEFAULT_SIZE * (0.05 + i * 0.03),
331
- anchor: "begin",
332
- baseline: "text-before-edge",
333
- ) << line[:title])
334
- field << Rect.new(
335
- x1: DEFAULT_SIZE * 0.05,
336
- y1: DEFAULT_SIZE * (0.05 + i * 0.03),
337
- width: DEFAULT_SIZE * 0.05,
338
- height: DEFAULT_SIZE * 0.03,
339
- fill_color: color,
340
- )
341
- end
342
- @lines.zip(colors).each_with_index do |(line, color), i|
343
- field << Path.new(
344
- stroke_color: color,
345
- points: line[:data_pairs].map{ |k,v| [f_x[k], DEFAULT_SIZE-f_y[v]] }
346
- )
347
- end
348
- field << Text.new(
349
- id: "tooltip",
350
- visibility: "hidden",
351
- baseline: "before-edge",
352
- size: DEFAULT_SIZE * 0.03,
353
- stroke_color: "none",
354
- )
355
- field << (Script.new(id: "TODOscript") << "
356
- var svg = document.getElementById(\"TODOscript\").ownerSVGElement;
357
- svg.tooltip = svg.getElementById(\"tooltip\");
358
- function show_tooltip(evt, text, x, y) {
359
- var tooltip = evt.target.ownerSVGElement.tooltip;
360
- tooltip.setAttributeNS(null, \"x\", x);
361
- tooltip.setAttributeNS(null, \"y\", y);
362
- tooltip.textContent = text;
363
- tooltip.setAttributeNS(null, \"visibility\", \"visible\");
364
- }
365
- function hide_tooltip(evt) { evt.target.ownerSVGElement.tooltip.setAttributeNS(null, \"visibility\", \"hidden\"); }
366
- ")
367
- @lines.zip(colors) do |line, color| line[:data_pairs].each do |k,v|
368
- x = f_x[k]
369
- y = DEFAULT_SIZE - f_y[v]
370
- field << Circle.new(
371
- fill_color: color,
372
- stroke_color: color,
373
- x: x,
374
- y: y,
375
- r: DEFAULT_SIZE * 0.005,
376
- onmousemove: "show_tooltip(evt, '#{k}/#{v} - #{line[:title]}', #{x}, #{y - DEFAULT_SIZE*0.025})",
377
- onmouseout: "hide_tooltip(evt)",
378
- )
379
- end end
380
- field << Rect.new(fill_color:"none")
381
- ticks_x.each_with_index{ |tick, i| _ = f_x[tick]
382
- field << Line.new(y1: DEFAULT_SIZE * 1.025, x1:_, x2:_)
383
- field << tick_group = Group.new(x: _, y: DEFAULT_SIZE * 1.025, rotate: 90)
384
- tick_group << (Text.new(x: 0, y: 0, size: size,
385
- #baseline: "text-before-edge",
386
- anchor: "begin",
387
- #style: "writing-mode: tb;",
388
- ) << tick.to_s)
389
- }
390
- ticks_y.each{ |tick| _ = f_y[tick]
391
- field << Line.new(x2: -DEFAULT_SIZE * 0.025, y1:_, y2:_) <<
392
- (Text.new(y: DEFAULT_SIZE - _, x: -DEFAULT_SIZE * left * 0.3, size: size, anchor: "end") << tick.to_s)
393
- }
394
- @to_s_cached = super
395
- end
330
+ ticks_y.each do |tick|
331
+ field << Line.new(
332
+ x2: -0.025, y1: 1 - f_y[tick], y2: 1 - f_y[tick]
333
+ ) << Line.new(
334
+ y1: 1 - f_y[tick], y2: 1 - f_y[tick], stroke_color: "silver"
335
+ ) << (Text.new(
336
+ y: 1 - f_y[tick], x: -left * 0.2, size: text_size, anchor: "end"
337
+ ) << tick.to_s
338
+ )
396
339
  end
340
+ (0...arrays.size).map do |i|
341
+ ?# + lambda do |h,s,v|
342
+ vmin = (100 - s) * v / 100
343
+ a = (v - vmin) * (h % 60) / 60.0
344
+ vinc = vmin + a
345
+ vdec = v - a
346
+ case h / 60
347
+ when 0 ; [v, vinc, vmin]
348
+ when 1 ; [vdec, v, vmin]
349
+ when 2 ; [vmin, v, vinc]
350
+ when 3 ; [vmin, vdec, v]
351
+ when 4 ; [vinc, vmin, v]
352
+ when 5 ; [v, vmin, vdec]
353
+ end.map{ |i| (2.55 * i).floor }
354
+ end.call(i * 360 / arrays.size, 100, 100).pack("C*").unpack("H*").first
355
+ end.zip(arrays).each_with_index do |(color, line), i|
356
+ #@@id = defined?(@@id) ? @@id + 1 : 0
357
+ field << (Text.new( # Legend text
358
+ #id: @@id,
359
+ # fill_color: color.tr("0123456789abcdef", "fedcba9876543210"),
360
+ size: text_size,
361
+ x: 0.12,
362
+ y: (0.025 + i * 0.03),
363
+ anchor: "begin",
364
+ baseline: "text-before-edge",
365
+ ) << line[:title]) << Rect.new( # Legend rectangle
366
+ x: 0.05,
367
+ y: 0.035 + i * 0.03,
368
+ width: 0.05,
369
+ height: 0.03,
370
+ fill_color: line[:color] || color,
371
+ ) if arrays.size > 1
372
+ line[:data].each do |x, y, info| # Line verticles
373
+ cx = f_x[x]
374
+ cy = 1 - f_y[y]
375
+ require "cgi"
376
+ field << Circle.new(
377
+ cx: cx.round(3),
378
+ cy: cy.round(3),
379
+ r: 0.005 * (line[:r] || 1),
380
+ stroke_width: line[:verticles_stroke_width],
381
+ fill_color: line[:color] || color,
382
+ # stroke_color: color,
383
+ onmousemove: "s(evt," +
384
+ " '(#{x}, #{y})#{" #{CGI.escapeHTML info}" if info}" \
385
+ "#{" \\'#{line[:title]}\\'" if arrays.size > 1}'," +
386
+ " #{(DEFAULT_SIZE * cx ).round(3)}," +
387
+ " #{(DEFAULT_SIZE * (cy - 0.025)).round(3)})",
388
+ onmouseout: "h(evt)",
389
+ )
390
+ end
391
+ field << Path.new( # Line itself
392
+ stroke_color: line[:color] || color,
393
+ stroke_width: line[:edges_stroke_width],
394
+ points: line[:data].map{ |k, v, | [f_x[k], 1 - f_y[v]] }
395
+ ) if line[:connected]
396
+ end
397
+ field << Text.new(
398
+ id: "tooltip",
399
+ visibility: "hidden",
400
+ baseline: "before-edge",
401
+ size: text_size,
402
+ ) << (Script.new(id: "TODOscript") << "
403
+ var svg = document.getElementById(\"TODOscript\").ownerSVGElement;
404
+ svg.tooltip = svg.getElementById(\"tooltip\");
405
+ function s(evt, text, x, y) {
406
+ var tooltip = evt.target.ownerSVGElement.tooltip;
407
+ tooltip.setAttributeNS(null, \"x\", x);
408
+ tooltip.setAttributeNS(null, \"y\", y);
409
+ tooltip.textContent = text;
410
+ tooltip.setAttributeNS(null, \"visibility\", \"visible\");
411
+ }
412
+ function h(evt) { evt.target.ownerSVGElement.tooltip.setAttributeNS(null, \"visibility\", \"hidden\"); }
413
+ ")
414
+ @to_s_cached = super
415
+ end
416
+ def add_line array
417
+ add_array array, true
418
+ end
419
+ def add_dots array
420
+ add_array array, false
421
+ end
422
+ private
423
+ def add_array array, connected
424
+ # array[:data] =
425
+ array[:connected] = connected
426
+ # array[:data] = Hash[array[:data]]
427
+ arrays << array
428
+ self
429
+ end
430
+ def arrays
431
+ @arrays ||= []
432
+ end
397
433
  end
434
+ end
398
435
 
399
436
  end
400
-
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rsvgr
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.2
4
+ version: 0.0.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Victor Maslov
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-07-11 00:00:00.000000000 Z
11
+ date: 2015-08-09 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: not ready for public usage -- uploaded for personal usage
14
14
  email: nakilon@gmail.com