p5rb 0.0.1 → 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 +5 -5
  2. data/lib/p5rb.rb +167 -54
  3. data/p5rb.gemspec +3 -1
  4. metadata +18 -5
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 2aeb9b49c2eeadc91b80d5c207e65e71d510ec41
4
- data.tar.gz: cb3054c7c311fa1862f9395b5ff1762e055421e3
2
+ SHA256:
3
+ metadata.gz: b79ebfd6c7fa06d28955e916d1dd8c40f550eac344f03b7eaf65f6281c3bed2f
4
+ data.tar.gz: f2b2555f10efd15b009e146dc232a3b947514960cb81c81487bc0c8d39e205e1
5
5
  SHA512:
6
- metadata.gz: '074992392feb37241a790014a43b600f30f513c4307fcfddd24c0db3820eb7d69c97088fd9e44ec65ca18315133b076897ceae2487af321e38f8e2417bbff3cb'
7
- data.tar.gz: 9f1a3b74222b8d23a38cedaae63ad2d078f1e402039cbe5f767d368081a386d5dbbbeeb1a28b0db65041b5ccec5d1b2aa6b68ecfe087be9e4c41c35ec788df09
6
+ metadata.gz: 5f7ccdcb0a16223887864366aeb2957adb705d8a96bbb60f51195bda826acad9e4a7a67ae925e82f5e7f35c4fdfca2641fac32eb560e8c7d01c9ae280760e008
7
+ data.tar.gz: ee31129a27f4073937c6bb5c2bdffbcc41c9b1ae29ccb425ee7d49b1bbcca391747461899544e21bd30557d0c1fa51d5f4460d5b62f410de580fa3b01909cc72
data/lib/p5rb.rb CHANGED
@@ -3,87 +3,200 @@ module P5
3
3
  attr_reader :buffer_setup
4
4
  attr_reader :buffer_draw
5
5
  end
6
- instance_variable_set :@buffer_setup, []
7
- instance_variable_set :@buffer_draw, []
6
+ @buffer_setup = []
7
+ @buffer_draw = []
8
8
 
9
- @buffer = []
10
- class << self
11
- def background color
12
- @buffer.push "background(#{color})"
13
- end
14
- def noStroke
15
- @buffer.push "noStroke()"
16
- end
17
- def stroke color
18
- @buffer.push "stroke(#{color})"
19
- end
20
- def translate x, y
21
- @buffer.push "translate(#{x}, #{y})"
22
- end
23
- def circle x, y, r
24
- @buffer.push "circle(#{x}, #{y}, #{r})"
25
- end
26
- def ellipse *args
27
- @buffer.push "ellipse(#{args.join ?,})"
28
- end
29
- def fill color, alpha = nil
30
- @buffer.push "fill(#{color}#{", #{alpha}" if alpha})"
31
- end
32
- def rect x, y, w, h, fill: nil
33
- (@buffer.push "push()"; fill fill) if fill
34
- @buffer.push "rect(#{x}, #{y}, #{w}, #{h})"
35
- @buffer.push "pop()" if fill
36
- end
37
- def point x, y
38
- @buffer.push "point(#{x}, #{y})"
39
- end
40
- def textSize size
41
- @buffer.push "textSize(#{size})"
42
- end
43
- def textAlign *args
44
- @buffer.push "textAlign(#{args.join ", "})"
45
- end
46
- def text text, x, y, fill: nil
47
- (@buffer.push "push()"; fill fill) if fill
48
- @buffer.push "text(#{text.inspect}, #{x}, #{y})"
49
- @buffer.push "pop()" if fill
9
+ module Block
10
+ class << self
11
+ attr_writer :buffer
12
+ def raw _
13
+ @buffer.push _
14
+ end
15
+ def background color
16
+ @buffer.push "background(#{color})"
17
+ end
18
+ def noStroke
19
+ @buffer.push "noStroke()"
20
+ end
21
+ def stroke color
22
+ @buffer.push "stroke(#{color})"
23
+ end
24
+ def translate x, y
25
+ @buffer.push "translate(#{x}, #{y})"
26
+ end
27
+ def line x1, y1, x2, y2
28
+ @buffer.push "line(#{x1}, #{y1}, #{x2}, #{y2})"
29
+ end
30
+ def circle x, y, r
31
+ @buffer.push "circle(#{x}, #{y}, #{r})"
32
+ end
33
+ def ellipse *args # not tested yet
34
+ @buffer.push "ellipse(#{args.join ?,})"
35
+ end
36
+ def fill color, alpha = nil
37
+ @buffer.push "fill(#{color}#{", #{alpha}" if alpha})"
38
+ end
39
+ def rect x, y, w, h, fill: nil
40
+ (@buffer.push "push()"; fill fill) if fill
41
+ @buffer.push "rect(#{x}, #{y}, #{w}, #{h})"
42
+ @buffer.push "pop()" if fill
43
+ end
44
+ def point x, y
45
+ @buffer.push "point(#{x}, #{y})"
46
+ end
47
+ def textSize size
48
+ @buffer.push "textSize(#{size})"
49
+ end
50
+ def textAlign *args
51
+ @buffer.push "textAlign(#{args.join ", "})"
52
+ end
53
+ def textWidth text
54
+ @buffer.push "textWidth(#{text.inspect})"
55
+ end
56
+ def textAscent text
57
+ @buffer.push "textAscent(#{text.inspect})"
58
+ end
59
+ def text text, x, y, fill: nil
60
+ (@buffer.push "push()"; fill fill) if fill
61
+ @buffer.push "text(#{text.inspect}, #{x}, #{y})"
62
+ @buffer.push "pop()" if fill
63
+ end
64
+ def map *args
65
+ "map(#{args.join ", "})"
66
+ end
50
67
  end
