peity_vanilla_rails 0.1.1 → 0.2.1

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.
@@ -0,0 +1,421 @@
1
+ /*!
2
+ Peity Vanila JS 0.0.8
3
+ Copyright © 2022 RailsJazz
4
+ https://railsjazz.com
5
+ */
6
+
7
+ const isFunction = (o) =>
8
+ o !== null && typeof o === "function" && !!o.apply;
9
+
10
+ const svgElement = (tag, attrs) => {
11
+ const element = document.createElementNS("http://www.w3.org/2000/svg", tag);
12
+ for (var attr in attrs) {
13
+ element.setAttribute(attr, attrs[attr]);
14
+ }
15
+ return element;
16
+ };
17
+
18
+ const svgSupported =
19
+ "createElementNS" in document && svgElement("svg", {}).createSVGRect();
20
+
21
+ class Peity {
22
+ static defaults = {};
23
+ static graphers = {};
24
+
25
+ constructor(element, type, options = {}) {
26
+ this.element = element;
27
+ this.type = type;
28
+ this.options = Object.assign(
29
+ {},
30
+ Peity.defaults[this.type],
31
+ JSON.parse(element.dataset["peity"] || "{}"),
32
+ options
33
+ );
34
+
35
+ if(this.element._peity) {
36
+ this.element._peity.destroy();
37
+ }
38
+ this.element._peity = this;
39
+ }
40
+
41
+ draw() {
42
+ const options = this.options;
43
+ Peity.graphers[this.type](this);
44
+ if (isFunction(options.after)) options.after.call(this, options);
45
+ }
46
+
47
+ fill() {
48
+ var fill = this.options.fill;
49
+
50
+ return isFunction(fill)
51
+ ? fill
52
+ : function (_, i) {
53
+ return fill[i % fill.length];
54
+ };
55
+ }
56
+
57
+ prepare(width, height) {
58
+ if (!this.svg) {
59
+ this.element.style.display = "none";
60
+ this.element.after(
61
+ (this.svg = svgElement("svg", {
62
+ class: "peity",
63
+ }))
64
+ );
65
+ }
66
+
67
+ this.svg.innerHTML = "";
68
+ this.svg.setAttribute("width", width);
69
+ this.svg.setAttribute("height", height);
70
+
71
+ return this.svg;
72
+ }
73
+
74
+ get values() {
75
+ return this.element.innerText
76
+ .split(this.options.delimiter)
77
+ .map((value) => parseFloat(value));
78
+ }
79
+
80
+ mount() {
81
+ if (!svgSupported) return;
82
+
83
+ this.element.addEventListener("DOMSubtreeModified", this.draw.bind(this));
84
+ this.draw();
85
+
86
+ this.mounted = true;
87
+ }
88
+
89
+ unmount() {
90
+ this.element.removeEventListener("DOMSubtreeModified", this.draw);
91
+ this.svg.remove();
92
+ this.mounted = false;
93
+ }
94
+
95
+ destroy() {
96
+ this.unmount();
97
+
98
+ delete this.element._peity;
99
+ }
100
+
101
+ static register(type, defaults, grapher) {
102
+ Peity.defaults[type] = defaults;
103
+ Peity.graphers[type] = grapher;
104
+ }
105
+ }
106
+
107
+ const renderer$2 = (peity) => {
108
+ if (!peity.options.delimiter) {
109
+ const delimiter = peity.element.innerText.match(/[^0-9\.]/);
110
+ peity.options.delimiter = delimiter ? delimiter[0] : ",";
111
+ }
112
+
113
+ let values = peity.values.map((n) => (n > 0 ? n : 0));
114
+
115
+ if (peity.options.delimiter == "/") {
116
+ let v1 = values[0];
117
+ let v2 = values[1];
118
+ values = [v1, Math.max(0, v2 - v1)];
119
+ }
120
+
121
+ let i = 0;
122
+ let length = values.length;
123
+ let sum = 0;
124
+
125
+ for (; i < length; i++) {
126
+ sum += values[i];
127
+ }
128
+
129
+ if (!sum) {
130
+ length = 2;
131
+ sum = 1;
132
+ values = [0, 1];
133
+ }
134
+
135
+ let diameter = peity.options.radius * 2;
136
+
137
+ const svg = peity.prepare(
138
+ peity.options.width || diameter,
139
+ peity.options.height || diameter
140
+ );
141
+
142
+ const width = svg.clientWidth;
143
+ const height = svg.clientHeight;
144
+ const cx = width / 2;
145
+ const cy = height / 2;
146
+
147
+ const radius = Math.min(cx, cy);
148
+ let innerRadius = peity.options.innerRadius;
149
+
150
+ if (peity.type == "donut" && !innerRadius) {
151
+ innerRadius = radius * 0.5;
152
+ }
153
+
154
+ const fill = peity.fill();
155
+
156
+ const scale = (value, radius) => {
157
+ const radians = (value / sum) * Math.PI * 2 - Math.PI / 2;
158
+
159
+ return [radius * Math.cos(radians) + cx, radius * Math.sin(radians) + cy];
160
+ };
161
+
162
+ let cumulative = 0;
163
+
164
+ for (i = 0; i < length; i++) {
165
+ const value = values[i];
166
+ const portion = value / sum;
167
+ let node;
168
+
169
+ if (portion == 0) continue;
170
+
171
+ if (portion == 1) {
172
+ if (innerRadius) {
173
+ const x2 = cx - 0.01;
174
+ const y1 = cy - radius;
175
+ const y2 = cy - innerRadius;
176
+
177
+ node = svgElement("path", {
178
+ d: [
179
+ "M",
180
+ cx,
181
+ y1,
182
+ "A",
183
+ radius,
184
+ radius,
185
+ 0,
186
+ 1,
187
+ 1,
188
+ x2,
189
+ y1,
190
+ "L",
191
+ x2,
192
+ y2,
193
+ "A",
194
+ innerRadius,
195
+ innerRadius,
196
+ 0,
197
+ 1,
198
+ 0,
199
+ cx,
200
+ y2,
201
+ ].join(" "),
202
+ "data-value": value,
203
+ });
204
+ } else {
205
+ node = svgElement("circle", {
206
+ cx: cx,
207
+ cy: cy,
208
+ "data-value": value,
209
+ r: radius,
210
+ });
211
+ }
212
+ } else {
213
+ const cumulativePlusValue = cumulative + value;
214
+
215
+ let d = ["M"].concat(
216
+ scale(cumulative, radius),
217
+ "A",
218
+ radius,
219
+ radius,
220
+ 0,
221
+ portion > 0.5 ? 1 : 0,
222
+ 1,
223
+ scale(cumulativePlusValue, radius),
224
+ "L"
225
+ );
226
+
227
+ if (innerRadius) {
228
+ d = d.concat(
229
+ scale(cumulativePlusValue, innerRadius),
230
+ "A",
231
+ innerRadius,
232
+ innerRadius,
233
+ 0,
234
+ portion > 0.5 ? 1 : 0,
235
+ 0,
236
+ scale(cumulative, innerRadius)
237
+ );
238
+ } else {
239
+ d.push(cx, cy);
240
+ }
241
+
242
+ cumulative += value;
243
+
244
+ node = svgElement("path", {
245
+ d: d.join(" "),
246
+ "data-value": value,
247
+ });
248
+ }
249
+
250
+ node.setAttribute("fill", fill.call(peity, value, i, values));
251
+
252
+ svg.append(node);
253
+ }
254
+ };
255
+
256
+ const defaults$2 = {
257
+ fill: ["#ff9900", "#fff4dd", "#ffc66e"],
258
+ radius: 8,
259
+ };
260
+
261
+ const renderer$1 = (peity) => {
262
+ const values = peity.values;
263
+ const max = Math.max.apply(
264
+ Math,
265
+ peity.options.max == undefined ? values : values.concat(peity.options.max)
266
+ );
267
+ const min = Math.min.apply(
268
+ Math,
269
+ peity.options.min == undefined ? values : values.concat(peity.options.min)
270
+ );
271
+
272
+ const svg = peity.prepare(peity.options.width, peity.options.height);
273
+ const width = svg.clientWidth;
274
+ const height = svg.clientHeight;
275
+ const diff = max - min;
276
+ const padding = peity.options.padding;
277
+ const fill = peity.fill();
278
+
279
+ const xScale = (input) => {
280
+ return (input * width) / values.length;
281
+ };
282
+
283
+ const yScale = (input) => {
284
+ return height - (diff ? ((input - min) / diff) * height : 1);
285
+ };
286
+
287
+ for (var i = 0; i < values.length; i++) {
288
+ let x = xScale(i + padding);
289
+ let w = xScale(i + 1 - padding) - x;
290
+ let value = values[i];
291
+ let valueY = yScale(value);
292
+ let y1 = valueY;
293
+ let y2 = valueY;
294
+ let h;
295
+
296
+ if (!diff) {
297
+ h = 1;
298
+ } else if (value < 0) {
299
+ y1 = yScale(Math.min(max, 0));
300
+ } else {
301
+ y2 = yScale(Math.max(min, 0));
302
+ }
303
+
304
+ h = y2 - y1;
305
+
306
+ if (h == 0) {
307
+ h = 1;
308
+ if (max > 0 && diff) y1--;
309
+ }
310
+
311
+ svg.append(
312
+ svgElement("rect", {
313
+ "data-value": value,
314
+ fill: fill.call(peity, value, i, values),
315
+ x: x,
316
+ y: y1,
317
+ width: w,
318
+ height: h,
319
+ })
320
+ );
321
+ }
322
+ };
323
+
324
+ const defaults$1 = {
325
+ delimiter: ",",
326
+ fill: ["#4D89F9"],
327
+ height: 16,
328
+ min: 0,
329
+ padding: 0.1,
330
+ width: 32,
331
+ };
332
+
333
+ const renderer = (peity) => {
334
+ const values = peity.values;
335
+ if (values.length == 1) values.push(values[0]);
336
+ const max = Math.max.apply(
337
+ Math,
338
+ peity.options.max == undefined ? values : values.concat(peity.options.max)
339
+ );
340
+ const min = Math.min.apply(
341
+ Math,
342
+ peity.options.min == undefined ? values : values.concat(peity.options.min)
343
+ );
344
+
345
+ const svg = peity.prepare(peity.options.width, peity.options.height);
346
+ const strokeWidth = peity.options.strokeWidth;
347
+ const width = svg.clientWidth;
348
+ const height = svg.clientHeight - strokeWidth;
349
+ const diff = max - min;
350
+
351
+ const xScale = (input) => {
352
+ return input * (width / (values.length - 1));
353
+ };
354
+
355
+ const yScale = (input) => {
356
+ let y = height;
357
+
358
+ if (diff) {
359
+ y -= ((input - min) / diff) * height;
360
+ }
361
+
362
+ return y + strokeWidth / 2;
363
+ };
364
+
365
+ let zero = yScale(Math.max(min, 0));
366
+ let coords = [0, zero];
367
+
368
+ for (var i = 0; i < values.length; i++) {
369
+ coords.push(xScale(i), yScale(values[i]));
370
+ }
371
+
372
+ coords.push(width, zero);
373
+
374
+ if (peity.options.fill) {
375
+ svg.append(
376
+ svgElement("polygon", {
377
+ fill: peity.options.fill,
378
+ points: coords.join(" "),
379
+ })
380
+ );
381
+ }
382
+
383
+ if (strokeWidth) {
384
+ svg.append(
385
+ svgElement("polyline", {
386
+ fill: "none",
387
+ points: coords.slice(2, coords.length - 2).join(" "),
388
+ stroke: peity.options.stroke,
389
+ "stroke-width": strokeWidth,
390
+ "stroke-linecap": "square",
391
+ })
392
+ );
393
+ }
394
+ };
395
+
396
+ const defaults = {
397
+ delimiter: ",",
398
+ fill: "#c6d9fd",
399
+ height: 16,
400
+ min: 0,
401
+ stroke: "#4d89f9",
402
+ strokeWidth: 1,
403
+ width: 32,
404
+ };
405
+
406
+ Peity.register("pie", defaults$2, renderer$2);
407
+ Peity.register("donut", defaults$2, renderer$2);
408
+ Peity.register("bar", defaults$1, renderer$1);
409
+ Peity.register("line", defaults, renderer);
410
+
411
+ const peity = function (element, type, options) {
412
+ const peity = new Peity(element, type, options);
413
+ peity.mount();
414
+
415
+ return peity;
416
+ };
417
+
418
+ peity.defaults = Peity.defaults;
419
+ peity.graphers = Peity.graphers;
420
+
421
+ export { peity as default };
@@ -0,0 +1,6 @@
1
+ var peity=function(){"use strict";
2
+ /*!
3
+ Peity Vanila JS 0.0.8
4
+ Copyright © 2022 RailsJazz
5
+ https://railsjazz.com
6
+ */const t=t=>null!==t&&"function"==typeof t&&!!t.apply,e=(t,e)=>{const i=document.createElementNS("http://www.w3.org/2000/svg",t);for(var n in e)i.setAttribute(n,e[n]);return i},i="createElementNS"in document&&e("svg",{}).createSVGRect();class n{static defaults={};static graphers={};constructor(t,e,i={}){this.element=t,this.type=e,this.options=Object.assign({},n.defaults[this.type],JSON.parse(t.dataset.peity||"{}"),i),this.element._peity&&this.element._peity.destroy(),this.element._peity=this}draw(){const e=this.options;n.graphers[this.type](this),t(e.after)&&e.after.call(this,e)}fill(){var e=this.options.fill;return t(e)?e:function(t,i){return e[i%e.length]}}prepare(t,i){return this.svg||(this.element.style.display="none",this.element.after(this.svg=e("svg",{class:"peity"}))),this.svg.innerHTML="",this.svg.setAttribute("width",t),this.svg.setAttribute("height",i),this.svg}get values(){return this.element.innerText.split(this.options.delimiter).map((t=>parseFloat(t)))}mount(){i&&(this.element.addEventListener("DOMSubtreeModified",this.draw.bind(this)),this.draw(),this.mounted=!0)}unmount(){this.element.removeEventListener("DOMSubtreeModified",this.draw),this.svg.remove(),this.mounted=!1}destroy(){this.unmount(),delete this.element._peity}static register(t,e,i){n.defaults[t]=e,n.graphers[t]=i}}const s=t=>{if(!t.options.delimiter){const e=t.element.innerText.match(/[^0-9\.]/);t.options.delimiter=e?e[0]:","}let i=t.values.map((t=>t>0?t:0));if("/"==t.options.delimiter){let t=i[0],e=i[1];i=[t,Math.max(0,e-t)]}let n=0,s=i.length,o=0;for(;n<s;n++)o+=i[n];o||(s=2,o=1,i=[0,1]);let l=2*t.options.radius;const a=t.prepare(t.options.width||l,t.options.height||l),r=a.clientWidth,h=a.clientHeight,p=r/2,d=h/2,c=Math.min(p,d);let u=t.options.innerRadius;"donut"!=t.type||u||(u=.5*c);const m=t.fill(),f=(t,e)=>{const i=t/o*Math.PI*2-Math.PI/2;return[e*Math.cos(i)+p,e*Math.sin(i)+d]};let g=0;for(n=0;n<s;n++){const s=i[n],l=s/o;let r;if(0!=l){if(1==l)if(u){const t=p-.01,i=d-c,n=d-u;r=e("path",{d:["M",p,i,"A",c,c,0,1,1,t,i,"L",t,n,"A",u,u,0,1,0,p,n].join(" "),"data-value":s})}else r=e("circle",{cx:p,cy:d,"data-value":s,r:c});else{const t=g+s;let i=["M"].concat(f(g,c),"A",c,c,0,l>.5?1:0,1,f(t,c),"L");u?i=i.concat(f(t,u),"A",u,u,0,l>.5?1:0,0,f(g,u)):i.push(p,d),g+=s,r=e("path",{d:i.join(" "),"data-value":s})}r.setAttribute("fill",m.call(t,s,n,i)),a.append(r)}}},o={fill:["#ff9900","#fff4dd","#ffc66e"],radius:8};n.register("pie",o,s),n.register("donut",o,s),n.register("bar",{delimiter:",",fill:["#4D89F9"],height:16,min:0,padding:.1,width:32},(t=>{const i=t.values,n=Math.max.apply(Math,null==t.options.max?i:i.concat(t.options.max)),s=Math.min.apply(Math,null==t.options.min?i:i.concat(t.options.min)),o=t.prepare(t.options.width,t.options.height),l=o.clientWidth,a=o.clientHeight,r=n-s,h=t.options.padding,p=t.fill(),d=t=>t*l/i.length,c=t=>a-(r?(t-s)/r*a:1);for(var u=0;u<i.length;u++){let l,a=d(u+h),m=d(u+1-h)-a,f=i[u],g=c(f),v=g,y=g;r?f<0?v=c(Math.min(n,0)):y=c(Math.max(s,0)):l=1,l=y-v,0==l&&(l=1,n>0&&r&&v--),o.append(e("rect",{"data-value":f,fill:p.call(t,f,u,i),x:a,y:v,width:m,height:l}))}})),n.register("line",{delimiter:",",fill:"#c6d9fd",height:16,min:0,stroke:"#4d89f9",strokeWidth:1,width:32},(t=>{const i=t.values;1==i.length&&i.push(i[0]);const n=Math.max.apply(Math,null==t.options.max?i:i.concat(t.options.max)),s=Math.min.apply(Math,null==t.options.min?i:i.concat(t.options.min)),o=t.prepare(t.options.width,t.options.height),l=t.options.strokeWidth,a=o.clientWidth,r=o.clientHeight-l,h=n-s,p=t=>{let e=r;return h&&(e-=(t-s)/h*r),e+l/2};let d=p(Math.max(s,0)),c=[0,d];for(var u=0;u<i.length;u++)c.push(u*(a/(i.length-1)),p(i[u]));c.push(a,d),t.options.fill&&o.append(e("polygon",{fill:t.options.fill,points:c.join(" ")})),l&&o.append(e("polyline",{fill:"none",points:c.slice(2,c.length-2).join(" "),stroke:t.options.stroke,"stroke-width":l,"stroke-linecap":"square"}))}));const l=function(t,e,i){const s=new n(t,e,i);return s.mount(),s};return l.defaults=n.defaults,l.graphers=n.graphers,l}();
@@ -0,0 +1,2 @@
1
+ pin 'peity-vanilla', to: 'peity-vanilla.esm.js'
2
+ pin 'peity-vanilla-rails', to: 'peity-vanilla-rails.esm.js'
@@ -1,15 +1,10 @@
1
1
  module PeityVanillaRails
