Imagify Image Optimizer - Version 1.4.5

Version Description

  • Interface
    • Bulk Optimization: optimize all SQL queries and improve by 65% the process time \o/
  • Misc
    • Chart.js library updated
    • Media List JS notice removed
Download this release

Release Info

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

Code changes from version 1.4.4 to 1.4.5

assets/css/admin.css CHANGED
@@ -581,6 +581,13 @@ td .imagify-chart {
581
  }
582
  .imagify-rkt-notice .imagify-rkt-cta {
583
  width: 200px!important; /* !important because of a dirtugly WP Engine code */
 
 
 
 
 
 
 
584
  }
585
  .imagify-rkt-notice .button.button {
586
  position: relative;
@@ -2223,6 +2230,11 @@ td.imagify-cell-filename {
2223
  float: none;
2224
  margin: 0;
2225
  }
 
 
 
 
 
2226
  .imagify-c-level.go-left {
2227
  float: left;
2228
  }
581
  }
582
  .imagify-rkt-notice .imagify-rkt-cta {
583
  width: 200px!important; /* !important because of a dirtugly WP Engine code */
584
+ -webkit-box-flex: 1;
585
+ -webkit-flex-grow: 1;
586
+ -ms-flex-positive: 1;
587
+ flex-grow: 1;
588
+ -webkit-flex-basis: 200px;
589
+ -ms-flex-preferred-size: 200px;
590
+ flex-basis: 200px;
591
  }
592
  .imagify-rkt-notice .button.button {
593
  position: relative;
2230
  float: none;
2231
  margin: 0;
2232
  }
2233
+ .imagify-visual-comparison .imagify-chart-container canvas {
2234
+ width: 15px!important;
2235
+ height: 15px!important;
2236
+ margin-right: 5px;
2237
+ }
2238
  .imagify-c-level.go-left {
2239
  float: left;
2240
  }