68
+ end
51
69
 
70
+ class << self
52
71
  def setup &block
53
- module_eval &block
54
- @buffer_setup = @buffer
55
- @buffer = []
72
+ ::P5::Block.buffer = @buffer_setup
73
+ ::P5::Block.module_eval &block
56
74
  end
57
- def draw &block
58
- module_eval &block
59
- @buffer_draw = @buffer
60
- @buffer = []
75
+ def draw &block # not tested yet
76
+ ::P5::Block.buffer = @buffer_draw
77
+ ::P5::Block.module_eval &block
61
78
  end
79
+ end
62
80
 
81
+ class << self
82
+ def plot_scatter data, reverse_y: false
83
+ size = 1000
84
+ max = nil
85
+ (x_range, x_from, x_to, x_enum, x_f),
86
+ (y_range, y_from, y_to, y_enum, y_f) = data.transpose.map do |axis|
87
+ min, max = axis.minmax
88
+ range = (min - max).abs
89
+ division = 10**Math::log10(range).floor
90
+ from = min.div(division)*division
91
+ to = -(-max).div(division)*division
92
+ [
93
+ to - from,
94
+ from, to,
95
+ from.step(to, division),
96
+ ]
97
+ end
98
+ max = [x_range, y_range].max
99
+ x_f = ->_{ 20 + (size-40.0) * (_ - x_from) / max }
100
+ y_f = ->_{ 20 + (size-40.0) * (reverse_y ? y_to - _ : _ - y_from) / max }
101
+ P5 40 + (size-40.0) * x_range / max + 50, # TODO: properly fix the issue that with wide labels the right end of the plot may be cut off
102
+ 40 + (size-40.0) * y_range / max do
103
+ setup do
104
+ textSize 15
105
+ raw "const w = max([#{y_enum.map{ |_| "textWidth(#{_})" }.join ?,}])"
106
+ raw "translate(w, 15)"
107
+ stroke 200
108
+ textAlign :CENTER, :BOTTOM; x_enum.each{ |_| line x_f[_], y_f[y_from], x_f[_], y_f[y_to]; text _, x_f[_], 20-5 }
109
+ textAlign :RIGHT, :CENTER; y_enum.each{ |_| line x_f[x_from], y_f[_], x_f[x_to], y_f[_]; text _, x_f[x_from]-5, y_f[_] }
110
+ stroke 0
111
+ data.each{ |x,y| point x_f[x], y_f[y] }
112
+ end
113
+ end
114
+ end
115
+ def plot_bar_grouped data
116
+ # TODO: this is currently pretty much hardcoded for a time dates charting
117
+ cls = data.values.flat_map(&:keys).uniq.sort
118
+ size = cls.size + 1
119
+ from, to = data.keys.minmax
120
+ max = data.values.flat_map(&:values).max
121
+ P5 500, 500 do
122
+ setup do
123
+ noStroke
124
+ textAlign :CENTER
125
+ cls.each_with_index{ |_, i| text _, 50+400/(size-2)*i, 25, fill: %w{ 'red' 'green' 'blue' }[i] }
126
+ textAlign :RIGHT, :TOP
127
+ (from..to).each do |date|
128
+ y = map date.ajd.to_i, from.ajd.to_i, to.ajd.to_i, 50, 450
129
+ text date.strftime("%m-%d"), 45, y
130
+ rect 50, y, map(data.fetch(date,{})[cls[0]]||0, 0, max, 0, 400), 400/(to-from)/size, fill: "'red'"
131
+ rect 50, "#{y}+#{400/(to-from)/size}", map(data.fetch(date,{})[cls[1]]||0, 0, max, 0, 400), 400/(to-from)/size, fill: "'green'"
132
+ rect 50, "#{y}+#{800/(to-from)/size}", map(data.fetch(date,{})[cls[2]]||0, 0, max, 0, 400), 400/(to-from)/size, fill: "'blue'"
133
+ end
134
+ end
135
+ end
136
+ end
137
+ def plot_bar_stacked data, names, colorize
138
+ count = {}
139
+ max = data.map do |_, day|
140
+ day.each{ |k,v| count[k] ||= 0; count[k] += v }.map(&:last).reduce :+
141
+ end.max
142
+ pairs = {}
143
+ data.each_cons(2) do |(_, day1), (_, day2)|
144
+ (day1.map(&:first) & day2.map(&:first)).each{ |_| pairs[_] ||= 0; pairs[_] += 1 }
145
+ end
146
+ require "pcbr"
147
+ require "set"
148
+ pcbr = PCBR.new
149
+ count.max_by(colorize){ |k,v| v }.each{ |k,v| pcbr.store k, [-v, pairs[k]||0] }
150
+ top = pcbr.sorted
151
+ size = 500
152
+ P5 size, size do
153
+ setup do
154
+ noStroke
155
+ textAlign :RIGHT, :TOP
156
+ border = 25
157
+ left = "#{border} + textWidth(\"00-00 - 00-00\") + 5"
158
+ data.each_with_index do |(bin, day), i|
159
+ y1 = map i, 0, data.size, border, size-border
160
+ y2 = map i+1, 0, data.size, border, size-border
161
+ text bin, "#{left} - 5", y1
162
+ pos = 0
163
+ day.sort_by{ |k,| top.index(k) || top.size }.each do |k, v|
164
+ rect \
165
+ map(pos, 0, max, left, size-border), y1,
166
+ map(v, 0, max, 0, "#{size}-#{border}-(#{left})"), "#{y2}-#{y1}",
167
+ fill: top.include?(k) ? "color('hsl(#{(((3-Math.sqrt(5))*180 * top.index(k)) % 360).round}, 75%, 75%)')" : "color('hsl(0, 0%, 75%)')"
168
+ pos += v
169
+ end
170
+ end
171
+ top.each_with_index{ |id, i| text names[id].inspect[1..-2], size-border, "#{border} + textAscent('X') * #{i}", fill: "color('hsl(#{(((3-Math.sqrt(5))*180 * top.index(id)) % 360).round}, 75%, 75%)')" }
172
+ end
173
+ end
174
+ end
63
175
  end
64
176
  end
65
177
 
66
178
  def P5 width, height, &block
67
- P5.module_eval &block
179
+ ::P5.module_eval &block
68
180
  <<~HEREDOC
69
181
  <html>
70
182
  <head>
183
+ <meta charset="UTF-8">
71
184
  <script src="https://github.com/processing/p5.js/releases/download/v1.4.2/p5.min.js"></script>
72
185
  <script>
73
186
  function setup() {
74
187
  createCanvas(#{width}, #{height});
75
188
  #{
76
- P5.buffer_setup.join(";\n").gsub(/^/, ?\s*8)
189
+ ::P5.buffer_setup.join(";\n").gsub(/^/, ?\s*12)
77
190
  }
78
191
  }
79
192
  function draw() {
80
193
  #{
81
- P5.buffer_draw.join(";\n").gsub(/^/, ?\s*8)
194
+ ::P5.buffer_draw.join(";\n").gsub(/^/, ?\s*12)
82
195
  }
83
196
  }