2
2
  class Railtie < ::Rails::Engine
3
+ PRECOMPILE_ASSETS = %w( peity-vanilla-rails.esm.js peity-vanilla.esm.js )
3
4
  initializer "peity_vanilla_rails.importmap", before: "importmap" do |app|
4
- if defined?(Importmap)
5
- app.config.importmap.cache_sweepers << root.join("app/assets/javascripts")
6
- end
7
- end
8
-
9
- PRECOMPILE_ASSETS = Dir[root.join("app/assets/javascripts/**/*")]
10
- initializer 'peity_vanilla_rails.assets' do |app|
11
- if app.config.respond_to?(:assets)
5
+ if Rails.application.respond_to?(:importmap)
12
6
  app.config.assets.precompile += PRECOMPILE_ASSETS
7
+ app.config.importmap.paths << root.join("config/importmap.rb")
13
8
  end
14
9
  end
15
10
 
@@ -1,52 +1,28 @@
1
1
  module PeityVanillaRails
2
2
  module Helpers
3
-
4
- def peity_line_chart(data, options: {})
5
- peity_chart(data, "line", ",", options: options)
3
+
4
+ def peity_line_chart(data, id: nil, options: {})
5
+ peity_chart(data, "line", ",", id: id, options: options)
6
6
  end
