rsvgr 0.0.2 → 0.0.3

Sign up to get free protection for your applications and to get access to all the features.
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