84
197
  </script>
85
198
  </head>
86
- <body><main></main></body>
199
+ <body style="margin: 0"><main></main></body>
87
200
  </html>
88
201
  HEREDOC
89
202
  end
data/p5rb.gemspec CHANGED
@@ -1,6 +1,6 @@
1
1
  Gem::Specification.new do |spec|
2
2
  spec.name = "p5rb"
3
- spec.version = "0.0.1"
3
+ spec.version = "0.0.3"
4
4
  spec.summary = "Ruby DSL for p5.js"
5
5
 
6
6
  spec.author = "Victor Maslov aka Nakilon"
@@ -8,5 +8,7 @@ Gem::Specification.new do |spec|
8
8
  spec.license = "MIT"
9
9
  spec.metadata = {"source_code_uri" => "https://github.com/nakilon/p5rb"}
10
10
 
11
+ spec.add_dependency "pcbr"
12
+
11
13
  spec.files = %w{ LICENSE p5rb.gemspec lib/p5rb.rb }
12
14
  end
metadata CHANGED
@@ -1,15 +1,29 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: p5rb
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.0.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Victor Maslov aka Nakilon
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-10-10 00:00:00.000000000 Z
12
- dependencies: []
11
+ date: 2022-12-09 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: pcbr
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
13
27
  description:
14
28
  email: nakilon@gmail.com
15
29
  executables: []
@@ -39,8 +53,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
39
53
  - !ruby/object:Gem::Version
40
54
  version: '0'
41
55
  requirements: []
42
- rubyforge_project:
43
- rubygems_version: 2.5.2.3
56
+ rubygems_version: 3.3.25
44
57
  signing_key:
45
58
  specification_version: 4
46
59
  summary: Ruby DSL for p5.js