7
7
 
8
- def peity_bar_chart(data, options: {})
9
- peity_chart(data, "bar", ",", options: options)
8
+ def peity_bar_chart(data, id: nil, options: {})
9
+ peity_chart(data, "bar", ",", id: id, options: options)
10
10
  end
11
11
 
12
- def peity_pie_chart(data, options: {})
13
- peity_chart(data, "pie", "/", options: options)
12
+ def peity_pie_chart(data, id: nil, options: {})
13
+ peity_chart(data, "pie", "/", id: id, options: options)
14
14
  end
15
15
 
16
- def peity_donut_chart(data, options: {})
17
- peity_chart(data, "donut", "/", options: options)
16
+ def peity_donut_chart(data, id: nil, options: {})
17
+ peity_chart(data, "donut", "/", id: id, options: options)
18
18
  end
19
19
 
20
- def peity_chart(value, type, delimiter, options: {})
20
+ def peity_chart(value, type, delimiter, id: nil, options: {})
21
21
  value = value.is_a?(Array) ? value.join(delimiter) : value
22
- id = "peity_charts_#{Digest::SHA1.hexdigest([Time.now, rand].join)}"
23
- [
24
- tag.span(class: 'peity_charts', id: id, "data-peity" => options.to_json) do
25
- value
26
- end,
27
- tag.script do
28
- %Q{
29
- function init_peity_charts_#{id}() {
30
- var element = document.getElementById("#{id}");
31
-
32
- if (!element) {
33
- return;
34
- }
35
-
36
- if(element.getAttribute("data-_peity")) {
37
- return;
38
- }
39
-
40
- window.peity(element, "#{type}");
41
- }
42
-
43
- window.addEventListener('load', init_peity_charts_#{id});
44
- window.addEventListener('turbo:load', init_peity_charts_#{id});
45
- window.addEventListener('turbolinks:load', init_peity_charts_#{id});
46
- }.html_safe
47
- end
48
- ].join.html_safe
49
- end
22
+ tag.span(id: id, class: 'peity_charts', peity: type, style: 'display: none;', data: { peity: options.to_json }) do
23
+ value
24
+ end
25
+ end
50
26
 
51
27
  end
52
28
  end
@@ -1,3 +1,3 @@
1
1
  module PeityVanillaRails
2
- VERSION = "0.1.1"
2
+ VERSION = "0.2.1"
3
3
  end
metadata CHANGED
@@ -1,14 +1,15 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: peity_vanilla_rails
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.1
4
+ version: 0.2.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Igor Kasyanchuk
8
+ - Liubomyr Manastyretskyi
8
9
  autorequire:
9
10
  bindir: bin
10
11
  cert_chain: []
11
- date: 2022-04-30 00:00:00.000000000 Z
12
+ date: 2022-05-24 00:00:00.000000000 Z
12
13
  dependencies:
13
14
  - !ruby/object:Gem::Dependency
14
15
  name: rails
@@ -69,6 +70,7 @@ dependencies:
69
70
  description: Sparklines are small but intense charts.
70
71
  email:
71
72
  - igorkasyanchuk@gmail.com
73
+ - manastyretskyi@gmail.com
72
74
  executables: []
73
75
  extensions: []
74
76
  extra_rdoc_files: []
@@ -76,8 +78,11 @@ files:
76
78
  - MIT-LICENSE
77
79
  - README.md
78
80
  - Rakefile
79
- - app/assets/javascripts/peity_vanilla.js
80
- - app/assets/javascripts/peity_vanilla.js.map
81
+ - app/assets/javascripts/peity-vanilla-rails.esm.js
82
+ - app/assets/javascripts/peity-vanilla-rails.min.js
83
+ - app/assets/javascripts/peity-vanilla.esm.js
84
+ - app/assets/javascripts/peity-vanilla.min.js
85
+ - config/importmap.rb
81
86
  - lib/peity_vanilla_rails.rb
82
87
  - lib/peity_vanilla_rails/engine.rb
83
88
  - lib/peity_vanilla_rails/helpers.rb
@@ -89,6 +94,7 @@ licenses:
89
94
  metadata:
90
95
  homepage_uri: https://github.com/railsjazz/peity_vanilla_rails
91
96
  source_code_uri: https://github.com/railsjazz/peity_vanilla_rails
97
+ changelog_uri: https://github.com/railsjazz/peity_vanilla_rails/releases
92
98
  post_install_message:
93
99
  rdoc_options: []
94
100
  require_paths:
@@ -104,7 +110,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
104
110
  - !ruby/object:Gem::Version
105
111
  version: '0'
106
112
  requirements: []
107
- rubygems_version: 3.2.3
113
+ rubygems_version: 3.3.7
108
114
  signing_key:
109
115
  specification_version: 4
110
116
  summary: Sparklines are small but intense charts.