chartkick 3.3.1 → 4.0.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 3d2deed8ea6acea7a2d4e68d7a0adfb2a396ff685ddd4763a6e7dc7cc9f981b5
4
- data.tar.gz: 8c1502d6b8a5b2feda3727c23d0a39e14c1c667b4bc3856f3f106e662490517d
3
+ metadata.gz: d9ca3fe125f71ef5a1a21a191a03244b9235396f4c72f4d8e742f7d1a3feaa98
4
+ data.tar.gz: d7da49117fa84b8525bf76acc421b22e71a0a38a2f2e798c182f96f0d6780a60
5
5
  SHA512:
6
- metadata.gz: 6b662ba0dea0a3c8e116fa6428bc52bd4288a301d20395f9671a3e478199c30278db020043c534f2edd62f0971fb5a7f4fa3608136d23b40103930afa59032d2
7
- data.tar.gz: 78d2f5473da5ce6b60a68eea76bb848339f4a77981595d9bc693e6e2fd83f9010f2ce6628570c7d034140e2c1416eda246d85fcae533a7d177d3ab4ef01e8281
6
+ metadata.gz: b00a3accac3e738dc1d0fa7480d162002f5302a8e725d28bfcd3c455514fa79080559b01cfc8a897c44a8d551fdfad3b80fb39a98a9b69671ec8dfa9c2d082e4
7
+ data.tar.gz: 5a1ccaf63c5bbd240e6ef7a14e240992387cc16c7ce43e6c1b3eab8cb1b632046adbea632db17a96194a21e6e7ce2427d1997ca5734541d51b3c6d2e506a3a8f
data/CHANGELOG.md CHANGED
@@ -1,7 +1,36 @@
1
+ ## 4.0.0 (2021-04-04)
2
+
3
+ - Added support for Chart.js 3
4
+ - Added `loading` option
5
+ - Made charts deferrable by default
6
+ - Set `nonce` automatically when present
7
+ - Prefer `empty` over `messages: {empty: ...}`
8
+ - Removed support for Ruby < 2.6 and Rails < 5.2
9
+
10
+ Breaking changes
11
+
12
+ - Removed support for Chart.js 2
13
+
14
+ ## 3.4.2 (2020-10-20)
15
+
16
+ - Updated Chart.js to 2.9.4
17
+
18
+ ## 3.4.1 (2020-10-06)
19
+
20
+ - Relaxed validation for `width` and `height` options
21
+
22
+ ## 3.4.0 (2020-08-04)
23
+
24
+ - Fixed CSS injection with `width` and `height` options - [more info](https://github.com/ankane/chartkick/issues/546)
25
+
26
+ ## 3.3.2 (2020-07-23)
27
+
28
+ - Updated Chartkick.js to 3.2.1
29
+
1
30
  ## 3.3.1 (2019-12-26)
2
31
 
3
32
  - Updated Chart.js to 2.9.3
4
- - Fixed deprecating warnings in Ruby 2.7
33
+ - Fixed deprecation warnings in Ruby 2.7
5
34
 
6
35
  ## 3.3.0 (2019-11-09)
7
36
 
@@ -19,7 +48,7 @@
19
48
 
20
49
  ## 3.2.0 (2019-06-04)
21
50
 
22
- - Fixed XSS vulnerability - see [#488](https://github.com/ankane/chartkick/issues/488)
51
+ - Fixed XSS vulnerability - [more info](https://github.com/ankane/chartkick/issues/488)
23
52
 
24
53
  ## 3.1.0 (2019-05-26)
25
54
 
data/LICENSE.txt CHANGED
@@ -1,4 +1,4 @@
1
- Copyright (c) 2013-2019 Andrew Kane
1
+ Copyright (c) 2013-2021 Andrew Kane
2
2
 
3
3
  MIT License
4
4
 
data/README.md CHANGED
@@ -4,13 +4,17 @@ Create beautiful JavaScript charts with one line of Ruby. No more fighting with
4
4
 
5
5
  [See it in action](https://chartkick.com)
6
6
 
7
- :fire: For admin charts and dashboards, check out [Blazer](https://github.com/ankane/blazer/)
7
+ **Chartkick 4.0 was recently released** - see [how to upgrade](#upgrading)
8
+
9
+ :fire: For admin charts and dashboards, check out [Blazer](https://github.com/ankane/blazer/), and for advanced visualizations, check out [Vega](https://github.com/ankane/vega)
8
10
 
9
11
  :two_hearts: A perfect companion to [Groupdate](https://github.com/ankane/groupdate), [Hightop](https://github.com/ankane/hightop), and [ActiveMedian](https://github.com/ankane/active_median)
10
12
 
13
+ [![Build Status](https://github.com/ankane/chartkick/workflows/build/badge.svg?branch=master)](https://github.com/ankane/chartkick/actions)
14
+
11
15
  ## Quick Start
12
16
 
13
- Add this line to your application's Gemfile:
17
+ Add this line to your applications Gemfile:
14
18
 
15
19
  ```ruby
16
20
  gem "chartkick"
@@ -19,14 +23,13 @@ gem "chartkick"
19
23
  For Rails 6 / Webpacker, run:
20
24
 
21
25
  ```sh
22
- yarn add chartkick chart.js
26
+ yarn add chartkick
23
27
  ```
24
28
 
25
29
  And in `app/javascript/packs/application.js`, add:
26
30
 
27
31
  ```js
28
- require("chartkick")
29
- require("chart.js")
32
+ require("chartkick/chart.js")
30
33
  ```
31
34
 
32
35
  For Rails 5 / Sprockets, in `app/assets/javascripts/application.js`, add:
@@ -36,7 +39,7 @@ For Rails 5 / Sprockets, in `app/assets/javascripts/application.js`, add:
36
39
  //= require Chart.bundle
37
40
  ```
38
41
 
39
- This sets up Chartkick with Chart.js. For other charting libraries, see [detailed instructions](#installation).
42
+ This sets up Chartkick with [Chart.js](https://www.chartjs.org/). For other charting libraries, see [detailed instructions](#installation).
40
43
 
41
44
  ## Charts
42
45
 
@@ -206,12 +209,6 @@ Specify legend position
206
209
  <%= line_chart data, legend: "bottom" %>
207
210
  ```
208
211
 
209
- Defer chart creation until after the page loads
210
-
211
- ```erb
212
- <%= line_chart data, defer: true %>
213
- ```
214
-
215
212
  Donut chart
216
213
 
217
214
  ```erb
@@ -260,16 +257,22 @@ Show insignificant zeros, useful for currency - *Chart.js, Highcharts*
260
257
  <%= line_chart data, round: 2, zeros: true %>
261
258
  ```
262
259
 
263
- Friendly byte sizes - *Chart.js 2.8+*
260
+ Friendly byte sizes
264
261
 
265
262
  ```erb
266
263
  <%= line_chart data, bytes: true %>
267
264
  ```
268
265
 
266
+ Show a message when data is loading
267
+
268
+ ```erb
269
+ <%= line_chart data, loading: "Loading..." %>
270
+ ```
271
+
269
272
  Show a message when data is empty
270
273
 
271
274
  ```erb
272
- <%= line_chart data, messages: {empty: "No data"} %>
275
+ <%= line_chart data, empty: "No data" %>
273
276
  ```
274
277
 
275
278
  Refresh data from a remote source every `n` seconds
@@ -308,7 +311,7 @@ Chartkick.options = {
308
311
  Customize the html
309
312
 
310
313
  ```ruby
311
- Chartkick.options[:html] = '<div id="%{id}" style="height: %{height};">Loading...</div>'
314
+ Chartkick.options[:html] = '<div id="%{id}" style="height: %{height};">%{loading}</div>'
312
315
  ```
313
316
 
314
317
  You capture the JavaScript in a content block with:
@@ -323,7 +326,7 @@ Then, in your layout, use:
323
326
  <%= yield :charts_js %>
324
327
  ```
325
328
 
326
- > For Padrino, use `yield_content` instead of `yield`
329
+ For Padrino, use `yield_content` instead of `yield`.
327
330
 
328
331
  This is great for including all of your JavaScript at the bottom of the page.
329
332
 
@@ -370,9 +373,7 @@ If you want to use the charting library directly, get the code with:
370
373
  <%= line_chart data, code: true %>
371
374
  ```
372
375
 
373
- The code will be logged to the JavaScript console.
374
-
375
- > JavaScript functions cannot be logged, so it may not be identical.
376
+ The code will be logged to the JavaScript console. JavaScript functions cannot be logged, so it may not be identical.
376
377
 
377
378
  ### Download Charts
378
379
 
@@ -384,7 +385,7 @@ Give users the ability to download charts. It all happens in the browser - no se
384
385
  <%= line_chart data, download: true %>
385
386
  ```
386
387
 
387
- > Safari will open the image in a new window instead of downloading.
388
+ Safari will open the image in a new window instead of downloading.
388
389
 
389
390
  Set the filename
390
391
 
@@ -418,21 +419,20 @@ Next, choose your charting library.
418
419
  - [Google Charts](#google-charts)
419
420
  - [Highcharts](#highcharts)
420
421
 
421
- > In the instructions below, `application.js` must be included **before** the charts in your views, unless using the `:content_for` option.
422
+ In the instructions below, `application.js` must be included **before** the charts in your views, unless using the `:content_for` option.
422
423
 
423
424
  ### Chart.js
424
425
 
425
426
  For Rails 6 / Webpacker, run:
426
427
 
427
428
  ```sh
428
- yarn add chartkick chart.js
429
+ yarn add chartkick
429
430
  ```
430
431
 
431
432
  And in `app/javascript/packs/application.js`, add:
432
433
 
433
434
  ```js
434
- require("chartkick")
435
- require("chart.js")
435
+ require("chartkick/chart.js")
436
436
  ```
437
437
 
438
438
  For Rails 5 / Sprockets, in `app/assets/javascripts/application.js`, add:
@@ -487,7 +487,7 @@ yarn add chartkick highcharts
487
487
  And in `app/javascript/packs/application.js`, add:
488
488
 
489
489
  ```js
490
- require("chartkick").use(require("highcharts"))
490
+ require("chartkick/highcharts")
491
491
  ```
492
492
 
493
493
  For Rails 5 / Sprockets, download [highcharts.js](https://code.highcharts.com/highcharts.js) into `vendor/assets/javascripts` (or use `yarn add highcharts` in Rails 5.1+), and in `app/assets/javascripts/application.js`, add:
@@ -505,6 +505,27 @@ Download [chartkick.js](https://raw.githubusercontent.com/ankane/chartkick/maste
505
505
  <script src="chartkick.js"></script>
506
506
  ```
507
507
 
508
+ Then include the charting library.
509
+
510
+ Chart.js - download [Chart.js](https://unpkg.com/chart.js@3/dist/chart.js) and the [date-fns adapter bundle](https://unpkg.com/chartjs-adapter-date-fns@2.0.0/dist/chartjs-adapter-date-fns.bundle.js)
511
+
512
+ ```html
513
+ <script src="chart.js"></script>
514
+ <script src="chartjs-adapter-date-fns.bundle.js"></script>
515
+ ```
516
+
517
+ Google Charts
518
+
519
+ ```html
520
+ <script src="https://www.gstatic.com/charts/loader.js"></script>
521
+ ```
522
+
523
+ Highcharts - download [highcharts.js](https://code.highcharts.com/highcharts.js)
524
+
525
+ ```html
526
+ <script src="highcharts.js"></script>
527
+ ```
528
+
508
529
  ### Multiple Libraries
509
530
 
510
531
  If more than one charting library is loaded, choose between them with:
@@ -562,6 +583,12 @@ Redraw the chart with:
562
583
  chart.redraw()
563
584
  ```
564
585
 
586
+ Destroy the chart with:
587
+
588
+ ```javascript
589
+ chart.destroy()
590
+ ```
591
+
565
592
  Loop over charts with:
566
593
 
567
594
  ```javascript
@@ -587,23 +614,28 @@ Check out [chartkick.js](https://github.com/ankane/chartkick.js)
587
614
 
588
615
  ## Upgrading
589
616
 
590
- ### 3.0
617
+ ### 4.0
591
618
 
592
- Breaking changes
619
+ If you use Sprockets, update the gem and you’re good to go!
593
620
 
594
- - Removed support for Rails < 4.2
595
- - Removed chartkick.js from asset precompile (no longer needed)
596
- - Removed `xtype` option - numeric axes are automatically detected
597
- - Removed `window.Chartkick = {...}` way to set config - use `Chartkick.configure` instead
598
- - Removed support for the Google Charts jsapi loader - use loader.js instead
621
+ If you use Webpacker, run:
599
622
 
600
- ### 2.0
623
+ ```sh
624
+ yarn upgrade chartkick --latest
625
+ ```
601
626
 
602
- Breaking changes
627
+ If you use Chart.js with Webpacker, in `app/javascript/packs/application.js`, change:
603
628
 
604
- - Chart.js is now the default adapter if multiple are loaded - yay open source!
605
- - Axis types are automatically detected - no need for `discrete: true`
606
- - Better date support - dates are no longer treated as UTC
629
+ ```js
630
+ require("chartkick")
631
+ require("chart.js")
632
+ ```
633
+
634
+ to:
635
+
636
+ ```js
637
+ require("chartkick/chart.js")
638
+ ```
607
639
 
608
640
  ## Credits
609
641
 
@@ -613,8 +645,6 @@ Chartkick uses [iso8601.js](https://github.com/Do/iso8601.js) to parse dates and
613
645
 
614
646
  View the [changelog](https://github.com/ankane/chartkick/blob/master/CHANGELOG.md)
615
647
 
616
- Chartkick follows [Semantic Versioning](https://semver.org/)
617
-
618
648
  ## Contributing
619
649
 
620
650
  Everyone is encouraged to help improve this project. Here are a few ways you can help:
@@ -623,3 +653,12 @@ Everyone is encouraged to help improve this project. Here are a few ways you can
623
653
  - Fix bugs and [submit pull requests](https://github.com/ankane/chartkick/pulls)
624
654
  - Write, clarify, or fix documentation
625
655
  - Suggest or add new features
656
+
657
+ To get started with development:
658
+
659
+ ```sh
660
+ git clone https://github.com/ankane/chartkick.git
661
+ cd chartkick
662
+ bundle install
663
+ bundle exec rake test
664
+ ```
data/lib/chartkick.rb CHANGED
@@ -1,3 +1,5 @@
1
+ # modules
2
+ require "chartkick/enumerable"
1
3
  require "chartkick/helper"
2
4
  require "chartkick/version"
3
5
 
@@ -18,29 +20,3 @@ module Chartkick
18
20
  end
19
21
  self.options = {}
20
22
  end
21
-
22
- # for multiple series
23
- # use Enumerable so it can be called on arrays
24
- module Enumerable
25
- def chart_json
26
- if is_a?(Hash)
27
- if (key = keys.first) && key.is_a?(Array) && key.size == 2
28
- group_by { |k, _v| k[0] }.map do |name, data|
29
- {name: name, data: data.map { |k, v| [k[1], v] }}
30
- end
31
- else
32
- to_a
33
- end
34
- elsif is_a?(Array)
35
- map do |v|
36
- if v.is_a?(Hash) && v[:data].is_a?(Hash)
37
- v = v.dup
38
- v[:data] = v[:data].to_a
39
- end
40
- v
41
- end
42
- else
43
- self
44
- end.to_json
45
- end
46
- end
@@ -0,0 +1,25 @@
1
+ # for both multiple series and
2
+ # making sure hash order is preserved in JavaScript
3
+ module Enumerable
4
+ def chart_json
5
+ if is_a?(Hash)
6
+ if (key = keys.first) && key.is_a?(Array) && key.size == 2
7
+ group_by { |k, _v| k[0] }.map do |name, data|
8
+ {name: name, data: data.map { |k, v| [k[1], v] }}
9
+ end
10
+ else
11
+ to_a
12
+ end
13
+ elsif is_a?(Array)
14
+ map do |v|
15
+ if v.is_a?(Hash) && v[:data].is_a?(Hash)
16
+ v = v.dup
17
+ v[:data] = v[:data].to_a
18
+ end
19
+ v
20
+ end
21
+ else
22
+ self
23
+ end.to_json
24
+ end
25
+ end
@@ -37,17 +37,16 @@ module Chartkick
37
37
 
38
38
  private
39
39
 
40
- def chartkick_chart(klass, data_source, **options)
40
+ def chartkick_chart(klass, data_source, nonce: true, **options)
41
41
  @chartkick_chart_id ||= 0
42
42
  options = chartkick_deep_merge(Chartkick.options, options)
43
43
  element_id = options.delete(:id) || "chart-#{@chartkick_chart_id += 1}"
44
- height = options.delete(:height) || "300px"
45
- width = options.delete(:width) || "100%"
44
+ height = (options.delete(:height) || "300px").to_s
45
+ width = (options.delete(:width) || "100%").to_s
46
46
  defer = !!options.delete(:defer)
47
47
  # content_for: nil must override default
48
48
  content_for = options.key?(:content_for) ? options.delete(:content_for) : Chartkick.content_for
49
49
 
50
- nonce = options.delete(:nonce)
51
50
  if nonce == true
52
51
  # Secure Headers also defines content_security_policy_nonce but it takes an argument
53
52
  # Rails 5.2 overrides this method, but earlier versions do not
@@ -57,6 +56,8 @@ module Chartkick
57
56
  elsif respond_to?(:content_security_policy_script_nonce)
58
57
  # Secure Headers
59
58
  nonce = content_security_policy_script_nonce
59
+ else
60
+ nonce = nil
60
61
  end
61
62
  end
62
63
  nonce_html = nonce ? " nonce=\"#{ERB::Util.html_escape(nonce)}\"" : nil
@@ -65,12 +66,26 @@ module Chartkick
65
66
  html_vars = {
66
67
  id: element_id,
67
68
  height: height,
68
- width: width
69
+ width: width,
70
+ # don't delete loading option since it needs to be passed to JS
71
+ loading: options[:loading] || "Loading..."
69
72
  }
73
+
74
+ [:height, :width].each do |k|
75
+ # limit to alphanumeric and % for simplicity
76
+ # this prevents things like calc() but safety is the priority
77
+ # dot does not need escaped in square brackets
78
+ raise ArgumentError, "Invalid #{k}" unless html_vars[k] =~ /\A[a-zA-Z0-9%.]*\z/
79
+ end
80
+
70
81
  html_vars.each_key do |k|
82
+ # escape all variables
83
+ # we already limit height and width above, but escape for safety as fail-safe
84
+ # to prevent XSS injection in worse-case scenario
71
85
  html_vars[k] = ERB::Util.html_escape(html_vars[k])
72
86
  end
73
- html = (options.delete(:html) || %(<div id="%{id}" style="height: %{height}; width: %{width}; text-align: center; color: #999; line-height: %{height}; font-size: 14px; font-family: 'Lucida Grande', 'Lucida Sans Unicode', Verdana, Arial, Helvetica, sans-serif;">Loading...</div>)) % html_vars
87
+
88
+ html = (options.delete(:html) || %(<div id="%{id}" style="height: %{height}; width: %{width}; text-align: center; color: #999; line-height: %{height}; font-size: 14px; font-family: 'Lucida Grande', 'Lucida Sans Unicode', Verdana, Arial, Helvetica, sans-serif;">%{loading}</div>)) % html_vars
74
89
 
75
90
  # js vars
76
91
  js_vars = {
@@ -84,28 +99,28 @@ module Chartkick
84
99
  end
85
100
  createjs = "new Chartkick[%{type}](%{id}, %{data}, %{options});" % js_vars
86
101
 
87
- if defer
88
- js = <<JS
89
- <script type="text/javascript"#{nonce_html}>
90
- (function() {
91
- var createChart = function() { #{createjs} };
92
- if (window.addEventListener) {
93
- window.addEventListener("load", createChart, true);
94
- } else if (window.attachEvent) {
95
- window.attachEvent("onload", createChart);
96
- } else {
97
- createChart();
98
- }
99
- })();
100
- </script>
101
- JS
102
- else
103
- js = <<JS
104
- <script type="text/javascript"#{nonce_html}>
105
- #{createjs}
106
- </script>
107
- JS
108
- end
102
+ warn "[chartkick] The defer option is no longer needed and can be removed" if defer
103
+
104
+ # Turbolinks preview restores the DOM except for painted <canvas>
105
+ # since it uses cloneNode(true) - https://developer.mozilla.org/en-US/docs/Web/API/Node/
106
+ #
107
+ # don't rerun JS on preview to prevent
108
+ # 1. animation
109
+ # 2. loading data from URL
110
+ js = <<~JS
111
+ <script#{nonce_html}>
112
+ (function() {
113
+ if (document.documentElement.hasAttribute("data-turbolinks-preview")) return;
114
+
115
+ var createChart = function() { #{createjs} };
116
+ if ("Chartkick" in window) {
117
+ createChart();
118
+ } else {
119
+ window.addEventListener("chartkick:load", createChart, true);
120
+ }
121
+ })();
122
+ </script>
123
+ JS
109
124
 
110
125
  if content_for
111
126
  content_for(content_for) { js.respond_to?(:html_safe) ? js.html_safe : js }