assets/css/admin.min.css CHANGED
@@ -1 +1 @@
1
- body.imagify-modal-is-open{overflow:hidden}.imagify-plugins-error{overflow:hidden;padding-left:20px;list-style-type:disc}.imagify-plugins-error li{width:300px;line-height:30px}@media (max-width:570px){.imagify-plugins-error li{width:auto}}.imagify-notice-dismiss.notice-dismiss{text-decoration:none}.imagify-spinner{display:inline-block;width:20px;height:20px;margin-right:5px;vertical-align:middle;background:rgba(0,0,0,0) url("../images/spinner.gif") no-repeat scroll 0 0 / 20px 20px;opacity:0.7}.spinner.imagify-hidden{width:0;margin:4px 0 0 0}.misc-pub-section.misc-pub-imagify h4{font-size:14px;margin-top:5px;margin-bottom:0}.imagify-sweet-alert button{margin-top:17px !important;height:45px !important;letter-spacing:3px;text-transform:uppercase !important;border-radius:3px !important;background-color:#40b1d0 !important;box-shadow:0 3px 0 #338ea6 !important}.imagify-sweet-alert button.cancel{background:#777 !important;box-shadow:0 3px 0 #444 !important}.imagify-sweet-alert-signup .sa-confirm-button-container{width:40%}.imagify-sweet-alert-signup button{width:100%;padding:0 !important}.imagify-sweet-alert .sa-input-error:before,.imagify-sweet-alert .sa-input-error:after,.imagify-sweet-alert .la-ball-fall{top:25% !important}#wpwrap{transition:all .4s}.stop-scrolling #wpwrap{filter:blur(2px)}.stop-scrolling #wpwrap #wpadminbar{top:-32px}.imagify-primary{color:#40b1d0}.imagify-secondary{color:#8cc152}#imagify-check-api-container{font-weight:bold}#imagify-check-api-container .dashicons{font-size:25px}#imagify-check-api-container .dashicons-no:before{color:#f06e57;vertical-align:-1px}#imagify-check-api-container .dashicons-yes:before{color:#8BC34A;vertical-align:-1px}.imagify-valid{color:#8BC34A}.imagify-chart{width:33.33%;position:relative}#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 200ms ease-in-out;-moz-transition:background-color 200ms ease-in-out;-o-transition:background-color 200ms ease-in-out;transition:background-color 200ms ease-in-out}.imagify-doughnut-legend li span{display:block;position:absolute;left:0;top:0;width:25px;height:25px;border-radius:50%}.imagify-chart{float:left;margin-bottom:20px}td .imagify-chart{float:none;margin-bottom:0}.imagify-chart-container{position:relative;width:180px;float:left;margin-right:40px}td .imagify-chart-container{width:18px;height:18px;float:none;margin-right:10px}td .imagify-chart{top:4px}.imagify-chart-percent{position:absolute;left:0;right:0;top:50%;margin-top:-14px;text-align:center;font-size:55px;font-weight:bold;color:#46B1CE}.imagify-chart-percent span{font-size:20px;vertical-align:super}.media_page_imagify-bulk-optimization .notice,.settings_page_imagify .notice{margin-right:20px;margin-left:2px}.media_page_imagify-bulk-optimization .media-item{margin:0}.media_page_imagify-bulk-optimization .media-item .progress{float:none;width:100%;margin:0;background:#1F2331;box-shadow:0;border-radius:0}.media_page_imagify-bulk-optimization .media-item .percent{width:auto;padding:0 5px;line-height:1.85;font-size:12px}.media_page_imagify-bulk-optimization .media-item .progress,.media_page_imagify-bulk-optimization .media-item .percent{text-align:right}.media_page_imagify-bulk-optimization .media-item .progress .bar{width:1px;height:22px;margin-top:0;background:#46B1CE;border-radius:0;overflow:visible;-webkit-transition:width .5s;transition:width .5s}.imagify-settings a,.imagify-settings .button,.imagify-settings input,.imagify-welcome a,.imagify-welcome .button,.imagify-weolcome input{-webkit-transition:all .275s;transition:all .275s}.imagify-settings a{color:#40b1d0}.imagify-options-title{padding-bottom:.5em;border-bottom:3px solid #F2F2F2;font-size:13px;font-weight:500;text-transform:uppercase;letter-spacing:0.025em;color:#40b1d0}.imagify-settings,.imagify-settings p,.imagify-settings th{color:#5F758E}@media (max-width:782px){.imagify-settings .form-table th{padding-top:2em;padding-bottom:.5em}}.imagify-settings .form-table td{vertical-align:top}.imagify-settings .form-table th span{cursor:pointer}.imagify-middle th{padding-top:35px}.imagify-settings .button,.imagify-welcome .button,.imagify-notice .button,.imagify-button-primary.imagify-button-primary{height:auto;padding:8px 20px;border:0 none;font-size:14px;font-weight:600;box-shadow:0 3px 0 rgba(0,0,0,.15)}.imagify-notice .button-mini{padding:2px 10px;font-size:13px}.button-primary.button-mini{padding:2px 10px}.imagify-settings .button.button-mini-flat{padding:3px 6px 5px;font-size:12px;box-shadow:none!important;line-height:1.2}.imagify-settings .button.button-mini-flat:hover,.imagify-settings .button.button-mini-flat:focus{box-shadow:none!important}.imagify-title .button-ghost.button-ghost{padding:2px 9px;border:1px solid #40B1D0;font-size:12px;font-weight:normal;color:#40B1D0;background:transparent}.imagify-title .button-ghost.button-ghost:hover,.imagify-title .button-ghost.button-ghost:focus{border-color:transparent;color:#000;background:#40B1D0}.button .dashicons{margin-right:5px;vertical-align:middle}.imagify-settings .button-primary.button-primary,.imagify-welcome .button-primary.button-primary,.imagify-button-primary.imagify-button-primary{background:#40B1D0;color:#FFF;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-settings .button-primary:hover,.imagify-settings .button-primary:focus,.imagify-welcome .button-primary:hover,.imagify-welcome .button-primary:focus,.imagify-button-primary.imagify-button-primary:hover,.imagify-button-primary.imagify-button-primary:focus{background:rgb(51,142,166);box-shadow:0 3px 0 rgb(31,122,146)}.wp_attachment_image .imagify-button-primary,.media-frame-content .imagify-button-primary{float:left;padding:0 10px 1px;margin:0 5px 2px 0;font-size:13px;line-height:26px;box-shadow:0 3px 0 rgba(51,142,166,1)}.imagify-settings input[type="text"]{color:#4A4A4A;font-weight:600;box-shadow:none}.imagify-settings p.submit .button-primary{margin-left:240px}@media (max-width:850px){.imagify-settings p.submit .button-primary{margin-left:0px}.imagify-settings p.submit{text-align:center}}.imagify-title.imagify-title{position:relative;padding:30px 50px;font-size:23px;background:#2E3243;color:#FFF}.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-sub-header,.imagify-sub-title.imagify-sub-title,.imagify-settings div.submit{margin:0;padding:20px;background:#F2F5F7}.imagify-bulk-info{margin:1em 1em 1em 240px;transition:margin .3s}@media (max-width:850px){.imagify-bulk-info{margin:1em}}.imagify-bulk-info p{display:inline-block;text-align:left;width:400px;max-width:100%;font-weight:bold}@media (min-width:1500px){.imagify-settings div.submit{display:table;width:100%}.imagify-settings div.submit >*{display:table-cell;vertical-align:middle}.imagify-bulk-info{padding:0 25px;text-align:right}}.imagify-settings div.submit{margin-top:2em;padding:20px 0}.imagify-sub-header th{text-align:right}.imagify-sub-header .form-table{margin:0}.imagify-sub-header th,.imagify-sub-header td{padding-top:0;padding-bottom:0}[for="api_key"]{padding-top:5px}.imagify-notice .imagify-rate-us.imagify-rate-us{position:relative;bottom:0;right:0;text-align:left}.imagify-notice .imagify-rate-us .stars{margin:0}.imagify-rate-us.imagify-rate-us{position:absolute;bottom:50%;right:20px;text-align:right;margin-bottom:-2.4em;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:hover,.imagify-rate-us a:focus{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-rkt-notice.imagify-rkt-notice{position:relative;display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-box-align:center;-webkit-align-items:center;-ms-flex-align:center;-ms-grid-row-align:center;align-items:center;padding:10px 45px 10px 0;border:0 none;box-shadow:none;color:#FFF;background:#412355}.media_page_imagify-bulk-optimization .imagify-rkt-notice{margin-left:2px;margin-right:20px}@media (max-width:782px){.media_page_imagify-bulk-optimization .imagify-rkt-notice{margin-left:0;margin-right:12px}}.imagify-rkt-notice .imagify-cross{position:absolute;right:8px;top:50%;width:22px;height:22px;padding:0;margin-top:-11px;background:transparent;color:#FD7300;border-radius:50%;transition:all .275s}.imagify-rkt-notice .imagify-cross .dashicons{position:relative;top:2px;left:1px;transition:all .275s}.imagify-rkt-notice .imagify-cross:hover{background:#FFF}.imagify-rkt-notice .imagify-cross:hover .dashicons{color:#412355}.imagify-rkt-notice .imagify-rkt-cta,.imagify-rkt-notice .imagify-rkt-logo,.imagify-rkt-notice .imagify-rkt-coupon{-webkit-flex-shrink:0;-ms-flex-negative:0;flex-shrink:0}.imagify-rkt-notice .imagify-rkt-logo{width:150px!important;text-align:center;padding:0 25px 0 30px;line-height:0.8}.imagify-rkt-notice .imagify-rkt-msg{width:100%!important;padding:0 15px;font-size:14px;line-height:1.6}.imagify-rkt-notice .imagify-rkt-coupon{width:150px!important;padding:0 15px}.imagify-rkt-notice .imagify-rkt-coupon-code{padding:5px 10px;font-size:23px;font-weight:bold;border:1px dashed #F7A933;color:#F7A933}.imagify-rkt-notice .imagify-rkt-cta{width:200px!important}.imagify-rkt-notice .button.button{position:relative;top:-1px;height:auto;font-weight:600;font-size:14px;box-shadow:0 4px 0 #B27A27;border:0 none;padding:9px 18px 9px;background:#F7A933;text-shadow:1px 1px 1px rgba(0,0,0,.2)}@media (max-width:880px){.imagify-rkt-notice{-webkit-flex-wrap:wrap;-ms-flex-wrap:wrap;flex-wrap:wrap}.imagify-rkt-notice .imagify-rkt-msg,.imagify-rkt-notice .imagify-rkt-cta,.imagify-rkt-notice .imagify-rkt-logo{text-align:left;padding:5px 15px}.imagify-cross.imagify-cross{top:8px;margin-top:0}.imagify-rkt-notice .imagify-cross .dashicons{top:1px}}.imagify-settings-section{padding:10px 20px}[id="imagify-settings"],.imagify-welcome .imagify-settings-section{border:1px solid #D9D9D9;border-top:0 none;background:#FFF}.imagify-br{line-height:2}.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}label+.imagify-info,label+.imagify-options-line,.imagify-visual-label{display:inline-block;max-width:70%;margin-left:15px;margin-top:2px!important;-webkit-transition:opacity .3s;transition:opacity .3s}.imagify-visual-label{vertical-align:-5px}label[for="imagify_sizes_full"]+.imagify-info{vertical-align:middle}.imagify-settings.imagify-settings [type="checkbox"]:not(:checked)+label+.imagify-options-line,.imagify-settings.imagify-settings [type="checkbox"]:not(:checked)+label .imagify-visual-label{opacity:.5}.imagify-settings.imagify-settings [type="checkbox"]:checked+label+.imagify-options-line,.imagify-settings.imagify-settings [type="checkbox"]:checked+label .imagify-visual-label{opacity:1}.imagify-checkbox-marged{max-width:500px;margin-left:45px}.imagify-settings.imagify-settings [type="checkbox"]:not(:checked),.imagify-settings.imagify-settings [type="checkbox"]:checked{opacity:0.01}.imagify-settings.imagify-settings [type="checkbox"]:not(:checked):focus,.imagify-settings.imagify-settings [type="checkbox"]:checked:focus{box-shadow:none!important;outline:none!important;border:0 none!important}.imagify-settings [type="checkbox"]:not(:checked)+label,.imagify-settings [type="checkbox"]:checked+label{position:relative;padding-left:6px;cursor:pointer;vertical-align:top}.imagify-settings [type="checkbox"]:not(:checked)+label:before,.imagify-settings [type="checkbox"]: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-settings [type="checkbox"]:not(:checked)+label:after,.imagify-settings [type="checkbox"]:checked+label:after{content:"✓";position:absolute;font-size:1.4em;top:3px;left:-16px;-webkit-transition:all .2s;-moz-transition:all .2s;-ms-transition:all .2s;transition:all .2s}.imagify-settings [type="checkbox"][disabled]:not(:checked)+label:before,.imagify-settings [type="checkbox"][disabled]:checked+label:before{border-color:#ccc;background:#ddd}.imagify-settings [type="checkbox"]:not(:checked)+label:after{opacity:0;-webkit-transform:scale(0);-moz-transform:scale(0);-ms-transform:scale(0);transform:scale(0)}.imagify-settings [type="checkbox"]:checked+label:after{opacity:1;-webkit-transform:scale(1);-moz-transform:scale(1);-ms-transform:scale(1);transform:scale(1)}input[id^="imagify_sizes_"]:checked+label{font-weight:bold}.imagify-settings .mini[type="checkbox"]:not(:checked)+label:before,.imagify-settings .mini[type="checkbox"]:checked+label:before{width:15px;height:15px;border-width:1px;border-radius:2px;margin-top:0}.imagify-settings .mini[type="checkbox"]:not(:checked)+label:after,.imagify-settings .mini[type="checkbox"]:checked+label:after{content:"✓";font-size:.9em;left:-21px;top:1px}.imagify-settings [type="checkbox"]:not(:checked):focus+label:before,.imagify-settings [type="checkbox"]: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:after{content:"";display:table;clear:both}.imagify-inline-options input[type="radio"]:not(:checked),.imagify-inline-options input[type="radio"]:checked{position:absolute;left:5px;top:5px;display:none}.imagify-inline-options input[type="radio"]:not(:checked)+label,.imagify-inline-options input[type="radio"]:checked+label{position:relative;display:table-cell;padding:13px 10px;text-align:center;font-weight:600;font-size:16px;text-transform:uppercase;letter-spacing:0.1em;color:#FFF;background:#2E3243;border-left:1px solid rgba(255,255,255,0.2);box-shadow:0 -3px 0 rgba(0,0,0,0.1) inset,inset -1px 0 0 rgba(255,255,255,0.2);z-index:2;-webkit-transition:all .275s;transition:all .275s}.imagify-bulk-submit .imagify-inline-options input[type="radio"]:not(:checked)+label,.imagify-bulk-submit .imagify-inline-options input[type="radio"]:checked+label{margin-bottom:1.75em}.imagify-inline-options input[type="radio"]:not(:checked)+label:first-of-type,.imagify-inline-options input[type="radio"]:checked+label:first-of-type{border-radius:3px 0 0 3px}.imagify-inline-options input[type="radio"]:not(:checked)+label:last-of-type,.imagify-inline-options input[type="radio"]: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-btn-info{display:block;font-size:0.7em;letter-spacing:0;line-height:1;text-transform:none}#describe-resize-larger input{width:5em}.imagify-col{overflow:hidden}.imagify-sidebar{float:right;width:280px;margin-left:25px}.imagify-sidebar-section{border:1px solid #BBB;background:#FFF}.imagify-sidebar-section+.imagify-sidebar-section{margin-top:2em}@media (max-width:760px){.imagify-settings{display:flex;flex-direction:column}.imagify-sidebar{order:2;float:none;width:auto;margin-left:0;margin-top:25px}.wp-media-products{text-align:center}.wp-media-products li{display:inline-block;width:100%;max-width:276px}}.imagify-sidebar-title{display:block;padding:20px 15px;border-bottom:1px solid #BBB;font-size:14px;font-weight:bold;color:#23282d;background:#F2F5F7}.imagify-sidebar-title img{vertical-align:top;margin-right:5px}.imagify-sidebar .wp-media-products{margin-top:0;margin-bottom:-.5em}.imagify-sidebar .wp-media-products .links{display:block;padding:85px 25px 24px;text-align:center;background-color:#2E3243;background-size:contain;background-repeat:no-repeat;background-position:50% 0;text-decoration:none}.imagify-sidebar .wp-media-products .links p{margin:1.5em auto;color:#FFF}.imagify-sidebar .wp-media-products .wprocket-link{background-image:linear-gradient(to bottom,rgba(59,30,78,0),rgba(59,30,78,0) 130px,rgba(59,30,78,1) 210px),url("../images/sidebar-wp-rocket.jpg");background-color:#3B1E4E;background-repeat:repeat-x,no-repeat}.imagify-sidebar-content{padding:10px 20px}.imagify-mark-styled{display:inline-block;padding:1px 2px 1px 4px;line-height:1.3;font-weight:bold;background:#F7A933;transform-origine:50% 50%;transform:rotateZ(-2deg) rotateX(-10deg) skewX(-2deg) skewY(-3deg);text-shadow:1px 1px 0 rgba(0,0,0,0.2)}.imagify-mark-styled span{display:inline-block;transform:rotateZ(2deg) rotateX(10deg) skewX(2deg) skewY(3deg)}.imagify-discount-code{margin:0.35em 0 .5em;display:block;font-size:2em;letter-spacing:.05em;font-weight:bold;text-align:center;text-shadow:1px 1px 0 rgba(0,0,0,0.2)}.imagify-big-text{font-size:15px;font-weight:bold}.imagify-big-text strong{font-size:20px}a.btn-rocket{display:block;font-size:1.15em;padding:12px;background:#F7A933;box-shadow:0 3px 0 #D69626;border-radius:3px;color:#FFF;text-transform:uppercase;font-weight:bold;text-shadow:1px 1px 0 rgba(0,0,0,0.2);text-decoration:none}a.btn-rocket:hover,a.btn-rocket:focus{background:darkorange;box-shadow:0 3px 0 darkorange}.imagify-welcome{margin:30px 20px 0 0}.imagify-welcome .baseline{display:inline-block;margin:.2em 0 0 2em;font-size:17px}.imagify-welcome .imagify-logo{vertical-align:middle}.imagify-welcome-remove{position:absolute;top:50%;right:15px;margin-top:-8px;color:#FFF;text-decoration:none}.imagify-columns{overflow:hidden;padding:15px 0;counter-reset:cols}.imagify-columns [class^="col-"]{float:left;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.imagify-columns .col-1-3{width:33.333%;padding-left:28px}.imagify-columns .col-1-2{width:50%;padding:0 20px}.imagify-columns .col-informations{width:41.6%;padding-right:30px}.imagify-columns .col-statistics{width:25%}@media (max-width:830px){.imagify-columns [class^="col-"]{float:none;margin-bottom:1.5em}.imagify-columns .col-1-3,.imagify-columns .col-1-2{width:auto;padding:0 28px;clear:both;padding-top:1em}}.imagify-columns [class^="col-"] img{float:left;margin-right:18px}.imagify-col-content{overflow:hidden}.imagify-col-title{margin:0 0 15px 0;font-size:23px}.counter .imagify-col-title:before{counter-increment:cols;content:counter(cols) ". ";color:#40B1D0}.imagify-col-desc{color:#5F758E;margin-bottom:2em}.imagify-notice.imagify-notice{position:relative;display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;padding:0;margin:10px 20px 10px 2px;border:0 none;background:#2E3243;box-shadow:none;color:#FFF}@media (max-width:782px){.imagify-notice.imagify-notice,.imagify-welcome{margin-right:12px}}@media (max-width:450px){.imagify-notice.imagify-notice{-webkit-box-orient:vertical;-webkit-box-direction:normal;-webkit-flex-direction:column; -ms-flex-direction:column; flex-direction:column}}.wrap .imagify-notice{margin:5px 15px 2px;position:relative}.imagify-notice-logo{padding:18px 23px;background:#40B1D0}.updated .imagify-notice-logo{background:#8BC34A}.error .imagify-notice-logo{background:#D0021B}.imagify-notice-title{font-size:15px}.imagify-notice-content{padding:5px 23px}.imagify-notice-content.imagify-notice-content p{margin:0.65em 0}.imagify-notice a{color:#40B1D0}.imagify-notice a:hover,.imagify-notice a:focus{color:#FEE102}.imagify-notice code{background:rgba(0,0,0,0.4) none repeat scroll 0 0}.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}ul.imagify-datas-list.imagify-datas-list{margin:0 auto;color:#555;font-size:10px}.compat-field-imagify .label{vertical-align:top}.compat-field-imagify ul.imagify-datas-list{margin-top:7px;font-size:11px}ul.imagify-datas-list .big{font-size:12px;color:#40B1D0}.imagify-data-item{overflow:hidden}.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;-moz-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:bold}.media-sidebar .imagify-datas-list .imagify-data-item .data{width:auto;float:none}ul.imagify-datas-list .imagify-data-item strong{text-align:left;padding-left:5px}.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: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:bold;line-height:1.9;text-decoration:none}.imagify-datas-more-action a.is-open{background:#555}.imagify-datas-more-action a.is-open .dashicons{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:20px;line-height:20px}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}.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}.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}.column-imagify_optimized_file .imagify-datas-actions-links a{margin:0 .7em;padding-left:15px}.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-title >h1{padding:0}.imagify-title-right{display:table;float:right;margin-top:-10px}.imagify-title-right p{margin:0}.imagify-title-right a{font-weight:bold;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:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-box-orient:vertical;-webkit-box-direction:normal;-webkit-flex-direction:column;-ms-flex-direction:column;flex-direction:column}.imagify-title-right{-webkit-box-ordinal-group:3;-webkit-order:2;-ms-flex-order:2;order:2;margin-top:20px}}.imagify-account,.imagify-account-link{padding-right:15px}.imagify-sep-v{width:1px;background:rgba(255,255,255,.2)}.imagify-credit-left{position:relative;min-width:280px;padding-left:15px}.imagify-meteo-icon{display:inline-block;height:38px;vertical-align:middle;margin-right:10px}.imagify-user-plan{color:#40b1d0}@media (max-width:630px){.imagify-title-right{display:block;width:auto}.imagify-title-right >div{display:block;width:auto;margin-top:10px;max-width:100%}.imagify-credit-left{padding-left:0}}.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-"],#wp-admin-bar-imagify-profile [class^="imagify-bar-"]{position:relative;height:15px;width:100%;background:#60758D;color:#FFF;font-size:10px}.base-transparent{background:transparent}[class^="imagify-bar-"].right-outside-number{-webkit-box-sizing:border-box;box-sizing:border-box;padding-right:45px}.right-outside-number .imagify-barnb{display:block;margin-right:-45px;text-align:right;font-weight:bold;line-height:15px}.imagify-progress-value,#wp-admin-bar-imagify-profile .imagify-progress-value{position:absolute;top:0;right:0;left:0;bottom:0;text-align:center;line-height:13px;font-weight:bold}.imagify-progress,#wp-admin-bar-imagify-profile .imagify-progress{height:15px}.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}#wpadminbar #wp-admin-bar-imagify-profile *{line-height:1.5;white-space:initial}#wpadminbar #wp-admin-bar-imagify .ab-submenu{padding-bottom:0}#wpadminbar #wp-admin-bar-imagify-profile .ab-item{height:auto;padding:0 13px}#wpadminbar #wp-admin-bar-imagify-profile{min-width:200px;padding:15px 0 10px;margin-top:0.7em;background:#222}#wp-admin-bar-imagify .dashicons{font-family:"dashicons";font-size:18px;vertical-align:middle;margin:0 5px 0 0}#wp-admin-bar-imagify .button-text{display:inline-block;vertical-align:middle}#wp-admin-bar-imagify .imagify-abq-row{display:table;width:100%}#wp-admin-bar-imagify .imagify-abq-row+.imagify-abq-row{margin-top:.75em}#wp-admin-bar-imagify .imagify-abq-row >*{display:table-cell}#wp-admin-bar-imagify-profile .imagify-meteo-icon{padding-right:7px}#wp-admin-bar-imagify-profile .imagify-meteo-icon img{width:37px}#wp-admin-bar-imagify-profile .imagify-meteo-title{font-size:17px}#wp-admin-bar-imagify-profile .imagify-meteo-subs{color:#72889F}#wpadminbar #wp-admin-bar-imagify-profile strong{font-weight:bold}#wpadminbar #wp-admin-bar-imagify-profile .imagify-user-plan,#wpadminbar #wp-admin-bar-imagify-profile a{padding:0;color:#40B1D0}#wpadminbar #wp-admin-bar-imagify-profile .imagify-account-link{display:table}#wpadminbar #wp-admin-bar-imagify-profile .imagify-account-link >* {display:table-cell}#wpadminbar #wp-admin-bar-imagify-profile .imagify-space-left{max-width:210px;min-width:210px;width:210px}#wpadminbar #wp-admin-bar-imagify-profile .imagify-space-left p{font-size:12px}#wp-admin-bar-imagify-profile .imagify-error,#wp-admin-bar-imagify-profile .imagify-warning{padding:10px;margin:0 -13px -13px}#wp-admin-bar-imagify-profile .imagify-error p+p,#wp-admin-bar-imagify-profile .imagify-warning p+p{margin-top:.5em}#wp-admin-bar-imagify-profile .imagify-error p+p+p,#wp-admin-bar-imagify-profile .imagify-warning p+p+p{margin-top:1em}.btn-ghost,#wpadminbar #wp-admin-bar-imagify-profile .btn-ghost{display:inline-block;height:auto;padding:7px 10px;border:1px solid #FFF;text-align:center;background:transparent;color:#FFF;border-radius:3px;transition:all .275s}.btn-ghost:hover,.btn-ghost:focus,#wpadminbar #wp-admin-bar-imagify-profile .btn-ghost:hover,#wpadminbar #wp-admin-bar-imagify-profile .btn-ghost:focus{background:#FFF;color:#888}.txt-center{text-align:center}.imagify-list-dash li{position:relative;padding-left:24px}.imagify-list-dash li:before{content:"";position:absolute;left:0;top:9px;height:1px;width:12px;background:#5f758e}.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 p,.imagify-bulk .imagify-settings-section li,.imagify-bulk .imagify-settings-section h3{color:#4A4A4A}.imagify-bulk .imagify-settings-section h3{margin-bottom:2em}.imagify-bulk-submit{margin-top:4em}#imagify-bulk-action{float:left}#imagify-bulk-action+.imagify-tooltips{overflow:hidden;display:block}.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:bold;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-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 5px;font-size:13px;background:#40B1D0;box-shadow:0 3px 0 #338EA6}.imagify-space-tooltips .tooltip-content:after{top:-14px;left:50%;margin-left:-7px;border:0 none;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:bold;line-height:1.1;vertical-align:middle}.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:0.85em;margin-bottom:1.35em;overflow:hidden;border-bottom:1px solid rgba(0,0,0,0.05)}.imagify-bars p{font-weight:bold;font-size:12px;margin-bottom:0}.imagify-bars+.imagify-number-you-optimized{border-bottom:0;padding-top:0.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-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 tr,.imagify-bulk-table thead th{background:#2E3242}.imagify-bulk-table tfoot tr,.imagify-bulk-table tfoot th{background:#73818C}.imagify-bulk-table thead th{padding:14px 15px;text-align:left;color:#F2F5F7;font-weight:bold;font-size:14px}.imagify-bulk-table tfoot td{padding:14px 15px;color:#F9FAFA}.imagify-bulk-table tbody tr,.imagify-bulk-table tbody td{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:bold;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;transform:scale(1)} 50%{transform:scale(1.05);opacity:1} 100%{transform:scale(1);opacity:1}}.imagify-row-complete.done{-webkit-animation:congrate 500ms ease-in-out;animation:congrate 500ms 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{overflow:hidden}.imagify-ac-report-text p{line-height:1.3}.imagify-ac-rt-big{font-weight:bold;font-size:24px;letter-spacing:0.15em;word-spacing:0.15em;text-transform:uppercase}.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{text-overflow:clip;white-space:nowrap;overflow:hidden}.imagify-bulk-table td.imagify-cell-totaloriginal{padding-right:78px}.imagiuploaded,.imagifilename{display:inline-block;vertical-align:middle}.imagifilename{font-size:12px}.imagiuploaded{width:33px;height:33px;margin-right:5px;margin-left:-8px;overflow:hidden;background:url(../images/upload-image.png) 0 0 no-repeat;background-size:cover}.imagiuploaded img{max-widht:100%;height:auto}.imagistatus{color:#8CA6B3;text-transform:uppercase;font-weight:bold}.status-compressing{color:#46B1CE}.status-error{color:#CE0B24}.status-warning{color:#f5a623}.status-complete{color:#8CC152}.imagify-error{background:#D0021B;color:#FFF}.imagify-warning,#wpadminbar .imagify-warning *{background:#f5a623;color:#FFF;text-shadow:0 0 2px rgba(0,0,0,0.2)}.imagify-bulk-table .imagify-cell-thumbnails{text-align:center}.imagify-cell-percentage,.imagify-cell-savings{color:#46B1CE;font-weight:bold}.imagify-cell-optimized{font-weight:bold}.imagify-cell-totaloriginal{text-align:right}.dashicons.rotate{-webkit-animation:icon-rotate 2.6s infinite linear;animation:icon-rotate 2.6s infinite linear}.dashicons-admin-generic{transform-origin:48.75% 51.75%}.imagify-modal{display:flex;flex-direction:column;align-items: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;-moz-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;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:transparent;padding:5px;box-shadow:none;border-radius:0}.imagify-modal .h2{margin:.5em 0;color:#8ba6b4;font-weight:normal;font-size:24px;letter-spacing:0.075em;text-align:center}.imagify-modal .h3{color:#40b1d0;font-weight:normal;font-size:18px;letter-spacing:0.075em;text-align:center}.text-justify{text-align:justify}.imagify-modal .close-btn{display:none;visibility:hidden;position:absolute;right:20px;top:20px;font-size:1.2em;border:0;background:transparent none;border-radius:0;cursor:pointer}.imagify-modal .close-btn i{margin-left:-2px}.imagify-modal .close-btn:hover,.imagify-modal .close-btn:focus{color:#40b1d0}.js .imagify-modal .close-btn{display:block;visibility:visible}#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%}.wp_attachment_image #imagify-visual-comparison .close-btn,.imagify-visual-comparison .close-btn{top:0}.wp_attachment_image #imagify-visual-comparison .imagify-modal-content,.imagify-visual-comparison .imagify-modal-content{padding-top:40px}.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: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-c-level.go-left{float:left}.imagify-c-level.go-right{float:right}.imagify-c-level.go-right,.imagify-c-level.go-left{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:bold}.imagify-c-level-row .value .imagify-chart{top:1px}@-webkit-keyframes icon-rotate{from{-webkit-transform:rotate(0deg);transform:rotate(0deg)}to{-webkit-transform:rotate(360deg);transform:rotate(360deg)}}@keyframes icon-rotate{from{transform:rotate(0deg)}to{transform:rotate(360deg)}}.imagify-menu-bar-img{margin-top:1em}.imagify-modal .loader{position:absolute;top:50%;left:50%;margin:-32px 0 0 -32px;opacity:0;visibility:hidden;transition:opacity .4s}.imagify-modal .loading .loader{visibility:visible;opacity:1}.imagify-settings .imagify-visual-comparison-text{margin-top:1em;color:#40b1d0;font-weight:bold}
1
+ body.imagify-modal-is-open{overflow:hidden}.imagify-plugins-error{overflow:hidden;padding-left:20px;list-style-type:disc}.imagify-plugins-error li{width:300px;line-height:30px}@media (max-width:570px){.imagify-plugins-error li{width:auto}}.imagify-notice-dismiss.notice-dismiss{text-decoration:none}.imagify-spinner{display:inline-block;width:20px;height:20px;margin-right:5px;vertical-align:middle;background:rgba(0,0,0,0) url("../images/spinner.gif") no-repeat scroll 0 0 / 20px 20px;opacity:0.7}.spinner.imagify-hidden{width:0;margin:4px 0 0 0}.misc-pub-section.misc-pub-imagify h4{font-size:14px;margin-top:5px;margin-bottom:0}.imagify-sweet-alert button{margin-top:17px !important;height:45px !important;letter-spacing:3px;text-transform:uppercase !important;border-radius:3px !important;background-color:#40b1d0 !important;box-shadow:0 3px 0 #338ea6 !important}.imagify-sweet-alert button.cancel{background:#777 !important;box-shadow:0 3px 0 #444 !important}.imagify-sweet-alert-signup .sa-confirm-button-container{width:40%}.imagify-sweet-alert-signup button{width:100%;padding:0 !important}.imagify-sweet-alert .sa-input-error:before,.imagify-sweet-alert .sa-input-error:after,.imagify-sweet-alert .la-ball-fall{top:25% !important}#wpwrap{transition:all .4s}.stop-scrolling #wpwrap{filter:blur(2px)}.stop-scrolling #wpwrap #wpadminbar{top:-32px}.imagify-primary{color:#40b1d0}.imagify-secondary{color:#8cc152}#imagify-check-api-container{font-weight:bold}#imagify-check-api-container .dashicons{font-size:25px}#imagify-check-api-container .dashicons-no:before{color:#f06e57;vertical-align:-1px}#imagify-check-api-container .dashicons-yes:before{color:#8BC34A;vertical-align:-1px}.imagify-valid{color:#8BC34A}.imagify-chart{width:33.33%;position:relative}#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 200ms ease-in-out;-moz-transition:background-color 200ms ease-in-out;-o-transition:background-color 200ms ease-in-out;transition:background-color 200ms ease-in-out}.imagify-doughnut-legend li span{display:block;position:absolute;left:0;top:0;width:25px;height:25px;border-radius:50%}.imagify-chart{float:left;margin-bottom:20px}td .imagify-chart{float:none;margin-bottom:0}.imagify-chart-container{position:relative;width:180px;float:left;margin-right:40px}td .imagify-chart-container{width:18px;height:18px;float:none;margin-right:10px}td .imagify-chart{top:4px}.imagify-chart-percent{position:absolute;left:0;right:0;top:50%;margin-top:-14px;text-align:center;font-size:55px;font-weight:bold;color:#46B1CE}.imagify-chart-percent span{font-size:20px;vertical-align:super}.media_page_imagify-bulk-optimization .notice,.settings_page_imagify .notice{margin-right:20px;margin-left:2px}.media_page_imagify-bulk-optimization .media-item{margin:0}.media_page_imagify-bulk-optimization .media-item .progress{float:none;width:100%;margin:0;background:#1F2331;box-shadow:0;border-radius:0}.media_page_imagify-bulk-optimization .media-item .percent{width:auto;padding:0 5px;line-height:1.85;font-size:12px}.media_page_imagify-bulk-optimization .media-item .progress,.media_page_imagify-bulk-optimization .media-item .percent{text-align:right}.media_page_imagify-bulk-optimization .media-item .progress .bar{width:1px;height:22px;margin-top:0;background:#46B1CE;border-radius:0;overflow:visible;-webkit-transition:width .5s;transition:width .5s}.imagify-settings a,.imagify-settings .button,.imagify-settings input,.imagify-welcome a,.imagify-welcome .button,.imagify-weolcome input{-webkit-transition:all .275s;transition:all .275s}.imagify-settings a{color:#40b1d0}.imagify-options-title{padding-bottom:.5em;border-bottom:3px solid #F2F2F2;font-size:13px;font-weight:500;text-transform:uppercase;letter-spacing:0.025em;color:#40b1d0}.imagify-settings,.imagify-settings p,.imagify-settings th{color:#5F758E}@media (max-width:782px){.imagify-settings .form-table th{padding-top:2em;padding-bottom:.5em}}.imagify-settings .form-table td{vertical-align:top}.imagify-settings .form-table th span{cursor:pointer}.imagify-middle th{padding-top:35px}.imagify-settings .button,.imagify-welcome .button,.imagify-notice .button,.imagify-button-primary.imagify-button-primary{height:auto;padding:8px 20px;border:0 none;font-size:14px;font-weight:600;box-shadow:0 3px 0 rgba(0,0,0,.15)}.imagify-notice .button-mini{padding:2px 10px;font-size:13px}.button-primary.button-mini{padding:2px 10px}.imagify-settings .button.button-mini-flat{padding:3px 6px 5px;font-size:12px;box-shadow:none!important;line-height:1.2}.imagify-settings .button.button-mini-flat:hover,.imagify-settings .button.button-mini-flat:focus{box-shadow:none!important}.imagify-title .button-ghost.button-ghost{padding:2px 9px;border:1px solid #40B1D0;font-size:12px;font-weight:normal;color:#40B1D0;background:transparent}.imagify-title .button-ghost.button-ghost:hover,.imagify-title .button-ghost.button-ghost:focus{border-color:transparent;color:#000;background:#40B1D0}.button .dashicons{margin-right:5px;vertical-align:middle}.imagify-settings .button-primary.button-primary,.imagify-welcome .button-primary.button-primary,.imagify-button-primary.imagify-button-primary{background:#40B1D0;color:#FFF;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-settings .button-primary:hover,.imagify-settings .button-primary:focus,.imagify-welcome .button-primary:hover,.imagify-welcome .button-primary:focus,.imagify-button-primary.imagify-button-primary:hover,.imagify-button-primary.imagify-button-primary:focus{background:rgb(51,142,166);box-shadow:0 3px 0 rgb(31,122,146)}.wp_attachment_image .imagify-button-primary,.media-frame-content .imagify-button-primary{float:left;padding:0 10px 1px;margin:0 5px 2px 0;font-size:13px;line-height:26px;box-shadow:0 3px 0 rgba(51,142,166,1)}.imagify-settings input[type="text"]{color:#4A4A4A;font-weight:600;box-shadow:none}.imagify-settings p.submit .button-primary{margin-left:240px}@media (max-width:850px){.imagify-settings p.submit .button-primary{margin-left:0px}.imagify-settings p.submit{text-align:center}}.imagify-title.imagify-title{position:relative;padding:30px 50px;font-size:23px;background:#2E3243;color:#FFF}.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-sub-header,.imagify-sub-title.imagify-sub-title,.imagify-settings div.submit{margin:0;padding:20px;background:#F2F5F7}.imagify-bulk-info{margin:1em 1em 1em 240px;transition:margin .3s}@media (max-width:850px){.imagify-bulk-info{margin:1em}}.imagify-bulk-info p{display:inline-block;text-align:left;width:400px;max-width:100%;font-weight:bold}@media (min-width:1500px){.imagify-settings div.submit{display:table;width:100%}.imagify-settings div.submit >*{display:table-cell;vertical-align:middle}.imagify-bulk-info{padding:0 25px;text-align:right}}.imagify-settings div.submit{margin-top:2em;padding:20px 0}.imagify-sub-header th{text-align:right}.imagify-sub-header .form-table{margin:0}.imagify-sub-header th,.imagify-sub-header td{padding-top:0;padding-bottom:0}[for="api_key"]{padding-top:5px}.imagify-notice .imagify-rate-us.imagify-rate-us{position:relative;bottom:0;right:0;text-align:left}.imagify-notice .imagify-rate-us .stars{margin:0}.imagify-rate-us.imagify-rate-us{position:absolute;bottom:50%;right:20px;text-align:right;margin-bottom:-2.4em;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:hover,.imagify-rate-us a:focus{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-rkt-notice.imagify-rkt-notice{position:relative;display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-box-align:center;-webkit-align-items:center;-ms-flex-align:center;-ms-grid-row-align:center;align-items:center;padding:10px 45px 10px 0;border:0 none;box-shadow:none;color:#FFF;background:#412355}.media_page_imagify-bulk-optimization .imagify-rkt-notice{margin-left:2px;margin-right:20px}@media (max-width:782px){.media_page_imagify-bulk-optimization .imagify-rkt-notice{margin-left:0;margin-right:12px}}.imagify-rkt-notice .imagify-cross{position:absolute;right:8px;top:50%;width:22px;height:22px;padding:0;margin-top:-11px;background:transparent;color:#FD7300;border-radius:50%;transition:all .275s}.imagify-rkt-notice .imagify-cross .dashicons{position:relative;top:2px;left:1px;transition:all .275s}.imagify-rkt-notice .imagify-cross:hover{background:#FFF}.imagify-rkt-notice .imagify-cross:hover .dashicons{color:#412355}.imagify-rkt-notice .imagify-rkt-cta,.imagify-rkt-notice .imagify-rkt-logo,.imagify-rkt-notice .imagify-rkt-coupon{-webkit-flex-shrink:0;-ms-flex-negative:0;flex-shrink:0}.imagify-rkt-notice .imagify-rkt-logo{width:150px!important;text-align:center;padding:0 25px 0 30px;line-height:0.8}.imagify-rkt-notice .imagify-rkt-msg{width:100%!important;padding:0 15px;font-size:14px;line-height:1.6}.imagify-rkt-notice .imagify-rkt-coupon{width:150px!important;padding:0 15px}.imagify-rkt-notice .imagify-rkt-coupon-code{padding:5px 10px;font-size:23px;font-weight:bold;border:1px dashed #F7A933;color:#F7A933}.imagify-rkt-notice .imagify-rkt-cta{width:200px!important;-webkit-box-flex:1;-webkit-flex-grow:1;-ms-flex-positive:1;flex-grow:1;-webkit-flex-basis:200px;-ms-flex-preferred-size:200px;flex-basis:200px;}.imagify-rkt-notice .button.button{position:relative;top:-1px;height:auto;font-weight:600;font-size:14px;box-shadow:0 4px 0 #B27A27;border:0 none;padding:9px 18px 9px;background:#F7A933;text-shadow:1px 1px 1px rgba(0,0,0,.2)}@media (max-width:880px){.imagify-rkt-notice{-webkit-flex-wrap:wrap;-ms-flex-wrap:wrap;flex-wrap:wrap}.imagify-rkt-notice .imagify-rkt-msg,.imagify-rkt-notice .imagify-rkt-cta,.imagify-rkt-notice .imagify-rkt-logo{text-align:left;padding:5px 15px}.imagify-cross.imagify-cross{top:8px;margin-top:0}.imagify-rkt-notice .imagify-cross .dashicons{top:1px}}.imagify-settings-section{padding:10px 20px}[id="imagify-settings"],.imagify-welcome .imagify-settings-section{border:1px solid #D9D9D9;border-top:0 none;background:#FFF}.imagify-br{line-height:2}.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}label+.imagify-info,label+.imagify-options-line,.imagify-visual-label{display:inline-block;max-width:70%;margin-left:15px;margin-top:2px!important;-webkit-transition:opacity .3s;transition:opacity .3s}.imagify-visual-label{vertical-align:-5px}label[for="imagify_sizes_full"]+.imagify-info{vertical-align:middle}.imagify-settings.imagify-settings [type="checkbox"]:not(:checked)+label+.imagify-options-line,.imagify-settings.imagify-settings [type="checkbox"]:not(:checked)+label .imagify-visual-label{opacity:.5}.imagify-settings.imagify-settings [type="checkbox"]:checked+label+.imagify-options-line,.imagify-settings.imagify-settings [type="checkbox"]:checked+label .imagify-visual-label{opacity:1}.imagify-checkbox-marged{max-width:500px;margin-left:45px}.imagify-settings.imagify-settings [type="checkbox"]:not(:checked),.imagify-settings.imagify-settings [type="checkbox"]:checked{opacity:0.01}.imagify-settings.imagify-settings [type="checkbox"]:not(:checked):focus,.imagify-settings.imagify-settings [type="checkbox"]:checked:focus{box-shadow:none!important;outline:none!important;border:0 none!important}.imagify-settings [type="checkbox"]:not(:checked)+label,.imagify-settings [type="checkbox"]:checked+label{position:relative;padding-left:6px;cursor:pointer;vertical-align:top}.imagify-settings [type="checkbox"]:not(:checked)+label:before,.imagify-settings [type="checkbox"]: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-settings [type="checkbox"]:not(:checked)+label:after,.imagify-settings [type="checkbox"]:checked+label:after{content:"✓";position:absolute;font-size:1.4em;top:3px;left:-16px;-webkit-transition:all .2s;-moz-transition:all .2s;-ms-transition:all .2s;transition:all .2s}.imagify-settings [type="checkbox"][disabled]:not(:checked)+label:before,.imagify-settings [type="checkbox"][disabled]:checked+label:before{border-color:#ccc;background:#ddd}.imagify-settings [type="checkbox"]:not(:checked)+label:after{opacity:0;-webkit-transform:scale(0);-moz-transform:scale(0);-ms-transform:scale(0);transform:scale(0)}.imagify-settings [type="checkbox"]:checked+label:after{opacity:1;-webkit-transform:scale(1);-moz-transform:scale(1);-ms-transform:scale(1);transform:scale(1)}input[id^="imagify_sizes_"]:checked+label{font-weight:bold}.imagify-settings .mini[type="checkbox"]:not(:checked)+label:before,.imagify-settings .mini[type="checkbox"]:checked+label:before{width:15px;height:15px;border-width:1px;border-radius:2px;margin-top:0}.imagify-settings .mini[type="checkbox"]:not(:checked)+label:after,.imagify-settings .mini[type="checkbox"]:checked+label:after{content:"✓";font-size:.9em;left:-21px;top:1px}.imagify-settings [type="checkbox"]:not(:checked):focus+label:before,.imagify-settings [type="checkbox"]: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:after{content:"";display:table;clear:both}.imagify-inline-options input[type="radio"]:not(:checked),.imagify-inline-options input[type="radio"]:checked{position:absolute;left:5px;top:5px;display:none}.imagify-inline-options input[type="radio"]:not(:checked)+label,.imagify-inline-options input[type="radio"]:checked+label{position:relative;display:table-cell;padding:13px 10px;text-align:center;font-weight:600;font-size:16px;text-transform:uppercase;letter-spacing:0.1em;color:#FFF;background:#2E3243;border-left:1px solid rgba(255,255,255,0.2);box-shadow:0 -3px 0 rgba(0,0,0,0.1) inset,inset -1px 0 0 rgba(255,255,255,0.2);z-index:2;-webkit-transition:all .275s;transition:all .275s}.imagify-bulk-submit .imagify-inline-options input[type="radio"]:not(:checked)+label,.imagify-bulk-submit .imagify-inline-options input[type="radio"]:checked+label{margin-bottom:1.75em}.imagify-inline-options input[type="radio"]:not(:checked)+label:first-of-type,.imagify-inline-options input[type="radio"]:checked+label:first-of-type{border-radius:3px 0 0 3px}.imagify-inline-options input[type="radio"]:not(:checked)+label:last-of-type,.imagify-inline-options input[type="radio"]: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-btn-info{display:block;font-size:0.7em;letter-spacing:0;line-height:1;text-transform:none}#describe-resize-larger input{width:5em}.imagify-col{overflow:hidden}.imagify-sidebar{float:right;width:280px;margin-left:25px}.imagify-sidebar-section{border:1px solid #BBB;background:#FFF}.imagify-sidebar-section+.imagify-sidebar-section{margin-top:2em}@media (max-width:760px){.imagify-settings{display:flex;flex-direction:column}.imagify-sidebar{order:2;float:none;width:auto;margin-left:0;margin-top:25px}.wp-media-products{text-align:center}.wp-media-products li{display:inline-block;width:100%;max-width:276px}}.imagify-sidebar-title{display:block;padding:20px 15px;border-bottom:1px solid #BBB;font-size:14px;font-weight:bold;color:#23282d;background:#F2F5F7}.imagify-sidebar-title img{vertical-align:top;margin-right:5px}.imagify-sidebar .wp-media-products{margin-top:0;margin-bottom:-.5em}.imagify-sidebar .wp-media-products .links{display:block;padding:85px 25px 24px;text-align:center;background-color:#2E3243;background-size:contain;background-repeat:no-repeat;background-position:50% 0;text-decoration:none}.imagify-sidebar .wp-media-products .links p{margin:1.5em auto;color:#FFF}.imagify-sidebar .wp-media-products .wprocket-link{background-image:linear-gradient(to bottom,rgba(59,30,78,0),rgba(59,30,78,0) 130px,rgba(59,30,78,1) 210px),url("../images/sidebar-wp-rocket.jpg");background-color:#3B1E4E;background-repeat:repeat-x,no-repeat}.imagify-sidebar-content{padding:10px 20px}.imagify-mark-styled{display:inline-block;padding:1px 2px 1px 4px;line-height:1.3;font-weight:bold;background:#F7A933;transform-origine:50% 50%;transform:rotateZ(-2deg) rotateX(-10deg) skewX(-2deg) skewY(-3deg);text-shadow:1px 1px 0 rgba(0,0,0,0.2)}.imagify-mark-styled span{display:inline-block;transform:rotateZ(2deg) rotateX(10deg) skewX(2deg) skewY(3deg)}.imagify-discount-code{margin:0.35em 0 .5em;display:block;font-size:2em;letter-spacing:.05em;font-weight:bold;text-align:center;text-shadow:1px 1px 0 rgba(0,0,0,0.2)}.imagify-big-text{font-size:15px;font-weight:bold}.imagify-big-text strong{font-size:20px}a.btn-rocket{display:block;font-size:1.15em;padding:12px;background:#F7A933;box-shadow:0 3px 0 #D69626;border-radius:3px;color:#FFF;text-transform:uppercase;font-weight:bold;text-shadow:1px 1px 0 rgba(0,0,0,0.2);text-decoration:none}a.btn-rocket:hover,a.btn-rocket:focus{background:darkorange;box-shadow:0 3px 0 darkorange}.imagify-welcome{margin:30px 20px 0 0}.imagify-welcome .baseline{display:inline-block;margin:.2em 0 0 2em;font-size:17px}.imagify-welcome .imagify-logo{vertical-align:middle}.imagify-welcome-remove{position:absolute;top:50%;right:15px;margin-top:-8px;color:#FFF;text-decoration:none}.imagify-columns{overflow:hidden;padding:15px 0;counter-reset:cols}.imagify-columns [class^="col-"]{float:left;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.imagify-columns .col-1-3{width:33.333%;padding-left:28px}.imagify-columns .col-1-2{width:50%;padding:0 20px}.imagify-columns .col-informations{width:41.6%;padding-right:30px}.imagify-columns .col-statistics{width:25%}@media (max-width:830px){.imagify-columns [class^="col-"]{float:none;margin-bottom:1.5em}.imagify-columns .col-1-3,.imagify-columns .col-1-2{width:auto;padding:0 28px;clear:both;padding-top:1em}}.imagify-columns [class^="col-"] img{float:left;margin-right:18px}.imagify-col-content{overflow:hidden}.imagify-col-title{margin:0 0 15px 0;font-size:23px}.counter .imagify-col-title:before{counter-increment:cols;content:counter(cols) ". ";color:#40B1D0}.imagify-col-desc{color:#5F758E;margin-bottom:2em}.imagify-notice.imagify-notice{position:relative;display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;padding:0;margin:10px 20px 10px 2px;border:0 none;background:#2E3243;box-shadow:none;color:#FFF}@media (max-width:782px){.imagify-notice.imagify-notice,.imagify-welcome{margin-right:12px}}@media (max-width:450px){.imagify-notice.imagify-notice{-webkit-box-orient:vertical;-webkit-box-direction:normal;-webkit-flex-direction:column; -ms-flex-direction:column; flex-direction:column}}.wrap .imagify-notice{margin:5px 15px 2px;position:relative}.imagify-notice-logo{padding:18px 23px;background:#40B1D0}.updated .imagify-notice-logo{background:#8BC34A}.error .imagify-notice-logo{background:#D0021B}.imagify-notice-title{font-size:15px}.imagify-notice-content{padding:5px 23px}.imagify-notice-content.imagify-notice-content p{margin:0.65em 0}.imagify-notice a{color:#40B1D0}.imagify-notice a:hover,.imagify-notice a:focus{color:#FEE102}.imagify-notice code{background:rgba(0,0,0,0.4) none repeat scroll 0 0}.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}ul.imagify-datas-list.imagify-datas-list{margin:0 auto;color:#555;font-size:10px}.compat-field-imagify .label{vertical-align:top}.compat-field-imagify ul.imagify-datas-list{margin-top:7px;font-size:11px}ul.imagify-datas-list .big{font-size:12px;color:#40B1D0}.imagify-data-item{overflow:hidden}.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;-moz-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:bold}.media-sidebar .imagify-datas-list .imagify-data-item .data{width:auto;float:none}ul.imagify-datas-list .imagify-data-item strong{text-align:left;padding-left:5px}.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: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:bold;line-height:1.9;text-decoration:none}.imagify-datas-more-action a.is-open{background:#555}.imagify-datas-more-action a.is-open .dashicons{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:20px;line-height:20px}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}.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}.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}.column-imagify_optimized_file .imagify-datas-actions-links a{margin:0 .7em;padding-left:15px}.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-title >h1{padding:0}.imagify-title-right{display:table;float:right;margin-top:-10px}.imagify-title-right p{margin:0}.imagify-title-right a{font-weight:bold;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:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-box-orient:vertical;-webkit-box-direction:normal;-webkit-flex-direction:column;-ms-flex-direction:column;flex-direction:column}.imagify-title-right{-webkit-box-ordinal-group:3;-webkit-order:2;-ms-flex-order:2;order:2;margin-top:20px}}.imagify-account,.imagify-account-link{padding-right:15px}.imagify-sep-v{width:1px;background:rgba(255,255,255,.2)}.imagify-credit-left{position:relative;min-width:280px;padding-left:15px}.imagify-meteo-icon{display:inline-block;height:38px;vertical-align:middle;margin-right:10px}.imagify-user-plan{color:#40b1d0}@media (max-width:630px){.imagify-title-right{display:block;width:auto}.imagify-title-right >div{display:block;width:auto;margin-top:10px;max-width:100%}.imagify-credit-left{padding-left:0}}.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-"],#wp-admin-bar-imagify-profile [class^="imagify-bar-"]{position:relative;height:15px;width:100%;background:#60758D;color:#FFF;font-size:10px}.base-transparent{background:transparent}[class^="imagify-bar-"].right-outside-number{-webkit-box-sizing:border-box;box-sizing:border-box;padding-right:45px}.right-outside-number .imagify-barnb{display:block;margin-right:-45px;text-align:right;font-weight:bold;line-height:15px}.imagify-progress-value,#wp-admin-bar-imagify-profile .imagify-progress-value{position:absolute;top:0;right:0;left:0;bottom:0;text-align:center;line-height:13px;font-weight:bold}.imagify-progress,#wp-admin-bar-imagify-profile .imagify-progress{height:15px}.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}#wpadminbar #wp-admin-bar-imagify-profile *{line-height:1.5;white-space:initial}#wpadminbar #wp-admin-bar-imagify .ab-submenu{padding-bottom:0}#wpadminbar #wp-admin-bar-imagify-profile .ab-item{height:auto;padding:0 13px}#wpadminbar #wp-admin-bar-imagify-profile{min-width:200px;padding:15px 0 10px;margin-top:0.7em;background:#222}#wp-admin-bar-imagify .dashicons{font-family:"dashicons";font-size:18px;vertical-align:middle;margin:0 5px 0 0}#wp-admin-bar-imagify .button-text{display:inline-block;vertical-align:middle}#wp-admin-bar-imagify .imagify-abq-row{display:table;width:100%}#wp-admin-bar-imagify .imagify-abq-row+.imagify-abq-row{margin-top:.75em}#wp-admin-bar-imagify .imagify-abq-row >*{display:table-cell}#wp-admin-bar-imagify-profile .imagify-meteo-icon{padding-right:7px}#wp-admin-bar-imagify-profile .imagify-meteo-icon img{width:37px}#wp-admin-bar-imagify-profile .imagify-meteo-title{font-size:17px}#wp-admin-bar-imagify-profile .imagify-meteo-subs{color:#72889F}#wpadminbar #wp-admin-bar-imagify-profile strong{font-weight:bold}#wpadminbar #wp-admin-bar-imagify-profile .imagify-user-plan,#wpadminbar #wp-admin-bar-imagify-profile a{padding:0;color:#40B1D0}#wpadminbar #wp-admin-bar-imagify-profile .imagify-account-link{display:table}#wpadminbar #wp-admin-bar-imagify-profile .imagify-account-link >* {display:table-cell}#wpadminbar #wp-admin-bar-imagify-profile .imagify-space-left{max-width:210px;min-width:210px;width:210px}#wpadminbar #wp-admin-bar-imagify-profile .imagify-space-left p{font-size:12px}#wp-admin-bar-imagify-profile .imagify-error,#wp-admin-bar-imagify-profile .imagify-warning{padding:10px;margin:0 -13px -13px}#wp-admin-bar-imagify-profile .imagify-error p+p,#wp-admin-bar-imagify-profile .imagify-warning p+p{margin-top:.5em}#wp-admin-bar-imagify-profile .imagify-error p+p+p,#wp-admin-bar-imagify-profile .imagify-warning p+p+p{margin-top:1em}.btn-ghost,#wpadminbar #wp-admin-bar-imagify-profile .btn-ghost{display:inline-block;height:auto;padding:7px 10px;border:1px solid #FFF;text-align:center;background:transparent;color:#FFF;border-radius:3px;transition:all .275s}.btn-ghost:hover,.btn-ghost:focus,#wpadminbar #wp-admin-bar-imagify-profile .btn-ghost:hover,#wpadminbar #wp-admin-bar-imagify-profile .btn-ghost:focus{background:#FFF;color:#888}.txt-center{text-align:center}.imagify-list-dash li{position:relative;padding-left:24px}.imagify-list-dash li:before{content:"";position:absolute;left:0;top:9px;height:1px;width:12px;background:#5f758e}.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 p,.imagify-bulk .imagify-settings-section li,.imagify-bulk .imagify-settings-section h3{color:#4A4A4A}.imagify-bulk .imagify-settings-section h3{margin-bottom:2em}.imagify-bulk-submit{margin-top:4em}#imagify-bulk-action{float:left}#imagify-bulk-action+.imagify-tooltips{overflow:hidden;display:block}.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:bold;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-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 5px;font-size:13px;background:#40B1D0;box-shadow:0 3px 0 #338EA6}.imagify-space-tooltips .tooltip-content:after{top:-14px;left:50%;margin-left:-7px;border:0 none;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:bold;line-height:1.1;vertical-align:middle}.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:0.85em;margin-bottom:1.35em;overflow:hidden;border-bottom:1px solid rgba(0,0,0,0.05)}.imagify-bars p{font-weight:bold;font-size:12px;margin-bottom:0}.imagify-bars+.imagify-number-you-optimized{border-bottom:0;padding-top:0.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-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 tr,.imagify-bulk-table thead th{background:#2E3242}.imagify-bulk-table tfoot tr,.imagify-bulk-table tfoot th{background:#73818C}.imagify-bulk-table thead th{padding:14px 15px;text-align:left;color:#F2F5F7;font-weight:bold;font-size:14px}.imagify-bulk-table tfoot td{padding:14px 15px;color:#F9FAFA}.imagify-bulk-table tbody tr,.imagify-bulk-table tbody td{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:bold;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;transform:scale(1)} 50%{transform:scale(1.05);opacity:1} 100%{transform:scale(1);opacity:1}}.imagify-row-complete.done{-webkit-animation:congrate 500ms ease-in-out;animation:congrate 500ms 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{overflow:hidden}.imagify-ac-report-text p{line-height:1.3}.imagify-ac-rt-big{font-weight:bold;font-size:24px;letter-spacing:0.15em;word-spacing:0.15em;text-transform:uppercase}.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{text-overflow:clip;white-space:nowrap;overflow:hidden}.imagify-bulk-table td.imagify-cell-totaloriginal{padding-right:78px}.imagiuploaded,.imagifilename{display:inline-block;vertical-align:middle}.imagifilename{font-size:12px}.imagiuploaded{width:33px;height:33px;margin-right:5px;margin-left:-8px;overflow:hidden;background:url(../images/upload-image.png) 0 0 no-repeat;background-size:cover}.imagiuploaded img{max-widht:100%;height:auto}.imagistatus{color:#8CA6B3;text-transform:uppercase;font-weight:bold}.status-compressing{color:#46B1CE}.status-error{color:#CE0B24}.status-warning{color:#f5a623}.status-complete{color:#8CC152}.imagify-error{background:#D0021B;color:#FFF}.imagify-warning,#wpadminbar .imagify-warning *{background:#f5a623;color:#FFF;text-shadow:0 0 2px rgba(0,0,0,0.2)}.imagify-bulk-table .imagify-cell-thumbnails{text-align:center}.imagify-cell-percentage,.imagify-cell-savings{color:#46B1CE;font-weight:bold}.imagify-cell-optimized{font-weight:bold}.imagify-cell-totaloriginal{text-align:right}.dashicons.rotate{-webkit-animation:icon-rotate 2.6s infinite linear;animation:icon-rotate 2.6s infinite linear}.dashicons-admin-generic{transform-origin:48.75% 51.75%}.imagify-modal{display:flex;flex-direction:column;align-items: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;-moz-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;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:transparent;padding:5px;box-shadow:none;border-radius:0}.imagify-modal .h2{margin:.5em 0;color:#8ba6b4;font-weight:normal;font-size:24px;letter-spacing:0.075em;text-align:center}.imagify-modal .h3{color:#40b1d0;font-weight:normal;font-size:18px;letter-spacing:0.075em;text-align:center}.text-justify{text-align:justify}.imagify-modal .close-btn{display:none;visibility:hidden;position:absolute;right:20px;top:20px;font-size:1.2em;border:0;background:transparent none;border-radius:0;cursor:pointer}.imagify-modal .close-btn i{margin-left:-2px}.imagify-modal .close-btn:hover,.imagify-modal .close-btn:focus{color:#40b1d0}.js .imagify-modal .close-btn{display:block;visibility:visible}#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%}.wp_attachment_image #imagify-visual-comparison .close-btn,.imagify-visual-comparison .close-btn{top:0}.wp_attachment_image #imagify-visual-comparison .imagify-modal-content,.imagify-visual-comparison .imagify-modal-content{padding-top:40px}.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: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-right,.imagify-c-level.go-left{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:bold}.imagify-c-level-row .value .imagify-chart{top:1px}@-webkit-keyframes icon-rotate{from{-webkit-transform:rotate(0deg);transform:rotate(0deg)}to{-webkit-transform:rotate(360deg);transform:rotate(360deg)}}@keyframes icon-rotate{from{transform:rotate(0deg)}to{transform:rotate(360deg)}}.imagify-menu-bar-img{margin-top:1em}.imagify-modal .loader{position:absolute;top:50%;left:50%;margin:-32px 0 0 -32px;opacity:0;visibility:hidden;transition:opacity .4s}.imagify-modal .loading .loader{visibility:visible;opacity:1}.imagify-settings .imagify-visual-comparison-text{margin-top:1em;color:#40b1d0;font-weight:bold}
assets/js/bulk.js CHANGED
@@ -9,8 +9,8 @@ jQuery(function($){
9
  }
10
  };
11
 
12
- var overviewCanvas = document.getElementById("imagify-overview-chart");
13
- var overviewData = [
14
  {
15
  value: imagifyBulk.totalUnoptimizedAttachments,
16
  color:"#D9E4EB",
@@ -29,7 +29,7 @@ jQuery(function($){
29
  highlight: "#2E3242",
30
  label: imagifyBulk.overviewChartLabels.error
31
  }
32
- ]
33
 
34
  // to avoid JS error
35
  if ( overviewCanvas ) {
@@ -43,12 +43,62 @@ jQuery(function($){
43
  tooltipTemplate: "<%= value %>"
44
  });
45
 
46
- //then you just need to generate the legend
47
- var overviewLegend = overviewDoughnut.generateLegend();
 
48
 
49
  //and append it to your page somewhere
 
 
 
 
 
 
 
 
50
  document.getElementById("imagify-overview-chart-legend").innerHTML = overviewLegend;
51
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
52
 
53
  // Simulate a click on the "Imagif'em all" button
54
  $('#imagify-simulate-bulk-action').click(function(e){
@@ -154,46 +204,25 @@ jQuery(function($){
154
  $('#attachment-'+data.image+' .imagify-cell-percentage').html('<span class="imagify-chart"><span class="imagify-chart-container"><canvas height="18" width="18" id="imagify-consumption-chart" style="width: 18px; height: 18px;"></canvas></span></span><span class="imagipercent">'+data.percent+'</span>%');
155
  draw_me_a_chart( $('#attachment-'+data.image+' .imagify-cell-percentage').find('canvas') );
156
  $('#attachment-'+data.image+' .imagify-cell-thumbnails').html(data.thumbnails);
157
- $('#attachment-'+data.image+' .imagify-cell-savings').html(Optimizer.toHumanSize(data.overall_saving, 1));
158
 
159
- // The overview chart percent
160
- $('#imagify-overview-chart-percent').html(data.global_optimized_attachments_percent + '<span>%</span>');
161
- // The total optimized images
162
- $('#imagify-total-optimized-attachments').html(data.global_already_optimized_attachments);
163
-
164
- // The comsuption bar
165
- $('.imagify-unconsumed-percent').html(data.global_unconsumed_quota + '%');
166
- $('.imagify-unconsumed-bar').animate({'width': data.global_unconsumed_quota + '%'});
167
-
168
- // The original bar
169
- $('#imagify-original-bar').find('.imagify-barnb')
170
- .html(data.global_original_human);
171
-
172
- // The optimized bar
173
- $('#imagify-optimized-bar').animate({'width': data.global_optimized_percent+"%"})
174
- $('#imagify-optimized-bar').find('.imagify-barnb')
175
- .html(data.global_optimized_human);
176
-
177
- // The Percent data
178
- $('#imagify-total-optimized-attachments-pct').html( data.global_optimized_percent + '%' );
179
-
180
  // The table footer total optimized files
181
  files = files + data.thumbnails + 1;
182
  $('.imagify-cell-nb-files').html(files + ' file(s)');
183
 
184
  // The table footer original size
185
  original_overall_size = original_overall_size + data.original_overall_size;
186
- $('.imagify-total-original').html(Optimizer.toHumanSize(original_overall_size, 1));
187
 
188
  // The table footer overall saving
189
  overall_saving = overall_saving + data.overall_saving;
190
- $('.imagify-total-gain').html(Optimizer.toHumanSize(overall_saving, 1));
191
 
192
  } else {
193
  error_class = 'error';
194
  error_dashicon = 'dismiss';
195
  error_message = 'Error';
196
-
197
  if ( data.error.indexOf("You've consumed all your data") >= 0 ) {
198
  swal({
199
  title: imagifyBulk.overQuotaTitle,
@@ -220,11 +249,6 @@ jQuery(function($){
220
 
221
  $('#attachment-'+data.image+' .imagify-cell-status').html('<span class="imagistatus status-'+error_class+'"><span class="dashicons dashicons-'+error_dashicon+'"></span>'+error_message+'</span>');
222
  }
223
-
224
- overviewDoughnut.segments[0].value = data.global_unoptimized_attachments;
225
- overviewDoughnut.segments[1].value = data.global_optimized_attachments;
226
- overviewDoughnut.segments[2].value = data.global_errors_attachments;
227
- overviewDoughnut.update();
228
  })
229
  // after all attachments optimization
230
  .done(function (data) {
9
  }
10
  };
11
 
12
+ var overviewCanvas = document.getElementById("imagify-overview-chart"),
13
+ overviewData = [
14
  {
15
  value: imagifyBulk.totalUnoptimizedAttachments,
16
  color:"#D9E4EB",
29
  highlight: "#2E3242",
30
  label: imagifyBulk.overviewChartLabels.error
31
  }
32
+ ];
33
 
34
  // to avoid JS error
35
  if ( overviewCanvas ) {
43
  tooltipTemplate: "<%= value %>"
44
  });
45
 
46
+ //then you just need to generate the legend
47
+ //var overviewLegend = overviewDoughnut.generateLegend();
48
+ //bugged `segments undefined` ?
49
 
50
  //and append it to your page somewhere
51
+ overviewLegend = '<ul class="imagify-doughnut-legend">';
52
+
53
+ $(overviewData).each(function(i){
54
+ overviewLegend += '<li><span style="background-color:' + overviewData[i].color + '"></span>' + overviewData[i].label + '</li>';
55
+ });
56
+
57
+ overviewLegend += '</ul>';
58
+
59
  document.getElementById("imagify-overview-chart-legend").innerHTML = overviewLegend;
60
  }
61
+
62
+ // Heartbeat
63
+ $(document).on('heartbeat-send', function(e, data) {
64
+ data['imagify_heartbeat'] = 'update_bulk_data';
65
+ });
66
+
67
+ // Listen for the custom event "heartbeat-tick" on $(document).
68
+ $(document).on( 'heartbeat-tick', function(e, data) {
69
+ if ( ! data['imagify_bulk_data'] ) {
70
+ return;
71
+ }
72
+
73
+ data = data['imagify_bulk_data'];
74
+
75
+ // The overview chart percent
76
+ $('#imagify-overview-chart-percent').html(data.optimized_attachments_percent + '<span>%</span>');
77
+
78
+ // The comsuption bar
79
+ $('.imagify-unconsumed-percent').html(data.unconsumed_quota + '%');
80
+ $('.imagify-unconsumed-bar').animate({'width': data.unconsumed_quota + '%'});
81
+
82
+ // The total optimized images
83
+ $('#imagify-total-optimized-attachments').html(data.already_optimized_attachments);
84
+
85
+ // The original bar
86
+ $('#imagify-original-bar').find('.imagify-barnb')
87
+ .html(data.original_human);
88
+
89
+ // The optimized bar
90
+ $('#imagify-optimized-bar').animate({'width': data.optimized_percent+"%"})
91
+ $('#imagify-optimized-bar').find('.imagify-barnb')
92
+ .html(data.optimized_human);
93
+
94
+ // The Percent data
95
+ $('#imagify-total-optimized-attachments-pct').html( data.optimized_percent + '%' );
96
+
97
+ overviewDoughnut.segments[0].value = data.unoptimized_attachments;
98
+ overviewDoughnut.segments[1].value = data.optimized_attachments;
99
+ overviewDoughnut.segments[2].value = data.errors_attachments;
100
+ overviewDoughnut.update();
101
+ });
102
 
103
  // Simulate a click on the "Imagif'em all" button
104
  $('#imagify-simulate-bulk-action').click(function(e){
204
  $('#attachment-'+data.image+' .imagify-cell-percentage').html('<span class="imagify-chart"><span class="imagify-chart-container"><canvas height="18" width="18" id="imagify-consumption-chart" style="width: 18px; height: 18px;"></canvas></span></span><span class="imagipercent">'+data.percent+'</span>%');
205
  draw_me_a_chart( $('#attachment-'+data.image+' .imagify-cell-percentage').find('canvas') );
206
  $('#attachment-'+data.image+' .imagify-cell-thumbnails').html(data.thumbnails);
207
+ $('#attachment-'+data.image+' .imagify-cell-savings').html(Optimizer.humanSize(data.overall_saving, 1));
208
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
209
  // The table footer total optimized files
210
  files = files + data.thumbnails + 1;
211
  $('.imagify-cell-nb-files').html(files + ' file(s)');
212
 
213
  // The table footer original size
214
  original_overall_size = original_overall_size + data.original_overall_size;
215
+ $('.imagify-total-original').html(Optimizer.humanSize(original_overall_size, 1));
216
 
217
  // The table footer overall saving
218
  overall_saving = overall_saving + data.overall_saving;
219
+ $('.imagify-total-gain').html(Optimizer.humanSize(overall_saving, 1));
220
 
221
  } else {
222
  error_class = 'error';
223
  error_dashicon = 'dismiss';
224
  error_message = 'Error';
225
+
226
  if ( data.error.indexOf("You've consumed all your data") >= 0 ) {
227
  swal({
228
  title: imagifyBulk.overQuotaTitle,
249
 
250
  $('#attachment-'+data.image+' .imagify-cell-status').html('<span class="imagistatus status-'+error_class+'"><span class="dashicons dashicons-'+error_dashicon+'"></span>'+error_message+'</span>');
251
  }
 
 
 
 
 
252
  })
253
  // after all attachments optimization
254
  .done(function (data) {
assets/js/bulk.min.js CHANGED
@@ -1,16 +1,16 @@
1
- jQuery(function(a){function p(c){c.each(function(){var c=parseInt(a(this).closest(".imagify-chart").next(".imagipercent").text()),c=[{value:c,color:"#00B3D3"},{value:100-c,color:"#D8D8D8"}];(new Chart(a(this)[0].getContext("2d"))).Doughnut(c,{segmentStrokeColor:"#FFF",segmentStrokeWidth:1,animateRotate:!0,tooltipEvents:[]})})}function q(c){c.each(function(){var c=parseInt(a(this).closest(".imagify-ac-chart").attr("data-percent")),c=[{value:c,color:"#40B1D0"},{value:100-c,color:"#FFFFFF"}];(new Chart(a(this)[0].getContext("2d"))).Doughnut(c,
2
- {segmentStrokeColor:"transparent",segmentStrokeWidth:0,animateRotate:!0,animation:!0,percentageInnerCutout:70,tooltipEvents:[]})})}var l=0<ajaxurl.indexOf("?")?"&":"?",m={log:function(a){"undefined"!==console&&console.log(a)}},d=document.getElementById("imagify-overview-chart"),f=[{value:imagifyBulk.totalUnoptimizedAttachments,color:"#D9E4EB",highlight:"#D9E4EB",label:imagifyBulk.overviewChartLabels.unoptimized},{value:imagifyBulk.totalOptimizedAttachments,color:"#46B1CE",highlight:"#46B1CE",label:imagifyBulk.overviewChartLabels.optimized},
3
- {value:imagifyBulk.totalErrorsAttachments,color:"#2E3242",highlight:"#2E3242",label:imagifyBulk.overviewChartLabels.error}];if(d){var e=(new Chart(d.getContext("2d"))).Doughnut(f,{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>',
4
- tooltipTemplate:"<%= value %>"}),d=e.generateLegend();document.getElementById("imagify-overview-chart-legend").innerHTML=d}a("#imagify-simulate-bulk-action").click(function(c){c.preventDefault();a("#imagify-bulk-action").trigger("click")});a("#imagify-bulk-action").click(function(){var c=a(this),d=a('[name="optimization_level"]:checked').val();"undefined"===typeof d&&(d=-1);if(c.attr("disabled"))return!1;c.attr("disabled","disabled");c.find(".dashicons").addClass("rotate");confirmMessage=function(){return imagifyBulk.processing};
5
- a(window).on("beforeunload",confirmMessage);swal({title:imagifyBulk.waitTitle,text:imagifyBulk.waitText,closeOnConfirm:!1,showConfirmButton:!1,imageUrl:imagifyBulk.waitImageUrl});a.get(ajaxurl+l+"action=imagify_get_unoptimized_attachment_ids&optimization_level="+d+"&imagifybulkuploadnonce="+a("#imagifybulkuploadnonce").val()).done(function(d){if(d.success){swal.close();d={lib:ajaxurl+l+"action=imagify_bulk_upload&imagifybulkuploadnonce="+a("#imagifybulkuploadnonce").val(),images:d.data};var f=a(".imagify-bulk-table table tbody"),
6
- g=0,n=0,h=0,k=0;a(".imagify-row-progress").slideDown();a(".imagify-no-uploaded-yet, .imagify-row-complete").hide(200);Optimizer=new ImagifyGulp(d);Optimizer.before(function(a){f.append('<tr id="attachment-'+a.id+'"><td class="imagify-cell-filename"><span class="imagiuploaded"><img src="'+a.thumbnail+'"/>"</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>Compressing<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=
7
- a("#imagify-progress-bar");c.css({width:b.progress+"%"});c.find(".percent").html(b.progress+"%");b.success?(a("#attachment-"+b.image+" .imagify-cell-status").html('<span class="imagistatus status-complete"><span class="dashicons dashicons-yes"></span>Complete</span>'),a("#attachment-"+b.image+" .imagify-cell-original").html(b.original_size_human),a("#attachment-"+b.image+" .imagify-cell-optimized").html(b.new_size_human),a("#attachment-"+b.image+" .imagify-cell-percentage").html('<span class="imagify-chart"><span class="imagify-chart-container"><canvas height="18" width="18" id="imagify-consumption-chart" style="width: 18px; height: 18px;"></canvas></span></span><span class="imagipercent">'+
8
- b.percent+"</span>%"),p(a("#attachment-"+b.image+" .imagify-cell-percentage").find("canvas")),a("#attachment-"+b.image+" .imagify-cell-thumbnails").html(b.thumbnails),a("#attachment-"+b.image+" .imagify-cell-savings").html(Optimizer.toHumanSize(b.overall_saving,1)),a("#imagify-overview-chart-percent").html(b.global_optimized_attachments_percent+"<span>%</span>"),a("#imagify-total-optimized-attachments").html(b.global_already_optimized_attachments),a(".imagify-unconsumed-percent").html(b.global_unconsumed_quota+
9
- "%"),a(".imagify-unconsumed-bar").animate({width:b.global_unconsumed_quota+"%"}),a("#imagify-original-bar").find(".imagify-barnb").html(b.global_original_human),a("#imagify-optimized-bar").animate({width:b.global_optimized_percent+"%"}),a("#imagify-optimized-bar").find(".imagify-barnb").html(b.global_optimized_human),a("#imagify-total-optimized-attachments-pct").html(b.global_optimized_percent+"%"),g=g+b.thumbnails+1,a(".imagify-cell-nb-files").html(g+" file(s)"),h+=b.original_overall_size,a(".imagify-total-original").html(Optimizer.toHumanSize(h,
10
- 1)),k+=b.overall_saving,a(".imagify-total-gain").html(Optimizer.toHumanSize(k,1))):(error_class="error",error_dashicon="dismiss",error_message="Error",0<=b.error.indexOf("You've consumed all your data")&&swal({title:imagifyBulk.overQuotaTitle,text:imagifyBulk.overQuotaText,type:"error",customClass:"imagify-sweet-alert",html:!0},function(){location.reload()}),0<=b.error.indexOf("This image is already compressed")?(error_dashicon=error_class="warning",error_message="Notice"):(n++,a(".imagify-cell-errors").html(n+
11
- " error(s)")),a("#attachment-"+b.image).after('<tr><td colspan="7"><span class="status-'+error_class+'">'+b.error+"</span></td></tr>"),a("#attachment-"+b.image+" .imagify-cell-status").html('<span class="imagistatus status-'+error_class+'"><span class="dashicons dashicons-'+error_dashicon+'"></span>'+error_message+"</span>"));e.segments[0].value=b.global_unoptimized_attachments;e.segments[1].value=b.global_optimized_attachments;e.segments[2].value=b.global_errors_attachments;e.update()}).done(function(b){c.removeAttr("disabled");
12
- c.find(".dashicons").removeClass("rotate");a(window).off("beforeunload",confirmMessage);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),text2share=imagifyBulk.textToShare,text2share=text2share.replace("%1$s",
13
- b.global_gain_human),text2share=text2share.replace("%2$s",b.global_original_size_human),text2share=encodeURIComponent(text2share),a(".imagify-sn-twitter").attr("href","https://twitter.com/intent/tweet?source=webclient&amp;original_referer="+imagifyBulk.pluginURL+"&amp;text="+text2share+"&amp;url="+imagifyBulk.pluginURL+"&amp;related=imagify&amp;hastags=performance,web,wordpress"),a(".imagify-ac-chart").attr("data-percent",b.global_percent),q(a(".imagify-ac-chart").find("canvas")))}).error(function(a){m.log("Can't optimize image with id "+
14
- a)}).run()}else c.removeAttr("disabled"),c.find(".dashicons").removeClass("rotate"),a(window).off("beforeunload",confirmMessage),m.log(d),"over-quota"==d.data.message&&swal({title:imagifyBulk.overQuotaTitle,text:imagifyBulk.overQuotaText,type:"error",customClass:"imagify-sweet-alert",html:!0}),"no-images"==d.data.message&&swal({title:imagifyBulk.noAttachmentToOptimizeTitle,text:imagifyBulk.noAttachmentToOptimizeText,type:"info",customClass:"imagify-sweet-alert"})}).fail(function(){swal({title:imagifyBulk.getUnoptimizedImagesErrorTitle,
15
- text:imagifyBulk.getUnoptimizedImagesErrorText,type:"error",customClass:"imagify-sweet-alert"},function(){location.reload()})})})});var width=700,height=290;if(window.innerWidth)var clientLeft=(window.innerWidth-width)/2,clientTop=(window.innerHeight-height)/2;else clientLeft=(document.body.clientWidth-width)/2,clientTop=(document.body.clientHeight-height)/2;
16
- [].forEach.call(document.querySelectorAll(".imagify-share-networks a"),function(a){a.addEventListener("click",function(a){window.open(this.href,"","status=no, scrollbars=no, menubar=no, top="+clientTop+", left="+clientLeft+", width="+width+", height="+height);a.preventDefault()},!1)});
1
+ jQuery(function(b){function m(c){c.each(function(){var a=parseInt(b(this).closest(".imagify-chart").next(".imagipercent").text()),a=[{value:a,color:"#00B3D3"},{value:100-a,color:"#D8D8D8"}];(new Chart(b(this)[0].getContext("2d"))).Doughnut(a,{segmentStrokeColor:"#FFF",segmentStrokeWidth:1,animateRotate:!0,tooltipEvents:[]})})}function n(c){c.each(function(){var a=parseInt(b(this).closest(".imagify-ac-chart").attr("data-percent")),a=[{value:a,color:"#40B1D0"},{value:100-a,color:"#FFFFFF"}];(new Chart(b(this)[0].getContext("2d"))).Doughnut(a,
2
+ {segmentStrokeColor:"transparent",segmentStrokeWidth:0,animateRotate:!0,animation:!0,percentageInnerCutout:70,tooltipEvents:[]})})}var k=0<ajaxurl.indexOf("?")?"&":"?",l={log:function(b){"undefined"!==console&&console.log(b)}},f=document.getElementById("imagify-overview-chart"),e=[{value:imagifyBulk.totalUnoptimizedAttachments,color:"#D9E4EB",highlight:"#D9E4EB",label:imagifyBulk.overviewChartLabels.unoptimized},{value:imagifyBulk.totalOptimizedAttachments,color:"#46B1CE",highlight:"#46B1CE",label:imagifyBulk.overviewChartLabels.optimized},
3
+ {value:imagifyBulk.totalErrorsAttachments,color:"#2E3242",highlight:"#2E3242",label:imagifyBulk.overviewChartLabels.error}];if(f){var d=(new Chart(f.getContext("2d"))).Doughnut(e,{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>',
4
+ tooltipTemplate:"<%= value %>"});overviewLegend='<ul class="imagify-doughnut-legend">';b(e).each(function(b){overviewLegend+='<li><span style="background-color:'+e[b].color+'"></span>'+e[b].label+"</li>"});overviewLegend+="</ul>";document.getElementById("imagify-overview-chart-legend").innerHTML=overviewLegend}b(document).on("heartbeat-send",function(b,a){a.imagify_heartbeat="update_bulk_data"});b(document).on("heartbeat-tick",function(c,a){a.imagify_bulk_data&&(a=a.imagify_bulk_data,b("#imagify-overview-chart-percent").html(a.optimized_attachments_percent+
5
+ "<span>%</span>"),b(".imagify-unconsumed-percent").html(a.unconsumed_quota+"%"),b(".imagify-unconsumed-bar").animate({width:a.unconsumed_quota+"%"}),b("#imagify-total-optimized-attachments").html(a.already_optimized_attachments),b("#imagify-original-bar").find(".imagify-barnb").html(a.original_human),b("#imagify-optimized-bar").animate({width:a.optimized_percent+"%"}),b("#imagify-optimized-bar").find(".imagify-barnb").html(a.optimized_human),b("#imagify-total-optimized-attachments-pct").html(a.optimized_percent+
6
+ "%"),d.segments[0].value=a.unoptimized_attachments,d.segments[1].value=a.optimized_attachments,d.segments[2].value=a.errors_attachments,d.update())});b("#imagify-simulate-bulk-action").click(function(c){c.preventDefault();b("#imagify-bulk-action").trigger("click")});b("#imagify-bulk-action").click(function(){var c=b(this),a=b('[name="optimization_level"]:checked').val();"undefined"===typeof a&&(a=-1);if(c.attr("disabled"))return!1;c.attr("disabled","disabled");c.find(".dashicons").addClass("rotate");
7
+ confirmMessage=function(){return imagifyBulk.processing};b(window).on("beforeunload",confirmMessage);swal({title:imagifyBulk.waitTitle,text:imagifyBulk.waitText,closeOnConfirm:!1,showConfirmButton:!1,imageUrl:imagifyBulk.waitImageUrl});b.get(ajaxurl+k+"action=imagify_get_unoptimized_attachment_ids&optimization_level="+a+"&imagifybulkuploadnonce="+b("#imagifybulkuploadnonce").val()).done(function(a){if(a.success){swal.close();a={lib:ajaxurl+k+"action=imagify_bulk_upload&imagifybulkuploadnonce="+b("#imagifybulkuploadnonce").val(),
8
+ images:a.data};var e=b(".imagify-bulk-table table tbody"),d=0,f=0,g=0,h=0;b(".imagify-row-progress").slideDown();b(".imagify-no-uploaded-yet, .imagify-row-complete").hide(200);Optimizer=new ImagifyGulp(a);Optimizer.before(function(b){e.append('<tr id="attachment-'+b.id+'"><td class="imagify-cell-filename"><span class="imagiuploaded"><img src="'+b.thumbnail+'"/>"</span><span class="imagifilename">'+b.filename+'</span></td><td class="imagify-cell-status"><span class="imagistatus status-compressing"><span class="dashicons dashicons-admin-generic rotate"></span>Compressing<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(a){var c=
9
+ b("#imagify-progress-bar");c.css({width:a.progress+"%"});c.find(".percent").html(a.progress+"%");a.success?(b("#attachment-"+a.image+" .imagify-cell-status").html('<span class="imagistatus status-complete"><span class="dashicons dashicons-yes"></span>Complete</span>'),b("#attachment-"+a.image+" .imagify-cell-original").html(a.original_size_human),b("#attachment-"+a.image+" .imagify-cell-optimized").html(a.new_size_human),b("#attachment-"+a.image+" .imagify-cell-percentage").html('<span class="imagify-chart"><span class="imagify-chart-container"><canvas height="18" width="18" id="imagify-consumption-chart" style="width: 18px; height: 18px;"></canvas></span></span><span class="imagipercent">'+
10
+ a.percent+"</span>%"),m(b("#attachment-"+a.image+" .imagify-cell-percentage").find("canvas")),b("#attachment-"+a.image+" .imagify-cell-thumbnails").html(a.thumbnails),b("#attachment-"+a.image+" .imagify-cell-savings").html(Optimizer.humanSize(a.overall_saving,1)),d=d+a.thumbnails+1,b(".imagify-cell-nb-files").html(d+" file(s)"),g+=a.original_overall_size,b(".imagify-total-original").html(Optimizer.humanSize(g,1)),h+=a.overall_saving,b(".imagify-total-gain").html(Optimizer.humanSize(h,1))):(error_class=
11
+ "error",error_dashicon="dismiss",error_message="Error",0<=a.error.indexOf("You've consumed all your data")&&swal({title:imagifyBulk.overQuotaTitle,text:imagifyBulk.overQuotaText,type:"error",customClass:"imagify-sweet-alert",html:!0},function(){location.reload()}),0<=a.error.indexOf("This image is already compressed")?(error_dashicon=error_class="warning",error_message="Notice"):(f++,b(".imagify-cell-errors").html(f+" error(s)")),b("#attachment-"+a.image).after('<tr><td colspan="7"><span class="status-'+
12
+ error_class+'">'+a.error+"</span></td></tr>"),b("#attachment-"+a.image+" .imagify-cell-status").html('<span class="imagistatus status-'+error_class+'"><span class="dashicons dashicons-'+error_dashicon+'"></span>'+error_message+"</span>"))}).done(function(a){c.removeAttr("disabled");c.find(".dashicons").removeClass("rotate");b(window).off("beforeunload",confirmMessage);b(".imagify-row-progress").slideUp();"NaN"!==a.global_percent&&(b(".imagify-row-complete").removeClass("hidden").addClass("done").attr("aria-hidden",
13
+ "false"),b("html, body").animate({scrollTop:b(".imagify-row-complete").offset().top},200),b(".imagify-ac-rt-total-gain").html(a.global_gain_human),b(".imagify-ac-rt-total-original").html(a.global_original_size_human),text2share=imagifyBulk.textToShare,text2share=text2share.replace("%1$s",a.global_gain_human),text2share=text2share.replace("%2$s",a.global_original_size_human),text2share=encodeURIComponent(text2share),b(".imagify-sn-twitter").attr("href","https://twitter.com/intent/tweet?source=webclient&amp;original_referer="+
14
+ imagifyBulk.pluginURL+"&amp;text="+text2share+"&amp;url="+imagifyBulk.pluginURL+"&amp;related=imagify&amp;hastags=performance,web,wordpress"),b(".imagify-ac-chart").attr("data-percent",a.global_percent),n(b(".imagify-ac-chart").find("canvas")))}).error(function(a){l.log("Can't optimize image with id "+a)}).run()}else c.removeAttr("disabled"),c.find(".dashicons").removeClass("rotate"),b(window).off("beforeunload",confirmMessage),l.log(a),"over-quota"==a.data.message&&swal({title:imagifyBulk.overQuotaTitle,
15
+ text:imagifyBulk.overQuotaText,type:"error",customClass:"imagify-sweet-alert",html:!0}),"no-images"==a.data.message&&swal({title:imagifyBulk.noAttachmentToOptimizeTitle,text:imagifyBulk.noAttachmentToOptimizeText,type:"info",customClass:"imagify-sweet-alert"})}).fail(function(){swal({title:imagifyBulk.getUnoptimizedImagesErrorTitle,text:imagifyBulk.getUnoptimizedImagesErrorText,type:"error",customClass:"imagify-sweet-alert"},function(){location.reload()})})})});var width=700,height=290;
16
+ if(window.innerWidth)var clientLeft=(window.innerWidth-width)/2,clientTop=(window.innerHeight-height)/2;else clientLeft=(document.body.clientWidth-width)/2,clientTop=(document.body.clientHeight-height)/2;[].forEach.call(document.querySelectorAll(".imagify-share-networks a"),function(b){b.addEventListener("click",function(b){window.open(this.href,"","status=no, scrollbars=no, menubar=no, top="+clientTop+", left="+clientLeft+", width="+width+", height="+height);b.preventDefault()},!1)});
assets/js/chart.js ADDED
@@ -0,0 +1,3732 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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);
assets/js/chart.min.js CHANGED
@@ -7,5 +7,5 @@
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"),n=this.height=i(t.canvas,"Height");t.canvas.width=e,t.canvas.height=n;var e=this.width=t.canvas.width,n=this.height=t.canvas.height;return 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",tooltipYPadding:6,tooltipXPadding:6,tooltipCaretSize:8,tooltipCornerRadius:6,tooltipXOffset:10,tooltipTemplate:"<%if (label){%><%=label%>: <%}%><%= value %>",multiTooltipTemplate:"<%= value %>",multiTooltipKeyBackground:"#fff",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(){var t=Array.prototype.slice.call(arguments,0);return t.unshift({}),a.apply(null,t)},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){return t%1!==0&&f(t)?t.toString().split(".")[1].length: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}),y=(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)}),C=(s.calculateScaleRange=function(t,i,e,s,n){var o=2,a=Math.floor(i/(1.5*e)),h=o>=a,l=g(t),r=m(t);l===r&&(l+=.5,r>=.5&&!s?r-=.5:l+=.5);for(var c=Math.abs(l-r),u=y(c),d=Math.ceil(l/(1*Math.pow(10,u)))*Math.pow(10,u),p=s?0:Math.floor(r/(1*Math.pow(10,u)))*Math.pow(10,u),f=d-p,v=Math.pow(10,u),S=Math.round(f/v);(S>a||a>2*S)&&!h;)if(S>a)v*=2,S=Math.round(f/v),S%1!==0&&(h=!0);else if(n&&u>=0){if(v/2%1!==0)break;v/=2,S=Math.round(f/v)}else v/=2,S=Math.round(f/v);return h&&(S=o,v=f/S),{steps:S,stepValue:v,min:p,max:p+S*v}},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)}),w=(s.generateLabels=function(t,i,e,s){var o=new Array(i);return labelTemplateString&&n(o,function(i,n){o[n]=C(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(2*(1*t-i)*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(2*(1*t-i)*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=.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(2*(1*t-i)*Math.PI/e):s*Math.pow(2,-10*(t-=1))*Math.sin(2*(1*t-i)*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-w.easeOutBounce(1-t)},easeOutBounce:function(t){return(t/=1)<1/2.75?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*w.easeInBounce(2*t):.5*w.easeOutBounce(2*t-1)+.5}}),b=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)}}(),L=(s.animationLoop=function(t,i,e,s,n,o){var a=0,h=w[e]||w.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=b(l):n.apply(o)};b(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}),k=s.removeEvent=function(t,i,e){t.removeEventListener?t.removeEventListener(i,e,!1):t.detachEvent?t.detachEvent("on"+i,e):t["on"+i]=c},F=(s.bindEvents=function(t,i,e){t.events||(t.events={}),n(i,function(i){t.events[i]=function(){e.apply(t,arguments)},L(t.chart.canvas,i,t.events[i])})},s.unbindEvents=function(t,i){n(i,function(i,e){k(t.chart.canvas,e,i)})}),R=s.getMaximumWidth=function(t){var i=t.parentNode;return i.clientWidth},T=s.getMaximumHeight=function(t){var i=t.parentNode;return i.clientHeight},A=(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 P(this.animationFrame),this},resize:function(t){this.stop();var i=this.chart.canvas,e=R(this.chart.canvas),s=this.options.maintainAspectRatio?e/this.chart.aspectRatio:T(this.chart.canvas);return i.width=this.chart.width=e,i.height=this.chart.height=s,A(this.chart),"function"==typeof t&&t.apply(this,Array.prototype.slice.call(arguments,1)),this},reflow:c,render:function(t){return t&&this.reflow(),this.options.animation&&!t?s.animationLoop(this.draw,this.options.animationSteps,this.options.animationEasing,this.options.onAnimationProgress,this.options.onAnimationComplete,this):(this.draw(),this.options.onAnimationComplete.call(this)),this},generateLegend:function(){return C(this.options.legendTemplate,this)},destroy:function(){this.clear(),F(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(){var t,i,e,n,o,a=[],l=[],r=[];return s.each(this.datasets,function(i){t=i.points||i.bars||i.segments,t[h]&&t[h].hasValue()&&a.push(t[h])}),s.each(a,function(t){l.push(t.x),r.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),o=m(r),e=g(r),n=m(l),i=g(l),{x:n>this.chart.width/2?n:i,y:(o+e)/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:t[0].label,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:C(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>=this.startAngle&&e.angle<=this.endAngle,o=e.distance>=this.innerRadius&&e.distance<=this.outerRadius;return n&&o},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,this.startAngle,this.endAngle),i.arc(this.x,this.y,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.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.height=this.labels.length*this.fontSize+(this.labels.length-1)*(this.fontSize/2)+2*this.yPadding+1.5*this.titleFontSize,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.titleFontSize/2:i+(1.5*this.fontSize*e+this.fontSize/2)+1.5*this.titleFontSize},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(C(this.templateString,{value:(this.min+i*this.stepValue).toFixed(t)}));this.yLabelWidth=this.display&&this.showLabels?z(this.ctx,this.font,this.yLabels):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-this.startPoint;for(this.calculateYRange(i),this.buildYLabels(),this.calculateXLabelRotation();i>this.endPoint-this.startPoint;)i=this.endPoint-this.startPoint,t=this.yLabelWidth,this.calculateYRange(i),this.buildYLabels(),t<this.yLabelWidth&&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+10?e/2:this.yLabelWidth+10,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+8&&(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(C(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(C(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--){if(this.angleLineWidth>0){var e=this.getPointPosition(i,this.calculateCenterOffset(this.max));t.beginPath(),t.moveTo(this.xCenter,this.yCenter),t.lineTo(e.x,e.y),t.stroke(),t.closePath()}var s=this.getPointPosition(i,this.calculateCenterOffset(this.max)+5);t.font=W(this.pointLabelFontSize,this.pointLabelFontStyle,this.pointLabelFontFamily),t.fillStyle=this.pointLabelFontColor;var o=this.labels.length,a=this.labels.length/2,h=a/2,l=h>i||i>o-h,r=i===h||i===o-h;t.textAlign=0===i?"center":i===a?"center":a>i?"left":"right",t.textBaseline=r?"middle":l?"bottom":"top",t.fillText(this.labels[i],s.x,s.y)}}}}}),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(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%>"></span><%if(datasets[i].label){%><%=datasets[i].label%><%}%></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},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){var s={label:i.label||null,fillColor:i.fillColor,strokeColor:i.strokeColor,bars:[]};this.datasets.push(s),e.each(i.data,function(e,n){s.bars.push(new this.BarClass({value:e,label:t.labels[n],datasetLabel:i.label,strokeColor:i.strokeColor,fillColor:i.fillColor,highlightFill:i.highlightFill||i.fillColor,highlightStroke:i.highlightStroke||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,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}))
11
- },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%>"></span><%if(segments[i].label){%><%=segments[i].label%><%}%></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(t,i){this.addData(t,i,!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,i,e){var s=i||this.segments.length;this.segments.splice(s,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})),e||(this.reflow(),this.update())},calculateCircumference:function(t){return 2*Math.PI*(Math.abs(t)/this.total)},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%>"></span><%if(datasets[i].label){%><%=datasets[i].label%><%}%></li><%}%></ul>'};i.Type.extend({name:"Line",defaults:s,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,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,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,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.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),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%>"></span><%if(segments[i].label){%><%=segments[i].label%><%}%></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%>"></span><%if(datasets[i].label){%><%=datasets[i].label%><%}%></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,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,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,s.fill(),e.each(t.points,function(t){t.hasValue()&&t.draw()})},this)}})}.call(this);
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);
assets/js/imagify.min.js CHANGED
@@ -1,2 +1,5 @@
1
- var ImagifyGulp;ImagifyGulp=function(){function a(a){var b,c;return this.cnf=a,this.images=[],this.formatted_image_id=0,this.current_image_id=0,this.total_original_size=0,this.total_optimized_size=0,this.total_gain=0,this.total_percent=0,this.global_original_size=0,this.global_optimized_size=0,this.global_gain=0,this.global_percent=0,this.callbackEach=function(){},this.callbackBefore=function(){},this.callbackError=function(){},this.callbackDone=function(){},this.defaultThumb="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACMAAAAjCAIAAACRuyQOAAACy0lEQVRIx+1XS1PTUBTuT/MB1NGF3bhyhys3Pv+Ai8pCF6Bb3bsWq8xAh8441I2TSlKwPIKQJsI40IbSV0pJ6qe3OeZ1b9PaYViQyaJzc+757j3nO985TVx5v3o+b+IS6XyQUgtrj/NqWtJmZf3lavnpl53bC2vjRLqRUV4pxqbZcnrBx3F6G2ZzTjFg879IMwWtanV7g56K1Z2RtBGRpj7IWb0a8HhqOz9O2rjHfrOD34GvWcPEruGQkhmlcFgnF7bjABVJmvA4uj4vY2VJr545/yClw/okBywaadF/m63j1gT/sNO5DbXW8t4sLtJzSQtnAme/ys/BrU9FpdIgY2R3MBLidtQ+ZRt2T9qZvQrtf/N9X5BwbEQKmSVIFGZjEGlWNojB93KbCBolDNl49nVPAIYwUs5QGAOQwCtmuuyGG5ExGhZbtM7s+5+3BGC5nyazhB8RElSAePRwRaX1u9nScadfVYjtncV1HtKDlW0KQMqvID4kCAydHST2fgKhu24B7dTaSY4oYBf2MjN44yK9+FZmRnrdCnuhr3jyB7Vr89G8L9f7oU77VSPhp4POjNarzUgv77Z/ERh+R9oUXbqDXFyktFtJ5ag74cU9cBsCwy3DNoht5Fcf0pO8ysuTt27IFzKH/Hm/Qopi5ekP99zzgkU8goF7VN21ThfM9BKHylHEPbzoQ8wUlSGoG1QVnR3Vhppj66hCtgg/Ayr3tdLXCFQ7al4ABr2gAEBHoCbQFDu+RkCvqPVBx5LCZvq2dEDsgELuDqV7rM/SfvmocfNjkYcEdV8Kdcu4Wh6QLzzoPQKtQ9DQvQL9ZYhOiCYteXougo/9UEIv9YHxKK+iZ9qenouE8QIunCMMMzxHYIIomU2ksBOaI5ZHmCO8OavEnI0K2hjmvTnevPe3bjBlTvKvMsoMi4kVAgO/qBXMGvidGu8Me/lf4yIg/QYbLcmjDg4bKwAAAABJRU5ErkJggg==",this.images=function(){var a,d;a=this.cnf.images,d=[];for(c in a)b=a[c],d.push(c);return d}.call(this),this.total_images=this.images.length,this.total_images?this:!1}return a.prototype.run=function(){return this.loop(),this},a.prototype.toHumanSize=function(a,b,c){var d,e;return null==b&&(b=1),null==c&&(c=!0),0===a?"0"+(c===!0?"kb":""):(e=["b","kb","mb"],d=parseInt(Math.floor(Math.log(a)/Math.log(1024))),(a/Math.pow(1024,d)).toFixed(b)+e[d])},a.prototype.each=function(a){return this.callbackEach=a,this},a.prototype.before=function(a){return this.callbackBefore=a,this},a.prototype.error=function(a){return this.callbackError=a,this},a.prototype.done=function(a){return this.callbackDone=a,this},a.prototype.createThumb=function(a,b){var c,d;return d=this,c=new Image,c.onerror=function(){return b.thumbnail=d.defaultThumb,d.callbackBefore(b),d.send()},c.onload=function(){var a,e,f,g,h,i,j,k,l,m;j=33,i=33,h=c.width,g=c.height,g>h?(m=j/h,l=j,k=g*m):(m=i/g,k=i,l=h*m),a=document.createElement("canvas"),a.width=l,a.height=k,c.width=l,c.height=k,e=a.getContext("2d"),e.drawImage(this,0,0,l,k);try{b.thumbnail=a.toDataURL("image/jpeg")}catch(n){f=n,b.thumbnail=d.defaultThumb}return d.callbackBefore(b),d.send()},c.src=a},a.prototype.loop=function(){var a,b;return this.formatted_image_id=this.images[this.current_image_id].toString().substr(1),this.current_image=this.images[this.current_image_id],b=this.cnf.images[this.current_image],a=b.split("/").pop(),this.createThumb(b,{id:this.formatted_image_id,filename:a})},a.prototype.send=function(){var a,b;return a=this,b=new XMLHttpRequest,b.onreadystatechange=function(){var b,c,d,e,f,g;if(4===this.readyState){try{d=JSON.parse(this.responseText),f=!0}catch(h){c=h,e={success:!1,image:parseInt(a.formatted_image_id),progress:Math.floor((a.current_image_id+1)/a.images.length*100),error:"Unknown error occured"},f=!1}return f===!0&&(b=d.data,e={success:b.success,image:parseInt(a.formatted_image_id),progress:Math.floor((a.current_image_id+1)/a.images.length*100),global_optimized_attachments:b.global_optimized_attachments,global_unoptimized_attachments:b.global_unoptimized_attachments,global_errors_attachments:b.global_errors_attachments,global_optimized_percent:b.global_optimized_percent}),e.success!==!1?(a.total_original_size+=b.original_size,a.total_optimized_size+=b.new_size,a.total_gain+=b.original_size-b.new_size,a.total_percent=(a.total_optimized_size/a.total_original_size*100).toFixed(2),a.global_original_size+=b.original_overall_size,a.global_optimized_size+=b.new_overall_size,a.global_gain+=b.overall_saving,a.global_percent=(100-a.global_optimized_size/a.global_optimized_size*100).toFixed(2),e.original_size_human=a.toHumanSize(b.original_size),e.new_size_human=a.toHumanSize(b.new_size),e.percent=(100-b.new_size/b.original_size*100).toFixed(2),e.thumbnails=b.thumbnails,e.global_optimized_attachments_percent=b.global_optimized_attachments_percent,e.global_optimized_human=b.global_optimized_human,e.global_unconsumed_quota=b.global_unconsumed_quota,e.global_original_human=b.global_original_human,e.overall_saving=b.overall_saving,e.original_overall_size=b.original_overall_size,e.global_already_optimized_attachments=b.global_already_optimized_attachments):f===!0&&(e.error=b.error),a.callbackEach(e),a.current_image_id++,a.current_image_id>=a.images.length?(g=0===a.global_original_size?0:(100-100*(a.global_optimized_size/a.global_original_size)).toFixed(2),a.callbackDone({global_original_size_human:a.toHumanSize(a.global_original_size),global_gain_human:a.toHumanSize(a.global_gain),global_percent:g})):a.loop()}},b.open("POST",this.cnf.lib,!0),b.setRequestHeader("Content-Type","application/x-www-form-urlencoded"),b.send("image="+a.formatted_image_id),this},a}();
2
- //# sourceMappingURL=imagify.min.js.map
 
 
 
1
+ /*
2
+ * imagify-gulpjs - version 0.0.1 - 2016-03-22
3
+ * WP Media <contact@wp-media.me>
4
+ */
5
+ "use strict";function _classCallCheck(a,b){if(!(a instanceof b))throw new TypeError("Cannot call a class as a function")}var _createClass=function(){function a(a,b){for(var c=0;c<b.length;c++){var d=b[c];d.enumerable=d.enumerable||!1,d.configurable=!0,"value"in d&&(d.writable=!0),Object.defineProperty(a,d.key,d)}}return function(b,c,d){return c&&a(b.prototype,c),d&&a(b,d),b}}(),ImagifyGulp=function(){function a(b){_classCallCheck(this,a),this.buffer_size=1,this.lib_url=b.lib,this.default_thumb="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACMAAAAjCAIAAACRuyQOAAACy0lEQVRIx+1XS1PTUBTuT/MB1NGF3bhyhys3Pv+Ai8pCF6Bb3bsWq8xAh8441I2TSlKwPIKQJsI40IbSV0pJ6qe3OeZ1b9PaYViQyaJzc+757j3nO985TVx5v3o+b+IS6XyQUgtrj/NqWtJmZf3lavnpl53bC2vjRLqRUV4pxqbZcnrBx3F6G2ZzTjFg879IMwWtanV7g56K1Z2RtBGRpj7IWb0a8HhqOz9O2rjHfrOD34GvWcPEruGQkhmlcFgnF7bjABVJmvA4uj4vY2VJr545/yClw/okBywaadF/m63j1gT/sNO5DbXW8t4sLtJzSQtnAme/ys/BrU9FpdIgY2R3MBLidtQ+ZRt2T9qZvQrtf/N9X5BwbEQKmSVIFGZjEGlWNojB93KbCBolDNl49nVPAIYwUs5QGAOQwCtmuuyGG5ExGhZbtM7s+5+3BGC5nyazhB8RElSAePRwRaX1u9nScadfVYjtncV1HtKDlW0KQMqvID4kCAydHST2fgKhu24B7dTaSY4oYBf2MjN44yK9+FZmRnrdCnuhr3jyB7Vr89G8L9f7oU77VSPhp4POjNarzUgv77Z/ERh+R9oUXbqDXFyktFtJ5ag74cU9cBsCwy3DNoht5Fcf0pO8ysuTt27IFzKH/Hm/Qopi5ekP99zzgkU8goF7VN21ThfM9BKHylHEPbzoQ8wUlSGoG1QVnR3Vhppj66hCtgg/Ayr3tdLXCFQ7al4ABr2gAEBHoCbQFDu+RkCvqPVBx5LCZvq2dEDsgELuDqV7rM/SfvmocfNjkYcEdV8Kdcu4Wh6QLzzoPQKtQ9DQvQL9ZYhOiCYteXougo/9UEIv9YHxKK+iZ9qenouE8QIunCMMMzxHYIIomU2ksBOaI5ZHmCO8OavEnI0K2hjmvTnevPe3bjBlTvKvMsoMi4kVAgO/qBXMGvidGu8Me/lf4yIg/QYbLcmjDg4bKwAAAABJRU5ErkJggg==",this.images=b.images,this.images_ids=Object.keys(b.images),this.total_images=this.images_ids.length,this.processed_images=0,this.inprocess_images=0,this._before=new Function,this._each=new Function,this._done=new Function,this._error=new Function,this.total_original_size=0,this.total_optimized_size=0,this.total_gain=0,this.total_percent=0,this.global_original_size=0,this.global_optimized_size=0,this.global_gain=0,this.global_percent=0}return _createClass(a,[{key:"before",value:function(a){return this._before=a,this}},{key:"each",value:function(a){return this._each=a,this}},{key:"done",value:function(a){return this._done=a,this}},{key:"error",value:function(a){return this._error=a,this}},{key:"humanSize",value:function(a){if(0==a)return"0kb";var b=["b","kb","mb"],c=parseInt(Math.floor(Math.log(a)/Math.log(1024)));return(a/Math.pow(1024,c)).toFixed(2)+b[c]}},{key:"run",value:function(){for(var a=this.images_ids.length>this.buffer_size?this.buffer_size:this.images_ids.length,b=0;a>b;b++){var c=this.images_ids.shift();this.process(c)}return this}},{key:"process",value:function(a){this.inprocess_images++;var b={id:a,image_id:parseInt(a.toString().substr(1)),image_src:this.images[a],filename:this.images[a].split("/").pop(),thumbnail:this.default_thumb,error:""};this.createThumb(b)}},{key:"createThumb",value:function(a){var b=this,c=new Image;c.onerror=function(){var c=a;c.id=a.image_id,b._before(c),b.send(a)},c.onload=function(){var d=33,e=33,f=c.width,g=c.height,h=1,i=0,j=0,k=null,l=null;g>f?(h=d/f,j=d,i=g*h):(h=e/g,i=e,j=f*h),k=document.createElement("canvas"),k.width=j,k.height=i,c.width=j,c.height=i,l=k.getContext("2d"),l.drawImage(this,0,0,j,i);try{a.thumbnail=k.toDataURL("image/jpeg")}catch(m){a.thumbnail=b.default_thumb}var n=a;n.id=a.image_id,b._before(n),b.send(a),k=null},c.src=a.image_src}},{key:"send",value:function(a){var b=this,c=new XMLHttpRequest,d=!1,e={},f={filename:a.filename,image:a.image_id,error:""};c.onreadystatechange=function(){if(4===this.readyState){b.processed_images++;try{e=JSON.parse(this.responseText),d=!1}catch(a){f.success=!1,f.error="Unknown error occured",d=!0}if(f.progress=Math.floor(b.processed_images/b.total_images*100),!d){var c=e.data;f.success=e.success,e.success===!0?(b.total_original_size+=c.original_size,b.total_optimized_size+=c.new_size,b.total_gain+=c.original_size-c.new_size,b.total_percent=(b.total_optimized_size/b.total_original_size*100).toFixed(2),b.global_original_size+=c.original_overall_size,b.global_optimized_size+=c.new_overall_size,b.global_gain+=c.overall_saving,b.global_percent=(100-b.global_optimized_size/b.global_optimized_size*100).toFixed(2),f.original_size=c.original_size,f.original_size_human=b.humanSize(c.original_size),f.new_size=c.new_size,f.new_size_human=b.humanSize(c.new_size),f.percent=c.percent,f.thumbnails=c.thumbnails,f.overall_saving=c.overall_saving,f.overall_saving_human=b.humanSize(c.overall_saving),f.original_overall_size=c.original_overall_size,f.original_overall_size_human=b.humanSize(c.original_overall_size)):f.error=c.error}if(b._each(f),b.inprocess_images<b.total_images&&b.process(b.images_ids.shift()),b.processed_images==b.total_images){var g=0;0!=b.global_original_size&&(g=(100-100*(b.global_optimized_size/b.global_original_size)).toFixed(2)),b._done({global_original_size_human:b.humanSize(b.global_original_size),global_gain_human:b.humanSize(b.global_gain),global_percent:g})}}},c.open("POST",this.lib_url,!0),c.setRequestHeader("Content-Type","application/x-www-form-urlencoded"),c.send("image="+a.image_id)}}]),a}();
assets/js/jquery.twentytwenty.js CHANGED
@@ -262,7 +262,7 @@
262
 
263
  if ( ! $tt.closest('.imagify-modal-content').hasClass('loaded') ) {
264
  $tt.closest('.imagify-modal-content').removeClass('loading').addClass('loaded');
265
- //draw_me_a_chart( $modal.find('.imagify-level-optimized').find('.imagify-chart').find('canvas') );
266
  }
267
 
268
  // check if image height is to big
262
 
263
  if ( ! $tt.closest('.imagify-modal-content').hasClass('loaded') ) {
264
  $tt.closest('.imagify-modal-content').removeClass('loading').addClass('loaded');
265
+ draw_me_a_chart( $modal.find('.imagify-level-optimized').find('.imagify-chart').find('canvas') );
266
  }
267
 
268
  // check if image height is to big
assets/js/jquery.twentytwenty.min.js CHANGED
@@ -1,28 +1,28 @@
1
- (function(a,n,q){n.fn.twentytwenty=function(k,x){k=n.extend({handlePosition:.5,orientation:"horizontal",labelBefore:"Before",labelAfter:"After"},k);return this.each(function(){var f=k.handlePosition,c=n(this),d=k.orientation,p="vertical"===d?"down":"left",t="vertical"===d?"up":"right",l=c.find("img:first"),q=c.find("img:last");c.wrap('<div class="twentytwenty-wrapper twentytwenty-'+d+'"></div>');c.append('<div class="twentytwenty-overlay"></div>');c.append('<div class="twentytwenty-handle"></div>');
2
  var h=c.find(".twentytwenty-handle");h.append('<span class="twentytwenty-'+p+'-arrow"></span>');h.append('<span class="twentytwenty-'+t+'-arrow"></span>');c.addClass("twentytwenty-container");l.addClass("twentytwenty-before");q.addClass("twentytwenty-after");p=c.find(".twentytwenty-overlay");p.append('<div class="twentytwenty-labels twentytwenty-before-label"><span class="twentytwenty-label-content">'+k.labelBefore+"</span></div>");p.append('<div class="twentytwenty-labels twentytwenty-after-label"><span class="twentytwenty-label-content">'+
3
- k.labelAfter+"</span></div>");var v=function(a){var b,A,g;g=l.width();var y=l.height();b=g+"px";A=y+"px";g=a*g+"px";a=a*y+"px";h.css("vertical"===d?"top":"left","vertical"===d?a:g);y=c.find(".twentytwenty-before");"vertical"===d?y.css("clip","rect(0,"+b+","+a+",0)"):y.css("clip","rect(0,"+g+","+A+",0)");c.css("height",A);"function"===typeof x&&x()},w=0,u=0,r=0,b=0;n(a).on("resize.twentytwenty",function(a){v(f)});h.on("movestart",function(a){(a.distX>a.distY&&a.distX<-a.distY||a.distX<a.distY&&a.distX>
4
- -a.distY)&&"vertical"!==d?a.preventDefault():(a.distX<a.distY&&a.distX<-a.distY||a.distX>a.distY&&a.distX>-a.distY)&&"vertical"===d&&a.preventDefault();c.addClass("active");w=c.offset().left;u=c.offset().top;r=l.width();b=l.height()});h.on("moveend",function(a){c.removeClass("active")});h.on("move",function(a){c.hasClass("active")&&(f="vertical"===d?(a.pageY-u)/b:(a.pageX-w)/r,0>f&&(f=0),1<f&&(f=1),v(f))});c.find("img").on("mousedown",function(a){a.preventDefault()});n(a).trigger("resize.twentytwenty")})}})(window,
5
  jQuery);
6
- (function(a,n,q,k){var x=function(b){b.each(function(){var b=parseInt(a(this).closest(".imagify-chart").next(".imagify-chart-value").text()),b=[{value:b,color:"#00B3D3"},{value:100-b,color:"#D8D8D8"}];(new Chart(a(this)[0].getContext("2d"))).Doughnut(b,{segmentStrokeColor:"#2A2E3C",segmentStrokeWidth:1,animateRotate:!0,percentageInnerCutout:60,tooltipEvents:[]})})},f=function(b){b=b.data("target")||b.attr("href");a(b).css("display","flex").hide().fadeIn(400).attr("aria-hidden","false").attr("tabindex","0").focus().removeAttr("tabindex").addClass("modal-is-open");
7
  a("body").addClass("imagify-modal-is-open")},c=function(b){var c={width:0,height:0,original_url:"",optimized_url:"",original_size:0,optimized_size:0,saving:0,modal_append_to:a("body"),trigger:a('[data-target="imagify-visual-comparison"]'),modal_id:"imagify-visual-comparison",open_modal:!1},e=a.extend({},c,b);if(0===e.width||0===e.height||""===e.original_url||""===e.optimized_url||0===e.original_size||0===e.optimized_size||0===e.saving)return"error";e.modal_append_to.append('<div id="'+e.modal_id+
8
  '" class="imagify-modal imagify-visual-comparison" aria-hidden="true"><div class="imagify-modal-content loading"><div class="twentytwenty-container"><img class="imagify-img-before" alt="" width="'+e.width+'" height="'+e.height+'"><img class="imagify-img-after" alt="" width="'+e.width+'" height="'+e.height+'"></div><div class="imagify-comparison-levels"><div class="imagify-c-level imagify-level-original go-left"><p class="imagify-c-level-row"><span class="label">'+imagifyTTT.labels.filesize+'</span><span class="value level">'+
9
  e.original_size+'</span></p></div><div class="imagify-c-level imagify-level-optimized go-right"><p class="imagify-c-level-row"><span class="label">'+imagifyTTT.labels.filesize+'</span><span class="value level">'+e.optimized_size+'</span></p><p class="imagify-c-level-row"><span class="label">'+imagifyTTT.labels.saving+'</span><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">'+
10
  e.saving+'</span>%</span></p></div></div><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></div></div>");e.trigger.on("click.imagify",function(){var b=a(a(this).data("target")),c=0;"function"===typeof f&&e.open_modal&&f(a(this));b.find(".imagify-modal-content").css({width:.85*a(n).outerWidth()+"px","max-width":e.width});b.find(".imagify-img-before").on("load",function(){c++}).attr("src",
11
  e.original_url);b.find(".imagify-img-after").on("load",function(){c++}).attr("src",e.optimized_url);var m=b.find(".twentytwenty-container"),d=setInterval(function(){if(2===c)return m.twentytwenty({handlePosition:.3,orientation:"horizontal",labelBefore:imagifyTTT.labels.original_l,labelAfter:imagifyTTT.labels.optimized_l},function(){var e=a(n).height(),c=b.find(".twentytwenty-container").height(),d=b.find(".twentytwenty-wrapper").position().top;m.closest(".imagify-modal-content").hasClass("loaded")||
12
- m.closest(".imagify-modal-content").removeClass("loading").addClass("loaded");if(e<c&&!b.hasClass("modal-is-too-high")){b.addClass("modal-is-too-high");var g=b.find(".twentytwenty-handle"),f=b.find(".twentytwenty-label-content"),h=b.find(".imagify-comparison-levels"),c=h.outerHeight(),k=(e-d-g.height())/2,l=e-3*d-c;g.css({top:k});f.css({top:l,bottom:"auto"});b.find(".twentytwenty-wrapper").css({paddingBottom:c});b.find(".imagify-modal-content").on("scroll.imagify",function(){g.css({top:k+a(this).scrollTop()});
13
- f.css({top:l+a(this).scrollTop()});h.css({bottom:-a(this).scrollTop()})})}}),clearInterval(d),d=null,"done"},75);return!1})};a(".imagify-visual-comparison-btn").on("click",function(){if(1!==a(".twentytwenty-wrapper").length&&(a(a(this).data("target")).find(".imagify-modal-content").css("width",.95*a(n).outerWidth()+"px"),0<a(".twentytwenty-container").length&&800<a(n).outerWidth())){var b=a(".twentytwenty-container"),c=0,e=b.data("loader"),d=b.data("label-original"),g=b.data("label-normal"),f=b.data("label-aggressive"),
14
- h=b.data("label-ultra"),k=b.data("original-label").replace(/\*\*/,"<strong>").replace(/\*\*/,"</strong>"),l=b.data("original-alt"),q=b.data("original-img"),p=b.data("original-dim").split("x");b.data("normal-label").replace(/\*\*/,"<strong>").replace(/\*\*/,"</strong>");var t=b.data("normal-alt"),u=b.data("normal-img"),r=b.data("normal-dim").split("x");b.data("aggressive-label").replace(/\*\*/,"<strong>").replace(/\*\*/,"</strong>");var v=b.data("aggressive-alt"),w=b.data("aggressive-img"),B=b.data("aggressive-dim").split("x"),
15
- z=b.data("ultra-label").replace(/\*\*/,"<strong>").replace(/\*\*/,"</strong>"),E=b.data("ultra-alt"),F=b.data("ultra-img"),C=b.data("ultra-dim").split("x"),d='<span class="twentytwenty-duo-buttons twentytwenty-duo-left"><button type="button" class="imagify-comparison-original selected" data-img="original">'+d+'</button><button type="button" class="imagify-comparison-normal" data-img="normal">'+g+'</button><button type="button" class="imagify-comparison-aggressive" data-img="aggressive">'+f+"</button></span>",
16
- g='<span class="twentytwenty-duo-buttons twentytwenty-duo-right"><button type="button" class="imagify-comparison-normal" data-img="normal">'+g+'</button><button type="button" class="imagify-comparison-aggressive" data-img="aggressive">'+f+'</button><button type="button" class="imagify-comparison-ultra selected" data-img="ultra">'+h+"</button></span>";b.before('<img class="loader" src="'+e+'" alt="Loading\u2026" width="64" height="64">');e=a(".twentytwenty-left-buttons").lenght?d+g:"";a(".twentytwenty-left-buttons").append(d);
17
- a(".twentytwenty-right-buttons").append(g);b.closest(".imagify-modal-content").addClass("loading").find(".twentytwenty-container").append('<img class="img-original" alt="'+l+'" width="'+p[0]+'" height="'+p[1]+'"><img class="img-normal" alt="'+t+'" width="'+r[0]+'" height="'+r[1]+'"><img class="img-aggressive" alt="'+v+'" width="'+B[0]+'" height="'+B[1]+'"><img class="img-ultra" alt="'+E+'" width="'+C[0]+'" height="'+C[1]+'">'+e);a(".img-original").on("load",function(){c++}).attr("src",q);a(".img-normal").on("load",
18
- function(){c++}).attr("src",u);a(".img-aggressive").on("load",function(){c++}).attr("src",w);a(".img-ultra").on("load",function(){c++}).attr("src",F);var D=setInterval(function(){4===c&&(b.twentytwenty({handlePosition:.6,orientation:"horizontal",labelBefore:k,labelAfter:z},function(){b.closest(".imagify-modal-content").hasClass("loaded")||(b.closest(".imagify-modal-content").removeClass("loading").addClass("loaded"),x(a(".imagify-level-ultra").find(".imagify-chart").find("canvas")))}),clearInterval(D),
19
- D=null)},75);a(".imagify-comparison-title").on("click",".twentytwenty-duo-buttons button:not(.selected)",function(b){b.stopPropagation();var c=a(this);b=c.closest(".imagify-comparison-title").nextAll(".twentytwenty-wrapper").find(".twentytwenty-container");var e=c.closest(".twentytwenty-duo-buttons").hasClass("twentytwenty-duo-left")?"left":"right",d="left"===e?c.closest(".imagify-comparison-title").find(".twentytwenty-duo-right"):c.closest(".imagify-comparison-title").find(".twentytwenty-duo-left"),
20
  g=c.closest(".twentytwenty-duo-buttons").find("button"),f=b.find(".twentytwenty-before"),h=b.find(".twentytwenty-after"),m=c.data("img");g.removeClass("selected");c.addClass("selected");d.find(".selected").data("img")===m&&d.find("button:not(.selected)").eq(0).trigger("click");"left"===e&&(c=f.css("clip"),f.attr("style",""),f.removeClass("twentytwenty-before"),b.find(".img-"+m).addClass("twentytwenty-before").css("clip",c),a(".twentytwenty-before-label").find(".twentytwenty-label-content").text(b.data(m+
21
  "-label")),a(".imagify-c-level.go-left").attr("aria-hidden","true").removeClass("go-left go-right"),a(".imagify-level-"+m).attr("aria-hidden","false").addClass("go-left"));"right"===e&&(h.removeClass("twentytwenty-after"),b.find(".img-"+m).addClass("twentytwenty-after"),a(".twentytwenty-after-label").find(".twentytwenty-label-content").text(b.data(m+"-label")),a(".imagify-c-level.go-right").attr("aria-hidden","true").removeClass("go-left go-right"),a(".imagify-level-"+m).attr("aria-hidden","false").addClass("go-right"));
22
- x(a(".imagify-level-"+m).find(".imagify-chart").find("canvas"));return!1})}});if(0<a(".post-php").find(".wp_attachment_image").find(".thumbnail").length){q=a(".post-php").find(".wp_attachment_image");var d=q.find(".thumbnail"),p=d.prop("src"),t=d.width(),d=d.height(),l=a("#imagify-full-original").val(),z=a("#imagify-full-original-size").val(),h=a("#misc-publishing-actions").find(".misc-pub-imagify").find(".button-primary");if(360<t&&0<a("#imagify-full-original").length&&""!==a("#imagify-full-original").val()){var h=
23
- a(".misc-pub-filesize").find("strong").text(),v=a(".imagify-data-item").find(".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>");c({width:t,height:d,original_url:l,optimized_url:p,original_size:z,optimized_size:h,saving:v,modal_append_to:q,trigger:a("#imagify-start-comparison"),modal_id:"imagify-visual-comparison"})}else 360>
24
  t&&0<a("#imagify-full-original").length&&""!==a("#imagify-full-original").val()||0<a("#imagify-full-original").length&&""===a("#imagify-full-original").val()||(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="'+h.attr("href")+'">'+imagifyTTT.labels.optimize+"</a>"),a("#imagify-optimize-trigger").on("click",function(){a(this).prev(".spinner").removeClass("imagify-hidden").addClass("is-active")}))}0<
25
  a(".upload-php").find(".imagify-compare-images").length&&a(".imagify-compare-images").each(function(){var b=a(this),d=b.data("id"),e=b.closest("#post-"+d).find(".column-imagify_optimized_file");c({width:b.data("full-width"),height:b.data("full-height"),original_url:b.data("backup-src"),optimized_url:b.data("full-src"),original_size:e.find(".original").text(),optimized_size:e.find(".imagify-data-item").find(".big").text(),saving:e.find(".imagify-chart-value").text(),modal_append_to:b.closest(".column-primary"),
26
- trigger:b,modal_id:"imagify-comparison-"+d})});if(0<a(".upload-php").length)var w=function(a){var c={};n.location.href.replace(/[?&]+([^=&]+)=?([^&]*)?/gi,function(a,b,d){c[b]=d!==k?d:""});return a?c[a]?c[a]:null:c},u=function(){var b=setInterval(function(){if(a(".media-modal").find(".imagify-datas-details").length){if(0<a("#imagify-original-src").length&&""!==a("#imagify-original-src")){a(".media-frame-content").find(".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">'+
27
  imagifyTTT.labels.compare+"</button>");var d=a(".media-frame-content").find(".compat-field-imagify");c({width:a("#imagify-full-width").val(),height:a("#imagify-full-height").val(),original_url:a("#imagify-original-src").val(),optimized_url:a("#imagify-full-src").val(),original_size:a("#imagify-original-size").val(),optimized_size:d.find(".imagify-data-item").find(".big").text(),saving:d.find(".imagify-chart-value").text(),modal_append_to:a(".media-frame-content").find(".thumbnail-image"),trigger:a("#imagify-media-frame-comparison-btn"),
28
- modal_id:"imagify-comparison-modal",open_modal:!0})}clearInterval(b);b=null}},20)},r=setInterval(function(){0<a(".upload-php").find(".media-frame.mode-grid").find(".attachments").length&&(a(".upload-php").find(".media-frame.mode-grid").on("click",".attachment",function(){u()}),w("item")&&u(),clearInterval(r),r=null)},100)})(jQuery,window,document);
1
+ (function(a,n,q){n.fn.twentytwenty=function(k,v){k=n.extend({handlePosition:.5,orientation:"horizontal",labelBefore:"Before",labelAfter:"After"},k);return this.each(function(){var f=k.handlePosition,c=n(this),d=k.orientation,p="vertical"===d?"down":"left",t="vertical"===d?"up":"right",l=c.find("img:first"),q=c.find("img:last");c.wrap('<div class="twentytwenty-wrapper twentytwenty-'+d+'"></div>');c.append('<div class="twentytwenty-overlay"></div>');c.append('<div class="twentytwenty-handle"></div>');
2
  var h=c.find(".twentytwenty-handle");h.append('<span class="twentytwenty-'+p+'-arrow"></span>');h.append('<span class="twentytwenty-'+t+'-arrow"></span>');c.addClass("twentytwenty-container");l.addClass("twentytwenty-before");q.addClass("twentytwenty-after");p=c.find(".twentytwenty-overlay");p.append('<div class="twentytwenty-labels twentytwenty-before-label"><span class="twentytwenty-label-content">'+k.labelBefore+"</span></div>");p.append('<div class="twentytwenty-labels twentytwenty-after-label"><span class="twentytwenty-label-content">'+
3
+ k.labelAfter+"</span></div>");var w=function(a){var b,A,g;g=l.width();var y=l.height();b=g+"px";A=y+"px";g=a*g+"px";a=a*y+"px";h.css("vertical"===d?"top":"left","vertical"===d?a:g);y=c.find(".twentytwenty-before");"vertical"===d?y.css("clip","rect(0,"+b+","+a+",0)"):y.css("clip","rect(0,"+g+","+A+",0)");c.css("height",A);"function"===typeof v&&v()},x=0,u=0,r=0,b=0;n(a).on("resize.twentytwenty",function(a){w(f)});h.on("movestart",function(a){(a.distX>a.distY&&a.distX<-a.distY||a.distX<a.distY&&a.distX>
4
+ -a.distY)&&"vertical"!==d?a.preventDefault():(a.distX<a.distY&&a.distX<-a.distY||a.distX>a.distY&&a.distX>-a.distY)&&"vertical"===d&&a.preventDefault();c.addClass("active");x=c.offset().left;u=c.offset().top;r=l.width();b=l.height()});h.on("moveend",function(a){c.removeClass("active")});h.on("move",function(a){c.hasClass("active")&&(f="vertical"===d?(a.pageY-u)/b:(a.pageX-x)/r,0>f&&(f=0),1<f&&(f=1),w(f))});c.find("img").on("mousedown",function(a){a.preventDefault()});n(a).trigger("resize.twentytwenty")})}})(window,
5
  jQuery);
6
+ (function(a,n,q,k){var v=function(b){b.each(function(){var b=parseInt(a(this).closest(".imagify-chart").next(".imagify-chart-value").text()),b=[{value:b,color:"#00B3D3"},{value:100-b,color:"#D8D8D8"}];(new Chart(a(this)[0].getContext("2d"))).Doughnut(b,{segmentStrokeColor:"#2A2E3C",segmentStrokeWidth:1,animateRotate:!0,percentageInnerCutout:60,tooltipEvents:[]})})},f=function(b){b=b.data("target")||b.attr("href");a(b).css("display","flex").hide().fadeIn(400).attr("aria-hidden","false").attr("tabindex","0").focus().removeAttr("tabindex").addClass("modal-is-open");
7
  a("body").addClass("imagify-modal-is-open")},c=function(b){var c={width:0,height:0,original_url:"",optimized_url:"",original_size:0,optimized_size:0,saving:0,modal_append_to:a("body"),trigger:a('[data-target="imagify-visual-comparison"]'),modal_id:"imagify-visual-comparison",open_modal:!1},e=a.extend({},c,b);if(0===e.width||0===e.height||""===e.original_url||""===e.optimized_url||0===e.original_size||0===e.optimized_size||0===e.saving)return"error";e.modal_append_to.append('<div id="'+e.modal_id+
8
  '" class="imagify-modal imagify-visual-comparison" aria-hidden="true"><div class="imagify-modal-content loading"><div class="twentytwenty-container"><img class="imagify-img-before" alt="" width="'+e.width+'" height="'+e.height+'"><img class="imagify-img-after" alt="" width="'+e.width+'" height="'+e.height+'"></div><div class="imagify-comparison-levels"><div class="imagify-c-level imagify-level-original go-left"><p class="imagify-c-level-row"><span class="label">'+imagifyTTT.labels.filesize+'</span><span class="value level">'+
9
  e.original_size+'</span></p></div><div class="imagify-c-level imagify-level-optimized go-right"><p class="imagify-c-level-row"><span class="label">'+imagifyTTT.labels.filesize+'</span><span class="value level">'+e.optimized_size+'</span></p><p class="imagify-c-level-row"><span class="label">'+imagifyTTT.labels.saving+'</span><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">'+
10
  e.saving+'</span>%</span></p></div></div><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></div></div>");e.trigger.on("click.imagify",function(){var b=a(a(this).data("target")),c=0;"function"===typeof f&&e.open_modal&&f(a(this));b.find(".imagify-modal-content").css({width:.85*a(n).outerWidth()+"px","max-width":e.width});b.find(".imagify-img-before").on("load",function(){c++}).attr("src",
11
  e.original_url);b.find(".imagify-img-after").on("load",function(){c++}).attr("src",e.optimized_url);var m=b.find(".twentytwenty-container"),d=setInterval(function(){if(2===c)return m.twentytwenty({handlePosition:.3,orientation:"horizontal",labelBefore:imagifyTTT.labels.original_l,labelAfter:imagifyTTT.labels.optimized_l},function(){var e=a(n).height(),c=b.find(".twentytwenty-container").height(),d=b.find(".twentytwenty-wrapper").position().top;m.closest(".imagify-modal-content").hasClass("loaded")||
12
+ (m.closest(".imagify-modal-content").removeClass("loading").addClass("loaded"),v(b.find(".imagify-level-optimized").find(".imagify-chart").find("canvas")));if(e<c&&!b.hasClass("modal-is-too-high")){b.addClass("modal-is-too-high");var g=b.find(".twentytwenty-handle"),f=b.find(".twentytwenty-label-content"),h=b.find(".imagify-comparison-levels"),c=h.outerHeight(),k=(e-d-g.height())/2,l=e-3*d-c;g.css({top:k});f.css({top:l,bottom:"auto"});b.find(".twentytwenty-wrapper").css({paddingBottom:c});b.find(".imagify-modal-content").on("scroll.imagify",
13
+ function(){g.css({top:k+a(this).scrollTop()});f.css({top:l+a(this).scrollTop()});h.css({bottom:-a(this).scrollTop()})})}}),clearInterval(d),d=null,"done"},75);return!1})};a(".imagify-visual-comparison-btn").on("click",function(){if(1!==a(".twentytwenty-wrapper").length&&(a(a(this).data("target")).find(".imagify-modal-content").css("width",.95*a(n).outerWidth()+"px"),0<a(".twentytwenty-container").length&&800<a(n).outerWidth())){var b=a(".twentytwenty-container"),c=0,e=b.data("loader"),d=b.data("label-original"),
14
+ g=b.data("label-normal"),f=b.data("label-aggressive"),h=b.data("label-ultra"),k=b.data("original-label").replace(/\*\*/,"<strong>").replace(/\*\*/,"</strong>"),l=b.data("original-alt"),q=b.data("original-img"),p=b.data("original-dim").split("x");b.data("normal-label").replace(/\*\*/,"<strong>").replace(/\*\*/,"</strong>");var t=b.data("normal-alt"),u=b.data("normal-img"),r=b.data("normal-dim").split("x");b.data("aggressive-label").replace(/\*\*/,"<strong>").replace(/\*\*/,"</strong>");var w=b.data("aggressive-alt"),
15
+ x=b.data("aggressive-img"),B=b.data("aggressive-dim").split("x"),z=b.data("ultra-label").replace(/\*\*/,"<strong>").replace(/\*\*/,"</strong>"),E=b.data("ultra-alt"),F=b.data("ultra-img"),C=b.data("ultra-dim").split("x"),d='<span class="twentytwenty-duo-buttons twentytwenty-duo-left"><button type="button" class="imagify-comparison-original selected" data-img="original">'+d+'</button><button type="button" class="imagify-comparison-normal" data-img="normal">'+g+'</button><button type="button" class="imagify-comparison-aggressive" data-img="aggressive">'+
16
+ f+"</button></span>",g='<span class="twentytwenty-duo-buttons twentytwenty-duo-right"><button type="button" class="imagify-comparison-normal" data-img="normal">'+g+'</button><button type="button" class="imagify-comparison-aggressive" data-img="aggressive">'+f+'</button><button type="button" class="imagify-comparison-ultra selected" data-img="ultra">'+h+"</button></span>";b.before('<img class="loader" src="'+e+'" alt="Loading\u2026" width="64" height="64">');e=a(".twentytwenty-left-buttons").lenght?
17
+ d+g:"";a(".twentytwenty-left-buttons").append(d);a(".twentytwenty-right-buttons").append(g);b.closest(".imagify-modal-content").addClass("loading").find(".twentytwenty-container").append('<img class="img-original" alt="'+l+'" width="'+p[0]+'" height="'+p[1]+'"><img class="img-normal" alt="'+t+'" width="'+r[0]+'" height="'+r[1]+'"><img class="img-aggressive" alt="'+w+'" width="'+B[0]+'" height="'+B[1]+'"><img class="img-ultra" alt="'+E+'" width="'+C[0]+'" height="'+C[1]+'">'+e);a(".img-original").on("load",
18
+ function(){c++}).attr("src",q);a(".img-normal").on("load",function(){c++}).attr("src",u);a(".img-aggressive").on("load",function(){c++}).attr("src",x);a(".img-ultra").on("load",function(){c++}).attr("src",F);var D=setInterval(function(){4===c&&(b.twentytwenty({handlePosition:.6,orientation:"horizontal",labelBefore:k,labelAfter:z},function(){b.closest(".imagify-modal-content").hasClass("loaded")||(b.closest(".imagify-modal-content").removeClass("loading").addClass("loaded"),v(a(".imagify-level-ultra").find(".imagify-chart").find("canvas")))}),
19
+ clearInterval(D),D=null)},75);a(".imagify-comparison-title").on("click",".twentytwenty-duo-buttons button:not(.selected)",function(b){b.stopPropagation();var c=a(this);b=c.closest(".imagify-comparison-title").nextAll(".twentytwenty-wrapper").find(".twentytwenty-container");var e=c.closest(".twentytwenty-duo-buttons").hasClass("twentytwenty-duo-left")?"left":"right",d="left"===e?c.closest(".imagify-comparison-title").find(".twentytwenty-duo-right"):c.closest(".imagify-comparison-title").find(".twentytwenty-duo-left"),
20
  g=c.closest(".twentytwenty-duo-buttons").find("button"),f=b.find(".twentytwenty-before"),h=b.find(".twentytwenty-after"),m=c.data("img");g.removeClass("selected");c.addClass("selected");d.find(".selected").data("img")===m&&d.find("button:not(.selected)").eq(0).trigger("click");"left"===e&&(c=f.css("clip"),f.attr("style",""),f.removeClass("twentytwenty-before"),b.find(".img-"+m).addClass("twentytwenty-before").css("clip",c),a(".twentytwenty-before-label").find(".twentytwenty-label-content").text(b.data(m+
21
  "-label")),a(".imagify-c-level.go-left").attr("aria-hidden","true").removeClass("go-left go-right"),a(".imagify-level-"+m).attr("aria-hidden","false").addClass("go-left"));"right"===e&&(h.removeClass("twentytwenty-after"),b.find(".img-"+m).addClass("twentytwenty-after"),a(".twentytwenty-after-label").find(".twentytwenty-label-content").text(b.data(m+"-label")),a(".imagify-c-level.go-right").attr("aria-hidden","true").removeClass("go-left go-right"),a(".imagify-level-"+m).attr("aria-hidden","false").addClass("go-right"));
22
+ v(a(".imagify-level-"+m).find(".imagify-chart").find("canvas"));return!1})}});if(0<a(".post-php").find(".wp_attachment_image").find(".thumbnail").length){q=a(".post-php").find(".wp_attachment_image");var d=q.find(".thumbnail"),p=d.prop("src"),t=d.width(),d=d.height(),l=a("#imagify-full-original").val(),z=a("#imagify-full-original-size").val(),h=a("#misc-publishing-actions").find(".misc-pub-imagify").find(".button-primary");if(360<t&&0<a("#imagify-full-original").length&&""!==a("#imagify-full-original").val()){var h=
23
+ a(".misc-pub-filesize").find("strong").text(),w=a(".imagify-data-item").find(".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>");c({width:t,height:d,original_url:l,optimized_url:p,original_size:z,optimized_size:h,saving:w,modal_append_to:q,trigger:a("#imagify-start-comparison"),modal_id:"imagify-visual-comparison"})}else 360>
24
  t&&0<a("#imagify-full-original").length&&""!==a("#imagify-full-original").val()||0<a("#imagify-full-original").length&&""===a("#imagify-full-original").val()||(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="'+h.attr("href")+'">'+imagifyTTT.labels.optimize+"</a>"),a("#imagify-optimize-trigger").on("click",function(){a(this).prev(".spinner").removeClass("imagify-hidden").addClass("is-active")}))}0<
25
  a(".upload-php").find(".imagify-compare-images").length&&a(".imagify-compare-images").each(function(){var b=a(this),d=b.data("id"),e=b.closest("#post-"+d).find(".column-imagify_optimized_file");c({width:b.data("full-width"),height:b.data("full-height"),original_url:b.data("backup-src"),optimized_url:b.data("full-src"),original_size:e.find(".original").text(),optimized_size:e.find(".imagify-data-item").find(".big").text(),saving:e.find(".imagify-chart-value").text(),modal_append_to:b.closest(".column-primary"),
26
+ trigger:b,modal_id:"imagify-comparison-"+d})});if(0<a(".upload-php").length)var x=function(a){var c={};n.location.href.replace(/[?&]+([^=&]+)=?([^&]*)?/gi,function(a,b,d){c[b]=d!==k?d:""});return a?c[a]?c[a]:null:c},u=function(){var b=setInterval(function(){if(a(".media-modal").find(".imagify-datas-details").length){if(0<a("#imagify-original-src").length&&""!==a("#imagify-original-src")){a(".media-frame-content").find(".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">'+
27
  imagifyTTT.labels.compare+"</button>");var d=a(".media-frame-content").find(".compat-field-imagify");c({width:a("#imagify-full-width").val(),height:a("#imagify-full-height").val(),original_url:a("#imagify-original-src").val(),optimized_url:a("#imagify-full-src").val(),original_size:a("#imagify-original-size").val(),optimized_size:d.find(".imagify-data-item").find(".big").text(),saving:d.find(".imagify-chart-value").text(),modal_append_to:a(".media-frame-content").find(".thumbnail-image"),trigger:a("#imagify-media-frame-comparison-btn"),
28
+ modal_id:"imagify-comparison-modal",open_modal:!0})}clearInterval(b);b=null}},20)},r=setInterval(function(){0<a(".upload-php").find(".media-frame.mode-grid").find(".attachments").length&&(a(".upload-php").find(".media-frame.mode-grid").on("click",".attachment",function(){u()}),x("item")&&u(),clearInterval(r),r=null)},100)})(jQuery,window,document);
assets/js/options.js CHANGED
@@ -88,7 +88,8 @@ jQuery(function($){
88
  text: imagifyOptions.noBackupText,
89
  type: "info",
90
  customClass: "imagify-sweet-alert",
91
- showCancelButton: true
 
92
  }, function(isConfirm){
93
  if ( ! isConfirm ) {
94
  $_this.prop('checked', true);
88
  text: imagifyOptions.noBackupText,
89
  type: "info",
90
  customClass: "imagify-sweet-alert",
91
+ showCancelButton: true,
92
+ cancelButtonText: imagify.swalCancel
93
  }, function(isConfirm){
94
  if ( ! isConfirm ) {
95
  $_this.prop('checked', true);
assets/js/options.min.js CHANGED
@@ -1,4 +1,4 @@
1
  jQuery(function(a){var c=!1,d=!1,f=0<ajaxurl.indexOf("?")?"&":"?";a("#imagify-settings #api_key").blur(function(){var b=a(this),e=b.val();if(""===a.trim(e))return!1;if(a("#check_api_key").val()===e)return a("#imagify-check-api-container").html('<span class="dashicons dashicons-yes"></span> '+imagify.ValidApiKeyText),!1;!0===c?d.abort():(a("#imagify-check-api-container").remove(),b.after('<span id="imagify-check-api-container"><span class="imagify-spinner"></span>'+imagify.waitApiKeyCheckText+"</span>"));
2
  c=!0;d=a.get(ajaxurl+f+"action=imagify_check_api_key_validity&api_key="+b.val()+"&imagifycheckapikeynonce="+a("#imagifycheckapikeynonce").val()).done(function(b){b.success?(a("#imagify-check-api-container").remove(),swal({title:imagify.ApiKeyCheckSuccessTitle,text:imagify.ApiKeyCheckSuccessText,type:"success",customClass:"imagify-sweet-alert"},function(){location.reload()})):a("#imagify-check-api-container").html('<span class="dashicons dashicons-no"></span> '+b.data);c=!1})});a(".imagify-options-line").css("cursor",
3
  "pointer").on("click",function(b){if("INPUT"!==b.target.nodeName)return a('input[aria-describedby="'+a(this).attr("id")+'"]').trigger("click"),!1});a(".imagify-settings th span").on("click",function(b){1===a(this).parent().next("td").find("input:checkbox").length&&a(this).parent().next("td").find("input:checkbox").trigger("click")});a(".imagify-options-line").find("input").on("change focus",function(){var b=a(this).closest(".imagify-options-line").prev("label").prev("input");b[0].checked||b.prop("checked",
4
- !0)});a(".imagify-settings-section").find("#backup").on("change",function(){if(!a(this).is(":checked")){var b=a(this);swal({title:imagifyOptions.noBackupTitle,text:imagifyOptions.noBackupText,type:"info",customClass:"imagify-sweet-alert",showCancelButton:!0},function(a){a||b.prop("checked",!0)})}})});
1
  jQuery(function(a){var c=!1,d=!1,f=0<ajaxurl.indexOf("?")?"&":"?";a("#imagify-settings #api_key").blur(function(){var b=a(this),e=b.val();if(""===a.trim(e))return!1;if(a("#check_api_key").val()===e)return a("#imagify-check-api-container").html('<span class="dashicons dashicons-yes"></span> '+imagify.ValidApiKeyText),!1;!0===c?d.abort():(a("#imagify-check-api-container").remove(),b.after('<span id="imagify-check-api-container"><span class="imagify-spinner"></span>'+imagify.waitApiKeyCheckText+"</span>"));
2
  c=!0;d=a.get(ajaxurl+f+"action=imagify_check_api_key_validity&api_key="+b.val()+"&imagifycheckapikeynonce="+a("#imagifycheckapikeynonce").val()).done(function(b){b.success?(a("#imagify-check-api-container").remove(),swal({title:imagify.ApiKeyCheckSuccessTitle,text:imagify.ApiKeyCheckSuccessText,type:"success",customClass:"imagify-sweet-alert"},function(){location.reload()})):a("#imagify-check-api-container").html('<span class="dashicons dashicons-no"></span> '+b.data);c=!1})});a(".imagify-options-line").css("cursor",
3
  "pointer").on("click",function(b){if("INPUT"!==b.target.nodeName)return a('input[aria-describedby="'+a(this).attr("id")+'"]').trigger("click"),!1});a(".imagify-settings th span").on("click",function(b){1===a(this).parent().next("td").find("input:checkbox").length&&a(this).parent().next("td").find("input:checkbox").trigger("click")});a(".imagify-options-line").find("input").on("change focus",function(){var b=a(this).closest(".imagify-options-line").prev("label").prev("input");b[0].checked||b.prop("checked",
4
+ !0)});a(".imagify-settings-section").find("#backup").on("change",function(){if(!a(this).is(":checked")){var b=a(this);swal({title:imagifyOptions.noBackupTitle,text:imagifyOptions.noBackupText,type:"info",customClass:"imagify-sweet-alert",showCancelButton:!0,cancelButtonText:imagify.swalCancel},function(a){a||b.prop("checked",!0)})}})});
contributors.txt CHANGED
@@ -6,4 +6,5 @@ Developers:
6
  Geoffrey Crofte <geoffrey@wp-media.me>
7
  Sébastien Decamme <sebastien@wp-media.me>
8
  Julio Potier <julio@wp-media.me>
9
- Caspar Huebinger <caspar@wp-rocket.me>
 
6
  Geoffrey Crofte <geoffrey@wp-media.me>
7
  Sébastien Decamme <sebastien@wp-media.me>
8
  Julio Potier <julio@wp-media.me>
9
+ Caspar Huebinger <caspar@wp-rocket.me>
10
+ Grégory Viguier <gregory@wp-rocket.me>
imagify.php CHANGED
@@ -2,8 +2,8 @@
2
  /*
3
  Plugin Name: Imagify
4
  Plugin URI: https://wordpress.org/plugins/imagify/
5
- Description: Dramaticaly reduce image file sizes without loosing quality, make your website load faster, boost your SEO and save money on your bandwith using Imagify, the new most advanced image optimization tool.
6
- Version: 1.4.4
7
  Author: WP Media
8
  Author URI: http://wp-media.me
9
  Licence: GPLv2
@@ -17,7 +17,7 @@ Copyright 2015 WP Media
17
  defined( 'ABSPATH' ) or die( 'Cheatin\' uh?' );
18
 
19
  // Imagify defines
20
- define( 'IMAGIFY_VERSION' , '1.4.4' );
21
  define( 'IMAGIFY_SLUG' , 'imagify' );
22
  define( 'IMAGIFY_SETTINGS_SLUG' , IMAGIFY_SLUG . '_settings' );
23
  define( 'IMAGIFY_WEB_MAIN' , 'https://imagify.io' );
@@ -76,6 +76,7 @@ function _imagify_init() {
76
 
77
  if ( is_admin() ) {
78
  require( IMAGIFY_ADMIN_PATH . 'upgrader.php' );
 
79
  require( IMAGIFY_ADMIN_PATH . 'ajax.php' );
80
  require( IMAGIFY_ADMIN_PATH . 'options.php' );
81
  require( IMAGIFY_ADMIN_PATH . 'menu.php' );
2
  /*
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 bandwith using Imagify, the new most advanced image optimization tool.
6
+ Version: 1.4.5
7
  Author: WP Media
8
  Author URI: http://wp-media.me
9
  Licence: GPLv2
17
  defined( 'ABSPATH' ) or die( 'Cheatin\' uh?' );
18
 
19
  // Imagify defines
20
+ define( 'IMAGIFY_VERSION' , '1.4.5' );
21
  define( 'IMAGIFY_SLUG' , 'imagify' );
22
  define( 'IMAGIFY_SETTINGS_SLUG' , IMAGIFY_SLUG . '_settings' );
23
  define( 'IMAGIFY_WEB_MAIN' , 'https://imagify.io' );
76
 
77
  if ( is_admin() ) {
78
  require( IMAGIFY_ADMIN_PATH . 'upgrader.php' );
79
+ require( IMAGIFY_ADMIN_PATH . 'heartbeat.php' );
80
  require( IMAGIFY_ADMIN_PATH . 'ajax.php' );
81
  require( IMAGIFY_ADMIN_PATH . 'options.php' );
82
  require( IMAGIFY_ADMIN_PATH . 'menu.php' );
inc/admin/ajax.php CHANGED
@@ -14,7 +14,7 @@ function _do_admin_post_imagify_manual_upload() {
14
  } else {
15
  check_admin_referer( 'imagify-manual-upload' );
16
  }
17
-
18
  if ( ! isset( $_GET['attachment_id'] ) || ! current_user_can( 'upload_files' ) ) {
19
  if ( defined( 'DOING_AJAX' ) ) {
20
  wp_send_json_error();
@@ -178,39 +178,104 @@ function _do_wp_ajax_imagify_get_unoptimized_attachment_ids() {
178
  'post_mime_type' => get_imagify_mime_type(),
179
  'meta_query' => $meta_query,
180
  'posts_per_page' => $unoptimized_attachment_limit,
 
 
181
  'no_found_rows' => true,
182
  'update_post_term_cache' => false,
183
  );
184
 
185
- $data = array();
186
- $query = new WP_Query( $args );
187
- $ids = $query->posts;
 
 
 
 
188
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
189
  // Save the optimization level in a transient to retrieve it later during the process
190
  set_transient( 'imagify_bulk_optimization_level', $optimization_level );
191
 
192
  foreach( $ids as $id ) {
193
  /** This filter is documented in inc/functions/process.php */
194
- $file_path = apply_filters( 'imagify_file_path', get_attached_file( $id ) );
195
 
196
  if ( file_exists( $file_path ) ) {
197
- $attachment = new Imagify_Attachment( $id );
198
- $attachment_error = $attachment->get_optimized_error();
199
- $attachment_error = trim( $attachment_error );
200
- $attachment_status = $attachment->get_status();
 
 
 
 
 
 
 
201
 
202
  // Don't try to re-optimize if the optimization level is still the same
203
- if ( $optimization_level === $attachment->get_optimization_level() && ! $attachment->has_error() ) {
204
  continue;
205
  }
206
 
207
  // Don't try to re-optimize if there is no backup file
208
- if ( $optimization_level !== $attachment->get_optimization_level() && ! $attachment->has_backup() && $attachment->is_optimized() ) {
209
  continue;
210
  }
211
 
212
  // Don't try to re-optimize images already compressed
213
- if ( $attachment->get_optimization_level() >= $optimization_level && $attachment_status == 'already_optimized' ) {
214
  continue;
215
  }
216
 
@@ -219,8 +284,8 @@ function _do_wp_ajax_imagify_get_unoptimized_attachment_ids() {
219
  continue;
220
  }
221
 
222
- $data[ '_' . $id ] = wp_get_attachment_url( $id );
223
- }
224
  }
225
 
226
  if ( (bool) $data ) {
@@ -258,19 +323,8 @@ function _do_wp_ajax_imagify_bulk_upload() {
258
  // Return the optimization statistics
259
  $fullsize_data = $attachment->get_size_data();
260
  $stats_data = $attachment->get_stats_data();
261
- $saving_data = imagify_count_saving_data();
262
  $user = new Imagify_User();
263
- $data = array(
264
- 'global_already_optimized_attachments' => $saving_data['count'],
265
- 'global_optimized_attachments' => imagify_count_optimized_attachments(),
266
- 'global_unoptimized_attachments' => imagify_count_unoptimized_attachments(),
267
- 'global_errors_attachments' => imagify_count_error_attachments(),
268
- 'global_optimized_attachments_percent' => imagify_percent_optimized_attachments(),
269
- 'global_optimized_percent' => $saving_data['percent'],
270
- 'global_original_human' => size_format( $saving_data['original_size'], 1 ),
271
- 'global_optimized_human' => size_format( $saving_data['optimized_size'], 1 ),
272
- 'global_unconsumed_quota' => $user->get_percent_unconsumed_quota(),
273
- );
274
 
275
  if ( ! $attachment->is_optimized() ) {
276
  $data['success'] = false;
@@ -535,5 +589,4 @@ function _do_admin_post_async_optimize_save_image_editor_file() {
535
 
536
  die( 1 );
537
  }
538
-
539
  }
14
  } else {
15
  check_admin_referer( 'imagify-manual-upload' );
16
  }
17
+
18
  if ( ! isset( $_GET['attachment_id'] ) || ! current_user_can( 'upload_files' ) ) {
19
  if ( defined( 'DOING_AJAX' ) ) {
20
  wp_send_json_error();
178
  'post_mime_type' => get_imagify_mime_type(),
179
  'meta_query' => $meta_query,
180
  'posts_per_page' => $unoptimized_attachment_limit,
181
+ 'orderby' => 'ID',
182
+ 'order' => 'DESC',
183
  'no_found_rows' => true,
184
  'update_post_term_cache' => false,
185
  );
186
 
187
+ global $wpdb;
188
+
189
+ $data = array();
190
+ $attachments = new WP_Query( $args );
191
+ $ids = $attachments->posts;
192
+ $ids = array_filter( (array) $ids );
193
+ $sql_ids = implode( ',', $ids );
194
 
195
+ if ( empty( $sql_ids ) ) {
196
+ wp_send_json_error( array( 'message' => 'no-images' ) );
197
+ }
198
+
199
+ // Get attachments filename
200
+ $attachments_filename = $wpdb->get_col(
201
+ "SELECT pm.meta_value
202
+ FROM $wpdb->postmeta as pm
203
+ WHERE pm.meta_key= '_wp_attached_file'
204
+ AND pm.post_id IN ($sql_ids)
205
+ ORDER BY pm.post_id DESC"
206
+ );
207
+
208
+ $attachments_filename = array_combine( $ids, $attachments_filename );
209
+
210
+ // Get attachments data
211
+ $attachments_data = $wpdb->get_results(
212
+ "SELECT pm.post_id as id, pm.meta_value as value
213
+ FROM $wpdb->postmeta as pm
214
+ WHERE pm.meta_key= '_imagify_data'
215
+ AND pm.post_id IN ($sql_ids)
216
+ ORDER BY pm.post_id DESC"
217
+ , ARRAY_A
218
+ );
219
+
220
+ $attachments_data = imagify_query_results_combine( $ids, $attachments_data );
221
+ $attachments_data = array_map( 'maybe_unserialize', $attachments_data );
222
+
223
+ // Get attachments optimization level
224
+ $attachments_optimization_level = $wpdb->get_results(
225
+ "SELECT pm.post_id as id, pm.meta_value as value
226
+ FROM $wpdb->postmeta as pm
227
+ WHERE pm.meta_key= '_imagify_optimization_level'
228
+ AND pm.post_id IN ($sql_ids)
229
+ ORDER BY pm.post_id DESC"
230
+ , ARRAY_A
231
+ );
232
+
233
+ $attachments_optimization_level = imagify_query_results_combine( $ids, $attachments_optimization_level );
234
+
235
+ // Get attachments status
236
+ $attachments_status = $wpdb->get_results(
237
+ "SELECT pm.post_id as id, pm.meta_value as value
238
+ FROM $wpdb->postmeta as pm
239
+ WHERE pm.meta_key= '_imagify_status'
240
+ AND pm.post_id IN ($sql_ids)
241
+ ORDER BY pm.post_id DESC"
242
+ , ARRAY_A
243
+ );
244
+
245
+ $attachments_status = imagify_query_results_combine( $ids, $attachments_status );
246
+
247
  // Save the optimization level in a transient to retrieve it later during the process
248
  set_transient( 'imagify_bulk_optimization_level', $optimization_level );
249
 
250
  foreach( $ids as $id ) {
251
  /** This filter is documented in inc/functions/process.php */
252
+ $file_path = apply_filters( 'imagify_file_path', get_imagify_attached_file( $attachments_filename[ $id ] ) );
253
 
254
  if ( file_exists( $file_path ) ) {
255
+ $attachment_data = ( isset( $attachments_data[ $id ] ) ) ? $attachments_data[ $id ] : false;
256
+ $attachment_error = '';
257
+
258
+ if ( isset( $attachment_data['sizes']['full']['error'] ) ) {
259
+ $attachment_error = $attachment_data['sizes']['full']['error'];
260
+ }
261
+
262
+ $attachment_error = trim( $attachment_error );
263
+ $attachment_status = ( isset( $attachments_status[ $id ] ) ) ? $attachments_status[ $id ] : false;
264
+ $attachment_optimization_level = ( isset( $attachments_optimization_level[ $id ] ) ) ? $attachments_optimization_level[ $id ] : false;
265
+ $attachment_backup_path = get_imagify_attachment_backup_path( $file_path );
266
 
267
  // Don't try to re-optimize if the optimization level is still the same
268
+ if ( $optimization_level === $attachment_optimization_level && is_string( $attachment_error ) ) {
269
  continue;
270
  }
271
 
272
  // Don't try to re-optimize if there is no backup file
273
+ if ( $optimization_level !== $attachment_optimization_level && ! file_exists( $attachment_backup_path ) && $attachment_status == 'success' ) {
274
  continue;
275
  }
276
 
277
  // Don't try to re-optimize images already compressed
278
+ if ( $attachment_optimization_level >= $optimization_level && $attachment_status == 'already_optimized' ) {
279
  continue;
280
  }
281
 
284
  continue;
285
  }
286
 
287
+ $data[ '_' . $id ] = get_imagify_attachment_url( $attachments_filename[ $id ] );
288
+ }
289
  }
290
 
291
  if ( (bool) $data ) {
323
  // Return the optimization statistics
324
  $fullsize_data = $attachment->get_size_data();
325
  $stats_data = $attachment->get_stats_data();
 
326
  $user = new Imagify_User();
327
+ $data = array();
 
 
 
 
 
 
 
 
 
 
328
 
329
  if ( ! $attachment->is_optimized() ) {
330
  $data['success'] = false;
589
 
590
  die( 1 );
591
  }
 
592
  }
inc/admin/enqueue.php CHANGED
@@ -76,7 +76,7 @@ function _imagify_admin_print_styles() {
76
 
77
  wp_register_script(
78
  'imagify-js-chart',
79
- IMAGIFY_ASSETS_JS_URL . 'chart.min.js',
80
  array(),
81
  IMAGIFY_VERSION,
82
  true
@@ -130,7 +130,8 @@ function _imagify_admin_print_styles() {
130
  'waitApiKeyCheckText' => __( 'Check in progress...', 'imagify' ),
131
  'ApiKeyCheckSuccessTitle' => __( 'Congratulations!', 'imagify' ),
132
  'ApiKeyCheckSuccessText' => __( 'Your API key is valid. You can now configure the Imagify settings to optimize your images.', 'imagify' ),
133
- 'ValidApiKeyText' => __( 'Your API key is valid.', 'imagify' )
 
134
 
135
  );
136
  wp_localize_script( 'imagify-js-admin', 'imagify', $admin_data );
@@ -197,6 +198,8 @@ function _imagify_admin_print_styles() {
197
  * Scripts loaded in /wp-admin/upload.php?page=imagify-bulk-optimization
198
  */
199
  if ( isset( $current_screen ) && 'media_page_imagify-bulk-optimization' === $current_screen->base ) {
 
 
200
  $user = get_imagify_user();
201
  $bulk_data = array(
202
  'waitTitle' => __( 'Please wait...', 'imagify' ),
76
 
77
  wp_register_script(
78
  'imagify-js-chart',
79
+ IMAGIFY_ASSETS_JS_URL . 'chart' . $js_ext,
80
  array(),
81
  IMAGIFY_VERSION,
82
  true
130
  'waitApiKeyCheckText' => __( 'Check in progress...', 'imagify' ),
131
  'ApiKeyCheckSuccessTitle' => __( 'Congratulations!', 'imagify' ),
132
  'ApiKeyCheckSuccessText' => __( 'Your API key is valid. You can now configure the Imagify settings to optimize your images.', 'imagify' ),
133
+ 'ValidApiKeyText' => __( 'Your API key is valid.', 'imagify' ),
134
+ 'swalCancel' => __( 'Cancel' )
135
 
136
  );
137
  wp_localize_script( 'imagify-js-admin', 'imagify', $admin_data );
198
  * Scripts loaded in /wp-admin/upload.php?page=imagify-bulk-optimization
199
  */
200
  if ( isset( $current_screen ) && 'media_page_imagify-bulk-optimization' === $current_screen->base ) {
201
+ wp_enqueue_script( 'heartbeat' );
202
+
203
  $user = get_imagify_user();
204
  $bulk_data = array(
205
  'waitTitle' => __( 'Please wait...', 'imagify' ),
inc/admin/heartbeat.php ADDED
@@ -0,0 +1,46 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ defined( 'ABSPATH' ) or die( 'Cheatin\' uh?' );
3
+
4
+ global $pagenow;
5
+
6
+ /**
7
+ * Prepare the data that goes back with the Heartbeat API.
8
+ *
9
+ * @since 1.4.5
10
+ */
11
+ add_filter( 'heartbeat_received', '_imagify_heartbeat_received', 10, 2 );
12
+ function _imagify_heartbeat_received( $response, $data ) {
13
+ if( isset( $data['imagify_heartbeat'] ) && 'update_bulk_data' === $data['imagify_heartbeat'] ) {
14
+ $saving_data = imagify_count_saving_data();
15
+ $user = new Imagify_User();
16
+
17
+ $response['imagify_bulk_data'] = array(
18
+ 'already_optimized_attachments' => $saving_data['count'],
19
+ 'optimized_attachments' => imagify_count_optimized_attachments(),
20
+ 'unoptimized_attachments' => imagify_count_unoptimized_attachments(),
21
+ 'errors_attachments' => imagify_count_error_attachments(),
22
+ 'optimized_attachments_percent' => imagify_percent_optimized_attachments(),
23
+ 'optimized_percent' => $saving_data['percent'],
24
+ 'original_human' => size_format( $saving_data['original_size'], 1 ),
25
+ 'optimized_human' => size_format( $saving_data['optimized_size'], 1 ),
26
+ 'unconsumed_quota' => $user->get_percent_unconsumed_quota(),
27
+ );
28
+ }
29
+
30
+ return $response;
31
+ }
32
+
33
+
34
+ /**
35
+ * Update the Heartbeat API settings
36
+ *
37
+ * @since 1.4.5
38
+ */
39
+ if ( 'upload.php' === $pagenow && isset( $_GET['page'] ) && 'imagify-bulk-optimization' === $_GET['page'] ) {
40
+ add_filter( 'heartbeat_settings', '_imagify_heartbeat_settings', PHP_INT_MAX );
41
+ }
42
+
43
+ function _imagify_heartbeat_settings( $settings ) {
44
+ $settings['interval'] = 30;
45
+ return $settings;
46
+ }
inc/admin/plugins.php CHANGED
@@ -12,6 +12,6 @@ function _imagify_plugin_action_links( $actions )
12
  {
13
  array_unshift( $actions, sprintf( '<a href="%s">%s</a>', get_imagify_admin_url( 'bulk-optimization' ), __( 'Bulk Optimization', 'imagify' ) ) );
14
  array_unshift( $actions, sprintf( '<a href="%s">%s</a>', get_imagify_admin_url(), __( 'Settings' ) ) );
15
-
16
  return $actions;
17
  }
12
  {
13
  array_unshift( $actions, sprintf( '<a href="%s">%s</a>', get_imagify_admin_url( 'bulk-optimization' ), __( 'Bulk Optimization', 'imagify' ) ) );
14
  array_unshift( $actions, sprintf( '<a href="%s">%s</a>', get_imagify_admin_url(), __( 'Settings' ) ) );
15
+
16
  return $actions;
17
  }
inc/admin/upgrader.php CHANGED
@@ -37,7 +37,7 @@ function _imagify_upgrader() {
37
  add_action( 'imagify_first_install', '_imagify_first_install' );
38
  function _imagify_first_install() {
39
  // Set a transient to know when we will have to display a notice to ask the user to rate the plugin.
40
- set_site_transient( 'imagify_seen_rating_notice', true, DAY_IN_SECONDS * 7 );
41
 
42
  // Create Options
43
  add_site_option( IMAGIFY_SETTINGS_SLUG,
@@ -134,7 +134,7 @@ function _imagify_new_upgrade( $imagify_version, $current_version ) {
134
  }
135
  }
136
 
137
- if ( version_compare( $current_version, '1.4.2', '<' ) ) {
138
  // Delete all transients used for async optimization
139
  global $wpdb;
140
  $wpdb->query( 'DELETE from ' . $wpdb->options . ' WHERE option_name LIKE "_transient_imagify-async-in-progress-%"' );
37
  add_action( 'imagify_first_install', '_imagify_first_install' );
38
  function _imagify_first_install() {
39
  // Set a transient to know when we will have to display a notice to ask the user to rate the plugin.
40
+ set_site_transient( 'imagify_seen_rating_notice', true, DAY_IN_SECONDS * 3 );
41
 
42
  // Create Options
43
  add_site_option( IMAGIFY_SETTINGS_SLUG,
134
  }
135
  }
136
 
137
+ if ( version_compare( $current_version, '1.4.5', '<' ) ) {
138
  // Delete all transients used for async optimization
139
  global $wpdb;
140
  $wpdb->query( 'DELETE from ' . $wpdb->options . ' WHERE option_name LIKE "_transient_imagify-async-in-progress-%"' );
inc/classes/class-attachment.php CHANGED
@@ -247,7 +247,7 @@ class Imagify_Attachment {
247
 
248
  return $stats;
249
  }
250
-
251
  /**
252
  * Get the global statistics data or a specific one.
253
  *
@@ -468,7 +468,6 @@ class Imagify_Attachment {
468
  // Check if the full size is already optimized
469
  if ( $this->is_optimized() && ( $this->get_optimization_level() == $optimization_level ) ) {
470
  delete_transient( 'imagify-async-in-progress-' . $id );
471
-
472
  return;
473
  }
474
 
@@ -500,7 +499,6 @@ class Imagify_Attachment {
500
 
501
  if( (bool) ! $data ) {
502
  delete_transient( 'imagify-async-in-progress-' . $id );
503
-
504
  return;
505
  }
506
 
247
 
248
  return $stats;
249
  }
250
+
251
  /**
252
  * Get the global statistics data or a specific one.
253
  *
468
  // Check if the full size is already optimized
469
  if ( $this->is_optimized() && ( $this->get_optimization_level() == $optimization_level ) ) {
470
  delete_transient( 'imagify-async-in-progress-' . $id );
 
471
  return;
472
  }
473
 
499
 
500
  if( (bool) ! $data ) {
501
  delete_transient( 'imagify-async-in-progress-' . $id );
 
502
  return;
503
  }
504
 
inc/common/attachments.php CHANGED
@@ -10,15 +10,16 @@ add_filter( 'wp_generate_attachment_metadata', '_imagify_optimize_attachment', P
10
  function _imagify_optimize_attachment( $metadata, $attachment_id ) {
11
  $api_key = get_imagify_option( 'api_key', false );
12
 
13
- if ( ! empty( $api_key ) && get_imagify_option( 'auto_optimize', false ) ) {
14
- $attachment = new Imagify_Attachment( $attachment_id );
15
-
16
  // Optimize it!!!!!
17
  $attachment->optimize( null, $metadata );
18
  }
19
 
20
  return $metadata;
21
  }
 
22
  /**
23
  * Delete the backup file when an attachement is deleted.
24
  *
10
  function _imagify_optimize_attachment( $metadata, $attachment_id ) {
11
  $api_key = get_imagify_option( 'api_key', false );
12
 
13
+ if ( ! empty( $api_key ) && get_imagify_option( 'auto_optimize', false ) ) {
14
+ $attachment = new Imagify_Attachment( $attachment_id );
15
+
16
  // Optimize it!!!!!
17
  $attachment->optimize( null, $metadata );
18
  }
19
 
20
  return $metadata;
21
  }
22
+
23
  /**
24
  * Delete the backup file when an attachement is deleted.
25
  *
inc/functions/admin-stats.php CHANGED
@@ -9,50 +9,18 @@ defined( 'ABSPATH' ) or die( 'Cheatin\' uh?' );
9
  * @return int The number of attachments.
10
  */
11
  function imagify_count_attachments() {
12
- $count = wp_count_attachments( get_imagify_mime_type() );
13
- $count = get_object_vars( $count );
14
- $count = array_sum( $count );
15
-
16
- if ( $count > apply_filters( 'imagify_unoptimized_attachment_limit', 10000 ) ) {
17
- set_transient( IMAGIFY_SLUG . '_large_library', 1 );
18
- }
19
 
20
- return (int) $count;
21
- }
22
-
23
- /*
24
- * Count number of execeed attachments (size > 5MB).
25
- *
26
- * @since 1.0
27
- *
28
- * @return int The number of exceeded attachments.
29
- */
30
- function imagify_count_exceeding_attachments() {
31
- $count = 0;
32
- $query = new WP_Query(
33
- array(
34
- 'post_type' => 'attachment',
35
- 'post_status' => 'inherit',
36
- 'post_mime_type' => get_imagify_mime_type(),
37
- 'posts_per_page' => -1,
38
- 'update_post_term_cache' => false,
39
- 'no_found_rows' => true,
40
- 'fields' => 'ids'
41
- )
42
  );
43
- $attachments = (array) $query->posts;
44
-
45
- foreach( $attachments as $attachment_id ) {
46
- $attachment = new Imagify_Attachment( $attachment_id );
47
-
48
- // Check if the attachment extension is allowed
49
- if ( ! wp_attachment_is_image( $attachment_id ) ) {
50
- continue;
51
- }
52
 
53
- if ( $attachment->is_exceeded() ) {
54
- $count++;
55
- }
56
  }
57
 
58
  return (int) $count;
@@ -65,22 +33,22 @@ function imagify_count_exceeding_attachments() {
65
  *
66
  * @return int The number of attachments.
67
  */
68
- function imagify_count_error_attachments() {
69
- $query = new WP_Query(
70
- array(
71
- 'post_type' => 'attachment',
72
- 'post_status' => 'inherit',
73
- 'post_mime_type' => get_imagify_mime_type(),
74
- 'meta_key' => '_imagify_status',
75
- 'meta_value' => 'error',
76
- 'posts_per_page' => -1,
77
- 'update_post_term_cache' => false,
78
- 'no_found_rows' => true,
79
- 'fields' => 'ids'
80
- )
81
  );
82
 
83
- return (int) $query->post_count;
84
  }
85
 
86
  /*
@@ -90,33 +58,21 @@ function imagify_count_error_attachments() {
90
  *
91
  * @return int The number of attachments.
92
  */
93
- function imagify_count_optimized_attachments() {
94
- $query = new WP_Query(
95
- array(
96
- 'post_type' => 'attachment',
97
- 'post_status' => 'inherit',
98
- 'post_mime_type' => get_imagify_mime_type(),
99
- 'meta_query' => array(
100
- 'relation' => 'or',
101
- array(
102
- 'key' => '_imagify_status',
103
- 'value' => 'success',
104
- 'compare' => '='
105
- ),
106
- array(
107
- 'key' => '_imagify_status',
108
- 'value' => 'already_optimized',
109
- 'compare' => '='
110
- )
111
- ),
112
- 'posts_per_page' => -1,
113
- 'update_post_term_cache' => false,
114
- 'no_found_rows' => true,
115
- 'fields' => 'ids'
116
- )
117
  );
118
 
119
- return (int) $query->post_count;
120
  }
121
 
122
  /*
@@ -156,56 +112,42 @@ function imagify_percent_optimized_attachments() {
156
  */
157
  function imagify_count_saving_data( $key = '' ) {
158
  global $wpdb;
159
-
 
 
 
 
 
 
 
 
 
 
160
  $original_size = 0;
161
  $optimized_size = 0;
162
- $query = new WP_Query(
163
- array(
164
- 'post_type' => 'attachment',
165
- 'post_status' => 'inherit',
166
- 'post_mime_type' => get_imagify_mime_type(),
167
- 'meta_key' => '_imagify_status',
168
- 'meta_value' => 'success',
169
- 'posts_per_page' => -1,
170
- 'update_post_term_cache' => false,
171
- 'no_found_rows' => true,
172
- 'fields' => 'ids'
173
- )
174
- );
175
- $attachments = (array) $query->posts;
176
-
177
- foreach( $attachments as $attachment_id ) {
178
- $attachment = new Imagify_Attachment( $attachment_id );
179
-
180
- // Check if the attachment extension is allowed
181
- if ( ! wp_attachment_is_image( $attachment_id ) ) {
182
- continue;
183
- }
184
-
185
- $stats_data = $attachment->get_stats_data();
186
- $original_data = $attachment->get_size_data( 'full' );
187
-
188
  // Incremente the original sizes
189
- if ( $attachment->is_optimized() ) {
190
- $original_size += ( $original_data['original_size'] ) ? $original_data['original_size'] : 0;
191
- $optimized_size += ( $original_data['optimized_size'] ) ? $original_data['optimized_size'] : 0;
192
- }
193
 
194
- $metadata = wp_get_attachment_metadata( $attachment_id );
195
- $sizes = ( isset( $metadata['sizes'] ) ) ? (array) $metadata['sizes'] : array();
196
-
197
  // Incremente the thumbnails sizes
198
- foreach ( $sizes as $size_key => $size_data ) {
199
- $size_data = $attachment->get_size_data( $size_key );
200
  if ( ! empty( $size_data['success'] ) ) {
201
  $original_size += ( $size_data['original_size'] ) ? $size_data['original_size'] : 0;
202
  $optimized_size += ( $size_data['optimized_size'] ) ? $size_data['optimized_size'] : 0;
203
  }
204
  }
205
  }
206
-
207
  $data = array(
208
- 'count' => $query->post_count,
209
  'original_size' => (int) $original_size,
210
  'optimized_size' => (int) $optimized_size,
211
  'percent' => ( 0 !== $optimized_size ) ? ceil( ( ( $original_size - $optimized_size ) / $original_size ) * 100 ) : 0
9
  * @return int The number of attachments.
10
  */
11
  function imagify_count_attachments() {
12
+ global $wpdb;
 
 
 
 
 
 
13
 
14
+ $count = $wpdb->get_var(
15
+ "SELECT COUNT($wpdb->posts.ID)
16
+ FROM $wpdb->posts
17
+ WHERE post_type = 'attachment'
18
+ AND post_status != 'trash'
19
+ AND ($wpdb->posts.post_mime_type = 'image/jpeg' OR $wpdb->posts.post_mime_type = 'image/png' OR $wpdb->posts.post_mime_type = 'image/gif')"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
20
  );
 
 
 
 
 
 
 
 
 
21
 
22
+ if ( $count > apply_filters( 'imagify_unoptimized_attachment_limit', 10000 ) ) {
23
+ set_transient( IMAGIFY_SLUG . '_large_library', 1 );
 
24
  }
25
 
26
  return (int) $count;
33
  *
34
  * @return int The number of attachments.
35
  */
36
+ function imagify_count_error_attachments() {
37
+ global $wpdb;
38
+
39
+ $count = $wpdb->get_var(
40
+ "SELECT COUNT($wpdb->posts.ID)
41
+ FROM $wpdb->posts
42
+ INNER JOIN $wpdb->postmeta
43
+ ON $wpdb->posts.ID = $wpdb->postmeta.post_id
44
+ WHERE ($wpdb->posts.post_mime_type = 'image/jpeg' OR $wpdb->posts.post_mime_type = 'image/png' OR $wpdb->posts.post_mime_type = 'image/gif')
45
+ AND ( ( $wpdb->postmeta.meta_key = '_imagify_status' AND CAST($wpdb->postmeta.meta_value AS CHAR) = 'error' )
46
+ )
47
+ AND $wpdb->posts.post_type = 'attachment'
48
+ AND $wpdb->posts.post_status = 'inherit'"
49
  );
50
 
51
+ return (int) $count;
52
  }
53
 
54
  /*
58
  *
59
  * @return int The number of attachments.
60
  */
61
+ function imagify_count_optimized_attachments() {
62
+ global $wpdb;
63
+
64
+ $count = $wpdb->get_var(
65
+ "SELECT COUNT($wpdb->posts.ID)
66
+ FROM $wpdb->posts
67
+ INNER JOIN $wpdb->postmeta
68
+ ON $wpdb->posts.ID = $wpdb->postmeta.post_id
69
+ WHERE ($wpdb->posts.post_mime_type = 'image/jpeg' OR $wpdb->posts.post_mime_type = 'image/png' OR $wpdb->posts.post_mime_type = 'image/gif')
70
+ AND ( ( $wpdb->postmeta.meta_key = '_imagify_status' AND CAST($wpdb->postmeta.meta_value AS CHAR) = 'success' ) OR ( $wpdb->postmeta.meta_key = '_imagify_status' AND CAST($wpdb->postmeta.meta_value AS CHAR) = 'already_optimized' ) )
71
+ AND $wpdb->posts.post_type = 'attachment'
72
+ AND $wpdb->posts.post_status = 'inherit'"
 
 
 
 
 
 
 
 
 
 
 
 
73
  );
74
 
75
+ return (int) $count;
76
  }
77
 
78
  /*
112
  */
113
  function imagify_count_saving_data( $key = '' ) {
114
  global $wpdb;
115
+
116
+ $attachments = $wpdb->get_col(
117
+ "SELECT pm1.meta_value
118
+ FROM $wpdb->postmeta as pm1
119
+ INNER JOIN $wpdb->postmeta as pm2
120
+ ON pm1.post_id = pm2.post_id
121
+ WHERE pm1.meta_key= '_imagify_data'
122
+ AND ( pm2.meta_key= '_imagify_status' AND pm2.meta_value= 'success' )"
123
+ );
124
+
125
+ $attachments = array_map( 'maybe_unserialize', (array) $attachments );
126
  $original_size = 0;
127
  $optimized_size = 0;
128
+ $count = 0;
129
+
130
+ foreach( $attachments as $attachment_data ) {
131
+ $stats_data = $attachment_data['stats'];
132
+ $original_data = $attachment_data['sizes']['full'];
133
+
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
134
  // Incremente the original sizes
135
+ $original_size += ( $original_data['original_size'] ) ? $original_data['original_size'] : 0;
136
+ $optimized_size += ( $original_data['optimized_size'] ) ? $original_data['optimized_size'] : 0;
137
+
138
+ unset( $attachment_data['sizes']['full'] );
139
 
 
 
 
140
  // Incremente the thumbnails sizes
141
+ foreach ( $attachment_data['sizes'] as $size_key => $size_data ) {
 
142
  if ( ! empty( $size_data['success'] ) ) {
143
  $original_size += ( $size_data['original_size'] ) ? $size_data['original_size'] : 0;
144
  $optimized_size += ( $size_data['optimized_size'] ) ? $size_data['optimized_size'] : 0;
145
  }
146
  }
147
  }
148
+
149
  $data = array(
150
+ 'count' => count( $attachments ),
151
  'original_size' => (int) $original_size,
152
  'optimized_size' => (int) $optimized_size,
153
  'percent' => ( 0 !== $optimized_size ) ? ceil( ( ( $original_size - $optimized_size ) / $original_size ) * 100 ) : 0
inc/functions/admin.php CHANGED
@@ -135,4 +135,29 @@ function imagify_dismiss_notice( $notice, $user_id = 0 ) {
135
  $notices = array_unique( $notices );
136
 
137
  update_user_meta( $user_id, '_imagify_ignore_notices', $notices );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
138
  }
135
  $notices = array_unique( $notices );
136
 
137
  update_user_meta( $user_id, '_imagify_ignore_notices', $notices );
138
+ }
139
+
140
+ /**
141
+ * Combine two arrays with some specific keys.
142
+ * We use this function to combine the result of 2 SQL queries.
143
+ *
144
+ * @since 1.4.5
145
+ *
146
+ * @return array $result The combined array
147
+ */
148
+ function imagify_query_results_combine( $keys, $values ) {
149
+ if ( ! $values ) {
150
+ return array();
151
+ }
152
+
153
+ $result = array();
154
+ $keys = array_flip( $keys );
155
+
156
+ foreach ( $values as $v ) {
157
+ if ( isset( $keys[ $v['id'] ] ) ) {
158
+ $result[ $v['id'] ] = $v['value'];
159
+ }
160
+ }
161
+
162
+ return $result;
163
  }
inc/functions/attachments.php CHANGED
@@ -43,4 +43,52 @@ function get_imagify_attachment_backup_path( $file_path ) {
43
 
44
  $backup_path = str_replace( $upload_basedir, $backup_dir, $file_path );
45
  return $backup_path;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
46
  }
43
 
44
  $backup_path = str_replace( $upload_basedir, $backup_dir, $file_path );
45
  return $backup_path;
46
+ }
47
+
48
+ /*
49
+ * Retrieve file path for an attachment based on filename.
50
+ *
51
+ * @since 1.4.5
52
+ *
53
+ * @param int $filename The filename.
54
+ * @return string|false $file_path The file path to where the attached file should be, false otherwise.
55
+ */
56
+ function get_imagify_attached_file( $filename ) {
57
+ $file_path = false;
58
+
59
+ // If the file is relative, prepend upload dir.
60
+ if ( $filename && 0 !== strpos( $filename, '/' ) && ! preg_match( '|^.:\\\|', $filename ) && ( ( $uploads = wp_upload_dir() ) && false === $uploads['error'] ) ) {
61
+ $file_path = $uploads['basedir'] . "/$filename";
62
+ }
63
+
64
+ return $file_path;
65
+ }
66
+
67
+ /*
68
+ * Retrieve the URL for an attachment based on filename.
69
+ *
70
+ * @since 1.4.5
71
+ *
72
+ * @param int $filename The filename.
73
+ * @return string|false $url Attachment URL, otherwise false.
74
+ */
75
+ function get_imagify_attachment_url( $filename ) {
76
+ $url = '';
77
+
78
+ // Get upload directory.
79
+ if ( ( $uploads = wp_upload_dir() ) && false === $uploads['error'] ) {
80
+ // Check that the upload base exists in the file location.
81
+ if ( 0 === strpos( $filename, $uploads['basedir'] ) ) {
82
+ // Replace file location with url location.
83
+ $url = str_replace( $uploads['basedir'], $uploads['baseurl'], $filename );
84
+ } elseif ( false !== strpos( $filename, 'wp-content/uploads' ) ) {
85
+ // Get the directory name relative to the basedir (back compat for pre-2.7 uploads)
86
+ $url = trailingslashit( $uploads['baseurl'] . '/' . _wp_get_attachment_relative_path( $filename ) ) . basename( $filename );
87
+ } else {
88
+ // It's a newly-uploaded file, therefore $file is relative to the basedir.
89
+ $url = $uploads['baseurl'] . "/$filename";
90
+ }
91
+ }
92
+
93
+ return $url;
94
  }
readme.txt CHANGED
@@ -3,11 +3,11 @@ Contributors: wp_media
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.4.2
6
- Stable tag: 1.4.4
7
  License: GPLv2 or later
8
  License URI: http://www.gnu.org/licenses/gpl-2.0.html
9
 
10
- Dramatically reduce image file sizes without loosing quality, make your website load faster, boost your SEO and save money on your bandwidth.
11
 
12
  == Description ==
13
 
@@ -134,6 +134,13 @@ When the plugin is disabled, your existing images remain optimized. Backups of t
134
 
135
  == Changelog ==
136
 
 
 
 
 
 
 
 
137
  = 1.4.4 =
138
  * Interface
139
  * Visual fix: CSS prefixed in notices to avoid class conflicts
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.4.2
6
+ Stable tag: 1.4.5
7
  License: GPLv2 or later
8
  License URI: http://www.gnu.org/licenses/gpl-2.0.html
9
 
10
+ Dramatically reduce image file sizes without losing quality, make your website load faster, boost your SEO and save money on your bandwidth.
11
 
12
  == Description ==
13
 
134
 
135
  == Changelog ==
136
 
137
+ = 1.4.5 =
138
+ * Interface
139
+ * Bulk Optimization: optimize all SQL queries and improve by 65% the process time \o/
140
+ * Misc
141
+ * Chart.js library updated
142
+ * Media List JS notice removed
143
+
144
  = 1.4.4 =
145
  * Interface
146
  * Visual fix: CSS prefixed in notices to avoid class conflicts
uninstall.php CHANGED
@@ -7,6 +7,11 @@ delete_site_option( 'imagify_settings' );
7
 
8
  // Delete all transients
9
  delete_site_transient( 'imagify_check_licence_1' );
 
 
 
 
 
10
 
11
  // Delete all user meta related to Imagify
12
- delete_metadata( 'user', '', '_imagify_ignore_notices', '', true );
7
 
8
  // Delete all transients
9
  delete_site_transient( 'imagify_check_licence_1' );
10
+ delete_site_transient( 'imagify_bulk_optimization_level' );
11
+ delete_site_transient( 'imagify_large_library' );
12
+
13
+ global $wpdb;
14
+ $wpdb->query( 'DELETE from ' . $wpdb->options . ' WHERE option_name LIKE "_transient_imagify-async-in-progress-%"' );
15
 
16
  // Delete all user meta related to Imagify
17
+ delete_metadata( 'user', '', '_imagify_ignore_notices', '', true );