Imagify Image Optimizer - Version 1.6.14

Version Description

  • 2018/01/10 =
  • New: added compatibility with partners' plugins.
  • Improvement: updated the script used for the charts, it will lower the risk of conflicts with other plugins (that are also up-to-date).
  • Improvement: the comparison tool button is now also inserted when clicking the next/previous buttons in the media modal.
  • Bug Fix: the comparison tool button should not be inserted several times anymore.
  • Bug Fix: the images wouldn't appear in the comparison tool sometimes.
Download this release

Release Info

Developer wp_media
Plugin Icon 128x128 Imagify Image Optimizer
Version 1.6.14
Comparing to
See all releases

Code changes from version 1.6.13.1 to 1.6.14

Files changed (60) hide show
  1. assets/css/admin.css +11 -30
  2. assets/css/admin.min.css +1 -1
  3. assets/css/bulk.css +7 -2
  4. assets/css/bulk.min.css +1 -1
  5. assets/css/twentytwenty.css +1 -15
  6. assets/css/twentytwenty.min.css +1 -1
  7. assets/images/big-blue-check.png +0 -0
  8. assets/images/icon-arrow-choice.png +0 -0
  9. assets/images/icon-arrow-choice.svg +0 -0
  10. assets/images/icon-lock.png +0 -0
  11. assets/images/icon-lock.svg +0 -0
  12. assets/images/icon-pack.png +0 -0
  13. assets/images/icon-pack.svg +0 -0
  14. assets/images/pic-ericwaltr.jpg +0 -0
  15. assets/images/pic-srhdesign.jpg +0 -0
  16. assets/js/bulk.js +126 -74
  17. assets/js/bulk.min.js +1 -1
  18. assets/js/chart.js +13582 -3169
  19. assets/js/chart.min.js +4 -5
  20. assets/js/imagify-gulp.js +0 -0
  21. assets/js/imagify-gulp.min.js +0 -0
  22. assets/js/jquery.twentytwenty.js +130 -123
  23. assets/js/jquery.twentytwenty.min.js +1 -1
  24. assets/js/media-modal.js +24 -17
  25. assets/js/media-modal.min.js +1 -1
  26. imagify.php +4 -2
  27. inc/3rd-party/hosting/siteground.php +0 -0
  28. inc/3rd-party/hosting/wpengine.php +0 -0
  29. inc/3rd-party/nextgen-gallery/inc/admin/ajax.php +2 -12
  30. inc/3rd-party/nextgen-gallery/inc/admin/bulk.php +0 -0
  31. inc/3rd-party/nextgen-gallery/inc/admin/db.php +0 -0
  32. inc/3rd-party/nextgen-gallery/inc/admin/gallery.php +0 -0
  33. inc/3rd-party/nextgen-gallery/inc/admin/heartbeat.php +0 -0
  34. inc/3rd-party/nextgen-gallery/inc/admin/menu.php +0 -0
  35. inc/3rd-party/nextgen-gallery/inc/classes/class-imagify-ngg-attachment.php +0 -0
  36. inc/3rd-party/nextgen-gallery/inc/classes/class-imagify-ngg-db.php +0 -0
  37. inc/3rd-party/nextgen-gallery/inc/functions/admin-stats.php +5 -1
  38. inc/3rd-party/nextgen-gallery/inc/functions/attachments.php +0 -0
  39. inc/3rd-party/wp-rocket.php +0 -0
  40. inc/admin/meta-boxes.php +1 -1
  41. inc/admin/ui/bulk.php +3 -8
  42. inc/admin/ui/options.php +1 -1
  43. inc/classes/class-imagify-abstract-attachment.php +4 -3
  44. inc/classes/class-imagify-admin-ajax-post.php +4 -14
  45. inc/classes/class-imagify-assets.php +2 -2
  46. inc/classes/class-imagify-attachment.php +0 -0
  47. inc/classes/class-imagify-db.php +0 -0
  48. inc/classes/class-imagify-user.php +8 -10
  49. inc/classes/class-imagify.php +64 -44
  50. inc/common/partners.php +33 -0
  51. inc/functions/admin-stats.php +6 -7
  52. inc/functions/admin-ui.php +2 -2
  53. inc/functions/admin.php +10 -20
  54. inc/functions/api.php +1 -0
  55. inc/functions/attachments.php +21 -0
  56. inc/functions/common.php +66 -10
  57. inc/functions/deprecated.php +82 -4
  58. inc/functions/partners.php +38 -0
  59. readme.txt +9 -2
  60. uninstall.php +8 -8
assets/css/admin.css CHANGED
@@ -132,34 +132,18 @@ body.imagify-modal-is-open {
132
 
133
  /* Doughnut */
134
  .imagify-chart {
135
- width: 33.33%;
136
  position: relative;
 
 
 
137
  }
138
-
139
- .imagify-chart {
140
- float: left;
141
- margin-bottom: 20px;
142
- }
143
-
144
  .imagify-chart-container {
145
  position: relative;
146
- width: 180px;
147
- float: left;
148
- margin-right: 20px;
149
- }
150
-
151
- /* On library page */
152
- td .imagify-chart {
153
- top: 4px;
154
- float: none;
155
- margin-bottom: 0;
156
  }
157
-
158
- td .imagify-chart-container {
159
- width: 18px;
160
- height: 18px;
161
- float: none;
162
- margin-right: 10px;
163
  }
164
 
165
  /**
@@ -779,13 +763,6 @@ ul.imagify-datas-list .big {
779
  .imagify-data-item {
780
  overflow: hidden;
781
  }
782
- .imagify-data-item .imagify-chart {
783
- display: inline-block;
784
- top: 1px;
785
- width: 20px;
786
- vertical-align: middle;
787
- margin-bottom: 0;
788
- }
789
  li.imagify-data-item {
790
  clear: both;
791
  margin-bottom: 2px;
@@ -816,9 +793,13 @@ ul.imagify-datas-list .imagify-data-item strong {
816
  float: none;
817
  }
818
  .media-sidebar .imagify-datas-list .imagify-data-item strong {
 
819
  width: auto;
820
  float: none;
821
  }
 
 
 
822
  .imagify-datas-more-action.imagify-datas-more-action {
823
  margin: .4em auto;
824
  background: linear-gradient(to bottom, transparent, transparent 49%, rgba(0,0,0,.075) 50%, rgba(0,0,0,.075) 58%, transparent 58%, transparent);
132
 
133
  /* Doughnut */
134
  .imagify-chart {
 
135
  position: relative;
136
+ top: 1px;
137
+ display: inline-block;
138
+ vertical-align: middle;
139
  }
 
 
 
 
 
 
140
  .imagify-chart-container {
141
  position: relative;
142
+ display: inline-block;
143
+ margin-right: 5px;
 
 
 
 
 
 
 
 
144
  }
145
+ .imagify-chart-container canvas {
146
+ display: block;
 
 
 
 
147
  }
148
 
149
  /**
763
  .imagify-data-item {
764
  overflow: hidden;
765
  }
 
 
 
 
 
 
 
766
  li.imagify-data-item {
767
  clear: both;
768
  margin-bottom: 2px;
793
  float: none;
794
  }
795
  .media-sidebar .imagify-datas-list .imagify-data-item strong {
796
+ display: inline-block;
797
  width: auto;
798
  float: none;
799
  }
800
+ .media-sidebar .imagify-datas-list .imagify-data-item .imagify-chart {
801
+ float: left;
802
+ }
803
  .imagify-datas-more-action.imagify-datas-more-action {
804
  margin: .4em auto;
805
  background: linear-gradient(to bottom, transparent, transparent 49%, rgba(0,0,0,.075) 50%, rgba(0,0,0,.075) 58%, transparent 58%, transparent);
assets/css/admin.min.css CHANGED
@@ -1 +1 @@
1
- .imagify-cell,.imagify-cell.va-top,.va-top .imagify-cell{vertical-align:top}.imagify-columns,.imagify-data-item,.imagify-oh,body.imagify-modal-is-open{overflow:hidden}.imagify-start{float:left}.imagify-end{float:right}.imagify-txt-start.imagify-txt-start.imagify-txt-start{text-align:left}.imagify-txt-center.imagify-txt-center.imagify-txt-center{text-align:center}.imagify-txt-end.imagify-txt-end.imagify-txt-end{text-align:right}.imagify-mt1.imagify-mt1{margin-top:1em}.imagify-mb1.imagify-mb1{margin-bottom:1em}.imagify-mr1.imagify-mr1{margin-right:1em}.imagify-ml2.imagify-ml2{margin-left:2em}.imagify-mr2.imagify-mr2{margin-right:2em}.imagify-pl0.imagify-pl0.imagify-pl0{padding-left:0}.imagify-pr1.imagify-pr1{padding-right:1em}.imagify-clear{clear:both}.imagify-clearfix:after,.imagify-inline-options:after{content:"";display:table;clear:both}.imagify-count.imagify-count{counter-reset:num}.imagify-count .imagify-count-title{font-weight:700}.imagify-default-settings{color:#73818c;font-weight:400}.imagify-count .imagify-count-title:before{counter-increment:num 1;content:counter(num) ". "}.imagify-table{display:table;width:100%}.imagify-cell{display:table-cell;padding:10px}.imagify-bulk-submit .imagify-cell{padding-top:0}.imagify-spinner{display:inline-block;width:20px;height:20px;margin-right:5px;vertical-align:middle;background:url(../images/spinner.gif) 0 0/20px 20px no-repeat rgba(0,0,0,0);opacity:.7}.spinner.imagify-hidden{width:0;margin:4px 0 0}.imagify-primary.imagify-primary.imagify-primary{color:#40b1d0}.imagify-secondary.imagify-secondary.imagify-secondary,.imagify-valid{color:#8BC34A}.misc-pub-section.misc-pub-imagify h4{font-size:14px;margin-top:5px;margin-bottom:0}.imagify-chart{width:33.33%;position:relative;float:left;margin-bottom:20px}.imagify-chart-container{position:relative;width:180px;float:left;margin-right:20px}td .imagify-chart{top:4px;float:none;margin-bottom:0}td .imagify-chart-container{width:18px;height:18px;float:none;margin-right:10px}.imagify-settings .button,.imagify-settings a,.imagify-settings input,.imagify-welcome .button,.imagify-welcome a,.imagify-weolcome input{-webkit-transition:all .275s;-o-transition:all .275s;transition:all .275s}.imagify-settings a{color:#40b1d0}.imagify-settings,.imagify-settings p,.imagify-settings th{color:#5F758E}.imagify-button-primary.imagify-button-primary,.imagify-button-secondary.imagify-button-secondary,.imagify-button.imagify-button,.imagify-notice .button,.imagify-settings .button,.imagify-welcome .button{height:auto;padding:8px 20px;border:0;font-size:14px;font-weight:600;-webkit-box-shadow:0 3px 0 rgba(0,0,0,.15);box-shadow:0 3px 0 rgba(0,0,0,.15);border-radius:3px;cursor:pointer;-webkit-transition:all .275s;-o-transition:all .275s;transition:all .275s}.button-primary.button-mini{padding:2px 10px}.imagify-settings .button.button-mini-flat{padding:3px 6px 5px;font-size:12px;-webkit-box-shadow:none!important;box-shadow:none!important;line-height:1.2}.imagify-settings .button.button-mini-flat:focus,.imagify-settings .button.button-mini-flat:hover{-webkit-box-shadow:none!important;box-shadow:none!important}.imagify-button-ghost.imagify-button-ghost,.imagify-title .button-ghost.button-ghost{padding:2px 9px;border:1px solid #40B1D0;font-size:12px;font-weight:400;color:#40B1D0;background:0 0;-webkit-box-shadow:none;box-shadow:none}.imagify-button-ghost.imagify-button-ghost:focus,.imagify-button-ghost.imagify-button-ghost:hover,.imagify-title .button-ghost.button-ghost:focus,.imagify-title .button-ghost.button-ghost:hover{border-color:transparent;color:#000;background:#40B1D0}.imagify-button-ghost.imagify-button-ghost:focus,.imagify-button-ghost.imagify-button-ghost:hover{color:#FFF}.imagify-button-medium.imagify-button-medium{text-transform:uppercase;letter-spacing:.1em;padding:3px 10px;font-weight:700}.imagify-button-medium.imagify-button-ghost{border-width:2px}[class*=imagify-] .button .dashicons{margin-right:5px;vertical-align:middle}.imagify-button-primary.imagify-button-primary,.imagify-settings .button-primary.button-primary,.imagify-welcome .button-primary.button-primary{background:#40B1D0;color:#FFF;-webkit-box-shadow:0 3px 0 rgba(51,142,166,1);box-shadow:0 3px 0 rgba(51,142,166,1);text-shadow:0 -1px 1px #006799,1px 0 1px #006799,0 1px 1px #006799!important}.imagify-button-secondary.imagify-button-secondary{background:#8BC34A;color:#FFF;-webkit-box-shadow:0 3px 0 #6F9C3B;box-shadow:0 3px 0 #6F9C3B;text-shadow:0 -1px 1px #6F9C3B,1px 0 1px #6F9C3B,0 1px 1px #6F9C3B!important}.imagify-button-primary.imagify-button-primary:focus,.imagify-button-primary.imagify-button-primary:hover,.imagify-settings .button-primary:focus,.imagify-settings .button-primary:hover,.imagify-welcome .button-primary:focus,.imagify-welcome .button-primary:hover{background:#338ea6;-webkit-box-shadow:0 3px 0 #1f7a92;box-shadow:0 3px 0 #1f7a92}.imagify-button-secondary.imagify-button-secondary:focus,.imagify-button-secondary.imagify-button-secondary:hover{background:#6F9C3B;color:#FFF}.imagify-button-light.imagify-button-light{background:#FFF;color:#4a4a4a;-webkit-box-shadow:0 2px 0 rgba(0,0,0,.2);box-shadow:0 2px 0 rgba(0,0,0,.2)}.imagify-button-light.imagify-button-light:focus,.imagify-button-light.imagify-button-light:hover{color:#FFF;background:rgba(0,0,0,.2)}.imagify-section-positive .imagify-button-light{color:#709A41}.imagify-button.imagify-button-big{font-size:15px;padding:11px 30px}.imagify-button-big .dashicons{font-size:1.45em;margin-right:6px;margin-left:-4px}.imagify-button-primary.imagify-button-primary .dashicons,.imagify-button-secondary.imagify-button-secondary .dashicons,.imagify-button.imagify-button .dashicons,.imagify-notice .button .dashicons,.imagify-settings .button .dashicons,.imagify-welcome .button .dashicons{vertical-align:middle}[class*=imagify-] .button-text{display:inline-block;vertical-align:middle}.media-frame-content .imagify-button-primary,.wp_attachment_image .imagify-button-primary{padding:0 10px 1px;margin:0 5px 2px 0;font-size:13px;line-height:26px;-webkit-box-shadow:0 3px 0 rgba(51,142,166,1);box-shadow:0 3px 0 rgba(51,142,166,1)}.wp_attachment_image .imagify-button-primary{float:left}.imagify-title.imagify-title{position:relative;padding:30px 50px;font-size:23px;background:#2E3243;color:#FFF}.imagify-settings .imagify-title{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-pack:justify;-ms-flex-pack:justify;justify-content:space-between;-webkit-box-align:center;-ms-flex-align:center;align-items:center}.imagify-settings .imagify-logo-block{-ms-flex-negative:0;flex-shrink:0;-webkit-box-flex:0;-ms-flex-positive:0;flex-grow:0;margin-right:35px}.imagify-settings .imagify-title+.imagify-notice{margin:0;border-right:1px solid #D9D9D9;padding-top:15px;padding-bottom:15px}.imagify-logo{vertical-align:top}.imagify-section,.imagify-settings div.submit,.imagify-sub-header,.imagify-sub-title.imagify-sub-title{margin:0;padding:20px;background:#F2F5F7}.imagify-section-positive,.imagify-sub-title.imagify-sub-title{padding-left:40px}.imagify-section-positive{background:#8cc152;color:#FFF}.imagify-section-positive p{color:#FFF}.imagify-section-gray{background:#D9E4EB}.imagify-section-gray .imagify-count-title{color:#4a4a4a}.imagify-section p:first-child{margin-top:0}.imagify-section p:last-child{margin-bottom:0}@media (max-width:1120px){.imagify-settings .imagify-title{-ms-flex-wrap:wrap;flex-wrap:wrap}}.imagify-settings-section{padding:10px 20px}.imagify-welcome .imagify-settings-section,[id=imagify-settings]{border:1px solid #D9D9D9;border-top:0 none;background:#FFF}.imagify-br{line-height:2}p.imagify-section-title.imagify-section-title{font-size:20px;margin-top:-.3em;margin-bottom:-.6em}.imagify-rate-us.imagify-rate-us{text-align:right;margin:-1em -2.4em -1em 0;color:#FFF}.imagify-rate-us a{color:#40B1D0}.imagify-rate-us .stars{display:inline-block;margin:2px 0 0 10px;text-decoration:none;letter-spacing:.2em;vertical-align:-1px}.imagify-rate-us .stars .dashicons:before{font-size:18px}.imagify-rate-us a:focus,.imagify-rate-us a:hover{color:#FEE102}@media (max-width:1220px){.imagify-rate-us.imagify-rate-us{position:static;margin-bottom:0;text-align:left}.imagify-rate-us.imagify-rate-us br{display:none}.imagify-rate-us .stars{display:block;margin-left:0}}.imagify-important{color:#F5A623}.imagify-info,.imagify-info a{color:#40B1D0;font-size:12px}.imagify-info{position:relative;display:inline-block;padding-left:25px;vertical-align:top}.imagify-info .dashicons{position:absolute;left:0;top:-1px}.imagify-checkbox.imagify-checkbox:checked,.imagify-checkbox.imagify-checkbox:not(:checked),.imagify-settings.imagify-settings [type=checkbox]:checked,.imagify-settings.imagify-settings [type=checkbox]:not(:checked){opacity:.01}.imagify-checkbox.imagify-checkbox:checked:focus,.imagify-checkbox.imagify-checkbox:not(:checked):focus,.imagify-settings.imagify-settings [type=checkbox]:checked:focus,.imagify-settings.imagify-settings [type=checkbox]:not(:checked):focus{-webkit-box-shadow:none!important;box-shadow:none!important;outline:0!important;border:0!important}.imagify-checkbox.imagify-checkbox:checked+label,.imagify-checkbox.imagify-checkbox:not(:checked)+label,.imagify-settings [type=checkbox]:checked+label,.imagify-settings [type=checkbox]:not(:checked)+label{position:relative;padding-left:6px;cursor:pointer;vertical-align:top}.imagify-checkbox.imagify-checkbox:checked+label:before,.imagify-checkbox.imagify-checkbox:not(:checked)+label:before,.imagify-settings [type=checkbox]:checked+label:before,.imagify-settings [type=checkbox]:not(:checked)+label:before{content:'';position:absolute;left:0;top:0;width:28px;height:28px;margin:0 0 0 -24px;border:2px solid #8BA6B4;background:#FFF;border-radius:4px}.imagify-checkbox.imagify-checkbox:checked+label:after,.imagify-checkbox.imagify-checkbox:not(:checked)+label:after,.imagify-settings [type=checkbox]:checked+label:after,.imagify-settings [type=checkbox]:not(:checked)+label:after{content:"✓";position:absolute;font-size:1.4em;top:3px;left:-16px;-webkit-transition:all .2s;-o-transition:all .2s;transition:all .2s}.imagify-checkbox.imagify-checkbox[disabled]:checked+label:before,.imagify-checkbox.imagify-checkbox[disabled]:not(:checked)+label:before,.imagify-settings [type=checkbox][disabled]:checked+label:before,.imagify-settings [type=checkbox][disabled]:not(:checked)+label:before{border-color:#ccc;background:#ddd}.imagify-checkbox.imagify-checkbox:not(:checked)+label:after,.imagify-settings [type=checkbox]:not(:checked)+label:after{opacity:0;-webkit-transform:scale(0);-ms-transform:scale(0);transform:scale(0)}.imagify-checkbox.imagify-checkbox:checked+label:after,.imagify-settings [type=checkbox]:checked+label:after{opacity:1;-webkit-transform:scale(1);-ms-transform:scale(1);transform:scale(1)}.medium.imagify-checkbox:checked+label:before,.medium.imagify-checkbox:not(:checked)+label:before{width:22px;height:22px;border-width:1.5px;border-radius:2px;margin-top:0}.medium.imagify-checkbox:checked+label:after,.medium.imagify-checkbox:not(:checked)+label:after{font-size:1.1em;left:-17px;top:3px}.imagify-settings .mini[type=checkbox]:checked+label:before,.imagify-settings .mini[type=checkbox]:not(:checked)+label:before,.mini.imagify-checkbox:checked+label:before,.mini.imagify-checkbox:not(:checked)+label:before{width:15px;height:15px;border-width:1px;border-radius:2px;margin-top:0}.imagify-settings .mini[type=checkbox]:checked+label:after,.imagify-settings .mini[type=checkbox]:not(:checked)+label:after,.mini.imagify-checkbox:checked+label:after,.mini.imagify-checkbox:not(:checked)+label:after{font-size:.9em;left:-21px;top:-.5px}.imagify-checkbox.imagify-checkbox:checked:focus+label:before,.imagify-checkbox.imagify-checkbox:not(:checked):focus+label:before,.imagify-settings [type=checkbox]:checked:focus+label:before,.imagify-settings [type=checkbox]:not(:checked):focus+label:before{border-style:dotted;border-color:#40b1d0}.imagify-inline-options{position:relative;display:table;width:100%;max-width:600px;border-collapse:collapse}.imagify-inline-options input[type=radio]:checked,.imagify-inline-options input[type=radio]:not(:checked){position:absolute;left:5px;top:5px;display:none}.imagify-inline-options input[type=radio]:checked+label,.imagify-inline-options input[type=radio]:not(:checked)+label{position:relative;display:table-cell;padding:13px 10px;text-align:center;font-weight:600;font-size:16px;text-transform:uppercase;letter-spacing:.1em;color:#FFF;background:#2E3243;border-left:1px solid rgba(255,255,255,.2);-webkit-box-shadow:0 -3px 0 rgba(0,0,0,.1) inset,inset -1px 0 0 rgba(255,255,255,.2);box-shadow:0 -3px 0 rgba(0,0,0,.1) inset,inset -1px 0 0 rgba(255,255,255,.2);z-index:2;-webkit-transition:all .275s;-o-transition:all .275s;transition:all .275s}.imagify-modal .h2,.imagify-modal .h3{letter-spacing:.075em;text-align:center;font-weight:400}.imagify-inline-options input[type=radio]:checked+label:first-of-type,.imagify-inline-options input[type=radio]:not(:checked)+label:first-of-type{border-radius:3px 0 0 3px}.imagify-inline-options input[type=radio]:checked+label:last-of-type,.imagify-inline-options input[type=radio]:not(:checked)+label:last-of-type{border-radius:0 3px 3px 0}.imagify-inline-options input[type=radio]:checked+label{background:#8BC34A}.imagify-inline-options .imagify-info{margin-top:15px}.imagify-columns{padding:15px 0;counter-reset:cols}.imagify-columns [class^=col-]{float:left;-webkit-box-sizing:border-box;box-sizing:border-box}.imagify-columns .col-1-3{width:33.333%;padding-left:28px}.imagify-columns .col-2-3{width:66.666%;padding-left:28px}.imagify-columns .col-1-2{width:50%;padding:0 20px}@media (max-width:830px){.imagify-columns [class^=col-]{float:none;margin-bottom:1.5em}.imagify-columns .col-1-2,.imagify-columns .col-1-3{width:auto;padding:0 28px;clear:both;padding-top:1em}}.column-imagify_optimized_file.column-imagify_optimized_file{width:300px;text-align:center;vertical-align:middle}.column-imagify_optimized_file>*{max-width:235px;margin:0 auto}@media (min-width:1151px) and (max-width:1800px){.column-imagify_optimized_file.column-imagify_optimized_file{width:235px}}@media (min-width:783px) and (max-width:1150px){.column-imagify_optimized_file.column-imagify_optimized_file{width:13em}table.media .column-title .has-media-icon~.row-actions.row-actions{margin-left:0}}@media (max-width:782px){table.media .column-imagify_optimized_file.column-imagify_optimized_file{text-align:left}table.media .imagify-datas-actions-links,table.media .imagify-datas-more-action{text-align:center}table.media .column-imagify_optimized_file .imagify-datas-actions-links a,table.media .column-imagify_optimized_file>*{max-width:100%;margin-left:0}}@media (min-width:783px) and (max-width:1150px),(max-width:360px){table.media .imagify-hide-if-small{position:absolute;margin:-1px;padding:0;height:1px;width:1px;overflow:hidden;clip:rect(0 0 0 0);border:0;word-wrap:normal!important}}.compat-field-imagify .label{vertical-align:top}.compat-field-imagify ul.imagify-datas-list{margin-top:7px;font-size:11px}ul.imagify-datas-list.imagify-datas-list{margin:0 auto;color:#555;font-size:10px}ul.imagify-datas-list .big{font-size:12px;color:#40B1D0}.imagify-data-item .imagify-chart{display:inline-block;top:1px;width:20px;vertical-align:middle;margin-bottom:0}li.imagify-data-item{clear:both;margin-bottom:2px}ul.imagify-datas-list .imagify-data-item span.data,ul.imagify-datas-list .imagify-data-item strong{float:left;width:50%;-webkit-box-sizing:border-box;box-sizing:border-box}ul.imagify-datas-list .imagify-data-item span.data{text-align:left;padding-right:5px}.compat-field-imagify .imagify-datas-list .imagify-data-item .data{width:130px;text-align:left;font-weight:700}ul.imagify-datas-list .imagify-data-item strong{text-align:left;padding-left:5px}.media-sidebar .imagify-datas-list .imagify-data-item .data,.media-sidebar .imagify-datas-list .imagify-data-item strong{width:auto;float:none}.imagify-datas-more-action.imagify-datas-more-action{margin:.4em auto;background:-webkit-gradient(linear,left top,left bottom,from(transparent),color-stop(49%,transparent),color-stop(50%,rgba(0,0,0,.075)),color-stop(58%,rgba(0,0,0,.075)),color-stop(58%,transparent),to(transparent));background:-o-linear-gradient(top,transparent,transparent 49%,rgba(0,0,0,.075) 50%,rgba(0,0,0,.075) 58%,transparent 58%,transparent);background:linear-gradient(to bottom,transparent,transparent 49%,rgba(0,0,0,.075) 50%,rgba(0,0,0,.075) 58%,transparent 58%,transparent)}.imagify-datas-more-action a{display:inline-block;padding:0 5px;background:#40B1D0;color:#FFF;text-transform:uppercase;font-size:9px;font-weight:700;line-height:1.9;text-decoration:none}.imagify-datas-more-action a.is-open{background:#555}.imagify-datas-more-action a.is-open .dashicons{-webkit-transform:rotate(180deg);-ms-transform:rotate(180deg);transform:rotate(180deg)}.imagify-datas-more-action a .dashicons{font-size:14px;vertical-align:middle;line-height:.8}.imagify-datas-more-action a .dashicons:before{vertical-align:middle;line-height:20px}.imagify-datas-more-action .the-text{display:inline-block;vertical-align:middle;height:auto;line-height:inherit}ul.imagify-datas-details.imagify-datas-details{margin:.7em auto}.imagify-datas-details strong{color:#40B1D0}.imagify-datas-details .original{color:#555}.imagify-datas-actions-links{overflow:hidden;border-top:2px solid transparent;padding-top:5px;font-size:8px}.nggform .imagify-datas-actions-links{position:relative;z-index:2}.nggform .row-actions{z-index:1}.imagify-datas-actions-links a{position:relative;display:inline-block;padding-left:17px;text-decoration:none;font-weight:600}.compat-field-imagify .imagify-datas-actions-links{max-width:300px}.misc-pub-imagify .imagify-datas-actions-links{border-top:2px solid #f2f2f2;padding-bottom:5px}.column-imagify_optimized_file .imagify-datas-actions-links a{margin:0 .7em;padding-left:15px}.compat-field-imagify .imagify-datas-actions-links a,.misc-pub-imagify .imagify-datas-actions-links a{font-size:10px;float:left;width:50%}.media-sidebar .compat-field-imagify .imagify-datas-actions-links a,.submitbox .misc-pub-imagify .imagify-datas-actions-links a{display:block;width:auto;float:none}.imagify-datas-actions-links a:only-child{float:none;width:auto}.imagify-datas-details.is-open+.imagify-datas-actions-links{border-top-color:rgba(0,0,0,.075)}.imagify-datas-actions-links .dashicons{position:absolute;left:0;top:4px;width:12px;margin-right:2px;font-size:11px}.imagify-account,.imagify-account-link{padding-right:15px}.imagify-meteo-icon{display:inline-block;height:38px;vertical-align:middle;margin-right:10px}.imagify-user-plan{color:#40b1d0}.imagify-meteo-title.imagify-meteo-title{color:#FFF;font-size:17px}.imagify-space-left{display:inline-block;min-height:38px;min-width:245px;vertical-align:middle}.imagify-space-left>p{color:#FFF}[class^=imagify-bar-]{position:relative;height:1.5em;width:100%;background:#60758D;color:#FFF;font-size:10px}.imagify-progress{height:1.5em;-webkit-transition:width .3s;-o-transition:width .3s;transition:width .3s}.imagify-bar-positive .imagify-progress{background:#8CC152}.imagify-bar-positive .imagify-barnb{color:#8CC152}.imagify-bar-negative .imagify-progress{background:#73818C}.imagify-bar-negative .imagify-barnb{color:#73818C}.imagify-bar-neutral .imagify-progress{background:#F5A623}.imagify-space-left .imagify-bar-negative .imagify-progress{background:#D0021B}.imagify-btn-ghost{display:inline-block;height:auto;padding:7px 10px;border:1px solid #FFF;text-align:center;background:0 0;color:#FFF;border-radius:3px;-webkit-transition:all .275s;-o-transition:all .275s;transition:all .275s}.imagify-btn-ghost:focus,.imagify-btn-ghost:hover{background:#FFF;color:#888}.imagify-error{background:#D0021B;color:#FFF}.imagify-settings-section .imagify-error{display:inline-block;padding:7px 10px;margin:10px 0 0 45px;border-radius:3px}.imagify-settings-section .imagify-error code{font-weight:400}.imagify-settings-section .imagify-error.hidden{display:none}.imagify-warning{background:#f5a623;color:#FFF;text-shadow:0 0 2px rgba(0,0,0,.2)}.imagify-modal{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-orient:vertical;-webkit-box-direction:normal;-ms-flex-direction:column;flex-direction:column;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center}.js .imagify-modal{display:none;position:fixed;top:0;right:0;bottom:0;left:0;background-color:#1F2332;background-color:rgba(31,35,50,.95);z-index:99999}.imagify-modal-content{-webkit-box-sizing:border-box;box-sizing:border-box;position:relative;width:800px;max-width:95%;max-height:90vw;overflow:auto;padding:20px 25px;margin:1em auto;background:#FFF;-webkit-box-shadow:1px 1px 4px rgba(0,0,0,.7);box-shadow:1px 1px 4px rgba(0,0,0,.7);border-radius:3px}#imagify-visual-comparison .imagify-modal-content,.imagify-visual-comparison .imagify-modal-content{max-width:1400px;background:0 0;padding:5px;-webkit-box-shadow:none;box-shadow:none;border-radius:0}.imagify-modal .h2{margin:.5em 0;color:#8ba6b4;font-size:24px}.imagify-modal .h3{color:#40b1d0;font-size:18px}.imagify-modal .close-btn{display:none;visibility:hidden;position:absolute;right:20px;top:20px;font-size:1.2em;border:0;background:0 0;border-radius:0;cursor:pointer}.imagify-modal .close-btn i{margin-left:-2px}.imagify-modal .close-btn:focus,.imagify-modal .close-btn:hover{color:#40b1d0}.js .imagify-modal .close-btn{display:block;visibility:visible}.imagify-visual-comparison .close-btn,.wp_attachment_image #imagify-visual-comparison .close-btn{top:0}.imagify-visual-comparison .imagify-modal-content,.wp_attachment_image #imagify-visual-comparison .imagify-modal-content{padding-top:40px}.imagify-col{float:left;width:50%;-ms-flex-preferred-size:50%;flex-basis:50%}
1
+ .imagify-cell,.imagify-cell.va-top,.va-top .imagify-cell{vertical-align:top}.imagify-columns,.imagify-data-item,.imagify-oh,body.imagify-modal-is-open{overflow:hidden}.imagify-start{float:left}.imagify-end{float:right}.imagify-txt-start.imagify-txt-start.imagify-txt-start{text-align:left}.imagify-txt-center.imagify-txt-center.imagify-txt-center{text-align:center}.imagify-txt-end.imagify-txt-end.imagify-txt-end{text-align:right}.imagify-mt1.imagify-mt1{margin-top:1em}.imagify-mb1.imagify-mb1{margin-bottom:1em}.imagify-mr1.imagify-mr1{margin-right:1em}.imagify-ml2.imagify-ml2{margin-left:2em}.imagify-mr2.imagify-mr2{margin-right:2em}.imagify-pl0.imagify-pl0.imagify-pl0{padding-left:0}.imagify-pr1.imagify-pr1{padding-right:1em}.imagify-clear{clear:both}.imagify-clearfix:after,.imagify-inline-options:after{content:"";display:table;clear:both}.imagify-count.imagify-count{counter-reset:num}.imagify-count .imagify-count-title{font-weight:700}.imagify-default-settings{color:#73818c;font-weight:400}.imagify-count .imagify-count-title:before{counter-increment:num 1;content:counter(num) ". "}.imagify-table{display:table;width:100%}.imagify-cell{display:table-cell;padding:10px}.imagify-bulk-submit .imagify-cell{padding-top:0}.imagify-spinner{display:inline-block;width:20px;height:20px;margin-right:5px;vertical-align:middle;background:url(../images/spinner.gif) 0 0/20px 20px no-repeat rgba(0,0,0,0);opacity:.7}.spinner.imagify-hidden{width:0;margin:4px 0 0}.imagify-primary.imagify-primary.imagify-primary{color:#40b1d0}.imagify-secondary.imagify-secondary.imagify-secondary,.imagify-valid{color:#8BC34A}.misc-pub-section.misc-pub-imagify h4{font-size:14px;margin-top:5px;margin-bottom:0}.imagify-chart{position:relative;top:1px;display:inline-block;vertical-align:middle}.imagify-chart-container{position:relative;display:inline-block;margin-right:5px}.imagify-chart-container canvas{display:block}.imagify-settings .button,.imagify-settings a,.imagify-settings input,.imagify-welcome .button,.imagify-welcome a,.imagify-weolcome input{-webkit-transition:all .275s;-o-transition:all .275s;transition:all .275s}.imagify-settings a{color:#40b1d0}.imagify-settings,.imagify-settings p,.imagify-settings th{color:#5F758E}.imagify-button-primary.imagify-button-primary,.imagify-button-secondary.imagify-button-secondary,.imagify-button.imagify-button,.imagify-notice .button,.imagify-settings .button,.imagify-welcome .button{height:auto;padding:8px 20px;border:0;font-size:14px;font-weight:600;-webkit-box-shadow:0 3px 0 rgba(0,0,0,.15);box-shadow:0 3px 0 rgba(0,0,0,.15);border-radius:3px;cursor:pointer;-webkit-transition:all .275s;-o-transition:all .275s;transition:all .275s}.button-primary.button-mini{padding:2px 10px}.imagify-settings .button.button-mini-flat{padding:3px 6px 5px;font-size:12px;-webkit-box-shadow:none!important;box-shadow:none!important;line-height:1.2}.imagify-settings .button.button-mini-flat:focus,.imagify-settings .button.button-mini-flat:hover{-webkit-box-shadow:none!important;box-shadow:none!important}.imagify-button-ghost.imagify-button-ghost,.imagify-title .button-ghost.button-ghost{padding:2px 9px;border:1px solid #40B1D0;font-size:12px;font-weight:400;color:#40B1D0;background:0 0;-webkit-box-shadow:none;box-shadow:none}.imagify-button-ghost.imagify-button-ghost:focus,.imagify-button-ghost.imagify-button-ghost:hover,.imagify-title .button-ghost.button-ghost:focus,.imagify-title .button-ghost.button-ghost:hover{border-color:transparent;color:#000;background:#40B1D0}.imagify-button-ghost.imagify-button-ghost:focus,.imagify-button-ghost.imagify-button-ghost:hover{color:#FFF}.imagify-button-medium.imagify-button-medium{text-transform:uppercase;letter-spacing:.1em;padding:3px 10px;font-weight:700}.imagify-button-medium.imagify-button-ghost{border-width:2px}[class*=imagify-] .button .dashicons{margin-right:5px;vertical-align:middle}.imagify-button-primary.imagify-button-primary,.imagify-settings .button-primary.button-primary,.imagify-welcome .button-primary.button-primary{background:#40B1D0;color:#FFF;-webkit-box-shadow:0 3px 0 rgba(51,142,166,1);box-shadow:0 3px 0 rgba(51,142,166,1);text-shadow:0 -1px 1px #006799,1px 0 1px #006799,0 1px 1px #006799!important}.imagify-button-secondary.imagify-button-secondary{background:#8BC34A;color:#FFF;-webkit-box-shadow:0 3px 0 #6F9C3B;box-shadow:0 3px 0 #6F9C3B;text-shadow:0 -1px 1px #6F9C3B,1px 0 1px #6F9C3B,0 1px 1px #6F9C3B!important}.imagify-button-primary.imagify-button-primary:focus,.imagify-button-primary.imagify-button-primary:hover,.imagify-settings .button-primary:focus,.imagify-settings .button-primary:hover,.imagify-welcome .button-primary:focus,.imagify-welcome .button-primary:hover{background:#338ea6;-webkit-box-shadow:0 3px 0 #1f7a92;box-shadow:0 3px 0 #1f7a92}.imagify-button-secondary.imagify-button-secondary:focus,.imagify-button-secondary.imagify-button-secondary:hover{background:#6F9C3B;color:#FFF}.imagify-button-light.imagify-button-light{background:#FFF;color:#4a4a4a;-webkit-box-shadow:0 2px 0 rgba(0,0,0,.2);box-shadow:0 2px 0 rgba(0,0,0,.2)}.imagify-button-light.imagify-button-light:focus,.imagify-button-light.imagify-button-light:hover{color:#FFF;background:rgba(0,0,0,.2)}.imagify-section-positive .imagify-button-light{color:#709A41}.imagify-button.imagify-button-big{font-size:15px;padding:11px 30px}.imagify-button-big .dashicons{font-size:1.45em;margin-right:6px;margin-left:-4px}.imagify-button-primary.imagify-button-primary .dashicons,.imagify-button-secondary.imagify-button-secondary .dashicons,.imagify-button.imagify-button .dashicons,.imagify-notice .button .dashicons,.imagify-settings .button .dashicons,.imagify-welcome .button .dashicons{vertical-align:middle}[class*=imagify-] .button-text{display:inline-block;vertical-align:middle}.media-frame-content .imagify-button-primary,.wp_attachment_image .imagify-button-primary{padding:0 10px 1px;margin:0 5px 2px 0;font-size:13px;line-height:26px;-webkit-box-shadow:0 3px 0 rgba(51,142,166,1);box-shadow:0 3px 0 rgba(51,142,166,1)}.wp_attachment_image .imagify-button-primary{float:left}.imagify-title.imagify-title{position:relative;padding:30px 50px;font-size:23px;background:#2E3243;color:#FFF}.imagify-settings .imagify-title{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-pack:justify;-ms-flex-pack:justify;justify-content:space-between;-webkit-box-align:center;-ms-flex-align:center;align-items:center}.imagify-settings .imagify-logo-block{-ms-flex-negative:0;flex-shrink:0;-webkit-box-flex:0;-ms-flex-positive:0;flex-grow:0;margin-right:35px}.imagify-settings .imagify-title+.imagify-notice{margin:0;border-right:1px solid #D9D9D9;padding-top:15px;padding-bottom:15px}.imagify-logo{vertical-align:top}.imagify-section,.imagify-settings div.submit,.imagify-sub-header,.imagify-sub-title.imagify-sub-title{margin:0;padding:20px;background:#F2F5F7}.imagify-section-positive,.imagify-sub-title.imagify-sub-title{padding-left:40px}.imagify-section-positive{background:#8cc152;color:#FFF}.imagify-section-positive p{color:#FFF}.imagify-section-gray{background:#D9E4EB}.imagify-section-gray .imagify-count-title{color:#4a4a4a}.imagify-section p:first-child{margin-top:0}.imagify-section p:last-child{margin-bottom:0}@media (max-width:1120px){.imagify-settings .imagify-title{-ms-flex-wrap:wrap;flex-wrap:wrap}}.imagify-settings-section{padding:10px 20px}.imagify-welcome .imagify-settings-section,[id=imagify-settings]{border:1px solid #D9D9D9;border-top:0 none;background:#FFF}.imagify-br{line-height:2}p.imagify-section-title.imagify-section-title{font-size:20px;margin-top:-.3em;margin-bottom:-.6em}.imagify-rate-us.imagify-rate-us{text-align:right;margin:-1em -2.4em -1em 0;color:#FFF}.imagify-rate-us a{color:#40B1D0}.imagify-rate-us .stars{display:inline-block;margin:2px 0 0 10px;text-decoration:none;letter-spacing:.2em;vertical-align:-1px}.imagify-rate-us .stars .dashicons:before{font-size:18px}.imagify-rate-us a:focus,.imagify-rate-us a:hover{color:#FEE102}@media (max-width:1220px){.imagify-rate-us.imagify-rate-us{position:static;margin-bottom:0;text-align:left}.imagify-rate-us.imagify-rate-us br{display:none}.imagify-rate-us .stars{display:block;margin-left:0}}.imagify-important{color:#F5A623}.imagify-info,.imagify-info a{color:#40B1D0;font-size:12px}.imagify-info{position:relative;display:inline-block;padding-left:25px;vertical-align:top}.imagify-info .dashicons{position:absolute;left:0;top:-1px}.imagify-checkbox.imagify-checkbox:checked,.imagify-checkbox.imagify-checkbox:not(:checked),.imagify-settings.imagify-settings [type=checkbox]:checked,.imagify-settings.imagify-settings [type=checkbox]:not(:checked){opacity:.01}.imagify-checkbox.imagify-checkbox:checked:focus,.imagify-checkbox.imagify-checkbox:not(:checked):focus,.imagify-settings.imagify-settings [type=checkbox]:checked:focus,.imagify-settings.imagify-settings [type=checkbox]:not(:checked):focus{-webkit-box-shadow:none!important;box-shadow:none!important;outline:0!important;border:0!important}.imagify-checkbox.imagify-checkbox:checked+label,.imagify-checkbox.imagify-checkbox:not(:checked)+label,.imagify-settings [type=checkbox]:checked+label,.imagify-settings [type=checkbox]:not(:checked)+label{position:relative;padding-left:6px;cursor:pointer;vertical-align:top}.imagify-checkbox.imagify-checkbox:checked+label:before,.imagify-checkbox.imagify-checkbox:not(:checked)+label:before,.imagify-settings [type=checkbox]:checked+label:before,.imagify-settings [type=checkbox]:not(:checked)+label:before{content:'';position:absolute;left:0;top:0;width:28px;height:28px;margin:0 0 0 -24px;border:2px solid #8BA6B4;background:#FFF;border-radius:4px}.imagify-checkbox.imagify-checkbox:checked+label:after,.imagify-checkbox.imagify-checkbox:not(:checked)+label:after,.imagify-settings [type=checkbox]:checked+label:after,.imagify-settings [type=checkbox]:not(:checked)+label:after{content:"✓";position:absolute;font-size:1.4em;top:3px;left:-16px;-webkit-transition:all .2s;-o-transition:all .2s;transition:all .2s}.imagify-checkbox.imagify-checkbox[disabled]:checked+label:before,.imagify-checkbox.imagify-checkbox[disabled]:not(:checked)+label:before,.imagify-settings [type=checkbox][disabled]:checked+label:before,.imagify-settings [type=checkbox][disabled]:not(:checked)+label:before{border-color:#ccc;background:#ddd}.imagify-checkbox.imagify-checkbox:not(:checked)+label:after,.imagify-settings [type=checkbox]:not(:checked)+label:after{opacity:0;-webkit-transform:scale(0);-ms-transform:scale(0);transform:scale(0)}.imagify-checkbox.imagify-checkbox:checked+label:after,.imagify-settings [type=checkbox]:checked+label:after{opacity:1;-webkit-transform:scale(1);-ms-transform:scale(1);transform:scale(1)}.medium.imagify-checkbox:checked+label:before,.medium.imagify-checkbox:not(:checked)+label:before{width:22px;height:22px;border-width:1.5px;border-radius:2px;margin-top:0}.medium.imagify-checkbox:checked+label:after,.medium.imagify-checkbox:not(:checked)+label:after{font-size:1.1em;left:-17px;top:3px}.imagify-settings .mini[type=checkbox]:checked+label:before,.imagify-settings .mini[type=checkbox]:not(:checked)+label:before,.mini.imagify-checkbox:checked+label:before,.mini.imagify-checkbox:not(:checked)+label:before{width:15px;height:15px;border-width:1px;border-radius:2px;margin-top:0}.imagify-settings .mini[type=checkbox]:checked+label:after,.imagify-settings .mini[type=checkbox]:not(:checked)+label:after,.mini.imagify-checkbox:checked+label:after,.mini.imagify-checkbox:not(:checked)+label:after{font-size:.9em;left:-21px;top:-.5px}.imagify-checkbox.imagify-checkbox:checked:focus+label:before,.imagify-checkbox.imagify-checkbox:not(:checked):focus+label:before,.imagify-settings [type=checkbox]:checked:focus+label:before,.imagify-settings [type=checkbox]:not(:checked):focus+label:before{border-style:dotted;border-color:#40b1d0}.imagify-inline-options{position:relative;display:table;width:100%;max-width:600px;border-collapse:collapse}.imagify-inline-options input[type=radio]:checked,.imagify-inline-options input[type=radio]:not(:checked){position:absolute;left:5px;top:5px;display:none}.imagify-inline-options input[type=radio]:checked+label,.imagify-inline-options input[type=radio]:not(:checked)+label{position:relative;display:table-cell;padding:13px 10px;text-align:center;font-weight:600;font-size:16px;text-transform:uppercase;letter-spacing:.1em;color:#FFF;background:#2E3243;border-left:1px solid rgba(255,255,255,.2);-webkit-box-shadow:0 -3px 0 rgba(0,0,0,.1) inset,inset -1px 0 0 rgba(255,255,255,.2);box-shadow:0 -3px 0 rgba(0,0,0,.1) inset,inset -1px 0 0 rgba(255,255,255,.2);z-index:2;-webkit-transition:all .275s;-o-transition:all .275s;transition:all .275s}.imagify-modal .h2,.imagify-modal .h3{letter-spacing:.075em;text-align:center;font-weight:400}.imagify-inline-options input[type=radio]:checked+label:first-of-type,.imagify-inline-options input[type=radio]:not(:checked)+label:first-of-type{border-radius:3px 0 0 3px}.imagify-inline-options input[type=radio]:checked+label:last-of-type,.imagify-inline-options input[type=radio]:not(:checked)+label:last-of-type{border-radius:0 3px 3px 0}.imagify-inline-options input[type=radio]:checked+label{background:#8BC34A}.imagify-inline-options .imagify-info{margin-top:15px}.imagify-columns{padding:15px 0;counter-reset:cols}.imagify-columns [class^=col-]{float:left;-webkit-box-sizing:border-box;box-sizing:border-box}.imagify-columns .col-1-3{width:33.333%;padding-left:28px}.imagify-columns .col-2-3{width:66.666%;padding-left:28px}.imagify-columns .col-1-2{width:50%;padding:0 20px}@media (max-width:830px){.imagify-columns [class^=col-]{float:none;margin-bottom:1.5em}.imagify-columns .col-1-2,.imagify-columns .col-1-3{width:auto;padding:0 28px;clear:both;padding-top:1em}}.column-imagify_optimized_file.column-imagify_optimized_file{width:300px;text-align:center;vertical-align:middle}.column-imagify_optimized_file>*{max-width:235px;margin:0 auto}@media (min-width:1151px) and (max-width:1800px){.column-imagify_optimized_file.column-imagify_optimized_file{width:235px}}@media (min-width:783px) and (max-width:1150px){.column-imagify_optimized_file.column-imagify_optimized_file{width:13em}table.media .column-title .has-media-icon~.row-actions.row-actions{margin-left:0}}@media (max-width:782px){table.media .column-imagify_optimized_file.column-imagify_optimized_file{text-align:left}table.media .imagify-datas-actions-links,table.media .imagify-datas-more-action{text-align:center}table.media .column-imagify_optimized_file .imagify-datas-actions-links a,table.media .column-imagify_optimized_file>*{max-width:100%;margin-left:0}}@media (min-width:783px) and (max-width:1150px),(max-width:360px){table.media .imagify-hide-if-small{position:absolute;margin:-1px;padding:0;height:1px;width:1px;overflow:hidden;clip:rect(0 0 0 0);border:0;word-wrap:normal!important}}.compat-field-imagify .label{vertical-align:top}.compat-field-imagify ul.imagify-datas-list{margin-top:7px;font-size:11px}ul.imagify-datas-list.imagify-datas-list{margin:0 auto;color:#555;font-size:10px}ul.imagify-datas-list .big{font-size:12px;color:#40B1D0}li.imagify-data-item{clear:both;margin-bottom:2px}ul.imagify-datas-list .imagify-data-item span.data,ul.imagify-datas-list .imagify-data-item strong{float:left;width:50%;-webkit-box-sizing:border-box;box-sizing:border-box}ul.imagify-datas-list .imagify-data-item span.data{text-align:left;padding-right:5px}.compat-field-imagify .imagify-datas-list .imagify-data-item .data{width:130px;text-align:left;font-weight:700}ul.imagify-datas-list .imagify-data-item strong{text-align:left;padding-left:5px}.media-sidebar .imagify-datas-list .imagify-data-item .data{width:auto;float:none}.media-sidebar .imagify-datas-list .imagify-data-item strong{display:inline-block;width:auto;float:none}.media-sidebar .imagify-datas-list .imagify-data-item .imagify-chart{float:left}.imagify-datas-more-action.imagify-datas-more-action{margin:.4em auto;background:-webkit-gradient(linear,left top,left bottom,from(transparent),color-stop(49%,transparent),color-stop(50%,rgba(0,0,0,.075)),color-stop(58%,rgba(0,0,0,.075)),color-stop(58%,transparent),to(transparent));background:-o-linear-gradient(top,transparent,transparent 49%,rgba(0,0,0,.075) 50%,rgba(0,0,0,.075) 58%,transparent 58%,transparent);background:linear-gradient(to bottom,transparent,transparent 49%,rgba(0,0,0,.075) 50%,rgba(0,0,0,.075) 58%,transparent 58%,transparent)}.imagify-datas-more-action a{display:inline-block;padding:0 5px;background:#40B1D0;color:#FFF;text-transform:uppercase;font-size:9px;font-weight:700;line-height:1.9;text-decoration:none}.imagify-datas-more-action a.is-open{background:#555}.imagify-datas-more-action a.is-open .dashicons{-webkit-transform:rotate(180deg);-ms-transform:rotate(180deg);transform:rotate(180deg)}.imagify-datas-more-action a .dashicons{font-size:14px;vertical-align:middle;line-height:.8}.imagify-datas-more-action a .dashicons:before{vertical-align:middle;line-height:20px}.imagify-datas-more-action .the-text{display:inline-block;vertical-align:middle;height:auto;line-height:inherit}ul.imagify-datas-details.imagify-datas-details{margin:.7em auto}.imagify-datas-details strong{color:#40B1D0}.imagify-datas-details .original{color:#555}.imagify-datas-actions-links{overflow:hidden;border-top:2px solid transparent;padding-top:5px;font-size:8px}.nggform .imagify-datas-actions-links{position:relative;z-index:2}.nggform .row-actions{z-index:1}.imagify-datas-actions-links a{position:relative;display:inline-block;padding-left:17px;text-decoration:none;font-weight:600}.compat-field-imagify .imagify-datas-actions-links{max-width:300px}.misc-pub-imagify .imagify-datas-actions-links{border-top:2px solid #f2f2f2;padding-bottom:5px}.column-imagify_optimized_file .imagify-datas-actions-links a{margin:0 .7em;padding-left:15px}.compat-field-imagify .imagify-datas-actions-links a,.misc-pub-imagify .imagify-datas-actions-links a{font-size:10px;float:left;width:50%}.media-sidebar .compat-field-imagify .imagify-datas-actions-links a,.submitbox .misc-pub-imagify .imagify-datas-actions-links a{display:block;width:auto;float:none}.imagify-datas-actions-links a:only-child{float:none;width:auto}.imagify-datas-details.is-open+.imagify-datas-actions-links{border-top-color:rgba(0,0,0,.075)}.imagify-datas-actions-links .dashicons{position:absolute;left:0;top:4px;width:12px;margin-right:2px;font-size:11px}.imagify-account,.imagify-account-link{padding-right:15px}.imagify-meteo-icon{display:inline-block;height:38px;vertical-align:middle;margin-right:10px}.imagify-user-plan{color:#40b1d0}.imagify-meteo-title.imagify-meteo-title{color:#FFF;font-size:17px}.imagify-space-left{display:inline-block;min-height:38px;min-width:245px;vertical-align:middle}.imagify-space-left>p{color:#FFF}[class^=imagify-bar-]{position:relative;height:1.5em;width:100%;background:#60758D;color:#FFF;font-size:10px}.imagify-progress{height:1.5em;-webkit-transition:width .3s;-o-transition:width .3s;transition:width .3s}.imagify-bar-positive .imagify-progress{background:#8CC152}.imagify-bar-positive .imagify-barnb{color:#8CC152}.imagify-bar-negative .imagify-progress{background:#73818C}.imagify-bar-negative .imagify-barnb{color:#73818C}.imagify-bar-neutral .imagify-progress{background:#F5A623}.imagify-space-left .imagify-bar-negative .imagify-progress{background:#D0021B}.imagify-btn-ghost{display:inline-block;height:auto;padding:7px 10px;border:1px solid #FFF;text-align:center;background:0 0;color:#FFF;border-radius:3px;-webkit-transition:all .275s;-o-transition:all .275s;transition:all .275s}.imagify-btn-ghost:focus,.imagify-btn-ghost:hover{background:#FFF;color:#888}.imagify-error{background:#D0021B;color:#FFF}.imagify-settings-section .imagify-error{display:inline-block;padding:7px 10px;margin:10px 0 0 45px;border-radius:3px}.imagify-settings-section .imagify-error code{font-weight:400}.imagify-settings-section .imagify-error.hidden{display:none}.imagify-warning{background:#f5a623;color:#FFF;text-shadow:0 0 2px rgba(0,0,0,.2)}.imagify-modal{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-orient:vertical;-webkit-box-direction:normal;-ms-flex-direction:column;flex-direction:column;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center}.js .imagify-modal{display:none;position:fixed;top:0;right:0;bottom:0;left:0;background-color:#1F2332;background-color:rgba(31,35,50,.95);z-index:99999}.imagify-modal-content{-webkit-box-sizing:border-box;box-sizing:border-box;position:relative;width:800px;max-width:95%;max-height:90vw;overflow:auto;padding:20px 25px;margin:1em auto;background:#FFF;-webkit-box-shadow:1px 1px 4px rgba(0,0,0,.7);box-shadow:1px 1px 4px rgba(0,0,0,.7);border-radius:3px}#imagify-visual-comparison .imagify-modal-content,.imagify-visual-comparison .imagify-modal-content{max-width:1400px;background:0 0;padding:5px;-webkit-box-shadow:none;box-shadow:none;border-radius:0}.imagify-modal .h2{margin:.5em 0;color:#8ba6b4;font-size:24px}.imagify-modal .h3{color:#40b1d0;font-size:18px}.imagify-modal .close-btn{display:none;visibility:hidden;position:absolute;right:20px;top:20px;font-size:1.2em;border:0;background:0 0;border-radius:0;cursor:pointer}.imagify-modal .close-btn i{margin-left:-2px}.imagify-modal .close-btn:focus,.imagify-modal .close-btn:hover{color:#40b1d0}.js .imagify-modal .close-btn{display:block;visibility:visible}.imagify-visual-comparison .close-btn,.wp_attachment_image #imagify-visual-comparison .close-btn{top:0}.imagify-visual-comparison .imagify-modal-content,.wp_attachment_image #imagify-visual-comparison .imagify-modal-content{padding-top:40px}.imagify-col{float:left;width:50%;-ms-flex-preferred-size:50%;flex-basis:50%}
assets/css/bulk.css CHANGED
@@ -45,11 +45,16 @@
45
  color: #46b1ce;
46
  }
47
 
 
 
 
 
48
  .imagify-chart-percent {
49
  position: absolute;
50
  left: 0; right: 0;
51
  top: 50%;
52
- margin-top: -14px;
 
53
  text-align: center;
54
  font-size: 55px;
55
  font-weight: bold;
@@ -751,4 +756,4 @@ td.imagify-cell-filename {
751
  to {
752
  transform: rotate(360deg);
753
  }
754
- }
45
  color: #46b1ce;
46
  }
47
 
48
+ .imagify-overview-chart-container {
49
+ float: left;
50
+ margin-right: 20px;
51
+ }
52
  .imagify-chart-percent {
53
  position: absolute;
54
  left: 0; right: 0;
55
  top: 50%;
56
+ margin-top: -.5em;
57
+ line-height: 1;
58
  text-align: center;
59
  font-size: 55px;
60
  font-weight: bold;
756
  to {
757
  transform: rotate(360deg);
758
  }
759
+ }
assets/css/bulk.min.css CHANGED
@@ -1 +1 @@
1
- #imagify-overview-chart-legend{overflow:hidden}.imagify-doughnut-legend{margin-top:38px;list-style:none}.imagify-doughnut-legend li{display:block;padding-left:30px;position:relative;margin-bottom:15px;border-radius:5px;padding:3px 8px 2px 31px;font-size:14px;font-weight:600;cursor:default;-webkit-transition:background-color .2s ease-in-out;-o-transition:background-color .2s ease-in-out;transition:background-color .2s ease-in-out}.imagify-doughnut-legend li span{display:block;position:absolute;left:0;top:0;width:25px;height:25px;border-radius:50%}.imagify-global-optim-phrase{width:180px;padding-top:20px;font-size:14px;font-weight:700;text-align:center}.imagify-total-percent{color:#46b1ce}.imagify-chart-percent{position:absolute;left:0;right:0;top:50%;margin-top:-14px;text-align:center;font-size:55px;font-weight:700;color:#46B1CE}.imagify-chart-percent span{font-size:20px;vertical-align:super}.media_page_imagify-bulk-optimization .media-item,body[class*="_imagify-ngg-bulk-optimization"] .media-item{margin:0}.media_page_imagify-bulk-optimization .media-item .progress,body[class*="_imagify-ngg-bulk-optimization"] .media-item .progress{float:none;width:100%;margin:0;background:#1F2331;-webkit-box-shadow:0;box-shadow:0;border-radius:0}.media_page_imagify-bulk-optimization .media-item .percent,body[class*="_imagify-ngg-bulk-optimization"] .media-item .percent{width:auto;padding:0 5px;line-height:1.85;font-size:12px}.media_page_imagify-bulk-optimization .media-item .percent,.media_page_imagify-bulk-optimization .media-item .progress,body[class*="_imagify-ngg-bulk-optimization"] .media-item .percent,body[class*="_imagify-ngg-bulk-optimization"] .media-item .progress{text-align:right}.media_page_imagify-bulk-optimization .media-item .progress .bar,body[class*="_imagify-ngg-bulk-optimization"] .media-item .progress .bar{width:1px;height:22px;margin-top:0;background:#46B1CE;border-radius:0;overflow:visible;-webkit-transition:width .5s;-o-transition:width .5s;transition:width .5s}#imagify-bulk-action{padding:11px 20px}.imagify-columns .col-overview.col-overview{padding-left:20px}.imagify-columns .col-informations.col-informations{width:36.6%;padding-right:30px}.imagify-columns .col-statistics.col-statistics{width:30%}.imagify-bulk-submit .imagify-inline-options input[type=radio]:checked+label,.imagify-bulk-submit .imagify-inline-options input[type=radio]:not(:checked)+label{margin-bottom:1.75em}.imagify-title-right{display:table;float:right;margin-top:-10px;-webkit-box-ordinal-group:3;-ms-flex-order:2;order:2}.imagify-title-right p{margin:0}.imagify-title-right a{font-weight:700;text-decoration:none}.imagify-title-right>div{display:table-cell;vertical-align:middle}.imagify-title-right .dashicons-arrow-down-alt2{vertical-align:-4px;margin-left:2px}@media (max-width:1200px){.imagify-bulk .imagify-title{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-orient:vertical;-webkit-box-direction:normal;-ms-flex-direction:column;flex-direction:column}.imagify-title-right{-webkit-box-ordinal-group:3;-ms-flex-order:2;order:2;margin-top:20px}}.imagify-sep-v{width:1px;background:rgba(255,255,255,.2)}.imagify-credit-left{position:relative;min-width:280px;padding-left:15px}@media (max-width:630px){.imagify-title-right,.imagify-title-right>div{display:block;width:auto}.imagify-title-right>div{margin-top:10px;max-width:100%}.imagify-credit-left{padding-left:0}}.base-transparent{background:0 0}[class^=imagify-bar-].right-outside-number{-webkit-box-sizing:border-box;box-sizing:border-box;padding-right:4.5em}.right-outside-number .imagify-barnb{display:block;margin-right:-4.5em;text-align:right;font-weight:700;line-height:1.5}.imagify-list-infos{max-width:100%;width:415px}.imagify-info-block,.imagify-list-infos li{position:relative;padding:10px;padding-left:42px;background:#D9E4EB;border-radius:4px;line-height:1.6}.imagify-documentation-link-box:after,.imagify-documentation-link-box:before{display:none}.imagify-list-infos .imagify-documentation-link-box{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center;padding-left:12px;border:1px solid #338EA6;background:#D9E4EC}.imagify-documentation-icon{width:15px;height:20px;margin-right:15px}.imagify-list-infos .imagify-alt.imagify-alt{background:#8BA7B5;color:#FFF;font-weight:700}.imagify-list-infos li+li{margin-top:1em}.imagify-info-block:before,.imagify-list-infos li:before{content:"";position:absolute;left:13px;top:14px;height:16px;width:16px;border:1px solid #46b1ce;border-radius:10px}.imagify-info-block:after,.imagify-list-infos li:after{content:"i";position:absolute;left:20px;top:13px;font-style:italic;color:#46b1ce}.imagify-cell .imagify-info-block{padding-top:0}.imagify-cell .imagify-info-block:after{top:6px}.imagify-cell .imagify-info-block:before{top:7px}.imagify-list-infos .imagify-alt:after,.imagify-list-infos .imagify-alt:before{color:#fff;border-color:#fff}.imagify-sub-title.imagify-sub-title{font-size:23px;background:#FFF;color:#2E3243;border-left:1px solid #D9D9D9;border-right:1px solid #D9D9D9;font-weight:lighter}.imagify-sub-title .icon-bulk{margin-right:10px;vertical-align:middle}.imagify-sub-title .title-text{display:inline-block;line-height:1;vertical-align:middle}.imagify-bulk .imagify-settings-section{border:1px solid #D9D9D9;border-top:0;background:#F2F5F7;color:#4A4A4A}.imagify-bulk .imagify-settings-section h3,.imagify-bulk .imagify-settings-section li,.imagify-bulk .imagify-settings-section p{color:#4A4A4A}.imagify-bulk .imagify-settings-section h3{margin-bottom:2em}.imagify-title .imagify-tooltips{position:absolute;top:100%;left:0}.imagify-tooltips .icon-round{float:left;display:inline-block;width:28px;height:28px;border:1px solid #FFF;margin-right:8px;margin-bottom:8px;font-size:17px;font-style:italic;line-height:29px;font-weight:700;text-align:center;border-radius:50%}.imagify-tooltips .tooltip-content{display:block;position:relative;max-width:250px;padding:7px 15px 8px;background:#2e3242;color:#FFF;font-size:10px;border-radius:3px}.imagify-tooltips.right .tooltip-content{margin-left:12px}.imagify-tooltips.bottom .tooltip-content{margin-top:4px}.imagify-inline-options label .tooltip-content{position:absolute;left:0;right:0;top:100%;text-transform:none;font-size:10px;letter-spacing:0;text-align:center}.imagify-ac-rt-big,.imagistatus{text-transform:uppercase;font-weight:700}.imagify-tooltips .tooltip-content:after{content:"";position:absolute}.imagify-tooltips.right .tooltip-content:after{top:16px;left:-6px;border-right:8px solid #2e3242;border-top:6px solid transparent;border-bottom:6px solid transparent}.imagify-tooltips.bottom .tooltip-content:after{top:-5px;left:50%;margin-left:-3px;border-bottom:6px solid #2e3242;border-left:6px solid transparent;border-right:6px solid transparent}.imagify-space-tooltips .tooltip-content{max-width:280px;margin-top:20px;margin-left:0;padding:5px 15px;font-size:13px;background:#40B1D0;-webkit-box-shadow:0 3px 0 #338EA6;box-shadow:0 3px 0 #338EA6}.imagify-space-tooltips .tooltip-content:after{top:-14px;left:50%;margin-left:-7px;border:0;border-bottom:15px solid #40B1D0;border-left:15px solid transparent;border-right:15px solid transparent}.tooltip-content.tooltip-table{display:table;width:100%}.tooltip-content.tooltip-table>*{display:table-cell;vertical-align:middle}.tooltip-content .cell-icon{width:28px}.tooltip-content .cell-icon .icon{margin-bottom:0}.tooltip-content .cell-text{padding:5px 10px 5px 0;line-height:1.3}.tooltip-content .cell-sep{width:1px;background:rgba(255,255,255,.4)}.tooltip-content .cell-cta{padding-left:10px}.tooltip-content .cell-cta a{display:block;color:#FFF;width:100%;height:100%;white-space:nowrap}.imagify-number-you-optimized .number{display:table-cell;padding-right:15px;font-size:36px;font-weight:700;line-height:1.1;vertical-align:middle;white-space:nowrap}.imagify-number-you-optimized .text{display:table-cell;vertical-align:middle;overflow:hidden;font-size:12px}.imagify-number-you-optimized .text br{display:none}.imagify-number-you-optimized>p{display:table}.imagify-number-you-optimized{padding-bottom:.85em;margin-bottom:1.35em;overflow:hidden;border-bottom:1px solid rgba(0,0,0,.05)}.imagify-bars p{font-weight:700;font-size:12px;margin-bottom:0}.imagify-bars+.imagify-number-you-optimized{border-bottom:0;padding-top:.85em}.imagify-bars+.imagify-number-you-optimized p{color:#46b1ce}.imagify-bulk-table{margin-top:2em;max-height:600px;max-height:60vh;overflow:auto}.imagify-ac-report-text,.imagiuploaded{overflow:hidden}.imagify-bulk-table table{width:100%;border-spacing:0;border-collapse:collapse;border:1px solid #D3D3D3}.imagify-bulk-table td{padding:8px 15px}.imagify-bulk-table thead th,.imagify-bulk-table thead tr{background:#2E3242}.imagify-bulk-table tfoot th,.imagify-bulk-table tfoot tr{background:#73818C}.imagify-bulk-table thead th{padding:14px 15px;text-align:left;color:#F2F5F7;font-weight:700;font-size:14px}.imagify-bulk-table tfoot td{padding:14px 15px;color:#F9FAFA}.imagify-bulk-table tbody td,.imagify-bulk-table tbody tr{background:#FFF}.imagify-bulk-table tbody tr:nth-child(odd),.imagify-bulk-table tbody tr:nth-child(odd) td{background:#F2F5F7}.imagify-bulk-table .imagify-row-progress{display:none}.imagify-bulk-table .imagify-row-progress,.imagify-bulk-table .imagify-row-progress td{height:15px;padding:0}.imagify-bulk-table .imagify-no-uploaded-yet td{height:200px;font-size:17px;letter-spacing:.1em;word-spacing:.12em;vertical-align:middle;text-transform:uppercase;font-weight:700;text-align:center;color:#999;background-color:#FFF}.imagify-row-complete{padding:35px 20px;margin-top:2em;background:#8BC34A;color:#FFF;text-shadow:0 0 2px rgba(0,0,0,.1)}.imagify-row-complete .imagify-ac-chart{margin-top:3px}.imagify-row-complete p{color:#FFF;margin:0}@-webkit-keyframes congrate{0%{opacity:0;-webkit-transform:scale(1)}50%{-webkit-transform:scale(1.05);opacity:1}100%{-webkit-transform:scale(1);opacity:1}}@keyframes congrate{0%{opacity:0;-webkit-transform:scale(1);transform:scale(1)}50%{-webkit-transform:scale(1.05);transform:scale(1.05);opacity:1}100%{-webkit-transform:scale(1);transform:scale(1);opacity:1}}.imagify-row-complete.done{-webkit-animation:congrate .5s ease-in-out;animation:congrate .5s ease-in-out}.imagify-all-complete{margin:1.5em 0}.imagify-all-complete>div{display:inline-block;vertical-align:middle}.imagify-ac-report{min-width:310px}.imagify-ac-chart{width:46px;height:46px;float:left;margin:0 20px 0 10px}.imagify-ac-report-text p{line-height:1.3}.imagify-ac-rt-big{font-size:24px;letter-spacing:.15em;word-spacing:.15em}.imagify-ac-share{text-align:right}.imagify-ac-share-content{display:inline-block;padding:10px 15px;background:rgba(255,255,255,.2)}.imagify-ac-share-content>*{display:inline-block;vertical-align:middle}.imagify-bulk-table .imagify-ac-share-content p{margin-right:5px}.imagify-share-networks,.imagify-share-networks li{margin:0}.imagify-share-networks li{display:inline-block}.imagify-share-networks a{display:inline-block;vertical-align:-7px;margin:0 5px;text-decoration:none;color:#FFF}.imagify-cell-filename{max-width:200px}.imagify-cell-status{max-width:145px}.imagify-cell-status .dashicons-warning{margin-right:2px}.imagify-cell-thumbnails{max-width:120px}td.imagify-cell-filename{-o-text-overflow:clip;text-overflow:clip;white-space:nowrap;overflow:hidden}.imagify-bulk-table .imagify-cell-thumbnails{text-align:center}.imagify-cell-percentage,.imagify-cell-savings{color:#46B1CE;font-weight:700}.imagify-cell-optimized{font-weight:700}.imagify-bulk-table td.imagify-cell-totaloriginal{padding-right:78px}.imagify-cell-totaloriginal{text-align:right}.imagifilename,.imagiuploaded{display:inline-block;vertical-align:middle}.imagifilename{font-size:12px}.imagiuploaded{width:33px;height:33px;margin-right:5px;margin-left:-8px;background:url(../images/upload-image.png) no-repeat;background-size:cover}.imagiuploaded img{max-widht:100%;height:auto}.imagistatus{color:#8CA6B3}.status-compressing{color:#46B1CE}.status-error{color:#CE0B24}.status-warning{color:#f5a623}.status-complete{color:#8CC152}.dashicons.rotate{-webkit-animation:icon-rotate 2.6s infinite linear;animation:icon-rotate 2.6s infinite linear}.imagify-cell-status .dashicons-admin-generic{-webkit-transform-origin:48.75% 51.75%;-ms-transform-origin:48.75% 51.75%;transform-origin:48.75% 51.75%}@-webkit-keyframes icon-rotate{from{-webkit-transform:rotate(0);transform:rotate(0)}to{-webkit-transform:rotate(360deg);transform:rotate(360deg)}}@keyframes icon-rotate{from{-webkit-transform:rotate(0);transform:rotate(0)}to{-webkit-transform:rotate(360deg);transform:rotate(360deg)}}
1
+ #imagify-overview-chart-legend{overflow:hidden}.imagify-doughnut-legend{margin-top:38px;list-style:none}.imagify-doughnut-legend li{display:block;padding-left:30px;position:relative;margin-bottom:15px;border-radius:5px;padding:3px 8px 2px 31px;font-size:14px;font-weight:600;cursor:default;-webkit-transition:background-color .2s ease-in-out;-o-transition:background-color .2s ease-in-out;transition:background-color .2s ease-in-out}.imagify-doughnut-legend li span{display:block;position:absolute;left:0;top:0;width:25px;height:25px;border-radius:50%}.imagify-global-optim-phrase{width:180px;padding-top:20px;font-size:14px;font-weight:700;text-align:center}.imagify-total-percent{color:#46b1ce}.imagify-overview-chart-container{float:left;margin-right:20px}.imagify-chart-percent{position:absolute;left:0;right:0;top:50%;margin-top:-.5em;line-height:1;text-align:center;font-size:55px;font-weight:700;color:#46B1CE}.imagify-chart-percent span{font-size:20px;vertical-align:super}.media_page_imagify-bulk-optimization .media-item,body[class*="_imagify-ngg-bulk-optimization"] .media-item{margin:0}.media_page_imagify-bulk-optimization .media-item .progress,body[class*="_imagify-ngg-bulk-optimization"] .media-item .progress{float:none;width:100%;margin:0;background:#1F2331;-webkit-box-shadow:0;box-shadow:0;border-radius:0}.media_page_imagify-bulk-optimization .media-item .percent,body[class*="_imagify-ngg-bulk-optimization"] .media-item .percent{width:auto;padding:0 5px;line-height:1.85;font-size:12px}.media_page_imagify-bulk-optimization .media-item .percent,.media_page_imagify-bulk-optimization .media-item .progress,body[class*="_imagify-ngg-bulk-optimization"] .media-item .percent,body[class*="_imagify-ngg-bulk-optimization"] .media-item .progress{text-align:right}.media_page_imagify-bulk-optimization .media-item .progress .bar,body[class*="_imagify-ngg-bulk-optimization"] .media-item .progress .bar{width:1px;height:22px;margin-top:0;background:#46B1CE;border-radius:0;overflow:visible;-webkit-transition:width .5s;-o-transition:width .5s;transition:width .5s}#imagify-bulk-action{padding:11px 20px}.imagify-columns .col-overview.col-overview{padding-left:20px}.imagify-columns .col-informations.col-informations{width:36.6%;padding-right:30px}.imagify-columns .col-statistics.col-statistics{width:30%}.imagify-bulk-submit .imagify-inline-options input[type=radio]:checked+label,.imagify-bulk-submit .imagify-inline-options input[type=radio]:not(:checked)+label{margin-bottom:1.75em}.imagify-title-right{display:table;float:right;margin-top:-10px;-webkit-box-ordinal-group:3;-ms-flex-order:2;order:2}.imagify-title-right p{margin:0}.imagify-title-right a{font-weight:700;text-decoration:none}.imagify-title-right>div{display:table-cell;vertical-align:middle}.imagify-title-right .dashicons-arrow-down-alt2{vertical-align:-4px;margin-left:2px}@media (max-width:1200px){.imagify-bulk .imagify-title{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-orient:vertical;-webkit-box-direction:normal;-ms-flex-direction:column;flex-direction:column}.imagify-title-right{-webkit-box-ordinal-group:3;-ms-flex-order:2;order:2;margin-top:20px}}.imagify-sep-v{width:1px;background:rgba(255,255,255,.2)}.imagify-credit-left{position:relative;min-width:280px;padding-left:15px}@media (max-width:630px){.imagify-title-right,.imagify-title-right>div{display:block;width:auto}.imagify-title-right>div{margin-top:10px;max-width:100%}.imagify-credit-left{padding-left:0}}.base-transparent{background:0 0}[class^=imagify-bar-].right-outside-number{-webkit-box-sizing:border-box;box-sizing:border-box;padding-right:4.5em}.right-outside-number .imagify-barnb{display:block;margin-right:-4.5em;text-align:right;font-weight:700;line-height:1.5}.imagify-list-infos{max-width:100%;width:415px}.imagify-info-block,.imagify-list-infos li{position:relative;padding:10px;padding-left:42px;background:#D9E4EB;border-radius:4px;line-height:1.6}.imagify-documentation-link-box:after,.imagify-documentation-link-box:before{display:none}.imagify-list-infos .imagify-documentation-link-box{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center;padding-left:12px;border:1px solid #338EA6;background:#D9E4EC}.imagify-documentation-icon{width:15px;height:20px;margin-right:15px}.imagify-list-infos .imagify-alt.imagify-alt{background:#8BA7B5;color:#FFF;font-weight:700}.imagify-list-infos li+li{margin-top:1em}.imagify-info-block:before,.imagify-list-infos li:before{content:"";position:absolute;left:13px;top:14px;height:16px;width:16px;border:1px solid #46b1ce;border-radius:10px}.imagify-info-block:after,.imagify-list-infos li:after{content:"i";position:absolute;left:20px;top:13px;font-style:italic;color:#46b1ce}.imagify-cell .imagify-info-block{padding-top:0}.imagify-cell .imagify-info-block:after{top:6px}.imagify-cell .imagify-info-block:before{top:7px}.imagify-list-infos .imagify-alt:after,.imagify-list-infos .imagify-alt:before{color:#fff;border-color:#fff}.imagify-sub-title.imagify-sub-title{font-size:23px;background:#FFF;color:#2E3243;border-left:1px solid #D9D9D9;border-right:1px solid #D9D9D9;font-weight:lighter}.imagify-sub-title .icon-bulk{margin-right:10px;vertical-align:middle}.imagify-sub-title .title-text{display:inline-block;line-height:1;vertical-align:middle}.imagify-bulk .imagify-settings-section{border:1px solid #D9D9D9;border-top:0;background:#F2F5F7;color:#4A4A4A}.imagify-bulk .imagify-settings-section h3,.imagify-bulk .imagify-settings-section li,.imagify-bulk .imagify-settings-section p{color:#4A4A4A}.imagify-bulk .imagify-settings-section h3{margin-bottom:2em}.imagify-title .imagify-tooltips{position:absolute;top:100%;left:0}.imagify-tooltips .icon-round{float:left;display:inline-block;width:28px;height:28px;border:1px solid #FFF;margin-right:8px;margin-bottom:8px;font-size:17px;font-style:italic;line-height:29px;font-weight:700;text-align:center;border-radius:50%}.imagify-tooltips .tooltip-content{display:block;position:relative;max-width:250px;padding:7px 15px 8px;background:#2e3242;color:#FFF;font-size:10px;border-radius:3px}.imagify-tooltips.right .tooltip-content{margin-left:12px}.imagify-tooltips.bottom .tooltip-content{margin-top:4px}.imagify-inline-options label .tooltip-content{position:absolute;left:0;right:0;top:100%;text-transform:none;font-size:10px;letter-spacing:0;text-align:center}.imagify-ac-rt-big,.imagistatus{text-transform:uppercase;font-weight:700}.imagify-tooltips .tooltip-content:after{content:"";position:absolute}.imagify-tooltips.right .tooltip-content:after{top:16px;left:-6px;border-right:8px solid #2e3242;border-top:6px solid transparent;border-bottom:6px solid transparent}.imagify-tooltips.bottom .tooltip-content:after{top:-5px;left:50%;margin-left:-3px;border-bottom:6px solid #2e3242;border-left:6px solid transparent;border-right:6px solid transparent}.imagify-space-tooltips .tooltip-content{max-width:280px;margin-top:20px;margin-left:0;padding:5px 15px;font-size:13px;background:#40B1D0;-webkit-box-shadow:0 3px 0 #338EA6;box-shadow:0 3px 0 #338EA6}.imagify-space-tooltips .tooltip-content:after{top:-14px;left:50%;margin-left:-7px;border:0;border-bottom:15px solid #40B1D0;border-left:15px solid transparent;border-right:15px solid transparent}.tooltip-content.tooltip-table{display:table;width:100%}.tooltip-content.tooltip-table>*{display:table-cell;vertical-align:middle}.tooltip-content .cell-icon{width:28px}.tooltip-content .cell-icon .icon{margin-bottom:0}.tooltip-content .cell-text{padding:5px 10px 5px 0;line-height:1.3}.tooltip-content .cell-sep{width:1px;background:rgba(255,255,255,.4)}.tooltip-content .cell-cta{padding-left:10px}.tooltip-content .cell-cta a{display:block;color:#FFF;width:100%;height:100%;white-space:nowrap}.imagify-number-you-optimized .number{display:table-cell;padding-right:15px;font-size:36px;font-weight:700;line-height:1.1;vertical-align:middle;white-space:nowrap}.imagify-number-you-optimized .text{display:table-cell;vertical-align:middle;overflow:hidden;font-size:12px}.imagify-number-you-optimized .text br{display:none}.imagify-number-you-optimized>p{display:table}.imagify-number-you-optimized{padding-bottom:.85em;margin-bottom:1.35em;overflow:hidden;border-bottom:1px solid rgba(0,0,0,.05)}.imagify-bars p{font-weight:700;font-size:12px;margin-bottom:0}.imagify-bars+.imagify-number-you-optimized{border-bottom:0;padding-top:.85em}.imagify-bars+.imagify-number-you-optimized p{color:#46b1ce}.imagify-bulk-table{margin-top:2em;max-height:600px;max-height:60vh;overflow:auto}.imagify-ac-report-text,.imagiuploaded{overflow:hidden}.imagify-bulk-table table{width:100%;border-spacing:0;border-collapse:collapse;border:1px solid #D3D3D3}.imagify-bulk-table td{padding:8px 15px}.imagify-bulk-table thead th,.imagify-bulk-table thead tr{background:#2E3242}.imagify-bulk-table tfoot th,.imagify-bulk-table tfoot tr{background:#73818C}.imagify-bulk-table thead th{padding:14px 15px;text-align:left;color:#F2F5F7;font-weight:700;font-size:14px}.imagify-bulk-table tfoot td{padding:14px 15px;color:#F9FAFA}.imagify-bulk-table tbody td,.imagify-bulk-table tbody tr{background:#FFF}.imagify-bulk-table tbody tr:nth-child(odd),.imagify-bulk-table tbody tr:nth-child(odd) td{background:#F2F5F7}.imagify-bulk-table .imagify-row-progress{display:none}.imagify-bulk-table .imagify-row-progress,.imagify-bulk-table .imagify-row-progress td{height:15px;padding:0}.imagify-bulk-table .imagify-no-uploaded-yet td{height:200px;font-size:17px;letter-spacing:.1em;word-spacing:.12em;vertical-align:middle;text-transform:uppercase;font-weight:700;text-align:center;color:#999;background-color:#FFF}.imagify-row-complete{padding:35px 20px;margin-top:2em;background:#8BC34A;color:#FFF;text-shadow:0 0 2px rgba(0,0,0,.1)}.imagify-row-complete .imagify-ac-chart{margin-top:3px}.imagify-row-complete p{color:#FFF;margin:0}@-webkit-keyframes congrate{0%{opacity:0;-webkit-transform:scale(1)}50%{-webkit-transform:scale(1.05);opacity:1}100%{-webkit-transform:scale(1);opacity:1}}@keyframes congrate{0%{opacity:0;-webkit-transform:scale(1);transform:scale(1)}50%{-webkit-transform:scale(1.05);transform:scale(1.05);opacity:1}100%{-webkit-transform:scale(1);transform:scale(1);opacity:1}}.imagify-row-complete.done{-webkit-animation:congrate .5s ease-in-out;animation:congrate .5s ease-in-out}.imagify-all-complete{margin:1.5em 0}.imagify-all-complete>div{display:inline-block;vertical-align:middle}.imagify-ac-report{min-width:310px}.imagify-ac-chart{width:46px;height:46px;float:left;margin:0 20px 0 10px}.imagify-ac-report-text p{line-height:1.3}.imagify-ac-rt-big{font-size:24px;letter-spacing:.15em;word-spacing:.15em}.imagify-ac-share{text-align:right}.imagify-ac-share-content{display:inline-block;padding:10px 15px;background:rgba(255,255,255,.2)}.imagify-ac-share-content>*{display:inline-block;vertical-align:middle}.imagify-bulk-table .imagify-ac-share-content p{margin-right:5px}.imagify-share-networks,.imagify-share-networks li{margin:0}.imagify-share-networks li{display:inline-block}.imagify-share-networks a{display:inline-block;vertical-align:-7px;margin:0 5px;text-decoration:none;color:#FFF}.imagify-cell-filename{max-width:200px}.imagify-cell-status{max-width:145px}.imagify-cell-status .dashicons-warning{margin-right:2px}.imagify-cell-thumbnails{max-width:120px}td.imagify-cell-filename{-o-text-overflow:clip;text-overflow:clip;white-space:nowrap;overflow:hidden}.imagify-bulk-table .imagify-cell-thumbnails{text-align:center}.imagify-cell-percentage,.imagify-cell-savings{color:#46B1CE;font-weight:700}.imagify-cell-optimized{font-weight:700}.imagify-bulk-table td.imagify-cell-totaloriginal{padding-right:78px}.imagify-cell-totaloriginal{text-align:right}.imagifilename,.imagiuploaded{display:inline-block;vertical-align:middle}.imagifilename{font-size:12px}.imagiuploaded{width:33px;height:33px;margin-right:5px;margin-left:-8px;background:url(../images/upload-image.png) no-repeat;background-size:cover}.imagiuploaded img{max-widht:100%;height:auto}.imagistatus{color:#8CA6B3}.status-compressing{color:#46B1CE}.status-error{color:#CE0B24}.status-warning{color:#f5a623}.status-complete{color:#8CC152}.dashicons.rotate{-webkit-animation:icon-rotate 2.6s infinite linear;animation:icon-rotate 2.6s infinite linear}.imagify-cell-status .dashicons-admin-generic{-webkit-transform-origin:48.75% 51.75%;-ms-transform-origin:48.75% 51.75%;transform-origin:48.75% 51.75%}@-webkit-keyframes icon-rotate{from{-webkit-transform:rotate(0);transform:rotate(0)}to{-webkit-transform:rotate(360deg);transform:rotate(360deg)}}@keyframes icon-rotate{from{-webkit-transform:rotate(0);transform:rotate(0)}to{-webkit-transform:rotate(360deg);transform:rotate(360deg)}}
assets/css/twentytwenty.css CHANGED
@@ -254,22 +254,11 @@
254
  margin: 15px 0;
255
  overflow: hidden;
256
  }
257
- .imagify-comparison-levels div {
258
  display: none;
259
  min-width: 175px;
260
  font-size: 11px;
261
  }
262
- .imagify-comparison-levels .imagify-chart,
263
- .imagify-comparison-levels .imagify-chart-container {
264
- width: 25px;
265
- float: none;
266
- margin: 0;
267
- }
268
- .imagify-visual-comparison .imagify-chart-container canvas {
269
- width: 15px!important;
270
- height: 15px!important;
271
- margin-right: 5px;
272
- }
273
  .imagify-c-level.go-left {
274
  float: left;
275
  }
@@ -300,9 +289,6 @@
300
  color: #8bc34a;
301
  font-weight: bold;
302
  }
303
- .imagify-c-level-row .value .imagify-chart {
304
- top: 1px;
305
- }
306
 
307
  /* TT Loader */
308
  .imagify-modal .loader {
254
  margin: 15px 0;
255
  overflow: hidden;
256
  }
257
+ .imagify-comparison-levels .imagify-c-level {
258
  display: none;
259
  min-width: 175px;
260
  font-size: 11px;
261
  }
 
 
 
 
 
 
 
 
 
 
 
262
  .imagify-c-level.go-left {
263
  float: left;
264
  }
289
  color: #8bc34a;
290
  font-weight: bold;
291
  }
 
 
 
292
 
293
  /* TT Loader */
294
  .imagify-modal .loader {
assets/css/twentytwenty.min.css CHANGED
@@ -1 +1 @@
1
- .twentytwenty-handle{z-index:40;position:absolute;left:50%;top:50%;height:64px;width:64px;margin-left:-32px;margin-top:-32px;border-radius:50%;-webkit-box-shadow:0 3px 0 #338EA6;box-shadow:0 3px 0 #338EA6;background:#40B1D0;cursor:pointer}.twentytwenty-horizontal .twentytwenty-handle:after,.twentytwenty-horizontal .twentytwenty-handle:before{left:50%;width:2px;height:9999px;margin-left:-1px;content:"";position:absolute;z-index:30;display:block;background:#F2F5F7;-webkit-box-shadow:0 0 12px rgba(51,51,51,.5);box-shadow:0 0 12px rgba(51,51,51,.5)}.twentytwenty-horizontal .twentytwenty-handle:before{bottom:50%;margin-bottom:32px}.twentytwenty-horizontal .twentytwenty-handle:after{top:50%;margin-top:34px}.twentytwenty-labels,.twentytwenty-overlay{position:absolute;top:0;width:100%;height:100%;-webkit-transition-duration:.5s;-o-transition-duration:.5s;transition-duration:.5s}.twentytwenty-labels{opacity:1;-webkit-transition-property:opacity;-o-transition-property:opacity;transition-property:opacity}.twentytwenty-labels .twentytwenty-label-content{position:absolute;padding:0 12px;font-size:13px;letter-spacing:.1em;line-height:38px;color:#fff;background:#1F2332;border-radius:2px}.twentytwenty-horizontal .twentytwenty-labels .twentytwenty-label-content{bottom:15px}.twentytwenty-after-label .twentytwenty-label-content{background:#40B1D0}.twentytwenty-left-arrow,.twentytwenty-right-arrow{position:absolute;width:0;height:0;border:8px inset transparent;top:50%;margin-top:-8px}.twentytwenty-container{-webkit-box-sizing:content-box;box-sizing:content-box;position:relative;z-index:0;overflow:hidden;-webkit-box-shadow:0 5px 10px rgba(0,0,0,.15);box-shadow:0 5px 10px rgba(0,0,0,.15);opacity:0;-webkit-transition:opacity .4s;-o-transition:opacity .4s;transition:opacity .4s;-webkit-user-select:none;-moz-user-select:none}.twentytwenty-container *{-webkit-box-sizing:content-box;box-sizing:content-box}.twentytwenty-container img{position:absolute;top:0;display:block;width:100%;height:auto}.loaded .twentytwenty-container{opacity:1}.twentytwenty-container.active .twentytwenty-overlay .twentytwenty-labels,.twentytwenty-container.active .twentytwenty-overlay:hover .twentytwenty-labels{opacity:0}.twentytwenty-horizontal .twentytwenty-before-label .twentytwenty-label-content{left:15px}.twentytwenty-horizontal .twentytwenty-after-label .twentytwenty-label-content{right:15px}.twentytwenty-overlay{z-index:25}.twentytwenty-before{z-index:20}.twentytwenty-after{z-index:10}.twentytwenty-duo-buttons{position:absolute;top:10px;z-index:30;overflow:hidden}.twentytwenty-duo-buttons button{float:left;padding:2px 6px;font-size:11px;text-transform:uppercase;letter-spacing:.125em;font-weight:700;border:0;background:#1f2332;color:#FFF;-webkit-transition:all .3s;-o-transition:all .3s;transition:all .3s;cursor:pointer}.twentytwenty-duo-buttons button:focus,.twentytwenty-duo-buttons button:hover{background:#444}.twentytwenty-duo-buttons button:first-child{border-radius:3px 0 0 3px}.twentytwenty-duo-buttons button:last-child{border-radius:0 3px 3px 0}.twentytwenty-duo-buttons button.selected{background:#8bc34a;text-shadow:0 0 1px rgba(0,0,0,.2);cursor:default}.twentytwenty-duo-left{left:10px}.twentytwenty-duo-right{right:10px}.twentytwenty-left-arrow{left:50%;margin-left:-22px;border-right:8px solid #fff}.twentytwenty-right-arrow{right:50%;margin-right:-22px;border-left:8px solid #fff}#imagify-visual-comparison .close-btn,.imagify-visual-comparison .close-btn{top:50px;right:5px;width:33px;height:33px;padding:1px 0 0 2px;border:1px solid #F2F2F2;color:#F2F2F2;line-height:19px;text-align:center;border-radius:50%}.imagify-modal .imagify-comparison-title{font-size:28px;margin-bottom:1em;color:#F2F2F2;text-align:left}.imagify-modal .imagify-comparison-title .twentytwenty-duo-buttons{position:static;margin:0 10px 0 15px}.imagify-comparison-title .twentytwenty-duo-buttons button{float:none;padding:6px 12px;font-size:16px;text-transform:none;border:1px solid #40B1D0;color:#889;letter-spacing:0}.imagify-comparison-title .twentytwenty-duo-buttons button:focus{outline:0;-webkit-box-shadow:none;box-shadow:none}.imagify-comparison-title .twentytwenty-duo-buttons .selected{border:1px solid #40B1D0;color:#FFF;background:#40B1D0}.imagify-comparison-levels{margin:15px 0;overflow:hidden}.imagify-comparison-levels div{display:none;min-width:175px;font-size:11px}.imagify-comparison-levels .imagify-chart,.imagify-comparison-levels .imagify-chart-container{width:25px;float:none;margin:0}.imagify-visual-comparison .imagify-chart-container canvas{width:15px!important;height:15px!important;margin-right:5px}.imagify-c-level.go-left{float:left}.imagify-c-level.go-right{float:right}.imagify-c-level.go-left,.imagify-c-level.go-right{display:table}.imagify-c-level .imagify-c-level-row{display:table-row;margin:0;color:#FFF}.imagify-c-level-row>span{display:table-cell;padding:2px 0}.imagify-c-level-row .value{text-align:right;padding-left:5px}.imagify-c-level-row .value.level{color:#40b1d0}.imagify-c-level-row .value.size{color:#8bc34a;font-weight:700}.imagify-c-level-row .value .imagify-chart{top:1px}.imagify-modal .loader{position:absolute;top:50%;left:50%;margin:-32px 0 0 -32px;opacity:0;visibility:hidden;-webkit-transition:opacity .4s;-o-transition:opacity .4s;transition:opacity .4s}.imagify-modal .loading .loader{visibility:visible;opacity:1}.imagify-settings .imagify-visual-comparison-text{margin-top:1em;color:#40b1d0;font-weight:700}.modal-is-too-high .imagify-comparison-levels{position:absolute;padding:15px 20px;background:rgba(31,35,50,.95);bottom:0;left:0;right:0;margin-bottom:0}
1
+ .twentytwenty-handle{z-index:40;position:absolute;left:50%;top:50%;height:64px;width:64px;margin-left:-32px;margin-top:-32px;border-radius:50%;-webkit-box-shadow:0 3px 0 #338EA6;box-shadow:0 3px 0 #338EA6;background:#40B1D0;cursor:pointer}.twentytwenty-horizontal .twentytwenty-handle:after,.twentytwenty-horizontal .twentytwenty-handle:before{left:50%;width:2px;height:9999px;margin-left:-1px;content:"";position:absolute;z-index:30;display:block;background:#F2F5F7;-webkit-box-shadow:0 0 12px rgba(51,51,51,.5);box-shadow:0 0 12px rgba(51,51,51,.5)}.twentytwenty-horizontal .twentytwenty-handle:before{bottom:50%;margin-bottom:32px}.twentytwenty-horizontal .twentytwenty-handle:after{top:50%;margin-top:34px}.twentytwenty-labels,.twentytwenty-overlay{position:absolute;top:0;width:100%;height:100%;-webkit-transition-duration:.5s;-o-transition-duration:.5s;transition-duration:.5s}.twentytwenty-labels{opacity:1;-webkit-transition-property:opacity;-o-transition-property:opacity;transition-property:opacity}.twentytwenty-labels .twentytwenty-label-content{position:absolute;padding:0 12px;font-size:13px;letter-spacing:.1em;line-height:38px;color:#fff;background:#1F2332;border-radius:2px}.twentytwenty-horizontal .twentytwenty-labels .twentytwenty-label-content{bottom:15px}.twentytwenty-after-label .twentytwenty-label-content{background:#40B1D0}.twentytwenty-left-arrow,.twentytwenty-right-arrow{position:absolute;width:0;height:0;border:8px inset transparent;top:50%;margin-top:-8px}.twentytwenty-container{-webkit-box-sizing:content-box;box-sizing:content-box;position:relative;z-index:0;overflow:hidden;-webkit-box-shadow:0 5px 10px rgba(0,0,0,.15);box-shadow:0 5px 10px rgba(0,0,0,.15);opacity:0;-webkit-transition:opacity .4s;-o-transition:opacity .4s;transition:opacity .4s;-webkit-user-select:none;-moz-user-select:none}.twentytwenty-container *{-webkit-box-sizing:content-box;box-sizing:content-box}.twentytwenty-container img{position:absolute;top:0;display:block;width:100%;height:auto}.loaded .twentytwenty-container{opacity:1}.twentytwenty-container.active .twentytwenty-overlay .twentytwenty-labels,.twentytwenty-container.active .twentytwenty-overlay:hover .twentytwenty-labels{opacity:0}.twentytwenty-horizontal .twentytwenty-before-label .twentytwenty-label-content{left:15px}.twentytwenty-horizontal .twentytwenty-after-label .twentytwenty-label-content{right:15px}.twentytwenty-overlay{z-index:25}.twentytwenty-before{z-index:20}.twentytwenty-after{z-index:10}.twentytwenty-duo-buttons{position:absolute;top:10px;z-index:30;overflow:hidden}.twentytwenty-duo-buttons button{float:left;padding:2px 6px;font-size:11px;text-transform:uppercase;letter-spacing:.125em;font-weight:700;border:0;background:#1f2332;color:#FFF;-webkit-transition:all .3s;-o-transition:all .3s;transition:all .3s;cursor:pointer}.twentytwenty-duo-buttons button:focus,.twentytwenty-duo-buttons button:hover{background:#444}.twentytwenty-duo-buttons button:first-child{border-radius:3px 0 0 3px}.twentytwenty-duo-buttons button:last-child{border-radius:0 3px 3px 0}.twentytwenty-duo-buttons button.selected{background:#8bc34a;text-shadow:0 0 1px rgba(0,0,0,.2);cursor:default}.twentytwenty-duo-left{left:10px}.twentytwenty-duo-right{right:10px}.twentytwenty-left-arrow{left:50%;margin-left:-22px;border-right:8px solid #fff}.twentytwenty-right-arrow{right:50%;margin-right:-22px;border-left:8px solid #fff}#imagify-visual-comparison .close-btn,.imagify-visual-comparison .close-btn{top:50px;right:5px;width:33px;height:33px;padding:1px 0 0 2px;border:1px solid #F2F2F2;color:#F2F2F2;line-height:19px;text-align:center;border-radius:50%}.imagify-modal .imagify-comparison-title{font-size:28px;margin-bottom:1em;color:#F2F2F2;text-align:left}.imagify-modal .imagify-comparison-title .twentytwenty-duo-buttons{position:static;margin:0 10px 0 15px}.imagify-comparison-title .twentytwenty-duo-buttons button{float:none;padding:6px 12px;font-size:16px;text-transform:none;border:1px solid #40B1D0;color:#889;letter-spacing:0}.imagify-comparison-title .twentytwenty-duo-buttons button:focus{outline:0;-webkit-box-shadow:none;box-shadow:none}.imagify-comparison-title .twentytwenty-duo-buttons .selected{border:1px solid #40B1D0;color:#FFF;background:#40B1D0}.imagify-comparison-levels{margin:15px 0;overflow:hidden}.imagify-comparison-levels .imagify-c-level{display:none;min-width:175px;font-size:11px}.imagify-c-level.go-left{float:left}.imagify-c-level.go-right{float:right}.imagify-c-level.go-left,.imagify-c-level.go-right{display:table}.imagify-c-level .imagify-c-level-row{display:table-row;margin:0;color:#FFF}.imagify-c-level-row>span{display:table-cell;padding:2px 0}.imagify-c-level-row .value{text-align:right;padding-left:5px}.imagify-c-level-row .value.level{color:#40b1d0}.imagify-c-level-row .value.size{color:#8bc34a;font-weight:700}.imagify-modal .loader{position:absolute;top:50%;left:50%;margin:-32px 0 0 -32px;opacity:0;visibility:hidden;-webkit-transition:opacity .4s;-o-transition:opacity .4s;transition:opacity .4s}.imagify-modal .loading .loader{visibility:visible;opacity:1}.imagify-settings .imagify-visual-comparison-text{margin-top:1em;color:#40b1d0;font-weight:700}.modal-is-too-high .imagify-comparison-levels{position:absolute;padding:15px 20px;background:rgba(31,35,50,.95);bottom:0;left:0;right:0;margin-bottom:0}
assets/images/big-blue-check.png CHANGED
File without changes
assets/images/icon-arrow-choice.png CHANGED
File without changes
assets/images/icon-arrow-choice.svg CHANGED
File without changes
assets/images/icon-lock.png CHANGED
File without changes
assets/images/icon-lock.svg CHANGED
File without changes
assets/images/icon-pack.png CHANGED
File without changes
assets/images/icon-pack.svg CHANGED
File without changes
assets/images/pic-ericwaltr.jpg CHANGED
File without changes
assets/images/pic-srhdesign.jpg CHANGED
File without changes
assets/js/bulk.js CHANGED
@@ -1,25 +1,21 @@
1
  (function($, d, w, undefined) { // eslint-disable-line no-unused-vars, no-shadow, no-shadow-restricted-names
2
  var overviewCanvas = d.getElementById( 'imagify-overview-chart' ),
3
- overviewData = [
4
- {
5
- value: imagifyBulk.totalUnoptimizedAttachments,
6
- color: '#D9E4EB',
7
- highlight: '#D9E4EB',
8
- label: imagifyBulk.labels.overviewChartLabels.unoptimized
9
- },
10
- {
11
- value: imagifyBulk.totalOptimizedAttachments,
12
- color: '#46B1CE',
13
- highlight: '#46B1CE',
14
- label: imagifyBulk.labels.overviewChartLabels.optimized
15
- },
16
- {
17
- value: imagifyBulk.totalErrorsAttachments,
18
- color: '#2E3242',
19
- highlight: '#2E3242',
20
- label: imagifyBulk.labels.overviewChartLabels.error
21
- }
22
- ],
23
  overviewDoughnut, overviewLegend;
24
 
25
  /**
@@ -29,27 +25,51 @@
29
  * @param {element} canvas
30
  */
31
  function drawMeAChart( canvas ) {
 
 
 
 
 
 
 
 
32
  canvas.each( function() {
33
- var $this = $( this ),
34
- theValue = parseInt( $this.closest( '.imagify-chart' ).next( '.imagipercent' ).text(), 10 ),
35
- data = [
36
- {
37
- value: theValue,
38
- color: '#00B3D3'
39
- },
40
- {
41
- value: 100 - theValue,
42
- color: '#D8D8D8'
43
- }
44
- ];
45
 
46
- new Chart( $this[0].getContext( '2d' ) ).Doughnut( data, { // eslint-disable-line new-cap
47
- segmentStrokeColor: '#FFF',
48
- segmentStrokeWidth: 1,
49
- animateRotate: true,
50
- tooltipEvents: []
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
51
  } );
52
  } );
 
 
53
  }
54
 
55
  /*
@@ -59,53 +79,84 @@
59
  * @param {element} canvas
60
  */
61
  function drawMeCompleteChart( canvas ) {
 
 
62
  canvas.each( function() {
63
- var $this = $( this ),
64
- theValue = parseInt( $this.closest( '.imagify-ac-chart' ).attr( 'data-percent' ), 10 ),
65
- data = [
66
- {
67
- value: theValue,
68
- color: '#40B1D0'
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
69
  },
70
- {
71
- value: 100 - theValue,
72
- color: '#FFFFFF'
73
- }
74
- ];
75
-
76
- new Chart( $this[0].getContext( '2d' ) ).Doughnut( data, { // eslint-disable-line new-cap
77
- segmentStrokeColor: 'transparent',
78
- segmentStrokeWidth: 0,
79
- animateRotate: true,
80
- animation: true,
81
- percentageInnerCutout: 70,
82
- tooltipEvents: []
83
  } );
84
  } );
 
 
85
  }
86
 
87
  if ( overviewCanvas ) {
88
- overviewDoughnut = new Chart( overviewCanvas.getContext( '2d' ) ).Doughnut( overviewData, { // eslint-disable-line new-cap
89
- segmentStrokeColor: 'transparent',
90
- segmentStrokeWidth: 0,
91
- animateRotate: true,
92
- animation: true,
93
- percentageInnerCutout: 85,
94
- legendTemplate: '<ul class="imagify-<%=name.toLowerCase()%>-legend"><% for (var i=0; i<segments.length; i++){%><li><span style="background-color:<%=segments[i].fillColor%>"></span><%if(segments[i].label){%><%=segments[i].label%><%}%></li><%}%></ul>',
95
- tooltipTemplate: '<%= value %>'
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
96
  } );
97
 
98
  /**
99
  * Then you just need to generate the legend.
100
  * var overviewLegend = overviewDoughnut.generateLegend();
101
- * bugged `segments undefined` ?
102
  */
103
 
104
  // And append it to your page somewhere.
105
  overviewLegend = '<ul class="imagify-doughnut-legend">';
106
 
107
- $( overviewData ).each( function( i ) {
108
- overviewLegend += '<li><span style="background-color:' + overviewData[ i ].color + '"></span>' + overviewData[ i ].label + '</li>';
109
  } );
110
 
111
  overviewLegend += '</ul>';
@@ -127,9 +178,9 @@
127
  }
128
 
129
  data = data.imagify_bulk_data;
130
- donutData = overviewDoughnut.segments;
131
 
132
- if ( data.unoptimized_attachments === donutData[0].value && data.optimized_attachments === donutData[1].value && data.errors_attachments === donutData[2].value ) {
133
  return;
134
  }
135
 
@@ -153,9 +204,9 @@
153
  // The Percent data.
154
  $( '#imagify-total-optimized-attachments-pct' ).html( data.optimized_percent + '%' );
155
 
156
- overviewDoughnut.segments[0].value = data.unoptimized_attachments;
157
- overviewDoughnut.segments[1].value = data.optimized_attachments;
158
- overviewDoughnut.segments[2].value = data.errors_attachments;
159
  overviewDoughnut.update();
160
  } );
161
 
@@ -194,7 +245,8 @@
194
  title: imagifyBulk.labels.waitTitle,
195
  html: imagifyBulk.labels.waitText,
196
  showConfirmButton: false,
197
- imageUrl: imagifyBulk.waitImageUrl
 
198
  } );
199
 
200
  $.get( ajaxurl + w.imagify.concat + 'action=' + imagifyBulk.ajaxAction + '&optimization_level=' + optimizationLevel + '&imagifybulkuploadnonce=' + $( '#imagifybulkuploadnonce' ).val() )
@@ -270,7 +322,7 @@
270
  $attachment.find( '.imagify-cell-status' ).html( '<span class="imagistatus status-complete"><span class="dashicons dashicons-yes"></span>' + imagifyBulk.labels.complete + '</span>' );
271
  $attachment.find( '.imagify-cell-original' ).html( data.original_size_human );
272
  $attachment.find( '.imagify-cell-optimized' ).html( data.new_size_human );
273
- $attachment.find( '.imagify-cell-percentage' ).html( '<span class="imagify-chart"><span class="imagify-chart-container"><canvas height="18" width="18" id="imagify-consumption-chart-' + data.image + '-' + incr + '" style="width: 18px; height: 18px;"></canvas></span></span><span class="imagipercent">' + data.percent + '</span>%' );
274
  drawMeAChart( $attachment.find( '.imagify-cell-percentage canvas' ) );
275
  $attachment.find( '.imagify-cell-thumbnails' ).html( data.thumbnails );
276
  $attachment.find( '.imagify-cell-savings' ).html( Optimizer.humanSize( data.overall_saving, 1 ) );
1
  (function($, d, w, undefined) { // eslint-disable-line no-unused-vars, no-shadow, no-shadow-restricted-names
2
  var overviewCanvas = d.getElementById( 'imagify-overview-chart' ),
3
+ overviewData = {
4
+ labels: [
5
+ imagifyBulk.labels.overviewChartLabels.unoptimized,
6
+ imagifyBulk.labels.overviewChartLabels.optimized,
7
+ imagifyBulk.labels.overviewChartLabels.error
8
+ ],
9
+ datasets: [{
10
+ data: [
11
+ imagifyBulk.totalUnoptimizedAttachments,
12
+ imagifyBulk.totalOptimizedAttachments,
13
+ imagifyBulk.totalErrorsAttachments
14
+ ],
15
+ backgroundColor: [ '#D9E4EB', '#46B1CE', '#2E3242' ],
16
+ borderWidth: 0
17
+ }]
18
+ },
 
 
 
 
19
  overviewDoughnut, overviewLegend;
20
 
21
  /**
25
  * @param {element} canvas
26
  */
27
  function drawMeAChart( canvas ) {
28
+ var donuts;
29
+
30
+ if ( ! this.donuts ) {
31
+ this.donuts = {};
32
+ }
33
+
34
+ donuts = this.donuts;
35
+
36
  canvas.each( function() {
37
+ var value = parseInt( $( this ).closest( '.imagify-chart' ).next( '.imagipercent' ).text(), 10 );
 
 
 
 
 
 
 
 
 
 
 
38
 
39
+ if ( undefined !== donuts[ this.id ] ) {
40
+ donuts[ this.id ].data.datasets[0].data[0] = value;
41
+ donuts[ this.id ].data.datasets[0].data[1] = 100 - value;
42
+ donuts[ this.id ].update();
43
+ return;
44
+ }
45
+
46
+ donuts[ this.id ] = new Chart( this, {
47
+ type: 'doughnut',
48
+ data: {
49
+ datasets: [{
50
+ data: [ value, 100 - value ],
51
+ backgroundColor: [ '#00B3D3', '#D8D8D8' ],
52
+ borderColor: '#fff',
53
+ borderWidth: 1
54
+ }]
55
+ },
56
+ options: {
57
+ legend: {
58
+ display: false
59
+ },
60
+ events: [],
61
+ animation: {
62
+ easing: 'easeOutBounce'
63
+ },
64
+ tooltips: {
65
+ enabled: false
66
+ },
67
+ responsive: false
68
+ }
69
  } );
70
  } );
71
+
72
+ this.donuts = donuts;
73
  }
74
 
75
  /*
79
  * @param {element} canvas
80
  */
81
  function drawMeCompleteChart( canvas ) {
82
+ var donut = this.donut;
83
+
84
  canvas.each( function() {
85
+ var value = parseInt( $( this ).closest( '.imagify-ac-chart' ).attr( 'data-percent' ), 10 );
86
+
87
+ if ( undefined !== donut ) {
88
+ donut.data.datasets[0].data[0] = value;
89
+ donut.data.datasets[0].data[1] = 100 - value;
90
+ donut.update();
91
+ return;
92
+ }
93
+
94
+ donut = new Chart( this, {
95
+ type: 'doughnut',
96
+ data: {
97
+ datasets: [{
98
+ data: [ value, 100 - value ],
99
+ backgroundColor: [ '#40B1D0', '#FFFFFF' ],
100
+ borderWidth: 0
101
+ }]
102
+ },
103
+ options: {
104
+ legend: {
105
+ display: false
106
  },
107
+ events: [],
108
+ animation: {
109
+ easing: 'easeOutBounce'
110
+ },
111
+ tooltips: {
112
+ enabled: false
113
+ },
114
+ responsive: false,
115
+ cutoutPercentage: 70
116
+ }
 
 
 
117
  } );
118
  } );
119
+
120
+ this.donut = donut;
121
  }
122
 
123
  if ( overviewCanvas ) {
124
+ overviewDoughnut = new Chart( overviewCanvas, {
125
+ type: 'doughnut',
126
+ data: overviewData,
127
+ options: {
128
+ legend: {
129
+ display: false/*,
130
+ template: '<ul class="imagify-<%=name.toLowerCase()%>-legend"><% for (var i=0; i<segments.length; i++){%><li><span style="background-color:<%=segments[i].fillColor%>"></span><%if(segments[i].label){%><%=segments[i].label%><%}%></li><%}%></ul>',*/
131
+ },
132
+ events: [],
133
+ animation: {
134
+ easing: 'easeOutBounce'
135
+ },
136
+ tooltips: {
137
+ displayColors: false,
138
+ callbacks: {
139
+ label: function( tooltipItem, data ) {
140
+ return data.datasets[ tooltipItem.datasetIndex ].data[ tooltipItem.index ];
141
+ }
142
+ }
143
+ },
144
+ responsive: false,
145
+ cutoutPercentage: 85
146
+ }
147
  } );
148
 
149
  /**
150
  * Then you just need to generate the legend.
151
  * var overviewLegend = overviewDoughnut.generateLegend();
152
+ * bugged `segments undefined`?
153
  */
154
 
155
  // And append it to your page somewhere.
156
  overviewLegend = '<ul class="imagify-doughnut-legend">';
157
 
158
+ $.each( overviewData.labels, function( i, label ) {
159
+ overviewLegend += '<li><span style="background-color:' + overviewData.datasets[0].backgroundColor[ i ] + '"></span>' + label + '</li>';
160
  } );
161
 
162
  overviewLegend += '</ul>';
178
  }
179
 
180
  data = data.imagify_bulk_data;
181
+ donutData = overviewDoughnut.data.datasets[0].data;
182
 
183
+ if ( data.unoptimized_attachments === donutData[0] && data.optimized_attachments === donutData[1] && data.errors_attachments === donutData[2] ) {
184
  return;
185
  }
186
 
204
  // The Percent data.
205
  $( '#imagify-total-optimized-attachments-pct' ).html( data.optimized_percent + '%' );
206
 
207
+ overviewDoughnut.data.datasets[0].data[0] = data.unoptimized_attachments;
208
+ overviewDoughnut.data.datasets[0].data[1] = data.optimized_attachments;
209
+ overviewDoughnut.data.datasets[0].data[2] = data.errors_attachments;
210
  overviewDoughnut.update();
211
  } );
212
 
245
  title: imagifyBulk.labels.waitTitle,
246
  html: imagifyBulk.labels.waitText,
247
  showConfirmButton: false,
248
+ imageUrl: imagifyBulk.waitImageUrl,
249
+ customClass: 'imagify-sweet-alert'
250
  } );
251
 
252
  $.get( ajaxurl + w.imagify.concat + 'action=' + imagifyBulk.ajaxAction + '&optimization_level=' + optimizationLevel + '&imagifybulkuploadnonce=' + $( '#imagifybulkuploadnonce' ).val() )
322
  $attachment.find( '.imagify-cell-status' ).html( '<span class="imagistatus status-complete"><span class="dashicons dashicons-yes"></span>' + imagifyBulk.labels.complete + '</span>' );
323
  $attachment.find( '.imagify-cell-original' ).html( data.original_size_human );
324
  $attachment.find( '.imagify-cell-optimized' ).html( data.new_size_human );
325
+ $attachment.find( '.imagify-cell-percentage' ).html( '<span class="imagify-chart"><span class="imagify-chart-container"><canvas height="18" width="18" id="imagify-consumption-chart-' + data.image + '-' + incr + '"></canvas></span></span><span class="imagipercent">' + data.percent + '</span>%' );
326
  drawMeAChart( $attachment.find( '.imagify-cell-percentage canvas' ) );
327
  $attachment.find( '.imagify-cell-thumbnails' ).html( data.thumbnails );
328
  $attachment.find( '.imagify-cell-savings' ).html( Optimizer.humanSize( data.overall_saving, 1 ) );
assets/js/bulk.min.js CHANGED
@@ -1 +1 @@
1
- !function(a,b,c,d){function e(b){b.each(function(){var b=a(this),c=parseInt(b.closest(".imagify-chart").next(".imagipercent").text(),10),d=[{value:c,color:"#00B3D3"},{value:100-c,color:"#D8D8D8"}];new Chart(b[0].getContext("2d")).Doughnut(d,{segmentStrokeColor:"#FFF",segmentStrokeWidth:1,animateRotate:!0,tooltipEvents:[]})})}function f(b){b.each(function(){var b=a(this),c=parseInt(b.closest(".imagify-ac-chart").attr("data-percent"),10),d=[{value:c,color:"#40B1D0"},{value:100-c,color:"#FFFFFF"}];new Chart(b[0].getContext("2d")).Doughnut(d,{segmentStrokeColor:"transparent",segmentStrokeWidth:0,animateRotate:!0,animation:!0,percentageInnerCutout:70,tooltipEvents:[]})})}var g,h,i=b.getElementById("imagify-overview-chart"),j=[{value:imagifyBulk.totalUnoptimizedAttachments,color:"#D9E4EB",highlight:"#D9E4EB",label:imagifyBulk.labels.overviewChartLabels.unoptimized},{value:imagifyBulk.totalOptimizedAttachments,color:"#46B1CE",highlight:"#46B1CE",label:imagifyBulk.labels.overviewChartLabels.optimized},{value:imagifyBulk.totalErrorsAttachments,color:"#2E3242",highlight:"#2E3242",label:imagifyBulk.labels.overviewChartLabels.error}];i&&(g=new Chart(i.getContext("2d")).Doughnut(j,{segmentStrokeColor:"transparent",segmentStrokeWidth:0,animateRotate:!0,animation:!0,percentageInnerCutout:85,legendTemplate:'<ul class="imagify-<%=name.toLowerCase()%>-legend"><% for (var i=0; i<segments.length; i++){%><li><span style="background-color:<%=segments[i].fillColor%>"></span><%if(segments[i].label){%><%=segments[i].label%><%}%></li><%}%></ul>',tooltipTemplate:"<%= value %>"}),h='<ul class="imagify-doughnut-legend">',a(j).each(function(a){h+='<li><span style="background-color:'+j[a].color+'"></span>'+j[a].label+"</li>"}),h+="</ul>",b.getElementById("imagify-overview-chart-legend").innerHTML=h),a(b).on("heartbeat-send",function(a,b){b.imagify_heartbeat=imagifyBulk.heartbeatId}),a(b).on("heartbeat-tick",function(b,c){var d;c.imagify_bulk_data&&(c=c.imagify_bulk_data,d=g.segments,c.unoptimized_attachments===d[0].value&&c.optimized_attachments===d[1].value&&c.errors_attachments===d[2].value||(a("#imagify-overview-chart-percent").html(c.optimized_attachments_percent+"<span>%</span>"),a(".imagify-total-percent").html(c.optimized_attachments_percent+"%"),a(".imagify-unconsumed-percent").html(c.unconsumed_quota+"%"),a(".imagify-unconsumed-bar").css("width",c.unconsumed_quota+"%"),a("#imagify-total-optimized-attachments").html(c.already_optimized_attachments),a("#imagify-original-bar").find(".imagify-barnb").html(c.original_human),a("#imagify-optimized-bar").css("width",100-c.optimized_percent+"%").find(".imagify-barnb").html(c.optimized_human),a("#imagify-total-optimized-attachments-pct").html(c.optimized_percent+"%"),g.segments[0].value=c.unoptimized_attachments,g.segments[1].value=c.optimized_attachments,g.segments[2].value=c.errors_attachments,g.update()))}),a("#imagify-simulate-bulk-action").on("click",function(b){b.preventDefault(),a("#imagify-bulk-action").trigger("click")}),a("#imagify-bulk-action").on("click",function(b){var d,g=a(this),h=a('[name="optimization_level"]:checked').val();b.preventDefault(),void 0===h&&(h=-1),g.attr("disabled")||(g.attr("disabled","disabled"),g.find(".dashicons").addClass("rotate"),d=function(){return imagifyBulk.labels.processing},a(c).on("beforeunload",d),swal({title:imagifyBulk.labels.waitTitle,html:imagifyBulk.labels.waitText,showConfirmButton:!1,imageUrl:imagifyBulk.waitImageUrl}),a.get(ajaxurl+c.imagify.concat+"action="+imagifyBulk.ajaxAction+"&optimization_level="+h+"&imagifybulkuploadnonce="+a("#imagifybulkuploadnonce").val()).done(function(b){var h,i,j="",k="",l=0,m=0,n=0,o=0,p=0,q=0;if(!b.success)return g.removeAttr("disabled"),g.find(".dashicons").removeClass("rotate"),a(c).off("beforeunload",d),"invalid-api-key"===b.data.message?j=imagifyBulk.labels.invalidAPIKeyTitle:"over-quota"===b.data.message?(j=imagifyBulk.labels.overQuotaTitle,k=imagifyBulk.labels.overQuotaText):"no-images"===b.data.message&&(j=imagifyBulk.labels.noAttachmentToOptimizeTitle,k=imagifyBulk.labels.noAttachmentToOptimizeText),void swal({title:j,html:k,type:"info",customClass:"imagify-sweet-alert"});swal.close(),a(".imagify-row-progress").slideDown(),a(".imagify-no-uploaded-yet, .imagify-row-complete").hide(200),i=a(".imagify-bulk-table table tbody"),h=new ImagifyGulp({buffer_size:imagifyBulk.bufferSize,lib:ajaxurl+c.imagify.concat+"action=imagify_bulk_upload&imagifybulkuploadnonce="+a("#imagifybulkuploadnonce").val(),images:b.data,context:imagifyBulk.ajaxContext}),h.before(function(a){i.find(".imagify-row-progress").after('<tr id="attachment-'+a.id+'"><td class="imagify-cell-filename"><span class="imagiuploaded"><img src="'+a.thumbnail+'" alt=""/></span><span class="imagifilename">'+a.filename+'</span></td><td class="imagify-cell-status"><span class="imagistatus status-compressing"><span class="dashicons dashicons-admin-generic rotate"></span>'+imagifyBulk.labels.optimizing+'<span></span></span></td><td class="imagify-cell-original"></td><td class="imagify-cell-optimized"></td><td class="imagify-cell-percentage"></td><td class="imagify-cell-thumbnails"></td><td class="imagify-cell-savings"></td></tr>')}).each(function(b){var c=a("#imagify-progress-bar"),d="error",f="dismiss",g=imagifyBulk.labels.error,i=a("#attachment-"+b.image);if(c.css({width:b.progress+"%"}),c.find(".percent").html(b.progress+"%"),b.success)return++q,i.find(".imagify-cell-status").html('<span class="imagistatus status-complete"><span class="dashicons dashicons-yes"></span>'+imagifyBulk.labels.complete+"</span>"),i.find(".imagify-cell-original").html(b.original_size_human),i.find(".imagify-cell-optimized").html(b.new_size_human),i.find(".imagify-cell-percentage").html('<span class="imagify-chart"><span class="imagify-chart-container"><canvas height="18" width="18" id="imagify-consumption-chart-'+b.image+"-"+q+'" style="width: 18px; height: 18px;"></canvas></span></span><span class="imagipercent">'+b.percent+"</span>%"),e(i.find(".imagify-cell-percentage canvas")),i.find(".imagify-cell-thumbnails").html(b.thumbnails),i.find(".imagify-cell-savings").html(h.humanSize(b.overall_saving,1)),l=l+b.thumbnails+1,a(".imagify-cell-nb-files").html(imagifyBulk.labels.nbrFiles.replace("%s",l)),o+=b.original_overall_size,a(".imagify-total-original").html(h.humanSize(o,1)),p+=b.overall_saving,void a(".imagify-total-gain").html(h.humanSize(p,1));!n&&b.error.indexOf("You've consumed all your data")>=0&&(n=1,h.stopProcess(),swal({title:imagifyBulk.labels.overQuotaTitle,html:imagifyBulk.labels.overQuotaText,type:"error",customClass:"imagify-sweet-alert"}).then(function(){location.reload()})),b.error.indexOf("This image is already compressed")>=0?(d="warning",f="warning",g=imagifyBulk.labels.notice):(m++,a(".imagify-cell-errors").html(imagifyBulk.labels.nbrErrors.replace("%s",m))),i.after('<tr><td colspan="7"><span class="status-'+d+'">'+b.error+"</span></td></tr>"),i.find(".imagify-cell-status").html('<span class="imagistatus status-'+d+'"><span class="dashicons dashicons-'+f+'"></span>'+g+"</span>")}).done(function(b){var e;g.removeAttr("disabled").find(".dashicons").removeClass("rotate"),a(c).off("beforeunload",d),a(".imagify-row-progress").slideUp(),"NaN"!==b.global_percent&&(a(".imagify-row-complete").removeClass("hidden").addClass("done").attr("aria-hidden","false"),a("html, body").animate({scrollTop:a(".imagify-row-complete").offset().top},200),a(".imagify-ac-rt-total-gain").html(b.global_gain_human),a(".imagify-ac-rt-total-original").html(b.global_original_size_human),e=imagifyBulk.labels.textToShare,e=e.replace("%1$s",b.global_gain_human),e=e.replace("%2$s",b.global_original_size_human),e=encodeURIComponent(e),a(".imagify-sn-twitter").attr("href",imagifyBulk.labels.twitterShareURL+"&amp;text="+e),a(".imagify-ac-chart").attr("data-percent",b.global_percent),f(a(".imagify-ac-chart").find("canvas"))),n=0}).error(function(a){c.imagify.log("Can't optimize image with id "+a+".")}).run()}).fail(function(){swal({title:imagifyBulk.labels.getUnoptimizedImagesErrorTitle,html:imagifyBulk.labels.getUnoptimizedImagesErrorText,type:"error",customClass:"imagify-sweet-alert"}).then(function(){location.reload()})}))})}(jQuery,document,window),function(a,b,c,d){var e,f;c.innerWidth?(e=(c.innerWidth-700)/2,f=(c.innerHeight-290)/2):(e=(b.body.clientWidth-700)/2,f=(b.body.clientHeight-290)/2),[].forEach.call(b.querySelectorAll(".imagify-share-networks a"),function(a){a.addEventListener("click",function(a){c.open(this.href,"","status=no, scrollbars=no, menubar=no, top="+f+", left="+e+", width=700, height=290"),a.preventDefault()},!1)})}(jQuery,document,window);
1
+ !function(a,b,c,d){function e(b){var c;this.donuts||(this.donuts={}),c=this.donuts,b.each(function(){var b=parseInt(a(this).closest(".imagify-chart").next(".imagipercent").text(),10);if(d!==c[this.id])return c[this.id].data.datasets[0].data[0]=b,c[this.id].data.datasets[0].data[1]=100-b,void c[this.id].update();c[this.id]=new Chart(this,{type:"doughnut",data:{datasets:[{data:[b,100-b],backgroundColor:["#00B3D3","#D8D8D8"],borderColor:"#fff",borderWidth:1}]},options:{legend:{display:!1},events:[],animation:{easing:"easeOutBounce"},tooltips:{enabled:!1},responsive:!1}})}),this.donuts=c}function f(b){var c=this.donut;b.each(function(){var b=parseInt(a(this).closest(".imagify-ac-chart").attr("data-percent"),10);if(d!==c)return c.data.datasets[0].data[0]=b,c.data.datasets[0].data[1]=100-b,void c.update();c=new Chart(this,{type:"doughnut",data:{datasets:[{data:[b,100-b],backgroundColor:["#40B1D0","#FFFFFF"],borderWidth:0}]},options:{legend:{display:!1},events:[],animation:{easing:"easeOutBounce"},tooltips:{enabled:!1},responsive:!1,cutoutPercentage:70}})}),this.donut=c}var g,h,i=b.getElementById("imagify-overview-chart"),j={labels:[imagifyBulk.labels.overviewChartLabels.unoptimized,imagifyBulk.labels.overviewChartLabels.optimized,imagifyBulk.labels.overviewChartLabels.error],datasets:[{data:[imagifyBulk.totalUnoptimizedAttachments,imagifyBulk.totalOptimizedAttachments,imagifyBulk.totalErrorsAttachments],backgroundColor:["#D9E4EB","#46B1CE","#2E3242"],borderWidth:0}]};i&&(g=new Chart(i,{type:"doughnut",data:j,options:{legend:{display:!1},events:[],animation:{easing:"easeOutBounce"},tooltips:{displayColors:!1,callbacks:{label:function(a,b){return b.datasets[a.datasetIndex].data[a.index]}}},responsive:!1,cutoutPercentage:85}}),h='<ul class="imagify-doughnut-legend">',a.each(j.labels,function(a,b){h+='<li><span style="background-color:'+j.datasets[0].backgroundColor[a]+'"></span>'+b+"</li>"}),h+="</ul>",b.getElementById("imagify-overview-chart-legend").innerHTML=h),a(b).on("heartbeat-send",function(a,b){b.imagify_heartbeat=imagifyBulk.heartbeatId}),a(b).on("heartbeat-tick",function(b,c){var d;c.imagify_bulk_data&&(c=c.imagify_bulk_data,d=g.data.datasets[0].data,c.unoptimized_attachments===d[0]&&c.optimized_attachments===d[1]&&c.errors_attachments===d[2]||(a("#imagify-overview-chart-percent").html(c.optimized_attachments_percent+"<span>%</span>"),a(".imagify-total-percent").html(c.optimized_attachments_percent+"%"),a(".imagify-unconsumed-percent").html(c.unconsumed_quota+"%"),a(".imagify-unconsumed-bar").css("width",c.unconsumed_quota+"%"),a("#imagify-total-optimized-attachments").html(c.already_optimized_attachments),a("#imagify-original-bar").find(".imagify-barnb").html(c.original_human),a("#imagify-optimized-bar").css("width",100-c.optimized_percent+"%").find(".imagify-barnb").html(c.optimized_human),a("#imagify-total-optimized-attachments-pct").html(c.optimized_percent+"%"),g.data.datasets[0].data[0]=c.unoptimized_attachments,g.data.datasets[0].data[1]=c.optimized_attachments,g.data.datasets[0].data[2]=c.errors_attachments,g.update()))}),a("#imagify-simulate-bulk-action").on("click",function(b){b.preventDefault(),a("#imagify-bulk-action").trigger("click")}),a("#imagify-bulk-action").on("click",function(b){var g,h=a(this),i=a('[name="optimization_level"]:checked').val();b.preventDefault(),d===i&&(i=-1),h.attr("disabled")||(h.attr("disabled","disabled"),h.find(".dashicons").addClass("rotate"),g=function(){return imagifyBulk.labels.processing},a(c).on("beforeunload",g),swal({title:imagifyBulk.labels.waitTitle,html:imagifyBulk.labels.waitText,showConfirmButton:!1,imageUrl:imagifyBulk.waitImageUrl,customClass:"imagify-sweet-alert"}),a.get(ajaxurl+c.imagify.concat+"action="+imagifyBulk.ajaxAction+"&optimization_level="+i+"&imagifybulkuploadnonce="+a("#imagifybulkuploadnonce").val()).done(function(b){var d,i,j="",k="",l=0,m=0,n=0,o=0,p=0,q=0;if(!b.success)return h.removeAttr("disabled"),h.find(".dashicons").removeClass("rotate"),a(c).off("beforeunload",g),"invalid-api-key"===b.data.message?j=imagifyBulk.labels.invalidAPIKeyTitle:"over-quota"===b.data.message?(j=imagifyBulk.labels.overQuotaTitle,k=imagifyBulk.labels.overQuotaText):"no-images"===b.data.message&&(j=imagifyBulk.labels.noAttachmentToOptimizeTitle,k=imagifyBulk.labels.noAttachmentToOptimizeText),void swal({title:j,html:k,type:"info",customClass:"imagify-sweet-alert"});swal.close(),a(".imagify-row-progress").slideDown(),a(".imagify-no-uploaded-yet, .imagify-row-complete").hide(200),i=a(".imagify-bulk-table table tbody"),d=new ImagifyGulp({buffer_size:imagifyBulk.bufferSize,lib:ajaxurl+c.imagify.concat+"action=imagify_bulk_upload&imagifybulkuploadnonce="+a("#imagifybulkuploadnonce").val(),images:b.data,context:imagifyBulk.ajaxContext}),d.before(function(a){i.find(".imagify-row-progress").after('<tr id="attachment-'+a.id+'"><td class="imagify-cell-filename"><span class="imagiuploaded"><img src="'+a.thumbnail+'" alt=""/></span><span class="imagifilename">'+a.filename+'</span></td><td class="imagify-cell-status"><span class="imagistatus status-compressing"><span class="dashicons dashicons-admin-generic rotate"></span>'+imagifyBulk.labels.optimizing+'<span></span></span></td><td class="imagify-cell-original"></td><td class="imagify-cell-optimized"></td><td class="imagify-cell-percentage"></td><td class="imagify-cell-thumbnails"></td><td class="imagify-cell-savings"></td></tr>')}).each(function(b){var c=a("#imagify-progress-bar"),f="error",g="dismiss",h=imagifyBulk.labels.error,i=a("#attachment-"+b.image);if(c.css({width:b.progress+"%"}),c.find(".percent").html(b.progress+"%"),b.success)return++q,i.find(".imagify-cell-status").html('<span class="imagistatus status-complete"><span class="dashicons dashicons-yes"></span>'+imagifyBulk.labels.complete+"</span>"),i.find(".imagify-cell-original").html(b.original_size_human),i.find(".imagify-cell-optimized").html(b.new_size_human),i.find(".imagify-cell-percentage").html('<span class="imagify-chart"><span class="imagify-chart-container"><canvas height="18" width="18" id="imagify-consumption-chart-'+b.image+"-"+q+'"></canvas></span></span><span class="imagipercent">'+b.percent+"</span>%"),e(i.find(".imagify-cell-percentage canvas")),i.find(".imagify-cell-thumbnails").html(b.thumbnails),i.find(".imagify-cell-savings").html(d.humanSize(b.overall_saving,1)),l=l+b.thumbnails+1,a(".imagify-cell-nb-files").html(imagifyBulk.labels.nbrFiles.replace("%s",l)),o+=b.original_overall_size,a(".imagify-total-original").html(d.humanSize(o,1)),p+=b.overall_saving,void a(".imagify-total-gain").html(d.humanSize(p,1));!n&&b.error.indexOf("You've consumed all your data")>=0&&(n=1,d.stopProcess(),swal({title:imagifyBulk.labels.overQuotaTitle,html:imagifyBulk.labels.overQuotaText,type:"error",customClass:"imagify-sweet-alert"}).then(function(){location.reload()})),b.error.indexOf("This image is already compressed")>=0?(f="warning",g="warning",h=imagifyBulk.labels.notice):(m++,a(".imagify-cell-errors").html(imagifyBulk.labels.nbrErrors.replace("%s",m))),i.after('<tr><td colspan="7"><span class="status-'+f+'">'+b.error+"</span></td></tr>"),i.find(".imagify-cell-status").html('<span class="imagistatus status-'+f+'"><span class="dashicons dashicons-'+g+'"></span>'+h+"</span>")}).done(function(b){var d;h.removeAttr("disabled").find(".dashicons").removeClass("rotate"),a(c).off("beforeunload",g),a(".imagify-row-progress").slideUp(),"NaN"!==b.global_percent&&(a(".imagify-row-complete").removeClass("hidden").addClass("done").attr("aria-hidden","false"),a("html, body").animate({scrollTop:a(".imagify-row-complete").offset().top},200),a(".imagify-ac-rt-total-gain").html(b.global_gain_human),a(".imagify-ac-rt-total-original").html(b.global_original_size_human),d=imagifyBulk.labels.textToShare,d=d.replace("%1$s",b.global_gain_human),d=d.replace("%2$s",b.global_original_size_human),d=encodeURIComponent(d),a(".imagify-sn-twitter").attr("href",imagifyBulk.labels.twitterShareURL+"&amp;text="+d),a(".imagify-ac-chart").attr("data-percent",b.global_percent),f(a(".imagify-ac-chart").find("canvas"))),n=0}).error(function(a){c.imagify.log("Can't optimize image with id "+a+".")}).run()}).fail(function(){swal({title:imagifyBulk.labels.getUnoptimizedImagesErrorTitle,html:imagifyBulk.labels.getUnoptimizedImagesErrorText,type:"error",customClass:"imagify-sweet-alert"}).then(function(){location.reload()})}))})}(jQuery,document,window),function(a,b,c,d){var e,f;c.innerWidth?(e=(c.innerWidth-700)/2,f=(c.innerHeight-290)/2):(e=(b.body.clientWidth-700)/2,f=(b.body.clientHeight-290)/2),[].forEach.call(b.querySelectorAll(".imagify-share-networks a"),function(a){a.addEventListener("click",function(a){c.open(this.href,"","status=no, scrollbars=no, menubar=no, top="+f+", left="+e+", width=700, height=290"),a.preventDefault()},!1)})}(jQuery,document,window);
assets/js/chart.js CHANGED
@@ -1,3732 +1,14145 @@
1
  /*!
2
  * Chart.js
3
  * http://chartjs.org/
4
- * Version: 1.0.2
5
  *
6
- * Copyright 2015 Nick Downie
7
  * Released under the MIT license
8
- * https://github.com/nnnick/Chart.js/blob/master/LICENSE.md
9
  */
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
10
 
 
 
 
 
 
 
 
 
 
11
 
12
- (function(){
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
13
 
14
- "use strict";
 
 
 
 
15
 
16
- //Declare root variable - window in the browser, global on the server
17
- var root = this,
18
- previous = root.Chart;
19
 
20
- //Occupy the global variable of Chart, and create a simple base class
21
- var Chart = function(context){
22
- var chart = this;
23
- this.canvas = context.canvas;
 
 
24
 
25
- this.ctx = context;
 
 
26
 
27
- //Variables global to the chart
28
- var computeDimension = function(element,dimension)
29
- {
30
- if (element['offset'+dimension])
31
- {
32
- return element['offset'+dimension];
33
- }
34
- else
35
- {
36
- return document.defaultView.getComputedStyle(element).getPropertyValue(dimension);
37
- }
38
- };
 
 
 
39
 
40
- var width = this.width = computeDimension(context.canvas,'Width') || context.canvas.width;
41
- var height = this.height = computeDimension(context.canvas,'Height') || context.canvas.height;
 
 
 
 
42
 
43
- width = this.width = context.canvas.width;
44
- height = this.height = context.canvas.height;
45
- this.aspectRatio = this.width / this.height;
46
- //High pixel density displays - multiply the size of the canvas height/width by the device pixel ratio, then scale.
47
- helpers.retinaScale(this);
 
48
 
 
 
 
 
49
  return this;
50
- };
51
- //Globally expose the defaults to allow for user updating/changing
52
- Chart.defaults = {
53
- global: {
54
- // Boolean - Whether to animate the chart
55
- animation: true,
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
56
 
57
- // Number - Number of animation steps
58
- animationSteps: 60,
 
 
 
59
 
60
- // String - Animation easing effect
61
- animationEasing: "easeOutQuart",
 
 
 
62
 
63
- // Boolean - If we should show the scale at all
64
- showScale: true,
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
65
 
66
- // Boolean - If we want to override with a hard coded scale
67
- scaleOverride: false,
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
68
 
69
- // ** Required if scaleOverride is true **
70
- // Number - The number of steps in a hard coded scale
71
- scaleSteps: null,
72
- // Number - The value jump in the hard coded scale
73
- scaleStepWidth: null,
74
- // Number - The scale starting value
75
- scaleStartValue: null,
76
 
77
- // String - Colour of the scale line
78
- scaleLineColor: "rgba(0,0,0,.1)",
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
79
 
80
- // Number - Pixel width of the scale line
81
- scaleLineWidth: 1,
 
 
82
 
83
- // Boolean - Whether to show labels on the scale
84
- scaleShowLabels: true,
 
85
 
86
- // Interpolated JS string - can access value
87
- scaleLabel: "<%=value%>",
88
 
89
- // Boolean - Whether the scale should stick to integers, and not show any floats even if drawing space is there
90
- scaleIntegersOnly: true,
91
 
92
- // Boolean - Whether the scale should start at zero, or an order of magnitude down from the lowest value
93
- scaleBeginAtZero: false,
 
94
 
95
- // String - Scale label font declaration for the scale label
96
- scaleFontFamily: "'Helvetica Neue', 'Helvetica', 'Arial', sans-serif",
97
 
98
- // Number - Scale label font size in pixels
99
- scaleFontSize: 12,
 
 
 
100
 
101
- // String - Scale label font weight style
102
- scaleFontStyle: "normal",
 
 
 
 
103
 
104
- // String - Scale label font colour
105
- scaleFontColor: "#666",
106
 
107
- // Boolean - whether or not the chart should be responsive and resize when the browser does.
108
- responsive: false,
109
 
110
- // Boolean - whether to maintain the starting aspect ratio or not when responsive, if set to false, will take up entire container
111
- maintainAspectRatio: true,
 
 
112
 
113
- // Boolean - Determines whether to draw tooltips on the canvas or not - attaches events to touchmove & mousemove
114
- showTooltips: true,
 
 
115
 
116
- // Boolean - Determines whether to draw built-in tooltip or call custom tooltip function
117
- customTooltips: false,
 
 
 
 
 
 
 
 
 
 
 
118
 
119
- // Array - Array of string names to attach tooltip events
120
- tooltipEvents: ["mousemove", "touchstart", "touchmove", "mouseout"],
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
121
 
122
- // String - Tooltip background colour
123
- tooltipFillColor: "rgba(0,0,0,0.8)",
124
 
125
- // String - Tooltip label font declaration for the scale label
126
- tooltipFontFamily: "'Helvetica Neue', 'Helvetica', 'Arial', sans-serif",
127
 
128
- // Number - Tooltip label font size in pixels
129
- tooltipFontSize: 14,
130
 
131
- // String - Tooltip font weight style
132
- tooltipFontStyle: "normal",
133
 
134
- // String - Tooltip label font colour
135
- tooltipFontColor: "#fff",
136
 
137
- // String - Tooltip title font declaration for the scale label
138
- tooltipTitleFontFamily: "'Helvetica Neue', 'Helvetica', 'Arial', sans-serif",
139
 
140
- // Number - Tooltip title font size in pixels
141
- tooltipTitleFontSize: 14,
142
 
143
- // String - Tooltip title font weight style
144
- tooltipTitleFontStyle: "bold",
 
 
145
 
146
- // String - Tooltip title font colour
147
- tooltipTitleFontColor: "#fff",
148
 
149
- // String - Tooltip title template
150
- tooltipTitleTemplate: "<%= label%>",
151
 
152
- // Number - pixel width of padding around tooltip text
153
- tooltipYPadding: 6,
154
 
155
- // Number - pixel width of padding around tooltip text
156
- tooltipXPadding: 6,
157
 
158
- // Number - Size of the caret on the tooltip
159
- tooltipCaretSize: 8,
160
 
161
- // Number - Pixel radius of the tooltip border
162
- tooltipCornerRadius: 6,
163
 
164
- // Number - Pixel offset from point x to tooltip edge
165
- tooltipXOffset: 10,
166
 
167
- // String - Template string for single tooltips
168
- tooltipTemplate: "<%if (label){%><%=label%>: <%}%><%= value %>",
169
 
170
- // String - Template string for single tooltips
171
- multiTooltipTemplate: "<%= datasetLabel %>: <%= value %>",
172
 
173
- // String - Colour behind the legend colour block
174
- multiTooltipKeyBackground: '#fff',
175
 
176
- // Array - A list of colors to use as the defaults
177
- segmentColorDefault: ["#A6CEE3", "#1F78B4", "#B2DF8A", "#33A02C", "#FB9A99", "#E31A1C", "#FDBF6F", "#FF7F00", "#CAB2D6", "#6A3D9A", "#B4B482", "#B15928" ],
178
 
179
- // Array - A list of highlight colors to use as the defaults
180
- segmentHighlightColorDefaults: [ "#CEF6FF", "#47A0DC", "#DAFFB2", "#5BC854", "#FFC2C1", "#FF4244", "#FFE797", "#FFA728", "#F2DAFE", "#9265C2", "#DCDCAA", "#D98150" ],
181
 
182
- // Function - Will fire on animation progression.
183
- onAnimationProgress: function(){},
184
 
185
- // Function - Will fire on animation completion.
186
- onAnimationComplete: function(){}
187
 
188
- }
189
  };
190
 
191
- //Create a dictionary of chart types, to allow for extension of existing types
192
- Chart.types = {};
193
 
194
- //Global Chart helpers object for utility methods and classes
195
- var helpers = Chart.helpers = {};
196
-
197
- //-- Basic js utility methods
198
- var each = helpers.each = function(loopable,callback,self){
199
- var additionalArgs = Array.prototype.slice.call(arguments, 3);
200
- // Check to see if null or undefined firstly.
201
- if (loopable){
202
- if (loopable.length === +loopable.length){
203
- var i;
204
- for (i=0; i<loopable.length; i++){
205
- callback.apply(self,[loopable[i], i].concat(additionalArgs));
206
- }
207
- }
208
- else{
209
- for (var item in loopable){
210
- callback.apply(self,[loopable[item],item].concat(additionalArgs));
211
- }
212
- }
213
- }
214
- },
215
- clone = helpers.clone = function(obj){
216
- var objClone = {};
217
- each(obj,function(value,key){
218
- if (obj.hasOwnProperty(key)){
219
- objClone[key] = value;
220
- }
221
- });
222
- return objClone;
223
- },
224
- extend = helpers.extend = function(base){
225
- each(Array.prototype.slice.call(arguments,1), function(extensionObject) {
226
- each(extensionObject,function(value,key){
227
- if (extensionObject.hasOwnProperty(key)){
228
- base[key] = value;
229
- }
230
- });
231
- });
232
- return base;
233
- },
234
- merge = helpers.merge = function(base,master){
235
- //Merge properties in left object over to a shallow clone of object right.
236
- var args = Array.prototype.slice.call(arguments,0);
237
- args.unshift({});
238
- return extend.apply(null, args);
239
- },
240
- indexOf = helpers.indexOf = function(arrayToSearch, item){
241
- if (Array.prototype.indexOf) {
242
- return arrayToSearch.indexOf(item);
243
- }
244
- else{
245
- for (var i = 0; i < arrayToSearch.length; i++) {
246
- if (arrayToSearch[i] === item) return i;
247
- }
248
- return -1;
249
- }
250
- },
251
- where = helpers.where = function(collection, filterCallback){
252
- var filtered = [];
253
 
254
- helpers.each(collection, function(item){
255
- if (filterCallback(item)){
256
- filtered.push(item);
257
- }
258
- });
259
 
260
- return filtered;
261
- },
262
- findNextWhere = helpers.findNextWhere = function(arrayToSearch, filterCallback, startIndex){
263
- // Default to start of the array
264
- if (!startIndex){
265
- startIndex = -1;
266
- }
267
- for (var i = startIndex + 1; i < arrayToSearch.length; i++) {
268
- var currentItem = arrayToSearch[i];
269
- if (filterCallback(currentItem)){
270
- return currentItem;
271
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
272
  }
273
- },
274
- findPreviousWhere = helpers.findPreviousWhere = function(arrayToSearch, filterCallback, startIndex){
275
- // Default to end of the array
276
- if (!startIndex){
277
- startIndex = arrayToSearch.length;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
278
  }
279
- for (var i = startIndex - 1; i >= 0; i--) {
280
- var currentItem = arrayToSearch[i];
281
- if (filterCallback(currentItem)){
282
- return currentItem;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
283
  }
 
 
 
 
 
 
 
284
  }
285
  },
286
- inherits = helpers.inherits = function(extensions){
287
- //Basic javascript inheritance based on the model created in Backbone.js
288
- var parent = this;
289
- var ChartElement = (extensions && extensions.hasOwnProperty("constructor")) ? extensions.constructor : function(){ return parent.apply(this, arguments); };
290
 
291
- var Surrogate = function(){ this.constructor = ChartElement;};
292
- Surrogate.prototype = parent.prototype;
293
- ChartElement.prototype = new Surrogate();
294
 
295
- ChartElement.extend = inherits;
296
 
297
- if (extensions) extend(ChartElement.prototype, extensions);
298
 
299
- ChartElement.__super__ = parent.prototype;
 
 
300
 
301
- return ChartElement;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
302
  },
303
- noop = helpers.noop = function(){},
304
- uid = helpers.uid = (function(){
305
- var id=0;
306
- return function(){
307
- return "chart-" + id++;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
308
  };
309
- })(),
310
- warn = helpers.warn = function(str){
311
- //Method for warning of errors
312
- if (window.console && typeof window.console.warn === "function") console.warn(str);
313
  },
314
- amd = helpers.amd = (typeof define === 'function' && define.amd),
315
- //-- Math methods
316
- isNumber = helpers.isNumber = function(n){
317
- return !isNaN(parseFloat(n)) && isFinite(n);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
318
  },
319
- max = helpers.max = function(array){
320
- return Math.max.apply( Math, array );
 
 
 
 
321
  },
322
- min = helpers.min = function(array){
323
- return Math.min.apply( Math, array );
 
 
 
 
324
  },
325
- cap = helpers.cap = function(valueToCap,maxValue,minValue){
326
- if(isNumber(maxValue)) {
327
- if( valueToCap > maxValue ) {
328
- return maxValue;
329
- }
330
- }
331
- else if(isNumber(minValue)){
332
- if ( valueToCap < minValue ){
333
- return minValue;
334
- }
335
- }
336
- return valueToCap;
337
  },
338
- getDecimalPlaces = helpers.getDecimalPlaces = function(num){
339
- if (num%1!==0 && isNumber(num)){
340
- var s = num.toString();
341
- if(s.indexOf("e-") < 0){
342
- // no exponent, e.g. 0.01
343
- return s.split(".")[1].length;
344
- }
345
- else if(s.indexOf(".") < 0) {
346
- // no decimal point, e.g. 1e-9
347
- return parseInt(s.split("e-")[1]);
348
- }
349
- else {
350
- // exponent and decimal point, e.g. 1.23e-9
351
- var parts = s.split(".")[1].split("e-");
352
- return parts[0].length + parseInt(parts[1]);
 
 
 
 
 
 
 
 
 
 
 
 
 
353
  }
354
  }
355
- else {
356
- return 0;
357
- }
358
- },
359
- toRadians = helpers.radians = function(degrees){
360
- return degrees * (Math.PI/180);
361
- },
362
- // Gets the angle from vertical upright to the point about a centre.
363
- getAngleFromPoint = helpers.getAngleFromPoint = function(centrePoint, anglePoint){
364
- var distanceFromXCenter = anglePoint.x - centrePoint.x,
365
- distanceFromYCenter = anglePoint.y - centrePoint.y,
366
- radialDistanceFromCenter = Math.sqrt( distanceFromXCenter * distanceFromXCenter + distanceFromYCenter * distanceFromYCenter);
367
 
 
 
368
 
369
- var angle = Math.PI * 2 + Math.atan2(distanceFromYCenter, distanceFromXCenter);
 
 
 
 
 
 
370
 
371
- //If the segment is in the top left quadrant, we need to add another rotation to the angle
372
- if (distanceFromXCenter < 0 && distanceFromYCenter < 0){
373
- angle += Math.PI*2;
 
 
 
 
 
 
 
 
 
 
 
 
 
374
  }
375
 
376
  return {
377
- angle: angle,
378
- distance: radialDistanceFromCenter
379
- };
380
- },
381
- aliasPixel = helpers.aliasPixel = function(pixelWidth){
382
- return (pixelWidth % 2 === 0) ? 0 : 0.5;
383
- },
384
- splineCurve = helpers.splineCurve = function(FirstPoint,MiddlePoint,AfterPoint,t){
385
- //Props to Rob Spencer at scaled innovation for his post on splining between points
386
- //http://scaledinnovation.com/analytics/splines/aboutSplines.html
387
- var d01=Math.sqrt(Math.pow(MiddlePoint.x-FirstPoint.x,2)+Math.pow(MiddlePoint.y-FirstPoint.y,2)),
388
- d12=Math.sqrt(Math.pow(AfterPoint.x-MiddlePoint.x,2)+Math.pow(AfterPoint.y-MiddlePoint.y,2)),
389
- fa=t*d01/(d01+d12),// scaling factor for triangle Ta
390
- fb=t*d12/(d01+d12);
391
- return {
392
- inner : {
393
- x : MiddlePoint.x-fa*(AfterPoint.x-FirstPoint.x),
394
- y : MiddlePoint.y-fa*(AfterPoint.y-FirstPoint.y)
395
- },
396
- outer : {
397
- x: MiddlePoint.x+fb*(AfterPoint.x-FirstPoint.x),
398
- y : MiddlePoint.y+fb*(AfterPoint.y-FirstPoint.y)
399
- }
400
  };
401
  },
402
- calculateOrderOfMagnitude = helpers.calculateOrderOfMagnitude = function(val){
403
- return Math.floor(Math.log(val) / Math.LN10);
404
- },
405
- calculateScaleRange = helpers.calculateScaleRange = function(valuesArray, drawingSize, textSize, startFromZero, integersOnly){
406
 
407
- //Set a minimum step of two - a point at the top of the graph, and a point at the base
408
- var minSteps = 2,
409
- maxSteps = Math.floor(drawingSize/(textSize * 1.5)),
410
- skipFitting = (minSteps >= maxSteps);
411
-
412
- // Filter out null values since these would min() to zero
413
- var values = [];
414
- each(valuesArray, function( v ){
415
- v == null || values.push( v );
416
- });
417
- var minValue = min(values),
418
- maxValue = max(values);
419
-
420
- // We need some degree of separation here to calculate the scales if all the values are the same
421
- // Adding/minusing 0.5 will give us a range of 1.
422
- if (maxValue === minValue){
423
- maxValue += 0.5;
424
- // So we don't end up with a graph with a negative start value if we've said always start from zero
425
- if (minValue >= 0.5 && !startFromZero){
426
- minValue -= 0.5;
427
- }
428
- else{
429
- // Make up a whole number above the values
430
- maxValue += 0.5;
431
- }
432
- }
433
-
434
- var valueRange = Math.abs(maxValue - minValue),
435
- rangeOrderOfMagnitude = calculateOrderOfMagnitude(valueRange),
436
- graphMax = Math.ceil(maxValue / (1 * Math.pow(10, rangeOrderOfMagnitude))) * Math.pow(10, rangeOrderOfMagnitude),
437
- graphMin = (startFromZero) ? 0 : Math.floor(minValue / (1 * Math.pow(10, rangeOrderOfMagnitude))) * Math.pow(10, rangeOrderOfMagnitude),
438
- graphRange = graphMax - graphMin,
439
- stepValue = Math.pow(10, rangeOrderOfMagnitude),
440
- numberOfSteps = Math.round(graphRange / stepValue);
441
-
442
- //If we have more space on the graph we'll use it to give more definition to the data
443
- while((numberOfSteps > maxSteps || (numberOfSteps * 2) < maxSteps) && !skipFitting) {
444
- if(numberOfSteps > maxSteps){
445
- stepValue *=2;
446
- numberOfSteps = Math.round(graphRange/stepValue);
447
- // Don't ever deal with a decimal number of steps - cancel fitting and just use the minimum number of steps.
448
- if (numberOfSteps % 1 !== 0){
449
- skipFitting = true;
450
- }
451
- }
452
- //We can fit in double the amount of scale points on the scale
453
- else{
454
- //If user has declared ints only, and the step value isn't a decimal
455
- if (integersOnly && rangeOrderOfMagnitude >= 0){
456
- //If the user has said integers only, we need to check that making the scale more granular wouldn't make it a float
457
- if(stepValue/2 % 1 === 0){
458
- stepValue /=2;
459
- numberOfSteps = Math.round(graphRange/stepValue);
460
- }
461
- //If it would make it a float break out of the loop
462
- else{
463
- break;
464
  }
465
  }
466
- //If the scale doesn't have to be an int, make the scale more granular anyway.
467
- else{
468
- stepValue /=2;
469
- numberOfSteps = Math.round(graphRange/stepValue);
470
- }
471
-
472
  }
473
  }
474
 
475
- if (skipFitting){
476
- numberOfSteps = minSteps;
477
- stepValue = graphRange / numberOfSteps;
478
- }
479
 
480
  return {
481
- steps : numberOfSteps,
482
- stepValue : stepValue,
483
- min : graphMin,
484
- max : graphMin + (numberOfSteps * stepValue)
485
  };
486
-
487
  },
488
- /* jshint ignore:start */
489
- // Blows up jshint errors based on the new Function constructor
490
- //Templating methods
491
- //Javascript micro templating by John Resig - source at http://ejohn.org/blog/javascript-micro-templating/
492
- template = helpers.template = function(templateString, valuesObject){
493
-
494
- // If templateString is function rather than string-template - call the function for valuesObject
495
-
496
- if(templateString instanceof Function){
497
- return templateString(valuesObject);
498
- }
499
-
500
- var cache = {};
501
- function tmpl(str, data){
502
- // Figure out if we're getting a template, or if we need to
503
- // load the template - and be sure to cache the result.
504
- var fn = !/\W/.test(str) ?
505
- cache[str] = cache[str] :
506
-
507
- // Generate a reusable function that will serve as a template
508
- // generator (and which will be cached).
509
- new Function("obj",
510
- "var p=[],print=function(){p.push.apply(p,arguments);};" +
511
-
512
- // Introduce the data as local variables using with(){}
513
- "with(obj){p.push('" +
514
-
515
- // Convert the template into pure JavaScript
516
- str
517
- .replace(/[\r\t\n]/g, " ")
518
- .split("<%").join("\t")
519
- .replace(/((^|%>)[^\t]*)'/g, "$1\r")
520
- .replace(/\t=(.*?)%>/g, "',$1,'")
521
- .split("\t").join("');")
522
- .split("%>").join("p.push('")
523
- .split("\r").join("\\'") +
524
- "');}return p.join('');"
525
- );
526
 
527
- // Provide some basic currying to the user
528
- return data ? fn( data ) : fn;
529
- }
530
- return tmpl(templateString,valuesObject);
531
- },
532
- /* jshint ignore:end */
533
- generateLabels = helpers.generateLabels = function(templateString,numberOfSteps,graphMin,stepValue){
534
- var labelsArray = new Array(numberOfSteps);
535
- if (templateString){
536
- each(labelsArray,function(val,index){
537
- labelsArray[index] = template(templateString,{value: (graphMin + (stepValue*(index+1)))});
538
- });
539
- }
540
- return labelsArray;
541
- },
542
- //--Animation methods
543
- //Easing functions adapted from Robert Penner's easing equations
544
- //http://www.robertpenner.com/easing/
545
- easingEffects = helpers.easingEffects = {
546
- linear: function (t) {
547
- return t;
548
- },
549
- easeInQuad: function (t) {
550
- return t * t;
551
- },
552
- easeOutQuad: function (t) {
553
- return -1 * t * (t - 2);
554
- },
555
- easeInOutQuad: function (t) {
556
- if ((t /= 1 / 2) < 1){
557
- return 1 / 2 * t * t;
558
- }
559
- return -1 / 2 * ((--t) * (t - 2) - 1);
560
- },
561
- easeInCubic: function (t) {
562
- return t * t * t;
563
- },
564
- easeOutCubic: function (t) {
565
- return 1 * ((t = t / 1 - 1) * t * t + 1);
566
- },
567
- easeInOutCubic: function (t) {
568
- if ((t /= 1 / 2) < 1){
569
- return 1 / 2 * t * t * t;
570
- }
571
- return 1 / 2 * ((t -= 2) * t * t + 2);
572
- },
573
- easeInQuart: function (t) {
574
- return t * t * t * t;
575
- },
576
- easeOutQuart: function (t) {
577
- return -1 * ((t = t / 1 - 1) * t * t * t - 1);
578
- },
579
- easeInOutQuart: function (t) {
580
- if ((t /= 1 / 2) < 1){
581
- return 1 / 2 * t * t * t * t;
582
- }
583
- return -1 / 2 * ((t -= 2) * t * t * t - 2);
584
- },
585
- easeInQuint: function (t) {
586
- return 1 * (t /= 1) * t * t * t * t;
587
- },
588
- easeOutQuint: function (t) {
589
- return 1 * ((t = t / 1 - 1) * t * t * t * t + 1);
590
- },
591
- easeInOutQuint: function (t) {
592
- if ((t /= 1 / 2) < 1){
593
- return 1 / 2 * t * t * t * t * t;
594
- }
595
- return 1 / 2 * ((t -= 2) * t * t * t * t + 2);
596
- },
597
- easeInSine: function (t) {
598
- return -1 * Math.cos(t / 1 * (Math.PI / 2)) + 1;
599
- },
600
- easeOutSine: function (t) {
601
- return 1 * Math.sin(t / 1 * (Math.PI / 2));
602
- },
603
- easeInOutSine: function (t) {
604
- return -1 / 2 * (Math.cos(Math.PI * t / 1) - 1);
605
- },
606
- easeInExpo: function (t) {
607
- return (t === 0) ? 1 : 1 * Math.pow(2, 10 * (t / 1 - 1));
608
- },
609
- easeOutExpo: function (t) {
610
- return (t === 1) ? 1 : 1 * (-Math.pow(2, -10 * t / 1) + 1);
611
- },
612
- easeInOutExpo: function (t) {
613
- if (t === 0){
614
- return 0;
615
- }
616
- if (t === 1){
617
- return 1;
618
- }
619
- if ((t /= 1 / 2) < 1){
620
- return 1 / 2 * Math.pow(2, 10 * (t - 1));
621
- }
622
- return 1 / 2 * (-Math.pow(2, -10 * --t) + 2);
623
- },
624
- easeInCirc: function (t) {
625
- if (t >= 1){
626
- return t;
627
- }
628
- return -1 * (Math.sqrt(1 - (t /= 1) * t) - 1);
629
- },
630
- easeOutCirc: function (t) {
631
- return 1 * Math.sqrt(1 - (t = t / 1 - 1) * t);
632
- },
633
- easeInOutCirc: function (t) {
634
- if ((t /= 1 / 2) < 1){
635
- return -1 / 2 * (Math.sqrt(1 - t * t) - 1);
636
- }
637
- return 1 / 2 * (Math.sqrt(1 - (t -= 2) * t) + 1);
638
- },
639
- easeInElastic: function (t) {
640
- var s = 1.70158;
641
- var p = 0;
642
- var a = 1;
643
- if (t === 0){
644
- return 0;
645
- }
646
- if ((t /= 1) == 1){
647
- return 1;
648
- }
649
- if (!p){
650
- p = 1 * 0.3;
651
- }
652
- if (a < Math.abs(1)) {
653
- a = 1;
654
- s = p / 4;
655
- } else{
656
- s = p / (2 * Math.PI) * Math.asin(1 / a);
657
- }
658
- return -(a * Math.pow(2, 10 * (t -= 1)) * Math.sin((t * 1 - s) * (2 * Math.PI) / p));
659
- },
660
- easeOutElastic: function (t) {
661
- var s = 1.70158;
662
- var p = 0;
663
- var a = 1;
664
- if (t === 0){
665
- return 0;
666
- }
667
- if ((t /= 1) == 1){
668
- return 1;
669
- }
670
- if (!p){
671
- p = 1 * 0.3;
672
- }
673
- if (a < Math.abs(1)) {
674
- a = 1;
675
- s = p / 4;
676
- } else{
677
- s = p / (2 * Math.PI) * Math.asin(1 / a);
678
- }
679
- return a * Math.pow(2, -10 * t) * Math.sin((t * 1 - s) * (2 * Math.PI) / p) + 1;
680
- },
681
- easeInOutElastic: function (t) {
682
- var s = 1.70158;
683
- var p = 0;
684
- var a = 1;
685
- if (t === 0){
686
- return 0;
687
- }
688
- if ((t /= 1 / 2) == 2){
689
- return 1;
690
- }
691
- if (!p){
692
- p = 1 * (0.3 * 1.5);
693
- }
694
- if (a < Math.abs(1)) {
695
- a = 1;
696
- s = p / 4;
697
- } else {
698
- s = p / (2 * Math.PI) * Math.asin(1 / a);
699
- }
700
- if (t < 1){
701
- return -0.5 * (a * Math.pow(2, 10 * (t -= 1)) * Math.sin((t * 1 - s) * (2 * Math.PI) / p));}
702
- return a * Math.pow(2, -10 * (t -= 1)) * Math.sin((t * 1 - s) * (2 * Math.PI) / p) * 0.5 + 1;
703
- },
704
- easeInBack: function (t) {
705
- var s = 1.70158;
706
- return 1 * (t /= 1) * t * ((s + 1) * t - s);
707
- },
708
- easeOutBack: function (t) {
709
- var s = 1.70158;
710
- return 1 * ((t = t / 1 - 1) * t * ((s + 1) * t + s) + 1);
711
- },
712
- easeInOutBack: function (t) {
713
- var s = 1.70158;
714
- if ((t /= 1 / 2) < 1){
715
- return 1 / 2 * (t * t * (((s *= (1.525)) + 1) * t - s));
716
  }
717
- return 1 / 2 * ((t -= 2) * t * (((s *= (1.525)) + 1) * t + s) + 2);
718
- },
719
- easeInBounce: function (t) {
720
- return 1 - easingEffects.easeOutBounce(1 - t);
721
- },
722
- easeOutBounce: function (t) {
723
- if ((t /= 1) < (1 / 2.75)) {
724
- return 1 * (7.5625 * t * t);
725
- } else if (t < (2 / 2.75)) {
726
- return 1 * (7.5625 * (t -= (1.5 / 2.75)) * t + 0.75);
727
- } else if (t < (2.5 / 2.75)) {
728
- return 1 * (7.5625 * (t -= (2.25 / 2.75)) * t + 0.9375);
729
- } else {
730
- return 1 * (7.5625 * (t -= (2.625 / 2.75)) * t + 0.984375);
731
  }
732
- },
733
- easeInOutBounce: function (t) {
734
- if (t < 1 / 2){
735
- return easingEffects.easeInBounce(t * 2) * 0.5;
736
- }
737
- return easingEffects.easeOutBounce(t * 2 - 1) * 0.5 + 1 * 0.5;
738
- }
739
- },
740
- //Request animation polyfill - http://www.paulirish.com/2011/requestanimationframe-for-smart-animating/
741
- requestAnimFrame = helpers.requestAnimFrame = (function(){
742
- return window.requestAnimationFrame ||
743
- window.webkitRequestAnimationFrame ||
744
- window.mozRequestAnimationFrame ||
745
- window.oRequestAnimationFrame ||
746
- window.msRequestAnimationFrame ||
747
- function(callback) {
748
- return window.setTimeout(callback, 1000 / 60);
749
- };
750
- })(),
751
- cancelAnimFrame = helpers.cancelAnimFrame = (function(){
752
- return window.cancelAnimationFrame ||
753
- window.webkitCancelAnimationFrame ||
754
- window.mozCancelAnimationFrame ||
755
- window.oCancelAnimationFrame ||
756
- window.msCancelAnimationFrame ||
757
- function(callback) {
758
- return window.clearTimeout(callback, 1000 / 60);
759
- };
760
- })(),
761
- animationLoop = helpers.animationLoop = function(callback,totalSteps,easingString,onProgress,onComplete,chartInstance){
762
 
763
- var currentStep = 0,
764
- easingFunction = easingEffects[easingString] || easingEffects.linear;
 
 
765
 
766
- var animationFrame = function(){
767
- currentStep++;
768
- var stepDecimal = currentStep/totalSteps;
769
- var easeDecimal = easingFunction(stepDecimal);
770
 
771
- callback.call(chartInstance,easeDecimal,stepDecimal, currentStep);
772
- onProgress.call(chartInstance,easeDecimal,stepDecimal);
773
- if (currentStep < totalSteps){
774
- chartInstance.animationFrame = requestAnimFrame(animationFrame);
775
- } else{
776
- onComplete.apply(chartInstance);
777
- }
 
 
778
  };
779
- requestAnimFrame(animationFrame);
780
  },
781
- //-- DOM methods
782
- getRelativePosition = helpers.getRelativePosition = function(evt){
783
- var mouseX, mouseY;
784
- var e = evt.originalEvent || evt,
785
- canvas = evt.currentTarget || evt.srcElement,
786
- boundingRect = canvas.getBoundingClientRect();
787
 
788
- if (e.touches){
789
- mouseX = e.touches[0].clientX - boundingRect.left;
790
- mouseY = e.touches[0].clientY - boundingRect.top;
 
 
 
 
 
791
 
792
- }
793
- else{
794
- mouseX = e.clientX - boundingRect.left;
795
- mouseY = e.clientY - boundingRect.top;
 
 
796
  }
797
 
798
- return {
799
- x : mouseX,
800
- y : mouseY
801
- };
 
 
 
 
802
 
 
 
 
803
  },
804
- addEvent = helpers.addEvent = function(node,eventType,method){
805
- if (node.addEventListener){
806
- node.addEventListener(eventType,method);
807
- } else if (node.attachEvent){
808
- node.attachEvent("on"+eventType, method);
809
- } else {
810
- node["on"+eventType] = method;
811
- }
 
 
 
 
 
 
 
 
 
 
 
 
812
  },
813
- removeEvent = helpers.removeEvent = function(node, eventType, handler){
814
- if (node.removeEventListener){
815
- node.removeEventListener(eventType, handler, false);
816
- } else if (node.detachEvent){
817
- node.detachEvent("on"+eventType,handler);
818
- } else{
819
- node["on" + eventType] = noop;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
820
  }
821
- },
822
- bindEvents = helpers.bindEvents = function(chartInstance, arrayOfEvents, handler){
823
- // Create the events object if it's not already present
824
- if (!chartInstance.events) chartInstance.events = {};
825
 
826
- each(arrayOfEvents,function(eventName){
827
- chartInstance.events[eventName] = function(){
828
- handler.apply(chartInstance, arguments);
829
- };
830
- addEvent(chartInstance.chart.canvas,eventName,chartInstance.events[eventName]);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
831
  });
832
  },
833
- unbindEvents = helpers.unbindEvents = function (chartInstance, arrayOfEvents) {
834
- each(arrayOfEvents, function(handler,eventName){
835
- removeEvent(chartInstance.chart.canvas, eventName, handler);
836
- });
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
837
  },
838
- getMaximumWidth = helpers.getMaximumWidth = function(domNode){
839
- var container = domNode.parentNode,
840
- padding = parseInt(getStyle(container, 'padding-left')) + parseInt(getStyle(container, 'padding-right'));
841
- // TODO = check cross browser stuff with this.
842
- return container ? container.clientWidth - padding : 0;
843
- },
844
- getMaximumHeight = helpers.getMaximumHeight = function(domNode){
845
- var container = domNode.parentNode,
846
- padding = parseInt(getStyle(container, 'padding-bottom')) + parseInt(getStyle(container, 'padding-top'));
847
- // TODO = check cross browser stuff with this.
848
- return container ? container.clientHeight - padding : 0;
849
- },
850
- getStyle = helpers.getStyle = function (el, property) {
851
- return el.currentStyle ?
852
- el.currentStyle[property] :
853
- document.defaultView.getComputedStyle(el, null).getPropertyValue(property);
854
- },
855
- getMaximumSize = helpers.getMaximumSize = helpers.getMaximumWidth, // legacy support
856
- retinaScale = helpers.retinaScale = function(chart){
857
- var ctx = chart.ctx,
858
- width = chart.canvas.width,
859
- height = chart.canvas.height;
860
-
861
- if (window.devicePixelRatio) {
862
- ctx.canvas.style.width = width + "px";
863
- ctx.canvas.style.height = height + "px";
864
- ctx.canvas.height = height * window.devicePixelRatio;
865
- ctx.canvas.width = width * window.devicePixelRatio;
866
- ctx.scale(window.devicePixelRatio, window.devicePixelRatio);
867
- }
868
- },
869
- //-- Canvas methods
870
- clear = helpers.clear = function(chart){
871
- chart.ctx.clearRect(0,0,chart.width,chart.height);
872
- },
873
- fontString = helpers.fontString = function(pixelSize,fontStyle,fontFamily){
874
- return fontStyle + " " + pixelSize+"px " + fontFamily;
875
- },
876
- longestText = helpers.longestText = function(ctx,font,arrayOfStrings){
877
- ctx.font = font;
878
- var longest = 0;
879
- each(arrayOfStrings,function(string){
880
- var textWidth = ctx.measureText(string).width;
881
- longest = (textWidth > longest) ? textWidth : longest;
882
- });
883
- return longest;
884
  },
885
- drawRoundedRectangle = helpers.drawRoundedRectangle = function(ctx,x,y,width,height,radius){
886
- ctx.beginPath();
887
- ctx.moveTo(x + radius, y);
888
- ctx.lineTo(x + width - radius, y);
889
- ctx.quadraticCurveTo(x + width, y, x + width, y + radius);
890
- ctx.lineTo(x + width, y + height - radius);
891
- ctx.quadraticCurveTo(x + width, y + height, x + width - radius, y + height);
892
- ctx.lineTo(x + radius, y + height);
893
- ctx.quadraticCurveTo(x, y + height, x, y + height - radius);
894
- ctx.lineTo(x, y + radius);
895
- ctx.quadraticCurveTo(x, y, x + radius, y);
896
- ctx.closePath();
897
- };
898
 
 
 
 
 
 
 
 
 
 
 
 
 
899
 
900
- //Store a reference to each instance - allowing us to globally resize chart instances on window resize.
901
- //Destroy method on the chart will remove the instance of the chart from this reference.
902
- Chart.instances = {};
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
903
 
904
- Chart.Type = function(data,options,chart){
905
- this.options = options;
906
- this.chart = chart;
907
- this.id = uid();
908
- //Add the chart instance to the global namespace
909
- Chart.instances[this.id] = this;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
910
 
911
- // Initialize is always called when a chart type is created
912
- // By default it is a no op, but it should be extended
913
- if (options.responsive){
914
- this.resize();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
915
  }
916
- this.initialize.call(this,data);
917
  };
918
 
919
- //Core methods that'll be a part of every chart type
920
- extend(Chart.Type.prototype,{
921
- initialize : function(){return this;},
922
- clear : function(){
923
- clear(this.chart);
924
- return this;
925
- },
926
- stop : function(){
927
- // Stops any current animation loop occuring
928
- Chart.animationService.cancelAnimation(this);
929
- return this;
930
- },
931
- resize : function(callback){
932
- this.stop();
933
- var canvas = this.chart.canvas,
934
- newWidth = getMaximumWidth(this.chart.canvas),
935
- newHeight = this.options.maintainAspectRatio ? newWidth / this.chart.aspectRatio : getMaximumHeight(this.chart.canvas);
936
 
937
- canvas.width = this.chart.width = newWidth;
938
- canvas.height = this.chart.height = newHeight;
 
939
 
940
- retinaScale(this.chart);
 
 
941
 
942
- if (typeof callback === "function"){
943
- callback.apply(this, Array.prototype.slice.call(arguments, 1));
944
- }
945
- return this;
946
- },
947
- reflow : noop,
948
- render : function(reflow){
949
- if (reflow){
950
- this.reflow();
951
- }
952
-
953
- if (this.options.animation && !reflow){
954
- var animation = new Chart.Animation();
955
- animation.numSteps = this.options.animationSteps;
956
- animation.easing = this.options.animationEasing;
957
-
958
- // render function
959
- animation.render = function(chartInstance, animationObject) {
960
- var easingFunction = helpers.easingEffects[animationObject.easing];
961
- var stepDecimal = animationObject.currentStep / animationObject.numSteps;
962
- var easeDecimal = easingFunction(stepDecimal);
963
-
964
- chartInstance.draw(easeDecimal, stepDecimal, animationObject.currentStep);
965
- };
966
-
967
- // user events
968
- animation.onAnimationProgress = this.options.onAnimationProgress;
969
- animation.onAnimationComplete = this.options.onAnimationComplete;
970
-
971
- Chart.animationService.addAnimation(this, animation);
972
- }
973
- else{
974
- this.draw();
975
- this.options.onAnimationComplete.call(this);
976
- }
977
- return this;
978
- },
979
- generateLegend : function(){
980
- return helpers.template(this.options.legendTemplate, {datasets: this.datasets});
981
- },
982
- destroy : function(){
983
- this.stop();
984
- this.clear();
985
- unbindEvents(this, this.events);
986
- var canvas = this.chart.canvas;
987
 
988
- // Reset canvas height/width attributes starts a fresh with the canvas context
989
- canvas.width = this.chart.width;
990
- canvas.height = this.chart.height;
 
 
991
 
992
- // < IE9 doesn't support removeProperty
993
- if (canvas.style.removeProperty) {
994
- canvas.style.removeProperty('width');
995
- canvas.style.removeProperty('height');
996
- } else {
997
- canvas.style.removeAttribute('width');
998
- canvas.style.removeAttribute('height');
999
  }
1000
 
1001
- delete Chart.instances[this.id];
1002
- },
1003
- showTooltip : function(ChartElements, forceRedraw){
1004
- // Only redraw the chart if we've actually changed what we're hovering on.
1005
- if (typeof this.activeElements === 'undefined') this.activeElements = [];
1006
 
1007
- var isChanged = (function(Elements){
1008
- var changed = false;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1009
 
1010
- if (Elements.length !== this.activeElements.length){
1011
- changed = true;
1012
- return changed;
1013
- }
 
 
1014
 
1015
- each(Elements, function(element, index){
1016
- if (element !== this.activeElements[index]){
1017
- changed = true;
1018
- }
1019
- }, this);
1020
- return changed;
1021
- }).call(this, ChartElements);
1022
 
1023
- if (!isChanged && !forceRedraw){
1024
- return;
1025
- }
1026
- else{
1027
- this.activeElements = ChartElements;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1028
  }
1029
- this.draw();
1030
- if(this.options.customTooltips){
1031
- this.options.customTooltips(false);
 
 
 
 
1032
  }
1033
- if (ChartElements.length > 0){
1034
- // If we have multiple datasets, show a MultiTooltip for all of the data points at that index
1035
- if (this.datasets && this.datasets.length > 1) {
1036
- var dataArray,
1037
- dataIndex;
1038
 
1039
- for (var i = this.datasets.length - 1; i >= 0; i--) {
1040
- dataArray = this.datasets[i].points || this.datasets[i].bars || this.datasets[i].segments;
1041
- dataIndex = indexOf(dataArray, ChartElements[0]);
1042
- if (dataIndex !== -1){
1043
- break;
1044
- }
1045
- }
1046
- var tooltipLabels = [],
1047
- tooltipColors = [],
1048
- medianPosition = (function(index) {
1049
-
1050
- // Get all the points at that particular index
1051
- var Elements = [],
1052
- dataCollection,
1053
- xPositions = [],
1054
- yPositions = [],
1055
- xMax,
1056
- yMax,
1057
- xMin,
1058
- yMin;
1059
- helpers.each(this.datasets, function(dataset){
1060
- dataCollection = dataset.points || dataset.bars || dataset.segments;
1061
- if (dataCollection[dataIndex] && dataCollection[dataIndex].hasValue()){
1062
- Elements.push(dataCollection[dataIndex]);
1063
- }
1064
- });
1065
-
1066
- helpers.each(Elements, function(element) {
1067
- xPositions.push(element.x);
1068
- yPositions.push(element.y);
1069
-
1070
-
1071
- //Include any colour information about the element
1072
- tooltipLabels.push(helpers.template(this.options.multiTooltipTemplate, element));
1073
- tooltipColors.push({
1074
- fill: element._saved.fillColor || element.fillColor,
1075
- stroke: element._saved.strokeColor || element.strokeColor
1076
- });
1077
-
1078
- }, this);
1079
-
1080
- yMin = min(yPositions);
1081
- yMax = max(yPositions);
1082
-
1083
- xMin = min(xPositions);
1084
- xMax = max(xPositions);
1085
-
1086
- return {
1087
- x: (xMin > this.chart.width/2) ? xMin : xMax,
1088
- y: (yMin + yMax)/2
1089
- };
1090
- }).call(this, dataIndex);
1091
-
1092
- new Chart.MultiTooltip({
1093
- x: medianPosition.x,
1094
- y: medianPosition.y,
1095
- xPadding: this.options.tooltipXPadding,
1096
- yPadding: this.options.tooltipYPadding,
1097
- xOffset: this.options.tooltipXOffset,
1098
- fillColor: this.options.tooltipFillColor,
1099
- textColor: this.options.tooltipFontColor,
1100
- fontFamily: this.options.tooltipFontFamily,
1101
- fontStyle: this.options.tooltipFontStyle,
1102
- fontSize: this.options.tooltipFontSize,
1103
- titleTextColor: this.options.tooltipTitleFontColor,
1104
- titleFontFamily: this.options.tooltipTitleFontFamily,
1105
- titleFontStyle: this.options.tooltipTitleFontStyle,
1106
- titleFontSize: this.options.tooltipTitleFontSize,
1107
- cornerRadius: this.options.tooltipCornerRadius,
1108
- labels: tooltipLabels,
1109
- legendColors: tooltipColors,
1110
- legendColorBackground : this.options.multiTooltipKeyBackground,
1111
- title: template(this.options.tooltipTitleTemplate,ChartElements[0]),
1112
- chart: this.chart,
1113
- ctx: this.chart.ctx,
1114
- custom: this.options.customTooltips
1115
- }).draw();
1116
 
1117
- } else {
1118
- each(ChartElements, function(Element) {
1119
- var tooltipPosition = Element.tooltipPosition();
1120
- new Chart.Tooltip({
1121
- x: Math.round(tooltipPosition.x),
1122
- y: Math.round(tooltipPosition.y),
1123
- xPadding: this.options.tooltipXPadding,
1124
- yPadding: this.options.tooltipYPadding,
1125
- fillColor: this.options.tooltipFillColor,
1126
- textColor: this.options.tooltipFontColor,
1127
- fontFamily: this.options.tooltipFontFamily,
1128
- fontStyle: this.options.tooltipFontStyle,
1129
- fontSize: this.options.tooltipFontSize,
1130
- caretHeight: this.options.tooltipCaretSize,
1131
- cornerRadius: this.options.tooltipCornerRadius,
1132
- text: template(this.options.tooltipTemplate, Element),
1133
- chart: this.chart,
1134
- custom: this.options.customTooltips
1135
- }).draw();
1136
- }, this);
1137
- }
1138
- }
1139
- return this;
1140
- },
1141
- toBase64Image : function(){
1142
- return this.chart.canvas.toDataURL.apply(this.chart.canvas, arguments);
1143
  }
1144
- });
1145
 
1146
- Chart.Type.extend = function(extensions){
 
 
 
1147
 
1148
- var parent = this;
 
 
 
1149
 
1150
- var ChartType = function(){
1151
- return parent.apply(this,arguments);
1152
- };
1153
 
1154
- //Copy the prototype object of the this class
1155
- ChartType.prototype = clone(parent.prototype);
1156
- //Now overwrite some of the properties in the base class with the new extensions
1157
- extend(ChartType.prototype, extensions);
1158
 
1159
- ChartType.extend = Chart.Type.extend;
 
1160
 
1161
- if (extensions.name || parent.prototype.name){
 
 
1162
 
1163
- var chartName = extensions.name || parent.prototype.name;
1164
- //Assign any potential default values of the new chart type
 
1165
 
1166
- //If none are defined, we'll use a clone of the chart type this is being extended from.
1167
- //I.e. if we extend a line chart, we'll use the defaults from the line chart if our new chart
1168
- //doesn't define some defaults of their own.
1169
 
1170
- var baseDefaults = (Chart.defaults[parent.prototype.name]) ? clone(Chart.defaults[parent.prototype.name]) : {};
 
1171
 
1172
- Chart.defaults[chartName] = extend(baseDefaults,extensions.defaults);
 
 
1173
 
1174
- Chart.types[chartName] = ChartType;
 
1175
 
1176
- //Register this new chart type in the Chart prototype
1177
- Chart.prototype[chartName] = function(data,options){
1178
- var config = merge(Chart.defaults.global, Chart.defaults[chartName], options || {});
1179
- return new ChartType(data,config,this);
1180
- };
1181
- } else{
1182
- warn("Name not provided for this chart, so it hasn't been registered");
1183
  }
1184
- return parent;
1185
- };
1186
 
1187
- Chart.Element = function(configuration){
1188
- extend(this,configuration);
1189
- this.initialize.apply(this,arguments);
1190
- this.save();
1191
- };
1192
- extend(Chart.Element.prototype,{
1193
- initialize : function(){},
1194
- restore : function(props){
1195
- if (!props){
1196
- extend(this,this._saved);
1197
- } else {
1198
- each(props,function(key){
1199
- this[key] = this._saved[key];
1200
- },this);
1201
- }
1202
- return this;
1203
- },
1204
- save : function(){
1205
- this._saved = clone(this);
1206
- delete this._saved._saved;
1207
- return this;
1208
- },
1209
- update : function(newProps){
1210
- each(newProps,function(value,key){
1211
- this._saved[key] = this[key];
1212
- this[key] = value;
1213
- },this);
1214
- return this;
1215
- },
1216
- transition : function(props,ease){
1217
- each(props,function(value,key){
1218
- this[key] = ((value - this._saved[key]) * ease) + this._saved[key];
1219
- },this);
1220
- return this;
1221
- },
1222
- tooltipPosition : function(){
1223
- return {
1224
- x : this.x,
1225
- y : this.y
1226
- };
1227
- },
1228
- hasValue: function(){
1229
- return isNumber(this.value);
1230
  }
1231
- });
1232
 
1233
- Chart.Element.extend = inherits;
 
1234
 
 
 
 
 
 
1235
 
1236
- Chart.Point = Chart.Element.extend({
1237
- display: true,
1238
- inRange: function(chartX,chartY){
1239
- var hitDetectionRange = this.hitDetectionRadius + this.radius;
1240
- return ((Math.pow(chartX-this.x, 2)+Math.pow(chartY-this.y, 2)) < Math.pow(hitDetectionRange,2));
1241
- },
1242
- draw : function(){
1243
- if (this.display){
1244
- var ctx = this.ctx;
1245
- ctx.beginPath();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1246
 
1247
- ctx.arc(this.x, this.y, this.radius, 0, Math.PI*2);
1248
- ctx.closePath();
1249
 
1250
- ctx.strokeStyle = this.strokeColor;
1251
- ctx.lineWidth = this.strokeWidth;
 
 
1252
 
1253
- ctx.fillStyle = this.fillColor;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1254
 
1255
- ctx.fill();
1256
- ctx.stroke();
1257
  }
1258
 
 
 
 
 
 
1259
 
1260
- //Quick debug for bezier curve splining
1261
- //Highlights control points and the line between them.
1262
- //Handy for dev - stripped in the min version.
1263
-
1264
- // ctx.save();
1265
- // ctx.fillStyle = "black";
1266
- // ctx.strokeStyle = "black"
1267
- // ctx.beginPath();
1268
- // ctx.arc(this.controlPoints.inner.x,this.controlPoints.inner.y, 2, 0, Math.PI*2);
1269
- // ctx.fill();
1270
 
1271
- // ctx.beginPath();
1272
- // ctx.arc(this.controlPoints.outer.x,this.controlPoints.outer.y, 2, 0, Math.PI*2);
1273
- // ctx.fill();
 
 
1274
 
1275
- // ctx.moveTo(this.controlPoints.inner.x,this.controlPoints.inner.y);
1276
- // ctx.lineTo(this.x, this.y);
1277
- // ctx.lineTo(this.controlPoints.outer.x,this.controlPoints.outer.y);
1278
- // ctx.stroke();
 
 
 
 
 
 
 
 
 
 
 
1279
 
1280
- // ctx.restore();
 
1281
 
 
 
 
1282
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1283
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1284
  }
1285
- });
1286
-
1287
- Chart.Arc = Chart.Element.extend({
1288
- inRange : function(chartX,chartY){
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1289
 
1290
- var pointRelativePosition = helpers.getAngleFromPoint(this, {
1291
- x: chartX,
1292
- y: chartY
1293
- });
1294
 
1295
- // Normalize all angles to 0 - 2*PI (0 - 360°)
1296
- var pointRelativeAngle = pointRelativePosition.angle % (Math.PI * 2),
1297
- startAngle = (Math.PI * 2 + this.startAngle) % (Math.PI * 2),
1298
- endAngle = (Math.PI * 2 + this.endAngle) % (Math.PI * 2) || 360;
1299
 
1300
- // Calculate wether the pointRelativeAngle is between the start and the end angle
1301
- var betweenAngles = (endAngle < startAngle) ?
1302
- pointRelativeAngle <= endAngle || pointRelativeAngle >= startAngle:
1303
- pointRelativeAngle >= startAngle && pointRelativeAngle <= endAngle;
1304
 
1305
- //Check if within the range of the open/close angle
1306
- var withinRadius = (pointRelativePosition.distance >= this.innerRadius && pointRelativePosition.distance <= this.outerRadius);
 
1307
 
1308
- return (betweenAngles && withinRadius);
1309
- //Ensure within the outside of the arc centre, but inside arc outer
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1310
  },
1311
- tooltipPosition : function(){
1312
- var centreAngle = this.startAngle + ((this.endAngle - this.startAngle) / 2),
1313
- rangeFromCentre = (this.outerRadius - this.innerRadius) / 2 + this.innerRadius;
1314
- return {
1315
- x : this.x + (Math.cos(centreAngle) * rangeFromCentre),
1316
- y : this.y + (Math.sin(centreAngle) * rangeFromCentre)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1317
  };
1318
  },
1319
- draw : function(animationPercent){
1320
 
1321
- var easingDecimal = animationPercent || 1;
1322
 
1323
- var ctx = this.ctx;
 
 
 
 
1324
 
1325
- ctx.beginPath();
 
 
 
 
1326
 
1327
- ctx.arc(this.x, this.y, this.outerRadius < 0 ? 0 : this.outerRadius, this.startAngle, this.endAngle);
 
 
1328
 
1329
- ctx.arc(this.x, this.y, this.innerRadius < 0 ? 0 : this.innerRadius, this.endAngle, this.startAngle, true);
 
 
1330
 
1331
- ctx.closePath();
1332
- ctx.strokeStyle = this.strokeColor;
1333
- ctx.lineWidth = this.strokeWidth;
1334
 
1335
- ctx.fillStyle = this.fillColor;
 
 
 
 
 
1336
 
1337
- ctx.fill();
1338
- ctx.lineJoin = 'bevel';
1339
 
1340
- if (this.showStroke){
1341
- ctx.stroke();
1342
- }
1343
- }
1344
- });
 
1345
 
1346
- Chart.Rectangle = Chart.Element.extend({
1347
- draw : function(){
1348
- var ctx = this.ctx,
1349
- halfWidth = this.width/2,
1350
- leftX = this.x - halfWidth,
1351
- rightX = this.x + halfWidth,
1352
- top = this.base - (this.base - this.y),
1353
- halfStroke = this.strokeWidth / 2;
1354
 
1355
- // Canvas doesn't allow us to stroke inside the width so we can
1356
- // adjust the sizes to fit if we're setting a stroke on the line
1357
- if (this.showStroke){
1358
- leftX += halfStroke;
1359
- rightX -= halfStroke;
1360
- top += halfStroke;
 
 
 
1361
  }
1362
 
1363
- ctx.beginPath();
 
 
1364
 
1365
- ctx.fillStyle = this.fillColor;
1366
- ctx.strokeStyle = this.strokeColor;
1367
- ctx.lineWidth = this.strokeWidth;
1368
 
1369
- // It'd be nice to keep this class totally generic to any rectangle
1370
- // and simply specify which border to miss out.
1371
- ctx.moveTo(leftX, this.base);
1372
- ctx.lineTo(leftX, top);
1373
- ctx.lineTo(rightX, top);
1374
- ctx.lineTo(rightX, this.base);
1375
- ctx.fill();
1376
- if (this.showStroke){
1377
- ctx.stroke();
1378
- }
1379
- },
1380
- height : function(){
1381
- return this.base - this.y;
1382
- },
1383
- inRange : function(chartX,chartY){
1384
- return (chartX >= this.x - this.width/2 && chartX <= this.x + this.width/2) && (chartY >= this.y && chartY <= this.base);
1385
- }
1386
- });
1387
 
1388
- Chart.Animation = Chart.Element.extend({
1389
- currentStep: null, // the current animation step
1390
- numSteps: 60, // default number of steps
1391
- easing: "", // the easing to use for this animation
1392
- render: null, // render function used by the animation service
1393
-
1394
- onAnimationProgress: null, // user specified callback to fire on each step of the animation
1395
- onAnimationComplete: null, // user specified callback to fire when the animation finishes
1396
- });
1397
-
1398
- Chart.Tooltip = Chart.Element.extend({
1399
- draw : function(){
1400
 
1401
- var ctx = this.chart.ctx;
 
 
 
 
 
 
 
1402
 
1403
- ctx.font = fontString(this.fontSize,this.fontStyle,this.fontFamily);
 
 
 
 
 
 
1404
 
1405
- this.xAlign = "center";
1406
- this.yAlign = "above";
1407
 
1408
- //Distance between the actual element.y position and the start of the tooltip caret
1409
- var caretPadding = this.caretPadding = 2;
1410
 
1411
- var tooltipWidth = ctx.measureText(this.text).width + 2*this.xPadding,
1412
- tooltipRectHeight = this.fontSize + 2*this.yPadding,
1413
- tooltipHeight = tooltipRectHeight + this.caretHeight + caretPadding;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1414
 
1415
- if (this.x + tooltipWidth/2 >this.chart.width){
1416
- this.xAlign = "left";
1417
- } else if (this.x - tooltipWidth/2 < 0){
1418
- this.xAlign = "right";
1419
- }
 
 
 
 
 
 
 
1420
 
1421
- if (this.y - tooltipHeight < 0){
1422
- this.yAlign = "below";
 
 
1423
  }
1424
 
 
 
 
 
1425
 
1426
- var tooltipX = this.x - tooltipWidth/2,
1427
- tooltipY = this.y - tooltipHeight;
 
 
1428
 
1429
- ctx.fillStyle = this.fillColor;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1430
 
1431
- // Custom Tooltips
1432
- if(this.custom){
1433
- this.custom(this);
1434
- }
1435
- else{
1436
- switch(this.yAlign)
1437
- {
1438
- case "above":
1439
- //Draw a caret above the x/y
1440
- ctx.beginPath();
1441
- ctx.moveTo(this.x,this.y - caretPadding);
1442
- ctx.lineTo(this.x + this.caretHeight, this.y - (caretPadding + this.caretHeight));
1443
- ctx.lineTo(this.x - this.caretHeight, this.y - (caretPadding + this.caretHeight));
1444
- ctx.closePath();
1445
- ctx.fill();
1446
- break;
1447
- case "below":
1448
- tooltipY = this.y + caretPadding + this.caretHeight;
1449
- //Draw a caret below the x/y
1450
- ctx.beginPath();
1451
- ctx.moveTo(this.x, this.y + caretPadding);
1452
- ctx.lineTo(this.x + this.caretHeight, this.y + caretPadding + this.caretHeight);
1453
- ctx.lineTo(this.x - this.caretHeight, this.y + caretPadding + this.caretHeight);
1454
- ctx.closePath();
1455
- ctx.fill();
1456
- break;
1457
- }
1458
 
1459
- switch(this.xAlign)
1460
- {
1461
- case "left":
1462
- tooltipX = this.x - tooltipWidth + (this.cornerRadius + this.caretHeight);
1463
- break;
1464
- case "right":
1465
- tooltipX = this.x - (this.cornerRadius + this.caretHeight);
1466
- break;
1467
- }
 
 
 
1468
 
1469
- drawRoundedRectangle(ctx,tooltipX,tooltipY,tooltipWidth,tooltipRectHeight,this.cornerRadius);
 
 
 
 
 
 
1470
 
1471
- ctx.fill();
 
 
 
 
 
 
 
 
1472
 
1473
- ctx.fillStyle = this.textColor;
1474
- ctx.textAlign = "center";
1475
- ctx.textBaseline = "middle";
1476
- ctx.fillText(this.text, tooltipX + tooltipWidth/2, tooltipY + tooltipRectHeight/2);
1477
- }
1478
- }
1479
- });
1480
 
1481
- Chart.MultiTooltip = Chart.Element.extend({
1482
- initialize : function(){
1483
- this.font = fontString(this.fontSize,this.fontStyle,this.fontFamily);
1484
 
1485
- this.titleFont = fontString(this.titleFontSize,this.titleFontStyle,this.titleFontFamily);
 
 
 
 
 
 
 
 
1486
 
1487
- this.titleHeight = this.title ? this.titleFontSize * 1.5 : 0;
1488
- this.height = (this.labels.length * this.fontSize) + ((this.labels.length-1) * (this.fontSize/2)) + (this.yPadding*2) + this.titleHeight;
 
 
 
 
 
 
 
 
 
 
 
 
 
1489
 
1490
- this.ctx.font = this.titleFont;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1491
 
1492
- var titleWidth = this.ctx.measureText(this.title).width,
1493
- //Label has a legend square as well so account for this.
1494
- labelWidth = longestText(this.ctx,this.font,this.labels) + this.fontSize + 3,
1495
- longestTextWidth = max([labelWidth,titleWidth]);
1496
 
1497
- this.width = longestTextWidth + (this.xPadding*2);
 
1498
 
 
 
1499
 
1500
- var halfHeight = this.height/2;
 
 
 
 
1501
 
1502
- //Check to ensure the height will fit on the canvas
1503
- if (this.y - halfHeight < 0 ){
1504
- this.y = halfHeight;
1505
- } else if (this.y + halfHeight > this.chart.height){
1506
- this.y = this.chart.height - halfHeight;
1507
  }
 
1508
 
1509
- //Decide whether to align left or right based on position on canvas
1510
- if (this.x > this.chart.width/2){
1511
- this.x -= this.xOffset + this.width;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1512
  } else {
1513
- this.x += this.xOffset;
1514
  }
1515
 
1516
-
1517
- },
1518
- getLineHeight : function(index){
1519
- var baseLineHeight = this.y - (this.height/2) + this.yPadding,
1520
- afterTitleIndex = index-1;
1521
-
1522
- //If the index is zero, we're getting the title
1523
- if (index === 0){
1524
- return baseLineHeight + this.titleHeight / 3;
1525
- } else{
1526
- return baseLineHeight + ((this.fontSize * 1.5 * afterTitleIndex) + this.fontSize / 2) + this.titleHeight;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1527
  }
1528
 
1529
- },
1530
- draw : function(){
1531
- // Custom Tooltips
1532
- if(this.custom){
1533
- this.custom(this);
1534
- }
1535
- else{
1536
- drawRoundedRectangle(this.ctx,this.x,this.y - this.height/2,this.width,this.height,this.cornerRadius);
1537
- var ctx = this.ctx;
1538
- ctx.fillStyle = this.fillColor;
1539
- ctx.fill();
1540
- ctx.closePath();
1541
 
1542
- ctx.textAlign = "left";
1543
- ctx.textBaseline = "middle";
1544
- ctx.fillStyle = this.titleTextColor;
1545
- ctx.font = this.titleFont;
 
 
 
 
 
 
 
1546
 
1547
- ctx.fillText(this.title,this.x + this.xPadding, this.getLineHeight(0));
 
1548
 
1549
- ctx.font = this.font;
1550
- helpers.each(this.labels,function(label,index){
1551
- ctx.fillStyle = this.textColor;
1552
- ctx.fillText(label,this.x + this.xPadding + this.fontSize + 3, this.getLineHeight(index + 1));
1553
 
1554
- //A bit gnarly, but clearing this rectangle breaks when using explorercanvas (clears whole canvas)
1555
- //ctx.clearRect(this.x + this.xPadding, this.getLineHeight(index + 1) - this.fontSize/2, this.fontSize, this.fontSize);
1556
- //Instead we'll make a white filled block to put the legendColour palette over.
 
1557
 
1558
- ctx.fillStyle = this.legendColorBackground;
1559
- ctx.fillRect(this.x + this.xPadding, this.getLineHeight(index + 1) - this.fontSize/2, this.fontSize, this.fontSize);
 
1560
 
1561
- ctx.fillStyle = this.legendColors[index].fill;
1562
- ctx.fillRect(this.x + this.xPadding, this.getLineHeight(index + 1) - this.fontSize/2, this.fontSize, this.fontSize);
1563
 
 
 
 
 
 
 
 
 
 
 
 
1564
 
1565
- },this);
 
 
 
1566
  }
1567
  }
1568
- });
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1569
 
1570
- Chart.Scale = Chart.Element.extend({
1571
- initialize : function(){
1572
- this.fit();
1573
- },
1574
- buildYLabels : function(){
1575
- this.yLabels = [];
1576
 
1577
- var stepDecimalPlaces = getDecimalPlaces(this.stepValue);
 
1578
 
1579
- for (var i=0; i<=this.steps; i++){
1580
- this.yLabels.push(template(this.templateString,{value:(this.min + (i * this.stepValue)).toFixed(stepDecimalPlaces)}));
1581
- }
1582
- this.yLabelWidth = (this.display && this.showLabels) ? longestText(this.ctx,this.font,this.yLabels) + 10 : 0;
1583
- },
1584
- addXLabel : function(label){
1585
- this.xLabels.push(label);
1586
- this.valuesCount++;
1587
- this.fit();
1588
- },
1589
- removeXLabel : function(){
1590
- this.xLabels.shift();
1591
- this.valuesCount--;
1592
- this.fit();
1593
  },
1594
- // Fitting loop to rotate x Labels and figure out what fits there, and also calculate how many Y steps to use
1595
- fit: function(){
1596
- // First we need the width of the yLabels, assuming the xLabels aren't rotated
1597
 
1598
- // To do that we need the base line at the top and base of the chart, assuming there is no x label rotation
1599
- this.startPoint = (this.display) ? this.fontSize : 0;
1600
- this.endPoint = (this.display) ? this.height - (this.fontSize * 1.5) - 5 : this.height; // -5 to pad labels
1601
 
1602
- // Apply padding settings to the start and end point.
1603
- this.startPoint += this.padding;
1604
- this.endPoint -= this.padding;
1605
 
1606
- // Cache the starting endpoint, excluding the space for x labels
1607
- var cachedEndPoint = this.endPoint;
1608
 
1609
- // Cache the starting height, so can determine if we need to recalculate the scale yAxis
1610
- var cachedHeight = this.endPoint - this.startPoint,
1611
- cachedYLabelWidth;
 
1612
 
1613
- // Build the current yLabels so we have an idea of what size they'll be to start
1614
- /*
1615
- * This sets what is returned from calculateScaleRange as static properties of this class:
1616
- *
1617
- this.steps;
1618
- this.stepValue;
1619
- this.min;
1620
- this.max;
1621
- *
1622
- */
1623
- this.calculateYRange(cachedHeight);
1624
 
1625
- // With these properties set we can now build the array of yLabels
1626
- // and also the width of the largest yLabel
1627
- this.buildYLabels();
 
 
 
1628
 
1629
- this.calculateXLabelRotation();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1630
 
1631
- while((cachedHeight > this.endPoint - this.startPoint)){
1632
- cachedHeight = this.endPoint - this.startPoint;
1633
- cachedYLabelWidth = this.yLabelWidth;
 
1634
 
1635
- this.calculateYRange(cachedHeight);
1636
- this.buildYLabels();
 
 
 
1637
 
1638
- // Only go through the xLabel loop again if the yLabel width has changed
1639
- if (cachedYLabelWidth < this.yLabelWidth){
1640
- this.endPoint = cachedEndPoint;
1641
- this.calculateXLabelRotation();
1642
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1643
  }
1644
 
 
 
 
 
 
 
 
 
 
 
1645
  },
1646
- calculateXLabelRotation : function(){
1647
- //Get the width of each grid by calculating the difference
1648
- //between x offsets between 0 and 1.
1649
 
1650
- this.ctx.font = this.font;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1651
 
1652
- var firstWidth = this.ctx.measureText(this.xLabels[0]).width,
1653
- lastWidth = this.ctx.measureText(this.xLabels[this.xLabels.length - 1]).width,
1654
- firstRotated,
1655
- lastRotated;
 
 
 
 
 
 
 
 
 
 
 
 
1656
 
 
 
 
 
1657
 
1658
- this.xScalePaddingRight = lastWidth/2 + 3;
1659
- this.xScalePaddingLeft = (firstWidth/2 > this.yLabelWidth) ? firstWidth/2 : this.yLabelWidth;
 
 
 
 
1660
 
1661
- this.xLabelRotation = 0;
1662
- if (this.display){
1663
- var originalLabelWidth = longestText(this.ctx,this.font,this.xLabels),
1664
- cosRotation,
1665
- firstRotatedWidth;
1666
- this.xLabelWidth = originalLabelWidth;
1667
- //Allow 3 pixels x2 padding either side for label readability
1668
- var xGridWidth = Math.floor(this.calculateX(1) - this.calculateX(0)) - 6;
1669
 
1670
- //Max label rotate should be 90 - also act as a loop counter
1671
- while ((this.xLabelWidth > xGridWidth && this.xLabelRotation === 0) || (this.xLabelWidth > xGridWidth && this.xLabelRotation <= 90 && this.xLabelRotation > 0)){
1672
- cosRotation = Math.cos(toRadians(this.xLabelRotation));
1673
 
1674
- firstRotated = cosRotation * firstWidth;
1675
- lastRotated = cosRotation * lastWidth;
1676
 
1677
- // We're right aligning the text now.
1678
- if (firstRotated + this.fontSize / 2 > this.yLabelWidth){
1679
- this.xScalePaddingLeft = firstRotated + this.fontSize / 2;
1680
- }
1681
- this.xScalePaddingRight = this.fontSize/2;
1682
 
 
 
 
1683
 
1684
- this.xLabelRotation++;
1685
- this.xLabelWidth = cosRotation * originalLabelWidth;
1686
 
 
 
 
 
 
1687
  }
1688
- if (this.xLabelRotation > 0){
1689
- this.endPoint -= Math.sin(toRadians(this.xLabelRotation))*originalLabelWidth + 3;
1690
- }
1691
- }
1692
- else{
1693
- this.xLabelWidth = 0;
1694
- this.xScalePaddingRight = this.padding;
1695
- this.xScalePaddingLeft = this.padding;
1696
  }
 
 
 
1697
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1698
  },
1699
- // Needs to be overidden in each Chart type
1700
- // Otherwise we need to pass all the data into the scale class
1701
- calculateYRange: noop,
1702
- drawingArea: function(){
1703
- return this.startPoint - this.endPoint;
1704
- },
1705
- calculateY : function(value){
1706
- var scalingFactor = this.drawingArea() / (this.min - this.max);
1707
- return this.endPoint - (scalingFactor * (value - this.min));
1708
- },
1709
- calculateX : function(index){
1710
- var isRotated = (this.xLabelRotation > 0),
1711
- // innerWidth = (this.offsetGridLines) ? this.width - offsetLeft - this.padding : this.width - (offsetLeft + halfLabelWidth * 2) - this.padding,
1712
- innerWidth = this.width - (this.xScalePaddingLeft + this.xScalePaddingRight),
1713
- valueWidth = innerWidth/Math.max((this.valuesCount - ((this.offsetGridLines) ? 0 : 1)), 1),
1714
- valueOffset = (valueWidth * index) + this.xScalePaddingLeft;
1715
 
1716
- if (this.offsetGridLines){
1717
- valueOffset += (valueWidth/2);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1718
  }
1719
 
1720
- return Math.round(valueOffset);
 
1721
  },
1722
- update : function(newProps){
1723
- helpers.extend(this, newProps);
1724
- this.fit();
 
 
 
1725
  },
1726
- draw : function(){
1727
- var ctx = this.ctx,
1728
- yLabelGap = (this.endPoint - this.startPoint) / this.steps,
1729
- xStart = Math.round(this.xScalePaddingLeft);
1730
- if (this.display){
1731
- ctx.fillStyle = this.textColor;
1732
- ctx.font = this.font;
1733
- each(this.yLabels,function(labelString,index){
1734
- var yLabelCenter = this.endPoint - (yLabelGap * index),
1735
- linePositionY = Math.round(yLabelCenter),
1736
- drawHorizontalLine = this.showHorizontalLines;
1737
 
1738
- ctx.textAlign = "right";
1739
- ctx.textBaseline = "middle";
1740
- if (this.showLabels){
1741
- ctx.fillText(labelString,xStart - 10,yLabelCenter);
1742
- }
1743
 
1744
- // This is X axis, so draw it
1745
- if (index === 0 && !drawHorizontalLine){
1746
- drawHorizontalLine = true;
1747
- }
 
1748
 
1749
- if (drawHorizontalLine){
1750
- ctx.beginPath();
1751
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1752
 
1753
- if (index > 0){
1754
- // This is a grid line in the centre, so drop that
1755
- ctx.lineWidth = this.gridLineWidth;
1756
- ctx.strokeStyle = this.gridLineColor;
1757
- } else {
1758
- // This is the first line on the scale
1759
- ctx.lineWidth = this.lineWidth;
1760
- ctx.strokeStyle = this.lineColor;
1761
- }
1762
 
1763
- linePositionY += helpers.aliasPixel(ctx.lineWidth);
 
 
1764
 
1765
- if(drawHorizontalLine){
1766
- ctx.moveTo(xStart, linePositionY);
1767
- ctx.lineTo(this.width, linePositionY);
1768
- ctx.stroke();
1769
- ctx.closePath();
1770
- }
1771
 
1772
- ctx.lineWidth = this.lineWidth;
1773
- ctx.strokeStyle = this.lineColor;
1774
- ctx.beginPath();
1775
- ctx.moveTo(xStart - 5, linePositionY);
1776
- ctx.lineTo(xStart, linePositionY);
1777
- ctx.stroke();
1778
- ctx.closePath();
1779
-
1780
- },this);
1781
-
1782
- each(this.xLabels,function(label,index){
1783
- var xPos = this.calculateX(index) + aliasPixel(this.lineWidth),
1784
- // Check to see if line/bar here and decide where to place the line
1785
- linePos = this.calculateX(index - (this.offsetGridLines ? 0.5 : 0)) + aliasPixel(this.lineWidth),
1786
- isRotated = (this.xLabelRotation > 0),
1787
- drawVerticalLine = this.showVerticalLines;
1788
-
1789
- // This is Y axis, so draw it
1790
- if (index === 0 && !drawVerticalLine){
1791
- drawVerticalLine = true;
1792
- }
1793
 
1794
- if (drawVerticalLine){
1795
- ctx.beginPath();
1796
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1797
 
1798
- if (index > 0){
1799
- // This is a grid line in the centre, so drop that
1800
- ctx.lineWidth = this.gridLineWidth;
1801
- ctx.strokeStyle = this.gridLineColor;
1802
- } else {
1803
- // This is the first line on the scale
1804
- ctx.lineWidth = this.lineWidth;
1805
- ctx.strokeStyle = this.lineColor;
1806
- }
1807
 
1808
- if (drawVerticalLine){
1809
- ctx.moveTo(linePos,this.endPoint);
1810
- ctx.lineTo(linePos,this.startPoint - 3);
1811
- ctx.stroke();
1812
- ctx.closePath();
1813
- }
1814
 
 
1815
 
1816
- ctx.lineWidth = this.lineWidth;
1817
- ctx.strokeStyle = this.lineColor;
1818
 
 
 
1819
 
1820
- // Small lines at the bottom of the base grid line
1821
- ctx.beginPath();
1822
- ctx.moveTo(linePos,this.endPoint);
1823
- ctx.lineTo(linePos,this.endPoint + 5);
1824
- ctx.stroke();
1825
- ctx.closePath();
1826
 
1827
- ctx.save();
1828
- ctx.translate(xPos,(isRotated) ? this.endPoint + 12 : this.endPoint + 8);
1829
- ctx.rotate(toRadians(this.xLabelRotation)*-1);
1830
- ctx.font = this.font;
1831
- ctx.textAlign = (isRotated) ? "right" : "center";
1832
- ctx.textBaseline = (isRotated) ? "middle" : "top";
1833
- ctx.fillText(label, 0, 0);
1834
- ctx.restore();
1835
- },this);
1836
 
1837
- }
 
 
 
1838
  }
 
1839
 
1840
- });
1841
 
1842
- Chart.RadialScale = Chart.Element.extend({
1843
- initialize: function(){
1844
- this.size = min([this.height, this.width]);
1845
- this.drawingArea = (this.display) ? (this.size/2) - (this.fontSize/2 + this.backdropPaddingY) : (this.size/2);
1846
- },
1847
- calculateCenterOffset: function(value){
1848
- // Take into account half font size + the yPadding of the top value
1849
- var scalingFactor = this.drawingArea / (this.max - this.min);
 
1850
 
1851
- return (value - this.min) * scalingFactor;
1852
- },
1853
- update : function(){
1854
- if (!this.lineArc){
1855
- this.setScaleSize();
1856
- } else {
1857
- this.drawingArea = (this.display) ? (this.size/2) - (this.fontSize/2 + this.backdropPaddingY) : (this.size/2);
1858
- }
1859
- this.buildYLabels();
1860
- },
1861
- buildYLabels: function(){
1862
- this.yLabels = [];
1863
-
1864
- var stepDecimalPlaces = getDecimalPlaces(this.stepValue);
1865
-
1866
- for (var i=0; i<=this.steps; i++){
1867
- this.yLabels.push(template(this.templateString,{value:(this.min + (i * this.stepValue)).toFixed(stepDecimalPlaces)}));
1868
- }
1869
- },
1870
- getCircumference : function(){
1871
- return ((Math.PI*2) / this.valuesCount);
1872
- },
1873
- setScaleSize: function(){
1874
- /*
1875
- * Right, this is really confusing and there is a lot of maths going on here
1876
- * The gist of the problem is here: https://gist.github.com/nnnick/696cc9c55f4b0beb8fe9
1877
- *
1878
- * Reaction: https://dl.dropboxusercontent.com/u/34601363/toomuchscience.gif
1879
- *
1880
- * Solution:
1881
- *
1882
- * We assume the radius of the polygon is half the size of the canvas at first
1883
- * at each index we check if the text overlaps.
1884
- *
1885
- * Where it does, we store that angle and that index.
1886
- *
1887
- * After finding the largest index and angle we calculate how much we need to remove
1888
- * from the shape radius to move the point inwards by that x.
1889
- *
1890
- * We average the left and right distances to get the maximum shape radius that can fit in the box
1891
- * along with labels.
1892
- *
1893
- * Once we have that, we can find the centre point for the chart, by taking the x text protrusion
1894
- * on each side, removing that from the size, halving it and adding the left x protrusion width.
1895
- *
1896
- * This will mean we have a shape fitted to the canvas, as large as it can be with the labels
1897
- * and position it in the most space efficient manner
1898
- *
1899
- * https://dl.dropboxusercontent.com/u/34601363/yeahscience.gif
1900
- */
1901
 
 
 
 
1902
 
1903
- // Get maximum radius of the polygon. Either half the height (minus the text width) or half the width.
1904
- // Use this to calculate the offset + change. - Make sure L/R protrusion is at least 0 to stop issues with centre points
1905
- var largestPossibleRadius = min([(this.height/2 - this.pointLabelFontSize - 5), this.width/2]),
1906
- pointPosition,
1907
- i,
1908
- textWidth,
1909
- halfTextWidth,
1910
- furthestRight = this.width,
1911
- furthestRightIndex,
1912
- furthestRightAngle,
1913
- furthestLeft = 0,
1914
- furthestLeftIndex,
1915
- furthestLeftAngle,
1916
- xProtrusionLeft,
1917
- xProtrusionRight,
1918
- radiusReductionRight,
1919
- radiusReductionLeft,
1920
- maxWidthRadius;
1921
- this.ctx.font = fontString(this.pointLabelFontSize,this.pointLabelFontStyle,this.pointLabelFontFamily);
1922
- for (i=0;i<this.valuesCount;i++){
1923
- // 5px to space the text slightly out - similar to what we do in the draw function.
1924
- pointPosition = this.getPointPosition(i, largestPossibleRadius);
1925
- textWidth = this.ctx.measureText(template(this.templateString, { value: this.labels[i] })).width + 5;
1926
- if (i === 0 || i === this.valuesCount/2){
1927
- // If we're at index zero, or exactly the middle, we're at exactly the top/bottom
1928
- // of the radar chart, so text will be aligned centrally, so we'll half it and compare
1929
- // w/left and right text sizes
1930
- halfTextWidth = textWidth/2;
1931
- if (pointPosition.x + halfTextWidth > furthestRight) {
1932
- furthestRight = pointPosition.x + halfTextWidth;
1933
- furthestRightIndex = i;
1934
- }
1935
- if (pointPosition.x - halfTextWidth < furthestLeft) {
1936
- furthestLeft = pointPosition.x - halfTextWidth;
1937
- furthestLeftIndex = i;
1938
  }
1939
- }
1940
- else if (i < this.valuesCount/2) {
1941
- // Less than half the values means we'll left align the text
1942
- if (pointPosition.x + textWidth > furthestRight) {
1943
- furthestRight = pointPosition.x + textWidth;
1944
- furthestRightIndex = i;
1945
- }
1946
- }
1947
- else if (i > this.valuesCount/2){
1948
- // More than half the values means we'll right align the text
1949
- if (pointPosition.x - textWidth < furthestLeft) {
1950
- furthestLeft = pointPosition.x - textWidth;
1951
- furthestLeftIndex = i;
1952
  }
1953
- }
1954
  }
1955
 
1956
- xProtrusionLeft = furthestLeft;
1957
-
1958
- xProtrusionRight = Math.ceil(furthestRight - this.width);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1959
 
1960
- furthestRightAngle = this.getIndexAngle(furthestRightIndex);
 
 
1961
 
1962
- furthestLeftAngle = this.getIndexAngle(furthestLeftIndex);
 
 
 
 
 
1963
 
1964
- radiusReductionRight = xProtrusionRight / Math.sin(furthestRightAngle + Math.PI/2);
 
1965
 
1966
- radiusReductionLeft = xProtrusionLeft / Math.sin(furthestLeftAngle + Math.PI/2);
 
 
 
 
 
 
 
 
 
1967
 
1968
- // Ensure we actually need to reduce the size of the chart
1969
- radiusReductionRight = (isNumber(radiusReductionRight)) ? radiusReductionRight : 0;
1970
- radiusReductionLeft = (isNumber(radiusReductionLeft)) ? radiusReductionLeft : 0;
 
 
 
 
1971
 
1972
- this.drawingArea = largestPossibleRadius - (radiusReductionLeft + radiusReductionRight)/2;
 
 
 
 
 
 
 
 
1973
 
1974
- //this.drawingArea = min([maxWidthRadius, (this.height - (2 * (this.pointLabelFontSize + 5)))/2])
1975
- this.setCenterPoint(radiusReductionLeft, radiusReductionRight);
 
 
 
1976
 
1977
- },
1978
- setCenterPoint: function(leftMovement, rightMovement){
 
 
 
 
 
 
 
1979
 
1980
- var maxRight = this.width - rightMovement - this.drawingArea,
1981
- maxLeft = leftMovement + this.drawingArea;
1982
 
1983
- this.xCenter = (maxLeft + maxRight)/2;
1984
- // Always vertically in the centre as the text height doesn't change
1985
- this.yCenter = (this.height/2);
1986
  },
 
 
 
 
1987
 
1988
- getIndexAngle : function(index){
1989
- var angleMultiplier = (Math.PI * 2) / this.valuesCount;
1990
- // Start from the top instead of right, so remove a quarter of the circle
 
 
 
 
1991
 
1992
- return index * angleMultiplier - (Math.PI/2);
1993
  },
1994
- getPointPosition : function(index, distanceFromCenter){
1995
- var thisAngle = this.getIndexAngle(index);
1996
- return {
1997
- x : (Math.cos(thisAngle) * distanceFromCenter) + this.xCenter,
1998
- y : (Math.sin(thisAngle) * distanceFromCenter) + this.yCenter
1999
- };
 
 
 
2000
  },
2001
- draw: function(){
2002
- if (this.display){
2003
- var ctx = this.ctx;
2004
- each(this.yLabels, function(label, index){
2005
- // Don't draw a centre value
2006
- if (index > 0){
2007
- var yCenterOffset = index * (this.drawingArea/this.steps),
2008
- yHeight = this.yCenter - yCenterOffset,
2009
- pointPosition;
 
 
 
 
 
 
2010
 
2011
- // Draw circular lines around the scale
2012
- if (this.lineWidth > 0){
2013
- ctx.strokeStyle = this.lineColor;
2014
- ctx.lineWidth = this.lineWidth;
2015
-
2016
- if(this.lineArc){
2017
- ctx.beginPath();
2018
- ctx.arc(this.xCenter, this.yCenter, yCenterOffset, 0, Math.PI*2);
2019
- ctx.closePath();
2020
- ctx.stroke();
2021
- } else{
2022
- ctx.beginPath();
2023
- for (var i=0;i<this.valuesCount;i++)
2024
- {
2025
- pointPosition = this.getPointPosition(i, this.calculateCenterOffset(this.min + (index * this.stepValue)));
2026
- if (i === 0){
2027
- ctx.moveTo(pointPosition.x, pointPosition.y);
2028
- } else {
2029
- ctx.lineTo(pointPosition.x, pointPosition.y);
2030
- }
2031
- }
2032
- ctx.closePath();
2033
- ctx.stroke();
2034
- }
2035
- }
2036
- if(this.showLabels){
2037
- ctx.font = fontString(this.fontSize,this.fontStyle,this.fontFamily);
2038
- if (this.showLabelBackdrop){
2039
- var labelWidth = ctx.measureText(label).width;
2040
- ctx.fillStyle = this.backdropColor;
2041
- ctx.fillRect(
2042
- this.xCenter - labelWidth/2 - this.backdropPaddingX,
2043
- yHeight - this.fontSize/2 - this.backdropPaddingY,
2044
- labelWidth + this.backdropPaddingX*2,
2045
- this.fontSize + this.backdropPaddingY*2
2046
- );
2047
- }
2048
- ctx.textAlign = 'center';
2049
- ctx.textBaseline = "middle";
2050
- ctx.fillStyle = this.fontColor;
2051
- ctx.fillText(label, this.xCenter, yHeight);
2052
- }
2053
- }
2054
- }, this);
2055
-
2056
- if (!this.lineArc){
2057
- ctx.lineWidth = this.angleLineWidth;
2058
- ctx.strokeStyle = this.angleLineColor;
2059
- for (var i = this.valuesCount - 1; i >= 0; i--) {
2060
- var centerOffset = null, outerPosition = null;
2061
-
2062
- if (this.angleLineWidth > 0){
2063
- centerOffset = this.calculateCenterOffset(this.max);
2064
- outerPosition = this.getPointPosition(i, centerOffset);
2065
- ctx.beginPath();
2066
- ctx.moveTo(this.xCenter, this.yCenter);
2067
- ctx.lineTo(outerPosition.x, outerPosition.y);
2068
- ctx.stroke();
2069
- ctx.closePath();
2070
- }
2071
 
2072
- if (this.backgroundColors && this.backgroundColors.length == this.valuesCount) {
2073
- if (centerOffset == null)
2074
- centerOffset = this.calculateCenterOffset(this.max);
2075
 
2076
- if (outerPosition == null)
2077
- outerPosition = this.getPointPosition(i, centerOffset);
2078
 
2079
- var previousOuterPosition = this.getPointPosition(i === 0 ? this.valuesCount - 1 : i - 1, centerOffset);
2080
- var nextOuterPosition = this.getPointPosition(i === this.valuesCount - 1 ? 0 : i + 1, centerOffset);
2081
 
2082
- var previousOuterHalfway = { x: (previousOuterPosition.x + outerPosition.x) / 2, y: (previousOuterPosition.y + outerPosition.y) / 2 };
2083
- var nextOuterHalfway = { x: (outerPosition.x + nextOuterPosition.x) / 2, y: (outerPosition.y + nextOuterPosition.y) / 2 };
2084
 
2085
- ctx.beginPath();
2086
- ctx.moveTo(this.xCenter, this.yCenter);
2087
- ctx.lineTo(previousOuterHalfway.x, previousOuterHalfway.y);
2088
- ctx.lineTo(outerPosition.x, outerPosition.y);
2089
- ctx.lineTo(nextOuterHalfway.x, nextOuterHalfway.y);
2090
- ctx.fillStyle = this.backgroundColors[i];
2091
- ctx.fill();
2092
- ctx.closePath();
2093
- }
2094
- // Extra 3px out for some label spacing
2095
- var pointLabelPosition = this.getPointPosition(i, this.calculateCenterOffset(this.max) + 5);
2096
- ctx.font = fontString(this.pointLabelFontSize,this.pointLabelFontStyle,this.pointLabelFontFamily);
2097
- ctx.fillStyle = this.pointLabelFontColor;
2098
-
2099
- var labelsCount = this.labels.length,
2100
- halfLabelsCount = this.labels.length/2,
2101
- quarterLabelsCount = halfLabelsCount/2,
2102
- upperHalf = (i < quarterLabelsCount || i > labelsCount - quarterLabelsCount),
2103
- exactQuarter = (i === quarterLabelsCount || i === labelsCount - quarterLabelsCount);
2104
- if (i === 0){
2105
- ctx.textAlign = 'center';
2106
- } else if(i === halfLabelsCount){
2107
- ctx.textAlign = 'center';
2108
- } else if (i < halfLabelsCount){
2109
- ctx.textAlign = 'left';
2110
- } else {
2111
- ctx.textAlign = 'right';
2112
- }
2113
 
2114
- // Set the correct text baseline based on outer positioning
2115
- if (exactQuarter){
2116
- ctx.textBaseline = 'middle';
2117
- } else if (upperHalf){
2118
- ctx.textBaseline = 'bottom';
2119
- } else {
2120
- ctx.textBaseline = 'top';
2121
- }
2122
 
2123
- ctx.fillText(this.labels[i], pointLabelPosition.x, pointLabelPosition.y);
2124
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2125
  }
2126
  }
2127
- }
2128
- });
2129
 
2130
- Chart.animationService = {
2131
- frameDuration: 17,
2132
- animations: [],
2133
- dropFrames: 0,
2134
- addAnimation: function(chartInstance, animationObject) {
2135
- for (var index = 0; index < this.animations.length; ++ index){
2136
- if (this.animations[index].chartInstance === chartInstance){
2137
- // replacing an in progress animation
2138
- this.animations[index].animationObject = animationObject;
2139
- return;
2140
  }
2141
  }
2142
-
2143
- this.animations.push({
2144
- chartInstance: chartInstance,
2145
- animationObject: animationObject
2146
- });
2147
 
2148
- // If there are no animations queued, manually kickstart a digest, for lack of a better word
2149
- if (this.animations.length == 1) {
2150
- helpers.requestAnimFrame.call(window, this.digestWrapper);
2151
- }
2152
- },
2153
- // Cancel the animation for a given chart instance
2154
- cancelAnimation: function(chartInstance) {
2155
- var index = helpers.findNextWhere(this.animations, function(animationWrapper) {
2156
- return animationWrapper.chartInstance === chartInstance;
2157
- });
2158
-
2159
- if (index)
2160
- {
2161
- this.animations.splice(index, 1);
2162
  }
2163
- },
2164
- // calls startDigest with the proper context
2165
- digestWrapper: function() {
2166
- Chart.animationService.startDigest.call(Chart.animationService);
2167
- },
2168
- startDigest: function() {
2169
-
2170
- var startTime = Date.now();
2171
- var framesToDrop = 0;
2172
 
2173
- if(this.dropFrames > 1){
2174
- framesToDrop = Math.floor(this.dropFrames);
2175
- this.dropFrames -= framesToDrop;
 
 
 
 
 
 
 
 
 
2176
  }
2177
 
2178
- for (var i = 0; i < this.animations.length; i++) {
2179
-
2180
- if (this.animations[i].animationObject.currentStep === null){
2181
- this.animations[i].animationObject.currentStep = 0;
2182
- }
2183
 
2184
- this.animations[i].animationObject.currentStep += 1 + framesToDrop;
2185
- if(this.animations[i].animationObject.currentStep > this.animations[i].animationObject.numSteps){
2186
- this.animations[i].animationObject.currentStep = this.animations[i].animationObject.numSteps;
2187
- }
2188
-
2189
- this.animations[i].animationObject.render(this.animations[i].chartInstance, this.animations[i].animationObject);
2190
-
2191
- // Check if executed the last frame.
2192
- if (this.animations[i].animationObject.currentStep == this.animations[i].animationObject.numSteps){
2193
- // Call onAnimationComplete
2194
- this.animations[i].animationObject.onAnimationComplete.call(this.animations[i].chartInstance);
2195
- // Remove the animation.
2196
- this.animations.splice(i, 1);
2197
- // Keep the index in place to offset the splice
2198
- i--;
2199
  }
2200
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2201
 
2202
- var endTime = Date.now();
2203
- var delay = endTime - startTime - this.frameDuration;
2204
- var frameDelay = delay / this.frameDuration;
2205
 
2206
- if(frameDelay > 1){
2207
- this.dropFrames += frameDelay;
2208
- }
 
2209
 
2210
- // Do we have more stuff to animate?
2211
- if (this.animations.length > 0){
2212
- helpers.requestAnimFrame.call(window, this.digestWrapper);
 
 
 
 
 
2213
  }
 
 
 
 
 
 
 
2214
  }
2215
- };
 
2216
 
2217
- // Attach global event to resize each chart instance when the browser resizes
2218
- helpers.addEvent(window, "resize", (function(){
2219
- // Basic debounce of resize function so it doesn't hurt performance when resizing browser.
2220
- var timeout;
2221
- return function(){
2222
- clearTimeout(timeout);
2223
- timeout = setTimeout(function(){
2224
- each(Chart.instances,function(instance){
2225
- // If the responsive flag is set in the chart instance config
2226
- // Cascade the resize event down to the chart.
2227
- if (instance.options.responsive){
2228
- instance.resize(instance.render, true);
2229
- }
2230
- });
2231
- }, 50);
2232
- };
2233
- })());
2234
 
 
 
2235
 
2236
- if (amd) {
2237
- define('Chart', [], function(){
2238
- return Chart;
2239
- });
2240
- } else if (typeof module === 'object' && module.exports) {
2241
- module.exports = Chart;
2242
- }
2243
 
2244
- root.Chart = Chart;
 
2245
 
2246
- Chart.noConflict = function(){
2247
- root.Chart = previous;
2248
- return Chart;
 
2249
  };
2250
 
2251
- }).call(this);
2252
-
2253
- (function(){
2254
- "use strict";
2255
-
2256
- var root = this,
2257
- Chart = root.Chart,
2258
- helpers = Chart.helpers;
 
 
 
 
 
2259
 
 
 
 
 
2260
 
2261
- var defaultConfig = {
2262
- //Boolean - Whether the scale should start at zero, or an order of magnitude down from the lowest value
2263
- scaleBeginAtZero : true,
 
 
 
2264
 
2265
- //Boolean - Whether grid lines are shown across the chart
2266
- scaleShowGridLines : true,
 
 
 
 
 
2267
 
2268
- //String - Colour of the grid lines
2269
- scaleGridLineColor : "rgba(0,0,0,.05)",
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2270
 
2271
- //Number - Width of the grid lines
2272
- scaleGridLineWidth : 1,
 
 
 
 
2273
 
2274
- //Boolean - Whether to show horizontal lines (except X axis)
2275
- scaleShowHorizontalLines: true,
2276
 
2277
- //Boolean - Whether to show vertical lines (except Y axis)
2278
- scaleShowVerticalLines: true,
 
 
 
 
 
 
 
2279
 
2280
- //Boolean - If there is a stroke on each bar
2281
- barShowStroke : true,
 
 
 
 
2282
 
2283
- //Number - Pixel width of the bar stroke
2284
- barStrokeWidth : 2,
 
 
 
 
 
 
 
2285
 
2286
- //Number - Spacing between each of the X value sets
2287
- barValueSpacing : 5,
 
 
 
2288
 
2289
- //Number - Spacing between data sets within X values
2290
- barDatasetSpacing : 1,
 
 
 
2291
 
2292
- //String - A legend template
2293
- legendTemplate : "<ul class=\"<%=name.toLowerCase()%>-legend\"><% for (var i=0; i<datasets.length; i++){%><li><span style=\"background-color:<%=datasets[i].fillColor%>\"><%if(datasets[i].label){%><%=datasets[i].label%><%}%></span></li><%}%></ul>"
 
 
 
 
 
2294
 
2295
- };
 
2296
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2297
 
2298
- Chart.Type.extend({
2299
- name: "Bar",
2300
- defaults : defaultConfig,
2301
- initialize: function(data){
2302
 
2303
- //Expose options as a scope variable here so we can access it in the ScaleClass
2304
- var options = this.options;
 
 
2305
 
2306
- this.ScaleClass = Chart.Scale.extend({
2307
- offsetGridLines : true,
2308
- calculateBarX : function(datasetCount, datasetIndex, barIndex){
2309
- //Reusable method for calculating the xPosition of a given bar based on datasetIndex & width of the bar
2310
- var xWidth = this.calculateBaseWidth(),
2311
- xAbsolute = this.calculateX(barIndex) - (xWidth/2),
2312
- barWidth = this.calculateBarWidth(datasetCount);
2313
 
2314
- return xAbsolute + (barWidth * datasetIndex) + (datasetIndex * options.barDatasetSpacing) + barWidth/2;
2315
- },
2316
- calculateBaseWidth : function(){
2317
- return (this.calculateX(1) - this.calculateX(0)) - (2*options.barValueSpacing);
2318
- },
2319
- calculateBarWidth : function(datasetCount){
2320
- //The padding between datasets is to the right of each bar, providing that there are more than 1 dataset
2321
- var baseWidth = this.calculateBaseWidth() - ((datasetCount - 1) * options.barDatasetSpacing);
 
2322
 
2323
- return (baseWidth / datasetCount);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2324
  }
2325
- });
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2326
 
2327
- this.datasets = [];
2328
 
2329
- //Set up tooltip events on the chart
2330
- if (this.options.showTooltips){
2331
- helpers.bindEvents(this, this.options.tooltipEvents, function(evt){
2332
- var activeBars = (evt.type !== 'mouseout') ? this.getBarsAtEvent(evt) : [];
2333
 
2334
- this.eachBars(function(bar){
2335
- bar.restore(['fillColor', 'strokeColor']);
2336
- });
2337
- helpers.each(activeBars, function(activeBar){
2338
- activeBar.fillColor = activeBar.highlightFill;
2339
- activeBar.strokeColor = activeBar.highlightStroke;
2340
- });
2341
- this.showTooltip(activeBars);
2342
- });
2343
- }
2344
 
2345
- //Declare the extension of the default point, to cater for the options passed in to the constructor
2346
- this.BarClass = Chart.Rectangle.extend({
2347
- strokeWidth : this.options.barStrokeWidth,
2348
- showStroke : this.options.barShowStroke,
2349
- ctx : this.chart.ctx
2350
- });
2351
 
2352
- //Iterate through each of the datasets, and build this into a property of the chart
2353
- helpers.each(data.datasets,function(dataset,datasetIndex){
2354
 
2355
- var datasetObject = {
2356
- label : dataset.label || null,
2357
- fillColor : dataset.fillColor,
2358
- strokeColor : dataset.strokeColor,
2359
- bars : []
2360
- };
2361
 
2362
- this.datasets.push(datasetObject);
 
 
 
 
 
 
 
 
2363
 
2364
- helpers.each(dataset.data,function(dataPoint,index){
2365
- //Add a new point for each piece of data, passing any required data to draw.
2366
- datasetObject.bars.push(new this.BarClass({
2367
- value : dataPoint,
2368
- label : data.labels[index],
2369
- datasetLabel: dataset.label,
2370
- strokeColor : (typeof dataset.strokeColor != 'string') ? dataset.strokeColor[index] : dataset.strokeColor,
2371
- fillColor : (typeof dataset.fillColor != 'string') ? dataset.fillColor[index] : dataset.fillColor,
2372
- highlightFill : (dataset.highlightFill && typeof dataset.highlightFill != 'string') ? dataset.highlightFill[index] || dataset.highlightFill : (typeof dataset.fillColor != 'string') ? dataset.fillColor[index] : dataset.fillColor,
2373
- highlightStroke : (dataset.highlightStroke && typeof dataset.highlightStroke != 'string') ? dataset.highlightStroke[index] || dataset.highlightStroke : (typeof dataset.strokeColor != 'string') ? dataset.strokeColor[index] : dataset.strokeColor
2374
- }));
2375
- },this);
2376
 
2377
- },this);
 
 
 
2378
 
2379
- this.buildScale(data.labels);
 
2380
 
2381
- this.BarClass.prototype.base = this.scale.endPoint;
 
2382
 
2383
- this.eachBars(function(bar, index, datasetIndex){
2384
- helpers.extend(bar, {
2385
- width : this.scale.calculateBarWidth(this.datasets.length),
2386
- x: this.scale.calculateBarX(this.datasets.length, datasetIndex, index),
2387
- y: this.scale.endPoint
2388
- });
2389
- bar.save();
2390
- }, this);
2391
 
2392
- this.render();
2393
  },
2394
- update : function(){
2395
- this.scale.update();
2396
- // Reset any highlight colours before updating.
2397
- helpers.each(this.activeElements, function(activeElement){
2398
- activeElement.restore(['fillColor', 'strokeColor']);
2399
- });
2400
 
2401
- this.eachBars(function(bar){
2402
- bar.save();
2403
- });
2404
- this.render();
2405
- },
2406
- eachBars : function(callback){
2407
- helpers.each(this.datasets,function(dataset, datasetIndex){
2408
- helpers.each(dataset.bars, callback, this, datasetIndex);
2409
- },this);
2410
- },
2411
- getBarsAtEvent : function(e){
2412
- var barsArray = [],
2413
- eventPosition = helpers.getRelativePosition(e),
2414
- datasetIterator = function(dataset){
2415
- barsArray.push(dataset.bars[barIndex]);
2416
- },
2417
- barIndex;
2418
 
2419
- for (var datasetIndex = 0; datasetIndex < this.datasets.length; datasetIndex++) {
2420
- for (barIndex = 0; barIndex < this.datasets[datasetIndex].bars.length; barIndex++) {
2421
- if (this.datasets[datasetIndex].bars[barIndex].inRange(eventPosition.x,eventPosition.y)){
2422
- helpers.each(this.datasets, datasetIterator);
2423
- return barsArray;
2424
- }
2425
- }
2426
  }
 
 
2427
 
2428
- return barsArray;
2429
- },
2430
- buildScale : function(labels){
2431
- var self = this;
2432
 
2433
- var dataTotal = function(){
2434
- var values = [];
2435
- self.eachBars(function(bar){
2436
- values.push(bar.value);
2437
- });
2438
- return values;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2439
  };
 
2440
 
2441
- var scaleOptions = {
2442
- templateString : this.options.scaleLabel,
2443
- height : this.chart.height,
2444
- width : this.chart.width,
2445
- ctx : this.chart.ctx,
2446
- textColor : this.options.scaleFontColor,
2447
- fontSize : this.options.scaleFontSize,
2448
- fontStyle : this.options.scaleFontStyle,
2449
- fontFamily : this.options.scaleFontFamily,
2450
- valuesCount : labels.length,
2451
- beginAtZero : this.options.scaleBeginAtZero,
2452
- integersOnly : this.options.scaleIntegersOnly,
2453
- calculateYRange: function(currentHeight){
2454
- var updatedRanges = helpers.calculateScaleRange(
2455
- dataTotal(),
2456
- currentHeight,
2457
- this.fontSize,
2458
- this.beginAtZero,
2459
- this.integersOnly
2460
- );
2461
- helpers.extend(this, updatedRanges);
2462
- },
2463
- xLabels : labels,
2464
- font : helpers.fontString(this.options.scaleFontSize, this.options.scaleFontStyle, this.options.scaleFontFamily),
2465
- lineWidth : this.options.scaleLineWidth,
2466
- lineColor : this.options.scaleLineColor,
2467
- showHorizontalLines : this.options.scaleShowHorizontalLines,
2468
- showVerticalLines : this.options.scaleShowVerticalLines,
2469
- gridLineWidth : (this.options.scaleShowGridLines) ? this.options.scaleGridLineWidth : 0,
2470
- gridLineColor : (this.options.scaleShowGridLines) ? this.options.scaleGridLineColor : "rgba(0,0,0,0)",
2471
- padding : (this.options.showScale) ? 0 : (this.options.barShowStroke) ? this.options.barStrokeWidth : 0,
2472
- showLabels : this.options.scaleShowLabels,
2473
- display : this.options.showScale
2474
  };
 
 
 
 
 
 
2475
 
2476
- if (this.options.scaleOverride){
2477
- helpers.extend(scaleOptions, {
2478
- calculateYRange: helpers.noop,
2479
- steps: this.options.scaleSteps,
2480
- stepValue: this.options.scaleStepWidth,
2481
- min: this.options.scaleStartValue,
2482
- max: this.options.scaleStartValue + (this.options.scaleSteps * this.options.scaleStepWidth)
2483
- });
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2484
  }
2485
 
2486
- this.scale = new this.ScaleClass(scaleOptions);
2487
- },
2488
- addData : function(valuesArray,label){
2489
- //Map the values array for each of the datasets
2490
- helpers.each(valuesArray,function(value,datasetIndex){
2491
- //Add a new point for each piece of data, passing any required data to draw.
2492
- this.datasets[datasetIndex].bars.push(new this.BarClass({
2493
- value : value,
2494
- label : label,
2495
- datasetLabel: this.datasets[datasetIndex].label,
2496
- x: this.scale.calculateBarX(this.datasets.length, datasetIndex, this.scale.valuesCount+1),
2497
- y: this.scale.endPoint,
2498
- width : this.scale.calculateBarWidth(this.datasets.length),
2499
- base : this.scale.endPoint,
2500
- strokeColor : this.datasets[datasetIndex].strokeColor,
2501
- fillColor : this.datasets[datasetIndex].fillColor
2502
- }));
2503
- },this);
2504
-
2505
- this.scale.addXLabel(label);
2506
- //Then re-render the chart.
2507
- this.update();
2508
- },
2509
- removeData : function(){
2510
- this.scale.removeXLabel();
2511
- //Then re-render the chart.
2512
- helpers.each(this.datasets,function(dataset){
2513
- dataset.bars.shift();
2514
- },this);
2515
- this.update();
2516
- },
2517
- reflow : function(){
2518
- helpers.extend(this.BarClass.prototype,{
2519
- y: this.scale.endPoint,
2520
- base : this.scale.endPoint
2521
- });
2522
- var newScaleProps = helpers.extend({
2523
- height : this.chart.height,
2524
- width : this.chart.width
2525
- });
2526
- this.scale.update(newScaleProps);
2527
- },
2528
- draw : function(ease){
2529
- var easingDecimal = ease || 1;
2530
- this.clear();
2531
-
2532
- var ctx = this.chart.ctx;
2533
-
2534
- this.scale.draw(easingDecimal);
2535
-
2536
- //Draw all the bars for each dataset
2537
- helpers.each(this.datasets,function(dataset,datasetIndex){
2538
- helpers.each(dataset.bars,function(bar,index){
2539
- if (bar.hasValue()){
2540
- bar.base = this.scale.endPoint;
2541
- //Transition then draw
2542
- bar.transition({
2543
- x : this.scale.calculateBarX(this.datasets.length, datasetIndex, index),
2544
- y : this.scale.calculateY(bar.value),
2545
- width : this.scale.calculateBarWidth(this.datasets.length)
2546
- }, easingDecimal).draw();
2547
- }
2548
- },this);
2549
 
2550
- },this);
 
 
 
 
 
 
 
 
2551
  }
2552
- });
2553
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2554
 
2555
- }).call(this);
 
2556
 
2557
- (function(){
2558
- "use strict";
 
 
2559
 
2560
- var root = this,
2561
- Chart = root.Chart,
2562
- //Cache a local reference to Chart.helpers
2563
- helpers = Chart.helpers;
 
 
 
 
2564
 
2565
- var defaultConfig = {
2566
- //Boolean - Whether we should show a stroke on each segment
2567
- segmentShowStroke : true,
 
 
 
 
2568
 
2569
- //String - The colour of each segment stroke
2570
- segmentStrokeColor : "#fff",
 
 
 
 
2571
 
2572
- //Number - The width of each segment stroke
2573
- segmentStrokeWidth : 2,
2574
 
2575
- //The percentage of the chart that we cut out of the middle.
2576
- percentageInnerCutout : 50,
2577
 
2578
- //Number - Amount of animation steps
2579
- animationSteps : 100,
2580
 
2581
- //String - Animation easing effect
2582
- animationEasing : "easeOutBounce",
2583
 
2584
- //Boolean - Whether we animate the rotation of the Doughnut
2585
- animateRotate : true,
 
 
 
 
 
 
 
2586
 
2587
- //Boolean - Whether we animate scaling the Doughnut from the centre
2588
- animateScale : false,
 
2589
 
2590
- //String - A legend template
2591
- legendTemplate : "<ul class=\"<%=name.toLowerCase()%>-legend\"><% for (var i=0; i<segments.length; i++){%><li><span style=\"background-color:<%=segments[i].fillColor%>\"><%if(segments[i].label){%><%=segments[i].label%><%}%></span></li><%}%></ul>"
 
 
2592
 
2593
- };
 
 
 
 
 
 
 
2594
 
2595
- Chart.Type.extend({
2596
- //Passing in a name registers this chart in the Chart namespace
2597
- name: "Doughnut",
2598
- //Providing a defaults will also register the deafults in the chart namespace
2599
- defaults : defaultConfig,
2600
- //Initialize is fired when the chart is initialized - Data is passed in as a parameter
2601
- //Config is automatically merged by the core of Chart.js, and is available at this.options
2602
- initialize: function(data){
2603
 
2604
- //Declare segments as a static property to prevent inheriting across the Chart type prototype
2605
- this.segments = [];
2606
- this.outerRadius = (helpers.min([this.chart.width,this.chart.height]) - this.options.segmentStrokeWidth/2)/2;
 
 
 
 
 
 
2607
 
2608
- this.SegmentArc = Chart.Arc.extend({
2609
- ctx : this.chart.ctx,
2610
- x : this.chart.width/2,
2611
- y : this.chart.height/2
2612
- });
2613
 
2614
- //Set up tooltip events on the chart
2615
- if (this.options.showTooltips){
2616
- helpers.bindEvents(this, this.options.tooltipEvents, function(evt){
2617
- var activeSegments = (evt.type !== 'mouseout') ? this.getSegmentsAtEvent(evt) : [];
2618
 
2619
- helpers.each(this.segments,function(segment){
2620
- segment.restore(["fillColor"]);
2621
- });
2622
- helpers.each(activeSegments,function(activeSegment){
2623
- activeSegment.fillColor = activeSegment.highlightColor;
2624
- });
2625
- this.showTooltip(activeSegments);
2626
- });
2627
- }
2628
- this.calculateTotal(data);
2629
-
2630
- helpers.each(data,function(datapoint, index){
2631
- if (!datapoint.color) {
2632
- datapoint.color = 'hsl(' + (360 * index / data.length) + ', 100%, 50%)';
2633
- }
2634
- this.addData(datapoint, index, true);
2635
- },this);
2636
-
2637
- this.render();
2638
- },
2639
- getSegmentsAtEvent : function(e){
2640
- var segmentsArray = [];
2641
-
2642
- var location = helpers.getRelativePosition(e);
2643
-
2644
- helpers.each(this.segments,function(segment){
2645
- if (segment.inRange(location.x,location.y)) segmentsArray.push(segment);
2646
- },this);
2647
- return segmentsArray;
2648
- },
2649
- addData : function(segment, atIndex, silent){
2650
- var index = atIndex !== undefined ? atIndex : this.segments.length;
2651
- if ( typeof(segment.color) === "undefined" ) {
2652
- segment.color = Chart.defaults.global.segmentColorDefault[index % Chart.defaults.global.segmentColorDefault.length];
2653
- segment.highlight = Chart.defaults.global.segmentHighlightColorDefaults[index % Chart.defaults.global.segmentHighlightColorDefaults.length];
2654
- }
2655
- this.segments.splice(index, 0, new this.SegmentArc({
2656
- value : segment.value,
2657
- outerRadius : (this.options.animateScale) ? 0 : this.outerRadius,
2658
- innerRadius : (this.options.animateScale) ? 0 : (this.outerRadius/100) * this.options.percentageInnerCutout,
2659
- fillColor : segment.color,
2660
- highlightColor : segment.highlight || segment.color,
2661
- showStroke : this.options.segmentShowStroke,
2662
- strokeWidth : this.options.segmentStrokeWidth,
2663
- strokeColor : this.options.segmentStrokeColor,
2664
- startAngle : Math.PI * 1.5,
2665
- circumference : (this.options.animateRotate) ? 0 : this.calculateCircumference(segment.value),
2666
- label : segment.label
2667
- }));
2668
- if (!silent){
2669
- this.reflow();
2670
- this.update();
2671
- }
2672
- },
2673
- calculateCircumference : function(value) {
2674
- if ( this.total > 0 ) {
2675
- return (Math.PI*2)*(value / this.total);
2676
- } else {
2677
- return 0;
2678
  }
2679
- },
2680
- calculateTotal : function(data){
2681
- this.total = 0;
2682
- helpers.each(data,function(segment){
2683
- this.total += Math.abs(segment.value);
2684
- },this);
2685
- },
2686
- update : function(){
2687
- this.calculateTotal(this.segments);
2688
 
2689
- // Reset any highlight colours before updating.
2690
- helpers.each(this.activeElements, function(activeElement){
2691
- activeElement.restore(['fillColor']);
2692
- });
2693
 
2694
- helpers.each(this.segments,function(segment){
2695
- segment.save();
2696
- });
2697
- this.render();
2698
- },
2699
 
2700
- removeData: function(atIndex){
2701
- var indexToDelete = (helpers.isNumber(atIndex)) ? atIndex : this.segments.length-1;
2702
- this.segments.splice(indexToDelete, 1);
2703
- this.reflow();
2704
- this.update();
 
 
 
 
 
 
 
 
 
2705
  },
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2706
 
2707
- reflow : function(){
2708
- helpers.extend(this.SegmentArc.prototype,{
2709
- x : this.chart.width/2,
2710
- y : this.chart.height/2
2711
  });
2712
- this.outerRadius = (helpers.min([this.chart.width,this.chart.height]) - this.options.segmentStrokeWidth/2)/2;
2713
- helpers.each(this.segments, function(segment){
2714
- segment.update({
2715
- outerRadius : this.outerRadius,
2716
- innerRadius : (this.outerRadius/100) * this.options.percentageInnerCutout
2717
- });
2718
- }, this);
2719
- },
2720
- draw : function(easeDecimal){
2721
- var animDecimal = (easeDecimal) ? easeDecimal : 1;
2722
- this.clear();
2723
- helpers.each(this.segments,function(segment,index){
2724
- segment.transition({
2725
- circumference : this.calculateCircumference(segment.value),
2726
- outerRadius : this.outerRadius,
2727
- innerRadius : (this.outerRadius/100) * this.options.percentageInnerCutout
2728
- },animDecimal);
2729
-
2730
- segment.endAngle = segment.startAngle + segment.circumference;
2731
 
2732
- segment.draw();
2733
- if (index === 0){
2734
- segment.startAngle = Math.PI * 1.5;
2735
- }
2736
- //Check to see if it's the last segment, if not get the next and update the start angle
2737
- if (index < this.segments.length-1){
2738
- this.segments[index+1].startAngle = segment.endAngle;
2739
- }
2740
- },this);
2741
 
2742
- }
2743
- });
 
 
 
 
 
 
 
 
2744
 
2745
- Chart.types.Doughnut.extend({
2746
- name : "Pie",
2747
- defaults : helpers.merge(defaultConfig,{percentageInnerCutout : 0})
2748
- });
2749
 
2750
- }).call(this);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2751
 
2752
- (function(){
2753
- "use strict";
 
 
 
2754
 
2755
- var root = this,
2756
- Chart = root.Chart,
2757
- helpers = Chart.helpers;
2758
 
2759
- var defaultConfig = {
 
 
 
 
2760
 
2761
- ///Boolean - Whether grid lines are shown across the chart
2762
- scaleShowGridLines : true,
 
2763
 
2764
- //String - Colour of the grid lines
2765
- scaleGridLineColor : "rgba(0,0,0,.05)",
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2766
 
2767
- //Number - Width of the grid lines
2768
- scaleGridLineWidth : 1,
 
 
2769
 
2770
- //Boolean - Whether to show horizontal lines (except X axis)
2771
- scaleShowHorizontalLines: true,
 
 
 
 
2772
 
2773
- //Boolean - Whether to show vertical lines (except Y axis)
2774
- scaleShowVerticalLines: true,
 
 
 
 
2775
 
2776
- //Boolean - Whether the line is curved between points
2777
- bezierCurve : true,
 
2778
 
2779
- //Number - Tension of the bezier curve between points
2780
- bezierCurveTension : 0.4,
 
 
 
2781
 
2782
- //Boolean - Whether to show a dot for each point
2783
- pointDot : true,
 
 
2784
 
2785
- //Number - Radius of each point dot in pixels
2786
- pointDotRadius : 4,
 
 
2787
 
2788
- //Number - Pixel width of point dot stroke
2789
- pointDotStrokeWidth : 1,
 
2790
 
2791
- //Number - amount extra to add to the radius to cater for hit detection outside the drawn point
2792
- pointHitDetectionRadius : 20,
 
2793
 
2794
- //Boolean - Whether to show a stroke for datasets
2795
- datasetStroke : true,
 
 
 
 
 
 
 
 
2796
 
2797
- //Number - Pixel width of dataset stroke
2798
- datasetStrokeWidth : 2,
 
 
 
 
 
 
2799
 
2800
- //Boolean - Whether to fill the dataset with a colour
2801
- datasetFill : true,
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2802
 
2803
- //String - A legend template
2804
- legendTemplate : "<ul class=\"<%=name.toLowerCase()%>-legend\"><% for (var i=0; i<datasets.length; i++){%><li><span style=\"background-color:<%=datasets[i].strokeColor%>\"><%if(datasets[i].label){%><%=datasets[i].label%><%}%></span></li><%}%></ul>",
2805
 
2806
- //Boolean - Whether to horizontally center the label and point dot inside the grid
2807
- offsetGridLines : false
 
2808
 
2809
- };
 
 
 
2810
 
 
 
 
 
 
 
 
2811
 
2812
- Chart.Type.extend({
2813
- name: "Line",
2814
- defaults : defaultConfig,
2815
- initialize: function(data){
2816
- //Declare the extension of the default point, to cater for the options passed in to the constructor
2817
- this.PointClass = Chart.Point.extend({
2818
- offsetGridLines : this.options.offsetGridLines,
2819
- strokeWidth : this.options.pointDotStrokeWidth,
2820
- radius : this.options.pointDotRadius,
2821
- display: this.options.pointDot,
2822
- hitDetectionRadius : this.options.pointHitDetectionRadius,
2823
- ctx : this.chart.ctx,
2824
- inRange : function(mouseX){
2825
- return (Math.pow(mouseX-this.x, 2) < Math.pow(this.radius + this.hitDetectionRadius,2));
2826
- }
2827
- });
2828
 
2829
- this.datasets = [];
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2830
 
2831
- //Set up tooltip events on the chart
2832
- if (this.options.showTooltips){
2833
- helpers.bindEvents(this, this.options.tooltipEvents, function(evt){
2834
- var activePoints = (evt.type !== 'mouseout') ? this.getPointsAtEvent(evt) : [];
2835
- this.eachPoints(function(point){
2836
- point.restore(['fillColor', 'strokeColor']);
2837
- });
2838
- helpers.each(activePoints, function(activePoint){
2839
- activePoint.fillColor = activePoint.highlightFill;
2840
- activePoint.strokeColor = activePoint.highlightStroke;
2841
- });
2842
- this.showTooltip(activePoints);
2843
- });
2844
- }
2845
 
2846
- //Iterate through each of the datasets, and build this into a property of the chart
2847
- helpers.each(data.datasets,function(dataset){
 
 
 
 
2848
 
2849
- var datasetObject = {
2850
- label : dataset.label || null,
2851
- fillColor : dataset.fillColor,
2852
- strokeColor : dataset.strokeColor,
2853
- pointColor : dataset.pointColor,
2854
- pointStrokeColor : dataset.pointStrokeColor,
2855
- points : []
2856
- };
2857
 
2858
- this.datasets.push(datasetObject);
 
 
 
2859
 
 
 
 
 
 
2860
 
2861
- helpers.each(dataset.data,function(dataPoint,index){
2862
- //Add a new point for each piece of data, passing any required data to draw.
2863
- datasetObject.points.push(new this.PointClass({
2864
- value : dataPoint,
2865
- label : data.labels[index],
2866
- datasetLabel: dataset.label,
2867
- strokeColor : dataset.pointStrokeColor,
2868
- fillColor : dataset.pointColor,
2869
- highlightFill : dataset.pointHighlightFill || dataset.pointColor,
2870
- highlightStroke : dataset.pointHighlightStroke || dataset.pointStrokeColor
2871
- }));
2872
- },this);
 
 
 
 
 
 
 
 
 
 
 
 
 
2873
 
2874
- this.buildScale(data.labels);
 
 
2875
 
 
 
 
 
 
 
 
 
2876
 
2877
- this.eachPoints(function(point, index){
2878
- helpers.extend(point, {
2879
- x: this.scale.calculateX(index),
2880
- y: this.scale.endPoint
2881
- });
2882
- point.save();
2883
- }, this);
2884
 
2885
- },this);
 
 
2886
 
 
 
2887
 
2888
- this.render();
2889
- },
2890
- update : function(){
2891
- this.scale.update();
2892
- // Reset any highlight colours before updating.
2893
- helpers.each(this.activeElements, function(activeElement){
2894
- activeElement.restore(['fillColor', 'strokeColor']);
2895
- });
2896
- this.eachPoints(function(point){
2897
- point.save();
2898
- });
2899
- this.render();
2900
- },
2901
- eachPoints : function(callback){
2902
- helpers.each(this.datasets,function(dataset){
2903
- helpers.each(dataset.points,callback,this);
2904
- },this);
2905
- },
2906
- getPointsAtEvent : function(e){
2907
- var pointsArray = [],
2908
- eventPosition = helpers.getRelativePosition(e);
2909
- helpers.each(this.datasets,function(dataset){
2910
- helpers.each(dataset.points,function(point){
2911
- if (point.inRange(eventPosition.x,eventPosition.y)) pointsArray.push(point);
2912
- });
2913
- },this);
2914
- return pointsArray;
2915
- },
2916
- buildScale : function(labels){
2917
- var self = this;
2918
 
2919
- var dataTotal = function(){
2920
- var values = [];
2921
- self.eachPoints(function(point){
2922
- values.push(point.value);
2923
- });
2924
 
2925
- return values;
2926
- };
 
2927
 
2928
- var scaleOptions = {
2929
- templateString : this.options.scaleLabel,
2930
- height : this.chart.height,
2931
- width : this.chart.width,
2932
- ctx : this.chart.ctx,
2933
- textColor : this.options.scaleFontColor,
2934
- offsetGridLines : this.options.offsetGridLines,
2935
- fontSize : this.options.scaleFontSize,
2936
- fontStyle : this.options.scaleFontStyle,
2937
- fontFamily : this.options.scaleFontFamily,
2938
- valuesCount : labels.length,
2939
- beginAtZero : this.options.scaleBeginAtZero,
2940
- integersOnly : this.options.scaleIntegersOnly,
2941
- calculateYRange : function(currentHeight){
2942
- var updatedRanges = helpers.calculateScaleRange(
2943
- dataTotal(),
2944
- currentHeight,
2945
- this.fontSize,
2946
- this.beginAtZero,
2947
- this.integersOnly
2948
- );
2949
- helpers.extend(this, updatedRanges);
2950
- },
2951
- xLabels : labels,
2952
- font : helpers.fontString(this.options.scaleFontSize, this.options.scaleFontStyle, this.options.scaleFontFamily),
2953
- lineWidth : this.options.scaleLineWidth,
2954
- lineColor : this.options.scaleLineColor,
2955
- showHorizontalLines : this.options.scaleShowHorizontalLines,
2956
- showVerticalLines : this.options.scaleShowVerticalLines,
2957
- gridLineWidth : (this.options.scaleShowGridLines) ? this.options.scaleGridLineWidth : 0,
2958
- gridLineColor : (this.options.scaleShowGridLines) ? this.options.scaleGridLineColor : "rgba(0,0,0,0)",
2959
- padding: (this.options.showScale) ? 0 : this.options.pointDotRadius + this.options.pointDotStrokeWidth,
2960
- showLabels : this.options.scaleShowLabels,
2961
- display : this.options.showScale
2962
- };
2963
 
2964
- if (this.options.scaleOverride){
2965
- helpers.extend(scaleOptions, {
2966
- calculateYRange: helpers.noop,
2967
- steps: this.options.scaleSteps,
2968
- stepValue: this.options.scaleStepWidth,
2969
- min: this.options.scaleStartValue,
2970
- max: this.options.scaleStartValue + (this.options.scaleSteps * this.options.scaleStepWidth)
2971
- });
2972
- }
2973
 
 
 
 
 
 
2974
 
2975
- this.scale = new Chart.Scale(scaleOptions);
2976
- },
2977
- addData : function(valuesArray,label){
2978
- //Map the values array for each of the datasets
2979
-
2980
- helpers.each(valuesArray,function(value,datasetIndex){
2981
- //Add a new point for each piece of data, passing any required data to draw.
2982
- this.datasets[datasetIndex].points.push(new this.PointClass({
2983
- value : value,
2984
- label : label,
2985
- datasetLabel: this.datasets[datasetIndex].label,
2986
- x: this.scale.calculateX(this.scale.valuesCount+1),
2987
- y: this.scale.endPoint,
2988
- strokeColor : this.datasets[datasetIndex].pointStrokeColor,
2989
- fillColor : this.datasets[datasetIndex].pointColor
2990
- }));
2991
- },this);
2992
-
2993
- this.scale.addXLabel(label);
2994
- //Then re-render the chart.
2995
- this.update();
2996
- },
2997
- removeData : function(){
2998
- this.scale.removeXLabel();
2999
- //Then re-render the chart.
3000
- helpers.each(this.datasets,function(dataset){
3001
- dataset.points.shift();
3002
- },this);
3003
- this.update();
3004
- },
3005
- reflow : function(){
3006
- var newScaleProps = helpers.extend({
3007
- height : this.chart.height,
3008
- width : this.chart.width
3009
- });
3010
- this.scale.update(newScaleProps);
3011
- },
3012
- draw : function(ease){
3013
- var easingDecimal = ease || 1;
3014
- this.clear();
3015
 
3016
- var ctx = this.chart.ctx;
 
 
 
3017
 
3018
- // Some helper methods for getting the next/prev points
3019
- var hasValue = function(item){
3020
- return item.value !== null;
3021
- },
3022
- nextPoint = function(point, collection, index){
3023
- return helpers.findNextWhere(collection, hasValue, index) || point;
3024
- },
3025
- previousPoint = function(point, collection, index){
3026
- return helpers.findPreviousWhere(collection, hasValue, index) || point;
3027
- };
3028
 
3029
- if (!this.scale) return;
3030
- this.scale.draw(easingDecimal);
 
3031
 
 
 
3032
 
3033
- helpers.each(this.datasets,function(dataset){
3034
- var pointsWithValues = helpers.where(dataset.points, hasValue);
 
 
 
 
 
 
 
 
 
 
 
 
3035
 
3036
- //Transition each point first so that the line and point drawing isn't out of sync
3037
- //We can use this extra loop to calculate the control points of this dataset also in this loop
 
 
 
 
3038
 
3039
- helpers.each(dataset.points, function(point, index){
3040
- if (point.hasValue()){
3041
- point.transition({
3042
- y : this.scale.calculateY(point.value),
3043
- x : this.scale.calculateX(index)
3044
- }, easingDecimal);
3045
- }
3046
- },this);
3047
-
3048
-
3049
- // Control points need to be calculated in a separate loop, because we need to know the current x/y of the point
3050
- // This would cause issues when there is no animation, because the y of the next point would be 0, so beziers would be skewed
3051
- if (this.options.bezierCurve){
3052
- helpers.each(pointsWithValues, function(point, index){
3053
- var tension = (index > 0 && index < pointsWithValues.length - 1) ? this.options.bezierCurveTension : 0;
3054
- point.controlPoints = helpers.splineCurve(
3055
- previousPoint(point, pointsWithValues, index),
3056
- point,
3057
- nextPoint(point, pointsWithValues, index),
3058
- tension
3059
- );
3060
-
3061
- // Prevent the bezier going outside of the bounds of the graph
3062
-
3063
- // Cap puter bezier handles to the upper/lower scale bounds
3064
- if (point.controlPoints.outer.y > this.scale.endPoint){
3065
- point.controlPoints.outer.y = this.scale.endPoint;
3066
- }
3067
- else if (point.controlPoints.outer.y < this.scale.startPoint){
3068
- point.controlPoints.outer.y = this.scale.startPoint;
3069
- }
3070
 
3071
- // Cap inner bezier handles to the upper/lower scale bounds
3072
- if (point.controlPoints.inner.y > this.scale.endPoint){
3073
- point.controlPoints.inner.y = this.scale.endPoint;
3074
- }
3075
- else if (point.controlPoints.inner.y < this.scale.startPoint){
3076
- point.controlPoints.inner.y = this.scale.startPoint;
3077
- }
3078
- },this);
3079
- }
3080
 
 
 
 
3081
 
3082
- //Draw the line between all the points
3083
- ctx.lineWidth = this.options.datasetStrokeWidth;
3084
- ctx.strokeStyle = dataset.strokeColor;
3085
- ctx.beginPath();
3086
 
3087
- helpers.each(pointsWithValues, function(point, index){
3088
- if (index === 0){
3089
- ctx.moveTo(point.x, point.y);
3090
- }
3091
- else{
3092
- if(this.options.bezierCurve){
3093
- var previous = previousPoint(point, pointsWithValues, index);
3094
-
3095
- ctx.bezierCurveTo(
3096
- previous.controlPoints.outer.x,
3097
- previous.controlPoints.outer.y,
3098
- point.controlPoints.inner.x,
3099
- point.controlPoints.inner.y,
3100
- point.x,
3101
- point.y
3102
- );
3103
- }
3104
- else{
3105
- ctx.lineTo(point.x,point.y);
3106
- }
3107
- }
3108
- }, this);
3109
 
3110
- if (this.options.datasetStroke) {
3111
- ctx.stroke();
3112
- }
 
 
 
 
 
 
 
 
 
 
 
3113
 
3114
- if (this.options.datasetFill && pointsWithValues.length > 0){
3115
- //Round off the line by going to the base of the chart, back to the start, then fill.
3116
- ctx.lineTo(pointsWithValues[pointsWithValues.length - 1].x, this.scale.endPoint);
3117
- ctx.lineTo(pointsWithValues[0].x, this.scale.endPoint);
3118
- ctx.fillStyle = dataset.fillColor;
3119
- ctx.closePath();
3120
- ctx.fill();
3121
- }
3122
 
3123
- //Now draw the points over the line
3124
- //A little inefficient double looping, but better than the line
3125
- //lagging behind the point positions
3126
- helpers.each(pointsWithValues,function(point){
3127
- point.draw();
3128
- });
3129
- },this);
3130
  }
3131
- });
 
3132
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3133
 
3134
- }).call(this);
 
 
 
 
3135
 
3136
- (function(){
3137
- "use strict";
 
3138
 
3139
- var root = this,
3140
- Chart = root.Chart,
3141
- //Cache a local reference to Chart.helpers
3142
- helpers = Chart.helpers;
3143
 
3144
- var defaultConfig = {
3145
- //Boolean - Show a backdrop to the scale label
3146
- scaleShowLabelBackdrop : true,
3147
 
3148
- //String - The colour of the label backdrop
3149
- scaleBackdropColor : "rgba(255,255,255,0.75)",
 
 
 
 
 
3150
 
3151
- // Boolean - Whether the scale should begin at zero
3152
- scaleBeginAtZero : true,
 
3153
 
3154
- //Number - The backdrop padding above & below the label in pixels
3155
- scaleBackdropPaddingY : 2,
3156
 
3157
- //Number - The backdrop padding to the side of the label in pixels
3158
- scaleBackdropPaddingX : 2,
3159
 
3160
- //Boolean - Show line for each value in the scale
3161
- scaleShowLine : true,
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3162
 
3163
- //Boolean - Stroke a line around each segment in the chart
3164
- segmentShowStroke : true,
3165
 
3166
- //String - The colour of the stroke on each segment.
3167
- segmentStrokeColor : "#fff",
 
3168
 
3169
- //Number - The width of the stroke value in pixels
3170
- segmentStrokeWidth : 2,
 
3171
 
3172
- //Number - Amount of animation steps
3173
- animationSteps : 100,
 
 
 
3174
 
3175
- //String - Animation easing effect.
3176
- animationEasing : "easeOutBounce",
3177
 
3178
- //Boolean - Whether to animate the rotation of the chart
3179
- animateRotate : true,
3180
 
3181
- //Boolean - Whether to animate scaling the chart from the centre
3182
- animateScale : false,
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3183
 
3184
- //String - A legend template
3185
- legendTemplate : "<ul class=\"<%=name.toLowerCase()%>-legend\"><% for (var i=0; i<segments.length; i++){%><li><span style=\"background-color:<%=segments[i].fillColor%>\"><%if(segments[i].label){%><%=segments[i].label%><%}%></span></li><%}%></ul>"
 
 
3186
  };
3187
 
3188
-
3189
- Chart.Type.extend({
3190
- //Passing in a name registers this chart in the Chart namespace
3191
- name: "PolarArea",
3192
- //Providing a defaults will also register the deafults in the chart namespace
3193
- defaults : defaultConfig,
3194
- //Initialize is fired when the chart is initialized - Data is passed in as a parameter
3195
- //Config is automatically merged by the core of Chart.js, and is available at this.options
3196
- initialize: function(data){
3197
- this.segments = [];
3198
- //Declare segment class as a chart instance specific class, so it can share props for this instance
3199
- this.SegmentArc = Chart.Arc.extend({
3200
- showStroke : this.options.segmentShowStroke,
3201
- strokeWidth : this.options.segmentStrokeWidth,
3202
- strokeColor : this.options.segmentStrokeColor,
3203
- ctx : this.chart.ctx,
3204
- innerRadius : 0,
3205
- x : this.chart.width/2,
3206
- y : this.chart.height/2
3207
- });
3208
- this.scale = new Chart.RadialScale({
3209
- display: this.options.showScale,
3210
- fontStyle: this.options.scaleFontStyle,
3211
- fontSize: this.options.scaleFontSize,
3212
- fontFamily: this.options.scaleFontFamily,
3213
- fontColor: this.options.scaleFontColor,
3214
- showLabels: this.options.scaleShowLabels,
3215
- showLabelBackdrop: this.options.scaleShowLabelBackdrop,
3216
- backdropColor: this.options.scaleBackdropColor,
3217
- backdropPaddingY : this.options.scaleBackdropPaddingY,
3218
- backdropPaddingX: this.options.scaleBackdropPaddingX,
3219
- lineWidth: (this.options.scaleShowLine) ? this.options.scaleLineWidth : 0,
3220
- lineColor: this.options.scaleLineColor,
3221
- lineArc: true,
3222
- width: this.chart.width,
3223
- height: this.chart.height,
3224
- xCenter: this.chart.width/2,
3225
- yCenter: this.chart.height/2,
3226
- ctx : this.chart.ctx,
3227
- templateString: this.options.scaleLabel,
3228
- valuesCount: data.length
3229
- });
3230
-
3231
- this.updateScaleRange(data);
3232
-
3233
- this.scale.update();
3234
-
3235
- helpers.each(data,function(segment,index){
3236
- this.addData(segment,index,true);
3237
- },this);
3238
-
3239
- //Set up tooltip events on the chart
3240
- if (this.options.showTooltips){
3241
- helpers.bindEvents(this, this.options.tooltipEvents, function(evt){
3242
- var activeSegments = (evt.type !== 'mouseout') ? this.getSegmentsAtEvent(evt) : [];
3243
- helpers.each(this.segments,function(segment){
3244
- segment.restore(["fillColor"]);
3245
- });
3246
- helpers.each(activeSegments,function(activeSegment){
3247
- activeSegment.fillColor = activeSegment.highlightColor;
3248
- });
3249
- this.showTooltip(activeSegments);
3250
- });
3251
  }
3252
 
3253
- this.render();
3254
- },
3255
- getSegmentsAtEvent : function(e){
3256
- var segmentsArray = [];
3257
-
3258
- var location = helpers.getRelativePosition(e);
3259
-
3260
- helpers.each(this.segments,function(segment){
3261
- if (segment.inRange(location.x,location.y)) segmentsArray.push(segment);
3262
- },this);
3263
- return segmentsArray;
3264
- },
3265
- addData : function(segment, atIndex, silent){
3266
- var index = atIndex || this.segments.length;
3267
-
3268
- this.segments.splice(index, 0, new this.SegmentArc({
3269
- fillColor: segment.color,
3270
- highlightColor: segment.highlight || segment.color,
3271
- label: segment.label,
3272
- value: segment.value,
3273
- outerRadius: (this.options.animateScale) ? 0 : this.scale.calculateCenterOffset(segment.value),
3274
- circumference: (this.options.animateRotate) ? 0 : this.scale.getCircumference(),
3275
- startAngle: Math.PI * 1.5
3276
- }));
3277
- if (!silent){
3278
- this.reflow();
3279
- this.update();
3280
- }
3281
- },
3282
- removeData: function(atIndex){
3283
- var indexToDelete = (helpers.isNumber(atIndex)) ? atIndex : this.segments.length-1;
3284
- this.segments.splice(indexToDelete, 1);
3285
- this.reflow();
3286
- this.update();
3287
- },
3288
- calculateTotal: function(data){
3289
- this.total = 0;
3290
- helpers.each(data,function(segment){
3291
- this.total += segment.value;
3292
- },this);
3293
- this.scale.valuesCount = this.segments.length;
3294
- },
3295
- updateScaleRange: function(datapoints){
3296
- var valuesArray = [];
3297
- helpers.each(datapoints,function(segment){
3298
- valuesArray.push(segment.value);
3299
- });
3300
-
3301
- var scaleSizes = (this.options.scaleOverride) ?
3302
- {
3303
- steps: this.options.scaleSteps,
3304
- stepValue: this.options.scaleStepWidth,
3305
- min: this.options.scaleStartValue,
3306
- max: this.options.scaleStartValue + (this.options.scaleSteps * this.options.scaleStepWidth)
3307
- } :
3308
- helpers.calculateScaleRange(
3309
- valuesArray,
3310
- helpers.min([this.chart.width, this.chart.height])/2,
3311
- this.options.scaleFontSize,
3312
- this.options.scaleBeginAtZero,
3313
- this.options.scaleIntegersOnly
3314
- );
3315
-
3316
- helpers.extend(
3317
- this.scale,
3318
- scaleSizes,
3319
- {
3320
- size: helpers.min([this.chart.width, this.chart.height]),
3321
- xCenter: this.chart.width/2,
3322
- yCenter: this.chart.height/2
3323
- }
3324
- );
3325
 
 
3326
  },
3327
- update : function(){
3328
- this.calculateTotal(this.segments);
3329
-
3330
- helpers.each(this.segments,function(segment){
3331
- segment.save();
3332
- });
3333
-
3334
- this.reflow();
3335
- this.render();
3336
- },
3337
- reflow : function(){
3338
- helpers.extend(this.SegmentArc.prototype,{
3339
- x : this.chart.width/2,
3340
- y : this.chart.height/2
3341
- });
3342
- this.updateScaleRange(this.segments);
3343
- this.scale.update();
3344
 
3345
- helpers.extend(this.scale,{
3346
- xCenter: this.chart.width/2,
3347
- yCenter: this.chart.height/2
3348
- });
3349
 
3350
- helpers.each(this.segments, function(segment){
3351
- segment.update({
3352
- outerRadius : this.scale.calculateCenterOffset(segment.value)
3353
- });
3354
- }, this);
3355
 
 
3356
  },
3357
- draw : function(ease){
3358
- var easingDecimal = ease || 1;
3359
- //Clear & draw the canvas
3360
- this.clear();
3361
- helpers.each(this.segments,function(segment, index){
3362
- segment.transition({
3363
- circumference : this.scale.getCircumference(),
3364
- outerRadius : this.scale.calculateCenterOffset(segment.value)
3365
- },easingDecimal);
3366
-
3367
- segment.endAngle = segment.startAngle + segment.circumference;
3368
-
3369
- // If we've removed the first segment we need to set the first one to
3370
- // start at the top.
3371
- if (index === 0){
3372
- segment.startAngle = Math.PI * 1.5;
3373
- }
3374
 
3375
- //Check to see if it's the last segment, if not get the next and update the start angle
3376
- if (index < this.segments.length - 1){
3377
- this.segments[index+1].startAngle = segment.endAngle;
3378
- }
3379
- segment.draw();
3380
- }, this);
3381
- this.scale.draw();
3382
- }
3383
- });
3384
 
3385
- }).call(this);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3386
 
3387
- (function(){
3388
- "use strict";
 
 
3389
 
3390
- var root = this,
3391
- Chart = root.Chart,
3392
- helpers = Chart.helpers;
3393
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3394
 
 
 
 
 
 
 
3395
 
3396
- Chart.Type.extend({
3397
- name: "Radar",
3398
- defaults:{
3399
- //Boolean - Whether to show lines for each scale point
3400
- scaleShowLine : true,
3401
 
3402
- //Boolean - Whether we show the angle lines out of the radar
3403
- angleShowLineOut : true,
3404
 
3405
- //Boolean - Whether to show labels on the scale
3406
- scaleShowLabels : false,
 
3407
 
3408
- // Boolean - Whether the scale should begin at zero
3409
- scaleBeginAtZero : true,
 
3410
 
3411
- //String - Colour of the angle line
3412
- angleLineColor : "rgba(0,0,0,.1)",
 
 
 
 
 
 
 
3413
 
3414
- //Number - Pixel width of the angle line
3415
- angleLineWidth : 1,
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3416
 
3417
- //String - Point label font declaration
3418
- pointLabelFontFamily : "'Arial'",
 
 
3419
 
3420
- //String - Point label font weight
3421
- pointLabelFontStyle : "normal",
 
3422
 
3423
- //Number - Point label font size in pixels
3424
- pointLabelFontSize : 10,
 
 
 
 
 
3425
 
3426
- //String - Point label font colour
3427
- pointLabelFontColor : "#666",
3428
 
3429
- //Boolean - Whether to show a dot for each point
3430
- pointDot : true,
 
 
 
3431
 
3432
- //Number - Radius of each point dot in pixels
3433
- pointDotRadius : 3,
3434
 
3435
- //Number - Pixel width of point dot stroke
3436
- pointDotStrokeWidth : 1,
 
 
 
 
3437
 
3438
- //Number - amount extra to add to the radius to cater for hit detection outside the drawn point
3439
- pointHitDetectionRadius : 20,
 
 
 
 
3440
 
3441
- //Boolean - Whether to show a stroke for datasets
3442
- datasetStroke : true,
3443
 
3444
- //Number - Pixel width of dataset stroke
3445
- datasetStrokeWidth : 2,
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3446
 
3447
- //Boolean - Whether to fill the dataset with a colour
3448
- datasetFill : true,
 
3449
 
3450
- //String - A legend template
3451
- legendTemplate : "<ul class=\"<%=name.toLowerCase()%>-legend\"><% for (var i=0; i<datasets.length; i++){%><li><span style=\"background-color:<%=datasets[i].strokeColor%>\"><%if(datasets[i].label){%><%=datasets[i].label%><%}%></span></li><%}%></ul>"
 
3452
 
 
3453
  },
3454
 
3455
- initialize: function(data){
3456
- this.PointClass = Chart.Point.extend({
3457
- strokeWidth : this.options.pointDotStrokeWidth,
3458
- radius : this.options.pointDotRadius,
3459
- display: this.options.pointDot,
3460
- hitDetectionRadius : this.options.pointHitDetectionRadius,
3461
- ctx : this.chart.ctx
3462
- });
3463
-
3464
- this.datasets = [];
3465
 
3466
- this.buildScale(data);
3467
-
3468
- //Set up tooltip events on the chart
3469
- if (this.options.showTooltips){
3470
- helpers.bindEvents(this, this.options.tooltipEvents, function(evt){
3471
- var activePointsCollection = (evt.type !== 'mouseout') ? this.getPointsAtEvent(evt) : [];
3472
 
3473
- this.eachPoints(function(point){
3474
- point.restore(['fillColor', 'strokeColor']);
3475
- });
3476
- helpers.each(activePointsCollection, function(activePoint){
3477
- activePoint.fillColor = activePoint.highlightFill;
3478
- activePoint.strokeColor = activePoint.highlightStroke;
3479
- });
3480
 
3481
- this.showTooltip(activePointsCollection);
3482
- });
3483
  }
3484
 
3485
- //Iterate through each of the datasets, and build this into a property of the chart
3486
- helpers.each(data.datasets,function(dataset){
3487
-
3488
- var datasetObject = {
3489
- label: dataset.label || null,
3490
- fillColor : dataset.fillColor,
3491
- strokeColor : dataset.strokeColor,
3492
- pointColor : dataset.pointColor,
3493
- pointStrokeColor : dataset.pointStrokeColor,
3494
- points : []
3495
- };
3496
-
3497
- this.datasets.push(datasetObject);
3498
-
3499
- helpers.each(dataset.data,function(dataPoint,index){
3500
- //Add a new point for each piece of data, passing any required data to draw.
3501
- var pointPosition;
3502
- if (!this.scale.animation){
3503
- pointPosition = this.scale.getPointPosition(index, this.scale.calculateCenterOffset(dataPoint));
3504
- }
3505
- datasetObject.points.push(new this.PointClass({
3506
- value : dataPoint,
3507
- label : data.labels[index],
3508
- datasetLabel: dataset.label,
3509
- x: (this.options.animation) ? this.scale.xCenter : pointPosition.x,
3510
- y: (this.options.animation) ? this.scale.yCenter : pointPosition.y,
3511
- strokeColor : dataset.pointStrokeColor,
3512
- fillColor : dataset.pointColor,
3513
- highlightFill : dataset.pointHighlightFill || dataset.pointColor,
3514
- highlightStroke : dataset.pointHighlightStroke || dataset.pointStrokeColor
3515
- }));
3516
- },this);
3517
-
3518
- },this);
3519
-
3520
- this.render();
3521
- },
3522
- eachPoints : function(callback){
3523
- helpers.each(this.datasets,function(dataset){
3524
- helpers.each(dataset.points,callback,this);
3525
- },this);
3526
- },
3527
-
3528
- getPointsAtEvent : function(evt){
3529
- var mousePosition = helpers.getRelativePosition(evt),
3530
- fromCenter = helpers.getAngleFromPoint({
3531
- x: this.scale.xCenter,
3532
- y: this.scale.yCenter
3533
- }, mousePosition);
3534
-
3535
- var anglePerIndex = (Math.PI * 2) /this.scale.valuesCount,
3536
- pointIndex = Math.round((fromCenter.angle - Math.PI * 1.5) / anglePerIndex),
3537
- activePointsCollection = [];
3538
-
3539
- // If we're at the top, make the pointIndex 0 to get the first of the array.
3540
- if (pointIndex >= this.scale.valuesCount || pointIndex < 0){
3541
- pointIndex = 0;
3542
- }
3543
-
3544
- if (fromCenter.distance <= this.scale.drawingArea){
3545
- helpers.each(this.datasets, function(dataset){
3546
- activePointsCollection.push(dataset.points[pointIndex]);
3547
- });
3548
  }
3549
 
3550
- return activePointsCollection;
3551
- },
3552
-
3553
- buildScale : function(data){
3554
- this.scale = new Chart.RadialScale({
3555
- display: this.options.showScale,
3556
- fontStyle: this.options.scaleFontStyle,
3557
- fontSize: this.options.scaleFontSize,
3558
- fontFamily: this.options.scaleFontFamily,
3559
- fontColor: this.options.scaleFontColor,
3560
- showLabels: this.options.scaleShowLabels,
3561
- showLabelBackdrop: this.options.scaleShowLabelBackdrop,
3562
- backdropColor: this.options.scaleBackdropColor,
3563
- backgroundColors: this.options.scaleBackgroundColors,
3564
- backdropPaddingY : this.options.scaleBackdropPaddingY,
3565
- backdropPaddingX: this.options.scaleBackdropPaddingX,
3566
- lineWidth: (this.options.scaleShowLine) ? this.options.scaleLineWidth : 0,
3567
- lineColor: this.options.scaleLineColor,
3568
- angleLineColor : this.options.angleLineColor,
3569
- angleLineWidth : (this.options.angleShowLineOut) ? this.options.angleLineWidth : 0,
3570
- // Point labels at the edge of each line
3571
- pointLabelFontColor : this.options.pointLabelFontColor,
3572
- pointLabelFontSize : this.options.pointLabelFontSize,
3573
- pointLabelFontFamily : this.options.pointLabelFontFamily,
3574
- pointLabelFontStyle : this.options.pointLabelFontStyle,
3575
- height : this.chart.height,
3576
- width: this.chart.width,
3577
- xCenter: this.chart.width/2,
3578
- yCenter: this.chart.height/2,
3579
- ctx : this.chart.ctx,
3580
- templateString: this.options.scaleLabel,
3581
- labels: data.labels,
3582
- valuesCount: data.datasets[0].data.length
3583
- });
3584
 
3585
- this.scale.setScaleSize();
3586
- this.updateScaleRange(data.datasets);
3587
- this.scale.buildYLabels();
 
 
3588
  },
3589
- updateScaleRange: function(datasets){
3590
- var valuesArray = (function(){
3591
- var totalDataArray = [];
3592
- helpers.each(datasets,function(dataset){
3593
- if (dataset.data){
3594
- totalDataArray = totalDataArray.concat(dataset.data);
3595
- }
3596
- else {
3597
- helpers.each(dataset.points, function(point){
3598
- totalDataArray.push(point.value);
3599
- });
3600
- }
3601
- });
3602
- return totalDataArray;
3603
- })();
3604
-
3605
-
3606
- var scaleSizes = (this.options.scaleOverride) ?
3607
- {
3608
- steps: this.options.scaleSteps,
3609
- stepValue: this.options.scaleStepWidth,
3610
- min: this.options.scaleStartValue,
3611
- max: this.options.scaleStartValue + (this.options.scaleSteps * this.options.scaleStepWidth)
3612
- } :
3613
- helpers.calculateScaleRange(
3614
- valuesArray,
3615
- helpers.min([this.chart.width, this.chart.height])/2,
3616
- this.options.scaleFontSize,
3617
- this.options.scaleBeginAtZero,
3618
- this.options.scaleIntegersOnly
3619
- );
3620
 
3621
- helpers.extend(
3622
- this.scale,
3623
- scaleSizes
3624
- );
3625
-
3626
- },
3627
- addData : function(valuesArray,label){
3628
- //Map the values array for each of the datasets
3629
- this.scale.valuesCount++;
3630
- helpers.each(valuesArray,function(value,datasetIndex){
3631
- var pointPosition = this.scale.getPointPosition(this.scale.valuesCount, this.scale.calculateCenterOffset(value));
3632
- this.datasets[datasetIndex].points.push(new this.PointClass({
3633
- value : value,
3634
- label : label,
3635
- datasetLabel: this.datasets[datasetIndex].label,
3636
- x: pointPosition.x,
3637
- y: pointPosition.y,
3638
- strokeColor : this.datasets[datasetIndex].pointStrokeColor,
3639
- fillColor : this.datasets[datasetIndex].pointColor
3640
- }));
3641
- },this);
3642
-
3643
- this.scale.labels.push(label);
3644
-
3645
- this.reflow();
3646
-
3647
- this.update();
3648
- },
3649
- removeData : function(){
3650
- this.scale.valuesCount--;
3651
- this.scale.labels.shift();
3652
- helpers.each(this.datasets,function(dataset){
3653
- dataset.points.shift();
3654
- },this);
3655
- this.reflow();
3656
- this.update();
3657
- },
3658
- update : function(){
3659
- this.eachPoints(function(point){
3660
- point.save();
3661
- });
3662
- this.reflow();
3663
- this.render();
3664
- },
3665
- reflow: function(){
3666
- helpers.extend(this.scale, {
3667
- width : this.chart.width,
3668
- height: this.chart.height,
3669
- size : helpers.min([this.chart.width, this.chart.height]),
3670
- xCenter: this.chart.width/2,
3671
- yCenter: this.chart.height/2
3672
- });
3673
- this.updateScaleRange(this.datasets);
3674
- this.scale.setScaleSize();
3675
- this.scale.buildYLabels();
3676
- },
3677
- draw : function(ease){
3678
- var easeDecimal = ease || 1,
3679
- ctx = this.chart.ctx;
3680
- this.clear();
3681
- this.scale.draw();
3682
-
3683
- helpers.each(this.datasets,function(dataset){
3684
-
3685
- //Transition each point first so that the line and point drawing isn't out of sync
3686
- helpers.each(dataset.points,function(point,index){
3687
- if (point.hasValue()){
3688
- point.transition(this.scale.getPointPosition(index, this.scale.calculateCenterOffset(point.value)), easeDecimal);
3689
- }
3690
- },this);
3691
 
 
 
3692
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3693
 
3694
- //Draw the line between all the points
3695
- ctx.lineWidth = this.options.datasetStrokeWidth;
3696
- ctx.strokeStyle = dataset.strokeColor;
3697
- ctx.beginPath();
3698
- helpers.each(dataset.points,function(point,index){
3699
- if (index === 0){
3700
- ctx.moveTo(point.x,point.y);
3701
- }
3702
- else{
3703
- ctx.lineTo(point.x,point.y);
3704
- }
3705
- },this);
3706
- ctx.closePath();
3707
- ctx.stroke();
3708
 
3709
- ctx.fillStyle = dataset.fillColor;
3710
- if(this.options.datasetFill){
3711
- ctx.fill();
3712
- }
3713
- //Now draw the points over the line
3714
- //A little inefficient double looping, but better than the line
3715
- //lagging behind the point positions
3716
- helpers.each(dataset.points,function(point){
3717
- if (point.hasValue()){
3718
- point.draw();
3719
- }
3720
- });
3721
 
3722
- },this);
 
 
3723
 
 
3724
  }
3725
-
3726
  });
3727
 
 
 
3728
 
3729
-
3730
-
3731
-
3732
- }).call(this);
1
  /*!
2
  * Chart.js
3
  * http://chartjs.org/
4
+ * Version: 2.7.1
5
  *
6
+ * Copyright 2017 Nick Downie
7
  * Released under the MIT license
8
+ * https://github.com/chartjs/Chart.js/blob/master/LICENSE.md
9
  */
10
+ (function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.Chart = f()}})(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){
11
+
12
+ },{}],2:[function(require,module,exports){
13
+ /* MIT license */
14
+ var colorNames = require(6);
15
+
16
+ module.exports = {
17
+ getRgba: getRgba,
18
+ getHsla: getHsla,
19
+ getRgb: getRgb,
20
+ getHsl: getHsl,
21
+ getHwb: getHwb,
22
+ getAlpha: getAlpha,
23
+
24
+ hexString: hexString,
25
+ rgbString: rgbString,
26
+ rgbaString: rgbaString,
27
+ percentString: percentString,
28
+ percentaString: percentaString,
29
+ hslString: hslString,
30
+ hslaString: hslaString,
31
+ hwbString: hwbString,
32
+ keyword: keyword
33
+ }
34
+
35
+ function getRgba(string) {
36
+ if (!string) {
37
+ return;
38
+ }
39
+ var abbr = /^#([a-fA-F0-9]{3})$/i,
40
+ hex = /^#([a-fA-F0-9]{6})$/i,
41
+ rgba = /^rgba?\(\s*([+-]?\d+)\s*,\s*([+-]?\d+)\s*,\s*([+-]?\d+)\s*(?:,\s*([+-]?[\d\.]+)\s*)?\)$/i,
42
+ per = /^rgba?\(\s*([+-]?[\d\.]+)\%\s*,\s*([+-]?[\d\.]+)\%\s*,\s*([+-]?[\d\.]+)\%\s*(?:,\s*([+-]?[\d\.]+)\s*)?\)$/i,
43
+ keyword = /(\w+)/;
44
+
45
+ var rgb = [0, 0, 0],
46
+ a = 1,
47
+ match = string.match(abbr);
48
+ if (match) {
49
+ match = match[1];
50
+ for (var i = 0; i < rgb.length; i++) {
51
+ rgb[i] = parseInt(match[i] + match[i], 16);
52
+ }
53
+ }
54
+ else if (match = string.match(hex)) {
55
+ match = match[1];
56
+ for (var i = 0; i < rgb.length; i++) {
57
+ rgb[i] = parseInt(match.slice(i * 2, i * 2 + 2), 16);
58
+ }
59
+ }
60
+ else if (match = string.match(rgba)) {
61
+ for (var i = 0; i < rgb.length; i++) {
62
+ rgb[i] = parseInt(match[i + 1]);
63
+ }
64
+ a = parseFloat(match[4]);
65
+ }
66
+ else if (match = string.match(per)) {
67
+ for (var i = 0; i < rgb.length; i++) {
68
+ rgb[i] = Math.round(parseFloat(match[i + 1]) * 2.55);
69
+ }
70
+ a = parseFloat(match[4]);
71
+ }
72
+ else if (match = string.match(keyword)) {
73
+ if (match[1] == "transparent") {
74
+ return [0, 0, 0, 0];
75
+ }
76
+ rgb = colorNames[match[1]];
77
+ if (!rgb) {
78
+ return;
79
+ }
80
+ }
81
+
82
+ for (var i = 0; i < rgb.length; i++) {
83
+ rgb[i] = scale(rgb[i], 0, 255);
84
+ }
85
+ if (!a && a != 0) {
86
+ a = 1;
87
+ }
88
+ else {
89
+ a = scale(a, 0, 1);
90
+ }
91
+ rgb[3] = a;
92
+ return rgb;
93
+ }
94
+
95
+ function getHsla(string) {
96
+ if (!string) {
97
+ return;
98
+ }
99
+ var hsl = /^hsla?\(\s*([+-]?\d+)(?:deg)?\s*,\s*([+-]?[\d\.]+)%\s*,\s*([+-]?[\d\.]+)%\s*(?:,\s*([+-]?[\d\.]+)\s*)?\)/;
100
+ var match = string.match(hsl);
101
+ if (match) {
102
+ var alpha = parseFloat(match[4]);
103
+ var h = scale(parseInt(match[1]), 0, 360),
104
+ s = scale(parseFloat(match[2]), 0, 100),
105
+ l = scale(parseFloat(match[3]), 0, 100),
106
+ a = scale(isNaN(alpha) ? 1 : alpha, 0, 1);
107
+ return [h, s, l, a];
108
+ }
109
+ }
110
+
111
+ function getHwb(string) {
112
+ if (!string) {
113
+ return;
114
+ }
115
+ var hwb = /^hwb\(\s*([+-]?\d+)(?:deg)?\s*,\s*([+-]?[\d\.]+)%\s*,\s*([+-]?[\d\.]+)%\s*(?:,\s*([+-]?[\d\.]+)\s*)?\)/;
116
+ var match = string.match(hwb);
117
+ if (match) {
118
+ var alpha = parseFloat(match[4]);
119
+ var h = scale(parseInt(match[1]), 0, 360),
120
+ w = scale(parseFloat(match[2]), 0, 100),
121
+ b = scale(parseFloat(match[3]), 0, 100),
122
+ a = scale(isNaN(alpha) ? 1 : alpha, 0, 1);
123
+ return [h, w, b, a];
124
+ }
125
+ }
126
+
127
+ function getRgb(string) {
128
+ var rgba = getRgba(string);
129
+ return rgba && rgba.slice(0, 3);
130
+ }
131
+
132
+ function getHsl(string) {
133
+ var hsla = getHsla(string);
134
+ return hsla && hsla.slice(0, 3);
135
+ }
136
+
137
+ function getAlpha(string) {
138
+ var vals = getRgba(string);
139
+ if (vals) {
140
+ return vals[3];
141
+ }
142
+ else if (vals = getHsla(string)) {
143
+ return vals[3];
144
+ }
145
+ else if (vals = getHwb(string)) {
146
+ return vals[3];
147
+ }
148
+ }
149
+
150
+ // generators
151
+ function hexString(rgb) {
152
+ return "#" + hexDouble(rgb[0]) + hexDouble(rgb[1])
153
+ + hexDouble(rgb[2]);
154
+ }
155
+
156
+ function rgbString(rgba, alpha) {
157
+ if (alpha < 1 || (rgba[3] && rgba[3] < 1)) {
158
+ return rgbaString(rgba, alpha);
159
+ }
160
+ return "rgb(" + rgba[0] + ", " + rgba[1] + ", " + rgba[2] + ")";
161
+ }
162
+
163
+ function rgbaString(rgba, alpha) {
164
+ if (alpha === undefined) {
165
+ alpha = (rgba[3] !== undefined ? rgba[3] : 1);
166
+ }
167
+ return "rgba(" + rgba[0] + ", " + rgba[1] + ", " + rgba[2]
168
+ + ", " + alpha + ")";
169
+ }
170
+
171
+ function percentString(rgba, alpha) {
172
+ if (alpha < 1 || (rgba[3] && rgba[3] < 1)) {
173
+ return percentaString(rgba, alpha);
174
+ }
175
+ var r = Math.round(rgba[0]/255 * 100),
176
+ g = Math.round(rgba[1]/255 * 100),
177
+ b = Math.round(rgba[2]/255 * 100);
178
+
179
+ return "rgb(" + r + "%, " + g + "%, " + b + "%)";
180
+ }
181
+
182
+ function percentaString(rgba, alpha) {
183
+ var r = Math.round(rgba[0]/255 * 100),
184
+ g = Math.round(rgba[1]/255 * 100),
185
+ b = Math.round(rgba[2]/255 * 100);
186
+ return "rgba(" + r + "%, " + g + "%, " + b + "%, " + (alpha || rgba[3] || 1) + ")";
187
+ }
188
+
189
+ function hslString(hsla, alpha) {
190
+ if (alpha < 1 || (hsla[3] && hsla[3] < 1)) {
191
+ return hslaString(hsla, alpha);
192
+ }
193
+ return "hsl(" + hsla[0] + ", " + hsla[1] + "%, " + hsla[2] + "%)";
194
+ }
195
+
196
+ function hslaString(hsla, alpha) {
197
+ if (alpha === undefined) {
198
+ alpha = (hsla[3] !== undefined ? hsla[3] : 1);
199
+ }
200
+ return "hsla(" + hsla[0] + ", " + hsla[1] + "%, " + hsla[2] + "%, "
201
+ + alpha + ")";
202
+ }
203
+
204
+ // hwb is a bit different than rgb(a) & hsl(a) since there is no alpha specific syntax
205
+ // (hwb have alpha optional & 1 is default value)
206
+ function hwbString(hwb, alpha) {
207
+ if (alpha === undefined) {
208
+ alpha = (hwb[3] !== undefined ? hwb[3] : 1);
209
+ }
210
+ return "hwb(" + hwb[0] + ", " + hwb[1] + "%, " + hwb[2] + "%"
211
+ + (alpha !== undefined && alpha !== 1 ? ", " + alpha : "") + ")";
212
+ }
213
+
214
+ function keyword(rgb) {
215
+ return reverseNames[rgb.slice(0, 3)];
216
+ }
217
+
218
+ // helpers
219
+ function scale(num, min, max) {
220
+ return Math.min(Math.max(min, num), max);
221
+ }
222
+
223
+ function hexDouble(num) {
224
+ var str = num.toString(16).toUpperCase();
225
+ return (str.length < 2) ? "0" + str : str;
226
+ }
227
+
228
+
229
+ //create a list of reverse color names
230
+ var reverseNames = {};
231
+ for (var name in colorNames) {
232
+ reverseNames[colorNames[name]] = name;
233
+ }
234
+
235
+ },{"6":6}],3:[function(require,module,exports){
236
+ /* MIT license */
237
+ var convert = require(5);
238
+ var string = require(2);
239
+
240
+ var Color = function (obj) {
241
+ if (obj instanceof Color) {
242
+ return obj;
243
+ }
244
+ if (!(this instanceof Color)) {
245
+ return new Color(obj);
246
+ }
247
 
248
+ this.valid = false;
249
+ this.values = {
250
+ rgb: [0, 0, 0],
251
+ hsl: [0, 0, 0],
252
+ hsv: [0, 0, 0],
253
+ hwb: [0, 0, 0],
254
+ cmyk: [0, 0, 0, 0],
255
+ alpha: 1
256
+ };
257
 
258
+ // parse Color() argument
259
+ var vals;
260
+ if (typeof obj === 'string') {
261
+ vals = string.getRgba(obj);
262
+ if (vals) {
263
+ this.setValues('rgb', vals);
264
+ } else if (vals = string.getHsla(obj)) {
265
+ this.setValues('hsl', vals);
266
+ } else if (vals = string.getHwb(obj)) {
267
+ this.setValues('hwb', vals);
268
+ }
269
+ } else if (typeof obj === 'object') {
270
+ vals = obj;
271
+ if (vals.r !== undefined || vals.red !== undefined) {
272
+ this.setValues('rgb', vals);
273
+ } else if (vals.l !== undefined || vals.lightness !== undefined) {
274
+ this.setValues('hsl', vals);
275
+ } else if (vals.v !== undefined || vals.value !== undefined) {
276
+ this.setValues('hsv', vals);
277
+ } else if (vals.w !== undefined || vals.whiteness !== undefined) {
278
+ this.setValues('hwb', vals);
279
+ } else if (vals.c !== undefined || vals.cyan !== undefined) {
280
+ this.setValues('cmyk', vals);
281
+ }
282
+ }
283
+ };
284
+
285
+ Color.prototype = {
286
+ isValid: function () {
287
+ return this.valid;
288
+ },
289
+ rgb: function () {
290
+ return this.setSpace('rgb', arguments);
291
+ },
292
+ hsl: function () {
293
+ return this.setSpace('hsl', arguments);
294
+ },
295
+ hsv: function () {
296
+ return this.setSpace('hsv', arguments);
297
+ },
298
+ hwb: function () {
299
+ return this.setSpace('hwb', arguments);
300
+ },
301
+ cmyk: function () {
302
+ return this.setSpace('cmyk', arguments);
303
+ },
304
+
305
+ rgbArray: function () {
306
+ return this.values.rgb;
307
+ },
308
+ hslArray: function () {
309
+ return this.values.hsl;
310
+ },
311
+ hsvArray: function () {
312
+ return this.values.hsv;
313
+ },
314
+ hwbArray: function () {
315
+ var values = this.values;
316
+ if (values.alpha !== 1) {
317
+ return values.hwb.concat([values.alpha]);
318
+ }
319
+ return values.hwb;
320
+ },
321
+ cmykArray: function () {
322
+ return this.values.cmyk;
323
+ },
324
+ rgbaArray: function () {
325
+ var values = this.values;
326
+ return values.rgb.concat([values.alpha]);
327
+ },
328
+ hslaArray: function () {
329
+ var values = this.values;
330
+ return values.hsl.concat([values.alpha]);
331
+ },
332
+ alpha: function (val) {
333
+ if (val === undefined) {
334
+ return this.values.alpha;
335
+ }
336
+ this.setValues('alpha', val);
337
+ return this;
338
+ },
339
+
340
+ red: function (val) {
341
+ return this.setChannel('rgb', 0, val);
342
+ },
343
+ green: function (val) {
344
+ return this.setChannel('rgb', 1, val);
345
+ },
346
+ blue: function (val) {
347
+ return this.setChannel('rgb', 2, val);
348
+ },
349
+ hue: function (val) {
350
+ if (val) {
351
+ val %= 360;
352
+ val = val < 0 ? 360 + val : val;
353
+ }
354
+ return this.setChannel('hsl', 0, val);
355
+ },
356
+ saturation: function (val) {
357
+ return this.setChannel('hsl', 1, val);
358
+ },
359
+ lightness: function (val) {
360
+ return this.setChannel('hsl', 2, val);
361
+ },
362
+ saturationv: function (val) {
363
+ return this.setChannel('hsv', 1, val);
364
+ },
365
+ whiteness: function (val) {
366
+ return this.setChannel('hwb', 1, val);
367
+ },
368
+ blackness: function (val) {
369
+ return this.setChannel('hwb', 2, val);
370
+ },
371
+ value: function (val) {
372
+ return this.setChannel('hsv', 2, val);
373
+ },
374
+ cyan: function (val) {
375
+ return this.setChannel('cmyk', 0, val);
376
+ },
377
+ magenta: function (val) {
378
+ return this.setChannel('cmyk', 1, val);
379
+ },
380
+ yellow: function (val) {
381
+ return this.setChannel('cmyk', 2, val);
382
+ },
383
+ black: function (val) {
384
+ return this.setChannel('cmyk', 3, val);
385
+ },
386
+
387
+ hexString: function () {
388
+ return string.hexString(this.values.rgb);
389
+ },
390
+ rgbString: function () {
391
+ return string.rgbString(this.values.rgb, this.values.alpha);
392
+ },
393
+ rgbaString: function () {
394
+ return string.rgbaString(this.values.rgb, this.values.alpha);
395
+ },
396
+ percentString: function () {
397
+ return string.percentString(this.values.rgb, this.values.alpha);
398
+ },
399
+ hslString: function () {
400
+ return string.hslString(this.values.hsl, this.values.alpha);
401
+ },
402
+ hslaString: function () {
403
+ return string.hslaString(this.values.hsl, this.values.alpha);
404
+ },
405
+ hwbString: function () {
406
+ return string.hwbString(this.values.hwb, this.values.alpha);
407
+ },
408
+ keyword: function () {
409
+ return string.keyword(this.values.rgb, this.values.alpha);
410
+ },
411
+
412
+ rgbNumber: function () {
413
+ var rgb = this.values.rgb;
414
+ return (rgb[0] << 16) | (rgb[1] << 8) | rgb[2];
415
+ },
416
+
417
+ luminosity: function () {
418
+ // http://www.w3.org/TR/WCAG20/#relativeluminancedef
419
+ var rgb = this.values.rgb;
420
+ var lum = [];
421
+ for (var i = 0; i < rgb.length; i++) {
422
+ var chan = rgb[i] / 255;
423
+ lum[i] = (chan <= 0.03928) ? chan / 12.92 : Math.pow(((chan + 0.055) / 1.055), 2.4);
424
+ }
425
+ return 0.2126 * lum[0] + 0.7152 * lum[1] + 0.0722 * lum[2];
426
+ },
427
+
428
+ contrast: function (color2) {
429
+ // http://www.w3.org/TR/WCAG20/#contrast-ratiodef
430
+ var lum1 = this.luminosity();
431
+ var lum2 = color2.luminosity();
432
+ if (lum1 > lum2) {
433
+ return (lum1 + 0.05) / (lum2 + 0.05);
434
+ }
435
+ return (lum2 + 0.05) / (lum1 + 0.05);
436
+ },
437
 
438
+ level: function (color2) {
439
+ var contrastRatio = this.contrast(color2);
440
+ if (contrastRatio >= 7.1) {
441
+ return 'AAA';
442
+ }
443
 
444
+ return (contrastRatio >= 4.5) ? 'AA' : '';
445
+ },
 
446
 
447
+ dark: function () {
448
+ // YIQ equation from http://24ways.org/2010/calculating-color-contrast
449
+ var rgb = this.values.rgb;
450
+ var yiq = (rgb[0] * 299 + rgb[1] * 587 + rgb[2] * 114) / 1000;
451
+ return yiq < 128;
452
+ },
453
 
454
+ light: function () {
455
+ return !this.dark();
456
+ },
457
 
458
+ negate: function () {
459
+ var rgb = [];
460
+ for (var i = 0; i < 3; i++) {
461
+ rgb[i] = 255 - this.values.rgb[i];
462
+ }
463
+ this.setValues('rgb', rgb);
464
+ return this;
465
+ },
466
+
467
+ lighten: function (ratio) {
468
+ var hsl = this.values.hsl;
469
+ hsl[2] += hsl[2] * ratio;
470
+ this.setValues('hsl', hsl);
471
+ return this;
472
+ },
473
 
474
+ darken: function (ratio) {
475
+ var hsl = this.values.hsl;
476
+ hsl[2] -= hsl[2] * ratio;
477
+ this.setValues('hsl', hsl);
478
+ return this;
479
+ },
480
 
481
+ saturate: function (ratio) {
482
+ var hsl = this.values.hsl;
483
+ hsl[1] += hsl[1] * ratio;
484
+ this.setValues('hsl', hsl);
485
+ return this;
486
+ },
487
 
488
+ desaturate: function (ratio) {
489
+ var hsl = this.values.hsl;
490
+ hsl[1] -= hsl[1] * ratio;
491
+ this.setValues('hsl', hsl);
492
  return this;
493
+ },
494
+
495
+ whiten: function (ratio) {
496
+ var hwb = this.values.hwb;
497
+ hwb[1] += hwb[1] * ratio;
498
+ this.setValues('hwb', hwb);
499
+ return this;
500
+ },
501
+
502
+ blacken: function (ratio) {
503
+ var hwb = this.values.hwb;
504
+ hwb[2] += hwb[2] * ratio;
505
+ this.setValues('hwb', hwb);
506
+ return this;
507
+ },
508
+
509
+ greyscale: function () {
510
+ var rgb = this.values.rgb;
511
+ // http://en.wikipedia.org/wiki/Grayscale#Converting_color_to_grayscale
512
+ var val = rgb[0] * 0.3 + rgb[1] * 0.59 + rgb[2] * 0.11;
513
+ this.setValues('rgb', [val, val, val]);
514
+ return this;
515
+ },
516
 
517
+ clearer: function (ratio) {
518
+ var alpha = this.values.alpha;
519
+ this.setValues('alpha', alpha - (alpha * ratio));
520
+ return this;
521
+ },
522
 
523
+ opaquer: function (ratio) {
524
+ var alpha = this.values.alpha;
525
+ this.setValues('alpha', alpha + (alpha * ratio));
526
+ return this;
527
+ },
528
 
529
+ rotate: function (degrees) {
530
+ var hsl = this.values.hsl;
531
+ var hue = (hsl[0] + degrees) % 360;
532
+ hsl[0] = hue < 0 ? 360 + hue : hue;
533
+ this.setValues('hsl', hsl);
534
+ return this;
535
+ },
536
+
537
+ /**
538
+ * Ported from sass implementation in C
539
+ * https://github.com/sass/libsass/blob/0e6b4a2850092356aa3ece07c6b249f0221caced/functions.cpp#L209
540
+ */
541
+ mix: function (mixinColor, weight) {
542
+ var color1 = this;
543
+ var color2 = mixinColor;
544
+ var p = weight === undefined ? 0.5 : weight;
545
+
546
+ var w = 2 * p - 1;
547
+ var a = color1.alpha() - color2.alpha();
548
+
549
+ var w1 = (((w * a === -1) ? w : (w + a) / (1 + w * a)) + 1) / 2.0;
550
+ var w2 = 1 - w1;
551
+
552
+ return this
553
+ .rgb(
554
+ w1 * color1.red() + w2 * color2.red(),
555
+ w1 * color1.green() + w2 * color2.green(),
556
+ w1 * color1.blue() + w2 * color2.blue()
557
+ )
558
+ .alpha(color1.alpha() * p + color2.alpha() * (1 - p));
559
+ },
560
+
561
+ toJSON: function () {
562
+ return this.rgb();
563
+ },
564
+
565
+ clone: function () {
566
+ // NOTE(SB): using node-clone creates a dependency to Buffer when using browserify,
567
+ // making the final build way to big to embed in Chart.js. So let's do it manually,
568
+ // assuming that values to clone are 1 dimension arrays containing only numbers,
569
+ // except 'alpha' which is a number.
570
+ var result = new Color();
571
+ var source = this.values;
572
+ var target = result.values;
573
+ var value, type;
574
+
575
+ for (var prop in source) {
576
+ if (source.hasOwnProperty(prop)) {
577
+ value = source[prop];
578
+ type = ({}).toString.call(value);
579
+ if (type === '[object Array]') {
580
+ target[prop] = value.slice(0);
581
+ } else if (type === '[object Number]') {
582
+ target[prop] = value;
583
+ } else {
584
+ console.error('unexpected color value:', value);
585
+ }
586
+ }
587
+ }
588
 
589
+ return result;
590
+ }
591
+ };
592
+
593
+ Color.prototype.spaces = {
594
+ rgb: ['red', 'green', 'blue'],
595
+ hsl: ['hue', 'saturation', 'lightness'],
596
+ hsv: ['hue', 'saturation', 'value'],
597
+ hwb: ['hue', 'whiteness', 'blackness'],
598
+ cmyk: ['cyan', 'magenta', 'yellow', 'black']
599
+ };
600
+
601
+ Color.prototype.maxes = {
602
+ rgb: [255, 255, 255],
603
+ hsl: [360, 100, 100],
604
+ hsv: [360, 100, 100],
605
+ hwb: [360, 100, 100],
606
+ cmyk: [100, 100, 100, 100]
607
+ };
608
+
609
+ Color.prototype.getValues = function (space) {
610
+ var values = this.values;
611
+ var vals = {};
612
+
613
+ for (var i = 0; i < space.length; i++) {
614
+ vals[space.charAt(i)] = values[space][i];
615
+ }
616
 
617
+ if (values.alpha !== 1) {
618
+ vals.a = values.alpha;
619
+ }
 
 
 
 
620
 
621
+ // {r: 255, g: 255, b: 255, a: 0.4}
622
+ return vals;
623
+ };
624
+
625
+ Color.prototype.setValues = function (space, vals) {
626
+ var values = this.values;
627
+ var spaces = this.spaces;
628
+ var maxes = this.maxes;
629
+ var alpha = 1;
630
+ var i;
631
+
632
+ this.valid = true;
633
+
634
+ if (space === 'alpha') {
635
+ alpha = vals;
636
+ } else if (vals.length) {
637
+ // [10, 10, 10]
638
+ values[space] = vals.slice(0, space.length);
639
+ alpha = vals[space.length];
640
+ } else if (vals[space.charAt(0)] !== undefined) {
641
+ // {r: 10, g: 10, b: 10}
642
+ for (i = 0; i < space.length; i++) {
643
+ values[space][i] = vals[space.charAt(i)];
644
+ }
645
 
646
+ alpha = vals.a;
647
+ } else if (vals[spaces[space][0]] !== undefined) {
648
+ // {red: 10, green: 10, blue: 10}
649
+ var chans = spaces[space];
650
 
651
+ for (i = 0; i < space.length; i++) {
652
+ values[space][i] = vals[chans[i]];
653
+ }
654
 
655
+ alpha = vals.alpha;
656
+ }
657
 
658
+ values.alpha = Math.max(0, Math.min(1, (alpha === undefined ? values.alpha : alpha)));
 
659
 
660
+ if (space === 'alpha') {
661
+ return false;
662
+ }
663
 
664
+ var capped;
 
665
 
666
+ // cap values of the space prior converting all values
667
+ for (i = 0; i < space.length; i++) {
668
+ capped = Math.max(0, Math.min(maxes[space][i], values[space][i]));
669
+ values[space][i] = Math.round(capped);
670
+ }
671
 
672
+ // convert to all the other color spaces
673
+ for (var sname in spaces) {
674
+ if (sname !== space) {
675
+ values[sname] = convert[space][sname](values[space]);
676
+ }
677
+ }
678
 
679
+ return true;
680
+ };
681
 
682
+ Color.prototype.setSpace = function (space, args) {
683
+ var vals = args[0];
684
 
685
+ if (vals === undefined) {
686
+ // color.rgb()
687
+ return this.getValues(space);
688
+ }
689
 
690
+ // color.rgb(10, 10, 10)
691
+ if (typeof vals === 'number') {
692
+ vals = Array.prototype.slice.call(args);
693
+ }
694
 
695
+ this.setValues(space, vals);
696
+ return this;
697
+ };
698
+
699
+ Color.prototype.setChannel = function (space, index, val) {
700
+ var svalues = this.values[space];
701
+ if (val === undefined) {
702
+ // color.red()
703
+ return svalues[index];
704
+ } else if (val === svalues[index]) {
705
+ // color.red(color.red())
706
+ return this;
707
+ }
708
 
709
+ // color.red(100)
710
+ svalues[index] = val;
711
+ this.setValues(space, svalues);
712
+
713
+ return this;
714
+ };
715
+
716
+ if (typeof window !== 'undefined') {
717
+ window.Color = Color;
718
+ }
719
+
720
+ module.exports = Color;
721
+
722
+ },{"2":2,"5":5}],4:[function(require,module,exports){
723
+ /* MIT license */
724
+
725
+ module.exports = {
726
+ rgb2hsl: rgb2hsl,
727
+ rgb2hsv: rgb2hsv,
728
+ rgb2hwb: rgb2hwb,
729
+ rgb2cmyk: rgb2cmyk,
730
+ rgb2keyword: rgb2keyword,
731
+ rgb2xyz: rgb2xyz,
732
+ rgb2lab: rgb2lab,
733
+ rgb2lch: rgb2lch,
734
+
735
+ hsl2rgb: hsl2rgb,
736
+ hsl2hsv: hsl2hsv,
737
+ hsl2hwb: hsl2hwb,
738
+ hsl2cmyk: hsl2cmyk,
739
+ hsl2keyword: hsl2keyword,
740
+
741
+ hsv2rgb: hsv2rgb,
742
+ hsv2hsl: hsv2hsl,
743
+ hsv2hwb: hsv2hwb,
744
+ hsv2cmyk: hsv2cmyk,
745
+ hsv2keyword: hsv2keyword,
746
+
747
+ hwb2rgb: hwb2rgb,
748
+ hwb2hsl: hwb2hsl,
749
+ hwb2hsv: hwb2hsv,
750
+ hwb2cmyk: hwb2cmyk,
751
+ hwb2keyword: hwb2keyword,
752
+
753
+ cmyk2rgb: cmyk2rgb,
754
+ cmyk2hsl: cmyk2hsl,
755
+ cmyk2hsv: cmyk2hsv,
756
+ cmyk2hwb: cmyk2hwb,
757
+ cmyk2keyword: cmyk2keyword,
758
+
759
+ keyword2rgb: keyword2rgb,
760
+ keyword2hsl: keyword2hsl,
761
+ keyword2hsv: keyword2hsv,
762
+ keyword2hwb: keyword2hwb,
763
+ keyword2cmyk: keyword2cmyk,
764
+ keyword2lab: keyword2lab,
765
+ keyword2xyz: keyword2xyz,
766
+
767
+ xyz2rgb: xyz2rgb,
768
+ xyz2lab: xyz2lab,
769
+ xyz2lch: xyz2lch,
770
+
771
+ lab2xyz: lab2xyz,
772
+ lab2rgb: lab2rgb,
773
+ lab2lch: lab2lch,
774
+
775
+ lch2lab: lch2lab,
776
+ lch2xyz: lch2xyz,
777
+ lch2rgb: lch2rgb
778
+ }
779
+
780
+
781
+ function rgb2hsl(rgb) {
782
+ var r = rgb[0]/255,
783
+ g = rgb[1]/255,
784
+ b = rgb[2]/255,
785
+ min = Math.min(r, g, b),
786
+ max = Math.max(r, g, b),
787
+ delta = max - min,
788
+ h, s, l;
789
+
790
+ if (max == min)
791
+ h = 0;
792
+ else if (r == max)
793
+ h = (g - b) / delta;
794
+ else if (g == max)
795
+ h = 2 + (b - r) / delta;
796
+ else if (b == max)
797
+ h = 4 + (r - g)/ delta;
798
+
799
+ h = Math.min(h * 60, 360);
800
+
801
+ if (h < 0)
802
+ h += 360;
803
+
804
+ l = (min + max) / 2;
805
+
806
+ if (max == min)
807
+ s = 0;
808
+ else if (l <= 0.5)
809
+ s = delta / (max + min);
810
+ else
811
+ s = delta / (2 - max - min);
812
+
813
+ return [h, s * 100, l * 100];
814
+ }
815
+
816
+ function rgb2hsv(rgb) {
817
+ var r = rgb[0],
818
+ g = rgb[1],
819
+ b = rgb[2],
820
+ min = Math.min(r, g, b),
821
+ max = Math.max(r, g, b),
822
+ delta = max - min,
823
+ h, s, v;
824
+
825
+ if (max == 0)
826
+ s = 0;
827
+ else
828
+ s = (delta/max * 1000)/10;
829
+
830
+ if (max == min)
831
+ h = 0;
832
+ else if (r == max)
833
+ h = (g - b) / delta;
834
+ else if (g == max)
835
+ h = 2 + (b - r) / delta;
836
+ else if (b == max)
837
+ h = 4 + (r - g) / delta;
838
+
839
+ h = Math.min(h * 60, 360);
840
+
841
+ if (h < 0)
842
+ h += 360;
843
+
844
+ v = ((max / 255) * 1000) / 10;
845
+
846
+ return [h, s, v];
847
+ }
848
+
849
+ function rgb2hwb(rgb) {
850
+ var r = rgb[0],
851
+ g = rgb[1],
852
+ b = rgb[2],
853
+ h = rgb2hsl(rgb)[0],
854
+ w = 1/255 * Math.min(r, Math.min(g, b)),
855
+ b = 1 - 1/255 * Math.max(r, Math.max(g, b));
856
+
857
+ return [h, w * 100, b * 100];
858
+ }
859
+
860
+ function rgb2cmyk(rgb) {
861
+ var r = rgb[0] / 255,
862
+ g = rgb[1] / 255,
863
+ b = rgb[2] / 255,
864
+ c, m, y, k;
865
+
866
+ k = Math.min(1 - r, 1 - g, 1 - b);
867
+ c = (1 - r - k) / (1 - k) || 0;
868
+ m = (1 - g - k) / (1 - k) || 0;
869
+ y = (1 - b - k) / (1 - k) || 0;
870
+ return [c * 100, m * 100, y * 100, k * 100];
871
+ }
872
+
873
+ function rgb2keyword(rgb) {
874
+ return reverseKeywords[JSON.stringify(rgb)];
875
+ }
876
+
877
+ function rgb2xyz(rgb) {
878
+ var r = rgb[0] / 255,
879
+ g = rgb[1] / 255,
880
+ b = rgb[2] / 255;
881
+
882
+ // assume sRGB
883
+ r = r > 0.04045 ? Math.pow(((r + 0.055) / 1.055), 2.4) : (r / 12.92);
884
+ g = g > 0.04045 ? Math.pow(((g + 0.055) / 1.055), 2.4) : (g / 12.92);
885
+ b = b > 0.04045 ? Math.pow(((b + 0.055) / 1.055), 2.4) : (b / 12.92);
886
+
887
+ var x = (r * 0.4124) + (g * 0.3576) + (b * 0.1805);
888
+ var y = (r * 0.2126) + (g * 0.7152) + (b * 0.0722);
889
+ var z = (r * 0.0193) + (g * 0.1192) + (b * 0.9505);
890
+
891
+ return [x * 100, y *100, z * 100];
892
+ }
893
+
894
+ function rgb2lab(rgb) {
895
+ var xyz = rgb2xyz(rgb),
896
+ x = xyz[0],
897
+ y = xyz[1],
898
+ z = xyz[2],
899
+ l, a, b;
900
+
901
+ x /= 95.047;
902
+ y /= 100;
903
+ z /= 108.883;
904
+
905
+ x = x > 0.008856 ? Math.pow(x, 1/3) : (7.787 * x) + (16 / 116);
906
+ y = y > 0.008856 ? Math.pow(y, 1/3) : (7.787 * y) + (16 / 116);
907
+ z = z > 0.008856 ? Math.pow(z, 1/3) : (7.787 * z) + (16 / 116);
908
+
909
+ l = (116 * y) - 16;
910
+ a = 500 * (x - y);
911
+ b = 200 * (y - z);
912
+
913
+ return [l, a, b];
914
+ }
915
+
916
+ function rgb2lch(args) {
917
+ return lab2lch(rgb2lab(args));
918
+ }
919
+
920
+ function hsl2rgb(hsl) {
921
+ var h = hsl[0] / 360,
922
+ s = hsl[1] / 100,
923
+ l = hsl[2] / 100,
924
+ t1, t2, t3, rgb, val;
925
+
926
+ if (s == 0) {
927
+ val = l * 255;
928
+ return [val, val, val];
929
+ }
930
+
931
+ if (l < 0.5)
932
+ t2 = l * (1 + s);
933
+ else
934
+ t2 = l + s - l * s;
935
+ t1 = 2 * l - t2;
936
+
937
+ rgb = [0, 0, 0];
938
+ for (var i = 0; i < 3; i++) {
939
+ t3 = h + 1 / 3 * - (i - 1);
940
+ t3 < 0 && t3++;
941
+ t3 > 1 && t3--;
942
+
943
+ if (6 * t3 < 1)
944
+ val = t1 + (t2 - t1) * 6 * t3;
945
+ else if (2 * t3 < 1)
946
+ val = t2;
947
+ else if (3 * t3 < 2)
948
+ val = t1 + (t2 - t1) * (2 / 3 - t3) * 6;
949
+ else
950
+ val = t1;
951
+
952
+ rgb[i] = val * 255;
953
+ }
954
+
955
+ return rgb;
956
+ }
957
+
958
+ function hsl2hsv(hsl) {
959
+ var h = hsl[0],
960
+ s = hsl[1] / 100,
961
+ l = hsl[2] / 100,
962
+ sv, v;
963
+
964
+ if(l === 0) {
965
+ // no need to do calc on black
966
+ // also avoids divide by 0 error
967
+ return [0, 0, 0];
968
+ }
969
+
970
+ l *= 2;
971
+ s *= (l <= 1) ? l : 2 - l;
972
+ v = (l + s) / 2;
973
+ sv = (2 * s) / (l + s);
974
+ return [h, sv * 100, v * 100];
975
+ }
976
+
977
+ function hsl2hwb(args) {
978
+ return rgb2hwb(hsl2rgb(args));
979
+ }
980
+
981
+ function hsl2cmyk(args) {
982
+ return rgb2cmyk(hsl2rgb(args));
983
+ }
984
+
985
+ function hsl2keyword(args) {
986
+ return rgb2keyword(hsl2rgb(args));
987
+ }
988
+
989
+
990
+ function hsv2rgb(hsv) {
991
+ var h = hsv[0] / 60,
992
+ s = hsv[1] / 100,
993
+ v = hsv[2] / 100,
994
+ hi = Math.floor(h) % 6;
995
+
996
+ var f = h - Math.floor(h),
997
+ p = 255 * v * (1 - s),
998
+ q = 255 * v * (1 - (s * f)),
999
+ t = 255 * v * (1 - (s * (1 - f))),
1000
+ v = 255 * v;
1001
+
1002
+ switch(hi) {
1003
+ case 0:
1004
+ return [v, t, p];
1005
+ case 1:
1006
+ return [q, v, p];
1007
+ case 2:
1008
+ return [p, v, t];
1009
+ case 3:
1010
+ return [p, q, v];
1011
+ case 4:
1012
+ return [t, p, v];
1013
+ case 5:
1014
+ return [v, p, q];
1015
+ }
1016
+ }
1017
+
1018
+ function hsv2hsl(hsv) {
1019
+ var h = hsv[0],
1020
+ s = hsv[1] / 100,
1021
+ v = hsv[2] / 100,
1022
+ sl, l;
1023
+
1024
+ l = (2 - s) * v;
1025
+ sl = s * v;
1026
+ sl /= (l <= 1) ? l : 2 - l;
1027
+ sl = sl || 0;
1028
+ l /= 2;
1029
+ return [h, sl * 100, l * 100];
1030
+ }
1031
+
1032
+ function hsv2hwb(args) {
1033
+ return rgb2hwb(hsv2rgb(args))
1034
+ }
1035
+
1036
+ function hsv2cmyk(args) {
1037
+ return rgb2cmyk(hsv2rgb(args));
1038
+ }
1039
+
1040
+ function hsv2keyword(args) {
1041
+ return rgb2keyword(hsv2rgb(args));
1042
+ }
1043
+
1044
+ // http://dev.w3.org/csswg/css-color/#hwb-to-rgb
1045
+ function hwb2rgb(hwb) {
1046
+ var h = hwb[0] / 360,
1047
+ wh = hwb[1] / 100,
1048
+ bl = hwb[2] / 100,
1049
+ ratio = wh + bl,
1050
+ i, v, f, n;
1051
+
1052
+ // wh + bl cant be > 1
1053
+ if (ratio > 1) {
1054
+ wh /= ratio;
1055
+ bl /= ratio;
1056
+ }
1057
+
1058
+ i = Math.floor(6 * h);
1059
+ v = 1 - bl;
1060
+ f = 6 * h - i;
1061
+ if ((i & 0x01) != 0) {
1062
+ f = 1 - f;
1063
+ }
1064
+ n = wh + f * (v - wh); // linear interpolation
1065
+
1066
+ switch (i) {
1067
+ default:
1068
+ case 6:
1069
+ case 0: r = v; g = n; b = wh; break;
1070
+ case 1: r = n; g = v; b = wh; break;
1071
+ case 2: r = wh; g = v; b = n; break;
1072
+ case 3: r = wh; g = n; b = v; break;
1073
+ case 4: r = n; g = wh; b = v; break;
1074
+ case 5: r = v; g = wh; b = n; break;
1075
+ }
1076
+
1077
+ return [r * 255, g * 255, b * 255];
1078
+ }
1079
+
1080
+ function hwb2hsl(args) {
1081
+ return rgb2hsl(hwb2rgb(args));
1082
+ }
1083
+
1084
+ function hwb2hsv(args) {
1085
+ return rgb2hsv(hwb2rgb(args));
1086
+ }
1087
+
1088
+ function hwb2cmyk(args) {
1089
+ return rgb2cmyk(hwb2rgb(args));
1090
+ }
1091
+
1092
+ function hwb2keyword(args) {
1093
+ return rgb2keyword(hwb2rgb(args));
1094
+ }
1095
+
1096
+ function cmyk2rgb(cmyk) {
1097
+ var c = cmyk[0] / 100,
1098
+ m = cmyk[1] / 100,
1099
+ y = cmyk[2] / 100,
1100
+ k = cmyk[3] / 100,
1101
+ r, g, b;
1102
+
1103
+ r = 1 - Math.min(1, c * (1 - k) + k);
1104
+ g = 1 - Math.min(1, m * (1 - k) + k);
1105
+ b = 1 - Math.min(1, y * (1 - k) + k);
1106
+ return [r * 255, g * 255, b * 255];
1107
+ }
1108
+
1109
+ function cmyk2hsl(args) {
1110
+ return rgb2hsl(cmyk2rgb(args));
1111
+ }
1112
+
1113
+ function cmyk2hsv(args) {
1114
+ return rgb2hsv(cmyk2rgb(args));
1115
+ }
1116
+
1117
+ function cmyk2hwb(args) {
1118
+ return rgb2hwb(cmyk2rgb(args));
1119
+ }
1120
+
1121
+ function cmyk2keyword(args) {
1122
+ return rgb2keyword(cmyk2rgb(args));
1123
+ }
1124
+
1125
+
1126
+ function xyz2rgb(xyz) {
1127
+ var x = xyz[0] / 100,
1128
+ y = xyz[1] / 100,
1129
+ z = xyz[2] / 100,
1130
+ r, g, b;
1131
+
1132
+ r = (x * 3.2406) + (y * -1.5372) + (z * -0.4986);
1133
+ g = (x * -0.9689) + (y * 1.8758) + (z * 0.0415);
1134
+ b = (x * 0.0557) + (y * -0.2040) + (z * 1.0570);
1135
+
1136
+ // assume sRGB
1137
+ r = r > 0.0031308 ? ((1.055 * Math.pow(r, 1.0 / 2.4)) - 0.055)
1138
+ : r = (r * 12.92);
1139
+
1140
+ g = g > 0.0031308 ? ((1.055 * Math.pow(g, 1.0 / 2.4)) - 0.055)
1141
+ : g = (g * 12.92);
1142
+
1143
+ b = b > 0.0031308 ? ((1.055 * Math.pow(b, 1.0 / 2.4)) - 0.055)
1144
+ : b = (b * 12.92);
1145
+
1146
+ r = Math.min(Math.max(0, r), 1);
1147
+ g = Math.min(Math.max(0, g), 1);
1148
+ b = Math.min(Math.max(0, b), 1);
1149
+
1150
+ return [r * 255, g * 255, b * 255];
1151
+ }
1152
+
1153
+ function xyz2lab(xyz) {
1154
+ var x = xyz[0],
1155
+ y = xyz[1],
1156
+ z = xyz[2],
1157
+ l, a, b;
1158
+
1159
+ x /= 95.047;
1160
+ y /= 100;
1161
+ z /= 108.883;
1162
+
1163
+ x = x > 0.008856 ? Math.pow(x, 1/3) : (7.787 * x) + (16 / 116);
1164
+ y = y > 0.008856 ? Math.pow(y, 1/3) : (7.787 * y) + (16 / 116);
1165
+ z = z > 0.008856 ? Math.pow(z, 1/3) : (7.787 * z) + (16 / 116);
1166
+
1167
+ l = (116 * y) - 16;
1168
+ a = 500 * (x - y);
1169
+ b = 200 * (y - z);
1170
+
1171
+ return [l, a, b];
1172
+ }
1173
+
1174
+ function xyz2lch(args) {
1175
+ return lab2lch(xyz2lab(args));
1176
+ }
1177
+
1178
+ function lab2xyz(lab) {
1179
+ var l = lab[0],
1180
+ a = lab[1],
1181
+ b = lab[2],
1182
+ x, y, z, y2;
1183
+
1184
+ if (l <= 8) {
1185
+ y = (l * 100) / 903.3;
1186
+ y2 = (7.787 * (y / 100)) + (16 / 116);
1187
+ } else {
1188
+ y = 100 * Math.pow((l + 16) / 116, 3);
1189
+ y2 = Math.pow(y / 100, 1/3);
1190
+ }
1191
+
1192
+ x = x / 95.047 <= 0.008856 ? x = (95.047 * ((a / 500) + y2 - (16 / 116))) / 7.787 : 95.047 * Math.pow((a / 500) + y2, 3);
1193
+
1194
+ z = z / 108.883 <= 0.008859 ? z = (108.883 * (y2 - (b / 200) - (16 / 116))) / 7.787 : 108.883 * Math.pow(y2 - (b / 200), 3);
1195
+
1196
+ return [x, y, z];
1197
+ }
1198
+
1199
+ function lab2lch(lab) {
1200
+ var l = lab[0],
1201
+ a = lab[1],
1202
+ b = lab[2],
1203
+ hr, h, c;
1204
+
1205
+ hr = Math.atan2(b, a);
1206
+ h = hr * 360 / 2 / Math.PI;
1207
+ if (h < 0) {
1208
+ h += 360;
1209
+ }
1210
+ c = Math.sqrt(a * a + b * b);
1211
+ return [l, c, h];
1212
+ }
1213
+
1214
+ function lab2rgb(args) {
1215
+ return xyz2rgb(lab2xyz(args));
1216
+ }
1217
+
1218
+ function lch2lab(lch) {
1219
+ var l = lch[0],
1220
+ c = lch[1],
1221
+ h = lch[2],
1222
+ a, b, hr;
1223
+
1224
+ hr = h / 360 * 2 * Math.PI;
1225
+ a = c * Math.cos(hr);
1226
+ b = c * Math.sin(hr);
1227
+ return [l, a, b];
1228
+ }
1229
+
1230
+ function lch2xyz(args) {
1231
+ return lab2xyz(lch2lab(args));
1232
+ }
1233
+
1234
+ function lch2rgb(args) {
1235
+ return lab2rgb(lch2lab(args));
1236
+ }
1237
+
1238
+ function keyword2rgb(keyword) {
1239
+ return cssKeywords[keyword];
1240
+ }
1241
+
1242
+ function keyword2hsl(args) {
1243
+ return rgb2hsl(keyword2rgb(args));
1244
+ }
1245
+
1246
+ function keyword2hsv(args) {
1247
+ return rgb2hsv(keyword2rgb(args));
1248
+ }
1249
+
1250
+ function keyword2hwb(args) {
1251
+ return rgb2hwb(keyword2rgb(args));
1252
+ }
1253
+
1254
+ function keyword2cmyk(args) {
1255
+ return rgb2cmyk(keyword2rgb(args));
1256
+ }
1257
+
1258
+ function keyword2lab(args) {
1259
+ return rgb2lab(keyword2rgb(args));
1260
+ }
1261
+
1262
+ function keyword2xyz(args) {
1263
+ return rgb2xyz(keyword2rgb(args));
1264
+ }
1265
+
1266
+ var cssKeywords = {
1267
+ aliceblue: [240,248,255],
1268
+ antiquewhite: [250,235,215],
1269
+ aqua: [0,255,255],
1270
+ aquamarine: [127,255,212],
1271
+ azure: [240,255,255],
1272
+ beige: [245,245,220],
1273
+ bisque: [255,228,196],
1274
+ black: [0,0,0],
1275
+ blanchedalmond: [255,235,205],
1276
+ blue: [0,0,255],
1277
+ blueviolet: [138,43,226],
1278
+ brown: [165,42,42],
1279
+ burlywood: [222,184,135],
1280
+ cadetblue: [95,158,160],
1281
+ chartreuse: [127,255,0],
1282
+ chocolate: [210,105,30],
1283
+ coral: [255,127,80],
1284
+ cornflowerblue: [100,149,237],
1285
+ cornsilk: [255,248,220],
1286
+ crimson: [220,20,60],
1287
+ cyan: [0,255,255],
1288
+ darkblue: [0,0,139],
1289
+ darkcyan: [0,139,139],
1290
+ darkgoldenrod: [184,134,11],
1291
+ darkgray: [169,169,169],
1292
+ darkgreen: [0,100,0],
1293
+ darkgrey: [169,169,169],
1294
+ darkkhaki: [189,183,107],
1295
+ darkmagenta: [139,0,139],
1296
+ darkolivegreen: [85,107,47],
1297
+ darkorange: [255,140,0],
1298
+ darkorchid: [153,50,204],
1299
+ darkred: [139,0,0],
1300
+ darksalmon: [233,150,122],
1301
+ darkseagreen: [143,188,143],
1302
+ darkslateblue: [72,61,139],
1303
+ darkslategray: [47,79,79],
1304
+ darkslategrey: [47,79,79],
1305
+ darkturquoise: [0,206,209],
1306
+ darkviolet: [148,0,211],
1307
+ deeppink: [255,20,147],
1308
+ deepskyblue: [0,191,255],
1309
+ dimgray: [105,105,105],
1310
+ dimgrey: [105,105,105],
1311
+ dodgerblue: [30,144,255],
1312
+ firebrick: [178,34,34],
1313
+ floralwhite: [255,250,240],
1314
+ forestgreen: [34,139,34],
1315
+ fuchsia: [255,0,255],
1316
+ gainsboro: [220,220,220],
1317
+ ghostwhite: [248,248,255],
1318
+ gold: [255,215,0],
1319
+ goldenrod: [218,165,32],
1320
+ gray: [128,128,128],
1321
+ green: [0,128,0],
1322
+ greenyellow: [173,255,47],
1323
+ grey: [128,128,128],
1324
+ honeydew: [240,255,240],
1325
+ hotpink: [255,105,180],
1326
+ indianred: [205,92,92],
1327
+ indigo: [75,0,130],
1328
+ ivory: [255,255,240],
1329
+ khaki: [240,230,140],
1330
+ lavender: [230,230,250],
1331
+ lavenderblush: [255,240,245],
1332
+ lawngreen: [124,252,0],
1333
+ lemonchiffon: [255,250,205],
1334
+ lightblue: [173,216,230],
1335
+ lightcoral: [240,128,128],
1336
+ lightcyan: [224,255,255],
1337
+ lightgoldenrodyellow: [250,250,210],
1338
+ lightgray: [211,211,211],
1339
+ lightgreen: [144,238,144],
1340
+ lightgrey: [211,211,211],
1341
+ lightpink: [255,182,193],
1342
+ lightsalmon: [255,160,122],
1343
+ lightseagreen: [32,178,170],
1344
+ lightskyblue: [135,206,250],
1345
+ lightslategray: [119,136,153],
1346
+ lightslategrey: [119,136,153],
1347
+ lightsteelblue: [176,196,222],
1348
+ lightyellow: [255,255,224],
1349
+ lime: [0,255,0],
1350
+ limegreen: [50,205,50],
1351
+ linen: [250,240,230],
1352
+ magenta: [255,0,255],
1353
+ maroon: [128,0,0],
1354
+ mediumaquamarine: [102,205,170],
1355
+ mediumblue: [0,0,205],
1356
+ mediumorchid: [186,85,211],
1357
+ mediumpurple: [147,112,219],
1358
+ mediumseagreen: [60,179,113],
1359
+ mediumslateblue: [123,104,238],
1360
+ mediumspringgreen: [0,250,154],
1361
+ mediumturquoise: [72,209,204],
1362
+ mediumvioletred: [199,21,133],
1363
+ midnightblue: [25,25,112],
1364
+ mintcream: [245,255,250],
1365
+ mistyrose: [255,228,225],
1366
+ moccasin: [255,228,181],
1367
+ navajowhite: [255,222,173],
1368
+ navy: [0,0,128],
1369
+ oldlace: [253,245,230],
1370
+ olive: [128,128,0],
1371
+ olivedrab: [107,142,35],
1372
+ orange: [255,165,0],
1373
+ orangered: [255,69,0],
1374
+ orchid: [218,112,214],
1375
+ palegoldenrod: [238,232,170],
1376
+ palegreen: [152,251,152],
1377
+ paleturquoise: [175,238,238],
1378
+ palevioletred: [219,112,147],
1379
+ papayawhip: [255,239,213],
1380
+ peachpuff: [255,218,185],
1381
+ peru: [205,133,63],
1382
+ pink: [255,192,203],
1383
+ plum: [221,160,221],
1384
+ powderblue: [176,224,230],
1385
+ purple: [128,0,128],
1386
+ rebeccapurple: [102, 51, 153],
1387
+ red: [255,0,0],
1388
+ rosybrown: [188,143,143],
1389
+ royalblue: [65,105,225],
1390
+ saddlebrown: [139,69,19],
1391
+ salmon: [250,128,114],
1392
+ sandybrown: [244,164,96],
1393
+ seagreen: [46,139,87],
1394
+ seashell: [255,245,238],
1395
+ sienna: [160,82,45],
1396
+ silver: [192,192,192],
1397
+ skyblue: [135,206,235],
1398
+ slateblue: [106,90,205],
1399
+ slategray: [112,128,144],
1400
+ slategrey: [112,128,144],
1401
+ snow: [255,250,250],
1402
+ springgreen: [0,255,127],
1403
+ steelblue: [70,130,180],
1404
+ tan: [210,180,140],
1405
+ teal: [0,128,128],
1406
+ thistle: [216,191,216],
1407
+ tomato: [255,99,71],
1408
+ turquoise: [64,224,208],
1409
+ violet: [238,130,238],
1410
+ wheat: [245,222,179],
1411
+ white: [255,255,255],
1412
+ whitesmoke: [245,245,245],
1413
+ yellow: [255,255,0],
1414
+ yellowgreen: [154,205,50]
1415
+ };
1416
+
1417
+ var reverseKeywords = {};
1418
+ for (var key in cssKeywords) {
1419
+ reverseKeywords[JSON.stringify(cssKeywords[key])] = key;
1420
+ }
1421
+
1422
+ },{}],5:[function(require,module,exports){
1423
+ var conversions = require(4);
1424
+
1425
+ var convert = function() {
1426
+ return new Converter();
1427
+ }
1428
+
1429
+ for (var func in conversions) {
1430
+ // export Raw versions
1431
+ convert[func + "Raw"] = (function(func) {
1432
+ // accept array or plain args
1433
+ return function(arg) {
1434
+ if (typeof arg == "number")
1435
+ arg = Array.prototype.slice.call(arguments);
1436
+ return conversions[func](arg);
1437
+ }
1438
+ })(func);
1439
+
1440
+ var pair = /(\w+)2(\w+)/.exec(func),
1441
+ from = pair[1],
1442
+ to = pair[2];
1443
+
1444
+ // export rgb2hsl and ["rgb"]["hsl"]
1445
+ convert[from] = convert[from] || {};
1446
+
1447
+ convert[from][to] = convert[func] = (function(func) {
1448
+ return function(arg) {
1449
+ if (typeof arg == "number")
1450
+ arg = Array.prototype.slice.call(arguments);
1451
+
1452
+ var val = conversions[func](arg);
1453
+ if (typeof val == "string" || val === undefined)
1454
+ return val; // keyword
1455
+
1456
+ for (var i = 0; i < val.length; i++)
1457
+ val[i] = Math.round(val[i]);
1458
+ return val;
1459
+ }
1460
+ })(func);
1461
+ }
1462
+
1463
+
1464
+ /* Converter does lazy conversion and caching */
1465
+ var Converter = function() {
1466
+ this.convs = {};
1467
+ };
1468
+
1469
+ /* Either get the values for a space or
1470
+ set the values for a space, depending on args */
1471
+ Converter.prototype.routeSpace = function(space, args) {
1472
+ var values = args[0];
1473
+ if (values === undefined) {
1474
+ // color.rgb()
1475
+ return this.getValues(space);
1476
+ }
1477
+ // color.rgb(10, 10, 10)
1478
+ if (typeof values == "number") {
1479
+ values = Array.prototype.slice.call(args);
1480
+ }
1481
+
1482
+ return this.setValues(space, values);
1483
+ };
1484
+
1485
+ /* Set the values for a space, invalidating cache */
1486
+ Converter.prototype.setValues = function(space, values) {
1487
+ this.space = space;
1488
+ this.convs = {};
1489
+ this.convs[space] = values;
1490
+ return this;
1491
+ };
1492
+
1493
+ /* Get the values for a space. If there's already
1494
+ a conversion for the space, fetch it, otherwise
1495
+ compute it */
1496
+ Converter.prototype.getValues = function(space) {
1497
+ var vals = this.convs[space];
1498
+ if (!vals) {
1499
+ var fspace = this.space,
1500
+ from = this.convs[fspace];
1501
+ vals = convert[fspace][space](from);
1502
+
1503
+ this.convs[space] = vals;
1504
+ }
1505
+ return vals;
1506
+ };
1507
+
1508
+ ["rgb", "hsl", "hsv", "cmyk", "keyword"].forEach(function(space) {
1509
+ Converter.prototype[space] = function(vals) {
1510
+ return this.routeSpace(space, arguments);
1511
+ }
1512
+ });
1513
+
1514
+ module.exports = convert;
1515
+ },{"4":4}],6:[function(require,module,exports){
1516
+ 'use strict'
1517
+
1518
+ module.exports = {
1519
+ "aliceblue": [240, 248, 255],
1520
+ "antiquewhite": [250, 235, 215],
1521
+ "aqua": [0, 255, 255],
1522
+ "aquamarine": [127, 255, 212],
1523
+ "azure": [240, 255, 255],
1524
+ "beige": [245, 245, 220],
1525
+ "bisque": [255, 228, 196],
1526
+ "black": [0, 0, 0],
1527
+ "blanchedalmond": [255, 235, 205],
1528
+ "blue": [0, 0, 255],
1529
+ "blueviolet": [138, 43, 226],
1530
+ "brown": [165, 42, 42],
1531
+ "burlywood": [222, 184, 135],
1532
+ "cadetblue": [95, 158, 160],
1533
+ "chartreuse": [127, 255, 0],
1534
+ "chocolate": [210, 105, 30],
1535
+ "coral": [255, 127, 80],
1536
+ "cornflowerblue": [100, 149, 237],
1537
+ "cornsilk": [255, 248, 220],
1538
+ "crimson": [220, 20, 60],
1539
+ "cyan": [0, 255, 255],
1540
+ "darkblue": [0, 0, 139],
1541
+ "darkcyan": [0, 139, 139],
1542
+ "darkgoldenrod": [184, 134, 11],
1543
+ "darkgray": [169, 169, 169],
1544
+ "darkgreen": [0, 100, 0],
1545
+ "darkgrey": [169, 169, 169],
1546
+ "darkkhaki": [189, 183, 107],
1547
+ "darkmagenta": [139, 0, 139],
1548
+ "darkolivegreen": [85, 107, 47],
1549
+ "darkorange": [255, 140, 0],
1550
+ "darkorchid": [153, 50, 204],
1551
+ "darkred": [139, 0, 0],
1552
+ "darksalmon": [233, 150, 122],
1553
+ "darkseagreen": [143, 188, 143],
1554
+ "darkslateblue": [72, 61, 139],
1555
+ "darkslategray": [47, 79, 79],
1556
+ "darkslategrey": [47, 79, 79],
1557
+ "darkturquoise": [0, 206, 209],
1558
+ "darkviolet": [148, 0, 211],
1559
+ "deeppink": [255, 20, 147],
1560
+ "deepskyblue": [0, 191, 255],
1561
+ "dimgray": [105, 105, 105],
1562
+ "dimgrey": [105, 105, 105],
1563
+ "dodgerblue": [30, 144, 255],
1564
+ "firebrick": [178, 34, 34],
1565
+ "floralwhite": [255, 250, 240],
1566
+ "forestgreen": [34, 139, 34],
1567
+ "fuchsia": [255, 0, 255],
1568
+ "gainsboro": [220, 220, 220],
1569
+ "ghostwhite": [248, 248, 255],
1570
+ "gold": [255, 215, 0],
1571
+ "goldenrod": [218, 165, 32],
1572
+ "gray": [128, 128, 128],
1573
+ "green": [0, 128, 0],
1574
+ "greenyellow": [173, 255, 47],
1575
+ "grey": [128, 128, 128],
1576
+ "honeydew": [240, 255, 240],
1577
+ "hotpink": [255, 105, 180],
1578
+ "indianred": [205, 92, 92],
1579
+ "indigo": [75, 0, 130],
1580
+ "ivory": [255, 255, 240],
1581
+ "khaki": [240, 230, 140],
1582
+ "lavender": [230, 230, 250],
1583
+ "lavenderblush": [255, 240, 245],
1584
+ "lawngreen": [124, 252, 0],
1585
+ "lemonchiffon": [255, 250, 205],
1586
+ "lightblue": [173, 216, 230],
1587
+ "lightcoral": [240, 128, 128],
1588
+ "lightcyan": [224, 255, 255],
1589
+ "lightgoldenrodyellow": [250, 250, 210],
1590
+ "lightgray": [211, 211, 211],
1591
+ "lightgreen": [144, 238, 144],
1592
+ "lightgrey": [211, 211, 211],
1593
+ "lightpink": [255, 182, 193],
1594
+ "lightsalmon": [255, 160, 122],
1595
+ "lightseagreen": [32, 178, 170],
1596
+ "lightskyblue": [135, 206, 250],
1597
+ "lightslategray": [119, 136, 153],
1598
+ "lightslategrey": [119, 136, 153],
1599
+ "lightsteelblue": [176, 196, 222],
1600
+ "lightyellow": [255, 255, 224],
1601
+ "lime": [0, 255, 0],
1602
+ "limegreen": [50, 205, 50],
1603
+ "linen": [250, 240, 230],
1604
+ "magenta": [255, 0, 255],
1605
+ "maroon": [128, 0, 0],
1606
+ "mediumaquamarine": [102, 205, 170],
1607
+ "mediumblue": [0, 0, 205],
1608
+ "mediumorchid": [186, 85, 211],
1609
+ "mediumpurple": [147, 112, 219],
1610
+ "mediumseagreen": [60, 179, 113],
1611
+ "mediumslateblue": [123, 104, 238],
1612
+ "mediumspringgreen": [0, 250, 154],
1613
+ "mediumturquoise": [72, 209, 204],
1614
+ "mediumvioletred": [199, 21, 133],
1615
+ "midnightblue": [25, 25, 112],
1616
+ "mintcream": [245, 255, 250],
1617
+ "mistyrose": [255, 228, 225],
1618
+ "moccasin": [255, 228, 181],
1619
+ "navajowhite": [255, 222, 173],
1620
+ "navy": [0, 0, 128],
1621
+ "oldlace": [253, 245, 230],
1622
+ "olive": [128, 128, 0],
1623
+ "olivedrab": [107, 142, 35],
1624
+ "orange": [255, 165, 0],
1625
+ "orangered": [255, 69, 0],
1626
+ "orchid": [218, 112, 214],
1627
+ "palegoldenrod": [238, 232, 170],
1628
+ "palegreen": [152, 251, 152],
1629
+ "paleturquoise": [175, 238, 238],
1630
+ "palevioletred": [219, 112, 147],
1631
+ "papayawhip": [255, 239, 213],
1632
+ "peachpuff": [255, 218, 185],
1633
+ "peru": [205, 133, 63],
1634
+ "pink": [255, 192, 203],
1635
+ "plum": [221, 160, 221],
1636
+ "powderblue": [176, 224, 230],
1637
+ "purple": [128, 0, 128],
1638
+ "rebeccapurple": [102, 51, 153],
1639
+ "red": [255, 0, 0],
1640
+ "rosybrown": [188, 143, 143],
1641
+ "royalblue": [65, 105, 225],
1642
+ "saddlebrown": [139, 69, 19],
1643
+ "salmon": [250, 128, 114],
1644
+ "sandybrown": [244, 164, 96],
1645
+ "seagreen": [46, 139, 87],
1646
+ "seashell": [255, 245, 238],
1647
+ "sienna": [160, 82, 45],
1648
+ "silver": [192, 192, 192],
1649
+ "skyblue": [135, 206, 235],
1650
+ "slateblue": [106, 90, 205],
1651
+ "slategray": [112, 128, 144],
1652
+ "slategrey": [112, 128, 144],
1653
+ "snow": [255, 250, 250],
1654
+ "springgreen": [0, 255, 127],
1655
+ "steelblue": [70, 130, 180],
1656
+ "tan": [210, 180, 140],
1657
+ "teal": [0, 128, 128],
1658
+ "thistle": [216, 191, 216],
1659
+ "tomato": [255, 99, 71],
1660
+ "turquoise": [64, 224, 208],
1661
+ "violet": [238, 130, 238],
1662
+ "wheat": [245, 222, 179],
1663
+ "white": [255, 255, 255],
1664
+ "whitesmoke": [245, 245, 245],
1665
+ "yellow": [255, 255, 0],
1666
+ "yellowgreen": [154, 205, 50]
1667
+ };
1668
+
1669
+ },{}],7:[function(require,module,exports){
1670
+ /**
1671
+ * @namespace Chart
1672
+ */
1673
+ var Chart = require(29)();
1674
+
1675
+ Chart.helpers = require(45);
1676
+
1677
+ // @todo dispatch these helpers into appropriated helpers/helpers.* file and write unit tests!
1678
+ require(27)(Chart);
1679
+
1680
+ Chart.defaults = require(25);
1681
+ Chart.Element = require(26);
1682
+ Chart.elements = require(40);
1683
+ Chart.Interaction = require(28);
1684
+ Chart.platform = require(48);
1685
+
1686
+ require(31)(Chart);
1687
+ require(22)(Chart);
1688
+ require(23)(Chart);
1689
+ require(24)(Chart);
1690
+ require(30)(Chart);
1691
+ require(33)(Chart);
1692
+ require(32)(Chart);
1693
+ require(35)(Chart);
1694
+
1695
+ require(54)(Chart);
1696
+ require(52)(Chart);
1697
+ require(53)(Chart);
1698
+ require(55)(Chart);
1699
+ require(56)(Chart);
1700
+ require(57)(Chart);
1701
+
1702
+ // Controllers must be loaded after elements
1703
+ // See Chart.core.datasetController.dataElementType
1704
+ require(15)(Chart);
1705
+ require(16)(Chart);
1706
+ require(17)(Chart);
1707
+ require(18)(Chart);
1708
+ require(19)(Chart);
1709
+ require(20)(Chart);
1710
+ require(21)(Chart);
1711
+
1712
+ require(8)(Chart);
1713
+ require(9)(Chart);
1714
+ require(10)(Chart);
1715
+ require(11)(Chart);
1716
+ require(12)(Chart);
1717
+ require(13)(Chart);
1718
+ require(14)(Chart);
1719
+
1720
+ // Loading built-it plugins
1721
+ var plugins = [];
1722
+
1723
+ plugins.push(
1724
+ require(49)(Chart),
1725
+ require(50)(Chart),
1726
+ require(51)(Chart)
1727
+ );
1728
+
1729
+ Chart.plugins.register(plugins);
1730
+
1731
+ Chart.platform.initialize();
1732
+
1733
+ module.exports = Chart;
1734
+ if (typeof window !== 'undefined') {
1735
+ window.Chart = Chart;
1736
+ }
1737
+
1738
+ // DEPRECATIONS
1739
+
1740
+ /**
1741
+ * Provided for backward compatibility, use Chart.helpers.canvas instead.
1742
+ * @namespace Chart.canvasHelpers
1743
+ * @deprecated since version 2.6.0
1744
+ * @todo remove at version 3
1745
+ * @private
1746
+ */
1747
+ Chart.canvasHelpers = Chart.helpers.canvas;
1748
 
1749
+ },{"10":10,"11":11,"12":12,"13":13,"14":14,"15":15,"16":16,"17":17,"18":18,"19":19,"20":20,"21":21,"22":22,"23":23,"24":24,"25":25,"26":26,"27":27,"28":28,"29":29,"30":30,"31":31,"32":32,"33":33,"35":35,"40":40,"45":45,"48":48,"49":49,"50":50,"51":51,"52":52,"53":53,"54":54,"55":55,"56":56,"57":57,"8":8,"9":9}],8:[function(require,module,exports){
1750
+ 'use strict';
1751
 
1752
+ module.exports = function(Chart) {
 
1753
 
1754
+ Chart.Bar = function(context, config) {
1755
+ config.type = 'bar';
1756
 
1757
+ return new Chart(context, config);
1758
+ };
1759
 
1760
+ };
 
1761
 
1762
+ },{}],9:[function(require,module,exports){
1763
+ 'use strict';
1764
 
1765
+ module.exports = function(Chart) {
 
1766
 
1767
+ Chart.Bubble = function(context, config) {
1768
+ config.type = 'bubble';
1769
+ return new Chart(context, config);
1770
+ };
1771
 
1772
+ };
 
1773
 
1774
+ },{}],10:[function(require,module,exports){
1775
+ 'use strict';
1776
 
1777
+ module.exports = function(Chart) {
 
1778
 
1779
+ Chart.Doughnut = function(context, config) {
1780
+ config.type = 'doughnut';
1781
 
1782
+ return new Chart(context, config);
1783
+ };
1784
 
1785
+ };
 
1786
 
1787
+ },{}],11:[function(require,module,exports){
1788
+ 'use strict';
1789
 
1790
+ module.exports = function(Chart) {
 
1791
 
1792
+ Chart.Line = function(context, config) {
1793
+ config.type = 'line';
1794
 
1795
+ return new Chart(context, config);
1796
+ };
1797
 
1798
+ };
 
1799
 
1800
+ },{}],12:[function(require,module,exports){
1801
+ 'use strict';
1802
 
1803
+ module.exports = function(Chart) {
 
1804
 
1805
+ Chart.PolarArea = function(context, config) {
1806
+ config.type = 'polarArea';
1807
 
1808
+ return new Chart(context, config);
1809
  };
1810
 
1811
+ };
 
1812
 
1813
+ },{}],13:[function(require,module,exports){
1814
+ 'use strict';
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1815
 
1816
+ module.exports = function(Chart) {
 
 
 
 
1817
 
1818
+ Chart.Radar = function(context, config) {
1819
+ config.type = 'radar';
1820
+
1821
+ return new Chart(context, config);
1822
+ };
1823
+
1824
+ };
1825
+
1826
+ },{}],14:[function(require,module,exports){
1827
+ 'use strict';
1828
+
1829
+ module.exports = function(Chart) {
1830
+ Chart.Scatter = function(context, config) {
1831
+ config.type = 'scatter';
1832
+ return new Chart(context, config);
1833
+ };
1834
+ };
1835
+
1836
+ },{}],15:[function(require,module,exports){
1837
+ 'use strict';
1838
+
1839
+ var defaults = require(25);
1840
+ var elements = require(40);
1841
+ var helpers = require(45);
1842
+
1843
+ defaults._set('bar', {
1844
+ hover: {
1845
+ mode: 'label'
1846
+ },
1847
+
1848
+ scales: {
1849
+ xAxes: [{
1850
+ type: 'category',
1851
+
1852
+ // Specific to Bar Controller
1853
+ categoryPercentage: 0.8,
1854
+ barPercentage: 0.9,
1855
+
1856
+ // offset settings
1857
+ offset: true,
1858
+
1859
+ // grid line settings
1860
+ gridLines: {
1861
+ offsetGridLines: true
1862
  }
1863
+ }],
1864
+
1865
+ yAxes: [{
1866
+ type: 'linear'
1867
+ }]
1868
+ }
1869
+ });
1870
+
1871
+ defaults._set('horizontalBar', {
1872
+ hover: {
1873
+ mode: 'index',
1874
+ axis: 'y'
1875
+ },
1876
+
1877
+ scales: {
1878
+ xAxes: [{
1879
+ type: 'linear',
1880
+ position: 'bottom'
1881
+ }],
1882
+
1883
+ yAxes: [{
1884
+ position: 'left',
1885
+ type: 'category',
1886
+
1887
+ // Specific to Horizontal Bar Controller
1888
+ categoryPercentage: 0.8,
1889
+ barPercentage: 0.9,
1890
+
1891
+ // offset settings
1892
+ offset: true,
1893
+
1894
+ // grid line settings
1895
+ gridLines: {
1896
+ offsetGridLines: true
1897
  }
1898
+ }]
1899
+ },
1900
+
1901
+ elements: {
1902
+ rectangle: {
1903
+ borderSkipped: 'left'
1904
+ }
1905
+ },
1906
+
1907
+ tooltips: {
1908
+ callbacks: {
1909
+ title: function(item, data) {
1910
+ // Pick first xLabel for now
1911
+ var title = '';
1912
+
1913
+ if (item.length > 0) {
1914
+ if (item[0].yLabel) {
1915
+ title = item[0].yLabel;
1916
+ } else if (data.labels.length > 0 && item[0].index < data.labels.length) {
1917
+ title = data.labels[item[0].index];
1918
+ }
1919
  }
1920
+
1921
+ return title;
1922
+ },
1923
+
1924
+ label: function(item, data) {
1925
+ var datasetLabel = data.datasets[item.datasetIndex].label || '';
1926
+ return datasetLabel + ': ' + item.xLabel;
1927
  }
1928
  },
1929
+ mode: 'index',
1930
+ axis: 'y'
1931
+ }
1932
+ });
1933
 
1934
+ module.exports = function(Chart) {
 
 
1935
 
1936
+ Chart.controllers.bar = Chart.DatasetController.extend({
1937
 
1938
+ dataElementType: elements.Rectangle,
1939
 
1940
+ initialize: function() {
1941
+ var me = this;
1942
+ var meta;
1943
 
1944
+ Chart.DatasetController.prototype.initialize.apply(me, arguments);
1945
+
1946
+ meta = me.getMeta();
1947
+ meta.stack = me.getDataset().stack;
1948
+ meta.bar = true;
1949
+ },
1950
+
1951
+ update: function(reset) {
1952
+ var me = this;
1953
+ var rects = me.getMeta().data;
1954
+ var i, ilen;
1955
+
1956
+ me._ruler = me.getRuler();
1957
+
1958
+ for (i = 0, ilen = rects.length; i < ilen; ++i) {
1959
+ me.updateElement(rects[i], i, reset);
1960
+ }
1961
  },
1962
+
1963
+ updateElement: function(rectangle, index, reset) {
1964
+ var me = this;
1965
+ var chart = me.chart;
1966
+ var meta = me.getMeta();
1967
+ var dataset = me.getDataset();
1968
+ var custom = rectangle.custom || {};
1969
+ var rectangleOptions = chart.options.elements.rectangle;
1970
+
1971
+ rectangle._xScale = me.getScaleForId(meta.xAxisID);
1972
+ rectangle._yScale = me.getScaleForId(meta.yAxisID);
1973
+ rectangle._datasetIndex = me.index;
1974
+ rectangle._index = index;
1975
+
1976
+ rectangle._model = {
1977
+ datasetLabel: dataset.label,
1978
+ label: chart.data.labels[index],
1979
+ borderSkipped: custom.borderSkipped ? custom.borderSkipped : rectangleOptions.borderSkipped,
1980
+ backgroundColor: custom.backgroundColor ? custom.backgroundColor : helpers.valueAtIndexOrDefault(dataset.backgroundColor, index, rectangleOptions.backgroundColor),
1981
+ borderColor: custom.borderColor ? custom.borderColor : helpers.valueAtIndexOrDefault(dataset.borderColor, index, rectangleOptions.borderColor),
1982
+ borderWidth: custom.borderWidth ? custom.borderWidth : helpers.valueAtIndexOrDefault(dataset.borderWidth, index, rectangleOptions.borderWidth)
1983
  };
1984
+
1985
+ me.updateElementGeometry(rectangle, index, reset);
1986
+
1987
+ rectangle.pivot();
1988
  },
1989
+
1990
+ /**
1991
+ * @private
1992
+ */
1993
+ updateElementGeometry: function(rectangle, index, reset) {
1994
+ var me = this;
1995
+ var model = rectangle._model;
1996
+ var vscale = me.getValueScale();
1997
+ var base = vscale.getBasePixel();
1998
+ var horizontal = vscale.isHorizontal();
1999
+ var ruler = me._ruler || me.getRuler();
2000
+ var vpixels = me.calculateBarValuePixels(me.index, index);
2001
+ var ipixels = me.calculateBarIndexPixels(me.index, index, ruler);
2002
+
2003
+ model.horizontal = horizontal;
2004
+ model.base = reset ? base : vpixels.base;
2005
+ model.x = horizontal ? reset ? base : vpixels.head : ipixels.center;
2006
+ model.y = horizontal ? ipixels.center : reset ? base : vpixels.head;
2007
+ model.height = horizontal ? ipixels.size : undefined;
2008
+ model.width = horizontal ? undefined : ipixels.size;
2009
  },
2010
+
2011
+ /**
2012
+ * @private
2013
+ */
2014
+ getValueScaleId: function() {
2015
+ return this.getMeta().yAxisID;
2016
  },
2017
+
2018
+ /**
2019
+ * @private
2020
+ */
2021
+ getIndexScaleId: function() {
2022
+ return this.getMeta().xAxisID;
2023
  },
2024
+
2025
+ /**
2026
+ * @private
2027
+ */
2028
+ getValueScale: function() {
2029
+ return this.getScaleForId(this.getValueScaleId());
 
 
 
 
 
 
2030
  },
2031
+
2032
+ /**
2033
+ * @private
2034
+ */
2035
+ getIndexScale: function() {
2036
+ return this.getScaleForId(this.getIndexScaleId());
2037
+ },
2038
+
2039
+ /**
2040
+ * Returns the effective number of stacks based on groups and bar visibility.
2041
+ * @private
2042
+ */
2043
+ getStackCount: function(last) {
2044
+ var me = this;
2045
+ var chart = me.chart;
2046
+ var scale = me.getIndexScale();
2047
+ var stacked = scale.options.stacked;
2048
+ var ilen = last === undefined ? chart.data.datasets.length : last + 1;
2049
+ var stacks = [];
2050
+ var i, meta;
2051
+
2052
+ for (i = 0; i < ilen; ++i) {
2053
+ meta = chart.getDatasetMeta(i);
2054
+ if (meta.bar && chart.isDatasetVisible(i) &&
2055
+ (stacked === false ||
2056
+ (stacked === true && stacks.indexOf(meta.stack) === -1) ||
2057
+ (stacked === undefined && (meta.stack === undefined || stacks.indexOf(meta.stack) === -1)))) {
2058
+ stacks.push(meta.stack);
2059
  }
2060
  }
 
 
 
 
 
 
 
 
 
 
 
 
2061
 
2062
+ return stacks.length;
2063
+ },
2064
 
2065
+ /**
2066
+ * Returns the stack index for the given dataset based on groups and bar visibility.
2067
+ * @private
2068
+ */
2069
+ getStackIndex: function(datasetIndex) {
2070
+ return this.getStackCount(datasetIndex) - 1;
2071
+ },
2072
 
2073
+ /**
2074
+ * @private
2075
+ */
2076
+ getRuler: function() {
2077
+ var me = this;
2078
+ var scale = me.getIndexScale();
2079
+ var stackCount = me.getStackCount();
2080
+ var datasetIndex = me.index;
2081
+ var pixels = [];
2082
+ var isHorizontal = scale.isHorizontal();
2083
+ var start = isHorizontal ? scale.left : scale.top;
2084
+ var end = start + (isHorizontal ? scale.width : scale.height);
2085
+ var i, ilen;
2086
+
2087
+ for (i = 0, ilen = me.getMeta().data.length; i < ilen; ++i) {
2088
+ pixels.push(scale.getPixelForValue(null, i, datasetIndex));
2089
  }
2090
 
2091
  return {
2092
+ pixels: pixels,
2093
+ start: start,
2094
+ end: end,
2095
+ stackCount: stackCount,
2096
+ scale: scale
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2097
  };
2098
  },
 
 
 
 
2099
 
2100
+ /**
2101
+ * Note: pixel values are not clamped to the scale area.
2102
+ * @private
2103
+ */
2104
+ calculateBarValuePixels: function(datasetIndex, index) {
2105
+ var me = this;
2106
+ var chart = me.chart;
2107
+ var meta = me.getMeta();
2108
+ var scale = me.getValueScale();
2109
+ var datasets = chart.data.datasets;
2110
+ var value = scale.getRightValue(datasets[datasetIndex].data[index]);
2111
+ var stacked = scale.options.stacked;
2112
+ var stack = meta.stack;
2113
+ var start = 0;
2114
+ var i, imeta, ivalue, base, head, size;
2115
+
2116
+ if (stacked || (stacked === undefined && stack !== undefined)) {
2117
+ for (i = 0; i < datasetIndex; ++i) {
2118
+ imeta = chart.getDatasetMeta(i);
2119
+
2120
+ if (imeta.bar &&
2121
+ imeta.stack === stack &&
2122
+ imeta.controller.getValueScaleId() === scale.id &&
2123
+ chart.isDatasetVisible(i)) {
2124
+
2125
+ ivalue = scale.getRightValue(datasets[i].data[index]);
2126
+ if ((value < 0 && ivalue < 0) || (value >= 0 && ivalue > 0)) {
2127
+ start += ivalue;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2128
  }
2129
  }
 
 
 
 
 
 
2130
  }
2131
  }
2132
 
2133
+ base = scale.getPixelForValue(start);
2134
+ head = scale.getPixelForValue(start + value);
2135
+ size = (head - base) / 2;
 
2136
 
2137
  return {
2138
+ size: size,
2139
+ base: base,
2140
+ head: head,
2141
+ center: head + size / 2
2142
  };
 
2143
  },
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2144
 
2145
+ /**
2146
+ * @private
2147
+ */
2148
+ calculateBarIndexPixels: function(datasetIndex, index, ruler) {
2149
+ var me = this;
2150
+ var options = ruler.scale.options;
2151
+ var stackIndex = me.getStackIndex(datasetIndex);
2152
+ var pixels = ruler.pixels;
2153
+ var base = pixels[index];
2154
+ var length = pixels.length;
2155
+ var start = ruler.start;
2156
+ var end = ruler.end;
2157
+ var leftSampleSize, rightSampleSize, leftCategorySize, rightCategorySize, fullBarSize, size;
2158
+
2159
+ if (length === 1) {
2160
+ leftSampleSize = base > start ? base - start : end - base;
2161
+ rightSampleSize = base < end ? end - base : base - start;
2162
+ } else {
2163
+ if (index > 0) {
2164
+ leftSampleSize = (base - pixels[index - 1]) / 2;
2165
+ if (index === length - 1) {
2166
+ rightSampleSize = leftSampleSize;
2167
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2168
  }
2169
+ if (index < length - 1) {
2170
+ rightSampleSize = (pixels[index + 1] - base) / 2;
2171
+ if (index === 0) {
2172
+ leftSampleSize = rightSampleSize;
2173
+ }
 
 
 
 
 
 
 
 
 
2174
  }
2175
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2176
 
2177
+ leftCategorySize = leftSampleSize * options.categoryPercentage;
2178
+ rightCategorySize = rightSampleSize * options.categoryPercentage;
2179
+ fullBarSize = (leftCategorySize + rightCategorySize) / ruler.stackCount;
2180
+ size = fullBarSize * options.barPercentage;
2181
 
2182
+ size = Math.min(
2183
+ helpers.valueOrDefault(options.barThickness, size),
2184
+ helpers.valueOrDefault(options.maxBarThickness, Infinity));
 
2185
 
2186
+ base -= leftCategorySize;
2187
+ base += fullBarSize * stackIndex;
2188
+ base += (fullBarSize - size) / 2;
2189
+
2190
+ return {
2191
+ size: size,
2192
+ base: base,
2193
+ head: base + size,
2194
+ center: base + size / 2
2195
  };
 
2196
  },
 
 
 
 
 
 
2197
 
2198
+ draw: function() {
2199
+ var me = this;
2200
+ var chart = me.chart;
2201
+ var scale = me.getValueScale();
2202
+ var rects = me.getMeta().data;
2203
+ var dataset = me.getDataset();
2204
+ var ilen = rects.length;
2205
+ var i = 0;
2206
 
2207
+ helpers.canvas.clipArea(chart.ctx, chart.chartArea);
2208
+
2209
+ for (; i < ilen; ++i) {
2210
+ if (!isNaN(scale.getRightValue(dataset.data[i]))) {
2211
+ rects[i].draw();
2212
+ }
2213
  }
2214
 
2215
+ helpers.canvas.unclipArea(chart.ctx);
2216
+ },
2217
+
2218
+ setHoverStyle: function(rectangle) {
2219
+ var dataset = this.chart.data.datasets[rectangle._datasetIndex];
2220
+ var index = rectangle._index;
2221
+ var custom = rectangle.custom || {};
2222
+ var model = rectangle._model;
2223
 
2224
+ model.backgroundColor = custom.hoverBackgroundColor ? custom.hoverBackgroundColor : helpers.valueAtIndexOrDefault(dataset.hoverBackgroundColor, index, helpers.getHoverColor(model.backgroundColor));
2225
+ model.borderColor = custom.hoverBorderColor ? custom.hoverBorderColor : helpers.valueAtIndexOrDefault(dataset.hoverBorderColor, index, helpers.getHoverColor(model.borderColor));
2226
+ model.borderWidth = custom.hoverBorderWidth ? custom.hoverBorderWidth : helpers.valueAtIndexOrDefault(dataset.hoverBorderWidth, index, model.borderWidth);
2227
  },
2228
+
2229
+ removeHoverStyle: function(rectangle) {
2230
+ var dataset = this.chart.data.datasets[rectangle._datasetIndex];
2231
+ var index = rectangle._index;
2232
+ var custom = rectangle.custom || {};
2233
+ var model = rectangle._model;
2234
+ var rectangleElementOptions = this.chart.options.elements.rectangle;
2235
+
2236
+ model.backgroundColor = custom.backgroundColor ? custom.backgroundColor : helpers.valueAtIndexOrDefault(dataset.backgroundColor, index, rectangleElementOptions.backgroundColor);
2237
+ model.borderColor = custom.borderColor ? custom.borderColor : helpers.valueAtIndexOrDefault(dataset.borderColor, index, rectangleElementOptions.borderColor);
2238
+ model.borderWidth = custom.borderWidth ? custom.borderWidth : helpers.valueAtIndexOrDefault(dataset.borderWidth, index, rectangleElementOptions.borderWidth);
2239
+ }
2240
+ });
2241
+
2242
+ Chart.controllers.horizontalBar = Chart.controllers.bar.extend({
2243
+ /**
2244
+ * @private
2245
+ */
2246
+ getValueScaleId: function() {
2247
+ return this.getMeta().xAxisID;
2248
  },
2249
+
2250
+ /**
2251
+ * @private
2252
+ */
2253
+ getIndexScaleId: function() {
2254
+ return this.getMeta().yAxisID;
2255
+ }
2256
+ });
2257
+ };
2258
+
2259
+ },{"25":25,"40":40,"45":45}],16:[function(require,module,exports){
2260
+ 'use strict';
2261
+
2262
+ var defaults = require(25);
2263
+ var elements = require(40);
2264
+ var helpers = require(45);
2265
+
2266
+ defaults._set('bubble', {
2267
+ hover: {
2268
+ mode: 'single'
2269
+ },
2270
+
2271
+ scales: {
2272
+ xAxes: [{
2273
+ type: 'linear', // bubble should probably use a linear scale by default
2274
+ position: 'bottom',
2275
+ id: 'x-axis-0' // need an ID so datasets can reference the scale
2276
+ }],
2277
+ yAxes: [{
2278
+ type: 'linear',
2279
+ position: 'left',
2280
+ id: 'y-axis-0'
2281
+ }]
2282
+ },
2283
+
2284
+ tooltips: {
2285
+ callbacks: {
2286
+ title: function() {
2287
+ // Title doesn't make sense for scatter since we format the data as a point
2288
+ return '';
2289
+ },
2290
+ label: function(item, data) {
2291
+ var datasetLabel = data.datasets[item.datasetIndex].label || '';
2292
+ var dataPoint = data.datasets[item.datasetIndex].data[item.index];
2293
+ return datasetLabel + ': (' + item.xLabel + ', ' + item.yLabel + ', ' + dataPoint.r + ')';
2294
  }
2295
+ }
2296
+ }
2297
+ });
 
2298
 
2299
+
2300
+ module.exports = function(Chart) {
2301
+
2302
+ Chart.controllers.bubble = Chart.DatasetController.extend({
2303
+ /**
2304
+ * @protected
2305
+ */
2306
+ dataElementType: elements.Point,
2307
+
2308
+ /**
2309
+ * @protected
2310
+ */
2311
+ update: function(reset) {
2312
+ var me = this;
2313
+ var meta = me.getMeta();
2314
+ var points = meta.data;
2315
+
2316
+ // Update Points
2317
+ helpers.each(points, function(point, index) {
2318
+ me.updateElement(point, index, reset);
2319
  });
2320
  },
2321
+
2322
+ /**
2323
+ * @protected
2324
+ */
2325
+ updateElement: function(point, index, reset) {
2326
+ var me = this;
2327
+ var meta = me.getMeta();
2328
+ var custom = point.custom || {};
2329
+ var xScale = me.getScaleForId(meta.xAxisID);
2330
+ var yScale = me.getScaleForId(meta.yAxisID);
2331
+ var options = me._resolveElementOptions(point, index);
2332
+ var data = me.getDataset().data[index];
2333
+ var dsIndex = me.index;
2334
+
2335
+ var x = reset ? xScale.getPixelForDecimal(0.5) : xScale.getPixelForValue(typeof data === 'object' ? data : NaN, index, dsIndex);
2336
+ var y = reset ? yScale.getBasePixel() : yScale.getPixelForValue(data, index, dsIndex);
2337
+
2338
+ point._xScale = xScale;
2339
+ point._yScale = yScale;
2340
+ point._options = options;
2341
+ point._datasetIndex = dsIndex;
2342
+ point._index = index;
2343
+ point._model = {
2344
+ backgroundColor: options.backgroundColor,
2345
+ borderColor: options.borderColor,
2346
+ borderWidth: options.borderWidth,
2347
+ hitRadius: options.hitRadius,
2348
+ pointStyle: options.pointStyle,
2349
+ radius: reset ? 0 : options.radius,
2350
+ skip: custom.skip || isNaN(x) || isNaN(y),
2351
+ x: x,
2352
+ y: y,
2353
+ };
2354
+
2355
+ point.pivot();
2356
  },
2357
+
2358
+ /**
2359
+ * @protected
2360
+ */
2361
+ setHoverStyle: function(point) {
2362
+ var model = point._model;
2363
+ var options = point._options;
2364
+
2365
+ model.backgroundColor = helpers.valueOrDefault(options.hoverBackgroundColor, helpers.getHoverColor(options.backgroundColor));
2366
+ model.borderColor = helpers.valueOrDefault(options.hoverBorderColor, helpers.getHoverColor(options.borderColor));
2367
+ model.borderWidth = helpers.valueOrDefault(options.hoverBorderWidth, options.borderWidth);
2368
+ model.radius = options.radius + options.hoverRadius;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2369
  },
 
 
 
 
 
 
 
 
 
 
 
 
 
2370
 
2371
+ /**
2372
+ * @protected
2373
+ */
2374
+ removeHoverStyle: function(point) {
2375
+ var model = point._model;
2376
+ var options = point._options;
2377
+
2378
+ model.backgroundColor = options.backgroundColor;
2379
+ model.borderColor = options.borderColor;
2380
+ model.borderWidth = options.borderWidth;
2381
+ model.radius = options.radius;
2382
+ },
2383
 
2384
+ /**
2385
+ * @private
2386
+ */
2387
+ _resolveElementOptions: function(point, index) {
2388
+ var me = this;
2389
+ var chart = me.chart;
2390
+ var datasets = chart.data.datasets;
2391
+ var dataset = datasets[me.index];
2392
+ var custom = point.custom || {};
2393
+ var options = chart.options.elements.point;
2394
+ var resolve = helpers.options.resolve;
2395
+ var data = dataset.data[index];
2396
+ var values = {};
2397
+ var i, ilen, key;
2398
+
2399
+ // Scriptable options
2400
+ var context = {
2401
+ chart: chart,
2402
+ dataIndex: index,
2403
+ dataset: dataset,
2404
+ datasetIndex: me.index
2405
+ };
2406
 
2407
+ var keys = [
2408
+ 'backgroundColor',
2409
+ 'borderColor',
2410
+ 'borderWidth',
2411
+ 'hoverBackgroundColor',
2412
+ 'hoverBorderColor',
2413
+ 'hoverBorderWidth',
2414
+ 'hoverRadius',
2415
+ 'hitRadius',
2416
+ 'pointStyle'
2417
+ ];
2418
+
2419
+ for (i = 0, ilen = keys.length; i < ilen; ++i) {
2420
+ key = keys[i];
2421
+ values[key] = resolve([
2422
+ custom[key],
2423
+ dataset[key],
2424
+ options[key]
2425
+ ], context, index);
2426
+ }
2427
+
2428
+ // Custom radius resolution
2429
+ values.radius = resolve([
2430
+ custom.radius,
2431
+ data ? data.r : undefined,
2432
+ dataset.radius,
2433
+ options.radius
2434
+ ], context, index);
2435
 
2436
+ return values;
2437
+ }
2438
+ });
2439
+ };
2440
+
2441
+ },{"25":25,"40":40,"45":45}],17:[function(require,module,exports){
2442
+ 'use strict';
2443
+
2444
+ var defaults = require(25);
2445
+ var elements = require(40);
2446
+ var helpers = require(45);
2447
+
2448
+ defaults._set('doughnut', {
2449
+ animation: {
2450
+ // Boolean - Whether we animate the rotation of the Doughnut
2451
+ animateRotate: true,
2452
+ // Boolean - Whether we animate scaling the Doughnut from the centre
2453
+ animateScale: false
2454
+ },
2455
+ hover: {
2456
+ mode: 'single'
2457
+ },
2458
+ legendCallback: function(chart) {
2459
+ var text = [];
2460
+ text.push('<ul class="' + chart.id + '-legend">');
2461
+
2462
+ var data = chart.data;
2463
+ var datasets = data.datasets;
2464
+ var labels = data.labels;
2465
+
2466
+ if (datasets.length) {
2467
+ for (var i = 0; i < datasets[0].data.length; ++i) {
2468
+ text.push('<li><span style="background-color:' + datasets[0].backgroundColor[i] + '"></span>');
2469
+ if (labels[i]) {
2470
+ text.push(labels[i]);
2471
+ }
2472
+ text.push('</li>');
2473
+ }
2474
+ }
2475
+
2476
+ text.push('</ul>');
2477
+ return text.join('');
2478
+ },
2479
+ legend: {
2480
+ labels: {
2481
+ generateLabels: function(chart) {
2482
+ var data = chart.data;
2483
+ if (data.labels.length && data.datasets.length) {
2484
+ return data.labels.map(function(label, i) {
2485
+ var meta = chart.getDatasetMeta(0);
2486
+ var ds = data.datasets[0];
2487
+ var arc = meta.data[i];
2488
+ var custom = arc && arc.custom || {};
2489
+ var valueAtIndexOrDefault = helpers.valueAtIndexOrDefault;
2490
+ var arcOpts = chart.options.elements.arc;
2491
+ var fill = custom.backgroundColor ? custom.backgroundColor : valueAtIndexOrDefault(ds.backgroundColor, i, arcOpts.backgroundColor);
2492
+ var stroke = custom.borderColor ? custom.borderColor : valueAtIndexOrDefault(ds.borderColor, i, arcOpts.borderColor);
2493
+ var bw = custom.borderWidth ? custom.borderWidth : valueAtIndexOrDefault(ds.borderWidth, i, arcOpts.borderWidth);
2494
+
2495
+ return {
2496
+ text: label,
2497
+ fillStyle: fill,
2498
+ strokeStyle: stroke,
2499
+ lineWidth: bw,
2500
+ hidden: isNaN(ds.data[i]) || meta.data[i].hidden,
2501
+
2502
+ // Extra data used for toggling the correct item
2503
+ index: i
2504
+ };
2505
+ });
2506
+ }
2507
+ return [];
2508
+ }
2509
+ },
2510
+
2511
+ onClick: function(e, legendItem) {
2512
+ var index = legendItem.index;
2513
+ var chart = this.chart;
2514
+ var i, ilen, meta;
2515
+
2516
+ for (i = 0, ilen = (chart.data.datasets || []).length; i < ilen; ++i) {
2517
+ meta = chart.getDatasetMeta(i);
2518
+ // toggle visibility of index if exists
2519
+ if (meta.data[index]) {
2520
+ meta.data[index].hidden = !meta.data[index].hidden;
2521
+ }
2522
+ }
2523
+
2524
+ chart.update();
2525
+ }
2526
+ },
2527
+
2528
+ // The percentage of the chart that we cut out of the middle.
2529
+ cutoutPercentage: 50,
2530
+
2531
+ // The rotation of the chart, where the first data arc begins.
2532
+ rotation: Math.PI * -0.5,
2533
+
2534
+ // The total circumference of the chart.
2535
+ circumference: Math.PI * 2.0,
2536
+
2537
+ // Need to override these to give a nice default
2538
+ tooltips: {
2539
+ callbacks: {
2540
+ title: function() {
2541
+ return '';
2542
+ },
2543
+ label: function(tooltipItem, data) {
2544
+ var dataLabel = data.labels[tooltipItem.index];
2545
+ var value = ': ' + data.datasets[tooltipItem.datasetIndex].data[tooltipItem.index];
2546
+
2547
+ if (helpers.isArray(dataLabel)) {
2548
+ // show value on first line of multiline label
2549
+ // need to clone because we are changing the value
2550
+ dataLabel = dataLabel.slice();
2551
+ dataLabel[0] += value;
2552
+ } else {
2553
+ dataLabel += value;
2554
+ }
2555
+
2556
+ return dataLabel;
2557
+ }
2558
+ }
2559
+ }
2560
+ });
2561
+
2562
+ defaults._set('pie', helpers.clone(defaults.doughnut));
2563
+ defaults._set('pie', {
2564
+ cutoutPercentage: 0
2565
+ });
2566
+
2567
+ module.exports = function(Chart) {
2568
+
2569
+ Chart.controllers.doughnut = Chart.controllers.pie = Chart.DatasetController.extend({
2570
+
2571
+ dataElementType: elements.Arc,
2572
+
2573
+ linkScales: helpers.noop,
2574
+
2575
+ // Get index of the dataset in relation to the visible datasets. This allows determining the inner and outer radius correctly
2576
+ getRingIndex: function(datasetIndex) {
2577
+ var ringIndex = 0;
2578
+
2579
+ for (var j = 0; j < datasetIndex; ++j) {
2580
+ if (this.chart.isDatasetVisible(j)) {
2581
+ ++ringIndex;
2582
+ }
2583
+ }
2584
+
2585
+ return ringIndex;
2586
+ },
2587
+
2588
+ update: function(reset) {
2589
+ var me = this;
2590
+ var chart = me.chart;
2591
+ var chartArea = chart.chartArea;
2592
+ var opts = chart.options;
2593
+ var arcOpts = opts.elements.arc;
2594
+ var availableWidth = chartArea.right - chartArea.left - arcOpts.borderWidth;
2595
+ var availableHeight = chartArea.bottom - chartArea.top - arcOpts.borderWidth;
2596
+ var minSize = Math.min(availableWidth, availableHeight);
2597
+ var offset = {x: 0, y: 0};
2598
+ var meta = me.getMeta();
2599
+ var cutoutPercentage = opts.cutoutPercentage;
2600
+ var circumference = opts.circumference;
2601
+
2602
+ // If the chart's circumference isn't a full circle, calculate minSize as a ratio of the width/height of the arc
2603
+ if (circumference < Math.PI * 2.0) {
2604
+ var startAngle = opts.rotation % (Math.PI * 2.0);
2605
+ startAngle += Math.PI * 2.0 * (startAngle >= Math.PI ? -1 : startAngle < -Math.PI ? 1 : 0);
2606
+ var endAngle = startAngle + circumference;
2607
+ var start = {x: Math.cos(startAngle), y: Math.sin(startAngle)};
2608
+ var end = {x: Math.cos(endAngle), y: Math.sin(endAngle)};
2609
+ var contains0 = (startAngle <= 0 && endAngle >= 0) || (startAngle <= Math.PI * 2.0 && Math.PI * 2.0 <= endAngle);
2610
+ var contains90 = (startAngle <= Math.PI * 0.5 && Math.PI * 0.5 <= endAngle) || (startAngle <= Math.PI * 2.5 && Math.PI * 2.5 <= endAngle);
2611
+ var contains180 = (startAngle <= -Math.PI && -Math.PI <= endAngle) || (startAngle <= Math.PI && Math.PI <= endAngle);
2612
+ var contains270 = (startAngle <= -Math.PI * 0.5 && -Math.PI * 0.5 <= endAngle) || (startAngle <= Math.PI * 1.5 && Math.PI * 1.5 <= endAngle);
2613
+ var cutout = cutoutPercentage / 100.0;
2614
+ var min = {x: contains180 ? -1 : Math.min(start.x * (start.x < 0 ? 1 : cutout), end.x * (end.x < 0 ? 1 : cutout)), y: contains270 ? -1 : Math.min(start.y * (start.y < 0 ? 1 : cutout), end.y * (end.y < 0 ? 1 : cutout))};
2615
+ var max = {x: contains0 ? 1 : Math.max(start.x * (start.x > 0 ? 1 : cutout), end.x * (end.x > 0 ? 1 : cutout)), y: contains90 ? 1 : Math.max(start.y * (start.y > 0 ? 1 : cutout), end.y * (end.y > 0 ? 1 : cutout))};
2616
+ var size = {width: (max.x - min.x) * 0.5, height: (max.y - min.y) * 0.5};
2617
+ minSize = Math.min(availableWidth / size.width, availableHeight / size.height);
2618
+ offset = {x: (max.x + min.x) * -0.5, y: (max.y + min.y) * -0.5};
2619
+ }
2620
+
2621
+ chart.borderWidth = me.getMaxBorderWidth(meta.data);
2622
+ chart.outerRadius = Math.max((minSize - chart.borderWidth) / 2, 0);
2623
+ chart.innerRadius = Math.max(cutoutPercentage ? (chart.outerRadius / 100) * (cutoutPercentage) : 0, 0);
2624
+ chart.radiusLength = (chart.outerRadius - chart.innerRadius) / chart.getVisibleDatasetCount();
2625
+ chart.offsetX = offset.x * chart.outerRadius;
2626
+ chart.offsetY = offset.y * chart.outerRadius;
2627
+
2628
+ meta.total = me.calculateTotal();
2629
+
2630
+ me.outerRadius = chart.outerRadius - (chart.radiusLength * me.getRingIndex(me.index));
2631
+ me.innerRadius = Math.max(me.outerRadius - chart.radiusLength, 0);
2632
+
2633
+ helpers.each(meta.data, function(arc, index) {
2634
+ me.updateElement(arc, index, reset);
2635
+ });
2636
+ },
2637
+
2638
+ updateElement: function(arc, index, reset) {
2639
+ var me = this;
2640
+ var chart = me.chart;
2641
+ var chartArea = chart.chartArea;
2642
+ var opts = chart.options;
2643
+ var animationOpts = opts.animation;
2644
+ var centerX = (chartArea.left + chartArea.right) / 2;
2645
+ var centerY = (chartArea.top + chartArea.bottom) / 2;
2646
+ var startAngle = opts.rotation; // non reset case handled later
2647
+ var endAngle = opts.rotation; // non reset case handled later
2648
+ var dataset = me.getDataset();
2649
+ var circumference = reset && animationOpts.animateRotate ? 0 : arc.hidden ? 0 : me.calculateCircumference(dataset.data[index]) * (opts.circumference / (2.0 * Math.PI));
2650
+ var innerRadius = reset && animationOpts.animateScale ? 0 : me.innerRadius;
2651
+ var outerRadius = reset && animationOpts.animateScale ? 0 : me.outerRadius;
2652
+ var valueAtIndexOrDefault = helpers.valueAtIndexOrDefault;
2653
+
2654
+ helpers.extend(arc, {
2655
+ // Utility
2656
+ _datasetIndex: me.index,
2657
+ _index: index,
2658
+
2659
+ // Desired view properties
2660
+ _model: {
2661
+ x: centerX + chart.offsetX,
2662
+ y: centerY + chart.offsetY,
2663
+ startAngle: startAngle,
2664
+ endAngle: endAngle,
2665
+ circumference: circumference,
2666
+ outerRadius: outerRadius,
2667
+ innerRadius: innerRadius,
2668
+ label: valueAtIndexOrDefault(dataset.label, index, chart.data.labels[index])
2669
+ }
2670
+ });
2671
+
2672
+ var model = arc._model;
2673
+ // Resets the visual styles
2674
+ this.removeHoverStyle(arc);
2675
+
2676
+ // Set correct angles if not resetting
2677
+ if (!reset || !animationOpts.animateRotate) {
2678
+ if (index === 0) {
2679
+ model.startAngle = opts.rotation;
2680
+ } else {
2681
+ model.startAngle = me.getMeta().data[index - 1]._model.endAngle;
2682
+ }
2683
+
2684
+ model.endAngle = model.startAngle + model.circumference;
2685
+ }
2686
+
2687
+ arc.pivot();
2688
+ },
2689
+
2690
+ removeHoverStyle: function(arc) {
2691
+ Chart.DatasetController.prototype.removeHoverStyle.call(this, arc, this.chart.options.elements.arc);
2692
+ },
2693
+
2694
+ calculateTotal: function() {
2695
+ var dataset = this.getDataset();
2696
+ var meta = this.getMeta();
2697
+ var total = 0;
2698
+ var value;
2699
+
2700
+ helpers.each(meta.data, function(element, index) {
2701
+ value = dataset.data[index];
2702
+ if (!isNaN(value) && !element.hidden) {
2703
+ total += Math.abs(value);
2704
+ }
2705
+ });
2706
+
2707
+ /* if (total === 0) {
2708
+ total = NaN;
2709
+ }*/
2710
+
2711
+ return total;
2712
+ },
2713
+
2714
+ calculateCircumference: function(value) {
2715
+ var total = this.getMeta().total;
2716
+ if (total > 0 && !isNaN(value)) {
2717
+ return (Math.PI * 2.0) * (value / total);
2718
+ }
2719
+ return 0;
2720
+ },
2721
+
2722
+ // gets the max border or hover width to properly scale pie charts
2723
+ getMaxBorderWidth: function(arcs) {
2724
+ var max = 0;
2725
+ var index = this.index;
2726
+ var length = arcs.length;
2727
+ var borderWidth;
2728
+ var hoverWidth;
2729
+
2730
+ for (var i = 0; i < length; i++) {
2731
+ borderWidth = arcs[i]._model ? arcs[i]._model.borderWidth : 0;
2732
+ hoverWidth = arcs[i]._chart ? arcs[i]._chart.config.data.datasets[index].hoverBorderWidth : 0;
2733
+
2734
+ max = borderWidth > max ? borderWidth : max;
2735
+ max = hoverWidth > max ? hoverWidth : max;
2736
+ }
2737
+ return max;
2738
+ }
2739
+ });
2740
+ };
2741
+
2742
+ },{"25":25,"40":40,"45":45}],18:[function(require,module,exports){
2743
+ 'use strict';
2744
+
2745
+ var defaults = require(25);
2746
+ var elements = require(40);
2747
+ var helpers = require(45);
2748
+
2749
+ defaults._set('line', {
2750
+ showLines: true,
2751
+ spanGaps: false,
2752
+
2753
+ hover: {
2754
+ mode: 'label'
2755
+ },
2756
+
2757
+ scales: {
2758
+ xAxes: [{
2759
+ type: 'category',
2760
+ id: 'x-axis-0'
2761
+ }],
2762
+ yAxes: [{
2763
+ type: 'linear',
2764
+ id: 'y-axis-0'
2765
+ }]
2766
+ }
2767
+ });
2768
+
2769
+ module.exports = function(Chart) {
2770
+
2771
+ function lineEnabled(dataset, options) {
2772
+ return helpers.valueOrDefault(dataset.showLine, options.showLines);
2773
+ }
2774
+
2775
+ Chart.controllers.line = Chart.DatasetController.extend({
2776
+
2777
+ datasetElementType: elements.Line,
2778
+
2779
+ dataElementType: elements.Point,
2780
+
2781
+ update: function(reset) {
2782
+ var me = this;
2783
+ var meta = me.getMeta();
2784
+ var line = meta.dataset;
2785
+ var points = meta.data || [];
2786
+ var options = me.chart.options;
2787
+ var lineElementOptions = options.elements.line;
2788
+ var scale = me.getScaleForId(meta.yAxisID);
2789
+ var i, ilen, custom;
2790
+ var dataset = me.getDataset();
2791
+ var showLine = lineEnabled(dataset, options);
2792
+
2793
+ // Update Line
2794
+ if (showLine) {
2795
+ custom = line.custom || {};
2796
+
2797
+ // Compatibility: If the properties are defined with only the old name, use those values
2798
+ if ((dataset.tension !== undefined) && (dataset.lineTension === undefined)) {
2799
+ dataset.lineTension = dataset.tension;
2800
+ }
2801
+
2802
+ // Utility
2803
+ line._scale = scale;
2804
+ line._datasetIndex = me.index;
2805
+ // Data
2806
+ line._children = points;
2807
+ // Model
2808
+ line._model = {
2809
+ // Appearance
2810
+ // The default behavior of lines is to break at null values, according
2811
+ // to https://github.com/chartjs/Chart.js/issues/2435#issuecomment-216718158
2812
+ // This option gives lines the ability to span gaps
2813
+ spanGaps: dataset.spanGaps ? dataset.spanGaps : options.spanGaps,
2814
+ tension: custom.tension ? custom.tension : helpers.valueOrDefault(dataset.lineTension, lineElementOptions.tension),
2815
+ backgroundColor: custom.backgroundColor ? custom.backgroundColor : (dataset.backgroundColor || lineElementOptions.backgroundColor),
2816
+ borderWidth: custom.borderWidth ? custom.borderWidth : (dataset.borderWidth || lineElementOptions.borderWidth),
2817
+ borderColor: custom.borderColor ? custom.borderColor : (dataset.borderColor || lineElementOptions.borderColor),
2818
+ borderCapStyle: custom.borderCapStyle ? custom.borderCapStyle : (dataset.borderCapStyle || lineElementOptions.borderCapStyle),
2819
+ borderDash: custom.borderDash ? custom.borderDash : (dataset.borderDash || lineElementOptions.borderDash),
2820
+ borderDashOffset: custom.borderDashOffset ? custom.borderDashOffset : (dataset.borderDashOffset || lineElementOptions.borderDashOffset),
2821
+ borderJoinStyle: custom.borderJoinStyle ? custom.borderJoinStyle : (dataset.borderJoinStyle || lineElementOptions.borderJoinStyle),
2822
+ fill: custom.fill ? custom.fill : (dataset.fill !== undefined ? dataset.fill : lineElementOptions.fill),
2823
+ steppedLine: custom.steppedLine ? custom.steppedLine : helpers.valueOrDefault(dataset.steppedLine, lineElementOptions.stepped),
2824
+ cubicInterpolationMode: custom.cubicInterpolationMode ? custom.cubicInterpolationMode : helpers.valueOrDefault(dataset.cubicInterpolationMode, lineElementOptions.cubicInterpolationMode),
2825
+ };
2826
+
2827
+ line.pivot();
2828
+ }
2829
+
2830
+ // Update Points
2831
+ for (i = 0, ilen = points.length; i < ilen; ++i) {
2832
+ me.updateElement(points[i], i, reset);
2833
+ }
2834
+
2835
+ if (showLine && line._model.tension !== 0) {
2836
+ me.updateBezierControlPoints();
2837
+ }
2838
+
2839
+ // Now pivot the point for animation
2840
+ for (i = 0, ilen = points.length; i < ilen; ++i) {
2841
+ points[i].pivot();
2842
+ }
2843
+ },
2844
+
2845
+ getPointBackgroundColor: function(point, index) {
2846
+ var backgroundColor = this.chart.options.elements.point.backgroundColor;
2847
+ var dataset = this.getDataset();
2848
+ var custom = point.custom || {};
2849
+
2850
+ if (custom.backgroundColor) {
2851
+ backgroundColor = custom.backgroundColor;
2852
+ } else if (dataset.pointBackgroundColor) {
2853
+ backgroundColor = helpers.valueAtIndexOrDefault(dataset.pointBackgroundColor, index, backgroundColor);
2854
+ } else if (dataset.backgroundColor) {
2855
+ backgroundColor = dataset.backgroundColor;
2856
+ }
2857
+
2858
+ return backgroundColor;
2859
+ },
2860
+
2861
+ getPointBorderColor: function(point, index) {
2862
+ var borderColor = this.chart.options.elements.point.borderColor;
2863
+ var dataset = this.getDataset();
2864
+ var custom = point.custom || {};
2865
+
2866
+ if (custom.borderColor) {
2867
+ borderColor = custom.borderColor;
2868
+ } else if (dataset.pointBorderColor) {
2869
+ borderColor = helpers.valueAtIndexOrDefault(dataset.pointBorderColor, index, borderColor);
2870
+ } else if (dataset.borderColor) {
2871
+ borderColor = dataset.borderColor;
2872
+ }
2873
+
2874
+ return borderColor;
2875
+ },
2876
+
2877
+ getPointBorderWidth: function(point, index) {
2878
+ var borderWidth = this.chart.options.elements.point.borderWidth;
2879
+ var dataset = this.getDataset();
2880
+ var custom = point.custom || {};
2881
+
2882
+ if (!isNaN(custom.borderWidth)) {
2883
+ borderWidth = custom.borderWidth;
2884
+ } else if (!isNaN(dataset.pointBorderWidth) || helpers.isArray(dataset.pointBorderWidth)) {
2885
+ borderWidth = helpers.valueAtIndexOrDefault(dataset.pointBorderWidth, index, borderWidth);
2886
+ } else if (!isNaN(dataset.borderWidth)) {
2887
+ borderWidth = dataset.borderWidth;
2888
+ }
2889
+
2890
+ return borderWidth;
2891
+ },
2892
+
2893
+ updateElement: function(point, index, reset) {
2894
+ var me = this;
2895
+ var meta = me.getMeta();
2896
+ var custom = point.custom || {};
2897
+ var dataset = me.getDataset();
2898
+ var datasetIndex = me.index;
2899
+ var value = dataset.data[index];
2900
+ var yScale = me.getScaleForId(meta.yAxisID);
2901
+ var xScale = me.getScaleForId(meta.xAxisID);
2902
+ var pointOptions = me.chart.options.elements.point;
2903
+ var x, y;
2904
+
2905
+ // Compatibility: If the properties are defined with only the old name, use those values
2906
+ if ((dataset.radius !== undefined) && (dataset.pointRadius === undefined)) {
2907
+ dataset.pointRadius = dataset.radius;
2908
+ }
2909
+ if ((dataset.hitRadius !== undefined) && (dataset.pointHitRadius === undefined)) {
2910
+ dataset.pointHitRadius = dataset.hitRadius;
2911
+ }
2912
+
2913
+ x = xScale.getPixelForValue(typeof value === 'object' ? value : NaN, index, datasetIndex);
2914
+ y = reset ? yScale.getBasePixel() : me.calculatePointY(value, index, datasetIndex);
2915
+
2916
+ // Utility
2917
+ point._xScale = xScale;
2918
+ point._yScale = yScale;
2919
+ point._datasetIndex = datasetIndex;
2920
+ point._index = index;
2921
+
2922
+ // Desired view properties
2923
+ point._model = {
2924
+ x: x,
2925
+ y: y,
2926
+ skip: custom.skip || isNaN(x) || isNaN(y),
2927
+ // Appearance
2928
+ radius: custom.radius || helpers.valueAtIndexOrDefault(dataset.pointRadius, index, pointOptions.radius),
2929
+ pointStyle: custom.pointStyle || helpers.valueAtIndexOrDefault(dataset.pointStyle, index, pointOptions.pointStyle),
2930
+ backgroundColor: me.getPointBackgroundColor(point, index),
2931
+ borderColor: me.getPointBorderColor(point, index),
2932
+ borderWidth: me.getPointBorderWidth(point, index),
2933
+ tension: meta.dataset._model ? meta.dataset._model.tension : 0,
2934
+ steppedLine: meta.dataset._model ? meta.dataset._model.steppedLine : false,
2935
+ // Tooltip
2936
+ hitRadius: custom.hitRadius || helpers.valueAtIndexOrDefault(dataset.pointHitRadius, index, pointOptions.hitRadius)
2937
+ };
2938
+ },
2939
+
2940
+ calculatePointY: function(value, index, datasetIndex) {
2941
+ var me = this;
2942
+ var chart = me.chart;
2943
+ var meta = me.getMeta();
2944
+ var yScale = me.getScaleForId(meta.yAxisID);
2945
+ var sumPos = 0;
2946
+ var sumNeg = 0;
2947
+ var i, ds, dsMeta;
2948
+
2949
+ if (yScale.options.stacked) {
2950
+ for (i = 0; i < datasetIndex; i++) {
2951
+ ds = chart.data.datasets[i];
2952
+ dsMeta = chart.getDatasetMeta(i);
2953
+ if (dsMeta.type === 'line' && dsMeta.yAxisID === yScale.id && chart.isDatasetVisible(i)) {
2954
+ var stackedRightValue = Number(yScale.getRightValue(ds.data[index]));
2955
+ if (stackedRightValue < 0) {
2956
+ sumNeg += stackedRightValue || 0;
2957
+ } else {
2958
+ sumPos += stackedRightValue || 0;
2959
+ }
2960
+ }
2961
+ }
2962
+
2963
+ var rightValue = Number(yScale.getRightValue(value));
2964
+ if (rightValue < 0) {
2965
+ return yScale.getPixelForValue(sumNeg + rightValue);
2966
+ }
2967
+ return yScale.getPixelForValue(sumPos + rightValue);
2968
+ }
2969
+
2970
+ return yScale.getPixelForValue(value);
2971
+ },
2972
+
2973
+ updateBezierControlPoints: function() {
2974
+ var me = this;
2975
+ var meta = me.getMeta();
2976
+ var area = me.chart.chartArea;
2977
+ var points = (meta.data || []);
2978
+ var i, ilen, point, model, controlPoints;
2979
+
2980
+ // Only consider points that are drawn in case the spanGaps option is used
2981
+ if (meta.dataset._model.spanGaps) {
2982
+ points = points.filter(function(pt) {
2983
+ return !pt._model.skip;
2984
+ });
2985
+ }
2986
+
2987
+ function capControlPoint(pt, min, max) {
2988
+ return Math.max(Math.min(pt, max), min);
2989
+ }
2990
+
2991
+ if (meta.dataset._model.cubicInterpolationMode === 'monotone') {
2992
+ helpers.splineCurveMonotone(points);
2993
+ } else {
2994
+ for (i = 0, ilen = points.length; i < ilen; ++i) {
2995
+ point = points[i];
2996
+ model = point._model;
2997
+ controlPoints = helpers.splineCurve(
2998
+ helpers.previousItem(points, i)._model,
2999
+ model,
3000
+ helpers.nextItem(points, i)._model,
3001
+ meta.dataset._model.tension
3002
+ );
3003
+ model.controlPointPreviousX = controlPoints.previous.x;
3004
+ model.controlPointPreviousY = controlPoints.previous.y;
3005
+ model.controlPointNextX = controlPoints.next.x;
3006
+ model.controlPointNextY = controlPoints.next.y;
3007
+ }
3008
+ }
3009
+
3010
+ if (me.chart.options.elements.line.capBezierPoints) {
3011
+ for (i = 0, ilen = points.length; i < ilen; ++i) {
3012
+ model = points[i]._model;
3013
+ model.controlPointPreviousX = capControlPoint(model.controlPointPreviousX, area.left, area.right);
3014
+ model.controlPointPreviousY = capControlPoint(model.controlPointPreviousY, area.top, area.bottom);
3015
+ model.controlPointNextX = capControlPoint(model.controlPointNextX, area.left, area.right);
3016
+ model.controlPointNextY = capControlPoint(model.controlPointNextY, area.top, area.bottom);
3017
+ }
3018
+ }
3019
+ },
3020
+
3021
+ draw: function() {
3022
+ var me = this;
3023
+ var chart = me.chart;
3024
+ var meta = me.getMeta();
3025
+ var points = meta.data || [];
3026
+ var area = chart.chartArea;
3027
+ var ilen = points.length;
3028
+ var i = 0;
3029
+
3030
+ helpers.canvas.clipArea(chart.ctx, area);
3031
+
3032
+ if (lineEnabled(me.getDataset(), chart.options)) {
3033
+ meta.dataset.draw();
3034
+ }
3035
+
3036
+ helpers.canvas.unclipArea(chart.ctx);
3037
+
3038
+ // Draw the points
3039
+ for (; i < ilen; ++i) {
3040
+ points[i].draw(area);
3041
+ }
3042
+ },
3043
+
3044
+ setHoverStyle: function(point) {
3045
+ // Point
3046
+ var dataset = this.chart.data.datasets[point._datasetIndex];
3047
+ var index = point._index;
3048
+ var custom = point.custom || {};
3049
+ var model = point._model;
3050
+
3051
+ model.radius = custom.hoverRadius || helpers.valueAtIndexOrDefault(dataset.pointHoverRadius, index, this.chart.options.elements.point.hoverRadius);
3052
+ model.backgroundColor = custom.hoverBackgroundColor || helpers.valueAtIndexOrDefault(dataset.pointHoverBackgroundColor, index, helpers.getHoverColor(model.backgroundColor));
3053
+ model.borderColor = custom.hoverBorderColor || helpers.valueAtIndexOrDefault(dataset.pointHoverBorderColor, index, helpers.getHoverColor(model.borderColor));
3054
+ model.borderWidth = custom.hoverBorderWidth || helpers.valueAtIndexOrDefault(dataset.pointHoverBorderWidth, index, model.borderWidth);
3055
+ },
3056
+
3057
+ removeHoverStyle: function(point) {
3058
+ var me = this;
3059
+ var dataset = me.chart.data.datasets[point._datasetIndex];
3060
+ var index = point._index;
3061
+ var custom = point.custom || {};
3062
+ var model = point._model;
3063
+
3064
+ // Compatibility: If the properties are defined with only the old name, use those values
3065
+ if ((dataset.radius !== undefined) && (dataset.pointRadius === undefined)) {
3066
+ dataset.pointRadius = dataset.radius;
3067
+ }
3068
+
3069
+ model.radius = custom.radius || helpers.valueAtIndexOrDefault(dataset.pointRadius, index, me.chart.options.elements.point.radius);
3070
+ model.backgroundColor = me.getPointBackgroundColor(point, index);
3071
+ model.borderColor = me.getPointBorderColor(point, index);
3072
+ model.borderWidth = me.getPointBorderWidth(point, index);
3073
+ }
3074
+ });
3075
+ };
3076
+
3077
+ },{"25":25,"40":40,"45":45}],19:[function(require,module,exports){
3078
+ 'use strict';
3079
+
3080
+ var defaults = require(25);
3081
+ var elements = require(40);
3082
+ var helpers = require(45);
3083
+
3084
+ defaults._set('polarArea', {
3085
+ scale: {
3086
+ type: 'radialLinear',
3087
+ angleLines: {
3088
+ display: false
3089
+ },
3090
+ gridLines: {
3091
+ circular: true
3092
+ },
3093
+ pointLabels: {
3094
+ display: false
3095
+ },
3096
+ ticks: {
3097
+ beginAtZero: true
3098
+ }
3099
+ },
3100
+
3101
+ // Boolean - Whether to animate the rotation of the chart
3102
+ animation: {
3103
+ animateRotate: true,
3104
+ animateScale: true
3105
+ },
3106
+
3107
+ startAngle: -0.5 * Math.PI,
3108
+ legendCallback: function(chart) {
3109
+ var text = [];
3110
+ text.push('<ul class="' + chart.id + '-legend">');
3111
+
3112
+ var data = chart.data;
3113
+ var datasets = data.datasets;
3114
+ var labels = data.labels;
3115
+
3116
+ if (datasets.length) {
3117
+ for (var i = 0; i < datasets[0].data.length; ++i) {
3118
+ text.push('<li><span style="background-color:' + datasets[0].backgroundColor[i] + '"></span>');
3119
+ if (labels[i]) {
3120
+ text.push(labels[i]);
3121
+ }
3122
+ text.push('</li>');
3123
+ }
3124
+ }
3125
+
3126
+ text.push('</ul>');
3127
+ return text.join('');
3128
+ },
3129
+ legend: {
3130
+ labels: {
3131
+ generateLabels: function(chart) {
3132
+ var data = chart.data;
3133
+ if (data.labels.length && data.datasets.length) {
3134
+ return data.labels.map(function(label, i) {
3135
+ var meta = chart.getDatasetMeta(0);
3136
+ var ds = data.datasets[0];
3137
+ var arc = meta.data[i];
3138
+ var custom = arc.custom || {};
3139
+ var valueAtIndexOrDefault = helpers.valueAtIndexOrDefault;
3140
+ var arcOpts = chart.options.elements.arc;
3141
+ var fill = custom.backgroundColor ? custom.backgroundColor : valueAtIndexOrDefault(ds.backgroundColor, i, arcOpts.backgroundColor);
3142
+ var stroke = custom.borderColor ? custom.borderColor : valueAtIndexOrDefault(ds.borderColor, i, arcOpts.borderColor);
3143
+ var bw = custom.borderWidth ? custom.borderWidth : valueAtIndexOrDefault(ds.borderWidth, i, arcOpts.borderWidth);
3144
+
3145
+ return {
3146
+ text: label,
3147
+ fillStyle: fill,
3148
+ strokeStyle: stroke,
3149
+ lineWidth: bw,
3150
+ hidden: isNaN(ds.data[i]) || meta.data[i].hidden,
3151
+
3152
+ // Extra data used for toggling the correct item
3153
+ index: i
3154
+ };
3155
+ });
3156
+ }
3157
+ return [];
3158
+ }
3159
+ },
3160
+
3161
+ onClick: function(e, legendItem) {
3162
+ var index = legendItem.index;
3163
+ var chart = this.chart;
3164
+ var i, ilen, meta;
3165
+
3166
+ for (i = 0, ilen = (chart.data.datasets || []).length; i < ilen; ++i) {
3167
+ meta = chart.getDatasetMeta(i);
3168
+ meta.data[index].hidden = !meta.data[index].hidden;
3169
+ }
3170
+
3171
+ chart.update();
3172
+ }
3173
+ },
3174
+
3175
+ // Need to override these to give a nice default
3176
+ tooltips: {
3177
+ callbacks: {
3178
+ title: function() {
3179
+ return '';
3180
+ },
3181
+ label: function(item, data) {
3182
+ return data.labels[item.index] + ': ' + item.yLabel;
3183
+ }
3184
+ }
3185
+ }
3186
+ });
3187
+
3188
+ module.exports = function(Chart) {
3189
+
3190
+ Chart.controllers.polarArea = Chart.DatasetController.extend({
3191
+
3192
+ dataElementType: elements.Arc,
3193
+
3194
+ linkScales: helpers.noop,
3195
+
3196
+ update: function(reset) {
3197
+ var me = this;
3198
+ var chart = me.chart;
3199
+ var chartArea = chart.chartArea;
3200
+ var meta = me.getMeta();
3201
+ var opts = chart.options;
3202
+ var arcOpts = opts.elements.arc;
3203
+ var minSize = Math.min(chartArea.right - chartArea.left, chartArea.bottom - chartArea.top);
3204
+ chart.outerRadius = Math.max((minSize - arcOpts.borderWidth / 2) / 2, 0);
3205
+ chart.innerRadius = Math.max(opts.cutoutPercentage ? (chart.outerRadius / 100) * (opts.cutoutPercentage) : 1, 0);
3206
+ chart.radiusLength = (chart.outerRadius - chart.innerRadius) / chart.getVisibleDatasetCount();
3207
+
3208
+ me.outerRadius = chart.outerRadius - (chart.radiusLength * me.index);
3209
+ me.innerRadius = me.outerRadius - chart.radiusLength;
3210
+
3211
+ meta.count = me.countVisibleElements();
3212
+
3213
+ helpers.each(meta.data, function(arc, index) {
3214
+ me.updateElement(arc, index, reset);
3215
+ });
3216
+ },
3217
+
3218
+ updateElement: function(arc, index, reset) {
3219
+ var me = this;
3220
+ var chart = me.chart;
3221
+ var dataset = me.getDataset();
3222
+ var opts = chart.options;
3223
+ var animationOpts = opts.animation;
3224
+ var scale = chart.scale;
3225
+ var labels = chart.data.labels;
3226
+
3227
+ var circumference = me.calculateCircumference(dataset.data[index]);
3228
+ var centerX = scale.xCenter;
3229
+ var centerY = scale.yCenter;
3230
+
3231
+ // If there is NaN data before us, we need to calculate the starting angle correctly.
3232
+ // We could be way more efficient here, but its unlikely that the polar area chart will have a lot of data
3233
+ var visibleCount = 0;
3234
+ var meta = me.getMeta();
3235
+ for (var i = 0; i < index; ++i) {
3236
+ if (!isNaN(dataset.data[i]) && !meta.data[i].hidden) {
3237
+ ++visibleCount;
3238
+ }
3239
+ }
3240
+
3241
+ // var negHalfPI = -0.5 * Math.PI;
3242
+ var datasetStartAngle = opts.startAngle;
3243
+ var distance = arc.hidden ? 0 : scale.getDistanceFromCenterForValue(dataset.data[index]);
3244
+ var startAngle = datasetStartAngle + (circumference * visibleCount);
3245
+ var endAngle = startAngle + (arc.hidden ? 0 : circumference);
3246
+
3247
+ var resetRadius = animationOpts.animateScale ? 0 : scale.getDistanceFromCenterForValue(dataset.data[index]);
3248
+
3249
+ helpers.extend(arc, {
3250
+ // Utility
3251
+ _datasetIndex: me.index,
3252
+ _index: index,
3253
+ _scale: scale,
3254
+
3255
+ // Desired view properties
3256
+ _model: {
3257
+ x: centerX,
3258
+ y: centerY,
3259
+ innerRadius: 0,
3260
+ outerRadius: reset ? resetRadius : distance,
3261
+ startAngle: reset && animationOpts.animateRotate ? datasetStartAngle : startAngle,
3262
+ endAngle: reset && animationOpts.animateRotate ? datasetStartAngle : endAngle,
3263
+ label: helpers.valueAtIndexOrDefault(labels, index, labels[index])
3264
+ }
3265
+ });
3266
+
3267
+ // Apply border and fill style
3268
+ me.removeHoverStyle(arc);
3269
+
3270
+ arc.pivot();
3271
+ },
3272
+
3273
+ removeHoverStyle: function(arc) {
3274
+ Chart.DatasetController.prototype.removeHoverStyle.call(this, arc, this.chart.options.elements.arc);
3275
+ },
3276
+
3277
+ countVisibleElements: function() {
3278
+ var dataset = this.getDataset();
3279
+ var meta = this.getMeta();
3280
+ var count = 0;
3281
+
3282
+ helpers.each(meta.data, function(element, index) {
3283
+ if (!isNaN(dataset.data[index]) && !element.hidden) {
3284
+ count++;
3285
+ }
3286
+ });
3287
+
3288
+ return count;
3289
+ },
3290
+
3291
+ calculateCircumference: function(value) {
3292
+ var count = this.getMeta().count;
3293
+ if (count > 0 && !isNaN(value)) {
3294
+ return (2 * Math.PI) / count;
3295
+ }
3296
+ return 0;
3297
+ }
3298
+ });
3299
+ };
3300
+
3301
+ },{"25":25,"40":40,"45":45}],20:[function(require,module,exports){
3302
+ 'use strict';
3303
+
3304
+ var defaults = require(25);
3305
+ var elements = require(40);
3306
+ var helpers = require(45);
3307
+
3308
+ defaults._set('radar', {
3309
+ scale: {
3310
+ type: 'radialLinear'
3311
+ },
3312
+ elements: {
3313
+ line: {
3314
+ tension: 0 // no bezier in radar
3315
+ }
3316
+ }
3317
+ });
3318
+
3319
+ module.exports = function(Chart) {
3320
+
3321
+ Chart.controllers.radar = Chart.DatasetController.extend({
3322
+
3323
+ datasetElementType: elements.Line,
3324
+
3325
+ dataElementType: elements.Point,
3326
+
3327
+ linkScales: helpers.noop,
3328
+
3329
+ update: function(reset) {
3330
+ var me = this;
3331
+ var meta = me.getMeta();
3332
+ var line = meta.dataset;
3333
+ var points = meta.data;
3334
+ var custom = line.custom || {};
3335
+ var dataset = me.getDataset();
3336
+ var lineElementOptions = me.chart.options.elements.line;
3337
+ var scale = me.chart.scale;
3338
+
3339
+ // Compatibility: If the properties are defined with only the old name, use those values
3340
+ if ((dataset.tension !== undefined) && (dataset.lineTension === undefined)) {
3341
+ dataset.lineTension = dataset.tension;
3342
+ }
3343
+
3344
+ helpers.extend(meta.dataset, {
3345
+ // Utility
3346
+ _datasetIndex: me.index,
3347
+ _scale: scale,
3348
+ // Data
3349
+ _children: points,
3350
+ _loop: true,
3351
+ // Model
3352
+ _model: {
3353
+ // Appearance
3354
+ tension: custom.tension ? custom.tension : helpers.valueOrDefault(dataset.lineTension, lineElementOptions.tension),
3355
+ backgroundColor: custom.backgroundColor ? custom.backgroundColor : (dataset.backgroundColor || lineElementOptions.backgroundColor),
3356
+ borderWidth: custom.borderWidth ? custom.borderWidth : (dataset.borderWidth || lineElementOptions.borderWidth),
3357
+ borderColor: custom.borderColor ? custom.borderColor : (dataset.borderColor || lineElementOptions.borderColor),
3358
+ fill: custom.fill ? custom.fill : (dataset.fill !== undefined ? dataset.fill : lineElementOptions.fill),
3359
+ borderCapStyle: custom.borderCapStyle ? custom.borderCapStyle : (dataset.borderCapStyle || lineElementOptions.borderCapStyle),
3360
+ borderDash: custom.borderDash ? custom.borderDash : (dataset.borderDash || lineElementOptions.borderDash),
3361
+ borderDashOffset: custom.borderDashOffset ? custom.borderDashOffset : (dataset.borderDashOffset || lineElementOptions.borderDashOffset),
3362
+ borderJoinStyle: custom.borderJoinStyle ? custom.borderJoinStyle : (dataset.borderJoinStyle || lineElementOptions.borderJoinStyle),
3363
+ }
3364
+ });
3365
+
3366
+ meta.dataset.pivot();
3367
+
3368
+ // Update Points
3369
+ helpers.each(points, function(point, index) {
3370
+ me.updateElement(point, index, reset);
3371
+ }, me);
3372
+
3373
+ // Update bezier control points
3374
+ me.updateBezierControlPoints();
3375
+ },
3376
+ updateElement: function(point, index, reset) {
3377
+ var me = this;
3378
+ var custom = point.custom || {};
3379
+ var dataset = me.getDataset();
3380
+ var scale = me.chart.scale;
3381
+ var pointElementOptions = me.chart.options.elements.point;
3382
+ var pointPosition = scale.getPointPositionForValue(index, dataset.data[index]);
3383
+
3384
+ // Compatibility: If the properties are defined with only the old name, use those values
3385
+ if ((dataset.radius !== undefined) && (dataset.pointRadius === undefined)) {
3386
+ dataset.pointRadius = dataset.radius;
3387
+ }
3388
+ if ((dataset.hitRadius !== undefined) && (dataset.pointHitRadius === undefined)) {
3389
+ dataset.pointHitRadius = dataset.hitRadius;
3390
+ }
3391
+
3392
+ helpers.extend(point, {
3393
+ // Utility
3394
+ _datasetIndex: me.index,
3395
+ _index: index,
3396
+ _scale: scale,
3397
+
3398
+ // Desired view properties
3399
+ _model: {
3400
+ x: reset ? scale.xCenter : pointPosition.x, // value not used in dataset scale, but we want a consistent API between scales
3401
+ y: reset ? scale.yCenter : pointPosition.y,
3402
+
3403
+ // Appearance
3404
+ tension: custom.tension ? custom.tension : helpers.valueOrDefault(dataset.lineTension, me.chart.options.elements.line.tension),
3405
+ radius: custom.radius ? custom.radius : helpers.valueAtIndexOrDefault(dataset.pointRadius, index, pointElementOptions.radius),
3406
+ backgroundColor: custom.backgroundColor ? custom.backgroundColor : helpers.valueAtIndexOrDefault(dataset.pointBackgroundColor, index, pointElementOptions.backgroundColor),
3407
+ borderColor: custom.borderColor ? custom.borderColor : helpers.valueAtIndexOrDefault(dataset.pointBorderColor, index, pointElementOptions.borderColor),
3408
+ borderWidth: custom.borderWidth ? custom.borderWidth : helpers.valueAtIndexOrDefault(dataset.pointBorderWidth, index, pointElementOptions.borderWidth),
3409
+ pointStyle: custom.pointStyle ? custom.pointStyle : helpers.valueAtIndexOrDefault(dataset.pointStyle, index, pointElementOptions.pointStyle),
3410
+
3411
+ // Tooltip
3412
+ hitRadius: custom.hitRadius ? custom.hitRadius : helpers.valueAtIndexOrDefault(dataset.pointHitRadius, index, pointElementOptions.hitRadius)
3413
+ }
3414
+ });
3415
+
3416
+ point._model.skip = custom.skip ? custom.skip : (isNaN(point._model.x) || isNaN(point._model.y));
3417
+ },
3418
+ updateBezierControlPoints: function() {
3419
+ var chartArea = this.chart.chartArea;
3420
+ var meta = this.getMeta();
3421
+
3422
+ helpers.each(meta.data, function(point, index) {
3423
+ var model = point._model;
3424
+ var controlPoints = helpers.splineCurve(
3425
+ helpers.previousItem(meta.data, index, true)._model,
3426
+ model,
3427
+ helpers.nextItem(meta.data, index, true)._model,
3428
+ model.tension
3429
+ );
3430
+
3431
+ // Prevent the bezier going outside of the bounds of the graph
3432
+ model.controlPointPreviousX = Math.max(Math.min(controlPoints.previous.x, chartArea.right), chartArea.left);
3433
+ model.controlPointPreviousY = Math.max(Math.min(controlPoints.previous.y, chartArea.bottom), chartArea.top);
3434
+
3435
+ model.controlPointNextX = Math.max(Math.min(controlPoints.next.x, chartArea.right), chartArea.left);
3436
+ model.controlPointNextY = Math.max(Math.min(controlPoints.next.y, chartArea.bottom), chartArea.top);
3437
+
3438
+ // Now pivot the point for animation
3439
+ point.pivot();
3440
+ });
3441
+ },
3442
+
3443
+ setHoverStyle: function(point) {
3444
+ // Point
3445
+ var dataset = this.chart.data.datasets[point._datasetIndex];
3446
+ var custom = point.custom || {};
3447
+ var index = point._index;
3448
+ var model = point._model;
3449
+
3450
+ model.radius = custom.hoverRadius ? custom.hoverRadius : helpers.valueAtIndexOrDefault(dataset.pointHoverRadius, index, this.chart.options.elements.point.hoverRadius);
3451
+ model.backgroundColor = custom.hoverBackgroundColor ? custom.hoverBackgroundColor : helpers.valueAtIndexOrDefault(dataset.pointHoverBackgroundColor, index, helpers.getHoverColor(model.backgroundColor));
3452
+ model.borderColor = custom.hoverBorderColor ? custom.hoverBorderColor : helpers.valueAtIndexOrDefault(dataset.pointHoverBorderColor, index, helpers.getHoverColor(model.borderColor));
3453
+ model.borderWidth = custom.hoverBorderWidth ? custom.hoverBorderWidth : helpers.valueAtIndexOrDefault(dataset.pointHoverBorderWidth, index, model.borderWidth);
3454
+ },
3455
+
3456
+ removeHoverStyle: function(point) {
3457
+ var dataset = this.chart.data.datasets[point._datasetIndex];
3458
+ var custom = point.custom || {};
3459
+ var index = point._index;
3460
+ var model = point._model;
3461
+ var pointElementOptions = this.chart.options.elements.point;
3462
+
3463
+ model.radius = custom.radius ? custom.radius : helpers.valueAtIndexOrDefault(dataset.pointRadius, index, pointElementOptions.radius);
3464
+ model.backgroundColor = custom.backgroundColor ? custom.backgroundColor : helpers.valueAtIndexOrDefault(dataset.pointBackgroundColor, index, pointElementOptions.backgroundColor);
3465
+ model.borderColor = custom.borderColor ? custom.borderColor : helpers.valueAtIndexOrDefault(dataset.pointBorderColor, index, pointElementOptions.borderColor);
3466
+ model.borderWidth = custom.borderWidth ? custom.borderWidth : helpers.valueAtIndexOrDefault(dataset.pointBorderWidth, index, pointElementOptions.borderWidth);
3467
+ }
3468
+ });
3469
+ };
3470
+
3471
+ },{"25":25,"40":40,"45":45}],21:[function(require,module,exports){
3472
+ 'use strict';
3473
+
3474
+ var defaults = require(25);
3475
+
3476
+ defaults._set('scatter', {
3477
+ hover: {
3478
+ mode: 'single'
3479
+ },
3480
+
3481
+ scales: {
3482
+ xAxes: [{
3483
+ id: 'x-axis-1', // need an ID so datasets can reference the scale
3484
+ type: 'linear', // scatter should not use a category axis
3485
+ position: 'bottom'
3486
+ }],
3487
+ yAxes: [{
3488
+ id: 'y-axis-1',
3489
+ type: 'linear',
3490
+ position: 'left'
3491
+ }]
3492
+ },
3493
+
3494
+ showLines: false,
3495
+
3496
+ tooltips: {
3497
+ callbacks: {
3498
+ title: function() {
3499
+ return ''; // doesn't make sense for scatter since data are formatted as a point
3500
+ },
3501
+ label: function(item) {
3502
+ return '(' + item.xLabel + ', ' + item.yLabel + ')';
3503
+ }
3504
+ }
3505
+ }
3506
+ });
3507
+
3508
+ module.exports = function(Chart) {
3509
+
3510
+ // Scatter charts use line controllers
3511
+ Chart.controllers.scatter = Chart.controllers.line;
3512
+
3513
+ };
3514
+
3515
+ },{"25":25}],22:[function(require,module,exports){
3516
+ /* global window: false */
3517
+ 'use strict';
3518
+
3519
+ var defaults = require(25);
3520
+ var Element = require(26);
3521
+ var helpers = require(45);
3522
+
3523
+ defaults._set('global', {
3524
+ animation: {
3525
+ duration: 1000,
3526
+ easing: 'easeOutQuart',
3527
+ onProgress: helpers.noop,
3528
+ onComplete: helpers.noop
3529
+ }
3530
+ });
3531
+
3532
+ module.exports = function(Chart) {
3533
+
3534
+ Chart.Animation = Element.extend({
3535
+ chart: null, // the animation associated chart instance
3536
+ currentStep: 0, // the current animation step
3537
+ numSteps: 60, // default number of steps
3538
+ easing: '', // the easing to use for this animation
3539
+ render: null, // render function used by the animation service
3540
+
3541
+ onAnimationProgress: null, // user specified callback to fire on each step of the animation
3542
+ onAnimationComplete: null, // user specified callback to fire when the animation finishes
3543
+ });
3544
+
3545
+ Chart.animationService = {
3546
+ frameDuration: 17,
3547
+ animations: [],
3548
+ dropFrames: 0,
3549
+ request: null,
3550
+
3551
+ /**
3552
+ * @param {Chart} chart - The chart to animate.
3553
+ * @param {Chart.Animation} animation - The animation that we will animate.
3554
+ * @param {Number} duration - The animation duration in ms.
3555
+ * @param {Boolean} lazy - if true, the chart is not marked as animating to enable more responsive interactions
3556
+ */
3557
+ addAnimation: function(chart, animation, duration, lazy) {
3558
+ var animations = this.animations;
3559
+ var i, ilen;
3560
+
3561
+ animation.chart = chart;
3562
+
3563
+ if (!lazy) {
3564
+ chart.animating = true;
3565
+ }
3566
+
3567
+ for (i = 0, ilen = animations.length; i < ilen; ++i) {
3568
+ if (animations[i].chart === chart) {
3569
+ animations[i] = animation;
3570
+ return;
3571
+ }
3572
+ }
3573
+
3574
+ animations.push(animation);
3575
+
3576
+ // If there are no animations queued, manually kickstart a digest, for lack of a better word
3577
+ if (animations.length === 1) {
3578
+ this.requestAnimationFrame();
3579
+ }
3580
+ },
3581
+
3582
+ cancelAnimation: function(chart) {
3583
+ var index = helpers.findIndex(this.animations, function(animation) {
3584
+ return animation.chart === chart;
3585
+ });
3586
+
3587
+ if (index !== -1) {
3588
+ this.animations.splice(index, 1);
3589
+ chart.animating = false;
3590
+ }
3591
+ },
3592
+
3593
+ requestAnimationFrame: function() {
3594
+ var me = this;
3595
+ if (me.request === null) {
3596
+ // Skip animation frame requests until the active one is executed.
3597
+ // This can happen when processing mouse events, e.g. 'mousemove'
3598
+ // and 'mouseout' events will trigger multiple renders.
3599
+ me.request = helpers.requestAnimFrame.call(window, function() {
3600
+ me.request = null;
3601
+ me.startDigest();
3602
+ });
3603
+ }
3604
+ },
3605
+
3606
+ /**
3607
+ * @private
3608
+ */
3609
+ startDigest: function() {
3610
+ var me = this;
3611
+ var startTime = Date.now();
3612
+ var framesToDrop = 0;
3613
+
3614
+ if (me.dropFrames > 1) {
3615
+ framesToDrop = Math.floor(me.dropFrames);
3616
+ me.dropFrames = me.dropFrames % 1;
3617
+ }
3618
+
3619
+ me.advance(1 + framesToDrop);
3620
+
3621
+ var endTime = Date.now();
3622
+
3623
+ me.dropFrames += (endTime - startTime) / me.frameDuration;
3624
+
3625
+ // Do we have more stuff to animate?
3626
+ if (me.animations.length > 0) {
3627
+ me.requestAnimationFrame();
3628
+ }
3629
+ },
3630
+
3631
+ /**
3632
+ * @private
3633
+ */
3634
+ advance: function(count) {
3635
+ var animations = this.animations;
3636
+ var animation, chart;
3637
+ var i = 0;
3638
+
3639
+ while (i < animations.length) {
3640
+ animation = animations[i];
3641
+ chart = animation.chart;
3642
+
3643
+ animation.currentStep = (animation.currentStep || 0) + count;
3644
+ animation.currentStep = Math.min(animation.currentStep, animation.numSteps);
3645
+
3646
+ helpers.callback(animation.render, [chart, animation], chart);
3647
+ helpers.callback(animation.onAnimationProgress, [animation], chart);
3648
+
3649
+ if (animation.currentStep >= animation.numSteps) {
3650
+ helpers.callback(animation.onAnimationComplete, [animation], chart);
3651
+ chart.animating = false;
3652
+ animations.splice(i, 1);
3653
+ } else {
3654
+ ++i;
3655
+ }
3656
+ }
3657
+ }
3658
+ };
3659
+
3660
+ /**
3661
+ * Provided for backward compatibility, use Chart.Animation instead
3662
+ * @prop Chart.Animation#animationObject
3663
+ * @deprecated since version 2.6.0
3664
+ * @todo remove at version 3
3665
+ */
3666
+ Object.defineProperty(Chart.Animation.prototype, 'animationObject', {
3667
+ get: function() {
3668
+ return this;
3669
+ }
3670
+ });
3671
+
3672
+ /**
3673
+ * Provided for backward compatibility, use Chart.Animation#chart instead
3674
+ * @prop Chart.Animation#chartInstance
3675
+ * @deprecated since version 2.6.0
3676
+ * @todo remove at version 3
3677
+ */
3678
+ Object.defineProperty(Chart.Animation.prototype, 'chartInstance', {
3679
+ get: function() {
3680
+ return this.chart;
3681
+ },
3682
+ set: function(value) {
3683
+ this.chart = value;
3684
+ }
3685
+ });
3686
+
3687
+ };
3688
+
3689
+ },{"25":25,"26":26,"45":45}],23:[function(require,module,exports){
3690
+ 'use strict';
3691
+
3692
+ var defaults = require(25);
3693
+ var helpers = require(45);
3694
+ var Interaction = require(28);
3695
+ var platform = require(48);
3696
+
3697
+ module.exports = function(Chart) {
3698
+ var plugins = Chart.plugins;
3699
+
3700
+ // Create a dictionary of chart types, to allow for extension of existing types
3701
+ Chart.types = {};
3702
+
3703
+ // Store a reference to each instance - allowing us to globally resize chart instances on window resize.
3704
+ // Destroy method on the chart will remove the instance of the chart from this reference.
3705
+ Chart.instances = {};
3706
+
3707
+ // Controllers available for dataset visualization eg. bar, line, slice, etc.
3708
+ Chart.controllers = {};
3709
+
3710
+ /**
3711
+ * Initializes the given config with global and chart default values.
3712
+ */
3713
+ function initConfig(config) {
3714
+ config = config || {};
3715
+
3716
+ // Do NOT use configMerge() for the data object because this method merges arrays
3717
+ // and so would change references to labels and datasets, preventing data updates.
3718
+ var data = config.data = config.data || {};
3719
+ data.datasets = data.datasets || [];
3720
+ data.labels = data.labels || [];
3721
+
3722
+ config.options = helpers.configMerge(
3723
+ defaults.global,
3724
+ defaults[config.type],
3725
+ config.options || {});
3726
+
3727
+ return config;
3728
+ }
3729
+
3730
+ /**
3731
+ * Updates the config of the chart
3732
+ * @param chart {Chart} chart to update the options for
3733
+ */
3734
+ function updateConfig(chart) {
3735
+ var newOptions = chart.options;
3736
+
3737
+ // Update Scale(s) with options
3738
+ if (newOptions.scale) {
3739
+ chart.scale.options = newOptions.scale;
3740
+ } else if (newOptions.scales) {
3741
+ newOptions.scales.xAxes.concat(newOptions.scales.yAxes).forEach(function(scaleOptions) {
3742
+ chart.scales[scaleOptions.id].options = scaleOptions;
3743
+ });
3744
+ }
3745
+
3746
+ // Tooltip
3747
+ chart.tooltip._options = newOptions.tooltips;
3748
+ }
3749
+
3750
+ function positionIsHorizontal(position) {
3751
+ return position === 'top' || position === 'bottom';
3752
+ }
3753
+
3754
+ helpers.extend(Chart.prototype, /** @lends Chart */ {
3755
+ /**
3756
+ * @private
3757
+ */
3758
+ construct: function(item, config) {
3759
+ var me = this;
3760
+
3761
+ config = initConfig(config);
3762
+
3763
+ var context = platform.acquireContext(item, config);
3764
+ var canvas = context && context.canvas;
3765
+ var height = canvas && canvas.height;
3766
+ var width = canvas && canvas.width;
3767
+
3768
+ me.id = helpers.uid();
3769
+ me.ctx = context;
3770
+ me.canvas = canvas;
3771
+ me.config = config;
3772
+ me.width = width;
3773
+ me.height = height;
3774
+ me.aspectRatio = height ? width / height : null;
3775
+ me.options = config.options;
3776
+ me._bufferedRender = false;
3777
+
3778
+ /**
3779
+ * Provided for backward compatibility, Chart and Chart.Controller have been merged,
3780
+ * the "instance" still need to be defined since it might be called from plugins.
3781
+ * @prop Chart#chart
3782
+ * @deprecated since version 2.6.0
3783
+ * @todo remove at version 3
3784
+ * @private
3785
+ */
3786
+ me.chart = me;
3787
+ me.controller = me; // chart.chart.controller #inception
3788
+
3789
+ // Add the chart instance to the global namespace
3790
+ Chart.instances[me.id] = me;
3791
+
3792
+ // Define alias to the config data: `chart.data === chart.config.data`
3793
+ Object.defineProperty(me, 'data', {
3794
+ get: function() {
3795
+ return me.config.data;
3796
+ },
3797
+ set: function(value) {
3798
+ me.config.data = value;
3799
+ }
3800
+ });
3801
+
3802
+ if (!context || !canvas) {
3803
+ // The given item is not a compatible context2d element, let's return before finalizing
3804
+ // the chart initialization but after setting basic chart / controller properties that
3805
+ // can help to figure out that the chart is not valid (e.g chart.canvas !== null);
3806
+ // https://github.com/chartjs/Chart.js/issues/2807
3807
+ console.error("Failed to create chart: can't acquire context from the given item");
3808
+ return;
3809
+ }
3810
+
3811
+ me.initialize();
3812
+ me.update();
3813
+ },
3814
+
3815
+ /**
3816
+ * @private
3817
+ */
3818
+ initialize: function() {
3819
+ var me = this;
3820
+
3821
+ // Before init plugin notification
3822
+ plugins.notify(me, 'beforeInit');
3823
+
3824
+ helpers.retinaScale(me, me.options.devicePixelRatio);
3825
+
3826
+ me.bindEvents();
3827
+
3828
+ if (me.options.responsive) {
3829
+ // Initial resize before chart draws (must be silent to preserve initial animations).
3830
+ me.resize(true);
3831
+ }
3832
+
3833
+ // Make sure scales have IDs and are built before we build any controllers.
3834
+ me.ensureScalesHaveIDs();
3835
+ me.buildScales();
3836
+ me.initToolTip();
3837
+
3838
+ // After init plugin notification
3839
+ plugins.notify(me, 'afterInit');
3840
+
3841
+ return me;
3842
+ },
3843
+
3844
+ clear: function() {
3845
+ helpers.canvas.clear(this);
3846
+ return this;
3847
+ },
3848
+
3849
+ stop: function() {
3850
+ // Stops any current animation loop occurring
3851
+ Chart.animationService.cancelAnimation(this);
3852
+ return this;
3853
+ },
3854
+
3855
+ resize: function(silent) {
3856
+ var me = this;
3857
+ var options = me.options;
3858
+ var canvas = me.canvas;
3859
+ var aspectRatio = (options.maintainAspectRatio && me.aspectRatio) || null;
3860
+
3861
+ // the canvas render width and height will be casted to integers so make sure that
3862
+ // the canvas display style uses the same integer values to avoid blurring effect.
3863
+
3864
+ // Set to 0 instead of canvas.size because the size defaults to 300x150 if the element is collased
3865
+ var newWidth = Math.max(0, Math.floor(helpers.getMaximumWidth(canvas)));
3866
+ var newHeight = Math.max(0, Math.floor(aspectRatio ? newWidth / aspectRatio : helpers.getMaximumHeight(canvas)));
3867
+
3868
+ if (me.width === newWidth && me.height === newHeight) {
3869
+ return;
3870
+ }
3871
+
3872
+ canvas.width = me.width = newWidth;
3873
+ canvas.height = me.height = newHeight;
3874
+ canvas.style.width = newWidth + 'px';
3875
+ canvas.style.height = newHeight + 'px';
3876
+
3877
+ helpers.retinaScale(me, options.devicePixelRatio);
3878
+
3879
+ if (!silent) {
3880
+ // Notify any plugins about the resize
3881
+ var newSize = {width: newWidth, height: newHeight};
3882
+ plugins.notify(me, 'resize', [newSize]);
3883
+
3884
+ // Notify of resize
3885
+ if (me.options.onResize) {
3886
+ me.options.onResize(me, newSize);
3887
+ }
3888
+
3889
+ me.stop();
3890
+ me.update(me.options.responsiveAnimationDuration);
3891
+ }
3892
+ },
3893
+
3894
+ ensureScalesHaveIDs: function() {
3895
+ var options = this.options;
3896
+ var scalesOptions = options.scales || {};
3897
+ var scaleOptions = options.scale;
3898
+
3899
+ helpers.each(scalesOptions.xAxes, function(xAxisOptions, index) {
3900
+ xAxisOptions.id = xAxisOptions.id || ('x-axis-' + index);
3901
+ });
3902
+
3903
+ helpers.each(scalesOptions.yAxes, function(yAxisOptions, index) {
3904
+ yAxisOptions.id = yAxisOptions.id || ('y-axis-' + index);
3905
+ });
3906
+
3907
+ if (scaleOptions) {
3908
+ scaleOptions.id = scaleOptions.id || 'scale';
3909
+ }
3910
+ },
3911
+
3912
+ /**
3913
+ * Builds a map of scale ID to scale object for future lookup.
3914
+ */
3915
+ buildScales: function() {
3916
+ var me = this;
3917
+ var options = me.options;
3918
+ var scales = me.scales = {};
3919
+ var items = [];
3920
+
3921
+ if (options.scales) {
3922
+ items = items.concat(
3923
+ (options.scales.xAxes || []).map(function(xAxisOptions) {
3924
+ return {options: xAxisOptions, dtype: 'category', dposition: 'bottom'};
3925
+ }),
3926
+ (options.scales.yAxes || []).map(function(yAxisOptions) {
3927
+ return {options: yAxisOptions, dtype: 'linear', dposition: 'left'};
3928
+ })
3929
+ );
3930
+ }
3931
+
3932
+ if (options.scale) {
3933
+ items.push({
3934
+ options: options.scale,
3935
+ dtype: 'radialLinear',
3936
+ isDefault: true,
3937
+ dposition: 'chartArea'
3938
+ });
3939
+ }
3940
+
3941
+ helpers.each(items, function(item) {
3942
+ var scaleOptions = item.options;
3943
+ var scaleType = helpers.valueOrDefault(scaleOptions.type, item.dtype);
3944
+ var scaleClass = Chart.scaleService.getScaleConstructor(scaleType);
3945
+ if (!scaleClass) {
3946
+ return;
3947
+ }
3948
+
3949
+ if (positionIsHorizontal(scaleOptions.position) !== positionIsHorizontal(item.dposition)) {
3950
+ scaleOptions.position = item.dposition;
3951
+ }
3952
+
3953
+ var scale = new scaleClass({
3954
+ id: scaleOptions.id,
3955
+ options: scaleOptions,
3956
+ ctx: me.ctx,
3957
+ chart: me
3958
+ });
3959
+
3960
+ scales[scale.id] = scale;
3961
+ scale.mergeTicksOptions();
3962
+
3963
+ // TODO(SB): I think we should be able to remove this custom case (options.scale)
3964
+ // and consider it as a regular scale part of the "scales"" map only! This would
3965
+ // make the logic easier and remove some useless? custom code.
3966
+ if (item.isDefault) {
3967
+ me.scale = scale;
3968
+ }
3969
+ });
3970
+
3971
+ Chart.scaleService.addScalesToLayout(this);
3972
+ },
3973
+
3974
+ buildOrUpdateControllers: function() {
3975
+ var me = this;
3976
+ var types = [];
3977
+ var newControllers = [];
3978
+
3979
+ helpers.each(me.data.datasets, function(dataset, datasetIndex) {
3980
+ var meta = me.getDatasetMeta(datasetIndex);
3981
+ var type = dataset.type || me.config.type;
3982
+
3983
+ if (meta.type && meta.type !== type) {
3984
+ me.destroyDatasetMeta(datasetIndex);
3985
+ meta = me.getDatasetMeta(datasetIndex);
3986
+ }
3987
+ meta.type = type;
3988
+
3989
+ types.push(meta.type);
3990
+
3991
+ if (meta.controller) {
3992
+ meta.controller.updateIndex(datasetIndex);
3993
+ } else {
3994
+ var ControllerClass = Chart.controllers[meta.type];
3995
+ if (ControllerClass === undefined) {
3996
+ throw new Error('"' + meta.type + '" is not a chart type.');
3997
+ }
3998
+
3999
+ meta.controller = new ControllerClass(me, datasetIndex);
4000
+ newControllers.push(meta.controller);
4001
+ }
4002
+ }, me);
4003
+
4004
+ return newControllers;
4005
+ },
4006
+
4007
+ /**
4008
+ * Reset the elements of all datasets
4009
+ * @private
4010
+ */
4011
+ resetElements: function() {
4012
+ var me = this;
4013
+ helpers.each(me.data.datasets, function(dataset, datasetIndex) {
4014
+ me.getDatasetMeta(datasetIndex).controller.reset();
4015
+ }, me);
4016
+ },
4017
+
4018
+ /**
4019
+ * Resets the chart back to it's state before the initial animation
4020
+ */
4021
+ reset: function() {
4022
+ this.resetElements();
4023
+ this.tooltip.initialize();
4024
+ },
4025
+
4026
+ update: function(config) {
4027
+ var me = this;
4028
+
4029
+ if (!config || typeof config !== 'object') {
4030
+ // backwards compatibility
4031
+ config = {
4032
+ duration: config,
4033
+ lazy: arguments[1]
4034
+ };
4035
+ }
4036
+
4037
+ updateConfig(me);
4038
+
4039
+ if (plugins.notify(me, 'beforeUpdate') === false) {
4040
+ return;
4041
+ }
4042
+
4043
+ // In case the entire data object changed
4044
+ me.tooltip._data = me.data;
4045
+
4046
+ // Make sure dataset controllers are updated and new controllers are reset
4047
+ var newControllers = me.buildOrUpdateControllers();
4048
+
4049
+ // Make sure all dataset controllers have correct meta data counts
4050
+ helpers.each(me.data.datasets, function(dataset, datasetIndex) {
4051
+ me.getDatasetMeta(datasetIndex).controller.buildOrUpdateElements();
4052
+ }, me);
4053
+
4054
+ me.updateLayout();
4055
+
4056
+ // Can only reset the new controllers after the scales have been updated
4057
+ helpers.each(newControllers, function(controller) {
4058
+ controller.reset();
4059
+ });
4060
+
4061
+ me.updateDatasets();
4062
+
4063
+ // Need to reset tooltip in case it is displayed with elements that are removed
4064
+ // after update.
4065
+ me.tooltip.initialize();
4066
+
4067
+ // Last active contains items that were previously in the tooltip.
4068
+ // When we reset the tooltip, we need to clear it
4069
+ me.lastActive = [];
4070
+
4071
+ // Do this before render so that any plugins that need final scale updates can use it
4072
+ plugins.notify(me, 'afterUpdate');
4073
+
4074
+ if (me._bufferedRender) {
4075
+ me._bufferedRequest = {
4076
+ duration: config.duration,
4077
+ easing: config.easing,
4078
+ lazy: config.lazy
4079
+ };
4080
+ } else {
4081
+ me.render(config);
4082
+ }
4083
+ },
4084
+
4085
+ /**
4086
+ * Updates the chart layout unless a plugin returns `false` to the `beforeLayout`
4087
+ * hook, in which case, plugins will not be called on `afterLayout`.
4088
+ * @private
4089
+ */
4090
+ updateLayout: function() {
4091
+ var me = this;
4092
+
4093
+ if (plugins.notify(me, 'beforeLayout') === false) {
4094
+ return;
4095
+ }
4096
+
4097
+ Chart.layoutService.update(this, this.width, this.height);
4098
+
4099
+ /**
4100
+ * Provided for backward compatibility, use `afterLayout` instead.
4101
+ * @method IPlugin#afterScaleUpdate
4102
+ * @deprecated since version 2.5.0
4103
+ * @todo remove at version 3
4104
+ * @private
4105
+ */
4106
+ plugins.notify(me, 'afterScaleUpdate');
4107
+ plugins.notify(me, 'afterLayout');
4108
+ },
4109
+
4110
+ /**
4111
+ * Updates all datasets unless a plugin returns `false` to the `beforeDatasetsUpdate`
4112
+ * hook, in which case, plugins will not be called on `afterDatasetsUpdate`.
4113
+ * @private
4114
+ */
4115
+ updateDatasets: function() {
4116
+ var me = this;
4117
+
4118
+ if (plugins.notify(me, 'beforeDatasetsUpdate') === false) {
4119
+ return;
4120
+ }
4121
+
4122
+ for (var i = 0, ilen = me.data.datasets.length; i < ilen; ++i) {
4123
+ me.updateDataset(i);
4124
+ }
4125
+
4126
+ plugins.notify(me, 'afterDatasetsUpdate');
4127
+ },
4128
+
4129
+ /**
4130
+ * Updates dataset at index unless a plugin returns `false` to the `beforeDatasetUpdate`
4131
+ * hook, in which case, plugins will not be called on `afterDatasetUpdate`.
4132
+ * @private
4133
+ */
4134
+ updateDataset: function(index) {
4135
+ var me = this;
4136
+ var meta = me.getDatasetMeta(index);
4137
+ var args = {
4138
+ meta: meta,
4139
+ index: index
4140
+ };
4141
+
4142
+ if (plugins.notify(me, 'beforeDatasetUpdate', [args]) === false) {
4143
+ return;
4144
+ }
4145
+
4146
+ meta.controller.update();
4147
+
4148
+ plugins.notify(me, 'afterDatasetUpdate', [args]);
4149
+ },
4150
+
4151
+ render: function(config) {
4152
+ var me = this;
4153
+
4154
+ if (!config || typeof config !== 'object') {
4155
+ // backwards compatibility
4156
+ config = {
4157
+ duration: config,
4158
+ lazy: arguments[1]
4159
+ };
4160
+ }
4161
+
4162
+ var duration = config.duration;
4163
+ var lazy = config.lazy;
4164
+
4165
+ if (plugins.notify(me, 'beforeRender') === false) {
4166
+ return;
4167
+ }
4168
+
4169
+ var animationOptions = me.options.animation;
4170
+ var onComplete = function(animation) {
4171
+ plugins.notify(me, 'afterRender');
4172
+ helpers.callback(animationOptions && animationOptions.onComplete, [animation], me);
4173
+ };
4174
+
4175
+ if (animationOptions && ((typeof duration !== 'undefined' && duration !== 0) || (typeof duration === 'undefined' && animationOptions.duration !== 0))) {
4176
+ var animation = new Chart.Animation({
4177
+ numSteps: (duration || animationOptions.duration) / 16.66, // 60 fps
4178
+ easing: config.easing || animationOptions.easing,
4179
+
4180
+ render: function(chart, animationObject) {
4181
+ var easingFunction = helpers.easing.effects[animationObject.easing];
4182
+ var currentStep = animationObject.currentStep;
4183
+ var stepDecimal = currentStep / animationObject.numSteps;
4184
+
4185
+ chart.draw(easingFunction(stepDecimal), stepDecimal, currentStep);
4186
+ },
4187
+
4188
+ onAnimationProgress: animationOptions.onProgress,
4189
+ onAnimationComplete: onComplete
4190
+ });
4191
+
4192
+ Chart.animationService.addAnimation(me, animation, duration, lazy);
4193
+ } else {
4194
+ me.draw();
4195
+
4196
+ // See https://github.com/chartjs/Chart.js/issues/3781
4197
+ onComplete(new Chart.Animation({numSteps: 0, chart: me}));
4198
+ }
4199
+
4200
+ return me;
4201
+ },
4202
+
4203
+ draw: function(easingValue) {
4204
+ var me = this;
4205
+
4206
+ me.clear();
4207
+
4208
+ if (helpers.isNullOrUndef(easingValue)) {
4209
+ easingValue = 1;
4210
+ }
4211
+
4212
+ me.transition(easingValue);
4213
+
4214
+ if (plugins.notify(me, 'beforeDraw', [easingValue]) === false) {
4215
+ return;
4216
+ }
4217
+
4218
+ // Draw all the scales
4219
+ helpers.each(me.boxes, function(box) {
4220
+ box.draw(me.chartArea);
4221
+ }, me);
4222
+
4223
+ if (me.scale) {
4224
+ me.scale.draw();
4225
+ }
4226
+
4227
+ me.drawDatasets(easingValue);
4228
+ me._drawTooltip(easingValue);
4229
+
4230
+ plugins.notify(me, 'afterDraw', [easingValue]);
4231
+ },
4232
+
4233
+ /**
4234
+ * @private
4235
+ */
4236
+ transition: function(easingValue) {
4237
+ var me = this;
4238
+
4239
+ for (var i = 0, ilen = (me.data.datasets || []).length; i < ilen; ++i) {
4240
+ if (me.isDatasetVisible(i)) {
4241
+ me.getDatasetMeta(i).controller.transition(easingValue);
4242
+ }
4243
+ }
4244
+
4245
+ me.tooltip.transition(easingValue);
4246
+ },
4247
+
4248
+ /**
4249
+ * Draws all datasets unless a plugin returns `false` to the `beforeDatasetsDraw`
4250
+ * hook, in which case, plugins will not be called on `afterDatasetsDraw`.
4251
+ * @private
4252
+ */
4253
+ drawDatasets: function(easingValue) {
4254
+ var me = this;
4255
+
4256
+ if (plugins.notify(me, 'beforeDatasetsDraw', [easingValue]) === false) {
4257
+ return;
4258
+ }
4259
+
4260
+ // Draw datasets reversed to support proper line stacking
4261
+ for (var i = (me.data.datasets || []).length - 1; i >= 0; --i) {
4262
+ if (me.isDatasetVisible(i)) {
4263
+ me.drawDataset(i, easingValue);
4264
+ }
4265
+ }
4266
+
4267
+ plugins.notify(me, 'afterDatasetsDraw', [easingValue]);
4268
+ },
4269
+
4270
+ /**
4271
+ * Draws dataset at index unless a plugin returns `false` to the `beforeDatasetDraw`
4272
+ * hook, in which case, plugins will not be called on `afterDatasetDraw`.
4273
+ * @private
4274
+ */
4275
+ drawDataset: function(index, easingValue) {
4276
+ var me = this;
4277
+ var meta = me.getDatasetMeta(index);
4278
+ var args = {
4279
+ meta: meta,
4280
+ index: index,
4281
+ easingValue: easingValue
4282
+ };
4283
+
4284
+ if (plugins.notify(me, 'beforeDatasetDraw', [args]) === false) {
4285
+ return;
4286
+ }
4287
+
4288
+ meta.controller.draw(easingValue);
4289
+
4290
+ plugins.notify(me, 'afterDatasetDraw', [args]);
4291
+ },
4292
+
4293
+ /**
4294
+ * Draws tooltip unless a plugin returns `false` to the `beforeTooltipDraw`
4295
+ * hook, in which case, plugins will not be called on `afterTooltipDraw`.
4296
+ * @private
4297
+ */
4298
+ _drawTooltip: function(easingValue) {
4299
+ var me = this;
4300
+ var tooltip = me.tooltip;
4301
+ var args = {
4302
+ tooltip: tooltip,
4303
+ easingValue: easingValue
4304
+ };
4305
+
4306
+ if (plugins.notify(me, 'beforeTooltipDraw', [args]) === false) {
4307
+ return;
4308
+ }
4309
+
4310
+ tooltip.draw();
4311
+
4312
+ plugins.notify(me, 'afterTooltipDraw', [args]);
4313
+ },
4314
+
4315
+ // Get the single element that was clicked on
4316
+ // @return : An object containing the dataset index and element index of the matching element. Also contains the rectangle that was draw
4317
+ getElementAtEvent: function(e) {
4318
+ return Interaction.modes.single(this, e);
4319
+ },
4320
+
4321
+ getElementsAtEvent: function(e) {
4322
+ return Interaction.modes.label(this, e, {intersect: true});
4323
+ },
4324
+
4325
+ getElementsAtXAxis: function(e) {
4326
+ return Interaction.modes['x-axis'](this, e, {intersect: true});
4327
+ },
4328
+
4329
+ getElementsAtEventForMode: function(e, mode, options) {
4330
+ var method = Interaction.modes[mode];
4331
+ if (typeof method === 'function') {
4332
+ return method(this, e, options);
4333
+ }
4334
+
4335
+ return [];
4336
+ },
4337
+
4338
+ getDatasetAtEvent: function(e) {
4339
+ return Interaction.modes.dataset(this, e, {intersect: true});
4340
+ },
4341
+
4342
+ getDatasetMeta: function(datasetIndex) {
4343
+ var me = this;
4344
+ var dataset = me.data.datasets[datasetIndex];
4345
+ if (!dataset._meta) {
4346
+ dataset._meta = {};
4347
+ }
4348
+
4349
+ var meta = dataset._meta[me.id];
4350
+ if (!meta) {
4351
+ meta = dataset._meta[me.id] = {
4352
+ type: null,
4353
+ data: [],
4354
+ dataset: null,
4355
+ controller: null,
4356
+ hidden: null, // See isDatasetVisible() comment
4357
+ xAxisID: null,
4358
+ yAxisID: null
4359
+ };
4360
+ }
4361
+
4362
+ return meta;
4363
+ },
4364
+
4365
+ getVisibleDatasetCount: function() {
4366
+ var count = 0;
4367
+ for (var i = 0, ilen = this.data.datasets.length; i < ilen; ++i) {
4368
+ if (this.isDatasetVisible(i)) {
4369
+ count++;
4370
+ }
4371
+ }
4372
+ return count;
4373
+ },
4374
+
4375
+ isDatasetVisible: function(datasetIndex) {
4376
+ var meta = this.getDatasetMeta(datasetIndex);
4377
+
4378
+ // meta.hidden is a per chart dataset hidden flag override with 3 states: if true or false,
4379
+ // the dataset.hidden value is ignored, else if null, the dataset hidden state is returned.
4380
+ return typeof meta.hidden === 'boolean' ? !meta.hidden : !this.data.datasets[datasetIndex].hidden;
4381
+ },
4382
+
4383
+ generateLegend: function() {
4384
+ return this.options.legendCallback(this);
4385
+ },
4386
+
4387
+ /**
4388
+ * @private
4389
+ */
4390
+ destroyDatasetMeta: function(datasetIndex) {
4391
+ var id = this.id;
4392
+ var dataset = this.data.datasets[datasetIndex];
4393
+ var meta = dataset._meta && dataset._meta[id];
4394
+
4395
+ if (meta) {
4396
+ meta.controller.destroy();
4397
+ delete dataset._meta[id];
4398
+ }
4399
+ },
4400
+
4401
+ destroy: function() {
4402
+ var me = this;
4403
+ var canvas = me.canvas;
4404
+ var i, ilen;
4405
+
4406
+ me.stop();
4407
+
4408
+ // dataset controllers need to cleanup associated data
4409
+ for (i = 0, ilen = me.data.datasets.length; i < ilen; ++i) {
4410
+ me.destroyDatasetMeta(i);
4411
+ }
4412
+
4413
+ if (canvas) {
4414
+ me.unbindEvents();
4415
+ helpers.canvas.clear(me);
4416
+ platform.releaseContext(me.ctx);
4417
+ me.canvas = null;
4418
+ me.ctx = null;
4419
+ }
4420
+
4421
+ plugins.notify(me, 'destroy');
4422
+
4423
+ delete Chart.instances[me.id];
4424
+ },
4425
+
4426
+ toBase64Image: function() {
4427
+ return this.canvas.toDataURL.apply(this.canvas, arguments);
4428
+ },
4429
+
4430
+ initToolTip: function() {
4431
+ var me = this;
4432
+ me.tooltip = new Chart.Tooltip({
4433
+ _chart: me,
4434
+ _chartInstance: me, // deprecated, backward compatibility
4435
+ _data: me.data,
4436
+ _options: me.options.tooltips
4437
+ }, me);
4438
+ },
4439
+
4440
+ /**
4441
+ * @private
4442
+ */
4443
+ bindEvents: function() {
4444
+ var me = this;
4445
+ var listeners = me._listeners = {};
4446
+ var listener = function() {
4447
+ me.eventHandler.apply(me, arguments);
4448
+ };
4449
+
4450
+ helpers.each(me.options.events, function(type) {
4451
+ platform.addEventListener(me, type, listener);
4452
+ listeners[type] = listener;
4453
+ });
4454
+
4455
+ // Elements used to detect size change should not be injected for non responsive charts.
4456
+ // See https://github.com/chartjs/Chart.js/issues/2210
4457
+ if (me.options.responsive) {
4458
+ listener = function() {
4459
+ me.resize();
4460
+ };
4461
+
4462
+ platform.addEventListener(me, 'resize', listener);
4463
+ listeners.resize = listener;
4464
+ }
4465
+ },
4466
+
4467
+ /**
4468
+ * @private
4469
+ */
4470
+ unbindEvents: function() {
4471
+ var me = this;
4472
+ var listeners = me._listeners;
4473
+ if (!listeners) {
4474
+ return;
4475
+ }
4476
+
4477
+ delete me._listeners;
4478
+ helpers.each(listeners, function(listener, type) {
4479
+ platform.removeEventListener(me, type, listener);
4480
+ });
4481
+ },
4482
+
4483
+ updateHoverStyle: function(elements, mode, enabled) {
4484
+ var method = enabled ? 'setHoverStyle' : 'removeHoverStyle';
4485
+ var element, i, ilen;
4486
+
4487
+ for (i = 0, ilen = elements.length; i < ilen; ++i) {
4488
+ element = elements[i];
4489
+ if (element) {
4490
+ this.getDatasetMeta(element._datasetIndex).controller[method](element);
4491
+ }
4492
+ }
4493
+ },
4494
+
4495
+ /**
4496
+ * @private
4497
+ */
4498
+ eventHandler: function(e) {
4499
+ var me = this;
4500
+ var tooltip = me.tooltip;
4501
+
4502
+ if (plugins.notify(me, 'beforeEvent', [e]) === false) {
4503
+ return;
4504
+ }
4505
+
4506
+ // Buffer any update calls so that renders do not occur
4507
+ me._bufferedRender = true;
4508
+ me._bufferedRequest = null;
4509
+
4510
+ var changed = me.handleEvent(e);
4511
+ changed |= tooltip && tooltip.handleEvent(e);
4512
+
4513
+ plugins.notify(me, 'afterEvent', [e]);
4514
+
4515
+ var bufferedRequest = me._bufferedRequest;
4516
+ if (bufferedRequest) {
4517
+ // If we have an update that was triggered, we need to do a normal render
4518
+ me.render(bufferedRequest);
4519
+ } else if (changed && !me.animating) {
4520
+ // If entering, leaving, or changing elements, animate the change via pivot
4521
+ me.stop();
4522
+
4523
+ // We only need to render at this point. Updating will cause scales to be
4524
+ // recomputed generating flicker & using more memory than necessary.
4525
+ me.render(me.options.hover.animationDuration, true);
4526
+ }
4527
+
4528
+ me._bufferedRender = false;
4529
+ me._bufferedRequest = null;
4530
+
4531
+ return me;
4532
+ },
4533
+
4534
+ /**
4535
+ * Handle an event
4536
+ * @private
4537
+ * @param {IEvent} event the event to handle
4538
+ * @return {Boolean} true if the chart needs to re-render
4539
+ */
4540
+ handleEvent: function(e) {
4541
+ var me = this;
4542
+ var options = me.options || {};
4543
+ var hoverOptions = options.hover;
4544
+ var changed = false;
4545
+
4546
+ me.lastActive = me.lastActive || [];
4547
+
4548
+ // Find Active Elements for hover and tooltips
4549
+ if (e.type === 'mouseout') {
4550
+ me.active = [];
4551
+ } else {
4552
+ me.active = me.getElementsAtEventForMode(e, hoverOptions.mode, hoverOptions);
4553
+ }
4554
+
4555
+ // Invoke onHover hook
4556
+ // Need to call with native event here to not break backwards compatibility
4557
+ helpers.callback(options.onHover || options.hover.onHover, [e.native, me.active], me);
4558
+
4559
+ if (e.type === 'mouseup' || e.type === 'click') {
4560
+ if (options.onClick) {
4561
+ // Use e.native here for backwards compatibility
4562
+ options.onClick.call(me, e.native, me.active);
4563
+ }
4564
+ }
4565
+
4566
+ // Remove styling for last active (even if it may still be active)
4567
+ if (me.lastActive.length) {
4568
+ me.updateHoverStyle(me.lastActive, hoverOptions.mode, false);
4569
+ }
4570
+
4571
+ // Built in hover styling
4572
+ if (me.active.length && hoverOptions.mode) {
4573
+ me.updateHoverStyle(me.active, hoverOptions.mode, true);
4574
+ }
4575
+
4576
+ changed = !helpers.arrayEquals(me.active, me.lastActive);
4577
+
4578
+ // Remember Last Actives
4579
+ me.lastActive = me.active;
4580
+
4581
+ return changed;
4582
+ }
4583
+ });
4584
+
4585
+ /**
4586
+ * Provided for backward compatibility, use Chart instead.
4587
+ * @class Chart.Controller
4588
+ * @deprecated since version 2.6.0
4589
+ * @todo remove at version 3
4590
+ * @private
4591
+ */
4592
+ Chart.Controller = Chart;
4593
+ };
4594
+
4595
+ },{"25":25,"28":28,"45":45,"48":48}],24:[function(require,module,exports){
4596
+ 'use strict';
4597
+
4598
+ var helpers = require(45);
4599
+
4600
+ module.exports = function(Chart) {
4601
+
4602
+ var arrayEvents = ['push', 'pop', 'shift', 'splice', 'unshift'];
4603
+
4604
+ /**
4605
+ * Hooks the array methods that add or remove values ('push', pop', 'shift', 'splice',
4606
+ * 'unshift') and notify the listener AFTER the array has been altered. Listeners are
4607
+ * called on the 'onData*' callbacks (e.g. onDataPush, etc.) with same arguments.
4608
+ */
4609
+ function listenArrayEvents(array, listener) {
4610
+ if (array._chartjs) {
4611
+ array._chartjs.listeners.push(listener);
4612
+ return;
4613
+ }
4614
+
4615
+ Object.defineProperty(array, '_chartjs', {
4616
+ configurable: true,
4617
+ enumerable: false,
4618
+ value: {
4619
+ listeners: [listener]
4620
+ }
4621
+ });
4622
+
4623
+ arrayEvents.forEach(function(key) {
4624
+ var method = 'onData' + key.charAt(0).toUpperCase() + key.slice(1);
4625
+ var base = array[key];
4626
+
4627
+ Object.defineProperty(array, key, {
4628
+ configurable: true,
4629
+ enumerable: false,
4630
+ value: function() {
4631
+ var args = Array.prototype.slice.call(arguments);
4632
+ var res = base.apply(this, args);
4633
+
4634
+ helpers.each(array._chartjs.listeners, function(object) {
4635
+ if (typeof object[method] === 'function') {
4636
+ object[method].apply(object, args);
4637
+ }
4638
+ });
4639
+
4640
+ return res;
4641
+ }
4642
+ });
4643
+ });
4644
+ }
4645
+
4646
+ /**
4647
+ * Removes the given array event listener and cleanup extra attached properties (such as
4648
+ * the _chartjs stub and overridden methods) if array doesn't have any more listeners.
4649
+ */
4650
+ function unlistenArrayEvents(array, listener) {
4651
+ var stub = array._chartjs;
4652
+ if (!stub) {
4653
+ return;
4654
+ }
4655
+
4656
+ var listeners = stub.listeners;
4657
+ var index = listeners.indexOf(listener);
4658
+ if (index !== -1) {
4659
+ listeners.splice(index, 1);
4660
+ }
4661
+
4662
+ if (listeners.length > 0) {
4663
+ return;
4664
+ }
4665
+
4666
+ arrayEvents.forEach(function(key) {
4667
+ delete array[key];
4668
+ });
4669
+
4670
+ delete array._chartjs;
4671
+ }
4672
+
4673
+ // Base class for all dataset controllers (line, bar, etc)
4674
+ Chart.DatasetController = function(chart, datasetIndex) {
4675
+ this.initialize(chart, datasetIndex);
4676
+ };
4677
+
4678
+ helpers.extend(Chart.DatasetController.prototype, {
4679
+
4680
+ /**
4681
+ * Element type used to generate a meta dataset (e.g. Chart.element.Line).
4682
+ * @type {Chart.core.element}
4683
+ */
4684
+ datasetElementType: null,
4685
+
4686
+ /**
4687
+ * Element type used to generate a meta data (e.g. Chart.element.Point).
4688
+ * @type {Chart.core.element}
4689
+ */
4690
+ dataElementType: null,
4691
+
4692
+ initialize: function(chart, datasetIndex) {
4693
+ var me = this;
4694
+ me.chart = chart;
4695
+ me.index = datasetIndex;
4696
+ me.linkScales();
4697
+ me.addElements();
4698
+ },
4699
+
4700
+ updateIndex: function(datasetIndex) {
4701
+ this.index = datasetIndex;
4702
+ },
4703
+
4704
+ linkScales: function() {
4705
+ var me = this;
4706
+ var meta = me.getMeta();
4707
+ var dataset = me.getDataset();
4708
+
4709
+ if (meta.xAxisID === null) {
4710
+ meta.xAxisID = dataset.xAxisID || me.chart.options.scales.xAxes[0].id;
4711
+ }
4712
+ if (meta.yAxisID === null) {
4713
+ meta.yAxisID = dataset.yAxisID || me.chart.options.scales.yAxes[0].id;
4714
+ }
4715
+ },
4716
+
4717
+ getDataset: function() {
4718
+ return this.chart.data.datasets[this.index];
4719
+ },
4720
+
4721
+ getMeta: function() {
4722
+ return this.chart.getDatasetMeta(this.index);
4723
+ },
4724
+
4725
+ getScaleForId: function(scaleID) {
4726
+ return this.chart.scales[scaleID];
4727
+ },
4728
+
4729
+ reset: function() {
4730
+ this.update(true);
4731
+ },
4732
+
4733
+ /**
4734
+ * @private
4735
+ */
4736
+ destroy: function() {
4737
+ if (this._data) {
4738
+ unlistenArrayEvents(this._data, this);
4739
+ }
4740
+ },
4741
+
4742
+ createMetaDataset: function() {
4743
+ var me = this;
4744
+ var type = me.datasetElementType;
4745
+ return type && new type({
4746
+ _chart: me.chart,
4747
+ _datasetIndex: me.index
4748
+ });
4749
+ },
4750
+
4751
+ createMetaData: function(index) {
4752
+ var me = this;
4753
+ var type = me.dataElementType;
4754
+ return type && new type({
4755
+ _chart: me.chart,
4756
+ _datasetIndex: me.index,
4757
+ _index: index
4758
+ });
4759
+ },
4760
+
4761
+ addElements: function() {
4762
+ var me = this;
4763
+ var meta = me.getMeta();
4764
+ var data = me.getDataset().data || [];
4765
+ var metaData = meta.data;
4766
+ var i, ilen;
4767
+
4768
+ for (i = 0, ilen = data.length; i < ilen; ++i) {
4769
+ metaData[i] = metaData[i] || me.createMetaData(i);
4770
+ }
4771
+
4772
+ meta.dataset = meta.dataset || me.createMetaDataset();
4773
+ },
4774
+
4775
+ addElementAndReset: function(index) {
4776
+ var element = this.createMetaData(index);
4777
+ this.getMeta().data.splice(index, 0, element);
4778
+ this.updateElement(element, index, true);
4779
+ },
4780
+
4781
+ buildOrUpdateElements: function() {
4782
+ var me = this;
4783
+ var dataset = me.getDataset();
4784
+ var data = dataset.data || (dataset.data = []);
4785
+
4786
+ // In order to correctly handle data addition/deletion animation (an thus simulate
4787
+ // real-time charts), we need to monitor these data modifications and synchronize
4788
+ // the internal meta data accordingly.
4789
+ if (me._data !== data) {
4790
+ if (me._data) {
4791
+ // This case happens when the user replaced the data array instance.
4792
+ unlistenArrayEvents(me._data, me);
4793
+ }
4794
+
4795
+ listenArrayEvents(data, me);
4796
+ me._data = data;
4797
+ }
4798
+
4799
+ // Re-sync meta data in case the user replaced the data array or if we missed
4800
+ // any updates and so make sure that we handle number of datapoints changing.
4801
+ me.resyncElements();
4802
+ },
4803
+
4804
+ update: helpers.noop,
4805
+
4806
+ transition: function(easingValue) {
4807
+ var meta = this.getMeta();
4808
+ var elements = meta.data || [];
4809
+ var ilen = elements.length;
4810
+ var i = 0;
4811
+
4812
+ for (; i < ilen; ++i) {
4813
+ elements[i].transition(easingValue);
4814
+ }
4815
+
4816
+ if (meta.dataset) {
4817
+ meta.dataset.transition(easingValue);
4818
+ }
4819
+ },
4820
+
4821
+ draw: function() {
4822
+ var meta = this.getMeta();
4823
+ var elements = meta.data || [];
4824
+ var ilen = elements.length;
4825
+ var i = 0;
4826
+
4827
+ if (meta.dataset) {
4828
+ meta.dataset.draw();
4829
+ }
4830
+
4831
+ for (; i < ilen; ++i) {
4832
+ elements[i].draw();
4833
+ }
4834
+ },
4835
+
4836
+ removeHoverStyle: function(element, elementOpts) {
4837
+ var dataset = this.chart.data.datasets[element._datasetIndex];
4838
+ var index = element._index;
4839
+ var custom = element.custom || {};
4840
+ var valueOrDefault = helpers.valueAtIndexOrDefault;
4841
+ var model = element._model;
4842
+
4843
+ model.backgroundColor = custom.backgroundColor ? custom.backgroundColor : valueOrDefault(dataset.backgroundColor, index, elementOpts.backgroundColor);
4844
+ model.borderColor = custom.borderColor ? custom.borderColor : valueOrDefault(dataset.borderColor, index, elementOpts.borderColor);
4845
+ model.borderWidth = custom.borderWidth ? custom.borderWidth : valueOrDefault(dataset.borderWidth, index, elementOpts.borderWidth);
4846
+ },
4847
+
4848
+ setHoverStyle: function(element) {
4849
+ var dataset = this.chart.data.datasets[element._datasetIndex];
4850
+ var index = element._index;
4851
+ var custom = element.custom || {};
4852
+ var valueOrDefault = helpers.valueAtIndexOrDefault;
4853
+ var getHoverColor = helpers.getHoverColor;
4854
+ var model = element._model;
4855
+
4856
+ model.backgroundColor = custom.hoverBackgroundColor ? custom.hoverBackgroundColor : valueOrDefault(dataset.hoverBackgroundColor, index, getHoverColor(model.backgroundColor));
4857
+ model.borderColor = custom.hoverBorderColor ? custom.hoverBorderColor : valueOrDefault(dataset.hoverBorderColor, index, getHoverColor(model.borderColor));
4858
+ model.borderWidth = custom.hoverBorderWidth ? custom.hoverBorderWidth : valueOrDefault(dataset.hoverBorderWidth, index, model.borderWidth);
4859
+ },
4860
+
4861
+ /**
4862
+ * @private
4863
+ */
4864
+ resyncElements: function() {
4865
+ var me = this;
4866
+ var meta = me.getMeta();
4867
+ var data = me.getDataset().data;
4868
+ var numMeta = meta.data.length;
4869
+ var numData = data.length;
4870
+
4871
+ if (numData < numMeta) {
4872
+ meta.data.splice(numData, numMeta - numData);
4873
+ } else if (numData > numMeta) {
4874
+ me.insertElements(numMeta, numData - numMeta);
4875
+ }
4876
+ },
4877
+
4878
+ /**
4879
+ * @private
4880
+ */
4881
+ insertElements: function(start, count) {
4882
+ for (var i = 0; i < count; ++i) {
4883
+ this.addElementAndReset(start + i);
4884
+ }
4885
+ },
4886
+
4887
+ /**
4888
+ * @private
4889
+ */
4890
+ onDataPush: function() {
4891
+ this.insertElements(this.getDataset().data.length - 1, arguments.length);
4892
+ },
4893
+
4894
+ /**
4895
+ * @private
4896
+ */
4897
+ onDataPop: function() {
4898
+ this.getMeta().data.pop();
4899
+ },
4900
+
4901
+ /**
4902
+ * @private
4903
+ */
4904
+ onDataShift: function() {
4905
+ this.getMeta().data.shift();
4906
+ },
4907
+
4908
+ /**
4909
+ * @private
4910
+ */
4911
+ onDataSplice: function(start, count) {
4912
+ this.getMeta().data.splice(start, count);
4913
+ this.insertElements(start, arguments.length - 2);
4914
+ },
4915
+
4916
+ /**
4917
+ * @private
4918
+ */
4919
+ onDataUnshift: function() {
4920
+ this.insertElements(0, arguments.length);
4921
+ }
4922
+ });
4923
+
4924
+ Chart.DatasetController.extend = helpers.inherits;
4925
+ };
4926
+
4927
+ },{"45":45}],25:[function(require,module,exports){
4928
+ 'use strict';
4929
+
4930
+ var helpers = require(45);
4931
+
4932
+ module.exports = {
4933
+ /**
4934
+ * @private
4935
+ */
4936
+ _set: function(scope, values) {
4937
+ return helpers.merge(this[scope] || (this[scope] = {}), values);
4938
+ }
4939
+ };
4940
+
4941
+ },{"45":45}],26:[function(require,module,exports){
4942
+ 'use strict';
4943
+
4944
+ var color = require(3);
4945
+ var helpers = require(45);
4946
+
4947
+ function interpolate(start, view, model, ease) {
4948
+ var keys = Object.keys(model);
4949
+ var i, ilen, key, actual, origin, target, type, c0, c1;
4950
+
4951
+ for (i = 0, ilen = keys.length; i < ilen; ++i) {
4952
+ key = keys[i];
4953
+
4954
+ target = model[key];
4955
+
4956
+ // if a value is added to the model after pivot() has been called, the view
4957
+ // doesn't contain it, so let's initialize the view to the target value.
4958
+ if (!view.hasOwnProperty(key)) {
4959
+ view[key] = target;
4960
+ }
4961
+
4962
+ actual = view[key];
4963
+
4964
+ if (actual === target || key[0] === '_') {
4965
+ continue;
4966
+ }
4967
+
4968
+ if (!start.hasOwnProperty(key)) {
4969
+ start[key] = actual;
4970
+ }
4971
+
4972
+ origin = start[key];
4973
+
4974
+ type = typeof target;
4975
+
4976
+ if (type === typeof origin) {
4977
+ if (type === 'string') {
4978
+ c0 = color(origin);
4979
+ if (c0.valid) {
4980
+ c1 = color(target);
4981
+ if (c1.valid) {
4982
+ view[key] = c1.mix(c0, ease).rgbString();
4983
+ continue;
4984
+ }
4985
+ }
4986
+ } else if (type === 'number' && isFinite(origin) && isFinite(target)) {
4987
+ view[key] = origin + (target - origin) * ease;
4988
+ continue;
4989
+ }
4990
+ }
4991
+
4992
+ view[key] = target;
4993
+ }
4994
+ }
4995
+
4996
+ var Element = function(configuration) {
4997
+ helpers.extend(this, configuration);
4998
+ this.initialize.apply(this, arguments);
4999
+ };
5000
+
5001
+ helpers.extend(Element.prototype, {
5002
+
5003
+ initialize: function() {
5004
+ this.hidden = false;
5005
+ },
5006
+
5007
+ pivot: function() {
5008
+ var me = this;
5009
+ if (!me._view) {
5010
+ me._view = helpers.clone(me._model);
5011
+ }
5012
+ me._start = {};
5013
+ return me;
5014
+ },
5015
+
5016
+ transition: function(ease) {
5017
+ var me = this;
5018
+ var model = me._model;
5019
+ var start = me._start;
5020
+ var view = me._view;
5021
+
5022
+ // No animation -> No Transition
5023
+ if (!model || ease === 1) {
5024
+ me._view = model;
5025
+ me._start = null;
5026
+ return me;
5027
+ }
5028
+
5029
+ if (!view) {
5030
+ view = me._view = {};
5031
+ }
5032
+
5033
+ if (!start) {
5034
+ start = me._start = {};
5035
+ }
5036
+
5037
+ interpolate(start, view, model, ease);
5038
+
5039
+ return me;
5040
+ },
5041
+
5042
+ tooltipPosition: function() {
5043
+ return {
5044
+ x: this._model.x,
5045
+ y: this._model.y
5046
+ };
5047
+ },
5048
+
5049
+ hasValue: function() {
5050
+ return helpers.isNumber(this._model.x) && helpers.isNumber(this._model.y);
5051
+ }
5052
+ });
5053
+
5054
+ Element.extend = helpers.inherits;
5055
+
5056
+ module.exports = Element;
5057
+
5058
+ },{"3":3,"45":45}],27:[function(require,module,exports){
5059
+ /* global window: false */
5060
+ /* global document: false */
5061
+ 'use strict';
5062
+
5063
+ var color = require(3);
5064
+ var defaults = require(25);
5065
+ var helpers = require(45);
5066
+
5067
+ module.exports = function(Chart) {
5068
+
5069
+ // -- Basic js utility methods
5070
+
5071
+ helpers.configMerge = function(/* objects ... */) {
5072
+ return helpers.merge(helpers.clone(arguments[0]), [].slice.call(arguments, 1), {
5073
+ merger: function(key, target, source, options) {
5074
+ var tval = target[key] || {};
5075
+ var sval = source[key];
5076
+
5077
+ if (key === 'scales') {
5078
+ // scale config merging is complex. Add our own function here for that
5079
+ target[key] = helpers.scaleMerge(tval, sval);
5080
+ } else if (key === 'scale') {
5081
+ // used in polar area & radar charts since there is only one scale
5082
+ target[key] = helpers.merge(tval, [Chart.scaleService.getScaleDefaults(sval.type), sval]);
5083
+ } else {
5084
+ helpers._merger(key, target, source, options);
5085
+ }
5086
+ }
5087
+ });
5088
+ };
5089
+
5090
+ helpers.scaleMerge = function(/* objects ... */) {
5091
+ return helpers.merge(helpers.clone(arguments[0]), [].slice.call(arguments, 1), {
5092
+ merger: function(key, target, source, options) {
5093
+ if (key === 'xAxes' || key === 'yAxes') {
5094
+ var slen = source[key].length;
5095
+ var i, type, scale;
5096
+
5097
+ if (!target[key]) {
5098
+ target[key] = [];
5099
+ }
5100
+
5101
+ for (i = 0; i < slen; ++i) {
5102
+ scale = source[key][i];
5103
+ type = helpers.valueOrDefault(scale.type, key === 'xAxes' ? 'category' : 'linear');
5104
+
5105
+ if (i >= target[key].length) {
5106
+ target[key].push({});
5107
+ }
5108
+
5109
+ if (!target[key][i].type || (scale.type && scale.type !== target[key][i].type)) {
5110
+ // new/untyped scale or type changed: let's apply the new defaults
5111
+ // then merge source scale to correctly overwrite the defaults.
5112
+ helpers.merge(target[key][i], [Chart.scaleService.getScaleDefaults(type), scale]);
5113
+ } else {
5114
+ // scales type are the same
5115
+ helpers.merge(target[key][i], scale);
5116
+ }
5117
+ }
5118
+ } else {
5119
+ helpers._merger(key, target, source, options);
5120
+ }
5121
+ }
5122
+ });
5123
+ };
5124
+
5125
+ helpers.where = function(collection, filterCallback) {
5126
+ if (helpers.isArray(collection) && Array.prototype.filter) {
5127
+ return collection.filter(filterCallback);
5128
+ }
5129
+ var filtered = [];
5130
+
5131
+ helpers.each(collection, function(item) {
5132
+ if (filterCallback(item)) {
5133
+ filtered.push(item);
5134
+ }
5135
+ });
5136
+
5137
+ return filtered;
5138
+ };
5139
+ helpers.findIndex = Array.prototype.findIndex ?
5140
+ function(array, callback, scope) {
5141
+ return array.findIndex(callback, scope);
5142
+ } :
5143
+ function(array, callback, scope) {
5144
+ scope = scope === undefined ? array : scope;
5145
+ for (var i = 0, ilen = array.length; i < ilen; ++i) {
5146
+ if (callback.call(scope, array[i], i, array)) {
5147
+ return i;
5148
+ }
5149
+ }
5150
+ return -1;
5151
+ };
5152
+ helpers.findNextWhere = function(arrayToSearch, filterCallback, startIndex) {
5153
+ // Default to start of the array
5154
+ if (helpers.isNullOrUndef(startIndex)) {
5155
+ startIndex = -1;
5156
+ }
5157
+ for (var i = startIndex + 1; i < arrayToSearch.length; i++) {
5158
+ var currentItem = arrayToSearch[i];
5159
+ if (filterCallback(currentItem)) {
5160
+ return currentItem;
5161
+ }
5162
+ }
5163
+ };
5164
+ helpers.findPreviousWhere = function(arrayToSearch, filterCallback, startIndex) {
5165
+ // Default to end of the array
5166
+ if (helpers.isNullOrUndef(startIndex)) {
5167
+ startIndex = arrayToSearch.length;
5168
+ }
5169
+ for (var i = startIndex - 1; i >= 0; i--) {
5170
+ var currentItem = arrayToSearch[i];
5171
+ if (filterCallback(currentItem)) {
5172
+ return currentItem;
5173
+ }
5174
+ }
5175
+ };
5176
+
5177
+ // -- Math methods
5178
+ helpers.isNumber = function(n) {
5179
+ return !isNaN(parseFloat(n)) && isFinite(n);
5180
+ };
5181
+ helpers.almostEquals = function(x, y, epsilon) {
5182
+ return Math.abs(x - y) < epsilon;
5183
+ };
5184
+ helpers.almostWhole = function(x, epsilon) {
5185
+ var rounded = Math.round(x);
5186
+ return (((rounded - epsilon) < x) && ((rounded + epsilon) > x));
5187
+ };
5188
+ helpers.max = function(array) {
5189
+ return array.reduce(function(max, value) {
5190
+ if (!isNaN(value)) {
5191
+ return Math.max(max, value);
5192
+ }
5193
+ return max;
5194
+ }, Number.NEGATIVE_INFINITY);
5195
+ };
5196
+ helpers.min = function(array) {
5197
+ return array.reduce(function(min, value) {
5198
+ if (!isNaN(value)) {
5199
+ return Math.min(min, value);
5200
+ }
5201
+ return min;
5202
+ }, Number.POSITIVE_INFINITY);
5203
+ };
5204
+ helpers.sign = Math.sign ?
5205
+ function(x) {
5206
+ return Math.sign(x);
5207
+ } :
5208
+ function(x) {
5209
+ x = +x; // convert to a number
5210
+ if (x === 0 || isNaN(x)) {
5211
+ return x;
5212
+ }
5213
+ return x > 0 ? 1 : -1;
5214
+ };
5215
+ helpers.log10 = Math.log10 ?
5216
+ function(x) {
5217
+ return Math.log10(x);
5218
+ } :
5219
+ function(x) {
5220
+ return Math.log(x) / Math.LN10;
5221
+ };
5222
+ helpers.toRadians = function(degrees) {
5223
+ return degrees * (Math.PI / 180);
5224
+ };
5225
+ helpers.toDegrees = function(radians) {
5226
+ return radians * (180 / Math.PI);
5227
+ };
5228
+ // Gets the angle from vertical upright to the point about a centre.
5229
+ helpers.getAngleFromPoint = function(centrePoint, anglePoint) {
5230
+ var distanceFromXCenter = anglePoint.x - centrePoint.x;
5231
+ var distanceFromYCenter = anglePoint.y - centrePoint.y;
5232
+ var radialDistanceFromCenter = Math.sqrt(distanceFromXCenter * distanceFromXCenter + distanceFromYCenter * distanceFromYCenter);
5233
+
5234
+ var angle = Math.atan2(distanceFromYCenter, distanceFromXCenter);
5235
+
5236
+ if (angle < (-0.5 * Math.PI)) {
5237
+ angle += 2.0 * Math.PI; // make sure the returned angle is in the range of (-PI/2, 3PI/2]
5238
+ }
5239
+
5240
+ return {
5241
+ angle: angle,
5242
+ distance: radialDistanceFromCenter
5243
+ };
5244
+ };
5245
+ helpers.distanceBetweenPoints = function(pt1, pt2) {
5246
+ return Math.sqrt(Math.pow(pt2.x - pt1.x, 2) + Math.pow(pt2.y - pt1.y, 2));
5247
+ };
5248
+ helpers.aliasPixel = function(pixelWidth) {
5249
+ return (pixelWidth % 2 === 0) ? 0 : 0.5;
5250
+ };
5251
+ helpers.splineCurve = function(firstPoint, middlePoint, afterPoint, t) {
5252
+ // Props to Rob Spencer at scaled innovation for his post on splining between points
5253
+ // http://scaledinnovation.com/analytics/splines/aboutSplines.html
5254
+
5255
+ // This function must also respect "skipped" points
5256
+
5257
+ var previous = firstPoint.skip ? middlePoint : firstPoint;
5258
+ var current = middlePoint;
5259
+ var next = afterPoint.skip ? middlePoint : afterPoint;
5260
+
5261
+ var d01 = Math.sqrt(Math.pow(current.x - previous.x, 2) + Math.pow(current.y - previous.y, 2));
5262
+ var d12 = Math.sqrt(Math.pow(next.x - current.x, 2) + Math.pow(next.y - current.y, 2));
5263
+
5264
+ var s01 = d01 / (d01 + d12);
5265
+ var s12 = d12 / (d01 + d12);
5266
+
5267
+ // If all points are the same, s01 & s02 will be inf
5268
+ s01 = isNaN(s01) ? 0 : s01;
5269
+ s12 = isNaN(s12) ? 0 : s12;
5270
+
5271
+ var fa = t * s01; // scaling factor for triangle Ta
5272
+ var fb = t * s12;
5273
+
5274
+ return {
5275
+ previous: {
5276
+ x: current.x - fa * (next.x - previous.x),
5277
+ y: current.y - fa * (next.y - previous.y)
5278
+ },
5279
+ next: {
5280
+ x: current.x + fb * (next.x - previous.x),
5281
+ y: current.y + fb * (next.y - previous.y)
5282
+ }
5283
+ };
5284
+ };
5285
+ helpers.EPSILON = Number.EPSILON || 1e-14;
5286
+ helpers.splineCurveMonotone = function(points) {
5287
+ // This function calculates Bézier control points in a similar way than |splineCurve|,
5288
+ // but preserves monotonicity of the provided data and ensures no local extremums are added
5289
+ // between the dataset discrete points due to the interpolation.
5290
+ // See : https://en.wikipedia.org/wiki/Monotone_cubic_interpolation
5291
+
5292
+ var pointsWithTangents = (points || []).map(function(point) {
5293
+ return {
5294
+ model: point._model,
5295
+ deltaK: 0,
5296
+ mK: 0
5297
+ };
5298
+ });
5299
+
5300
+ // Calculate slopes (deltaK) and initialize tangents (mK)
5301
+ var pointsLen = pointsWithTangents.length;
5302
+ var i, pointBefore, pointCurrent, pointAfter;
5303
+ for (i = 0; i < pointsLen; ++i) {
5304
+ pointCurrent = pointsWithTangents[i];
5305
+ if (pointCurrent.model.skip) {
5306
+ continue;
5307
+ }
5308
+
5309
+ pointBefore = i > 0 ? pointsWithTangents[i - 1] : null;
5310
+ pointAfter = i < pointsLen - 1 ? pointsWithTangents[i + 1] : null;
5311
+ if (pointAfter && !pointAfter.model.skip) {
5312
+ var slopeDeltaX = (pointAfter.model.x - pointCurrent.model.x);
5313
+
5314
+ // In the case of two points that appear at the same x pixel, slopeDeltaX is 0
5315
+ pointCurrent.deltaK = slopeDeltaX !== 0 ? (pointAfter.model.y - pointCurrent.model.y) / slopeDeltaX : 0;
5316
+ }
5317
+
5318
+ if (!pointBefore || pointBefore.model.skip) {
5319
+ pointCurrent.mK = pointCurrent.deltaK;
5320
+ } else if (!pointAfter || pointAfter.model.skip) {
5321
+ pointCurrent.mK = pointBefore.deltaK;
5322
+ } else if (this.sign(pointBefore.deltaK) !== this.sign(pointCurrent.deltaK)) {
5323
+ pointCurrent.mK = 0;
5324
+ } else {
5325
+ pointCurrent.mK = (pointBefore.deltaK + pointCurrent.deltaK) / 2;
5326
+ }
5327
+ }
5328
+
5329
+ // Adjust tangents to ensure monotonic properties
5330
+ var alphaK, betaK, tauK, squaredMagnitude;
5331
+ for (i = 0; i < pointsLen - 1; ++i) {
5332
+ pointCurrent = pointsWithTangents[i];
5333
+ pointAfter = pointsWithTangents[i + 1];
5334
+ if (pointCurrent.model.skip || pointAfter.model.skip) {
5335
+ continue;
5336
+ }
5337
+
5338
+ if (helpers.almostEquals(pointCurrent.deltaK, 0, this.EPSILON)) {
5339
+ pointCurrent.mK = pointAfter.mK = 0;
5340
+ continue;
5341
+ }
5342
+
5343
+ alphaK = pointCurrent.mK / pointCurrent.deltaK;
5344
+ betaK = pointAfter.mK / pointCurrent.deltaK;
5345
+ squaredMagnitude = Math.pow(alphaK, 2) + Math.pow(betaK, 2);
5346
+ if (squaredMagnitude <= 9) {
5347
+ continue;
5348
+ }
5349
+
5350
+ tauK = 3 / Math.sqrt(squaredMagnitude);
5351
+ pointCurrent.mK = alphaK * tauK * pointCurrent.deltaK;
5352
+ pointAfter.mK = betaK * tauK * pointCurrent.deltaK;
5353
+ }
5354
+
5355
+ // Compute control points
5356
+ var deltaX;
5357
+ for (i = 0; i < pointsLen; ++i) {
5358
+ pointCurrent = pointsWithTangents[i];
5359
+ if (pointCurrent.model.skip) {
5360
+ continue;
5361
+ }
5362
+
5363
+ pointBefore = i > 0 ? pointsWithTangents[i - 1] : null;
5364
+ pointAfter = i < pointsLen - 1 ? pointsWithTangents[i + 1] : null;
5365
+ if (pointBefore && !pointBefore.model.skip) {
5366
+ deltaX = (pointCurrent.model.x - pointBefore.model.x) / 3;
5367
+ pointCurrent.model.controlPointPreviousX = pointCurrent.model.x - deltaX;
5368
+ pointCurrent.model.controlPointPreviousY = pointCurrent.model.y - deltaX * pointCurrent.mK;
5369
+ }
5370
+ if (pointAfter && !pointAfter.model.skip) {
5371
+ deltaX = (pointAfter.model.x - pointCurrent.model.x) / 3;
5372
+ pointCurrent.model.controlPointNextX = pointCurrent.model.x + deltaX;
5373
+ pointCurrent.model.controlPointNextY = pointCurrent.model.y + deltaX * pointCurrent.mK;
5374
+ }
5375
+ }
5376
+ };
5377
+ helpers.nextItem = function(collection, index, loop) {
5378
+ if (loop) {
5379
+ return index >= collection.length - 1 ? collection[0] : collection[index + 1];
5380
+ }
5381
+ return index >= collection.length - 1 ? collection[collection.length - 1] : collection[index + 1];
5382
+ };
5383
+ helpers.previousItem = function(collection, index, loop) {
5384
+ if (loop) {
5385
+ return index <= 0 ? collection[collection.length - 1] : collection[index - 1];
5386
+ }
5387
+ return index <= 0 ? collection[0] : collection[index - 1];
5388
+ };
5389
+ // Implementation of the nice number algorithm used in determining where axis labels will go
5390
+ helpers.niceNum = function(range, round) {
5391
+ var exponent = Math.floor(helpers.log10(range));
5392
+ var fraction = range / Math.pow(10, exponent);
5393
+ var niceFraction;
5394
+
5395
+ if (round) {
5396
+ if (fraction < 1.5) {
5397
+ niceFraction = 1;
5398
+ } else if (fraction < 3) {
5399
+ niceFraction = 2;
5400
+ } else if (fraction < 7) {
5401
+ niceFraction = 5;
5402
+ } else {
5403
+ niceFraction = 10;
5404
+ }
5405
+ } else if (fraction <= 1.0) {
5406
+ niceFraction = 1;
5407
+ } else if (fraction <= 2) {
5408
+ niceFraction = 2;
5409
+ } else if (fraction <= 5) {
5410
+ niceFraction = 5;
5411
+ } else {
5412
+ niceFraction = 10;
5413
+ }
5414
+
5415
+ return niceFraction * Math.pow(10, exponent);
5416
+ };
5417
+ // Request animation polyfill - http://www.paulirish.com/2011/requestanimationframe-for-smart-animating/
5418
+ helpers.requestAnimFrame = (function() {
5419
+ if (typeof window === 'undefined') {
5420
+ return function(callback) {
5421
+ callback();
5422
+ };
5423
+ }
5424
+ return window.requestAnimationFrame ||
5425
+ window.webkitRequestAnimationFrame ||
5426
+ window.mozRequestAnimationFrame ||
5427
+ window.oRequestAnimationFrame ||
5428
+ window.msRequestAnimationFrame ||
5429
+ function(callback) {
5430
+ return window.setTimeout(callback, 1000 / 60);
5431
+ };
5432
+ }());
5433
+ // -- DOM methods
5434
+ helpers.getRelativePosition = function(evt, chart) {
5435
+ var mouseX, mouseY;
5436
+ var e = evt.originalEvent || evt;
5437
+ var canvas = evt.currentTarget || evt.srcElement;
5438
+ var boundingRect = canvas.getBoundingClientRect();
5439
+
5440
+ var touches = e.touches;
5441
+ if (touches && touches.length > 0) {
5442
+ mouseX = touches[0].clientX;
5443
+ mouseY = touches[0].clientY;
5444
+
5445
+ } else {
5446
+ mouseX = e.clientX;
5447
+ mouseY = e.clientY;
5448
+ }
5449
+
5450
+ // Scale mouse coordinates into canvas coordinates
5451
+ // by following the pattern laid out by 'jerryj' in the comments of
5452
+ // http://www.html5canvastutorials.com/advanced/html5-canvas-mouse-coordinates/
5453
+ var paddingLeft = parseFloat(helpers.getStyle(canvas, 'padding-left'));
5454
+ var paddingTop = parseFloat(helpers.getStyle(canvas, 'padding-top'));
5455
+ var paddingRight = parseFloat(helpers.getStyle(canvas, 'padding-right'));
5456
+ var paddingBottom = parseFloat(helpers.getStyle(canvas, 'padding-bottom'));
5457
+ var width = boundingRect.right - boundingRect.left - paddingLeft - paddingRight;
5458
+ var height = boundingRect.bottom - boundingRect.top - paddingTop - paddingBottom;
5459
+
5460
+ // We divide by the current device pixel ratio, because the canvas is scaled up by that amount in each direction. However
5461
+ // the backend model is in unscaled coordinates. Since we are going to deal with our model coordinates, we go back here
5462
+ mouseX = Math.round((mouseX - boundingRect.left - paddingLeft) / (width) * canvas.width / chart.currentDevicePixelRatio);
5463
+ mouseY = Math.round((mouseY - boundingRect.top - paddingTop) / (height) * canvas.height / chart.currentDevicePixelRatio);
5464
+
5465
+ return {
5466
+ x: mouseX,
5467
+ y: mouseY
5468
+ };
5469
+
5470
+ };
5471
+
5472
+ // Private helper function to convert max-width/max-height values that may be percentages into a number
5473
+ function parseMaxStyle(styleValue, node, parentProperty) {
5474
+ var valueInPixels;
5475
+ if (typeof styleValue === 'string') {
5476
+ valueInPixels = parseInt(styleValue, 10);
5477
+
5478
+ if (styleValue.indexOf('%') !== -1) {
5479
+ // percentage * size in dimension
5480
+ valueInPixels = valueInPixels / 100 * node.parentNode[parentProperty];
5481
+ }
5482
+ } else {
5483
+ valueInPixels = styleValue;
5484
+ }
5485
+
5486
+ return valueInPixels;
5487
+ }
5488
+
5489
+ /**
5490
+ * Returns if the given value contains an effective constraint.
5491
+ * @private
5492
+ */
5493
+ function isConstrainedValue(value) {
5494
+ return value !== undefined && value !== null && value !== 'none';
5495
+ }
5496
+
5497
+ // Private helper to get a constraint dimension
5498
+ // @param domNode : the node to check the constraint on
5499
+ // @param maxStyle : the style that defines the maximum for the direction we are using (maxWidth / maxHeight)
5500
+ // @param percentageProperty : property of parent to use when calculating width as a percentage
5501
+ // @see http://www.nathanaeljones.com/blog/2013/reading-max-width-cross-browser
5502
+ function getConstraintDimension(domNode, maxStyle, percentageProperty) {
5503
+ var view = document.defaultView;
5504
+ var parentNode = domNode.parentNode;
5505
+ var constrainedNode = view.getComputedStyle(domNode)[maxStyle];
5506
+ var constrainedContainer = view.getComputedStyle(parentNode)[maxStyle];
5507
+ var hasCNode = isConstrainedValue(constrainedNode);
5508
+ var hasCContainer = isConstrainedValue(constrainedContainer);
5509
+ var infinity = Number.POSITIVE_INFINITY;
5510
+
5511
+ if (hasCNode || hasCContainer) {
5512
+ return Math.min(
5513
+ hasCNode ? parseMaxStyle(constrainedNode, domNode, percentageProperty) : infinity,
5514
+ hasCContainer ? parseMaxStyle(constrainedContainer, parentNode, percentageProperty) : infinity);
5515
+ }
5516
+
5517
+ return 'none';
5518
+ }
5519
+ // returns Number or undefined if no constraint
5520
+ helpers.getConstraintWidth = function(domNode) {
5521
+ return getConstraintDimension(domNode, 'max-width', 'clientWidth');
5522
+ };
5523
+ // returns Number or undefined if no constraint
5524
+ helpers.getConstraintHeight = function(domNode) {
5525
+ return getConstraintDimension(domNode, 'max-height', 'clientHeight');
5526
+ };
5527
+ helpers.getMaximumWidth = function(domNode) {
5528
+ var container = domNode.parentNode;
5529
+ if (!container) {
5530
+ return domNode.clientWidth;
5531
+ }
5532
+
5533
+ var paddingLeft = parseInt(helpers.getStyle(container, 'padding-left'), 10);
5534
+ var paddingRight = parseInt(helpers.getStyle(container, 'padding-right'), 10);
5535
+ var w = container.clientWidth - paddingLeft - paddingRight;
5536
+ var cw = helpers.getConstraintWidth(domNode);
5537
+ return isNaN(cw) ? w : Math.min(w, cw);
5538
+ };
5539
+ helpers.getMaximumHeight = function(domNode) {
5540
+ var container = domNode.parentNode;
5541
+ if (!container) {
5542
+ return domNode.clientHeight;
5543
+ }
5544
+
5545
+ var paddingTop = parseInt(helpers.getStyle(container, 'padding-top'), 10);
5546
+ var paddingBottom = parseInt(helpers.getStyle(container, 'padding-bottom'), 10);
5547
+ var h = container.clientHeight - paddingTop - paddingBottom;
5548
+ var ch = helpers.getConstraintHeight(domNode);
5549
+ return isNaN(ch) ? h : Math.min(h, ch);
5550
+ };
5551
+ helpers.getStyle = function(el, property) {
5552
+ return el.currentStyle ?
5553
+ el.currentStyle[property] :
5554
+ document.defaultView.getComputedStyle(el, null).getPropertyValue(property);
5555
+ };
5556
+ helpers.retinaScale = function(chart, forceRatio) {
5557
+ var pixelRatio = chart.currentDevicePixelRatio = forceRatio || window.devicePixelRatio || 1;
5558
+ if (pixelRatio === 1) {
5559
+ return;
5560
+ }
5561
+
5562
+ var canvas = chart.canvas;
5563
+ var height = chart.height;
5564
+ var width = chart.width;
5565
+
5566
+ canvas.height = height * pixelRatio;
5567
+ canvas.width = width * pixelRatio;
5568
+ chart.ctx.scale(pixelRatio, pixelRatio);
5569
+
5570
+ // If no style has been set on the canvas, the render size is used as display size,
5571
+ // making the chart visually bigger, so let's enforce it to the "correct" values.
5572
+ // See https://github.com/chartjs/Chart.js/issues/3575
5573
+ canvas.style.height = height + 'px';
5574
+ canvas.style.width = width + 'px';
5575
+ };
5576
+ // -- Canvas methods
5577
+ helpers.fontString = function(pixelSize, fontStyle, fontFamily) {
5578
+ return fontStyle + ' ' + pixelSize + 'px ' + fontFamily;
5579
+ };
5580
+ helpers.longestText = function(ctx, font, arrayOfThings, cache) {
5581
+ cache = cache || {};
5582
+ var data = cache.data = cache.data || {};
5583
+ var gc = cache.garbageCollect = cache.garbageCollect || [];
5584
+
5585
+ if (cache.font !== font) {
5586
+ data = cache.data = {};
5587
+ gc = cache.garbageCollect = [];
5588
+ cache.font = font;
5589
+ }
5590
+
5591
+ ctx.font = font;
5592
+ var longest = 0;
5593
+ helpers.each(arrayOfThings, function(thing) {
5594
+ // Undefined strings and arrays should not be measured
5595
+ if (thing !== undefined && thing !== null && helpers.isArray(thing) !== true) {
5596
+ longest = helpers.measureText(ctx, data, gc, longest, thing);
5597
+ } else if (helpers.isArray(thing)) {
5598
+ // if it is an array lets measure each element
5599
+ // to do maybe simplify this function a bit so we can do this more recursively?
5600
+ helpers.each(thing, function(nestedThing) {
5601
+ // Undefined strings and arrays should not be measured
5602
+ if (nestedThing !== undefined && nestedThing !== null && !helpers.isArray(nestedThing)) {
5603
+ longest = helpers.measureText(ctx, data, gc, longest, nestedThing);
5604
+ }
5605
+ });
5606
+ }
5607
+ });
5608
+
5609
+ var gcLen = gc.length / 2;
5610
+ if (gcLen > arrayOfThings.length) {
5611
+ for (var i = 0; i < gcLen; i++) {
5612
+ delete data[gc[i]];
5613
+ }
5614
+ gc.splice(0, gcLen);
5615
+ }
5616
+ return longest;
5617
+ };
5618
+ helpers.measureText = function(ctx, data, gc, longest, string) {
5619
+ var textWidth = data[string];
5620
+ if (!textWidth) {
5621
+ textWidth = data[string] = ctx.measureText(string).width;
5622
+ gc.push(string);
5623
+ }
5624
+ if (textWidth > longest) {
5625
+ longest = textWidth;
5626
+ }
5627
+ return longest;
5628
+ };
5629
+ helpers.numberOfLabelLines = function(arrayOfThings) {
5630
+ var numberOfLines = 1;
5631
+ helpers.each(arrayOfThings, function(thing) {
5632
+ if (helpers.isArray(thing)) {
5633
+ if (thing.length > numberOfLines) {
5634
+ numberOfLines = thing.length;
5635
+ }
5636
+ }
5637
+ });
5638
+ return numberOfLines;
5639
+ };
5640
+
5641
+ helpers.color = !color ?
5642
+ function(value) {
5643
+ console.error('Color.js not found!');
5644
+ return value;
5645
+ } :
5646
+ function(value) {
5647
+ /* global CanvasGradient */
5648
+ if (value instanceof CanvasGradient) {
5649
+ value = defaults.global.defaultColor;
5650
+ }
5651
+
5652
+ return color(value);
5653
+ };
5654
+
5655
+ helpers.getHoverColor = function(colorValue) {
5656
+ /* global CanvasPattern */
5657
+ return (colorValue instanceof CanvasPattern) ?
5658
+ colorValue :
5659
+ helpers.color(colorValue).saturate(0.5).darken(0.1).rgbString();
5660
+ };
5661
+ };
5662
+
5663
+ },{"25":25,"3":3,"45":45}],28:[function(require,module,exports){
5664
+ 'use strict';
5665
+
5666
+ var helpers = require(45);
5667
+
5668
+ /**
5669
+ * Helper function to get relative position for an event
5670
+ * @param {Event|IEvent} event - The event to get the position for
5671
+ * @param {Chart} chart - The chart
5672
+ * @returns {Point} the event position
5673
+ */
5674
+ function getRelativePosition(e, chart) {
5675
+ if (e.native) {
5676
+ return {
5677
+ x: e.x,
5678
+ y: e.y
5679
+ };
5680
+ }
5681
+
5682
+ return helpers.getRelativePosition(e, chart);
5683
+ }
5684
+
5685
+ /**
5686
+ * Helper function to traverse all of the visible elements in the chart
5687
+ * @param chart {chart} the chart
5688
+ * @param handler {Function} the callback to execute for each visible item
5689
+ */
5690
+ function parseVisibleItems(chart, handler) {
5691
+ var datasets = chart.data.datasets;
5692
+ var meta, i, j, ilen, jlen;
5693
+
5694
+ for (i = 0, ilen = datasets.length; i < ilen; ++i) {
5695
+ if (!chart.isDatasetVisible(i)) {
5696
+ continue;
5697
+ }
5698
+
5699
+ meta = chart.getDatasetMeta(i);
5700
+ for (j = 0, jlen = meta.data.length; j < jlen; ++j) {
5701
+ var element = meta.data[j];
5702
+ if (!element._view.skip) {
5703
+ handler(element);
5704
+ }
5705
+ }
5706
+ }
5707
+ }
5708
+
5709
+ /**
5710
+ * Helper function to get the items that intersect the event position
5711
+ * @param items {ChartElement[]} elements to filter
5712
+ * @param position {Point} the point to be nearest to
5713
+ * @return {ChartElement[]} the nearest items
5714
+ */
5715
+ function getIntersectItems(chart, position) {
5716
+ var elements = [];
5717
+
5718
+ parseVisibleItems(chart, function(element) {
5719
+ if (element.inRange(position.x, position.y)) {
5720
+ elements.push(element);
5721
+ }
5722
+ });
5723
+
5724
+ return elements;
5725
+ }
5726
+
5727
+ /**
5728
+ * Helper function to get the items nearest to the event position considering all visible items in teh chart
5729
+ * @param chart {Chart} the chart to look at elements from
5730
+ * @param position {Point} the point to be nearest to
5731
+ * @param intersect {Boolean} if true, only consider items that intersect the position
5732
+ * @param distanceMetric {Function} function to provide the distance between points
5733
+ * @return {ChartElement[]} the nearest items
5734
+ */
5735
+ function getNearestItems(chart, position, intersect, distanceMetric) {
5736
+ var minDistance = Number.POSITIVE_INFINITY;
5737
+ var nearestItems = [];
5738
+
5739
+ parseVisibleItems(chart, function(element) {
5740
+ if (intersect && !element.inRange(position.x, position.y)) {
5741
+ return;
5742
+ }
5743
+
5744
+ var center = element.getCenterPoint();
5745
+ var distance = distanceMetric(position, center);
5746
+
5747
+ if (distance < minDistance) {
5748
+ nearestItems = [element];
5749
+ minDistance = distance;
5750
+ } else if (distance === minDistance) {
5751
+ // Can have multiple items at the same distance in which case we sort by size
5752
+ nearestItems.push(element);
5753
+ }
5754
+ });
5755
+
5756
+ return nearestItems;
5757
+ }
5758
+
5759
+ /**
5760
+ * Get a distance metric function for two points based on the
5761
+ * axis mode setting
5762
+ * @param {String} axis the axis mode. x|y|xy
5763
+ */
5764
+ function getDistanceMetricForAxis(axis) {
5765
+ var useX = axis.indexOf('x') !== -1;
5766
+ var useY = axis.indexOf('y') !== -1;
5767
+
5768
+ return function(pt1, pt2) {
5769
+ var deltaX = useX ? Math.abs(pt1.x - pt2.x) : 0;
5770
+ var deltaY = useY ? Math.abs(pt1.y - pt2.y) : 0;
5771
+ return Math.sqrt(Math.pow(deltaX, 2) + Math.pow(deltaY, 2));
5772
+ };
5773
+ }
5774
+
5775
+ function indexMode(chart, e, options) {
5776
+ var position = getRelativePosition(e, chart);
5777
+ // Default axis for index mode is 'x' to match old behaviour
5778
+ options.axis = options.axis || 'x';
5779
+ var distanceMetric = getDistanceMetricForAxis(options.axis);
5780
+ var items = options.intersect ? getIntersectItems(chart, position) : getNearestItems(chart, position, false, distanceMetric);
5781
+ var elements = [];
5782
+
5783
+ if (!items.length) {
5784
+ return [];
5785
+ }
5786
+
5787
+ chart.data.datasets.forEach(function(dataset, datasetIndex) {
5788
+ if (chart.isDatasetVisible(datasetIndex)) {
5789
+ var meta = chart.getDatasetMeta(datasetIndex);
5790
+ var element = meta.data[items[0]._index];
5791
+
5792
+ // don't count items that are skipped (null data)
5793
+ if (element && !element._view.skip) {
5794
+ elements.push(element);
5795
+ }
5796
+ }
5797
+ });
5798
+
5799
+ return elements;
5800
+ }
5801
+
5802
+ /**
5803
+ * @interface IInteractionOptions
5804
+ */
5805
+ /**
5806
+ * If true, only consider items that intersect the point
5807
+ * @name IInterfaceOptions#boolean
5808
+ * @type Boolean
5809
+ */
5810
+
5811
+ /**
5812
+ * Contains interaction related functions
5813
+ * @namespace Chart.Interaction
5814
+ */
5815
+ module.exports = {
5816
+ // Helper function for different modes
5817
+ modes: {
5818
+ single: function(chart, e) {
5819
+ var position = getRelativePosition(e, chart);
5820
+ var elements = [];
5821
+
5822
+ parseVisibleItems(chart, function(element) {
5823
+ if (element.inRange(position.x, position.y)) {
5824
+ elements.push(element);
5825
+ return elements;
5826
+ }
5827
+ });
5828
+
5829
+ return elements.slice(0, 1);
5830
+ },
5831
+
5832
+ /**
5833
+ * @function Chart.Interaction.modes.label
5834
+ * @deprecated since version 2.4.0
5835
+ * @todo remove at version 3
5836
+ * @private
5837
+ */
5838
+ label: indexMode,
5839
+
5840
+ /**
5841
+ * Returns items at the same index. If the options.intersect parameter is true, we only return items if we intersect something
5842
+ * If the options.intersect mode is false, we find the nearest item and return the items at the same index as that item
5843
+ * @function Chart.Interaction.modes.index
5844
+ * @since v2.4.0
5845
+ * @param chart {chart} the chart we are returning items from
5846
+ * @param e {Event} the event we are find things at
5847
+ * @param options {IInteractionOptions} options to use during interaction
5848
+ * @return {Chart.Element[]} Array of elements that are under the point. If none are found, an empty array is returned
5849
+ */
5850
+ index: indexMode,
5851
+
5852
+ /**
5853
+ * Returns items in the same dataset. If the options.intersect parameter is true, we only return items if we intersect something
5854
+ * If the options.intersect is false, we find the nearest item and return the items in that dataset
5855
+ * @function Chart.Interaction.modes.dataset
5856
+ * @param chart {chart} the chart we are returning items from
5857
+ * @param e {Event} the event we are find things at
5858
+ * @param options {IInteractionOptions} options to use during interaction
5859
+ * @return {Chart.Element[]} Array of elements that are under the point. If none are found, an empty array is returned
5860
+ */
5861
+ dataset: function(chart, e, options) {
5862
+ var position = getRelativePosition(e, chart);
5863
+ options.axis = options.axis || 'xy';
5864
+ var distanceMetric = getDistanceMetricForAxis(options.axis);
5865
+ var items = options.intersect ? getIntersectItems(chart, position) : getNearestItems(chart, position, false, distanceMetric);
5866
+
5867
+ if (items.length > 0) {
5868
+ items = chart.getDatasetMeta(items[0]._datasetIndex).data;
5869
+ }
5870
+
5871
+ return items;
5872
+ },
5873
+
5874
+ /**
5875
+ * @function Chart.Interaction.modes.x-axis
5876
+ * @deprecated since version 2.4.0. Use index mode and intersect == true
5877
+ * @todo remove at version 3
5878
+ * @private
5879
+ */
5880
+ 'x-axis': function(chart, e) {
5881
+ return indexMode(chart, e, {intersect: false});
5882
+ },
5883
+
5884
+ /**
5885
+ * Point mode returns all elements that hit test based on the event position
5886
+ * of the event
5887
+ * @function Chart.Interaction.modes.intersect
5888
+ * @param chart {chart} the chart we are returning items from
5889
+ * @param e {Event} the event we are find things at
5890
+ * @return {Chart.Element[]} Array of elements that are under the point. If none are found, an empty array is returned
5891
+ */
5892
+ point: function(chart, e) {
5893
+ var position = getRelativePosition(e, chart);
5894
+ return getIntersectItems(chart, position);
5895
+ },
5896
+
5897
+ /**
5898
+ * nearest mode returns the element closest to the point
5899
+ * @function Chart.Interaction.modes.intersect
5900
+ * @param chart {chart} the chart we are returning items from
5901
+ * @param e {Event} the event we are find things at
5902
+ * @param options {IInteractionOptions} options to use
5903
+ * @return {Chart.Element[]} Array of elements that are under the point. If none are found, an empty array is returned
5904
+ */
5905
+ nearest: function(chart, e, options) {
5906
+ var position = getRelativePosition(e, chart);
5907
+ options.axis = options.axis || 'xy';
5908
+ var distanceMetric = getDistanceMetricForAxis(options.axis);
5909
+ var nearestItems = getNearestItems(chart, position, options.intersect, distanceMetric);
5910
+
5911
+ // We have multiple items at the same distance from the event. Now sort by smallest
5912
+ if (nearestItems.length > 1) {
5913
+ nearestItems.sort(function(a, b) {
5914
+ var sizeA = a.getArea();
5915
+ var sizeB = b.getArea();
5916
+ var ret = sizeA - sizeB;
5917
+
5918
+ if (ret === 0) {
5919
+ // if equal sort by dataset index
5920
+ ret = a._datasetIndex - b._datasetIndex;
5921
+ }
5922
+
5923
+ return ret;
5924
+ });
5925
+ }
5926
+
5927
+ // Return only 1 item
5928
+ return nearestItems.slice(0, 1);
5929
+ },
5930
+
5931
+ /**
5932
+ * x mode returns the elements that hit-test at the current x coordinate
5933
+ * @function Chart.Interaction.modes.x
5934
+ * @param chart {chart} the chart we are returning items from
5935
+ * @param e {Event} the event we are find things at
5936
+ * @param options {IInteractionOptions} options to use
5937
+ * @return {Chart.Element[]} Array of elements that are under the point. If none are found, an empty array is returned
5938
+ */
5939
+ x: function(chart, e, options) {
5940
+ var position = getRelativePosition(e, chart);
5941
+ var items = [];
5942
+ var intersectsItem = false;
5943
+
5944
+ parseVisibleItems(chart, function(element) {
5945
+ if (element.inXRange(position.x)) {
5946
+ items.push(element);
5947
+ }
5948
+
5949
+ if (element.inRange(position.x, position.y)) {
5950
+ intersectsItem = true;
5951
+ }
5952
+ });
5953
+
5954
+ // If we want to trigger on an intersect and we don't have any items
5955
+ // that intersect the position, return nothing
5956
+ if (options.intersect && !intersectsItem) {
5957
+ items = [];
5958
+ }
5959
+ return items;
5960
+ },
5961
+
5962
+ /**
5963
+ * y mode returns the elements that hit-test at the current y coordinate
5964
+ * @function Chart.Interaction.modes.y
5965
+ * @param chart {chart} the chart we are returning items from
5966
+ * @param e {Event} the event we are find things at
5967
+ * @param options {IInteractionOptions} options to use
5968
+ * @return {Chart.Element[]} Array of elements that are under the point. If none are found, an empty array is returned
5969
+ */
5970
+ y: function(chart, e, options) {
5971
+ var position = getRelativePosition(e, chart);
5972
+ var items = [];
5973
+ var intersectsItem = false;
5974
+
5975
+ parseVisibleItems(chart, function(element) {
5976
+ if (element.inYRange(position.y)) {
5977
+ items.push(element);
5978
+ }
5979
+
5980
+ if (element.inRange(position.x, position.y)) {
5981
+ intersectsItem = true;
5982
+ }
5983
+ });
5984
+
5985
+ // If we want to trigger on an intersect and we don't have any items
5986
+ // that intersect the position, return nothing
5987
+ if (options.intersect && !intersectsItem) {
5988
+ items = [];
5989
+ }
5990
+ return items;
5991
+ }
5992
+ }
5993
+ };
5994
+
5995
+ },{"45":45}],29:[function(require,module,exports){
5996
+ 'use strict';
5997
+
5998
+ var defaults = require(25);
5999
+
6000
+ defaults._set('global', {
6001
+ responsive: true,
6002
+ responsiveAnimationDuration: 0,
6003
+ maintainAspectRatio: true,
6004
+ events: ['mousemove', 'mouseout', 'click', 'touchstart', 'touchmove'],
6005
+ hover: {
6006
+ onHover: null,
6007
+ mode: 'nearest',
6008
+ intersect: true,
6009
+ animationDuration: 400
6010
+ },
6011
+ onClick: null,
6012
+ defaultColor: 'rgba(0,0,0,0.1)',
6013
+ defaultFontColor: '#666',
6014
+ defaultFontFamily: "'Helvetica Neue', 'Helvetica', 'Arial', sans-serif",
6015
+ defaultFontSize: 12,
6016
+ defaultFontStyle: 'normal',
6017
+ showLines: true,
6018
+
6019
+ // Element defaults defined in element extensions
6020
+ elements: {},
6021
+
6022
+ // Layout options such as padding
6023
+ layout: {
6024
+ padding: {
6025
+ top: 0,
6026
+ right: 0,
6027
+ bottom: 0,
6028
+ left: 0
6029
+ }
6030
+ }
6031
+ });
6032
+
6033
+ module.exports = function() {
6034
+
6035
+ // Occupy the global variable of Chart, and create a simple base class
6036
+ var Chart = function(item, config) {
6037
+ this.construct(item, config);
6038
+ return this;
6039
+ };
6040
+
6041
+ Chart.Chart = Chart;
6042
+
6043
+ return Chart;
6044
+ };
6045
+
6046
+ },{"25":25}],30:[function(require,module,exports){
6047
+ 'use strict';
6048
+
6049
+ var helpers = require(45);
6050
+
6051
+ module.exports = function(Chart) {
6052
+
6053
+ function filterByPosition(array, position) {
6054
+ return helpers.where(array, function(v) {
6055
+ return v.position === position;
6056
+ });
6057
+ }
6058
+
6059
+ function sortByWeight(array, reverse) {
6060
+ array.forEach(function(v, i) {
6061
+ v._tmpIndex_ = i;
6062
+ return v;
6063
+ });
6064
+ array.sort(function(a, b) {
6065
+ var v0 = reverse ? b : a;
6066
+ var v1 = reverse ? a : b;
6067
+ return v0.weight === v1.weight ?
6068
+ v0._tmpIndex_ - v1._tmpIndex_ :
6069
+ v0.weight - v1.weight;
6070
+ });
6071
+ array.forEach(function(v) {
6072
+ delete v._tmpIndex_;
6073
+ });
6074
+ }
6075
+
6076
+ /**
6077
+ * @interface ILayoutItem
6078
+ * @prop {String} position - The position of the item in the chart layout. Possible values are
6079
+ * 'left', 'top', 'right', 'bottom', and 'chartArea'
6080
+ * @prop {Number} weight - The weight used to sort the item. Higher weights are further away from the chart area
6081
+ * @prop {Boolean} fullWidth - if true, and the item is horizontal, then push vertical boxes down
6082
+ * @prop {Function} isHorizontal - returns true if the layout item is horizontal (ie. top or bottom)
6083
+ * @prop {Function} update - Takes two parameters: width and height. Returns size of item
6084
+ * @prop {Function} getPadding - Returns an object with padding on the edges
6085
+ * @prop {Number} width - Width of item. Must be valid after update()
6086
+ * @prop {Number} height - Height of item. Must be valid after update()
6087
+ * @prop {Number} left - Left edge of the item. Set by layout system and cannot be used in update
6088
+ * @prop {Number} top - Top edge of the item. Set by layout system and cannot be used in update
6089
+ * @prop {Number} right - Right edge of the item. Set by layout system and cannot be used in update
6090
+ * @prop {Number} bottom - Bottom edge of the item. Set by layout system and cannot be used in update
6091
+ */
6092
+
6093
+ // The layout service is very self explanatory. It's responsible for the layout within a chart.
6094
+ // Scales, Legends and Plugins all rely on the layout service and can easily register to be placed anywhere they need
6095
+ // It is this service's responsibility of carrying out that layout.
6096
+ Chart.layoutService = {
6097
+ defaults: {},
6098
+
6099
+ /**
6100
+ * Register a box to a chart.
6101
+ * A box is simply a reference to an object that requires layout. eg. Scales, Legend, Title.
6102
+ * @param {Chart} chart - the chart to use
6103
+ * @param {ILayoutItem} item - the item to add to be layed out
6104
+ */
6105
+ addBox: function(chart, item) {
6106
+ if (!chart.boxes) {
6107
+ chart.boxes = [];
6108
+ }
6109
+
6110
+ // initialize item with default values
6111
+ item.fullWidth = item.fullWidth || false;
6112
+ item.position = item.position || 'top';
6113
+ item.weight = item.weight || 0;
6114
+
6115
+ chart.boxes.push(item);
6116
+ },
6117
+
6118
+ /**
6119
+ * Remove a layoutItem from a chart
6120
+ * @param {Chart} chart - the chart to remove the box from
6121
+ * @param {Object} layoutItem - the item to remove from the layout
6122
+ */
6123
+ removeBox: function(chart, layoutItem) {
6124
+ var index = chart.boxes ? chart.boxes.indexOf(layoutItem) : -1;
6125
+ if (index !== -1) {
6126
+ chart.boxes.splice(index, 1);
6127
+ }
6128
+ },
6129
+
6130
+ /**
6131
+ * Sets (or updates) options on the given `item`.
6132
+ * @param {Chart} chart - the chart in which the item lives (or will be added to)
6133
+ * @param {Object} item - the item to configure with the given options
6134
+ * @param {Object} options - the new item options.
6135
+ */
6136
+ configure: function(chart, item, options) {
6137
+ var props = ['fullWidth', 'position', 'weight'];
6138
+ var ilen = props.length;
6139
+ var i = 0;
6140
+ var prop;
6141
+
6142
+ for (; i < ilen; ++i) {
6143
+ prop = props[i];
6144
+ if (options.hasOwnProperty(prop)) {
6145
+ item[prop] = options[prop];
6146
+ }
6147
+ }
6148
+ },
6149
+
6150
+ /**
6151
+ * Fits boxes of the given chart into the given size by having each box measure itself
6152
+ * then running a fitting algorithm
6153
+ * @param {Chart} chart - the chart
6154
+ * @param {Number} width - the width to fit into
6155
+ * @param {Number} height - the height to fit into
6156
+ */
6157
+ update: function(chart, width, height) {
6158
+ if (!chart) {
6159
+ return;
6160
+ }
6161
+
6162
+ var layoutOptions = chart.options.layout || {};
6163
+ var padding = helpers.options.toPadding(layoutOptions.padding);
6164
+ var leftPadding = padding.left;
6165
+ var rightPadding = padding.right;
6166
+ var topPadding = padding.top;
6167
+ var bottomPadding = padding.bottom;
6168
+
6169
+ var leftBoxes = filterByPosition(chart.boxes, 'left');
6170
+ var rightBoxes = filterByPosition(chart.boxes, 'right');
6171
+ var topBoxes = filterByPosition(chart.boxes, 'top');
6172
+ var bottomBoxes = filterByPosition(chart.boxes, 'bottom');
6173
+ var chartAreaBoxes = filterByPosition(chart.boxes, 'chartArea');
6174
+
6175
+ // Sort boxes by weight. A higher weight is further away from the chart area
6176
+ sortByWeight(leftBoxes, true);
6177
+ sortByWeight(rightBoxes, false);
6178
+ sortByWeight(topBoxes, true);
6179
+ sortByWeight(bottomBoxes, false);
6180
+
6181
+ // Essentially we now have any number of boxes on each of the 4 sides.
6182
+ // Our canvas looks like the following.
6183
+ // The areas L1 and L2 are the left axes. R1 is the right axis, T1 is the top axis and
6184
+ // B1 is the bottom axis
6185
+ // There are also 4 quadrant-like locations (left to right instead of clockwise) reserved for chart overlays
6186
+ // These locations are single-box locations only, when trying to register a chartArea location that is already taken,
6187
+ // an error will be thrown.
6188
+ //
6189
+ // |----------------------------------------------------|
6190
+ // | T1 (Full Width) |
6191
+ // |----------------------------------------------------|
6192
+ // | | | T2 | |
6193
+ // | |----|-------------------------------------|----|
6194
+ // | | | C1 | | C2 | |
6195
+ // | | |----| |----| |
6196
+ // | | | | |
6197
+ // | L1 | L2 | ChartArea (C0) | R1 |
6198
+ // | | | | |
6199
+ // | | |----| |----| |
6200
+ // | | | C3 | | C4 | |
6201
+ // | |----|-------------------------------------|----|
6202
+ // | | | B1 | |
6203
+ // |----------------------------------------------------|
6204
+ // | B2 (Full Width) |
6205
+ // |----------------------------------------------------|
6206
+ //
6207
+ // What we do to find the best sizing, we do the following
6208
+ // 1. Determine the minimum size of the chart area.
6209
+ // 2. Split the remaining width equally between each vertical axis
6210
+ // 3. Split the remaining height equally between each horizontal axis
6211
+ // 4. Give each layout the maximum size it can be. The layout will return it's minimum size
6212
+ // 5. Adjust the sizes of each axis based on it's minimum reported size.
6213
+ // 6. Refit each axis
6214
+ // 7. Position each axis in the final location
6215
+ // 8. Tell the chart the final location of the chart area
6216
+ // 9. Tell any axes that overlay the chart area the positions of the chart area
6217
+
6218
+ // Step 1
6219
+ var chartWidth = width - leftPadding - rightPadding;
6220
+ var chartHeight = height - topPadding - bottomPadding;
6221
+ var chartAreaWidth = chartWidth / 2; // min 50%
6222
+ var chartAreaHeight = chartHeight / 2; // min 50%
6223
+
6224
+ // Step 2
6225
+ var verticalBoxWidth = (width - chartAreaWidth) / (leftBoxes.length + rightBoxes.length);
6226
+
6227
+ // Step 3
6228
+ var horizontalBoxHeight = (height - chartAreaHeight) / (topBoxes.length + bottomBoxes.length);
6229
+
6230
+ // Step 4
6231
+ var maxChartAreaWidth = chartWidth;
6232
+ var maxChartAreaHeight = chartHeight;
6233
+ var minBoxSizes = [];
6234
+
6235
+ function getMinimumBoxSize(box) {
6236
+ var minSize;
6237
+ var isHorizontal = box.isHorizontal();
6238
+
6239
+ if (isHorizontal) {
6240
+ minSize = box.update(box.fullWidth ? chartWidth : maxChartAreaWidth, horizontalBoxHeight);
6241
+ maxChartAreaHeight -= minSize.height;
6242
+ } else {
6243
+ minSize = box.update(verticalBoxWidth, chartAreaHeight);
6244
+ maxChartAreaWidth -= minSize.width;
6245
+ }
6246
+
6247
+ minBoxSizes.push({
6248
+ horizontal: isHorizontal,
6249
+ minSize: minSize,
6250
+ box: box,
6251
+ });
6252
+ }
6253
+
6254
+ helpers.each(leftBoxes.concat(rightBoxes, topBoxes, bottomBoxes), getMinimumBoxSize);
6255
+
6256
+ // If a horizontal box has padding, we move the left boxes over to avoid ugly charts (see issue #2478)
6257
+ var maxHorizontalLeftPadding = 0;
6258
+ var maxHorizontalRightPadding = 0;
6259
+ var maxVerticalTopPadding = 0;
6260
+ var maxVerticalBottomPadding = 0;
6261
+
6262
+ helpers.each(topBoxes.concat(bottomBoxes), function(horizontalBox) {
6263
+ if (horizontalBox.getPadding) {
6264
+ var boxPadding = horizontalBox.getPadding();
6265
+ maxHorizontalLeftPadding = Math.max(maxHorizontalLeftPadding, boxPadding.left);
6266
+ maxHorizontalRightPadding = Math.max(maxHorizontalRightPadding, boxPadding.right);
6267
+ }
6268
+ });
6269
+
6270
+ helpers.each(leftBoxes.concat(rightBoxes), function(verticalBox) {
6271
+ if (verticalBox.getPadding) {
6272
+ var boxPadding = verticalBox.getPadding();
6273
+ maxVerticalTopPadding = Math.max(maxVerticalTopPadding, boxPadding.top);
6274
+ maxVerticalBottomPadding = Math.max(maxVerticalBottomPadding, boxPadding.bottom);
6275
+ }
6276
+ });
6277
+
6278
+ // At this point, maxChartAreaHeight and maxChartAreaWidth are the size the chart area could
6279
+ // be if the axes are drawn at their minimum sizes.
6280
+ // Steps 5 & 6
6281
+ var totalLeftBoxesWidth = leftPadding;
6282
+ var totalRightBoxesWidth = rightPadding;
6283
+ var totalTopBoxesHeight = topPadding;
6284
+ var totalBottomBoxesHeight = bottomPadding;
6285
+
6286
+ // Function to fit a box
6287
+ function fitBox(box) {
6288
+ var minBoxSize = helpers.findNextWhere(minBoxSizes, function(minBox) {
6289
+ return minBox.box === box;
6290
+ });
6291
+
6292
+ if (minBoxSize) {
6293
+ if (box.isHorizontal()) {
6294
+ var scaleMargin = {
6295
+ left: Math.max(totalLeftBoxesWidth, maxHorizontalLeftPadding),
6296
+ right: Math.max(totalRightBoxesWidth, maxHorizontalRightPadding),
6297
+ top: 0,
6298
+ bottom: 0
6299
+ };
6300
+
6301
+ // Don't use min size here because of label rotation. When the labels are rotated, their rotation highly depends
6302
+ // on the margin. Sometimes they need to increase in size slightly
6303
+ box.update(box.fullWidth ? chartWidth : maxChartAreaWidth, chartHeight / 2, scaleMargin);
6304
+ } else {
6305
+ box.update(minBoxSize.minSize.width, maxChartAreaHeight);
6306
+ }
6307
+ }
6308
+ }
6309
+
6310
+ // Update, and calculate the left and right margins for the horizontal boxes
6311
+ helpers.each(leftBoxes.concat(rightBoxes), fitBox);
6312
+
6313
+ helpers.each(leftBoxes, function(box) {
6314
+ totalLeftBoxesWidth += box.width;
6315
+ });
6316
+
6317
+ helpers.each(rightBoxes, function(box) {
6318
+ totalRightBoxesWidth += box.width;
6319
+ });
6320
+
6321
+ // Set the Left and Right margins for the horizontal boxes
6322
+ helpers.each(topBoxes.concat(bottomBoxes), fitBox);
6323
+
6324
+ // Figure out how much margin is on the top and bottom of the vertical boxes
6325
+ helpers.each(topBoxes, function(box) {
6326
+ totalTopBoxesHeight += box.height;
6327
+ });
6328
+
6329
+ helpers.each(bottomBoxes, function(box) {
6330
+ totalBottomBoxesHeight += box.height;
6331
+ });
6332
+
6333
+ function finalFitVerticalBox(box) {
6334
+ var minBoxSize = helpers.findNextWhere(minBoxSizes, function(minSize) {
6335
+ return minSize.box === box;
6336
+ });
6337
+
6338
+ var scaleMargin = {
6339
+ left: 0,
6340
+ right: 0,
6341
+ top: totalTopBoxesHeight,
6342
+ bottom: totalBottomBoxesHeight
6343
+ };
6344
+
6345
+ if (minBoxSize) {
6346
+ box.update(minBoxSize.minSize.width, maxChartAreaHeight, scaleMargin);
6347
+ }
6348
+ }
6349
+
6350
+ // Let the left layout know the final margin
6351
+ helpers.each(leftBoxes.concat(rightBoxes), finalFitVerticalBox);
6352
+
6353
+ // Recalculate because the size of each layout might have changed slightly due to the margins (label rotation for instance)
6354
+ totalLeftBoxesWidth = leftPadding;
6355
+ totalRightBoxesWidth = rightPadding;
6356
+ totalTopBoxesHeight = topPadding;
6357
+ totalBottomBoxesHeight = bottomPadding;
6358
+
6359
+ helpers.each(leftBoxes, function(box) {
6360
+ totalLeftBoxesWidth += box.width;
6361
+ });
6362
+
6363
+ helpers.each(rightBoxes, function(box) {
6364
+ totalRightBoxesWidth += box.width;
6365
+ });
6366
+
6367
+ helpers.each(topBoxes, function(box) {
6368
+ totalTopBoxesHeight += box.height;
6369
+ });
6370
+ helpers.each(bottomBoxes, function(box) {
6371
+ totalBottomBoxesHeight += box.height;
6372
+ });
6373
+
6374
+ // We may be adding some padding to account for rotated x axis labels
6375
+ var leftPaddingAddition = Math.max(maxHorizontalLeftPadding - totalLeftBoxesWidth, 0);
6376
+ totalLeftBoxesWidth += leftPaddingAddition;
6377
+ totalRightBoxesWidth += Math.max(maxHorizontalRightPadding - totalRightBoxesWidth, 0);
6378
+
6379
+ var topPaddingAddition = Math.max(maxVerticalTopPadding - totalTopBoxesHeight, 0);
6380
+ totalTopBoxesHeight += topPaddingAddition;
6381
+ totalBottomBoxesHeight += Math.max(maxVerticalBottomPadding - totalBottomBoxesHeight, 0);
6382
+
6383
+ // Figure out if our chart area changed. This would occur if the dataset layout label rotation
6384
+ // changed due to the application of the margins in step 6. Since we can only get bigger, this is safe to do
6385
+ // without calling `fit` again
6386
+ var newMaxChartAreaHeight = height - totalTopBoxesHeight - totalBottomBoxesHeight;
6387
+ var newMaxChartAreaWidth = width - totalLeftBoxesWidth - totalRightBoxesWidth;
6388
+
6389
+ if (newMaxChartAreaWidth !== maxChartAreaWidth || newMaxChartAreaHeight !== maxChartAreaHeight) {
6390
+ helpers.each(leftBoxes, function(box) {
6391
+ box.height = newMaxChartAreaHeight;
6392
+ });
6393
+
6394
+ helpers.each(rightBoxes, function(box) {
6395
+ box.height = newMaxChartAreaHeight;
6396
+ });
6397
+
6398
+ helpers.each(topBoxes, function(box) {
6399
+ if (!box.fullWidth) {
6400
+ box.width = newMaxChartAreaWidth;
6401
+ }
6402
+ });
6403
+
6404
+ helpers.each(bottomBoxes, function(box) {
6405
+ if (!box.fullWidth) {
6406
+ box.width = newMaxChartAreaWidth;
6407
+ }
6408
+ });
6409
+
6410
+ maxChartAreaHeight = newMaxChartAreaHeight;
6411
+ maxChartAreaWidth = newMaxChartAreaWidth;
6412
+ }
6413
+
6414
+ // Step 7 - Position the boxes
6415
+ var left = leftPadding + leftPaddingAddition;
6416
+ var top = topPadding + topPaddingAddition;
6417
+
6418
+ function placeBox(box) {
6419
+ if (box.isHorizontal()) {
6420
+ box.left = box.fullWidth ? leftPadding : totalLeftBoxesWidth;
6421
+ box.right = box.fullWidth ? width - rightPadding : totalLeftBoxesWidth + maxChartAreaWidth;
6422
+ box.top = top;
6423
+ box.bottom = top + box.height;
6424
+
6425
+ // Move to next point
6426
+ top = box.bottom;
6427
+
6428
+ } else {
6429
+
6430
+ box.left = left;
6431
+ box.right = left + box.width;
6432
+ box.top = totalTopBoxesHeight;
6433
+ box.bottom = totalTopBoxesHeight + maxChartAreaHeight;
6434
+
6435
+ // Move to next point
6436
+ left = box.right;
6437
+ }
6438
+ }
6439
+
6440
+ helpers.each(leftBoxes.concat(topBoxes), placeBox);
6441
+
6442
+ // Account for chart width and height
6443
+ left += maxChartAreaWidth;
6444
+ top += maxChartAreaHeight;
6445
+
6446
+ helpers.each(rightBoxes, placeBox);
6447
+ helpers.each(bottomBoxes, placeBox);
6448
+
6449
+ // Step 8
6450
+ chart.chartArea = {
6451
+ left: totalLeftBoxesWidth,
6452
+ top: totalTopBoxesHeight,
6453
+ right: totalLeftBoxesWidth + maxChartAreaWidth,
6454
+ bottom: totalTopBoxesHeight + maxChartAreaHeight
6455
+ };
6456
+
6457
+ // Step 9
6458
+ helpers.each(chartAreaBoxes, function(box) {
6459
+ box.left = chart.chartArea.left;
6460
+ box.top = chart.chartArea.top;
6461
+ box.right = chart.chartArea.right;
6462
+ box.bottom = chart.chartArea.bottom;
6463
+
6464
+ box.update(maxChartAreaWidth, maxChartAreaHeight);
6465
+ });
6466
+ }
6467
+ };
6468
+ };
6469
+
6470
+ },{"45":45}],31:[function(require,module,exports){
6471
+ 'use strict';
6472
+
6473
+ var defaults = require(25);
6474
+ var Element = require(26);
6475
+ var helpers = require(45);
6476
+
6477
+ defaults._set('global', {
6478
+ plugins: {}
6479
+ });
6480
+
6481
+ module.exports = function(Chart) {
6482
+
6483
+ /**
6484
+ * The plugin service singleton
6485
+ * @namespace Chart.plugins
6486
+ * @since 2.1.0
6487
+ */
6488
+ Chart.plugins = {
6489
+ /**
6490
+ * Globally registered plugins.
6491
+ * @private
6492
+ */
6493
+ _plugins: [],
6494
+
6495
+ /**
6496
+ * This identifier is used to invalidate the descriptors cache attached to each chart
6497
+ * when a global plugin is registered or unregistered. In this case, the cache ID is
6498
+ * incremented and descriptors are regenerated during following API calls.
6499
+ * @private
6500
+ */
6501
+ _cacheId: 0,
6502
+
6503
+ /**
6504
+ * Registers the given plugin(s) if not already registered.
6505
+ * @param {Array|Object} plugins plugin instance(s).
6506
+ */
6507
+ register: function(plugins) {
6508
+ var p = this._plugins;
6509
+ ([]).concat(plugins).forEach(function(plugin) {
6510
+ if (p.indexOf(plugin) === -1) {
6511
+ p.push(plugin);
6512
+ }
6513
+ });
6514
+
6515
+ this._cacheId++;
6516
+ },
6517
+
6518
+ /**
6519
+ * Unregisters the given plugin(s) only if registered.
6520
+ * @param {Array|Object} plugins plugin instance(s).
6521
+ */
6522
+ unregister: function(plugins) {
6523
+ var p = this._plugins;
6524
+ ([]).concat(plugins).forEach(function(plugin) {
6525
+ var idx = p.indexOf(plugin);
6526
+ if (idx !== -1) {
6527
+ p.splice(idx, 1);
6528
+ }
6529
+ });
6530
+
6531
+ this._cacheId++;
6532
+ },
6533
+
6534
+ /**
6535
+ * Remove all registered plugins.
6536
+ * @since 2.1.5
6537
+ */
6538
+ clear: function() {
6539
+ this._plugins = [];
6540
+ this._cacheId++;
6541
+ },
6542
+
6543
+ /**
6544
+ * Returns the number of registered plugins?
6545
+ * @returns {Number}
6546
+ * @since 2.1.5
6547
+ */
6548
+ count: function() {
6549
+ return this._plugins.length;
6550
+ },
6551
+
6552
+ /**
6553
+ * Returns all registered plugin instances.
6554
+ * @returns {Array} array of plugin objects.
6555
+ * @since 2.1.5
6556
+ */
6557
+ getAll: function() {
6558
+ return this._plugins;
6559
+ },
6560
+
6561
+ /**
6562
+ * Calls enabled plugins for `chart` on the specified hook and with the given args.
6563
+ * This method immediately returns as soon as a plugin explicitly returns false. The
6564
+ * returned value can be used, for instance, to interrupt the current action.
6565
+ * @param {Object} chart - The chart instance for which plugins should be called.
6566
+ * @param {String} hook - The name of the plugin method to call (e.g. 'beforeUpdate').
6567
+ * @param {Array} [args] - Extra arguments to apply to the hook call.
6568
+ * @returns {Boolean} false if any of the plugins return false, else returns true.
6569
+ */
6570
+ notify: function(chart, hook, args) {
6571
+ var descriptors = this.descriptors(chart);
6572
+ var ilen = descriptors.length;
6573
+ var i, descriptor, plugin, params, method;
6574
+
6575
+ for (i = 0; i < ilen; ++i) {
6576
+ descriptor = descriptors[i];
6577
+ plugin = descriptor.plugin;
6578
+ method = plugin[hook];
6579
+ if (typeof method === 'function') {
6580
+ params = [chart].concat(args || []);
6581
+ params.push(descriptor.options);
6582
+ if (method.apply(plugin, params) === false) {
6583
+ return false;
6584
+ }
6585
+ }
6586
+ }
6587
+
6588
+ return true;
6589
+ },
6590
+
6591
+ /**
6592
+ * Returns descriptors of enabled plugins for the given chart.
6593
+ * @returns {Array} [{ plugin, options }]
6594
+ * @private
6595
+ */
6596
+ descriptors: function(chart) {
6597
+ var cache = chart._plugins || (chart._plugins = {});
6598
+ if (cache.id === this._cacheId) {
6599
+ return cache.descriptors;
6600
+ }
6601
+
6602
+ var plugins = [];
6603
+ var descriptors = [];
6604
+ var config = (chart && chart.config) || {};
6605
+ var options = (config.options && config.options.plugins) || {};
6606
+
6607
+ this._plugins.concat(config.plugins || []).forEach(function(plugin) {
6608
+ var idx = plugins.indexOf(plugin);
6609
+ if (idx !== -1) {
6610
+ return;
6611
+ }
6612
+
6613
+ var id = plugin.id;
6614
+ var opts = options[id];
6615
+ if (opts === false) {
6616
+ return;
6617
+ }
6618
+
6619
+ if (opts === true) {
6620
+ opts = helpers.clone(defaults.global.plugins[id]);
6621
+ }
6622
+
6623
+ plugins.push(plugin);
6624
+ descriptors.push({
6625
+ plugin: plugin,
6626
+ options: opts || {}
6627
+ });
6628
+ });
6629
+
6630
+ cache.descriptors = descriptors;
6631
+ cache.id = this._cacheId;
6632
+ return descriptors;
6633
+ }
6634
+ };
6635
+
6636
+ /**
6637
+ * Plugin extension hooks.
6638
+ * @interface IPlugin
6639
+ * @since 2.1.0
6640
+ */
6641
+ /**
6642
+ * @method IPlugin#beforeInit
6643
+ * @desc Called before initializing `chart`.
6644
+ * @param {Chart.Controller} chart - The chart instance.
6645
+ * @param {Object} options - The plugin options.
6646
+ */
6647
+ /**
6648
+ * @method IPlugin#afterInit
6649
+ * @desc Called after `chart` has been initialized and before the first update.
6650
+ * @param {Chart.Controller} chart - The chart instance.
6651
+ * @param {Object} options - The plugin options.
6652
+ */
6653
+ /**
6654
+ * @method IPlugin#beforeUpdate
6655
+ * @desc Called before updating `chart`. If any plugin returns `false`, the update
6656
+ * is cancelled (and thus subsequent render(s)) until another `update` is triggered.
6657
+ * @param {Chart.Controller} chart - The chart instance.
6658
+ * @param {Object} options - The plugin options.
6659
+ * @returns {Boolean} `false` to cancel the chart update.
6660
+ */
6661
+ /**
6662
+ * @method IPlugin#afterUpdate
6663
+ * @desc Called after `chart` has been updated and before rendering. Note that this
6664
+ * hook will not be called if the chart update has been previously cancelled.
6665
+ * @param {Chart.Controller} chart - The chart instance.
6666
+ * @param {Object} options - The plugin options.
6667
+ */
6668
+ /**
6669
+ * @method IPlugin#beforeDatasetsUpdate
6670
+ * @desc Called before updating the `chart` datasets. If any plugin returns `false`,
6671
+ * the datasets update is cancelled until another `update` is triggered.
6672
+ * @param {Chart.Controller} chart - The chart instance.
6673
+ * @param {Object} options - The plugin options.
6674
+ * @returns {Boolean} false to cancel the datasets update.
6675
+ * @since version 2.1.5
6676
+ */
6677
+ /**
6678
+ * @method IPlugin#afterDatasetsUpdate
6679
+ * @desc Called after the `chart` datasets have been updated. Note that this hook
6680
+ * will not be called if the datasets update has been previously cancelled.
6681
+ * @param {Chart.Controller} chart - The chart instance.
6682
+ * @param {Object} options - The plugin options.
6683
+ * @since version 2.1.5
6684
+ */
6685
+ /**
6686
+ * @method IPlugin#beforeDatasetUpdate
6687
+ * @desc Called before updating the `chart` dataset at the given `args.index`. If any plugin
6688
+ * returns `false`, the datasets update is cancelled until another `update` is triggered.
6689
+ * @param {Chart} chart - The chart instance.
6690
+ * @param {Object} args - The call arguments.
6691
+ * @param {Number} args.index - The dataset index.
6692
+ * @param {Object} args.meta - The dataset metadata.
6693
+ * @param {Object} options - The plugin options.
6694
+ * @returns {Boolean} `false` to cancel the chart datasets drawing.
6695
+ */
6696
+ /**
6697
+ * @method IPlugin#afterDatasetUpdate
6698
+ * @desc Called after the `chart` datasets at the given `args.index` has been updated. Note
6699
+ * that this hook will not be called if the datasets update has been previously cancelled.
6700
+ * @param {Chart} chart - The chart instance.
6701
+ * @param {Object} args - The call arguments.
6702
+ * @param {Number} args.index - The dataset index.
6703
+ * @param {Object} args.meta - The dataset metadata.
6704
+ * @param {Object} options - The plugin options.
6705
+ */
6706
+ /**
6707
+ * @method IPlugin#beforeLayout
6708
+ * @desc Called before laying out `chart`. If any plugin returns `false`,
6709
+ * the layout update is cancelled until another `update` is triggered.
6710
+ * @param {Chart.Controller} chart - The chart instance.
6711
+ * @param {Object} options - The plugin options.
6712
+ * @returns {Boolean} `false` to cancel the chart layout.
6713
+ */
6714
+ /**
6715
+ * @method IPlugin#afterLayout
6716
+ * @desc Called after the `chart` has been layed out. Note that this hook will not
6717
+ * be called if the layout update has been previously cancelled.
6718
+ * @param {Chart.Controller} chart - The chart instance.
6719
+ * @param {Object} options - The plugin options.
6720
+ */
6721
+ /**
6722
+ * @method IPlugin#beforeRender
6723
+ * @desc Called before rendering `chart`. If any plugin returns `false`,
6724
+ * the rendering is cancelled until another `render` is triggered.
6725
+ * @param {Chart.Controller} chart - The chart instance.
6726
+ * @param {Object} options - The plugin options.
6727
+ * @returns {Boolean} `false` to cancel the chart rendering.
6728
+ */
6729
+ /**
6730
+ * @method IPlugin#afterRender
6731
+ * @desc Called after the `chart` has been fully rendered (and animation completed). Note
6732
+ * that this hook will not be called if the rendering has been previously cancelled.
6733
+ * @param {Chart.Controller} chart - The chart instance.
6734
+ * @param {Object} options - The plugin options.
6735
+ */
6736
+ /**
6737
+ * @method IPlugin#beforeDraw
6738
+ * @desc Called before drawing `chart` at every animation frame specified by the given
6739
+ * easing value. If any plugin returns `false`, the frame drawing is cancelled until
6740
+ * another `render` is triggered.
6741
+ * @param {Chart.Controller} chart - The chart instance.
6742
+ * @param {Number} easingValue - The current animation value, between 0.0 and 1.0.
6743
+ * @param {Object} options - The plugin options.
6744
+ * @returns {Boolean} `false` to cancel the chart drawing.
6745
+ */
6746
+ /**
6747
+ * @method IPlugin#afterDraw
6748
+ * @desc Called after the `chart` has been drawn for the specific easing value. Note
6749
+ * that this hook will not be called if the drawing has been previously cancelled.
6750
+ * @param {Chart.Controller} chart - The chart instance.
6751
+ * @param {Number} easingValue - The current animation value, between 0.0 and 1.0.
6752
+ * @param {Object} options - The plugin options.
6753
+ */
6754
+ /**
6755
+ * @method IPlugin#beforeDatasetsDraw
6756
+ * @desc Called before drawing the `chart` datasets. If any plugin returns `false`,
6757
+ * the datasets drawing is cancelled until another `render` is triggered.
6758
+ * @param {Chart.Controller} chart - The chart instance.
6759
+ * @param {Number} easingValue - The current animation value, between 0.0 and 1.0.
6760
+ * @param {Object} options - The plugin options.
6761
+ * @returns {Boolean} `false` to cancel the chart datasets drawing.
6762
+ */
6763
+ /**
6764
+ * @method IPlugin#afterDatasetsDraw
6765
+ * @desc Called after the `chart` datasets have been drawn. Note that this hook
6766
+ * will not be called if the datasets drawing has been previously cancelled.
6767
+ * @param {Chart.Controller} chart - The chart instance.
6768
+ * @param {Number} easingValue - The current animation value, between 0.0 and 1.0.
6769
+ * @param {Object} options - The plugin options.
6770
+ */
6771
+ /**
6772
+ * @method IPlugin#beforeDatasetDraw
6773
+ * @desc Called before drawing the `chart` dataset at the given `args.index` (datasets
6774
+ * are drawn in the reverse order). If any plugin returns `false`, the datasets drawing
6775
+ * is cancelled until another `render` is triggered.
6776
+ * @param {Chart} chart - The chart instance.
6777
+ * @param {Object} args - The call arguments.
6778
+ * @param {Number} args.index - The dataset index.
6779
+ * @param {Object} args.meta - The dataset metadata.
6780
+ * @param {Number} args.easingValue - The current animation value, between 0.0 and 1.0.
6781
+ * @param {Object} options - The plugin options.
6782
+ * @returns {Boolean} `false` to cancel the chart datasets drawing.
6783
+ */
6784
+ /**
6785
+ * @method IPlugin#afterDatasetDraw
6786
+ * @desc Called after the `chart` datasets at the given `args.index` have been drawn
6787
+ * (datasets are drawn in the reverse order). Note that this hook will not be called
6788
+ * if the datasets drawing has been previously cancelled.
6789
+ * @param {Chart} chart - The chart instance.
6790
+ * @param {Object} args - The call arguments.
6791
+ * @param {Number} args.index - The dataset index.
6792
+ * @param {Object} args.meta - The dataset metadata.
6793
+ * @param {Number} args.easingValue - The current animation value, between 0.0 and 1.0.
6794
+ * @param {Object} options - The plugin options.
6795
+ */
6796
+ /**
6797
+ * @method IPlugin#beforeTooltipDraw
6798
+ * @desc Called before drawing the `tooltip`. If any plugin returns `false`,
6799
+ * the tooltip drawing is cancelled until another `render` is triggered.
6800
+ * @param {Chart} chart - The chart instance.
6801
+ * @param {Object} args - The call arguments.
6802
+ * @param {Object} args.tooltip - The tooltip.
6803
+ * @param {Number} args.easingValue - The current animation value, between 0.0 and 1.0.
6804
+ * @param {Object} options - The plugin options.
6805
+ * @returns {Boolean} `false` to cancel the chart tooltip drawing.
6806
+ */
6807
+ /**
6808
+ * @method IPlugin#afterTooltipDraw
6809
+ * @desc Called after drawing the `tooltip`. Note that this hook will not
6810
+ * be called if the tooltip drawing has been previously cancelled.
6811
+ * @param {Chart} chart - The chart instance.
6812
+ * @param {Object} args - The call arguments.
6813
+ * @param {Object} args.tooltip - The tooltip.
6814
+ * @param {Number} args.easingValue - The current animation value, between 0.0 and 1.0.
6815
+ * @param {Object} options - The plugin options.
6816
+ */
6817
+ /**
6818
+ * @method IPlugin#beforeEvent
6819
+ * @desc Called before processing the specified `event`. If any plugin returns `false`,
6820
+ * the event will be discarded.
6821
+ * @param {Chart.Controller} chart - The chart instance.
6822
+ * @param {IEvent} event - The event object.
6823
+ * @param {Object} options - The plugin options.
6824
+ */
6825
+ /**
6826
+ * @method IPlugin#afterEvent
6827
+ * @desc Called after the `event` has been consumed. Note that this hook
6828
+ * will not be called if the `event` has been previously discarded.
6829
+ * @param {Chart.Controller} chart - The chart instance.
6830
+ * @param {IEvent} event - The event object.
6831
+ * @param {Object} options - The plugin options.
6832
+ */
6833
+ /**
6834
+ * @method IPlugin#resize
6835
+ * @desc Called after the chart as been resized.
6836
+ * @param {Chart.Controller} chart - The chart instance.
6837
+ * @param {Number} size - The new canvas display size (eq. canvas.style width & height).
6838
+ * @param {Object} options - The plugin options.
6839
+ */
6840
+ /**
6841
+ * @method IPlugin#destroy
6842
+ * @desc Called after the chart as been destroyed.
6843
+ * @param {Chart.Controller} chart - The chart instance.
6844
+ * @param {Object} options - The plugin options.
6845
+ */
6846
+
6847
+ /**
6848
+ * Provided for backward compatibility, use Chart.plugins instead
6849
+ * @namespace Chart.pluginService
6850
+ * @deprecated since version 2.1.5
6851
+ * @todo remove at version 3
6852
+ * @private
6853
+ */
6854
+ Chart.pluginService = Chart.plugins;
6855
+
6856
+ /**
6857
+ * Provided for backward compatibility, inheriting from Chart.PlugingBase has no
6858
+ * effect, instead simply create/register plugins via plain JavaScript objects.
6859
+ * @interface Chart.PluginBase
6860
+ * @deprecated since version 2.5.0
6861
+ * @todo remove at version 3
6862
+ * @private
6863
+ */
6864
+ Chart.PluginBase = Element.extend({});
6865
+ };
6866
+
6867
+ },{"25":25,"26":26,"45":45}],32:[function(require,module,exports){
6868
+ 'use strict';
6869
+
6870
+ var defaults = require(25);
6871
+ var Element = require(26);
6872
+ var helpers = require(45);
6873
+ var Ticks = require(34);
6874
+
6875
+ defaults._set('scale', {
6876
+ display: true,
6877
+ position: 'left',
6878
+ offset: false,
6879
+
6880
+ // grid line settings
6881
+ gridLines: {
6882
+ display: true,
6883
+ color: 'rgba(0, 0, 0, 0.1)',
6884
+ lineWidth: 1,
6885
+ drawBorder: true,
6886
+ drawOnChartArea: true,
6887
+ drawTicks: true,
6888
+ tickMarkLength: 10,
6889
+ zeroLineWidth: 1,
6890
+ zeroLineColor: 'rgba(0,0,0,0.25)',
6891
+ zeroLineBorderDash: [],
6892
+ zeroLineBorderDashOffset: 0.0,
6893
+ offsetGridLines: false,
6894
+ borderDash: [],
6895
+ borderDashOffset: 0.0
6896
+ },
6897
+
6898
+ // scale label
6899
+ scaleLabel: {
6900
+ // display property
6901
+ display: false,
6902
+
6903
+ // actual label
6904
+ labelString: '',
6905
+
6906
+ // line height
6907
+ lineHeight: 1.2,
6908
+
6909
+ // top/bottom padding
6910
+ padding: {
6911
+ top: 4,
6912
+ bottom: 4
6913
+ }
6914
+ },
6915
+
6916
+ // label settings
6917
+ ticks: {
6918
+ beginAtZero: false,
6919
+ minRotation: 0,
6920
+ maxRotation: 50,
6921
+ mirror: false,
6922
+ padding: 0,
6923
+ reverse: false,
6924
+ display: true,
6925
+ autoSkip: true,
6926
+ autoSkipPadding: 0,
6927
+ labelOffset: 0,
6928
+ // We pass through arrays to be rendered as multiline labels, we convert Others to strings here.
6929
+ callback: Ticks.formatters.values,
6930
+ minor: {},
6931
+ major: {}
6932
+ }
6933
+ });
6934
+
6935
+ function labelsFromTicks(ticks) {
6936
+ var labels = [];
6937
+ var i, ilen;
6938
+
6939
+ for (i = 0, ilen = ticks.length; i < ilen; ++i) {
6940
+ labels.push(ticks[i].label);
6941
+ }
6942
+
6943
+ return labels;
6944
+ }
6945
+
6946
+ function getLineValue(scale, index, offsetGridLines) {
6947
+ var lineValue = scale.getPixelForTick(index);
6948
+
6949
+ if (offsetGridLines) {
6950
+ if (index === 0) {
6951
+ lineValue -= (scale.getPixelForTick(1) - lineValue) / 2;
6952
+ } else {
6953
+ lineValue -= (lineValue - scale.getPixelForTick(index - 1)) / 2;
6954
+ }
6955
+ }
6956
+ return lineValue;
6957
+ }
6958
+
6959
+ module.exports = function(Chart) {
6960
+
6961
+ function computeTextSize(context, tick, font) {
6962
+ return helpers.isArray(tick) ?
6963
+ helpers.longestText(context, font, tick) :
6964
+ context.measureText(tick).width;
6965
+ }
6966
+
6967
+ function parseFontOptions(options) {
6968
+ var valueOrDefault = helpers.valueOrDefault;
6969
+ var globalDefaults = defaults.global;
6970
+ var size = valueOrDefault(options.fontSize, globalDefaults.defaultFontSize);
6971
+ var style = valueOrDefault(options.fontStyle, globalDefaults.defaultFontStyle);
6972
+ var family = valueOrDefault(options.fontFamily, globalDefaults.defaultFontFamily);
6973
+
6974
+ return {
6975
+ size: size,
6976
+ style: style,
6977
+ family: family,
6978
+ font: helpers.fontString(size, style, family)
6979
+ };
6980
+ }
6981
+
6982
+ function parseLineHeight(options) {
6983
+ return helpers.options.toLineHeight(
6984
+ helpers.valueOrDefault(options.lineHeight, 1.2),
6985
+ helpers.valueOrDefault(options.fontSize, defaults.global.defaultFontSize));
6986
+ }
6987
+
6988
+ Chart.Scale = Element.extend({
6989
+ /**
6990
+ * Get the padding needed for the scale
6991
+ * @method getPadding
6992
+ * @private
6993
+ * @returns {Padding} the necessary padding
6994
+ */
6995
+ getPadding: function() {
6996
+ var me = this;
6997
+ return {
6998
+ left: me.paddingLeft || 0,
6999
+ top: me.paddingTop || 0,
7000
+ right: me.paddingRight || 0,
7001
+ bottom: me.paddingBottom || 0
7002
+ };
7003
+ },
7004
+
7005
+ /**
7006
+ * Returns the scale tick objects ({label, major})
7007
+ * @since 2.7
7008
+ */
7009
+ getTicks: function() {
7010
+ return this._ticks;
7011
+ },
7012
+
7013
+ // These methods are ordered by lifecyle. Utilities then follow.
7014
+ // Any function defined here is inherited by all scale types.
7015
+ // Any function can be extended by the scale type
7016
+
7017
+ mergeTicksOptions: function() {
7018
+ var ticks = this.options.ticks;
7019
+ if (ticks.minor === false) {
7020
+ ticks.minor = {
7021
+ display: false
7022
+ };
7023
+ }
7024
+ if (ticks.major === false) {
7025
+ ticks.major = {
7026
+ display: false
7027
+ };
7028
+ }
7029
+ for (var key in ticks) {
7030
+ if (key !== 'major' && key !== 'minor') {
7031
+ if (typeof ticks.minor[key] === 'undefined') {
7032
+ ticks.minor[key] = ticks[key];
7033
+ }
7034
+ if (typeof ticks.major[key] === 'undefined') {
7035
+ ticks.major[key] = ticks[key];
7036
+ }
7037
+ }
7038
+ }
7039
+ },
7040
+ beforeUpdate: function() {
7041
+ helpers.callback(this.options.beforeUpdate, [this]);
7042
+ },
7043
+ update: function(maxWidth, maxHeight, margins) {
7044
+ var me = this;
7045
+ var i, ilen, labels, label, ticks, tick;
7046
+
7047
+ // Update Lifecycle - Probably don't want to ever extend or overwrite this function ;)
7048
+ me.beforeUpdate();
7049
+
7050
+ // Absorb the master measurements
7051
+ me.maxWidth = maxWidth;
7052
+ me.maxHeight = maxHeight;
7053
+ me.margins = helpers.extend({
7054
+ left: 0,
7055
+ right: 0,
7056
+ top: 0,
7057
+ bottom: 0
7058
+ }, margins);
7059
+ me.longestTextCache = me.longestTextCache || {};
7060
+
7061
+ // Dimensions
7062
+ me.beforeSetDimensions();
7063
+ me.setDimensions();
7064
+ me.afterSetDimensions();
7065
+
7066
+ // Data min/max
7067
+ me.beforeDataLimits();
7068
+ me.determineDataLimits();
7069
+ me.afterDataLimits();
7070
+
7071
+ // Ticks - `this.ticks` is now DEPRECATED!
7072
+ // Internal ticks are now stored as objects in the PRIVATE `this._ticks` member
7073
+ // and must not be accessed directly from outside this class. `this.ticks` being
7074
+ // around for long time and not marked as private, we can't change its structure
7075
+ // without unexpected breaking changes. If you need to access the scale ticks,
7076
+ // use scale.getTicks() instead.
7077
+
7078
+ me.beforeBuildTicks();
7079
+
7080
+ // New implementations should return an array of objects but for BACKWARD COMPAT,
7081
+ // we still support no return (`this.ticks` internally set by calling this method).
7082
+ ticks = me.buildTicks() || [];
7083
+
7084
+ me.afterBuildTicks();
7085
+
7086
+ me.beforeTickToLabelConversion();
7087
+
7088
+ // New implementations should return the formatted tick labels but for BACKWARD
7089
+ // COMPAT, we still support no return (`this.ticks` internally changed by calling
7090
+ // this method and supposed to contain only string values).
7091
+ labels = me.convertTicksToLabels(ticks) || me.ticks;
7092
+
7093
+ me.afterTickToLabelConversion();
7094
+
7095
+ me.ticks = labels; // BACKWARD COMPATIBILITY
7096
+
7097
+ // IMPORTANT: from this point, we consider that `this.ticks` will NEVER change!
7098
+
7099
+ // BACKWARD COMPAT: synchronize `_ticks` with labels (so potentially `this.ticks`)
7100
+ for (i = 0, ilen = labels.length; i < ilen; ++i) {
7101
+ label = labels[i];
7102
+ tick = ticks[i];
7103
+ if (!tick) {
7104
+ ticks.push(tick = {
7105
+ label: label,
7106
+ major: false
7107
+ });
7108
+ } else {
7109
+ tick.label = label;
7110
+ }
7111
+ }
7112
+
7113
+ me._ticks = ticks;
7114
+
7115
+ // Tick Rotation
7116
+ me.beforeCalculateTickRotation();
7117
+ me.calculateTickRotation();
7118
+ me.afterCalculateTickRotation();
7119
+ // Fit
7120
+ me.beforeFit();
7121
+ me.fit();
7122
+ me.afterFit();
7123
+ //
7124
+ me.afterUpdate();
7125
+
7126
+ return me.minSize;
7127
+
7128
+ },
7129
+ afterUpdate: function() {
7130
+ helpers.callback(this.options.afterUpdate, [this]);
7131
+ },
7132
+
7133
+ //
7134
+
7135
+ beforeSetDimensions: function() {
7136
+ helpers.callback(this.options.beforeSetDimensions, [this]);
7137
+ },
7138
+ setDimensions: function() {
7139
+ var me = this;
7140
+ // Set the unconstrained dimension before label rotation
7141
+ if (me.isHorizontal()) {
7142
+ // Reset position before calculating rotation
7143
+ me.width = me.maxWidth;
7144
+ me.left = 0;
7145
+ me.right = me.width;
7146
+ } else {
7147
+ me.height = me.maxHeight;
7148
+
7149
+ // Reset position before calculating rotation
7150
+ me.top = 0;
7151
+ me.bottom = me.height;
7152
+ }
7153
+
7154
+ // Reset padding
7155
+ me.paddingLeft = 0;
7156
+ me.paddingTop = 0;
7157
+ me.paddingRight = 0;
7158
+ me.paddingBottom = 0;
7159
+ },
7160
+ afterSetDimensions: function() {
7161
+ helpers.callback(this.options.afterSetDimensions, [this]);
7162
+ },
7163
+
7164
+ // Data limits
7165
+ beforeDataLimits: function() {
7166
+ helpers.callback(this.options.beforeDataLimits, [this]);
7167
+ },
7168
+ determineDataLimits: helpers.noop,
7169
+ afterDataLimits: function() {
7170
+ helpers.callback(this.options.afterDataLimits, [this]);
7171
+ },
7172
+
7173
+ //
7174
+ beforeBuildTicks: function() {
7175
+ helpers.callback(this.options.beforeBuildTicks, [this]);
7176
+ },
7177
+ buildTicks: helpers.noop,
7178
+ afterBuildTicks: function() {
7179
+ helpers.callback(this.options.afterBuildTicks, [this]);
7180
+ },
7181
+
7182
+ beforeTickToLabelConversion: function() {
7183
+ helpers.callback(this.options.beforeTickToLabelConversion, [this]);
7184
+ },
7185
+ convertTicksToLabels: function() {
7186
+ var me = this;
7187
+ // Convert ticks to strings
7188
+ var tickOpts = me.options.ticks;
7189
+ me.ticks = me.ticks.map(tickOpts.userCallback || tickOpts.callback, this);
7190
+ },
7191
+ afterTickToLabelConversion: function() {
7192
+ helpers.callback(this.options.afterTickToLabelConversion, [this]);
7193
+ },
7194
+
7195
+ //
7196
+
7197
+ beforeCalculateTickRotation: function() {
7198
+ helpers.callback(this.options.beforeCalculateTickRotation, [this]);
7199
+ },
7200
+ calculateTickRotation: function() {
7201
+ var me = this;
7202
+ var context = me.ctx;
7203
+ var tickOpts = me.options.ticks;
7204
+ var labels = labelsFromTicks(me._ticks);
7205
+
7206
+ // Get the width of each grid by calculating the difference
7207
+ // between x offsets between 0 and 1.
7208
+ var tickFont = parseFontOptions(tickOpts);
7209
+ context.font = tickFont.font;
7210
+
7211
+ var labelRotation = tickOpts.minRotation || 0;
7212
+
7213
+ if (labels.length && me.options.display && me.isHorizontal()) {
7214
+ var originalLabelWidth = helpers.longestText(context, tickFont.font, labels, me.longestTextCache);
7215
+ var labelWidth = originalLabelWidth;
7216
+ var cosRotation, sinRotation;
7217
+
7218
+ // Allow 3 pixels x2 padding either side for label readability
7219
+ var tickWidth = me.getPixelForTick(1) - me.getPixelForTick(0) - 6;
7220
+
7221
+ // Max label rotation can be set or default to 90 - also act as a loop counter
7222
+ while (labelWidth > tickWidth && labelRotation < tickOpts.maxRotation) {
7223
+ var angleRadians = helpers.toRadians(labelRotation);
7224
+ cosRotation = Math.cos(angleRadians);
7225
+ sinRotation = Math.sin(angleRadians);
7226
+
7227
+ if (sinRotation * originalLabelWidth > me.maxHeight) {
7228
+ // go back one step
7229
+ labelRotation--;
7230
+ break;
7231
+ }
7232
+
7233
+ labelRotation++;
7234
+ labelWidth = cosRotation * originalLabelWidth;
7235
+ }
7236
+ }
7237
+
7238
+ me.labelRotation = labelRotation;
7239
+ },
7240
+ afterCalculateTickRotation: function() {
7241
+ helpers.callback(this.options.afterCalculateTickRotation, [this]);
7242
+ },
7243
+
7244
+ //
7245
+
7246
+ beforeFit: function() {
7247
+ helpers.callback(this.options.beforeFit, [this]);
7248
+ },
7249
+ fit: function() {
7250
+ var me = this;
7251
+ // Reset
7252
+ var minSize = me.minSize = {
7253
+ width: 0,
7254
+ height: 0
7255
+ };
7256
+
7257
+ var labels = labelsFromTicks(me._ticks);
7258
+
7259
+ var opts = me.options;
7260
+ var tickOpts = opts.ticks;
7261
+ var scaleLabelOpts = opts.scaleLabel;
7262
+ var gridLineOpts = opts.gridLines;
7263
+ var display = opts.display;
7264
+ var isHorizontal = me.isHorizontal();
7265
+
7266
+ var tickFont = parseFontOptions(tickOpts);
7267
+ var tickMarkLength = opts.gridLines.tickMarkLength;
7268
+
7269
+ // Width
7270
+ if (isHorizontal) {
7271
+ // subtract the margins to line up with the chartArea if we are a full width scale
7272
+ minSize.width = me.isFullWidth() ? me.maxWidth - me.margins.left - me.margins.right : me.maxWidth;
7273
+ } else {
7274
+ minSize.width = display && gridLineOpts.drawTicks ? tickMarkLength : 0;
7275
+ }
7276
+
7277
+ // height
7278
+ if (isHorizontal) {
7279
+ minSize.height = display && gridLineOpts.drawTicks ? tickMarkLength : 0;
7280
+ } else {
7281
+ minSize.height = me.maxHeight; // fill all the height
7282
+ }
7283
+
7284
+ // Are we showing a title for the scale?
7285
+ if (scaleLabelOpts.display && display) {
7286
+ var scaleLabelLineHeight = parseLineHeight(scaleLabelOpts);
7287
+ var scaleLabelPadding = helpers.options.toPadding(scaleLabelOpts.padding);
7288
+ var deltaHeight = scaleLabelLineHeight + scaleLabelPadding.height;
7289
+
7290
+ if (isHorizontal) {
7291
+ minSize.height += deltaHeight;
7292
+ } else {
7293
+ minSize.width += deltaHeight;
7294
+ }
7295
+ }
7296
+
7297
+ // Don't bother fitting the ticks if we are not showing them
7298
+ if (tickOpts.display && display) {
7299
+ var largestTextWidth = helpers.longestText(me.ctx, tickFont.font, labels, me.longestTextCache);
7300
+ var tallestLabelHeightInLines = helpers.numberOfLabelLines(labels);
7301
+ var lineSpace = tickFont.size * 0.5;
7302
+ var tickPadding = me.options.ticks.padding;
7303
+
7304
+ if (isHorizontal) {
7305
+ // A horizontal axis is more constrained by the height.
7306
+ me.longestLabelWidth = largestTextWidth;
7307
+
7308
+ var angleRadians = helpers.toRadians(me.labelRotation);
7309
+ var cosRotation = Math.cos(angleRadians);
7310
+ var sinRotation = Math.sin(angleRadians);
7311
+
7312
+ // TODO - improve this calculation
7313
+ var labelHeight = (sinRotation * largestTextWidth)
7314
+ + (tickFont.size * tallestLabelHeightInLines)
7315
+ + (lineSpace * (tallestLabelHeightInLines - 1))
7316
+ + lineSpace; // padding
7317
+
7318
+ minSize.height = Math.min(me.maxHeight, minSize.height + labelHeight + tickPadding);
7319
+
7320
+ me.ctx.font = tickFont.font;
7321
+ var firstLabelWidth = computeTextSize(me.ctx, labels[0], tickFont.font);
7322
+ var lastLabelWidth = computeTextSize(me.ctx, labels[labels.length - 1], tickFont.font);
7323
+
7324
+ // Ensure that our ticks are always inside the canvas. When rotated, ticks are right aligned
7325
+ // which means that the right padding is dominated by the font height
7326
+ if (me.labelRotation !== 0) {
7327
+ me.paddingLeft = opts.position === 'bottom' ? (cosRotation * firstLabelWidth) + 3 : (cosRotation * lineSpace) + 3; // add 3 px to move away from canvas edges
7328
+ me.paddingRight = opts.position === 'bottom' ? (cosRotation * lineSpace) + 3 : (cosRotation * lastLabelWidth) + 3;
7329
+ } else {
7330
+ me.paddingLeft = firstLabelWidth / 2 + 3; // add 3 px to move away from canvas edges
7331
+ me.paddingRight = lastLabelWidth / 2 + 3;
7332
+ }
7333
+ } else {
7334
+ // A vertical axis is more constrained by the width. Labels are the
7335
+ // dominant factor here, so get that length first and account for padding
7336
+ if (tickOpts.mirror) {
7337
+ largestTextWidth = 0;
7338
+ } else {
7339
+ // use lineSpace for consistency with horizontal axis
7340
+ // tickPadding is not implemented for horizontal
7341
+ largestTextWidth += tickPadding + lineSpace;
7342
+ }
7343
+
7344
+ minSize.width = Math.min(me.maxWidth, minSize.width + largestTextWidth);
7345
+
7346
+ me.paddingTop = tickFont.size / 2;
7347
+ me.paddingBottom = tickFont.size / 2;
7348
+ }
7349
+ }
7350
+
7351
+ me.handleMargins();
7352
+
7353
+ me.width = minSize.width;
7354
+ me.height = minSize.height;
7355
+ },
7356
+
7357
+ /**
7358
+ * Handle margins and padding interactions
7359
+ * @private
7360
+ */
7361
+ handleMargins: function() {
7362
+ var me = this;
7363
+ if (me.margins) {
7364
+ me.paddingLeft = Math.max(me.paddingLeft - me.margins.left, 0);
7365
+ me.paddingTop = Math.max(me.paddingTop - me.margins.top, 0);
7366
+ me.paddingRight = Math.max(me.paddingRight - me.margins.right, 0);
7367
+ me.paddingBottom = Math.max(me.paddingBottom - me.margins.bottom, 0);
7368
+ }
7369
+ },
7370
+
7371
+ afterFit: function() {
7372
+ helpers.callback(this.options.afterFit, [this]);
7373
+ },
7374
+
7375
+ // Shared Methods
7376
+ isHorizontal: function() {
7377
+ return this.options.position === 'top' || this.options.position === 'bottom';
7378
+ },
7379
+ isFullWidth: function() {
7380
+ return (this.options.fullWidth);
7381
+ },
7382
+
7383
+ // Get the correct value. NaN bad inputs, If the value type is object get the x or y based on whether we are horizontal or not
7384
+ getRightValue: function(rawValue) {
7385
+ // Null and undefined values first
7386
+ if (helpers.isNullOrUndef(rawValue)) {
7387
+ return NaN;
7388
+ }
7389
+ // isNaN(object) returns true, so make sure NaN is checking for a number; Discard Infinite values
7390
+ if (typeof rawValue === 'number' && !isFinite(rawValue)) {
7391
+ return NaN;
7392
+ }
7393
+ // If it is in fact an object, dive in one more level
7394
+ if (rawValue) {
7395
+ if (this.isHorizontal()) {
7396
+ if (rawValue.x !== undefined) {
7397
+ return this.getRightValue(rawValue.x);
7398
+ }
7399
+ } else if (rawValue.y !== undefined) {
7400
+ return this.getRightValue(rawValue.y);
7401
+ }
7402
+ }
7403
+
7404
+ // Value is good, return it
7405
+ return rawValue;
7406
+ },
7407
+
7408
+ /**
7409
+ * Used to get the value to display in the tooltip for the data at the given index
7410
+ * @param index
7411
+ * @param datasetIndex
7412
+ */
7413
+ getLabelForIndex: helpers.noop,
7414
+
7415
+ /**
7416
+ * Returns the location of the given data point. Value can either be an index or a numerical value
7417
+ * The coordinate (0, 0) is at the upper-left corner of the canvas
7418
+ * @param value
7419
+ * @param index
7420
+ * @param datasetIndex
7421
+ */
7422
+ getPixelForValue: helpers.noop,
7423
+
7424
+ /**
7425
+ * Used to get the data value from a given pixel. This is the inverse of getPixelForValue
7426
+ * The coordinate (0, 0) is at the upper-left corner of the canvas
7427
+ * @param pixel
7428
+ */
7429
+ getValueForPixel: helpers.noop,
7430
+
7431
+ /**
7432
+ * Returns the location of the tick at the given index
7433
+ * The coordinate (0, 0) is at the upper-left corner of the canvas
7434
+ */
7435
+ getPixelForTick: function(index) {
7436
+ var me = this;
7437
+ var offset = me.options.offset;
7438
+ if (me.isHorizontal()) {
7439
+ var innerWidth = me.width - (me.paddingLeft + me.paddingRight);
7440
+ var tickWidth = innerWidth / Math.max((me._ticks.length - (offset ? 0 : 1)), 1);
7441
+ var pixel = (tickWidth * index) + me.paddingLeft;
7442
+
7443
+ if (offset) {
7444
+ pixel += tickWidth / 2;
7445
+ }
7446
+
7447
+ var finalVal = me.left + Math.round(pixel);
7448
+ finalVal += me.isFullWidth() ? me.margins.left : 0;
7449
+ return finalVal;
7450
+ }
7451
+ var innerHeight = me.height - (me.paddingTop + me.paddingBottom);
7452
+ return me.top + (index * (innerHeight / (me._ticks.length - 1)));
7453
+ },
7454
+
7455
+ /**
7456
+ * Utility for getting the pixel location of a percentage of scale
7457
+ * The coordinate (0, 0) is at the upper-left corner of the canvas
7458
+ */
7459
+ getPixelForDecimal: function(decimal) {
7460
+ var me = this;
7461
+ if (me.isHorizontal()) {
7462
+ var innerWidth = me.width - (me.paddingLeft + me.paddingRight);
7463
+ var valueOffset = (innerWidth * decimal) + me.paddingLeft;
7464
+
7465
+ var finalVal = me.left + Math.round(valueOffset);
7466
+ finalVal += me.isFullWidth() ? me.margins.left : 0;
7467
+ return finalVal;
7468
+ }
7469
+ return me.top + (decimal * me.height);
7470
+ },
7471
+
7472
+ /**
7473
+ * Returns the pixel for the minimum chart value
7474
+ * The coordinate (0, 0) is at the upper-left corner of the canvas
7475
+ */
7476
+ getBasePixel: function() {
7477
+ return this.getPixelForValue(this.getBaseValue());
7478
+ },
7479
+
7480
+ getBaseValue: function() {
7481
+ var me = this;
7482
+ var min = me.min;
7483
+ var max = me.max;
7484
+
7485
+ return me.beginAtZero ? 0 :
7486
+ min < 0 && max < 0 ? max :
7487
+ min > 0 && max > 0 ? min :
7488
+ 0;
7489
+ },
7490
+
7491
+ /**
7492
+ * Returns a subset of ticks to be plotted to avoid overlapping labels.
7493
+ * @private
7494
+ */
7495
+ _autoSkip: function(ticks) {
7496
+ var skipRatio;
7497
+ var me = this;
7498
+ var isHorizontal = me.isHorizontal();
7499
+ var optionTicks = me.options.ticks.minor;
7500
+ var tickCount = ticks.length;
7501
+ var labelRotationRadians = helpers.toRadians(me.labelRotation);
7502
+ var cosRotation = Math.cos(labelRotationRadians);
7503
+ var longestRotatedLabel = me.longestLabelWidth * cosRotation;
7504
+ var result = [];
7505
+ var i, tick, shouldSkip;
7506
+
7507
+ // figure out the maximum number of gridlines to show
7508
+ var maxTicks;
7509
+ if (optionTicks.maxTicksLimit) {
7510
+ maxTicks = optionTicks.maxTicksLimit;
7511
+ }
7512
+
7513
+ if (isHorizontal) {
7514
+ skipRatio = false;
7515
+
7516
+ if ((longestRotatedLabel + optionTicks.autoSkipPadding) * tickCount > (me.width - (me.paddingLeft + me.paddingRight))) {
7517
+ skipRatio = 1 + Math.floor(((longestRotatedLabel + optionTicks.autoSkipPadding) * tickCount) / (me.width - (me.paddingLeft + me.paddingRight)));
7518
+ }
7519
+
7520
+ // if they defined a max number of optionTicks,
7521
+ // increase skipRatio until that number is met
7522
+ if (maxTicks && tickCount > maxTicks) {
7523
+ skipRatio = Math.max(skipRatio, Math.floor(tickCount / maxTicks));
7524
+ }
7525
+ }
7526
+
7527
+ for (i = 0; i < tickCount; i++) {
7528
+ tick = ticks[i];
7529
+
7530
+ // Since we always show the last tick,we need may need to hide the last shown one before
7531
+ shouldSkip = (skipRatio > 1 && i % skipRatio > 0) || (i % skipRatio === 0 && i + skipRatio >= tickCount);
7532
+ if (shouldSkip && i !== tickCount - 1) {
7533
+ // leave tick in place but make sure it's not displayed (#4635)
7534
+ delete tick.label;
7535
+ }
7536
+ result.push(tick);
7537
+ }
7538
+ return result;
7539
+ },
7540
+
7541
+ // Actually draw the scale on the canvas
7542
+ // @param {rectangle} chartArea : the area of the chart to draw full grid lines on
7543
+ draw: function(chartArea) {
7544
+ var me = this;
7545
+ var options = me.options;
7546
+ if (!options.display) {
7547
+ return;
7548
+ }
7549
+
7550
+ var context = me.ctx;
7551
+ var globalDefaults = defaults.global;
7552
+ var optionTicks = options.ticks.minor;
7553
+ var optionMajorTicks = options.ticks.major || optionTicks;
7554
+ var gridLines = options.gridLines;
7555
+ var scaleLabel = options.scaleLabel;
7556
+
7557
+ var isRotated = me.labelRotation !== 0;
7558
+ var isHorizontal = me.isHorizontal();
7559
+
7560
+ var ticks = optionTicks.autoSkip ? me._autoSkip(me.getTicks()) : me.getTicks();
7561
+ var tickFontColor = helpers.valueOrDefault(optionTicks.fontColor, globalDefaults.defaultFontColor);
7562
+ var tickFont = parseFontOptions(optionTicks);
7563
+ var majorTickFontColor = helpers.valueOrDefault(optionMajorTicks.fontColor, globalDefaults.defaultFontColor);
7564
+ var majorTickFont = parseFontOptions(optionMajorTicks);
7565
+
7566
+ var tl = gridLines.drawTicks ? gridLines.tickMarkLength : 0;
7567
+
7568
+ var scaleLabelFontColor = helpers.valueOrDefault(scaleLabel.fontColor, globalDefaults.defaultFontColor);
7569
+ var scaleLabelFont = parseFontOptions(scaleLabel);
7570
+ var scaleLabelPadding = helpers.options.toPadding(scaleLabel.padding);
7571
+ var labelRotationRadians = helpers.toRadians(me.labelRotation);
7572
+
7573
+ var itemsToDraw = [];
7574
+
7575
+ var xTickStart = options.position === 'right' ? me.left : me.right - tl;
7576
+ var xTickEnd = options.position === 'right' ? me.left + tl : me.right;
7577
+ var yTickStart = options.position === 'bottom' ? me.top : me.bottom - tl;
7578
+ var yTickEnd = options.position === 'bottom' ? me.top + tl : me.bottom;
7579
+
7580
+ helpers.each(ticks, function(tick, index) {
7581
+ // autoskipper skipped this tick (#4635)
7582
+ if (helpers.isNullOrUndef(tick.label)) {
7583
+ return;
7584
+ }
7585
+
7586
+ var label = tick.label;
7587
+ var lineWidth, lineColor, borderDash, borderDashOffset;
7588
+ if (index === me.zeroLineIndex && options.offset === gridLines.offsetGridLines) {
7589
+ // Draw the first index specially
7590
+ lineWidth = gridLines.zeroLineWidth;
7591
+ lineColor = gridLines.zeroLineColor;
7592
+ borderDash = gridLines.zeroLineBorderDash;
7593
+ borderDashOffset = gridLines.zeroLineBorderDashOffset;
7594
+ } else {
7595
+ lineWidth = helpers.valueAtIndexOrDefault(gridLines.lineWidth, index);
7596
+ lineColor = helpers.valueAtIndexOrDefault(gridLines.color, index);
7597
+ borderDash = helpers.valueOrDefault(gridLines.borderDash, globalDefaults.borderDash);
7598
+ borderDashOffset = helpers.valueOrDefault(gridLines.borderDashOffset, globalDefaults.borderDashOffset);
7599
+ }
7600
+
7601
+ // Common properties
7602
+ var tx1, ty1, tx2, ty2, x1, y1, x2, y2, labelX, labelY;
7603
+ var textAlign = 'middle';
7604
+ var textBaseline = 'middle';
7605
+ var tickPadding = optionTicks.padding;
7606
+
7607
+ if (isHorizontal) {
7608
+ var labelYOffset = tl + tickPadding;
7609
+
7610
+ if (options.position === 'bottom') {
7611
+ // bottom
7612
+ textBaseline = !isRotated ? 'top' : 'middle';
7613
+ textAlign = !isRotated ? 'center' : 'right';
7614
+ labelY = me.top + labelYOffset;
7615
+ } else {
7616
+ // top
7617
+ textBaseline = !isRotated ? 'bottom' : 'middle';
7618
+ textAlign = !isRotated ? 'center' : 'left';
7619
+ labelY = me.bottom - labelYOffset;
7620
+ }
7621
+
7622
+ var xLineValue = getLineValue(me, index, gridLines.offsetGridLines && ticks.length > 1);
7623
+ if (xLineValue < me.left) {
7624
+ lineColor = 'rgba(0,0,0,0)';
7625
+ }
7626
+ xLineValue += helpers.aliasPixel(lineWidth);
7627
+
7628
+ labelX = me.getPixelForTick(index) + optionTicks.labelOffset; // x values for optionTicks (need to consider offsetLabel option)
7629
+
7630
+ tx1 = tx2 = x1 = x2 = xLineValue;
7631
+ ty1 = yTickStart;
7632
+ ty2 = yTickEnd;
7633
+ y1 = chartArea.top;
7634
+ y2 = chartArea.bottom;
7635
+ } else {
7636
+ var isLeft = options.position === 'left';
7637
+ var labelXOffset;
7638
+
7639
+ if (optionTicks.mirror) {
7640
+ textAlign = isLeft ? 'left' : 'right';
7641
+ labelXOffset = tickPadding;
7642
+ } else {
7643
+ textAlign = isLeft ? 'right' : 'left';
7644
+ labelXOffset = tl + tickPadding;
7645
+ }
7646
+
7647
+ labelX = isLeft ? me.right - labelXOffset : me.left + labelXOffset;
7648
+
7649
+ var yLineValue = getLineValue(me, index, gridLines.offsetGridLines && ticks.length > 1);
7650
+ if (yLineValue < me.top) {
7651
+ lineColor = 'rgba(0,0,0,0)';
7652
+ }
7653
+ yLineValue += helpers.aliasPixel(lineWidth);
7654
+
7655
+ labelY = me.getPixelForTick(index) + optionTicks.labelOffset;
7656
+
7657
+ tx1 = xTickStart;
7658
+ tx2 = xTickEnd;
7659
+ x1 = chartArea.left;
7660
+ x2 = chartArea.right;
7661
+ ty1 = ty2 = y1 = y2 = yLineValue;
7662
+ }
7663
+
7664
+ itemsToDraw.push({
7665
+ tx1: tx1,
7666
+ ty1: ty1,
7667
+ tx2: tx2,
7668
+ ty2: ty2,
7669
+ x1: x1,
7670
+ y1: y1,
7671
+ x2: x2,
7672
+ y2: y2,
7673
+ labelX: labelX,
7674
+ labelY: labelY,
7675
+ glWidth: lineWidth,
7676
+ glColor: lineColor,
7677
+ glBorderDash: borderDash,
7678
+ glBorderDashOffset: borderDashOffset,
7679
+ rotation: -1 * labelRotationRadians,
7680
+ label: label,
7681
+ major: tick.major,
7682
+ textBaseline: textBaseline,
7683
+ textAlign: textAlign
7684
+ });
7685
+ });
7686
+
7687
+ // Draw all of the tick labels, tick marks, and grid lines at the correct places
7688
+ helpers.each(itemsToDraw, function(itemToDraw) {
7689
+ if (gridLines.display) {
7690
+ context.save();
7691
+ context.lineWidth = itemToDraw.glWidth;
7692
+ context.strokeStyle = itemToDraw.glColor;
7693
+ if (context.setLineDash) {
7694
+ context.setLineDash(itemToDraw.glBorderDash);
7695
+ context.lineDashOffset = itemToDraw.glBorderDashOffset;
7696
+ }
7697
+
7698
+ context.beginPath();
7699
+
7700
+ if (gridLines.drawTicks) {
7701
+ context.moveTo(itemToDraw.tx1, itemToDraw.ty1);
7702
+ context.lineTo(itemToDraw.tx2, itemToDraw.ty2);
7703
+ }
7704
+
7705
+ if (gridLines.drawOnChartArea) {
7706
+ context.moveTo(itemToDraw.x1, itemToDraw.y1);
7707
+ context.lineTo(itemToDraw.x2, itemToDraw.y2);
7708
+ }
7709
+
7710
+ context.stroke();
7711
+ context.restore();
7712
+ }
7713
+
7714
+ if (optionTicks.display) {
7715
+ // Make sure we draw text in the correct color and font
7716
+ context.save();
7717
+ context.translate(itemToDraw.labelX, itemToDraw.labelY);
7718
+ context.rotate(itemToDraw.rotation);
7719
+ context.font = itemToDraw.major ? majorTickFont.font : tickFont.font;
7720
+ context.fillStyle = itemToDraw.major ? majorTickFontColor : tickFontColor;
7721
+ context.textBaseline = itemToDraw.textBaseline;
7722
+ context.textAlign = itemToDraw.textAlign;
7723
+
7724
+ var label = itemToDraw.label;
7725
+ if (helpers.isArray(label)) {
7726
+ for (var i = 0, y = 0; i < label.length; ++i) {
7727
+ // We just make sure the multiline element is a string here..
7728
+ context.fillText('' + label[i], 0, y);
7729
+ // apply same lineSpacing as calculated @ L#320
7730
+ y += (tickFont.size * 1.5);
7731
+ }
7732
+ } else {
7733
+ context.fillText(label, 0, 0);
7734
+ }
7735
+ context.restore();
7736
+ }
7737
+ });
7738
+
7739
+ if (scaleLabel.display) {
7740
+ // Draw the scale label
7741
+ var scaleLabelX;
7742
+ var scaleLabelY;
7743
+ var rotation = 0;
7744
+ var halfLineHeight = parseLineHeight(scaleLabel) / 2;
7745
+
7746
+ if (isHorizontal) {
7747
+ scaleLabelX = me.left + ((me.right - me.left) / 2); // midpoint of the width
7748
+ scaleLabelY = options.position === 'bottom'
7749
+ ? me.bottom - halfLineHeight - scaleLabelPadding.bottom
7750
+ : me.top + halfLineHeight + scaleLabelPadding.top;
7751
+ } else {
7752
+ var isLeft = options.position === 'left';
7753
+ scaleLabelX = isLeft
7754
+ ? me.left + halfLineHeight + scaleLabelPadding.top
7755
+ : me.right - halfLineHeight - scaleLabelPadding.top;
7756
+ scaleLabelY = me.top + ((me.bottom - me.top) / 2);
7757
+ rotation = isLeft ? -0.5 * Math.PI : 0.5 * Math.PI;
7758
+ }
7759
+
7760
+ context.save();
7761
+ context.translate(scaleLabelX, scaleLabelY);
7762
+ context.rotate(rotation);
7763
+ context.textAlign = 'center';
7764
+ context.textBaseline = 'middle';
7765
+ context.fillStyle = scaleLabelFontColor; // render in correct colour
7766
+ context.font = scaleLabelFont.font;
7767
+ context.fillText(scaleLabel.labelString, 0, 0);
7768
+ context.restore();
7769
+ }
7770
+
7771
+ if (gridLines.drawBorder) {
7772
+ // Draw the line at the edge of the axis
7773
+ context.lineWidth = helpers.valueAtIndexOrDefault(gridLines.lineWidth, 0);
7774
+ context.strokeStyle = helpers.valueAtIndexOrDefault(gridLines.color, 0);
7775
+ var x1 = me.left;
7776
+ var x2 = me.right;
7777
+ var y1 = me.top;
7778
+ var y2 = me.bottom;
7779
+
7780
+ var aliasPixel = helpers.aliasPixel(context.lineWidth);
7781
+ if (isHorizontal) {
7782
+ y1 = y2 = options.position === 'top' ? me.bottom : me.top;
7783
+ y1 += aliasPixel;
7784
+ y2 += aliasPixel;
7785
+ } else {
7786
+ x1 = x2 = options.position === 'left' ? me.right : me.left;
7787
+ x1 += aliasPixel;
7788
+ x2 += aliasPixel;
7789
+ }
7790
+
7791
+ context.beginPath();
7792
+ context.moveTo(x1, y1);
7793
+ context.lineTo(x2, y2);
7794
+ context.stroke();
7795
+ }
7796
+ }
7797
+ });
7798
+ };
7799
+
7800
+ },{"25":25,"26":26,"34":34,"45":45}],33:[function(require,module,exports){
7801
+ 'use strict';
7802
+
7803
+ var defaults = require(25);
7804
+ var helpers = require(45);
7805
+
7806
+ module.exports = function(Chart) {
7807
+
7808
+ Chart.scaleService = {
7809
+ // Scale registration object. Extensions can register new scale types (such as log or DB scales) and then
7810
+ // use the new chart options to grab the correct scale
7811
+ constructors: {},
7812
+ // Use a registration function so that we can move to an ES6 map when we no longer need to support
7813
+ // old browsers
7814
+
7815
+ // Scale config defaults
7816
+ defaults: {},
7817
+ registerScaleType: function(type, scaleConstructor, scaleDefaults) {
7818
+ this.constructors[type] = scaleConstructor;
7819
+ this.defaults[type] = helpers.clone(scaleDefaults);
7820
+ },
7821
+ getScaleConstructor: function(type) {
7822
+ return this.constructors.hasOwnProperty(type) ? this.constructors[type] : undefined;
7823
+ },
7824
+ getScaleDefaults: function(type) {
7825
+ // Return the scale defaults merged with the global settings so that we always use the latest ones
7826
+ return this.defaults.hasOwnProperty(type) ? helpers.merge({}, [defaults.scale, this.defaults[type]]) : {};
7827
+ },
7828
+ updateScaleDefaults: function(type, additions) {
7829
+ var me = this;
7830
+ if (me.defaults.hasOwnProperty(type)) {
7831
+ me.defaults[type] = helpers.extend(me.defaults[type], additions);
7832
+ }
7833
+ },
7834
+ addScalesToLayout: function(chart) {
7835
+ // Adds each scale to the chart.boxes array to be sized accordingly
7836
+ helpers.each(chart.scales, function(scale) {
7837
+ // Set ILayoutItem parameters for backwards compatibility
7838
+ scale.fullWidth = scale.options.fullWidth;
7839
+ scale.position = scale.options.position;
7840
+ scale.weight = scale.options.weight;
7841
+ Chart.layoutService.addBox(chart, scale);
7842
+ });
7843
+ }
7844
+ };
7845
+ };
7846
+
7847
+ },{"25":25,"45":45}],34:[function(require,module,exports){
7848
+ 'use strict';
7849
+
7850
+ var helpers = require(45);
7851
+
7852
+ /**
7853
+ * Namespace to hold static tick generation functions
7854
+ * @namespace Chart.Ticks
7855
+ */
7856
+ module.exports = {
7857
+ /**
7858
+ * Namespace to hold generators for different types of ticks
7859
+ * @namespace Chart.Ticks.generators
7860
+ */
7861
+ generators: {
7862
+ /**
7863
+ * Interface for the options provided to the numeric tick generator
7864
+ * @interface INumericTickGenerationOptions
7865
+ */
7866
+ /**
7867
+ * The maximum number of ticks to display
7868
+ * @name INumericTickGenerationOptions#maxTicks
7869
+ * @type Number
7870
+ */
7871
+ /**
7872
+ * The distance between each tick.
7873
+ * @name INumericTickGenerationOptions#stepSize
7874
+ * @type Number
7875
+ * @optional
7876
+ */
7877
+ /**
7878
+ * Forced minimum for the ticks. If not specified, the minimum of the data range is used to calculate the tick minimum
7879
+ * @name INumericTickGenerationOptions#min
7880
+ * @type Number
7881
+ * @optional
7882
+ */
7883
+ /**
7884
+ * The maximum value of the ticks. If not specified, the maximum of the data range is used to calculate the tick maximum
7885
+ * @name INumericTickGenerationOptions#max
7886
+ * @type Number
7887
+ * @optional
7888
+ */
7889
+
7890
+ /**
7891
+ * Generate a set of linear ticks
7892
+ * @method Chart.Ticks.generators.linear
7893
+ * @param generationOptions {INumericTickGenerationOptions} the options used to generate the ticks
7894
+ * @param dataRange {IRange} the range of the data
7895
+ * @returns {Array<Number>} array of tick values
7896
+ */
7897
+ linear: function(generationOptions, dataRange) {
7898
+ var ticks = [];
7899
+ // To get a "nice" value for the tick spacing, we will use the appropriately named
7900
+ // "nice number" algorithm. See http://stackoverflow.com/questions/8506881/nice-label-algorithm-for-charts-with-minimum-ticks
7901
+ // for details.
7902
+
7903
+ var spacing;
7904
+ if (generationOptions.stepSize && generationOptions.stepSize > 0) {
7905
+ spacing = generationOptions.stepSize;
7906
+ } else {
7907
+ var niceRange = helpers.niceNum(dataRange.max - dataRange.min, false);
7908
+ spacing = helpers.niceNum(niceRange / (generationOptions.maxTicks - 1), true);
7909
+ }
7910
+ var niceMin = Math.floor(dataRange.min / spacing) * spacing;
7911
+ var niceMax = Math.ceil(dataRange.max / spacing) * spacing;
7912
+
7913
+ // If min, max and stepSize is set and they make an evenly spaced scale use it.
7914
+ if (generationOptions.min && generationOptions.max && generationOptions.stepSize) {
7915
+ // If very close to our whole number, use it.
7916
+ if (helpers.almostWhole((generationOptions.max - generationOptions.min) / generationOptions.stepSize, spacing / 1000)) {
7917
+ niceMin = generationOptions.min;
7918
+ niceMax = generationOptions.max;
7919
+ }
7920
+ }
7921
+
7922
+ var numSpaces = (niceMax - niceMin) / spacing;
7923
+ // If very close to our rounded value, use it.
7924
+ if (helpers.almostEquals(numSpaces, Math.round(numSpaces), spacing / 1000)) {
7925
+ numSpaces = Math.round(numSpaces);
7926
+ } else {
7927
+ numSpaces = Math.ceil(numSpaces);
7928
+ }
7929
+
7930
+ // Put the values into the ticks array
7931
+ ticks.push(generationOptions.min !== undefined ? generationOptions.min : niceMin);
7932
+ for (var j = 1; j < numSpaces; ++j) {
7933
+ ticks.push(niceMin + (j * spacing));
7934
+ }
7935
+ ticks.push(generationOptions.max !== undefined ? generationOptions.max : niceMax);
7936
+
7937
+ return ticks;
7938
+ },
7939
+
7940
+ /**
7941
+ * Generate a set of logarithmic ticks
7942
+ * @method Chart.Ticks.generators.logarithmic
7943
+ * @param generationOptions {INumericTickGenerationOptions} the options used to generate the ticks
7944
+ * @param dataRange {IRange} the range of the data
7945
+ * @returns {Array<Number>} array of tick values
7946
+ */
7947
+ logarithmic: function(generationOptions, dataRange) {
7948
+ var ticks = [];
7949
+ var valueOrDefault = helpers.valueOrDefault;
7950
+
7951
+ // Figure out what the max number of ticks we can support it is based on the size of
7952
+ // the axis area. For now, we say that the minimum tick spacing in pixels must be 50
7953
+ // We also limit the maximum number of ticks to 11 which gives a nice 10 squares on
7954
+ // the graph
7955
+ var tickVal = valueOrDefault(generationOptions.min, Math.pow(10, Math.floor(helpers.log10(dataRange.min))));
7956
+
7957
+ var endExp = Math.floor(helpers.log10(dataRange.max));
7958
+ var endSignificand = Math.ceil(dataRange.max / Math.pow(10, endExp));
7959
+ var exp, significand;
7960
+
7961
+ if (tickVal === 0) {
7962
+ exp = Math.floor(helpers.log10(dataRange.minNotZero));
7963
+ significand = Math.floor(dataRange.minNotZero / Math.pow(10, exp));
7964
+
7965
+ ticks.push(tickVal);
7966
+ tickVal = significand * Math.pow(10, exp);
7967
+ } else {
7968
+ exp = Math.floor(helpers.log10(tickVal));
7969
+ significand = Math.floor(tickVal / Math.pow(10, exp));
7970
+ }
7971
+
7972
+ do {
7973
+ ticks.push(tickVal);
7974
+
7975
+ ++significand;
7976
+ if (significand === 10) {
7977
+ significand = 1;
7978
+ ++exp;
7979
+ }
7980
+
7981
+ tickVal = significand * Math.pow(10, exp);
7982
+ } while (exp < endExp || (exp === endExp && significand < endSignificand));
7983
+
7984
+ var lastTick = valueOrDefault(generationOptions.max, tickVal);
7985
+ ticks.push(lastTick);
7986
+
7987
+ return ticks;
7988
+ }
7989
+ },
7990
+
7991
+ /**
7992
+ * Namespace to hold formatters for different types of ticks
7993
+ * @namespace Chart.Ticks.formatters
7994
+ */
7995
+ formatters: {
7996
+ /**
7997
+ * Formatter for value labels
7998
+ * @method Chart.Ticks.formatters.values
7999
+ * @param value the value to display
8000
+ * @return {String|Array} the label to display
8001
+ */
8002
+ values: function(value) {
8003
+ return helpers.isArray(value) ? value : '' + value;
8004
+ },
8005
+
8006
+ /**
8007
+ * Formatter for linear numeric ticks
8008
+ * @method Chart.Ticks.formatters.linear
8009
+ * @param tickValue {Number} the value to be formatted
8010
+ * @param index {Number} the position of the tickValue parameter in the ticks array
8011
+ * @param ticks {Array<Number>} the list of ticks being converted
8012
+ * @return {String} string representation of the tickValue parameter
8013
+ */
8014
+ linear: function(tickValue, index, ticks) {
8015
+ // If we have lots of ticks, don't use the ones
8016
+ var delta = ticks.length > 3 ? ticks[2] - ticks[1] : ticks[1] - ticks[0];
8017
+
8018
+ // If we have a number like 2.5 as the delta, figure out how many decimal places we need
8019
+ if (Math.abs(delta) > 1) {
8020
+ if (tickValue !== Math.floor(tickValue)) {
8021
+ // not an integer
8022
+ delta = tickValue - Math.floor(tickValue);
8023
+ }
8024
+ }
8025
+
8026
+ var logDelta = helpers.log10(Math.abs(delta));
8027
+ var tickString = '';
8028
+
8029
+ if (tickValue !== 0) {
8030
+ var numDecimal = -1 * Math.floor(logDelta);
8031
+ numDecimal = Math.max(Math.min(numDecimal, 20), 0); // toFixed has a max of 20 decimal places
8032
+ tickString = tickValue.toFixed(numDecimal);
8033
+ } else {
8034
+ tickString = '0'; // never show decimal places for 0
8035
+ }
8036
+
8037
+ return tickString;
8038
+ },
8039
+
8040
+ logarithmic: function(tickValue, index, ticks) {
8041
+ var remain = tickValue / (Math.pow(10, Math.floor(helpers.log10(tickValue))));
8042
+
8043
+ if (tickValue === 0) {
8044
+ return '0';
8045
+ } else if (remain === 1 || remain === 2 || remain === 5 || index === 0 || index === ticks.length - 1) {
8046
+ return tickValue.toExponential();
8047
+ }
8048
+ return '';
8049
+ }
8050
+ }
8051
+ };
8052
+
8053
+ },{"45":45}],35:[function(require,module,exports){
8054
+ 'use strict';
8055
+
8056
+ var defaults = require(25);
8057
+ var Element = require(26);
8058
+ var helpers = require(45);
8059
+
8060
+ defaults._set('global', {
8061
+ tooltips: {
8062
+ enabled: true,
8063
+ custom: null,
8064
+ mode: 'nearest',
8065
+ position: 'average',
8066
+ intersect: true,
8067
+ backgroundColor: 'rgba(0,0,0,0.8)',
8068
+ titleFontStyle: 'bold',
8069
+ titleSpacing: 2,
8070
+ titleMarginBottom: 6,
8071
+ titleFontColor: '#fff',
8072
+ titleAlign: 'left',
8073
+ bodySpacing: 2,
8074
+ bodyFontColor: '#fff',
8075
+ bodyAlign: 'left',
8076
+ footerFontStyle: 'bold',
8077
+ footerSpacing: 2,
8078
+ footerMarginTop: 6,
8079
+ footerFontColor: '#fff',
8080
+ footerAlign: 'left',
8081
+ yPadding: 6,
8082
+ xPadding: 6,
8083
+ caretPadding: 2,
8084
+ caretSize: 5,
8085
+ cornerRadius: 6,
8086
+ multiKeyBackground: '#fff',
8087
+ displayColors: true,
8088
+ borderColor: 'rgba(0,0,0,0)',
8089
+ borderWidth: 0,
8090
+ callbacks: {
8091
+ // Args are: (tooltipItems, data)
8092
+ beforeTitle: helpers.noop,
8093
+ title: function(tooltipItems, data) {
8094
+ // Pick first xLabel for now
8095
+ var title = '';
8096
+ var labels = data.labels;
8097
+ var labelCount = labels ? labels.length : 0;
8098
+
8099
+ if (tooltipItems.length > 0) {
8100
+ var item = tooltipItems[0];
8101
+
8102
+ if (item.xLabel) {
8103
+ title = item.xLabel;
8104
+ } else if (labelCount > 0 && item.index < labelCount) {
8105
+ title = labels[item.index];
8106
+ }
8107
+ }
8108
+
8109
+ return title;
8110
+ },
8111
+ afterTitle: helpers.noop,
8112
+
8113
+ // Args are: (tooltipItems, data)
8114
+ beforeBody: helpers.noop,
8115
+
8116
+ // Args are: (tooltipItem, data)
8117
+ beforeLabel: helpers.noop,
8118
+ label: function(tooltipItem, data) {
8119
+ var label = data.datasets[tooltipItem.datasetIndex].label || '';
8120
+
8121
+ if (label) {
8122
+ label += ': ';
8123
+ }
8124
+ label += tooltipItem.yLabel;
8125
+ return label;
8126
+ },
8127
+ labelColor: function(tooltipItem, chart) {
8128
+ var meta = chart.getDatasetMeta(tooltipItem.datasetIndex);
8129
+ var activeElement = meta.data[tooltipItem.index];
8130
+ var view = activeElement._view;
8131
+ return {
8132
+ borderColor: view.borderColor,
8133
+ backgroundColor: view.backgroundColor
8134
+ };
8135
+ },
8136
+ labelTextColor: function() {
8137
+ return this._options.bodyFontColor;
8138
+ },
8139
+ afterLabel: helpers.noop,
8140
+
8141
+ // Args are: (tooltipItems, data)
8142
+ afterBody: helpers.noop,
8143
+
8144
+ // Args are: (tooltipItems, data)
8145
+ beforeFooter: helpers.noop,
8146
+ footer: helpers.noop,
8147
+ afterFooter: helpers.noop
8148
+ }
8149
+ }
8150
+ });
8151
+
8152
+ module.exports = function(Chart) {
8153
+
8154
+ /**
8155
+ * Helper method to merge the opacity into a color
8156
+ */
8157
+ function mergeOpacity(colorString, opacity) {
8158
+ var color = helpers.color(colorString);
8159
+ return color.alpha(opacity * color.alpha()).rgbaString();
8160
+ }
8161
+
8162
+ // Helper to push or concat based on if the 2nd parameter is an array or not
8163
+ function pushOrConcat(base, toPush) {
8164
+ if (toPush) {
8165
+ if (helpers.isArray(toPush)) {
8166
+ // base = base.concat(toPush);
8167
+ Array.prototype.push.apply(base, toPush);
8168
+ } else {
8169
+ base.push(toPush);
8170
+ }
8171
+ }
8172
+
8173
+ return base;
8174
+ }
8175
+
8176
+ // Private helper to create a tooltip item model
8177
+ // @param element : the chart element (point, arc, bar) to create the tooltip item for
8178
+ // @return : new tooltip item
8179
+ function createTooltipItem(element) {
8180
+ var xScale = element._xScale;
8181
+ var yScale = element._yScale || element._scale; // handle radar || polarArea charts
8182
+ var index = element._index;
8183
+ var datasetIndex = element._datasetIndex;
8184
+
8185
+ return {
8186
+ xLabel: xScale ? xScale.getLabelForIndex(index, datasetIndex) : '',
8187
+ yLabel: yScale ? yScale.getLabelForIndex(index, datasetIndex) : '',
8188
+ index: index,
8189
+ datasetIndex: datasetIndex,
8190
+ x: element._model.x,
8191
+ y: element._model.y
8192
+ };
8193
+ }
8194
+
8195
+ /**
8196
+ * Helper to get the reset model for the tooltip
8197
+ * @param tooltipOpts {Object} the tooltip options
8198
+ */
8199
+ function getBaseModel(tooltipOpts) {
8200
+ var globalDefaults = defaults.global;
8201
+ var valueOrDefault = helpers.valueOrDefault;
8202
+
8203
+ return {
8204
+ // Positioning
8205
+ xPadding: tooltipOpts.xPadding,
8206
+ yPadding: tooltipOpts.yPadding,
8207
+ xAlign: tooltipOpts.xAlign,
8208
+ yAlign: tooltipOpts.yAlign,
8209
+
8210
+ // Body
8211
+ bodyFontColor: tooltipOpts.bodyFontColor,
8212
+ _bodyFontFamily: valueOrDefault(tooltipOpts.bodyFontFamily, globalDefaults.defaultFontFamily),
8213
+ _bodyFontStyle: valueOrDefault(tooltipOpts.bodyFontStyle, globalDefaults.defaultFontStyle),
8214
+ _bodyAlign: tooltipOpts.bodyAlign,
8215
+ bodyFontSize: valueOrDefault(tooltipOpts.bodyFontSize, globalDefaults.defaultFontSize),
8216
+ bodySpacing: tooltipOpts.bodySpacing,
8217
+
8218
+ // Title
8219
+ titleFontColor: tooltipOpts.titleFontColor,
8220
+ _titleFontFamily: valueOrDefault(tooltipOpts.titleFontFamily, globalDefaults.defaultFontFamily),
8221
+ _titleFontStyle: valueOrDefault(tooltipOpts.titleFontStyle, globalDefaults.defaultFontStyle),
8222
+ titleFontSize: valueOrDefault(tooltipOpts.titleFontSize, globalDefaults.defaultFontSize),
8223
+ _titleAlign: tooltipOpts.titleAlign,
8224
+ titleSpacing: tooltipOpts.titleSpacing,
8225
+ titleMarginBottom: tooltipOpts.titleMarginBottom,
8226
+
8227
+ // Footer
8228
+ footerFontColor: tooltipOpts.footerFontColor,
8229
+ _footerFontFamily: valueOrDefault(tooltipOpts.footerFontFamily, globalDefaults.defaultFontFamily),
8230
+ _footerFontStyle: valueOrDefault(tooltipOpts.footerFontStyle, globalDefaults.defaultFontStyle),
8231
+ footerFontSize: valueOrDefault(tooltipOpts.footerFontSize, globalDefaults.defaultFontSize),
8232
+ _footerAlign: tooltipOpts.footerAlign,
8233
+ footerSpacing: tooltipOpts.footerSpacing,
8234
+ footerMarginTop: tooltipOpts.footerMarginTop,
8235
+
8236
+ // Appearance
8237
+ caretSize: tooltipOpts.caretSize,
8238
+ cornerRadius: tooltipOpts.cornerRadius,
8239
+ backgroundColor: tooltipOpts.backgroundColor,
8240
+ opacity: 0,
8241
+ legendColorBackground: tooltipOpts.multiKeyBackground,
8242
+ displayColors: tooltipOpts.displayColors,
8243
+ borderColor: tooltipOpts.borderColor,
8244
+ borderWidth: tooltipOpts.borderWidth
8245
+ };
8246
+ }
8247
+
8248
+ /**
8249
+ * Get the size of the tooltip
8250
+ */
8251
+ function getTooltipSize(tooltip, model) {
8252
+ var ctx = tooltip._chart.ctx;
8253
+
8254
+ var height = model.yPadding * 2; // Tooltip Padding
8255
+ var width = 0;
8256
+
8257
+ // Count of all lines in the body
8258
+ var body = model.body;
8259
+ var combinedBodyLength = body.reduce(function(count, bodyItem) {
8260
+ return count + bodyItem.before.length + bodyItem.lines.length + bodyItem.after.length;
8261
+ }, 0);
8262
+ combinedBodyLength += model.beforeBody.length + model.afterBody.length;
8263
+
8264
+ var titleLineCount = model.title.length;
8265
+ var footerLineCount = model.footer.length;
8266
+ var titleFontSize = model.titleFontSize;
8267
+ var bodyFontSize = model.bodyFontSize;
8268
+ var footerFontSize = model.footerFontSize;
8269
+
8270
+ height += titleLineCount * titleFontSize; // Title Lines
8271
+ height += titleLineCount ? (titleLineCount - 1) * model.titleSpacing : 0; // Title Line Spacing
8272
+ height += titleLineCount ? model.titleMarginBottom : 0; // Title's bottom Margin
8273
+ height += combinedBodyLength * bodyFontSize; // Body Lines
8274
+ height += combinedBodyLength ? (combinedBodyLength - 1) * model.bodySpacing : 0; // Body Line Spacing
8275
+ height += footerLineCount ? model.footerMarginTop : 0; // Footer Margin
8276
+ height += footerLineCount * (footerFontSize); // Footer Lines
8277
+ height += footerLineCount ? (footerLineCount - 1) * model.footerSpacing : 0; // Footer Line Spacing
8278
+
8279
+ // Title width
8280
+ var widthPadding = 0;
8281
+ var maxLineWidth = function(line) {
8282
+ width = Math.max(width, ctx.measureText(line).width + widthPadding);
8283
+ };
8284
+
8285
+ ctx.font = helpers.fontString(titleFontSize, model._titleFontStyle, model._titleFontFamily);
8286
+ helpers.each(model.title, maxLineWidth);
8287
+
8288
+ // Body width
8289
+ ctx.font = helpers.fontString(bodyFontSize, model._bodyFontStyle, model._bodyFontFamily);
8290
+ helpers.each(model.beforeBody.concat(model.afterBody), maxLineWidth);
8291
+
8292
+ // Body lines may include some extra width due to the color box
8293
+ widthPadding = model.displayColors ? (bodyFontSize + 2) : 0;
8294
+ helpers.each(body, function(bodyItem) {
8295
+ helpers.each(bodyItem.before, maxLineWidth);
8296
+ helpers.each(bodyItem.lines, maxLineWidth);
8297
+ helpers.each(bodyItem.after, maxLineWidth);
8298
+ });
8299
+
8300
+ // Reset back to 0
8301
+ widthPadding = 0;
8302
+
8303
+ // Footer width
8304
+ ctx.font = helpers.fontString(footerFontSize, model._footerFontStyle, model._footerFontFamily);
8305
+ helpers.each(model.footer, maxLineWidth);
8306
+
8307
+ // Add padding
8308
+ width += 2 * model.xPadding;
8309
+
8310
+ return {
8311
+ width: width,
8312
+ height: height
8313
+ };
8314
+ }
8315
+
8316
+ /**
8317
+ * Helper to get the alignment of a tooltip given the size
8318
+ */
8319
+ function determineAlignment(tooltip, size) {
8320
+ var model = tooltip._model;
8321
+ var chart = tooltip._chart;
8322
+ var chartArea = tooltip._chart.chartArea;
8323
+ var xAlign = 'center';
8324
+ var yAlign = 'center';
8325
+
8326
+ if (model.y < size.height) {
8327
+ yAlign = 'top';
8328
+ } else if (model.y > (chart.height - size.height)) {
8329
+ yAlign = 'bottom';
8330
+ }
8331
+
8332
+ var lf, rf; // functions to determine left, right alignment
8333
+ var olf, orf; // functions to determine if left/right alignment causes tooltip to go outside chart
8334
+ var yf; // function to get the y alignment if the tooltip goes outside of the left or right edges
8335
+ var midX = (chartArea.left + chartArea.right) / 2;
8336
+ var midY = (chartArea.top + chartArea.bottom) / 2;
8337
+
8338
+ if (yAlign === 'center') {
8339
+ lf = function(x) {
8340
+ return x <= midX;
8341
+ };
8342
+ rf = function(x) {
8343
+ return x > midX;
8344
+ };
8345
+ } else {
8346
+ lf = function(x) {
8347
+ return x <= (size.width / 2);
8348
+ };
8349
+ rf = function(x) {
8350
+ return x >= (chart.width - (size.width / 2));
8351
+ };
8352
+ }
8353
+
8354
+ olf = function(x) {
8355
+ return x + size.width > chart.width;
8356
+ };
8357
+ orf = function(x) {
8358
+ return x - size.width < 0;
8359
+ };
8360
+ yf = function(y) {
8361
+ return y <= midY ? 'top' : 'bottom';
8362
+ };
8363
+
8364
+ if (lf(model.x)) {
8365
+ xAlign = 'left';
8366
+
8367
+ // Is tooltip too wide and goes over the right side of the chart.?
8368
+ if (olf(model.x)) {
8369
+ xAlign = 'center';
8370
+ yAlign = yf(model.y);
8371
+ }
8372
+ } else if (rf(model.x)) {
8373
+ xAlign = 'right';
8374
+
8375
+ // Is tooltip too wide and goes outside left edge of canvas?
8376
+ if (orf(model.x)) {
8377
+ xAlign = 'center';
8378
+ yAlign = yf(model.y);
8379
+ }
8380
+ }
8381
+
8382
+ var opts = tooltip._options;
8383
+ return {
8384
+ xAlign: opts.xAlign ? opts.xAlign : xAlign,
8385
+ yAlign: opts.yAlign ? opts.yAlign : yAlign
8386
+ };
8387
+ }
8388
+
8389
+ /**
8390
+ * @Helper to get the location a tooltip needs to be placed at given the initial position (via the vm) and the size and alignment
8391
+ */
8392
+ function getBackgroundPoint(vm, size, alignment) {
8393
+ // Background Position
8394
+ var x = vm.x;
8395
+ var y = vm.y;
8396
+
8397
+ var caretSize = vm.caretSize;
8398
+ var caretPadding = vm.caretPadding;
8399
+ var cornerRadius = vm.cornerRadius;
8400
+ var xAlign = alignment.xAlign;
8401
+ var yAlign = alignment.yAlign;
8402
+ var paddingAndSize = caretSize + caretPadding;
8403
+ var radiusAndPadding = cornerRadius + caretPadding;
8404
+
8405
+ if (xAlign === 'right') {
8406
+ x -= size.width;
8407
+ } else if (xAlign === 'center') {
8408
+ x -= (size.width / 2);
8409
+ }
8410
+
8411
+ if (yAlign === 'top') {
8412
+ y += paddingAndSize;
8413
+ } else if (yAlign === 'bottom') {
8414
+ y -= size.height + paddingAndSize;
8415
+ } else {
8416
+ y -= (size.height / 2);
8417
+ }
8418
+
8419
+ if (yAlign === 'center') {
8420
+ if (xAlign === 'left') {
8421
+ x += paddingAndSize;
8422
+ } else if (xAlign === 'right') {
8423
+ x -= paddingAndSize;
8424
+ }
8425
+ } else if (xAlign === 'left') {
8426
+ x -= radiusAndPadding;
8427
+ } else if (xAlign === 'right') {
8428
+ x += radiusAndPadding;
8429
+ }
8430
+
8431
+ return {
8432
+ x: x,
8433
+ y: y
8434
+ };
8435
+ }
8436
+
8437
+ Chart.Tooltip = Element.extend({
8438
+ initialize: function() {
8439
+ this._model = getBaseModel(this._options);
8440
+ this._lastActive = [];
8441
+ },
8442
+
8443
+ // Get the title
8444
+ // Args are: (tooltipItem, data)
8445
+ getTitle: function() {
8446
+ var me = this;
8447
+ var opts = me._options;
8448
+ var callbacks = opts.callbacks;
8449
+
8450
+ var beforeTitle = callbacks.beforeTitle.apply(me, arguments);
8451
+ var title = callbacks.title.apply(me, arguments);
8452
+ var afterTitle = callbacks.afterTitle.apply(me, arguments);
8453
+
8454
+ var lines = [];
8455
+ lines = pushOrConcat(lines, beforeTitle);
8456
+ lines = pushOrConcat(lines, title);
8457
+ lines = pushOrConcat(lines, afterTitle);
8458
+
8459
+ return lines;
8460
+ },
8461
+
8462
+ // Args are: (tooltipItem, data)
8463
+ getBeforeBody: function() {
8464
+ var lines = this._options.callbacks.beforeBody.apply(this, arguments);
8465
+ return helpers.isArray(lines) ? lines : lines !== undefined ? [lines] : [];
8466
+ },
8467
+
8468
+ // Args are: (tooltipItem, data)
8469
+ getBody: function(tooltipItems, data) {
8470
+ var me = this;
8471
+ var callbacks = me._options.callbacks;
8472
+ var bodyItems = [];
8473
+
8474
+ helpers.each(tooltipItems, function(tooltipItem) {
8475
+ var bodyItem = {
8476
+ before: [],
8477
+ lines: [],
8478
+ after: []
8479
+ };
8480
+ pushOrConcat(bodyItem.before, callbacks.beforeLabel.call(me, tooltipItem, data));
8481
+ pushOrConcat(bodyItem.lines, callbacks.label.call(me, tooltipItem, data));
8482
+ pushOrConcat(bodyItem.after, callbacks.afterLabel.call(me, tooltipItem, data));
8483
+
8484
+ bodyItems.push(bodyItem);
8485
+ });
8486
+
8487
+ return bodyItems;
8488
+ },
8489
+
8490
+ // Args are: (tooltipItem, data)
8491
+ getAfterBody: function() {
8492
+ var lines = this._options.callbacks.afterBody.apply(this, arguments);
8493
+ return helpers.isArray(lines) ? lines : lines !== undefined ? [lines] : [];
8494
+ },
8495
+
8496
+ // Get the footer and beforeFooter and afterFooter lines
8497
+ // Args are: (tooltipItem, data)
8498
+ getFooter: function() {
8499
+ var me = this;
8500
+ var callbacks = me._options.callbacks;
8501
+
8502
+ var beforeFooter = callbacks.beforeFooter.apply(me, arguments);
8503
+ var footer = callbacks.footer.apply(me, arguments);
8504
+ var afterFooter = callbacks.afterFooter.apply(me, arguments);
8505
+
8506
+ var lines = [];
8507
+ lines = pushOrConcat(lines, beforeFooter);
8508
+ lines = pushOrConcat(lines, footer);
8509
+ lines = pushOrConcat(lines, afterFooter);
8510
+
8511
+ return lines;
8512
+ },
8513
+
8514
+ update: function(changed) {
8515
+ var me = this;
8516
+ var opts = me._options;
8517
+
8518
+ // Need to regenerate the model because its faster than using extend and it is necessary due to the optimization in Chart.Element.transition
8519
+ // that does _view = _model if ease === 1. This causes the 2nd tooltip update to set properties in both the view and model at the same time
8520
+ // which breaks any animations.
8521
+ var existingModel = me._model;
8522
+ var model = me._model = getBaseModel(opts);
8523
+ var active = me._active;
8524
+
8525
+ var data = me._data;
8526
+
8527
+ // In the case where active.length === 0 we need to keep these at existing values for good animations
8528
+ var alignment = {
8529
+ xAlign: existingModel.xAlign,
8530
+ yAlign: existingModel.yAlign
8531
+ };
8532
+ var backgroundPoint = {
8533
+ x: existingModel.x,
8534
+ y: existingModel.y
8535
+ };
8536
+ var tooltipSize = {
8537
+ width: existingModel.width,
8538
+ height: existingModel.height
8539
+ };
8540
+ var tooltipPosition = {
8541
+ x: existingModel.caretX,
8542
+ y: existingModel.caretY
8543
+ };
8544
+
8545
+ var i, len;
8546
+
8547
+ if (active.length) {
8548
+ model.opacity = 1;
8549
+
8550
+ var labelColors = [];
8551
+ var labelTextColors = [];
8552
+ tooltipPosition = Chart.Tooltip.positioners[opts.position].call(me, active, me._eventPosition);
8553
+
8554
+ var tooltipItems = [];
8555
+ for (i = 0, len = active.length; i < len; ++i) {
8556
+ tooltipItems.push(createTooltipItem(active[i]));
8557
+ }
8558
+
8559
+ // If the user provided a filter function, use it to modify the tooltip items
8560
+ if (opts.filter) {
8561
+ tooltipItems = tooltipItems.filter(function(a) {
8562
+ return opts.filter(a, data);
8563
+ });
8564
+ }
8565
+
8566
+ // If the user provided a sorting function, use it to modify the tooltip items
8567
+ if (opts.itemSort) {
8568
+ tooltipItems = tooltipItems.sort(function(a, b) {
8569
+ return opts.itemSort(a, b, data);
8570
+ });
8571
+ }
8572
+
8573
+ // Determine colors for boxes
8574
+ helpers.each(tooltipItems, function(tooltipItem) {
8575
+ labelColors.push(opts.callbacks.labelColor.call(me, tooltipItem, me._chart));
8576
+ labelTextColors.push(opts.callbacks.labelTextColor.call(me, tooltipItem, me._chart));
8577
+ });
8578
+
8579
+
8580
+ // Build the Text Lines
8581
+ model.title = me.getTitle(tooltipItems, data);
8582
+ model.beforeBody = me.getBeforeBody(tooltipItems, data);
8583
+ model.body = me.getBody(tooltipItems, data);
8584
+ model.afterBody = me.getAfterBody(tooltipItems, data);
8585
+ model.footer = me.getFooter(tooltipItems, data);
8586
+
8587
+ // Initial positioning and colors
8588
+ model.x = Math.round(tooltipPosition.x);
8589
+ model.y = Math.round(tooltipPosition.y);
8590
+ model.caretPadding = opts.caretPadding;
8591
+ model.labelColors = labelColors;
8592
+ model.labelTextColors = labelTextColors;
8593
+
8594
+ // data points
8595
+ model.dataPoints = tooltipItems;
8596
+
8597
+ // We need to determine alignment of the tooltip
8598
+ tooltipSize = getTooltipSize(this, model);
8599
+ alignment = determineAlignment(this, tooltipSize);
8600
+ // Final Size and Position
8601
+ backgroundPoint = getBackgroundPoint(model, tooltipSize, alignment);
8602
+ } else {
8603
+ model.opacity = 0;
8604
+ }
8605
+
8606
+ model.xAlign = alignment.xAlign;
8607
+ model.yAlign = alignment.yAlign;
8608
+ model.x = backgroundPoint.x;
8609
+ model.y = backgroundPoint.y;
8610
+ model.width = tooltipSize.width;
8611
+ model.height = tooltipSize.height;
8612
+
8613
+ // Point where the caret on the tooltip points to
8614
+ model.caretX = tooltipPosition.x;
8615
+ model.caretY = tooltipPosition.y;
8616
+
8617
+ me._model = model;
8618
+
8619
+ if (changed && opts.custom) {
8620
+ opts.custom.call(me, model);
8621
+ }
8622
+
8623
+ return me;
8624
+ },
8625
+ drawCaret: function(tooltipPoint, size) {
8626
+ var ctx = this._chart.ctx;
8627
+ var vm = this._view;
8628
+ var caretPosition = this.getCaretPosition(tooltipPoint, size, vm);
8629
+
8630
+ ctx.lineTo(caretPosition.x1, caretPosition.y1);
8631
+ ctx.lineTo(caretPosition.x2, caretPosition.y2);
8632
+ ctx.lineTo(caretPosition.x3, caretPosition.y3);
8633
+ },
8634
+ getCaretPosition: function(tooltipPoint, size, vm) {
8635
+ var x1, x2, x3, y1, y2, y3;
8636
+ var caretSize = vm.caretSize;
8637
+ var cornerRadius = vm.cornerRadius;
8638
+ var xAlign = vm.xAlign;
8639
+ var yAlign = vm.yAlign;
8640
+ var ptX = tooltipPoint.x;
8641
+ var ptY = tooltipPoint.y;
8642
+ var width = size.width;
8643
+ var height = size.height;
8644
+
8645
+ if (yAlign === 'center') {
8646
+ y2 = ptY + (height / 2);
8647
+
8648
+ if (xAlign === 'left') {
8649
+ x1 = ptX;
8650
+ x2 = x1 - caretSize;
8651
+ x3 = x1;
8652
+
8653
+ y1 = y2 + caretSize;
8654
+ y3 = y2 - caretSize;
8655
+ } else {
8656
+ x1 = ptX + width;
8657
+ x2 = x1 + caretSize;
8658
+ x3 = x1;
8659
+
8660
+ y1 = y2 - caretSize;
8661
+ y3 = y2 + caretSize;
8662
+ }
8663
+ } else {
8664
+ if (xAlign === 'left') {
8665
+ x2 = ptX + cornerRadius + (caretSize);
8666
+ x1 = x2 - caretSize;
8667
+ x3 = x2 + caretSize;
8668
+ } else if (xAlign === 'right') {
8669
+ x2 = ptX + width - cornerRadius - caretSize;
8670
+ x1 = x2 - caretSize;
8671
+ x3 = x2 + caretSize;
8672
+ } else {
8673
+ x2 = ptX + (width / 2);
8674
+ x1 = x2 - caretSize;
8675
+ x3 = x2 + caretSize;
8676
+ }
8677
+ if (yAlign === 'top') {
8678
+ y1 = ptY;
8679
+ y2 = y1 - caretSize;
8680
+ y3 = y1;
8681
+ } else {
8682
+ y1 = ptY + height;
8683
+ y2 = y1 + caretSize;
8684
+ y3 = y1;
8685
+ // invert drawing order
8686
+ var tmp = x3;
8687
+ x3 = x1;
8688
+ x1 = tmp;
8689
+ }
8690
+ }
8691
+ return {x1: x1, x2: x2, x3: x3, y1: y1, y2: y2, y3: y3};
8692
+ },
8693
+ drawTitle: function(pt, vm, ctx, opacity) {
8694
+ var title = vm.title;
8695
+
8696
+ if (title.length) {
8697
+ ctx.textAlign = vm._titleAlign;
8698
+ ctx.textBaseline = 'top';
8699
+
8700
+ var titleFontSize = vm.titleFontSize;
8701
+ var titleSpacing = vm.titleSpacing;
8702
+
8703
+ ctx.fillStyle = mergeOpacity(vm.titleFontColor, opacity);
8704
+ ctx.font = helpers.fontString(titleFontSize, vm._titleFontStyle, vm._titleFontFamily);
8705
+
8706
+ var i, len;
8707
+ for (i = 0, len = title.length; i < len; ++i) {
8708
+ ctx.fillText(title[i], pt.x, pt.y);
8709
+ pt.y += titleFontSize + titleSpacing; // Line Height and spacing
8710
+
8711
+ if (i + 1 === title.length) {
8712
+ pt.y += vm.titleMarginBottom - titleSpacing; // If Last, add margin, remove spacing
8713
+ }
8714
+ }
8715
+ }
8716
+ },
8717
+ drawBody: function(pt, vm, ctx, opacity) {
8718
+ var bodyFontSize = vm.bodyFontSize;
8719
+ var bodySpacing = vm.bodySpacing;
8720
+ var body = vm.body;
8721
+
8722
+ ctx.textAlign = vm._bodyAlign;
8723
+ ctx.textBaseline = 'top';
8724
+ ctx.font = helpers.fontString(bodyFontSize, vm._bodyFontStyle, vm._bodyFontFamily);
8725
+
8726
+ // Before Body
8727
+ var xLinePadding = 0;
8728
+ var fillLineOfText = function(line) {
8729
+ ctx.fillText(line, pt.x + xLinePadding, pt.y);
8730
+ pt.y += bodyFontSize + bodySpacing;
8731
+ };
8732
+
8733
+ // Before body lines
8734
+ ctx.fillStyle = mergeOpacity(vm.bodyFontColor, opacity);
8735
+ helpers.each(vm.beforeBody, fillLineOfText);
8736
+
8737
+ var drawColorBoxes = vm.displayColors;
8738
+ xLinePadding = drawColorBoxes ? (bodyFontSize + 2) : 0;
8739
+
8740
+ // Draw body lines now
8741
+ helpers.each(body, function(bodyItem, i) {
8742
+ var textColor = mergeOpacity(vm.labelTextColors[i], opacity);
8743
+ ctx.fillStyle = textColor;
8744
+ helpers.each(bodyItem.before, fillLineOfText);
8745
+
8746
+ helpers.each(bodyItem.lines, function(line) {
8747
+ // Draw Legend-like boxes if needed
8748
+ if (drawColorBoxes) {
8749
+ // Fill a white rect so that colours merge nicely if the opacity is < 1
8750
+ ctx.fillStyle = mergeOpacity(vm.legendColorBackground, opacity);
8751
+ ctx.fillRect(pt.x, pt.y, bodyFontSize, bodyFontSize);
8752
+
8753
+ // Border
8754
+ ctx.lineWidth = 1;
8755
+ ctx.strokeStyle = mergeOpacity(vm.labelColors[i].borderColor, opacity);
8756
+ ctx.strokeRect(pt.x, pt.y, bodyFontSize, bodyFontSize);
8757
+
8758
+ // Inner square
8759
+ ctx.fillStyle = mergeOpacity(vm.labelColors[i].backgroundColor, opacity);
8760
+ ctx.fillRect(pt.x + 1, pt.y + 1, bodyFontSize - 2, bodyFontSize - 2);
8761
+ ctx.fillStyle = textColor;
8762
+ }
8763
+
8764
+ fillLineOfText(line);
8765
+ });
8766
+
8767
+ helpers.each(bodyItem.after, fillLineOfText);
8768
+ });
8769
+
8770
+ // Reset back to 0 for after body
8771
+ xLinePadding = 0;
8772
+
8773
+ // After body lines
8774
+ helpers.each(vm.afterBody, fillLineOfText);
8775
+ pt.y -= bodySpacing; // Remove last body spacing
8776
+ },
8777
+ drawFooter: function(pt, vm, ctx, opacity) {
8778
+ var footer = vm.footer;
8779
+
8780
+ if (footer.length) {
8781
+ pt.y += vm.footerMarginTop;
8782
+
8783
+ ctx.textAlign = vm._footerAlign;
8784
+ ctx.textBaseline = 'top';
8785
+
8786
+ ctx.fillStyle = mergeOpacity(vm.footerFontColor, opacity);
8787
+ ctx.font = helpers.fontString(vm.footerFontSize, vm._footerFontStyle, vm._footerFontFamily);
8788
+
8789
+ helpers.each(footer, function(line) {
8790
+ ctx.fillText(line, pt.x, pt.y);
8791
+ pt.y += vm.footerFontSize + vm.footerSpacing;
8792
+ });
8793
+ }
8794
+ },
8795
+ drawBackground: function(pt, vm, ctx, tooltipSize, opacity) {
8796
+ ctx.fillStyle = mergeOpacity(vm.backgroundColor, opacity);
8797
+ ctx.strokeStyle = mergeOpacity(vm.borderColor, opacity);
8798
+ ctx.lineWidth = vm.borderWidth;
8799
+ var xAlign = vm.xAlign;
8800
+ var yAlign = vm.yAlign;
8801
+ var x = pt.x;
8802
+ var y = pt.y;
8803
+ var width = tooltipSize.width;
8804
+ var height = tooltipSize.height;
8805
+ var radius = vm.cornerRadius;
8806
+
8807
+ ctx.beginPath();
8808
+ ctx.moveTo(x + radius, y);
8809
+ if (yAlign === 'top') {
8810
+ this.drawCaret(pt, tooltipSize);
8811
+ }
8812
+ ctx.lineTo(x + width - radius, y);
8813
+ ctx.quadraticCurveTo(x + width, y, x + width, y + radius);
8814
+ if (yAlign === 'center' && xAlign === 'right') {
8815
+ this.drawCaret(pt, tooltipSize);
8816
+ }
8817
+ ctx.lineTo(x + width, y + height - radius);
8818
+ ctx.quadraticCurveTo(x + width, y + height, x + width - radius, y + height);
8819
+ if (yAlign === 'bottom') {
8820
+ this.drawCaret(pt, tooltipSize);
8821
+ }
8822
+ ctx.lineTo(x + radius, y + height);
8823
+ ctx.quadraticCurveTo(x, y + height, x, y + height - radius);
8824
+ if (yAlign === 'center' && xAlign === 'left') {
8825
+ this.drawCaret(pt, tooltipSize);
8826
+ }
8827
+ ctx.lineTo(x, y + radius);
8828
+ ctx.quadraticCurveTo(x, y, x + radius, y);
8829
+ ctx.closePath();
8830
+
8831
+ ctx.fill();
8832
+
8833
+ if (vm.borderWidth > 0) {
8834
+ ctx.stroke();
8835
+ }
8836
+ },
8837
+ draw: function() {
8838
+ var ctx = this._chart.ctx;
8839
+ var vm = this._view;
8840
+
8841
+ if (vm.opacity === 0) {
8842
+ return;
8843
+ }
8844
+
8845
+ var tooltipSize = {
8846
+ width: vm.width,
8847
+ height: vm.height
8848
+ };
8849
+ var pt = {
8850
+ x: vm.x,
8851
+ y: vm.y
8852
+ };
8853
+
8854
+ // IE11/Edge does not like very small opacities, so snap to 0
8855
+ var opacity = Math.abs(vm.opacity < 1e-3) ? 0 : vm.opacity;
8856
+
8857
+ // Truthy/falsey value for empty tooltip
8858
+ var hasTooltipContent = vm.title.length || vm.beforeBody.length || vm.body.length || vm.afterBody.length || vm.footer.length;
8859
+
8860
+ if (this._options.enabled && hasTooltipContent) {
8861
+ // Draw Background
8862
+ this.drawBackground(pt, vm, ctx, tooltipSize, opacity);
8863
+
8864
+ // Draw Title, Body, and Footer
8865
+ pt.x += vm.xPadding;
8866
+ pt.y += vm.yPadding;
8867
+
8868
+ // Titles
8869
+ this.drawTitle(pt, vm, ctx, opacity);
8870
+
8871
+ // Body
8872
+ this.drawBody(pt, vm, ctx, opacity);
8873
+
8874
+ // Footer
8875
+ this.drawFooter(pt, vm, ctx, opacity);
8876
+ }
8877
+ },
8878
+
8879
+ /**
8880
+ * Handle an event
8881
+ * @private
8882
+ * @param {IEvent} event - The event to handle
8883
+ * @returns {Boolean} true if the tooltip changed
8884
+ */
8885
+ handleEvent: function(e) {
8886
+ var me = this;
8887
+ var options = me._options;
8888
+ var changed = false;
8889
+
8890
+ me._lastActive = me._lastActive || [];
8891
+
8892
+ // Find Active Elements for tooltips
8893
+ if (e.type === 'mouseout') {
8894
+ me._active = [];
8895
+ } else {
8896
+ me._active = me._chart.getElementsAtEventForMode(e, options.mode, options);
8897
+ }
8898
+
8899
+ // Remember Last Actives
8900
+ changed = !helpers.arrayEquals(me._active, me._lastActive);
8901
+
8902
+ // If tooltip didn't change, do not handle the target event
8903
+ if (!changed) {
8904
+ return false;
8905
+ }
8906
+
8907
+ me._lastActive = me._active;
8908
+
8909
+ if (options.enabled || options.custom) {
8910
+ me._eventPosition = {
8911
+ x: e.x,
8912
+ y: e.y
8913
+ };
8914
+
8915
+ var model = me._model;
8916
+ me.update(true);
8917
+ me.pivot();
8918
+
8919
+ // See if our tooltip position changed
8920
+ changed |= (model.x !== me._model.x) || (model.y !== me._model.y);
8921
+ }
8922
+
8923
+ return changed;
8924
+ }
8925
+ });
8926
+
8927
+ /**
8928
+ * @namespace Chart.Tooltip.positioners
8929
+ */
8930
+ Chart.Tooltip.positioners = {
8931
+ /**
8932
+ * Average mode places the tooltip at the average position of the elements shown
8933
+ * @function Chart.Tooltip.positioners.average
8934
+ * @param elements {ChartElement[]} the elements being displayed in the tooltip
8935
+ * @returns {Point} tooltip position
8936
+ */
8937
+ average: function(elements) {
8938
+ if (!elements.length) {
8939
+ return false;
8940
+ }
8941
+
8942
+ var i, len;
8943
+ var x = 0;
8944
+ var y = 0;
8945
+ var count = 0;
8946
+
8947
+ for (i = 0, len = elements.length; i < len; ++i) {
8948
+ var el = elements[i];
8949
+ if (el && el.hasValue()) {
8950
+ var pos = el.tooltipPosition();
8951
+ x += pos.x;
8952
+ y += pos.y;
8953
+ ++count;
8954
+ }
8955
+ }
8956
+
8957
+ return {
8958
+ x: Math.round(x / count),
8959
+ y: Math.round(y / count)
8960
+ };
8961
+ },
8962
+
8963
+ /**
8964
+ * Gets the tooltip position nearest of the item nearest to the event position
8965
+ * @function Chart.Tooltip.positioners.nearest
8966
+ * @param elements {Chart.Element[]} the tooltip elements
8967
+ * @param eventPosition {Point} the position of the event in canvas coordinates
8968
+ * @returns {Point} the tooltip position
8969
+ */
8970
+ nearest: function(elements, eventPosition) {
8971
+ var x = eventPosition.x;
8972
+ var y = eventPosition.y;
8973
+ var minDistance = Number.POSITIVE_INFINITY;
8974
+ var i, len, nearestElement;
8975
+
8976
+ for (i = 0, len = elements.length; i < len; ++i) {
8977
+ var el = elements[i];
8978
+ if (el && el.hasValue()) {
8979
+ var center = el.getCenterPoint();
8980
+ var d = helpers.distanceBetweenPoints(eventPosition, center);
8981
+
8982
+ if (d < minDistance) {
8983
+ minDistance = d;
8984
+ nearestElement = el;
8985
+ }
8986
+ }
8987
+ }
8988
+
8989
+ if (nearestElement) {
8990
+ var tp = nearestElement.tooltipPosition();
8991
+ x = tp.x;
8992
+ y = tp.y;
8993
+ }
8994
+
8995
+ return {
8996
+ x: x,
8997
+ y: y
8998
+ };
8999
+ }
9000
+ };
9001
+ };
9002
+
9003
+ },{"25":25,"26":26,"45":45}],36:[function(require,module,exports){
9004
+ 'use strict';
9005
+
9006
+ var defaults = require(25);
9007
+ var Element = require(26);
9008
+ var helpers = require(45);
9009
+
9010
+ defaults._set('global', {
9011
+ elements: {
9012
+ arc: {
9013
+ backgroundColor: defaults.global.defaultColor,
9014
+ borderColor: '#fff',
9015
+ borderWidth: 2
9016
+ }
9017
+ }
9018
+ });
9019
+
9020
+ module.exports = Element.extend({
9021
+ inLabelRange: function(mouseX) {
9022
+ var vm = this._view;
9023
+
9024
+ if (vm) {
9025
+ return (Math.pow(mouseX - vm.x, 2) < Math.pow(vm.radius + vm.hoverRadius, 2));
9026
+ }
9027
+ return false;
9028
+ },
9029
+
9030
+ inRange: function(chartX, chartY) {
9031
+ var vm = this._view;
9032
+
9033
+ if (vm) {
9034
+ var pointRelativePosition = helpers.getAngleFromPoint(vm, {x: chartX, y: chartY});
9035
+ var angle = pointRelativePosition.angle;
9036
+ var distance = pointRelativePosition.distance;
9037
+
9038
+ // Sanitise angle range
9039
+ var startAngle = vm.startAngle;
9040
+ var endAngle = vm.endAngle;
9041
+ while (endAngle < startAngle) {
9042
+ endAngle += 2.0 * Math.PI;
9043
+ }
9044
+ while (angle > endAngle) {
9045
+ angle -= 2.0 * Math.PI;
9046
+ }
9047
+ while (angle < startAngle) {
9048
+ angle += 2.0 * Math.PI;
9049
+ }
9050
+
9051
+ // Check if within the range of the open/close angle
9052
+ var betweenAngles = (angle >= startAngle && angle <= endAngle);
9053
+ var withinRadius = (distance >= vm.innerRadius && distance <= vm.outerRadius);
9054
+
9055
+ return (betweenAngles && withinRadius);
9056
+ }
9057
+ return false;
9058
+ },
9059
+
9060
+ getCenterPoint: function() {
9061
+ var vm = this._view;
9062
+ var halfAngle = (vm.startAngle + vm.endAngle) / 2;
9063
+ var halfRadius = (vm.innerRadius + vm.outerRadius) / 2;
9064
+ return {
9065
+ x: vm.x + Math.cos(halfAngle) * halfRadius,
9066
+ y: vm.y + Math.sin(halfAngle) * halfRadius
9067
+ };
9068
+ },
9069
+
9070
+ getArea: function() {
9071
+ var vm = this._view;
9072
+ return Math.PI * ((vm.endAngle - vm.startAngle) / (2 * Math.PI)) * (Math.pow(vm.outerRadius, 2) - Math.pow(vm.innerRadius, 2));
9073
+ },
9074
+
9075
+ tooltipPosition: function() {
9076
+ var vm = this._view;
9077
+ var centreAngle = vm.startAngle + ((vm.endAngle - vm.startAngle) / 2);
9078
+ var rangeFromCentre = (vm.outerRadius - vm.innerRadius) / 2 + vm.innerRadius;
9079
+
9080
+ return {
9081
+ x: vm.x + (Math.cos(centreAngle) * rangeFromCentre),
9082
+ y: vm.y + (Math.sin(centreAngle) * rangeFromCentre)
9083
+ };
9084
+ },
9085
+
9086
+ draw: function() {
9087
+ var ctx = this._chart.ctx;
9088
+ var vm = this._view;
9089
+ var sA = vm.startAngle;
9090
+ var eA = vm.endAngle;
9091
+
9092
+ ctx.beginPath();
9093
+
9094
+ ctx.arc(vm.x, vm.y, vm.outerRadius, sA, eA);
9095
+ ctx.arc(vm.x, vm.y, vm.innerRadius, eA, sA, true);
9096
+
9097
+ ctx.closePath();
9098
+ ctx.strokeStyle = vm.borderColor;
9099
+ ctx.lineWidth = vm.borderWidth;
9100
+
9101
+ ctx.fillStyle = vm.backgroundColor;
9102
+
9103
+ ctx.fill();
9104
+ ctx.lineJoin = 'bevel';
9105
+
9106
+ if (vm.borderWidth) {
9107
+ ctx.stroke();
9108
+ }
9109
+ }
9110
+ });
9111
+
9112
+ },{"25":25,"26":26,"45":45}],37:[function(require,module,exports){
9113
+ 'use strict';
9114
+
9115
+ var defaults = require(25);
9116
+ var Element = require(26);
9117
+ var helpers = require(45);
9118
+
9119
+ var globalDefaults = defaults.global;
9120
+
9121
+ defaults._set('global', {
9122
+ elements: {
9123
+ line: {
9124
+ tension: 0.4,
9125
+ backgroundColor: globalDefaults.defaultColor,
9126
+ borderWidth: 3,
9127
+ borderColor: globalDefaults.defaultColor,
9128
+ borderCapStyle: 'butt',
9129
+ borderDash: [],
9130
+ borderDashOffset: 0.0,
9131
+ borderJoinStyle: 'miter',
9132
+ capBezierPoints: true,
9133
+ fill: true, // do we fill in the area between the line and its base axis
9134
+ }
9135
+ }
9136
+ });
9137
+
9138
+ module.exports = Element.extend({
9139
+ draw: function() {
9140
+ var me = this;
9141
+ var vm = me._view;
9142
+ var ctx = me._chart.ctx;
9143
+ var spanGaps = vm.spanGaps;
9144
+ var points = me._children.slice(); // clone array
9145
+ var globalOptionLineElements = globalDefaults.elements.line;
9146
+ var lastDrawnIndex = -1;
9147
+ var index, current, previous, currentVM;
9148
+
9149
+ // If we are looping, adding the first point again
9150
+ if (me._loop && points.length) {
9151
+ points.push(points[0]);
9152
+ }
9153
+
9154
+ ctx.save();
9155
+
9156
+ // Stroke Line Options
9157
+ ctx.lineCap = vm.borderCapStyle || globalOptionLineElements.borderCapStyle;
9158
+
9159
+ // IE 9 and 10 do not support line dash
9160
+ if (ctx.setLineDash) {
9161
+ ctx.setLineDash(vm.borderDash || globalOptionLineElements.borderDash);
9162
+ }
9163
+
9164
+ ctx.lineDashOffset = vm.borderDashOffset || globalOptionLineElements.borderDashOffset;
9165
+ ctx.lineJoin = vm.borderJoinStyle || globalOptionLineElements.borderJoinStyle;
9166
+ ctx.lineWidth = vm.borderWidth || globalOptionLineElements.borderWidth;
9167
+ ctx.strokeStyle = vm.borderColor || globalDefaults.defaultColor;
9168
+
9169
+ // Stroke Line
9170
+ ctx.beginPath();
9171
+ lastDrawnIndex = -1;
9172
+
9173
+ for (index = 0; index < points.length; ++index) {
9174
+ current = points[index];
9175
+ previous = helpers.previousItem(points, index);
9176
+ currentVM = current._view;
9177
+
9178
+ // First point moves to it's starting position no matter what
9179
+ if (index === 0) {
9180
+ if (!currentVM.skip) {
9181
+ ctx.moveTo(currentVM.x, currentVM.y);
9182
+ lastDrawnIndex = index;
9183
+ }
9184
+ } else {
9185
+ previous = lastDrawnIndex === -1 ? previous : points[lastDrawnIndex];
9186
+
9187
+ if (!currentVM.skip) {
9188
+ if ((lastDrawnIndex !== (index - 1) && !spanGaps) || lastDrawnIndex === -1) {
9189
+ // There was a gap and this is the first point after the gap
9190
+ ctx.moveTo(currentVM.x, currentVM.y);
9191
+ } else {
9192
+ // Line to next point
9193
+ helpers.canvas.lineTo(ctx, previous._view, current._view);
9194
+ }
9195
+ lastDrawnIndex = index;
9196
+ }
9197
+ }
9198
+ }
9199
+
9200
+ ctx.stroke();
9201
+ ctx.restore();
9202
+ }
9203
+ });
9204
+
9205
+ },{"25":25,"26":26,"45":45}],38:[function(require,module,exports){
9206
+ 'use strict';
9207
+
9208
+ var defaults = require(25);
9209
+ var Element = require(26);
9210
+ var helpers = require(45);
9211
+
9212
+ var defaultColor = defaults.global.defaultColor;
9213
+
9214
+ defaults._set('global', {
9215
+ elements: {
9216
+ point: {
9217
+ radius: 3,
9218
+ pointStyle: 'circle',
9219
+ backgroundColor: defaultColor,
9220
+ borderColor: defaultColor,
9221
+ borderWidth: 1,
9222
+ // Hover
9223
+ hitRadius: 1,
9224
+ hoverRadius: 4,
9225
+ hoverBorderWidth: 1
9226
+ }
9227
+ }
9228
+ });
9229
+
9230
+ function xRange(mouseX) {
9231
+ var vm = this._view;
9232
+ return vm ? (Math.pow(mouseX - vm.x, 2) < Math.pow(vm.radius + vm.hitRadius, 2)) : false;
9233
+ }
9234
+
9235
+ function yRange(mouseY) {
9236
+ var vm = this._view;
9237
+ return vm ? (Math.pow(mouseY - vm.y, 2) < Math.pow(vm.radius + vm.hitRadius, 2)) : false;
9238
+ }
9239
+
9240
+ module.exports = Element.extend({
9241
+ inRange: function(mouseX, mouseY) {
9242
+ var vm = this._view;
9243
+ return vm ? ((Math.pow(mouseX - vm.x, 2) + Math.pow(mouseY - vm.y, 2)) < Math.pow(vm.hitRadius + vm.radius, 2)) : false;
9244
+ },
9245
+
9246
+ inLabelRange: xRange,
9247
+ inXRange: xRange,
9248
+ inYRange: yRange,
9249
+
9250
+ getCenterPoint: function() {
9251
+ var vm = this._view;
9252
+ return {
9253
+ x: vm.x,
9254
+ y: vm.y
9255
+ };
9256
+ },
9257
+
9258
+ getArea: function() {
9259
+ return Math.PI * Math.pow(this._view.radius, 2);
9260
+ },
9261
+
9262
+ tooltipPosition: function() {
9263
+ var vm = this._view;
9264
+ return {
9265
+ x: vm.x,
9266
+ y: vm.y,
9267
+ padding: vm.radius + vm.borderWidth
9268
+ };
9269
+ },
9270
+
9271
+ draw: function(chartArea) {
9272
+ var vm = this._view;
9273
+ var model = this._model;
9274
+ var ctx = this._chart.ctx;
9275
+ var pointStyle = vm.pointStyle;
9276
+ var radius = vm.radius;
9277
+ var x = vm.x;
9278
+ var y = vm.y;
9279
+ var color = helpers.color;
9280
+ var errMargin = 1.01; // 1.01 is margin for Accumulated error. (Especially Edge, IE.)
9281
+ var ratio = 0;
9282
+
9283
+ if (vm.skip) {
9284
+ return;
9285
+ }
9286
+
9287
+ ctx.strokeStyle = vm.borderColor || defaultColor;
9288
+ ctx.lineWidth = helpers.valueOrDefault(vm.borderWidth, defaults.global.elements.point.borderWidth);
9289
+ ctx.fillStyle = vm.backgroundColor || defaultColor;
9290
+
9291
+ // Cliping for Points.
9292
+ // going out from inner charArea?
9293
+ if ((chartArea !== undefined) && ((model.x < chartArea.left) || (chartArea.right * errMargin < model.x) || (model.y < chartArea.top) || (chartArea.bottom * errMargin < model.y))) {
9294
+ // Point fade out
9295
+ if (model.x < chartArea.left) {
9296
+ ratio = (x - model.x) / (chartArea.left - model.x);
9297
+ } else if (chartArea.right * errMargin < model.x) {
9298
+ ratio = (model.x - x) / (model.x - chartArea.right);
9299
+ } else if (model.y < chartArea.top) {
9300
+ ratio = (y - model.y) / (chartArea.top - model.y);
9301
+ } else if (chartArea.bottom * errMargin < model.y) {
9302
+ ratio = (model.y - y) / (model.y - chartArea.bottom);
9303
+ }
9304
+ ratio = Math.round(ratio * 100) / 100;
9305
+ ctx.strokeStyle = color(ctx.strokeStyle).alpha(ratio).rgbString();
9306
+ ctx.fillStyle = color(ctx.fillStyle).alpha(ratio).rgbString();
9307
+ }
9308
+
9309
+ helpers.canvas.drawPoint(ctx, pointStyle, radius, x, y);
9310
+ }
9311
+ });
9312
+
9313
+ },{"25":25,"26":26,"45":45}],39:[function(require,module,exports){
9314
+ 'use strict';
9315
+
9316
+ var defaults = require(25);
9317
+ var Element = require(26);
9318
+
9319
+ defaults._set('global', {
9320
+ elements: {
9321
+ rectangle: {
9322
+ backgroundColor: defaults.global.defaultColor,
9323
+ borderColor: defaults.global.defaultColor,
9324
+ borderSkipped: 'bottom',
9325
+ borderWidth: 0
9326
+ }
9327
+ }
9328
+ });
9329
+
9330
+ function isVertical(bar) {
9331
+ return bar._view.width !== undefined;
9332
+ }
9333
+
9334
+ /**
9335
+ * Helper function to get the bounds of the bar regardless of the orientation
9336
+ * @param bar {Chart.Element.Rectangle} the bar
9337
+ * @return {Bounds} bounds of the bar
9338
+ * @private
9339
+ */
9340
+ function getBarBounds(bar) {
9341
+ var vm = bar._view;
9342
+ var x1, x2, y1, y2;
9343
+
9344
+ if (isVertical(bar)) {
9345
+ // vertical
9346
+ var halfWidth = vm.width / 2;
9347
+ x1 = vm.x - halfWidth;
9348
+ x2 = vm.x + halfWidth;
9349
+ y1 = Math.min(vm.y, vm.base);
9350
+ y2 = Math.max(vm.y, vm.base);
9351
+ } else {
9352
+ // horizontal bar
9353
+ var halfHeight = vm.height / 2;
9354
+ x1 = Math.min(vm.x, vm.base);
9355
+ x2 = Math.max(vm.x, vm.base);
9356
+ y1 = vm.y - halfHeight;
9357
+ y2 = vm.y + halfHeight;
9358
+ }
9359
+
9360
+ return {
9361
+ left: x1,
9362
+ top: y1,
9363
+ right: x2,
9364
+ bottom: y2
9365
+ };
9366
+ }
9367
+
9368
+ module.exports = Element.extend({
9369
+ draw: function() {
9370
+ var ctx = this._chart.ctx;
9371
+ var vm = this._view;
9372
+ var left, right, top, bottom, signX, signY, borderSkipped;
9373
+ var borderWidth = vm.borderWidth;
9374
+
9375
+ if (!vm.horizontal) {
9376
+ // bar
9377
+ left = vm.x - vm.width / 2;
9378
+ right = vm.x + vm.width / 2;
9379
+ top = vm.y;
9380
+ bottom = vm.base;
9381
+ signX = 1;
9382
+ signY = bottom > top ? 1 : -1;
9383
+ borderSkipped = vm.borderSkipped || 'bottom';
9384
+ } else {
9385
+ // horizontal bar
9386
+ left = vm.base;
9387
+ right = vm.x;
9388
+ top = vm.y - vm.height / 2;
9389
+ bottom = vm.y + vm.height / 2;
9390
+ signX = right > left ? 1 : -1;
9391
+ signY = 1;
9392
+ borderSkipped = vm.borderSkipped || 'left';
9393
+ }
9394
+
9395
+ // Canvas doesn't allow us to stroke inside the width so we can
9396
+ // adjust the sizes to fit if we're setting a stroke on the line
9397
+ if (borderWidth) {
9398
+ // borderWidth shold be less than bar width and bar height.
9399
+ var barSize = Math.min(Math.abs(left - right), Math.abs(top - bottom));
9400
+ borderWidth = borderWidth > barSize ? barSize : borderWidth;
9401
+ var halfStroke = borderWidth / 2;
9402
+ // Adjust borderWidth when bar top position is near vm.base(zero).
9403
+ var borderLeft = left + (borderSkipped !== 'left' ? halfStroke * signX : 0);
9404
+ var borderRight = right + (borderSkipped !== 'right' ? -halfStroke * signX : 0);
9405
+ var borderTop = top + (borderSkipped !== 'top' ? halfStroke * signY : 0);
9406
+ var borderBottom = bottom + (borderSkipped !== 'bottom' ? -halfStroke * signY : 0);
9407
+ // not become a vertical line?
9408
+ if (borderLeft !== borderRight) {
9409
+ top = borderTop;
9410
+ bottom = borderBottom;
9411
+ }
9412
+ // not become a horizontal line?
9413
+ if (borderTop !== borderBottom) {
9414
+ left = borderLeft;
9415
+ right = borderRight;
9416
+ }
9417
+ }
9418
+
9419
+ ctx.beginPath();
9420
+ ctx.fillStyle = vm.backgroundColor;
9421
+ ctx.strokeStyle = vm.borderColor;
9422
+ ctx.lineWidth = borderWidth;
9423
+
9424
+ // Corner points, from bottom-left to bottom-right clockwise
9425
+ // | 1 2 |
9426
+ // | 0 3 |
9427
+ var corners = [
9428
+ [left, bottom],
9429
+ [left, top],
9430
+ [right, top],
9431
+ [right, bottom]
9432
+ ];
9433
+
9434
+ // Find first (starting) corner with fallback to 'bottom'
9435
+ var borders = ['bottom', 'left', 'top', 'right'];
9436
+ var startCorner = borders.indexOf(borderSkipped, 0);
9437
+ if (startCorner === -1) {
9438
+ startCorner = 0;
9439
+ }
9440
+
9441
+ function cornerAt(index) {
9442
+ return corners[(startCorner + index) % 4];
9443
+ }
9444
+
9445
+ // Draw rectangle from 'startCorner'
9446
+ var corner = cornerAt(0);
9447
+ ctx.moveTo(corner[0], corner[1]);
9448
+
9449
+ for (var i = 1; i < 4; i++) {
9450
+ corner = cornerAt(i);
9451
+ ctx.lineTo(corner[0], corner[1]);
9452
+ }
9453
+
9454
+ ctx.fill();
9455
+ if (borderWidth) {
9456
+ ctx.stroke();
9457
+ }
9458
+ },
9459
+
9460
+ height: function() {
9461
+ var vm = this._view;
9462
+ return vm.base - vm.y;
9463
+ },
9464
+
9465
+ inRange: function(mouseX, mouseY) {
9466
+ var inRange = false;
9467
+
9468
+ if (this._view) {
9469
+ var bounds = getBarBounds(this);
9470
+ inRange = mouseX >= bounds.left && mouseX <= bounds.right && mouseY >= bounds.top && mouseY <= bounds.bottom;
9471
+ }
9472
+
9473
+ return inRange;
9474
+ },
9475
+
9476
+ inLabelRange: function(mouseX, mouseY) {
9477
+ var me = this;
9478
+ if (!me._view) {
9479
+ return false;
9480
+ }
9481
+
9482
+ var inRange = false;
9483
+ var bounds = getBarBounds(me);
9484
+
9485
+ if (isVertical(me)) {
9486
+ inRange = mouseX >= bounds.left && mouseX <= bounds.right;
9487
+ } else {
9488
+ inRange = mouseY >= bounds.top && mouseY <= bounds.bottom;
9489
+ }
9490
+
9491
+ return inRange;
9492
+ },
9493
+
9494
+ inXRange: function(mouseX) {
9495
+ var bounds = getBarBounds(this);
9496
+ return mouseX >= bounds.left && mouseX <= bounds.right;
9497
+ },
9498
+
9499
+ inYRange: function(mouseY) {
9500
+ var bounds = getBarBounds(this);
9501
+ return mouseY >= bounds.top && mouseY <= bounds.bottom;
9502
+ },
9503
+
9504
+ getCenterPoint: function() {
9505
+ var vm = this._view;
9506
+ var x, y;
9507
+ if (isVertical(this)) {
9508
+ x = vm.x;
9509
+ y = (vm.y + vm.base) / 2;
9510
+ } else {
9511
+ x = (vm.x + vm.base) / 2;
9512
+ y = vm.y;
9513
+ }
9514
+
9515
+ return {x: x, y: y};
9516
+ },
9517
+
9518
+ getArea: function() {
9519
+ var vm = this._view;
9520
+ return vm.width * Math.abs(vm.y - vm.base);
9521
+ },
9522
+
9523
+ tooltipPosition: function() {
9524
+ var vm = this._view;
9525
+ return {
9526
+ x: vm.x,
9527
+ y: vm.y
9528
+ };
9529
+ }
9530
+ });
9531
+
9532
+ },{"25":25,"26":26}],40:[function(require,module,exports){
9533
+ 'use strict';
9534
+
9535
+ module.exports = {};
9536
+ module.exports.Arc = require(36);
9537
+ module.exports.Line = require(37);
9538
+ module.exports.Point = require(38);
9539
+ module.exports.Rectangle = require(39);
9540
+
9541
+ },{"36":36,"37":37,"38":38,"39":39}],41:[function(require,module,exports){
9542
+ 'use strict';
9543
+
9544
+ var helpers = require(42);
9545
+
9546
+ /**
9547
+ * @namespace Chart.helpers.canvas
9548
+ */
9549
+ var exports = module.exports = {
9550
+ /**
9551
+ * Clears the entire canvas associated to the given `chart`.
9552
+ * @param {Chart} chart - The chart for which to clear the canvas.
9553
+ */
9554
+ clear: function(chart) {
9555
+ chart.ctx.clearRect(0, 0, chart.width, chart.height);
9556
+ },
9557
+
9558
+ /**
9559
+ * Creates a "path" for a rectangle with rounded corners at position (x, y) with a
9560
+ * given size (width, height) and the same `radius` for all corners.
9561
+ * @param {CanvasRenderingContext2D} ctx - The canvas 2D Context.
9562
+ * @param {Number} x - The x axis of the coordinate for the rectangle starting point.
9563
+ * @param {Number} y - The y axis of the coordinate for the rectangle starting point.
9564
+ * @param {Number} width - The rectangle's width.
9565
+ * @param {Number} height - The rectangle's height.
9566
+ * @param {Number} radius - The rounded amount (in pixels) for the four corners.
9567
+ * @todo handle `radius` as top-left, top-right, bottom-right, bottom-left array/object?
9568
+ */
9569
+ roundedRect: function(ctx, x, y, width, height, radius) {
9570
+ if (radius) {
9571
+ var rx = Math.min(radius, width / 2);
9572
+ var ry = Math.min(radius, height / 2);
9573
+
9574
+ ctx.moveTo(x + rx, y);
9575
+ ctx.lineTo(x + width - rx, y);
9576
+ ctx.quadraticCurveTo(x + width, y, x + width, y + ry);
9577
+ ctx.lineTo(x + width, y + height - ry);
9578
+ ctx.quadraticCurveTo(x + width, y + height, x + width - rx, y + height);
9579
+ ctx.lineTo(x + rx, y + height);
9580
+ ctx.quadraticCurveTo(x, y + height, x, y + height - ry);
9581
+ ctx.lineTo(x, y + ry);
9582
+ ctx.quadraticCurveTo(x, y, x + rx, y);
9583
+ } else {
9584
+ ctx.rect(x, y, width, height);
9585
+ }
9586
+ },
9587
+
9588
+ drawPoint: function(ctx, style, radius, x, y) {
9589
+ var type, edgeLength, xOffset, yOffset, height, size;
9590
+
9591
+ if (style && typeof style === 'object') {
9592
+ type = style.toString();
9593
+ if (type === '[object HTMLImageElement]' || type === '[object HTMLCanvasElement]') {
9594
+ ctx.drawImage(style, x - style.width / 2, y - style.height / 2, style.width, style.height);
9595
+ return;
9596
+ }
9597
+ }
9598
+
9599
+ if (isNaN(radius) || radius <= 0) {
9600
+ return;
9601
+ }
9602
+
9603
+ switch (style) {
9604
+ // Default includes circle
9605
+ default:
9606
+ ctx.beginPath();
9607
+ ctx.arc(x, y, radius, 0, Math.PI * 2);
9608
+ ctx.closePath();
9609
+ ctx.fill();
9610
+ break;
9611
+ case 'triangle':
9612
+ ctx.beginPath();
9613
+ edgeLength = 3 * radius / Math.sqrt(3);
9614
+ height = edgeLength * Math.sqrt(3) / 2;
9615
+ ctx.moveTo(x - edgeLength / 2, y + height / 3);
9616
+ ctx.lineTo(x + edgeLength / 2, y + height / 3);
9617
+ ctx.lineTo(x, y - 2 * height / 3);
9618
+ ctx.closePath();
9619
+ ctx.fill();
9620
+ break;
9621
+ case 'rect':
9622
+ size = 1 / Math.SQRT2 * radius;
9623
+ ctx.beginPath();
9624
+ ctx.fillRect(x - size, y - size, 2 * size, 2 * size);
9625
+ ctx.strokeRect(x - size, y - size, 2 * size, 2 * size);
9626
+ break;
9627
+ case 'rectRounded':
9628
+ var offset = radius / Math.SQRT2;
9629
+ var leftX = x - offset;
9630
+ var topY = y - offset;
9631
+ var sideSize = Math.SQRT2 * radius;
9632
+ ctx.beginPath();
9633
+ this.roundedRect(ctx, leftX, topY, sideSize, sideSize, radius / 2);
9634
+ ctx.closePath();
9635
+ ctx.fill();
9636
+ break;
9637
+ case 'rectRot':
9638
+ size = 1 / Math.SQRT2 * radius;
9639
+ ctx.beginPath();
9640
+ ctx.moveTo(x - size, y);
9641
+ ctx.lineTo(x, y + size);
9642
+ ctx.lineTo(x + size, y);
9643
+ ctx.lineTo(x, y - size);
9644
+ ctx.closePath();
9645
+ ctx.fill();
9646
+ break;
9647
+ case 'cross':
9648
+ ctx.beginPath();
9649
+ ctx.moveTo(x, y + radius);
9650
+ ctx.lineTo(x, y - radius);
9651
+ ctx.moveTo(x - radius, y);
9652
+ ctx.lineTo(x + radius, y);
9653
+ ctx.closePath();
9654
+ break;
9655
+ case 'crossRot':
9656
+ ctx.beginPath();
9657
+ xOffset = Math.cos(Math.PI / 4) * radius;
9658
+ yOffset = Math.sin(Math.PI / 4) * radius;
9659
+ ctx.moveTo(x - xOffset, y - yOffset);
9660
+ ctx.lineTo(x + xOffset, y + yOffset);
9661
+ ctx.moveTo(x - xOffset, y + yOffset);
9662
+ ctx.lineTo(x + xOffset, y - yOffset);
9663
+ ctx.closePath();
9664
+ break;
9665
+ case 'star':
9666
+ ctx.beginPath();
9667
+ ctx.moveTo(x, y + radius);
9668
+ ctx.lineTo(x, y - radius);
9669
+ ctx.moveTo(x - radius, y);
9670
+ ctx.lineTo(x + radius, y);
9671
+ xOffset = Math.cos(Math.PI / 4) * radius;
9672
+ yOffset = Math.sin(Math.PI / 4) * radius;
9673
+ ctx.moveTo(x - xOffset, y - yOffset);
9674
+ ctx.lineTo(x + xOffset, y + yOffset);
9675
+ ctx.moveTo(x - xOffset, y + yOffset);
9676
+ ctx.lineTo(x + xOffset, y - yOffset);
9677
+ ctx.closePath();
9678
+ break;
9679
+ case 'line':
9680
+ ctx.beginPath();
9681
+ ctx.moveTo(x - radius, y);
9682
+ ctx.lineTo(x + radius, y);
9683
+ ctx.closePath();
9684
+ break;
9685
+ case 'dash':
9686
+ ctx.beginPath();
9687
+ ctx.moveTo(x, y);
9688
+ ctx.lineTo(x + radius, y);
9689
+ ctx.closePath();
9690
+ break;
9691
+ }
9692
+
9693
+ ctx.stroke();
9694
+ },
9695
+
9696
+ clipArea: function(ctx, area) {
9697
+ ctx.save();
9698
+ ctx.beginPath();
9699
+ ctx.rect(area.left, area.top, area.right - area.left, area.bottom - area.top);
9700
+ ctx.clip();
9701
+ },
9702
+
9703
+ unclipArea: function(ctx) {
9704
+ ctx.restore();
9705
+ },
9706
+
9707
+ lineTo: function(ctx, previous, target, flip) {
9708
+ if (target.steppedLine) {
9709
+ if ((target.steppedLine === 'after' && !flip) || (target.steppedLine !== 'after' && flip)) {
9710
+ ctx.lineTo(previous.x, target.y);
9711
+ } else {
9712
+ ctx.lineTo(target.x, previous.y);
9713
+ }
9714
+ ctx.lineTo(target.x, target.y);
9715
+ return;
9716
+ }
9717
+
9718
+ if (!target.tension) {
9719
+ ctx.lineTo(target.x, target.y);
9720
+ return;
9721
+ }
9722
+
9723
+ ctx.bezierCurveTo(
9724
+ flip ? previous.controlPointPreviousX : previous.controlPointNextX,
9725
+ flip ? previous.controlPointPreviousY : previous.controlPointNextY,
9726
+ flip ? target.controlPointNextX : target.controlPointPreviousX,
9727
+ flip ? target.controlPointNextY : target.controlPointPreviousY,
9728
+ target.x,
9729
+ target.y);
9730
+ }
9731
+ };
9732
+
9733
+ // DEPRECATIONS
9734
+
9735
+ /**
9736
+ * Provided for backward compatibility, use Chart.helpers.canvas.clear instead.
9737
+ * @namespace Chart.helpers.clear
9738
+ * @deprecated since version 2.7.0
9739
+ * @todo remove at version 3
9740
+ * @private
9741
+ */
9742
+ helpers.clear = exports.clear;
9743
+
9744
+ /**
9745
+ * Provided for backward compatibility, use Chart.helpers.canvas.roundedRect instead.
9746
+ * @namespace Chart.helpers.drawRoundedRectangle
9747
+ * @deprecated since version 2.7.0
9748
+ * @todo remove at version 3
9749
+ * @private
9750
+ */
9751
+ helpers.drawRoundedRectangle = function(ctx) {
9752
+ ctx.beginPath();
9753
+ exports.roundedRect.apply(exports, arguments);
9754
+ ctx.closePath();
9755
+ };
9756
+
9757
+ },{"42":42}],42:[function(require,module,exports){
9758
+ 'use strict';
9759
+
9760
+ /**
9761
+ * @namespace Chart.helpers
9762
+ */
9763
+ var helpers = {
9764
+ /**
9765
+ * An empty function that can be used, for example, for optional callback.
9766
+ */
9767
+ noop: function() {},
9768
+
9769
+ /**
9770
+ * Returns a unique id, sequentially generated from a global variable.
9771
+ * @returns {Number}
9772
+ * @function
9773
+ */
9774
+ uid: (function() {
9775
+ var id = 0;
9776
+ return function() {
9777
+ return id++;
9778
+ };
9779
+ }()),
9780
+
9781
+ /**
9782
+ * Returns true if `value` is neither null nor undefined, else returns false.
9783
+ * @param {*} value - The value to test.
9784
+ * @returns {Boolean}
9785
+ * @since 2.7.0
9786
+ */
9787
+ isNullOrUndef: function(value) {
9788
+ return value === null || typeof value === 'undefined';
9789
+ },
9790
+
9791
+ /**
9792
+ * Returns true if `value` is an array, else returns false.
9793
+ * @param {*} value - The value to test.
9794
+ * @returns {Boolean}
9795
+ * @function
9796
+ */
9797
+ isArray: Array.isArray ? Array.isArray : function(value) {
9798
+ return Object.prototype.toString.call(value) === '[object Array]';
9799
+ },
9800
+
9801
+ /**
9802
+ * Returns true if `value` is an object (excluding null), else returns false.
9803
+ * @param {*} value - The value to test.
9804
+ * @returns {Boolean}
9805
+ * @since 2.7.0
9806
+ */
9807
+ isObject: function(value) {
9808
+ return value !== null && Object.prototype.toString.call(value) === '[object Object]';
9809
+ },
9810
+
9811
+ /**
9812
+ * Returns `value` if defined, else returns `defaultValue`.
9813
+ * @param {*} value - The value to return if defined.
9814
+ * @param {*} defaultValue - The value to return if `value` is undefined.
9815
+ * @returns {*}
9816
+ */
9817
+ valueOrDefault: function(value, defaultValue) {
9818
+ return typeof value === 'undefined' ? defaultValue : value;
9819
+ },
9820
+
9821
+ /**
9822
+ * Returns value at the given `index` in array if defined, else returns `defaultValue`.
9823
+ * @param {Array} value - The array to lookup for value at `index`.
9824
+ * @param {Number} index - The index in `value` to lookup for value.
9825
+ * @param {*} defaultValue - The value to return if `value[index]` is undefined.
9826
+ * @returns {*}
9827
+ */
9828
+ valueAtIndexOrDefault: function(value, index, defaultValue) {
9829
+ return helpers.valueOrDefault(helpers.isArray(value) ? value[index] : value, defaultValue);
9830
+ },
9831
+
9832
+ /**
9833
+ * Calls `fn` with the given `args` in the scope defined by `thisArg` and returns the
9834
+ * value returned by `fn`. If `fn` is not a function, this method returns undefined.
9835
+ * @param {Function} fn - The function to call.
9836
+ * @param {Array|undefined|null} args - The arguments with which `fn` should be called.
9837
+ * @param {Object} [thisArg] - The value of `this` provided for the call to `fn`.
9838
+ * @returns {*}
9839
+ */
9840
+ callback: function(fn, args, thisArg) {
9841
+ if (fn && typeof fn.call === 'function') {
9842
+ return fn.apply(thisArg, args);
9843
+ }
9844
+ },
9845
+
9846
+ /**
9847
+ * Note(SB) for performance sake, this method should only be used when loopable type
9848
+ * is unknown or in none intensive code (not called often and small loopable). Else
9849
+ * it's preferable to use a regular for() loop and save extra function calls.
9850
+ * @param {Object|Array} loopable - The object or array to be iterated.
9851
+ * @param {Function} fn - The function to call for each item.
9852
+ * @param {Object} [thisArg] - The value of `this` provided for the call to `fn`.
9853
+ * @param {Boolean} [reverse] - If true, iterates backward on the loopable.
9854
+ */
9855
+ each: function(loopable, fn, thisArg, reverse) {
9856
+ var i, len, keys;
9857
+ if (helpers.isArray(loopable)) {
9858
+ len = loopable.length;
9859
+ if (reverse) {
9860
+ for (i = len - 1; i >= 0; i--) {
9861
+ fn.call(thisArg, loopable[i], i);
9862
+ }
9863
+ } else {
9864
+ for (i = 0; i < len; i++) {
9865
+ fn.call(thisArg, loopable[i], i);
9866
+ }
9867
+ }
9868
+ } else if (helpers.isObject(loopable)) {
9869
+ keys = Object.keys(loopable);
9870
+ len = keys.length;
9871
+ for (i = 0; i < len; i++) {
9872
+ fn.call(thisArg, loopable[keys[i]], keys[i]);
9873
+ }
9874
+ }
9875
+ },
9876
+
9877
+ /**
9878
+ * Returns true if the `a0` and `a1` arrays have the same content, else returns false.
9879
+ * @see http://stackoverflow.com/a/14853974
9880
+ * @param {Array} a0 - The array to compare
9881
+ * @param {Array} a1 - The array to compare
9882
+ * @returns {Boolean}
9883
+ */
9884
+ arrayEquals: function(a0, a1) {
9885
+ var i, ilen, v0, v1;
9886
+
9887
+ if (!a0 || !a1 || a0.length !== a1.length) {
9888
+ return false;
9889
+ }
9890
+
9891
+ for (i = 0, ilen = a0.length; i < ilen; ++i) {
9892
+ v0 = a0[i];
9893
+ v1 = a1[i];
9894
+
9895
+ if (v0 instanceof Array && v1 instanceof Array) {
9896
+ if (!helpers.arrayEquals(v0, v1)) {
9897
+ return false;
9898
+ }
9899
+ } else if (v0 !== v1) {
9900
+ // NOTE: two different object instances will never be equal: {x:20} != {x:20}
9901
+ return false;
9902
+ }
9903
+ }
9904
+
9905
+ return true;
9906
+ },
9907
+
9908
+ /**
9909
+ * Returns a deep copy of `source` without keeping references on objects and arrays.
9910
+ * @param {*} source - The value to clone.
9911
+ * @returns {*}
9912
+ */
9913
+ clone: function(source) {
9914
+ if (helpers.isArray(source)) {
9915
+ return source.map(helpers.clone);
9916
+ }
9917
+
9918
+ if (helpers.isObject(source)) {
9919
+ var target = {};
9920
+ var keys = Object.keys(source);
9921
+ var klen = keys.length;
9922
+ var k = 0;
9923
+
9924
+ for (; k < klen; ++k) {
9925
+ target[keys[k]] = helpers.clone(source[keys[k]]);
9926
+ }
9927
+
9928
+ return target;
9929
+ }
9930
+
9931
+ return source;
9932
+ },
9933
+
9934
+ /**
9935
+ * The default merger when Chart.helpers.merge is called without merger option.
9936
+ * Note(SB): this method is also used by configMerge and scaleMerge as fallback.
9937
+ * @private
9938
+ */
9939
+ _merger: function(key, target, source, options) {
9940
+ var tval = target[key];
9941
+ var sval = source[key];
9942
+
9943
+ if (helpers.isObject(tval) && helpers.isObject(sval)) {
9944
+ helpers.merge(tval, sval, options);
9945
+ } else {
9946
+ target[key] = helpers.clone(sval);
9947
+ }
9948
+ },
9949
+
9950
+ /**
9951
+ * Merges source[key] in target[key] only if target[key] is undefined.
9952
+ * @private
9953
+ */
9954
+ _mergerIf: function(key, target, source) {
9955
+ var tval = target[key];
9956
+ var sval = source[key];
9957
+
9958
+ if (helpers.isObject(tval) && helpers.isObject(sval)) {
9959
+ helpers.mergeIf(tval, sval);
9960
+ } else if (!target.hasOwnProperty(key)) {
9961
+ target[key] = helpers.clone(sval);
9962
+ }
9963
+ },
9964
+
9965
+ /**
9966
+ * Recursively deep copies `source` properties into `target` with the given `options`.
9967
+ * IMPORTANT: `target` is not cloned and will be updated with `source` properties.
9968
+ * @param {Object} target - The target object in which all sources are merged into.
9969
+ * @param {Object|Array(Object)} source - Object(s) to merge into `target`.
9970
+ * @param {Object} [options] - Merging options:
9971
+ * @param {Function} [options.merger] - The merge method (key, target, source, options)
9972
+ * @returns {Object} The `target` object.
9973
+ */
9974
+ merge: function(target, source, options) {
9975
+ var sources = helpers.isArray(source) ? source : [source];
9976
+ var ilen = sources.length;
9977
+ var merge, i, keys, klen, k;
9978
+
9979
+ if (!helpers.isObject(target)) {
9980
+ return target;
9981
+ }
9982
+
9983
+ options = options || {};
9984
+ merge = options.merger || helpers._merger;
9985
+
9986
+ for (i = 0; i < ilen; ++i) {
9987
+ source = sources[i];
9988
+ if (!helpers.isObject(source)) {
9989
+ continue;
9990
+ }
9991
+
9992
+ keys = Object.keys(source);
9993
+ for (k = 0, klen = keys.length; k < klen; ++k) {
9994
+ merge(keys[k], target, source, options);
9995
+ }
9996
+ }
9997
+
9998
+ return target;
9999
+ },
10000
+
10001
+ /**
10002
+ * Recursively deep copies `source` properties into `target` *only* if not defined in target.
10003
+ * IMPORTANT: `target` is not cloned and will be updated with `source` properties.
10004
+ * @param {Object} target - The target object in which all sources are merged into.
10005
+ * @param {Object|Array(Object)} source - Object(s) to merge into `target`.
10006
+ * @returns {Object} The `target` object.
10007
+ */
10008
+ mergeIf: function(target, source) {
10009
+ return helpers.merge(target, source, {merger: helpers._mergerIf});
10010
+ },
10011
+
10012
+ /**
10013
+ * Applies the contents of two or more objects together into the first object.
10014
+ * @param {Object} target - The target object in which all objects are merged into.
10015
+ * @param {Object} arg1 - Object containing additional properties to merge in target.
10016
+ * @param {Object} argN - Additional objects containing properties to merge in target.
10017
+ * @returns {Object} The `target` object.
10018
+ */
10019
+ extend: function(target) {
10020
+ var setFn = function(value, key) {
10021
+ target[key] = value;
10022
+ };
10023
+ for (var i = 1, ilen = arguments.length; i < ilen; ++i) {
10024
+ helpers.each(arguments[i], setFn);
10025
+ }
10026
+ return target;
10027
+ },
10028
+
10029
+ /**
10030
+ * Basic javascript inheritance based on the model created in Backbone.js
10031
+ */
10032
+ inherits: function(extensions) {
10033
+ var me = this;
10034
+ var ChartElement = (extensions && extensions.hasOwnProperty('constructor')) ? extensions.constructor : function() {
10035
+ return me.apply(this, arguments);
10036
+ };
10037
+
10038
+ var Surrogate = function() {
10039
+ this.constructor = ChartElement;
10040
+ };
10041
+
10042
+ Surrogate.prototype = me.prototype;
10043
+ ChartElement.prototype = new Surrogate();
10044
+ ChartElement.extend = helpers.inherits;
10045
+
10046
+ if (extensions) {
10047
+ helpers.extend(ChartElement.prototype, extensions);
10048
+ }
10049
+
10050
+ ChartElement.__super__ = me.prototype;
10051
+ return ChartElement;
10052
+ }
10053
+ };
10054
+
10055
+ module.exports = helpers;
10056
+
10057
+ // DEPRECATIONS
10058
+
10059
+ /**
10060
+ * Provided for backward compatibility, use Chart.helpers.callback instead.
10061
+ * @function Chart.helpers.callCallback
10062
+ * @deprecated since version 2.6.0
10063
+ * @todo remove at version 3
10064
+ * @private
10065
+ */
10066
+ helpers.callCallback = helpers.callback;
10067
+
10068
+ /**
10069
+ * Provided for backward compatibility, use Array.prototype.indexOf instead.
10070
+ * Array.prototype.indexOf compatibility: Chrome, Opera, Safari, FF1.5+, IE9+
10071
+ * @function Chart.helpers.indexOf
10072
+ * @deprecated since version 2.7.0
10073
+ * @todo remove at version 3
10074
+ * @private
10075
+ */
10076
+ helpers.indexOf = function(array, item, fromIndex) {
10077
+ return Array.prototype.indexOf.call(array, item, fromIndex);
10078
+ };
10079
+
10080
+ /**
10081
+ * Provided for backward compatibility, use Chart.helpers.valueOrDefault instead.
10082
+ * @function Chart.helpers.getValueOrDefault
10083
+ * @deprecated since version 2.7.0
10084
+ * @todo remove at version 3
10085
+ * @private
10086
+ */
10087
+ helpers.getValueOrDefault = helpers.valueOrDefault;
10088
+
10089
+ /**
10090
+ * Provided for backward compatibility, use Chart.helpers.valueAtIndexOrDefault instead.
10091
+ * @function Chart.helpers.getValueAtIndexOrDefault
10092
+ * @deprecated since version 2.7.0
10093
+ * @todo remove at version 3
10094
+ * @private
10095
+ */
10096
+ helpers.getValueAtIndexOrDefault = helpers.valueAtIndexOrDefault;
10097
+
10098
+ },{}],43:[function(require,module,exports){
10099
+ 'use strict';
10100
+
10101
+ var helpers = require(42);
10102
+
10103
+ /**
10104
+ * Easing functions adapted from Robert Penner's easing equations.
10105
+ * @namespace Chart.helpers.easingEffects
10106
+ * @see http://www.robertpenner.com/easing/
10107
+ */
10108
+ var effects = {
10109
+ linear: function(t) {
10110
+ return t;
10111
+ },
10112
+
10113
+ easeInQuad: function(t) {
10114
+ return t * t;
10115
+ },
10116
+
10117
+ easeOutQuad: function(t) {
10118
+ return -t * (t - 2);
10119
+ },
10120
+
10121
+ easeInOutQuad: function(t) {
10122
+ if ((t /= 0.5) < 1) {
10123
+ return 0.5 * t * t;
10124
+ }
10125
+ return -0.5 * ((--t) * (t - 2) - 1);
10126
+ },
10127
+
10128
+ easeInCubic: function(t) {
10129
+ return t * t * t;
10130
+ },
10131
+
10132
+ easeOutCubic: function(t) {
10133
+ return (t = t - 1) * t * t + 1;
10134
+ },
10135
+
10136
+ easeInOutCubic: function(t) {
10137
+ if ((t /= 0.5) < 1) {
10138
+ return 0.5 * t * t * t;
10139
+ }
10140
+ return 0.5 * ((t -= 2) * t * t + 2);
10141
+ },
10142
+
10143
+ easeInQuart: function(t) {
10144
+ return t * t * t * t;
10145
+ },
10146
+
10147
+ easeOutQuart: function(t) {
10148
+ return -((t = t - 1) * t * t * t - 1);
10149
+ },
10150
+
10151
+ easeInOutQuart: function(t) {
10152
+ if ((t /= 0.5) < 1) {
10153
+ return 0.5 * t * t * t * t;
10154
+ }
10155
+ return -0.5 * ((t -= 2) * t * t * t - 2);
10156
+ },
10157
+
10158
+ easeInQuint: function(t) {
10159
+ return t * t * t * t * t;
10160
+ },
10161
+
10162
+ easeOutQuint: function(t) {
10163
+ return (t = t - 1) * t * t * t * t + 1;
10164
+ },
10165
+
10166
+ easeInOutQuint: function(t) {
10167
+ if ((t /= 0.5) < 1) {
10168
+ return 0.5 * t * t * t * t * t;
10169
+ }
10170
+ return 0.5 * ((t -= 2) * t * t * t * t + 2);
10171
+ },
10172
+
10173
+ easeInSine: function(t) {
10174
+ return -Math.cos(t * (Math.PI / 2)) + 1;
10175
+ },
10176
+
10177
+ easeOutSine: function(t) {
10178
+ return Math.sin(t * (Math.PI / 2));
10179
+ },
10180
+
10181
+ easeInOutSine: function(t) {
10182
+ return -0.5 * (Math.cos(Math.PI * t) - 1);
10183
+ },
10184
+
10185
+ easeInExpo: function(t) {
10186
+ return (t === 0) ? 0 : Math.pow(2, 10 * (t - 1));
10187
+ },
10188
+
10189
+ easeOutExpo: function(t) {
10190
+ return (t === 1) ? 1 : -Math.pow(2, -10 * t) + 1;
10191
+ },
10192
+
10193
+ easeInOutExpo: function(t) {
10194
+ if (t === 0) {
10195
+ return 0;
10196
+ }
10197
+ if (t === 1) {
10198
+ return 1;
10199
+ }
10200
+ if ((t /= 0.5) < 1) {
10201
+ return 0.5 * Math.pow(2, 10 * (t - 1));
10202
+ }
10203
+ return 0.5 * (-Math.pow(2, -10 * --t) + 2);
10204
+ },
10205
+
10206
+ easeInCirc: function(t) {
10207
+ if (t >= 1) {
10208
+ return t;
10209
+ }
10210
+ return -(Math.sqrt(1 - t * t) - 1);
10211
+ },
10212
+
10213
+ easeOutCirc: function(t) {
10214
+ return Math.sqrt(1 - (t = t - 1) * t);
10215
+ },
10216
+
10217
+ easeInOutCirc: function(t) {
10218
+ if ((t /= 0.5) < 1) {
10219
+ return -0.5 * (Math.sqrt(1 - t * t) - 1);
10220
+ }
10221
+ return 0.5 * (Math.sqrt(1 - (t -= 2) * t) + 1);
10222
+ },
10223
+
10224
+ easeInElastic: function(t) {
10225
+ var s = 1.70158;
10226
+ var p = 0;
10227
+ var a = 1;
10228
+ if (t === 0) {
10229
+ return 0;
10230
+ }
10231
+ if (t === 1) {
10232
+ return 1;
10233
+ }
10234
+ if (!p) {
10235
+ p = 0.3;
10236
+ }
10237
+ if (a < 1) {
10238
+ a = 1;
10239
+ s = p / 4;
10240
+ } else {
10241
+ s = p / (2 * Math.PI) * Math.asin(1 / a);
10242
+ }
10243
+ return -(a * Math.pow(2, 10 * (t -= 1)) * Math.sin((t - s) * (2 * Math.PI) / p));
10244
+ },
10245
+
10246
+ easeOutElastic: function(t) {
10247
+ var s = 1.70158;
10248
+ var p = 0;
10249
+ var a = 1;
10250
+ if (t === 0) {
10251
+ return 0;
10252
+ }
10253
+ if (t === 1) {
10254
+ return 1;
10255
+ }
10256
+ if (!p) {
10257
+ p = 0.3;
10258
+ }
10259
+ if (a < 1) {
10260
+ a = 1;
10261
+ s = p / 4;
10262
+ } else {
10263
+ s = p / (2 * Math.PI) * Math.asin(1 / a);
10264
+ }
10265
+ return a * Math.pow(2, -10 * t) * Math.sin((t - s) * (2 * Math.PI) / p) + 1;
10266
+ },
10267
+
10268
+ easeInOutElastic: function(t) {
10269
+ var s = 1.70158;
10270
+ var p = 0;
10271
+ var a = 1;
10272
+ if (t === 0) {
10273
+ return 0;
10274
+ }
10275
+ if ((t /= 0.5) === 2) {
10276
+ return 1;
10277
+ }
10278
+ if (!p) {
10279
+ p = 0.45;
10280
+ }
10281
+ if (a < 1) {
10282
+ a = 1;
10283
+ s = p / 4;
10284
+ } else {
10285
+ s = p / (2 * Math.PI) * Math.asin(1 / a);
10286
+ }
10287
+ if (t < 1) {
10288
+ return -0.5 * (a * Math.pow(2, 10 * (t -= 1)) * Math.sin((t - s) * (2 * Math.PI) / p));
10289
+ }
10290
+ return a * Math.pow(2, -10 * (t -= 1)) * Math.sin((t - s) * (2 * Math.PI) / p) * 0.5 + 1;
10291
+ },
10292
+ easeInBack: function(t) {
10293
+ var s = 1.70158;
10294
+ return t * t * ((s + 1) * t - s);
10295
+ },
10296
+
10297
+ easeOutBack: function(t) {
10298
+ var s = 1.70158;
10299
+ return (t = t - 1) * t * ((s + 1) * t + s) + 1;
10300
+ },
10301
+
10302
+ easeInOutBack: function(t) {
10303
+ var s = 1.70158;
10304
+ if ((t /= 0.5) < 1) {
10305
+ return 0.5 * (t * t * (((s *= (1.525)) + 1) * t - s));
10306
+ }
10307
+ return 0.5 * ((t -= 2) * t * (((s *= (1.525)) + 1) * t + s) + 2);
10308
+ },
10309
+
10310
+ easeInBounce: function(t) {
10311
+ return 1 - effects.easeOutBounce(1 - t);
10312
+ },
10313
+
10314
+ easeOutBounce: function(t) {
10315
+ if (t < (1 / 2.75)) {
10316
+ return 7.5625 * t * t;
10317
+ }
10318
+ if (t < (2 / 2.75)) {
10319
+ return 7.5625 * (t -= (1.5 / 2.75)) * t + 0.75;
10320
+ }
10321
+ if (t < (2.5 / 2.75)) {
10322
+ return 7.5625 * (t -= (2.25 / 2.75)) * t + 0.9375;
10323
+ }
10324
+ return 7.5625 * (t -= (2.625 / 2.75)) * t + 0.984375;
10325
+ },
10326
+
10327
+ easeInOutBounce: function(t) {
10328
+ if (t < 0.5) {
10329
+ return effects.easeInBounce(t * 2) * 0.5;
10330
+ }
10331
+ return effects.easeOutBounce(t * 2 - 1) * 0.5 + 0.5;
10332
+ }
10333
+ };
10334
+
10335
+ module.exports = {
10336
+ effects: effects
10337
+ };
10338
+
10339
+ // DEPRECATIONS
10340
+
10341
+ /**
10342
+ * Provided for backward compatibility, use Chart.helpers.easing.effects instead.
10343
+ * @function Chart.helpers.easingEffects
10344
+ * @deprecated since version 2.7.0
10345
+ * @todo remove at version 3
10346
+ * @private
10347
+ */
10348
+ helpers.easingEffects = effects;
10349
+
10350
+ },{"42":42}],44:[function(require,module,exports){
10351
+ 'use strict';
10352
+
10353
+ var helpers = require(42);
10354
+
10355
+ /**
10356
+ * @alias Chart.helpers.options
10357
+ * @namespace
10358
+ */
10359
+ module.exports = {
10360
+ /**
10361
+ * Converts the given line height `value` in pixels for a specific font `size`.
10362
+ * @param {Number|String} value - The lineHeight to parse (eg. 1.6, '14px', '75%', '1.6em').
10363
+ * @param {Number} size - The font size (in pixels) used to resolve relative `value`.
10364
+ * @returns {Number} The effective line height in pixels (size * 1.2 if value is invalid).
10365
+ * @see https://developer.mozilla.org/en-US/docs/Web/CSS/line-height
10366
+ * @since 2.7.0
10367
+ */
10368
+ toLineHeight: function(value, size) {
10369
+ var matches = ('' + value).match(/^(normal|(\d+(?:\.\d+)?)(px|em|%)?)$/);
10370
+ if (!matches || matches[1] === 'normal') {
10371
+ return size * 1.2;
10372
+ }
10373
+
10374
+ value = +matches[2];
10375
+
10376
+ switch (matches[3]) {
10377
+ case 'px':
10378
+ return value;
10379
+ case '%':
10380
+ value /= 100;
10381
+ break;
10382
+ default:
10383
+ break;
10384
+ }
10385
+
10386
+ return size * value;
10387
+ },
10388
+
10389
+ /**
10390
+ * Converts the given value into a padding object with pre-computed width/height.
10391
+ * @param {Number|Object} value - If a number, set the value to all TRBL component,
10392
+ * else, if and object, use defined properties and sets undefined ones to 0.
10393
+ * @returns {Object} The padding values (top, right, bottom, left, width, height)
10394
+ * @since 2.7.0
10395
+ */
10396
+ toPadding: function(value) {
10397
+ var t, r, b, l;
10398
+
10399
+ if (helpers.isObject(value)) {
10400
+ t = +value.top || 0;
10401
+ r = +value.right || 0;
10402
+ b = +value.bottom || 0;
10403
+ l = +value.left || 0;
10404
+ } else {
10405
+ t = r = b = l = +value || 0;
10406
+ }
10407
+
10408
+ return {
10409
+ top: t,
10410
+ right: r,
10411
+ bottom: b,
10412
+ left: l,
10413
+ height: t + b,
10414
+ width: l + r
10415
+ };
10416
+ },
10417
+
10418
+ /**
10419
+ * Evaluates the given `inputs` sequentially and returns the first defined value.
10420
+ * @param {Array[]} inputs - An array of values, falling back to the last value.
10421
+ * @param {Object} [context] - If defined and the current value is a function, the value
10422
+ * is called with `context` as first argument and the result becomes the new input.
10423
+ * @param {Number} [index] - If defined and the current value is an array, the value
10424
+ * at `index` become the new input.
10425
+ * @since 2.7.0
10426
+ */
10427
+ resolve: function(inputs, context, index) {
10428
+ var i, ilen, value;
10429
+
10430
+ for (i = 0, ilen = inputs.length; i < ilen; ++i) {
10431
+ value = inputs[i];
10432
+ if (value === undefined) {
10433
+ continue;
10434
+ }
10435
+ if (context !== undefined && typeof value === 'function') {
10436
+ value = value(context);
10437
+ }
10438
+ if (index !== undefined && helpers.isArray(value)) {
10439
+ value = value[index];
10440
+ }
10441
+ if (value !== undefined) {
10442
+ return value;
10443
+ }
10444
+ }
10445
+ }
10446
+ };
10447
+
10448
+ },{"42":42}],45:[function(require,module,exports){
10449
+ 'use strict';
10450
+
10451
+ module.exports = require(42);
10452
+ module.exports.easing = require(43);
10453
+ module.exports.canvas = require(41);
10454
+ module.exports.options = require(44);
10455
+
10456
+ },{"41":41,"42":42,"43":43,"44":44}],46:[function(require,module,exports){
10457
+ /**
10458
+ * Platform fallback implementation (minimal).
10459
+ * @see https://github.com/chartjs/Chart.js/pull/4591#issuecomment-319575939
10460
+ */
10461
+
10462
+ module.exports = {
10463
+ acquireContext: function(item) {
10464
+ if (item && item.canvas) {
10465
+ // Support for any object associated to a canvas (including a context2d)
10466
+ item = item.canvas;
10467
+ }
10468
+
10469
+ return item && item.getContext('2d') || null;
10470
+ }
10471
+ };
10472
+
10473
+ },{}],47:[function(require,module,exports){
10474
+ /**
10475
+ * Chart.Platform implementation for targeting a web browser
10476
+ */
10477
+
10478
+ 'use strict';
10479
+
10480
+ var helpers = require(45);
10481
+
10482
+ var EXPANDO_KEY = '$chartjs';
10483
+ var CSS_PREFIX = 'chartjs-';
10484
+ var CSS_RENDER_MONITOR = CSS_PREFIX + 'render-monitor';
10485
+ var CSS_RENDER_ANIMATION = CSS_PREFIX + 'render-animation';
10486
+ var ANIMATION_START_EVENTS = ['animationstart', 'webkitAnimationStart'];
10487
+
10488
+ /**
10489
+ * DOM event types -> Chart.js event types.
10490
+ * Note: only events with different types are mapped.
10491
+ * @see https://developer.mozilla.org/en-US/docs/Web/Events
10492
+ */
10493
+ var EVENT_TYPES = {
10494
+ touchstart: 'mousedown',
10495
+ touchmove: 'mousemove',
10496
+ touchend: 'mouseup',
10497
+ pointerenter: 'mouseenter',
10498
+ pointerdown: 'mousedown',
10499
+ pointermove: 'mousemove',
10500
+ pointerup: 'mouseup',
10501
+ pointerleave: 'mouseout',
10502
+ pointerout: 'mouseout'
10503
+ };
10504
+
10505
+ /**
10506
+ * The "used" size is the final value of a dimension property after all calculations have
10507
+ * been performed. This method uses the computed style of `element` but returns undefined
10508
+ * if the computed style is not expressed in pixels. That can happen in some cases where
10509
+ * `element` has a size relative to its parent and this last one is not yet displayed,
10510
+ * for example because of `display: none` on a parent node.
10511
+ * @see https://developer.mozilla.org/en-US/docs/Web/CSS/used_value
10512
+ * @returns {Number} Size in pixels or undefined if unknown.
10513
+ */
10514
+ function readUsedSize(element, property) {
10515
+ var value = helpers.getStyle(element, property);
10516
+ var matches = value && value.match(/^(\d+)(\.\d+)?px$/);
10517
+ return matches ? Number(matches[1]) : undefined;
10518
+ }
10519
+
10520
+ /**
10521
+ * Initializes the canvas style and render size without modifying the canvas display size,
10522
+ * since responsiveness is handled by the controller.resize() method. The config is used
10523
+ * to determine the aspect ratio to apply in case no explicit height has been specified.
10524
+ */
10525
+ function initCanvas(canvas, config) {
10526
+ var style = canvas.style;
10527
+
10528
+ // NOTE(SB) canvas.getAttribute('width') !== canvas.width: in the first case it
10529
+ // returns null or '' if no explicit value has been set to the canvas attribute.
10530
+ var renderHeight = canvas.getAttribute('height');
10531
+ var renderWidth = canvas.getAttribute('width');
10532
+
10533
+ // Chart.js modifies some canvas values that we want to restore on destroy
10534
+ canvas[EXPANDO_KEY] = {
10535
+ initial: {
10536
+ height: renderHeight,
10537
+ width: renderWidth,
10538
+ style: {
10539
+ display: style.display,
10540
+ height: style.height,
10541
+ width: style.width
10542
+ }
10543
+ }
10544
+ };
10545
+
10546
+ // Force canvas to display as block to avoid extra space caused by inline
10547
+ // elements, which would interfere with the responsive resize process.
10548
+ // https://github.com/chartjs/Chart.js/issues/2538
10549
+ style.display = style.display || 'block';
10550
+
10551
+ if (renderWidth === null || renderWidth === '') {
10552
+ var displayWidth = readUsedSize(canvas, 'width');
10553
+ if (displayWidth !== undefined) {
10554
+ canvas.width = displayWidth;
10555
+ }
10556
+ }
10557
+
10558
+ if (renderHeight === null || renderHeight === '') {
10559
+ if (canvas.style.height === '') {
10560
+ // If no explicit render height and style height, let's apply the aspect ratio,
10561
+ // which one can be specified by the user but also by charts as default option
10562
+ // (i.e. options.aspectRatio). If not specified, use canvas aspect ratio of 2.
10563
+ canvas.height = canvas.width / (config.options.aspectRatio || 2);
10564
+ } else {
10565
+ var displayHeight = readUsedSize(canvas, 'height');
10566
+ if (displayWidth !== undefined) {
10567
+ canvas.height = displayHeight;
10568
+ }
10569
+ }
10570
+ }
10571
+
10572
+ return canvas;
10573
+ }
10574
+
10575
+ /**
10576
+ * Detects support for options object argument in addEventListener.
10577
+ * https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener#Safely_detecting_option_support
10578
+ * @private
10579
+ */
10580
+ var supportsEventListenerOptions = (function() {
10581
+ var supports = false;
10582
+ try {
10583
+ var options = Object.defineProperty({}, 'passive', {
10584
+ get: function() {
10585
+ supports = true;
10586
+ }
10587
+ });
10588
+ window.addEventListener('e', null, options);
10589
+ } catch (e) {
10590
+ // continue regardless of error
10591
+ }
10592
+ return supports;
10593
+ }());
10594
+
10595
+ // Default passive to true as expected by Chrome for 'touchstart' and 'touchend' events.
10596
+ // https://github.com/chartjs/Chart.js/issues/4287
10597
+ var eventListenerOptions = supportsEventListenerOptions ? {passive: true} : false;
10598
+
10599
+ function addEventListener(node, type, listener) {
10600
+ node.addEventListener(type, listener, eventListenerOptions);
10601
+ }
10602
+
10603
+ function removeEventListener(node, type, listener) {
10604
+ node.removeEventListener(type, listener, eventListenerOptions);
10605
+ }
10606
+
10607
+ function createEvent(type, chart, x, y, nativeEvent) {
10608
+ return {
10609
+ type: type,
10610
+ chart: chart,
10611
+ native: nativeEvent || null,
10612
+ x: x !== undefined ? x : null,
10613
+ y: y !== undefined ? y : null,
10614
+ };
10615
+ }
10616
+
10617
+ function fromNativeEvent(event, chart) {
10618
+ var type = EVENT_TYPES[event.type] || event.type;
10619
+ var pos = helpers.getRelativePosition(event, chart);
10620
+ return createEvent(type, chart, pos.x, pos.y, event);
10621
+ }
10622
+
10623
+ function throttled(fn, thisArg) {
10624
+ var ticking = false;
10625
+ var args = [];
10626
+
10627
+ return function() {
10628
+ args = Array.prototype.slice.call(arguments);
10629
+ thisArg = thisArg || this;
10630
+
10631
+ if (!ticking) {
10632
+ ticking = true;
10633
+ helpers.requestAnimFrame.call(window, function() {
10634
+ ticking = false;
10635
+ fn.apply(thisArg, args);
10636
+ });
10637
+ }
10638
+ };
10639
+ }
10640
+
10641
+ // Implementation based on https://github.com/marcj/css-element-queries
10642
+ function createResizer(handler) {
10643
+ var resizer = document.createElement('div');
10644
+ var cls = CSS_PREFIX + 'size-monitor';
10645
+ var maxSize = 1000000;
10646
+ var style =
10647
+ 'position:absolute;' +
10648
+ 'left:0;' +
10649
+ 'top:0;' +
10650
+ 'right:0;' +
10651
+ 'bottom:0;' +
10652
+ 'overflow:hidden;' +
10653
+ 'pointer-events:none;' +
10654
+ 'visibility:hidden;' +
10655
+ 'z-index:-1;';
10656
+
10657
+ resizer.style.cssText = style;
10658
+ resizer.className = cls;
10659
+ resizer.innerHTML =
10660
+ '<div class="' + cls + '-expand" style="' + style + '">' +
10661
+ '<div style="' +
10662
+ 'position:absolute;' +
10663
+ 'width:' + maxSize + 'px;' +
10664
+ 'height:' + maxSize + 'px;' +
10665
+ 'left:0;' +
10666
+ 'top:0">' +
10667
+ '</div>' +
10668
+ '</div>' +
10669
+ '<div class="' + cls + '-shrink" style="' + style + '">' +
10670
+ '<div style="' +
10671
+ 'position:absolute;' +
10672
+ 'width:200%;' +
10673
+ 'height:200%;' +
10674
+ 'left:0; ' +
10675
+ 'top:0">' +
10676
+ '</div>' +
10677
+ '</div>';
10678
+
10679
+ var expand = resizer.childNodes[0];
10680
+ var shrink = resizer.childNodes[1];
10681
+
10682
+ resizer._reset = function() {
10683
+ expand.scrollLeft = maxSize;
10684
+ expand.scrollTop = maxSize;
10685
+ shrink.scrollLeft = maxSize;
10686
+ shrink.scrollTop = maxSize;
10687
+ };
10688
+ var onScroll = function() {
10689
+ resizer._reset();
10690
+ handler();
10691
+ };
10692
+
10693
+ addEventListener(expand, 'scroll', onScroll.bind(expand, 'expand'));
10694
+ addEventListener(shrink, 'scroll', onScroll.bind(shrink, 'shrink'));
10695
+
10696
+ return resizer;
10697
+ }
10698
+
10699
+ // https://davidwalsh.name/detect-node-insertion
10700
+ function watchForRender(node, handler) {
10701
+ var expando = node[EXPANDO_KEY] || (node[EXPANDO_KEY] = {});
10702
+ var proxy = expando.renderProxy = function(e) {
10703
+ if (e.animationName === CSS_RENDER_ANIMATION) {
10704
+ handler();
10705
+ }
10706
+ };
10707
+
10708
+ helpers.each(ANIMATION_START_EVENTS, function(type) {
10709
+ addEventListener(node, type, proxy);
10710
+ });
10711
+
10712
+ // #4737: Chrome might skip the CSS animation when the CSS_RENDER_MONITOR class
10713
+ // is removed then added back immediately (same animation frame?). Accessing the
10714
+ // `offsetParent` property will force a reflow and re-evaluate the CSS animation.
10715
+ // https://gist.github.com/paulirish/5d52fb081b3570c81e3a#box-metrics
10716
+ // https://github.com/chartjs/Chart.js/issues/4737
10717
+ expando.reflow = !!node.offsetParent;
10718
+
10719
+ node.classList.add(CSS_RENDER_MONITOR);
10720
+ }
10721
+
10722
+ function unwatchForRender(node) {
10723
+ var expando = node[EXPANDO_KEY] || {};
10724
+ var proxy = expando.renderProxy;
10725
+
10726
+ if (proxy) {
10727
+ helpers.each(ANIMATION_START_EVENTS, function(type) {
10728
+ removeEventListener(node, type, proxy);
10729
+ });
10730
+
10731
+ delete expando.renderProxy;
10732
+ }
10733
+
10734
+ node.classList.remove(CSS_RENDER_MONITOR);
10735
+ }
10736
+
10737
+ function addResizeListener(node, listener, chart) {
10738
+ var expando = node[EXPANDO_KEY] || (node[EXPANDO_KEY] = {});
10739
+
10740
+ // Let's keep track of this added resizer and thus avoid DOM query when removing it.
10741
+ var resizer = expando.resizer = createResizer(throttled(function() {
10742
+ if (expando.resizer) {
10743
+ return listener(createEvent('resize', chart));
10744
+ }
10745
+ }));
10746
+
10747
+ // The resizer needs to be attached to the node parent, so we first need to be
10748
+ // sure that `node` is attached to the DOM before injecting the resizer element.
10749
+ watchForRender(node, function() {
10750
+ if (expando.resizer) {
10751
+ var container = node.parentNode;
10752
+ if (container && container !== resizer.parentNode) {
10753
+ container.insertBefore(resizer, container.firstChild);
10754
+ }
10755
+
10756
+ // The container size might have changed, let's reset the resizer state.
10757
+ resizer._reset();
10758
+ }
10759
+ });
10760
+ }
10761
+
10762
+ function removeResizeListener(node) {
10763
+ var expando = node[EXPANDO_KEY] || {};
10764
+ var resizer = expando.resizer;
10765
+
10766
+ delete expando.resizer;
10767
+ unwatchForRender(node);
10768
+
10769
+ if (resizer && resizer.parentNode) {
10770
+ resizer.parentNode.removeChild(resizer);
10771
+ }
10772
+ }
10773
+
10774
+ function injectCSS(platform, css) {
10775
+ // http://stackoverflow.com/q/3922139
10776
+ var style = platform._style || document.createElement('style');
10777
+ if (!platform._style) {
10778
+ platform._style = style;
10779
+ css = '/* Chart.js */\n' + css;
10780
+ style.setAttribute('type', 'text/css');
10781
+ document.getElementsByTagName('head')[0].appendChild(style);
10782
+ }
10783
+
10784
+ style.appendChild(document.createTextNode(css));
10785
+ }
10786
+
10787
+ module.exports = {
10788
+ /**
10789
+ * This property holds whether this platform is enabled for the current environment.
10790
+ * Currently used by platform.js to select the proper implementation.
10791
+ * @private
10792
+ */
10793
+ _enabled: typeof window !== 'undefined' && typeof document !== 'undefined',
10794
+
10795
+ initialize: function() {
10796
+ var keyframes = 'from{opacity:0.99}to{opacity:1}';
10797
+
10798
+ injectCSS(this,
10799
+ // DOM rendering detection
10800
+ // https://davidwalsh.name/detect-node-insertion
10801
+ '@-webkit-keyframes ' + CSS_RENDER_ANIMATION + '{' + keyframes + '}' +
10802
+ '@keyframes ' + CSS_RENDER_ANIMATION + '{' + keyframes + '}' +
10803
+ '.' + CSS_RENDER_MONITOR + '{' +
10804
+ '-webkit-animation:' + CSS_RENDER_ANIMATION + ' 0.001s;' +
10805
+ 'animation:' + CSS_RENDER_ANIMATION + ' 0.001s;' +
10806
+ '}'
10807
+ );
10808
+ },
10809
+
10810
+ acquireContext: function(item, config) {
10811
+ if (typeof item === 'string') {
10812
+ item = document.getElementById(item);
10813
+ } else if (item.length) {
10814
+ // Support for array based queries (such as jQuery)
10815
+ item = item[0];
10816
+ }
10817
+
10818
+ if (item && item.canvas) {
10819
+ // Support for any object associated to a canvas (including a context2d)
10820
+ item = item.canvas;
10821
+ }
10822
+
10823
+ // To prevent canvas fingerprinting, some add-ons undefine the getContext
10824
+ // method, for example: https://github.com/kkapsner/CanvasBlocker
10825
+ // https://github.com/chartjs/Chart.js/issues/2807
10826
+ var context = item && item.getContext && item.getContext('2d');
10827
+
10828
+ // `instanceof HTMLCanvasElement/CanvasRenderingContext2D` fails when the item is
10829
+ // inside an iframe or when running in a protected environment. We could guess the
10830
+ // types from their toString() value but let's keep things flexible and assume it's
10831
+ // a sufficient condition if the item has a context2D which has item as `canvas`.
10832
+ // https://github.com/chartjs/Chart.js/issues/3887
10833
+ // https://github.com/chartjs/Chart.js/issues/4102
10834
+ // https://github.com/chartjs/Chart.js/issues/4152
10835
+ if (context && context.canvas === item) {
10836
+ initCanvas(item, config);
10837
+ return context;
10838
+ }
10839
+
10840
+ return null;
10841
+ },
10842
+
10843
+ releaseContext: function(context) {
10844
+ var canvas = context.canvas;
10845
+ if (!canvas[EXPANDO_KEY]) {
10846
+ return;
10847
+ }
10848
+
10849
+ var initial = canvas[EXPANDO_KEY].initial;
10850
+ ['height', 'width'].forEach(function(prop) {
10851
+ var value = initial[prop];
10852
+ if (helpers.isNullOrUndef(value)) {
10853
+ canvas.removeAttribute(prop);
10854
+ } else {
10855
+ canvas.setAttribute(prop, value);
10856
+ }
10857
+ });
10858
+
10859
+ helpers.each(initial.style || {}, function(value, key) {
10860
+ canvas.style[key] = value;
10861
+ });
10862
+
10863
+ // The canvas render size might have been changed (and thus the state stack discarded),
10864
+ // we can't use save() and restore() to restore the initial state. So make sure that at
10865
+ // least the canvas context is reset to the default state by setting the canvas width.
10866
+ // https://www.w3.org/TR/2011/WD-html5-20110525/the-canvas-element.html
10867
+ canvas.width = canvas.width;
10868
+
10869
+ delete canvas[EXPANDO_KEY];
10870
+ },
10871
+
10872
+ addEventListener: function(chart, type, listener) {
10873
+ var canvas = chart.canvas;
10874
+ if (type === 'resize') {
10875
+ // Note: the resize event is not supported on all browsers.
10876
+ addResizeListener(canvas, listener, chart);
10877
+ return;
10878
+ }
10879
+
10880
+ var expando = listener[EXPANDO_KEY] || (listener[EXPANDO_KEY] = {});
10881
+ var proxies = expando.proxies || (expando.proxies = {});
10882
+ var proxy = proxies[chart.id + '_' + type] = function(event) {
10883
+ listener(fromNativeEvent(event, chart));
10884
+ };
10885
+
10886
+ addEventListener(canvas, type, proxy);
10887
+ },
10888
+
10889
+ removeEventListener: function(chart, type, listener) {
10890
+ var canvas = chart.canvas;
10891
+ if (type === 'resize') {
10892
+ // Note: the resize event is not supported on all browsers.
10893
+ removeResizeListener(canvas, listener);
10894
+ return;
10895
+ }
10896
+
10897
+ var expando = listener[EXPANDO_KEY] || {};
10898
+ var proxies = expando.proxies || {};
10899
+ var proxy = proxies[chart.id + '_' + type];
10900
+ if (!proxy) {
10901
+ return;
10902
+ }
10903
+
10904
+ removeEventListener(canvas, type, proxy);
10905
+ }
10906
+ };
10907
+
10908
+ // DEPRECATIONS
10909
+
10910
+ /**
10911
+ * Provided for backward compatibility, use EventTarget.addEventListener instead.
10912
+ * EventTarget.addEventListener compatibility: Chrome, Opera 7, Safari, FF1.5+, IE9+
10913
+ * @see https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener
10914
+ * @function Chart.helpers.addEvent
10915
+ * @deprecated since version 2.7.0
10916
+ * @todo remove at version 3
10917
+ * @private
10918
+ */
10919
+ helpers.addEvent = addEventListener;
10920
+
10921
+ /**
10922
+ * Provided for backward compatibility, use EventTarget.removeEventListener instead.
10923
+ * EventTarget.removeEventListener compatibility: Chrome, Opera 7, Safari, FF1.5+, IE9+
10924
+ * @see https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/removeEventListener
10925
+ * @function Chart.helpers.removeEvent
10926
+ * @deprecated since version 2.7.0
10927
+ * @todo remove at version 3
10928
+ * @private
10929
+ */
10930
+ helpers.removeEvent = removeEventListener;
10931
+
10932
+ },{"45":45}],48:[function(require,module,exports){
10933
+ 'use strict';
10934
+
10935
+ var helpers = require(45);
10936
+ var basic = require(46);
10937
+ var dom = require(47);
10938
+
10939
+ // @TODO Make possible to select another platform at build time.
10940
+ var implementation = dom._enabled ? dom : basic;
10941
+
10942
+ /**
10943
+ * @namespace Chart.platform
10944
+ * @see https://chartjs.gitbooks.io/proposals/content/Platform.html
10945
+ * @since 2.4.0
10946
+ */
10947
+ module.exports = helpers.extend({
10948
+ /**
10949
+ * @since 2.7.0
10950
+ */
10951
+ initialize: function() {},
10952
+
10953
+ /**
10954
+ * Called at chart construction time, returns a context2d instance implementing
10955
+ * the [W3C Canvas 2D Context API standard]{@link https://www.w3.org/TR/2dcontext/}.
10956
+ * @param {*} item - The native item from which to acquire context (platform specific)
10957
+ * @param {Object} options - The chart options
10958
+ * @returns {CanvasRenderingContext2D} context2d instance
10959
+ */
10960
+ acquireContext: function() {},
10961
+
10962
+ /**
10963
+ * Called at chart destruction time, releases any resources associated to the context
10964
+ * previously returned by the acquireContext() method.
10965
+ * @param {CanvasRenderingContext2D} context - The context2d instance
10966
+ * @returns {Boolean} true if the method succeeded, else false
10967
+ */
10968
+ releaseContext: function() {},
10969
+
10970
+ /**
10971
+ * Registers the specified listener on the given chart.
10972
+ * @param {Chart} chart - Chart from which to listen for event
10973
+ * @param {String} type - The ({@link IEvent}) type to listen for
10974
+ * @param {Function} listener - Receives a notification (an object that implements
10975
+ * the {@link IEvent} interface) when an event of the specified type occurs.
10976
+ */
10977
+ addEventListener: function() {},
10978
+
10979
+ /**
10980
+ * Removes the specified listener previously registered with addEventListener.
10981
+ * @param {Chart} chart -Chart from which to remove the listener
10982
+ * @param {String} type - The ({@link IEvent}) type to remove
10983
+ * @param {Function} listener - The listener function to remove from the event target.
10984
+ */
10985
+ removeEventListener: function() {}
10986
+
10987
+ }, implementation);
10988
+
10989
+ /**
10990
+ * @interface IPlatform
10991
+ * Allows abstracting platform dependencies away from the chart
10992
+ * @borrows Chart.platform.acquireContext as acquireContext
10993
+ * @borrows Chart.platform.releaseContext as releaseContext
10994
+ * @borrows Chart.platform.addEventListener as addEventListener
10995
+ * @borrows Chart.platform.removeEventListener as removeEventListener
10996
+ */
10997
+
10998
+ /**
10999
+ * @interface IEvent
11000
+ * @prop {String} type - The event type name, possible values are:
11001
+ * 'contextmenu', 'mouseenter', 'mousedown', 'mousemove', 'mouseup', 'mouseout',
11002
+ * 'click', 'dblclick', 'keydown', 'keypress', 'keyup' and 'resize'
11003
+ * @prop {*} native - The original native event (null for emulated events, e.g. 'resize')
11004
+ * @prop {Number} x - The mouse x position, relative to the canvas (null for incompatible events)
11005
+ * @prop {Number} y - The mouse y position, relative to the canvas (null for incompatible events)
11006
+ */
11007
+
11008
+ },{"45":45,"46":46,"47":47}],49:[function(require,module,exports){
11009
+ /**
11010
+ * Plugin based on discussion from the following Chart.js issues:
11011
+ * @see https://github.com/chartjs/Chart.js/issues/2380#issuecomment-279961569
11012
+ * @see https://github.com/chartjs/Chart.js/issues/2440#issuecomment-256461897
11013
+ */
11014
+
11015
+ 'use strict';
11016
+
11017
+ var defaults = require(25);
11018
+ var elements = require(40);
11019
+ var helpers = require(45);
11020
+
11021
+ defaults._set('global', {
11022
+ plugins: {
11023
+ filler: {
11024
+ propagate: true
11025
+ }
11026
+ }
11027
+ });
11028
+
11029
+ module.exports = function() {
11030
+
11031
+ var mappers = {
11032
+ dataset: function(source) {
11033
+ var index = source.fill;
11034
+ var chart = source.chart;
11035
+ var meta = chart.getDatasetMeta(index);
11036
+ var visible = meta && chart.isDatasetVisible(index);
11037
+ var points = (visible && meta.dataset._children) || [];
11038
+ var length = points.length || 0;
11039
+
11040
+ return !length ? null : function(point, i) {
11041
+ return (i < length && points[i]._view) || null;
11042
+ };
11043
+ },
11044
+
11045
+ boundary: function(source) {
11046
+ var boundary = source.boundary;
11047
+ var x = boundary ? boundary.x : null;
11048
+ var y = boundary ? boundary.y : null;
11049
+
11050
+ return function(point) {
11051
+ return {
11052
+ x: x === null ? point.x : x,
11053
+ y: y === null ? point.y : y,
11054
+ };
11055
+ };
11056
  }
 
11057
  };
11058
 
11059
+ // @todo if (fill[0] === '#')
11060
+ function decodeFill(el, index, count) {
11061
+ var model = el._model || {};
11062
+ var fill = model.fill;
11063
+ var target;
 
 
 
 
 
 
 
 
 
 
 
 
11064
 
11065
+ if (fill === undefined) {
11066
+ fill = !!model.backgroundColor;
11067
+ }
11068
 
11069
+ if (fill === false || fill === null) {
11070
+ return false;
11071
+ }
11072
 
11073
+ if (fill === true) {
11074
+ return 'origin';
11075
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
11076
 
11077
+ target = parseFloat(fill, 10);
11078
+ if (isFinite(target) && Math.floor(target) === target) {
11079
+ if (fill[0] === '-' || fill[0] === '+') {
11080
+ target = index + target;
11081
+ }
11082
 
11083
+ if (target === index || target < 0 || target >= count) {
11084
+ return false;
 
 
 
 
 
11085
  }
11086
 
11087
+ return target;
11088
+ }
 
 
 
11089
 
11090
+ switch (fill) {
11091
+ // compatibility
11092
+ case 'bottom':
11093
+ return 'start';
11094
+ case 'top':
11095
+ return 'end';
11096
+ case 'zero':
11097
+ return 'origin';
11098
+ // supported boundaries
11099
+ case 'origin':
11100
+ case 'start':
11101
+ case 'end':
11102
+ return fill;
11103
+ // invalid fill values
11104
+ default:
11105
+ return false;
11106
+ }
11107
+ }
11108
 
11109
+ function computeBoundary(source) {
11110
+ var model = source.el._model || {};
11111
+ var scale = source.el._scale || {};
11112
+ var fill = source.fill;
11113
+ var target = null;
11114
+ var horizontal;
11115
 
11116
+ if (isFinite(fill)) {
11117
+ return null;
11118
+ }
 
 
 
 
11119
 
11120
+ // Backward compatibility: until v3, we still need to support boundary values set on
11121
+ // the model (scaleTop, scaleBottom and scaleZero) because some external plugins and
11122
+ // controllers might still use it (e.g. the Smith chart).
11123
+
11124
+ if (fill === 'start') {
11125
+ target = model.scaleBottom === undefined ? scale.bottom : model.scaleBottom;
11126
+ } else if (fill === 'end') {
11127
+ target = model.scaleTop === undefined ? scale.top : model.scaleTop;
11128
+ } else if (model.scaleZero !== undefined) {
11129
+ target = model.scaleZero;
11130
+ } else if (scale.getBasePosition) {
11131
+ target = scale.getBasePosition();
11132
+ } else if (scale.getBasePixel) {
11133
+ target = scale.getBasePixel();
11134
+ }
11135
+
11136
+ if (target !== undefined && target !== null) {
11137
+ if (target.x !== undefined && target.y !== undefined) {
11138
+ return target;
11139
  }
11140
+
11141
+ if (typeof target === 'number' && isFinite(target)) {
11142
+ horizontal = scale.isHorizontal();
11143
+ return {
11144
+ x: horizontal ? target : null,
11145
+ y: horizontal ? null : target
11146
+ };
11147
  }
11148
+ }
 
 
 
 
11149
 
11150
+ return null;
11151
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
11152
 
11153
+ function resolveTarget(sources, index, propagate) {
11154
+ var source = sources[index];
11155
+ var fill = source.fill;
11156
+ var visited = [index];
11157
+ var target;
11158
+
11159
+ if (!propagate) {
11160
+ return fill;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
11161
  }
 
11162
 
11163
+ while (fill !== false && visited.indexOf(fill) === -1) {
11164
+ if (!isFinite(fill)) {
11165
+ return fill;
11166
+ }
11167
 
11168
+ target = sources[fill];
11169
+ if (!target) {
11170
+ return false;
11171
+ }
11172
 
11173
+ if (target.visible) {
11174
+ return fill;
11175
+ }
11176
 
11177
+ visited.push(fill);
11178
+ fill = target.fill;
11179
+ }
 
11180
 
11181
+ return false;
11182
+ }
11183
 
11184
+ function createMapper(source) {
11185
+ var fill = source.fill;
11186
+ var type = 'dataset';
11187
 
11188
+ if (fill === false) {
11189
+ return null;
11190
+ }
11191
 
11192
+ if (!isFinite(fill)) {
11193
+ type = 'boundary';
11194
+ }
11195
 
11196
+ return mappers[type](source);
11197
+ }
11198
 
11199
+ function isDrawable(point) {
11200
+ return point && !point.skip;
11201
+ }
11202
 
11203
+ function drawArea(ctx, curve0, curve1, len0, len1) {
11204
+ var i;
11205
 
11206
+ if (!len0 || !len1) {
11207
+ return;
 
 
 
 
 
11208
  }
 
 
11209
 
11210
+ // building first area curve (normal)
11211
+ ctx.moveTo(curve0[0].x, curve0[0].y);
11212
+ for (i = 1; i < len0; ++i) {
11213
+ helpers.canvas.lineTo(ctx, curve0[i - 1], curve0[i]);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
11214
  }
 
11215
 
11216
+ // joining the two area curves
11217
+ ctx.lineTo(curve1[len1 - 1].x, curve1[len1 - 1].y);
11218
 
11219
+ // building opposite area curve (reverse)
11220
+ for (i = len1 - 1; i > 0; --i) {
11221
+ helpers.canvas.lineTo(ctx, curve1[i], curve1[i - 1], true);
11222
+ }
11223
+ }
11224
 
11225
+ function doFill(ctx, points, mapper, view, color, loop) {
11226
+ var count = points.length;
11227
+ var span = view.spanGaps;
11228
+ var curve0 = [];
11229
+ var curve1 = [];
11230
+ var len0 = 0;
11231
+ var len1 = 0;
11232
+ var i, ilen, index, p0, p1, d0, d1;
11233
+
11234
+ ctx.beginPath();
11235
+
11236
+ for (i = 0, ilen = (count + !!loop); i < ilen; ++i) {
11237
+ index = i % count;
11238
+ p0 = points[index]._view;
11239
+ p1 = mapper(p0, index, view);
11240
+ d0 = isDrawable(p0);
11241
+ d1 = isDrawable(p1);
11242
+
11243
+ if (d0 && d1) {
11244
+ len0 = curve0.push(p0);
11245
+ len1 = curve1.push(p1);
11246
+ } else if (len0 && len1) {
11247
+ if (!span) {
11248
+ drawArea(ctx, curve0, curve1, len0, len1);
11249
+ len0 = len1 = 0;
11250
+ curve0 = [];
11251
+ curve1 = [];
11252
+ } else {
11253
+ if (d0) {
11254
+ curve0.push(p0);
11255
+ }
11256
+ if (d1) {
11257
+ curve1.push(p1);
11258
+ }
11259
+ }
11260
+ }
11261
+ }
11262
 
11263
+ drawArea(ctx, curve0, curve1, len0, len1);
 
11264
 
11265
+ ctx.closePath();
11266
+ ctx.fillStyle = color;
11267
+ ctx.fill();
11268
+ }
11269
 
11270
+ return {
11271
+ id: 'filler',
11272
+
11273
+ afterDatasetsUpdate: function(chart, options) {
11274
+ var count = (chart.data.datasets || []).length;
11275
+ var propagate = options.propagate;
11276
+ var sources = [];
11277
+ var meta, i, el, source;
11278
+
11279
+ for (i = 0; i < count; ++i) {
11280
+ meta = chart.getDatasetMeta(i);
11281
+ el = meta.dataset;
11282
+ source = null;
11283
+
11284
+ if (el && el._model && el instanceof elements.Line) {
11285
+ source = {
11286
+ visible: chart.isDatasetVisible(i),
11287
+ fill: decodeFill(el, i, count),
11288
+ chart: chart,
11289
+ el: el
11290
+ };
11291
+ }
11292
 
11293
+ meta.$filler = source;
11294
+ sources.push(source);
11295
  }
11296
 
11297
+ for (i = 0; i < count; ++i) {
11298
+ source = sources[i];
11299
+ if (!source) {
11300
+ continue;
11301
+ }
11302
 
11303
+ source.fill = resolveTarget(sources, i, propagate);
11304
+ source.boundary = computeBoundary(source);
11305
+ source.mapper = createMapper(source);
11306
+ }
11307
+ },
 
 
 
 
 
11308
 
11309
+ beforeDatasetDraw: function(chart, args) {
11310
+ var meta = args.meta.$filler;
11311
+ if (!meta) {
11312
+ return;
11313
+ }
11314
 
11315
+ var ctx = chart.ctx;
11316
+ var el = meta.el;
11317
+ var view = el._view;
11318
+ var points = el._children || [];
11319
+ var mapper = meta.mapper;
11320
+ var color = view.backgroundColor || defaults.global.defaultColor;
11321
+
11322
+ if (mapper && color && points.length) {
11323
+ helpers.canvas.clipArea(ctx, chart.chartArea);
11324
+ doFill(ctx, points, mapper, view, color, el._loop);
11325
+ helpers.canvas.unclipArea(ctx);
11326
+ }
11327
+ }
11328
+ };
11329
+ };
11330
 
11331
+ },{"25":25,"40":40,"45":45}],50:[function(require,module,exports){
11332
+ 'use strict';
11333
 
11334
+ var defaults = require(25);
11335
+ var Element = require(26);
11336
+ var helpers = require(45);
11337
 
11338
+ defaults._set('global', {
11339
+ legend: {
11340
+ display: true,
11341
+ position: 'top',
11342
+ fullWidth: true,
11343
+ reverse: false,
11344
+ weight: 1000,
11345
+
11346
+ // a callback that will handle
11347
+ onClick: function(e, legendItem) {
11348
+ var index = legendItem.datasetIndex;
11349
+ var ci = this.chart;
11350
+ var meta = ci.getDatasetMeta(index);
11351
+
11352
+ // See controller.isDatasetVisible comment
11353
+ meta.hidden = meta.hidden === null ? !ci.data.datasets[index].hidden : null;
11354
+
11355
+ // We hid a dataset ... rerender the chart
11356
+ ci.update();
11357
+ },
11358
 
11359
+ onHover: null,
11360
+
11361
+ labels: {
11362
+ boxWidth: 40,
11363
+ padding: 10,
11364
+ // Generates labels shown in the legend
11365
+ // Valid properties to return:
11366
+ // text : text to display
11367
+ // fillStyle : fill of coloured box
11368
+ // strokeStyle: stroke of coloured box
11369
+ // hidden : if this legend item refers to a hidden item
11370
+ // lineCap : cap style for line
11371
+ // lineDash
11372
+ // lineDashOffset :
11373
+ // lineJoin :
11374
+ // lineWidth :
11375
+ generateLabels: function(chart) {
11376
+ var data = chart.data;
11377
+ return helpers.isArray(data.datasets) ? data.datasets.map(function(dataset, i) {
11378
+ return {
11379
+ text: dataset.label,
11380
+ fillStyle: (!helpers.isArray(dataset.backgroundColor) ? dataset.backgroundColor : dataset.backgroundColor[0]),
11381
+ hidden: !chart.isDatasetVisible(i),
11382
+ lineCap: dataset.borderCapStyle,
11383
+ lineDash: dataset.borderDash,
11384
+ lineDashOffset: dataset.borderDashOffset,
11385
+ lineJoin: dataset.borderJoinStyle,
11386
+ lineWidth: dataset.borderWidth,
11387
+ strokeStyle: dataset.borderColor,
11388
+ pointStyle: dataset.pointStyle,
11389
+
11390
+ // Below is extra data used for toggling the datasets
11391
+ datasetIndex: i
11392
+ };
11393
+ }, this) : [];
11394
+ }
11395
  }
11396
+ },
11397
+
11398
+ legendCallback: function(chart) {
11399
+ var text = [];
11400
+ text.push('<ul class="' + chart.id + '-legend">');
11401
+ for (var i = 0; i < chart.data.datasets.length; i++) {
11402
+ text.push('<li><span style="background-color:' + chart.data.datasets[i].backgroundColor + '"></span>');
11403
+ if (chart.data.datasets[i].label) {
11404
+ text.push(chart.data.datasets[i].label);
11405
+ }
11406
+ text.push('</li>');
11407
+ }
11408
+ text.push('</ul>');
11409
+ return text.join('');
11410
+ }
11411
+ });
11412
+
11413
+ module.exports = function(Chart) {
11414
+
11415
+ var layout = Chart.layoutService;
11416
+ var noop = helpers.noop;
11417
+
11418
+ /**
11419
+ * Helper function to get the box width based on the usePointStyle option
11420
+ * @param labelopts {Object} the label options on the legend
11421
+ * @param fontSize {Number} the label font size
11422
+ * @return {Number} width of the color box area
11423
+ */
11424
+ function getBoxWidth(labelOpts, fontSize) {
11425
+ return labelOpts.usePointStyle ?
11426
+ fontSize * Math.SQRT2 :
11427
+ labelOpts.boxWidth;
11428
+ }
11429
 
11430
+ Chart.Legend = Element.extend({
 
 
 
11431
 
11432
+ initialize: function(config) {
11433
+ helpers.extend(this, config);
 
 
11434
 
11435
+ // Contains hit boxes for each dataset (in dataset order)
11436
+ this.legendHitBoxes = [];
 
 
11437
 
11438
+ // Are we in doughnut mode which has a different data type
11439
+ this.doughnutMode = false;
11440
+ },
11441
 
11442
+ // These methods are ordered by lifecycle. Utilities then follow.
11443
+ // Any function defined here is inherited by all legend types.
11444
+ // Any function can be extended by the legend type
11445
+
11446
+ beforeUpdate: noop,
11447
+ update: function(maxWidth, maxHeight, margins) {
11448
+ var me = this;
11449
+
11450
+ // Update Lifecycle - Probably don't want to ever extend or overwrite this function ;)
11451
+ me.beforeUpdate();
11452
+
11453
+ // Absorb the master measurements
11454
+ me.maxWidth = maxWidth;
11455
+ me.maxHeight = maxHeight;
11456
+ me.margins = margins;
11457
+
11458
+ // Dimensions
11459
+ me.beforeSetDimensions();
11460
+ me.setDimensions();
11461
+ me.afterSetDimensions();
11462
+ // Labels
11463
+ me.beforeBuildLabels();
11464
+ me.buildLabels();
11465
+ me.afterBuildLabels();
11466
+
11467
+ // Fit
11468
+ me.beforeFit();
11469
+ me.fit();
11470
+ me.afterFit();
11471
+ //
11472
+ me.afterUpdate();
11473
+
11474
+ return me.minSize;
11475
  },
11476
+ afterUpdate: noop,
11477
+
11478
+ //
11479
+
11480
+ beforeSetDimensions: noop,
11481
+ setDimensions: function() {
11482
+ var me = this;
11483
+ // Set the unconstrained dimension before label rotation
11484
+ if (me.isHorizontal()) {
11485
+ // Reset position before calculating rotation
11486
+ me.width = me.maxWidth;
11487
+ me.left = 0;
11488
+ me.right = me.width;
11489
+ } else {
11490
+ me.height = me.maxHeight;
11491
+
11492
+ // Reset position before calculating rotation
11493
+ me.top = 0;
11494
+ me.bottom = me.height;
11495
+ }
11496
+
11497
+ // Reset padding
11498
+ me.paddingLeft = 0;
11499
+ me.paddingTop = 0;
11500
+ me.paddingRight = 0;
11501
+ me.paddingBottom = 0;
11502
+
11503
+ // Reset minSize
11504
+ me.minSize = {
11505
+ width: 0,
11506
+ height: 0
11507
  };
11508
  },
11509
+ afterSetDimensions: noop,
11510
 
11511
+ //
11512
 
11513
+ beforeBuildLabels: noop,
11514
+ buildLabels: function() {
11515
+ var me = this;
11516
+ var labelOpts = me.options.labels || {};
11517
+ var legendItems = helpers.callback(labelOpts.generateLabels, [me.chart], me) || [];
11518
 
11519
+ if (labelOpts.filter) {
11520
+ legendItems = legendItems.filter(function(item) {
11521
+ return labelOpts.filter(item, me.chart.data);
11522
+ });
11523
+ }
11524
 
11525
+ if (me.options.reverse) {
11526
+ legendItems.reverse();
11527
+ }
11528
 
11529
+ me.legendItems = legendItems;
11530
+ },
11531
+ afterBuildLabels: noop,
11532
 
11533
+ //
 
 
11534
 
11535
+ beforeFit: noop,
11536
+ fit: function() {
11537
+ var me = this;
11538
+ var opts = me.options;
11539
+ var labelOpts = opts.labels;
11540
+ var display = opts.display;
11541
 
11542
+ var ctx = me.ctx;
 
11543
 
11544
+ var globalDefault = defaults.global;
11545
+ var valueOrDefault = helpers.valueOrDefault;
11546
+ var fontSize = valueOrDefault(labelOpts.fontSize, globalDefault.defaultFontSize);
11547
+ var fontStyle = valueOrDefault(labelOpts.fontStyle, globalDefault.defaultFontStyle);
11548
+ var fontFamily = valueOrDefault(labelOpts.fontFamily, globalDefault.defaultFontFamily);
11549
+ var labelFont = helpers.fontString(fontSize, fontStyle, fontFamily);
11550
 
11551
+ // Reset hit boxes
11552
+ var hitboxes = me.legendHitBoxes = [];
 
 
 
 
 
 
11553
 
11554
+ var minSize = me.minSize;
11555
+ var isHorizontal = me.isHorizontal();
11556
+
11557
+ if (isHorizontal) {
11558
+ minSize.width = me.maxWidth; // fill all the width
11559
+ minSize.height = display ? 10 : 0;
11560
+ } else {
11561
+ minSize.width = display ? 10 : 0;
11562
+ minSize.height = me.maxHeight; // fill all the height
11563
  }
11564
 
11565
+ // Increase sizes here
11566
+ if (display) {
11567
+ ctx.font = labelFont;
11568
 
11569
+ if (isHorizontal) {
11570
+ // Labels
 
11571
 
11572
+ // Width of each line of legend boxes. Labels wrap onto multiple lines when there are too many to fit on one
11573
+ var lineWidths = me.lineWidths = [0];
11574
+ var totalHeight = me.legendItems.length ? fontSize + (labelOpts.padding) : 0;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
11575
 
11576
+ ctx.textAlign = 'left';
11577
+ ctx.textBaseline = 'top';
 
 
 
 
 
 
 
 
 
 
11578
 
11579
+ helpers.each(me.legendItems, function(legendItem, i) {
11580
+ var boxWidth = getBoxWidth(labelOpts, fontSize);
11581
+ var width = boxWidth + (fontSize / 2) + ctx.measureText(legendItem.text).width;
11582
+
11583
+ if (lineWidths[lineWidths.length - 1] + width + labelOpts.padding >= me.width) {
11584
+ totalHeight += fontSize + (labelOpts.padding);
11585
+ lineWidths[lineWidths.length] = me.left;
11586
+ }
11587
 
11588
+ // Store the hitbox width and height here. Final position will be updated in `draw`
11589
+ hitboxes[i] = {
11590
+ left: 0,
11591
+ top: 0,
11592
+ width: width,
11593
+ height: fontSize
11594
+ };
11595
 
11596
+ lineWidths[lineWidths.length - 1] += width + labelOpts.padding;
11597
+ });
11598
 
11599
+ minSize.height += totalHeight;
 
11600
 
11601
+ } else {
11602
+ var vPadding = labelOpts.padding;
11603
+ var columnWidths = me.columnWidths = [];
11604
+ var totalWidth = labelOpts.padding;
11605
+ var currentColWidth = 0;
11606
+ var currentColHeight = 0;
11607
+ var itemHeight = fontSize + vPadding;
11608
+
11609
+ helpers.each(me.legendItems, function(legendItem, i) {
11610
+ var boxWidth = getBoxWidth(labelOpts, fontSize);
11611
+ var itemWidth = boxWidth + (fontSize / 2) + ctx.measureText(legendItem.text).width;
11612
+
11613
+ // If too tall, go to new column
11614
+ if (currentColHeight + itemHeight > minSize.height) {
11615
+ totalWidth += currentColWidth + labelOpts.padding;
11616
+ columnWidths.push(currentColWidth); // previous column width
11617
+
11618
+ currentColWidth = 0;
11619
+ currentColHeight = 0;
11620
+ }
11621
 
11622
+ // Get max width
11623
+ currentColWidth = Math.max(currentColWidth, itemWidth);
11624
+ currentColHeight += itemHeight;
11625
+
11626
+ // Store the hitbox width and height here. Final position will be updated in `draw`
11627
+ hitboxes[i] = {
11628
+ left: 0,
11629
+ top: 0,
11630
+ width: itemWidth,
11631
+ height: fontSize
11632
+ };
11633
+ });
11634
 
11635
+ totalWidth += currentColWidth;
11636
+ columnWidths.push(currentColWidth);
11637
+ minSize.width += totalWidth;
11638
+ }
11639
  }
11640
 
11641
+ me.width = minSize.width;
11642
+ me.height = minSize.height;
11643
+ },
11644
+ afterFit: noop,
11645
 
11646
+ // Shared Methods
11647
+ isHorizontal: function() {
11648
+ return this.options.position === 'top' || this.options.position === 'bottom';
11649
+ },
11650
 
11651
+ // Actually draw the legend on the canvas
11652
+ draw: function() {
11653
+ var me = this;
11654
+ var opts = me.options;
11655
+ var labelOpts = opts.labels;
11656
+ var globalDefault = defaults.global;
11657
+ var lineDefault = globalDefault.elements.line;
11658
+ var legendWidth = me.width;
11659
+ var lineWidths = me.lineWidths;
11660
+
11661
+ if (opts.display) {
11662
+ var ctx = me.ctx;
11663
+ var valueOrDefault = helpers.valueOrDefault;
11664
+ var fontColor = valueOrDefault(labelOpts.fontColor, globalDefault.defaultFontColor);
11665
+ var fontSize = valueOrDefault(labelOpts.fontSize, globalDefault.defaultFontSize);
11666
+ var fontStyle = valueOrDefault(labelOpts.fontStyle, globalDefault.defaultFontStyle);
11667
+ var fontFamily = valueOrDefault(labelOpts.fontFamily, globalDefault.defaultFontFamily);
11668
+ var labelFont = helpers.fontString(fontSize, fontStyle, fontFamily);
11669
+ var cursor;
11670
+
11671
+ // Canvas setup
11672
+ ctx.textAlign = 'left';
11673
+ ctx.textBaseline = 'middle';
11674
+ ctx.lineWidth = 0.5;
11675
+ ctx.strokeStyle = fontColor; // for strikethrough effect
11676
+ ctx.fillStyle = fontColor; // render in correct colour
11677
+ ctx.font = labelFont;
11678
+
11679
+ var boxWidth = getBoxWidth(labelOpts, fontSize);
11680
+ var hitboxes = me.legendHitBoxes;
11681
+
11682
+ // current position
11683
+ var drawLegendBox = function(x, y, legendItem) {
11684
+ if (isNaN(boxWidth) || boxWidth <= 0) {
11685
+ return;
11686
+ }
11687
 
11688
+ // Set the ctx for the box
11689
+ ctx.save();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
11690
 
11691
+ ctx.fillStyle = valueOrDefault(legendItem.fillStyle, globalDefault.defaultColor);
11692
+ ctx.lineCap = valueOrDefault(legendItem.lineCap, lineDefault.borderCapStyle);
11693
+ ctx.lineDashOffset = valueOrDefault(legendItem.lineDashOffset, lineDefault.borderDashOffset);
11694
+ ctx.lineJoin = valueOrDefault(legendItem.lineJoin, lineDefault.borderJoinStyle);
11695
+ ctx.lineWidth = valueOrDefault(legendItem.lineWidth, lineDefault.borderWidth);
11696
+ ctx.strokeStyle = valueOrDefault(legendItem.strokeStyle, globalDefault.defaultColor);
11697
+ var isLineWidthZero = (valueOrDefault(legendItem.lineWidth, lineDefault.borderWidth) === 0);
11698
+
11699
+ if (ctx.setLineDash) {
11700
+ // IE 9 and 10 do not support line dash
11701
+ ctx.setLineDash(valueOrDefault(legendItem.lineDash, lineDefault.borderDash));
11702
+ }
11703
 
11704
+ if (opts.labels && opts.labels.usePointStyle) {
11705
+ // Recalculate x and y for drawPoint() because its expecting
11706
+ // x and y to be center of figure (instead of top left)
11707
+ var radius = fontSize * Math.SQRT2 / 2;
11708
+ var offSet = radius / Math.SQRT2;
11709
+ var centerX = x + offSet;
11710
+ var centerY = y + offSet;
11711
 
11712
+ // Draw pointStyle as legend symbol
11713
+ helpers.canvas.drawPoint(ctx, legendItem.pointStyle, radius, centerX, centerY);
11714
+ } else {
11715
+ // Draw box as legend symbol
11716
+ if (!isLineWidthZero) {
11717
+ ctx.strokeRect(x, y, boxWidth, fontSize);
11718
+ }
11719
+ ctx.fillRect(x, y, boxWidth, fontSize);
11720
+ }
11721
 
11722
+ ctx.restore();
11723
+ };
11724
+ var fillText = function(x, y, legendItem, textWidth) {
11725
+ var halfFontSize = fontSize / 2;
11726
+ var xLeft = boxWidth + halfFontSize + x;
11727
+ var yMiddle = y + halfFontSize;
 
11728
 
11729
+ ctx.fillText(legendItem.text, xLeft, yMiddle);
 
 
11730
 
11731
+ if (legendItem.hidden) {
11732
+ // Strikethrough the text if hidden
11733
+ ctx.beginPath();
11734
+ ctx.lineWidth = 2;
11735
+ ctx.moveTo(xLeft, yMiddle);
11736
+ ctx.lineTo(xLeft + textWidth, yMiddle);
11737
+ ctx.stroke();
11738
+ }
11739
+ };
11740
 
11741
+ // Horizontal
11742
+ var isHorizontal = me.isHorizontal();
11743
+ if (isHorizontal) {
11744
+ cursor = {
11745
+ x: me.left + ((legendWidth - lineWidths[0]) / 2),
11746
+ y: me.top + labelOpts.padding,
11747
+ line: 0
11748
+ };
11749
+ } else {
11750
+ cursor = {
11751
+ x: me.left + labelOpts.padding,
11752
+ y: me.top + labelOpts.padding,
11753
+ line: 0
11754
+ };
11755
+ }
11756
 
11757
+ var itemHeight = fontSize + labelOpts.padding;
11758
+ helpers.each(me.legendItems, function(legendItem, i) {
11759
+ var textWidth = ctx.measureText(legendItem.text).width;
11760
+ var width = boxWidth + (fontSize / 2) + textWidth;
11761
+ var x = cursor.x;
11762
+ var y = cursor.y;
11763
+
11764
+ if (isHorizontal) {
11765
+ if (x + width >= legendWidth) {
11766
+ y = cursor.y += itemHeight;
11767
+ cursor.line++;
11768
+ x = cursor.x = me.left + ((legendWidth - lineWidths[cursor.line]) / 2);
11769
+ }
11770
+ } else if (y + itemHeight > me.bottom) {
11771
+ x = cursor.x = x + me.columnWidths[cursor.line] + labelOpts.padding;
11772
+ y = cursor.y = me.top + labelOpts.padding;
11773
+ cursor.line++;
11774
+ }
11775
 
11776
+ drawLegendBox(x, y, legendItem);
 
 
 
11777
 
11778
+ hitboxes[i].left = x;
11779
+ hitboxes[i].top = y;
11780
 
11781
+ // Fill the actual label
11782
+ fillText(x, y, legendItem, textWidth);
11783
 
11784
+ if (isHorizontal) {
11785
+ cursor.x += width + (labelOpts.padding);
11786
+ } else {
11787
+ cursor.y += itemHeight;
11788
+ }
11789
 
11790
+ });
 
 
 
 
11791
  }
11792
+ },
11793
 
11794
+ /**
11795
+ * Handle an event
11796
+ * @private
11797
+ * @param {IEvent} event - The event to handle
11798
+ * @return {Boolean} true if a change occured
11799
+ */
11800
+ handleEvent: function(e) {
11801
+ var me = this;
11802
+ var opts = me.options;
11803
+ var type = e.type === 'mouseup' ? 'click' : e.type;
11804
+ var changed = false;
11805
+
11806
+ if (type === 'mousemove') {
11807
+ if (!opts.onHover) {
11808
+ return;
11809
+ }
11810
+ } else if (type === 'click') {
11811
+ if (!opts.onClick) {
11812
+ return;
11813
+ }
11814
  } else {
11815
+ return;
11816
  }
11817
 
11818
+ // Chart event already has relative position in it
11819
+ var x = e.x;
11820
+ var y = e.y;
11821
+
11822
+ if (x >= me.left && x <= me.right && y >= me.top && y <= me.bottom) {
11823
+ // See if we are touching one of the dataset boxes
11824
+ var lh = me.legendHitBoxes;
11825
+ for (var i = 0; i < lh.length; ++i) {
11826
+ var hitBox = lh[i];
11827
+
11828
+ if (x >= hitBox.left && x <= hitBox.left + hitBox.width && y >= hitBox.top && y <= hitBox.top + hitBox.height) {
11829
+ // Touching an element
11830
+ if (type === 'click') {
11831
+ // use e.native for backwards compatibility
11832
+ opts.onClick.call(me, e.native, me.legendItems[i]);
11833
+ changed = true;
11834
+ break;
11835
+ } else if (type === 'mousemove') {
11836
+ // use e.native for backwards compatibility
11837
+ opts.onHover.call(me, e.native, me.legendItems[i]);
11838
+ changed = true;
11839
+ break;
11840
+ }
11841
+ }
11842
+ }
11843
  }
11844
 
11845
+ return changed;
11846
+ }
11847
+ });
 
 
 
 
 
 
 
 
 
11848
 
11849
+ function createNewLegendAndAttach(chart, legendOpts) {
11850
+ var legend = new Chart.Legend({
11851
+ ctx: chart.ctx,
11852
+ options: legendOpts,
11853
+ chart: chart
11854
+ });
11855
+
11856
+ layout.configure(chart, legend, legendOpts);
11857
+ layout.addBox(chart, legend);
11858
+ chart.legend = legend;
11859
+ }
11860
 
11861
+ return {
11862
+ id: 'legend',
11863
 
11864
+ beforeInit: function(chart) {
11865
+ var legendOpts = chart.options.legend;
 
 
11866
 
11867
+ if (legendOpts) {
11868
+ createNewLegendAndAttach(chart, legendOpts);
11869
+ }
11870
+ },
11871
 
11872
+ beforeUpdate: function(chart) {
11873
+ var legendOpts = chart.options.legend;
11874
+ var legend = chart.legend;
11875
 
11876
+ if (legendOpts) {
11877
+ helpers.mergeIf(legendOpts, defaults.global.legend);
11878
 
11879
+ if (legend) {
11880
+ layout.configure(chart, legend, legendOpts);
11881
+ legend.options = legendOpts;
11882
+ } else {
11883
+ createNewLegendAndAttach(chart, legendOpts);
11884
+ }
11885
+ } else if (legend) {
11886
+ layout.removeBox(chart, legend);
11887
+ delete chart.legend;
11888
+ }
11889
+ },
11890
 
11891
+ afterEvent: function(chart, e) {
11892
+ var legend = chart.legend;
11893
+ if (legend) {
11894
+ legend.handleEvent(e);
11895
  }
11896
  }
11897
+ };
11898
+ };
11899
+
11900
+ },{"25":25,"26":26,"45":45}],51:[function(require,module,exports){
11901
+ 'use strict';
11902
+
11903
+ var defaults = require(25);
11904
+ var Element = require(26);
11905
+ var helpers = require(45);
11906
+
11907
+ defaults._set('global', {
11908
+ title: {
11909
+ display: false,
11910
+ fontStyle: 'bold',
11911
+ fullWidth: true,
11912
+ lineHeight: 1.2,
11913
+ padding: 10,
11914
+ position: 'top',
11915
+ text: '',
11916
+ weight: 2000 // by default greater than legend (1000) to be above
11917
+ }
11918
+ });
11919
 
11920
+ module.exports = function(Chart) {
 
 
 
 
 
11921
 
11922
+ var layout = Chart.layoutService;
11923
+ var noop = helpers.noop;
11924
 
11925
+ Chart.Title = Element.extend({
11926
+ initialize: function(config) {
11927
+ var me = this;
11928
+ helpers.extend(me, config);
11929
+
11930
+ // Contains hit boxes for each dataset (in dataset order)
11931
+ me.legendHitBoxes = [];
 
 
 
 
 
 
 
11932
  },
 
 
 
11933
 
11934
+ // These methods are ordered by lifecycle. Utilities then follow.
 
 
11935
 
11936
+ beforeUpdate: noop,
11937
+ update: function(maxWidth, maxHeight, margins) {
11938
+ var me = this;
11939
 
11940
+ // Update Lifecycle - Probably don't want to ever extend or overwrite this function ;)
11941
+ me.beforeUpdate();
11942
 
11943
+ // Absorb the master measurements
11944
+ me.maxWidth = maxWidth;
11945
+ me.maxHeight = maxHeight;
11946
+ me.margins = margins;
11947
 
11948
+ // Dimensions
11949
+ me.beforeSetDimensions();
11950
+ me.setDimensions();
11951
+ me.afterSetDimensions();
11952
+ // Labels
11953
+ me.beforeBuildLabels();
11954
+ me.buildLabels();
11955
+ me.afterBuildLabels();
 
 
 
11956
 
11957
+ // Fit
11958
+ me.beforeFit();
11959
+ me.fit();
11960
+ me.afterFit();
11961
+ //
11962
+ me.afterUpdate();
11963
 
11964
+ return me.minSize;
11965
+
11966
+ },
11967
+ afterUpdate: noop,
11968
+
11969
+ //
11970
+
11971
+ beforeSetDimensions: noop,
11972
+ setDimensions: function() {
11973
+ var me = this;
11974
+ // Set the unconstrained dimension before label rotation
11975
+ if (me.isHorizontal()) {
11976
+ // Reset position before calculating rotation
11977
+ me.width = me.maxWidth;
11978
+ me.left = 0;
11979
+ me.right = me.width;
11980
+ } else {
11981
+ me.height = me.maxHeight;
11982
 
11983
+ // Reset position before calculating rotation
11984
+ me.top = 0;
11985
+ me.bottom = me.height;
11986
+ }
11987
 
11988
+ // Reset padding
11989
+ me.paddingLeft = 0;
11990
+ me.paddingTop = 0;
11991
+ me.paddingRight = 0;
11992
+ me.paddingBottom = 0;
11993
 
11994
+ // Reset minSize
11995
+ me.minSize = {
11996
+ width: 0,
11997
+ height: 0
11998
+ };
11999
+ },
12000
+ afterSetDimensions: noop,
12001
+
12002
+ //
12003
+
12004
+ beforeBuildLabels: noop,
12005
+ buildLabels: noop,
12006
+ afterBuildLabels: noop,
12007
+
12008
+ //
12009
+
12010
+ beforeFit: noop,
12011
+ fit: function() {
12012
+ var me = this;
12013
+ var valueOrDefault = helpers.valueOrDefault;
12014
+ var opts = me.options;
12015
+ var display = opts.display;
12016
+ var fontSize = valueOrDefault(opts.fontSize, defaults.global.defaultFontSize);
12017
+ var minSize = me.minSize;
12018
+ var lineCount = helpers.isArray(opts.text) ? opts.text.length : 1;
12019
+ var lineHeight = helpers.options.toLineHeight(opts.lineHeight, fontSize);
12020
+ var textSize = display ? (lineCount * lineHeight) + (opts.padding * 2) : 0;
12021
+
12022
+ if (me.isHorizontal()) {
12023
+ minSize.width = me.maxWidth; // fill all the width
12024
+ minSize.height = textSize;
12025
+ } else {
12026
+ minSize.width = textSize;
12027
+ minSize.height = me.maxHeight; // fill all the height
12028
  }
12029
 
12030
+ me.width = minSize.width;
12031
+ me.height = minSize.height;
12032
+
12033
+ },
12034
+ afterFit: noop,
12035
+
12036
+ // Shared Methods
12037
+ isHorizontal: function() {
12038
+ var pos = this.options.position;
12039
+ return pos === 'top' || pos === 'bottom';
12040
  },
 
 
 
12041
 
12042
+ // Actually draw the title block on the canvas
12043
+ draw: function() {
12044
+ var me = this;
12045
+ var ctx = me.ctx;
12046
+ var valueOrDefault = helpers.valueOrDefault;
12047
+ var opts = me.options;
12048
+ var globalDefaults = defaults.global;
12049
+
12050
+ if (opts.display) {
12051
+ var fontSize = valueOrDefault(opts.fontSize, globalDefaults.defaultFontSize);
12052
+ var fontStyle = valueOrDefault(opts.fontStyle, globalDefaults.defaultFontStyle);
12053
+ var fontFamily = valueOrDefault(opts.fontFamily, globalDefaults.defaultFontFamily);
12054
+ var titleFont = helpers.fontString(fontSize, fontStyle, fontFamily);
12055
+ var lineHeight = helpers.options.toLineHeight(opts.lineHeight, fontSize);
12056
+ var offset = lineHeight / 2 + opts.padding;
12057
+ var rotation = 0;
12058
+ var top = me.top;
12059
+ var left = me.left;
12060
+ var bottom = me.bottom;
12061
+ var right = me.right;
12062
+ var maxWidth, titleX, titleY;
12063
+
12064
+ ctx.fillStyle = valueOrDefault(opts.fontColor, globalDefaults.defaultFontColor); // render in correct colour
12065
+ ctx.font = titleFont;
12066
+
12067
+ // Horizontal
12068
+ if (me.isHorizontal()) {
12069
+ titleX = left + ((right - left) / 2); // midpoint of the width
12070
+ titleY = top + offset;
12071
+ maxWidth = right - left;
12072
+ } else {
12073
+ titleX = opts.position === 'left' ? left + offset : right - offset;
12074
+ titleY = top + ((bottom - top) / 2);
12075
+ maxWidth = bottom - top;
12076
+ rotation = Math.PI * (opts.position === 'left' ? -0.5 : 0.5);
12077
+ }
12078
 
12079
+ ctx.save();
12080
+ ctx.translate(titleX, titleY);
12081
+ ctx.rotate(rotation);
12082
+ ctx.textAlign = 'center';
12083
+ ctx.textBaseline = 'middle';
12084
+
12085
+ var text = opts.text;
12086
+ if (helpers.isArray(text)) {
12087
+ var y = 0;
12088
+ for (var i = 0; i < text.length; ++i) {
12089
+ ctx.fillText(text[i], 0, y, maxWidth);
12090
+ y += lineHeight;
12091
+ }
12092
+ } else {
12093
+ ctx.fillText(text, 0, 0, maxWidth);
12094
+ }
12095
 
12096
+ ctx.restore();
12097
+ }
12098
+ }
12099
+ });
12100
 
12101
+ function createNewTitleBlockAndAttach(chart, titleOpts) {
12102
+ var title = new Chart.Title({
12103
+ ctx: chart.ctx,
12104
+ options: titleOpts,
12105
+ chart: chart
12106
+ });
12107
 
12108
+ layout.configure(chart, title, titleOpts);
12109
+ layout.addBox(chart, title);
12110
+ chart.titleBlock = title;
12111
+ }
 
 
 
 
12112
 
12113
+ return {
12114
+ id: 'title',
 
12115
 
12116
+ beforeInit: function(chart) {
12117
+ var titleOpts = chart.options.title;
12118
 
12119
+ if (titleOpts) {
12120
+ createNewTitleBlockAndAttach(chart, titleOpts);
12121
+ }
12122
+ },
 
12123
 
12124
+ beforeUpdate: function(chart) {
12125
+ var titleOpts = chart.options.title;
12126
+ var titleBlock = chart.titleBlock;
12127
 
12128
+ if (titleOpts) {
12129
+ helpers.mergeIf(titleOpts, defaults.global.title);
12130
 
12131
+ if (titleBlock) {
12132
+ layout.configure(chart, titleBlock, titleOpts);
12133
+ titleBlock.options = titleOpts;
12134
+ } else {
12135
+ createNewTitleBlockAndAttach(chart, titleOpts);
12136
  }
12137
+ } else if (titleBlock) {
12138
+ Chart.layoutService.removeBox(chart, titleBlock);
12139
+ delete chart.titleBlock;
 
 
 
 
 
12140
  }
12141
+ }
12142
+ };
12143
+ };
12144
 
12145
+ },{"25":25,"26":26,"45":45}],52:[function(require,module,exports){
12146
+ 'use strict';
12147
+
12148
+ module.exports = function(Chart) {
12149
+
12150
+ // Default config for a category scale
12151
+ var defaultConfig = {
12152
+ position: 'bottom'
12153
+ };
12154
+
12155
+ var DatasetScale = Chart.Scale.extend({
12156
+ /**
12157
+ * Internal function to get the correct labels. If data.xLabels or data.yLabels are defined, use those
12158
+ * else fall back to data.labels
12159
+ * @private
12160
+ */
12161
+ getLabels: function() {
12162
+ var data = this.chart.data;
12163
+ return this.options.labels || (this.isHorizontal() ? data.xLabels : data.yLabels) || data.labels;
12164
  },
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
12165
 
12166
+ determineDataLimits: function() {
12167
+ var me = this;
12168
+ var labels = me.getLabels();
12169
+ me.minIndex = 0;
12170
+ me.maxIndex = labels.length - 1;
12171
+ var findIndex;
12172
+
12173
+ if (me.options.ticks.min !== undefined) {
12174
+ // user specified min value
12175
+ findIndex = labels.indexOf(me.options.ticks.min);
12176
+ me.minIndex = findIndex !== -1 ? findIndex : me.minIndex;
12177
+ }
12178
+
12179
+ if (me.options.ticks.max !== undefined) {
12180
+ // user specified max value
12181
+ findIndex = labels.indexOf(me.options.ticks.max);
12182
+ me.maxIndex = findIndex !== -1 ? findIndex : me.maxIndex;
12183
  }
12184
 
12185
+ me.min = labels[me.minIndex];
12186
+ me.max = labels[me.maxIndex];
12187
  },
12188
+
12189
+ buildTicks: function() {
12190
+ var me = this;
12191
+ var labels = me.getLabels();
12192
+ // If we are viewing some subset of labels, slice the original array
12193
+ me.ticks = (me.minIndex === 0 && me.maxIndex === labels.length - 1) ? labels : labels.slice(me.minIndex, me.maxIndex + 1);
12194
  },
 
 
 
 
 
 
 
 
 
 
 
12195
 
12196
+ getLabelForIndex: function(index, datasetIndex) {
12197
+ var me = this;
12198
+ var data = me.chart.data;
12199
+ var isHorizontal = me.isHorizontal();
 
12200
 
12201
+ if (data.yLabels && !isHorizontal) {
12202
+ return me.getRightValue(data.datasets[datasetIndex].data[index]);
12203
+ }
12204
+ return me.ticks[index - me.minIndex];
12205
+ },
12206
 
12207
+ // Used to get data value locations. Value can either be an index or a numerical value
12208
+ getPixelForValue: function(value, index) {
12209
+ var me = this;
12210
+ var offset = me.options.offset;
12211
+ // 1 is added because we need the length but we have the indexes
12212
+ var offsetAmt = Math.max((me.maxIndex + 1 - me.minIndex - (offset ? 0 : 1)), 1);
12213
+
12214
+ // If value is a data object, then index is the index in the data array,
12215
+ // not the index of the scale. We need to change that.
12216
+ var valueCategory;
12217
+ if (value !== undefined && value !== null) {
12218
+ valueCategory = me.isHorizontal() ? value.x : value.y;
12219
+ }
12220
+ if (valueCategory !== undefined || (value !== undefined && isNaN(index))) {
12221
+ var labels = me.getLabels();
12222
+ value = valueCategory || value;
12223
+ var idx = labels.indexOf(value);
12224
+ index = idx !== -1 ? idx : index;
12225
+ }
12226
 
12227
+ if (me.isHorizontal()) {
12228
+ var valueWidth = me.width / offsetAmt;
12229
+ var widthOffset = (valueWidth * (index - me.minIndex));
 
 
 
 
 
 
12230
 
12231
+ if (offset) {
12232
+ widthOffset += (valueWidth / 2);
12233
+ }
12234
 
12235
+ return me.left + Math.round(widthOffset);
12236
+ }
12237
+ var valueHeight = me.height / offsetAmt;
12238
+ var heightOffset = (valueHeight * (index - me.minIndex));
 
 
12239
 
12240
+ if (offset) {
12241
+ heightOffset += (valueHeight / 2);
12242
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
12243
 
12244
+ return me.top + Math.round(heightOffset);
12245
+ },
12246
+ getPixelForTick: function(index) {
12247
+ return this.getPixelForValue(this.ticks[index], index + this.minIndex, null);
12248
+ },
12249
+ getValueForPixel: function(pixel) {
12250
+ var me = this;
12251
+ var offset = me.options.offset;
12252
+ var value;
12253
+ var offsetAmt = Math.max((me._ticks.length - (offset ? 0 : 1)), 1);
12254
+ var horz = me.isHorizontal();
12255
+ var valueDimension = (horz ? me.width : me.height) / offsetAmt;
12256
+
12257
+ pixel -= horz ? me.left : me.top;
12258
+
12259
+ if (offset) {
12260
+ pixel -= (valueDimension / 2);
12261
+ }
12262
 
12263
+ if (pixel <= 0) {
12264
+ value = 0;
12265
+ } else {
12266
+ value = Math.round(pixel / valueDimension);
12267
+ }
 
 
 
 
12268
 
12269
+ return value + me.minIndex;
12270
+ },
12271
+ getBasePixel: function() {
12272
+ return this.bottom;
12273
+ }
12274
+ });
12275
 
12276
+ Chart.scaleService.registerScaleType('category', DatasetScale, defaultConfig);
12277
 
12278
+ };
 
12279
 
12280
+ },{}],53:[function(require,module,exports){
12281
+ 'use strict';
12282
 
12283
+ var defaults = require(25);
12284
+ var helpers = require(45);
12285
+ var Ticks = require(34);
 
 
 
12286
 
12287
+ module.exports = function(Chart) {
 
 
 
 
 
 
 
 
12288
 
12289
+ var defaultConfig = {
12290
+ position: 'left',
12291
+ ticks: {
12292
+ callback: Ticks.formatters.linear
12293
  }
12294
+ };
12295
 
12296
+ var LinearScale = Chart.LinearScaleBase.extend({
12297
 
12298
+ determineDataLimits: function() {
12299
+ var me = this;
12300
+ var opts = me.options;
12301
+ var chart = me.chart;
12302
+ var data = chart.data;
12303
+ var datasets = data.datasets;
12304
+ var isHorizontal = me.isHorizontal();
12305
+ var DEFAULT_MIN = 0;
12306
+ var DEFAULT_MAX = 1;
12307
 
12308
+ function IDMatches(meta) {
12309
+ return isHorizontal ? meta.xAxisID === me.id : meta.yAxisID === me.id;
12310
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
12311
 
12312
+ // First Calculate the range
12313
+ me.min = null;
12314
+ me.max = null;
12315
 
12316
+ var hasStacks = opts.stacked;
12317
+ if (hasStacks === undefined) {
12318
+ helpers.each(datasets, function(dataset, datasetIndex) {
12319
+ if (hasStacks) {
12320
+ return;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
12321
  }
12322
+
12323
+ var meta = chart.getDatasetMeta(datasetIndex);
12324
+ if (chart.isDatasetVisible(datasetIndex) && IDMatches(meta) &&
12325
+ meta.stack !== undefined) {
12326
+ hasStacks = true;
 
 
 
 
 
 
 
 
12327
  }
12328
+ });
12329
  }
12330
 
12331
+ if (opts.stacked || hasStacks) {
12332
+ var valuesPerStack = {};
12333
+
12334
+ helpers.each(datasets, function(dataset, datasetIndex) {
12335
+ var meta = chart.getDatasetMeta(datasetIndex);
12336
+ var key = [
12337
+ meta.type,
12338
+ // we have a separate stack for stack=undefined datasets when the opts.stacked is undefined
12339
+ ((opts.stacked === undefined && meta.stack === undefined) ? datasetIndex : ''),
12340
+ meta.stack
12341
+ ].join('.');
12342
+
12343
+ if (valuesPerStack[key] === undefined) {
12344
+ valuesPerStack[key] = {
12345
+ positiveValues: [],
12346
+ negativeValues: []
12347
+ };
12348
+ }
12349
 
12350
+ // Store these per type
12351
+ var positiveValues = valuesPerStack[key].positiveValues;
12352
+ var negativeValues = valuesPerStack[key].negativeValues;
12353
 
12354
+ if (chart.isDatasetVisible(datasetIndex) && IDMatches(meta)) {
12355
+ helpers.each(dataset.data, function(rawValue, index) {
12356
+ var value = +me.getRightValue(rawValue);
12357
+ if (isNaN(value) || meta.data[index].hidden) {
12358
+ return;
12359
+ }
12360
 
12361
+ positiveValues[index] = positiveValues[index] || 0;
12362
+ negativeValues[index] = negativeValues[index] || 0;
12363
 
12364
+ if (opts.relativePoints) {
12365
+ positiveValues[index] = 100;
12366
+ } else if (value < 0) {
12367
+ negativeValues[index] += value;
12368
+ } else {
12369
+ positiveValues[index] += value;
12370
+ }
12371
+ });
12372
+ }
12373
+ });
12374
 
12375
+ helpers.each(valuesPerStack, function(valuesForType) {
12376
+ var values = valuesForType.positiveValues.concat(valuesForType.negativeValues);
12377
+ var minVal = helpers.min(values);
12378
+ var maxVal = helpers.max(values);
12379
+ me.min = me.min === null ? minVal : Math.min(me.min, minVal);
12380
+ me.max = me.max === null ? maxVal : Math.max(me.max, maxVal);
12381
+ });
12382
 
12383
+ } else {
12384
+ helpers.each(datasets, function(dataset, datasetIndex) {
12385
+ var meta = chart.getDatasetMeta(datasetIndex);
12386
+ if (chart.isDatasetVisible(datasetIndex) && IDMatches(meta)) {
12387
+ helpers.each(dataset.data, function(rawValue, index) {
12388
+ var value = +me.getRightValue(rawValue);
12389
+ if (isNaN(value) || meta.data[index].hidden) {
12390
+ return;
12391
+ }
12392
 
12393
+ if (me.min === null) {
12394
+ me.min = value;
12395
+ } else if (value < me.min) {
12396
+ me.min = value;
12397
+ }
12398
 
12399
+ if (me.max === null) {
12400
+ me.max = value;
12401
+ } else if (value > me.max) {
12402
+ me.max = value;
12403
+ }
12404
+ });
12405
+ }
12406
+ });
12407
+ }
12408
 
12409
+ me.min = isFinite(me.min) && !isNaN(me.min) ? me.min : DEFAULT_MIN;
12410
+ me.max = isFinite(me.max) && !isNaN(me.max) ? me.max : DEFAULT_MAX;
12411
 
12412
+ // Common base implementation to handle ticks.min, ticks.max, ticks.beginAtZero
12413
+ this.handleTickRangeOptions();
 
12414
  },
12415
+ getTickLimit: function() {
12416
+ var maxTicks;
12417
+ var me = this;
12418
+ var tickOpts = me.options.ticks;
12419
 
12420
+ if (me.isHorizontal()) {
12421
+ maxTicks = Math.min(tickOpts.maxTicksLimit ? tickOpts.maxTicksLimit : 11, Math.ceil(me.width / 50));
12422
+ } else {
12423
+ // The factor of 2 used to scale the font size has been experimentally determined.
12424
+ var tickFontSize = helpers.valueOrDefault(tickOpts.fontSize, defaults.global.defaultFontSize);
12425
+ maxTicks = Math.min(tickOpts.maxTicksLimit ? tickOpts.maxTicksLimit : 11, Math.ceil(me.height / (2 * tickFontSize)));
12426
+ }
12427
 
12428
+ return maxTicks;
12429
  },
12430
+ // Called after the ticks are built. We need
12431
+ handleDirectionalChanges: function() {
12432
+ if (!this.isHorizontal()) {
12433
+ // We are in a vertical orientation. The top value is the highest. So reverse the array
12434
+ this.ticks.reverse();
12435
+ }
12436
+ },
12437
+ getLabelForIndex: function(index, datasetIndex) {
12438
+ return +this.getRightValue(this.chart.data.datasets[datasetIndex].data[index]);
12439
  },
12440
+ // Utils
12441
+ getPixelForValue: function(value) {
12442
+ // This must be called after fit has been run so that
12443
+ // this.left, this.top, this.right, and this.bottom have been defined
12444
+ var me = this;
12445
+ var start = me.start;
12446
+
12447
+ var rightValue = +me.getRightValue(value);
12448
+ var pixel;
12449
+ var range = me.end - start;
12450
+
12451
+ if (me.isHorizontal()) {
12452
+ pixel = me.left + (me.width / range * (rightValue - start));
12453
+ return Math.round(pixel);
12454
+ }
12455
 
12456
+ pixel = me.bottom - (me.height / range * (rightValue - start));
12457
+ return Math.round(pixel);
12458
+ },
12459
+ getValueForPixel: function(pixel) {
12460
+ var me = this;
12461
+ var isHorizontal = me.isHorizontal();
12462
+ var innerDimension = isHorizontal ? me.width : me.height;
12463
+ var offset = (isHorizontal ? pixel - me.left : me.bottom - pixel) / innerDimension;
12464
+ return me.start + ((me.end - me.start) * offset);
12465
+ },
12466
+ getPixelForTick: function(index) {
12467
+ return this.getPixelForValue(this.ticksAsNumbers[index]);
12468
+ }
12469
+ });
12470
+ Chart.scaleService.registerScaleType('linear', LinearScale, defaultConfig);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
12471
 
12472
+ };
 
 
12473
 
12474
+ },{"25":25,"34":34,"45":45}],54:[function(require,module,exports){
12475
+ 'use strict';
12476
 
12477
+ var helpers = require(45);
12478
+ var Ticks = require(34);
12479
 
12480
+ module.exports = function(Chart) {
 
12481
 
12482
+ var noop = helpers.noop;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
12483
 
12484
+ Chart.LinearScaleBase = Chart.Scale.extend({
12485
+ getRightValue: function(value) {
12486
+ if (typeof value === 'string') {
12487
+ return +value;
12488
+ }
12489
+ return Chart.Scale.prototype.getRightValue.call(this, value);
12490
+ },
 
12491
 
12492
+ handleTickRangeOptions: function() {
12493
+ var me = this;
12494
+ var opts = me.options;
12495
+ var tickOpts = opts.ticks;
12496
+
12497
+ // If we are forcing it to begin at 0, but 0 will already be rendered on the chart,
12498
+ // do nothing since that would make the chart weird. If the user really wants a weird chart
12499
+ // axis, they can manually override it
12500
+ if (tickOpts.beginAtZero) {
12501
+ var minSign = helpers.sign(me.min);
12502
+ var maxSign = helpers.sign(me.max);
12503
+
12504
+ if (minSign < 0 && maxSign < 0) {
12505
+ // move the top up to 0
12506
+ me.max = 0;
12507
+ } else if (minSign > 0 && maxSign > 0) {
12508
+ // move the bottom down to 0
12509
+ me.min = 0;
12510
  }
12511
  }
 
 
12512
 
12513
+ var setMin = tickOpts.min !== undefined || tickOpts.suggestedMin !== undefined;
12514
+ var setMax = tickOpts.max !== undefined || tickOpts.suggestedMax !== undefined;
12515
+
12516
+ if (tickOpts.min !== undefined) {
12517
+ me.min = tickOpts.min;
12518
+ } else if (tickOpts.suggestedMin !== undefined) {
12519
+ if (me.min === null) {
12520
+ me.min = tickOpts.suggestedMin;
12521
+ } else {
12522
+ me.min = Math.min(me.min, tickOpts.suggestedMin);
12523
  }
12524
  }
 
 
 
 
 
12525
 
12526
+ if (tickOpts.max !== undefined) {
12527
+ me.max = tickOpts.max;
12528
+ } else if (tickOpts.suggestedMax !== undefined) {
12529
+ if (me.max === null) {
12530
+ me.max = tickOpts.suggestedMax;
12531
+ } else {
12532
+ me.max = Math.max(me.max, tickOpts.suggestedMax);
12533
+ }
 
 
 
 
 
 
12534
  }
 
 
 
 
 
 
 
 
 
12535
 
12536
+ if (setMin !== setMax) {
12537
+ // We set the min or the max but not both.
12538
+ // So ensure that our range is good
12539
+ // Inverted or 0 length range can happen when
12540
+ // ticks.min is set, and no datasets are visible
12541
+ if (me.min >= me.max) {
12542
+ if (setMin) {
12543
+ me.max = me.min + 1;
12544
+ } else {
12545
+ me.min = me.max - 1;
12546
+ }
12547
+ }
12548
  }
12549
 
12550
+ if (me.min === me.max) {
12551
+ me.max++;
 
 
 
12552
 
12553
+ if (!tickOpts.beginAtZero) {
12554
+ me.min--;
 
 
 
 
 
 
 
 
 
 
 
 
 
12555
  }
12556
  }
12557
+ },
12558
+ getTickLimit: noop,
12559
+ handleDirectionalChanges: noop,
12560
+
12561
+ buildTicks: function() {
12562
+ var me = this;
12563
+ var opts = me.options;
12564
+ var tickOpts = opts.ticks;
12565
+
12566
+ // Figure out what the max number of ticks we can support it is based on the size of
12567
+ // the axis area. For now, we say that the minimum tick spacing in pixels must be 50
12568
+ // We also limit the maximum number of ticks to 11 which gives a nice 10 squares on
12569
+ // the graph. Make sure we always have at least 2 ticks
12570
+ var maxTicks = me.getTickLimit();
12571
+ maxTicks = Math.max(2, maxTicks);
12572
+
12573
+ var numericGeneratorOptions = {
12574
+ maxTicks: maxTicks,
12575
+ min: tickOpts.min,
12576
+ max: tickOpts.max,
12577
+ stepSize: helpers.valueOrDefault(tickOpts.fixedStepSize, tickOpts.stepSize)
12578
+ };
12579
+ var ticks = me.ticks = Ticks.generators.linear(numericGeneratorOptions, me);
12580
 
12581
+ me.handleDirectionalChanges();
 
 
12582
 
12583
+ // At this point, we need to update our max and min given the tick values since we have expanded the
12584
+ // range of the scale
12585
+ me.max = helpers.max(ticks);
12586
+ me.min = helpers.min(ticks);
12587
 
12588
+ if (tickOpts.reverse) {
12589
+ ticks.reverse();
12590
+
12591
+ me.start = me.max;
12592
+ me.end = me.min;
12593
+ } else {
12594
+ me.start = me.min;
12595
+ me.end = me.max;
12596
  }
12597
+ },
12598
+ convertTicksToLabels: function() {
12599
+ var me = this;
12600
+ me.ticksAsNumbers = me.ticks.slice();
12601
+ me.zeroLineIndex = me.ticks.indexOf(0);
12602
+
12603
+ Chart.Scale.prototype.convertTicksToLabels.call(me);
12604
  }
12605
+ });
12606
+ };
12607
 
12608
+ },{"34":34,"45":45}],55:[function(require,module,exports){
12609
+ 'use strict';
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
12610
 
12611
+ var helpers = require(45);
12612
+ var Ticks = require(34);
12613
 
12614
+ module.exports = function(Chart) {
 
 
 
 
 
 
12615
 
12616
+ var defaultConfig = {
12617
+ position: 'left',
12618
 
12619
+ // label settings
12620
+ ticks: {
12621
+ callback: Ticks.formatters.logarithmic
12622
+ }
12623
  };
12624
 
12625
+ var LogarithmicScale = Chart.Scale.extend({
12626
+ determineDataLimits: function() {
12627
+ var me = this;
12628
+ var opts = me.options;
12629
+ var tickOpts = opts.ticks;
12630
+ var chart = me.chart;
12631
+ var data = chart.data;
12632
+ var datasets = data.datasets;
12633
+ var valueOrDefault = helpers.valueOrDefault;
12634
+ var isHorizontal = me.isHorizontal();
12635
+ function IDMatches(meta) {
12636
+ return isHorizontal ? meta.xAxisID === me.id : meta.yAxisID === me.id;
12637
+ }
12638
 
12639
+ // Calculate Range
12640
+ me.min = null;
12641
+ me.max = null;
12642
+ me.minNotZero = null;
12643
 
12644
+ var hasStacks = opts.stacked;
12645
+ if (hasStacks === undefined) {
12646
+ helpers.each(datasets, function(dataset, datasetIndex) {
12647
+ if (hasStacks) {
12648
+ return;
12649
+ }
12650
 
12651
+ var meta = chart.getDatasetMeta(datasetIndex);
12652
+ if (chart.isDatasetVisible(datasetIndex) && IDMatches(meta) &&
12653
+ meta.stack !== undefined) {
12654
+ hasStacks = true;
12655
+ }
12656
+ });
12657
+ }
12658
 
12659
+ if (opts.stacked || hasStacks) {
12660
+ var valuesPerStack = {};
12661
+
12662
+ helpers.each(datasets, function(dataset, datasetIndex) {
12663
+ var meta = chart.getDatasetMeta(datasetIndex);
12664
+ var key = [
12665
+ meta.type,
12666
+ // we have a separate stack for stack=undefined datasets when the opts.stacked is undefined
12667
+ ((opts.stacked === undefined && meta.stack === undefined) ? datasetIndex : ''),
12668
+ meta.stack
12669
+ ].join('.');
12670
+
12671
+ if (chart.isDatasetVisible(datasetIndex) && IDMatches(meta)) {
12672
+ if (valuesPerStack[key] === undefined) {
12673
+ valuesPerStack[key] = [];
12674
+ }
12675
 
12676
+ helpers.each(dataset.data, function(rawValue, index) {
12677
+ var values = valuesPerStack[key];
12678
+ var value = +me.getRightValue(rawValue);
12679
+ if (isNaN(value) || meta.data[index].hidden) {
12680
+ return;
12681
+ }
12682
 
12683
+ values[index] = values[index] || 0;
 
12684
 
12685
+ if (opts.relativePoints) {
12686
+ values[index] = 100;
12687
+ } else {
12688
+ // Don't need to split positive and negative since the log scale can't handle a 0 crossing
12689
+ values[index] += value;
12690
+ }
12691
+ });
12692
+ }
12693
+ });
12694
 
12695
+ helpers.each(valuesPerStack, function(valuesForType) {
12696
+ var minVal = helpers.min(valuesForType);
12697
+ var maxVal = helpers.max(valuesForType);
12698
+ me.min = me.min === null ? minVal : Math.min(me.min, minVal);
12699
+ me.max = me.max === null ? maxVal : Math.max(me.max, maxVal);
12700
+ });
12701
 
12702
+ } else {
12703
+ helpers.each(datasets, function(dataset, datasetIndex) {
12704
+ var meta = chart.getDatasetMeta(datasetIndex);
12705
+ if (chart.isDatasetVisible(datasetIndex) && IDMatches(meta)) {
12706
+ helpers.each(dataset.data, function(rawValue, index) {
12707
+ var value = +me.getRightValue(rawValue);
12708
+ if (isNaN(value) || meta.data[index].hidden) {
12709
+ return;
12710
+ }
12711
 
12712
+ if (me.min === null) {
12713
+ me.min = value;
12714
+ } else if (value < me.min) {
12715
+ me.min = value;
12716
+ }
12717
 
12718
+ if (me.max === null) {
12719
+ me.max = value;
12720
+ } else if (value > me.max) {
12721
+ me.max = value;
12722
+ }
12723
 
12724
+ if (value !== 0 && (me.minNotZero === null || value < me.minNotZero)) {
12725
+ me.minNotZero = value;
12726
+ }
12727
+ });
12728
+ }
12729
+ });
12730
+ }
12731
 
12732
+ me.min = valueOrDefault(tickOpts.min, me.min);
12733
+ me.max = valueOrDefault(tickOpts.max, me.max);
12734
 
12735
+ if (me.min === me.max) {
12736
+ if (me.min !== 0 && me.min !== null) {
12737
+ me.min = Math.pow(10, Math.floor(helpers.log10(me.min)) - 1);
12738
+ me.max = Math.pow(10, Math.floor(helpers.log10(me.max)) + 1);
12739
+ } else {
12740
+ me.min = 1;
12741
+ me.max = 10;
12742
+ }
12743
+ }
12744
+ },
12745
+ buildTicks: function() {
12746
+ var me = this;
12747
+ var opts = me.options;
12748
+ var tickOpts = opts.ticks;
12749
+
12750
+ var generationOptions = {
12751
+ min: tickOpts.min,
12752
+ max: tickOpts.max
12753
+ };
12754
+ var ticks = me.ticks = Ticks.generators.logarithmic(generationOptions, me);
12755
 
12756
+ if (!me.isHorizontal()) {
12757
+ // We are in a vertical orientation. The top value is the highest. So reverse the array
12758
+ ticks.reverse();
12759
+ }
12760
 
12761
+ // At this point, we need to update our max and min given the tick values since we have expanded the
12762
+ // range of the scale
12763
+ me.max = helpers.max(ticks);
12764
+ me.min = helpers.min(ticks);
12765
 
12766
+ if (tickOpts.reverse) {
12767
+ ticks.reverse();
 
 
 
 
 
12768
 
12769
+ me.start = me.max;
12770
+ me.end = me.min;
12771
+ } else {
12772
+ me.start = me.min;
12773
+ me.end = me.max;
12774
+ }
12775
+ },
12776
+ convertTicksToLabels: function() {
12777
+ this.tickValues = this.ticks.slice();
12778
 
12779
+ Chart.Scale.prototype.convertTicksToLabels.call(this);
12780
+ },
12781
+ // Get the correct tooltip label
12782
+ getLabelForIndex: function(index, datasetIndex) {
12783
+ return +this.getRightValue(this.chart.data.datasets[datasetIndex].data[index]);
12784
+ },
12785
+ getPixelForTick: function(index) {
12786
+ return this.getPixelForValue(this.tickValues[index]);
12787
+ },
12788
+ getPixelForValue: function(value) {
12789
+ var me = this;
12790
+ var start = me.start;
12791
+ var newVal = +me.getRightValue(value);
12792
+ var opts = me.options;
12793
+ var tickOpts = opts.ticks;
12794
+ var innerDimension, pixel, range;
12795
+
12796
+ if (me.isHorizontal()) {
12797
+ range = helpers.log10(me.end) - helpers.log10(start); // todo: if start === 0
12798
+ if (newVal === 0) {
12799
+ pixel = me.left;
12800
+ } else {
12801
+ innerDimension = me.width;
12802
+ pixel = me.left + (innerDimension / range * (helpers.log10(newVal) - helpers.log10(start)));
12803
  }
12804
+ } else {
12805
+ // Bottom - top since pixels increase downward on a screen
12806
+ innerDimension = me.height;
12807
+ if (start === 0 && !tickOpts.reverse) {
12808
+ range = helpers.log10(me.end) - helpers.log10(me.minNotZero);
12809
+ if (newVal === start) {
12810
+ pixel = me.bottom;
12811
+ } else if (newVal === me.minNotZero) {
12812
+ pixel = me.bottom - innerDimension * 0.02;
12813
+ } else {
12814
+ pixel = me.bottom - innerDimension * 0.02 - (innerDimension * 0.98 / range * (helpers.log10(newVal) - helpers.log10(me.minNotZero)));
12815
+ }
12816
+ } else if (me.end === 0 && tickOpts.reverse) {
12817
+ range = helpers.log10(me.start) - helpers.log10(me.minNotZero);
12818
+ if (newVal === me.end) {
12819
+ pixel = me.top;
12820
+ } else if (newVal === me.minNotZero) {
12821
+ pixel = me.top + innerDimension * 0.02;
12822
+ } else {
12823
+ pixel = me.top + innerDimension * 0.02 + (innerDimension * 0.98 / range * (helpers.log10(newVal) - helpers.log10(me.minNotZero)));
12824
+ }
12825
+ } else if (newVal === 0) {
12826
+ pixel = tickOpts.reverse ? me.top : me.bottom;
12827
+ } else {
12828
+ range = helpers.log10(me.end) - helpers.log10(start);
12829
+ innerDimension = me.height;
12830
+ pixel = me.bottom - (innerDimension / range * (helpers.log10(newVal) - helpers.log10(start)));
12831
+ }
12832
+ }
12833
+ return pixel;
12834
+ },
12835
+ getValueForPixel: function(pixel) {
12836
+ var me = this;
12837
+ var range = helpers.log10(me.end) - helpers.log10(me.start);
12838
+ var value, innerDimension;
12839
+
12840
+ if (me.isHorizontal()) {
12841
+ innerDimension = me.width;
12842
+ value = me.start * Math.pow(10, (pixel - me.left) * range / innerDimension);
12843
+ } else { // todo: if start === 0
12844
+ innerDimension = me.height;
12845
+ value = Math.pow(10, (me.bottom - pixel) * range / innerDimension) / me.start;
12846
+ }
12847
+ return value;
12848
+ }
12849
+ });
12850
+ Chart.scaleService.registerScaleType('logarithmic', LogarithmicScale, defaultConfig);
12851
 
12852
+ };
12853
 
12854
+ },{"34":34,"45":45}],56:[function(require,module,exports){
12855
+ 'use strict';
 
 
12856
 
12857
+ var defaults = require(25);
12858
+ var helpers = require(45);
12859
+ var Ticks = require(34);
 
 
 
 
 
 
 
12860
 
12861
+ module.exports = function(Chart) {
 
 
 
 
 
12862
 
12863
+ var globalDefaults = defaults.global;
 
12864
 
12865
+ var defaultConfig = {
12866
+ display: true,
 
 
 
 
12867
 
12868
+ // Boolean - Whether to animate scaling the chart from the centre
12869
+ animate: true,
12870
+ position: 'chartArea',
12871
+
12872
+ angleLines: {
12873
+ display: true,
12874
+ color: 'rgba(0, 0, 0, 0.1)',
12875
+ lineWidth: 1
12876
+ },
12877
 
12878
+ gridLines: {
12879
+ circular: false
12880
+ },
 
 
 
 
 
 
 
 
 
12881
 
12882
+ // label settings
12883
+ ticks: {
12884
+ // Boolean - Show a backdrop to the scale label
12885
+ showLabelBackdrop: true,
12886
 
12887
+ // String - The colour of the label backdrop
12888
+ backdropColor: 'rgba(255,255,255,0.75)',
12889
 
12890
+ // Number - The backdrop padding above & below the label in pixels
12891
+ backdropPaddingY: 2,
12892
 
12893
+ // Number - The backdrop padding to the side of the label in pixels
12894
+ backdropPaddingX: 2,
 
 
 
 
 
 
12895
 
12896
+ callback: Ticks.formatters.linear
12897
  },
 
 
 
 
 
 
12898
 
12899
+ pointLabels: {
12900
+ // Boolean - if true, show point labels
12901
+ display: true,
 
 
 
 
 
 
 
 
 
 
 
 
 
 
12902
 
12903
+ // Number - Point label font size in pixels
12904
+ fontSize: 10,
12905
+
12906
+ // Function - Used to convert point labels
12907
+ callback: function(label) {
12908
+ return label;
 
12909
  }
12910
+ }
12911
+ };
12912
 
12913
+ function getValueCount(scale) {
12914
+ var opts = scale.options;
12915
+ return opts.angleLines.display || opts.pointLabels.display ? scale.chart.data.labels.length : 0;
12916
+ }
12917
 
12918
+ function getPointLabelFontOptions(scale) {
12919
+ var pointLabelOptions = scale.options.pointLabels;
12920
+ var fontSize = helpers.valueOrDefault(pointLabelOptions.fontSize, globalDefaults.defaultFontSize);
12921
+ var fontStyle = helpers.valueOrDefault(pointLabelOptions.fontStyle, globalDefaults.defaultFontStyle);
12922
+ var fontFamily = helpers.valueOrDefault(pointLabelOptions.fontFamily, globalDefaults.defaultFontFamily);
12923
+ var font = helpers.fontString(fontSize, fontStyle, fontFamily);
12924
+
12925
+ return {
12926
+ size: fontSize,
12927
+ style: fontStyle,
12928
+ family: fontFamily,
12929
+ font: font
12930
+ };
12931
+ }
12932
+
12933
+ function measureLabelSize(ctx, fontSize, label) {
12934
+ if (helpers.isArray(label)) {
12935
+ return {
12936
+ w: helpers.longestText(ctx, ctx.font, label),
12937
+ h: (label.length * fontSize) + ((label.length - 1) * 1.5 * fontSize)
12938
  };
12939
+ }
12940
 
12941
+ return {
12942
+ w: ctx.measureText(label).width,
12943
+ h: fontSize
12944
+ };
12945
+ }
12946
+
12947
+ function determineLimits(angle, pos, size, min, max) {
12948
+ if (angle === min || angle === max) {
12949
+ return {
12950
+ start: pos - (size / 2),
12951
+ end: pos + (size / 2)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
12952
  };
12953
+ } else if (angle < min || angle > max) {
12954
+ return {
12955
+ start: pos - size - 5,
12956
+ end: pos
12957
+ };
12958
+ }
12959
 
12960
+ return {
12961
+ start: pos,
12962
+ end: pos + size + 5
12963
+ };
12964
+ }
12965
+
12966
+ /**
12967
+ * Helper function to fit a radial linear scale with point labels
12968
+ */
12969
+ function fitWithPointLabels(scale) {
12970
+ /*
12971
+ * Right, this is really confusing and there is a lot of maths going on here
12972
+ * The gist of the problem is here: https://gist.github.com/nnnick/696cc9c55f4b0beb8fe9
12973
+ *
12974
+ * Reaction: https://dl.dropboxusercontent.com/u/34601363/toomuchscience.gif
12975
+ *
12976
+ * Solution:
12977
+ *
12978
+ * We assume the radius of the polygon is half the size of the canvas at first
12979
+ * at each index we check if the text overlaps.
12980
+ *
12981
+ * Where it does, we store that angle and that index.
12982
+ *
12983
+ * After finding the largest index and angle we calculate how much we need to remove
12984
+ * from the shape radius to move the point inwards by that x.
12985
+ *
12986
+ * We average the left and right distances to get the maximum shape radius that can fit in the box
12987
+ * along with labels.
12988
+ *
12989
+ * Once we have that, we can find the centre point for the chart, by taking the x text protrusion
12990
+ * on each side, removing that from the size, halving it and adding the left x protrusion width.
12991
+ *
12992
+ * This will mean we have a shape fitted to the canvas, as large as it can be with the labels
12993
+ * and position it in the most space efficient manner
12994
+ *
12995
+ * https://dl.dropboxusercontent.com/u/34601363/yeahscience.gif
12996
+ */
12997
+
12998
+ var plFont = getPointLabelFontOptions(scale);
12999
+
13000
+ // Get maximum radius of the polygon. Either half the height (minus the text width) or half the width.
13001
+ // Use this to calculate the offset + change. - Make sure L/R protrusion is at least 0 to stop issues with centre points
13002
+ var largestPossibleRadius = Math.min(scale.height / 2, scale.width / 2);
13003
+ var furthestLimits = {
13004
+ r: scale.width,
13005
+ l: 0,
13006
+ t: scale.height,
13007
+ b: 0
13008
+ };
13009
+ var furthestAngles = {};
13010
+ var i, textSize, pointPosition;
13011
+
13012
+ scale.ctx.font = plFont.font;
13013
+ scale._pointLabelSizes = [];
13014
+
13015
+ var valueCount = getValueCount(scale);
13016
+ for (i = 0; i < valueCount; i++) {
13017
+ pointPosition = scale.getPointPosition(i, largestPossibleRadius);
13018
+ textSize = measureLabelSize(scale.ctx, plFont.size, scale.pointLabels[i] || '');
13019
+ scale._pointLabelSizes[i] = textSize;
13020
+
13021
+ // Add quarter circle to make degree 0 mean top of circle
13022
+ var angleRadians = scale.getIndexAngle(i);
13023
+ var angle = helpers.toDegrees(angleRadians) % 360;
13024
+ var hLimits = determineLimits(angle, pointPosition.x, textSize.w, 0, 180);
13025
+ var vLimits = determineLimits(angle, pointPosition.y, textSize.h, 90, 270);
13026
+
13027
+ if (hLimits.start < furthestLimits.l) {
13028
+ furthestLimits.l = hLimits.start;
13029
+ furthestAngles.l = angleRadians;
13030
  }
13031
 
13032
+ if (hLimits.end > furthestLimits.r) {
13033
+ furthestLimits.r = hLimits.end;
13034
+ furthestAngles.r = angleRadians;
13035
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
13036
 
13037
+ if (vLimits.start < furthestLimits.t) {
13038
+ furthestLimits.t = vLimits.start;
13039
+ furthestAngles.t = angleRadians;
13040
+ }
13041
+
13042
+ if (vLimits.end > furthestLimits.b) {
13043
+ furthestLimits.b = vLimits.end;
13044
+ furthestAngles.b = angleRadians;
13045
+ }
13046
  }
 
13047
 
13048
+ scale.setReductions(largestPossibleRadius, furthestLimits, furthestAngles);
13049
+ }
13050
+
13051
+ /**
13052
+ * Helper function to fit a radial linear scale with no point labels
13053
+ */
13054
+ function fit(scale) {
13055
+ var largestPossibleRadius = Math.min(scale.height / 2, scale.width / 2);
13056
+ scale.drawingArea = Math.round(largestPossibleRadius);
13057
+ scale.setCenterPoint(0, 0, 0, 0);
13058
+ }
13059
+
13060
+ function getTextAlignForAngle(angle) {
13061
+ if (angle === 0 || angle === 180) {
13062
+ return 'center';
13063
+ } else if (angle < 180) {
13064
+ return 'left';
13065
+ }
13066
 
13067
+ return 'right';
13068
+ }
13069
 
13070
+ function fillText(ctx, text, position, fontSize) {
13071
+ if (helpers.isArray(text)) {
13072
+ var y = position.y;
13073
+ var spacing = 1.5 * fontSize;
13074
 
13075
+ for (var i = 0; i < text.length; ++i) {
13076
+ ctx.fillText(text[i], position.x, y);
13077
+ y += spacing;
13078
+ }
13079
+ } else {
13080
+ ctx.fillText(text, position.x, position.y);
13081
+ }
13082
+ }
13083
 
13084
+ function adjustPointPositionForLabelHeight(angle, textSize, position) {
13085
+ if (angle === 90 || angle === 270) {
13086
+ position.y -= (textSize.h / 2);
13087
+ } else if (angle > 270 || angle < 90) {
13088
+ position.y -= textSize.h;
13089
+ }
13090
+ }
13091
 
13092
+ function drawPointLabels(scale) {
13093
+ var ctx = scale.ctx;
13094
+ var valueOrDefault = helpers.valueOrDefault;
13095
+ var opts = scale.options;
13096
+ var angleLineOpts = opts.angleLines;
13097
+ var pointLabelOpts = opts.pointLabels;
13098
 
13099
+ ctx.lineWidth = angleLineOpts.lineWidth;
13100
+ ctx.strokeStyle = angleLineOpts.color;
13101
 
13102
+ var outerDistance = scale.getDistanceFromCenterForValue(opts.ticks.reverse ? scale.min : scale.max);
 
13103
 
13104
+ // Point Label Font
13105
+ var plFont = getPointLabelFontOptions(scale);
13106
 
13107
+ ctx.textBaseline = 'top';
 
13108
 
13109
+ for (var i = getValueCount(scale) - 1; i >= 0; i--) {
13110
+ if (angleLineOpts.display) {
13111
+ var outerPosition = scale.getPointPosition(i, outerDistance);
13112
+ ctx.beginPath();
13113
+ ctx.moveTo(scale.xCenter, scale.yCenter);
13114
+ ctx.lineTo(outerPosition.x, outerPosition.y);
13115
+ ctx.stroke();
13116
+ ctx.closePath();
13117
+ }
13118
 
13119
+ if (pointLabelOpts.display) {
13120
+ // Extra 3px out for some label spacing
13121
+ var pointLabelPosition = scale.getPointPosition(i, outerDistance + 5);
13122
 
13123
+ // Keep this in loop since we may support array properties here
13124
+ var pointLabelFontColor = valueOrDefault(pointLabelOpts.fontColor, globalDefaults.defaultFontColor);
13125
+ ctx.font = plFont.font;
13126
+ ctx.fillStyle = pointLabelFontColor;
13127
 
13128
+ var angleRadians = scale.getIndexAngle(i);
13129
+ var angle = helpers.toDegrees(angleRadians);
13130
+ ctx.textAlign = getTextAlignForAngle(angle);
13131
+ adjustPointPositionForLabelHeight(angle, scale._pointLabelSizes[i], pointLabelPosition);
13132
+ fillText(ctx, scale.pointLabels[i] || '', pointLabelPosition, plFont.size);
13133
+ }
13134
+ }
13135
+ }
13136
 
13137
+ function drawRadiusLine(scale, gridLineOpts, radius, index) {
13138
+ var ctx = scale.ctx;
13139
+ ctx.strokeStyle = helpers.valueAtIndexOrDefault(gridLineOpts.color, index - 1);
13140
+ ctx.lineWidth = helpers.valueAtIndexOrDefault(gridLineOpts.lineWidth, index - 1);
 
 
 
 
13141
 
13142
+ if (scale.options.gridLines.circular) {
13143
+ // Draw circular arcs between the points
13144
+ ctx.beginPath();
13145
+ ctx.arc(scale.xCenter, scale.yCenter, radius, 0, Math.PI * 2);
13146
+ ctx.closePath();
13147
+ ctx.stroke();
13148
+ } else {
13149
+ // Draw straight lines connecting each index
13150
+ var valueCount = getValueCount(scale);
13151
 
13152
+ if (valueCount === 0) {
13153
+ return;
13154
+ }
 
 
13155
 
13156
+ ctx.beginPath();
13157
+ var pointPosition = scale.getPointPosition(0, radius);
13158
+ ctx.moveTo(pointPosition.x, pointPosition.y);
 
13159
 
13160
+ for (var i = 1; i < valueCount; i++) {
13161
+ pointPosition = scale.getPointPosition(i, radius);
13162
+ ctx.lineTo(pointPosition.x, pointPosition.y);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
13163
  }
 
 
 
 
 
 
 
 
 
13164
 
13165
+ ctx.closePath();
13166
+ ctx.stroke();
13167
+ }
13168
+ }
13169
 
13170
+ function numberOrZero(param) {
13171
+ return helpers.isNumber(param) ? param : 0;
13172
+ }
 
 
13173
 
13174
+ var LinearRadialScale = Chart.LinearScaleBase.extend({
13175
+ setDimensions: function() {
13176
+ var me = this;
13177
+ var opts = me.options;
13178
+ var tickOpts = opts.ticks;
13179
+ // Set the unconstrained dimension before label rotation
13180
+ me.width = me.maxWidth;
13181
+ me.height = me.maxHeight;
13182
+ me.xCenter = Math.round(me.width / 2);
13183
+ me.yCenter = Math.round(me.height / 2);
13184
+
13185
+ var minSize = helpers.min([me.height, me.width]);
13186
+ var tickFontSize = helpers.valueOrDefault(tickOpts.fontSize, globalDefaults.defaultFontSize);
13187
+ me.drawingArea = opts.display ? (minSize / 2) - (tickFontSize / 2 + tickOpts.backdropPaddingY) : (minSize / 2);
13188
  },
13189
+ determineDataLimits: function() {
13190
+ var me = this;
13191
+ var chart = me.chart;
13192
+ var min = Number.POSITIVE_INFINITY;
13193
+ var max = Number.NEGATIVE_INFINITY;
13194
+
13195
+ helpers.each(chart.data.datasets, function(dataset, datasetIndex) {
13196
+ if (chart.isDatasetVisible(datasetIndex)) {
13197
+ var meta = chart.getDatasetMeta(datasetIndex);
13198
+
13199
+ helpers.each(dataset.data, function(rawValue, index) {
13200
+ var value = +me.getRightValue(rawValue);
13201
+ if (isNaN(value) || meta.data[index].hidden) {
13202
+ return;
13203
+ }
13204
 
13205
+ min = Math.min(value, min);
13206
+ max = Math.max(value, max);
13207
+ });
13208
+ }
13209
  });
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
13210
 
13211
+ me.min = (min === Number.POSITIVE_INFINITY ? 0 : min);
13212
+ me.max = (max === Number.NEGATIVE_INFINITY ? 0 : max);
 
 
 
 
 
 
 
13213
 
13214
+ // Common base implementation to handle ticks.min, ticks.max, ticks.beginAtZero
13215
+ me.handleTickRangeOptions();
13216
+ },
13217
+ getTickLimit: function() {
13218
+ var tickOpts = this.options.ticks;
13219
+ var tickFontSize = helpers.valueOrDefault(tickOpts.fontSize, globalDefaults.defaultFontSize);
13220
+ return Math.min(tickOpts.maxTicksLimit ? tickOpts.maxTicksLimit : 11, Math.ceil(this.drawingArea / (1.5 * tickFontSize)));
13221
+ },
13222
+ convertTicksToLabels: function() {
13223
+ var me = this;
13224
 
13225
+ Chart.LinearScaleBase.prototype.convertTicksToLabels.call(me);
 
 
 
13226
 
13227
+ // Point labels
13228
+ me.pointLabels = me.chart.data.labels.map(me.options.pointLabels.callback, me);
13229
+ },
13230
+ getLabelForIndex: function(index, datasetIndex) {
13231
+ return +this.getRightValue(this.chart.data.datasets[datasetIndex].data[index]);
13232
+ },
13233
+ fit: function() {
13234
+ if (this.options.pointLabels.display) {
13235
+ fitWithPointLabels(this);
13236
+ } else {
13237
+ fit(this);
13238
+ }
13239
+ },
13240
+ /**
13241
+ * Set radius reductions and determine new radius and center point
13242
+ * @private
13243
+ */
13244
+ setReductions: function(largestPossibleRadius, furthestLimits, furthestAngles) {
13245
+ var me = this;
13246
+ var radiusReductionLeft = furthestLimits.l / Math.sin(furthestAngles.l);
13247
+ var radiusReductionRight = Math.max(furthestLimits.r - me.width, 0) / Math.sin(furthestAngles.r);
13248
+ var radiusReductionTop = -furthestLimits.t / Math.cos(furthestAngles.t);
13249
+ var radiusReductionBottom = -Math.max(furthestLimits.b - me.height, 0) / Math.cos(furthestAngles.b);
13250
+
13251
+ radiusReductionLeft = numberOrZero(radiusReductionLeft);
13252
+ radiusReductionRight = numberOrZero(radiusReductionRight);
13253
+ radiusReductionTop = numberOrZero(radiusReductionTop);
13254
+ radiusReductionBottom = numberOrZero(radiusReductionBottom);
13255
+
13256
+ me.drawingArea = Math.min(
13257
+ Math.round(largestPossibleRadius - (radiusReductionLeft + radiusReductionRight) / 2),
13258
+ Math.round(largestPossibleRadius - (radiusReductionTop + radiusReductionBottom) / 2));
13259
+ me.setCenterPoint(radiusReductionLeft, radiusReductionRight, radiusReductionTop, radiusReductionBottom);
13260
+ },
13261
+ setCenterPoint: function(leftMovement, rightMovement, topMovement, bottomMovement) {
13262
+ var me = this;
13263
+ var maxRight = me.width - rightMovement - me.drawingArea;
13264
+ var maxLeft = leftMovement + me.drawingArea;
13265
+ var maxTop = topMovement + me.drawingArea;
13266
+ var maxBottom = me.height - bottomMovement - me.drawingArea;
13267
+
13268
+ me.xCenter = Math.round(((maxLeft + maxRight) / 2) + me.left);
13269
+ me.yCenter = Math.round(((maxTop + maxBottom) / 2) + me.top);
13270
+ },
13271
 
13272
+ getIndexAngle: function(index) {
13273
+ var angleMultiplier = (Math.PI * 2) / getValueCount(this);
13274
+ var startAngle = this.chart.options && this.chart.options.startAngle ?
13275
+ this.chart.options.startAngle :
13276
+ 0;
13277
 
13278
+ var startAngleRadians = startAngle * Math.PI * 2 / 360;
 
 
13279
 
13280
+ // Start from the top instead of right, so remove a quarter of the circle
13281
+ return index * angleMultiplier + startAngleRadians;
13282
+ },
13283
+ getDistanceFromCenterForValue: function(value) {
13284
+ var me = this;
13285
 
13286
+ if (value === null) {
13287
+ return 0; // null always in center
13288
+ }
13289
 
13290
+ // Take into account half font size + the yPadding of the top value
13291
+ var scalingFactor = me.drawingArea / (me.max - me.min);
13292
+ if (me.options.ticks.reverse) {
13293
+ return (me.max - value) * scalingFactor;
13294
+ }
13295
+ return (value - me.min) * scalingFactor;
13296
+ },
13297
+ getPointPosition: function(index, distanceFromCenter) {
13298
+ var me = this;
13299
+ var thisAngle = me.getIndexAngle(index) - (Math.PI / 2);
13300
+ return {
13301
+ x: Math.round(Math.cos(thisAngle) * distanceFromCenter) + me.xCenter,
13302
+ y: Math.round(Math.sin(thisAngle) * distanceFromCenter) + me.yCenter
13303
+ };
13304
+ },
13305
+ getPointPositionForValue: function(index, value) {
13306
+ return this.getPointPosition(index, this.getDistanceFromCenterForValue(value));
13307
+ },
13308
 
13309
+ getBasePosition: function() {
13310
+ var me = this;
13311
+ var min = me.min;
13312
+ var max = me.max;
13313
 
13314
+ return me.getPointPositionForValue(0,
13315
+ me.beginAtZero ? 0 :
13316
+ min < 0 && max < 0 ? max :
13317
+ min > 0 && max > 0 ? min :
13318
+ 0);
13319
+ },
13320
 
13321
+ draw: function() {
13322
+ var me = this;
13323
+ var opts = me.options;
13324
+ var gridLineOpts = opts.gridLines;
13325
+ var tickOpts = opts.ticks;
13326
+ var valueOrDefault = helpers.valueOrDefault;
13327
 
13328
+ if (opts.display) {
13329
+ var ctx = me.ctx;
13330
+ var startAngle = this.getIndexAngle(0);
13331
 
13332
+ // Tick Font
13333
+ var tickFontSize = valueOrDefault(tickOpts.fontSize, globalDefaults.defaultFontSize);
13334
+ var tickFontStyle = valueOrDefault(tickOpts.fontStyle, globalDefaults.defaultFontStyle);
13335
+ var tickFontFamily = valueOrDefault(tickOpts.fontFamily, globalDefaults.defaultFontFamily);
13336
+ var tickLabelFont = helpers.fontString(tickFontSize, tickFontStyle, tickFontFamily);
13337
 
13338
+ helpers.each(me.ticks, function(label, index) {
13339
+ // Don't draw a centre value (if it is minimum)
13340
+ if (index > 0 || tickOpts.reverse) {
13341
+ var yCenterOffset = me.getDistanceFromCenterForValue(me.ticksAsNumbers[index]);
13342
 
13343
+ // Draw circular lines around the scale
13344
+ if (gridLineOpts.display && index !== 0) {
13345
+ drawRadiusLine(me, gridLineOpts, yCenterOffset, index);
13346
+ }
13347
 
13348
+ if (tickOpts.display) {
13349
+ var tickFontColor = valueOrDefault(tickOpts.fontColor, globalDefaults.defaultFontColor);
13350
+ ctx.font = tickLabelFont;
13351
 
13352
+ ctx.save();
13353
+ ctx.translate(me.xCenter, me.yCenter);
13354
+ ctx.rotate(startAngle);
13355
 
13356
+ if (tickOpts.showLabelBackdrop) {
13357
+ var labelWidth = ctx.measureText(label).width;
13358
+ ctx.fillStyle = tickOpts.backdropColor;
13359
+ ctx.fillRect(
13360
+ -labelWidth / 2 - tickOpts.backdropPaddingX,
13361
+ -yCenterOffset - tickFontSize / 2 - tickOpts.backdropPaddingY,
13362
+ labelWidth + tickOpts.backdropPaddingX * 2,
13363
+ tickFontSize + tickOpts.backdropPaddingY * 2
13364
+ );
13365
+ }
13366
 
13367
+ ctx.textAlign = 'center';
13368
+ ctx.textBaseline = 'middle';
13369
+ ctx.fillStyle = tickFontColor;
13370
+ ctx.fillText(label, 0, -yCenterOffset);
13371
+ ctx.restore();
13372
+ }
13373
+ }
13374
+ });
13375
 
13376
+ if (opts.angleLines.display || opts.pointLabels.display) {
13377
+ drawPointLabels(me);
13378
+ }
13379
+ }
13380
+ }
13381
+ });
13382
+ Chart.scaleService.registerScaleType('radialLinear', LinearRadialScale, defaultConfig);
13383
+
13384
+ };
13385
+
13386
+ },{"25":25,"34":34,"45":45}],57:[function(require,module,exports){
13387
+ /* global window: false */
13388
+ 'use strict';
13389
+
13390
+ var moment = require(1);
13391
+ moment = typeof moment === 'function' ? moment : window.moment;
13392
+
13393
+ var defaults = require(25);
13394
+ var helpers = require(45);
13395
+
13396
+ // Integer constants are from the ES6 spec.
13397
+ var MIN_INTEGER = Number.MIN_SAFE_INTEGER || -9007199254740991;
13398
+ var MAX_INTEGER = Number.MAX_SAFE_INTEGER || 9007199254740991;
13399
+
13400
+ var INTERVALS = {
13401
+ millisecond: {
13402
+ common: true,
13403
+ size: 1,
13404
+ steps: [1, 2, 5, 10, 20, 50, 100, 250, 500]
13405
+ },
13406
+ second: {
13407
+ common: true,
13408
+ size: 1000,
13409
+ steps: [1, 2, 5, 10, 30]
13410
+ },
13411
+ minute: {
13412
+ common: true,
13413
+ size: 60000,
13414
+ steps: [1, 2, 5, 10, 30]
13415
+ },
13416
+ hour: {
13417
+ common: true,
13418
+ size: 3600000,
13419
+ steps: [1, 2, 3, 6, 12]
13420
+ },
13421
+ day: {
13422
+ common: true,
13423
+ size: 86400000,
13424
+ steps: [1, 2, 5]
13425
+ },
13426
+ week: {
13427
+ common: false,
13428
+ size: 604800000,
13429
+ steps: [1, 2, 3, 4]
13430
+ },
13431
+ month: {
13432
+ common: true,
13433
+ size: 2.628e9,
13434
+ steps: [1, 2, 3]
13435
+ },
13436
+ quarter: {
13437
+ common: false,
13438
+ size: 7.884e9,
13439
+ steps: [1, 2, 3, 4]
13440
+ },
13441
+ year: {
13442
+ common: true,
13443
+ size: 3.154e10
13444
+ }
13445
+ };
13446
 
13447
+ var UNITS = Object.keys(INTERVALS);
 
13448
 
13449
+ function sorter(a, b) {
13450
+ return a - b;
13451
+ }
13452
 
13453
+ function arrayUnique(items) {
13454
+ var hash = {};
13455
+ var out = [];
13456
+ var i, ilen, item;
13457
 
13458
+ for (i = 0, ilen = items.length; i < ilen; ++i) {
13459
+ item = items[i];
13460
+ if (!hash[item]) {
13461
+ hash[item] = true;
13462
+ out.push(item);
13463
+ }
13464
+ }
13465
 
13466
+ return out;
13467
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
13468
 
13469
+ /**
13470
+ * Returns an array of {time, pos} objects used to interpolate a specific `time` or position
13471
+ * (`pos`) on the scale, by searching entries before and after the requested value. `pos` is
13472
+ * a decimal between 0 and 1: 0 being the start of the scale (left or top) and 1 the other
13473
+ * extremity (left + width or top + height). Note that it would be more optimized to directly
13474
+ * store pre-computed pixels, but the scale dimensions are not guaranteed at the time we need
13475
+ * to create the lookup table. The table ALWAYS contains at least two items: min and max.
13476
+ *
13477
+ * @param {Number[]} timestamps - timestamps sorted from lowest to highest.
13478
+ * @param {String} distribution - If 'linear', timestamps will be spread linearly along the min
13479
+ * and max range, so basically, the table will contains only two items: {min, 0} and {max, 1}.
13480
+ * If 'series', timestamps will be positioned at the same distance from each other. In this
13481
+ * case, only timestamps that break the time linearity are registered, meaning that in the
13482
+ * best case, all timestamps are linear, the table contains only min and max.
13483
+ */
13484
+ function buildLookupTable(timestamps, min, max, distribution) {
13485
+ if (distribution === 'linear' || !timestamps.length) {
13486
+ return [
13487
+ {time: min, pos: 0},
13488
+ {time: max, pos: 1}
13489
+ ];
13490
+ }
13491
 
13492
+ var table = [];
13493
+ var items = [min];
13494
+ var i, ilen, prev, curr, next;
 
 
 
 
 
 
 
 
 
 
 
13495
 
13496
+ for (i = 0, ilen = timestamps.length; i < ilen; ++i) {
13497
+ curr = timestamps[i];
13498
+ if (curr > min && curr < max) {
13499
+ items.push(curr);
13500
+ }
13501
+ }
13502
 
13503
+ items.push(max);
 
 
 
 
 
 
 
13504
 
13505
+ for (i = 0, ilen = items.length; i < ilen; ++i) {
13506
+ next = items[i + 1];
13507
+ prev = items[i - 1];
13508
+ curr = items[i];
13509
 
13510
+ // only add points that breaks the scale linearity
13511
+ if (prev === undefined || next === undefined || Math.round((next + prev) / 2) !== curr) {
13512
+ table.push({time: curr, pos: i / (ilen - 1)});
13513
+ }
13514
+ }
13515
 
13516
+ return table;
13517
+ }
13518
+
13519
+ // @see adapted from http://www.anujgakhar.com/2014/03/01/binary-search-in-javascript/
13520
+ function lookup(table, key, value) {
13521
+ var lo = 0;
13522
+ var hi = table.length - 1;
13523
+ var mid, i0, i1;
13524
+
13525
+ while (lo >= 0 && lo <= hi) {
13526
+ mid = (lo + hi) >> 1;
13527
+ i0 = table[mid - 1] || null;
13528
+ i1 = table[mid];
13529
+
13530
+ if (!i0) {
13531
+ // given value is outside table (before first item)
13532
+ return {lo: null, hi: i1};
13533
+ } else if (i1[key] < value) {
13534
+ lo = mid + 1;
13535
+ } else if (i0[key] > value) {
13536
+ hi = mid - 1;
13537
+ } else {
13538
+ return {lo: i0, hi: i1};
13539
+ }
13540
+ }
13541
 
13542
+ // given value is outside table (after last item)
13543
+ return {lo: i1, hi: null};
13544
+ }
13545
 
13546
+ /**
13547
+ * Linearly interpolates the given source `value` using the table items `skey` values and
13548
+ * returns the associated `tkey` value. For example, interpolate(table, 'time', 42, 'pos')
13549
+ * returns the position for a timestamp equal to 42. If value is out of bounds, values at
13550
+ * index [0, 1] or [n - 1, n] are used for the interpolation.
13551
+ */
13552
+ function interpolate(table, skey, sval, tkey) {
13553
+ var range = lookup(table, skey, sval);
13554
 
13555
+ // Note: the lookup table ALWAYS contains at least 2 items (min and max)
13556
+ var prev = !range.lo ? table[0] : !range.hi ? table[table.length - 2] : range.lo;
13557
+ var next = !range.lo ? table[1] : !range.hi ? table[table.length - 1] : range.hi;
 
 
 
 
13558
 
13559
+ var span = next[skey] - prev[skey];
13560
+ var ratio = span ? (sval - prev[skey]) / span : 0;
13561
+ var offset = (next[tkey] - prev[tkey]) * ratio;
13562
 
13563
+ return prev[tkey] + offset;
13564
+ }
13565
 
13566
+ /**
13567
+ * Convert the given value to a moment object using the given time options.
13568
+ * @see http://momentjs.com/docs/#/parsing/
13569
+ */
13570
+ function momentify(value, options) {
13571
+ var parser = options.parser;
13572
+ var format = options.parser || options.format;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
13573
 
13574
+ if (typeof parser === 'function') {
13575
+ return parser(value);
13576
+ }
 
 
13577
 
13578
+ if (typeof value === 'string' && typeof format === 'string') {
13579
+ return moment(value, format);
13580
+ }
13581
 
13582
+ if (!(value instanceof moment)) {
13583
+ value = moment(value);
13584
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
13585
 
13586
+ if (value.isValid()) {
13587
+ return value;
13588
+ }
 
 
 
 
 
 
13589
 
13590
+ // Labels are in an incompatible moment format and no `parser` has been provided.
13591
+ // The user might still use the deprecated `format` option to convert his inputs.
13592
+ if (typeof format === 'function') {
13593
+ return format(value);
13594
+ }
13595
 
13596
+ return value;
13597
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
13598
 
13599
+ function parse(input, scale) {
13600
+ if (helpers.isNullOrUndef(input)) {
13601
+ return null;
13602
+ }
13603
 
13604
+ var options = scale.options.time;
13605
+ var value = momentify(scale.getRightValue(input), options);
13606
+ if (!value.isValid()) {
13607
+ return null;
13608
+ }
 
 
 
 
 
13609
 
13610
+ if (options.round) {
13611
+ value.startOf(options.round);
13612
+ }
13613
 
13614
+ return value.valueOf();
13615
+ }
13616
 
13617
+ /**
13618
+ * Returns the number of unit to skip to be able to display up to `capacity` number of ticks
13619
+ * in `unit` for the given `min` / `max` range and respecting the interval steps constraints.
13620
+ */
13621
+ function determineStepSize(min, max, unit, capacity) {
13622
+ var range = max - min;
13623
+ var interval = INTERVALS[unit];
13624
+ var milliseconds = interval.size;
13625
+ var steps = interval.steps;
13626
+ var i, ilen, factor;
13627
+
13628
+ if (!steps) {
13629
+ return Math.ceil(range / ((capacity || 1) * milliseconds));
13630
+ }
13631
 
13632
+ for (i = 0, ilen = steps.length; i < ilen; ++i) {
13633
+ factor = steps[i];
13634
+ if (Math.ceil(range / (milliseconds * factor)) <= capacity) {
13635
+ break;
13636
+ }
13637
+ }
13638
 
13639
+ return factor;
13640
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
13641
 
13642
+ /**
13643
+ * Figures out what unit results in an appropriate number of auto-generated ticks
13644
+ */
13645
+ function determineUnitForAutoTicks(minUnit, min, max, capacity) {
13646
+ var ilen = UNITS.length;
13647
+ var i, interval, factor;
 
 
 
13648
 
13649
+ for (i = UNITS.indexOf(minUnit); i < ilen - 1; ++i) {
13650
+ interval = INTERVALS[UNITS[i]];
13651
+ factor = interval.steps ? interval.steps[interval.steps.length - 1] : MAX_INTEGER;
13652
 
13653
+ if (interval.common && Math.ceil((max - min) / (factor * interval.size)) <= capacity) {
13654
+ return UNITS[i];
13655
+ }
13656
+ }
13657
 
13658
+ return UNITS[ilen - 1];
13659
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
13660
 
13661
+ /**
13662
+ * Figures out what unit to format a set of ticks with
13663
+ */
13664
+ function determineUnitForFormatting(ticks, minUnit, min, max) {
13665
+ var duration = moment.duration(moment(max).diff(moment(min)));
13666
+ var ilen = UNITS.length;
13667
+ var i, unit;
13668
+
13669
+ for (i = ilen - 1; i >= UNITS.indexOf(minUnit); i--) {
13670
+ unit = UNITS[i];
13671
+ if (INTERVALS[unit].common && duration.as(unit) >= ticks.length) {
13672
+ return unit;
13673
+ }
13674
+ }
13675
 
13676
+ return UNITS[minUnit ? UNITS.indexOf(minUnit) : 0];
13677
+ }
 
 
 
 
 
 
13678
 
13679
+ function determineMajorUnit(unit) {
13680
+ for (var i = UNITS.indexOf(unit) + 1, ilen = UNITS.length; i < ilen; ++i) {
13681
+ if (INTERVALS[UNITS[i]].common) {
13682
+ return UNITS[i];
 
 
 
13683
  }
13684
+ }
13685
+ }
13686
 
13687
+ /**
13688
+ * Generates a maximum of `capacity` timestamps between min and max, rounded to the
13689
+ * `minor` unit, aligned on the `major` unit and using the given scale time `options`.
13690
+ * Important: this method can return ticks outside the min and max range, it's the
13691
+ * responsibility of the calling code to clamp values if needed.
13692
+ */
13693
+ function generate(min, max, capacity, options) {
13694
+ var timeOpts = options.time;
13695
+ var minor = timeOpts.unit || determineUnitForAutoTicks(timeOpts.minUnit, min, max, capacity);
13696
+ var major = determineMajorUnit(minor);
13697
+ var stepSize = helpers.valueOrDefault(timeOpts.stepSize, timeOpts.unitStepSize);
13698
+ var weekday = minor === 'week' ? timeOpts.isoWeekday : false;
13699
+ var majorTicksEnabled = options.ticks.major.enabled;
13700
+ var interval = INTERVALS[minor];
13701
+ var first = moment(min);
13702
+ var last = moment(max);
13703
+ var ticks = [];
13704
+ var time;
13705
+
13706
+ if (!stepSize) {
13707
+ stepSize = determineStepSize(min, max, minor, capacity);
13708
+ }
13709
 
13710
+ // For 'week' unit, handle the first day of week option
13711
+ if (weekday) {
13712
+ first = first.isoWeekday(weekday);
13713
+ last = last.isoWeekday(weekday);
13714
+ }
13715
 
13716
+ // Align first/last ticks on unit
13717
+ first = first.startOf(weekday ? 'day' : minor);
13718
+ last = last.startOf(weekday ? 'day' : minor);
13719
 
13720
+ // Make sure that the last tick include max
13721
+ if (last < max) {
13722
+ last.add(1, minor);
13723
+ }
13724
 
13725
+ time = moment(first);
 
 
13726
 
13727
+ if (majorTicksEnabled && major && !weekday && !timeOpts.round) {
13728
+ // Align the first tick on the previous `minor` unit aligned on the `major` unit:
13729
+ // we first aligned time on the previous `major` unit then add the number of full
13730
+ // stepSize there is between first and the previous major time.
13731
+ time.startOf(major);
13732
+ time.add(~~((first - time) / (interval.size * stepSize)) * stepSize, minor);
13733
+ }
13734
 
13735
+ for (; time < last; time.add(stepSize, minor)) {
13736
+ ticks.push(+time);
13737
+ }
13738
 
13739
+ ticks.push(+time);
 
13740
 
13741
+ return ticks;
13742
+ }
13743
 
13744
+ /**
13745
+ * Returns the right and left offsets from edges in the form of {left, right}.
13746
+ * Offsets are added when the `offset` option is true.
13747
+ */
13748
+ function computeOffsets(table, ticks, min, max, options) {
13749
+ var left = 0;
13750
+ var right = 0;
13751
+ var upper, lower;
13752
+
13753
+ if (options.offset && ticks.length) {
13754
+ if (!options.time.min) {
13755
+ upper = ticks.length > 1 ? ticks[1] : max;
13756
+ lower = ticks[0];
13757
+ left = (
13758
+ interpolate(table, 'time', upper, 'pos') -
13759
+ interpolate(table, 'time', lower, 'pos')
13760
+ ) / 2;
13761
+ }
13762
+ if (!options.time.max) {
13763
+ upper = ticks[ticks.length - 1];
13764
+ lower = ticks.length > 1 ? ticks[ticks.length - 2] : min;
13765
+ right = (
13766
+ interpolate(table, 'time', upper, 'pos') -
13767
+ interpolate(table, 'time', lower, 'pos')
13768
+ ) / 2;
13769
+ }
13770
+ }
13771
 
13772
+ return {left: left, right: right};
13773
+ }
13774
 
13775
+ function ticksFromTimestamps(values, majorUnit) {
13776
+ var ticks = [];
13777
+ var i, ilen, value, major;
13778
 
13779
+ for (i = 0, ilen = values.length; i < ilen; ++i) {
13780
+ value = values[i];
13781
+ major = majorUnit ? value === +moment(value).startOf(majorUnit) : false;
13782
 
13783
+ ticks.push({
13784
+ value: value,
13785
+ major: major
13786
+ });
13787
+ }
13788
 
13789
+ return ticks;
13790
+ }
13791
 
13792
+ module.exports = function(Chart) {
 
13793
 
13794
+ var defaultConfig = {
13795
+ position: 'bottom',
13796
+
13797
+ /**
13798
+ * Data distribution along the scale:
13799
+ * - 'linear': data are spread according to their time (distances can vary),
13800
+ * - 'series': data are spread at the same distance from each other.
13801
+ * @see https://github.com/chartjs/Chart.js/pull/4507
13802
+ * @since 2.7.0
13803
+ */
13804
+ distribution: 'linear',
13805
+
13806
+ /**
13807
+ * Scale boundary strategy (bypassed by min/max time options)
13808
+ * - `data`: make sure data are fully visible, ticks outside are removed
13809
+ * - `ticks`: make sure ticks are fully visible, data outside are truncated
13810
+ * @see https://github.com/chartjs/Chart.js/pull/4556
13811
+ * @since 2.7.0
13812
+ */
13813
+ bounds: 'data',
13814
+
13815
+ time: {
13816
+ parser: false, // false == a pattern string from http://momentjs.com/docs/#/parsing/string-format/ or a custom callback that converts its argument to a moment
13817
+ format: false, // DEPRECATED false == date objects, moment object, callback or a pattern string from http://momentjs.com/docs/#/parsing/string-format/
13818
+ unit: false, // false == automatic or override with week, month, year, etc.
13819
+ round: false, // none, or override with week, month, year, etc.
13820
+ displayFormat: false, // DEPRECATED
13821
+ isoWeekday: false, // override week start day - see http://momentjs.com/docs/#/get-set/iso-weekday/
13822
+ minUnit: 'millisecond',
13823
+
13824
+ // defaults to unit's corresponding unitFormat below or override using pattern string from http://momentjs.com/docs/#/displaying/format/
13825
+ displayFormats: {
13826
+ millisecond: 'h:mm:ss.SSS a', // 11:20:01.123 AM,
13827
+ second: 'h:mm:ss a', // 11:20:01 AM
13828
+ minute: 'h:mm a', // 11:20 AM
13829
+ hour: 'hA', // 5PM
13830
+ day: 'MMM D', // Sep 4
13831
+ week: 'll', // Week 46, or maybe "[W]WW - YYYY" ?
13832
+ month: 'MMM YYYY', // Sept 2015
13833
+ quarter: '[Q]Q - YYYY', // Q3
13834
+ year: 'YYYY' // 2015
13835
+ },
13836
+ },
13837
+ ticks: {
13838
+ autoSkip: false,
13839
+
13840
+ /**
13841
+ * Ticks generation input values:
13842
+ * - 'auto': generates "optimal" ticks based on scale size and time options.
13843
+ * - 'data': generates ticks from data (including labels from data {t|x|y} objects).
13844
+ * - 'labels': generates ticks from user given `data.labels` values ONLY.
13845
+ * @see https://github.com/chartjs/Chart.js/pull/4507
13846
+ * @since 2.7.0
13847
+ */
13848
+ source: 'auto',
13849
 
13850
+ major: {
13851
+ enabled: false
13852
+ }
13853
+ }
13854
  };
13855
 
13856
+ var TimeScale = Chart.Scale.extend({
13857
+ initialize: function() {
13858
+ if (!moment) {
13859
+ throw new Error('Chart.js - Moment.js could not be found! You must include it before Chart.js to use the time scale. Download at https://momentjs.com');
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
13860
  }
13861
 
13862
+ this.mergeTicksOptions();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
13863
 
13864
+ Chart.Scale.prototype.initialize.call(this);
13865
  },
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
13866
 
13867
+ update: function() {
13868
+ var me = this;
13869
+ var options = me.options;
 
13870
 
13871
+ // DEPRECATIONS: output a message only one time per update
13872
+ if (options.time && options.time.format) {
13873
+ console.warn('options.time.format is deprecated and replaced by options.time.parser.');
13874
+ }
 
13875
 
13876
+ return Chart.Scale.prototype.update.apply(me, arguments);
13877
  },
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
13878
 
13879
+ /**
13880
+ * Allows data to be referenced via 't' attribute
13881
+ */
13882
+ getRightValue: function(rawValue) {
13883
+ if (rawValue && rawValue.t !== undefined) {
13884
+ rawValue = rawValue.t;
13885
+ }
13886
+ return Chart.Scale.prototype.getRightValue.call(this, rawValue);
13887
+ },
13888
 
13889
+ determineDataLimits: function() {
13890
+ var me = this;
13891
+ var chart = me.chart;
13892
+ var timeOpts = me.options.time;
13893
+ var min = MAX_INTEGER;
13894
+ var max = MIN_INTEGER;
13895
+ var timestamps = [];
13896
+ var datasets = [];
13897
+ var labels = [];
13898
+ var i, j, ilen, jlen, data, timestamp;
13899
+
13900
+ // Convert labels to timestamps
13901
+ for (i = 0, ilen = chart.data.labels.length; i < ilen; ++i) {
13902
+ labels.push(parse(chart.data.labels[i], me));
13903
+ }
13904
 
13905
+ // Convert data to timestamps
13906
+ for (i = 0, ilen = (chart.data.datasets || []).length; i < ilen; ++i) {
13907
+ if (chart.isDatasetVisible(i)) {
13908
+ data = chart.data.datasets[i].data;
13909
 
13910
+ // Let's consider that all data have the same format.
13911
+ if (helpers.isObject(data[0])) {
13912
+ datasets[i] = [];
13913
 
13914
+ for (j = 0, jlen = data.length; j < jlen; ++j) {
13915
+ timestamp = parse(data[j], me);
13916
+ timestamps.push(timestamp);
13917
+ datasets[i][j] = timestamp;
13918
+ }
13919
+ } else {
13920
+ timestamps.push.apply(timestamps, labels);
13921
+ datasets[i] = labels.slice(0);
13922
+ }
13923
+ } else {
13924
+ datasets[i] = [];
13925
+ }
13926
+ }
13927
 
13928
+ if (labels.length) {
13929
+ // Sort labels **after** data have been converted
13930
+ labels = arrayUnique(labels).sort(sorter);
13931
+ min = Math.min(min, labels[0]);
13932
+ max = Math.max(max, labels[labels.length - 1]);
13933
+ }
13934
 
13935
+ if (timestamps.length) {
13936
+ timestamps = arrayUnique(timestamps).sort(sorter);
13937
+ min = Math.min(min, timestamps[0]);
13938
+ max = Math.max(max, timestamps[timestamps.length - 1]);
13939
+ }
13940
 
13941
+ min = parse(timeOpts.min, me) || min;
13942
+ max = parse(timeOpts.max, me) || max;
13943
 
13944
+ // In case there is no valid min/max, let's use today limits
13945
+ min = min === MAX_INTEGER ? +moment().startOf('day') : min;
13946
+ max = max === MIN_INTEGER ? +moment().endOf('day') + 1 : max;
13947
 
13948
+ // Make sure that max is strictly higher than min (required by the lookup table)
13949
+ me.min = Math.min(min, max);
13950
+ me.max = Math.max(min + 1, max);
13951
 
13952
+ // PRIVATE
13953
+ me._horizontal = me.isHorizontal();
13954
+ me._table = [];
13955
+ me._timestamps = {
13956
+ data: timestamps,
13957
+ datasets: datasets,
13958
+ labels: labels
13959
+ };
13960
+ },
13961
 
13962
+ buildTicks: function() {
13963
+ var me = this;
13964
+ var min = me.min;
13965
+ var max = me.max;
13966
+ var options = me.options;
13967
+ var timeOpts = options.time;
13968
+ var timestamps = [];
13969
+ var ticks = [];
13970
+ var i, ilen, timestamp;
13971
+
13972
+ switch (options.ticks.source) {
13973
+ case 'data':
13974
+ timestamps = me._timestamps.data;
13975
+ break;
13976
+ case 'labels':
13977
+ timestamps = me._timestamps.labels;
13978
+ break;
13979
+ case 'auto':
13980
+ default:
13981
+ timestamps = generate(min, max, me.getLabelCapacity(min), options);
13982
+ }
13983
 
13984
+ if (options.bounds === 'ticks' && timestamps.length) {
13985
+ min = timestamps[0];
13986
+ max = timestamps[timestamps.length - 1];
13987
+ }
13988
 
13989
+ // Enforce limits with user min/max options
13990
+ min = parse(timeOpts.min, me) || min;
13991
+ max = parse(timeOpts.max, me) || max;
13992
 
13993
+ // Remove ticks outside the min/max range
13994
+ for (i = 0, ilen = timestamps.length; i < ilen; ++i) {
13995
+ timestamp = timestamps[i];
13996
+ if (timestamp >= min && timestamp <= max) {
13997
+ ticks.push(timestamp);
13998
+ }
13999
+ }
14000
 
14001
+ me.min = min;
14002
+ me.max = max;
14003
 
14004
+ // PRIVATE
14005
+ me._unit = timeOpts.unit || determineUnitForFormatting(ticks, timeOpts.minUnit, me.min, me.max);
14006
+ me._majorUnit = determineMajorUnit(me._unit);
14007
+ me._table = buildLookupTable(me._timestamps.data, min, max, options.distribution);
14008
+ me._offsets = computeOffsets(me._table, ticks, min, max, options);
14009
 
14010
+ return ticksFromTimestamps(ticks, me._majorUnit);
14011
+ },
14012
 
14013
+ getLabelForIndex: function(index, datasetIndex) {
14014
+ var me = this;
14015
+ var data = me.chart.data;
14016
+ var timeOpts = me.options.time;
14017
+ var label = data.labels && index < data.labels.length ? data.labels[index] : '';
14018
+ var value = data.datasets[datasetIndex].data[index];
14019
 
14020
+ if (helpers.isObject(value)) {
14021
+ label = me.getRightValue(value);
14022
+ }
14023
+ if (timeOpts.tooltipFormat) {
14024
+ label = momentify(label, timeOpts).format(timeOpts.tooltipFormat);
14025
+ }
14026
 
14027
+ return label;
14028
+ },
14029
 
14030
+ /**
14031
+ * Function to format an individual tick mark
14032
+ * @private
14033
+ */
14034
+ tickFormatFunction: function(tick, index, ticks, formatOverride) {
14035
+ var me = this;
14036
+ var options = me.options;
14037
+ var time = tick.valueOf();
14038
+ var formats = options.time.displayFormats;
14039
+ var minorFormat = formats[me._unit];
14040
+ var majorUnit = me._majorUnit;
14041
+ var majorFormat = formats[majorUnit];
14042
+ var majorTime = tick.clone().startOf(majorUnit).valueOf();
14043
+ var majorTickOpts = options.ticks.major;
14044
+ var major = majorTickOpts.enabled && majorUnit && majorFormat && time === majorTime;
14045
+ var label = tick.format(formatOverride ? formatOverride : major ? majorFormat : minorFormat);
14046
+ var tickOpts = major ? majorTickOpts : options.ticks.minor;
14047
+ var formatter = helpers.valueOrDefault(tickOpts.callback, tickOpts.userCallback);
14048
+
14049
+ return formatter ? formatter(label, index, ticks) : label;
14050
+ },
14051
 
14052
+ convertTicksToLabels: function(ticks) {
14053
+ var labels = [];
14054
+ var i, ilen;
14055
 
14056
+ for (i = 0, ilen = ticks.length; i < ilen; ++i) {
14057
+ labels.push(this.tickFormatFunction(moment(ticks[i].value), i, ticks));
14058
+ }
14059
 
14060
+ return labels;
14061
  },
14062
 
14063
+ /**
14064
+ * @private
14065
+ */
14066
+ getPixelForOffset: function(time) {
14067
+ var me = this;
14068
+ var size = me._horizontal ? me.width : me.height;
14069
+ var start = me._horizontal ? me.left : me.top;
14070
+ var pos = interpolate(me._table, 'time', time, 'pos');
 
 
14071
 
14072
+ return start + size * (me._offsets.left + pos) / (me._offsets.left + 1 + me._offsets.right);
14073
+ },
 
 
 
 
14074
 
14075
+ getPixelForValue: function(value, index, datasetIndex) {
14076
+ var me = this;
14077
+ var time = null;
 
 
 
 
14078
 
14079
+ if (index !== undefined && datasetIndex !== undefined) {
14080
+ time = me._timestamps.datasets[datasetIndex][index];
14081
  }
14082
 
14083
+ if (time === null) {
14084
+ time = parse(value, me);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
14085
  }
14086
 
14087
+ if (time !== null) {
14088
+ return me.getPixelForOffset(time);
14089
+ }
14090
+ },
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
14091
 
14092
+ getPixelForTick: function(index) {
14093
+ var ticks = this.getTicks();
14094
+ return index >= 0 && index < ticks.length ?
14095
+ this.getPixelForOffset(ticks[index].value) :
14096
+ null;
14097
  },
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
14098
 
14099
+ getValueForPixel: function(pixel) {
14100
+ var me = this;
14101
+ var size = me._horizontal ? me.width : me.height;
14102
+ var start = me._horizontal ? me.left : me.top;
14103
+ var pos = (size ? (pixel - start) / size : 0) * (me._offsets.left + 1 + me._offsets.left) - me._offsets.right;
14104
+ var time = interpolate(me._table, 'pos', pos, 'time');
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
14105
 
14106
+ return moment(time);
14107
+ },
14108
 
14109
+ /**
14110
+ * Crude approximation of what the label width might be
14111
+ * @private
14112
+ */
14113
+ getLabelWidth: function(label) {
14114
+ var me = this;
14115
+ var ticksOpts = me.options.ticks;
14116
+ var tickLabelWidth = me.ctx.measureText(label).width;
14117
+ var angle = helpers.toRadians(ticksOpts.maxRotation);
14118
+ var cosRotation = Math.cos(angle);
14119
+ var sinRotation = Math.sin(angle);
14120
+ var tickFontSize = helpers.valueOrDefault(ticksOpts.fontSize, defaults.global.defaultFontSize);
14121
+
14122
+ return (tickLabelWidth * cosRotation) + (tickFontSize * sinRotation);
14123
+ },
14124
 
14125
+ /**
14126
+ * @private
14127
+ */
14128
+ getLabelCapacity: function(exampleTime) {
14129
+ var me = this;
 
 
 
 
 
 
 
 
 
14130
 
14131
+ var formatOverride = me.options.time.displayFormats.millisecond; // Pick the longest format for guestimation
 
 
 
 
 
 
 
 
 
 
 
14132
 
14133
+ var exampleLabel = me.tickFormatFunction(moment(exampleTime), 0, [], formatOverride);
14134
+ var tickLabelWidth = me.getLabelWidth(exampleLabel);
14135
+ var innerWidth = me.isHorizontal() ? me.width : me.height;
14136
 
14137
+ return Math.floor(innerWidth / tickLabelWidth);
14138
  }
 
14139
  });
14140
 
14141
+ Chart.scaleService.registerScaleType('time', TimeScale, defaultConfig);
14142
+ };
14143
 
14144
+ },{"1":1,"25":25,"45":45}]},{},[7])(7)
14145
+ });
 
 
assets/js/chart.min.js CHANGED
@@ -1,11 +1,10 @@
1
  /*!
2
  * Chart.js
3
  * http://chartjs.org/
4
- * Version: 1.0.2
5
  *
6
- * Copyright 2015 Nick Downie
7
  * Released under the MIT license
8
- * https://github.com/nnnick/Chart.js/blob/master/LICENSE.md
9
  */
10
- (function(){"use strict";var t=this,i=t.Chart,e=function(t){this.canvas=t.canvas,this.ctx=t;var i=function(t,i){return t["offset"+i]?t["offset"+i]:document.defaultView.getComputedStyle(t).getPropertyValue(i)},e=this.width=i(t.canvas,"Width")||t.canvas.width,n=this.height=i(t.canvas,"Height")||t.canvas.height;return e=this.width=t.canvas.width,n=this.height=t.canvas.height,this.aspectRatio=this.width/this.height,s.retinaScale(this),this};e.defaults={global:{animation:!0,animationSteps:60,animationEasing:"easeOutQuart",showScale:!0,scaleOverride:!1,scaleSteps:null,scaleStepWidth:null,scaleStartValue:null,scaleLineColor:"rgba(0,0,0,.1)",scaleLineWidth:1,scaleShowLabels:!0,scaleLabel:"<%=value%>",scaleIntegersOnly:!0,scaleBeginAtZero:!1,scaleFontFamily:"'Helvetica Neue', 'Helvetica', 'Arial', sans-serif",scaleFontSize:12,scaleFontStyle:"normal",scaleFontColor:"#666",responsive:!1,maintainAspectRatio:!0,showTooltips:!0,customTooltips:!1,tooltipEvents:["mousemove","touchstart","touchmove","mouseout"],tooltipFillColor:"rgba(0,0,0,0.8)",tooltipFontFamily:"'Helvetica Neue', 'Helvetica', 'Arial', sans-serif",tooltipFontSize:14,tooltipFontStyle:"normal",tooltipFontColor:"#fff",tooltipTitleFontFamily:"'Helvetica Neue', 'Helvetica', 'Arial', sans-serif",tooltipTitleFontSize:14,tooltipTitleFontStyle:"bold",tooltipTitleFontColor:"#fff",tooltipTitleTemplate:"<%= label%>",tooltipYPadding:6,tooltipXPadding:6,tooltipCaretSize:8,tooltipCornerRadius:6,tooltipXOffset:10,tooltipTemplate:"<%if (label){%><%=label%>: <%}%><%= value %>",multiTooltipTemplate:"<%= datasetLabel %>: <%= value %>",multiTooltipKeyBackground:"#fff",segmentColorDefault:["#A6CEE3","#1F78B4","#B2DF8A","#33A02C","#FB9A99","#E31A1C","#FDBF6F","#FF7F00","#CAB2D6","#6A3D9A","#B4B482","#B15928"],segmentHighlightColorDefaults:["#CEF6FF","#47A0DC","#DAFFB2","#5BC854","#FFC2C1","#FF4244","#FFE797","#FFA728","#F2DAFE","#9265C2","#DCDCAA","#D98150"],onAnimationProgress:function(){},onAnimationComplete:function(){}}},e.types={};var s=e.helpers={},n=s.each=function(t,i,e){var s=Array.prototype.slice.call(arguments,3);if(t)if(t.length===+t.length){var n;for(n=0;n<t.length;n++)i.apply(e,[t[n],n].concat(s))}else for(var o in t)i.apply(e,[t[o],o].concat(s))},o=s.clone=function(t){var i={};return n(t,function(e,s){t.hasOwnProperty(s)&&(i[s]=e)}),i},a=s.extend=function(t){return n(Array.prototype.slice.call(arguments,1),function(i){n(i,function(e,s){i.hasOwnProperty(s)&&(t[s]=e)})}),t},h=s.merge=function(t,i){var e=Array.prototype.slice.call(arguments,0);return e.unshift({}),a.apply(null,e)},l=s.indexOf=function(t,i){if(Array.prototype.indexOf)return t.indexOf(i);for(var e=0;e<t.length;e++)if(t[e]===i)return e;return-1},r=(s.where=function(t,i){var e=[];return s.each(t,function(t){i(t)&&e.push(t)}),e},s.findNextWhere=function(t,i,e){e||(e=-1);for(var s=e+1;s<t.length;s++){var n=t[s];if(i(n))return n}},s.findPreviousWhere=function(t,i,e){e||(e=t.length);for(var s=e-1;s>=0;s--){var n=t[s];if(i(n))return n}},s.inherits=function(t){var i=this,e=t&&t.hasOwnProperty("constructor")?t.constructor:function(){return i.apply(this,arguments)},s=function(){this.constructor=e};return s.prototype=i.prototype,e.prototype=new s,e.extend=r,t&&a(e.prototype,t),e.__super__=i.prototype,e}),c=s.noop=function(){},u=s.uid=function(){var t=0;return function(){return"chart-"+t++}}(),d=s.warn=function(t){window.console&&"function"==typeof window.console.warn&&console.warn(t)},p=s.amd="function"==typeof define&&define.amd,f=s.isNumber=function(t){return!isNaN(parseFloat(t))&&isFinite(t)},g=s.max=function(t){return Math.max.apply(Math,t)},m=s.min=function(t){return Math.min.apply(Math,t)},v=(s.cap=function(t,i,e){if(f(i)){if(t>i)return i}else if(f(e)&&e>t)return e;return t},s.getDecimalPlaces=function(t){if(t%1!==0&&f(t)){var i=t.toString();if(i.indexOf("e-")<0)return i.split(".")[1].length;if(i.indexOf(".")<0)return parseInt(i.split("e-")[1]);var e=i.split(".")[1].split("e-");return e[0].length+parseInt(e[1])}return 0}),S=s.radians=function(t){return t*(Math.PI/180)},x=(s.getAngleFromPoint=function(t,i){var e=i.x-t.x,s=i.y-t.y,n=Math.sqrt(e*e+s*s),o=2*Math.PI+Math.atan2(s,e);return 0>e&&0>s&&(o+=2*Math.PI),{angle:o,distance:n}},s.aliasPixel=function(t){return t%2===0?0:.5}),C=(s.splineCurve=function(t,i,e,s){var n=Math.sqrt(Math.pow(i.x-t.x,2)+Math.pow(i.y-t.y,2)),o=Math.sqrt(Math.pow(e.x-i.x,2)+Math.pow(e.y-i.y,2)),a=s*n/(n+o),h=s*o/(n+o);return{inner:{x:i.x-a*(e.x-t.x),y:i.y-a*(e.y-t.y)},outer:{x:i.x+h*(e.x-t.x),y:i.y+h*(e.y-t.y)}}},s.calculateOrderOfMagnitude=function(t){return Math.floor(Math.log(t)/Math.LN10)}),y=(s.calculateScaleRange=function(t,i,e,s,o){var a=2,h=Math.floor(i/(1.5*e)),l=a>=h,r=[];n(t,function(t){null==t||r.push(t)});var c=m(r),u=g(r);u===c&&(u+=.5,c>=.5&&!s?c-=.5:u+=.5);for(var d=Math.abs(u-c),p=C(d),f=Math.ceil(u/(1*Math.pow(10,p)))*Math.pow(10,p),v=s?0:Math.floor(c/(1*Math.pow(10,p)))*Math.pow(10,p),S=f-v,x=Math.pow(10,p),y=Math.round(S/x);(y>h||h>2*y)&&!l;)if(y>h)x*=2,y=Math.round(S/x),y%1!==0&&(l=!0);else if(o&&p>=0){if(x/2%1!==0)break;x/=2,y=Math.round(S/x)}else x/=2,y=Math.round(S/x);return l&&(y=a,x=S/y),{steps:y,stepValue:x,min:v,max:v+y*x}},s.template=function(t,i){function e(t,i){var e=/\W/.test(t)?new Function("obj","var p=[],print=function(){p.push.apply(p,arguments);};with(obj){p.push('"+t.replace(/[\r\t\n]/g," ").split("<%").join(" ").replace(/((^|%>)[^\t]*)'/g,"$1\r").replace(/\t=(.*?)%>/g,"',$1,'").split(" ").join("');").split("%>").join("p.push('").split("\r").join("\\'")+"');}return p.join('');"):s[t]=s[t];return i?e(i):e}if(t instanceof Function)return t(i);var s={};return e(t,i)}),b=(s.generateLabels=function(t,i,e,s){var o=new Array(i);return t&&n(o,function(i,n){o[n]=y(t,{value:e+s*(n+1)})}),o},s.easingEffects={linear:function(t){return t},easeInQuad:function(t){return t*t},easeOutQuad:function(t){return-1*t*(t-2)},easeInOutQuad:function(t){return(t/=.5)<1?.5*t*t:-0.5*(--t*(t-2)-1)},easeInCubic:function(t){return t*t*t},easeOutCubic:function(t){return 1*((t=t/1-1)*t*t+1)},easeInOutCubic:function(t){return(t/=.5)<1?.5*t*t*t:.5*((t-=2)*t*t+2)},easeInQuart:function(t){return t*t*t*t},easeOutQuart:function(t){return-1*((t=t/1-1)*t*t*t-1)},easeInOutQuart:function(t){return(t/=.5)<1?.5*t*t*t*t:-0.5*((t-=2)*t*t*t-2)},easeInQuint:function(t){return 1*(t/=1)*t*t*t*t},easeOutQuint:function(t){return 1*((t=t/1-1)*t*t*t*t+1)},easeInOutQuint:function(t){return(t/=.5)<1?.5*t*t*t*t*t:.5*((t-=2)*t*t*t*t+2)},easeInSine:function(t){return-1*Math.cos(t/1*(Math.PI/2))+1},easeOutSine:function(t){return 1*Math.sin(t/1*(Math.PI/2))},easeInOutSine:function(t){return-0.5*(Math.cos(Math.PI*t/1)-1)},easeInExpo:function(t){return 0===t?1:1*Math.pow(2,10*(t/1-1))},easeOutExpo:function(t){return 1===t?1:1*(-Math.pow(2,-10*t/1)+1)},easeInOutExpo:function(t){return 0===t?0:1===t?1:(t/=.5)<1?.5*Math.pow(2,10*(t-1)):.5*(-Math.pow(2,-10*--t)+2)},easeInCirc:function(t){return t>=1?t:-1*(Math.sqrt(1-(t/=1)*t)-1)},easeOutCirc:function(t){return 1*Math.sqrt(1-(t=t/1-1)*t)},easeInOutCirc:function(t){return(t/=.5)<1?-0.5*(Math.sqrt(1-t*t)-1):.5*(Math.sqrt(1-(t-=2)*t)+1)},easeInElastic:function(t){var i=1.70158,e=0,s=1;return 0===t?0:1==(t/=1)?1:(e||(e=.3),s<Math.abs(1)?(s=1,i=e/4):i=e/(2*Math.PI)*Math.asin(1/s),-(s*Math.pow(2,10*(t-=1))*Math.sin((1*t-i)*(2*Math.PI)/e)))},easeOutElastic:function(t){var i=1.70158,e=0,s=1;return 0===t?0:1==(t/=1)?1:(e||(e=.3),s<Math.abs(1)?(s=1,i=e/4):i=e/(2*Math.PI)*Math.asin(1/s),s*Math.pow(2,-10*t)*Math.sin((1*t-i)*(2*Math.PI)/e)+1)},easeInOutElastic:function(t){var i=1.70158,e=0,s=1;return 0===t?0:2==(t/=.5)?1:(e||(e=1*(.3*1.5)),s<Math.abs(1)?(s=1,i=e/4):i=e/(2*Math.PI)*Math.asin(1/s),1>t?-.5*(s*Math.pow(2,10*(t-=1))*Math.sin((1*t-i)*(2*Math.PI)/e)):s*Math.pow(2,-10*(t-=1))*Math.sin((1*t-i)*(2*Math.PI)/e)*.5+1)},easeInBack:function(t){var i=1.70158;return 1*(t/=1)*t*((i+1)*t-i)},easeOutBack:function(t){var i=1.70158;return 1*((t=t/1-1)*t*((i+1)*t+i)+1)},easeInOutBack:function(t){var i=1.70158;return(t/=.5)<1?.5*(t*t*(((i*=1.525)+1)*t-i)):.5*((t-=2)*t*(((i*=1.525)+1)*t+i)+2)},easeInBounce:function(t){return 1-b.easeOutBounce(1-t)},easeOutBounce:function(t){return(t/=1)<1/2.75?1*(7.5625*t*t):2/2.75>t?1*(7.5625*(t-=1.5/2.75)*t+.75):2.5/2.75>t?1*(7.5625*(t-=2.25/2.75)*t+.9375):1*(7.5625*(t-=2.625/2.75)*t+.984375)},easeInOutBounce:function(t){return.5>t?.5*b.easeInBounce(2*t):.5*b.easeOutBounce(2*t-1)+.5}}),w=s.requestAnimFrame=function(){return window.requestAnimationFrame||window.webkitRequestAnimationFrame||window.mozRequestAnimationFrame||window.oRequestAnimationFrame||window.msRequestAnimationFrame||function(t){return window.setTimeout(t,1e3/60)}}(),P=(s.cancelAnimFrame=function(){return window.cancelAnimationFrame||window.webkitCancelAnimationFrame||window.mozCancelAnimationFrame||window.oCancelAnimationFrame||window.msCancelAnimationFrame||function(t){return window.clearTimeout(t,1e3/60)}}(),s.animationLoop=function(t,i,e,s,n,o){var a=0,h=b[e]||b.linear,l=function(){a++;var e=a/i,r=h(e);t.call(o,r,e,a),s.call(o,r,e),i>a?o.animationFrame=w(l):n.apply(o)};w(l)},s.getRelativePosition=function(t){var i,e,s=t.originalEvent||t,n=t.currentTarget||t.srcElement,o=n.getBoundingClientRect();return s.touches?(i=s.touches[0].clientX-o.left,e=s.touches[0].clientY-o.top):(i=s.clientX-o.left,e=s.clientY-o.top),{x:i,y:e}},s.addEvent=function(t,i,e){t.addEventListener?t.addEventListener(i,e):t.attachEvent?t.attachEvent("on"+i,e):t["on"+i]=e}),L=s.removeEvent=function(t,i,e){t.removeEventListener?t.removeEventListener(i,e,!1):t.detachEvent?t.detachEvent("on"+i,e):t["on"+i]=c},k=(s.bindEvents=function(t,i,e){t.events||(t.events={}),n(i,function(i){t.events[i]=function(){e.apply(t,arguments)},P(t.chart.canvas,i,t.events[i])})},s.unbindEvents=function(t,i){n(i,function(i,e){L(t.chart.canvas,e,i)})}),F=s.getMaximumWidth=function(t){var i=t.parentNode,e=parseInt(R(i,"padding-left"))+parseInt(R(i,"padding-right"));return i?i.clientWidth-e:0},A=s.getMaximumHeight=function(t){var i=t.parentNode,e=parseInt(R(i,"padding-bottom"))+parseInt(R(i,"padding-top"));return i?i.clientHeight-e:0},R=s.getStyle=function(t,i){return t.currentStyle?t.currentStyle[i]:document.defaultView.getComputedStyle(t,null).getPropertyValue(i)},T=(s.getMaximumSize=s.getMaximumWidth,s.retinaScale=function(t){var i=t.ctx,e=t.canvas.width,s=t.canvas.height;window.devicePixelRatio&&(i.canvas.style.width=e+"px",i.canvas.style.height=s+"px",i.canvas.height=s*window.devicePixelRatio,i.canvas.width=e*window.devicePixelRatio,i.scale(window.devicePixelRatio,window.devicePixelRatio))}),M=s.clear=function(t){t.ctx.clearRect(0,0,t.width,t.height)},W=s.fontString=function(t,i,e){return i+" "+t+"px "+e},z=s.longestText=function(t,i,e){t.font=i;var s=0;return n(e,function(i){var e=t.measureText(i).width;s=e>s?e:s}),s},B=s.drawRoundedRectangle=function(t,i,e,s,n,o){t.beginPath(),t.moveTo(i+o,e),t.lineTo(i+s-o,e),t.quadraticCurveTo(i+s,e,i+s,e+o),t.lineTo(i+s,e+n-o),t.quadraticCurveTo(i+s,e+n,i+s-o,e+n),t.lineTo(i+o,e+n),t.quadraticCurveTo(i,e+n,i,e+n-o),t.lineTo(i,e+o),t.quadraticCurveTo(i,e,i+o,e),t.closePath()};e.instances={},e.Type=function(t,i,s){this.options=i,this.chart=s,this.id=u(),e.instances[this.id]=this,i.responsive&&this.resize(),this.initialize.call(this,t)},a(e.Type.prototype,{initialize:function(){return this},clear:function(){return M(this.chart),this},stop:function(){return e.animationService.cancelAnimation(this),this},resize:function(t){this.stop();var i=this.chart.canvas,e=F(this.chart.canvas),s=this.options.maintainAspectRatio?e/this.chart.aspectRatio:A(this.chart.canvas);return i.width=this.chart.width=e,i.height=this.chart.height=s,T(this.chart),"function"==typeof t&&t.apply(this,Array.prototype.slice.call(arguments,1)),this},reflow:c,render:function(t){if(t&&this.reflow(),this.options.animation&&!t){var i=new e.Animation;i.numSteps=this.options.animationSteps,i.easing=this.options.animationEasing,i.render=function(t,i){var e=s.easingEffects[i.easing],n=i.currentStep/i.numSteps,o=e(n);t.draw(o,n,i.currentStep)},i.onAnimationProgress=this.options.onAnimationProgress,i.onAnimationComplete=this.options.onAnimationComplete,e.animationService.addAnimation(this,i)}else this.draw(),this.options.onAnimationComplete.call(this);return this},generateLegend:function(){return s.template(this.options.legendTemplate,{datasets:this.datasets})},destroy:function(){this.stop(),this.clear(),k(this,this.events);var t=this.chart.canvas;t.width=this.chart.width,t.height=this.chart.height,t.style.removeProperty?(t.style.removeProperty("width"),t.style.removeProperty("height")):(t.style.removeAttribute("width"),t.style.removeAttribute("height")),delete e.instances[this.id]},showTooltip:function(t,i){"undefined"==typeof this.activeElements&&(this.activeElements=[]);var o=function(t){var i=!1;return t.length!==this.activeElements.length?i=!0:(n(t,function(t,e){t!==this.activeElements[e]&&(i=!0)},this),i)}.call(this,t);if(o||i){if(this.activeElements=t,this.draw(),this.options.customTooltips&&this.options.customTooltips(!1),t.length>0)if(this.datasets&&this.datasets.length>1){for(var a,h,r=this.datasets.length-1;r>=0&&(a=this.datasets[r].points||this.datasets[r].bars||this.datasets[r].segments,h=l(a,t[0]),-1===h);r--);var c=[],u=[],d=function(t){var i,e,n,o,a,l=[],r=[],d=[];return s.each(this.datasets,function(t){i=t.points||t.bars||t.segments,i[h]&&i[h].hasValue()&&l.push(i[h])}),s.each(l,function(t){r.push(t.x),d.push(t.y),c.push(s.template(this.options.multiTooltipTemplate,t)),u.push({fill:t._saved.fillColor||t.fillColor,stroke:t._saved.strokeColor||t.strokeColor})},this),a=m(d),n=g(d),o=m(r),e=g(r),{x:o>this.chart.width/2?o:e,y:(a+n)/2}}.call(this,h);new e.MultiTooltip({x:d.x,y:d.y,xPadding:this.options.tooltipXPadding,yPadding:this.options.tooltipYPadding,xOffset:this.options.tooltipXOffset,fillColor:this.options.tooltipFillColor,textColor:this.options.tooltipFontColor,fontFamily:this.options.tooltipFontFamily,fontStyle:this.options.tooltipFontStyle,fontSize:this.options.tooltipFontSize,titleTextColor:this.options.tooltipTitleFontColor,titleFontFamily:this.options.tooltipTitleFontFamily,titleFontStyle:this.options.tooltipTitleFontStyle,titleFontSize:this.options.tooltipTitleFontSize,cornerRadius:this.options.tooltipCornerRadius,labels:c,legendColors:u,legendColorBackground:this.options.multiTooltipKeyBackground,title:y(this.options.tooltipTitleTemplate,t[0]),chart:this.chart,ctx:this.chart.ctx,custom:this.options.customTooltips}).draw()}else n(t,function(t){var i=t.tooltipPosition();new e.Tooltip({x:Math.round(i.x),y:Math.round(i.y),xPadding:this.options.tooltipXPadding,yPadding:this.options.tooltipYPadding,fillColor:this.options.tooltipFillColor,textColor:this.options.tooltipFontColor,fontFamily:this.options.tooltipFontFamily,fontStyle:this.options.tooltipFontStyle,fontSize:this.options.tooltipFontSize,caretHeight:this.options.tooltipCaretSize,cornerRadius:this.options.tooltipCornerRadius,text:y(this.options.tooltipTemplate,t),chart:this.chart,custom:this.options.customTooltips}).draw()},this);return this}},toBase64Image:function(){return this.chart.canvas.toDataURL.apply(this.chart.canvas,arguments)}}),e.Type.extend=function(t){var i=this,s=function(){return i.apply(this,arguments)};if(s.prototype=o(i.prototype),a(s.prototype,t),s.extend=e.Type.extend,t.name||i.prototype.name){var n=t.name||i.prototype.name,l=e.defaults[i.prototype.name]?o(e.defaults[i.prototype.name]):{};e.defaults[n]=a(l,t.defaults),e.types[n]=s,e.prototype[n]=function(t,i){var o=h(e.defaults.global,e.defaults[n],i||{});return new s(t,o,this)}}else d("Name not provided for this chart, so it hasn't been registered");return i},e.Element=function(t){a(this,t),this.initialize.apply(this,arguments),this.save()},a(e.Element.prototype,{initialize:function(){},restore:function(t){return t?n(t,function(t){this[t]=this._saved[t]},this):a(this,this._saved),this},save:function(){return this._saved=o(this),delete this._saved._saved,this},update:function(t){return n(t,function(t,i){this._saved[i]=this[i],this[i]=t},this),this},transition:function(t,i){return n(t,function(t,e){this[e]=(t-this._saved[e])*i+this._saved[e]},this),this},tooltipPosition:function(){return{x:this.x,y:this.y}},hasValue:function(){return f(this.value)}}),e.Element.extend=r,e.Point=e.Element.extend({display:!0,inRange:function(t,i){var e=this.hitDetectionRadius+this.radius;return Math.pow(t-this.x,2)+Math.pow(i-this.y,2)<Math.pow(e,2)},draw:function(){if(this.display){var t=this.ctx;t.beginPath(),t.arc(this.x,this.y,this.radius,0,2*Math.PI),t.closePath(),t.strokeStyle=this.strokeColor,t.lineWidth=this.strokeWidth,t.fillStyle=this.fillColor,t.fill(),t.stroke()}}}),e.Arc=e.Element.extend({inRange:function(t,i){var e=s.getAngleFromPoint(this,{x:t,y:i}),n=e.angle%(2*Math.PI),o=(2*Math.PI+this.startAngle)%(2*Math.PI),a=(2*Math.PI+this.endAngle)%(2*Math.PI)||360,h=o>a?a>=n||n>=o:n>=o&&a>=n,l=e.distance>=this.innerRadius&&e.distance<=this.outerRadius;return h&&l},tooltipPosition:function(){var t=this.startAngle+(this.endAngle-this.startAngle)/2,i=(this.outerRadius-this.innerRadius)/2+this.innerRadius;return{x:this.x+Math.cos(t)*i,y:this.y+Math.sin(t)*i}},draw:function(t){var i=this.ctx;i.beginPath(),i.arc(this.x,this.y,this.outerRadius<0?0:this.outerRadius,this.startAngle,this.endAngle),i.arc(this.x,this.y,this.innerRadius<0?0:this.innerRadius,this.endAngle,this.startAngle,!0),i.closePath(),i.strokeStyle=this.strokeColor,i.lineWidth=this.strokeWidth,i.fillStyle=this.fillColor,i.fill(),i.lineJoin="bevel",this.showStroke&&i.stroke()}}),e.Rectangle=e.Element.extend({draw:function(){var t=this.ctx,i=this.width/2,e=this.x-i,s=this.x+i,n=this.base-(this.base-this.y),o=this.strokeWidth/2;this.showStroke&&(e+=o,s-=o,n+=o),t.beginPath(),t.fillStyle=this.fillColor,t.strokeStyle=this.strokeColor,t.lineWidth=this.strokeWidth,t.moveTo(e,this.base),t.lineTo(e,n),t.lineTo(s,n),t.lineTo(s,this.base),t.fill(),this.showStroke&&t.stroke()},height:function(){return this.base-this.y},inRange:function(t,i){return t>=this.x-this.width/2&&t<=this.x+this.width/2&&i>=this.y&&i<=this.base}}),e.Animation=e.Element.extend({currentStep:null,numSteps:60,easing:"",render:null,onAnimationProgress:null,onAnimationComplete:null}),e.Tooltip=e.Element.extend({draw:function(){var t=this.chart.ctx;t.font=W(this.fontSize,this.fontStyle,this.fontFamily),this.xAlign="center",this.yAlign="above";var i=this.caretPadding=2,e=t.measureText(this.text).width+2*this.xPadding,s=this.fontSize+2*this.yPadding,n=s+this.caretHeight+i;this.x+e/2>this.chart.width?this.xAlign="left":this.x-e/2<0&&(this.xAlign="right"),this.y-n<0&&(this.yAlign="below");var o=this.x-e/2,a=this.y-n;if(t.fillStyle=this.fillColor,this.custom)this.custom(this);else{switch(this.yAlign){case"above":t.beginPath(),t.moveTo(this.x,this.y-i),t.lineTo(this.x+this.caretHeight,this.y-(i+this.caretHeight)),t.lineTo(this.x-this.caretHeight,this.y-(i+this.caretHeight)),t.closePath(),t.fill();break;case"below":a=this.y+i+this.caretHeight,t.beginPath(),t.moveTo(this.x,this.y+i),t.lineTo(this.x+this.caretHeight,this.y+i+this.caretHeight),t.lineTo(this.x-this.caretHeight,this.y+i+this.caretHeight),t.closePath(),t.fill()}switch(this.xAlign){case"left":o=this.x-e+(this.cornerRadius+this.caretHeight);break;case"right":o=this.x-(this.cornerRadius+this.caretHeight)}B(t,o,a,e,s,this.cornerRadius),t.fill(),t.fillStyle=this.textColor,t.textAlign="center",t.textBaseline="middle",t.fillText(this.text,o+e/2,a+s/2)}}}),e.MultiTooltip=e.Element.extend({initialize:function(){this.font=W(this.fontSize,this.fontStyle,this.fontFamily),this.titleFont=W(this.titleFontSize,this.titleFontStyle,this.titleFontFamily),this.titleHeight=this.title?1.5*this.titleFontSize:0,this.height=this.labels.length*this.fontSize+(this.labels.length-1)*(this.fontSize/2)+2*this.yPadding+this.titleHeight,this.ctx.font=this.titleFont;var t=this.ctx.measureText(this.title).width,i=z(this.ctx,this.font,this.labels)+this.fontSize+3,e=g([i,t]);this.width=e+2*this.xPadding;var s=this.height/2;this.y-s<0?this.y=s:this.y+s>this.chart.height&&(this.y=this.chart.height-s),this.x>this.chart.width/2?this.x-=this.xOffset+this.width:this.x+=this.xOffset},getLineHeight:function(t){var i=this.y-this.height/2+this.yPadding,e=t-1;return 0===t?i+this.titleHeight/3:i+(1.5*this.fontSize*e+this.fontSize/2)+this.titleHeight},draw:function(){if(this.custom)this.custom(this);else{B(this.ctx,this.x,this.y-this.height/2,this.width,this.height,this.cornerRadius);var t=this.ctx;t.fillStyle=this.fillColor,t.fill(),t.closePath(),t.textAlign="left",t.textBaseline="middle",t.fillStyle=this.titleTextColor,t.font=this.titleFont,t.fillText(this.title,this.x+this.xPadding,this.getLineHeight(0)),t.font=this.font,s.each(this.labels,function(i,e){t.fillStyle=this.textColor,t.fillText(i,this.x+this.xPadding+this.fontSize+3,this.getLineHeight(e+1)),t.fillStyle=this.legendColorBackground,t.fillRect(this.x+this.xPadding,this.getLineHeight(e+1)-this.fontSize/2,this.fontSize,this.fontSize),t.fillStyle=this.legendColors[e].fill,t.fillRect(this.x+this.xPadding,this.getLineHeight(e+1)-this.fontSize/2,this.fontSize,this.fontSize)},this)}}}),e.Scale=e.Element.extend({initialize:function(){this.fit()},buildYLabels:function(){this.yLabels=[];for(var t=v(this.stepValue),i=0;i<=this.steps;i++)this.yLabels.push(y(this.templateString,{value:(this.min+i*this.stepValue).toFixed(t)}));this.yLabelWidth=this.display&&this.showLabels?z(this.ctx,this.font,this.yLabels)+10:0},addXLabel:function(t){this.xLabels.push(t),this.valuesCount++,this.fit()},removeXLabel:function(){this.xLabels.shift(),this.valuesCount--,this.fit()},fit:function(){this.startPoint=this.display?this.fontSize:0,this.endPoint=this.display?this.height-1.5*this.fontSize-5:this.height,this.startPoint+=this.padding,this.endPoint-=this.padding;var t,i=this.endPoint,e=this.endPoint-this.startPoint;for(this.calculateYRange(e),this.buildYLabels(),this.calculateXLabelRotation();e>this.endPoint-this.startPoint;)e=this.endPoint-this.startPoint,t=this.yLabelWidth,this.calculateYRange(e),this.buildYLabels(),t<this.yLabelWidth&&(this.endPoint=i,this.calculateXLabelRotation())},calculateXLabelRotation:function(){this.ctx.font=this.font;var t,i,e=this.ctx.measureText(this.xLabels[0]).width,s=this.ctx.measureText(this.xLabels[this.xLabels.length-1]).width;if(this.xScalePaddingRight=s/2+3,this.xScalePaddingLeft=e/2>this.yLabelWidth?e/2:this.yLabelWidth,this.xLabelRotation=0,this.display){var n,o=z(this.ctx,this.font,this.xLabels);this.xLabelWidth=o;for(var a=Math.floor(this.calculateX(1)-this.calculateX(0))-6;this.xLabelWidth>a&&0===this.xLabelRotation||this.xLabelWidth>a&&this.xLabelRotation<=90&&this.xLabelRotation>0;)n=Math.cos(S(this.xLabelRotation)),t=n*e,i=n*s,t+this.fontSize/2>this.yLabelWidth&&(this.xScalePaddingLeft=t+this.fontSize/2),this.xScalePaddingRight=this.fontSize/2,this.xLabelRotation++,this.xLabelWidth=n*o;this.xLabelRotation>0&&(this.endPoint-=Math.sin(S(this.xLabelRotation))*o+3)}else this.xLabelWidth=0,this.xScalePaddingRight=this.padding,this.xScalePaddingLeft=this.padding},calculateYRange:c,drawingArea:function(){return this.startPoint-this.endPoint},calculateY:function(t){var i=this.drawingArea()/(this.min-this.max);return this.endPoint-i*(t-this.min)},calculateX:function(t){var i=(this.xLabelRotation>0,this.width-(this.xScalePaddingLeft+this.xScalePaddingRight)),e=i/Math.max(this.valuesCount-(this.offsetGridLines?0:1),1),s=e*t+this.xScalePaddingLeft;return this.offsetGridLines&&(s+=e/2),Math.round(s)},update:function(t){s.extend(this,t),this.fit()},draw:function(){var t=this.ctx,i=(this.endPoint-this.startPoint)/this.steps,e=Math.round(this.xScalePaddingLeft);this.display&&(t.fillStyle=this.textColor,t.font=this.font,n(this.yLabels,function(n,o){var a=this.endPoint-i*o,h=Math.round(a),l=this.showHorizontalLines;t.textAlign="right",t.textBaseline="middle",this.showLabels&&t.fillText(n,e-10,a),0!==o||l||(l=!0),l&&t.beginPath(),o>0?(t.lineWidth=this.gridLineWidth,t.strokeStyle=this.gridLineColor):(t.lineWidth=this.lineWidth,t.strokeStyle=this.lineColor),h+=s.aliasPixel(t.lineWidth),l&&(t.moveTo(e,h),t.lineTo(this.width,h),t.stroke(),t.closePath()),t.lineWidth=this.lineWidth,t.strokeStyle=this.lineColor,t.beginPath(),t.moveTo(e-5,h),t.lineTo(e,h),t.stroke(),t.closePath()},this),n(this.xLabels,function(i,e){var s=this.calculateX(e)+x(this.lineWidth),n=this.calculateX(e-(this.offsetGridLines?.5:0))+x(this.lineWidth),o=this.xLabelRotation>0,a=this.showVerticalLines;0!==e||a||(a=!0),a&&t.beginPath(),e>0?(t.lineWidth=this.gridLineWidth,t.strokeStyle=this.gridLineColor):(t.lineWidth=this.lineWidth,t.strokeStyle=this.lineColor),a&&(t.moveTo(n,this.endPoint),t.lineTo(n,this.startPoint-3),t.stroke(),t.closePath()),t.lineWidth=this.lineWidth,t.strokeStyle=this.lineColor,t.beginPath(),t.moveTo(n,this.endPoint),t.lineTo(n,this.endPoint+5),t.stroke(),t.closePath(),t.save(),t.translate(s,o?this.endPoint+12:this.endPoint+8),t.rotate(-1*S(this.xLabelRotation)),t.font=this.font,t.textAlign=o?"right":"center",t.textBaseline=o?"middle":"top",t.fillText(i,0,0),t.restore()},this))}}),e.RadialScale=e.Element.extend({initialize:function(){this.size=m([this.height,this.width]),this.drawingArea=this.display?this.size/2-(this.fontSize/2+this.backdropPaddingY):this.size/2},calculateCenterOffset:function(t){var i=this.drawingArea/(this.max-this.min);return(t-this.min)*i},update:function(){this.lineArc?this.drawingArea=this.display?this.size/2-(this.fontSize/2+this.backdropPaddingY):this.size/2:this.setScaleSize(),this.buildYLabels()},buildYLabels:function(){this.yLabels=[];for(var t=v(this.stepValue),i=0;i<=this.steps;i++)this.yLabels.push(y(this.templateString,{value:(this.min+i*this.stepValue).toFixed(t)}))},getCircumference:function(){return 2*Math.PI/this.valuesCount},setScaleSize:function(){var t,i,e,s,n,o,a,h,l,r,c,u,d=m([this.height/2-this.pointLabelFontSize-5,this.width/2]),p=this.width,g=0;for(this.ctx.font=W(this.pointLabelFontSize,this.pointLabelFontStyle,this.pointLabelFontFamily),i=0;i<this.valuesCount;i++)t=this.getPointPosition(i,d),e=this.ctx.measureText(y(this.templateString,{value:this.labels[i]})).width+5,0===i||i===this.valuesCount/2?(s=e/2,t.x+s>p&&(p=t.x+s,n=i),t.x-s<g&&(g=t.x-s,a=i)):i<this.valuesCount/2?t.x+e>p&&(p=t.x+e,n=i):i>this.valuesCount/2&&t.x-e<g&&(g=t.x-e,a=i);l=g,r=Math.ceil(p-this.width),o=this.getIndexAngle(n),h=this.getIndexAngle(a),c=r/Math.sin(o+Math.PI/2),u=l/Math.sin(h+Math.PI/2),c=f(c)?c:0,u=f(u)?u:0,this.drawingArea=d-(u+c)/2,this.setCenterPoint(u,c)},setCenterPoint:function(t,i){var e=this.width-i-this.drawingArea,s=t+this.drawingArea;this.xCenter=(s+e)/2,this.yCenter=this.height/2},getIndexAngle:function(t){var i=2*Math.PI/this.valuesCount;return t*i-Math.PI/2},getPointPosition:function(t,i){var e=this.getIndexAngle(t);return{x:Math.cos(e)*i+this.xCenter,y:Math.sin(e)*i+this.yCenter}},draw:function(){if(this.display){var t=this.ctx;if(n(this.yLabels,function(i,e){if(e>0){var s,n=e*(this.drawingArea/this.steps),o=this.yCenter-n;if(this.lineWidth>0)if(t.strokeStyle=this.lineColor,t.lineWidth=this.lineWidth,this.lineArc)t.beginPath(),t.arc(this.xCenter,this.yCenter,n,0,2*Math.PI),t.closePath(),t.stroke();else{t.beginPath();for(var a=0;a<this.valuesCount;a++)s=this.getPointPosition(a,this.calculateCenterOffset(this.min+e*this.stepValue)),0===a?t.moveTo(s.x,s.y):t.lineTo(s.x,s.y);t.closePath(),t.stroke()}if(this.showLabels){if(t.font=W(this.fontSize,this.fontStyle,this.fontFamily),this.showLabelBackdrop){var h=t.measureText(i).width;t.fillStyle=this.backdropColor,t.fillRect(this.xCenter-h/2-this.backdropPaddingX,o-this.fontSize/2-this.backdropPaddingY,h+2*this.backdropPaddingX,this.fontSize+2*this.backdropPaddingY)}t.textAlign="center",t.textBaseline="middle",t.fillStyle=this.fontColor,t.fillText(i,this.xCenter,o)}}},this),!this.lineArc){t.lineWidth=this.angleLineWidth,t.strokeStyle=this.angleLineColor;for(var i=this.valuesCount-1;i>=0;i--){var e=null,s=null;if(this.angleLineWidth>0&&(e=this.calculateCenterOffset(this.max),s=this.getPointPosition(i,e),t.beginPath(),t.moveTo(this.xCenter,this.yCenter),t.lineTo(s.x,s.y),t.stroke(),t.closePath()),this.backgroundColors&&this.backgroundColors.length==this.valuesCount){null==e&&(e=this.calculateCenterOffset(this.max)),null==s&&(s=this.getPointPosition(i,e));var o=this.getPointPosition(0===i?this.valuesCount-1:i-1,e),a=this.getPointPosition(i===this.valuesCount-1?0:i+1,e),h={x:(o.x+s.x)/2,y:(o.y+s.y)/2},l={x:(s.x+a.x)/2,y:(s.y+a.y)/2};t.beginPath(),t.moveTo(this.xCenter,this.yCenter),t.lineTo(h.x,h.y),t.lineTo(s.x,s.y),t.lineTo(l.x,l.y),t.fillStyle=this.backgroundColors[i],t.fill(),t.closePath()}var r=this.getPointPosition(i,this.calculateCenterOffset(this.max)+5);t.font=W(this.pointLabelFontSize,this.pointLabelFontStyle,this.pointLabelFontFamily),t.fillStyle=this.pointLabelFontColor;var c=this.labels.length,u=this.labels.length/2,d=u/2,p=d>i||i>c-d,f=i===d||i===c-d;0===i?t.textAlign="center":i===u?t.textAlign="center":u>i?t.textAlign="left":t.textAlign="right",f?t.textBaseline="middle":p?t.textBaseline="bottom":t.textBaseline="top",t.fillText(this.labels[i],r.x,r.y)}}}}}),e.animationService={frameDuration:17,animations:[],dropFrames:0,addAnimation:function(t,i){for(var e=0;e<this.animations.length;++e)if(this.animations[e].chartInstance===t)return void(this.animations[e].animationObject=i);this.animations.push({chartInstance:t,animationObject:i}),1==this.animations.length&&s.requestAnimFrame.call(window,this.digestWrapper)},cancelAnimation:function(t){var i=s.findNextWhere(this.animations,function(i){return i.chartInstance===t});i&&this.animations.splice(i,1)},digestWrapper:function(){e.animationService.startDigest.call(e.animationService)},startDigest:function(){var t=Date.now(),i=0;this.dropFrames>1&&(i=Math.floor(this.dropFrames),this.dropFrames-=i);for(var e=0;e<this.animations.length;e++)null===this.animations[e].animationObject.currentStep&&(this.animations[e].animationObject.currentStep=0),this.animations[e].animationObject.currentStep+=1+i,this.animations[e].animationObject.currentStep>this.animations[e].animationObject.numSteps&&(this.animations[e].animationObject.currentStep=this.animations[e].animationObject.numSteps),this.animations[e].animationObject.render(this.animations[e].chartInstance,this.animations[e].animationObject),this.animations[e].animationObject.currentStep==this.animations[e].animationObject.numSteps&&(this.animations[e].animationObject.onAnimationComplete.call(this.animations[e].chartInstance),this.animations.splice(e,1),e--);var n=Date.now(),o=n-t-this.frameDuration,a=o/this.frameDuration;a>1&&(this.dropFrames+=a),this.animations.length>0&&s.requestAnimFrame.call(window,this.digestWrapper)}},s.addEvent(window,"resize",function(){var t;return function(){clearTimeout(t),t=setTimeout(function(){n(e.instances,function(t){t.options.responsive&&t.resize(t.render,!0)})},50)}}()),p?define("Chart",[],function(){return e}):"object"==typeof module&&module.exports&&(module.exports=e),t.Chart=e,e.noConflict=function(){return t.Chart=i,e}}).call(this),function(){"use strict";var t=this,i=t.Chart,e=i.helpers,s={scaleBeginAtZero:!0,scaleShowGridLines:!0,scaleGridLineColor:"rgba(0,0,0,.05)",scaleGridLineWidth:1,scaleShowHorizontalLines:!0,scaleShowVerticalLines:!0,barShowStroke:!0,barStrokeWidth:2,barValueSpacing:5,barDatasetSpacing:1,legendTemplate:'<ul class="<%=name.toLowerCase()%>-legend"><% for (var i=0; i<datasets.length; i++){%><li><span style="background-color:<%=datasets[i].fillColor%>"><%if(datasets[i].label){%><%=datasets[i].label%><%}%></span></li><%}%></ul>'};i.Type.extend({name:"Bar",defaults:s,initialize:function(t){var s=this.options;this.ScaleClass=i.Scale.extend({offsetGridLines:!0,calculateBarX:function(t,i,e){var n=this.calculateBaseWidth(),o=this.calculateX(e)-n/2,a=this.calculateBarWidth(t);return o+a*i+i*s.barDatasetSpacing+a/2},calculateBaseWidth:function(){return this.calculateX(1)-this.calculateX(0)-2*s.barValueSpacing;
11
- },calculateBarWidth:function(t){var i=this.calculateBaseWidth()-(t-1)*s.barDatasetSpacing;return i/t}}),this.datasets=[],this.options.showTooltips&&e.bindEvents(this,this.options.tooltipEvents,function(t){var i="mouseout"!==t.type?this.getBarsAtEvent(t):[];this.eachBars(function(t){t.restore(["fillColor","strokeColor"])}),e.each(i,function(t){t.fillColor=t.highlightFill,t.strokeColor=t.highlightStroke}),this.showTooltip(i)}),this.BarClass=i.Rectangle.extend({strokeWidth:this.options.barStrokeWidth,showStroke:this.options.barShowStroke,ctx:this.chart.ctx}),e.each(t.datasets,function(i,s){var n={label:i.label||null,fillColor:i.fillColor,strokeColor:i.strokeColor,bars:[]};this.datasets.push(n),e.each(i.data,function(e,s){n.bars.push(new this.BarClass({value:e,label:t.labels[s],datasetLabel:i.label,strokeColor:"string"!=typeof i.strokeColor?i.strokeColor[s]:i.strokeColor,fillColor:"string"!=typeof i.fillColor?i.fillColor[s]:i.fillColor,highlightFill:i.highlightFill&&"string"!=typeof i.highlightFill?i.highlightFill[s]||i.highlightFill:"string"!=typeof i.fillColor?i.fillColor[s]:i.fillColor,highlightStroke:i.highlightStroke&&"string"!=typeof i.highlightStroke?i.highlightStroke[s]||i.highlightStroke:"string"!=typeof i.strokeColor?i.strokeColor[s]:i.strokeColor}))},this)},this),this.buildScale(t.labels),this.BarClass.prototype.base=this.scale.endPoint,this.eachBars(function(t,i,s){e.extend(t,{width:this.scale.calculateBarWidth(this.datasets.length),x:this.scale.calculateBarX(this.datasets.length,s,i),y:this.scale.endPoint}),t.save()},this),this.render()},update:function(){this.scale.update(),e.each(this.activeElements,function(t){t.restore(["fillColor","strokeColor"])}),this.eachBars(function(t){t.save()}),this.render()},eachBars:function(t){e.each(this.datasets,function(i,s){e.each(i.bars,t,this,s)},this)},getBarsAtEvent:function(t){for(var i,s=[],n=e.getRelativePosition(t),o=function(t){s.push(t.bars[i])},a=0;a<this.datasets.length;a++)for(i=0;i<this.datasets[a].bars.length;i++)if(this.datasets[a].bars[i].inRange(n.x,n.y))return e.each(this.datasets,o),s;return s},buildScale:function(t){var i=this,s=function(){var t=[];return i.eachBars(function(i){t.push(i.value)}),t},n={templateString:this.options.scaleLabel,height:this.chart.height,width:this.chart.width,ctx:this.chart.ctx,textColor:this.options.scaleFontColor,fontSize:this.options.scaleFontSize,fontStyle:this.options.scaleFontStyle,fontFamily:this.options.scaleFontFamily,valuesCount:t.length,beginAtZero:this.options.scaleBeginAtZero,integersOnly:this.options.scaleIntegersOnly,calculateYRange:function(t){var i=e.calculateScaleRange(s(),t,this.fontSize,this.beginAtZero,this.integersOnly);e.extend(this,i)},xLabels:t,font:e.fontString(this.options.scaleFontSize,this.options.scaleFontStyle,this.options.scaleFontFamily),lineWidth:this.options.scaleLineWidth,lineColor:this.options.scaleLineColor,showHorizontalLines:this.options.scaleShowHorizontalLines,showVerticalLines:this.options.scaleShowVerticalLines,gridLineWidth:this.options.scaleShowGridLines?this.options.scaleGridLineWidth:0,gridLineColor:this.options.scaleShowGridLines?this.options.scaleGridLineColor:"rgba(0,0,0,0)",padding:this.options.showScale?0:this.options.barShowStroke?this.options.barStrokeWidth:0,showLabels:this.options.scaleShowLabels,display:this.options.showScale};this.options.scaleOverride&&e.extend(n,{calculateYRange:e.noop,steps:this.options.scaleSteps,stepValue:this.options.scaleStepWidth,min:this.options.scaleStartValue,max:this.options.scaleStartValue+this.options.scaleSteps*this.options.scaleStepWidth}),this.scale=new this.ScaleClass(n)},addData:function(t,i){e.each(t,function(t,e){this.datasets[e].bars.push(new this.BarClass({value:t,label:i,datasetLabel:this.datasets[e].label,x:this.scale.calculateBarX(this.datasets.length,e,this.scale.valuesCount+1),y:this.scale.endPoint,width:this.scale.calculateBarWidth(this.datasets.length),base:this.scale.endPoint,strokeColor:this.datasets[e].strokeColor,fillColor:this.datasets[e].fillColor}))},this),this.scale.addXLabel(i),this.update()},removeData:function(){this.scale.removeXLabel(),e.each(this.datasets,function(t){t.bars.shift()},this),this.update()},reflow:function(){e.extend(this.BarClass.prototype,{y:this.scale.endPoint,base:this.scale.endPoint});var t=e.extend({height:this.chart.height,width:this.chart.width});this.scale.update(t)},draw:function(t){var i=t||1;this.clear();this.chart.ctx;this.scale.draw(i),e.each(this.datasets,function(t,s){e.each(t.bars,function(t,e){t.hasValue()&&(t.base=this.scale.endPoint,t.transition({x:this.scale.calculateBarX(this.datasets.length,s,e),y:this.scale.calculateY(t.value),width:this.scale.calculateBarWidth(this.datasets.length)},i).draw())},this)},this)}})}.call(this),function(){"use strict";var t=this,i=t.Chart,e=i.helpers,s={segmentShowStroke:!0,segmentStrokeColor:"#fff",segmentStrokeWidth:2,percentageInnerCutout:50,animationSteps:100,animationEasing:"easeOutBounce",animateRotate:!0,animateScale:!1,legendTemplate:'<ul class="<%=name.toLowerCase()%>-legend"><% for (var i=0; i<segments.length; i++){%><li><span style="background-color:<%=segments[i].fillColor%>"><%if(segments[i].label){%><%=segments[i].label%><%}%></span></li><%}%></ul>'};i.Type.extend({name:"Doughnut",defaults:s,initialize:function(t){this.segments=[],this.outerRadius=(e.min([this.chart.width,this.chart.height])-this.options.segmentStrokeWidth/2)/2,this.SegmentArc=i.Arc.extend({ctx:this.chart.ctx,x:this.chart.width/2,y:this.chart.height/2}),this.options.showTooltips&&e.bindEvents(this,this.options.tooltipEvents,function(t){var i="mouseout"!==t.type?this.getSegmentsAtEvent(t):[];e.each(this.segments,function(t){t.restore(["fillColor"])}),e.each(i,function(t){t.fillColor=t.highlightColor}),this.showTooltip(i)}),this.calculateTotal(t),e.each(t,function(i,e){i.color||(i.color="hsl("+360*e/t.length+", 100%, 50%)"),this.addData(i,e,!0)},this),this.render()},getSegmentsAtEvent:function(t){var i=[],s=e.getRelativePosition(t);return e.each(this.segments,function(t){t.inRange(s.x,s.y)&&i.push(t)},this),i},addData:function(t,e,s){var n=void 0!==e?e:this.segments.length;"undefined"==typeof t.color&&(t.color=i.defaults.global.segmentColorDefault[n%i.defaults.global.segmentColorDefault.length],t.highlight=i.defaults.global.segmentHighlightColorDefaults[n%i.defaults.global.segmentHighlightColorDefaults.length]),this.segments.splice(n,0,new this.SegmentArc({value:t.value,outerRadius:this.options.animateScale?0:this.outerRadius,innerRadius:this.options.animateScale?0:this.outerRadius/100*this.options.percentageInnerCutout,fillColor:t.color,highlightColor:t.highlight||t.color,showStroke:this.options.segmentShowStroke,strokeWidth:this.options.segmentStrokeWidth,strokeColor:this.options.segmentStrokeColor,startAngle:1.5*Math.PI,circumference:this.options.animateRotate?0:this.calculateCircumference(t.value),label:t.label})),s||(this.reflow(),this.update())},calculateCircumference:function(t){return this.total>0?2*Math.PI*(t/this.total):0},calculateTotal:function(t){this.total=0,e.each(t,function(t){this.total+=Math.abs(t.value)},this)},update:function(){this.calculateTotal(this.segments),e.each(this.activeElements,function(t){t.restore(["fillColor"])}),e.each(this.segments,function(t){t.save()}),this.render()},removeData:function(t){var i=e.isNumber(t)?t:this.segments.length-1;this.segments.splice(i,1),this.reflow(),this.update()},reflow:function(){e.extend(this.SegmentArc.prototype,{x:this.chart.width/2,y:this.chart.height/2}),this.outerRadius=(e.min([this.chart.width,this.chart.height])-this.options.segmentStrokeWidth/2)/2,e.each(this.segments,function(t){t.update({outerRadius:this.outerRadius,innerRadius:this.outerRadius/100*this.options.percentageInnerCutout})},this)},draw:function(t){var i=t?t:1;this.clear(),e.each(this.segments,function(t,e){t.transition({circumference:this.calculateCircumference(t.value),outerRadius:this.outerRadius,innerRadius:this.outerRadius/100*this.options.percentageInnerCutout},i),t.endAngle=t.startAngle+t.circumference,t.draw(),0===e&&(t.startAngle=1.5*Math.PI),e<this.segments.length-1&&(this.segments[e+1].startAngle=t.endAngle)},this)}}),i.types.Doughnut.extend({name:"Pie",defaults:e.merge(s,{percentageInnerCutout:0})})}.call(this),function(){"use strict";var t=this,i=t.Chart,e=i.helpers,s={scaleShowGridLines:!0,scaleGridLineColor:"rgba(0,0,0,.05)",scaleGridLineWidth:1,scaleShowHorizontalLines:!0,scaleShowVerticalLines:!0,bezierCurve:!0,bezierCurveTension:.4,pointDot:!0,pointDotRadius:4,pointDotStrokeWidth:1,pointHitDetectionRadius:20,datasetStroke:!0,datasetStrokeWidth:2,datasetFill:!0,legendTemplate:'<ul class="<%=name.toLowerCase()%>-legend"><% for (var i=0; i<datasets.length; i++){%><li><span style="background-color:<%=datasets[i].strokeColor%>"><%if(datasets[i].label){%><%=datasets[i].label%><%}%></span></li><%}%></ul>',offsetGridLines:!1};i.Type.extend({name:"Line",defaults:s,initialize:function(t){this.PointClass=i.Point.extend({offsetGridLines:this.options.offsetGridLines,strokeWidth:this.options.pointDotStrokeWidth,radius:this.options.pointDotRadius,display:this.options.pointDot,hitDetectionRadius:this.options.pointHitDetectionRadius,ctx:this.chart.ctx,inRange:function(t){return Math.pow(t-this.x,2)<Math.pow(this.radius+this.hitDetectionRadius,2)}}),this.datasets=[],this.options.showTooltips&&e.bindEvents(this,this.options.tooltipEvents,function(t){var i="mouseout"!==t.type?this.getPointsAtEvent(t):[];this.eachPoints(function(t){t.restore(["fillColor","strokeColor"])}),e.each(i,function(t){t.fillColor=t.highlightFill,t.strokeColor=t.highlightStroke}),this.showTooltip(i)}),e.each(t.datasets,function(i){var s={label:i.label||null,fillColor:i.fillColor,strokeColor:i.strokeColor,pointColor:i.pointColor,pointStrokeColor:i.pointStrokeColor,points:[]};this.datasets.push(s),e.each(i.data,function(e,n){s.points.push(new this.PointClass({value:e,label:t.labels[n],datasetLabel:i.label,strokeColor:i.pointStrokeColor,fillColor:i.pointColor,highlightFill:i.pointHighlightFill||i.pointColor,highlightStroke:i.pointHighlightStroke||i.pointStrokeColor}))},this),this.buildScale(t.labels),this.eachPoints(function(t,i){e.extend(t,{x:this.scale.calculateX(i),y:this.scale.endPoint}),t.save()},this)},this),this.render()},update:function(){this.scale.update(),e.each(this.activeElements,function(t){t.restore(["fillColor","strokeColor"])}),this.eachPoints(function(t){t.save()}),this.render()},eachPoints:function(t){e.each(this.datasets,function(i){e.each(i.points,t,this)},this)},getPointsAtEvent:function(t){var i=[],s=e.getRelativePosition(t);return e.each(this.datasets,function(t){e.each(t.points,function(t){t.inRange(s.x,s.y)&&i.push(t)})},this),i},buildScale:function(t){var s=this,n=function(){var t=[];return s.eachPoints(function(i){t.push(i.value)}),t},o={templateString:this.options.scaleLabel,height:this.chart.height,width:this.chart.width,ctx:this.chart.ctx,textColor:this.options.scaleFontColor,offsetGridLines:this.options.offsetGridLines,fontSize:this.options.scaleFontSize,fontStyle:this.options.scaleFontStyle,fontFamily:this.options.scaleFontFamily,valuesCount:t.length,beginAtZero:this.options.scaleBeginAtZero,integersOnly:this.options.scaleIntegersOnly,calculateYRange:function(t){var i=e.calculateScaleRange(n(),t,this.fontSize,this.beginAtZero,this.integersOnly);e.extend(this,i)},xLabels:t,font:e.fontString(this.options.scaleFontSize,this.options.scaleFontStyle,this.options.scaleFontFamily),lineWidth:this.options.scaleLineWidth,lineColor:this.options.scaleLineColor,showHorizontalLines:this.options.scaleShowHorizontalLines,showVerticalLines:this.options.scaleShowVerticalLines,gridLineWidth:this.options.scaleShowGridLines?this.options.scaleGridLineWidth:0,gridLineColor:this.options.scaleShowGridLines?this.options.scaleGridLineColor:"rgba(0,0,0,0)",padding:this.options.showScale?0:this.options.pointDotRadius+this.options.pointDotStrokeWidth,showLabels:this.options.scaleShowLabels,display:this.options.showScale};this.options.scaleOverride&&e.extend(o,{calculateYRange:e.noop,steps:this.options.scaleSteps,stepValue:this.options.scaleStepWidth,min:this.options.scaleStartValue,max:this.options.scaleStartValue+this.options.scaleSteps*this.options.scaleStepWidth}),this.scale=new i.Scale(o)},addData:function(t,i){e.each(t,function(t,e){this.datasets[e].points.push(new this.PointClass({value:t,label:i,datasetLabel:this.datasets[e].label,x:this.scale.calculateX(this.scale.valuesCount+1),y:this.scale.endPoint,strokeColor:this.datasets[e].pointStrokeColor,fillColor:this.datasets[e].pointColor}))},this),this.scale.addXLabel(i),this.update()},removeData:function(){this.scale.removeXLabel(),e.each(this.datasets,function(t){t.points.shift()},this),this.update()},reflow:function(){var t=e.extend({height:this.chart.height,width:this.chart.width});this.scale.update(t)},draw:function(t){var i=t||1;this.clear();var s=this.chart.ctx,n=function(t){return null!==t.value},o=function(t,i,s){return e.findNextWhere(i,n,s)||t},a=function(t,i,s){return e.findPreviousWhere(i,n,s)||t};this.scale&&(this.scale.draw(i),e.each(this.datasets,function(t){var h=e.where(t.points,n);e.each(t.points,function(t,e){t.hasValue()&&t.transition({y:this.scale.calculateY(t.value),x:this.scale.calculateX(e)},i)},this),this.options.bezierCurve&&e.each(h,function(t,i){var s=i>0&&i<h.length-1?this.options.bezierCurveTension:0;t.controlPoints=e.splineCurve(a(t,h,i),t,o(t,h,i),s),t.controlPoints.outer.y>this.scale.endPoint?t.controlPoints.outer.y=this.scale.endPoint:t.controlPoints.outer.y<this.scale.startPoint&&(t.controlPoints.outer.y=this.scale.startPoint),t.controlPoints.inner.y>this.scale.endPoint?t.controlPoints.inner.y=this.scale.endPoint:t.controlPoints.inner.y<this.scale.startPoint&&(t.controlPoints.inner.y=this.scale.startPoint)},this),s.lineWidth=this.options.datasetStrokeWidth,s.strokeStyle=t.strokeColor,s.beginPath(),e.each(h,function(t,i){if(0===i)s.moveTo(t.x,t.y);else if(this.options.bezierCurve){var e=a(t,h,i);s.bezierCurveTo(e.controlPoints.outer.x,e.controlPoints.outer.y,t.controlPoints.inner.x,t.controlPoints.inner.y,t.x,t.y)}else s.lineTo(t.x,t.y)},this),this.options.datasetStroke&&s.stroke(),this.options.datasetFill&&h.length>0&&(s.lineTo(h[h.length-1].x,this.scale.endPoint),s.lineTo(h[0].x,this.scale.endPoint),s.fillStyle=t.fillColor,s.closePath(),s.fill()),e.each(h,function(t){t.draw()})},this))}})}.call(this),function(){"use strict";var t=this,i=t.Chart,e=i.helpers,s={scaleShowLabelBackdrop:!0,scaleBackdropColor:"rgba(255,255,255,0.75)",scaleBeginAtZero:!0,scaleBackdropPaddingY:2,scaleBackdropPaddingX:2,scaleShowLine:!0,segmentShowStroke:!0,segmentStrokeColor:"#fff",segmentStrokeWidth:2,animationSteps:100,animationEasing:"easeOutBounce",animateRotate:!0,animateScale:!1,legendTemplate:'<ul class="<%=name.toLowerCase()%>-legend"><% for (var i=0; i<segments.length; i++){%><li><span style="background-color:<%=segments[i].fillColor%>"><%if(segments[i].label){%><%=segments[i].label%><%}%></span></li><%}%></ul>'};i.Type.extend({name:"PolarArea",defaults:s,initialize:function(t){this.segments=[],this.SegmentArc=i.Arc.extend({showStroke:this.options.segmentShowStroke,strokeWidth:this.options.segmentStrokeWidth,strokeColor:this.options.segmentStrokeColor,ctx:this.chart.ctx,innerRadius:0,x:this.chart.width/2,y:this.chart.height/2}),this.scale=new i.RadialScale({display:this.options.showScale,fontStyle:this.options.scaleFontStyle,fontSize:this.options.scaleFontSize,fontFamily:this.options.scaleFontFamily,fontColor:this.options.scaleFontColor,showLabels:this.options.scaleShowLabels,showLabelBackdrop:this.options.scaleShowLabelBackdrop,backdropColor:this.options.scaleBackdropColor,backdropPaddingY:this.options.scaleBackdropPaddingY,backdropPaddingX:this.options.scaleBackdropPaddingX,lineWidth:this.options.scaleShowLine?this.options.scaleLineWidth:0,lineColor:this.options.scaleLineColor,lineArc:!0,width:this.chart.width,height:this.chart.height,xCenter:this.chart.width/2,yCenter:this.chart.height/2,ctx:this.chart.ctx,templateString:this.options.scaleLabel,valuesCount:t.length}),this.updateScaleRange(t),this.scale.update(),e.each(t,function(t,i){this.addData(t,i,!0)},this),this.options.showTooltips&&e.bindEvents(this,this.options.tooltipEvents,function(t){var i="mouseout"!==t.type?this.getSegmentsAtEvent(t):[];e.each(this.segments,function(t){t.restore(["fillColor"])}),e.each(i,function(t){t.fillColor=t.highlightColor}),this.showTooltip(i)}),this.render()},getSegmentsAtEvent:function(t){var i=[],s=e.getRelativePosition(t);return e.each(this.segments,function(t){t.inRange(s.x,s.y)&&i.push(t)},this),i},addData:function(t,i,e){var s=i||this.segments.length;this.segments.splice(s,0,new this.SegmentArc({fillColor:t.color,highlightColor:t.highlight||t.color,label:t.label,value:t.value,outerRadius:this.options.animateScale?0:this.scale.calculateCenterOffset(t.value),circumference:this.options.animateRotate?0:this.scale.getCircumference(),startAngle:1.5*Math.PI})),e||(this.reflow(),this.update())},removeData:function(t){var i=e.isNumber(t)?t:this.segments.length-1;this.segments.splice(i,1),this.reflow(),this.update()},calculateTotal:function(t){this.total=0,e.each(t,function(t){this.total+=t.value},this),this.scale.valuesCount=this.segments.length},updateScaleRange:function(t){var i=[];e.each(t,function(t){i.push(t.value)});var s=this.options.scaleOverride?{steps:this.options.scaleSteps,stepValue:this.options.scaleStepWidth,min:this.options.scaleStartValue,max:this.options.scaleStartValue+this.options.scaleSteps*this.options.scaleStepWidth}:e.calculateScaleRange(i,e.min([this.chart.width,this.chart.height])/2,this.options.scaleFontSize,this.options.scaleBeginAtZero,this.options.scaleIntegersOnly);e.extend(this.scale,s,{size:e.min([this.chart.width,this.chart.height]),xCenter:this.chart.width/2,yCenter:this.chart.height/2})},update:function(){this.calculateTotal(this.segments),e.each(this.segments,function(t){t.save()}),this.reflow(),this.render()},reflow:function(){e.extend(this.SegmentArc.prototype,{x:this.chart.width/2,y:this.chart.height/2}),this.updateScaleRange(this.segments),this.scale.update(),e.extend(this.scale,{xCenter:this.chart.width/2,yCenter:this.chart.height/2}),e.each(this.segments,function(t){t.update({outerRadius:this.scale.calculateCenterOffset(t.value)})},this)},draw:function(t){var i=t||1;this.clear(),e.each(this.segments,function(t,e){t.transition({circumference:this.scale.getCircumference(),outerRadius:this.scale.calculateCenterOffset(t.value)},i),t.endAngle=t.startAngle+t.circumference,0===e&&(t.startAngle=1.5*Math.PI),e<this.segments.length-1&&(this.segments[e+1].startAngle=t.endAngle),t.draw()},this),this.scale.draw()}})}.call(this),function(){"use strict";var t=this,i=t.Chart,e=i.helpers;i.Type.extend({name:"Radar",defaults:{scaleShowLine:!0,angleShowLineOut:!0,scaleShowLabels:!1,scaleBeginAtZero:!0,angleLineColor:"rgba(0,0,0,.1)",angleLineWidth:1,pointLabelFontFamily:"'Arial'",pointLabelFontStyle:"normal",pointLabelFontSize:10,pointLabelFontColor:"#666",pointDot:!0,pointDotRadius:3,pointDotStrokeWidth:1,pointHitDetectionRadius:20,datasetStroke:!0,datasetStrokeWidth:2,datasetFill:!0,legendTemplate:'<ul class="<%=name.toLowerCase()%>-legend"><% for (var i=0; i<datasets.length; i++){%><li><span style="background-color:<%=datasets[i].strokeColor%>"><%if(datasets[i].label){%><%=datasets[i].label%><%}%></span></li><%}%></ul>'},initialize:function(t){this.PointClass=i.Point.extend({strokeWidth:this.options.pointDotStrokeWidth,radius:this.options.pointDotRadius,display:this.options.pointDot,hitDetectionRadius:this.options.pointHitDetectionRadius,ctx:this.chart.ctx}),this.datasets=[],this.buildScale(t),this.options.showTooltips&&e.bindEvents(this,this.options.tooltipEvents,function(t){var i="mouseout"!==t.type?this.getPointsAtEvent(t):[];this.eachPoints(function(t){t.restore(["fillColor","strokeColor"])}),e.each(i,function(t){t.fillColor=t.highlightFill,t.strokeColor=t.highlightStroke}),this.showTooltip(i)}),e.each(t.datasets,function(i){var s={label:i.label||null,fillColor:i.fillColor,strokeColor:i.strokeColor,pointColor:i.pointColor,pointStrokeColor:i.pointStrokeColor,points:[]};this.datasets.push(s),e.each(i.data,function(e,n){var o;this.scale.animation||(o=this.scale.getPointPosition(n,this.scale.calculateCenterOffset(e))),s.points.push(new this.PointClass({value:e,label:t.labels[n],datasetLabel:i.label,x:this.options.animation?this.scale.xCenter:o.x,y:this.options.animation?this.scale.yCenter:o.y,strokeColor:i.pointStrokeColor,fillColor:i.pointColor,highlightFill:i.pointHighlightFill||i.pointColor,highlightStroke:i.pointHighlightStroke||i.pointStrokeColor}))},this)},this),this.render()},eachPoints:function(t){e.each(this.datasets,function(i){e.each(i.points,t,this)},this)},getPointsAtEvent:function(t){var i=e.getRelativePosition(t),s=e.getAngleFromPoint({x:this.scale.xCenter,y:this.scale.yCenter},i),n=2*Math.PI/this.scale.valuesCount,o=Math.round((s.angle-1.5*Math.PI)/n),a=[];return(o>=this.scale.valuesCount||0>o)&&(o=0),s.distance<=this.scale.drawingArea&&e.each(this.datasets,function(t){a.push(t.points[o])}),a},buildScale:function(t){this.scale=new i.RadialScale({display:this.options.showScale,fontStyle:this.options.scaleFontStyle,fontSize:this.options.scaleFontSize,fontFamily:this.options.scaleFontFamily,fontColor:this.options.scaleFontColor,showLabels:this.options.scaleShowLabels,showLabelBackdrop:this.options.scaleShowLabelBackdrop,backdropColor:this.options.scaleBackdropColor,backgroundColors:this.options.scaleBackgroundColors,backdropPaddingY:this.options.scaleBackdropPaddingY,backdropPaddingX:this.options.scaleBackdropPaddingX,lineWidth:this.options.scaleShowLine?this.options.scaleLineWidth:0,lineColor:this.options.scaleLineColor,angleLineColor:this.options.angleLineColor,angleLineWidth:this.options.angleShowLineOut?this.options.angleLineWidth:0,pointLabelFontColor:this.options.pointLabelFontColor,pointLabelFontSize:this.options.pointLabelFontSize,pointLabelFontFamily:this.options.pointLabelFontFamily,pointLabelFontStyle:this.options.pointLabelFontStyle,height:this.chart.height,width:this.chart.width,xCenter:this.chart.width/2,yCenter:this.chart.height/2,ctx:this.chart.ctx,templateString:this.options.scaleLabel,labels:t.labels,valuesCount:t.datasets[0].data.length}),this.scale.setScaleSize(),this.updateScaleRange(t.datasets),this.scale.buildYLabels()},updateScaleRange:function(t){var i=function(){var i=[];return e.each(t,function(t){t.data?i=i.concat(t.data):e.each(t.points,function(t){i.push(t.value)})}),i}(),s=this.options.scaleOverride?{steps:this.options.scaleSteps,stepValue:this.options.scaleStepWidth,min:this.options.scaleStartValue,max:this.options.scaleStartValue+this.options.scaleSteps*this.options.scaleStepWidth}:e.calculateScaleRange(i,e.min([this.chart.width,this.chart.height])/2,this.options.scaleFontSize,this.options.scaleBeginAtZero,this.options.scaleIntegersOnly);e.extend(this.scale,s)},addData:function(t,i){this.scale.valuesCount++,e.each(t,function(t,e){var s=this.scale.getPointPosition(this.scale.valuesCount,this.scale.calculateCenterOffset(t));this.datasets[e].points.push(new this.PointClass({value:t,label:i,datasetLabel:this.datasets[e].label,x:s.x,y:s.y,strokeColor:this.datasets[e].pointStrokeColor,fillColor:this.datasets[e].pointColor}))},this),this.scale.labels.push(i),this.reflow(),this.update()},removeData:function(){this.scale.valuesCount--,this.scale.labels.shift(),e.each(this.datasets,function(t){t.points.shift()},this),this.reflow(),this.update()},update:function(){this.eachPoints(function(t){t.save()}),this.reflow(),this.render()},reflow:function(){e.extend(this.scale,{width:this.chart.width,height:this.chart.height,size:e.min([this.chart.width,this.chart.height]),xCenter:this.chart.width/2,yCenter:this.chart.height/2}),this.updateScaleRange(this.datasets),this.scale.setScaleSize(),this.scale.buildYLabels()},draw:function(t){var i=t||1,s=this.chart.ctx;this.clear(),this.scale.draw(),e.each(this.datasets,function(t){e.each(t.points,function(t,e){t.hasValue()&&t.transition(this.scale.getPointPosition(e,this.scale.calculateCenterOffset(t.value)),i)},this),s.lineWidth=this.options.datasetStrokeWidth,s.strokeStyle=t.strokeColor,s.beginPath(),e.each(t.points,function(t,i){0===i?s.moveTo(t.x,t.y):s.lineTo(t.x,t.y)},this),s.closePath(),s.stroke(),s.fillStyle=t.fillColor,this.options.datasetFill&&s.fill(),e.each(t.points,function(t){t.hasValue()&&t.draw()})},this)}})}.call(this);
1
  /*!
2
  * Chart.js
3
  * http://chartjs.org/
4
+ * Version: 2.7.1
5
  *
6
+ * Copyright 2017 Nick Downie
7
  * Released under the MIT license
8
+ * https://github.com/chartjs/Chart.js/blob/master/LICENSE.md
9
  */
10
+ !function(t){if("object"==typeof exports&&"undefined"!=typeof module)module.exports=t();else if("function"==typeof define&&define.amd)define([],t);else{("undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self?self:this).Chart=t()}}(function(){return function t(e,n,i){function a(r,l){if(!n[r]){if(!e[r]){var s="function"==typeof require&&require;if(!l&&s)return s(r,!0);if(o)return o(r,!0);var u=new Error("Cannot find module '"+r+"'");throw u.code="MODULE_NOT_FOUND",u}var d=n[r]={exports:{}};e[r][0].call(d.exports,function(t){var n=e[r][1][t];return a(n||t)},d,d.exports,t,e,n,i)}return n[r].exports}for(var o="function"==typeof require&&require,r=0;r<i.length;r++)a(i[r]);return a}({1:[function(t,e,n){},{}],2:[function(t,e,n){function i(t){if(t){var e=[0,0,0],n=1,i=t.match(/^#([a-fA-F0-9]{3})$/i);if(i){i=i[1];for(a=0;a<e.length;a++)e[a]=parseInt(i[a]+i[a],16)}else if(i=t.match(/^#([a-fA-F0-9]{6})$/i)){i=i[1];for(a=0;a<e.length;a++)e[a]=parseInt(i.slice(2*a,2*a+2),16)}else if(i=t.match(/^rgba?\(\s*([+-]?\d+)\s*,\s*([+-]?\d+)\s*,\s*([+-]?\d+)\s*(?:,\s*([+-]?[\d\.]+)\s*)?\)$/i)){for(a=0;a<e.length;a++)e[a]=parseInt(i[a+1]);n=parseFloat(i[4])}else if(i=t.match(/^rgba?\(\s*([+-]?[\d\.]+)\%\s*,\s*([+-]?[\d\.]+)\%\s*,\s*([+-]?[\d\.]+)\%\s*(?:,\s*([+-]?[\d\.]+)\s*)?\)$/i)){for(a=0;a<e.length;a++)e[a]=Math.round(2.55*parseFloat(i[a+1]));n=parseFloat(i[4])}else if(i=t.match(/(\w+)/)){if("transparent"==i[1])return[0,0,0,0];if(!(e=c[i[1]]))return}for(var a=0;a<e.length;a++)e[a]=u(e[a],0,255);return n=n||0==n?u(n,0,1):1,e[3]=n,e}}function a(t){if(t){var e=t.match(/^hsla?\(\s*([+-]?\d+)(?:deg)?\s*,\s*([+-]?[\d\.]+)%\s*,\s*([+-]?[\d\.]+)%\s*(?:,\s*([+-]?[\d\.]+)\s*)?\)/);if(e){var n=parseFloat(e[4]);return[u(parseInt(e[1]),0,360),u(parseFloat(e[2]),0,100),u(parseFloat(e[3]),0,100),u(isNaN(n)?1:n,0,1)]}}}function o(t){if(t){var e=t.match(/^hwb\(\s*([+-]?\d+)(?:deg)?\s*,\s*([+-]?[\d\.]+)%\s*,\s*([+-]?[\d\.]+)%\s*(?:,\s*([+-]?[\d\.]+)\s*)?\)/);if(e){var n=parseFloat(e[4]);return[u(parseInt(e[1]),0,360),u(parseFloat(e[2]),0,100),u(parseFloat(e[3]),0,100),u(isNaN(n)?1:n,0,1)]}}}function r(t,e){return void 0===e&&(e=void 0!==t[3]?t[3]:1),"rgba("+t[0]+", "+t[1]+", "+t[2]+", "+e+")"}function l(t,e){return"rgba("+Math.round(t[0]/255*100)+"%, "+Math.round(t[1]/255*100)+"%, "+Math.round(t[2]/255*100)+"%, "+(e||t[3]||1)+")"}function s(t,e){return void 0===e&&(e=void 0!==t[3]?t[3]:1),"hsla("+t[0]+", "+t[1]+"%, "+t[2]+"%, "+e+")"}function u(t,e,n){return Math.min(Math.max(e,t),n)}function d(t){var e=t.toString(16).toUpperCase();return e.length<2?"0"+e:e}var c=t(6);e.exports={getRgba:i,getHsla:a,getRgb:function(t){var e=i(t);return e&&e.slice(0,3)},getHsl:function(t){var e=a(t);return e&&e.slice(0,3)},getHwb:o,getAlpha:function(t){var e=i(t);return e?e[3]:(e=a(t))?e[3]:(e=o(t))?e[3]:void 0},hexString:function(t){return"#"+d(t[0])+d(t[1])+d(t[2])},rgbString:function(t,e){return e<1||t[3]&&t[3]<1?r(t,e):"rgb("+t[0]+", "+t[1]+", "+t[2]+")"},rgbaString:r,percentString:function(t,e){return e<1||t[3]&&t[3]<1?l(t,e):"rgb("+Math.round(t[0]/255*100)+"%, "+Math.round(t[1]/255*100)+"%, "+Math.round(t[2]/255*100)+"%)"},percentaString:l,hslString:function(t,e){return e<1||t[3]&&t[3]<1?s(t,e):"hsl("+t[0]+", "+t[1]+"%, "+t[2]+"%)"},hslaString:s,hwbString:function(t,e){return void 0===e&&(e=void 0!==t[3]?t[3]:1),"hwb("+t[0]+", "+t[1]+"%, "+t[2]+"%"+(void 0!==e&&1!==e?", "+e:"")+")"},keyword:function(t){return h[t.slice(0,3)]}};var h={};for(var f in c)h[c[f]]=f},{6:6}],3:[function(t,e,n){var i=t(5),a=t(2),o=function(t){if(t instanceof o)return t;if(!(this instanceof o))return new o(t);this.valid=!1,this.values={rgb:[0,0,0],hsl:[0,0,0],hsv:[0,0,0],hwb:[0,0,0],cmyk:[0,0,0,0],alpha:1};var e;"string"==typeof t?(e=a.getRgba(t))?this.setValues("rgb",e):(e=a.getHsla(t))?this.setValues("hsl",e):(e=a.getHwb(t))&&this.setValues("hwb",e):"object"==typeof t&&(void 0!==(e=t).r||void 0!==e.red?this.setValues("rgb",e):void 0!==e.l||void 0!==e.lightness?this.setValues("hsl",e):void 0!==e.v||void 0!==e.value?this.setValues("hsv",e):void 0!==e.w||void 0!==e.whiteness?this.setValues("hwb",e):void 0===e.c&&void 0===e.cyan||this.setValues("cmyk",e))};o.prototype={isValid:function(){return this.valid},rgb:function(){return this.setSpace("rgb",arguments)},hsl:function(){return this.setSpace("hsl",arguments)},hsv:function(){return this.setSpace("hsv",arguments)},hwb:function(){return this.setSpace("hwb",arguments)},cmyk:function(){return this.setSpace("cmyk",arguments)},rgbArray:function(){return this.values.rgb},hslArray:function(){return this.values.hsl},hsvArray:function(){return this.values.hsv},hwbArray:function(){var t=this.values;return 1!==t.alpha?t.hwb.concat([t.alpha]):t.hwb},cmykArray:function(){return this.values.cmyk},rgbaArray:function(){var t=this.values;return t.rgb.concat([t.alpha])},hslaArray:function(){var t=this.values;return t.hsl.concat([t.alpha])},alpha:function(t){return void 0===t?this.values.alpha:(this.setValues("alpha",t),this)},red:function(t){return this.setChannel("rgb",0,t)},green:function(t){return this.setChannel("rgb",1,t)},blue:function(t){return this.setChannel("rgb",2,t)},hue:function(t){return t&&(t=(t%=360)<0?360+t:t),this.setChannel("hsl",0,t)},saturation:function(t){return this.setChannel("hsl",1,t)},lightness:function(t){return this.setChannel("hsl",2,t)},saturationv:function(t){return this.setChannel("hsv",1,t)},whiteness:function(t){return this.setChannel("hwb",1,t)},blackness:function(t){return this.setChannel("hwb",2,t)},value:function(t){return this.setChannel("hsv",2,t)},cyan:function(t){return this.setChannel("cmyk",0,t)},magenta:function(t){return this.setChannel("cmyk",1,t)},yellow:function(t){return this.setChannel("cmyk",2,t)},black:function(t){return this.setChannel("cmyk",3,t)},hexString:function(){return a.hexString(this.values.rgb)},rgbString:function(){return a.rgbString(this.values.rgb,this.values.alpha)},rgbaString:function(){return a.rgbaString(this.values.rgb,this.values.alpha)},percentString:function(){return a.percentString(this.values.rgb,this.values.alpha)},hslString:function(){return a.hslString(this.values.hsl,this.values.alpha)},hslaString:function(){return a.hslaString(this.values.hsl,this.values.alpha)},hwbString:function(){return a.hwbString(this.values.hwb,this.values.alpha)},keyword:function(){return a.keyword(this.values.rgb,this.values.alpha)},rgbNumber:function(){var t=this.values.rgb;return t[0]<<16|t[1]<<8|t[2]},luminosity:function(){for(var t=this.values.rgb,e=[],n=0;n<t.length;n++){var i=t[n]/255;e[n]=i<=.03928?i/12.92:Math.pow((i+.055)/1.055,2.4)}return.2126*e[0]+.7152*e[1]+.0722*e[2]},contrast:function(t){var e=this.luminosity(),n=t.luminosity();return e>n?(e+.05)/(n+.05):(n+.05)/(e+.05)},level:function(t){var e=this.contrast(t);return e>=7.1?"AAA":e>=4.5?"AA":""},dark:function(){var t=this.values.rgb;return(299*t[0]+587*t[1]+114*t[2])/1e3<128},light:function(){return!this.dark()},negate:function(){for(var t=[],e=0;e<3;e++)t[e]=255-this.values.rgb[e];return this.setValues("rgb",t),this},lighten:function(t){var e=this.values.hsl;return e[2]+=e[2]*t,this.setValues("hsl",e),this},darken:function(t){var e=this.values.hsl;return e[2]-=e[2]*t,this.setValues("hsl",e),this},saturate:function(t){var e=this.values.hsl;return e[1]+=e[1]*t,this.setValues("hsl",e),this},desaturate:function(t){var e=this.values.hsl;return e[1]-=e[1]*t,this.setValues("hsl",e),this},whiten:function(t){var e=this.values.hwb;return e[1]+=e[1]*t,this.setValues("hwb",e),this},blacken:function(t){var e=this.values.hwb;return e[2]+=e[2]*t,this.setValues("hwb",e),this},greyscale:function(){var t=this.values.rgb,e=.3*t[0]+.59*t[1]+.11*t[2];return this.setValues("rgb",[e,e,e]),this},clearer:function(t){var e=this.values.alpha;return this.setValues("alpha",e-e*t),this},opaquer:function(t){var e=this.values.alpha;return this.setValues("alpha",e+e*t),this},rotate:function(t){var e=this.values.hsl,n=(e[0]+t)%360;return e[0]=n<0?360+n:n,this.setValues("hsl",e),this},mix:function(t,e){var n=this,i=t,a=void 0===e?.5:e,o=2*a-1,r=n.alpha()-i.alpha(),l=((o*r==-1?o:(o+r)/(1+o*r))+1)/2,s=1-l;return this.rgb(l*n.red()+s*i.red(),l*n.green()+s*i.green(),l*n.blue()+s*i.blue()).alpha(n.alpha()*a+i.alpha()*(1-a))},toJSON:function(){return this.rgb()},clone:function(){var t,e,n=new o,i=this.values,a=n.values;for(var r in i)i.hasOwnProperty(r)&&(t=i[r],"[object Array]"===(e={}.toString.call(t))?a[r]=t.slice(0):"[object Number]"===e?a[r]=t:console.error("unexpected color value:",t));return n}},o.prototype.spaces={rgb:["red","green","blue"],hsl:["hue","saturation","lightness"],hsv:["hue","saturation","value"],hwb:["hue","whiteness","blackness"],cmyk:["cyan","magenta","yellow","black"]},o.prototype.maxes={rgb:[255,255,255],hsl:[360,100,100],hsv:[360,100,100],hwb:[360,100,100],cmyk:[100,100,100,100]},o.prototype.getValues=function(t){for(var e=this.values,n={},i=0;i<t.length;i++)n[t.charAt(i)]=e[t][i];return 1!==e.alpha&&(n.a=e.alpha),n},o.prototype.setValues=function(t,e){var n,a=this.values,o=this.spaces,r=this.maxes,l=1;if(this.valid=!0,"alpha"===t)l=e;else if(e.length)a[t]=e.slice(0,t.length),l=e[t.length];else if(void 0!==e[t.charAt(0)]){for(n=0;n<t.length;n++)a[t][n]=e[t.charAt(n)];l=e.a}else if(void 0!==e[o[t][0]]){var s=o[t];for(n=0;n<t.length;n++)a[t][n]=e[s[n]];l=e.alpha}if(a.alpha=Math.max(0,Math.min(1,void 0===l?a.alpha:l)),"alpha"===t)return!1;var u;for(n=0;n<t.length;n++)u=Math.max(0,Math.min(r[t][n],a[t][n])),a[t][n]=Math.round(u);for(var d in o)d!==t&&(a[d]=i[t][d](a[t]));return!0},o.prototype.setSpace=function(t,e){var n=e[0];return void 0===n?this.getValues(t):("number"==typeof n&&(n=Array.prototype.slice.call(e)),this.setValues(t,n),this)},o.prototype.setChannel=function(t,e,n){var i=this.values[t];return void 0===n?i[e]:n===i[e]?this:(i[e]=n,this.setValues(t,i),this)},"undefined"!=typeof window&&(window.Color=o),e.exports=o},{2:2,5:5}],4:[function(t,e,n){function i(t){var e,n,i,a=t[0]/255,o=t[1]/255,r=t[2]/255,l=Math.min(a,o,r),s=Math.max(a,o,r),u=s-l;return s==l?e=0:a==s?e=(o-r)/u:o==s?e=2+(r-a)/u:r==s&&(e=4+(a-o)/u),(e=Math.min(60*e,360))<0&&(e+=360),i=(l+s)/2,n=s==l?0:i<=.5?u/(s+l):u/(2-s-l),[e,100*n,100*i]}function a(t){var e,n,i,a=t[0],o=t[1],r=t[2],l=Math.min(a,o,r),s=Math.max(a,o,r),u=s-l;return n=0==s?0:u/s*1e3/10,s==l?e=0:a==s?e=(o-r)/u:o==s?e=2+(r-a)/u:r==s&&(e=4+(a-o)/u),(e=Math.min(60*e,360))<0&&(e+=360),i=s/255*1e3/10,[e,n,i]}function o(t){var e=t[0],n=t[1],a=t[2];return[i(t)[0],100*(1/255*Math.min(e,Math.min(n,a))),100*(a=1-1/255*Math.max(e,Math.max(n,a)))]}function l(t){var e,n,i,a,o=t[0]/255,r=t[1]/255,l=t[2]/255;return a=Math.min(1-o,1-r,1-l),e=(1-o-a)/(1-a)||0,n=(1-r-a)/(1-a)||0,i=(1-l-a)/(1-a)||0,[100*e,100*n,100*i,100*a]}function s(t){return C[JSON.stringify(t)]}function u(t){var e=t[0]/255,n=t[1]/255,i=t[2]/255;return[100*(.4124*(e=e>.04045?Math.pow((e+.055)/1.055,2.4):e/12.92)+.3576*(n=n>.04045?Math.pow((n+.055)/1.055,2.4):n/12.92)+.1805*(i=i>.04045?Math.pow((i+.055)/1.055,2.4):i/12.92)),100*(.2126*e+.7152*n+.0722*i),100*(.0193*e+.1192*n+.9505*i)]}function d(t){var e,n,i,a=u(t),o=a[0],r=a[1],l=a[2];return o/=95.047,r/=100,l/=108.883,o=o>.008856?Math.pow(o,1/3):7.787*o+16/116,r=r>.008856?Math.pow(r,1/3):7.787*r+16/116,l=l>.008856?Math.pow(l,1/3):7.787*l+16/116,e=116*r-16,n=500*(o-r),i=200*(r-l),[e,n,i]}function c(t){var e,n,i,a,o,r=t[0]/360,l=t[1]/100,s=t[2]/100;if(0==l)return o=255*s,[o,o,o];e=2*s-(n=s<.5?s*(1+l):s+l-s*l),a=[0,0,0];for(var u=0;u<3;u++)(i=r+1/3*-(u-1))<0&&i++,i>1&&i--,o=6*i<1?e+6*(n-e)*i:2*i<1?n:3*i<2?e+(n-e)*(2/3-i)*6:e,a[u]=255*o;return a}function h(t){var e=t[0]/60,n=t[1]/100,i=t[2]/100,a=Math.floor(e)%6,o=e-Math.floor(e),r=255*i*(1-n),l=255*i*(1-n*o),s=255*i*(1-n*(1-o)),i=255*i;switch(a){case 0:return[i,s,r];case 1:return[l,i,r];case 2:return[r,i,s];case 3:return[r,l,i];case 4:return[s,r,i];case 5:return[i,r,l]}}function f(t){var e,n,i,a,o=t[0]/360,l=t[1]/100,s=t[2]/100,u=l+s;switch(u>1&&(l/=u,s/=u),e=Math.floor(6*o),n=1-s,i=6*o-e,0!=(1&e)&&(i=1-i),a=l+i*(n-l),e){default:case 6:case 0:r=n,g=a,b=l;break;case 1:r=a,g=n,b=l;break;case 2:r=l,g=n,b=a;break;case 3:r=l,g=a,b=n;break;case 4:r=a,g=l,b=n;break;case 5:r=n,g=l,b=a}return[255*r,255*g,255*b]}function p(t){var e,n,i,a=t[0]/100,o=t[1]/100,r=t[2]/100,l=t[3]/100;return e=1-Math.min(1,a*(1-l)+l),n=1-Math.min(1,o*(1-l)+l),i=1-Math.min(1,r*(1-l)+l),[255*e,255*n,255*i]}function v(t){var e,n,i,a=t[0]/100,o=t[1]/100,r=t[2]/100;return e=3.2406*a+-1.5372*o+-.4986*r,n=-.9689*a+1.8758*o+.0415*r,i=.0557*a+-.204*o+1.057*r,e=e>.0031308?1.055*Math.pow(e,1/2.4)-.055:e*=12.92,n=n>.0031308?1.055*Math.pow(n,1/2.4)-.055:n*=12.92,i=i>.0031308?1.055*Math.pow(i,1/2.4)-.055:i*=12.92,e=Math.min(Math.max(0,e),1),n=Math.min(Math.max(0,n),1),i=Math.min(Math.max(0,i),1),[255*e,255*n,255*i]}function m(t){var e,n,i,a=t[0],o=t[1],r=t[2];return a/=95.047,o/=100,r/=108.883,a=a>.008856?Math.pow(a,1/3):7.787*a+16/116,o=o>.008856?Math.pow(o,1/3):7.787*o+16/116,r=r>.008856?Math.pow(r,1/3):7.787*r+16/116,e=116*o-16,n=500*(a-o),i=200*(o-r),[e,n,i]}function x(t){var e,n,i,a,o=t[0],r=t[1],l=t[2];return o<=8?a=(n=100*o/903.3)/100*7.787+16/116:(n=100*Math.pow((o+16)/116,3),a=Math.pow(n/100,1/3)),e=e/95.047<=.008856?e=95.047*(r/500+a-16/116)/7.787:95.047*Math.pow(r/500+a,3),i=i/108.883<=.008859?i=108.883*(a-l/200-16/116)/7.787:108.883*Math.pow(a-l/200,3),[e,n,i]}function y(t){var e,n,i,a=t[0],o=t[1],r=t[2];return e=Math.atan2(r,o),(n=360*e/2/Math.PI)<0&&(n+=360),i=Math.sqrt(o*o+r*r),[a,i,n]}function k(t){return v(x(t))}function w(t){var e,n,i,a=t[0],o=t[1];return i=t[2]/360*2*Math.PI,e=o*Math.cos(i),n=o*Math.sin(i),[a,e,n]}function M(t){return S[t]}e.exports={rgb2hsl:i,rgb2hsv:a,rgb2hwb:o,rgb2cmyk:l,rgb2keyword:s,rgb2xyz:u,rgb2lab:d,rgb2lch:function(t){return y(d(t))},hsl2rgb:c,hsl2hsv:function(t){var e,n,i=t[0],a=t[1]/100,o=t[2]/100;return 0===o?[0,0,0]:(o*=2,a*=o<=1?o:2-o,n=(o+a)/2,e=2*a/(o+a),[i,100*e,100*n])},hsl2hwb:function(t){return o(c(t))},hsl2cmyk:function(t){return l(c(t))},hsl2keyword:function(t){return s(c(t))},hsv2rgb:h,hsv2hsl:function(t){var e,n,i=t[0],a=t[1]/100,o=t[2]/100;return n=(2-a)*o,e=a*o,e/=n<=1?n:2-n,e=e||0,n/=2,[i,100*e,100*n]},hsv2hwb:function(t){return o(h(t))},hsv2cmyk:function(t){return l(h(t))},hsv2keyword:function(t){return s(h(t))},hwb2rgb:f,hwb2hsl:function(t){return i(f(t))},hwb2hsv:function(t){return a(f(t))},hwb2cmyk:function(t){return l(f(t))},hwb2keyword:function(t){return s(f(t))},cmyk2rgb:p,cmyk2hsl:function(t){return i(p(t))},cmyk2hsv:function(t){return a(p(t))},cmyk2hwb:function(t){return o(p(t))},cmyk2keyword:function(t){return s(p(t))},keyword2rgb:M,keyword2hsl:function(t){return i(M(t))},keyword2hsv:function(t){return a(M(t))},keyword2hwb:function(t){return o(M(t))},keyword2cmyk:function(t){return l(M(t))},keyword2lab:function(t){return d(M(t))},keyword2xyz:function(t){return u(M(t))},xyz2rgb:v,xyz2lab:m,xyz2lch:function(t){return y(m(t))},lab2xyz:x,lab2rgb:k,lab2lch:y,lch2lab:w,lch2xyz:function(t){return x(w(t))},lch2rgb:function(t){return k(w(t))}};var S={aliceblue:[240,248,255],antiquewhite:[250,235,215],aqua:[0,255,255],aquamarine:[127,255,212],azure:[240,255,255],beige:[245,245,220],bisque:[255,228,196],black:[0,0,0],blanchedalmond:[255,235,205],blue:[0,0,255],blueviolet:[138,43,226],brown:[165,42,42],burlywood:[222,184,135],cadetblue:[95,158,160],chartreuse:[127,255,0],chocolate:[210,105,30],coral:[255,127,80],cornflowerblue:[100,149,237],cornsilk:[255,248,220],crimson:[220,20,60],cyan:[0,255,255],darkblue:[0,0,139],darkcyan:[0,139,139],darkgoldenrod:[184,134,11],darkgray:[169,169,169],darkgreen:[0,100,0],darkgrey:[169,169,169],darkkhaki:[189,183,107],darkmagenta:[139,0,139],darkolivegreen:[85,107,47],darkorange:[255,140,0],darkorchid:[153,50,204],darkred:[139,0,0],darksalmon:[233,150,122],darkseagreen:[143,188,143],darkslateblue:[72,61,139],darkslategray:[47,79,79],darkslategrey:[47,79,79],darkturquoise:[0,206,209],darkviolet:[148,0,211],deeppink:[255,20,147],deepskyblue:[0,191,255],dimgray:[105,105,105],dimgrey:[105,105,105],dodgerblue:[30,144,255],firebrick:[178,34,34],floralwhite:[255,250,240],forestgreen:[34,139,34],fuchsia:[255,0,255],gainsboro:[220,220,220],ghostwhite:[248,248,255],gold:[255,215,0],goldenrod:[218,165,32],gray:[128,128,128],green:[0,128,0],greenyellow:[173,255,47],grey:[128,128,128],honeydew:[240,255,240],hotpink:[255,105,180],indianred:[205,92,92],indigo:[75,0,130],ivory:[255,255,240],khaki:[240,230,140],lavender:[230,230,250],lavenderblush:[255,240,245],lawngreen:[124,252,0],lemonchiffon:[255,250,205],lightblue:[173,216,230],lightcoral:[240,128,128],lightcyan:[224,255,255],lightgoldenrodyellow:[250,250,210],lightgray:[211,211,211],lightgreen:[144,238,144],lightgrey:[211,211,211],lightpink:[255,182,193],lightsalmon:[255,160,122],lightseagreen:[32,178,170],lightskyblue:[135,206,250],lightslategray:[119,136,153],lightslategrey:[119,136,153],lightsteelblue:[176,196,222],lightyellow:[255,255,224],lime:[0,255,0],limegreen:[50,205,50],linen:[250,240,230],magenta:[255,0,255],maroon:[128,0,0],mediumaquamarine:[102,205,170],mediumblue:[0,0,205],mediumorchid:[186,85,211],mediumpurple:[147,112,219],mediumseagreen:[60,179,113],mediumslateblue:[123,104,238],mediumspringgreen:[0,250,154],mediumturquoise:[72,209,204],mediumvioletred:[199,21,133],midnightblue:[25,25,112],mintcream:[245,255,250],mistyrose:[255,228,225],moccasin:[255,228,181],navajowhite:[255,222,173],navy:[0,0,128],oldlace:[253,245,230],olive:[128,128,0],olivedrab:[107,142,35],orange:[255,165,0],orangered:[255,69,0],orchid:[218,112,214],palegoldenrod:[238,232,170],palegreen:[152,251,152],paleturquoise:[175,238,238],palevioletred:[219,112,147],papayawhip:[255,239,213],peachpuff:[255,218,185],peru:[205,133,63],pink:[255,192,203],plum:[221,160,221],powderblue:[176,224,230],purple:[128,0,128],rebeccapurple:[102,51,153],red:[255,0,0],rosybrown:[188,143,143],royalblue:[65,105,225],saddlebrown:[139,69,19],salmon:[250,128,114],sandybrown:[244,164,96],seagreen:[46,139,87],seashell:[255,245,238],sienna:[160,82,45],silver:[192,192,192],skyblue:[135,206,235],slateblue:[106,90,205],slategray:[112,128,144],slategrey:[112,128,144],snow:[255,250,250],springgreen:[0,255,127],steelblue:[70,130,180],tan:[210,180,140],teal:[0,128,128],thistle:[216,191,216],tomato:[255,99,71],turquoise:[64,224,208],violet:[238,130,238],wheat:[245,222,179],white:[255,255,255],whitesmoke:[245,245,245],yellow:[255,255,0],yellowgreen:[154,205,50]},C={};for(var _ in S)C[JSON.stringify(S[_])]=_},{}],5:[function(t,e,n){var i=t(4),a=function(){return new u};for(var o in i){a[o+"Raw"]=function(t){return function(e){return"number"==typeof e&&(e=Array.prototype.slice.call(arguments)),i[t](e)}}(o);var r=/(\w+)2(\w+)/.exec(o),l=r[1],s=r[2];(a[l]=a[l]||{})[s]=a[o]=function(t){return function(e){"number"==typeof e&&(e=Array.prototype.slice.call(arguments));var n=i[t](e);if("string"==typeof n||void 0===n)return n;for(var a=0;a<n.length;a++)n[a]=Math.round(n[a]);return n}}(o)}var u=function(){this.convs={}};u.prototype.routeSpace=function(t,e){var n=e[0];return void 0===n?this.getValues(t):("number"==typeof n&&(n=Array.prototype.slice.call(e)),this.setValues(t,n))},u.prototype.setValues=function(t,e){return this.space=t,this.convs={},this.convs[t]=e,this},u.prototype.getValues=function(t){var e=this.convs[t];if(!e){var n=this.space,i=this.convs[n];e=a[n][t](i),this.convs[t]=e}return e},["rgb","hsl","hsv","cmyk","keyword"].forEach(function(t){u.prototype[t]=function(e){return this.routeSpace(t,arguments)}}),e.exports=a},{4:4}],6:[function(t,e,n){"use strict";e.exports={aliceblue:[240,248,255],antiquewhite:[250,235,215],aqua:[0,255,255],aquamarine:[127,255,212],azure:[240,255,255],beige:[245,245,220],bisque:[255,228,196],black:[0,0,0],blanchedalmond:[255,235,205],blue:[0,0,255],blueviolet:[138,43,226],brown:[165,42,42],burlywood:[222,184,135],cadetblue:[95,158,160],chartreuse:[127,255,0],chocolate:[210,105,30],coral:[255,127,80],cornflowerblue:[100,149,237],cornsilk:[255,248,220],crimson:[220,20,60],cyan:[0,255,255],darkblue:[0,0,139],darkcyan:[0,139,139],darkgoldenrod:[184,134,11],darkgray:[169,169,169],darkgreen:[0,100,0],darkgrey:[169,169,169],darkkhaki:[189,183,107],darkmagenta:[139,0,139],darkolivegreen:[85,107,47],darkorange:[255,140,0],darkorchid:[153,50,204],darkred:[139,0,0],darksalmon:[233,150,122],darkseagreen:[143,188,143],darkslateblue:[72,61,139],darkslategray:[47,79,79],darkslategrey:[47,79,79],darkturquoise:[0,206,209],darkviolet:[148,0,211],deeppink:[255,20,147],deepskyblue:[0,191,255],dimgray:[105,105,105],dimgrey:[105,105,105],dodgerblue:[30,144,255],firebrick:[178,34,34],floralwhite:[255,250,240],forestgreen:[34,139,34],fuchsia:[255,0,255],gainsboro:[220,220,220],ghostwhite:[248,248,255],gold:[255,215,0],goldenrod:[218,165,32],gray:[128,128,128],green:[0,128,0],greenyellow:[173,255,47],grey:[128,128,128],honeydew:[240,255,240],hotpink:[255,105,180],indianred:[205,92,92],indigo:[75,0,130],ivory:[255,255,240],khaki:[240,230,140],lavender:[230,230,250],lavenderblush:[255,240,245],lawngreen:[124,252,0],lemonchiffon:[255,250,205],lightblue:[173,216,230],lightcoral:[240,128,128],lightcyan:[224,255,255],lightgoldenrodyellow:[250,250,210],lightgray:[211,211,211],lightgreen:[144,238,144],lightgrey:[211,211,211],lightpink:[255,182,193],lightsalmon:[255,160,122],lightseagreen:[32,178,170],lightskyblue:[135,206,250],lightslategray:[119,136,153],lightslategrey:[119,136,153],lightsteelblue:[176,196,222],lightyellow:[255,255,224],lime:[0,255,0],limegreen:[50,205,50],linen:[250,240,230],magenta:[255,0,255],maroon:[128,0,0],mediumaquamarine:[102,205,170],mediumblue:[0,0,205],mediumorchid:[186,85,211],mediumpurple:[147,112,219],mediumseagreen:[60,179,113],mediumslateblue:[123,104,238],mediumspringgreen:[0,250,154],mediumturquoise:[72,209,204],mediumvioletred:[199,21,133],midnightblue:[25,25,112],mintcream:[245,255,250],mistyrose:[255,228,225],moccasin:[255,228,181],navajowhite:[255,222,173],navy:[0,0,128],oldlace:[253,245,230],olive:[128,128,0],olivedrab:[107,142,35],orange:[255,165,0],orangered:[255,69,0],orchid:[218,112,214],palegoldenrod:[238,232,170],palegreen:[152,251,152],paleturquoise:[175,238,238],palevioletred:[219,112,147],papayawhip:[255,239,213],peachpuff:[255,218,185],peru:[205,133,63],pink:[255,192,203],plum:[221,160,221],powderblue:[176,224,230],purple:[128,0,128],rebeccapurple:[102,51,153],red:[255,0,0],rosybrown:[188,143,143],royalblue:[65,105,225],saddlebrown:[139,69,19],salmon:[250,128,114],sandybrown:[244,164,96],seagreen:[46,139,87],seashell:[255,245,238],sienna:[160,82,45],silver:[192,192,192],skyblue:[135,206,235],slateblue:[106,90,205],slategray:[112,128,144],slategrey:[112,128,144],snow:[255,250,250],springgreen:[0,255,127],steelblue:[70,130,180],tan:[210,180,140],teal:[0,128,128],thistle:[216,191,216],tomato:[255,99,71],turquoise:[64,224,208],violet:[238,130,238],wheat:[245,222,179],white:[255,255,255],whitesmoke:[245,245,245],yellow:[255,255,0],yellowgreen:[154,205,50]}},{}],7:[function(t,e,n){var i=t(29)();i.helpers=t(45),t(27)(i),i.defaults=t(25),i.Element=t(26),i.elements=t(40),i.Interaction=t(28),i.platform=t(48),t(31)(i),t(22)(i),t(23)(i),t(24)(i),t(30)(i),t(33)(i),t(32)(i),t(35)(i),t(54)(i),t(52)(i),t(53)(i),t(55)(i),t(56)(i),t(57)(i),t(15)(i),t(16)(i),t(17)(i),t(18)(i),t(19)(i),t(20)(i),t(21)(i),t(8)(i),t(9)(i),t(10)(i),t(11)(i),t(12)(i),t(13)(i),t(14)(i);var a=[];a.push(t(49)(i),t(50)(i),t(51)(i)),i.plugins.register(a),i.platform.initialize(),e.exports=i,"undefined"!=typeof window&&(window.Chart=i),i.canvasHelpers=i.helpers.canvas},{10:10,11:11,12:12,13:13,14:14,15:15,16:16,17:17,18:18,19:19,20:20,21:21,22:22,23:23,24:24,25:25,26:26,27:27,28:28,29:29,30:30,31:31,32:32,33:33,35:35,40:40,45:45,48:48,49:49,50:50,51:51,52:52,53:53,54:54,55:55,56:56,57:57,8:8,9:9}],8:[function(t,e,n){"use strict";e.exports=function(t){t.Bar=function(e,n){return n.type="bar",new t(e,n)}}},{}],9:[function(t,e,n){"use strict";e.exports=function(t){t.Bubble=function(e,n){return n.type="bubble",new t(e,n)}}},{}],10:[function(t,e,n){"use strict";e.exports=function(t){t.Doughnut=function(e,n){return n.type="doughnut",new t(e,n)}}},{}],11:[function(t,e,n){"use strict";e.exports=function(t){t.Line=function(e,n){return n.type="line",new t(e,n)}}},{}],12:[function(t,e,n){"use strict";e.exports=function(t){t.PolarArea=function(e,n){return n.type="polarArea",new t(e,n)}}},{}],13:[function(t,e,n){"use strict";e.exports=function(t){t.Radar=function(e,n){return n.type="radar",new t(e,n)}}},{}],14:[function(t,e,n){"use strict";e.exports=function(t){t.Scatter=function(e,n){return n.type="scatter",new t(e,n)}}},{}],15:[function(t,e,n){"use strict";var i=t(25),a=t(40),o=t(45);i._set("bar",{hover:{mode:"label"},scales:{xAxes:[{type:"category",categoryPercentage:.8,barPercentage:.9,offset:!0,gridLines:{offsetGridLines:!0}}],yAxes:[{type:"linear"}]}}),i._set("horizontalBar",{hover:{mode:"index",axis:"y"},scales:{xAxes:[{type:"linear",position:"bottom"}],yAxes:[{position:"left",type:"category",categoryPercentage:.8,barPercentage:.9,offset:!0,gridLines:{offsetGridLines:!0}}]},elements:{rectangle:{borderSkipped:"left"}},tooltips:{callbacks:{title:function(t,e){var n="";return t.length>0&&(t[0].yLabel?n=t[0].yLabel:e.labels.length>0&&t[0].index<e.labels.length&&(n=e.labels[t[0].index])),n},label:function(t,e){return(e.datasets[t.datasetIndex].label||"")+": "+t.xLabel}},mode:"index",axis:"y"}}),e.exports=function(t){t.controllers.bar=t.DatasetController.extend({dataElementType:a.Rectangle,initialize:function(){var e,n=this;t.DatasetController.prototype.initialize.apply(n,arguments),(e=n.getMeta()).stack=n.getDataset().stack,e.bar=!0},update:function(t){var e,n,i=this,a=i.getMeta().data;for(i._ruler=i.getRuler(),e=0,n=a.length;e<n;++e)i.updateElement(a[e],e,t)},updateElement:function(t,e,n){var i=this,a=i.chart,r=i.getMeta(),l=i.getDataset(),s=t.custom||{},u=a.options.elements.rectangle;t._xScale=i.getScaleForId(r.xAxisID),t._yScale=i.getScaleForId(r.yAxisID),t._datasetIndex=i.index,t._index=e,t._model={datasetLabel:l.label,label:a.data.labels[e],borderSkipped:s.borderSkipped?s.borderSkipped:u.borderSkipped,backgroundColor:s.backgroundColor?s.backgroundColor:o.valueAtIndexOrDefault(l.backgroundColor,e,u.backgroundColor),borderColor:s.borderColor?s.borderColor:o.valueAtIndexOrDefault(l.borderColor,e,u.borderColor),borderWidth:s.borderWidth?s.borderWidth:o.valueAtIndexOrDefault(l.borderWidth,e,u.borderWidth)},i.updateElementGeometry(t,e,n),t.pivot()},updateElementGeometry:function(t,e,n){var i=this,a=t._model,o=i.getValueScale(),r=o.getBasePixel(),l=o.isHorizontal(),s=i._ruler||i.getRuler(),u=i.calculateBarValuePixels(i.index,e),d=i.calculateBarIndexPixels(i.index,e,s);a.horizontal=l,a.base=n?r:u.base,a.x=l?n?r:u.head:d.center,a.y=l?d.center:n?r:u.head,a.height=l?d.size:void 0,a.width=l?void 0:d.size},getValueScaleId:function(){return this.getMeta().yAxisID},getIndexScaleId:function(){return this.getMeta().xAxisID},getValueScale:function(){return this.getScaleForId(this.getValueScaleId())},getIndexScale:function(){return this.getScaleForId(this.getIndexScaleId())},getStackCount:function(t){var e,n,i=this,a=i.chart,o=i.getIndexScale().options.stacked,r=void 0===t?a.data.datasets.length:t+1,l=[];for(e=0;e<r;++e)(n=a.getDatasetMeta(e)).bar&&a.isDatasetVisible(e)&&(!1===o||!0===o&&-1===l.indexOf(n.stack)||void 0===o&&(void 0===n.stack||-1===l.indexOf(n.stack)))&&l.push(n.stack);return l.length},getStackIndex:function(t){return this.getStackCount(t)-1},getRuler:function(){var t,e,n=this,i=n.getIndexScale(),a=n.getStackCount(),o=n.index,r=[],l=i.isHorizontal(),s=l?i.left:i.top,u=s+(l?i.width:i.height);for(t=0,e=n.getMeta().data.length;t<e;++t)r.push(i.getPixelForValue(null,t,o));return{pixels:r,start:s,end:u,stackCount:a,scale:i}},calculateBarValuePixels:function(t,e){var n,i,a,o,r,l,s=this,u=s.chart,d=s.getMeta(),c=s.getValueScale(),h=u.data.datasets,f=c.getRightValue(h[t].data[e]),g=c.options.stacked,p=d.stack,v=0;if(g||void 0===g&&void 0!==p)for(n=0;n<t;++n)(i=u.getDatasetMeta(n)).bar&&i.stack===p&&i.controller.getValueScaleId()===c.id&&u.isDatasetVisible(n)&&(a=c.getRightValue(h[n].data[e]),(f<0&&a<0||f>=0&&a>0)&&(v+=a));return o=c.getPixelForValue(v),r=c.getPixelForValue(v+f),l=(r-o)/2,{size:l,base:o,head:r,center:r+l/2}},calculateBarIndexPixels:function(t,e,n){var i,a,r,l,s,u,d=this,c=n.scale.options,h=d.getStackIndex(t),f=n.pixels,g=f[e],p=f.length,v=n.start,m=n.end;return 1===p?(i=g>v?g-v:m-g,a=g<m?m-g:g-v):(e>0&&(i=(g-f[e-1])/2,e===p-1&&(a=i)),e<p-1&&(a=(f[e+1]-g)/2,0===e&&(i=a))),r=i*c.categoryPercentage,l=a*c.categoryPercentage,s=(r+l)/n.stackCount,u=s*c.barPercentage,u=Math.min(o.valueOrDefault(c.barThickness,u),o.valueOrDefault(c.maxBarThickness,1/0)),g-=r,g+=s*h,g+=(s-u)/2,{size:u,base:g,head:g+u,center:g+u/2}},draw:function(){var t=this,e=t.chart,n=t.getValueScale(),i=t.getMeta().data,a=t.getDataset(),r=i.length,l=0;for(o.canvas.clipArea(e.ctx,e.chartArea);l<r;++l)isNaN(n.getRightValue(a.data[l]))||i[l].draw();o.canvas.unclipArea(e.ctx)},setHoverStyle:function(t){var e=this.chart.data.datasets[t._datasetIndex],n=t._index,i=t.custom||{},a=t._model;a.backgroundColor=i.hoverBackgroundColor?i.hoverBackgroundColor:o.valueAtIndexOrDefault(e.hoverBackgroundColor,n,o.getHoverColor(a.backgroundColor)),a.borderColor=i.hoverBorderColor?i.hoverBorderColor:o.valueAtIndexOrDefault(e.hoverBorderColor,n,o.getHoverColor(a.borderColor)),a.borderWidth=i.hoverBorderWidth?i.hoverBorderWidth:o.valueAtIndexOrDefault(e.hoverBorderWidth,n,a.borderWidth)},removeHoverStyle:function(t){var e=this.chart.data.datasets[t._datasetIndex],n=t._index,i=t.custom||{},a=t._model,r=this.chart.options.elements.rectangle;a.backgroundColor=i.backgroundColor?i.backgroundColor:o.valueAtIndexOrDefault(e.backgroundColor,n,r.backgroundColor),a.borderColor=i.borderColor?i.borderColor:o.valueAtIndexOrDefault(e.borderColor,n,r.borderColor),a.borderWidth=i.borderWidth?i.borderWidth:o.valueAtIndexOrDefault(e.borderWidth,n,r.borderWidth)}}),t.controllers.horizontalBar=t.controllers.bar.extend({getValueScaleId:function(){return this.getMeta().xAxisID},getIndexScaleId:function(){return this.getMeta().yAxisID}})}},{25:25,40:40,45:45}],16:[function(t,e,n){"use strict";var i=t(25),a=t(40),o=t(45);i._set("bubble",{hover:{mode:"single"},scales:{xAxes:[{type:"linear",position:"bottom",id:"x-axis-0"}],yAxes:[{type:"linear",position:"left",id:"y-axis-0"}]},tooltips:{callbacks:{title:function(){return""},label:function(t,e){var n=e.datasets[t.datasetIndex].label||"",i=e.datasets[t.datasetIndex].data[t.index];return n+": ("+t.xLabel+", "+t.yLabel+", "+i.r+")"}}}}),e.exports=function(t){t.controllers.bubble=t.DatasetController.extend({dataElementType:a.Point,update:function(t){var e=this,n=e.getMeta().data;o.each(n,function(n,i){e.updateElement(n,i,t)})},updateElement:function(t,e,n){var i=this,a=i.getMeta(),o=t.custom||{},r=i.getScaleForId(a.xAxisID),l=i.getScaleForId(a.yAxisID),s=i._resolveElementOptions(t,e),u=i.getDataset().data[e],d=i.index,c=n?r.getPixelForDecimal(.5):r.getPixelForValue("object"==typeof u?u:NaN,e,d),h=n?l.getBasePixel():l.getPixelForValue(u,e,d);t._xScale=r,t._yScale=l,t._options=s,t._datasetIndex=d,t._index=e,t._model={backgroundColor:s.backgroundColor,borderColor:s.borderColor,borderWidth:s.borderWidth,hitRadius:s.hitRadius,pointStyle:s.pointStyle,radius:n?0:s.radius,skip:o.skip||isNaN(c)||isNaN(h),x:c,y:h},t.pivot()},setHoverStyle:function(t){var e=t._model,n=t._options;e.backgroundColor=o.valueOrDefault(n.hoverBackgroundColor,o.getHoverColor(n.backgroundColor)),e.borderColor=o.valueOrDefault(n.hoverBorderColor,o.getHoverColor(n.borderColor)),e.borderWidth=o.valueOrDefault(n.hoverBorderWidth,n.borderWidth),e.radius=n.radius+n.hoverRadius},removeHoverStyle:function(t){var e=t._model,n=t._options;e.backgroundColor=n.backgroundColor,e.borderColor=n.borderColor,e.borderWidth=n.borderWidth,e.radius=n.radius},_resolveElementOptions:function(t,e){var n,i,a,r=this,l=r.chart,s=l.data.datasets[r.index],u=t.custom||{},d=l.options.elements.point,c=o.options.resolve,h=s.data[e],f={},g={chart:l,dataIndex:e,dataset:s,datasetIndex:r.index},p=["backgroundColor","borderColor","borderWidth","hoverBackgroundColor","hoverBorderColor","hoverBorderWidth","hoverRadius","hitRadius","pointStyle"];for(n=0,i=p.length;n<i;++n)f[a=p[n]]=c([u[a],s[a],d[a]],g,e);return f.radius=c([u.radius,h?h.r:void 0,s.radius,d.radius],g,e),f}})}},{25:25,40:40,45:45}],17:[function(t,e,n){"use strict";var i=t(25),a=t(40),o=t(45);i._set("doughnut",{animation:{animateRotate:!0,animateScale:!1},hover:{mode:"single"},legendCallback:function(t){var e=[];e.push('<ul class="'+t.id+'-legend">');var n=t.data,i=n.datasets,a=n.labels;if(i.length)for(var o=0;o<i[0].data.length;++o)e.push('<li><span style="background-color:'+i[0].backgroundColor[o]+'"></span>'),a[o]&&e.push(a[o]),e.push("</li>");return e.push("</ul>"),e.join("")},legend:{labels:{generateLabels:function(t){var e=t.data;return e.labels.length&&e.datasets.length?e.labels.map(function(n,i){var a=t.getDatasetMeta(0),r=e.datasets[0],l=a.data[i],s=l&&l.custom||{},u=o.valueAtIndexOrDefault,d=t.options.elements.arc;return{text:n,fillStyle:s.backgroundColor?s.backgroundColor:u(r.backgroundColor,i,d.backgroundColor),strokeStyle:s.borderColor?s.borderColor:u(r.borderColor,i,d.borderColor),lineWidth:s.borderWidth?s.borderWidth:u(r.borderWidth,i,d.borderWidth),hidden:isNaN(r.data[i])||a.data[i].hidden,index:i}}):[]}},onClick:function(t,e){var n,i,a,o=e.index,r=this.chart;for(n=0,i=(r.data.datasets||[]).length;n<i;++n)(a=r.getDatasetMeta(n)).data[o]&&(a.data[o].hidden=!a.data[o].hidden);r.update()}},cutoutPercentage:50,rotation:-.5*Math.PI,circumference:2*Math.PI,tooltips:{callbacks:{title:function(){return""},label:function(t,e){var n=e.labels[t.index],i=": "+e.datasets[t.datasetIndex].data[t.index];return o.isArray(n)?(n=n.slice())[0]+=i:n+=i,n}}}}),i._set("pie",o.clone(i.doughnut)),i._set("pie",{cutoutPercentage:0}),e.exports=function(t){t.controllers.doughnut=t.controllers.pie=t.DatasetController.extend({dataElementType:a.Arc,linkScales:o.noop,getRingIndex:function(t){for(var e=0,n=0;n<t;++n)this.chart.isDatasetVisible(n)&&++e;return e},update:function(t){var e=this,n=e.chart,i=n.chartArea,a=n.options,r=a.elements.arc,l=i.right-i.left-r.borderWidth,s=i.bottom-i.top-r.borderWidth,u=Math.min(l,s),d={x:0,y:0},c=e.getMeta(),h=a.cutoutPercentage,f=a.circumference;if(f<2*Math.PI){var g=a.rotation%(2*Math.PI),p=(g+=2*Math.PI*(g>=Math.PI?-1:g<-Math.PI?1:0))+f,v={x:Math.cos(g),y:Math.sin(g)},m={x:Math.cos(p),y:Math.sin(p)},b=g<=0&&p>=0||g<=2*Math.PI&&2*Math.PI<=p,x=g<=.5*Math.PI&&.5*Math.PI<=p||g<=2.5*Math.PI&&2.5*Math.PI<=p,y=g<=-Math.PI&&-Math.PI<=p||g<=Math.PI&&Math.PI<=p,k=g<=.5*-Math.PI&&.5*-Math.PI<=p||g<=1.5*Math.PI&&1.5*Math.PI<=p,w=h/100,M={x:y?-1:Math.min(v.x*(v.x<0?1:w),m.x*(m.x<0?1:w)),y:k?-1:Math.min(v.y*(v.y<0?1:w),m.y*(m.y<0?1:w))},S={x:b?1:Math.max(v.x*(v.x>0?1:w),m.x*(m.x>0?1:w)),y:x?1:Math.max(v.y*(v.y>0?1:w),m.y*(m.y>0?1:w))},C={width:.5*(S.x-M.x),height:.5*(S.y-M.y)};u=Math.min(l/C.width,s/C.height),d={x:-.5*(S.x+M.x),y:-.5*(S.y+M.y)}}n.borderWidth=e.getMaxBorderWidth(c.data),n.outerRadius=Math.max((u-n.borderWidth)/2,0),n.innerRadius=Math.max(h?n.outerRadius/100*h:0,0),n.radiusLength=(n.outerRadius-n.innerRadius)/n.getVisibleDatasetCount(),n.offsetX=d.x*n.outerRadius,n.offsetY=d.y*n.outerRadius,c.total=e.calculateTotal(),e.outerRadius=n.outerRadius-n.radiusLength*e.getRingIndex(e.index),e.innerRadius=Math.max(e.outerRadius-n.radiusLength,0),o.each(c.data,function(n,i){e.updateElement(n,i,t)})},updateElement:function(t,e,n){var i=this,a=i.chart,r=a.chartArea,l=a.options,s=l.animation,u=(r.left+r.right)/2,d=(r.top+r.bottom)/2,c=l.rotation,h=l.rotation,f=i.getDataset(),g=n&&s.animateRotate?0:t.hidden?0:i.calculateCircumference(f.data[e])*(l.circumference/(2*Math.PI)),p=n&&s.animateScale?0:i.innerRadius,v=n&&s.animateScale?0:i.outerRadius,m=o.valueAtIndexOrDefault;o.extend(t,{_datasetIndex:i.index,_index:e,_model:{x:u+a.offsetX,y:d+a.offsetY,startAngle:c,endAngle:h,circumference:g,outerRadius:v,innerRadius:p,label:m(f.label,e,a.data.labels[e])}});var b=t._model;this.removeHoverStyle(t),n&&s.animateRotate||(b.startAngle=0===e?l.rotation:i.getMeta().data[e-1]._model.endAngle,b.endAngle=b.startAngle+b.circumference),t.pivot()},removeHoverStyle:function(e){t.DatasetController.prototype.removeHoverStyle.call(this,e,this.chart.options.elements.arc)},calculateTotal:function(){var t,e=this.getDataset(),n=this.getMeta(),i=0;return o.each(n.data,function(n,a){t=e.data[a],isNaN(t)||n.hidden||(i+=Math.abs(t))}),i},calculateCircumference:function(t){var e=this.getMeta().total;return e>0&&!isNaN(t)?2*Math.PI*(t/e):0},getMaxBorderWidth:function(t){for(var e,n,i=0,a=this.index,o=t.length,r=0;r<o;r++)e=t[r]._model?t[r]._model.borderWidth:0,i=(n=t[r]._chart?t[r]._chart.config.data.datasets[a].hoverBorderWidth:0)>(i=e>i?e:i)?n:i;return i}})}},{25:25,40:40,45:45}],18:[function(t,e,n){"use strict";var i=t(25),a=t(40),o=t(45);i._set("line",{showLines:!0,spanGaps:!1,hover:{mode:"label"},scales:{xAxes:[{type:"category",id:"x-axis-0"}],yAxes:[{type:"linear",id:"y-axis-0"}]}}),e.exports=function(t){function e(t,e){return o.valueOrDefault(t.showLine,e.showLines)}t.controllers.line=t.DatasetController.extend({datasetElementType:a.Line,dataElementType:a.Point,update:function(t){var n,i,a,r=this,l=r.getMeta(),s=l.dataset,u=l.data||[],d=r.chart.options,c=d.elements.line,h=r.getScaleForId(l.yAxisID),f=r.getDataset(),g=e(f,d);for(g&&(a=s.custom||{},void 0!==f.tension&&void 0===f.lineTension&&(f.lineTension=f.tension),s._scale=h,s._datasetIndex=r.index,s._children=u,s._model={spanGaps:f.spanGaps?f.spanGaps:d.spanGaps,tension:a.tension?a.tension:o.valueOrDefault(f.lineTension,c.tension),backgroundColor:a.backgroundColor?a.backgroundColor:f.backgroundColor||c.backgroundColor,borderWidth:a.borderWidth?a.borderWidth:f.borderWidth||c.borderWidth,borderColor:a.borderColor?a.borderColor:f.borderColor||c.borderColor,borderCapStyle:a.borderCapStyle?a.borderCapStyle:f.borderCapStyle||c.borderCapStyle,borderDash:a.borderDash?a.borderDash:f.borderDash||c.borderDash,borderDashOffset:a.borderDashOffset?a.borderDashOffset:f.borderDashOffset||c.borderDashOffset,borderJoinStyle:a.borderJoinStyle?a.borderJoinStyle:f.borderJoinStyle||c.borderJoinStyle,fill:a.fill?a.fill:void 0!==f.fill?f.fill:c.fill,steppedLine:a.steppedLine?a.steppedLine:o.valueOrDefault(f.steppedLine,c.stepped),cubicInterpolationMode:a.cubicInterpolationMode?a.cubicInterpolationMode:o.valueOrDefault(f.cubicInterpolationMode,c.cubicInterpolationMode)},s.pivot()),n=0,i=u.length;n<i;++n)r.updateElement(u[n],n,t);for(g&&0!==s._model.tension&&r.updateBezierControlPoints(),n=0,i=u.length;n<i;++n)u[n].pivot()},getPointBackgroundColor:function(t,e){var n=this.chart.options.elements.point.backgroundColor,i=this.getDataset(),a=t.custom||{};return a.backgroundColor?n=a.backgroundColor:i.pointBackgroundColor?n=o.valueAtIndexOrDefault(i.pointBackgroundColor,e,n):i.backgroundColor&&(n=i.backgroundColor),n},getPointBorderColor:function(t,e){var n=this.chart.options.elements.point.borderColor,i=this.getDataset(),a=t.custom||{};return a.borderColor?n=a.borderColor:i.pointBorderColor?n=o.valueAtIndexOrDefault(i.pointBorderColor,e,n):i.borderColor&&(n=i.borderColor),n},getPointBorderWidth:function(t,e){var n=this.chart.options.elements.point.borderWidth,i=this.getDataset(),a=t.custom||{};return isNaN(a.borderWidth)?!isNaN(i.pointBorderWidth)||o.isArray(i.pointBorderWidth)?n=o.valueAtIndexOrDefault(i.pointBorderWidth,e,n):isNaN(i.borderWidth)||(n=i.borderWidth):n=a.borderWidth,n},updateElement:function(t,e,n){var i,a,r=this,l=r.getMeta(),s=t.custom||{},u=r.getDataset(),d=r.index,c=u.data[e],h=r.getScaleForId(l.yAxisID),f=r.getScaleForId(l.xAxisID),g=r.chart.options.elements.point;void 0!==u.radius&&void 0===u.pointRadius&&(u.pointRadius=u.radius),void 0!==u.hitRadius&&void 0===u.pointHitRadius&&(u.pointHitRadius=u.hitRadius),i=f.getPixelForValue("object"==typeof c?c:NaN,e,d),a=n?h.getBasePixel():r.calculatePointY(c,e,d),t._xScale=f,t._yScale=h,t._datasetIndex=d,t._index=e,t._model={x:i,y:a,skip:s.skip||isNaN(i)||isNaN(a),radius:s.radius||o.valueAtIndexOrDefault(u.pointRadius,e,g.radius),pointStyle:s.pointStyle||o.valueAtIndexOrDefault(u.pointStyle,e,g.pointStyle),backgroundColor:r.getPointBackgroundColor(t,e),borderColor:r.getPointBorderColor(t,e),borderWidth:r.getPointBorderWidth(t,e),tension:l.dataset._model?l.dataset._model.tension:0,steppedLine:!!l.dataset._model&&l.dataset._model.steppedLine,hitRadius:s.hitRadius||o.valueAtIndexOrDefault(u.pointHitRadius,e,g.hitRadius)}},calculatePointY:function(t,e,n){var i,a,o,r=this,l=r.chart,s=r.getMeta(),u=r.getScaleForId(s.yAxisID),d=0,c=0;if(u.options.stacked){for(i=0;i<n;i++)if(a=l.data.datasets[i],"line"===(o=l.getDatasetMeta(i)).type&&o.yAxisID===u.id&&l.isDatasetVisible(i)){var h=Number(u.getRightValue(a.data[e]));h<0?c+=h||0:d+=h||0}var f=Number(u.getRightValue(t));return f<0?u.getPixelForValue(c+f):u.getPixelForValue(d+f)}return u.getPixelForValue(t)},updateBezierControlPoints:function(){function t(t,e,n){return Math.max(Math.min(t,n),e)}var e,n,i,a,r=this,l=r.getMeta(),s=r.chart.chartArea,u=l.data||[];if(l.dataset._model.spanGaps&&(u=u.filter(function(t){return!t._model.skip})),"monotone"===l.dataset._model.cubicInterpolationMode)o.splineCurveMonotone(u);else for(e=0,n=u.length;e<n;++e)i=u[e]._model,a=o.splineCurve(o.previousItem(u,e)._model,i,o.nextItem(u,e)._model,l.dataset._model.tension),i.controlPointPreviousX=a.previous.x,i.controlPointPreviousY=a.previous.y,i.controlPointNextX=a.next.x,i.controlPointNextY=a.next.y;if(r.chart.options.elements.line.capBezierPoints)for(e=0,n=u.length;e<n;++e)(i=u[e]._model).controlPointPreviousX=t(i.controlPointPreviousX,s.left,s.right),i.controlPointPreviousY=t(i.controlPointPreviousY,s.top,s.bottom),i.controlPointNextX=t(i.controlPointNextX,s.left,s.right),i.controlPointNextY=t(i.controlPointNextY,s.top,s.bottom)},draw:function(){var t=this,n=t.chart,i=t.getMeta(),a=i.data||[],r=n.chartArea,l=a.length,s=0;for(o.canvas.clipArea(n.ctx,r),e(t.getDataset(),n.options)&&i.dataset.draw(),o.canvas.unclipArea(n.ctx);s<l;++s)a[s].draw(r)},setHoverStyle:function(t){var e=this.chart.data.datasets[t._datasetIndex],n=t._index,i=t.custom||{},a=t._model;a.radius=i.hoverRadius||o.valueAtIndexOrDefault(e.pointHoverRadius,n,this.chart.options.elements.point.hoverRadius),a.backgroundColor=i.hoverBackgroundColor||o.valueAtIndexOrDefault(e.pointHoverBackgroundColor,n,o.getHoverColor(a.backgroundColor)),a.borderColor=i.hoverBorderColor||o.valueAtIndexOrDefault(e.pointHoverBorderColor,n,o.getHoverColor(a.borderColor)),a.borderWidth=i.hoverBorderWidth||o.valueAtIndexOrDefault(e.pointHoverBorderWidth,n,a.borderWidth)},removeHoverStyle:function(t){var e=this,n=e.chart.data.datasets[t._datasetIndex],i=t._index,a=t.custom||{},r=t._model;void 0!==n.radius&&void 0===n.pointRadius&&(n.pointRadius=n.radius),r.radius=a.radius||o.valueAtIndexOrDefault(n.pointRadius,i,e.chart.options.elements.point.radius),r.backgroundColor=e.getPointBackgroundColor(t,i),r.borderColor=e.getPointBorderColor(t,i),r.borderWidth=e.getPointBorderWidth(t,i)}})}},{25:25,40:40,45:45}],19:[function(t,e,n){"use strict";var i=t(25),a=t(40),o=t(45);i._set("polarArea",{scale:{type:"radialLinear",angleLines:{display:!1},gridLines:{circular:!0},pointLabels:{display:!1},ticks:{beginAtZero:!0}},animation:{animateRotate:!0,animateScale:!0},startAngle:-.5*Math.PI,legendCallback:function(t){var e=[];e.push('<ul class="'+t.id+'-legend">');var n=t.data,i=n.datasets,a=n.labels;if(i.length)for(var o=0;o<i[0].data.length;++o)e.push('<li><span style="background-color:'+i[0].backgroundColor[o]+'"></span>'),a[o]&&e.push(a[o]),e.push("</li>");return e.push("</ul>"),e.join("")},legend:{labels:{generateLabels:function(t){var e=t.data;return e.labels.length&&e.datasets.length?e.labels.map(function(n,i){var a=t.getDatasetMeta(0),r=e.datasets[0],l=a.data[i].custom||{},s=o.valueAtIndexOrDefault,u=t.options.elements.arc;return{text:n,fillStyle:l.backgroundColor?l.backgroundColor:s(r.backgroundColor,i,u.backgroundColor),strokeStyle:l.borderColor?l.borderColor:s(r.borderColor,i,u.borderColor),lineWidth:l.borderWidth?l.borderWidth:s(r.borderWidth,i,u.borderWidth),hidden:isNaN(r.data[i])||a.data[i].hidden,index:i}}):[]}},onClick:function(t,e){var n,i,a,o=e.index,r=this.chart;for(n=0,i=(r.data.datasets||[]).length;n<i;++n)(a=r.getDatasetMeta(n)).data[o].hidden=!a.data[o].hidden;r.update()}},tooltips:{callbacks:{title:function(){return""},label:function(t,e){return e.labels[t.index]+": "+t.yLabel}}}}),e.exports=function(t){t.controllers.polarArea=t.DatasetController.extend({dataElementType:a.Arc,linkScales:o.noop,update:function(t){var e=this,n=e.chart,i=n.chartArea,a=e.getMeta(),r=n.options,l=r.elements.arc,s=Math.min(i.right-i.left,i.bottom-i.top);n.outerRadius=Math.max((s-l.borderWidth/2)/2,0),n.innerRadius=Math.max(r.cutoutPercentage?n.outerRadius/100*r.cutoutPercentage:1,0),n.radiusLength=(n.outerRadius-n.innerRadius)/n.getVisibleDatasetCount(),e.outerRadius=n.outerRadius-n.radiusLength*e.index,e.innerRadius=e.outerRadius-n.radiusLength,a.count=e.countVisibleElements(),o.each(a.data,function(n,i){e.updateElement(n,i,t)})},updateElement:function(t,e,n){for(var i=this,a=i.chart,r=i.getDataset(),l=a.options,s=l.animation,u=a.scale,d=a.data.labels,c=i.calculateCircumference(r.data[e]),h=u.xCenter,f=u.yCenter,g=0,p=i.getMeta(),v=0;v<e;++v)isNaN(r.data[v])||p.data[v].hidden||++g;var m=l.startAngle,b=t.hidden?0:u.getDistanceFromCenterForValue(r.data[e]),x=m+c*g,y=x+(t.hidden?0:c),k=s.animateScale?0:u.getDistanceFromCenterForValue(r.data[e]);o.extend(t,{_datasetIndex:i.index,_index:e,_scale:u,_model:{x:h,y:f,innerRadius:0,outerRadius:n?k:b,startAngle:n&&s.animateRotate?m:x,endAngle:n&&s.animateRotate?m:y,label:o.valueAtIndexOrDefault(d,e,d[e])}}),i.removeHoverStyle(t),t.pivot()},removeHoverStyle:function(e){t.DatasetController.prototype.removeHoverStyle.call(this,e,this.chart.options.elements.arc)},countVisibleElements:function(){var t=this.getDataset(),e=this.getMeta(),n=0;return o.each(e.data,function(e,i){isNaN(t.data[i])||e.hidden||n++}),n},calculateCircumference:function(t){var e=this.getMeta().count;return e>0&&!isNaN(t)?2*Math.PI/e:0}})}},{25:25,40:40,45:45}],20:[function(t,e,n){"use strict";var i=t(25),a=t(40),o=t(45);i._set("radar",{scale:{type:"radialLinear"},elements:{line:{tension:0}}}),e.exports=function(t){t.controllers.radar=t.DatasetController.extend({datasetElementType:a.Line,dataElementType:a.Point,linkScales:o.noop,update:function(t){var e=this,n=e.getMeta(),i=n.dataset,a=n.data,r=i.custom||{},l=e.getDataset(),s=e.chart.options.elements.line,u=e.chart.scale;void 0!==l.tension&&void 0===l.lineTension&&(l.lineTension=l.tension),o.extend(n.dataset,{_datasetIndex:e.index,_scale:u,_children:a,_loop:!0,_model:{tension:r.tension?r.tension:o.valueOrDefault(l.lineTension,s.tension),backgroundColor:r.backgroundColor?r.backgroundColor:l.backgroundColor||s.backgroundColor,borderWidth:r.borderWidth?r.borderWidth:l.borderWidth||s.borderWidth,borderColor:r.borderColor?r.borderColor:l.borderColor||s.borderColor,fill:r.fill?r.fill:void 0!==l.fill?l.fill:s.fill,borderCapStyle:r.borderCapStyle?r.borderCapStyle:l.borderCapStyle||s.borderCapStyle,borderDash:r.borderDash?r.borderDash:l.borderDash||s.borderDash,borderDashOffset:r.borderDashOffset?r.borderDashOffset:l.borderDashOffset||s.borderDashOffset,borderJoinStyle:r.borderJoinStyle?r.borderJoinStyle:l.borderJoinStyle||s.borderJoinStyle}}),n.dataset.pivot(),o.each(a,function(n,i){e.updateElement(n,i,t)},e),e.updateBezierControlPoints()},updateElement:function(t,e,n){var i=this,a=t.custom||{},r=i.getDataset(),l=i.chart.scale,s=i.chart.options.elements.point,u=l.getPointPositionForValue(e,r.data[e]);void 0!==r.radius&&void 0===r.pointRadius&&(r.pointRadius=r.radius),void 0!==r.hitRadius&&void 0===r.pointHitRadius&&(r.pointHitRadius=r.hitRadius),o.extend(t,{_datasetIndex:i.index,_index:e,_scale:l,_model:{x:n?l.xCenter:u.x,y:n?l.yCenter:u.y,tension:a.tension?a.tension:o.valueOrDefault(r.lineTension,i.chart.options.elements.line.tension),radius:a.radius?a.radius:o.valueAtIndexOrDefault(r.pointRadius,e,s.radius),backgroundColor:a.backgroundColor?a.backgroundColor:o.valueAtIndexOrDefault(r.pointBackgroundColor,e,s.backgroundColor),borderColor:a.borderColor?a.borderColor:o.valueAtIndexOrDefault(r.pointBorderColor,e,s.borderColor),borderWidth:a.borderWidth?a.borderWidth:o.valueAtIndexOrDefault(r.pointBorderWidth,e,s.borderWidth),pointStyle:a.pointStyle?a.pointStyle:o.valueAtIndexOrDefault(r.pointStyle,e,s.pointStyle),hitRadius:a.hitRadius?a.hitRadius:o.valueAtIndexOrDefault(r.pointHitRadius,e,s.hitRadius)}}),t._model.skip=a.skip?a.skip:isNaN(t._model.x)||isNaN(t._model.y)},updateBezierControlPoints:function(){var t=this.chart.chartArea,e=this.getMeta();o.each(e.data,function(n,i){var a=n._model,r=o.splineCurve(o.previousItem(e.data,i,!0)._model,a,o.nextItem(e.data,i,!0)._model,a.tension);a.controlPointPreviousX=Math.max(Math.min(r.previous.x,t.right),t.left),a.controlPointPreviousY=Math.max(Math.min(r.previous.y,t.bottom),t.top),a.controlPointNextX=Math.max(Math.min(r.next.x,t.right),t.left),a.controlPointNextY=Math.max(Math.min(r.next.y,t.bottom),t.top),n.pivot()})},setHoverStyle:function(t){var e=this.chart.data.datasets[t._datasetIndex],n=t.custom||{},i=t._index,a=t._model;a.radius=n.hoverRadius?n.hoverRadius:o.valueAtIndexOrDefault(e.pointHoverRadius,i,this.chart.options.elements.point.hoverRadius),a.backgroundColor=n.hoverBackgroundColor?n.hoverBackgroundColor:o.valueAtIndexOrDefault(e.pointHoverBackgroundColor,i,o.getHoverColor(a.backgroundColor)),a.borderColor=n.hoverBorderColor?n.hoverBorderColor:o.valueAtIndexOrDefault(e.pointHoverBorderColor,i,o.getHoverColor(a.borderColor)),a.borderWidth=n.hoverBorderWidth?n.hoverBorderWidth:o.valueAtIndexOrDefault(e.pointHoverBorderWidth,i,a.borderWidth)},removeHoverStyle:function(t){var e=this.chart.data.datasets[t._datasetIndex],n=t.custom||{},i=t._index,a=t._model,r=this.chart.options.elements.point;a.radius=n.radius?n.radius:o.valueAtIndexOrDefault(e.pointRadius,i,r.radius),a.backgroundColor=n.backgroundColor?n.backgroundColor:o.valueAtIndexOrDefault(e.pointBackgroundColor,i,r.backgroundColor),a.borderColor=n.borderColor?n.borderColor:o.valueAtIndexOrDefault(e.pointBorderColor,i,r.borderColor),a.borderWidth=n.borderWidth?n.borderWidth:o.valueAtIndexOrDefault(e.pointBorderWidth,i,r.borderWidth)}})}},{25:25,40:40,45:45}],21:[function(t,e,n){"use strict";t(25)._set("scatter",{hover:{mode:"single"},scales:{xAxes:[{id:"x-axis-1",type:"linear",position:"bottom"}],yAxes:[{id:"y-axis-1",type:"linear",position:"left"}]},showLines:!1,tooltips:{callbacks:{title:function(){return""},label:function(t){return"("+t.xLabel+", "+t.yLabel+")"}}}}),e.exports=function(t){t.controllers.scatter=t.controllers.line}},{25:25}],22:[function(t,e,n){"use strict";var i=t(25),a=t(26),o=t(45);i._set("global",{animation:{duration:1e3,easing:"easeOutQuart",onProgress:o.noop,onComplete:o.noop}}),e.exports=function(t){t.Animation=a.extend({chart:null,currentStep:0,numSteps:60,easing:"",render:null,onAnimationProgress:null,onAnimationComplete:null}),t.animationService={frameDuration:17,animations:[],dropFrames:0,request:null,addAnimation:function(t,e,n,i){var a,o,r=this.animations;for(e.chart=t,i||(t.animating=!0),a=0,o=r.length;a<o;++a)if(r[a].chart===t)return void(r[a]=e);r.push(e),1===r.length&&this.requestAnimationFrame()},cancelAnimation:function(t){var e=o.findIndex(this.animations,function(e){return e.chart===t});-1!==e&&(this.animations.splice(e,1),t.animating=!1)},requestAnimationFrame:function(){var t=this;null===t.request&&(t.request=o.requestAnimFrame.call(window,function(){t.request=null,t.startDigest()}))},startDigest:function(){var t=this,e=Date.now(),n=0;t.dropFrames>1&&(n=Math.floor(t.dropFrames),t.dropFrames=t.dropFrames%1),t.advance(1+n);var i=Date.now();t.dropFrames+=(i-e)/t.frameDuration,t.animations.length>0&&t.requestAnimationFrame()},advance:function(t){for(var e,n,i=this.animations,a=0;a<i.length;)n=(e=i[a]).chart,e.currentStep=(e.currentStep||0)+t,e.currentStep=Math.min(e.currentStep,e.numSteps),o.callback(e.render,[n,e],n),o.callback(e.onAnimationProgress,[e],n),e.currentStep>=e.numSteps?(o.callback(e.onAnimationComplete,[e],n),n.animating=!1,i.splice(a,1)):++a}},Object.defineProperty(t.Animation.prototype,"animationObject",{get:function(){return this}}),Object.defineProperty(t.Animation.prototype,"chartInstance",{get:function(){return this.chart},set:function(t){this.chart=t}})}},{25:25,26:26,45:45}],23:[function(t,e,n){"use strict";var i=t(25),a=t(45),o=t(28),r=t(48);e.exports=function(t){function e(t){var e=(t=t||{}).data=t.data||{};return e.datasets=e.datasets||[],e.labels=e.labels||[],t.options=a.configMerge(i.global,i[t.type],t.options||{}),t}function n(t){var e=t.options;e.scale?t.scale.options=e.scale:e.scales&&e.scales.xAxes.concat(e.scales.yAxes).forEach(function(e){t.scales[e.id].options=e}),t.tooltip._options=e.tooltips}function l(t){return"top"===t||"bottom"===t}var s=t.plugins;t.types={},t.instances={},t.controllers={},a.extend(t.prototype,{construct:function(n,i){var o=this;i=e(i);var l=r.acquireContext(n,i),s=l&&l.canvas,u=s&&s.height,d=s&&s.width;o.id=a.uid(),o.ctx=l,o.canvas=s,o.config=i,o.width=d,o.height=u,o.aspectRatio=u?d/u:null,o.options=i.options,o._bufferedRender=!1,o.chart=o,o.controller=o,t.instances[o.id]=o,Object.defineProperty(o,"data",{get:function(){return o.config.data},set:function(t){o.config.data=t}}),l&&s?(o.initialize(),o.update()):console.error("Failed to create chart: can't acquire context from the given item")},initialize:function(){var t=this;return s.notify(t,"beforeInit"),a.retinaScale(t,t.options.devicePixelRatio),t.bindEvents(),t.options.responsive&&t.resize(!0),t.ensureScalesHaveIDs(),t.buildScales(),t.initToolTip(),s.notify(t,"afterInit"),t},clear:function(){return a.canvas.clear(this),this},stop:function(){return t.animationService.cancelAnimation(this),this},resize:function(t){var e=this,n=e.options,i=e.canvas,o=n.maintainAspectRatio&&e.aspectRatio||null,r=Math.max(0,Math.floor(a.getMaximumWidth(i))),l=Math.max(0,Math.floor(o?r/o:a.getMaximumHeight(i)));if((e.width!==r||e.height!==l)&&(i.width=e.width=r,i.height=e.height=l,i.style.width=r+"px",i.style.height=l+"px",a.retinaScale(e,n.devicePixelRatio),!t)){var u={width:r,height:l};s.notify(e,"resize",[u]),e.options.onResize&&e.options.onResize(e,u),e.stop(),e.update(e.options.responsiveAnimationDuration)}},ensureScalesHaveIDs:function(){var t=this.options,e=t.scales||{},n=t.scale;a.each(e.xAxes,function(t,e){t.id=t.id||"x-axis-"+e}),a.each(e.yAxes,function(t,e){t.id=t.id||"y-axis-"+e}),n&&(n.id=n.id||"scale")},buildScales:function(){var e=this,n=e.options,i=e.scales={},o=[];n.scales&&(o=o.concat((n.scales.xAxes||[]).map(function(t){return{options:t,dtype:"category",dposition:"bottom"}}),(n.scales.yAxes||[]).map(function(t){return{options:t,dtype:"linear",dposition:"left"}}))),n.scale&&o.push({options:n.scale,dtype:"radialLinear",isDefault:!0,dposition:"chartArea"}),a.each(o,function(n){var o=n.options,r=a.valueOrDefault(o.type,n.dtype),s=t.scaleService.getScaleConstructor(r);if(s){l(o.position)!==l(n.dposition)&&(o.position=n.dposition);var u=new s({id:o.id,options:o,ctx:e.ctx,chart:e});i[u.id]=u,u.mergeTicksOptions(),n.isDefault&&(e.scale=u)}}),t.scaleService.addScalesToLayout(this)},buildOrUpdateControllers:function(){var e=this,n=[],i=[];return a.each(e.data.datasets,function(a,o){var r=e.getDatasetMeta(o),l=a.type||e.config.type;if(r.type&&r.type!==l&&(e.destroyDatasetMeta(o),r=e.getDatasetMeta(o)),r.type=l,n.push(r.type),r.controller)r.controller.updateIndex(o);else{var s=t.controllers[r.type];if(void 0===s)throw new Error('"'+r.type+'" is not a chart type.');r.controller=new s(e,o),i.push(r.controller)}},e),i},resetElements:function(){var t=this;a.each(t.data.datasets,function(e,n){t.getDatasetMeta(n).controller.reset()},t)},reset:function(){this.resetElements(),this.tooltip.initialize()},update:function(t){var e=this;if(t&&"object"==typeof t||(t={duration:t,lazy:arguments[1]}),n(e),!1!==s.notify(e,"beforeUpdate")){e.tooltip._data=e.data;var i=e.buildOrUpdateControllers();a.each(e.data.datasets,function(t,n){e.getDatasetMeta(n).controller.buildOrUpdateElements()},e),e.updateLayout(),a.each(i,function(t){t.reset()}),e.updateDatasets(),e.tooltip.initialize(),e.lastActive=[],s.notify(e,"afterUpdate"),e._bufferedRender?e._bufferedRequest={duration:t.duration,easing:t.easing,lazy:t.lazy}:e.render(t)}},updateLayout:function(){var e=this;!1!==s.notify(e,"beforeLayout")&&(t.layoutService.update(this,this.width,this.height),s.notify(e,"afterScaleUpdate"),s.notify(e,"afterLayout"))},updateDatasets:function(){var t=this;if(!1!==s.notify(t,"beforeDatasetsUpdate")){for(var e=0,n=t.data.datasets.length;e<n;++e)t.updateDataset(e);s.notify(t,"afterDatasetsUpdate")}},updateDataset:function(t){var e=this,n=e.getDatasetMeta(t),i={meta:n,index:t};!1!==s.notify(e,"beforeDatasetUpdate",[i])&&(n.controller.update(),s.notify(e,"afterDatasetUpdate",[i]))},render:function(e){var n=this;e&&"object"==typeof e||(e={duration:e,lazy:arguments[1]});var i=e.duration,o=e.lazy;if(!1!==s.notify(n,"beforeRender")){var r=n.options.animation,l=function(t){s.notify(n,"afterRender"),a.callback(r&&r.onComplete,[t],n)};if(r&&(void 0!==i&&0!==i||void 0===i&&0!==r.duration)){var u=new t.Animation({numSteps:(i||r.duration)/16.66,easing:e.easing||r.easing,render:function(t,e){var n=a.easing.effects[e.easing],i=e.currentStep,o=i/e.numSteps;t.draw(n(o),o,i)},onAnimationProgress:r.onProgress,onAnimationComplete:l});t.animationService.addAnimation(n,u,i,o)}else n.draw(),l(new t.Animation({numSteps:0,chart:n}));return n}},draw:function(t){var e=this;e.clear(),a.isNullOrUndef(t)&&(t=1),e.transition(t),!1!==s.notify(e,"beforeDraw",[t])&&(a.each(e.boxes,function(t){t.draw(e.chartArea)},e),e.scale&&e.scale.draw(),e.drawDatasets(t),e._drawTooltip(t),s.notify(e,"afterDraw",[t]))},transition:function(t){for(var e=this,n=0,i=(e.data.datasets||[]).length;n<i;++n)e.isDatasetVisible(n)&&e.getDatasetMeta(n).controller.transition(t);e.tooltip.transition(t)},drawDatasets:function(t){var e=this;if(!1!==s.notify(e,"beforeDatasetsDraw",[t])){for(var n=(e.data.datasets||[]).length-1;n>=0;--n)e.isDatasetVisible(n)&&e.drawDataset(n,t);s.notify(e,"afterDatasetsDraw",[t])}},drawDataset:function(t,e){var n=this,i=n.getDatasetMeta(t),a={meta:i,index:t,easingValue:e};!1!==s.notify(n,"beforeDatasetDraw",[a])&&(i.controller.draw(e),s.notify(n,"afterDatasetDraw",[a]))},_drawTooltip:function(t){var e=this,n=e.tooltip,i={tooltip:n,easingValue:t};!1!==s.notify(e,"beforeTooltipDraw",[i])&&(n.draw(),s.notify(e,"afterTooltipDraw",[i]))},getElementAtEvent:function(t){return o.modes.single(this,t)},getElementsAtEvent:function(t){return o.modes.label(this,t,{intersect:!0})},getElementsAtXAxis:function(t){return o.modes["x-axis"](this,t,{intersect:!0})},getElementsAtEventForMode:function(t,e,n){var i=o.modes[e];return"function"==typeof i?i(this,t,n):[]},getDatasetAtEvent:function(t){return o.modes.dataset(this,t,{intersect:!0})},getDatasetMeta:function(t){var e=this,n=e.data.datasets[t];n._meta||(n._meta={});var i=n._meta[e.id];return i||(i=n._meta[e.id]={type:null,data:[],dataset:null,controller:null,hidden:null,xAxisID:null,yAxisID:null}),i},getVisibleDatasetCount:function(){for(var t=0,e=0,n=this.data.datasets.length;e<n;++e)this.isDatasetVisible(e)&&t++;return t},isDatasetVisible:function(t){var e=this.getDatasetMeta(t);return"boolean"==typeof e.hidden?!e.hidden:!this.data.datasets[t].hidden},generateLegend:function(){return this.options.legendCallback(this)},destroyDatasetMeta:function(t){var e=this.id,n=this.data.datasets[t],i=n._meta&&n._meta[e];i&&(i.controller.destroy(),delete n._meta[e])},destroy:function(){var e,n,i=this,o=i.canvas;for(i.stop(),e=0,n=i.data.datasets.length;e<n;++e)i.destroyDatasetMeta(e);o&&(i.unbindEvents(),a.canvas.clear(i),r.releaseContext(i.ctx),i.canvas=null,i.ctx=null),s.notify(i,"destroy"),delete t.instances[i.id]},toBase64Image:function(){return this.canvas.toDataURL.apply(this.canvas,arguments)},initToolTip:function(){var e=this;e.tooltip=new t.Tooltip({_chart:e,_chartInstance:e,_data:e.data,_options:e.options.tooltips},e)},bindEvents:function(){var t=this,e=t._listeners={},n=function(){t.eventHandler.apply(t,arguments)};a.each(t.options.events,function(i){r.addEventListener(t,i,n),e[i]=n}),t.options.responsive&&(n=function(){t.resize()},r.addEventListener(t,"resize",n),e.resize=n)},unbindEvents:function(){var t=this,e=t._listeners;e&&(delete t._listeners,a.each(e,function(e,n){r.removeEventListener(t,n,e)}))},updateHoverStyle:function(t,e,n){var i,a,o,r=n?"setHoverStyle":"removeHoverStyle";for(a=0,o=t.length;a<o;++a)(i=t[a])&&this.getDatasetMeta(i._datasetIndex).controller[r](i)},eventHandler:function(t){var e=this,n=e.tooltip;if(!1!==s.notify(e,"beforeEvent",[t])){e._bufferedRender=!0,e._bufferedRequest=null;var i=e.handleEvent(t);i|=n&&n.handleEvent(t),s.notify(e,"afterEvent",[t]);var a=e._bufferedRequest;return a?e.render(a):i&&!e.animating&&(e.stop(),e.render(e.options.hover.animationDuration,!0)),e._bufferedRender=!1,e._bufferedRequest=null,e}},handleEvent:function(t){var e=this,n=e.options||{},i=n.hover,o=!1;return e.lastActive=e.lastActive||[],"mouseout"===t.type?e.active=[]:e.active=e.getElementsAtEventForMode(t,i.mode,i),a.callback(n.onHover||n.hover.onHover,[t.native,e.active],e),"mouseup"!==t.type&&"click"!==t.type||n.onClick&&n.onClick.call(e,t.native,e.active),e.lastActive.length&&e.updateHoverStyle(e.lastActive,i.mode,!1),e.active.length&&i.mode&&e.updateHoverStyle(e.active,i.mode,!0),o=!a.arrayEquals(e.active,e.lastActive),e.lastActive=e.active,o}}),t.Controller=t}},{25:25,28:28,45:45,48:48}],24:[function(t,e,n){"use strict";var i=t(45);e.exports=function(t){function e(t,e){t._chartjs?t._chartjs.listeners.push(e):(Object.defineProperty(t,"_chartjs",{configurable:!0,enumerable:!1,value:{listeners:[e]}}),a.forEach(function(e){var n="onData"+e.charAt(0).toUpperCase()+e.slice(1),a=t[e];Object.defineProperty(t,e,{configurable:!0,enumerable:!1,value:function(){var e=Array.prototype.slice.call(arguments),o=a.apply(this,e);return i.each(t._chartjs.listeners,function(t){"function"==typeof t[n]&&t[n].apply(t,e)}),o}})}))}function n(t,e){var n=t._chartjs;if(n){var i=n.listeners,o=i.indexOf(e);-1!==o&&i.splice(o,1),i.length>0||(a.forEach(function(e){delete t[e]}),delete t._chartjs)}}var a=["push","pop","shift","splice","unshift"];t.DatasetController=function(t,e){this.initialize(t,e)},i.extend(t.DatasetController.prototype,{datasetElementType:null,dataElementType:null,initialize:function(t,e){var n=this;n.chart=t,n.index=e,n.linkScales(),n.addElements()},updateIndex:function(t){this.index=t},linkScales:function(){var t=this,e=t.getMeta(),n=t.getDataset();null===e.xAxisID&&(e.xAxisID=n.xAxisID||t.chart.options.scales.xAxes[0].id),null===e.yAxisID&&(e.yAxisID=n.yAxisID||t.chart.options.scales.yAxes[0].id)},getDataset:function(){return this.chart.data.datasets[this.index]},getMeta:function(){return this.chart.getDatasetMeta(this.index)},getScaleForId:function(t){return this.chart.scales[t]},reset:function(){this.update(!0)},destroy:function(){this._data&&n(this._data,this)},createMetaDataset:function(){var t=this,e=t.datasetElementType;return e&&new e({_chart:t.chart,_datasetIndex:t.index})},createMetaData:function(t){var e=this,n=e.dataElementType;return n&&new n({_chart:e.chart,_datasetIndex:e.index,_index:t})},addElements:function(){var t,e,n=this,i=n.getMeta(),a=n.getDataset().data||[],o=i.data;for(t=0,e=a.length;t<e;++t)o[t]=o[t]||n.createMetaData(t);i.dataset=i.dataset||n.createMetaDataset()},addElementAndReset:function(t){var e=this.createMetaData(t);this.getMeta().data.splice(t,0,e),this.updateElement(e,t,!0)},buildOrUpdateElements:function(){var t=this,i=t.getDataset(),a=i.data||(i.data=[]);t._data!==a&&(t._data&&n(t._data,t),e(a,t),t._data=a),t.resyncElements()},update:i.noop,transition:function(t){for(var e=this.getMeta(),n=e.data||[],i=n.length,a=0;a<i;++a)n[a].transition(t);e.dataset&&e.dataset.transition(t)},draw:function(){var t=this.getMeta(),e=t.data||[],n=e.length,i=0;for(t.dataset&&t.dataset.draw();i<n;++i)e[i].draw()},removeHoverStyle:function(t,e){var n=this.chart.data.datasets[t._datasetIndex],a=t._index,o=t.custom||{},r=i.valueAtIndexOrDefault,l=t._model;l.backgroundColor=o.backgroundColor?o.backgroundColor:r(n.backgroundColor,a,e.backgroundColor),l.borderColor=o.borderColor?o.borderColor:r(n.borderColor,a,e.borderColor),l.borderWidth=o.borderWidth?o.borderWidth:r(n.borderWidth,a,e.borderWidth)},setHoverStyle:function(t){var e=this.chart.data.datasets[t._datasetIndex],n=t._index,a=t.custom||{},o=i.valueAtIndexOrDefault,r=i.getHoverColor,l=t._model;l.backgroundColor=a.hoverBackgroundColor?a.hoverBackgroundColor:o(e.hoverBackgroundColor,n,r(l.backgroundColor)),l.borderColor=a.hoverBorderColor?a.hoverBorderColor:o(e.hoverBorderColor,n,r(l.borderColor)),l.borderWidth=a.hoverBorderWidth?a.hoverBorderWidth:o(e.hoverBorderWidth,n,l.borderWidth)},resyncElements:function(){var t=this,e=t.getMeta(),n=t.getDataset().data,i=e.data.length,a=n.length;a<i?e.data.splice(a,i-a):a>i&&t.insertElements(i,a-i)},insertElements:function(t,e){for(var n=0;n<e;++n)this.addElementAndReset(t+n)},onDataPush:function(){this.insertElements(this.getDataset().data.length-1,arguments.length)},onDataPop:function(){this.getMeta().data.pop()},onDataShift:function(){this.getMeta().data.shift()},onDataSplice:function(t,e){this.getMeta().data.splice(t,e),this.insertElements(t,arguments.length-2)},onDataUnshift:function(){this.insertElements(0,arguments.length)}}),t.DatasetController.extend=i.inherits}},{45:45}],25:[function(t,e,n){"use strict";var i=t(45);e.exports={_set:function(t,e){return i.merge(this[t]||(this[t]={}),e)}}},{45:45}],26:[function(t,e,n){"use strict";function i(t,e,n,i){var o,r,l,s,u,d,c,h,f,g=Object.keys(n);for(o=0,r=g.length;o<r;++o)if(l=g[o],d=n[l],e.hasOwnProperty(l)||(e[l]=d),(s=e[l])!==d&&"_"!==l[0]){if(t.hasOwnProperty(l)||(t[l]=s),u=t[l],(c=typeof d)===typeof u)if("string"===c){if((h=a(u)).valid&&(f=a(d)).valid){e[l]=f.mix(h,i).rgbString();continue}}else if("number"===c&&isFinite(u)&&isFinite(d)){e[l]=u+(d-u)*i;continue}e[l]=d}}var a=t(3),o=t(45),r=function(t){o.extend(this,t),this.initialize.apply(this,arguments)};o.extend(r.prototype,{initialize:function(){this.hidden=!1},pivot:function(){var t=this;return t._view||(t._view=o.clone(t._model)),t._start={},t},transition:function(t){var e=this,n=e._model,a=e._start,o=e._view;return n&&1!==t?(o||(o=e._view={}),a||(a=e._start={}),i(a,o,n,t),e):(e._view=n,e._start=null,e)},tooltipPosition:function(){return{x:this._model.x,y:this._model.y}},hasValue:function(){return o.isNumber(this._model.x)&&o.isNumber(this._model.y)}}),r.extend=o.inherits,e.exports=r},{3:3,45:45}],27:[function(t,e,n){"use strict";var i=t(3),a=t(25),o=t(45);e.exports=function(t){function e(t,e,n){var i;return"string"==typeof t?(i=parseInt(t,10),-1!==t.indexOf("%")&&(i=i/100*e.parentNode[n])):i=t,i}function n(t){return void 0!==t&&null!==t&&"none"!==t}function r(t,i,a){var o=document.defaultView,r=t.parentNode,l=o.getComputedStyle(t)[i],s=o.getComputedStyle(r)[i],u=n(l),d=n(s),c=Number.POSITIVE_INFINITY;return u||d?Math.min(u?e(l,t,a):c,d?e(s,r,a):c):"none"}o.configMerge=function(){return o.merge(o.clone(arguments[0]),[].slice.call(arguments,1),{merger:function(e,n,i,a){var r=n[e]||{},l=i[e];"scales"===e?n[e]=o.scaleMerge(r,l):"scale"===e?n[e]=o.merge(r,[t.scaleService.getScaleDefaults(l.type),l]):o._merger(e,n,i,a)}})},o.scaleMerge=function(){return o.merge(o.clone(arguments[0]),[].slice.call(arguments,1),{merger:function(e,n,i,a){if("xAxes"===e||"yAxes"===e){var r,l,s,u=i[e].length;for(n[e]||(n[e]=[]),r=0;r<u;++r)s=i[e][r],l=o.valueOrDefault(s.type,"xAxes"===e?"category":"linear"),r>=n[e].length&&n[e].push({}),!n[e][r].type||s.type&&s.type!==n[e][r].type?o.merge(n[e][r],[t.scaleService.getScaleDefaults(l),s]):o.merge(n[e][r],s)}else o._merger(e,n,i,a)}})},o.where=function(t,e){if(o.isArray(t)&&Array.prototype.filter)return t.filter(e);var n=[];return o.each(t,function(t){e(t)&&n.push(t)}),n},o.findIndex=Array.prototype.findIndex?function(t,e,n){return t.findIndex(e,n)}:function(t,e,n){n=void 0===n?t:n;for(var i=0,a=t.length;i<a;++i)if(e.call(n,t[i],i,t))return i;return-1},o.findNextWhere=function(t,e,n){o.isNullOrUndef(n)&&(n=-1);for(var i=n+1;i<t.length;i++){var a=t[i];if(e(a))return a}},o.findPreviousWhere=function(t,e,n){o.isNullOrUndef(n)&&(n=t.length);for(var i=n-1;i>=0;i--){var a=t[i];if(e(a))return a}},o.isNumber=function(t){return!isNaN(parseFloat(t))&&isFinite(t)},o.almostEquals=function(t,e,n){return Math.abs(t-e)<n},o.almostWhole=function(t,e){var n=Math.round(t);return n-e<t&&n+e>t},o.max=function(t){return t.reduce(function(t,e){return isNaN(e)?t:Math.max(t,e)},Number.NEGATIVE_INFINITY)},o.min=function(t){return t.reduce(function(t,e){return isNaN(e)?t:Math.min(t,e)},Number.POSITIVE_INFINITY)},o.sign=Math.sign?function(t){return Math.sign(t)}:function(t){return 0==(t=+t)||isNaN(t)?t:t>0?1:-1},o.log10=Math.log10?function(t){return Math.log10(t)}:function(t){return Math.log(t)/Math.LN10},o.toRadians=function(t){return t*(Math.PI/180)},o.toDegrees=function(t){return t*(180/Math.PI)},o.getAngleFromPoint=function(t,e){var n=e.x-t.x,i=e.y-t.y,a=Math.sqrt(n*n+i*i),o=Math.atan2(i,n);return o<-.5*Math.PI&&(o+=2*Math.PI),{angle:o,distance:a}},o.distanceBetweenPoints=function(t,e){return Math.sqrt(Math.pow(e.x-t.x,2)+Math.pow(e.y-t.y,2))},o.aliasPixel=function(t){return t%2==0?0:.5},o.splineCurve=function(t,e,n,i){var a=t.skip?e:t,o=e,r=n.skip?e:n,l=Math.sqrt(Math.pow(o.x-a.x,2)+Math.pow(o.y-a.y,2)),s=Math.sqrt(Math.pow(r.x-o.x,2)+Math.pow(r.y-o.y,2)),u=l/(l+s),d=s/(l+s),c=i*(u=isNaN(u)?0:u),h=i*(d=isNaN(d)?0:d);return{previous:{x:o.x-c*(r.x-a.x),y:o.y-c*(r.y-a.y)},next:{x:o.x+h*(r.x-a.x),y:o.y+h*(r.y-a.y)}}},o.EPSILON=Number.EPSILON||1e-14,o.splineCurveMonotone=function(t){var e,n,i,a,r=(t||[]).map(function(t){return{model:t._model,deltaK:0,mK:0}}),l=r.length;for(e=0;e<l;++e)if(!(i=r[e]).model.skip){if(n=e>0?r[e-1]:null,(a=e<l-1?r[e+1]:null)&&!a.model.skip){var s=a.model.x-i.model.x;i.deltaK=0!==s?(a.model.y-i.model.y)/s:0}!n||n.model.skip?i.mK=i.deltaK:!a||a.model.skip?i.mK=n.deltaK:this.sign(n.deltaK)!==this.sign(i.deltaK)?i.mK=0:i.mK=(n.deltaK+i.deltaK)/2}var u,d,c,h;for(e=0;e<l-1;++e)i=r[e],a=r[e+1],i.model.skip||a.model.skip||(o.almostEquals(i.deltaK,0,this.EPSILON)?i.mK=a.mK=0:(u=i.mK/i.deltaK,d=a.mK/i.deltaK,(h=Math.pow(u,2)+Math.pow(d,2))<=9||(c=3/Math.sqrt(h),i.mK=u*c*i.deltaK,a.mK=d*c*i.deltaK)));var f;for(e=0;e<l;++e)(i=r[e]).model.skip||(n=e>0?r[e-1]:null,a=e<l-1?r[e+1]:null,n&&!n.model.skip&&(f=(i.model.x-n.model.x)/3,i.model.controlPointPreviousX=i.model.x-f,i.model.controlPointPreviousY=i.model.y-f*i.mK),a&&!a.model.skip&&(f=(a.model.x-i.model.x)/3,i.model.controlPointNextX=i.model.x+f,i.model.controlPointNextY=i.model.y+f*i.mK))},o.nextItem=function(t,e,n){return n?e>=t.length-1?t[0]:t[e+1]:e>=t.length-1?t[t.length-1]:t[e+1]},o.previousItem=function(t,e,n){return n?e<=0?t[t.length-1]:t[e-1]:e<=0?t[0]:t[e-1]},o.niceNum=function(t,e){var n=Math.floor(o.log10(t)),i=t/Math.pow(10,n);return(e?i<1.5?1:i<3?2:i<7?5:10:i<=1?1:i<=2?2:i<=5?5:10)*Math.pow(10,n)},o.requestAnimFrame="undefined"==typeof window?function(t){t()}:window.requestAnimationFrame||window.webkitRequestAnimationFrame||window.mozRequestAnimationFrame||window.oRequestAnimationFrame||window.msRequestAnimationFrame||function(t){return window.setTimeout(t,1e3/60)},o.getRelativePosition=function(t,e){var n,i,a=t.originalEvent||t,r=t.currentTarget||t.srcElement,l=r.getBoundingClientRect(),s=a.touches;s&&s.length>0?(n=s[0].clientX,i=s[0].clientY):(n=a.clientX,i=a.clientY);var u=parseFloat(o.getStyle(r,"padding-left")),d=parseFloat(o.getStyle(r,"padding-top")),c=parseFloat(o.getStyle(r,"padding-right")),h=parseFloat(o.getStyle(r,"padding-bottom")),f=l.right-l.left-u-c,g=l.bottom-l.top-d-h;return n=Math.round((n-l.left-u)/f*r.width/e.currentDevicePixelRatio),i=Math.round((i-l.top-d)/g*r.height/e.currentDevicePixelRatio),{x:n,y:i}},o.getConstraintWidth=function(t){return r(t,"max-width","clientWidth")},o.getConstraintHeight=function(t){return r(t,"max-height","clientHeight")},o.getMaximumWidth=function(t){var e=t.parentNode;if(!e)return t.clientWidth;var n=parseInt(o.getStyle(e,"padding-left"),10),i=parseInt(o.getStyle(e,"padding-right"),10),a=e.clientWidth-n-i,r=o.getConstraintWidth(t);return isNaN(r)?a:Math.min(a,r)},o.getMaximumHeight=function(t){var e=t.parentNode;if(!e)return t.clientHeight;var n=parseInt(o.getStyle(e,"padding-top"),10),i=parseInt(o.getStyle(e,"padding-bottom"),10),a=e.clientHeight-n-i,r=o.getConstraintHeight(t);return isNaN(r)?a:Math.min(a,r)},o.getStyle=function(t,e){return t.currentStyle?t.currentStyle[e]:document.defaultView.getComputedStyle(t,null).getPropertyValue(e)},o.retinaScale=function(t,e){var n=t.currentDevicePixelRatio=e||window.devicePixelRatio||1;if(1!==n){var i=t.canvas,a=t.height,o=t.width;i.height=a*n,i.width=o*n,t.ctx.scale(n,n),i.style.height=a+"px",i.style.width=o+"px"}},o.fontString=function(t,e,n){return e+" "+t+"px "+n},o.longestText=function(t,e,n,i){var a=(i=i||{}).data=i.data||{},r=i.garbageCollect=i.garbageCollect||[];i.font!==e&&(a=i.data={},r=i.garbageCollect=[],i.font=e),t.font=e;var l=0;o.each(n,function(e){void 0!==e&&null!==e&&!0!==o.isArray(e)?l=o.measureText(t,a,r,l,e):o.isArray(e)&&o.each(e,function(e){void 0===e||null===e||o.isArray(e)||(l=o.measureText(t,a,r,l,e))})});var s=r.length/2;if(s>n.length){for(var u=0;u<s;u++)delete a[r[u]];r.splice(0,s)}return l},o.measureText=function(t,e,n,i,a){var o=e[a];return o||(o=e[a]=t.measureText(a).width,n.push(a)),o>i&&(i=o),i},o.numberOfLabelLines=function(t){var e=1;return o.each(t,function(t){o.isArray(t)&&t.length>e&&(e=t.length)}),e},o.color=i?function(t){return t instanceof CanvasGradient&&(t=a.global.defaultColor),i(t)}:function(t){return console.error("Color.js not found!"),t},o.getHoverColor=function(t){return t instanceof CanvasPattern?t:o.color(t).saturate(.5).darken(.1).rgbString()}}},{25:25,3:3,45:45}],28:[function(t,e,n){"use strict";function i(t,e){return t.native?{x:t.x,y:t.y}:u.getRelativePosition(t,e)}function a(t,e){var n,i,a,o,r;for(i=0,o=t.data.datasets.length;i<o;++i)if(t.isDatasetVisible(i))for(a=0,r=(n=t.getDatasetMeta(i)).data.length;a<r;++a){var l=n.data[a];l._view.skip||e(l)}}function o(t,e){var n=[];return a(t,function(t){t.inRange(e.x,e.y)&&n.push(t)}),n}function r(t,e,n,i){var o=Number.POSITIVE_INFINITY,r=[];return a(t,function(t){if(!n||t.inRange(e.x,e.y)){var a=t.getCenterPoint(),l=i(e,a);l<o?(r=[t],o=l):l===o&&r.push(t)}}),r}function l(t){var e=-1!==t.indexOf("x"),n=-1!==t.indexOf("y");return function(t,i){var a=e?Math.abs(t.x-i.x):0,o=n?Math.abs(t.y-i.y):0;return Math.sqrt(Math.pow(a,2)+Math.pow(o,2))}}function s(t,e,n){var a=i(e,t);n.axis=n.axis||"x";var s=l(n.axis),u=n.intersect?o(t,a):r(t,a,!1,s),d=[];return u.length?(t.data.datasets.forEach(function(e,n){if(t.isDatasetVisible(n)){var i=t.getDatasetMeta(n).data[u[0]._index];i&&!i._view.skip&&d.push(i)}}),d):[]}var u=t(45);e.exports={modes:{single:function(t,e){var n=i(e,t),o=[];return a(t,function(t){if(t.inRange(n.x,n.y))return o.push(t),o}),o.slice(0,1)},label:s,index:s,dataset:function(t,e,n){var a=i(e,t);n.axis=n.axis||"xy";var s=l(n.axis),u=n.intersect?o(t,a):r(t,a,!1,s);return u.length>0&&(u=t.getDatasetMeta(u[0]._datasetIndex).data),u},"x-axis":function(t,e){return s(t,e,{intersect:!1})},point:function(t,e){return o(t,i(e,t))},nearest:function(t,e,n){var a=i(e,t);n.axis=n.axis||"xy";var o=l(n.axis),s=r(t,a,n.intersect,o);return s.length>1&&s.sort(function(t,e){var n=t.getArea()-e.getArea();return 0===n&&(n=t._datasetIndex-e._datasetIndex),n}),s.slice(0,1)},x:function(t,e,n){var o=i(e,t),r=[],l=!1;return a(t,function(t){t.inXRange(o.x)&&r.push(t),t.inRange(o.x,o.y)&&(l=!0)}),n.intersect&&!l&&(r=[]),r},y:function(t,e,n){var o=i(e,t),r=[],l=!1;return a(t,function(t){t.inYRange(o.y)&&r.push(t),t.inRange(o.x,o.y)&&(l=!0)}),n.intersect&&!l&&(r=[]),r}}}},{45:45}],29:[function(t,e,n){"use strict";t(25)._set("global",{responsive:!0,responsiveAnimationDuration:0,maintainAspectRatio:!0,events:["mousemove","mouseout","click","touchstart","touchmove"],hover:{onHover:null,mode:"nearest",intersect:!0,animationDuration:400},onClick:null,defaultColor:"rgba(0,0,0,0.1)",defaultFontColor:"#666",defaultFontFamily:"'Helvetica Neue', 'Helvetica', 'Arial', sans-serif",defaultFontSize:12,defaultFontStyle:"normal",showLines:!0,elements:{},layout:{padding:{top:0,right:0,bottom:0,left:0}}}),e.exports=function(){var t=function(t,e){return this.construct(t,e),this};return t.Chart=t,t}},{25:25}],30:[function(t,e,n){"use strict";var i=t(45);e.exports=function(t){function e(t,e){return i.where(t,function(t){return t.position===e})}function n(t,e){t.forEach(function(t,e){return t._tmpIndex_=e,t}),t.sort(function(t,n){var i=e?n:t,a=e?t:n;return i.weight===a.weight?i._tmpIndex_-a._tmpIndex_:i.weight-a.weight}),t.forEach(function(t){delete t._tmpIndex_})}t.layoutService={defaults:{},addBox:function(t,e){t.boxes||(t.boxes=[]),e.fullWidth=e.fullWidth||!1,e.position=e.position||"top",e.weight=e.weight||0,t.boxes.push(e)},removeBox:function(t,e){var n=t.boxes?t.boxes.indexOf(e):-1;-1!==n&&t.boxes.splice(n,1)},configure:function(t,e,n){for(var i,a=["fullWidth","position","weight"],o=a.length,r=0;r<o;++r)i=a[r],n.hasOwnProperty(i)&&(e[i]=n[i])},update:function(t,a,o){function r(t){var e=i.findNextWhere(_,function(e){return e.box===t});if(e)if(t.isHorizontal()){var n={left:Math.max(T,D),right:Math.max(F,I),top:0,bottom:0};t.update(t.fullWidth?x:S,y/2,n)}else t.update(e.minSize.width,C)}function l(t){t.isHorizontal()?(t.left=t.fullWidth?d:T,t.right=t.fullWidth?a-c:T+S,t.top=V,t.bottom=V+t.height,V=t.bottom):(t.left=N,t.right=N+t.width,t.top=O,t.bottom=O+C,N=t.right)}if(t){var s=t.options.layout||{},u=i.options.toPadding(s.padding),d=u.left,c=u.right,h=u.top,f=u.bottom,g=e(t.boxes,"left"),p=e(t.boxes,"right"),v=e(t.boxes,"top"),m=e(t.boxes,"bottom"),b=e(t.boxes,"chartArea");n(g,!0),n(p,!1),n(v,!0),n(m,!1);var x=a-d-c,y=o-h-f,k=y/2,w=(a-x/2)/(g.length+p.length),M=(o-k)/(v.length+m.length),S=x,C=y,_=[];i.each(g.concat(p,v,m),function(t){var e,n=t.isHorizontal();n?(e=t.update(t.fullWidth?x:S,M),C-=e.height):(e=t.update(w,k),S-=e.width),_.push({horizontal:n,minSize:e,box:t})});var D=0,I=0,P=0,A=0;i.each(v.concat(m),function(t){if(t.getPadding){var e=t.getPadding();D=Math.max(D,e.left),I=Math.max(I,e.right)}}),i.each(g.concat(p),function(t){if(t.getPadding){var e=t.getPadding();P=Math.max(P,e.top),A=Math.max(A,e.bottom)}});var T=d,F=c,O=h,R=f;i.each(g.concat(p),r),i.each(g,function(t){T+=t.width}),i.each(p,function(t){F+=t.width}),i.each(v.concat(m),r),i.each(v,function(t){O+=t.height}),i.each(m,function(t){R+=t.height}),i.each(g.concat(p),function(t){var e=i.findNextWhere(_,function(e){return e.box===t}),n={left:0,right:0,top:O,bottom:R};e&&t.update(e.minSize.width,C,n)}),T=d,F=c,O=h,R=f,i.each(g,function(t){T+=t.width}),i.each(p,function(t){F+=t.width}),i.each(v,function(t){O+=t.height}),i.each(m,function(t){R+=t.height});var L=Math.max(D-T,0);T+=L,F+=Math.max(I-F,0);var z=Math.max(P-O,0);O+=z,R+=Math.max(A-R,0);var B=o-O-R,W=a-T-F;W===S&&B===C||(i.each(g,function(t){t.height=B}),i.each(p,function(t){t.height=B}),i.each(v,function(t){t.fullWidth||(t.width=W)}),i.each(m,function(t){t.fullWidth||(t.width=W)}),C=B,S=W);var N=d+L,V=h+z;i.each(g.concat(v),l),N+=S,V+=C,i.each(p,l),i.each(m,l),t.chartArea={left:T,top:O,right:T+S,bottom:O+C},i.each(b,function(e){e.left=t.chartArea.left,e.top=t.chartArea.top,e.right=t.chartArea.right,e.bottom=t.chartArea.bottom,e.update(S,C)})}}}}},{45:45}],31:[function(t,e,n){"use strict";var i=t(25),a=t(26),o=t(45);i._set("global",{plugins:{}}),e.exports=function(t){t.plugins={_plugins:[],_cacheId:0,register:function(t){var e=this._plugins;[].concat(t).forEach(function(t){-1===e.indexOf(t)&&e.push(t)}),this._cacheId++},unregister:function(t){var e=this._plugins;[].concat(t).forEach(function(t){var n=e.indexOf(t);-1!==n&&e.splice(n,1)}),this._cacheId++},clear:function(){this._plugins=[],this._cacheId++},count:function(){return this._plugins.length},getAll:function(){return this._plugins},notify:function(t,e,n){var i,a,o,r,l,s=this.descriptors(t),u=s.length;for(i=0;i<u;++i)if(a=s[i],o=a.plugin,"function"==typeof(l=o[e])&&((r=[t].concat(n||[])).push(a.options),!1===l.apply(o,r)))return!1;return!0},descriptors:function(t){var e=t._plugins||(t._plugins={});if(e.id===this._cacheId)return e.descriptors;var n=[],a=[],r=t&&t.config||{},l=r.options&&r.options.plugins||{};return this._plugins.concat(r.plugins||[]).forEach(function(t){if(-1===n.indexOf(t)){var e=t.id,r=l[e];!1!==r&&(!0===r&&(r=o.clone(i.global.plugins[e])),n.push(t),a.push({plugin:t,options:r||{}}))}}),e.descriptors=a,e.id=this._cacheId,a}},t.pluginService=t.plugins,t.PluginBase=a.extend({})}},{25:25,26:26,45:45}],32:[function(t,e,n){"use strict";function i(t){var e,n,i=[];for(e=0,n=t.length;e<n;++e)i.push(t[e].label);return i}function a(t,e,n){var i=t.getPixelForTick(e);return n&&(i-=0===e?(t.getPixelForTick(1)-i)/2:(i-t.getPixelForTick(e-1))/2),i}var o=t(25),r=t(26),l=t(45),s=t(34);o._set("scale",{display:!0,position:"left",offset:!1,gridLines:{display:!0,color:"rgba(0, 0, 0, 0.1)",lineWidth:1,drawBorder:!0,drawOnChartArea:!0,drawTicks:!0,tickMarkLength:10,zeroLineWidth:1,zeroLineColor:"rgba(0,0,0,0.25)",zeroLineBorderDash:[],zeroLineBorderDashOffset:0,offsetGridLines:!1,borderDash:[],borderDashOffset:0},scaleLabel:{display:!1,labelString:"",lineHeight:1.2,padding:{top:4,bottom:4}},ticks:{beginAtZero:!1,minRotation:0,maxRotation:50,mirror:!1,padding:0,reverse:!1,display:!0,autoSkip:!0,autoSkipPadding:0,labelOffset:0,callback:s.formatters.values,minor:{},major:{}}}),e.exports=function(t){function e(t,e,n){return l.isArray(e)?l.longestText(t,n,e):t.measureText(e).width}function n(t){var e=l.valueOrDefault,n=o.global,i=e(t.fontSize,n.defaultFontSize),a=e(t.fontStyle,n.defaultFontStyle),r=e(t.fontFamily,n.defaultFontFamily);return{size:i,style:a,family:r,font:l.fontString(i,a,r)}}function s(t){return l.options.toLineHeight(l.valueOrDefault(t.lineHeight,1.2),l.valueOrDefault(t.fontSize,o.global.defaultFontSize))}t.Scale=r.extend({getPadding:function(){var t=this;return{left:t.paddingLeft||0,top:t.paddingTop||0,right:t.paddingRight||0,bottom:t.paddingBottom||0}},getTicks:function(){return this._ticks},mergeTicksOptions:function(){var t=this.options.ticks;!1===t.minor&&(t.minor={display:!1}),!1===t.major&&(t.major={display:!1});for(var e in t)"major"!==e&&"minor"!==e&&(void 0===t.minor[e]&&(t.minor[e]=t[e]),void 0===t.major[e]&&(t.major[e]=t[e]))},beforeUpdate:function(){l.callback(this.options.beforeUpdate,[this])},update:function(t,e,n){var i,a,o,r,s,u,d=this;for(d.beforeUpdate(),d.maxWidth=t,d.maxHeight=e,d.margins=l.extend({left:0,right:0,top:0,bottom:0},n),d.longestTextCache=d.longestTextCache||{},d.beforeSetDimensions(),d.setDimensions(),d.afterSetDimensions(),d.beforeDataLimits(),d.determineDataLimits(),d.afterDataLimits(),d.beforeBuildTicks(),s=d.buildTicks()||[],d.afterBuildTicks(),d.beforeTickToLabelConversion(),o=d.convertTicksToLabels(s)||d.ticks,d.afterTickToLabelConversion(),d.ticks=o,i=0,a=o.length;i<a;++i)r=o[i],(u=s[i])?u.label=r:s.push(u={label:r,major:!1});return d._ticks=s,d.beforeCalculateTickRotation(),d.calculateTickRotation(),d.afterCalculateTickRotation(),d.beforeFit(),d.fit(),d.afterFit(),d.afterUpdate(),d.minSize},afterUpdate:function(){l.callback(this.options.afterUpdate,[this])},beforeSetDimensions:function(){l.callback(this.options.beforeSetDimensions,[this])},setDimensions:function(){var t=this;t.isHorizontal()?(t.width=t.maxWidth,t.left=0,t.right=t.width):(t.height=t.maxHeight,t.top=0,t.bottom=t.height),t.paddingLeft=0,t.paddingTop=0,t.paddingRight=0,t.paddingBottom=0},afterSetDimensions:function(){l.callback(this.options.afterSetDimensions,[this])},beforeDataLimits:function(){l.callback(this.options.beforeDataLimits,[this])},determineDataLimits:l.noop,afterDataLimits:function(){l.callback(this.options.afterDataLimits,[this])},beforeBuildTicks:function(){l.callback(this.options.beforeBuildTicks,[this])},buildTicks:l.noop,afterBuildTicks:function(){l.callback(this.options.afterBuildTicks,[this])},beforeTickToLabelConversion:function(){l.callback(this.options.beforeTickToLabelConversion,[this])},convertTicksToLabels:function(){var t=this,e=t.options.ticks;t.ticks=t.ticks.map(e.userCallback||e.callback,this)},afterTickToLabelConversion:function(){l.callback(this.options.afterTickToLabelConversion,[this])},beforeCalculateTickRotation:function(){l.callback(this.options.beforeCalculateTickRotation,[this])},calculateTickRotation:function(){var t=this,e=t.ctx,a=t.options.ticks,o=i(t._ticks),r=n(a);e.font=r.font;var s=a.minRotation||0;if(o.length&&t.options.display&&t.isHorizontal())for(var u,d=l.longestText(e,r.font,o,t.longestTextCache),c=d,h=t.getPixelForTick(1)-t.getPixelForTick(0)-6;c>h&&s<a.maxRotation;){var f=l.toRadians(s);if(u=Math.cos(f),Math.sin(f)*d>t.maxHeight){s--;break}s++,c=u*d}t.labelRotation=s},afterCalculateTickRotation:function(){l.callback(this.options.afterCalculateTickRotation,[this])},beforeFit:function(){l.callback(this.options.beforeFit,[this])},fit:function(){var t=this,a=t.minSize={width:0,height:0},o=i(t._ticks),r=t.options,u=r.ticks,d=r.scaleLabel,c=r.gridLines,h=r.display,f=t.isHorizontal(),g=n(u),p=r.gridLines.tickMarkLength;if(a.width=f?t.isFullWidth()?t.maxWidth-t.margins.left-t.margins.right:t.maxWidth:h&&c.drawTicks?p:0,a.height=f?h&&c.drawTicks?p:0:t.maxHeight,d.display&&h){var v=s(d)+l.options.toPadding(d.padding).height;f?a.height+=v:a.width+=v}if(u.display&&h){var m=l.longestText(t.ctx,g.font,o,t.longestTextCache),b=l.numberOfLabelLines(o),x=.5*g.size,y=t.options.ticks.padding;if(f){t.longestLabelWidth=m;var k=l.toRadians(t.labelRotation),w=Math.cos(k),M=Math.sin(k)*m+g.size*b+x*(b-1)+x;a.height=Math.min(t.maxHeight,a.height+M+y),t.ctx.font=g.font;var S=e(t.ctx,o[0],g.font),C=e(t.ctx,o[o.length-1],g.font);0!==t.labelRotation?(t.paddingLeft="bottom"===r.position?w*S+3:w*x+3,t.paddingRight="bottom"===r.position?w*x+3:w*C+3):(t.paddingLeft=S/2+3,t.paddingRight=C/2+3)}else u.mirror?m=0:m+=y+x,a.width=Math.min(t.maxWidth,a.width+m),t.paddingTop=g.size/2,t.paddingBottom=g.size/2}t.handleMargins(),t.width=a.width,t.height=a.height},handleMargins:function(){var t=this;t.margins&&(t.paddingLeft=Math.max(t.paddingLeft-t.margins.left,0),t.paddingTop=Math.max(t.paddingTop-t.margins.top,0),t.paddingRight=Math.max(t.paddingRight-t.margins.right,0),t.paddingBottom=Math.max(t.paddingBottom-t.margins.bottom,0))},afterFit:function(){l.callback(this.options.afterFit,[this])},isHorizontal:function(){return"top"===this.options.position||"bottom"===this.options.position},isFullWidth:function(){return this.options.fullWidth},getRightValue:function(t){if(l.isNullOrUndef(t))return NaN;if("number"==typeof t&&!isFinite(t))return NaN;if(t)if(this.isHorizontal()){if(void 0!==t.x)return this.getRightValue(t.x)}else if(void 0!==t.y)return this.getRightValue(t.y);return t},getLabelForIndex:l.noop,getPixelForValue:l.noop,getValueForPixel:l.noop,getPixelForTick:function(t){var e=this,n=e.options.offset;if(e.isHorizontal()){var i=(e.width-(e.paddingLeft+e.paddingRight))/Math.max(e._ticks.length-(n?0:1),1),a=i*t+e.paddingLeft;n&&(a+=i/2);var o=e.left+Math.round(a);return o+=e.isFullWidth()?e.margins.left:0}var r=e.height-(e.paddingTop+e.paddingBottom);return e.top+t*(r/(e._ticks.length-1))},getPixelForDecimal:function(t){var e=this;if(e.isHorizontal()){var n=(e.width-(e.paddingLeft+e.paddingRight))*t+e.paddingLeft,i=e.left+Math.round(n);return i+=e.isFullWidth()?e.margins.left:0}return e.top+t*e.height},getBasePixel:function(){return this.getPixelForValue(this.getBaseValue())},getBaseValue:function(){var t=this,e=t.min,n=t.max;return t.beginAtZero?0:e<0&&n<0?n:e>0&&n>0?e:0},_autoSkip:function(t){var e,n,i,a,o=this,r=o.isHorizontal(),s=o.options.ticks.minor,u=t.length,d=l.toRadians(o.labelRotation),c=Math.cos(d),h=o.longestLabelWidth*c,f=[];for(s.maxTicksLimit&&(a=s.maxTicksLimit),r&&(e=!1,(h+s.autoSkipPadding)*u>o.width-(o.paddingLeft+o.paddingRight)&&(e=1+Math.floor((h+s.autoSkipPadding)*u/(o.width-(o.paddingLeft+o.paddingRight)))),a&&u>a&&(e=Math.max(e,Math.floor(u/a)))),n=0;n<u;n++)i=t[n],(e>1&&n%e>0||n%e==0&&n+e>=u)&&n!==u-1&&delete i.label,f.push(i);return f},draw:function(t){var e=this,i=e.options;if(i.display){var r=e.ctx,u=o.global,d=i.ticks.minor,c=i.ticks.major||d,h=i.gridLines,f=i.scaleLabel,g=0!==e.labelRotation,p=e.isHorizontal(),v=d.autoSkip?e._autoSkip(e.getTicks()):e.getTicks(),m=l.valueOrDefault(d.fontColor,u.defaultFontColor),b=n(d),x=l.valueOrDefault(c.fontColor,u.defaultFontColor),y=n(c),k=h.drawTicks?h.tickMarkLength:0,w=l.valueOrDefault(f.fontColor,u.defaultFontColor),M=n(f),S=l.options.toPadding(f.padding),C=l.toRadians(e.labelRotation),_=[],D="right"===i.position?e.left:e.right-k,I="right"===i.position?e.left+k:e.right,P="bottom"===i.position?e.top:e.bottom-k,A="bottom"===i.position?e.top+k:e.bottom;if(l.each(v,function(n,o){if(!l.isNullOrUndef(n.label)){var r,s,c,f,m=n.label;o===e.zeroLineIndex&&i.offset===h.offsetGridLines?(r=h.zeroLineWidth,s=h.zeroLineColor,c=h.zeroLineBorderDash,f=h.zeroLineBorderDashOffset):(r=l.valueAtIndexOrDefault(h.lineWidth,o),s=l.valueAtIndexOrDefault(h.color,o),c=l.valueOrDefault(h.borderDash,u.borderDash),f=l.valueOrDefault(h.borderDashOffset,u.borderDashOffset));var b,x,y,w,M,S,T,F,O,R,L="middle",z="middle",B=d.padding;if(p){var W=k+B;"bottom"===i.position?(z=g?"middle":"top",L=g?"right":"center",R=e.top+W):(z=g?"middle":"bottom",L=g?"left":"center",R=e.bottom-W);var N=a(e,o,h.offsetGridLines&&v.length>1);N<e.left&&(s="rgba(0,0,0,0)"),N+=l.aliasPixel(r),O=e.getPixelForTick(o)+d.labelOffset,b=y=M=T=N,x=P,w=A,S=t.top,F=t.bottom}else{var V,E="left"===i.position;d.mirror?(L=E?"left":"right",V=B):(L=E?"right":"left",V=k+B),O=E?e.right-V:e.left+V;var H=a(e,o,h.offsetGridLines&&v.length>1);H<e.top&&(s="rgba(0,0,0,0)"),H+=l.aliasPixel(r),R=e.getPixelForTick(o)+d.labelOffset,b=D,y=I,M=t.left,T=t.right,x=w=S=F=H}_.push({tx1:b,ty1:x,tx2:y,ty2:w,x1:M,y1:S,x2:T,y2:F,labelX:O,labelY:R,glWidth:r,glColor:s,glBorderDash:c,glBorderDashOffset:f,rotation:-1*C,label:m,major:n.major,textBaseline:z,textAlign:L})}}),l.each(_,function(t){if(h.display&&(r.save(),r.lineWidth=t.glWidth,r.strokeStyle=t.glColor,r.setLineDash&&(r.setLineDash(t.glBorderDash),r.lineDashOffset=t.glBorderDashOffset),r.beginPath(),h.drawTicks&&(r.moveTo(t.tx1,t.ty1),r.lineTo(t.tx2,t.ty2)),h.drawOnChartArea&&(r.moveTo(t.x1,t.y1),r.lineTo(t.x2,t.y2)),r.stroke(),r.restore()),d.display){r.save(),r.translate(t.labelX,t.labelY),r.rotate(t.rotation),r.font=t.major?y.font:b.font,r.fillStyle=t.major?x:m,r.textBaseline=t.textBaseline,r.textAlign=t.textAlign;var e=t.label;if(l.isArray(e))for(var n=0,i=0;n<e.length;++n)r.fillText(""+e[n],0,i),i+=1.5*b.size;else r.fillText(e,0,0);r.restore()}}),f.display){var T,F,O=0,R=s(f)/2;if(p)T=e.left+(e.right-e.left)/2,F="bottom"===i.position?e.bottom-R-S.bottom:e.top+R+S.top;else{var L="left"===i.position;T=L?e.left+R+S.top:e.right-R-S.top,F=e.top+(e.bottom-e.top)/2,O=L?-.5*Math.PI:.5*Math.PI}r.save(),r.translate(T,F),r.rotate(O),r.textAlign="center",r.textBaseline="middle",r.fillStyle=w,r.font=M.font,r.fillText(f.labelString,0,0),r.restore()}if(h.drawBorder){r.lineWidth=l.valueAtIndexOrDefault(h.lineWidth,0),r.strokeStyle=l.valueAtIndexOrDefault(h.color,0);var z=e.left,B=e.right,W=e.top,N=e.bottom,V=l.aliasPixel(r.lineWidth);p?(W=N="top"===i.position?e.bottom:e.top,W+=V,N+=V):(z=B="left"===i.position?e.right:e.left,z+=V,B+=V),r.beginPath(),r.moveTo(z,W),r.lineTo(B,N),r.stroke()}}}})}},{25:25,26:26,34:34,45:45}],33:[function(t,e,n){"use strict";var i=t(25),a=t(45);e.exports=function(t){t.scaleService={constructors:{},defaults:{},registerScaleType:function(t,e,n){this.constructors[t]=e,this.defaults[t]=a.clone(n)},getScaleConstructor:function(t){return this.constructors.hasOwnProperty(t)?this.constructors[t]:void 0},getScaleDefaults:function(t){return this.defaults.hasOwnProperty(t)?a.merge({},[i.scale,this.defaults[t]]):{}},updateScaleDefaults:function(t,e){var n=this;n.defaults.hasOwnProperty(t)&&(n.defaults[t]=a.extend(n.defaults[t],e))},addScalesToLayout:function(e){a.each(e.scales,function(n){n.fullWidth=n.options.fullWidth,n.position=n.options.position,n.weight=n.options.weight,t.layoutService.addBox(e,n)})}}}},{25:25,45:45}],34:[function(t,e,n){"use strict";var i=t(45);e.exports={generators:{linear:function(t,e){var n,a=[];if(t.stepSize&&t.stepSize>0)n=t.stepSize;else{var o=i.niceNum(e.max-e.min,!1);n=i.niceNum(o/(t.maxTicks-1),!0)}var r=Math.floor(e.min/n)*n,l=Math.ceil(e.max/n)*n;t.min&&t.max&&t.stepSize&&i.almostWhole((t.max-t.min)/t.stepSize,n/1e3)&&(r=t.min,l=t.max);var s=(l-r)/n;s=i.almostEquals(s,Math.round(s),n/1e3)?Math.round(s):Math.ceil(s),a.push(void 0!==t.min?t.min:r);for(var u=1;u<s;++u)a.push(r+u*n);return a.push(void 0!==t.max?t.max:l),a},logarithmic:function(t,e){var n,a,o=[],r=i.valueOrDefault,l=r(t.min,Math.pow(10,Math.floor(i.log10(e.min)))),s=Math.floor(i.log10(e.max)),u=Math.ceil(e.max/Math.pow(10,s));0===l?(n=Math.floor(i.log10(e.minNotZero)),a=Math.floor(e.minNotZero/Math.pow(10,n)),o.push(l),l=a*Math.pow(10,n)):(n=Math.floor(i.log10(l)),a=Math.floor(l/Math.pow(10,n)));do{o.push(l),10===++a&&(a=1,++n),l=a*Math.pow(10,n)}while(n<s||n===s&&a<u);var d=r(t.max,l);return o.push(d),o}},formatters:{values:function(t){return i.isArray(t)?t:""+t},linear:function(t,e,n){var a=n.length>3?n[2]-n[1]:n[1]-n[0];Math.abs(a)>1&&t!==Math.floor(t)&&(a=t-Math.floor(t));var o=i.log10(Math.abs(a)),r="";if(0!==t){var l=-1*Math.floor(o);l=Math.max(Math.min(l,20),0),r=t.toFixed(l)}else r="0";return r},logarithmic:function(t,e,n){var a=t/Math.pow(10,Math.floor(i.log10(t)));return 0===t?"0":1===a||2===a||5===a||0===e||e===n.length-1?t.toExponential():""}}}},{45:45}],35:[function(t,e,n){"use strict";var i=t(25),a=t(26),o=t(45);i._set("global",{tooltips:{enabled:!0,custom:null,mode:"nearest",position:"average",intersect:!0,backgroundColor:"rgba(0,0,0,0.8)",titleFontStyle:"bold",titleSpacing:2,titleMarginBottom:6,titleFontColor:"#fff",titleAlign:"left",bodySpacing:2,bodyFontColor:"#fff",bodyAlign:"left",footerFontStyle:"bold",footerSpacing:2,footerMarginTop:6,footerFontColor:"#fff",footerAlign:"left",yPadding:6,xPadding:6,caretPadding:2,caretSize:5,cornerRadius:6,multiKeyBackground:"#fff",displayColors:!0,borderColor:"rgba(0,0,0,0)",borderWidth:0,callbacks:{beforeTitle:o.noop,title:function(t,e){var n="",i=e.labels,a=i?i.length:0;if(t.length>0){var o=t[0];o.xLabel?n=o.xLabel:a>0&&o.index<a&&(n=i[o.index])}return n},afterTitle:o.noop,beforeBody:o.noop,beforeLabel:o.noop,label:function(t,e){var n=e.datasets[t.datasetIndex].label||"";return n&&(n+=": "),n+=t.yLabel},labelColor:function(t,e){var n=e.getDatasetMeta(t.datasetIndex).data[t.index]._view;return{borderColor:n.borderColor,backgroundColor:n.backgroundColor}},labelTextColor:function(){return this._options.bodyFontColor},afterLabel:o.noop,afterBody:o.noop,beforeFooter:o.noop,footer:o.noop,afterFooter:o.noop}}}),e.exports=function(t){function e(t,e){var n=o.color(t);return n.alpha(e*n.alpha()).rgbaString()}function n(t,e){return e&&(o.isArray(e)?Array.prototype.push.apply(t,e):t.push(e)),t}function r(t){var e=t._xScale,n=t._yScale||t._scale,i=t._index,a=t._datasetIndex;return{xLabel:e?e.getLabelForIndex(i,a):"",yLabel:n?n.getLabelForIndex(i,a):"",index:i,datasetIndex:a,x:t._model.x,y:t._model.y}}function l(t){var e=i.global,n=o.valueOrDefault;return{xPadding:t.xPadding,yPadding:t.yPadding,xAlign:t.xAlign,yAlign:t.yAlign,bodyFontColor:t.bodyFontColor,_bodyFontFamily:n(t.bodyFontFamily,e.defaultFontFamily),_bodyFontStyle:n(t.bodyFontStyle,e.defaultFontStyle),_bodyAlign:t.bodyAlign,bodyFontSize:n(t.bodyFontSize,e.defaultFontSize),bodySpacing:t.bodySpacing,titleFontColor:t.titleFontColor,_titleFontFamily:n(t.titleFontFamily,e.defaultFontFamily),_titleFontStyle:n(t.titleFontStyle,e.defaultFontStyle),titleFontSize:n(t.titleFontSize,e.defaultFontSize),_titleAlign:t.titleAlign,titleSpacing:t.titleSpacing,titleMarginBottom:t.titleMarginBottom,footerFontColor:t.footerFontColor,_footerFontFamily:n(t.footerFontFamily,e.defaultFontFamily),_footerFontStyle:n(t.footerFontStyle,e.defaultFontStyle),footerFontSize:n(t.footerFontSize,e.defaultFontSize),_footerAlign:t.footerAlign,footerSpacing:t.footerSpacing,footerMarginTop:t.footerMarginTop,caretSize:t.caretSize,cornerRadius:t.cornerRadius,backgroundColor:t.backgroundColor,opacity:0,legendColorBackground:t.multiKeyBackground,displayColors:t.displayColors,borderColor:t.borderColor,borderWidth:t.borderWidth}}function s(t,e){var n=t._chart.ctx,i=2*e.yPadding,a=0,r=e.body,l=r.reduce(function(t,e){return t+e.before.length+e.lines.length+e.after.length},0);l+=e.beforeBody.length+e.afterBody.length;var s=e.title.length,u=e.footer.length,d=e.titleFontSize,c=e.bodyFontSize,h=e.footerFontSize;i+=s*d,i+=s?(s-1)*e.titleSpacing:0,i+=s?e.titleMarginBottom:0,i+=l*c,i+=l?(l-1)*e.bodySpacing:0,i+=u?e.footerMarginTop:0,i+=u*h,i+=u?(u-1)*e.footerSpacing:0;var f=0,g=function(t){a=Math.max(a,n.measureText(t).width+f)};return n.font=o.fontString(d,e._titleFontStyle,e._titleFontFamily),o.each(e.title,g),n.font=o.fontString(c,e._bodyFontStyle,e._bodyFontFamily),o.each(e.beforeBody.concat(e.afterBody),g),f=e.displayColors?c+2:0,o.each(r,function(t){o.each(t.before,g),o.each(t.lines,g),o.each(t.after,g)}),f=0,n.font=o.fontString(h,e._footerFontStyle,e._footerFontFamily),o.each(e.footer,g),a+=2*e.xPadding,{width:a,height:i}}function u(t,e){var n=t._model,i=t._chart,a=t._chart.chartArea,o="center",r="center";n.y<e.height?r="top":n.y>i.height-e.height&&(r="bottom");var l,s,u,d,c,h=(a.left+a.right)/2,f=(a.top+a.bottom)/2;"center"===r?(l=function(t){return t<=h},s=function(t){return t>h}):(l=function(t){return t<=e.width/2},s=function(t){return t>=i.width-e.width/2}),u=function(t){return t+e.width>i.width},d=function(t){return t-e.width<0},c=function(t){return t<=f?"top":"bottom"},l(n.x)?(o="left",u(n.x)&&(o="center",r=c(n.y))):s(n.x)&&(o="right",d(n.x)&&(o="center",r=c(n.y)));var g=t._options;return{xAlign:g.xAlign?g.xAlign:o,yAlign:g.yAlign?g.yAlign:r}}function d(t,e,n){var i=t.x,a=t.y,o=t.caretSize,r=t.caretPadding,l=t.cornerRadius,s=n.xAlign,u=n.yAlign,d=o+r,c=l+r;return"right"===s?i-=e.width:"center"===s&&(i-=e.width/2),"top"===u?a+=d:a-="bottom"===u?e.height+d:e.height/2,"center"===u?"left"===s?i+=d:"right"===s&&(i-=d):"left"===s?i-=c:"right"===s&&(i+=c),{x:i,y:a}}t.Tooltip=a.extend({initialize:function(){this._model=l(this._options),this._lastActive=[]},getTitle:function(){var t=this,e=t._options.callbacks,i=e.beforeTitle.apply(t,arguments),a=e.title.apply(t,arguments),o=e.afterTitle.apply(t,arguments),r=[];return r=n(r,i),r=n(r,a),r=n(r,o)},getBeforeBody:function(){var t=this._options.callbacks.beforeBody.apply(this,arguments);return o.isArray(t)?t:void 0!==t?[t]:[]},getBody:function(t,e){var i=this,a=i._options.callbacks,r=[];return o.each(t,function(t){var o={before:[],lines:[],after:[]};n(o.before,a.beforeLabel.call(i,t,e)),n(o.lines,a.label.call(i,t,e)),n(o.after,a.afterLabel.call(i,t,e)),r.push(o)}),r},getAfterBody:function(){var t=this._options.callbacks.afterBody.apply(this,arguments);return o.isArray(t)?t:void 0!==t?[t]:[]},getFooter:function(){var t=this,e=t._options.callbacks,i=e.beforeFooter.apply(t,arguments),a=e.footer.apply(t,arguments),o=e.afterFooter.apply(t,arguments),r=[];return r=n(r,i),r=n(r,a),r=n(r,o)},update:function(e){var n,i,a=this,c=a._options,h=a._model,f=a._model=l(c),g=a._active,p=a._data,v={xAlign:h.xAlign,yAlign:h.yAlign},m={x:h.x,y:h.y},b={width:h.width,height:h.height},x={x:h.caretX,y:h.caretY};if(g.length){f.opacity=1;var y=[],k=[];x=t.Tooltip.positioners[c.position].call(a,g,a._eventPosition);var w=[];for(n=0,i=g.length;n<i;++n)w.push(r(g[n]));c.filter&&(w=w.filter(function(t){return c.filter(t,p)})),c.itemSort&&(w=w.sort(function(t,e){return c.itemSort(t,e,p)})),o.each(w,function(t){y.push(c.callbacks.labelColor.call(a,t,a._chart)),k.push(c.callbacks.labelTextColor.call(a,t,a._chart))}),f.title=a.getTitle(w,p),f.beforeBody=a.getBeforeBody(w,p),f.body=a.getBody(w,p),f.afterBody=a.getAfterBody(w,p),f.footer=a.getFooter(w,p),f.x=Math.round(x.x),f.y=Math.round(x.y),f.caretPadding=c.caretPadding,f.labelColors=y,f.labelTextColors=k,f.dataPoints=w,m=d(f,b=s(this,f),v=u(this,b))}else f.opacity=0;return f.xAlign=v.xAlign,f.yAlign=v.yAlign,f.x=m.x,f.y=m.y,f.width=b.width,f.height=b.height,f.caretX=x.x,f.caretY=x.y,a._model=f,e&&c.custom&&c.custom.call(a,f),a},drawCaret:function(t,e){var n=this._chart.ctx,i=this._view,a=this.getCaretPosition(t,e,i);n.lineTo(a.x1,a.y1),n.lineTo(a.x2,a.y2),n.lineTo(a.x3,a.y3)},getCaretPosition:function(t,e,n){var i,a,o,r,l,s,u=n.caretSize,d=n.cornerRadius,c=n.xAlign,h=n.yAlign,f=t.x,g=t.y,p=e.width,v=e.height;if("center"===h)l=g+v/2,"left"===c?(a=(i=f)-u,o=i,r=l+u,s=l-u):(a=(i=f+p)+u,o=i,r=l-u,s=l+u);else if("left"===c?(i=(a=f+d+u)-u,o=a+u):"right"===c?(i=(a=f+p-d-u)-u,o=a+u):(i=(a=f+p/2)-u,o=a+u),"top"===h)l=(r=g)-u,s=r;else{l=(r=g+v)+u,s=r;var m=o;o=i,i=m}return{x1:i,x2:a,x3:o,y1:r,y2:l,y3:s}},drawTitle:function(t,n,i,a){var r=n.title;if(r.length){i.textAlign=n._titleAlign,i.textBaseline="top";var l=n.titleFontSize,s=n.titleSpacing;i.fillStyle=e(n.titleFontColor,a),i.font=o.fontString(l,n._titleFontStyle,n._titleFontFamily);var u,d;for(u=0,d=r.length;u<d;++u)i.fillText(r[u],t.x,t.y),t.y+=l+s,u+1===r.length&&(t.y+=n.titleMarginBottom-s)}},drawBody:function(t,n,i,a){var r=n.bodyFontSize,l=n.bodySpacing,s=n.body;i.textAlign=n._bodyAlign,i.textBaseline="top",i.font=o.fontString(r,n._bodyFontStyle,n._bodyFontFamily);var u=0,d=function(e){i.fillText(e,t.x+u,t.y),t.y+=r+l};i.fillStyle=e(n.bodyFontColor,a),o.each(n.beforeBody,d);var c=n.displayColors;u=c?r+2:0,o.each(s,function(l,s){var u=e(n.labelTextColors[s],a);i.fillStyle=u,o.each(l.before,d),o.each(l.lines,function(o){c&&(i.fillStyle=e(n.legendColorBackground,a),i.fillRect(t.x,t.y,r,r),i.lineWidth=1,i.strokeStyle=e(n.labelColors[s].borderColor,a),i.strokeRect(t.x,t.y,r,r),i.fillStyle=e(n.labelColors[s].backgroundColor,a),i.fillRect(t.x+1,t.y+1,r-2,r-2),i.fillStyle=u),d(o)}),o.each(l.after,d)}),u=0,o.each(n.afterBody,d),t.y-=l},drawFooter:function(t,n,i,a){var r=n.footer;r.length&&(t.y+=n.footerMarginTop,i.textAlign=n._footerAlign,i.textBaseline="top",i.fillStyle=e(n.footerFontColor,a),i.font=o.fontString(n.footerFontSize,n._footerFontStyle,n._footerFontFamily),o.each(r,function(e){i.fillText(e,t.x,t.y),t.y+=n.footerFontSize+n.footerSpacing}))},drawBackground:function(t,n,i,a,o){i.fillStyle=e(n.backgroundColor,o),i.strokeStyle=e(n.borderColor,o),i.lineWidth=n.borderWidth;var r=n.xAlign,l=n.yAlign,s=t.x,u=t.y,d=a.width,c=a.height,h=n.cornerRadius;i.beginPath(),i.moveTo(s+h,u),"top"===l&&this.drawCaret(t,a),i.lineTo(s+d-h,u),i.quadraticCurveTo(s+d,u,s+d,u+h),"center"===l&&"right"===r&&this.drawCaret(t,a),i.lineTo(s+d,u+c-h),i.quadraticCurveTo(s+d,u+c,s+d-h,u+c),"bottom"===l&&this.drawCaret(t,a),i.lineTo(s+h,u+c),i.quadraticCurveTo(s,u+c,s,u+c-h),"center"===l&&"left"===r&&this.drawCaret(t,a),i.lineTo(s,u+h),i.quadraticCurveTo(s,u,s+h,u),i.closePath(),i.fill(),n.borderWidth>0&&i.stroke()},draw:function(){var t=this._chart.ctx,e=this._view;if(0!==e.opacity){var n={width:e.width,height:e.height},i={x:e.x,y:e.y},a=Math.abs(e.opacity<.001)?0:e.opacity,o=e.title.length||e.beforeBody.length||e.body.length||e.afterBody.length||e.footer.length;this._options.enabled&&o&&(this.drawBackground(i,e,t,n,a),i.x+=e.xPadding,i.y+=e.yPadding,this.drawTitle(i,e,t,a),this.drawBody(i,e,t,a),this.drawFooter(i,e,t,a))}},handleEvent:function(t){var e=this,n=e._options,i=!1;if(e._lastActive=e._lastActive||[],"mouseout"===t.type?e._active=[]:e._active=e._chart.getElementsAtEventForMode(t,n.mode,n),!(i=!o.arrayEquals(e._active,e._lastActive)))return!1;if(e._lastActive=e._active,n.enabled||n.custom){e._eventPosition={x:t.x,y:t.y};var a=e._model;e.update(!0),e.pivot(),i|=a.x!==e._model.x||a.y!==e._model.y}return i}}),t.Tooltip.positioners={average:function(t){if(!t.length)return!1;var e,n,i=0,a=0,o=0;for(e=0,n=t.length;e<n;++e){var r=t[e];if(r&&r.hasValue()){var l=r.tooltipPosition();i+=l.x,a+=l.y,++o}}return{x:Math.round(i/o),y:Math.round(a/o)}},nearest:function(t,e){var n,i,a,r=e.x,l=e.y,s=Number.POSITIVE_INFINITY;for(n=0,i=t.length;n<i;++n){var u=t[n];if(u&&u.hasValue()){var d=u.getCenterPoint(),c=o.distanceBetweenPoints(e,d);c<s&&(s=c,a=u)}}if(a){var h=a.tooltipPosition();r=h.x,l=h.y}return{x:r,y:l}}}}},{25:25,26:26,45:45}],36:[function(t,e,n){"use strict";var i=t(25),a=t(26),o=t(45);i._set("global",{elements:{arc:{backgroundColor:i.global.defaultColor,borderColor:"#fff",borderWidth:2}}}),e.exports=a.extend({inLabelRange:function(t){var e=this._view;return!!e&&Math.pow(t-e.x,2)<Math.pow(e.radius+e.hoverRadius,2)},inRange:function(t,e){var n=this._view;if(n){for(var i=o.getAngleFromPoint(n,{x:t,y:e}),a=i.angle,r=i.distance,l=n.startAngle,s=n.endAngle;s<l;)s+=2*Math.PI;for(;a>s;)a-=2*Math.PI;for(;a<l;)a+=2*Math.PI;var u=a>=l&&a<=s,d=r>=n.innerRadius&&r<=n.outerRadius;return u&&d}return!1},getCenterPoint:function(){var t=this._view,e=(t.startAngle+t.endAngle)/2,n=(t.innerRadius+t.outerRadius)/2;return{x:t.x+Math.cos(e)*n,y:t.y+Math.sin(e)*n}},getArea:function(){var t=this._view;return Math.PI*((t.endAngle-t.startAngle)/(2*Math.PI))*(Math.pow(t.outerRadius,2)-Math.pow(t.innerRadius,2))},tooltipPosition:function(){var t=this._view,e=t.startAngle+(t.endAngle-t.startAngle)/2,n=(t.outerRadius-t.innerRadius)/2+t.innerRadius;return{x:t.x+Math.cos(e)*n,y:t.y+Math.sin(e)*n}},draw:function(){var t=this._chart.ctx,e=this._view,n=e.startAngle,i=e.endAngle;t.beginPath(),t.arc(e.x,e.y,e.outerRadius,n,i),t.arc(e.x,e.y,e.innerRadius,i,n,!0),t.closePath(),t.strokeStyle=e.borderColor,t.lineWidth=e.borderWidth,t.fillStyle=e.backgroundColor,t.fill(),t.lineJoin="bevel",e.borderWidth&&t.stroke()}})},{25:25,26:26,45:45}],37:[function(t,e,n){"use strict";var i=t(25),a=t(26),o=t(45),r=i.global;i._set("global",{elements:{line:{tension:.4,backgroundColor:r.defaultColor,borderWidth:3,borderColor:r.defaultColor,borderCapStyle:"butt",borderDash:[],borderDashOffset:0,borderJoinStyle:"miter",capBezierPoints:!0,fill:!0}}}),e.exports=a.extend({draw:function(){var t,e,n,i,a=this,l=a._view,s=a._chart.ctx,u=l.spanGaps,d=a._children.slice(),c=r.elements.line,h=-1;for(a._loop&&d.length&&d.push(d[0]),s.save(),s.lineCap=l.borderCapStyle||c.borderCapStyle,s.setLineDash&&s.setLineDash(l.borderDash||c.borderDash),s.lineDashOffset=l.borderDashOffset||c.borderDashOffset,s.lineJoin=l.borderJoinStyle||c.borderJoinStyle,s.lineWidth=l.borderWidth||c.borderWidth,s.strokeStyle=l.borderColor||r.defaultColor,s.beginPath(),h=-1,t=0;t<d.length;++t)e=d[t],n=o.previousItem(d,t),i=e._view,0===t?i.skip||(s.moveTo(i.x,i.y),h=t):(n=-1===h?n:d[h],i.skip||(h!==t-1&&!u||-1===h?s.moveTo(i.x,i.y):o.canvas.lineTo(s,n._view,e._view),h=t));s.stroke(),s.restore()}})},{25:25,26:26,45:45}],38:[function(t,e,n){"use strict";function i(t){var e=this._view;return!!e&&Math.pow(t-e.x,2)<Math.pow(e.radius+e.hitRadius,2)}var a=t(25),o=t(26),r=t(45),l=a.global.defaultColor;a._set("global",{elements:{point:{radius:3,pointStyle:"circle",backgroundColor:l,borderColor:l,borderWidth:1,hitRadius:1,hoverRadius:4,hoverBorderWidth:1}}}),e.exports=o.extend({inRange:function(t,e){var n=this._view;return!!n&&Math.pow(t-n.x,2)+Math.pow(e-n.y,2)<Math.pow(n.hitRadius+n.radius,2)},inLabelRange:i,inXRange:i,inYRange:function(t){var e=this._view;return!!e&&Math.pow(t-e.y,2)<Math.pow(e.radius+e.hitRadius,2)},getCenterPoint:function(){var t=this._view;return{x:t.x,y:t.y}},getArea:function(){return Math.PI*Math.pow(this._view.radius,2)},tooltipPosition:function(){var t=this._view;return{x:t.x,y:t.y,padding:t.radius+t.borderWidth}},draw:function(t){var e=this._view,n=this._model,i=this._chart.ctx,o=e.pointStyle,s=e.radius,u=e.x,d=e.y,c=r.color,h=0;e.skip||(i.strokeStyle=e.borderColor||l,i.lineWidth=r.valueOrDefault(e.borderWidth,a.global.elements.point.borderWidth),i.fillStyle=e.backgroundColor||l,void 0!==t&&(n.x<t.left||1.01*t.right<n.x||n.y<t.top||1.01*t.bottom<n.y)&&(n.x<t.left?h=(u-n.x)/(t.left-n.x):1.01*t.right<n.x?h=(n.x-u)/(n.x-t.right):n.y<t.top?h=(d-n.y)/(t.top-n.y):1.01*t.bottom<n.y&&(h=(n.y-d)/(n.y-t.bottom)),h=Math.round(100*h)/100,i.strokeStyle=c(i.strokeStyle).alpha(h).rgbString(),i.fillStyle=c(i.fillStyle).alpha(h).rgbString()),r.canvas.drawPoint(i,o,s,u,d))}})},{25:25,26:26,45:45}],39:[function(t,e,n){"use strict";function i(t){return void 0!==t._view.width}function a(t){var e,n,a,o,r=t._view;if(i(t)){var l=r.width/2;e=r.x-l,n=r.x+l,a=Math.min(r.y,r.base),o=Math.max(r.y,r.base)}else{var s=r.height/2;e=Math.min(r.x,r.base),n=Math.max(r.x,r.base),a=r.y-s,o=r.y+s}return{left:e,top:a,right:n,bottom:o}}var o=t(25),r=t(26);o._set("global",{elements:{rectangle:{backgroundColor:o.global.defaultColor,borderColor:o.global.defaultColor,borderSkipped:"bottom",borderWidth:0}}}),e.exports=r.extend({draw:function(){function t(t){return m[(b+t)%4]}var e,n,i,a,o,r,l,s=this._chart.ctx,u=this._view,d=u.borderWidth;if(u.horizontal?(e=u.base,n=u.x,i=u.y-u.height/2,a=u.y+u.height/2,o=n>e?1:-1,r=1,l=u.borderSkipped||"left"):(e=u.x-u.width/2,n=u.x+u.width/2,i=u.y,o=1,r=(a=u.base)>i?1:-1,l=u.borderSkipped||"bottom"),d){var c=Math.min(Math.abs(e-n),Math.abs(i-a)),h=(d=d>c?c:d)/2,f=e+("left"!==l?h*o:0),g=n+("right"!==l?-h*o:0),p=i+("top"!==l?h*r:0),v=a+("bottom"!==l?-h*r:0);f!==g&&(i=p,a=v),p!==v&&(e=f,n=g)}s.beginPath(),s.fillStyle=u.backgroundColor,s.strokeStyle=u.borderColor,s.lineWidth=d;var m=[[e,a],[e,i],[n,i],[n,a]],b=["bottom","left","top","right"].indexOf(l,0);-1===b&&(b=0);var x=t(0);s.moveTo(x[0],x[1]);for(var y=1;y<4;y++)x=t(y),s.lineTo(x[0],x[1]);s.fill(),d&&s.stroke()},height:function(){var t=this._view;return t.base-t.y},inRange:function(t,e){var n=!1;if(this._view){var i=a(this);n=t>=i.left&&t<=i.right&&e>=i.top&&e<=i.bottom}return n},inLabelRange:function(t,e){var n=this;if(!n._view)return!1;var o=a(n);return i(n)?t>=o.left&&t<=o.right:e>=o.top&&e<=o.bottom},inXRange:function(t){var e=a(this);return t>=e.left&&t<=e.right},inYRange:function(t){var e=a(this);return t>=e.top&&t<=e.bottom},getCenterPoint:function(){var t,e,n=this._view;return i(this)?(t=n.x,e=(n.y+n.base)/2):(t=(n.x+n.base)/2,e=n.y),{x:t,y:e}},getArea:function(){var t=this._view;return t.width*Math.abs(t.y-t.base)},tooltipPosition:function(){var t=this._view;return{x:t.x,y:t.y}}})},{25:25,26:26}],40:[function(t,e,n){"use strict";e.exports={},e.exports.Arc=t(36),e.exports.Line=t(37),e.exports.Point=t(38),e.exports.Rectangle=t(39)},{36:36,37:37,38:38,39:39}],41:[function(t,e,n){"use strict";var i=t(42),n=e.exports={clear:function(t){t.ctx.clearRect(0,0,t.width,t.height)},roundedRect:function(t,e,n,i,a,o){if(o){var r=Math.min(o,i/2),l=Math.min(o,a/2);t.moveTo(e+r,n),t.lineTo(e+i-r,n),t.quadraticCurveTo(e+i,n,e+i,n+l),t.lineTo(e+i,n+a-l),t.quadraticCurveTo(e+i,n+a,e+i-r,n+a),t.lineTo(e+r,n+a),t.quadraticCurveTo(e,n+a,e,n+a-l),t.lineTo(e,n+l),t.quadraticCurveTo(e,n,e+r,n)}else t.rect(e,n,i,a)},drawPoint:function(t,e,n,i,a){var o,r,l,s,u,d;if(!e||"object"!=typeof e||"[object HTMLImageElement]"!==(o=e.toString())&&"[object HTMLCanvasElement]"!==o){if(!(isNaN(n)||n<=0)){switch(e){default:t.beginPath(),t.arc(i,a,n,0,2*Math.PI),t.closePath(),t.fill();break;case"triangle":t.beginPath(),u=(r=3*n/Math.sqrt(3))*Math.sqrt(3)/2,t.moveTo(i-r/2,a+u/3),t.lineTo(i+r/2,a+u/3),t.lineTo(i,a-2*u/3),t.closePath(),t.fill();break;case"rect":d=1/Math.SQRT2*n,t.beginPath(),t.fillRect(i-d,a-d,2*d,2*d),t.strokeRect(i-d,a-d,2*d,2*d);break;case"rectRounded":var c=n/Math.SQRT2,h=i-c,f=a-c,g=Math.SQRT2*n;t.beginPath(),this.roundedRect(t,h,f,g,g,n/2),t.closePath(),t.fill();break;case"rectRot":d=1/Math.SQRT2*n,t.beginPath(),t.moveTo(i-d,a),t.lineTo(i,a+d),t.lineTo(i+d,a),t.lineTo(i,a-d),t.closePath(),t.fill();break;case"cross":t.beginPath(),t.moveTo(i,a+n),t.lineTo(i,a-n),t.moveTo(i-n,a),t.lineTo(i+n,a),t.closePath();break;case"crossRot":t.beginPath(),l=Math.cos(Math.PI/4)*n,s=Math.sin(Math.PI/4)*n,t.moveTo(i-l,a-s),t.lineTo(i+l,a+s),t.moveTo(i-l,a+s),t.lineTo(i+l,a-s),t.closePath();break;case"star":t.beginPath(),t.moveTo(i,a+n),t.lineTo(i,a-n),t.moveTo(i-n,a),t.lineTo(i+n,a),l=Math.cos(Math.PI/4)*n,s=Math.sin(Math.PI/4)*n,t.moveTo(i-l,a-s),t.lineTo(i+l,a+s),t.moveTo(i-l,a+s),t.lineTo(i+l,a-s),t.closePath();break;case"line":t.beginPath(),t.moveTo(i-n,a),t.lineTo(i+n,a),t.closePath();break;case"dash":t.beginPath(),t.moveTo(i,a),t.lineTo(i+n,a),t.closePath()}t.stroke()}}else t.drawImage(e,i-e.width/2,a-e.height/2,e.width,e.height)},clipArea:function(t,e){t.save(),t.beginPath(),t.rect(e.left,e.top,e.right-e.left,e.bottom-e.top),t.clip()},unclipArea:function(t){t.restore()},lineTo:function(t,e,n,i){if(n.steppedLine)return"after"===n.steppedLine&&!i||"after"!==n.steppedLine&&i?t.lineTo(e.x,n.y):t.lineTo(n.x,e.y),void t.lineTo(n.x,n.y);n.tension?t.bezierCurveTo(i?e.controlPointPreviousX:e.controlPointNextX,i?e.controlPointPreviousY:e.controlPointNextY,i?n.controlPointNextX:n.controlPointPreviousX,i?n.controlPointNextY:n.controlPointPreviousY,n.x,n.y):t.lineTo(n.x,n.y)}};i.clear=n.clear,i.drawRoundedRectangle=function(t){t.beginPath(),n.roundedRect.apply(n,arguments),t.closePath()}},{42:42}],42:[function(t,e,n){"use strict";var i={noop:function(){},uid:function(){var t=0;return function(){return t++}}(),isNullOrUndef:function(t){return null===t||void 0===t},isArray:Array.isArray?Array.isArray:function(t){return"[object Array]"===Object.prototype.toString.call(t)},isObject:function(t){return null!==t&&"[object Object]"===Object.prototype.toString.call(t)},valueOrDefault:function(t,e){return void 0===t?e:t},valueAtIndexOrDefault:function(t,e,n){return i.valueOrDefault(i.isArray(t)?t[e]:t,n)},callback:function(t,e,n){if(t&&"function"==typeof t.call)return t.apply(n,e)},each:function(t,e,n,a){var o,r,l;if(i.isArray(t))if(r=t.length,a)for(o=r-1;o>=0;o--)e.call(n,t[o],o);else for(o=0;o<r;o++)e.call(n,t[o],o);else if(i.isObject(t))for(r=(l=Object.keys(t)).length,o=0;o<r;o++)e.call(n,t[l[o]],l[o])},arrayEquals:function(t,e){var n,a,o,r;if(!t||!e||t.length!==e.length)return!1;for(n=0,a=t.length;n<a;++n)if(o=t[n],r=e[n],o instanceof Array&&r instanceof Array){if(!i.arrayEquals(o,r))return!1}else if(o!==r)return!1;return!0},clone:function(t){if(i.isArray(t))return t.map(i.clone);if(i.isObject(t)){for(var e={},n=Object.keys(t),a=n.length,o=0;o<a;++o)e[n[o]]=i.clone(t[n[o]]);return e}return t},_merger:function(t,e,n,a){var o=e[t],r=n[t];i.isObject(o)&&i.isObject(r)?i.merge(o,r,a):e[t]=i.clone(r)},_mergerIf:function(t,e,n){var a=e[t],o=n[t];i.isObject(a)&&i.isObject(o)?i.mergeIf(a,o):e.hasOwnProperty(t)||(e[t]=i.clone(o))},merge:function(t,e,n){var a,o,r,l,s,u=i.isArray(e)?e:[e],d=u.length;if(!i.isObject(t))return t;for(a=(n=n||{}).merger||i._merger,o=0;o<d;++o)if(e=u[o],i.isObject(e))for(s=0,l=(r=Object.keys(e)).length;s<l;++s)a(r[s],t,e,n);return t},mergeIf:function(t,e){return i.merge(t,e,{merger:i._mergerIf})},extend:function(t){for(var e=1,n=arguments.length;e<n;++e)i.each(arguments[e],function(e,n){t[n]=e});return t},inherits:function(t){var e=this,n=t&&t.hasOwnProperty("constructor")?t.constructor:function(){return e.apply(this,arguments)},a=function(){this.constructor=n};return a.prototype=e.prototype,n.prototype=new a,n.extend=i.inherits,t&&i.extend(n.prototype,t),n.__super__=e.prototype,n}};e.exports=i,i.callCallback=i.callback,i.indexOf=function(t,e,n){return Array.prototype.indexOf.call(t,e,n)},i.getValueOrDefault=i.valueOrDefault,i.getValueAtIndexOrDefault=i.valueAtIndexOrDefault},{}],43:[function(t,e,n){"use strict";var i=t(42),a={linear:function(t){return t},easeInQuad:function(t){return t*t},easeOutQuad:function(t){return-t*(t-2)},easeInOutQuad:function(t){return(t/=.5)<1?.5*t*t:-.5*(--t*(t-2)-1)},easeInCubic:function(t){return t*t*t},easeOutCubic:function(t){return(t-=1)*t*t+1},easeInOutCubic:function(t){return(t/=.5)<1?.5*t*t*t:.5*((t-=2)*t*t+2)},easeInQuart:function(t){return t*t*t*t},easeOutQuart:function(t){return-((t-=1)*t*t*t-1)},easeInOutQuart:function(t){return(t/=.5)<1?.5*t*t*t*t:-.5*((t-=2)*t*t*t-2)},easeInQuint:function(t){return t*t*t*t*t},easeOutQuint:function(t){return(t-=1)*t*t*t*t+1},easeInOutQuint:function(t){return(t/=.5)<1?.5*t*t*t*t*t:.5*((t-=2)*t*t*t*t+2)},easeInSine:function(t){return 1-Math.cos(t*(Math.PI/2))},easeOutSine:function(t){return Math.sin(t*(Math.PI/2))},easeInOutSine:function(t){return-.5*(Math.cos(Math.PI*t)-1)},easeInExpo:function(t){return 0===t?0:Math.pow(2,10*(t-1))},easeOutExpo:function(t){return 1===t?1:1-Math.pow(2,-10*t)},easeInOutExpo:function(t){return 0===t?0:1===t?1:(t/=.5)<1?.5*Math.pow(2,10*(t-1)):.5*(2-Math.pow(2,-10*--t))},easeInCirc:function(t){return t>=1?t:-(Math.sqrt(1-t*t)-1)},easeOutCirc:function(t){return Math.sqrt(1-(t-=1)*t)},easeInOutCirc:function(t){return(t/=.5)<1?-.5*(Math.sqrt(1-t*t)-1):.5*(Math.sqrt(1-(t-=2)*t)+1)},easeInElastic:function(t){var e=1.70158,n=0,i=1;return 0===t?0:1===t?1:(n||(n=.3),i<1?(i=1,e=n/4):e=n/(2*Math.PI)*Math.asin(1/i),-i*Math.pow(2,10*(t-=1))*Math.sin((t-e)*(2*Math.PI)/n))},easeOutElastic:function(t){var e=1.70158,n=0,i=1;return 0===t?0:1===t?1:(n||(n=.3),i<1?(i=1,e=n/4):e=n/(2*Math.PI)*Math.asin(1/i),i*Math.pow(2,-10*t)*Math.sin((t-e)*(2*Math.PI)/n)+1)},easeInOutElastic:function(t){var e=1.70158,n=0,i=1;return 0===t?0:2==(t/=.5)?1:(n||(n=.45),i<1?(i=1,e=n/4):e=n/(2*Math.PI)*Math.asin(1/i),t<1?i*Math.pow(2,10*(t-=1))*Math.sin((t-e)*(2*Math.PI)/n)*-.5:i*Math.pow(2,-10*(t-=1))*Math.sin((t-e)*(2*Math.PI)/n)*.5+1)},easeInBack:function(t){var e=1.70158;return t*t*((e+1)*t-e)},easeOutBack:function(t){var e=1.70158;return(t-=1)*t*((e+1)*t+e)+1},easeInOutBack:function(t){var e=1.70158;return(t/=.5)<1?t*t*((1+(e*=1.525))*t-e)*.5:.5*((t-=2)*t*((1+(e*=1.525))*t+e)+2)},easeInBounce:function(t){return 1-a.easeOutBounce(1-t)},easeOutBounce:function(t){return t<1/2.75?7.5625*t*t:t<2/2.75?7.5625*(t-=1.5/2.75)*t+.75:t<2.5/2.75?7.5625*(t-=2.25/2.75)*t+.9375:7.5625*(t-=2.625/2.75)*t+.984375},easeInOutBounce:function(t){return t<.5?.5*a.easeInBounce(2*t):.5*a.easeOutBounce(2*t-1)+.5}};e.exports={effects:a},i.easingEffects=a},{42:42}],44:[function(t,e,n){"use strict";var i=t(42);e.exports={toLineHeight:function(t,e){var n=(""+t).match(/^(normal|(\d+(?:\.\d+)?)(px|em|%)?)$/);if(!n||"normal"===n[1])return 1.2*e;switch(t=+n[2],n[3]){case"px":return t;case"%":t/=100}return e*t},toPadding:function(t){var e,n,a,o;return i.isObject(t)?(e=+t.top||0,n=+t.right||0,a=+t.bottom||0,o=+t.left||0):e=n=a=o=+t||0,{top:e,right:n,bottom:a,left:o,height:e+a,width:o+n}},resolve:function(t,e,n){var a,o,r;for(a=0,o=t.length;a<o;++a)if(void 0!==(r=t[a])&&(void 0!==e&&"function"==typeof r&&(r=r(e)),void 0!==n&&i.isArray(r)&&(r=r[n]),void 0!==r))return r}}},{42:42}],45:[function(t,e,n){"use strict";e.exports=t(42),e.exports.easing=t(43),e.exports.canvas=t(41),e.exports.options=t(44)},{41:41,42:42,43:43,44:44}],46:[function(t,e,n){e.exports={acquireContext:function(t){return t&&t.canvas&&(t=t.canvas),t&&t.getContext("2d")||null}}},{}],47:[function(t,e,n){"use strict";function i(t,e){var n=v.getStyle(t,e),i=n&&n.match(/^(\d+)(\.\d+)?px$/);return i?Number(i[1]):void 0}function a(t,e){var n=t.style,a=t.getAttribute("height"),o=t.getAttribute("width");if(t[m]={initial:{height:a,width:o,style:{display:n.display,height:n.height,width:n.width}}},n.display=n.display||"block",null===o||""===o){var r=i(t,"width");void 0!==r&&(t.width=r)}if(null===a||""===a)if(""===t.style.height)t.height=t.width/(e.options.aspectRatio||2);else{var l=i(t,"height");void 0!==r&&(t.height=l)}return t}function o(t,e,n){t.addEventListener(e,n,M)}function r(t,e,n){t.removeEventListener(e,n,M)}function l(t,e,n,i,a){return{type:t,chart:e,native:a||null,x:void 0!==n?n:null,y:void 0!==i?i:null}}function s(t,e){var n=w[t.type]||t.type,i=v.getRelativePosition(t,e);return l(n,e,i.x,i.y,t)}function u(t,e){var n=!1,i=[];return function(){i=Array.prototype.slice.call(arguments),e=e||this,n||(n=!0,v.requestAnimFrame.call(window,function(){n=!1,t.apply(e,i)}))}}function d(t){var e=document.createElement("div"),n=b+"size-monitor",i="position:absolute;left:0;top:0;right:0;bottom:0;overflow:hidden;pointer-events:none;visibility:hidden;z-index:-1;";e.style.cssText=i,e.className=n,e.innerHTML='<div class="'+n+'-expand" style="'+i+'"><div style="position:absolute;width:1000000px;height:1000000px;left:0;top:0"></div></div><div class="'+n+'-shrink" style="'+i+'"><div style="position:absolute;width:200%;height:200%;left:0; top:0"></div></div>';var a=e.childNodes[0],r=e.childNodes[1];e._reset=function(){a.scrollLeft=1e6,a.scrollTop=1e6,r.scrollLeft=1e6,r.scrollTop=1e6};var l=function(){e._reset(),t()};return o(a,"scroll",l.bind(a,"expand")),o(r,"scroll",l.bind(r,"shrink")),e}function c(t,e){var n=t[m]||(t[m]={}),i=n.renderProxy=function(t){t.animationName===y&&e()};v.each(k,function(e){o(t,e,i)}),n.reflow=!!t.offsetParent,t.classList.add(x)}function h(t){var e=t[m]||{},n=e.renderProxy;n&&(v.each(k,function(e){r(t,e,n)}),delete e.renderProxy),t.classList.remove(x)}function f(t,e,n){var i=t[m]||(t[m]={}),a=i.resizer=d(u(function(){if(i.resizer)return e(l("resize",n))}));c(t,function(){if(i.resizer){var e=t.parentNode;e&&e!==a.parentNode&&e.insertBefore(a,e.firstChild),a._reset()}})}function g(t){var e=t[m]||{},n=e.resizer;delete e.resizer,h(t),n&&n.parentNode&&n.parentNode.removeChild(n)}function p(t,e){var n=t._style||document.createElement("style");t._style||(t._style=n,e="/* Chart.js */\n"+e,n.setAttribute("type","text/css"),document.getElementsByTagName("head")[0].appendChild(n)),n.appendChild(document.createTextNode(e))}var v=t(45),m="$chartjs",b="chartjs-",x=b+"render-monitor",y=b+"render-animation",k=["animationstart","webkitAnimationStart"],w={touchstart:"mousedown",touchmove:"mousemove",touchend:"mouseup",pointerenter:"mouseenter",pointerdown:"mousedown",pointermove:"mousemove",pointerup:"mouseup",pointerleave:"mouseout",pointerout:"mouseout"},M=!!function(){var t=!1;try{var e=Object.defineProperty({},"passive",{get:function(){t=!0}});window.addEventListener("e",null,e)}catch(t){}return t}()&&{passive:!0};e.exports={_enabled:"undefined"!=typeof window&&"undefined"!=typeof document,initialize:function(){var t="from{opacity:0.99}to{opacity:1}";p(this,"@-webkit-keyframes "+y+"{"+t+"}@keyframes "+y+"{"+t+"}."+x+"{-webkit-animation:"+y+" 0.001s;animation:"+y+" 0.001s;}")},acquireContext:function(t,e){"string"==typeof t?t=document.getElementById(t):t.length&&(t=t[0]),t&&t.canvas&&(t=t.canvas);var n=t&&t.getContext&&t.getContext("2d");return n&&n.canvas===t?(a(t,e),n):null},releaseContext:function(t){var e=t.canvas;if(e[m]){var n=e[m].initial;["height","width"].forEach(function(t){var i=n[t];v.isNullOrUndef(i)?e.removeAttribute(t):e.setAttribute(t,i)}),v.each(n.style||{},function(t,n){e.style[n]=t}),e.width=e.width,delete e[m]}},addEventListener:function(t,e,n){var i=t.canvas;if("resize"!==e){var a=n[m]||(n[m]={});o(i,e,(a.proxies||(a.proxies={}))[t.id+"_"+e]=function(e){n(s(e,t))})}else f(i,n,t)},removeEventListener:function(t,e,n){var i=t.canvas;if("resize"!==e){var a=((n[m]||{}).proxies||{})[t.id+"_"+e];a&&r(i,e,a)}else g(i)}},v.addEvent=o,v.removeEvent=r},{45:45}],48:[function(t,e,n){"use strict";var i=t(45),a=t(46),o=t(47),r=o._enabled?o:a;e.exports=i.extend({initialize:function(){},acquireContext:function(){},releaseContext:function(){},addEventListener:function(){},removeEventListener:function(){}},r)},{45:45,46:46,47:47}],49:[function(t,e,n){"use strict";var i=t(25),a=t(40),o=t(45);i._set("global",{plugins:{filler:{propagate:!0}}}),e.exports=function(){function t(t,e,n){var i,a=t._model||{},o=a.fill;if(void 0===o&&(o=!!a.backgroundColor),!1===o||null===o)return!1;if(!0===o)return"origin";if(i=parseFloat(o,10),isFinite(i)&&Math.floor(i)===i)return"-"!==o[0]&&"+"!==o[0]||(i=e+i),!(i===e||i<0||i>=n)&&i;switch(o){case"bottom":return"start";case"top":return"end";case"zero":return"origin";case"origin":case"start":case"end":return o;default:return!1}}function e(t){var e,n=t.el._model||{},i=t.el._scale||{},a=t.fill,o=null;if(isFinite(a))return null;if("start"===a?o=void 0===n.scaleBottom?i.bottom:n.scaleBottom:"end"===a?o=void 0===n.scaleTop?i.top:n.scaleTop:void 0!==n.scaleZero?o=n.scaleZero:i.getBasePosition?o=i.getBasePosition():i.getBasePixel&&(o=i.getBasePixel()),void 0!==o&&null!==o){if(void 0!==o.x&&void 0!==o.y)return o;if("number"==typeof o&&isFinite(o))return e=i.isHorizontal(),{x:e?o:null,y:e?null:o}}return null}function n(t,e,n){var i,a=t[e].fill,o=[e];if(!n)return a;for(;!1!==a&&-1===o.indexOf(a);){if(!isFinite(a))return a;if(!(i=t[a]))return!1;if(i.visible)return a;o.push(a),a=i.fill}return!1}function r(t){var e=t.fill,n="dataset";return!1===e?null:(isFinite(e)||(n="boundary"),d[n](t))}function l(t){return t&&!t.skip}function s(t,e,n,i,a){var r;if(i&&a){for(t.moveTo(e[0].x,e[0].y),r=1;r<i;++r)o.canvas.lineTo(t,e[r-1],e[r]);for(t.lineTo(n[a-1].x,n[a-1].y),r=a-1;r>0;--r)o.canvas.lineTo(t,n[r],n[r-1],!0)}}function u(t,e,n,i,a,o){var r,u,d,c,h,f,g,p=e.length,v=i.spanGaps,m=[],b=[],x=0,y=0;for(t.beginPath(),r=0,u=p+!!o;r<u;++r)h=n(c=e[d=r%p]._view,d,i),f=l(c),g=l(h),f&&g?(x=m.push(c),y=b.push(h)):x&&y&&(v?(f&&m.push(c),g&&b.push(h)):(s(t,m,b,x,y),x=y=0,m=[],b=[]));s(t,m,b,x,y),t.closePath(),t.fillStyle=a,t.fill()}var d={dataset:function(t){var e=t.fill,n=t.chart,i=n.getDatasetMeta(e),a=i&&n.isDatasetVisible(e)&&i.dataset._children||[],o=a.length||0;return o?function(t,e){return e<o&&a[e]._view||null}:null},boundary:function(t){var e=t.boundary,n=e?e.x:null,i=e?e.y:null;return function(t){return{x:null===n?t.x:n,y:null===i?t.y:i}}}};return{id:"filler",afterDatasetsUpdate:function(i,o){var l,s,u,d,c=(i.data.datasets||[]).length,h=o.propagate,f=[];for(s=0;s<c;++s)d=null,(u=(l=i.getDatasetMeta(s)).dataset)&&u._model&&u instanceof a.Line&&(d={visible:i.isDatasetVisible(s),fill:t(u,s,c),chart:i,el:u}),l.$filler=d,f.push(d);for(s=0;s<c;++s)(d=f[s])&&(d.fill=n(f,s,h),d.boundary=e(d),d.mapper=r(d))},beforeDatasetDraw:function(t,e){var n=e.meta.$filler;if(n){var a=t.ctx,r=n.el,l=r._view,s=r._children||[],d=n.mapper,c=l.backgroundColor||i.global.defaultColor;d&&c&&s.length&&(o.canvas.clipArea(a,t.chartArea),u(a,s,d,l,c,r._loop),o.canvas.unclipArea(a))}}}}},{25:25,40:40,45:45}],50:[function(t,e,n){"use strict";var i=t(25),a=t(26),o=t(45);i._set("global",{legend:{display:!0,position:"top",fullWidth:!0,reverse:!1,weight:1e3,onClick:function(t,e){var n=e.datasetIndex,i=this.chart,a=i.getDatasetMeta(n);a.hidden=null===a.hidden?!i.data.datasets[n].hidden:null,i.update()},onHover:null,labels:{boxWidth:40,padding:10,generateLabels:function(t){var e=t.data;return o.isArray(e.datasets)?e.datasets.map(function(e,n){return{text:e.label,fillStyle:o.isArray(e.backgroundColor)?e.backgroundColor[0]:e.backgroundColor,hidden:!t.isDatasetVisible(n),lineCap:e.borderCapStyle,lineDash:e.borderDash,lineDashOffset:e.borderDashOffset,lineJoin:e.borderJoinStyle,lineWidth:e.borderWidth,strokeStyle:e.borderColor,pointStyle:e.pointStyle,datasetIndex:n}},this):[]}}},legendCallback:function(t){var e=[];e.push('<ul class="'+t.id+'-legend">');for(var n=0;n<t.data.datasets.length;n++)e.push('<li><span style="background-color:'+t.data.datasets[n].backgroundColor+'"></span>'),t.data.datasets[n].label&&e.push(t.data.datasets[n].label),e.push("</li>");return e.push("</ul>"),e.join("")}}),e.exports=function(t){function e(t,e){return t.usePointStyle?e*Math.SQRT2:t.boxWidth}function n(e,n){var i=new t.Legend({ctx:e.ctx,options:n,chart:e});r.configure(e,i,n),r.addBox(e,i),e.legend=i}var r=t.layoutService,l=o.noop;return t.Legend=a.extend({initialize:function(t){o.extend(this,t),this.legendHitBoxes=[],this.doughnutMode=!1},beforeUpdate:l,update:function(t,e,n){var i=this;return i.beforeUpdate(),i.maxWidth=t,i.maxHeight=e,i.margins=n,i.beforeSetDimensions(),i.setDimensions(),i.afterSetDimensions(),i.beforeBuildLabels(),i.buildLabels(),i.afterBuildLabels(),i.beforeFit(),i.fit(),i.afterFit(),i.afterUpdate(),i.minSize},afterUpdate:l,beforeSetDimensions:l,setDimensions:function(){var t=this;t.isHorizontal()?(t.width=t.maxWidth,t.left=0,t.right=t.width):(t.height=t.maxHeight,t.top=0,t.bottom=t.height),t.paddingLeft=0,t.paddingTop=0,t.paddingRight=0,t.paddingBottom=0,t.minSize={width:0,height:0}},afterSetDimensions:l,beforeBuildLabels:l,buildLabels:function(){var t=this,e=t.options.labels||{},n=o.callback(e.generateLabels,[t.chart],t)||[];e.filter&&(n=n.filter(function(n){return e.filter(n,t.chart.data)})),t.options.reverse&&n.reverse(),t.legendItems=n},afterBuildLabels:l,beforeFit:l,fit:function(){var t=this,n=t.options,a=n.labels,r=n.display,l=t.ctx,s=i.global,u=o.valueOrDefault,d=u(a.fontSize,s.defaultFontSize),c=u(a.fontStyle,s.defaultFontStyle),h=u(a.fontFamily,s.defaultFontFamily),f=o.fontString(d,c,h),g=t.legendHitBoxes=[],p=t.minSize,v=t.isHorizontal();if(v?(p.width=t.maxWidth,p.height=r?10:0):(p.width=r?10:0,p.height=t.maxHeight),r)if(l.font=f,v){var m=t.lineWidths=[0],b=t.legendItems.length?d+a.padding:0;l.textAlign="left",l.textBaseline="top",o.each(t.legendItems,function(n,i){var o=e(a,d)+d/2+l.measureText(n.text).width;m[m.length-1]+o+a.padding>=t.width&&(b+=d+a.padding,m[m.length]=t.left),g[i]={left:0,top:0,width:o,height:d},m[m.length-1]+=o+a.padding}),p.height+=b}else{var x=a.padding,y=t.columnWidths=[],k=a.padding,w=0,M=0,S=d+x;o.each(t.legendItems,function(t,n){var i=e(a,d)+d/2+l.measureText(t.text).width;M+S>p.height&&(k+=w+a.padding,y.push(w),w=0,M=0),w=Math.max(w,i),M+=S,g[n]={left:0,top:0,width:i,height:d}}),k+=w,y.push(w),p.width+=k}t.width=p.width,t.height=p.height},afterFit:l,isHorizontal:function(){return"top"===this.options.position||"bottom"===this.options.position},draw:function(){var t=this,n=t.options,a=n.labels,r=i.global,l=r.elements.line,s=t.width,u=t.lineWidths;if(n.display){var d,c=t.ctx,h=o.valueOrDefault,f=h(a.fontColor,r.defaultFontColor),g=h(a.fontSize,r.defaultFontSize),p=h(a.fontStyle,r.defaultFontStyle),v=h(a.fontFamily,r.defaultFontFamily),m=o.fontString(g,p,v);c.textAlign="left",c.textBaseline="middle",c.lineWidth=.5,c.strokeStyle=f,c.fillStyle=f,c.font=m;var b=e(a,g),x=t.legendHitBoxes,y=function(t,e,i){if(!(isNaN(b)||b<=0)){c.save(),c.fillStyle=h(i.fillStyle,r.defaultColor),c.lineCap=h(i.lineCap,l.borderCapStyle),c.lineDashOffset=h(i.lineDashOffset,l.borderDashOffset),c.lineJoin=h(i.lineJoin,l.borderJoinStyle),c.lineWidth=h(i.lineWidth,l.borderWidth),c.strokeStyle=h(i.strokeStyle,r.defaultColor);var a=0===h(i.lineWidth,l.borderWidth);if(c.setLineDash&&c.setLineDash(h(i.lineDash,l.borderDash)),n.labels&&n.labels.usePointStyle){var s=g*Math.SQRT2/2,u=s/Math.SQRT2,d=t+u,f=e+u;o.canvas.drawPoint(c,i.pointStyle,s,d,f)}else a||c.strokeRect(t,e,b,g),c.fillRect(t,e,b,g);c.restore()}},k=function(t,e,n,i){var a=g/2,o=b+a+t,r=e+a;c.fillText(n.text,o,r),n.hidden&&(c.beginPath(),c.lineWidth=2,c.moveTo(o,r),c.lineTo(o+i,r),c.stroke())},w=t.isHorizontal();d=w?{x:t.left+(s-u[0])/2,y:t.top+a.padding,line:0}:{x:t.left+a.padding,y:t.top+a.padding,line:0};var M=g+a.padding;o.each(t.legendItems,function(e,n){var i=c.measureText(e.text).width,o=b+g/2+i,r=d.x,l=d.y;w?r+o>=s&&(l=d.y+=M,d.line++,r=d.x=t.left+(s-u[d.line])/2):l+M>t.bottom&&(r=d.x=r+t.columnWidths[d.line]+a.padding,l=d.y=t.top+a.padding,d.line++),y(r,l,e),x[n].left=r,x[n].top=l,k(r,l,e,i),w?d.x+=o+a.padding:d.y+=M})}},handleEvent:function(t){var e=this,n=e.options,i="mouseup"===t.type?"click":t.type,a=!1;if("mousemove"===i){if(!n.onHover)return}else{if("click"!==i)return;if(!n.onClick)return}var o=t.x,r=t.y;if(o>=e.left&&o<=e.right&&r>=e.top&&r<=e.bottom)for(var l=e.legendHitBoxes,s=0;s<l.length;++s){var u=l[s];if(o>=u.left&&o<=u.left+u.width&&r>=u.top&&r<=u.top+u.height){if("click"===i){n.onClick.call(e,t.native,e.legendItems[s]),a=!0;break}if("mousemove"===i){n.onHover.call(e,t.native,e.legendItems[s]),a=!0;break}}}return a}}),{id:"legend",beforeInit:function(t){var e=t.options.legend;e&&n(t,e)},beforeUpdate:function(t){var e=t.options.legend,a=t.legend;e?(o.mergeIf(e,i.global.legend),a?(r.configure(t,a,e),a.options=e):n(t,e)):a&&(r.removeBox(t,a),delete t.legend)},afterEvent:function(t,e){var n=t.legend;n&&n.handleEvent(e)}}}},{25:25,26:26,45:45}],51:[function(t,e,n){"use strict";var i=t(25),a=t(26),o=t(45);i._set("global",{title:{display:!1,fontStyle:"bold",fullWidth:!0,lineHeight:1.2,padding:10,position:"top",text:"",weight:2e3}}),e.exports=function(t){function e(e,i){var a=new t.Title({ctx:e.ctx,options:i,chart:e});n.configure(e,a,i),n.addBox(e,a),e.titleBlock=a}var n=t.layoutService,r=o.noop;return t.Title=a.extend({initialize:function(t){var e=this;o.extend(e,t),e.legendHitBoxes=[]},beforeUpdate:r,update:function(t,e,n){var i=this;return i.beforeUpdate(),i.maxWidth=t,i.maxHeight=e,i.margins=n,i.beforeSetDimensions(),i.setDimensions(),i.afterSetDimensions(),i.beforeBuildLabels(),i.buildLabels(),i.afterBuildLabels(),i.beforeFit(),i.fit(),i.afterFit(),i.afterUpdate(),i.minSize},afterUpdate:r,beforeSetDimensions:r,setDimensions:function(){var t=this;t.isHorizontal()?(t.width=t.maxWidth,t.left=0,t.right=t.width):(t.height=t.maxHeight,t.top=0,t.bottom=t.height),t.paddingLeft=0,t.paddingTop=0,t.paddingRight=0,t.paddingBottom=0,t.minSize={width:0,height:0}},afterSetDimensions:r,beforeBuildLabels:r,buildLabels:r,afterBuildLabels:r,beforeFit:r,fit:function(){var t=this,e=o.valueOrDefault,n=t.options,a=n.display,r=e(n.fontSize,i.global.defaultFontSize),l=t.minSize,s=o.isArray(n.text)?n.text.length:1,u=o.options.toLineHeight(n.lineHeight,r),d=a?s*u+2*n.padding:0;t.isHorizontal()?(l.width=t.maxWidth,l.height=d):(l.width=d,l.height=t.maxHeight),t.width=l.width,t.height=l.height},afterFit:r,isHorizontal:function(){var t=this.options.position;return"top"===t||"bottom"===t},draw:function(){var t=this,e=t.ctx,n=o.valueOrDefault,a=t.options,r=i.global;if(a.display){var l,s,u,d=n(a.fontSize,r.defaultFontSize),c=n(a.fontStyle,r.defaultFontStyle),h=n(a.fontFamily,r.defaultFontFamily),f=o.fontString(d,c,h),g=o.options.toLineHeight(a.lineHeight,d),p=g/2+a.padding,v=0,m=t.top,b=t.left,x=t.bottom,y=t.right;e.fillStyle=n(a.fontColor,r.defaultFontColor),e.font=f,t.isHorizontal()?(s=b+(y-b)/2,u=m+p,l=y-b):(s="left"===a.position?b+p:y-p,u=m+(x-m)/2,l=x-m,v=Math.PI*("left"===a.position?-.5:.5)),e.save(),e.translate(s,u),e.rotate(v),e.textAlign="center",e.textBaseline="middle";var k=a.text;if(o.isArray(k))for(var w=0,M=0;M<k.length;++M)e.fillText(k[M],0,w,l),w+=g;else e.fillText(k,0,0,l);e.restore()}}}),{id:"title",beforeInit:function(t){var n=t.options.title;n&&e(t,n)},beforeUpdate:function(a){var r=a.options.title,l=a.titleBlock;r?(o.mergeIf(r,i.global.title),l?(n.configure(a,l,r),l.options=r):e(a,r)):l&&(t.layoutService.removeBox(a,l),delete a.titleBlock)}}}},{25:25,26:26,45:45}],52:[function(t,e,n){"use strict";e.exports=function(t){var e=t.Scale.extend({getLabels:function(){var t=this.chart.data;return this.options.labels||(this.isHorizontal()?t.xLabels:t.yLabels)||t.labels},determineDataLimits:function(){var t=this,e=t.getLabels();t.minIndex=0,t.maxIndex=e.length-1;var n;void 0!==t.options.ticks.min&&(n=e.indexOf(t.options.ticks.min),t.minIndex=-1!==n?n:t.minIndex),void 0!==t.options.ticks.max&&(n=e.indexOf(t.options.ticks.max),t.maxIndex=-1!==n?n:t.maxIndex),t.min=e[t.minIndex],t.max=e[t.maxIndex]},buildTicks:function(){var t=this,e=t.getLabels();t.ticks=0===t.minIndex&&t.maxIndex===e.length-1?e:e.slice(t.minIndex,t.maxIndex+1)},getLabelForIndex:function(t,e){var n=this,i=n.chart.data,a=n.isHorizontal();return i.yLabels&&!a?n.getRightValue(i.datasets[e].data[t]):n.ticks[t-n.minIndex]},getPixelForValue:function(t,e){var n,i=this,a=i.options.offset,o=Math.max(i.maxIndex+1-i.minIndex-(a?0:1),1);if(void 0!==t&&null!==t&&(n=i.isHorizontal()?t.x:t.y),void 0!==n||void 0!==t&&isNaN(e)){var r=i.getLabels();t=n||t;var l=r.indexOf(t);e=-1!==l?l:e}if(i.isHorizontal()){var s=i.width/o,u=s*(e-i.minIndex);return a&&(u+=s/2),i.left+Math.round(u)}var d=i.height/o,c=d*(e-i.minIndex);return a&&(c+=d/2),i.top+Math.round(c)},getPixelForTick:function(t){return this.getPixelForValue(this.ticks[t],t+this.minIndex,null)},getValueForPixel:function(t){var e=this,n=e.options.offset,i=Math.max(e._ticks.length-(n?0:1),1),a=e.isHorizontal(),o=(a?e.width:e.height)/i;return t-=a?e.left:e.top,n&&(t-=o/2),(t<=0?0:Math.round(t/o))+e.minIndex},getBasePixel:function(){return this.bottom}});t.scaleService.registerScaleType("category",e,{position:"bottom"})}},{}],53:[function(t,e,n){"use strict";var i=t(25),a=t(45),o=t(34);e.exports=function(t){var e={position:"left",ticks:{callback:o.formatters.linear}},n=t.LinearScaleBase.extend({determineDataLimits:function(){function t(t){return r?t.xAxisID===e.id:t.yAxisID===e.id}var e=this,n=e.options,i=e.chart,o=i.data.datasets,r=e.isHorizontal();e.min=null,e.max=null;var l=n.stacked;if(void 0===l&&a.each(o,function(e,n){if(!l){var a=i.getDatasetMeta(n);i.isDatasetVisible(n)&&t(a)&&void 0!==a.stack&&(l=!0)}}),n.stacked||l){var s={};a.each(o,function(o,r){var l=i.getDatasetMeta(r),u=[l.type,void 0===n.stacked&&void 0===l.stack?r:"",l.stack].join(".");void 0===s[u]&&(s[u]={positiveValues:[],negativeValues:[]});var d=s[u].positiveValues,c=s[u].negativeValues;i.isDatasetVisible(r)&&t(l)&&a.each(o.data,function(t,i){var a=+e.getRightValue(t);isNaN(a)||l.data[i].hidden||(d[i]=d[i]||0,c[i]=c[i]||0,n.relativePoints?d[i]=100:a<0?c[i]+=a:d[i]+=a)})}),a.each(s,function(t){var n=t.positiveValues.concat(t.negativeValues),i=a.min(n),o=a.max(n);e.min=null===e.min?i:Math.min(e.min,i),e.max=null===e.max?o:Math.max(e.max,o)})}else a.each(o,function(n,o){var r=i.getDatasetMeta(o);i.isDatasetVisible(o)&&t(r)&&a.each(n.data,function(t,n){var i=+e.getRightValue(t);isNaN(i)||r.data[n].hidden||(null===e.min?e.min=i:i<e.min&&(e.min=i),null===e.max?e.max=i:i>e.max&&(e.max=i))})});e.min=isFinite(e.min)&&!isNaN(e.min)?e.min:0,e.max=isFinite(e.max)&&!isNaN(e.max)?e.max:1,this.handleTickRangeOptions()},getTickLimit:function(){var t,e=this,n=e.options.ticks;if(e.isHorizontal())t=Math.min(n.maxTicksLimit?n.maxTicksLimit:11,Math.ceil(e.width/50));else{var o=a.valueOrDefault(n.fontSize,i.global.defaultFontSize);t=Math.min(n.maxTicksLimit?n.maxTicksLimit:11,Math.ceil(e.height/(2*o)))}return t},handleDirectionalChanges:function(){this.isHorizontal()||this.ticks.reverse()},getLabelForIndex:function(t,e){return+this.getRightValue(this.chart.data.datasets[e].data[t])},getPixelForValue:function(t){var e,n=this,i=n.start,a=+n.getRightValue(t),o=n.end-i;return n.isHorizontal()?(e=n.left+n.width/o*(a-i),Math.round(e)):(e=n.bottom-n.height/o*(a-i),Math.round(e))},getValueForPixel:function(t){var e=this,n=e.isHorizontal(),i=n?e.width:e.height,a=(n?t-e.left:e.bottom-t)/i;return e.start+(e.end-e.start)*a},getPixelForTick:function(t){return this.getPixelForValue(this.ticksAsNumbers[t])}});t.scaleService.registerScaleType("linear",n,e)}},{25:25,34:34,45:45}],54:[function(t,e,n){"use strict";var i=t(45),a=t(34);e.exports=function(t){var e=i.noop;t.LinearScaleBase=t.Scale.extend({getRightValue:function(e){return"string"==typeof e?+e:t.Scale.prototype.getRightValue.call(this,e)},handleTickRangeOptions:function(){var t=this,e=t.options.ticks;if(e.beginAtZero){var n=i.sign(t.min),a=i.sign(t.max);n<0&&a<0?t.max=0:n>0&&a>0&&(t.min=0)}var o=void 0!==e.min||void 0!==e.suggestedMin,r=void 0!==e.max||void 0!==e.suggestedMax;void 0!==e.min?t.min=e.min:void 0!==e.suggestedMin&&(null===t.min?t.min=e.suggestedMin:t.min=Math.min(t.min,e.suggestedMin)),void 0!==e.max?t.max=e.max:void 0!==e.suggestedMax&&(null===t.max?t.max=e.suggestedMax:t.max=Math.max(t.max,e.suggestedMax)),o!==r&&t.min>=t.max&&(o?t.max=t.min+1:t.min=t.max-1),t.min===t.max&&(t.max++,e.beginAtZero||t.min--)},getTickLimit:e,handleDirectionalChanges:e,buildTicks:function(){var t=this,e=t.options.ticks,n=t.getTickLimit(),o={maxTicks:n=Math.max(2,n),min:e.min,max:e.max,stepSize:i.valueOrDefault(e.fixedStepSize,e.stepSize)},r=t.ticks=a.generators.linear(o,t);t.handleDirectionalChanges(),t.max=i.max(r),t.min=i.min(r),e.reverse?(r.reverse(),t.start=t.max,t.end=t.min):(t.start=t.min,t.end=t.max)},convertTicksToLabels:function(){var e=this;e.ticksAsNumbers=e.ticks.slice(),e.zeroLineIndex=e.ticks.indexOf(0),t.Scale.prototype.convertTicksToLabels.call(e)}})}},{34:34,45:45}],55:[function(t,e,n){"use strict";var i=t(45),a=t(34);e.exports=function(t){var e={position:"left",ticks:{callback:a.formatters.logarithmic}},n=t.Scale.extend({determineDataLimits:function(){function t(t){return s?t.xAxisID===e.id:t.yAxisID===e.id}var e=this,n=e.options,a=n.ticks,o=e.chart,r=o.data.datasets,l=i.valueOrDefault,s=e.isHorizontal();e.min=null,e.max=null,e.minNotZero=null;var u=n.stacked;if(void 0===u&&i.each(r,function(e,n){if(!u){var i=o.getDatasetMeta(n);o.isDatasetVisible(n)&&t(i)&&void 0!==i.stack&&(u=!0)}}),n.stacked||u){var d={};i.each(r,function(a,r){var l=o.getDatasetMeta(r),s=[l.type,void 0===n.stacked&&void 0===l.stack?r:"",l.stack].join(".");o.isDatasetVisible(r)&&t(l)&&(void 0===d[s]&&(d[s]=[]),i.each(a.data,function(t,i){var a=d[s],o=+e.getRightValue(t);isNaN(o)||l.data[i].hidden||(a[i]=a[i]||0,n.relativePoints?a[i]=100:a[i]+=o)}))}),i.each(d,function(t){var n=i.min(t),a=i.max(t);e.min=null===e.min?n:Math.min(e.min,n),e.max=null===e.max?a:Math.max(e.max,a)})}else i.each(r,function(n,a){var r=o.getDatasetMeta(a);o.isDatasetVisible(a)&&t(r)&&i.each(n.data,function(t,n){var i=+e.getRightValue(t);isNaN(i)||r.data[n].hidden||(null===e.min?e.min=i:i<e.min&&(e.min=i),null===e.max?e.max=i:i>e.max&&(e.max=i),0!==i&&(null===e.minNotZero||i<e.minNotZero)&&(e.minNotZero=i))})});e.min=l(a.min,e.min),e.max=l(a.max,e.max),e.min===e.max&&(0!==e.min&&null!==e.min?(e.min=Math.pow(10,Math.floor(i.log10(e.min))-1),e.max=Math.pow(10,Math.floor(i.log10(e.max))+1)):(e.min=1,e.max=10))},buildTicks:function(){var t=this,e=t.options.ticks,n={min:e.min,max:e.max},o=t.ticks=a.generators.logarithmic(n,t);t.isHorizontal()||o.reverse(),t.max=i.max(o),t.min=i.min(o),e.reverse?(o.reverse(),t.start=t.max,t.end=t.min):(t.start=t.min,t.end=t.max)},convertTicksToLabels:function(){this.tickValues=this.ticks.slice(),t.Scale.prototype.convertTicksToLabels.call(this)},getLabelForIndex:function(t,e){return+this.getRightValue(this.chart.data.datasets[e].data[t])},getPixelForTick:function(t){return this.getPixelForValue(this.tickValues[t])},getPixelForValue:function(t){var e,n,a,o=this,r=o.start,l=+o.getRightValue(t),s=o.options.ticks;return o.isHorizontal()?(a=i.log10(o.end)-i.log10(r),0===l?n=o.left:(e=o.width,n=o.left+e/a*(i.log10(l)-i.log10(r)))):(e=o.height,0!==r||s.reverse?0===o.end&&s.reverse?(a=i.log10(o.start)-i.log10(o.minNotZero),n=l===o.end?o.top:l===o.minNotZero?o.top+.02*e:o.top+.02*e+.98*e/a*(i.log10(l)-i.log10(o.minNotZero))):0===l?n=s.reverse?o.top:o.bottom:(a=i.log10(o.end)-i.log10(r),e=o.height,n=o.bottom-e/a*(i.log10(l)-i.log10(r))):(a=i.log10(o.end)-i.log10(o.minNotZero),n=l===r?o.bottom:l===o.minNotZero?o.bottom-.02*e:o.bottom-.02*e-.98*e/a*(i.log10(l)-i.log10(o.minNotZero)))),n},getValueForPixel:function(t){var e,n,a=this,o=i.log10(a.end)-i.log10(a.start);return a.isHorizontal()?(n=a.width,e=a.start*Math.pow(10,(t-a.left)*o/n)):(n=a.height,e=Math.pow(10,(a.bottom-t)*o/n)/a.start),e}});t.scaleService.registerScaleType("logarithmic",n,e)}},{34:34,45:45}],56:[function(t,e,n){"use strict";var i=t(25),a=t(45),o=t(34);e.exports=function(t){function e(t){var e=t.options;return e.angleLines.display||e.pointLabels.display?t.chart.data.labels.length:0}function n(t){var e=t.options.pointLabels,n=a.valueOrDefault(e.fontSize,v.defaultFontSize),i=a.valueOrDefault(e.fontStyle,v.defaultFontStyle),o=a.valueOrDefault(e.fontFamily,v.defaultFontFamily);return{size:n,style:i,family:o,font:a.fontString(n,i,o)}}function r(t,e,n){return a.isArray(n)?{w:a.longestText(t,t.font,n),h:n.length*e+1.5*(n.length-1)*e}:{w:t.measureText(n).width,h:e}}function l(t,e,n,i,a){return t===i||t===a?{start:e-n/2,end:e+n/2}:t<i||t>a?{start:e-n-5,end:e}:{start:e,end:e+n+5}}function s(t){var i,o,s,u=n(t),d=Math.min(t.height/2,t.width/2),c={r:t.width,l:0,t:t.height,b:0},h={};t.ctx.font=u.font,t._pointLabelSizes=[];var f=e(t);for(i=0;i<f;i++){s=t.getPointPosition(i,d),o=r(t.ctx,u.size,t.pointLabels[i]||""),t._pointLabelSizes[i]=o;var g=t.getIndexAngle(i),p=a.toDegrees(g)%360,v=l(p,s.x,o.w,0,180),m=l(p,s.y,o.h,90,270);v.start<c.l&&(c.l=v.start,h.l=g),v.end>c.r&&(c.r=v.end,h.r=g),m.start<c.t&&(c.t=m.start,h.t=g),m.end>c.b&&(c.b=m.end,h.b=g)}t.setReductions(d,c,h)}function u(t){var e=Math.min(t.height/2,t.width/2);t.drawingArea=Math.round(e),t.setCenterPoint(0,0,0,0)}function d(t){return 0===t||180===t?"center":t<180?"left":"right"}function c(t,e,n,i){if(a.isArray(e))for(var o=n.y,r=1.5*i,l=0;l<e.length;++l)t.fillText(e[l],n.x,o),o+=r;else t.fillText(e,n.x,n.y)}function h(t,e,n){90===t||270===t?n.y-=e.h/2:(t>270||t<90)&&(n.y-=e.h)}function f(t){var i=t.ctx,o=a.valueOrDefault,r=t.options,l=r.angleLines,s=r.pointLabels;i.lineWidth=l.lineWidth,i.strokeStyle=l.color;var u=t.getDistanceFromCenterForValue(r.ticks.reverse?t.min:t.max),f=n(t);i.textBaseline="top";for(var g=e(t)-1;g>=0;g--){if(l.display){var p=t.getPointPosition(g,u);i.beginPath(),i.moveTo(t.xCenter,t.yCenter),i.lineTo(p.x,p.y),i.stroke(),i.closePath()}if(s.display){var m=t.getPointPosition(g,u+5),b=o(s.fontColor,v.defaultFontColor);i.font=f.font,i.fillStyle=b;var x=t.getIndexAngle(g),y=a.toDegrees(x);i.textAlign=d(y),h(y,t._pointLabelSizes[g],m),c(i,t.pointLabels[g]||"",m,f.size)}}}function g(t,n,i,o){var r=t.ctx;if(r.strokeStyle=a.valueAtIndexOrDefault(n.color,o-1),r.lineWidth=a.valueAtIndexOrDefault(n.lineWidth,o-1),t.options.gridLines.circular)r.beginPath(),r.arc(t.xCenter,t.yCenter,i,0,2*Math.PI),r.closePath(),r.stroke();else{var l=e(t);if(0===l)return;r.beginPath();var s=t.getPointPosition(0,i);r.moveTo(s.x,s.y);for(var u=1;u<l;u++)s=t.getPointPosition(u,i),r.lineTo(s.x,s.y);r.closePath(),r.stroke()}}function p(t){return a.isNumber(t)?t:0}var v=i.global,m={display:!0,animate:!0,position:"chartArea",angleLines:{display:!0,color:"rgba(0, 0, 0, 0.1)",lineWidth:1},gridLines:{circular:!1},ticks:{showLabelBackdrop:!0,backdropColor:"rgba(255,255,255,0.75)",backdropPaddingY:2,backdropPaddingX:2,callback:o.formatters.linear},pointLabels:{display:!0,fontSize:10,callback:function(t){return t}}},b=t.LinearScaleBase.extend({setDimensions:function(){var t=this,e=t.options,n=e.ticks;t.width=t.maxWidth,t.height=t.maxHeight,t.xCenter=Math.round(t.width/2),t.yCenter=Math.round(t.height/2);var i=a.min([t.height,t.width]),o=a.valueOrDefault(n.fontSize,v.defaultFontSize);t.drawingArea=e.display?i/2-(o/2+n.backdropPaddingY):i/2},determineDataLimits:function(){var t=this,e=t.chart,n=Number.POSITIVE_INFINITY,i=Number.NEGATIVE_INFINITY;a.each(e.data.datasets,function(o,r){if(e.isDatasetVisible(r)){var l=e.getDatasetMeta(r);a.each(o.data,function(e,a){var o=+t.getRightValue(e);isNaN(o)||l.data[a].hidden||(n=Math.min(o,n),i=Math.max(o,i))})}}),t.min=n===Number.POSITIVE_INFINITY?0:n,t.max=i===Number.NEGATIVE_INFINITY?0:i,t.handleTickRangeOptions()},getTickLimit:function(){var t=this.options.ticks,e=a.valueOrDefault(t.fontSize,v.defaultFontSize);return Math.min(t.maxTicksLimit?t.maxTicksLimit:11,Math.ceil(this.drawingArea/(1.5*e)))},convertTicksToLabels:function(){var e=this;t.LinearScaleBase.prototype.convertTicksToLabels.call(e),e.pointLabels=e.chart.data.labels.map(e.options.pointLabels.callback,e)},getLabelForIndex:function(t,e){return+this.getRightValue(this.chart.data.datasets[e].data[t])},fit:function(){this.options.pointLabels.display?s(this):u(this)},setReductions:function(t,e,n){var i=this,a=e.l/Math.sin(n.l),o=Math.max(e.r-i.width,0)/Math.sin(n.r),r=-e.t/Math.cos(n.t),l=-Math.max(e.b-i.height,0)/Math.cos(n.b);a=p(a),o=p(o),r=p(r),l=p(l),i.drawingArea=Math.min(Math.round(t-(a+o)/2),Math.round(t-(r+l)/2)),i.setCenterPoint(a,o,r,l)},setCenterPoint:function(t,e,n,i){var a=this,o=a.width-e-a.drawingArea,r=t+a.drawingArea,l=n+a.drawingArea,s=a.height-i-a.drawingArea;a.xCenter=Math.round((r+o)/2+a.left),a.yCenter=Math.round((l+s)/2+a.top)},getIndexAngle:function(t){return t*(2*Math.PI/e(this))+(this.chart.options&&this.chart.options.startAngle?this.chart.options.startAngle:0)*Math.PI*2/360},getDistanceFromCenterForValue:function(t){var e=this;if(null===t)return 0;var n=e.drawingArea/(e.max-e.min);return e.options.ticks.reverse?(e.max-t)*n:(t-e.min)*n},getPointPosition:function(t,e){var n=this,i=n.getIndexAngle(t)-Math.PI/2;return{x:Math.round(Math.cos(i)*e)+n.xCenter,y:Math.round(Math.sin(i)*e)+n.yCenter}},getPointPositionForValue:function(t,e){return this.getPointPosition(t,this.getDistanceFromCenterForValue(e))},getBasePosition:function(){var t=this,e=t.min,n=t.max;return t.getPointPositionForValue(0,t.beginAtZero?0:e<0&&n<0?n:e>0&&n>0?e:0)},draw:function(){var t=this,e=t.options,n=e.gridLines,i=e.ticks,o=a.valueOrDefault;if(e.display){var r=t.ctx,l=this.getIndexAngle(0),s=o(i.fontSize,v.defaultFontSize),u=o(i.fontStyle,v.defaultFontStyle),d=o(i.fontFamily,v.defaultFontFamily),c=a.fontString(s,u,d);a.each(t.ticks,function(e,a){if(a>0||i.reverse){var u=t.getDistanceFromCenterForValue(t.ticksAsNumbers[a]);if(n.display&&0!==a&&g(t,n,u,a),i.display){var d=o(i.fontColor,v.defaultFontColor);if(r.font=c,r.save(),r.translate(t.xCenter,t.yCenter),r.rotate(l),i.showLabelBackdrop){var h=r.measureText(e).width;r.fillStyle=i.backdropColor,r.fillRect(-h/2-i.backdropPaddingX,-u-s/2-i.backdropPaddingY,h+2*i.backdropPaddingX,s+2*i.backdropPaddingY)}r.textAlign="center",r.textBaseline="middle",r.fillStyle=d,r.fillText(e,0,-u),r.restore()}}}),(e.angleLines.display||e.pointLabels.display)&&f(t)}}});t.scaleService.registerScaleType("radialLinear",b,m)}},{25:25,34:34,45:45}],57:[function(t,e,n){"use strict";function i(t,e){return t-e}function a(t){var e,n,i,a={},o=[];for(e=0,n=t.length;e<n;++e)a[i=t[e]]||(a[i]=!0,o.push(i));return o}function o(t,e,n,i){if("linear"===i||!t.length)return[{time:e,pos:0},{time:n,pos:1}];var a,o,r,l,s,u=[],d=[e];for(a=0,o=t.length;a<o;++a)(l=t[a])>e&&l<n&&d.push(l);for(d.push(n),a=0,o=d.length;a<o;++a)s=d[a+1],r=d[a-1],l=d[a],void 0!==r&&void 0!==s&&Math.round((s+r)/2)===l||u.push({time:l,pos:a/(o-1)});return u}function r(t,e,n){for(var i,a,o,r=0,l=t.length-1;r>=0&&r<=l;){if(i=r+l>>1,a=t[i-1]||null,o=t[i],!a)return{lo:null,hi:o};if(o[e]<n)r=i+1;else{if(!(a[e]>n))return{lo:a,hi:o};l=i-1}}return{lo:o,hi:null}}function l(t,e,n,i){var a=r(t,e,n),o=a.lo?a.hi?a.lo:t[t.length-2]:t[0],l=a.lo?a.hi?a.hi:t[t.length-1]:t[1],s=l[e]-o[e],u=s?(n-o[e])/s:0,d=(l[i]-o[i])*u;return o[i]+d}function s(t,e){var n=e.parser,i=e.parser||e.format;return"function"==typeof n?n(t):"string"==typeof t&&"string"==typeof i?m(t,i):(t instanceof m||(t=m(t)),t.isValid()?t:"function"==typeof i?i(t):t)}function u(t,e){if(x.isNullOrUndef(t))return null;var n=e.options.time,i=s(e.getRightValue(t),n);return i.isValid()?(n.round&&i.startOf(n.round),i.valueOf()):null}function d(t,e,n,i){var a,o,r,l=e-t,s=w[n],u=s.size,d=s.steps;if(!d)return Math.ceil(l/((i||1)*u));for(a=0,o=d.length;a<o&&(r=d[a],!(Math.ceil(l/(u*r))<=i));++a);return r}function c(t,e,n,i){var a,o,r,l=M.length;for(a=M.indexOf(t);a<l-1;++a)if(o=w[M[a]],r=o.steps?o.steps[o.steps.length-1]:k,o.common&&Math.ceil((n-e)/(r*o.size))<=i)return M[a];return M[l-1]}function h(t,e,n,i){var a,o,r=m.duration(m(i).diff(m(n)));for(a=M.length-1;a>=M.indexOf(e);a--)if(o=M[a],w[o].common&&r.as(o)>=t.length)return o;return M[e?M.indexOf(e):0]}function f(t){for(var e=M.indexOf(t)+1,n=M.length;e<n;++e)if(w[M[e]].common)return M[e]}function g(t,e,n,i){var a,o=i.time,r=o.unit||c(o.minUnit,t,e,n),l=f(r),s=x.valueOrDefault(o.stepSize,o.unitStepSize),u="week"===r&&o.isoWeekday,h=i.ticks.major.enabled,g=w[r],p=m(t),v=m(e),b=[];for(s||(s=d(t,e,r,n)),u&&(p=p.isoWeekday(u),v=v.isoWeekday(u)),p=p.startOf(u?"day":r),(v=v.startOf(u?"day":r))<e&&v.add(1,r),a=m(p),h&&l&&!u&&!o.round&&(a.startOf(l),a.add(~~((p-a)/(g.size*s))*s,r));a<v;a.add(s,r))b.push(+a);return b.push(+a),b}function p(t,e,n,i,a){var o,r,s=0,u=0;return a.offset&&e.length&&(a.time.min||(o=e.length>1?e[1]:i,r=e[0],s=(l(t,"time",o,"pos")-l(t,"time",r,"pos"))/2),a.time.max||(o=e[e.length-1],r=e.length>1?e[e.length-2]:n,u=(l(t,"time",o,"pos")-l(t,"time",r,"pos"))/2)),{left:s,right:u}}function v(t,e){var n,i,a,o,r=[];for(n=0,i=t.length;n<i;++n)a=t[n],o=!!e&&a===+m(a).startOf(e),r.push({value:a,major:o});return r}var m=t(1);m="function"==typeof m?m:window.moment;var b=t(25),x=t(45),y=Number.MIN_SAFE_INTEGER||-9007199254740991,k=Number.MAX_SAFE_INTEGER||9007199254740991,w={millisecond:{common:!0,size:1,steps:[1,2,5,10,20,50,100,250,500]},second:{common:!0,size:1e3,steps:[1,2,5,10,30]},minute:{common:!0,size:6e4,steps:[1,2,5,10,30]},hour:{common:!0,size:36e5,steps:[1,2,3,6,12]},day:{common:!0,size:864e5,steps:[1,2,5]},week:{common:!1,size:6048e5,steps:[1,2,3,4]},month:{common:!0,size:2628e6,steps:[1,2,3]},quarter:{common:!1,size:7884e6,steps:[1,2,3,4]},year:{common:!0,size:3154e7}},M=Object.keys(w);e.exports=function(t){var e=t.Scale.extend({initialize:function(){if(!m)throw new Error("Chart.js - Moment.js could not be found! You must include it before Chart.js to use the time scale. Download at https://momentjs.com");this.mergeTicksOptions(),t.Scale.prototype.initialize.call(this)},update:function(){var e=this,n=e.options;return n.time&&n.time.format&&console.warn("options.time.format is deprecated and replaced by options.time.parser."),t.Scale.prototype.update.apply(e,arguments)},getRightValue:function(e){return e&&void 0!==e.t&&(e=e.t),t.Scale.prototype.getRightValue.call(this,e)},determineDataLimits:function(){var t,e,n,o,r,l,s=this,d=s.chart,c=s.options.time,h=k,f=y,g=[],p=[],v=[];for(t=0,n=d.data.labels.length;t<n;++t)v.push(u(d.data.labels[t],s));for(t=0,n=(d.data.datasets||[]).length;t<n;++t)if(d.isDatasetVisible(t))if(r=d.data.datasets[t].data,x.isObject(r[0]))for(p[t]=[],e=0,o=r.length;e<o;++e)l=u(r[e],s),g.push(l),p[t][e]=l;else g.push.apply(g,v),p[t]=v.slice(0);else p[t]=[];v.length&&(v=a(v).sort(i),h=Math.min(h,v[0]),f=Math.max(f,v[v.length-1])),g.length&&(g=a(g).sort(i),h=Math.min(h,g[0]),f=Math.max(f,g[g.length-1])),h=u(c.min,s)||h,f=u(c.max,s)||f,h=h===k?+m().startOf("day"):h,f=f===y?+m().endOf("day")+1:f,s.min=Math.min(h,f),s.max=Math.max(h+1,f),s._horizontal=s.isHorizontal(),s._table=[],s._timestamps={data:g,datasets:p,labels:v}},buildTicks:function(){var t,e,n,i=this,a=i.min,r=i.max,l=i.options,s=l.time,d=[],c=[];switch(l.ticks.source){case"data":d=i._timestamps.data;break;case"labels":d=i._timestamps.labels;break;case"auto":default:d=g(a,r,i.getLabelCapacity(a),l)}for("ticks"===l.bounds&&d.length&&(a=d[0],r=d[d.length-1]),a=u(s.min,i)||a,r=u(s.max,i)||r,t=0,e=d.length;t<e;++t)(n=d[t])>=a&&n<=r&&c.push(n);return i.min=a,i.max=r,i._unit=s.unit||h(c,s.minUnit,i.min,i.max),i._majorUnit=f(i._unit),i._table=o(i._timestamps.data,a,r,l.distribution),i._offsets=p(i._table,c,a,r,l),v(c,i._majorUnit)},getLabelForIndex:function(t,e){var n=this,i=n.chart.data,a=n.options.time,o=i.labels&&t<i.labels.length?i.labels[t]:"",r=i.datasets[e].data[t];return x.isObject(r)&&(o=n.getRightValue(r)),a.tooltipFormat&&(o=s(o,a).format(a.tooltipFormat)),o},tickFormatFunction:function(t,e,n,i){var a=this,o=a.options,r=t.valueOf(),l=o.time.displayFormats,s=l[a._unit],u=a._majorUnit,d=l[u],c=t.clone().startOf(u).valueOf(),h=o.ticks.major,f=h.enabled&&u&&d&&r===c,g=t.format(i||(f?d:s)),p=f?h:o.ticks.minor,v=x.valueOrDefault(p.callback,p.userCallback);return v?v(g,e,n):g},convertTicksToLabels:function(t){var e,n,i=[];for(e=0,n=t.length;e<n;++e)i.push(this.tickFormatFunction(m(t[e].value),e,t));return i},getPixelForOffset:function(t){var e=this,n=e._horizontal?e.width:e.height,i=e._horizontal?e.left:e.top,a=l(e._table,"time",t,"pos");return i+n*(e._offsets.left+a)/(e._offsets.left+1+e._offsets.right)},getPixelForValue:function(t,e,n){var i=this,a=null;if(void 0!==e&&void 0!==n&&(a=i._timestamps.datasets[n][e]),null===a&&(a=u(t,i)),null!==a)return i.getPixelForOffset(a)},getPixelForTick:function(t){var e=this.getTicks();return t>=0&&t<e.length?this.getPixelForOffset(e[t].value):null},getValueForPixel:function(t){var e=this,n=e._horizontal?e.width:e.height,i=e._horizontal?e.left:e.top,a=(n?(t-i)/n:0)*(e._offsets.left+1+e._offsets.left)-e._offsets.right,o=l(e._table,"pos",a,"time");return m(o)},getLabelWidth:function(t){var e=this,n=e.options.ticks,i=e.ctx.measureText(t).width,a=x.toRadians(n.maxRotation),o=Math.cos(a),r=Math.sin(a);return i*o+x.valueOrDefault(n.fontSize,b.global.defaultFontSize)*r},getLabelCapacity:function(t){var e=this,n=e.options.time.displayFormats.millisecond,i=e.tickFormatFunction(m(t),0,[],n),a=e.getLabelWidth(i),o=e.isHorizontal()?e.width:e.height;return Math.floor(o/a)}});t.scaleService.registerScaleType("time",e,{position:"bottom",distribution:"linear",bounds:"data",time:{parser:!1,format:!1,unit:!1,round:!1,displayFormat:!1,isoWeekday:!1,minUnit:"millisecond",displayFormats:{millisecond:"h:mm:ss.SSS a",second:"h:mm:ss a",minute:"h:mm a",hour:"hA",day:"MMM D",week:"ll",month:"MMM YYYY",quarter:"[Q]Q - YYYY",year:"YYYY"}},ticks:{autoSkip:!1,source:"auto",major:{enabled:!1}}})}},{1:1,25:25,45:45}]},{},[7])(7)});
 
assets/js/imagify-gulp.js CHANGED
File without changes
assets/js/imagify-gulp.min.js CHANGED
File without changes
assets/js/jquery.twentytwenty.js CHANGED
@@ -1,65 +1,52 @@
1
- /* eslint-disable */
2
- (function($, d, w, undefined) {
3
 
4
- $.fn.twentytwenty = function(options, callback) {
5
- options = $.extend({
6
  handlePosition: 0.5,
7
  orientation: 'horizontal',
8
  labelBefore: 'Before',
9
  labelAfter: 'After'
10
- }, options);
11
 
12
- return this.each(function() {
13
  var sliderPct = options.handlePosition,
14
- $container = $(this),
15
  sliderOrientation = options.orientation,
16
- beforeDirection = (sliderOrientation === 'vertical') ? 'down' : 'left',
17
- afterDirection = (sliderOrientation === 'vertical') ? 'up' : 'right',
18
- $beforeImg = $container.find('img:first'),
19
- $afterImg = $container.find('img:last');
20
-
21
-
22
- $container.wrap('<div class="twentytwenty-wrapper twentytwenty-' + sliderOrientation + '"></div>');
23
- $container.append('<div class="twentytwenty-overlay"></div>');
24
- $container.append('<div class="twentytwenty-handle"></div>');
25
-
26
- var $slider = $container.find('.twentytwenty-handle');
27
-
28
- $slider.append('<span class="twentytwenty-' + beforeDirection + '-arrow"></span>');
29
- $slider.append('<span class="twentytwenty-' + afterDirection + '-arrow"></span>');
30
- $container.addClass('twentytwenty-container');
31
- $beforeImg.addClass('twentytwenty-before');
32
- $afterImg.addClass('twentytwenty-after');
33
-
34
- var $overlay = $container.find('.twentytwenty-overlay');
35
-
36
- $overlay.append('<div class="twentytwenty-labels twentytwenty-before-label"><span class="twentytwenty-label-content">' + options.labelBefore + '</span></div>');
37
- $overlay.append('<div class="twentytwenty-labels twentytwenty-after-label"><span class="twentytwenty-label-content">' + options.labelAfter + '</span></div>');
38
-
39
-
40
- // some usefull function and vars declarations
41
 
42
- var calcOffset = function(dimensionPct) {
43
- var w = $beforeImg.width();
44
- var h = $beforeImg.height();
45
  return {
46
- w: w+"px",
47
- h: h+"px",
48
- cw: (dimensionPct*w)+"px",
49
- ch: (dimensionPct*h)+"px"
50
  };
51
  },
52
-
53
  adjustContainer = function( offset ) {
54
- // make it dynamic, in case "before" image change
55
- var $beforeImg = $container.find('.twentytwenty-before');
56
 
57
- if ( sliderOrientation === 'vertical' ) {
58
- $beforeImg.css( 'clip', 'rect(0,' + offset.w + ',' + offset.ch + ',0)' );
59
- }
60
- else {
61
- $beforeImg.css( 'clip', 'rect(0,' + offset.cw + ',' + offset.h + ',0)' );
62
  }
 
63
  $container.css( 'height', offset.h );
64
 
65
  if ( typeof callback === 'function' ) {
@@ -67,62 +54,81 @@
67
  }
68
  },
69
  adjustSlider = function( pct ) {
70
- var offset = calcOffset(pct);
71
- $slider.css( ( sliderOrientation === 'vertical' ) ? 'top' : 'left', ( sliderOrientation === 'vertical' ) ? offset.ch : offset.cw );
 
 
 
 
 
 
72
  adjustContainer( offset );
73
- },
74
- offsetX = 0,
75
- offsetY = 0,
76
- imgWidth = 0,
77
- imgHeight = 0;
 
78
 
79
- $( w ).on('resize.twentytwenty', function() {
 
 
 
 
 
 
 
 
 
 
 
 
 
80
  adjustSlider( sliderPct );
81
- });
82
 
83
- $slider.on('movestart', function(e) {
84
- if ( ( ( e.distX > e.distY && e.distX < -e.distY ) || ( e.distX < e.distY && e.distX > -e.distY ) ) && sliderOrientation !== 'vertical' ) {
85
  e.preventDefault();
86
- }
87
- else if ( ( ( e.distX < e.distY && e.distX < -e.distY ) || ( e.distX > e.distY && e.distX > -e.distY ) ) && sliderOrientation === 'vertical' ) {
88
  e.preventDefault();
89
  }
90
- $container.addClass('active');
91
- offsetX = $container.offset().left;
92
- offsetY = $container.offset().top;
93
- imgWidth = $beforeImg.width();
94
- imgHeight = $beforeImg.height();
95
- });
96
-
97
- $slider.on('moveend', function() {
98
- $container.removeClass('active');
99
- });
100
-
101
- $slider.on('move', function(e) {
102
- if ( $container.hasClass('active') ) {
103
 
104
- sliderPct = ( sliderOrientation === 'vertical' ) ? ( e.pageY-offsetY )/imgHeight : ( e.pageX-offsetX )/imgWidth;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
105
 
106
  if ( sliderPct < 0 ) {
107
  sliderPct = 0;
108
- }
109
- if ( sliderPct > 1 ) {
110
  sliderPct = 1;
111
  }
 
112
  adjustSlider( sliderPct );
113
  }
114
- });
115
 
116
- $container.find('img').on('mousedown', function(event) {
117
- event.preventDefault();
118
- });
119
 
120
- $( w ).trigger('resize.twentytwenty');
121
- });
122
  };
123
 
124
  } )(jQuery, document, window);
125
- /* eslint-enable */
126
 
127
  /**
128
  * Twentytwenty Imagify Init
@@ -136,25 +142,32 @@
136
  */
137
  var drawMeAChart = function ( canvas ) {
138
  canvas.each( function() {
139
- var $this = $( this ),
140
- theValue = parseInt( $this.closest( '.imagify-chart' ).next( '.imagify-chart-value' ).text(), 10 ),
141
- overviewData = [
142
- {
143
- value: theValue,
144
- color: '#00B3D3'
 
 
 
 
 
 
 
 
 
145
  },
146
- {
147
- value: 100 - theValue,
148
- color: '#D8D8D8'
149
- }
150
- ];
151
-
152
- new Chart( $this[0].getContext( '2d' ) ).Doughnut( overviewData, { // eslint-disable-line new-cap
153
- segmentStrokeColor: '#2A2E3C',
154
- segmentStrokeWidth: 1,
155
- animateRotate: true,
156
- percentageInnerCutout: 60,
157
- tooltipEvents: []
158
  } );
159
  } );
160
  },
@@ -570,11 +583,11 @@
570
  */
571
  if ( $( '.upload-php' ).length > 0 ) {
572
 
573
- var getVar = function ( param ) {
574
  var vars = {};
575
 
576
  w.location.href.replace(
577
- /[?&]+([^=&]+)=?([^&]*)?/gi,//
578
  function( m, key, value ) {
579
  vars[ key ] = undefined !== value ? value : '';
580
  }
@@ -587,7 +600,7 @@
587
  },
588
  imagifyContentInModal = function() {
589
  var tempTimer = setInterval( function() {
590
- var $datas, originalSrc;
591
 
592
  if ( ! $( '.media-modal .imagify-datas-details' ).length ) {
593
  return;
@@ -597,7 +610,10 @@
597
 
598
  if ( originalSrc ) {
599
  // Trigger creation.
600
- $( '.media-frame-content .attachment-actions' ).prepend( '<button type="button" class="imagify-button-primary button-primary imagify-modal-trigger" data-target="#imagify-comparison-modal" id="imagify-media-frame-comparison-btn">' + imagifyTTT.labels.compare + '</button>' );
 
 
 
601
 
602
  // Get datas.
603
  $datas = $( '.media-frame-content .compat-field-imagify' );
@@ -621,26 +637,17 @@
621
  clearInterval( tempTimer );
622
  tempTimer = null;
623
  }, 20 );
624
- },
625
- waitContent = setInterval( function() {
626
- if ( ! $( '.upload-php .media-frame.mode-grid .attachments' ).length ) {
627
- return;
628
- }
629
-
630
- // If attachment is clicked, build the modal inside the modal.
631
- $( '.upload-php .media-frame.mode-grid' ).on( 'click', '.attachment', function() {
632
- imagifyContentInModal();
633
- } );
634
 
635
- // If attachment is mentionned in URL, build the modal inside the modal.
636
- if ( getVar( 'item' ) ) {
637
- imagifyContentInModal();
638
- }
639
 
640
- clearInterval( waitContent );
641
- waitContent = null;
642
- }, 100 );
643
- // If URL contain item, that will open the WP Modal View.
644
  }
645
 
646
  } )(jQuery, document, window);
1
+ (function($, d, w, undefined) { // eslint-disable-line no-unused-vars, no-shadow, no-shadow-restricted-names
 
2
 
3
+ $.fn.twentytwenty = function( options, callback ) {
4
+ options = $.extend( {
5
  handlePosition: 0.5,
6
  orientation: 'horizontal',
7
  labelBefore: 'Before',
8
  labelAfter: 'After'
9
+ }, options );
10
 
11
+ return this.each( function() {
12
  var sliderPct = options.handlePosition,
13
+ $container = $( this ),
14
  sliderOrientation = options.orientation,
15
+ beforeDirection = ( 'vertical' === sliderOrientation ) ? 'down' : 'left',
16
+ afterDirection = ( 'vertical' === sliderOrientation ) ? 'up' : 'right',
17
+ $beforeImg = $container.find( 'img:first' ),
18
+ $afterImg = $container.find( 'img:last' ),
19
+ offsetX = 0,
20
+ offsetY = 0,
21
+ imgWidth = 0,
22
+ imgHeight = 0,
23
+ $slider, $overlay,
24
+ calcOffset = function( dimensionPct ) {
25
+ var width = parseInt( $beforeImg.attr( 'width' ), 10 ),
26
+ height = parseInt( $beforeImg.attr( 'height' ), 10 );
27
+
28
+ if ( ! width || ! height ) {
29
+ width = parseInt( $beforeImg.width(), 10 );
30
+ height = parseInt( $beforeImg.height(), 10 );
31
+ }
 
 
 
 
 
 
 
 
32
 
 
 
 
33
  return {
34
+ w: width + "px",
35
+ h: height + "px",
36
+ cw: ( dimensionPct * width ) + "px",
37
+ ch: ( dimensionPct * height ) + "px"
38
  };
39
  },
 
40
  adjustContainer = function( offset ) {
41
+ // Make it dynamic, in case the "before" image changes.
42
+ var $beforeImage = $container.find( '.twentytwenty-before' );
43
 
44
+ if ( 'vertical' === sliderOrientation ) {
45
+ $beforeImage.css( 'clip', 'rect(0,' + offset.w + ',' + offset.ch + ',0)' );
46
+ } else {
47
+ $beforeImage.css( 'clip', 'rect(0,' + offset.cw + ',' + offset.h + ',0)' );
 
48
  }
49
+
50
  $container.css( 'height', offset.h );
51
 
52
  if ( typeof callback === 'function' ) {
54
  }
55
  },
56
  adjustSlider = function( pct ) {
57
+ var offset = calcOffset( pct );
58
+
59
+ if ( 'vertical' === sliderOrientation ) {
60
+ $slider.css( 'top', offset.ch );
61
+ } else {
62
+ $slider.css( 'left', offset.cw );
63
+ }
64
+
65
  adjustContainer( offset );
66
+ };
67
+
68
+
69
+ $container.wrap( '<div class="twentytwenty-wrapper twentytwenty-' + sliderOrientation + '"></div>' );
70
+ $container.append( '<div class="twentytwenty-overlay"></div>' );
71
+ $container.append( '<div class="twentytwenty-handle"></div>' );
72
 
73
+ $slider = $container.find( '.twentytwenty-handle' );
74
+
75
+ $slider.append( '<span class="twentytwenty-' + beforeDirection + '-arrow"></span>' );
76
+ $slider.append( '<span class="twentytwenty-' + afterDirection + '-arrow"></span>' );
77
+ $container.addClass( 'twentytwenty-container' );
78
+ $beforeImg.addClass( 'twentytwenty-before' );
79
+ $afterImg.addClass( 'twentytwenty-after' );
80
+
81
+ $overlay = $container.find( '.twentytwenty-overlay' );
82
+
83
+ $overlay.append( '<div class="twentytwenty-labels twentytwenty-before-label"><span class="twentytwenty-label-content">' + options.labelBefore + '</span></div>' );
84
+ $overlay.append( '<div class="twentytwenty-labels twentytwenty-after-label"><span class="twentytwenty-label-content">' + options.labelAfter + '</span></div>' );
85
+
86
+ $( w ).on( 'resize.twentytwenty', function() {
87
  adjustSlider( sliderPct );
88
+ } );
89
 
90
+ $slider.on( 'movestart', function( e ) {
91
+ if ( 'vertical' !== sliderOrientation && ( ( e.distX > e.distY && e.distX < -e.distY ) || ( e.distX < e.distY && e.distX > -e.distY ) ) ) {
92
  e.preventDefault();
93
+ } else if ( 'vertical' === sliderOrientation && ( ( e.distX < e.distY && e.distX < -e.distY ) || ( e.distX > e.distY && e.distX > -e.distY ) ) ) {
 
94
  e.preventDefault();
95
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
96
 
97
+ $container.addClass( 'active' );
98
+
99
+ offsetX = $container.offset().left;
100
+ offsetY = $container.offset().top;
101
+ imgWidth = $beforeImg.width();
102
+ imgHeight = $beforeImg.height();
103
+ } );
104
+
105
+ $slider.on( 'moveend', function() {
106
+ $container.removeClass( 'active' );
107
+ } );
108
+
109
+ $slider.on( 'move', function( e ) {
110
+ if ( $container.hasClass('active') ) {
111
+ sliderPct = 'vertical' === sliderOrientation ? ( e.pageY - offsetY ) / imgHeight : ( e.pageX - offsetX ) / imgWidth;
112
 
113
  if ( sliderPct < 0 ) {
114
  sliderPct = 0;
115
+ } else if ( sliderPct > 1 ) {
 
116
  sliderPct = 1;
117
  }
118
+
119
  adjustSlider( sliderPct );
120
  }
121
+ } );
122
 
123
+ $container.find( 'img' ).on( 'mousedown', function( e ) {
124
+ e.preventDefault();
125
+ } );
126
 
127
+ $( w ).trigger( 'resize.twentytwenty' );
128
+ } );
129
  };
130
 
131
  } )(jQuery, document, window);
 
132
 
133
  /**
134
  * Twentytwenty Imagify Init
142
  */
143
  var drawMeAChart = function ( canvas ) {
144
  canvas.each( function() {
145
+ var value = parseInt( $( this ).closest( '.imagify-chart' ).next( '.imagify-chart-value' ).text(), 10 );
146
+
147
+ new Chart( this, { // eslint-disable-line no-new
148
+ type: 'doughnut',
149
+ data: {
150
+ datasets: [{
151
+ data: [ value, 100 - value ],
152
+ backgroundColor: [ '#00B3D3', '#D8D8D8' ],
153
+ borderColor: '#2A2E3C',
154
+ borderWidth: 1
155
+ }]
156
+ },
157
+ options: {
158
+ legend: {
159
+ display: false
160
  },
161
+ events: [],
162
+ animation: {
163
+ easing: 'easeOutBounce'
164
+ },
165
+ tooltips: {
166
+ enabled: false
167
+ },
168
+ responsive: false,
169
+ cutoutPercentage: 60
170
+ }
 
 
171
  } );
172
  } );
173
  },
583
  */
584
  if ( $( '.upload-php' ).length > 0 ) {
585
 
586
+ var getVar = function( param ) {
587
  var vars = {};
588
 
589
  w.location.href.replace(
590
+ /[?&]+([^=&]+)=?([^&]*)?/gi,
591
  function( m, key, value ) {
592
  vars[ key ] = undefined !== value ? value : '';
593
  }
600
  },
601
  imagifyContentInModal = function() {
602
  var tempTimer = setInterval( function() {
603
+ var $datas, originalSrc, $actions;
604
 
605
  if ( ! $( '.media-modal .imagify-datas-details' ).length ) {
606
  return;
610
 
611
  if ( originalSrc ) {
612
  // Trigger creation.
613
+ $actions = $( '.media-frame-content .attachment-actions' );
614
+
615
+ $actions.find( '#imagify-media-frame-comparison-btn' ).remove();
616
+ $actions.prepend( '<button type="button" class="imagify-button-primary button-primary imagify-modal-trigger" data-target="#imagify-comparison-modal" id="imagify-media-frame-comparison-btn">' + imagifyTTT.labels.compare + '</button>' );
617
 
618
  // Get datas.
619
  $datas = $( '.media-frame-content .compat-field-imagify' );
637
  clearInterval( tempTimer );
638
  tempTimer = null;
639
  }, 20 );
640
+ };
 
 
 
 
 
 
 
 
 
641
 
642
+ // If attachment is clicked, or the "Previous" and "Next" buttons, build the modal inside the modal.
643
+ $( '.upload-php' ).on( 'click', '.media-frame.mode-grid .attachment, .edit-media-header .left, .edit-media-header .right', function() {
644
+ imagifyContentInModal();
645
+ } );
646
 
647
+ // If attachment is mentionned in URL, build the modal inside the modal.
648
+ if ( getVar( 'item' ) ) {
649
+ imagifyContentInModal();
650
+ }
651
  }
652
 
653
  } )(jQuery, document, window);
assets/js/jquery.twentytwenty.min.js CHANGED
@@ -1 +1 @@
1
- !function(a,b,c,d){a.fn.twentytwenty=function(b,d){return b=a.extend({handlePosition:.5,orientation:"horizontal",labelBefore:"Before",labelAfter:"After"},b),this.each(function(){var e=b.handlePosition,f=a(this),g=b.orientation,h="vertical"===g?"down":"left",i="vertical"===g?"up":"right",j=f.find("img:first"),k=f.find("img:last");f.wrap('<div class="twentytwenty-wrapper twentytwenty-'+g+'"></div>'),f.append('<div class="twentytwenty-overlay"></div>'),f.append('<div class="twentytwenty-handle"></div>');var l=f.find(".twentytwenty-handle");l.append('<span class="twentytwenty-'+h+'-arrow"></span>'),l.append('<span class="twentytwenty-'+i+'-arrow"></span>'),f.addClass("twentytwenty-container"),j.addClass("twentytwenty-before"),k.addClass("twentytwenty-after");var m=f.find(".twentytwenty-overlay");m.append('<div class="twentytwenty-labels twentytwenty-before-label"><span class="twentytwenty-label-content">'+b.labelBefore+"</span></div>"),m.append('<div class="twentytwenty-labels twentytwenty-after-label"><span class="twentytwenty-label-content">'+b.labelAfter+"</span></div>");var n=function(a){var b=j.width(),c=j.height();return{w:b+"px",h:c+"px",cw:a*b+"px",ch:a*c+"px"}},o=function(a){var b=f.find(".twentytwenty-before");"vertical"===g?b.css("clip","rect(0,"+a.w+","+a.ch+",0)"):b.css("clip","rect(0,"+a.cw+","+a.h+",0)"),f.css("height",a.h),"function"==typeof d&&d()},p=function(a){var b=n(a);l.css("vertical"===g?"top":"left","vertical"===g?b.ch:b.cw),o(b)},q=0,r=0,s=0,t=0;a(c).on("resize.twentytwenty",function(){p(e)}),l.on("movestart",function(a){(a.distX>a.distY&&a.distX<-a.distY||a.distX<a.distY&&a.distX>-a.distY)&&"vertical"!==g?a.preventDefault():(a.distX<a.distY&&a.distX<-a.distY||a.distX>a.distY&&a.distX>-a.distY)&&"vertical"===g&&a.preventDefault(),f.addClass("active"),q=f.offset().left,r=f.offset().top,s=j.width(),t=j.height()}),l.on("moveend",function(){f.removeClass("active")}),l.on("move",function(a){f.hasClass("active")&&(e="vertical"===g?(a.pageY-r)/t:(a.pageX-q)/s,e<0&&(e=0),e>1&&(e=1),p(e))}),f.find("img").on("mousedown",function(a){a.preventDefault()}),a(c).trigger("resize.twentytwenty")})}}(jQuery,document,window),function(a,b,c,d){var e=function(b){b.each(function(){var b=a(this),c=parseInt(b.closest(".imagify-chart").next(".imagify-chart-value").text(),10),d=[{value:c,color:"#00B3D3"},{value:100-c,color:"#D8D8D8"}];new Chart(b[0].getContext("2d")).Doughnut(d,{segmentStrokeColor:"#2A2E3C",segmentStrokeWidth:1,animateRotate:!0,percentageInnerCutout:60,tooltipEvents:[]})})},f=function(b){var d,f={width:0,height:0,originalUrl:"",optimizedUrl:"",originalSize:0,optimizedSize:0,saving:0,modalAppendTo:a("body"),trigger:a('[data-target="imagify-visual-comparison"]'),modalId:"imagify-visual-comparison",openModal:!1},g=a.extend({},f,b);if(0===g.width||0===g.height||""===g.originalUrl||""===g.optimizedUrl||0===g.originalSize||0===g.optimizedSize||0===g.saving)return"error";d='<div id="'+g.modalId+'" class="imagify-modal imagify-visual-comparison" aria-hidden="true">',d+='<div class="imagify-modal-content loading">',d+='<div class="twentytwenty-container">',d+='<img class="imagify-img-before" alt="" width="'+g.width+'" height="'+g.height+'">',d+='<img class="imagify-img-after" alt="" width="'+g.width+'" height="'+g.height+'">',d+="</div>",d+='<div class="imagify-comparison-levels">',d+='<div class="imagify-c-level imagify-level-original go-left">',d+='<p class="imagify-c-level-row">',d+='<span class="label">'+imagifyTTT.labels.filesize+"</span>",d+='<span class="value level">'+g.originalSize+"</span>",d+="</p>",d+="</div>",d+='<div class="imagify-c-level imagify-level-optimized go-right">',d+='<p class="imagify-c-level-row">',d+='<span class="label">'+imagifyTTT.labels.filesize+"</span>",d+='<span class="value level">'+g.optimizedSize+"</span>",d+="</p>",d+='<p class="imagify-c-level-row">',d+='<span class="label">'+imagifyTTT.labels.saving+"</span>",d+='<span class="value"><span class="imagify-chart"><span class="imagify-chart-container"><canvas id="imagify-consumption-chart-normal" width="15" height="15"></canvas></span></span><span class="imagify-chart-value">'+g.saving+"</span>%</span>",d+="</p>",d+="</div>",d+="</div>",d+='<button class="close-btn absolute" type="button"><i aria-hidden="true" class="dashicons dashicons-no-alt"></i><span class="screen-reader-text">'+imagifyTTT.labels.close+"</span></button>",d+="</div>",d+="</div>",g.modalAppendTo.append(d),g.trigger.on("click.imagify",function(b){var d,f,h=a(a(this).data("target")),i=0;b.preventDefault(),g.openModal&&c.imagify.openModal(a(this)),h.find(".imagify-modal-content").css({width:.85*a(c).outerWidth()+"px","max-width":g.width}),h.find(".imagify-img-before").on("load",function(){i++}).attr("src",g.originalUrl),h.find(".imagify-img-after").on("load",function(){i++}).attr("src",g.optimizedUrl+(g.optimizedUrl.indexOf("?")>0?"&":"?")+"v="+Date.now()),d=h.find(".twentytwenty-container"),f=setInterval(function(){if(2===i)return d.twentytwenty({handlePosition:.3,orientation:"horizontal",labelBefore:imagifyTTT.labels.originalL,labelAfter:imagifyTTT.labels.optimizedL},function(){var b,f,g,i,j,k,l=a(c).height(),m=h.find(".twentytwenty-container").height(),n=h.find(".twentytwenty-wrapper").position().top;d.closest(".imagify-modal-content").hasClass("loaded")||(d.closest(".imagify-modal-content").removeClass("loading").addClass("loaded"),e(h.find(".imagify-level-optimized .imagify-chart canvas"))),l<m&&!h.hasClass("modal-is-too-high")&&(h.addClass("modal-is-too-high"),b=h.find(".twentytwenty-handle"),f=h.find(".twentytwenty-label-content"),g=h.find(".imagify-comparison-levels"),i=g.outerHeight(),j=(l-n-b.height())/2,k=l-3*n-i,b.css({top:j}),f.css({top:k,bottom:"auto"}),h.find(".twentytwenty-wrapper").css({paddingBottom:i}),h.find(".imagify-modal-content").on("scroll.imagify",function(){var c=a(this).scrollTop();b.css({top:j+c}),f.css({top:k+c}),g.css({bottom:-c})}))}),clearInterval(f),f=null,"done"},75)})};if(a(".imagify-visual-comparison-btn").on("click",function(){var b,d,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z,A,B;1!==a(".twentytwenty-wrapper").length&&(a(a(this).data("target")).find(".imagify-modal-content").css("width",.95*a(c).outerWidth()+"px"),a(".twentytwenty-container").length>0&&a(c).outerWidth()<=800||(b=a(".twentytwenty-container"),d=0,f=b.data("loader"),g=b.data("label-original"),h=b.data("label-normal"),i=b.data("label-aggressive"),j=b.data("label-ultra"),k=b.data("original-label").replace(/\*\*/,"<strong>").replace(/\*\*/,"</strong>"),l=b.data("original-alt"),m=b.data("original-img"),n=b.data("original-dim").split("x"),o=b.data("normal-alt"),p=b.data("normal-img"),q=b.data("normal-dim").split("x"),r=b.data("aggressive-alt"),s=b.data("aggressive-img"),t=b.data("aggressive-dim").split("x"),u=b.data("ultra-label").replace(/\*\*/,"<strong>").replace(/\*\*/,"</strong>"),v=b.data("ultra-alt"),w=b.data("ultra-img"),x=b.data("ultra-dim").split("x"),y='<span class="twentytwenty-duo-buttons twentytwenty-duo-left">',y+='<button type="button" class="imagify-comparison-original selected" data-img="original">'+g+"</button>",y+='<button type="button" class="imagify-comparison-normal" data-img="normal">'+h+"</button>",y+='<button type="button" class="imagify-comparison-aggressive" data-img="aggressive">'+i+"</button>",y+="</span>",z='<span class="twentytwenty-duo-buttons twentytwenty-duo-right">',z+='<button type="button" class="imagify-comparison-normal" data-img="normal">'+h+"</button>",z+='<button type="button" class="imagify-comparison-aggressive" data-img="aggressive">'+i+"</button>",z+='<button type="button" class="imagify-comparison-ultra selected" data-img="ultra">'+j+"</button>",z+="</span>",b.before('<img class="loader" src="'+f+'" alt="Loading…" width="64" height="64">'),a(".twentytwenty-left-buttons").append(y),a(".twentytwenty-right-buttons").append(z),A='<img class="img-original" alt="'+l+'" width="'+n[0]+'" height="'+n[1]+'">',A+='<img class="img-normal" alt="'+o+'" width="'+q[0]+'" height="'+q[1]+'">',A+='<img class="img-aggressive" alt="'+r+'" width="'+t[0]+'" height="'+t[1]+'">',A+='<img class="img-ultra" alt="'+v+'" width="'+x[0]+'" height="'+x[1]+'">',A+=a(".twentytwenty-left-buttons").lenght?y+z:"",b.closest(".imagify-modal-content").addClass("loading").find(".twentytwenty-container").append(A),a(".img-original").on("load",function(){d++}).attr("src",m),a(".img-normal").on("load",function(){d++}).attr("src",p),a(".img-aggressive").on("load",function(){d++}).attr("src",s),a(".img-ultra").on("load",function(){d++}).attr("src",w),B=setInterval(function(){4===d&&(b.twentytwenty({handlePosition:.6,orientation:"horizontal",labelBefore:k,labelAfter:u},function(){b.closest(".imagify-modal-content").hasClass("loaded")||(b.closest(".imagify-modal-content").removeClass("loading").addClass("loaded"),e(a(".imagify-level-ultra .imagify-chart canvas")))}),clearInterval(B),B=null)},75),a(".imagify-comparison-title").on("click",".twentytwenty-duo-buttons button:not(.selected)",function(b){var c,d=a(this),f=d.closest(".imagify-comparison-title").nextAll(".twentytwenty-wrapper").find(".twentytwenty-container"),g=d.closest(".twentytwenty-duo-buttons").hasClass("twentytwenty-duo-left")?"left":"right",h="left"===g?d.closest(".imagify-comparison-title").find(".twentytwenty-duo-right"):d.closest(".imagify-comparison-title").find(".twentytwenty-duo-left"),i=d.closest(".twentytwenty-duo-buttons").find("button"),j=f.find(".twentytwenty-before"),k=f.find(".twentytwenty-after"),l=d.data("img");b.stopPropagation(),b.preventDefault(),i.removeClass("selected"),d.addClass("selected"),h.find(".selected").data("img")===l&&h.find("button:not(.selected)").eq(0).trigger("click"),"left"===g&&(c=j.css("clip"),j.attr("style",""),j.removeClass("twentytwenty-before"),f.find(".img-"+l).addClass("twentytwenty-before").css("clip",c),a(".twentytwenty-before-label .twentytwenty-label-content").text(f.data(l+"-label")),a(".imagify-c-level.go-left").attr("aria-hidden","true").removeClass("go-left go-right"),a(".imagify-level-"+l).attr("aria-hidden","false").addClass("go-left")),"right"===g&&(k.removeClass("twentytwenty-after"),f.find(".img-"+l).addClass("twentytwenty-after"),a(".twentytwenty-after-label .twentytwenty-label-content").text(f.data(l+"-label")),a(".imagify-c-level.go-right").attr("aria-hidden","true").removeClass("go-left go-right"),a(".imagify-level-"+l).attr("aria-hidden","false").addClass("go-right")),e(a(".imagify-level-"+l+" .imagify-chart canvas"))})))}),imagifyTTT.imageWidth&&a(".post-php .wp_attachment_image .thumbnail").length>0){var g,h,i=a(".post-php .wp_attachment_image"),j={src:a("#imagify-full-original").val(),size:a("#imagify-full-original-size").val()},k=a("#misc-publishing-actions").find(".misc-pub-imagify .button-primary");imagifyTTT.widthLimit=parseInt(imagifyTTT.widthLimit,10),imagifyTTT.imageWidth>imagifyTTT.widthLimit&&j.src?(g=a(".misc-pub-filesize strong").text(),h=a(".imagify-data-item .imagify-chart-value").text(),a('[id^="imgedit-open-btn-"]').before('<button type="button" class="imagify-button-primary button-primary imagify-modal-trigger" data-target="#imagify-visual-comparison" id="imagify-start-comparison">'+imagifyTTT.labels.compare+"</button>"),f({width:parseInt(imagifyTTT.imageWidth,10),height:parseInt(imagifyTTT.imageHeight,10),originalUrl:j.src,optimizedUrl:imagifyTTT.imageSrc,originalSize:j.size,optimizedSize:g,saving:h,modalAppendTo:i,trigger:a("#imagify-start-comparison"),modalId:"imagify-visual-comparison"})):imagifyTTT.imageWidth<imagifyTTT.widthLimit&&j.src||a("#imagify-full-original").length>0&&""===j.src||1===a("#misc-publishing-actions").find(".misc-pub-imagify .button-primary").length&&(a('[id^="imgedit-open-btn-"]').before('<span class="spinner imagify-hidden"></span><a class="imagify-button-primary button-primary imagify-optimize-trigger" id="imagify-optimize-trigger" href="'+k.attr("href")+'">'+imagifyTTT.labels.optimize+"</a>"),a("#imagify-optimize-trigger").on("click",function(){a(this).prev(".spinner").removeClass("imagify-hidden").addClass("is-active")}))}if(a(".upload-php .imagify-compare-images").length>0&&a(".imagify-compare-images").each(function(){var b=a(this),c=b.data("id"),d=b.closest("#post-"+c).find(".column-imagify_optimized_file");f({width:parseInt(b.data("full-width"),10),height:parseInt(b.data("full-height"),10),originalUrl:b.data("backup-src"),optimizedUrl:b.data("full-src"),originalSize:d.find(".original").text(),optimizedSize:d.find(".imagify-data-item .big").text(),saving:d.find(".imagify-chart-value").text(),modalAppendTo:b.closest(".column-primary"),trigger:b,modalId:"imagify-comparison-"+c})}),a(".upload-php").length>0)var l=function(a){var b={};return c.location.href.replace(/[?&]+([^=&]+)=?([^&]*)?/gi,function(a,c,d){b[c]=void 0!==d?d:""}),a?b[a]?b[a]:null:b},m=function(){var b=setInterval(function(){var c,d;a(".media-modal .imagify-datas-details").length&&(d=a("#imagify-original-src").val(),d&&(a(".media-frame-content .attachment-actions").prepend('<button type="button" class="imagify-button-primary button-primary imagify-modal-trigger" data-target="#imagify-comparison-modal" id="imagify-media-frame-comparison-btn">'+imagifyTTT.labels.compare+"</button>"),c=a(".media-frame-content .compat-field-imagify"),f({width:parseInt(a("#imagify-full-width").val(),10),height:parseInt(a("#imagify-full-height").val(),10),originalUrl:d,optimizedUrl:a("#imagify-full-src").val(),originalSize:a("#imagify-original-size").val(),optimizedSize:c.find(".imagify-data-item .big").text(),saving:c.find(".imagify-chart-value").text(),modalAppendTo:a(".media-frame-content .thumbnail-image"),trigger:a("#imagify-media-frame-comparison-btn"),modalId:"imagify-comparison-modal",openModal:!0})),clearInterval(b),b=null)},20)},n=setInterval(function(){a(".upload-php .media-frame.mode-grid .attachments").length&&(a(".upload-php .media-frame.mode-grid").on("click",".attachment",function(){m()}),l("item")&&m(),clearInterval(n),n=null)},100)}(jQuery,document,window);
1
+ !function(a,b,c,d){a.fn.twentytwenty=function(b,d){return b=a.extend({handlePosition:.5,orientation:"horizontal",labelBefore:"Before",labelAfter:"After"},b),this.each(function(){var e,f,g=b.handlePosition,h=a(this),i=b.orientation,j="vertical"===i?"down":"left",k="vertical"===i?"up":"right",l=h.find("img:first"),m=h.find("img:last"),n=0,o=0,p=0,q=0,r=function(a){var b=parseInt(l.attr("width"),10),c=parseInt(l.attr("height"),10);return b&&c||(b=parseInt(l.width(),10),c=parseInt(l.height(),10)),{w:b+"px",h:c+"px",cw:a*b+"px",ch:a*c+"px"}},s=function(a){var b=h.find(".twentytwenty-before");"vertical"===i?b.css("clip","rect(0,"+a.w+","+a.ch+",0)"):b.css("clip","rect(0,"+a.cw+","+a.h+",0)"),h.css("height",a.h),"function"==typeof d&&d()},t=function(a){var b=r(a);"vertical"===i?e.css("top",b.ch):e.css("left",b.cw),s(b)};h.wrap('<div class="twentytwenty-wrapper twentytwenty-'+i+'"></div>'),h.append('<div class="twentytwenty-overlay"></div>'),h.append('<div class="twentytwenty-handle"></div>'),e=h.find(".twentytwenty-handle"),e.append('<span class="twentytwenty-'+j+'-arrow"></span>'),e.append('<span class="twentytwenty-'+k+'-arrow"></span>'),h.addClass("twentytwenty-container"),l.addClass("twentytwenty-before"),m.addClass("twentytwenty-after"),f=h.find(".twentytwenty-overlay"),f.append('<div class="twentytwenty-labels twentytwenty-before-label"><span class="twentytwenty-label-content">'+b.labelBefore+"</span></div>"),f.append('<div class="twentytwenty-labels twentytwenty-after-label"><span class="twentytwenty-label-content">'+b.labelAfter+"</span></div>"),a(c).on("resize.twentytwenty",function(){t(g)}),e.on("movestart",function(a){"vertical"!==i&&(a.distX>a.distY&&a.distX<-a.distY||a.distX<a.distY&&a.distX>-a.distY)?a.preventDefault():"vertical"===i&&(a.distX<a.distY&&a.distX<-a.distY||a.distX>a.distY&&a.distX>-a.distY)&&a.preventDefault(),h.addClass("active"),n=h.offset().left,o=h.offset().top,p=l.width(),q=l.height()}),e.on("moveend",function(){h.removeClass("active")}),e.on("move",function(a){h.hasClass("active")&&(g="vertical"===i?(a.pageY-o)/q:(a.pageX-n)/p,g<0?g=0:g>1&&(g=1),t(g))}),h.find("img").on("mousedown",function(a){a.preventDefault()}),a(c).trigger("resize.twentytwenty")})}}(jQuery,document,window),function(a,b,c,d){var e=function(b){b.each(function(){var b=parseInt(a(this).closest(".imagify-chart").next(".imagify-chart-value").text(),10);new Chart(this,{type:"doughnut",data:{datasets:[{data:[b,100-b],backgroundColor:["#00B3D3","#D8D8D8"],borderColor:"#2A2E3C",borderWidth:1}]},options:{legend:{display:!1},events:[],animation:{easing:"easeOutBounce"},tooltips:{enabled:!1},responsive:!1,cutoutPercentage:60}})})},f=function(b){var d,f={width:0,height:0,originalUrl:"",optimizedUrl:"",originalSize:0,optimizedSize:0,saving:0,modalAppendTo:a("body"),trigger:a('[data-target="imagify-visual-comparison"]'),modalId:"imagify-visual-comparison",openModal:!1},g=a.extend({},f,b);if(0===g.width||0===g.height||""===g.originalUrl||""===g.optimizedUrl||0===g.originalSize||0===g.optimizedSize||0===g.saving)return"error";d='<div id="'+g.modalId+'" class="imagify-modal imagify-visual-comparison" aria-hidden="true">',d+='<div class="imagify-modal-content loading">',d+='<div class="twentytwenty-container">',d+='<img class="imagify-img-before" alt="" width="'+g.width+'" height="'+g.height+'">',d+='<img class="imagify-img-after" alt="" width="'+g.width+'" height="'+g.height+'">',d+="</div>",d+='<div class="imagify-comparison-levels">',d+='<div class="imagify-c-level imagify-level-original go-left">',d+='<p class="imagify-c-level-row">',d+='<span class="label">'+imagifyTTT.labels.filesize+"</span>",d+='<span class="value level">'+g.originalSize+"</span>",d+="</p>",d+="</div>",d+='<div class="imagify-c-level imagify-level-optimized go-right">',d+='<p class="imagify-c-level-row">',d+='<span class="label">'+imagifyTTT.labels.filesize+"</span>",d+='<span class="value level">'+g.optimizedSize+"</span>",d+="</p>",d+='<p class="imagify-c-level-row">',d+='<span class="label">'+imagifyTTT.labels.saving+"</span>",d+='<span class="value"><span class="imagify-chart"><span class="imagify-chart-container"><canvas id="imagify-consumption-chart-normal" width="15" height="15"></canvas></span></span><span class="imagify-chart-value">'+g.saving+"</span>%</span>",d+="</p>",d+="</div>",d+="</div>",d+='<button class="close-btn absolute" type="button"><i aria-hidden="true" class="dashicons dashicons-no-alt"></i><span class="screen-reader-text">'+imagifyTTT.labels.close+"</span></button>",d+="</div>",d+="</div>",g.modalAppendTo.append(d),g.trigger.on("click.imagify",function(b){var d,f,h=a(a(this).data("target")),i=0;b.preventDefault(),g.openModal&&c.imagify.openModal(a(this)),h.find(".imagify-modal-content").css({width:.85*a(c).outerWidth()+"px","max-width":g.width}),h.find(".imagify-img-before").on("load",function(){i++}).attr("src",g.originalUrl),h.find(".imagify-img-after").on("load",function(){i++}).attr("src",g.optimizedUrl+(g.optimizedUrl.indexOf("?")>0?"&":"?")+"v="+Date.now()),d=h.find(".twentytwenty-container"),f=setInterval(function(){if(2===i)return d.twentytwenty({handlePosition:.3,orientation:"horizontal",labelBefore:imagifyTTT.labels.originalL,labelAfter:imagifyTTT.labels.optimizedL},function(){var b,f,g,i,j,k,l=a(c).height(),m=h.find(".twentytwenty-container").height(),n=h.find(".twentytwenty-wrapper").position().top;d.closest(".imagify-modal-content").hasClass("loaded")||(d.closest(".imagify-modal-content").removeClass("loading").addClass("loaded"),e(h.find(".imagify-level-optimized .imagify-chart canvas"))),l<m&&!h.hasClass("modal-is-too-high")&&(h.addClass("modal-is-too-high"),b=h.find(".twentytwenty-handle"),f=h.find(".twentytwenty-label-content"),g=h.find(".imagify-comparison-levels"),i=g.outerHeight(),j=(l-n-b.height())/2,k=l-3*n-i,b.css({top:j}),f.css({top:k,bottom:"auto"}),h.find(".twentytwenty-wrapper").css({paddingBottom:i}),h.find(".imagify-modal-content").on("scroll.imagify",function(){var c=a(this).scrollTop();b.css({top:j+c}),f.css({top:k+c}),g.css({bottom:-c})}))}),clearInterval(f),f=null,"done"},75)})};if(a(".imagify-visual-comparison-btn").on("click",function(){var b,d,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z,A,B;1!==a(".twentytwenty-wrapper").length&&(a(a(this).data("target")).find(".imagify-modal-content").css("width",.95*a(c).outerWidth()+"px"),a(".twentytwenty-container").length>0&&a(c).outerWidth()<=800||(b=a(".twentytwenty-container"),d=0,f=b.data("loader"),g=b.data("label-original"),h=b.data("label-normal"),i=b.data("label-aggressive"),j=b.data("label-ultra"),k=b.data("original-label").replace(/\*\*/,"<strong>").replace(/\*\*/,"</strong>"),l=b.data("original-alt"),m=b.data("original-img"),n=b.data("original-dim").split("x"),o=b.data("normal-alt"),p=b.data("normal-img"),q=b.data("normal-dim").split("x"),r=b.data("aggressive-alt"),s=b.data("aggressive-img"),t=b.data("aggressive-dim").split("x"),u=b.data("ultra-label").replace(/\*\*/,"<strong>").replace(/\*\*/,"</strong>"),v=b.data("ultra-alt"),w=b.data("ultra-img"),x=b.data("ultra-dim").split("x"),y='<span class="twentytwenty-duo-buttons twentytwenty-duo-left">',y+='<button type="button" class="imagify-comparison-original selected" data-img="original">'+g+"</button>",y+='<button type="button" class="imagify-comparison-normal" data-img="normal">'+h+"</button>",y+='<button type="button" class="imagify-comparison-aggressive" data-img="aggressive">'+i+"</button>",y+="</span>",z='<span class="twentytwenty-duo-buttons twentytwenty-duo-right">',z+='<button type="button" class="imagify-comparison-normal" data-img="normal">'+h+"</button>",z+='<button type="button" class="imagify-comparison-aggressive" data-img="aggressive">'+i+"</button>",z+='<button type="button" class="imagify-comparison-ultra selected" data-img="ultra">'+j+"</button>",z+="</span>",b.before('<img class="loader" src="'+f+'" alt="Loading…" width="64" height="64">'),a(".twentytwenty-left-buttons").append(y),a(".twentytwenty-right-buttons").append(z),A='<img class="img-original" alt="'+l+'" width="'+n[0]+'" height="'+n[1]+'">',A+='<img class="img-normal" alt="'+o+'" width="'+q[0]+'" height="'+q[1]+'">',A+='<img class="img-aggressive" alt="'+r+'" width="'+t[0]+'" height="'+t[1]+'">',A+='<img class="img-ultra" alt="'+v+'" width="'+x[0]+'" height="'+x[1]+'">',A+=a(".twentytwenty-left-buttons").lenght?y+z:"",b.closest(".imagify-modal-content").addClass("loading").find(".twentytwenty-container").append(A),a(".img-original").on("load",function(){d++}).attr("src",m),a(".img-normal").on("load",function(){d++}).attr("src",p),a(".img-aggressive").on("load",function(){d++}).attr("src",s),a(".img-ultra").on("load",function(){d++}).attr("src",w),B=setInterval(function(){4===d&&(b.twentytwenty({handlePosition:.6,orientation:"horizontal",labelBefore:k,labelAfter:u},function(){b.closest(".imagify-modal-content").hasClass("loaded")||(b.closest(".imagify-modal-content").removeClass("loading").addClass("loaded"),e(a(".imagify-level-ultra .imagify-chart canvas")))}),clearInterval(B),B=null)},75),a(".imagify-comparison-title").on("click",".twentytwenty-duo-buttons button:not(.selected)",function(b){var c,d=a(this),f=d.closest(".imagify-comparison-title").nextAll(".twentytwenty-wrapper").find(".twentytwenty-container"),g=d.closest(".twentytwenty-duo-buttons").hasClass("twentytwenty-duo-left")?"left":"right",h="left"===g?d.closest(".imagify-comparison-title").find(".twentytwenty-duo-right"):d.closest(".imagify-comparison-title").find(".twentytwenty-duo-left"),i=d.closest(".twentytwenty-duo-buttons").find("button"),j=f.find(".twentytwenty-before"),k=f.find(".twentytwenty-after"),l=d.data("img");b.stopPropagation(),b.preventDefault(),i.removeClass("selected"),d.addClass("selected"),h.find(".selected").data("img")===l&&h.find("button:not(.selected)").eq(0).trigger("click"),"left"===g&&(c=j.css("clip"),j.attr("style",""),j.removeClass("twentytwenty-before"),f.find(".img-"+l).addClass("twentytwenty-before").css("clip",c),a(".twentytwenty-before-label .twentytwenty-label-content").text(f.data(l+"-label")),a(".imagify-c-level.go-left").attr("aria-hidden","true").removeClass("go-left go-right"),a(".imagify-level-"+l).attr("aria-hidden","false").addClass("go-left")),"right"===g&&(k.removeClass("twentytwenty-after"),f.find(".img-"+l).addClass("twentytwenty-after"),a(".twentytwenty-after-label .twentytwenty-label-content").text(f.data(l+"-label")),a(".imagify-c-level.go-right").attr("aria-hidden","true").removeClass("go-left go-right"),a(".imagify-level-"+l).attr("aria-hidden","false").addClass("go-right")),e(a(".imagify-level-"+l+" .imagify-chart canvas"))})))}),imagifyTTT.imageWidth&&a(".post-php .wp_attachment_image .thumbnail").length>0){var g,h,i=a(".post-php .wp_attachment_image"),j={src:a("#imagify-full-original").val(),size:a("#imagify-full-original-size").val()},k=a("#misc-publishing-actions").find(".misc-pub-imagify .button-primary");imagifyTTT.widthLimit=parseInt(imagifyTTT.widthLimit,10),imagifyTTT.imageWidth>imagifyTTT.widthLimit&&j.src?(g=a(".misc-pub-filesize strong").text(),h=a(".imagify-data-item .imagify-chart-value").text(),a('[id^="imgedit-open-btn-"]').before('<button type="button" class="imagify-button-primary button-primary imagify-modal-trigger" data-target="#imagify-visual-comparison" id="imagify-start-comparison">'+imagifyTTT.labels.compare+"</button>"),f({width:parseInt(imagifyTTT.imageWidth,10),height:parseInt(imagifyTTT.imageHeight,10),originalUrl:j.src,optimizedUrl:imagifyTTT.imageSrc,originalSize:j.size,optimizedSize:g,saving:h,modalAppendTo:i,trigger:a("#imagify-start-comparison"),modalId:"imagify-visual-comparison"})):imagifyTTT.imageWidth<imagifyTTT.widthLimit&&j.src||a("#imagify-full-original").length>0&&""===j.src||1===a("#misc-publishing-actions").find(".misc-pub-imagify .button-primary").length&&(a('[id^="imgedit-open-btn-"]').before('<span class="spinner imagify-hidden"></span><a class="imagify-button-primary button-primary imagify-optimize-trigger" id="imagify-optimize-trigger" href="'+k.attr("href")+'">'+imagifyTTT.labels.optimize+"</a>"),a("#imagify-optimize-trigger").on("click",function(){a(this).prev(".spinner").removeClass("imagify-hidden").addClass("is-active")}))}if(a(".upload-php .imagify-compare-images").length>0&&a(".imagify-compare-images").each(function(){var b=a(this),c=b.data("id"),d=b.closest("#post-"+c).find(".column-imagify_optimized_file");f({width:parseInt(b.data("full-width"),10),height:parseInt(b.data("full-height"),10),originalUrl:b.data("backup-src"),optimizedUrl:b.data("full-src"),originalSize:d.find(".original").text(),optimizedSize:d.find(".imagify-data-item .big").text(),saving:d.find(".imagify-chart-value").text(),modalAppendTo:b.closest(".column-primary"),trigger:b,modalId:"imagify-comparison-"+c})}),a(".upload-php").length>0){var l=function(){var b=setInterval(function(){var c,d,e;a(".media-modal .imagify-datas-details").length&&(d=a("#imagify-original-src").val(),d&&(e=a(".media-frame-content .attachment-actions"),e.find("#imagify-media-frame-comparison-btn").remove(),e.prepend('<button type="button" class="imagify-button-primary button-primary imagify-modal-trigger" data-target="#imagify-comparison-modal" id="imagify-media-frame-comparison-btn">'+imagifyTTT.labels.compare+"</button>"),c=a(".media-frame-content .compat-field-imagify"),f({width:parseInt(a("#imagify-full-width").val(),10),height:parseInt(a("#imagify-full-height").val(),10),originalUrl:d,optimizedUrl:a("#imagify-full-src").val(),originalSize:a("#imagify-original-size").val(),optimizedSize:c.find(".imagify-data-item .big").text(),saving:c.find(".imagify-chart-value").text(),modalAppendTo:a(".media-frame-content .thumbnail-image"),trigger:a("#imagify-media-frame-comparison-btn"),modalId:"imagify-comparison-modal",openModal:!0})),clearInterval(b),b=null)},20)};a(".upload-php").on("click",".media-frame.mode-grid .attachment, .edit-media-header .left, .edit-media-header .right",function(){l()}),function(a){var b={};return c.location.href.replace(/[?&]+([^=&]+)=?([^&]*)?/gi,function(a,c,d){b[c]=void 0!==d?d:""}),a?b[a]?b[a]:null:b}("item")&&l()}}(jQuery,document,window);
assets/js/media-modal.js CHANGED
@@ -5,24 +5,31 @@
5
  */
6
  window.imagify.drawMeAChart = function( canvas ) {
7
  canvas.each( function() {
8
- var $this = jQuery( this ),
9
- theValue = parseInt( $this.closest( '.imagify-chart' ).next( '.imagify-chart-value' ).text() ),
10
- overviewData = [
11
- {
12
- value: theValue,
13
- color: '#00B3D3'
 
 
 
 
 
 
 
 
 
14
  },
15
- {
16
- value: 100 - theValue,
17
- color: '#D8D8D8'
18
- }
19
- ];
20
-
21
- new Chart( $this[0].getContext( '2d' ) ).Doughnut( overviewData, { // eslint-disable-line new-cap
22
- segmentStrokeColor: '#FFF',
23
- segmentStrokeWidth: 1,
24
- animateRotate: true,
25
- tooltipEvents: []
26
  } );
27
  } );
28
  };
5
  */
6
  window.imagify.drawMeAChart = function( canvas ) {
7
  canvas.each( function() {
8
+ var value = parseInt( jQuery( this ).closest( '.imagify-chart' ).next( '.imagify-chart-value' ).text() );
9
+
10
+ new Chart( this, { // eslint-disable-line no-new
11
+ type: 'doughnut',
12
+ data: {
13
+ datasets: [{
14
+ data: [ value, 100 - value ],
15
+ backgroundColor: [ '#00B3D3', '#D8D8D8' ],
16
+ borderColor: '#fff',
17
+ borderWidth: 1
18
+ }]
19
+ },
20
+ options: {
21
+ legend: {
22
+ display: false
23
  },
24
+ events: [],
25
+ animation: {
26
+ easing: 'easeOutBounce'
27
+ },
28
+ tooltips: {
29
+ enabled: false
30
+ },
31
+ responsive: false
32
+ }
 
 
33
  } );
34
  } );
35
  };
assets/js/media-modal.min.js CHANGED
@@ -1 +1 @@
1
- window.imagify.drawMeAChart=function(a){a.each(function(){var a=jQuery(this),b=parseInt(a.closest(".imagify-chart").next(".imagify-chart-value").text()),c=[{value:b,color:"#00B3D3"},{value:100-b,color:"#D8D8D8"}];new Chart(a[0].getContext("2d")).Doughnut(c,{segmentStrokeColor:"#FFF",segmentStrokeWidth:1,animateRotate:!0,tooltipEvents:[]})})},function(a,b,c,d){var e=!1;a(".imagify-datas-details").hide(),a(b).on("click",".imagify-datas-more-action a",function(b){var c=a(this);b.preventDefault(),c.hasClass("is-open")?(a(c.attr("href")).slideUp(300).removeClass("is-open"),c.removeClass("is-open").find(".the-text").text(c.data("open"))):(a(c.attr("href")).slideDown(300).addClass("is-open"),c.addClass("is-open").find(".the-text").text(c.data("close")))}),a(b).on("click",".button-imagify-restore, .button-imagify-manual-upload, .button-imagify-manual-override-upload, .button-imagify-optimize-missing-sizes",function(b){var d=a(this),f=d.parents(".column-imagify_optimized_file, .compat-field-imagify .field"),g=d.attr("href");b.preventDefault(),f.length||(f=d.closest(".column")),f.html('<div class="button"><span class="imagify-spinner"></span>'+d.data("waiting-label")+"</div>"),a.get(g.replace("admin-post.php","admin-ajax.php")).done(function(a){e=!0,f.html(a.data),f.find(".imagify-datas-more-action a").addClass("is-open").find(".the-text").text(f.find(".imagify-datas-more-action a").data("close")),f.find(".imagify-datas-details").addClass("is-open"),c.imagify.drawMeAChart(f.find(".imagify-consumption-chart")),e=!1})}),a(c).on("canvasprinted.imagify",function(b,d){var f;d=d||".imagify-consumption-chart",f=a(d),c.imagify.drawMeAChart(f),e||f.closest(".imagify-datas-list").siblings(".imagify-datas-details").hide()}).trigger("canvasprinted.imagify")}(jQuery,document,window);
1
+ window.imagify.drawMeAChart=function(a){a.each(function(){var a=parseInt(jQuery(this).closest(".imagify-chart").next(".imagify-chart-value").text());new Chart(this,{type:"doughnut",data:{datasets:[{data:[a,100-a],backgroundColor:["#00B3D3","#D8D8D8"],borderColor:"#fff",borderWidth:1}]},options:{legend:{display:!1},events:[],animation:{easing:"easeOutBounce"},tooltips:{enabled:!1},responsive:!1}})})},function(a,b,c,d){var e=!1;a(".imagify-datas-details").hide(),a(b).on("click",".imagify-datas-more-action a",function(b){var c=a(this);b.preventDefault(),c.hasClass("is-open")?(a(c.attr("href")).slideUp(300).removeClass("is-open"),c.removeClass("is-open").find(".the-text").text(c.data("open"))):(a(c.attr("href")).slideDown(300).addClass("is-open"),c.addClass("is-open").find(".the-text").text(c.data("close")))}),a(b).on("click",".button-imagify-restore, .button-imagify-manual-upload, .button-imagify-manual-override-upload, .button-imagify-optimize-missing-sizes",function(b){var d=a(this),f=d.parents(".column-imagify_optimized_file, .compat-field-imagify .field"),g=d.attr("href");b.preventDefault(),f.length||(f=d.closest(".column")),f.html('<div class="button"><span class="imagify-spinner"></span>'+d.data("waiting-label")+"</div>"),a.get(g.replace("admin-post.php","admin-ajax.php")).done(function(a){e=!0,f.html(a.data),f.find(".imagify-datas-more-action a").addClass("is-open").find(".the-text").text(f.find(".imagify-datas-more-action a").data("close")),f.find(".imagify-datas-details").addClass("is-open"),c.imagify.drawMeAChart(f.find(".imagify-consumption-chart")),e=!1})}),a(c).on("canvasprinted.imagify",function(b,d){var f;d=d||".imagify-consumption-chart",f=a(d),c.imagify.drawMeAChart(f),e||f.closest(".imagify-datas-list").siblings(".imagify-datas-details").hide()}).trigger("canvasprinted.imagify")}(jQuery,document,window);
imagify.php CHANGED
@@ -3,7 +3,7 @@
3
  * Plugin Name: Imagify
4
  * Plugin URI: https://wordpress.org/plugins/imagify/
5
  * Description: Dramaticaly reduce image file sizes without losing quality, make your website load faster, boost your SEO and save money on your bandwidth using Imagify, the new most advanced image optimization tool.
6
- * Version: 1.6.13.1
7
  * Author: WP Media
8
  * Author URI: https://wp-media.me/
9
  * Licence: GPLv2
@@ -17,7 +17,7 @@
17
  defined( 'ABSPATH' ) || die( 'Cheatin\' uh?' );
18
 
19
  // Imagify defines.
20
- define( 'IMAGIFY_VERSION' , '1.6.13.1' );
21
  define( 'IMAGIFY_SLUG' , 'imagify' );
22
  define( 'IMAGIFY_SETTINGS_SLUG' , IMAGIFY_SLUG . '_settings' );
23
  define( 'IMAGIFY_FILE' , __FILE__ );
@@ -71,9 +71,11 @@ function _imagify_init() {
71
  require( IMAGIFY_FUNCTIONS_PATH . 'admin-ui.php' );
72
  require( IMAGIFY_FUNCTIONS_PATH . 'admin-stats.php' );
73
  require( IMAGIFY_FUNCTIONS_PATH . 'i18n.php' );
 
74
  require( IMAGIFY_COMMON_PATH . 'attachments.php' );
75
  require( IMAGIFY_COMMON_PATH . 'admin-bar.php' );
76
  require( IMAGIFY_COMMON_PATH . 'cron.php' );
 
77
  require( IMAGIFY_3RD_PARTY_PATH . '3rd-party.php' );
78
 
79
  if ( is_admin() ) {
3
  * Plugin Name: Imagify
4
  * Plugin URI: https://wordpress.org/plugins/imagify/
5
  * Description: Dramaticaly reduce image file sizes without losing quality, make your website load faster, boost your SEO and save money on your bandwidth using Imagify, the new most advanced image optimization tool.
6
+ * Version: 1.6.14
7
  * Author: WP Media
8
  * Author URI: https://wp-media.me/
9
  * Licence: GPLv2
17
  defined( 'ABSPATH' ) || die( 'Cheatin\' uh?' );
18
 
19
  // Imagify defines.
20
+ define( 'IMAGIFY_VERSION' , '1.6.14' );
21
  define( 'IMAGIFY_SLUG' , 'imagify' );
22
  define( 'IMAGIFY_SETTINGS_SLUG' , IMAGIFY_SLUG . '_settings' );
23
  define( 'IMAGIFY_FILE' , __FILE__ );
71
  require( IMAGIFY_FUNCTIONS_PATH . 'admin-ui.php' );
72
  require( IMAGIFY_FUNCTIONS_PATH . 'admin-stats.php' );
73
  require( IMAGIFY_FUNCTIONS_PATH . 'i18n.php' );
74
+ require( IMAGIFY_FUNCTIONS_PATH . 'partners.php' );
75
  require( IMAGIFY_COMMON_PATH . 'attachments.php' );
76
  require( IMAGIFY_COMMON_PATH . 'admin-bar.php' );
77
  require( IMAGIFY_COMMON_PATH . 'cron.php' );
78
+ require( IMAGIFY_COMMON_PATH . 'partners.php' );
79
  require( IMAGIFY_3RD_PARTY_PATH . '3rd-party.php' );
80
 
81
  if ( is_admin() ) {
inc/3rd-party/hosting/siteground.php CHANGED
File without changes
inc/3rd-party/hosting/wpengine.php CHANGED
File without changes
inc/3rd-party/nextgen-gallery/inc/admin/ajax.php CHANGED
@@ -81,17 +81,7 @@ function _do_wp_ajax_imagify_ngg_get_unoptimized_attachment_ids() {
81
  @set_time_limit( 0 );
82
 
83
  $optimization_level = (int) $_GET['optimization_level'];
84
- $optimization_level = ( -1 !== $optimization_level ) ? $optimization_level : get_imagify_option( 'optimization_level', 1 );
85
- $optimization_level = (int) $optimization_level;
86
-
87
- /**
88
- * Filter the unoptimized attachments limit query.
89
- *
90
- * @since 1.4.4
91
- *
92
- * @param int The limit (-1 for unlimited).
93
- */
94
- $unoptimized_attachment_limit = apply_filters( 'imagify_unoptimized_attachment_limit', 10000 );
95
 
96
  $storage = C_Gallery_Storage::get_instance();
97
  $ngg_table = $wpdb->prefix . 'ngg_pictures';
@@ -106,7 +96,7 @@ function _do_wp_ajax_imagify_ngg_get_unoptimized_attachment_ids() {
106
  OR idata.status = 'error'
107
  LIMIT %d",
108
  $optimization_level,
109
- $unoptimized_attachment_limit
110
  ), ARRAY_A );
111
 
112
  // Save the optimization level in a transient to retrieve it later during the process.
81
  @set_time_limit( 0 );
82
 
83
  $optimization_level = (int) $_GET['optimization_level'];
84
+ $optimization_level = -1 !== $optimization_level ? $optimization_level : (int) get_imagify_option( 'optimization_level', 1 );
 
 
 
 
 
 
 
 
 
 
85
 
86
  $storage = C_Gallery_Storage::get_instance();
87
  $ngg_table = $wpdb->prefix . 'ngg_pictures';
96
  OR idata.status = 'error'
97
  LIMIT %d",
98
  $optimization_level,
99
+ imagify_get_unoptimized_attachment_limit()
100
  ), ARRAY_A );
101
 
102
  // Save the optimization level in a transient to retrieve it later during the process.
inc/3rd-party/nextgen-gallery/inc/admin/bulk.php CHANGED
File without changes
inc/3rd-party/nextgen-gallery/inc/admin/db.php CHANGED
File without changes
inc/3rd-party/nextgen-gallery/inc/admin/gallery.php CHANGED
File without changes
inc/3rd-party/nextgen-gallery/inc/admin/heartbeat.php CHANGED
File without changes
inc/3rd-party/nextgen-gallery/inc/admin/menu.php CHANGED
File without changes
inc/3rd-party/nextgen-gallery/inc/classes/class-imagify-ngg-attachment.php CHANGED
File without changes
inc/3rd-party/nextgen-gallery/inc/classes/class-imagify-ngg-db.php CHANGED
File without changes
inc/3rd-party/nextgen-gallery/inc/functions/admin-stats.php CHANGED
@@ -87,7 +87,11 @@ function imagify_ngg_percent_optimized_attachments() {
87
  $total_attachments = imagify_ngg_count_attachments();
88
  $total_optimized_attachments = imagify_ngg_count_optimized_attachments();
89
 
90
- return $total_attachments && $total_optimized_attachments ? round( 100 - ( ( $total_attachments - $total_optimized_attachments ) / $total_attachments ) * 100 ) : 0;
 
 
 
 
91
  }
92
 
93
  /**
87
  $total_attachments = imagify_ngg_count_attachments();
88
  $total_optimized_attachments = imagify_ngg_count_optimized_attachments();
89
 
90
+ if ( ! $total_attachments || ! $total_optimized_attachments ) {
91
+ return 0;
92
+ }
93
+
94
+ return min( round( 100 * $total_optimized_attachments / $total_attachments ), 100 );
95
  }
96
 
97
  /**
inc/3rd-party/nextgen-gallery/inc/functions/attachments.php CHANGED
File without changes
inc/3rd-party/wp-rocket.php CHANGED
File without changes
inc/admin/meta-boxes.php CHANGED
@@ -55,6 +55,6 @@ function _imagify_attachment_submitbox_misc_actions() {
55
 
56
  if ( $attachment->is_optimized() ) {
57
  echo '<input id="imagify-full-original" type="hidden" value="' . esc_url( $attachment->get_backup_url() ) . '">';
58
- echo '<input id="imagify-full-original-size" type="hidden" value="' . esc_attr( $attachment->get_original_size() ) . '">';
59
  }
60
  }
55
 
56
  if ( $attachment->is_optimized() ) {
57
  echo '<input id="imagify-full-original" type="hidden" value="' . esc_url( $attachment->get_backup_url() ) . '">';
58
+ echo '<input id="imagify-full-original-size" type="hidden" value="' . esc_attr( $attachment->get_original_size( true, 0 ) ) . '">';
59
  }
60
  }
inc/admin/ui/bulk.php CHANGED
@@ -104,7 +104,7 @@ function _imagify_display_bulk_page() {
104
  <div class="col-1-3 col-overview">
105
  <h3><?php _e( 'Overview', 'imagify' ); ?></h3>
106
 
107
- <div class="imagify-chart-container">
108
  <canvas id="imagify-overview-chart" width="180" height="180"></canvas>
109
  <div id="imagify-overview-chart-percent" class="imagify-chart-percent"><?php echo imagify_percent_optimized_attachments(); ?><span>%</span></div>
110
  </div>
@@ -182,16 +182,11 @@ function _imagify_display_bulk_page() {
182
  <?php
183
  esc_html_e( 'Please be aware that optimizing a large number of images can take a while depending on your server and network speed.', 'imagify' );
184
 
185
- if ( get_transient( IMAGIFY_SLUG . '_large_library' ) ) {
186
  printf(
187
  /* translators: %s is a formatted number. Don't use %d. */
188
  __( 'If you have more than %s images, you will need to launch the bulk optimization several times.' , 'imagify' ),
189
- /**
190
- * Filter the unoptimized attachments limit.
191
- *
192
- * @param int Default is 10000.
193
- */
194
- number_format_i18n( apply_filters( 'imagify_unoptimized_attachment_limit', 10000 ) )
195
  );
196
  }
197
  ?>
104
  <div class="col-1-3 col-overview">
105
  <h3><?php _e( 'Overview', 'imagify' ); ?></h3>
106
 
107
+ <div class="imagify-chart-container imagify-overview-chart-container">
108
  <canvas id="imagify-overview-chart" width="180" height="180"></canvas>
109
  <div id="imagify-overview-chart-percent" class="imagify-chart-percent"><?php echo imagify_percent_optimized_attachments(); ?><span>%</span></div>
110
  </div>
182
  <?php
183
  esc_html_e( 'Please be aware that optimizing a large number of images can take a while depending on your server and network speed.', 'imagify' );
184
 
185
+ if ( get_transient( 'imagify_large_library' ) ) {
186
  printf(
187
  /* translators: %s is a formatted number. Don't use %d. */
188
  __( 'If you have more than %s images, you will need to launch the bulk optimization several times.' , 'imagify' ),
189
+ number_format_i18n( imagify_get_unoptimized_attachment_limit() )
 
 
 
 
 
190
  );
191
  }
192
  ?>
inc/admin/ui/options.php CHANGED
@@ -351,7 +351,7 @@ function _imagify_display_options_page() {
351
  </tbody>
352
  </table>
353
 
354
- <h3 class="imagify-options-title"><?php _e( 'Display options', 'Imagify' ); ?></h3>
355
 
356
  <table class="form-table">
357
  <tbody>
351
  </tbody>
352
  </table>
353
 
354
+ <h3 class="imagify-options-title"><?php _e( 'Display options', 'imagify' ); ?></h3>
355
 
356
  <table class="form-table">
357
  <tbody>
inc/classes/class-imagify-abstract-attachment.php CHANGED
@@ -257,15 +257,16 @@ abstract class Imagify_Abstract_Attachment {
257
  * @access public
258
  *
259
  * @param bool $human_format True to display the image human format size (1Mb).
 
260
  * @return string
261
  */
262
- public function get_original_size( $human_format = true ) {
263
  $filesystem = imagify_get_filesystem();
264
  $original_size = $this->get_size_data( 'full', 'original_size' );
265
  $original_size = empty( $original_size ) ? $filesystem->size( $this->get_original_path() ) : (int) $original_size;
266
 
267
  if ( true === $human_format ) {
268
- $original_size = @size_format( $original_size, 2 );
269
  }
270
 
271
  return $original_size;
@@ -593,7 +594,7 @@ abstract class Imagify_Abstract_Attachment {
593
  $image_type = pathinfo( $attachment_path, PATHINFO_EXTENSION );
594
 
595
  // Try to correct for auto-rotation if the info is available.
596
- if ( function_exists( 'exif_read_data' ) && ( 'jpg' === $image_type || 'jpeg' === $image_type) ) {
597
  $exif = @exif_read_data( $attachment_path );
598
  $orientation = is_array( $exif ) && array_key_exists( 'Orientation', $exif ) ? $exif['Orientation'] : 0;
599
 
257
  * @access public
258
  *
259
  * @param bool $human_format True to display the image human format size (1Mb).
260
+ * @param int $decimals Precision of number of decimal places.
261
  * @return string
262
  */
263
+ public function get_original_size( $human_format = true, $decimals = 2 ) {
264
  $filesystem = imagify_get_filesystem();
265
  $original_size = $this->get_size_data( 'full', 'original_size' );
266
  $original_size = empty( $original_size ) ? $filesystem->size( $this->get_original_path() ) : (int) $original_size;
267
 
268
  if ( true === $human_format ) {
269
+ $original_size = @size_format( $original_size, $decimals );
270
  }
271
 
272
  return $original_size;
594
  $image_type = pathinfo( $attachment_path, PATHINFO_EXTENSION );
595
 
596
  // Try to correct for auto-rotation if the info is available.
597
+ if ( function_exists( 'exif_read_data' ) && ( 'jpg' === $image_type || 'jpe' === $image_type || 'jpeg' === $image_type ) ) {
598
  $exif = @exif_read_data( $attachment_path );
599
  $orientation = is_array( $exif ) && array_key_exists( 'Orientation', $exif ) ? $exif['Orientation'] : 0;
600
 
inc/classes/class-imagify-admin-ajax-post.php CHANGED
@@ -402,17 +402,7 @@ class Imagify_Admin_Ajax_Post {
402
 
403
  // Get (ordered) IDs.
404
  $optimization_level = (int) $_GET['optimization_level'];
405
- $optimization_level = ( -1 !== $optimization_level ) ? $optimization_level : (int) get_imagify_option( 'optimization_level', 1 );
406
-
407
- /**
408
- * Filter the unoptimized attachments limit query.
409
- *
410
- * @since 1.4.4
411
- *
412
- * @param int The limit (-1 for unlimited).
413
- */
414
- $unoptimized_attachment_limit = (int) apply_filters( 'imagify_unoptimized_attachment_limit', 10000 );
415
- $unoptimized_attachment_limit = -1 === $unoptimized_attachment_limit ? PHP_INT_MAX : $unoptimized_attachment_limit;
416
 
417
  Imagify_DB::unlimit_joins();
418
 
@@ -448,11 +438,11 @@ class Imagify_Admin_Ajax_Post {
448
  $wpdb->posts.ID DESC
449
  LIMIT 0, %d",
450
  $optimization_level,
451
- $unoptimized_attachment_limit
452
  ) );
453
 
454
  $wpdb->flush();
455
- unset( $unoptimized_attachment_limit, $mime_types );
456
  $ids = array_filter( array_map( 'absint', $ids ) );
457
 
458
  if ( ! $ids ) {
@@ -645,7 +635,7 @@ class Imagify_Admin_Ajax_Post {
645
  $data = array(
646
  'email' => $_GET['email'],
647
  'password' => wp_generate_password( 12, false ),
648
- 'lang' => get_locale(),
649
  );
650
 
651
  $response = add_imagify_user( $data );
402
 
403
  // Get (ordered) IDs.
404
  $optimization_level = (int) $_GET['optimization_level'];
405
+ $optimization_level = -1 !== $optimization_level ? $optimization_level : (int) get_imagify_option( 'optimization_level', 1 );
 
 
 
 
 
 
 
 
 
 
406
 
407
  Imagify_DB::unlimit_joins();
408
 
438
  $wpdb->posts.ID DESC
439
  LIMIT 0, %d",
440
  $optimization_level,
441
+ imagify_get_unoptimized_attachment_limit()
442
  ) );
443
 
444
  $wpdb->flush();
445
+ unset( $mime_types );
446
  $ids = array_filter( array_map( 'absint', $ids ) );
447
 
448
  if ( ! $ids ) {
635
  $data = array(
636
  'email' => $_GET['email'],
637
  'password' => wp_generate_password( 12, false ),
638
+ 'lang' => imagify_get_locale(),
639
  );
640
 
641
  $response = add_imagify_user( $data );
inc/classes/class-imagify-assets.php CHANGED
@@ -14,7 +14,7 @@ class Imagify_Assets {
14
  *
15
  * @var string
16
  */
17
- const VERSION = '1.0';
18
 
19
  /**
20
  * Prefix used for stylesheet handles.
@@ -192,7 +192,7 @@ class Imagify_Assets {
192
 
193
  $this->register_script( 'sweetalert', 'sweetalert2', array( 'promise-polyfill' ), '4.6.6' )->localize( 'imagifySwal' );
194
 
195
- $this->register_script( 'chart', 'chart', array(), '1.0.2' );
196
 
197
  $this->register_script( 'event-move', 'jquery.event.move', array( 'jquery' ), '2.0.1' );
198
 
14
  *
15
  * @var string
16
  */
17
+ const VERSION = '1.0.1';
18
 
19
  /**
20
  * Prefix used for stylesheet handles.
192
 
193
  $this->register_script( 'sweetalert', 'sweetalert2', array( 'promise-polyfill' ), '4.6.6' )->localize( 'imagifySwal' );
194
 
195
+ $this->register_script( 'chart', 'chart', array(), '2.7.1' );
196
 
197
  $this->register_script( 'event-move', 'jquery.event.move', array( 'jquery' ), '2.0.1' );
198
 
inc/classes/class-imagify-attachment.php CHANGED
File without changes
inc/classes/class-imagify-db.php CHANGED
File without changes
inc/classes/class-imagify-user.php CHANGED
@@ -142,7 +142,7 @@ class Imagify_User {
142
  }
143
 
144
  /**
145
- * Count percent of consumed quota.
146
  *
147
  * @since 1.0
148
  *
@@ -150,23 +150,21 @@ class Imagify_User {
150
  * @return int
151
  */
152
  public function get_percent_consumed_quota() {
153
- $percent = 0;
154
  $quota = $this->quota;
155
  $consumed_quota = $this->consumed_current_month_quota;
156
 
157
- if ( ( $this->quota + $this->extra_quota ) - ( $this->consumed_current_month_quota + $this->extra_quota_consumed ) <= 0 ) {
158
- return 100;
 
159
  }
160
 
161
- if ( imagify_round_half_five( $this->extra_quota_consumed ) < $this->extra_quota ) {
162
- $quota = $this->extra_quota + $quota;
163
- $consumed_quota = $consumed_quota + $this->extra_quota_consumed;
164
  }
165
 
166
- $percent = 100 - ( ( $quota - $consumed_quota ) / $quota ) * 100;
167
- $percent = min( round( $percent, 1 ), 100 );
168
 
169
- return $percent;
170
  }
171
 
172
  /**
142
  }
143
 
144
  /**
145
+ * Percentage of consumed quota, including extra quota.
146
  *
147
  * @since 1.0
148
  *
150
  * @return int
151
  */
152
  public function get_percent_consumed_quota() {
 
153
  $quota = $this->quota;
154
  $consumed_quota = $this->consumed_current_month_quota;
155
 
156
+ if ( imagify_round_half_five( $this->extra_quota_consumed ) < $this->extra_quota ) {
157
+ $quota += $this->extra_quota;
158
+ $consumed_quota += $this->extra_quota_consumed;
159
  }
160
 
161
+ if ( ! $quota || ! $consumed_quota ) {
162
+ return 0;
 
163
  }
164
 
165
+ $percent = 100 * $consumed_quota / $quota;
 
166
 
167
+ return min( round( $percent, 1 ), 100 );
168
  }
169
 
170
  /**
inc/classes/class-imagify.php CHANGED
@@ -11,7 +11,7 @@ class Imagify extends Imagify_Deprecated {
11
  *
12
  * @var string
13
  */
14
- const VERSION = '1.0.6';
15
  /**
16
  * The Imagify API endpoint.
17
  *
@@ -51,8 +51,6 @@ class Imagify extends Imagify_Deprecated {
51
 
52
  /**
53
  * The constructor.
54
- *
55
- * @return void
56
  */
57
  protected function __construct() {
58
  // Check if the WordPress plugin is activated and the API key is stored in the options.
@@ -74,9 +72,9 @@ class Imagify extends Imagify_Deprecated {
74
  /**
75
  * Get the main Instance.
76
  *
77
- * @access public
78
- * @since 1.6.5
79
- * @author Grégory Viguier
80
  *
81
  * @return object Main instance.
82
  */
@@ -91,8 +89,8 @@ class Imagify extends Imagify_Deprecated {
91
  /**
92
  * Get your Imagify account infos.
93
  *
94
- * @access public
95
- * @since 1.6.5
96
  *
97
  * @return object
98
  */
@@ -113,29 +111,42 @@ class Imagify extends Imagify_Deprecated {
113
  /**
114
  * Create a user on your Imagify account.
115
  *
116
- * @access public
117
- * @since 1.6.5
118
  *
119
- * @param array $data All user data. Details here: --.
120
  * @return object
121
  */
122
  public function create_user( $data ) {
123
- $this->headers = array();
124
- $data['from_plugin'] = true;
 
 
 
125
 
126
- return $this->http_call( 'users/', array(
 
 
 
 
127
  'method' => 'POST',
128
  'post_data' => $data,
129
  ) );
 
 
 
 
 
 
130
  }
131
 
132
  /**
133
  * Update an existing user on your Imagify account.
134
  *
135
- * @access public
136
- * @since 1.6.5
137
  *
138
- * @param string $data All user data. Details here: --.
139
  * @return object
140
  */
141
  public function update_user( $data ) {
@@ -151,8 +162,8 @@ class Imagify extends Imagify_Deprecated {
151
  /**
152
  * Check your Imagify API key status.
153
  *
154
- * @access public
155
- * @since 1.6.5
156
  *
157
  * @param string $data The license key.
158
  * @return object
@@ -160,24 +171,33 @@ class Imagify extends Imagify_Deprecated {
160
  public function get_status( $data ) {
161
  static $status = array();
162
 
163
- if ( ! isset( $status[ $data ] ) ) {
164
- $this->headers = array(
165
- 'Authorization' => 'Authorization: token ' . $data,
166
- );
167
 
168
- $status[ $data ] = $this->http_call( 'status/', array(
169
- 'timeout' => 10,
170
- ) );
 
 
 
 
 
 
171
  }
172
 
 
 
 
 
173
  return $status[ $data ];
174
  }
175
 
176
  /**
177
  * Get the Imagify API version.
178
  *
179
- * @access public
180
- * @since 1.6.5
181
  *
182
  * @return object
183
  */
@@ -200,8 +220,8 @@ class Imagify extends Imagify_Deprecated {
200
  /**
201
  * Get Public Info.
202
  *
203
- * @access public
204
- * @since 1.6.5
205
  *
206
  * @return object
207
  */
@@ -215,8 +235,8 @@ class Imagify extends Imagify_Deprecated {
215
  * Optimize an image from its binary content.
216
  *
217
  * @access public
218
- * @since 1.6.5
219
- * @since 1.6.7 $data['image'] can contain the file path (prefered) or the result of `curl_file_create()`.
220
  *
221
  * @param string $data All options.
222
  * @return object
@@ -235,8 +255,8 @@ class Imagify extends Imagify_Deprecated {
235
  /**
236
  * Optimize an image from its URL.
237
  *
238
- * @access public
239
- * @since 1.6.5
240
  *
241
  * @param string $data All options. Details here: --.
242
  * @return object
@@ -253,8 +273,8 @@ class Imagify extends Imagify_Deprecated {
253
  /**
254
  * Get prices for plans.
255
  *
256
- * @access public
257
- * @since 1.6.5
258
  *
259
  * @return object
260
  */
@@ -267,8 +287,8 @@ class Imagify extends Imagify_Deprecated {
267
  /**
268
  * Get prices for packs (one time).
269
  *
270
- * @access public
271
- * @since 1.6.5
272
  *
273
  * @return object
274
  */
@@ -281,8 +301,8 @@ class Imagify extends Imagify_Deprecated {
281
  /**
282
  * Get all prices (packs & plans included).
283
  *
284
- * @access public
285
- * @since 1.6.5
286
  *
287
  * @return object
288
  */
@@ -295,8 +315,8 @@ class Imagify extends Imagify_Deprecated {
295
  /**
296
  * Get all prices (packs & plans included).
297
  *
298
- * @access public
299
- * @since 1.6.5
300
  *
301
  * @param string $coupon A coupon code.
302
  * @return object
@@ -310,8 +330,8 @@ class Imagify extends Imagify_Deprecated {
310
  /**
311
  * Get information about current discount.
312
  *
313
- * @access public
314
- * @since 1.6.5
315
  *
316
  * @return object
317
  */
11
  *
12
  * @var string
13
  */
14
+ const VERSION = '1.1';
15
  /**
16
  * The Imagify API endpoint.
17
  *
51
 
52
  /**
53
  * The constructor.
 
 
54
  */
55
  protected function __construct() {
56
  // Check if the WordPress plugin is activated and the API key is stored in the options.
72
  /**
73
  * Get the main Instance.
74
  *
75
+ * @access public
76
+ * @since 1.6.5
77
+ * @author Grégory Viguier
78
  *
79
  * @return object Main instance.
80
  */
89
  /**
90
  * Get your Imagify account infos.
91
  *
92
+ * @access public
93
+ * @since 1.6.5
94
  *
95
  * @return object
96
  */
111
  /**
112
  * Create a user on your Imagify account.
113
  *
114
+ * @access public
115
+ * @since 1.6.5
116
  *
117
+ * @param array $data All user data.
118
  * @return object
119
  */
120
  public function create_user( $data ) {
121
+ $this->headers = array();
122
+ $data = array_merge( $data, array(
123
+ 'from_plugin' => true,
124
+ 'partner' => imagify_get_partner(),
125
+ ) );
126
 
127
+ if ( ! $data['partner'] ) {
128
+ unset( $data['partner'] );
129
+ }
130
+
131
+ $response = $this->http_call( 'users/', array(
132
  'method' => 'POST',
133
  'post_data' => $data,
134
  ) );
135
+
136
+ if ( ! is_wp_error( $response ) ) {
137
+ imagify_delete_partner();
138
+ }
139
+
140
+ return $response;
141
  }
142
 
143
  /**
144
  * Update an existing user on your Imagify account.
145
  *
146
+ * @access public
147
+ * @since 1.6.5
148
  *
149
+ * @param string $data All user data.
150
  * @return object
151
  */
152
  public function update_user( $data ) {
162
  /**
163
  * Check your Imagify API key status.
164
  *
165
+ * @access public
166
+ * @since 1.6.5
167
  *
168
  * @param string $data The license key.
169
  * @return object
171
  public function get_status( $data ) {
172
  static $status = array();
173
 
174
+ if ( isset( $status[ $data ] ) ) {
175
+ return $status[ $data ];
176
+ }
 
177
 
178
+ $this->headers = array(
179
+ 'Authorization' => 'Authorization: token ' . $data,
180
+ );
181
+
182
+ $uri = 'status/';
183
+ $partner = imagify_get_partner();
184
+
185
+ if ( $partner ) {
186
+ $uri .= '?partner=' . $partner;
187
  }
188
 
189
+ $status[ $data ] = $this->http_call( $uri, array(
190
+ 'timeout' => 10,
191
+ ) );
192
+
193
  return $status[ $data ];
194
  }
195
 
196
  /**
197
  * Get the Imagify API version.
198
  *
199
+ * @access public
200
+ * @since 1.6.5
201
  *
202
  * @return object
203
  */
220
  /**
221
  * Get Public Info.
222
  *
223
+ * @access public
224
+ * @since 1.6.5
225
  *
226
  * @return object
227
  */
235
  * Optimize an image from its binary content.
236
  *
237
  * @access public
238
+ * @since 1.6.5
239
+ * @since 1.6.7 $data['image'] can contain the file path (prefered) or the result of `curl_file_create()`.
240
  *
241
  * @param string $data All options.
242
  * @return object
255
  /**
256
  * Optimize an image from its URL.
257
  *
258
+ * @access public
259
+ * @since 1.6.5
260
  *
261
  * @param string $data All options. Details here: --.
262
  * @return object
273
  /**
274
  * Get prices for plans.
275
  *
276
+ * @access public
277
+ * @since 1.6.5
278
  *
279
  * @return object
280
  */
287
  /**
288
  * Get prices for packs (one time).
289
  *
290
+ * @access public
291
+ * @since 1.6.5
292
  *
293
  * @return object
294
  */
301
  /**
302
  * Get all prices (packs & plans included).
303
  *
304
+ * @access public
305
+ * @since 1.6.5
306
  *
307
  * @return object
308
  */
315
  /**
316
  * Get all prices (packs & plans included).
317
  *
318
+ * @access public
319
+ * @since 1.6.5
320
  *
321
  * @param string $coupon A coupon code.
322
  * @return object
330
  /**
331
  * Get information about current discount.
332
  *
333
+ * @access public
334
+ * @since 1.6.5
335
  *
336
  * @return object
337
  */
inc/common/partners.php ADDED
@@ -0,0 +1,33 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ defined( 'ABSPATH' ) || die( 'Cheatin\' uh?' );
3
+
4
+ add_action( 'update_option_' . IMAGIFY_SETTINGS_SLUG, 'imagify_maybe_delete_partner_on_option_update', 10, 2 );
5
+ /**
6
+ * After the first API key has been successfully added, make sure the partner ID is deleted.
7
+ *
8
+ * @since 1.6.14
9
+ * @author Grégory Viguier
10
+ *
11
+ * @param mixed $old_value The old option value.
12
+ * @param mixed $new_value The new option value.
13
+ */
14
+ function imagify_maybe_delete_partner_on_option_update( $old_value, $new_value ) {
15
+ if ( empty( $old_value['api_key'] ) && ! empty( $new_value['api_key'] ) ) {
16
+ imagify_delete_partner();
17
+ }
18
+ }
19
+
20
+ add_action( 'update_site_option_' . IMAGIFY_SETTINGS_SLUG, 'imagify_maybe_delete_partner_on_network_option_update', 10, 3 );
21
+ /**
22
+ * After the first API key has been successfully added to the network option, make sure the partner ID is deleted.
23
+ *
24
+ * @since 1.6.14
25
+ * @author Grégory Viguier
26
+ *
27
+ * @param string $option Name of the network option.
28
+ * @param mixed $new_value The new network option value.
29
+ * @param mixed $old_value The old network option value.
30
+ */
31
+ function imagify_maybe_delete_partner_on_network_option_update( $option, $new_value, $old_value ) {
32
+ imagify_maybe_delete_partner_on_option_update( $old_value, $new_value );
33
+ }
inc/functions/admin-stats.php CHANGED
@@ -45,12 +45,7 @@ function imagify_count_attachments() {
45
  AND $wpdb->posts.post_status = 'inherit'"
46
  );
47
 
48
- /**
49
- * Filter the limit from which the library is considered large.
50
- *
51
- * @param int $limit Number of attachments.
52
- */
53
- if ( $count > apply_filters( 'imagify_unoptimized_attachment_limit', 10000 ) ) {
54
  set_transient( 'imagify_large_library', 1 );
55
  } elseif ( get_transient( 'imagify_large_library' ) ) {
56
  // In case the number is decreasing under our limit.
@@ -220,7 +215,11 @@ function imagify_percent_optimized_attachments() {
220
  $total_attachments = imagify_count_attachments();
221
  $total_optimized_attachments = imagify_count_optimized_attachments();
222
 
223
- return $total_attachments && $total_optimized_attachments ? round( 100 - ( ( $total_attachments - $total_optimized_attachments ) / $total_attachments ) * 100 ) : 0;
 
 
 
 
224
  }
225
 
226
  /**
45
  AND $wpdb->posts.post_status = 'inherit'"
46
  );
47
 
48
+ if ( $count > imagify_get_unoptimized_attachment_limit() ) {
 
 
 
 
 
49
  set_transient( 'imagify_large_library', 1 );
50
  } elseif ( get_transient( 'imagify_large_library' ) ) {
51
  // In case the number is decreasing under our limit.
215
  $total_attachments = imagify_count_attachments();
216
  $total_optimized_attachments = imagify_count_optimized_attachments();
217
 
218
+ if ( ! $total_attachments || ! $total_optimized_attachments ) {
219
+ return 0;
220
+ }
221
+
222
+ return min( round( 100 * $total_optimized_attachments / $total_attachments ), 100 );
223
  }
224
 
225
  /**
inc/functions/admin-ui.php CHANGED
@@ -104,8 +104,8 @@ function get_imagify_attachment_optimization_text( $attachment, $context = 'wp'
104
  'context' => $context,
105
  );
106
  $class = $is_media_page ? '' : ' class="button-imagify-restore attachment-has-backup"';
107
- $waiting = $is_media_page ? '' : ' data-waiting-label="' . esc_attr__( 'Optimizing...', 'imagify' ) . '"';
108
- $output .= '<a id="imagify-restore-' . $attachment_id . '" href="' . get_imagify_admin_url( 'restore-upload', $args ) . '"' . $class . $waiting . '>';
109
  $output .= '<span class="dashicons dashicons-image-rotate"></span>' . __( 'Restore Original', 'imagify' );
110
  $output .= '</a>';
111
 
104
  'context' => $context,
105
  );
106
  $class = $is_media_page ? '' : ' class="button-imagify-restore attachment-has-backup"';
107
+ $waiting = $is_media_page ? '' : ' data-waiting-label="' . esc_attr__( 'Restoring...', 'imagify' ) . '"';
108
+ $output .= '<a id="imagify-restore-' . $attachment_id . '" href="' . esc_url( get_imagify_admin_url( 'restore-upload', $args ) ) . '"' . $class . $waiting . '>';
109
  $output .= '<span class="dashicons dashicons-image-rotate"></span>' . __( 'Restore Original', 'imagify' );
110
  $output .= '</a>';
111
 
inc/functions/admin.php CHANGED
@@ -201,27 +201,21 @@ function get_imagify_bulk_buffer_size() {
201
  function imagify_get_wp_rocket_url( $path = false, $query = array() ) {
202
  $wprocket_url = 'https://wp-rocket.me/';
203
 
204
- // Locale.
205
- $locale = function_exists( 'get_user_locale' ) ? get_user_locale() : get_locale();
206
- $suffixes = array(
207
- 'fr_FR' => 'fr',
208
- 'es_ES' => 'es',
209
- 'it_IT' => 'it',
210
- 'de_DE' => 'de',
211
- );
212
 
213
- if ( isset( $suffixes[ $locale ] ) ) {
214
- $wprocket_url .= $suffixes[ $locale ] . '/';
215
  }
216
 
217
  // URI.
218
  $paths = array(
219
  'pricing' => array(
220
- 'default' => 'pricing',
221
- 'fr_FR' => 'offres',
222
- 'es_ES' => 'precios',
223
- 'it_IT' => 'offerte',
224
- 'de_DE' => 'preise',
225
  ),
226
  );
227
 
@@ -229,11 +223,7 @@ function imagify_get_wp_rocket_url( $path = false, $query = array() ) {
229
  $path = trim( $path, '/' );
230
 
231
  if ( isset( $paths[ $path ] ) ) {
232
- if ( isset( $paths[ $path ][ $locale ] ) ) {
233
- $wprocket_url .= $paths[ $path ][ $locale ] . '/';
234
- } else {
235
- $wprocket_url .= $paths[ $path ]['default'] . '/';
236
- }
237
  } else {
238
  $wprocket_url .= $path . '/';
239
  }
201
  function imagify_get_wp_rocket_url( $path = false, $query = array() ) {
202
  $wprocket_url = 'https://wp-rocket.me/';
203
 
204
+ // Current lang.
205
+ $lang = imagify_get_current_lang_in( array( 'de', 'es', 'fr', 'it' ) );
 
 
 
 
 
 
206
 
207
+ if ( 'en' !== $lang ) {
208
+ $wprocket_url .= $lang . '/';
209
  }
210
 
211
  // URI.
212
  $paths = array(
213
  'pricing' => array(
214
+ 'de' => 'preise',
215
+ 'en' => 'pricing',
216
+ 'es' => 'precios',
217
+ 'fr' => 'offres',
218
+ 'it' => 'offerte',
219
  ),
220
  );
221
 
223
  $path = trim( $path, '/' );
224
 
225
  if ( isset( $paths[ $path ] ) ) {
226
+ $wprocket_url .= $paths[ $path ][ $lang ] . '/';
 
 
 
 
227
  } else {
228
  $wprocket_url .= $path . '/';
229
  }
inc/functions/api.php CHANGED
@@ -272,6 +272,7 @@ function imagify_translate_api_message( $message ) {
272
  'Confirm your account to continue optimizing image' => __( 'Confirm your account to continue optimizing images.', 'imagify' ),
273
  'Coupon doesn\'t exist' => __( 'Coupon does not exist.', 'imagify' ),
274
  'Email field shouldn\'t be empty' => __( 'Email field should not be empty.', 'imagify' ),
 
275
  'Error uploading to data Storage' => __( 'Error uploading to Data Storage.', 'imagify' ),
276
  'Not able to connect to Data Storage API to get the token' => __( 'Unable to connect to Data Storage API to get the token.', 'imagify' ),
277
  'Not able to connect to Data Storage API' => __( 'Unable to connect to Data Storage API.', 'imagify' ),
272
  'Confirm your account to continue optimizing image' => __( 'Confirm your account to continue optimizing images.', 'imagify' ),
273
  'Coupon doesn\'t exist' => __( 'Coupon does not exist.', 'imagify' ),
274
  'Email field shouldn\'t be empty' => __( 'Email field should not be empty.', 'imagify' ),
275
+ 'Email or Password field shouldn\'t be empty' => __( 'This account already exists.', 'imagify' ),
276
  'Error uploading to data Storage' => __( 'Error uploading to Data Storage.', 'imagify' ),
277
  'Not able to connect to Data Storage API to get the token' => __( 'Unable to connect to Data Storage API to get the token.', 'imagify' ),
278
  'Not able to connect to Data Storage API' => __( 'Unable to connect to Data Storage API.', 'imagify' ),
inc/functions/attachments.php CHANGED
@@ -337,3 +337,24 @@ function get_imagify_upload_baseurl() {
337
 
338
  return $upload_baseurl;
339
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
337
 
338
  return $upload_baseurl;
339
  }
340
+
341
+ /**
342
+ * Get the maximal number of unoptimized attachments to fetch.
343
+ *
344
+ * @since 1.6.14
345
+ * @author Grégory Viguier
346
+ *
347
+ * @return int
348
+ */
349
+ function imagify_get_unoptimized_attachment_limit() {
350
+ /**
351
+ * Filter the unoptimized attachments limit query.
352
+ *
353
+ * @since 1.4.4
354
+ *
355
+ * @param int $limit The limit (-1 for unlimited).
356
+ */
357
+ $limit = (int) apply_filters( 'imagify_unoptimized_attachment_limit', 10000 );
358
+
359
+ return -1 === $limit ? PHP_INT_MAX : abs( $limit );
360
+ }
inc/functions/common.php CHANGED
@@ -212,14 +212,13 @@ function imagify_get_external_url( $target, $query_args = array() ) {
212
  break;
213
 
214
  case 'contact':
215
- $locale = function_exists( 'get_user_locale' ) ? get_user_locale() : get_locale();
216
- $paths = array(
217
- 'default' => 'contact',
218
- 'fr_FR' => 'fr/contact',
219
  );
220
 
221
- $url = isset( $paths[ $locale ] ) ? $paths[ $locale ] : $paths['default'];
222
- $url = $site_url . $url . '/';
223
  break;
224
 
225
  case 'documentation':
@@ -227,17 +226,27 @@ function imagify_get_external_url( $target, $query_args = array() ) {
227
  break;
228
 
229
  case 'register':
230
- return $app_url . 'register';
 
 
 
 
 
 
 
231
 
232
  case 'subscription':
233
- return $app_url . 'subscription';
 
234
 
235
  case 'get-api-key':
236
- return $app_url . 'api';
 
237
 
238
  case 'payment':
239
  // Don't remove the trailing slash.
240
- return $app_url . 'plugin/';
 
241
 
242
  default:
243
  return '';
@@ -249,3 +258,50 @@ function imagify_get_external_url( $target, $query_args = array() ) {
249
 
250
  return $url;
251
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
212
  break;
213
 
214
  case 'contact':
215
+ $lang = imagify_get_current_lang_in( 'fr' );
216
+ $paths = array(
217
+ 'en' => 'contact',
218
+ 'fr' => 'fr/contact',
219
  );
220
 
221
+ $url = $site_url . $paths[ $lang ] . '/';
 
222
  break;
223
 
224
  case 'documentation':
226
  break;
227
 
228
  case 'register':
229
+ $partner = imagify_get_partner();
230
+
231
+ if ( $partner ) {
232
+ $query_args['partner'] = $partner;
233
+ }
234
+
235
+ $url = $app_url . 'register';
236
+ break;
237
 
238
  case 'subscription':
239
+ $url = $app_url . 'subscription';
240
+ break;
241
 
242
  case 'get-api-key':
243
+ $url = $app_url . 'api';
244
+ break;
245
 
246
  case 'payment':
247
  // Don't remove the trailing slash.
248
+ $url = $app_url . 'plugin/';
249
+ break;
250
 
251
  default:
252
  return '';
258
 
259
  return $url;
260
  }
261
+
262
+ /**
263
+ * Get the current lang ('fr', 'en', 'de'...), limited to a given list.
264
+ *
265
+ * @since 1.6.14
266
+ * @author Grégory Viguier
267
+ *
268
+ * @param array $langs An array of langs, like array( 'de', 'es', 'fr', 'it' ).
269
+ * @return string The current lang. Default is 'en'.
270
+ */
271
+ function imagify_get_current_lang_in( $langs ) {
272
+ static $locale;
273
+
274
+ if ( ! isset( $locale ) ) {
275
+ $locale = imagify_get_locale();
276
+ $locale = explode( '_', strtolower( $locale . '_' ) ); // Trailing underscore is to make sure $locale[1] is set.
277
+ }
278
+
279
+ foreach ( (array) $langs as $lang ) {
280
+ if ( $lang === $locale[0] || $lang === $locale[1] ) {
281
+ return $lang;
282
+ }
283
+ }
284
+
285
+ return 'en';
286
+ }
287
+
288
+ /**
289
+ * Get the current locale.
290
+ *
291
+ * @since 1.6.14
292
+ * @author Grégory Viguier
293
+ *
294
+ * @return string The current locale.
295
+ */
296
+ function imagify_get_locale() {
297
+ $locale = function_exists( 'get_user_locale' ) ? get_user_locale() : get_locale();
298
+ /**
299
+ * Filter the locale used by Imagify.
300
+ *
301
+ * @since 1.6.14
302
+ * @author Grégory Viguier
303
+ *
304
+ * @param string $locale The current locale.
305
+ */
306
+ return apply_filters( 'imagify_locale', $locale );
307
+ }
inc/functions/deprecated.php CHANGED
@@ -5,6 +5,7 @@ defined( 'ABSPATH' ) || die( 'Cheatin\' uh?' );
5
  * Deprecated imagify.io API for WordPress.
6
  *
7
  * @since 1.6.5
 
8
  */
9
  class Imagify_Deprecated {
10
 
@@ -12,7 +13,9 @@ class Imagify_Deprecated {
12
  * A shorthand to display a message about a deprecated method.
13
  *
14
  * @since 1.6.5
 
15
  * @author Grégory Viguier
 
16
  *
17
  * @param string $method_name The deprecated method.
18
  */
@@ -27,6 +30,9 @@ class Imagify_Deprecated {
27
  * Ensures only one instance of class is loaded or can be loaded.
28
  * Well, actually it ensures nothing since it's not a full singleton pattern.
29
  *
 
 
 
30
  * @return object Main instance.
31
  */
32
  public static function instance() {
@@ -37,6 +43,9 @@ class Imagify_Deprecated {
37
  /**
38
  * Get your Imagify account infos.
39
  *
 
 
 
40
  * @return object
41
  */
42
  public function getUser() {
@@ -47,7 +56,10 @@ class Imagify_Deprecated {
47
  /**
48
  * Create a user on your Imagify account.
49
  *
50
- * @param array $data All user data. Details here: --.
 
 
 
51
  * @return object
52
  */
53
  public function createUser( $data ) {
@@ -58,7 +70,10 @@ class Imagify_Deprecated {
58
  /**
59
  * Update an existing user on your Imagify account.
60
  *
61
- * @param string $data All user data. Details here: --.
 
 
 
62
  * @return object
63
  */
64
  public function updateUser( $data ) {
@@ -69,6 +84,9 @@ class Imagify_Deprecated {
69
  /**
70
  * Check your Imagify API key status.
71
  *
 
 
 
72
  * @param string $data The license key.
73
  * @return object
74
  */
@@ -80,6 +98,9 @@ class Imagify_Deprecated {
80
  /**
81
  * Get the Imagify API version.
82
  *
 
 
 
83
  * @return object
84
  */
85
  public function getApiVersion() {
@@ -90,6 +111,9 @@ class Imagify_Deprecated {
90
  /**
91
  * Get Public Info.
92
  *
 
 
 
93
  * @return object
94
  */
95
  public function getPublicInfo() {
@@ -100,7 +124,10 @@ class Imagify_Deprecated {
100
  /**
101
  * Optimize an image from its binary content.
102
  *
103
- * @param string $data All options. Details here: --.
 
 
 
104
  * @return object
105
  */
106
  public function uploadImage( $data ) {
@@ -111,7 +138,10 @@ class Imagify_Deprecated {
111
  /**
112
  * Optimize an image from its URL.
113
  *
114
- * @param string $data All options. Details here: --.
 
 
 
115
  * @return object
116
  */
117
  public function fetchImage( $data ) {
@@ -122,6 +152,9 @@ class Imagify_Deprecated {
122
  /**
123
  * Get prices for plans.
124
  *
 
 
 
125
  * @return object
126
  */
127
  public function getPlansPrices() {
@@ -132,6 +165,9 @@ class Imagify_Deprecated {
132
  /**
133
  * Get prices for packs (one time).
134
  *
 
 
 
135
  * @return object
136
  */
137
  public function getPacksPrices() {
@@ -142,6 +178,9 @@ class Imagify_Deprecated {
142
  /**
143
  * Get all prices (packs & plans included).
144
  *
 
 
 
145
  * @return object
146
  */
147
  public function getAllPrices() {
@@ -152,6 +191,9 @@ class Imagify_Deprecated {
152
  /**
153
  * Get all prices (packs & plans included).
154
  *
 
 
 
155
  * @param string $coupon A coupon code.
156
  * @return object
157
  */
@@ -163,6 +205,9 @@ class Imagify_Deprecated {
163
  /**
164
  * Get information about current discount.
165
  *
 
 
 
166
  * @return object
167
  */
168
  public function checkDiscount() {
@@ -173,6 +218,9 @@ class Imagify_Deprecated {
173
  /**
174
  * Make an HTTP call using curl.
175
  *
 
 
 
176
  * @param string $url The URL to call.
177
  * @param array $args The request args.
178
  * @return object
@@ -191,6 +239,7 @@ if ( class_exists( 'WpeCommon' ) ) :
191
  * @since 1.4.7
192
  * @since 1.6.7 Deprecated.
193
  * @author Jonathan Buttigieg
 
194
  *
195
  * @return int
196
  */
@@ -209,6 +258,7 @@ if ( function_exists( 'emr_delete_current_files' ) ) :
209
  * @since 1.0
210
  * @since 1.6.9 Deprecated.
211
  * @author Jonathan Buttigieg
 
212
  *
213
  * @param string $guid A post guid.
214
  */
@@ -246,6 +296,7 @@ endif;
246
  *
247
  * @since 1.2
248
  * @since 1.6.10 Deprecated.
 
249
  */
250
  function _imagify_admin_bar_styles() {
251
  _deprecated_function( __FUNCTION__ . '()', '1.6.10', 'Imagify_Assets::get_instance()->enqueue_styles_and_scripts_frontend()' );
@@ -262,6 +313,7 @@ function _imagify_admin_bar_styles() {
262
  * @since 1.6.8
263
  * @since 1.6.10 Deprecated. Don't laugh.
264
  * @author Grégory Viguier
 
265
  *
266
  * @param string $file_path An absolute path.
267
  * @return string A relative path. Can return the absolute path in case of a failure.
@@ -280,6 +332,7 @@ if ( is_admin() && ( function_exists( 'as3cf_init' ) || function_exists( 'as3cf_
280
  * @since 1.6.6
281
  * @since 1.6.12 Deprecated.
282
  * @author Grégory Viguier
 
283
  *
284
  * @return object The Imagify_AS3CF instance.
285
  */
@@ -299,6 +352,7 @@ if ( function_exists( 'enable_media_replace' ) ) :
299
  * @since 1.6.9
300
  * @since 1.6.12 Deprecated.
301
  * @author Grégory Viguier
 
302
  *
303
  * @return object The Imagify_Enable_Media_Replace instance.
304
  */
@@ -318,6 +372,7 @@ if ( class_exists( 'C_NextGEN_Bootstrap' ) && class_exists( 'Mixin' ) && get_sit
318
  * @since 1.6.5
319
  * @since 1.6.12 Deprecated.
320
  * @author Grégory Viguier
 
321
  *
322
  * @return object The Imagify_NGG instance.
323
  */
@@ -333,6 +388,7 @@ if ( class_exists( 'C_NextGEN_Bootstrap' ) && class_exists( 'Mixin' ) && get_sit
333
  * @since 1.6.5
334
  * @since 1.6.12 Deprecated.
335
  * @author Jonathan Buttigieg
 
336
  *
337
  * @return object The Imagify_NGG_DB instance.
338
  */
@@ -348,6 +404,7 @@ if ( class_exists( 'C_NextGEN_Bootstrap' ) && class_exists( 'Mixin' ) && get_sit
348
  * @since 1.5
349
  * @since 1.6.13 Deprecated.
350
  * @author Jonathan Buttigieg
 
351
  *
352
  * @param int $image_id An image ID.
353
  */
@@ -364,6 +421,7 @@ if ( class_exists( 'C_NextGEN_Bootstrap' ) && class_exists( 'Mixin' ) && get_sit
364
  * @since 1.4.5
365
  * @since 1.6.7 Added the $keep_keys_order parameter.
366
  * @since 1.6.13 Deprecated.
 
367
  *
368
  * @param array $keys An array of keys.
369
  * @param array $values An array of arrays like array( 'id' => id, 'value' => value ).
@@ -383,6 +441,7 @@ if ( class_exists( 'C_NextGEN_Bootstrap' ) && class_exists( 'Mixin' ) && get_sit
383
  * @since 1.6.7
384
  * @since 1.6.13 Deprecated.
385
  * @author Grégory Viguier
 
386
  *
387
  * @param array $metas An array of meta names like:
388
  * array(
@@ -414,6 +473,7 @@ if ( is_admin() ) :
414
  *
415
  * @since 1.0
416
  * @since 1.6.10 Deprecated.
 
417
  */
418
  function _imagify_admin_print_styles() {
419
  _deprecated_function( __FUNCTION__ . '()', '1.6.10', 'Imagify_Assets::get_instance()->enqueue_styles_and_scripts()' );
@@ -426,6 +486,7 @@ if ( is_admin() ) :
426
  *
427
  * @since 1.0
428
  * @since 1.6.10 Deprecated.
 
429
  */
430
  function _imagify_admin_print_intercom() {
431
  _deprecated_function( __FUNCTION__ . '()', '1.6.10', 'Imagify_Assets::get_instance()->print_support_script()' );
@@ -439,6 +500,7 @@ if ( is_admin() ) :
439
  * @since 1.5
440
  * @since 1.6.10 Deprecated.
441
  * @author Jonathan Buttigieg
 
442
  */
443
  function _imagify_ngg_admin_print_intercom() {
444
  _deprecated_function( __FUNCTION__ . '()', '1.6.10', 'Imagify_Assets::get_instance()->print_support_script()' );
@@ -456,6 +518,7 @@ if ( is_admin() ) :
456
  * @since 1.6.10
457
  * @author Grégory Viguier
458
  * @see Imagify_Notices::notices()
 
459
  *
460
  * @param string $function The function to deprecate.
461
  * @param string $notice_id The notice to deprecate.
@@ -478,6 +541,7 @@ if ( is_admin() ) :
478
  * @since 1.0
479
  * @since 1.6.10 Deprecated.
480
  * @author Jonathan Buttigieg
 
481
  */
482
  function _imagify_warning_empty_api_key_notice() {
483
  _imagify_deprecate_old_notice( __FUNCTION__, 'welcome-steps' );
@@ -489,6 +553,7 @@ if ( is_admin() ) :
489
  * @since 1.0
490
  * @since 1.6.10 Deprecated.
491
  * @author Jonathan Buttigieg
 
492
  */
493
  function _imagify_warning_wrong_api_key_notice() {
494
  _imagify_deprecate_old_notice( __FUNCTION__, 'wrong-api-key' );
@@ -500,6 +565,7 @@ if ( is_admin() ) :
500
  * @since 1.0
501
  * @since 1.6.10 Deprecated.
502
  * @author Jonathan Buttigieg
 
503
  */
504
  function _imagify_warning_plugins_to_deactivate_notice() {
505
  _imagify_deprecate_old_notice( __FUNCTION__, 'plugins-to-deactivate' );
@@ -511,6 +577,7 @@ if ( is_admin() ) :
511
  * @since 1.0
512
  * @since 1.6.10 Deprecated.
513
  * @author Jonathan Buttigieg
 
514
  */
515
  function _imagify_http_block_external_notice() {
516
  _imagify_deprecate_old_notice( __FUNCTION__, 'http-block-external' );
@@ -522,6 +589,7 @@ if ( is_admin() ) :
522
  * @since 1.0.2
523
  * @since 1.6.10 Deprecated.
524
  * @author Jonathan Buttigieg
 
525
  */
526
  function _imagify_warning_grid_view_notice() {
527
  _imagify_deprecate_old_notice( __FUNCTION__, 'grid-view' );
@@ -533,6 +601,7 @@ if ( is_admin() ) :
533
  * @since 1.1.1
534
  * @since 1.6.10 Deprecated.
535
  * @author Jonathan Buttigieg
 
536
  */
537
  function _imagify_warning_over_quota_notice() {
538
  _imagify_deprecate_old_notice( __FUNCTION__, 'over-quota' );
@@ -544,6 +613,7 @@ if ( is_admin() ) :
544
  * @since 1.6.8
545
  * @since 1.6.10 Deprecated.
546
  * @author Grégory Viguier
 
547
  */
548
  function _imagify_warning_backup_folder_not_writable_notice() {
549
  _imagify_deprecate_old_notice( __FUNCTION__, 'backup-folder-not-writable' );
@@ -554,6 +624,7 @@ if ( is_admin() ) :
554
  *
555
  * @since 1.6.10 Deprecated.
556
  * @author Jonathan Buttigieg
 
557
  */
558
  function _imagify_rocket_notice() {
559
  _imagify_deprecate_old_notice( __FUNCTION__, 'rocket' );
@@ -565,6 +636,7 @@ if ( is_admin() ) :
565
  * @since 1.4.2
566
  * @since 1.6.10 Deprecated.
567
  * @author Jonathan Buttigieg
 
568
  */
569
  function _imagify_rating_notice() {
570
  _imagify_deprecate_old_notice( __FUNCTION__, 'rating' );
@@ -574,6 +646,7 @@ if ( is_admin() ) :
574
  * Stop the rating cron when the notice is dismissed.
575
  *
576
  * @since 1.6.10 Deprecated.
 
577
  *
578
  * @param string $notice The notice name.
579
  */
@@ -589,6 +662,7 @@ if ( is_admin() ) :
589
  * @since 1.0
590
  * @since 1.6.10 Deprecated.
591
  * @author Jonathan Buttigieg
 
592
  */
593
  function _do_admin_post_imagify_dismiss_notice() {
594
  _deprecated_function( __FUNCTION__ . '()', '1.6.10', 'Imagify_Notices::get_instance()->admin_post_dismiss_notice()' );
@@ -602,6 +676,7 @@ if ( is_admin() ) :
602
  * @since 1.2
603
  * @since 1.6.10 Deprecated.
604
  * @author Jonathan Buttigieg
 
605
  */
606
  function _imagify_deactivate_plugin() {
607
  _deprecated_function( __FUNCTION__ . '()', '1.6.10', 'Imagify_Notices::get_instance()->deactivate_plugin()' );
@@ -614,6 +689,7 @@ if ( is_admin() ) :
614
  *
615
  * @since 1.0
616
  * @since 1.6.10 Deprecated.
 
617
  *
618
  * @param string $notice A notice ID.
619
  * @param int $user_id A user ID.
@@ -630,6 +706,7 @@ if ( is_admin() ) :
630
  *
631
  * @since 1.0
632
  * @since 1.6.10 Deprecated.
 
633
  *
634
  * @param string $notice A notice ID.
635
  * @param int $user_id A user ID.
@@ -647,6 +724,7 @@ if ( is_admin() ) :
647
  * @since 1.6.5
648
  * @since 1.6.10 Deprecated.
649
  * @author Grégory Viguier
 
650
  *
651
  * @param string $notice A notice ID.
652
  * @param int $user_id A user ID.
5
  * Deprecated imagify.io API for WordPress.
6
  *
7
  * @since 1.6.5
8
+ * @deprecated
9
  */
10
  class Imagify_Deprecated {
11
 
13
  * A shorthand to display a message about a deprecated method.
14
  *
15
  * @since 1.6.5
16
+ * @since 1.6.5 Deprecated
17
  * @author Grégory Viguier
18
+ * @deprecated
19
  *
20
  * @param string $method_name The deprecated method.
21
  */
30
  * Ensures only one instance of class is loaded or can be loaded.
31
  * Well, actually it ensures nothing since it's not a full singleton pattern.
32
  *
33
+ * @since 1.6.5 Deprecated
34
+ * @deprecated
35
+ *
36
  * @return object Main instance.
37
  */
38
  public static function instance() {
43
  /**
44
  * Get your Imagify account infos.
45
  *
46
+ * @since 1.6.5 Deprecated
47
+ * @deprecated
48
+ *
49
  * @return object
50
  */
51
  public function getUser() {
56
  /**
57
  * Create a user on your Imagify account.
58
  *
59
+ * @since 1.6.5 Deprecated
60
+ * @deprecated
61
+ *
62
+ * @param array $data All user data.
63
  * @return object
64
  */
65
  public function createUser( $data ) {
70
  /**
71
  * Update an existing user on your Imagify account.
72
  *
73
+ * @since 1.6.5 Deprecated
74
+ * @deprecated
75
+ *
76
+ * @param string $data All user data.
77
  * @return object
78
  */
79
  public function updateUser( $data ) {
84
  /**
85
  * Check your Imagify API key status.
86
  *
87
+ * @since 1.6.5 Deprecated
88
+ * @deprecated
89
+ *
90
  * @param string $data The license key.
91
  * @return object
92
  */
98
  /**
99
  * Get the Imagify API version.
100
  *
101
+ * @since 1.6.5 Deprecated
102
+ * @deprecated
103
+ *
104
  * @return object
105
  */
106
  public function getApiVersion() {
111
  /**
112
  * Get Public Info.
113
  *
114
+ * @since 1.6.5 Deprecated
115
+ * @deprecated
116
+ *
117
  * @return object
118
  */
119
  public function getPublicInfo() {
124
  /**
125
  * Optimize an image from its binary content.
126
  *
127
+ * @since 1.6.5 Deprecated
128
+ * @deprecated
129
+ *
130
+ * @param string $data All options.
131
  * @return object
132
  */
133
  public function uploadImage( $data ) {
138
  /**
139
  * Optimize an image from its URL.
140
  *
141
+ * @since 1.6.5 Deprecated
142
+ * @deprecated
143
+ *
144
+ * @param string $data All options.
145
  * @return object
146
  */
147
  public function fetchImage( $data ) {
152
  /**
153
  * Get prices for plans.
154
  *
155
+ * @since 1.6.5 Deprecated
156
+ * @deprecated
157
+ *
158
  * @return object
159
  */
160
  public function getPlansPrices() {
165
  /**
166
  * Get prices for packs (one time).
167
  *
168
+ * @since 1.6.5 Deprecated
169
+ * @deprecated
170
+ *
171
  * @return object
172
  */
173
  public function getPacksPrices() {
178
  /**
179
  * Get all prices (packs & plans included).
180
  *
181
+ * @since 1.6.5 Deprecated
182
+ * @deprecated
183
+ *
184
  * @return object
185
  */
186
  public function getAllPrices() {
191
  /**
192
  * Get all prices (packs & plans included).
193
  *
194
+ * @since 1.6.5 Deprecated
195
+ * @deprecated
196
+ *
197
  * @param string $coupon A coupon code.
198
  * @return object
199
  */
205
  /**
206
  * Get information about current discount.
207
  *
208
+ * @since 1.6.5 Deprecated
209
+ * @deprecated
210
+ *
211
  * @return object
212
  */
213
  public function checkDiscount() {
218
  /**
219
  * Make an HTTP call using curl.
220
  *
221
+ * @since 1.6.5 Deprecated
222
+ * @deprecated
223
+ *
224
  * @param string $url The URL to call.
225
  * @param array $args The request args.
226
  * @return object
239
  * @since 1.4.7
240
  * @since 1.6.7 Deprecated.
241
  * @author Jonathan Buttigieg
242
+ * @deprecated
243
  *
244
  * @return int
245
  */
258
  * @since 1.0
259
  * @since 1.6.9 Deprecated.
260
  * @author Jonathan Buttigieg
261
+ * @deprecated
262
  *
263
  * @param string $guid A post guid.
264
  */
296
  *
297
  * @since 1.2
298
  * @since 1.6.10 Deprecated.
299
+ * @deprecated
300
  */
301
  function _imagify_admin_bar_styles() {
302
  _deprecated_function( __FUNCTION__ . '()', '1.6.10', 'Imagify_Assets::get_instance()->enqueue_styles_and_scripts_frontend()' );
313
  * @since 1.6.8
314
  * @since 1.6.10 Deprecated. Don't laugh.
315
  * @author Grégory Viguier
316
+ * @deprecated
317
  *
318
  * @param string $file_path An absolute path.
319
  * @return string A relative path. Can return the absolute path in case of a failure.
332
  * @since 1.6.6
333
  * @since 1.6.12 Deprecated.
334
  * @author Grégory Viguier
335
+ * @deprecated
336
  *
337
  * @return object The Imagify_AS3CF instance.
338
  */
352
  * @since 1.6.9
353
  * @since 1.6.12 Deprecated.
354
  * @author Grégory Viguier
355
+ * @deprecated
356
  *
357
  * @return object The Imagify_Enable_Media_Replace instance.
358
  */
372
  * @since 1.6.5
373
  * @since 1.6.12 Deprecated.
374
  * @author Grégory Viguier
375
+ * @deprecated
376
  *
377
  * @return object The Imagify_NGG instance.
378
  */
388
  * @since 1.6.5
389
  * @since 1.6.12 Deprecated.
390
  * @author Jonathan Buttigieg
391
+ * @deprecated
392
  *
393
  * @return object The Imagify_NGG_DB instance.
394
  */
404
  * @since 1.5
405
  * @since 1.6.13 Deprecated.
406
  * @author Jonathan Buttigieg
407
+ * @deprecated
408
  *
409
  * @param int $image_id An image ID.
410
  */
421
  * @since 1.4.5
422
  * @since 1.6.7 Added the $keep_keys_order parameter.
423
  * @since 1.6.13 Deprecated.
424
+ * @deprecated
425
  *
426
  * @param array $keys An array of keys.
427
  * @param array $values An array of arrays like array( 'id' => id, 'value' => value ).
441
  * @since 1.6.7
442
  * @since 1.6.13 Deprecated.
443
  * @author Grégory Viguier
444
+ * @deprecated
445
  *
446
  * @param array $metas An array of meta names like:
447
  * array(
473
  *
474
  * @since 1.0
475
  * @since 1.6.10 Deprecated.
476
+ * @deprecated
477
  */
478
  function _imagify_admin_print_styles() {
479
  _deprecated_function( __FUNCTION__ . '()', '1.6.10', 'Imagify_Assets::get_instance()->enqueue_styles_and_scripts()' );
486
  *
487
  * @since 1.0
488
  * @since 1.6.10 Deprecated.
489
+ * @deprecated
490
  */
491
  function _imagify_admin_print_intercom() {
492
  _deprecated_function( __FUNCTION__ . '()', '1.6.10', 'Imagify_Assets::get_instance()->print_support_script()' );
500
  * @since 1.5
501
  * @since 1.6.10 Deprecated.
502
  * @author Jonathan Buttigieg
503
+ * @deprecated
504
  */
505
  function _imagify_ngg_admin_print_intercom() {
506
  _deprecated_function( __FUNCTION__ . '()', '1.6.10', 'Imagify_Assets::get_instance()->print_support_script()' );
518
  * @since 1.6.10
519
  * @author Grégory Viguier
520
  * @see Imagify_Notices::notices()
521
+ * @deprecated
522
  *
523
  * @param string $function The function to deprecate.
524
  * @param string $notice_id The notice to deprecate.
541
  * @since 1.0
542
  * @since 1.6.10 Deprecated.
543
  * @author Jonathan Buttigieg
544
+ * @deprecated
545
  */
546
  function _imagify_warning_empty_api_key_notice() {
547
  _imagify_deprecate_old_notice( __FUNCTION__, 'welcome-steps' );
553
  * @since 1.0
554
  * @since 1.6.10 Deprecated.
555
  * @author Jonathan Buttigieg
556
+ * @deprecated
557
  */
558
  function _imagify_warning_wrong_api_key_notice() {
559
  _imagify_deprecate_old_notice( __FUNCTION__, 'wrong-api-key' );
565
  * @since 1.0
566
  * @since 1.6.10 Deprecated.
567
  * @author Jonathan Buttigieg
568
+ * @deprecated
569
  */
570
  function _imagify_warning_plugins_to_deactivate_notice() {
571
  _imagify_deprecate_old_notice( __FUNCTION__, 'plugins-to-deactivate' );
577
  * @since 1.0
578
  * @since 1.6.10 Deprecated.
579
  * @author Jonathan Buttigieg
580
+ * @deprecated
581
  */
582
  function _imagify_http_block_external_notice() {
583
  _imagify_deprecate_old_notice( __FUNCTION__, 'http-block-external' );
589
  * @since 1.0.2
590
  * @since 1.6.10 Deprecated.
591
  * @author Jonathan Buttigieg
592
+ * @deprecated
593
  */
594
  function _imagify_warning_grid_view_notice() {
595
  _imagify_deprecate_old_notice( __FUNCTION__, 'grid-view' );
601
  * @since 1.1.1
602
  * @since 1.6.10 Deprecated.
603
  * @author Jonathan Buttigieg
604
+ * @deprecated
605
  */
606
  function _imagify_warning_over_quota_notice() {
607
  _imagify_deprecate_old_notice( __FUNCTION__, 'over-quota' );
613
  * @since 1.6.8
614
  * @since 1.6.10 Deprecated.
615
  * @author Grégory Viguier
616
+ * @deprecated
617
  */
618
  function _imagify_warning_backup_folder_not_writable_notice() {
619
  _imagify_deprecate_old_notice( __FUNCTION__, 'backup-folder-not-writable' );
624
  *
625
  * @since 1.6.10 Deprecated.
626
  * @author Jonathan Buttigieg
627
+ * @deprecated
628
  */
629
  function _imagify_rocket_notice() {
630
  _imagify_deprecate_old_notice( __FUNCTION__, 'rocket' );
636
  * @since 1.4.2
637
  * @since 1.6.10 Deprecated.
638
  * @author Jonathan Buttigieg
639
+ * @deprecated
640
  */
641
  function _imagify_rating_notice() {
642
  _imagify_deprecate_old_notice( __FUNCTION__, 'rating' );
646
  * Stop the rating cron when the notice is dismissed.
647
  *
648
  * @since 1.6.10 Deprecated.
649
+ * @deprecated
650
  *
651
  * @param string $notice The notice name.
652
  */
662
  * @since 1.0
663
  * @since 1.6.10 Deprecated.
664
  * @author Jonathan Buttigieg
665
+ * @deprecated
666
  */
667
  function _do_admin_post_imagify_dismiss_notice() {
668
  _deprecated_function( __FUNCTION__ . '()', '1.6.10', 'Imagify_Notices::get_instance()->admin_post_dismiss_notice()' );
676
  * @since 1.2
677
  * @since 1.6.10 Deprecated.
678
  * @author Jonathan Buttigieg
679
+ * @deprecated
680
  */
681
  function _imagify_deactivate_plugin() {
682
  _deprecated_function( __FUNCTION__ . '()', '1.6.10', 'Imagify_Notices::get_instance()->deactivate_plugin()' );
689
  *
690
  * @since 1.0
691
  * @since 1.6.10 Deprecated.
692
+ * @deprecated
693
  *
694
  * @param string $notice A notice ID.
695
  * @param int $user_id A user ID.
706
  *
707
  * @since 1.0
708
  * @since 1.6.10 Deprecated.
709
+ * @deprecated
710
  *
711
  * @param string $notice A notice ID.
712
  * @param int $user_id A user ID.
724
  * @since 1.6.5
725
  * @since 1.6.10 Deprecated.
726
  * @author Grégory Viguier
727
+ * @deprecated
728
  *
729
  * @param string $notice A notice ID.
730
  * @param int $user_id A user ID.
inc/functions/partners.php ADDED
@@ -0,0 +1,38 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ defined( 'ABSPATH' ) || die( 'Cheatin\' uh?' );
3
+
4
+ /**
5
+ * Get the partner ID stored in the database.
6
+ *
7
+ * @since 1.6.14
8
+ * @author Grégory Viguier
9
+ *
10
+ * @return string|bool The partner ID. False otherwise.
11
+ */
12
+ function imagify_get_partner() {
13
+ if ( class_exists( 'Imagify_Partner' ) ) {
14
+ return Imagify_Partner::get_stored_partner();
15
+ }
16
+
17
+ $partner = get_option( 'imagifyp_id' );
18
+
19
+ if ( $partner && is_string( $partner ) ) {
20
+ $partner = preg_replace( '@[^a-z0-9_-]@', '', strtolower( $partner ) );
21
+ }
22
+
23
+ return $partner ? $partner : false;
24
+ }
25
+
26
+ /**
27
+ * Delete the partner ID stored in the database.
28
+ *
29
+ * @since 1.6.14
30
+ * @author Grégory Viguier
31
+ */
32
+ function imagify_delete_partner() {
33
+ if ( class_exists( 'Imagify_Partner' ) ) {
34
+ Imagify_Partner::delete_stored_partner();
35
+ } elseif ( false !== get_option( 'imagifyp_id' ) ) {
36
+ delete_option( 'imagifyp_id' );
37
+ }
38
+ }
readme.txt CHANGED
@@ -3,7 +3,7 @@ Contributors: wp_media, GregLone
3
  Tags: compress image, images, performance, optimization, photos, upload, resize, gif, png, jpg, reduce image size, retina
4
  Requires at least: 3.7.0
5
  Tested up to: 4.9.1
6
- Stable tag: 1.6.13.1
7
 
8
  Dramatically reduce image file sizes without losing quality, make your website load faster, boost your SEO and save money on your bandwidth.
9
 
@@ -136,6 +136,13 @@ When the plugin is disabled, your existing images remain optimized. Backups of t
136
  3. Media Page
137
 
138
  == Changelog ==
 
 
 
 
 
 
 
139
  = 1.6.13.1 - 2017/11/08 =
140
  * Bug Fix: fixed a php error with php 5.2.
141
 
@@ -144,7 +151,7 @@ When the plugin is disabled, your existing images remain optimized. Backups of t
144
  * Improvement: better compatibility with NextGen Gallery plugin. Imagify no longer resizes NextGen images nor removes exif, to let NextGen Gallery do its job peacefully.
145
  * Improvement: better compatibility with WP Real Media Library plugin, our modal wasn't working correctly.
146
  * Improvement: better compatibility with plugins that use cookies, like Duo Two-Factor Authentication and Shield Security, to prevent being disconnected.
147
- * Improvement: better compatibility with SireGround. A "security" measure was preventing Imagify to work correctly.
148
  * Improvement: better compatibility with hosts that limit some SQL queries, it prevented our bulk optimization to work.
149
  * Improvement: better compatibility with Heartbeat Control plugin, it prevented our bulk optimization to work.
150
  * Improvement: better compatibility with Formidable Forms Pro plugin, the bulk optimizer was never satisfied.
3
  Tags: compress image, images, performance, optimization, photos, upload, resize, gif, png, jpg, reduce image size, retina
4
  Requires at least: 3.7.0
5
  Tested up to: 4.9.1
6
+ Stable tag: 1.6.14
7
 
8
  Dramatically reduce image file sizes without losing quality, make your website load faster, boost your SEO and save money on your bandwidth.
9
 
136
  3. Media Page
137
 
138
  == Changelog ==
139
+ = 1.6.14 - 2018/01/10 =
140
+ * New: added compatibility with partners' plugins.
141
+ * Improvement: updated the script used for the charts, it will lower the risk of conflicts with other plugins (that are also up-to-date).
142
+ * Improvement: the comparison tool button is now also inserted when clicking the next/previous buttons in the media modal.
143
+ * Bug Fix: the comparison tool button should not be inserted several times anymore.
144
+ * Bug Fix: the images wouldn't appear in the comparison tool sometimes.
145
+
146
  = 1.6.13.1 - 2017/11/08 =
147
  * Bug Fix: fixed a php error with php 5.2.
148
 
151
  * Improvement: better compatibility with NextGen Gallery plugin. Imagify no longer resizes NextGen images nor removes exif, to let NextGen Gallery do its job peacefully.
152
  * Improvement: better compatibility with WP Real Media Library plugin, our modal wasn't working correctly.
153
  * Improvement: better compatibility with plugins that use cookies, like Duo Two-Factor Authentication and Shield Security, to prevent being disconnected.
154
+ * Improvement: better compatibility with SiteGround. A "security" measure was preventing Imagify to work correctly.
155
  * Improvement: better compatibility with hosts that limit some SQL queries, it prevented our bulk optimization to work.
156
  * Improvement: better compatibility with Heartbeat Control plugin, it prevented our bulk optimization to work.
157
  * Improvement: better compatibility with Formidable Forms Pro plugin, the bulk optimizer was never satisfied.
uninstall.php CHANGED
@@ -8,13 +8,9 @@ delete_site_option( 'imagify_settings' );
8
 
9
  // Delete all transients.
10
  delete_site_transient( 'imagify_check_licence_1' );
11
- delete_site_transient( 'imagify_bulk_optimization_level' );
12
- delete_site_transient( 'imagify_large_library' );
13
- delete_site_transient( 'imagify_max_image_size' );
14
-
15
- // Clear scheduled hooks.
16
- wp_clear_scheduled_hook( 'imagify_rating_event' );
17
- wp_clear_scheduled_hook( 'imagify_update_library_size_calculations_event' );
18
 
19
  // Delete transients.
20
  $transients = implode( '" OR option_name LIKE "', array(
@@ -24,8 +20,12 @@ $transients = implode( '" OR option_name LIKE "', array(
24
  ) );
25
  $wpdb->query( 'DELETE from ' . $wpdb->options . ' WHERE option_name LIKE "' . $transients . '"' ); // WPCS: unprepared SQL ok.
26
 
 
 
 
 
27
  // Delete all user meta related to Imagify.
28
  delete_metadata( 'user', '', '_imagify_ignore_notices', '', true );
29
 
30
  // Drop the tables.
31
- $wpdb->query( 'DROP TABLE IF EXISTS ' . $wpdb->ngg_imagify_data );
8
 
9
  // Delete all transients.
10
  delete_site_transient( 'imagify_check_licence_1' );
11
+ delete_transient( 'imagify_bulk_optimization_level' );
12
+ delete_transient( 'imagify_large_library' );
13
+ delete_transient( 'imagify_max_image_size' );
 
 
 
 
14
 
15
  // Delete transients.
16
  $transients = implode( '" OR option_name LIKE "', array(
20
  ) );
21
  $wpdb->query( 'DELETE from ' . $wpdb->options . ' WHERE option_name LIKE "' . $transients . '"' ); // WPCS: unprepared SQL ok.
22
 
23
+ // Clear scheduled hooks.
24
+ wp_clear_scheduled_hook( 'imagify_rating_event' );
25
+ wp_clear_scheduled_hook( 'imagify_update_library_size_calculations_event' );
26
+
27
  // Delete all user meta related to Imagify.
28
  delete_metadata( 'user', '', '_imagify_ignore_notices', '', true );
29
 
30
  // Drop the tables.
31
+ $wpdb->query( 'DROP TABLE IF EXISTS ' . $wpdb->prefix . 'ngg_imagify_data' );