`, and ``.
-@font-family-monospace: Menlo, Monaco, Consolas, "Courier New", monospace;
+@font-family-monospace: Monaco, Menlo, Consolas, "Courier New", monospace;
@font-family-base: @font-family-sans-serif;
@font-size-base: 14px;
-@font-size-large: ceil((@font-size-base * 1.25)); // ~18px
-@font-size-small: ceil((@font-size-base * 0.85)); // ~12px
+@font-size-large: ceil(@font-size-base * 1.25); // ~18px
+@font-size-small: ceil(@font-size-base * 0.85); // ~12px
-@font-size-h1: floor((@font-size-base * 2.6)); // ~36px
-@font-size-h2: floor((@font-size-base * 2.15)); // ~30px
-@font-size-h3: ceil((@font-size-base * 1.7)); // ~24px
-@font-size-h4: ceil((@font-size-base * 1.25)); // ~18px
-@font-size-h5: @font-size-base;
-@font-size-h6: ceil((@font-size-base * 0.85)); // ~12px
-
-//** Unit-less `line-height` for use in components like buttons.
@line-height-base: 1.428571429; // 20/14
-//** Computed "line-height" (`font-size` * `line-height`) for use with `margin`, `padding`, etc.
-@line-height-computed: floor((@font-size-base * @line-height-base)); // ~20px
+@line-height-computed: floor(@font-size-base * @line-height-base); // ~20px
-//** By default, this inherits from the ``.
-@headings-font-family: inherit;
+@headings-font-family: @font-family-base;
@headings-font-weight: 500;
@headings-line-height: 1.1;
-@headings-color: inherit;
+// Iconography
+// -------------------------
-//== Iconography
-//
-//## Specify custom location and filename of the included Glyphicons icon font. Useful for those including Bootstrap via Bower.
-
-//** Load fonts from this directory.
@icon-font-path: "../fonts/";
-//** File name for all font files.
@icon-font-name: "glyphicons-halflings-regular";
-//** Element ID within SVG icon file.
-@icon-font-svg-id: "glyphicons_halflingsregular";
-//== Components
-//
-//## Define common padding and border radius sizes and more. Values based on 14px text and 1.428 line-height (~20px to start).
+// Components
+// -------------------------
+// Based on 14px font-size and 1.428 line-height (~20px to start)
-@padding-base-vertical: 6px;
-@padding-base-horizontal: 12px;
+@padding-base-vertical: 6px;
+@padding-base-horizontal: 12px;
-@padding-large-vertical: 10px;
-@padding-large-horizontal: 16px;
+@padding-large-vertical: 10px;
+@padding-large-horizontal: 16px;
-@padding-small-vertical: 5px;
-@padding-small-horizontal: 10px;
+@padding-small-vertical: 5px;
+@padding-small-horizontal: 10px;
-@padding-xs-vertical: 1px;
-@padding-xs-horizontal: 5px;
+@line-height-large: 1.33;
+@line-height-small: 1.5;
-@line-height-large: 1.33;
-@line-height-small: 1.5;
+@border-radius-base: 4px;
+@border-radius-large: 6px;
+@border-radius-small: 3px;
-@border-radius-base: 4px;
-@border-radius-large: 6px;
-@border-radius-small: 3px;
+@component-active-bg: @brand-primary;
-//** Global color for active items (e.g., navs or dropdowns).
-@component-active-color: #fff;
-//** Global background color for active items (e.g., navs or dropdowns).
-@component-active-bg: @brand-primary;
+@caret-width-base: 4px;
+@caret-width-large: 5px;
-//** Width of the `border` for generating carets that indicator dropdowns.
-@caret-width-base: 4px;
-//** Carets increase slightly in size for larger components.
-@caret-width-large: 5px;
+// Tables
+// -------------------------
+
+@table-cell-padding: 8px;
+@table-condensed-cell-padding: 5px;
+
+@table-bg: transparent; // overall background-color
+@table-bg-accent: #f9f9f9; // for striping
+@table-bg-hover: #f5f5f5;
+@table-bg-active: @table-bg-hover;
+
+@table-border-color: #ddd; // table and cell border
-//== Tables
-//
-//## Customizes the `.table` component with basic values, each used across all table variations.
-
-//** Padding for ``s and ` `s.
-@table-cell-padding: 8px;
-//** Padding for cells in `.table-condensed`.
-@table-condensed-cell-padding: 5px;
-
-//** Default background color used for all tables.
-@table-bg: transparent;
-//** Background color used for `.table-striped`.
-@table-bg-accent: #f9f9f9;
-//** Background color used for `.table-hover`.
-@table-bg-hover: #f5f5f5;
-@table-bg-active: @table-bg-hover;
-
-//** Border color for table and cell borders.
-@table-border-color: #ddd;
-
-
-//== Buttons
-//
-//## For each of Bootstrap's buttons, define text, background and border color.
+// Buttons
+// -------------------------
@btn-font-weight: normal;
@@ -153,10 +118,6 @@
@btn-success-bg: @brand-success;
@btn-success-border: darken(@btn-success-bg, 5%);
-@btn-info-color: #fff;
-@btn-info-bg: @brand-info;
-@btn-info-border: darken(@btn-info-bg, 5%);
-
@btn-warning-color: #fff;
@btn-warning-bg: @brand-warning;
@btn-warning-border: darken(@btn-warning-bg, 5%);
@@ -165,186 +126,124 @@
@btn-danger-bg: @brand-danger;
@btn-danger-border: darken(@btn-danger-bg, 5%);
+@btn-info-color: #fff;
+@btn-info-bg: @brand-info;
+@btn-info-border: darken(@btn-info-bg, 5%);
+
@btn-link-disabled-color: @gray-light;
-//== Forms
-//
-//##
+// Forms
+// -------------------------
-//** ` ` background color
@input-bg: #fff;
-//** ` ` background color
@input-bg-disabled: @gray-lighter;
-//** Text color for ` `s
@input-color: @gray;
-//** ` ` border color
@input-border: #ccc;
-//** ` ` border radius
@input-border-radius: @border-radius-base;
-//** Border color for inputs on focus
@input-border-focus: #66afe9;
-//** Placeholder text color
@input-color-placeholder: @gray-light;
-//** Default `.form-control` height
@input-height-base: (@line-height-computed + (@padding-base-vertical * 2) + 2);
-//** Large `.form-control` height
-@input-height-large: (ceil(@font-size-large * @line-height-large) + (@padding-large-vertical * 2) + 2);
-//** Small `.form-control` height
+@input-height-large: (floor(@font-size-large * @line-height-large) + (@padding-large-vertical * 2) + 2);
@input-height-small: (floor(@font-size-small * @line-height-small) + (@padding-small-vertical * 2) + 2);
@legend-color: @gray-dark;
@legend-border-color: #e5e5e5;
-//** Background color for textual input addons
@input-group-addon-bg: @gray-lighter;
-//** Border color for textual input addons
@input-group-addon-border-color: @input-border;
-//== Dropdowns
-//
-//## Dropdown menu container and contents.
+// Dropdowns
+// -------------------------
-//** Background for the dropdown menu.
@dropdown-bg: #fff;
-//** Dropdown menu `border-color`.
@dropdown-border: rgba(0,0,0,.15);
-//** Dropdown menu `border-color` **for IE8**.
@dropdown-fallback-border: #ccc;
-//** Divider color for between dropdown items.
@dropdown-divider-bg: #e5e5e5;
-//** Dropdown link text color.
-@dropdown-link-color: @gray-dark;
-//** Hover color for dropdown links.
-@dropdown-link-hover-color: darken(@gray-dark, 5%);
-//** Hover background for dropdown links.
-@dropdown-link-hover-bg: #f5f5f5;
-
-//** Active dropdown menu item text color.
-@dropdown-link-active-color: @component-active-color;
-//** Active dropdown menu item background color.
+@dropdown-link-active-color: #fff;
@dropdown-link-active-bg: @component-active-bg;
-//** Disabled dropdown menu item background color.
+@dropdown-link-color: @gray-dark;
+@dropdown-link-hover-color: #fff;
+@dropdown-link-hover-bg: @dropdown-link-active-bg;
+
@dropdown-link-disabled-color: @gray-light;
-//** Text color for headers within dropdown menus.
@dropdown-header-color: @gray-light;
-//** Deprecated `@dropdown-caret-color` as of v3.1.0
@dropdown-caret-color: #000;
-//-- Z-index master list
-//
-// Warning: Avoid customizing these values. They're used for a bird's eye view
-// of components dependent on the z-axis and are designed to all work together.
-//
-// Note: These variables are not generated into the Customizer.
+// COMPONENT VARIABLES
+// --------------------------------------------------
+
+
+// Z-index master list
+// -------------------------
+// Used for a bird's eye view of components dependent on the z-axis
+// Try to avoid customizing these :)
@zindex-navbar: 1000;
@zindex-dropdown: 1000;
-@zindex-popover: 1060;
-@zindex-tooltip: 1070;
+@zindex-popover: 1010;
+@zindex-tooltip: 1030;
@zindex-navbar-fixed: 1030;
@zindex-modal-background: 1040;
@zindex-modal: 1050;
-
-//== Media queries breakpoints
-//
-//## Define the breakpoints at which your layout will change, adapting to different screen sizes.
+// Media queries breakpoints
+// --------------------------------------------------
// Extra small screen / phone
-//** Deprecated `@screen-xs` as of v3.0.1
@screen-xs: 480px;
-//** Deprecated `@screen-xs-min` as of v3.2.0
-@screen-xs-min: @screen-xs;
-//** Deprecated `@screen-phone` as of v3.0.1
-@screen-phone: @screen-xs-min;
+@screen-phone: @screen-xs;
// Small screen / tablet
-//** Deprecated `@screen-sm` as of v3.0.1
@screen-sm: 768px;
-@screen-sm-min: @screen-sm;
-//** Deprecated `@screen-tablet` as of v3.0.1
-@screen-tablet: @screen-sm-min;
+@screen-tablet: @screen-sm;
// Medium screen / desktop
-//** Deprecated `@screen-md` as of v3.0.1
@screen-md: 992px;
-@screen-md-min: @screen-md;
-//** Deprecated `@screen-desktop` as of v3.0.1
-@screen-desktop: @screen-md-min;
+@screen-desktop: @screen-md;
// Large screen / wide desktop
-//** Deprecated `@screen-lg` as of v3.0.1
@screen-lg: 1200px;
-@screen-lg-min: @screen-lg;
-//** Deprecated `@screen-lg-desktop` as of v3.0.1
-@screen-lg-desktop: @screen-lg-min;
+@screen-lg-desktop: @screen-lg;
// So media queries don't overlap when required, provide a maximum
-@screen-xs-max: (@screen-sm-min - 1);
-@screen-sm-max: (@screen-md-min - 1);
-@screen-md-max: (@screen-lg-min - 1);
+@screen-xs-max: (@screen-sm - 1);
+@screen-sm-max: (@screen-md - 1);
+@screen-md-max: (@screen-lg - 1);
-//== Grid system
-//
-//## Define your custom responsive grid.
+// Grid system
+// --------------------------------------------------
-//** Number of columns in the grid.
+// Number of columns in the grid system
@grid-columns: 12;
-//** Padding between columns. Gets divided in half for the left and right.
+// Padding, to be divided by two and applied to the left and right of all columns
@grid-gutter-width: 30px;
-// Navbar collapse
-//** Point at which the navbar becomes uncollapsed.
-@grid-float-breakpoint: @screen-sm-min;
-//** Point at which the navbar begins collapsing.
-@grid-float-breakpoint-max: (@grid-float-breakpoint - 1);
+// Point at which the navbar stops collapsing
+@grid-float-breakpoint: @screen-tablet;
-//== Container sizes
-//
-//## Define the maximum width of `.container` for different screen sizes.
-
-// Small screen / tablet
-@container-tablet: ((720px + @grid-gutter-width));
-//** For `@screen-sm-min` and up.
-@container-sm: @container-tablet;
-
-// Medium screen / desktop
-@container-desktop: ((940px + @grid-gutter-width));
-//** For `@screen-md-min` and up.
-@container-md: @container-desktop;
-
-// Large screen / wide desktop
-@container-large-desktop: ((1140px + @grid-gutter-width));
-//** For `@screen-lg-min` and up.
-@container-lg: @container-large-desktop;
-
-
-//== Navbar
-//
-//##
+// Navbar
+// -------------------------
// Basics of a navbar
@navbar-height: 50px;
@navbar-margin-bottom: @line-height-computed;
-@navbar-border-radius: @border-radius-base;
-@navbar-padding-horizontal: floor((@grid-gutter-width / 2));
-@navbar-padding-vertical: ((@navbar-height - @line-height-computed) / 2);
-@navbar-collapse-max-height: 340px;
-
@navbar-default-color: #777;
@navbar-default-bg: #f8f8f8;
@navbar-default-border: darken(@navbar-default-bg, 6.5%);
+@navbar-border-radius: @border-radius-base;
+@navbar-padding-horizontal: floor(@grid-gutter-width / 2);
+@navbar-padding-vertical: ((@navbar-height - @line-height-computed) / 2);
// Navbar links
@navbar-default-link-color: #777;
@@ -357,16 +256,17 @@
// Navbar brand label
@navbar-default-brand-color: @navbar-default-link-color;
-@navbar-default-brand-hover-color: darken(@navbar-default-brand-color, 10%);
+@navbar-default-brand-hover-color: darken(@navbar-default-link-color, 10%);
@navbar-default-brand-hover-bg: transparent;
// Navbar toggle
@navbar-default-toggle-hover-bg: #ddd;
-@navbar-default-toggle-icon-bar-bg: #888;
+@navbar-default-toggle-icon-bar-bg: #ccc;
@navbar-default-toggle-border-color: #ddd;
// Inverted navbar
+//
// Reset inverted navbar basics
@navbar-inverse-color: @gray-light;
@navbar-inverse-bg: #222;
@@ -386,17 +286,22 @@
@navbar-inverse-brand-hover-color: #fff;
@navbar-inverse-brand-hover-bg: transparent;
+// Inverted navbar search
+// Normal navbar needs no special styles or vars
+@navbar-inverse-search-bg: lighten(@navbar-inverse-bg, 25%);
+@navbar-inverse-search-bg-focus: #fff;
+@navbar-inverse-search-border: @navbar-inverse-bg;
+@navbar-inverse-search-placeholder-color: #ccc;
+
// Inverted navbar toggle
@navbar-inverse-toggle-hover-bg: #333;
@navbar-inverse-toggle-icon-bar-bg: #fff;
@navbar-inverse-toggle-border-color: #333;
-//== Navs
-//
-//##
+// Navs
+// -------------------------
-//=== Shared nav styles
@nav-link-padding: 10px 15px;
@nav-link-hover-bg: @gray-lighter;
@@ -404,8 +309,9 @@
@nav-disabled-link-hover-color: @gray-light;
@nav-open-link-hover-color: #fff;
+@nav-open-caret-border-color: #fff;
-//== Tabs
+// Tabs
@nav-tabs-border-color: #ddd;
@nav-tabs-link-hover-border-color: @gray-lighter;
@@ -417,188 +323,121 @@
@nav-tabs-justified-link-border-color: #ddd;
@nav-tabs-justified-active-link-border-color: @body-bg;
-//== Pills
-@nav-pills-border-radius: @border-radius-base;
+// Pills
@nav-pills-active-link-hover-bg: @component-active-bg;
-@nav-pills-active-link-hover-color: @component-active-color;
+@nav-pills-active-link-hover-color: #fff;
-//== Pagination
-//
-//##
+// Pagination
+// -------------------------
-@pagination-color: @link-color;
@pagination-bg: #fff;
@pagination-border: #ddd;
-@pagination-hover-color: @link-hover-color;
@pagination-hover-bg: @gray-lighter;
-@pagination-hover-border: #ddd;
-@pagination-active-color: #fff;
@pagination-active-bg: @brand-primary;
-@pagination-active-border: @brand-primary;
+@pagination-active-color: #fff;
@pagination-disabled-color: @gray-light;
-@pagination-disabled-bg: #fff;
-@pagination-disabled-border: #ddd;
-//== Pager
-//
-//##
+// Pager
+// -------------------------
-@pager-bg: @pagination-bg;
-@pager-border: @pagination-border;
@pager-border-radius: 15px;
-
-@pager-hover-bg: @pagination-hover-bg;
-
-@pager-active-bg: @pagination-active-bg;
-@pager-active-color: @pagination-active-color;
-
-@pager-disabled-color: @pagination-disabled-color;
+@pager-disabled-color: @gray-light;
-//== Jumbotron
-//
-//##
+// Jumbotron
+// -------------------------
@jumbotron-padding: 30px;
@jumbotron-color: inherit;
@jumbotron-bg: @gray-lighter;
+
@jumbotron-heading-color: inherit;
-@jumbotron-font-size: ceil((@font-size-base * 1.5));
-//== Form states and alerts
-//
-//## Define colors for form feedback states and, by default, alerts.
+// Form states and alerts
+// -------------------------
-@state-success-text: #3c763d;
+@state-warning-text: #c09853;
+@state-warning-bg: #fcf8e3;
+@state-warning-border: darken(spin(@state-warning-bg, -10), 3%);
+
+@state-danger-text: #b94a48;
+@state-danger-bg: #f2dede;
+@state-danger-border: darken(spin(@state-danger-bg, -10), 3%);
+
+@state-success-text: #468847;
@state-success-bg: #dff0d8;
@state-success-border: darken(spin(@state-success-bg, -10), 5%);
-@state-info-text: #31708f;
+@state-info-text: #3a87ad;
@state-info-bg: #d9edf7;
@state-info-border: darken(spin(@state-info-bg, -10), 7%);
-@state-warning-text: #8a6d3b;
-@state-warning-bg: #fcf8e3;
-@state-warning-border: darken(spin(@state-warning-bg, -10), 5%);
-@state-danger-text: #a94442;
-@state-danger-bg: #f2dede;
-@state-danger-border: darken(spin(@state-danger-bg, -10), 5%);
-
-
-//== Tooltips
-//
-//##
-
-//** Tooltip max width
+// Tooltips
+// -------------------------
@tooltip-max-width: 200px;
-//** Tooltip text color
@tooltip-color: #fff;
-//** Tooltip background color
@tooltip-bg: #000;
-@tooltip-opacity: .9;
-//** Tooltip arrow width
@tooltip-arrow-width: 5px;
-//** Tooltip arrow color
@tooltip-arrow-color: @tooltip-bg;
-//== Popovers
-//
-//##
-
-//** Popover body background color
+// Popovers
+// -------------------------
@popover-bg: #fff;
-//** Popover maximum width
@popover-max-width: 276px;
-//** Popover border color
@popover-border-color: rgba(0,0,0,.2);
-//** Popover fallback border color
@popover-fallback-border-color: #ccc;
-//** Popover title background color
@popover-title-bg: darken(@popover-bg, 3%);
-//** Popover arrow width
@popover-arrow-width: 10px;
-//** Popover arrow color
@popover-arrow-color: #fff;
-//** Popover outer arrow width
@popover-arrow-outer-width: (@popover-arrow-width + 1);
-//** Popover outer arrow color
-@popover-arrow-outer-color: fadein(@popover-border-color, 5%);
-//** Popover outer arrow fallback color
-@popover-arrow-outer-fallback-color: darken(@popover-fallback-border-color, 20%);
+@popover-arrow-outer-color: rgba(0,0,0,.25);
+@popover-arrow-outer-fallback-color: #999;
-//== Labels
-//
-//##
+// Labels
+// -------------------------
-//** Default label background color
@label-default-bg: @gray-light;
-//** Primary label background color
@label-primary-bg: @brand-primary;
-//** Success label background color
@label-success-bg: @brand-success;
-//** Info label background color
@label-info-bg: @brand-info;
-//** Warning label background color
@label-warning-bg: @brand-warning;
-//** Danger label background color
@label-danger-bg: @brand-danger;
-//** Default label text color
@label-color: #fff;
-//** Default text color of a linked label
@label-link-hover-color: #fff;
-//== Modals
-//
-//##
+// Modals
+// -------------------------
+@modal-inner-padding: 20px;
-//** Padding applied to the modal body
-@modal-inner-padding: 15px;
-
-//** Padding applied to the modal title
@modal-title-padding: 15px;
-//** Modal title line-height
@modal-title-line-height: @line-height-base;
-//** Background color of modal content area
@modal-content-bg: #fff;
-//** Modal content border color
@modal-content-border-color: rgba(0,0,0,.2);
-//** Modal content border color **for IE8**
@modal-content-fallback-border-color: #999;
-//** Modal backdrop background color
@modal-backdrop-bg: #000;
-//** Modal backdrop opacity
-@modal-backdrop-opacity: .5;
-//** Modal header border color
@modal-header-border-color: #e5e5e5;
-//** Modal footer border color
@modal-footer-border-color: @modal-header-border-color;
-@modal-lg: 900px;
-@modal-md: 600px;
-@modal-sm: 300px;
-
-
-//== Alerts
-//
-//## Define alert colors, border radius, and padding.
+// Alerts
+// -------------------------
@alert-padding: 15px;
@alert-border-radius: @border-radius-base;
@alert-link-font-weight: bold;
@@ -620,73 +459,38 @@
@alert-danger-border: @state-danger-border;
-//== Progress bars
-//
-//##
-
-//** Background color of the whole progress component
+// Progress bars
+// -------------------------
@progress-bg: #f5f5f5;
-//** Progress bar text color
@progress-bar-color: #fff;
-//** Default progress bar color
@progress-bar-bg: @brand-primary;
-//** Success progress bar color
@progress-bar-success-bg: @brand-success;
-//** Warning progress bar color
@progress-bar-warning-bg: @brand-warning;
-//** Danger progress bar color
@progress-bar-danger-bg: @brand-danger;
-//** Info progress bar color
@progress-bar-info-bg: @brand-info;
-//== List group
-//
-//##
+// List group
+// -------------------------
+@list-group-bg: #fff;
+@list-group-border: #ddd;
+@list-group-border-radius: @border-radius-base;
-//** Background color on `.list-group-item`
-@list-group-bg: #fff;
-//** `.list-group-item` border color
-@list-group-border: #ddd;
-//** List group border radius
-@list-group-border-radius: @border-radius-base;
+@list-group-hover-bg: #f5f5f5;
+@list-group-active-color: #fff;
+@list-group-active-bg: @component-active-bg;
+@list-group-active-border: @list-group-active-bg;
-//** Background color of single list items on hover
-@list-group-hover-bg: #f5f5f5;
-//** Text color of active list items
-@list-group-active-color: @component-active-color;
-//** Background color of active list items
-@list-group-active-bg: @component-active-bg;
-//** Border color of active list elements
-@list-group-active-border: @list-group-active-bg;
-//** Text color for content within active list items
-@list-group-active-text-color: lighten(@list-group-active-bg, 40%);
-
-//** Text color of disabled list items
-@list-group-disabled-color: @gray-light;
-//** Background color of disabled list items
-@list-group-disabled-bg: @gray-lighter;
-//** Text color for content within disabled list items
-@list-group-disabled-text-color: @list-group-disabled-color;
-
-@list-group-link-color: #555;
-@list-group-link-hover-color: @list-group-link-color;
-@list-group-link-heading-color: #333;
+@list-group-link-color: #555;
+@list-group-link-heading-color: #333;
-//== Panels
-//
-//##
-
+// Panels
+// -------------------------
@panel-bg: #fff;
-@panel-body-padding: 15px;
-@panel-heading-padding: 10px 15px;
-@panel-footer-padding: @panel-heading-padding;
-@panel-border-radius: @border-radius-base;
-
-//** Border color for elements within panels
@panel-inner-border: #ddd;
+@panel-border-radius: @border-radius-base;
@panel-footer-bg: #f5f5f5;
@panel-default-text: @gray-dark;
@@ -701,10 +505,6 @@
@panel-success-border: @state-success-border;
@panel-success-heading-bg: @state-success-bg;
-@panel-info-text: @state-info-text;
-@panel-info-border: @state-info-border;
-@panel-info-heading-bg: @state-info-bg;
-
@panel-warning-text: @state-warning-text;
@panel-warning-border: @state-warning-border;
@panel-warning-heading-bg: @state-warning-bg;
@@ -713,46 +513,34 @@
@panel-danger-border: @state-danger-border;
@panel-danger-heading-bg: @state-danger-bg;
+@panel-info-text: @state-info-text;
+@panel-info-border: @state-info-border;
+@panel-info-heading-bg: @state-info-bg;
-//== Thumbnails
-//
-//##
-//** Padding around the thumbnail image
+// Thumbnails
+// -------------------------
@thumbnail-padding: 4px;
-//** Thumbnail background color
@thumbnail-bg: @body-bg;
-//** Thumbnail border color
@thumbnail-border: #ddd;
-//** Thumbnail border radius
@thumbnail-border-radius: @border-radius-base;
-//** Custom text color for thumbnail captions
@thumbnail-caption-color: @text-color;
-//** Padding around the thumbnail caption
@thumbnail-caption-padding: 9px;
-//== Wells
-//
-//##
-
+// Wells
+// -------------------------
@well-bg: #f5f5f5;
-@well-border: darken(@well-bg, 7%);
-//== Badges
-//
-//##
-
+// Badges
+// -------------------------
@badge-color: #fff;
-//** Linked badge text color on hover
@badge-link-hover-color: #fff;
@badge-bg: @gray-light;
-//** Badge text color in active nav link
@badge-active-color: @link-color;
-//** Badge background color in active nav link
@badge-active-bg: #fff;
@badge-font-weight: bold;
@@ -760,25 +548,15 @@
@badge-border-radius: 10px;
-//== Breadcrumbs
-//
-//##
-
-@breadcrumb-padding-vertical: 8px;
-@breadcrumb-padding-horizontal: 15px;
-//** Breadcrumb background color
-@breadcrumb-bg: #f5f5f5;
-//** Breadcrumb text color
-@breadcrumb-color: #ccc;
-//** Text color of current page in the breadcrumb
-@breadcrumb-active-color: @gray-light;
-//** Textual separator for between breadcrumb elements
-@breadcrumb-separator: "/";
+// Breadcrumbs
+// -------------------------
+@breadcrumb-bg: #f5f5f5;
+@breadcrumb-color: #ccc;
+@breadcrumb-active-color: @gray-light;
-//== Carousel
-//
-//##
+// Carousel
+// ------------------------
@carousel-text-shadow: 0 1px 2px rgba(0,0,0,.6);
@@ -793,54 +571,50 @@
@carousel-caption-color: #fff;
-//== Close
-//
-//##
-
-@close-font-weight: bold;
+// Close
+// ------------------------
@close-color: #000;
+@close-font-weight: bold;
@close-text-shadow: 0 1px 0 #fff;
-//== Code
-//
-//##
-
+// Code
+// ------------------------
@code-color: #c7254e;
@code-bg: #f9f2f4;
-@kbd-color: #fff;
-@kbd-bg: #333;
-
@pre-bg: #f5f5f5;
@pre-color: @gray-dark;
@pre-border-color: #ccc;
@pre-scrollable-max-height: 340px;
-
-//== Type
-//
-//##
-
-//** Horizontal offset for forms and lists.
-@component-offset-horizontal: 180px;
-//** Text muted color
+// Type
+// ------------------------
@text-muted: @gray-light;
-//** Abbreviations and acronyms border color
@abbr-border-color: @gray-light;
-//** Headings small color
@headings-small-color: @gray-light;
-//** Blockquote small color
@blockquote-small-color: @gray-light;
-//** Blockquote font size
-@blockquote-font-size: (@font-size-base * 1.25);
-//** Blockquote border color
@blockquote-border-color: @gray-lighter;
-//** Page header border color
@page-header-border-color: @gray-lighter;
-//** Width of horizontal description list titles
-@dl-horizontal-offset: @component-offset-horizontal;
-//** Horizontal line color.
+
+// Miscellaneous
+// -------------------------
+
+// Hr border color
@hr-border: @gray-lighter;
+// Horizontal forms & lists
+@component-offset-horizontal: 180px;
+
+// Container sizes
+// --------------------------------------------------
+
+// Small screen / tablet
+@container-tablet: ((720px + @grid-gutter-width));
+
+// Medium screen / desktop
+@container-desktop: ((940px + @grid-gutter-width));
+
+// Large screen / wide desktop
+@container-lg-desktop: ((1140px + @grid-gutter-width));
diff --git a/public/vendor/bootstrap/less/wells.less b/public/vendor/bootstrap/less/wells.less
index 15d072b0..865abc2e 100644
--- a/public/vendor/bootstrap/less/wells.less
+++ b/public/vendor/bootstrap/less/wells.less
@@ -9,7 +9,7 @@
padding: 19px;
margin-bottom: 20px;
background-color: @well-bg;
- border: 1px solid @well-border;
+ border: 1px solid darken(@well-bg, 7%);
border-radius: @border-radius-base;
.box-shadow(inset 0 1px 1px rgba(0,0,0,.05));
blockquote {
diff --git a/public/vendor/bootstrap/package.json b/public/vendor/bootstrap/package.json
index 3243fa8b..71f7aa5b 100644
--- a/public/vendor/bootstrap/package.json
+++ b/public/vendor/bootstrap/package.json
@@ -1,81 +1,34 @@
{
- "name": "bootstrap",
- "description": "The most popular front-end framework for developing responsive, mobile first projects on the web.",
- "version": "3.2.0",
- "keywords": [
- "css",
- "less",
- "mobile-first",
- "responsive",
- "front-end",
- "framework",
- "web"
- ],
- "homepage": "http://getbootstrap.com",
- "author": "Twitter, Inc.",
- "scripts": {
- "test": "grunt test"
- },
- "style": "dist/css/bootstrap.css",
- "less": "less/bootstrap.less",
- "repository": {
- "type": "git",
- "url": "https://github.com/twbs/bootstrap.git"
- },
- "bugs": {
- "url": "https://github.com/twbs/bootstrap/issues"
- },
- "license": {
- "type": "MIT",
- "url": "https://github.com/twbs/bootstrap/blob/master/LICENSE"
- },
- "devDependencies": {
- "btoa": "~1.1.2",
- "glob": "~4.0.2",
- "grunt": "~0.4.5",
- "grunt-autoprefixer": "~0.7.6",
- "grunt-banner": "~0.2.3",
- "grunt-contrib-clean": "~0.5.0",
- "grunt-contrib-concat": "~0.4.0",
- "grunt-contrib-connect": "~0.8.0",
- "grunt-contrib-copy": "~0.5.0",
- "grunt-contrib-csslint": "~0.2.0",
- "grunt-contrib-cssmin": "~0.10.0",
- "grunt-contrib-jade": "~0.12.0",
- "grunt-contrib-jshint": "~0.10.0",
- "grunt-contrib-less": "~0.11.3",
- "grunt-contrib-qunit": "~0.5.1",
- "grunt-contrib-uglify": "~0.5.0",
- "grunt-contrib-watch": "~0.6.1",
- "grunt-csscomb": "~2.0.1",
- "grunt-exec": "~0.4.5",
- "grunt-html-validation": "~0.1.18",
- "grunt-jekyll": "~0.4.2",
- "grunt-jscs-checker": "~0.6.0",
- "grunt-saucelabs": "~8.1.0",
- "grunt-sed": "~0.1.1",
- "load-grunt-tasks": "~0.6.0",
- "markdown": "~0.5.0",
- "npm-shrinkwrap": "~3.1.6",
- "time-grunt": "~0.3.2"
- },
- "engines": {
- "node": "~0.10.1"
- },
- "jspm": {
- "main": "js/bootstrap",
- "directories": {
- "example": "examples",
- "lib": "dist"
- },
- "shim": {
- "js/bootstrap": {
- "imports": "jquery",
- "exports": "$"
- }
- },
- "buildConfig": {
- "uglify": true
+ "name": "bootstrap"
+ , "description": "Sleek, intuitive, and powerful front-end framework for faster and easier web development."
+ , "version": "3.0.0"
+ , "keywords": ["bootstrap", "css"]
+ , "homepage": "http://twbs.github.com/bootstrap/"
+ , "author": "Twitter Inc."
+ , "scripts": { "test": "grunt test" }
+ , "repository": {
+ "type": "git"
+ , "url": "https://github.com/twbs/bootstrap.git"
+ }
+ , "licenses": [
+ {
+ "type": "Apache-2.0"
+ , "url": "http://www.apache.org/licenses/LICENSE-2.0"
}
+ ]
+ , "devDependencies": {
+ "grunt": "~0.4.1"
+ , "grunt-contrib-clean": "~0.5.0"
+ , "grunt-contrib-connect": "~0.3.0"
+ , "grunt-contrib-concat": "~0.3.0"
+ , "grunt-contrib-copy": "~0.4.0"
+ , "grunt-contrib-jshint": "~0.6.0"
+ , "grunt-contrib-uglify": "~0.2.2"
+ , "grunt-contrib-qunit": "~0.2.2"
+ , "grunt-contrib-watch": "~0.5.1"
+ , "grunt-html-validation": "git://github.com/praveenvijayan/grunt-html-validation.git"
+ , "grunt-jekyll": "~0.3.8"
+ , "grunt-recess": "~0.3.3"
+ , "browserstack-runner": "~0.0.11"
}
}
diff --git a/public/vendor/chartjs/.bower.json b/public/vendor/chartjs/.bower.json
index 981233a6..21f81d69 100644
--- a/public/vendor/chartjs/.bower.json
+++ b/public/vendor/chartjs/.bower.json
@@ -1,23 +1,22 @@
{
"name": "Chart.js",
- "version": "0.2.0",
+ "version": "2.0.0-beta2",
"description": "Simple HTML5 Charts using the canvas element",
- "keywords": [
- "charts"
- ],
"homepage": "https://github.com/nnnick/Chart.js",
"author": "nnnick",
"main": [
- "Chart.min.js"
+ "Chart.js"
],
- "dependencies": {},
- "_release": "0.2.0",
+ "devDependencies": {
+ "jquery": "~2.1.4"
+ },
+ "_release": "2.0.0-beta2",
"_resolution": {
"type": "version",
- "tag": "v0.2.0",
- "commit": "8f025f33c08c66991a12f02f908bab156a963aef"
+ "tag": "2.0.0-beta2",
+ "commit": "5a5d698b11ac7915ab640fd01e7a001f6a7b25e7"
},
"_source": "git://github.com/nnnick/Chart.js.git",
- "_target": "~0.2.0",
+ "_target": "~2.0.0-beta2",
"_originalSource": "chartjs"
}
\ No newline at end of file
diff --git a/public/vendor/chartjs/.gitignore b/public/vendor/chartjs/.gitignore
index 9bea4330..5b80f24c 100644
--- a/public/vendor/chartjs/.gitignore
+++ b/public/vendor/chartjs/.gitignore
@@ -1,2 +1,11 @@
.DS_Store
+
+node_modules/*
+custom/*
+
+docs/index.md
+
+bower_components/
+
+coverage/*
diff --git a/public/vendor/chartjs/Chart.js b/public/vendor/chartjs/Chart.js
index ffbe16f3..5b58703a 100644
--- a/public/vendor/chartjs/Chart.js
+++ b/public/vendor/chartjs/Chart.js
@@ -1,1426 +1,7210 @@
+;(function(root, factory) {
+ if (typeof define === 'function' && define.amd) {
+ define(['moment'], factory);
+ } else if (typeof exports === 'object') {
+ module.exports = factory.call(root,require('moment'));
+ } else {
+ root.Chart = factory.call(root,root.moment);
+ }
+}(this, function(moment) {
+!function e(r,t,n){function a(i,u){if(!t[i]){if(!r[i]){var l="function"==typeof require&&require;if(!u&&l)return l(i,!0);if(s)return s(i,!0);var h=new Error("Cannot find module '"+i+"'");throw h.code="MODULE_NOT_FOUND",h}var o=t[i]={exports:{}};r[i][0].call(o.exports,function(e){var t=r[i][1][e];return a(t?t:e)},o,o.exports,e,r,t,n)}return t[i].exports}for(var s="function"==typeof require&&require,i=0;i=n?n/12.92:Math.pow((n+.055)/1.055,2.4)}return.2126*r[0]+.7152*r[1]+.0722*r[2]},contrast:function(e){var r=this.luminosity(),t=e.luminosity();return r>t?(r+.05)/(t+.05):(t+.05)/(r+.05)},level:function(e){var r=this.contrast(e);return r>=7.1?"AAA":r>=4.5?"AA":""},dark:function(){var e=this.values.rgb,r=(299*e[0]+587*e[1]+114*e[2])/1e3;return 128>r},light:function(){return!this.dark()},negate:function(){for(var e=[],r=0;3>r;r++)e[r]=255-this.values.rgb[r];return this.setValues("rgb",e),this},lighten:function(e){return this.values.hsl[2]+=this.values.hsl[2]*e,this.setValues("hsl",this.values.hsl),this},darken:function(e){return this.values.hsl[2]-=this.values.hsl[2]*e,this.setValues("hsl",this.values.hsl),this},saturate:function(e){return this.values.hsl[1]+=this.values.hsl[1]*e,this.setValues("hsl",this.values.hsl),this},desaturate:function(e){return this.values.hsl[1]-=this.values.hsl[1]*e,this.setValues("hsl",this.values.hsl),this},whiten:function(e){return this.values.hwb[1]+=this.values.hwb[1]*e,this.setValues("hwb",this.values.hwb),this},blacken:function(e){return this.values.hwb[2]+=this.values.hwb[2]*e,this.setValues("hwb",this.values.hwb),this},greyscale:function(){var e=this.values.rgb,r=.3*e[0]+.59*e[1]+.11*e[2];return this.setValues("rgb",[r,r,r]),this},clearer:function(e){return this.setValues("alpha",this.values.alpha-this.values.alpha*e),this},opaquer:function(e){return this.setValues("alpha",this.values.alpha+this.values.alpha*e),this},rotate:function(e){var r=this.values.hsl[0];return r=(r+e)%360,r=0>r?360+r:r,this.values.hsl[0]=r,this.setValues("hsl",this.values.hsl),this},mix:function(e,r){r=1-(null==r?.5:r);for(var t=2*r-1,n=this.alpha()-e.alpha(),a=((t*n==-1?t:(t+n)/(1+t*n))+1)/2,s=1-a,i=this.rgbArray(),u=e.rgbArray(),l=0;lr&&(r+=360),n=(u+l)/2,t=l==u?0:.5>=n?h/(l+u):h/(2-l-u),[r,100*t,100*n]}function s(e){var r,t,n,a=e[0],s=e[1],i=e[2],u=Math.min(a,s,i),l=Math.max(a,s,i),h=l-u;return t=0==l?0:h/l*1e3/10,l==u?r=0:a==l?r=(s-i)/h:s==l?r=2+(i-a)/h:i==l&&(r=4+(a-s)/h),r=Math.min(60*r,360),0>r&&(r+=360),n=l/255*1e3/10,[r,t,n]}function i(e){var r=e[0],t=e[1],n=e[2],s=a(e)[0],i=1/255*Math.min(r,Math.min(t,n)),n=1-1/255*Math.max(r,Math.max(t,n));return[s,100*i,100*n]}function u(e){var r,t,n,a,s=e[0]/255,i=e[1]/255,u=e[2]/255;return a=Math.min(1-s,1-i,1-u),r=(1-s-a)/(1-a)||0,t=(1-i-a)/(1-a)||0,n=(1-u-a)/(1-a)||0,[100*r,100*t,100*n,100*a]}function l(e){return X[JSON.stringify(e)]}function h(e){var r=e[0]/255,t=e[1]/255,n=e[2]/255;r=r>.04045?Math.pow((r+.055)/1.055,2.4):r/12.92,t=t>.04045?Math.pow((t+.055)/1.055,2.4):t/12.92,n=n>.04045?Math.pow((n+.055)/1.055,2.4):n/12.92;var a=.4124*r+.3576*t+.1805*n,s=.2126*r+.7152*t+.0722*n,i=.0193*r+.1192*t+.9505*n;return[100*a,100*s,100*i]}function o(e){var r,t,n,a=h(e),s=a[0],i=a[1],u=a[2];return s/=95.047,i/=100,u/=108.883,s=s>.008856?Math.pow(s,1/3):7.787*s+16/116,i=i>.008856?Math.pow(i,1/3):7.787*i+16/116,u=u>.008856?Math.pow(u,1/3):7.787*u+16/116,r=116*i-16,t=500*(s-i),n=200*(i-u),[r,t,n]}function c(e){return J(o(e))}function v(e){var r,t,n,a,s,i=e[0]/360,u=e[1]/100,l=e[2]/100;if(0==u)return s=255*l,[s,s,s];t=.5>l?l*(1+u):l+u-l*u,r=2*l-t,a=[0,0,0];for(var h=0;3>h;h++)n=i+1/3*-(h-1),0>n&&n++,n>1&&n--,s=1>6*n?r+6*(t-r)*n:1>2*n?t:2>3*n?r+(t-r)*(2/3-n)*6:r,a[h]=255*s;return a}function f(e){var r,t,n=e[0],a=e[1]/100,s=e[2]/100;return s*=2,a*=1>=s?s:2-s,t=(s+a)/2,r=2*a/(s+a),[n,100*r,100*t]}function d(e){return i(v(e))}function p(e){return u(v(e))}function m(e){return l(v(e))}function y(e){var r=e[0]/60,t=e[1]/100,n=e[2]/100,a=Math.floor(r)%6,s=r-Math.floor(r),i=255*n*(1-t),u=255*n*(1-t*s),l=255*n*(1-t*(1-s)),n=255*n;switch(a){case 0:return[n,l,i];case 1:return[u,n,i];case 2:return[i,n,l];case 3:return[i,u,n];case 4:return[l,i,n];case 5:return[n,i,u]}}function w(e){var r,t,n=e[0],a=e[1]/100,s=e[2]/100;return t=(2-a)*s,r=a*s,r/=1>=t?t:2-t,r=r||0,t/=2,[n,100*r,100*t]}function k(e){return i(y(e))}function M(e){return u(y(e))}function S(e){return l(y(e))}function x(e){var t,n,a,s,i=e[0]/360,u=e[1]/100,l=e[2]/100,h=u+l;switch(h>1&&(u/=h,l/=h),t=Math.floor(6*i),n=1-l,a=6*i-t,0!=(1&t)&&(a=1-a),s=u+a*(n-u),t){default:case 6:case 0:r=n,g=s,b=u;break;case 1:r=s,g=n,b=u;break;case 2:r=u,g=n,b=s;break;case 3:r=u,g=s,b=n;break;case 4:r=s,g=u,b=n;break;case 5:r=n,g=u,b=s}return[255*r,255*g,255*b]}function V(e){return a(x(e))}function q(e){return s(x(e))}function A(e){return u(x(e))}function C(e){return l(x(e))}function F(e){var r,t,n,a=e[0]/100,s=e[1]/100,i=e[2]/100,u=e[3]/100;return r=1-Math.min(1,a*(1-u)+u),t=1-Math.min(1,s*(1-u)+u),n=1-Math.min(1,i*(1-u)+u),[255*r,255*t,255*n]}function N(e){return a(F(e))}function z(e){return s(F(e))}function I(e){return i(F(e))}function O(e){return l(F(e))}function E(e){var r,t,n,a=e[0]/100,s=e[1]/100,i=e[2]/100;return r=3.2406*a+-1.5372*s+i*-.4986,t=a*-.9689+1.8758*s+.0415*i,n=.0557*a+s*-.204+1.057*i,r=r>.0031308?1.055*Math.pow(r,1/2.4)-.055:r=12.92*r,t=t>.0031308?1.055*Math.pow(t,1/2.4)-.055:t=12.92*t,n=n>.0031308?1.055*Math.pow(n,1/2.4)-.055:n=12.92*n,r=Math.min(Math.max(0,r),1),t=Math.min(Math.max(0,t),1),n=Math.min(Math.max(0,n),1),[255*r,255*t,255*n]}function H(e){var r,t,n,a=e[0],s=e[1],i=e[2];return a/=95.047,s/=100,i/=108.883,a=a>.008856?Math.pow(a,1/3):7.787*a+16/116,s=s>.008856?Math.pow(s,1/3):7.787*s+16/116,i=i>.008856?Math.pow(i,1/3):7.787*i+16/116,r=116*s-16,t=500*(a-s),n=200*(s-i),[r,t,n]}function U(e){return J(H(e))}function j(e){var r,t,n,a,s=e[0],i=e[1],u=e[2];return 8>=s?(t=100*s/903.3,a=7.787*(t/100)+16/116):(t=100*Math.pow((s+16)/116,3),a=Math.pow(t/100,1/3)),r=.008856>=r/95.047?r=95.047*(i/500+a-16/116)/7.787:95.047*Math.pow(i/500+a,3),n=.008859>=n/108.883?n=108.883*(a-u/200-16/116)/7.787:108.883*Math.pow(a-u/200,3),[r,t,n]}function J(e){var r,t,n,a=e[0],s=e[1],i=e[2];return r=Math.atan2(i,s),t=360*r/2/Math.PI,0>t&&(t+=360),n=Math.sqrt(s*s+i*i),[a,n,t]}function R(e){return E(j(e))}function $(e){var r,t,n,a=e[0],s=e[1],i=e[2];return n=i/360*2*Math.PI,r=s*Math.cos(n),t=s*Math.sin(n),[a,r,t]}function D(e){return j($(e))}function P(e){return R($(e))}function _(e){return W[e]}function L(e){return a(_(e))}function T(e){return s(_(e))}function B(e){return i(_(e))}function G(e){return u(_(e))}function K(e){return o(_(e))}function Q(e){return h(_(e))}t.exports={rgb2hsl:a,rgb2hsv:s,rgb2hwb:i,rgb2cmyk:u,rgb2keyword:l,rgb2xyz:h,rgb2lab:o,rgb2lch:c,hsl2rgb:v,hsl2hsv:f,hsl2hwb:d,hsl2cmyk:p,hsl2keyword:m,hsv2rgb:y,hsv2hsl:w,hsv2hwb:k,hsv2cmyk:M,hsv2keyword:S,hwb2rgb:x,hwb2hsl:V,hwb2hsv:q,hwb2cmyk:A,hwb2keyword:C,cmyk2rgb:F,cmyk2hsl:N,cmyk2hsv:z,cmyk2hwb:I,cmyk2keyword:O,keyword2rgb:_,keyword2hsl:L,keyword2hsv:T,keyword2hwb:B,keyword2cmyk:G,keyword2lab:K,keyword2xyz:Q,xyz2rgb:E,xyz2lab:H,xyz2lch:U,lab2xyz:j,lab2rgb:R,lab2lch:J,lch2lab:$,lch2xyz:D,lch2rgb:P};var W={aliceblue:[240,248,255],antiquewhite:[250,235,215],aqua:[0,255,255],aquamarine:[127,255,212],azure:[240,255,255],beige:[245,245,220],bisque:[255,228,196],black:[0,0,0],blanchedalmond:[255,235,205],blue:[0,0,255],blueviolet:[138,43,226],brown:[165,42,42],burlywood:[222,184,135],cadetblue:[95,158,160],chartreuse:[127,255,0],chocolate:[210,105,30],coral:[255,127,80],cornflowerblue:[100,149,237],cornsilk:[255,248,220],crimson:[220,20,60],cyan:[0,255,255],darkblue:[0,0,139],darkcyan:[0,139,139],darkgoldenrod:[184,134,11],darkgray:[169,169,169],darkgreen:[0,100,0],darkgrey:[169,169,169],darkkhaki:[189,183,107],darkmagenta:[139,0,139],darkolivegreen:[85,107,47],darkorange:[255,140,0],darkorchid:[153,50,204],darkred:[139,0,0],darksalmon:[233,150,122],darkseagreen:[143,188,143],darkslateblue:[72,61,139],darkslategray:[47,79,79],darkslategrey:[47,79,79],darkturquoise:[0,206,209],darkviolet:[148,0,211],deeppink:[255,20,147],deepskyblue:[0,191,255],dimgray:[105,105,105],dimgrey:[105,105,105],dodgerblue:[30,144,255],firebrick:[178,34,34],floralwhite:[255,250,240],forestgreen:[34,139,34],fuchsia:[255,0,255],gainsboro:[220,220,220],ghostwhite:[248,248,255],gold:[255,215,0],goldenrod:[218,165,32],gray:[128,128,128],green:[0,128,0],greenyellow:[173,255,47],grey:[128,128,128],honeydew:[240,255,240],hotpink:[255,105,180],indianred:[205,92,92],indigo:[75,0,130],ivory:[255,255,240],khaki:[240,230,140],lavender:[230,230,250],lavenderblush:[255,240,245],lawngreen:[124,252,0],lemonchiffon:[255,250,205],lightblue:[173,216,230],lightcoral:[240,128,128],lightcyan:[224,255,255],lightgoldenrodyellow:[250,250,210],lightgray:[211,211,211],lightgreen:[144,238,144],lightgrey:[211,211,211],lightpink:[255,182,193],lightsalmon:[255,160,122],lightseagreen:[32,178,170],lightskyblue:[135,206,250],lightslategray:[119,136,153],lightslategrey:[119,136,153],lightsteelblue:[176,196,222],lightyellow:[255,255,224],lime:[0,255,0],limegreen:[50,205,50],linen:[250,240,230],magenta:[255,0,255],maroon:[128,0,0],mediumaquamarine:[102,205,170],mediumblue:[0,0,205],mediumorchid:[186,85,211],mediumpurple:[147,112,219],mediumseagreen:[60,179,113],mediumslateblue:[123,104,238],mediumspringgreen:[0,250,154],mediumturquoise:[72,209,204],mediumvioletred:[199,21,133],midnightblue:[25,25,112],mintcream:[245,255,250],mistyrose:[255,228,225],moccasin:[255,228,181],navajowhite:[255,222,173],navy:[0,0,128],oldlace:[253,245,230],olive:[128,128,0],olivedrab:[107,142,35],orange:[255,165,0],orangered:[255,69,0],orchid:[218,112,214],palegoldenrod:[238,232,170],palegreen:[152,251,152],paleturquoise:[175,238,238],palevioletred:[219,112,147],papayawhip:[255,239,213],peachpuff:[255,218,185],peru:[205,133,63],pink:[255,192,203],plum:[221,160,221],powderblue:[176,224,230],purple:[128,0,128],rebeccapurple:[102,51,153],red:[255,0,0],rosybrown:[188,143,143],royalblue:[65,105,225],saddlebrown:[139,69,19],salmon:[250,128,114],sandybrown:[244,164,96],seagreen:[46,139,87],seashell:[255,245,238],sienna:[160,82,45],silver:[192,192,192],skyblue:[135,206,235],slateblue:[106,90,205],slategray:[112,128,144],slategrey:[112,128,144],snow:[255,250,250],springgreen:[0,255,127],steelblue:[70,130,180],tan:[210,180,140],teal:[0,128,128],thistle:[216,191,216],tomato:[255,99,71],turquoise:[64,224,208],violet:[238,130,238],wheat:[245,222,179],white:[255,255,255],whitesmoke:[245,245,245],yellow:[255,255,0],yellowgreen:[154,205,50]},X={};for(var Y in W)X[JSON.stringify(W[Y])]=Y},{}],3:[function(e,r,t){var n=e("./conversions"),a=function(){return new h};for(var s in n){a[s+"Raw"]=function(e){return function(r){return"number"==typeof r&&(r=Array.prototype.slice.call(arguments)),n[e](r)}}(s);var i=/(\w+)2(\w+)/.exec(s),u=i[1],l=i[2];a[u]=a[u]||{},a[u][l]=a[s]=function(e){return function(r){"number"==typeof r&&(r=Array.prototype.slice.call(arguments));var t=n[e](r);if("string"==typeof t||void 0===t)return t;for(var a=0;ar||e[3]&&e[3]<1?c(e,r):"rgb("+e[0]+", "+e[1]+", "+e[2]+")"}function c(e,r){return void 0===r&&(r=void 0!==e[3]?e[3]:1),"rgba("+e[0]+", "+e[1]+", "+e[2]+", "+r+")"}function g(e,r){if(1>r||e[3]&&e[3]<1)return v(e,r);var t=Math.round(e[0]/255*100),n=Math.round(e[1]/255*100),a=Math.round(e[2]/255*100);return"rgb("+t+"%, "+n+"%, "+a+"%)"}function v(e,r){var t=Math.round(e[0]/255*100),n=Math.round(e[1]/255*100),a=Math.round(e[2]/255*100);return"rgba("+t+"%, "+n+"%, "+a+"%, "+(r||e[3]||1)+")"}function f(e,r){return 1>r||e[3]&&e[3]<1?d(e,r):"hsl("+e[0]+", "+e[1]+"%, "+e[2]+"%)"}function d(e,r){return void 0===r&&(r=void 0!==e[3]?e[3]:1),"hsla("+e[0]+", "+e[1]+"%, "+e[2]+"%, "+r+")"}function b(e,r){return void 0===r&&(r=void 0!==e[3]?e[3]:1),"hwb("+e[0]+", "+e[1]+"%, "+e[2]+"%"+(void 0!==r&&1!==r?", "+r:"")+")"}function p(e){return k[e.slice(0,3)]}function m(e,r,t){return Math.min(Math.max(r,e),t)}function y(e){var r=e.toString(16).toUpperCase();return r.length<2?"0"+r:r}var w=e("color-name");r.exports={getRgba:n,getHsla:a,getRgb:i,getHsl:u,getHwb:s,getAlpha:l,hexString:h,rgbString:o,rgbaString:c,percentString:g,percentaString:v,hslString:f,hslaString:d,hwbString:b,keyword:p};var k={};for(var M in w)k[w[M]]=M},{"color-name":5}],5:[function(e,r,t){r.exports={aliceblue:[240,248,255],antiquewhite:[250,235,215],aqua:[0,255,255],aquamarine:[127,255,212],azure:[240,255,255],beige:[245,245,220],bisque:[255,228,196],black:[0,0,0],blanchedalmond:[255,235,205],blue:[0,0,255],blueviolet:[138,43,226],brown:[165,42,42],burlywood:[222,184,135],cadetblue:[95,158,160],chartreuse:[127,255,0],chocolate:[210,105,30],coral:[255,127,80],cornflowerblue:[100,149,237],cornsilk:[255,248,220],crimson:[220,20,60],cyan:[0,255,255],darkblue:[0,0,139],darkcyan:[0,139,139],darkgoldenrod:[184,134,11],darkgray:[169,169,169],darkgreen:[0,100,0],darkgrey:[169,169,169],darkkhaki:[189,183,107],darkmagenta:[139,0,139],darkolivegreen:[85,107,47],darkorange:[255,140,0],darkorchid:[153,50,204],darkred:[139,0,0],darksalmon:[233,150,122],darkseagreen:[143,188,143],darkslateblue:[72,61,139],darkslategray:[47,79,79],darkslategrey:[47,79,79],darkturquoise:[0,206,209],darkviolet:[148,0,211],deeppink:[255,20,147],deepskyblue:[0,191,255],dimgray:[105,105,105],dimgrey:[105,105,105],dodgerblue:[30,144,255],firebrick:[178,34,34],floralwhite:[255,250,240],forestgreen:[34,139,34],fuchsia:[255,0,255],gainsboro:[220,220,220],ghostwhite:[248,248,255],gold:[255,215,0],goldenrod:[218,165,32],gray:[128,128,128],green:[0,128,0],greenyellow:[173,255,47],grey:[128,128,128],honeydew:[240,255,240],hotpink:[255,105,180],indianred:[205,92,92],indigo:[75,0,130],ivory:[255,255,240],khaki:[240,230,140],lavender:[230,230,250],lavenderblush:[255,240,245],lawngreen:[124,252,0],lemonchiffon:[255,250,205],lightblue:[173,216,230],lightcoral:[240,128,128],lightcyan:[224,255,255],lightgoldenrodyellow:[250,250,210],lightgray:[211,211,211],lightgreen:[144,238,144],lightgrey:[211,211,211],lightpink:[255,182,193],lightsalmon:[255,160,122],lightseagreen:[32,178,170],lightskyblue:[135,206,250],lightslategray:[119,136,153],lightslategrey:[119,136,153],lightsteelblue:[176,196,222],lightyellow:[255,255,224],lime:[0,255,0],limegreen:[50,205,50],linen:[250,240,230],magenta:[255,0,255],maroon:[128,0,0],mediumaquamarine:[102,205,170],mediumblue:[0,0,205],mediumorchid:[186,85,211],mediumpurple:[147,112,219],mediumseagreen:[60,179,113],mediumslateblue:[123,104,238],mediumspringgreen:[0,250,154],mediumturquoise:[72,209,204],mediumvioletred:[199,21,133],midnightblue:[25,25,112],mintcream:[245,255,250],mistyrose:[255,228,225],moccasin:[255,228,181],navajowhite:[255,222,173],navy:[0,0,128],oldlace:[253,245,230],olive:[128,128,0],olivedrab:[107,142,35],orange:[255,165,0],orangered:[255,69,0],orchid:[218,112,214],palegoldenrod:[238,232,170],palegreen:[152,251,152],paleturquoise:[175,238,238],palevioletred:[219,112,147],papayawhip:[255,239,213],peachpuff:[255,218,185],peru:[205,133,63],pink:[255,192,203],plum:[221,160,221],powderblue:[176,224,230],purple:[128,0,128],rebeccapurple:[102,51,153],red:[255,0,0],rosybrown:[188,143,143],royalblue:[65,105,225],saddlebrown:[139,69,19],salmon:[250,128,114],sandybrown:[244,164,96],seagreen:[46,139,87],seashell:[255,245,238],sienna:[160,82,45],silver:[192,192,192],skyblue:[135,206,235],slateblue:[106,90,205],slategray:[112,128,144],slategrey:[112,128,144],snow:[255,250,250],springgreen:[0,255,127],steelblue:[70,130,180],tan:[210,180,140],teal:[0,128,128],thistle:[216,191,216],tomato:[255,99,71],turquoise:[64,224,208],violet:[238,130,238],wheat:[245,222,179],white:[255,255,255],whitesmoke:[245,245,245],yellow:[255,255,0],yellowgreen:[154,205,50]}},{}]},{},[1]);
/*!
* Chart.js
* http://chartjs.org/
+ * Version: 2.0.0-beta2
*
- * Copyright 2013 Nick Downie
+ * Copyright 2015 Nick Downie
* Released under the MIT license
* https://github.com/nnnick/Chart.js/blob/master/LICENSE.md
*/
-//Define the global Chart Variable as a class.
-window.Chart = function(context){
- var chart = this;
-
-
- //Easing functions adapted from Robert Penner's easing equations
- //http://www.robertpenner.com/easing/
-
- var animationOptions = {
- linear : function (t){
- return t;
- },
- easeInQuad: function (t) {
- return t*t;
- },
- easeOutQuad: function (t) {
- return -1 *t*(t-2);
- },
- easeInOutQuad: function (t) {
- if ((t/=1/2) < 1) return 1/2*t*t;
- return -1/2 * ((--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) {
- if ((t/=1/2) < 1) return 1/2*t*t*t;
- return 1/2*((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) {
- if ((t/=1/2) < 1) return 1/2*t*t*t*t;
- return -1/2 * ((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) {
- if ((t/=1/2) < 1) return 1/2*t*t*t*t*t;
- return 1/2*((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 -1/2 * (Math.cos(Math.PI*t/1) - 1);
- },
- easeInExpo: function (t) {
- return (t==0) ? 1 : 1 * Math.pow(2, 10 * (t/1 - 1));
- },
- easeOutExpo: function (t) {
- return (t==1) ? 1 : 1 * (-Math.pow(2, -10 * t/1) + 1);
- },
- easeInOutExpo: function (t) {
- if (t==0) return 0;
- if (t==1) return 1;
- if ((t/=1/2) < 1) return 1/2 * Math.pow(2, 10 * (t - 1));
- return 1/2 * (-Math.pow(2, -10 * --t) + 2);
+(function() {
+
+ "use strict";
+
+ //Declare root variable - window in the browser, global on the server
+ var root = this,
+ previous = root.Chart;
+
+ //Occupy the global variable of Chart, and create a simple base class
+ var Chart = function(context, config) {
+ this.config = config;
+
+ // Support a jQuery'd canvas element
+ if (context.length && context[0].getContext) {
+ context = context[0];
+ }
+
+ // Support a canvas domnode
+ if (context.getContext) {
+ context = context.getContext("2d");
+ }
+
+ this.ctx = context;
+ this.canvas = context.canvas;
+
+ // Figure out what the size of the chart will be.
+ // If the canvas has a specified width and height, we use those else
+ // we look to see if the canvas node has a CSS width and height.
+ // If there is still no height, fill the parent container
+ this.width = context.canvas.width || parseInt(Chart.helpers.getStyle(context.canvas, 'width')) || Chart.helpers.getMaximumWidth(context.canvas);
+ this.height = context.canvas.height || parseInt(Chart.helpers.getStyle(context.canvas, 'height')) || Chart.helpers.getMaximumHeight(context.canvas);
+
+ this.aspectRatio = this.width / this.height;
+
+ if (isNaN(this.aspectRatio) || isFinite(this.aspectRatio) === false) {
+ // If the canvas has no size, try and figure out what the aspect ratio will be.
+ // Some charts prefer square canvases (pie, radar, etc). If that is specified, use that
+ // else use the canvas default ratio of 2
+ this.aspectRatio = config.aspectRatio !== undefined ? config.aspectRatio : 2;
+ }
+
+ // Store the original style of the element so we can set it back
+ this.originalCanvasStyleWidth = context.canvas.style.width;
+ this.originalCanvasStyleHeight = context.canvas.style.height;
+
+ // High pixel density displays - multiply the size of the canvas height/width by the device pixel ratio, then scale.
+ Chart.helpers.retinaScale(this);
+
+ if (config) {
+ this.controller = new Chart.Controller(this);
+ }
+
+ // Always bind this so that if the responsive state changes we still work
+ var _this = this;
+ Chart.helpers.addResizeListener(context.canvas.parentNode, function() {
+ if (_this.controller && _this.controller.config.options.responsive) {
+ _this.controller.resize();
+ }
+ });
+
+ return this.controller ? this.controller : this;
+
+ };
+
+ //Globally expose the defaults to allow for user updating/changing
+ Chart.defaults = {
+ global: {
+ responsive: true,
+ responsiveAnimationDuration: 0,
+ maintainAspectRatio: true,
+ events: ["mousemove", "mouseout", "click", "touchstart", "touchmove"],
+ hover: {
+ onHover: null,
+ mode: 'single',
+ animationDuration: 400,
},
- easeInCirc: function (t) {
- if (t>=1) return t;
- return -1 * (Math.sqrt(1 - (t/=1)*t) - 1);
+ onClick: null,
+ defaultColor: 'rgba(0,0,0,0.1)',
+
+ // Element defaults defined in element extensions
+ elements: {},
+
+ // Legend callback string
+ legendCallback: function(chart) {
+ var text = [];
+ text.push('');
+ for (var i = 0; i < chart.data.datasets.length; i++) {
+ text.push('');
+ if (chart.data.datasets[i].label) {
+ text.push(chart.data.datasets[i].label);
+ }
+ text.push(' ');
+ }
+ text.push(' ');
+
+ return text.join("");
+ }
},
- easeOutCirc: function (t) {
- return 1 * Math.sqrt(1 - (t=t/1-1)*t);
+ };
+
+ root.Chart = Chart;
+
+ Chart.noConflict = function() {
+ root.Chart = previous;
+ return Chart;
+ };
+
+}).call(this);
+
+(function() {
+
+ "use strict";
+
+ //Declare root variable - window in the browser, global on the server
+ var root = this,
+ Chart = root.Chart;
+
+ //Global Chart helpers object for utility methods and classes
+ var helpers = Chart.helpers = {};
+
+ //-- Basic js utility methods
+ var each = helpers.each = function(loopable, callback, self, reverse) {
+ var additionalArgs = Array.prototype.slice.call(arguments, 3);
+ // Check to see if null or undefined firstly.
+ if (loopable) {
+ if (loopable.length === +loopable.length) {
+ var i;
+ if (reverse) {
+ for (i = loopable.length - 1; i >= 0; i--) {
+ callback.apply(self, [loopable[i], i].concat(additionalArgs));
+ }
+ } else {
+ for (i = 0; i < loopable.length; i++) {
+ callback.apply(self, [loopable[i], i].concat(additionalArgs));
+ }
+ }
+ } else {
+ for (var item in loopable) {
+ callback.apply(self, [loopable[item], item].concat(additionalArgs));
+ }
+ }
+ }
},
- easeInOutCirc: function (t) {
- if ((t/=1/2) < 1) return -1/2 * (Math.sqrt(1 - t*t) - 1);
- return 1/2 * (Math.sqrt(1 - (t-=2)*t) + 1);
+ clone = helpers.clone = function(obj) {
+ var objClone = {};
+ each(obj, function(value, key) {
+ if (obj.hasOwnProperty(key)) {
+ if (helpers.isArray(value)) {
+ objClone[key] = value.slice(0);
+ } else if (typeof value === 'object' && value !== null) {
+ objClone[key] = clone(value);
+ } else {
+ objClone[key] = value;
+ }
+ }
+ });
+ return objClone;
},
- easeInElastic: function (t) {
- var s=1.70158;var p=0;var a=1;
- if (t==0) return 0; if ((t/=1)==1) return 1; if (!p) p=1*.3;
- if (a < Math.abs(1)) { a=1; var s=p/4; }
- else var s = p/(2*Math.PI) * Math.asin (1/a);
- return -(a*Math.pow(2,10*(t-=1)) * Math.sin( (t*1-s)*(2*Math.PI)/p ));
+ extend = helpers.extend = function(base) {
+ each(Array.prototype.slice.call(arguments, 1), function(extensionObject) {
+ each(extensionObject, function(value, key) {
+ if (extensionObject.hasOwnProperty(key)) {
+ base[key] = value;
+ }
+ });
+ });
+ return base;
},
- easeOutElastic: function (t) {
- var s=1.70158;var p=0;var a=1;
- if (t==0) return 0; if ((t/=1)==1) return 1; if (!p) p=1*.3;
- if (a < Math.abs(1)) { a=1; var s=p/4; }
- else var s = p/(2*Math.PI) * Math.asin (1/a);
- return a*Math.pow(2,-10*t) * Math.sin( (t*1-s)*(2*Math.PI)/p ) + 1;
+ // Need a special merge function to chart configs since they are now grouped
+ configMerge = helpers.configMerge = function(_base) {
+ var base = clone(_base);
+ helpers.each(Array.prototype.slice.call(arguments, 1), function(extension) {
+ helpers.each(extension, function(value, key) {
+ if (extension.hasOwnProperty(key)) {
+ if (key === 'scales') {
+ // Scale config merging is complex. Add out own function here for that
+ base[key] = helpers.scaleMerge(base.hasOwnProperty(key) ? base[key] : {}, value);
+
+ } else if (key === 'scale') {
+ // Used in polar area & radar charts since there is only one scale
+ base[key] = helpers.configMerge(base.hasOwnProperty(key) ? base[key] : {}, Chart.scaleService.getScaleDefaults(value.type), value);
+ } else if (base.hasOwnProperty(key) && helpers.isArray(base[key]) && helpers.isArray(value)) {
+ // In this case we have an array of objects replacing another array. Rather than doing a strict replace,
+ // merge. This allows easy scale option merging
+ var baseArray = base[key];
+
+ helpers.each(value, function(valueObj, index) {
+
+ if (index < baseArray.length) {
+ if (typeof baseArray[index] == 'object' && baseArray[index] !== null && typeof valueObj == 'object' && valueObj !== null) {
+ // Two objects are coming together. Do a merge of them.
+ baseArray[index] = helpers.configMerge(baseArray[index], valueObj);
+ } else {
+ // Just overwrite in this case since there is nothing to merge
+ baseArray[index] = valueObj;
+ }
+ } else {
+ baseArray.push(valueObj); // nothing to merge
+ }
+ });
+
+ } else if (base.hasOwnProperty(key) && typeof base[key] == "object" && base[key] !== null && typeof value == "object") {
+ // If we are overwriting an object with an object, do a merge of the properties.
+ base[key] = helpers.configMerge(base[key], value);
+
+ } else {
+ // can just overwrite the value in this case
+ base[key] = value;
+ }
+ }
+ });
+ });
+
+ return base;
},
- easeInOutElastic: function (t) {
- var s=1.70158;var p=0;var a=1;
- if (t==0) return 0; if ((t/=1/2)==2) return 1; if (!p) p=1*(.3*1.5);
- if (a < Math.abs(1)) { a=1; var s=p/4; }
- else var s = p/(2*Math.PI) * Math.asin (1/a);
- if (t < 1) return -.5*(a*Math.pow(2,10*(t-=1)) * Math.sin( (t*1-s)*(2*Math.PI)/p ));
- return a*Math.pow(2,-10*(t-=1)) * Math.sin( (t*1-s)*(2*Math.PI)/p )*.5 + 1;
+ extendDeep = helpers.extendDeep = function(_base) {
+ return _extendDeep.apply(this, arguments);
+
+ function _extendDeep(dst) {
+ helpers.each(arguments, function(obj) {
+ if (obj !== dst) {
+ helpers.each(obj, function(value, key) {
+ if (dst[key] && dst[key].constructor && dst[key].constructor === Object) {
+ _extendDeep(dst[key], value);
+ } else {
+ dst[key] = value;
+ }
+ });
+ }
+ });
+ return dst;
+ }
},
- easeInBack: function (t) {
- var s = 1.70158;
- return 1*(t/=1)*t*((s+1)*t - s);
+ scaleMerge = helpers.scaleMerge = function(_base, extension) {
+ var base = clone(_base);
+
+ helpers.each(extension, function(value, key) {
+ if (extension.hasOwnProperty(key)) {
+ if (key === 'xAxes' || key === 'yAxes') {
+ // These properties are arrays of items
+ if (base.hasOwnProperty(key)) {
+ helpers.each(value, function(valueObj, index) {
+ if (index >= base[key].length || !base[key][index].type) {
+ base[key].push(helpers.configMerge(valueObj.type ? Chart.scaleService.getScaleDefaults(valueObj.type) : {}, valueObj));
+ } else if (valueObj.type !== base[key][index].type) {
+ // Type changed. Bring in the new defaults before we bring in valueObj so that valueObj can override the correct scale defaults
+ base[key][index] = helpers.configMerge(base[key][index], valueObj.type ? Chart.scaleService.getScaleDefaults(valueObj.type) : {}, valueObj);
+ } else {
+ // Type is the same
+ base[key][index] = helpers.configMerge(base[key][index], valueObj);
+ }
+ });
+ } else {
+ base[key] = [];
+ helpers.each(value, function(valueObj) {
+ base[key].push(helpers.configMerge(valueObj.type ? Chart.scaleService.getScaleDefaults(valueObj.type) : {}, valueObj));
+ });
+ }
+ } else if (base.hasOwnProperty(key) && typeof base[key] == "object" && base[key] !== null && typeof value == "object") {
+ // If we are overwriting an object with an object, do a merge of the properties.
+ base[key] = helpers.configMerge(base[key], value);
+
+ } else {
+ // can just overwrite the value in this case
+ base[key] = value;
+ }
+ }
+ });
+
+ return base;
},
- easeOutBack: function (t) {
- var s = 1.70158;
- return 1*((t=t/1-1)*t*((s+1)*t + s) + 1);
+ getValueAtIndexOrDefault = helpers.getValueAtIndexOrDefault = function(value, index, defaultValue) {
+ if (value === undefined || value === null) {
+ return defaultValue;
+ }
+
+ if (helpers.isArray(value)) {
+ return index < value.length ? value[index] : defaultValue;
+ }
+
+ return value;
},
- easeInOutBack: function (t) {
- var s = 1.70158;
- if ((t/=1/2) < 1) return 1/2*(t*t*(((s*=(1.525))+1)*t - s));
- return 1/2*((t-=2)*t*(((s*=(1.525))+1)*t + s) + 2);
+ getValueOrDefault = helpers.getValueOrDefault = function(value, defaultValue) {
+ return value === undefined ? defaultValue : value;
},
- easeInBounce: function (t) {
- return 1 - animationOptions.easeOutBounce (1-t);
- },
- easeOutBounce: function (t) {
- if ((t/=1) < (1/2.75)) {
- return 1*(7.5625*t*t);
- } else if (t < (2/2.75)) {
- return 1*(7.5625*(t-=(1.5/2.75))*t + .75);
- } else if (t < (2.5/2.75)) {
- return 1*(7.5625*(t-=(2.25/2.75))*t + .9375);
+ indexOf = helpers.indexOf = function(arrayToSearch, item) {
+ if (Array.prototype.indexOf) {
+ return arrayToSearch.indexOf(item);
} else {
- return 1*(7.5625*(t-=(2.625/2.75))*t + .984375);
+ for (var i = 0; i < arrayToSearch.length; i++) {
+ if (arrayToSearch[i] === item) return i;
+ }
+ return -1;
}
},
- easeInOutBounce: function (t) {
- if (t < 1/2) return animationOptions.easeInBounce (t*2) * .5;
- return animationOptions.easeOutBounce (t*2-1) * .5 + 1*.5;
- }
- };
+ where = helpers.where = function(collection, filterCallback) {
+ var filtered = [];
- //Variables global to the chart
- var width = context.canvas.width;
- var height = context.canvas.height;
-
-
- //High pixel density displays - multiply the size of the canvas height/width by the device pixel ratio, then scale.
- if (window.devicePixelRatio) {
- context.canvas.style.width = width + "px";
- context.canvas.style.height = height + "px";
- context.canvas.height = height * window.devicePixelRatio;
- context.canvas.width = width * window.devicePixelRatio;
- context.scale(window.devicePixelRatio, window.devicePixelRatio);
- }
-
- this.PolarArea = function(data,options){
-
- chart.PolarArea.defaults = {
- scaleOverlay : true,
- scaleOverride : false,
- scaleSteps : null,
- scaleStepWidth : null,
- scaleStartValue : null,
- scaleShowLine : true,
- scaleLineColor : "rgba(0,0,0,.1)",
- scaleLineWidth : 1,
- scaleShowLabels : true,
- scaleLabel : "<%=value%>",
- scaleFontFamily : "'Arial'",
- scaleFontSize : 12,
- scaleFontStyle : "normal",
- scaleFontColor : "#666",
- scaleShowLabelBackdrop : true,
- scaleBackdropColor : "rgba(255,255,255,0.75)",
- scaleBackdropPaddingY : 2,
- scaleBackdropPaddingX : 2,
- segmentShowStroke : true,
- segmentStrokeColor : "#fff",
- segmentStrokeWidth : 2,
- animation : true,
- animationSteps : 100,
- animationEasing : "easeOutBounce",
- animateRotate : true,
- animateScale : false,
- onAnimationComplete : null
- };
-
- var config = (options)? mergeChartConfig(chart.PolarArea.defaults,options) : chart.PolarArea.defaults;
-
- return new PolarArea(data,config,context);
- };
-
- this.Radar = function(data,options){
-
- chart.Radar.defaults = {
- scaleOverlay : false,
- scaleOverride : false,
- scaleSteps : null,
- scaleStepWidth : null,
- scaleStartValue : null,
- scaleShowLine : true,
- scaleLineColor : "rgba(0,0,0,.1)",
- scaleLineWidth : 1,
- scaleShowLabels : false,
- scaleLabel : "<%=value%>",
- scaleFontFamily : "'Arial'",
- scaleFontSize : 12,
- scaleFontStyle : "normal",
- scaleFontColor : "#666",
- scaleShowLabelBackdrop : true,
- scaleBackdropColor : "rgba(255,255,255,0.75)",
- scaleBackdropPaddingY : 2,
- scaleBackdropPaddingX : 2,
- angleShowLineOut : true,
- angleLineColor : "rgba(0,0,0,.1)",
- angleLineWidth : 1,
- pointLabelFontFamily : "'Arial'",
- pointLabelFontStyle : "normal",
- pointLabelFontSize : 12,
- pointLabelFontColor : "#666",
- pointDot : true,
- pointDotRadius : 3,
- pointDotStrokeWidth : 1,
- datasetStroke : true,
- datasetStrokeWidth : 2,
- datasetFill : true,
- animation : true,
- animationSteps : 60,
- animationEasing : "easeOutQuart",
- onAnimationComplete : null
- };
-
- var config = (options)? mergeChartConfig(chart.Radar.defaults,options) : chart.Radar.defaults;
-
- return new Radar(data,config,context);
- };
-
- this.Pie = function(data,options){
- chart.Pie.defaults = {
- segmentShowStroke : true,
- segmentStrokeColor : "#fff",
- segmentStrokeWidth : 2,
- animation : true,
- animationSteps : 100,
- animationEasing : "easeOutBounce",
- animateRotate : true,
- animateScale : false,
- onAnimationComplete : null
- };
-
- var config = (options)? mergeChartConfig(chart.Pie.defaults,options) : chart.Pie.defaults;
-
- return new Pie(data,config,context);
- };
-
- this.Doughnut = function(data,options){
-
- chart.Doughnut.defaults = {
- segmentShowStroke : true,
- segmentStrokeColor : "#fff",
- segmentStrokeWidth : 2,
- percentageInnerCutout : 50,
- animation : true,
- animationSteps : 100,
- animationEasing : "easeOutBounce",
- animateRotate : true,
- animateScale : false,
- onAnimationComplete : null
- };
-
- var config = (options)? mergeChartConfig(chart.Doughnut.defaults,options) : chart.Doughnut.defaults;
-
- return new Doughnut(data,config,context);
-
- };
-
- this.Line = function(data,options){
-
- chart.Line.defaults = {
- scaleOverlay : false,
- scaleOverride : false,
- scaleSteps : null,
- scaleStepWidth : null,
- scaleStartValue : null,
- scaleLineColor : "rgba(0,0,0,.1)",
- scaleLineWidth : 1,
- scaleShowLabels : true,
- scaleLabel : "<%=value%>",
- scaleFontFamily : "'Arial'",
- scaleFontSize : 12,
- scaleFontStyle : "normal",
- scaleFontColor : "#666",
- scaleShowGridLines : true,
- scaleGridLineColor : "rgba(0,0,0,.05)",
- scaleGridLineWidth : 1,
- bezierCurve : true,
- pointDot : true,
- pointDotRadius : 4,
- pointDotStrokeWidth : 2,
- datasetStroke : true,
- datasetStrokeWidth : 2,
- datasetFill : true,
- animation : true,
- animationSteps : 60,
- animationEasing : "easeOutQuart",
- onAnimationComplete : null
- };
- var config = (options) ? mergeChartConfig(chart.Line.defaults,options) : chart.Line.defaults;
-
- return new Line(data,config,context);
- }
-
- this.Bar = function(data,options){
- chart.Bar.defaults = {
- scaleOverlay : false,
- scaleOverride : false,
- scaleSteps : null,
- scaleStepWidth : null,
- scaleStartValue : null,
- scaleLineColor : "rgba(0,0,0,.1)",
- scaleLineWidth : 1,
- scaleShowLabels : true,
- scaleLabel : "<%=value%>",
- scaleFontFamily : "'Arial'",
- scaleFontSize : 12,
- scaleFontStyle : "normal",
- scaleFontColor : "#666",
- scaleShowGridLines : true,
- scaleGridLineColor : "rgba(0,0,0,.05)",
- scaleGridLineWidth : 1,
- barShowStroke : true,
- barStrokeWidth : 2,
- barValueSpacing : 5,
- barDatasetSpacing : 1,
- animation : true,
- animationSteps : 60,
- animationEasing : "easeOutQuart",
- onAnimationComplete : null
- };
- var config = (options) ? mergeChartConfig(chart.Bar.defaults,options) : chart.Bar.defaults;
-
- return new Bar(data,config,context);
- }
-
- var clear = function(c){
- c.clearRect(0, 0, width, height);
- };
-
- var PolarArea = function(data,config,ctx){
- var maxSize, scaleHop, calculatedScale, labelHeight, scaleHeight, valueBounds, labelTemplateString;
-
-
- calculateDrawingSizes();
-
- valueBounds = getValueBounds();
-
- labelTemplateString = (config.scaleShowLabels)? config.scaleLabel : null;
-
- //Check and set the scale
- if (!config.scaleOverride){
-
- calculatedScale = calculateScale(scaleHeight,valueBounds.maxSteps,valueBounds.minSteps,valueBounds.maxValue,valueBounds.minValue,labelTemplateString);
- }
- else {
- calculatedScale = {
- steps : config.scaleSteps,
- stepValue : config.scaleStepWidth,
- graphMin : config.scaleStartValue,
- labels : []
- }
- populateLabels(labelTemplateString, calculatedScale.labels,calculatedScale.steps,config.scaleStartValue,config.scaleStepWidth);
- }
-
- scaleHop = maxSize/(calculatedScale.steps);
-
- //Wrap in an animation loop wrapper
- animationLoop(config,drawScale,drawAllSegments,ctx);
-
- function calculateDrawingSizes(){
- maxSize = (Min([width,height])/2);
- //Remove whatever is larger - the font size or line width.
-
- maxSize -= Max([config.scaleFontSize*0.5,config.scaleLineWidth*0.5]);
-
- labelHeight = config.scaleFontSize*2;
- //If we're drawing the backdrop - add the Y padding to the label height and remove from drawing region.
- if (config.scaleShowLabelBackdrop){
- labelHeight += (2 * config.scaleBackdropPaddingY);
- maxSize -= config.scaleBackdropPaddingY*1.5;
- }
-
- scaleHeight = maxSize;
- //If the label height is less than 5, set it to 5 so we don't have lines on top of each other.
- labelHeight = Default(labelHeight,5);
- }
- function drawScale(){
- for (var i=0; i= 0; i--) {
+ var currentItem = arrayToSearch[i];
+ if (filterCallback(currentItem)) {
+ return currentItem;
}
}
-
- for (var i=0; i upperValue) {upperValue = data[i].value;}
- if (data[i].value < lowerValue) {lowerValue = data[i].value;}
+ },
+ inherits = helpers.inherits = function(extensions) {
+ //Basic javascript inheritance based on the model created in Backbone.js
+ var parent = this;
+ var ChartElement = (extensions && extensions.hasOwnProperty("constructor")) ? extensions.constructor : function() {
+ return parent.apply(this, arguments);
};
- var maxSteps = Math.floor((scaleHeight / (labelHeight*0.66)));
- var minSteps = Math.floor((scaleHeight / labelHeight*0.5));
-
+ var Surrogate = function() {
+ this.constructor = ChartElement;
+ };
+ Surrogate.prototype = parent.prototype;
+ ChartElement.prototype = new Surrogate();
+
+ ChartElement.extend = inherits;
+
+ if (extensions) extend(ChartElement.prototype, extensions);
+
+ ChartElement.__super__ = parent.prototype;
+
+ return ChartElement;
+ },
+ noop = helpers.noop = function() {},
+ uid = helpers.uid = (function() {
+ var id = 0;
+ return function() {
+ return "chart-" + id++;
+ };
+ })(),
+ warn = helpers.warn = function(str) {
+ //Method for warning of errors
+ if (console && typeof console.warn === "function") {
+ console.warn(str);
+ }
+ },
+ //-- Math methods
+ isNumber = helpers.isNumber = function(n) {
+ return !isNaN(parseFloat(n)) && isFinite(n);
+ },
+ max = helpers.max = function(array) {
+ return Math.max.apply(Math, array);
+ },
+ min = helpers.min = function(array) {
+ return Math.min.apply(Math, array);
+ },
+ sign = helpers.sign = function(x) {
+ if (Math.sign) {
+ return Math.sign(x);
+ } else {
+ x = +x; // convert to a number
+ if (x === 0 || isNaN(x)) {
+ return x;
+ }
+ return x > 0 ? 1 : -1;
+ }
+ },
+ log10 = helpers.log10 = function(x) {
+ if (Math.log10) {
+ return Math.log10(x);
+ } else {
+ return Math.log(x) / Math.LN10;
+ }
+ },
+ getDecimalPlaces = helpers.getDecimalPlaces = function(num) {
+ if (num % 1 !== 0 && isNumber(num)) {
+ var s = num.toString();
+ if (s.indexOf("e-") < 0) {
+ // no exponent, e.g. 0.01
+ return s.split(".")[1].length;
+ } else if (s.indexOf(".") < 0) {
+ // no decimal point, e.g. 1e-9
+ return parseInt(s.split("e-")[1]);
+ } else {
+ // exponent and decimal point, e.g. 1.23e-9
+ var parts = s.split(".")[1].split("e-");
+ return parts[0].length + parseInt(parts[1]);
+ }
+ } else {
+ return 0;
+ }
+ },
+ toRadians = helpers.toRadians = function(degrees) {
+ return degrees * (Math.PI / 180);
+ },
+ toDegrees = helpers.toDegrees = function(radians) {
+ return radians * (180 / Math.PI);
+ },
+ // Gets the angle from vertical upright to the point about a centre.
+ getAngleFromPoint = helpers.getAngleFromPoint = function(centrePoint, anglePoint) {
+ var distanceFromXCenter = anglePoint.x - centrePoint.x,
+ distanceFromYCenter = anglePoint.y - centrePoint.y,
+ radialDistanceFromCenter = Math.sqrt(distanceFromXCenter * distanceFromXCenter + distanceFromYCenter * distanceFromYCenter);
+
+ var angle = Math.atan2(distanceFromYCenter, distanceFromXCenter);
+
+ if (angle < (-0.5 * Math.PI)) {
+ angle += 2.0 * Math.PI; // make sure the returned angle is in the range of (-PI/2, 3PI/2]
+ }
+
return {
- maxValue : upperValue,
- minValue : lowerValue,
- maxSteps : maxSteps,
- minSteps : minSteps
+ angle: angle,
+ distance: radialDistanceFromCenter
};
-
+ },
+ aliasPixel = helpers.aliasPixel = function(pixelWidth) {
+ return (pixelWidth % 2 === 0) ? 0 : 0.5;
+ },
+ splineCurve = helpers.splineCurve = function(firstPoint, middlePoint, afterPoint, t) {
+ //Props to Rob Spencer at scaled innovation for his post on splining between points
+ //http://scaledinnovation.com/analytics/splines/aboutSplines.html
+ // This function must also respect "skipped" points
+
+ var previous = firstPoint.skip ? middlePoint : firstPoint,
+ current = middlePoint,
+ next = afterPoint.skip ? middlePoint : afterPoint;
+
+ var d01 = Math.sqrt(Math.pow(current.x - previous.x, 2) + Math.pow(current.y - previous.y, 2));
+ var d12 = Math.sqrt(Math.pow(next.x - current.x, 2) + Math.pow(next.y - current.y, 2));
+
+ var s01 = d01 / (d01 + d12);
+ var s12 = d12 / (d01 + d12);
+
+ // If all points are the same, s01 & s02 will be inf
+ s01 = isNaN(s01) ? 0 : s01;
+ s12 = isNaN(s12) ? 0 : s12;
+
+ var fa = t * s01; // scaling factor for triangle Ta
+ var fb = t * s12;
+
+ return {
+ previous: {
+ x: current.x - fa * (next.x - previous.x),
+ y: current.y - fa * (next.y - previous.y)
+ },
+ next: {
+ x: current.x + fb * (next.x - previous.x),
+ y: current.y + fb * (next.y - previous.y)
+ }
+ };
+ },
+ nextItem = helpers.nextItem = function(collection, index, loop) {
+ if (loop) {
+ return index >= collection.length - 1 ? collection[0] : collection[index + 1];
+ }
+
+ return index >= collection.length - 1 ? collection[collection.length - 1] : collection[index + 1];
+ },
+ previousItem = helpers.previousItem = function(collection, index, loop) {
+ if (loop) {
+ return index <= 0 ? collection[collection.length - 1] : collection[index - 1];
+ }
+ return index <= 0 ? collection[0] : collection[index - 1];
+ },
+ // Implementation of the nice number algorithm used in determining where axis labels will go
+ niceNum = helpers.niceNum = function(range, round) {
+ var exponent = Math.floor(helpers.log10(range));
+ var fraction = range / Math.pow(10, exponent);
+ var niceFraction;
+
+ if (round) {
+ if (fraction < 1.5) {
+ niceFraction = 1;
+ } else if (fraction < 3) {
+ niceFraction = 2;
+ } else if (fraction < 7) {
+ niceFraction = 5;
+ } else {
+ niceFraction = 10;
+ }
+ } else {
+ if (fraction <= 1.0) {
+ niceFraction = 1;
+ } else if (fraction <= 2) {
+ niceFraction = 2;
+ } else if (fraction <= 5) {
+ niceFraction = 5;
+ } else {
+ niceFraction = 10;
+ }
+ }
+
+ return niceFraction * Math.pow(10, exponent);
+ },
+ //Easing functions adapted from Robert Penner's easing equations
+ //http://www.robertpenner.com/easing/
+ easingEffects = helpers.easingEffects = {
+ linear: function(t) {
+ return t;
+ },
+ easeInQuad: function(t) {
+ return t * t;
+ },
+ easeOutQuad: function(t) {
+ return -1 * t * (t - 2);
+ },
+ easeInOutQuad: function(t) {
+ if ((t /= 1 / 2) < 1) {
+ return 1 / 2 * t * t;
+ }
+ return -1 / 2 * ((--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) {
+ if ((t /= 1 / 2) < 1) {
+ return 1 / 2 * t * t * t;
+ }
+ return 1 / 2 * ((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) {
+ if ((t /= 1 / 2) < 1) {
+ return 1 / 2 * t * t * t * t;
+ }
+ return -1 / 2 * ((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) {
+ if ((t /= 1 / 2) < 1) {
+ return 1 / 2 * t * t * t * t * t;
+ }
+ return 1 / 2 * ((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 -1 / 2 * (Math.cos(Math.PI * t / 1) - 1);
+ },
+ easeInExpo: function(t) {
+ return (t === 0) ? 1 : 1 * Math.pow(2, 10 * (t / 1 - 1));
+ },
+ easeOutExpo: function(t) {
+ return (t === 1) ? 1 : 1 * (-Math.pow(2, -10 * t / 1) + 1);
+ },
+ easeInOutExpo: function(t) {
+ if (t === 0) {
+ return 0;
+ }
+ if (t === 1) {
+ return 1;
+ }
+ if ((t /= 1 / 2) < 1) {
+ return 1 / 2 * Math.pow(2, 10 * (t - 1));
+ }
+ return 1 / 2 * (-Math.pow(2, -10 * --t) + 2);
+ },
+ easeInCirc: function(t) {
+ if (t >= 1) {
+ return t;
+ }
+ return -1 * (Math.sqrt(1 - (t /= 1) * t) - 1);
+ },
+ easeOutCirc: function(t) {
+ return 1 * Math.sqrt(1 - (t = t / 1 - 1) * t);
+ },
+ easeInOutCirc: function(t) {
+ if ((t /= 1 / 2) < 1) {
+ return -1 / 2 * (Math.sqrt(1 - t * t) - 1);
+ }
+ return 1 / 2 * (Math.sqrt(1 - (t -= 2) * t) + 1);
+ },
+ easeInElastic: function(t) {
+ var s = 1.70158;
+ var p = 0;
+ var a = 1;
+ if (t === 0) {
+ return 0;
+ }
+ if ((t /= 1) == 1) {
+ return 1;
+ }
+ if (!p) {
+ p = 1 * 0.3;
+ }
+ if (a < Math.abs(1)) {
+ a = 1;
+ s = p / 4;
+ } else {
+ s = p / (2 * Math.PI) * Math.asin(1 / a);
+ }
+ return -(a * Math.pow(2, 10 * (t -= 1)) * Math.sin((t * 1 - s) * (2 * Math.PI) / p));
+ },
+ easeOutElastic: function(t) {
+ var s = 1.70158;
+ var p = 0;
+ var a = 1;
+ if (t === 0) {
+ return 0;
+ }
+ if ((t /= 1) == 1) {
+ return 1;
+ }
+ if (!p) {
+ p = 1 * 0.3;
+ }
+ if (a < Math.abs(1)) {
+ a = 1;
+ s = p / 4;
+ } else {
+ s = p / (2 * Math.PI) * Math.asin(1 / a);
+ }
+ return a * Math.pow(2, -10 * t) * Math.sin((t * 1 - s) * (2 * Math.PI) / p) + 1;
+ },
+ easeInOutElastic: function(t) {
+ var s = 1.70158;
+ var p = 0;
+ var a = 1;
+ if (t === 0) {
+ return 0;
+ }
+ if ((t /= 1 / 2) == 2) {
+ return 1;
+ }
+ if (!p) {
+ p = 1 * (0.3 * 1.5);
+ }
+ if (a < Math.abs(1)) {
+ a = 1;
+ s = p / 4;
+ } else {
+ s = p / (2 * Math.PI) * Math.asin(1 / a);
+ }
+ if (t < 1) {
+ return -0.5 * (a * Math.pow(2, 10 * (t -= 1)) * Math.sin((t * 1 - s) * (2 * Math.PI) / p));
+ }
+ return a * Math.pow(2, -10 * (t -= 1)) * Math.sin((t * 1 - s) * (2 * Math.PI) / p) * 0.5 + 1;
+ },
+ easeInBack: function(t) {
+ var s = 1.70158;
+ return 1 * (t /= 1) * t * ((s + 1) * t - s);
+ },
+ easeOutBack: function(t) {
+ var s = 1.70158;
+ return 1 * ((t = t / 1 - 1) * t * ((s + 1) * t + s) + 1);
+ },
+ easeInOutBack: function(t) {
+ var s = 1.70158;
+ if ((t /= 1 / 2) < 1) {
+ return 1 / 2 * (t * t * (((s *= (1.525)) + 1) * t - s));
+ }
+ return 1 / 2 * ((t -= 2) * t * (((s *= (1.525)) + 1) * t + s) + 2);
+ },
+ easeInBounce: function(t) {
+ return 1 - easingEffects.easeOutBounce(1 - t);
+ },
+ easeOutBounce: function(t) {
+ if ((t /= 1) < (1 / 2.75)) {
+ return 1 * (7.5625 * t * t);
+ } else if (t < (2 / 2.75)) {
+ return 1 * (7.5625 * (t -= (1.5 / 2.75)) * t + 0.75);
+ } else if (t < (2.5 / 2.75)) {
+ return 1 * (7.5625 * (t -= (2.25 / 2.75)) * t + 0.9375);
+ } else {
+ return 1 * (7.5625 * (t -= (2.625 / 2.75)) * t + 0.984375);
+ }
+ },
+ easeInOutBounce: function(t) {
+ if (t < 1 / 2) {
+ return easingEffects.easeInBounce(t * 2) * 0.5;
+ }
+ return easingEffects.easeOutBounce(t * 2 - 1) * 0.5 + 1 * 0.5;
+ }
+ },
+ //Request animation polyfill - http://www.paulirish.com/2011/requestanimationframe-for-smart-animating/
+ requestAnimFrame = helpers.requestAnimFrame = (function() {
+ return window.requestAnimationFrame ||
+ window.webkitRequestAnimationFrame ||
+ window.mozRequestAnimationFrame ||
+ window.oRequestAnimationFrame ||
+ window.msRequestAnimationFrame ||
+ function(callback) {
+ return window.setTimeout(callback, 1000 / 60);
+ };
+ })(),
+ cancelAnimFrame = helpers.cancelAnimFrame = (function() {
+ return window.cancelAnimationFrame ||
+ window.webkitCancelAnimationFrame ||
+ window.mozCancelAnimationFrame ||
+ window.oCancelAnimationFrame ||
+ window.msCancelAnimationFrame ||
+ function(callback) {
+ return window.clearTimeout(callback, 1000 / 60);
+ };
+ })(),
+ //-- DOM methods
+ getRelativePosition = helpers.getRelativePosition = function(evt, chart) {
+ var mouseX, mouseY;
+ var e = evt.originalEvent || evt,
+ canvas = evt.currentTarget || evt.srcElement,
+ boundingRect = canvas.getBoundingClientRect();
+
+ if (e.touches && e.touches.length > 0) {
+ mouseX = e.touches[0].clientX;
+ mouseY = e.touches[0].clientY;
+
+ } else {
+ mouseX = e.clientX;
+ mouseY = e.clientY;
+ }
+
+ // Scale mouse coordinates into canvas coordinates
+ // by following the pattern laid out by 'jerryj' in the comments of
+ // http://www.html5canvastutorials.com/advanced/html5-canvas-mouse-coordinates/
+
+ // We divide by the current device pixel ratio, because the canvas is scaled up by that amount in each direction. However
+ // the backend model is in unscaled coordinates. Since we are going to deal with our model coordinates, we go back here
+ mouseX = Math.round((mouseX - boundingRect.left) / (boundingRect.right - boundingRect.left) * canvas.width / chart.currentDevicePixelRatio);
+ mouseY = Math.round((mouseY - boundingRect.top) / (boundingRect.bottom - boundingRect.top) * canvas.height / chart.currentDevicePixelRatio);
+
+ return {
+ x: mouseX,
+ y: mouseY
+ };
+
+ },
+ addEvent = helpers.addEvent = function(node, eventType, method) {
+ if (node.addEventListener) {
+ node.addEventListener(eventType, method);
+ } else if (node.attachEvent) {
+ node.attachEvent("on" + eventType, method);
+ } else {
+ node["on" + eventType] = method;
+ }
+ },
+ removeEvent = helpers.removeEvent = function(node, eventType, handler) {
+ if (node.removeEventListener) {
+ node.removeEventListener(eventType, handler, false);
+ } else if (node.detachEvent) {
+ node.detachEvent("on" + eventType, handler);
+ } else {
+ node["on" + eventType] = noop;
+ }
+ },
+ bindEvents = helpers.bindEvents = function(chartInstance, arrayOfEvents, handler) {
+ // Create the events object if it's not already present
+ if (!chartInstance.events) chartInstance.events = {};
+
+ each(arrayOfEvents, function(eventName) {
+ chartInstance.events[eventName] = function() {
+ handler.apply(chartInstance, arguments);
+ };
+ addEvent(chartInstance.chart.canvas, eventName, chartInstance.events[eventName]);
+ });
+ },
+ unbindEvents = helpers.unbindEvents = function(chartInstance, arrayOfEvents) {
+ each(arrayOfEvents, function(handler, eventName) {
+ removeEvent(chartInstance.chart.canvas, eventName, handler);
+ });
+ },
+ getConstraintWidth = helpers.getConstraintWidth = function(domNode) { // returns Number or undefined if no constraint
+ var constrainedWidth;
+ var constrainedWNode = document.defaultView.getComputedStyle(domNode)['max-width'];
+ var constrainedWContainer = document.defaultView.getComputedStyle(domNode.parentNode)['max-width'];
+ var hasCWNode = constrainedWNode !== null && constrainedWNode !== "none";
+ var hasCWContainer = constrainedWContainer !== null && constrainedWContainer !== "none";
+
+ if (hasCWNode || hasCWContainer) {
+ constrainedWidth = Math.min((hasCWNode ? parseInt(constrainedWNode, 10) : Number.POSITIVE_INFINITY), (hasCWContainer ? parseInt(constrainedWContainer, 10) : Number.POSITIVE_INFINITY));
+ }
+ return constrainedWidth;
+ },
+ getConstraintHeight = helpers.getConstraintHeight = function(domNode) { // returns Number or undefined if no constraint
+
+ var constrainedHeight;
+ var constrainedHNode = document.defaultView.getComputedStyle(domNode)['max-height'];
+ var constrainedHContainer = document.defaultView.getComputedStyle(domNode.parentNode)['max-height'];
+ var hasCHNode = constrainedHNode !== null && constrainedHNode !== "none";
+ var hasCHContainer = constrainedHContainer !== null && constrainedHContainer !== "none";
+
+ if (constrainedHNode || constrainedHContainer) {
+ constrainedHeight = Math.min((hasCHNode ? parseInt(constrainedHNode, 10) : Number.POSITIVE_INFINITY), (hasCHContainer ? parseInt(constrainedHContainer, 10) : Number.POSITIVE_INFINITY));
+ }
+ return constrainedHeight;
+ },
+ getMaximumWidth = helpers.getMaximumWidth = function(domNode) {
+ var container = domNode.parentNode;
+ var padding = parseInt(getStyle(container, 'padding-left')) + parseInt(getStyle(container, 'padding-right'));
+
+ var w = container.clientWidth - padding;
+ var cw = getConstraintWidth(domNode);
+ if (cw !== undefined) {
+ w = Math.min(w, cw);
+ }
+
+ return w;
+ },
+ getMaximumHeight = helpers.getMaximumHeight = function(domNode) {
+ var container = domNode.parentNode;
+ var padding = parseInt(getStyle(container, 'padding-top')) + parseInt(getStyle(container, 'padding-bottom'));
+
+ var h = container.clientHeight - padding;
+ var ch = getConstraintHeight(domNode);
+ if (ch !== undefined) {
+ h = Math.min(h, ch);
+ }
+
+ return h;
+ },
+ getStyle = helpers.getStyle = function(el, property) {
+ return el.currentStyle ?
+ el.currentStyle[property] :
+ document.defaultView.getComputedStyle(el, null).getPropertyValue(property);
+ },
+ getMaximumSize = helpers.getMaximumSize = helpers.getMaximumWidth, // legacy support
+ retinaScale = helpers.retinaScale = function(chart) {
+ var ctx = chart.ctx;
+ var width = chart.canvas.width;
+ var height = chart.canvas.height;
+ var pixelRatio = chart.currentDevicePixelRatio = window.devicePixelRatio || 1;
+
+ if (pixelRatio !== 1) {
+ ctx.canvas.height = height * pixelRatio;
+ ctx.canvas.width = width * pixelRatio;
+ ctx.scale(pixelRatio, pixelRatio);
+
+ ctx.canvas.style.width = width + 'px';
+ ctx.canvas.style.height = height + 'px';
+
+ // Store the device pixel ratio so that we can go backwards in `destroy`.
+ // The devicePixelRatio changes with zoom, so there are no guarantees that it is the same
+ // when destroy is called
+ chart.originalDevicePixelRatio = chart.originalDevicePixelRatio || pixelRatio;
+ }
+ },
+ //-- Canvas methods
+ clear = helpers.clear = function(chart) {
+ chart.ctx.clearRect(0, 0, chart.width, chart.height);
+ },
+ fontString = helpers.fontString = function(pixelSize, fontStyle, fontFamily) {
+ return fontStyle + " " + pixelSize + "px " + fontFamily;
+ },
+ longestText = helpers.longestText = function(ctx, font, arrayOfStrings) {
+ ctx.font = font;
+ var longest = 0;
+ each(arrayOfStrings, function(string) {
+ var textWidth = ctx.measureText(string).width;
+ longest = (textWidth > longest) ? textWidth : longest;
+ });
+ return longest;
+ },
+ drawRoundedRectangle = helpers.drawRoundedRectangle = function(ctx, x, y, width, height, radius) {
+ ctx.beginPath();
+ ctx.moveTo(x + radius, y);
+ ctx.lineTo(x + width - radius, y);
+ ctx.quadraticCurveTo(x + width, y, x + width, y + radius);
+ ctx.lineTo(x + width, y + height - radius);
+ ctx.quadraticCurveTo(x + width, y + height, x + width - radius, y + height);
+ ctx.lineTo(x + radius, y + height);
+ ctx.quadraticCurveTo(x, y + height, x, y + height - radius);
+ ctx.lineTo(x, y + radius);
+ ctx.quadraticCurveTo(x, y, x + radius, y);
+ ctx.closePath();
+ },
+ color = helpers.color = function(color) {
+ if (!root.Color) {
+ console.log('Color.js not found!');
+ return color;
+ }
+ return root.Color(color);
+ },
+ addResizeListener = helpers.addResizeListener = function(node, callback) {
+ // Hide an iframe before the node
+ var hiddenIframe = document.createElement('iframe');
+ var hiddenIframeClass = 'chartjs-hidden-iframe';
+
+ if (hiddenIframe.classlist) {
+ // can use classlist
+ hiddenIframe.classlist.add(hiddenIframeClass);
+ } else {
+ hiddenIframe.setAttribute('class', hiddenIframeClass);
+ }
+
+ // Set the style
+ hiddenIframe.style.width = '100%';
+ hiddenIframe.style.display = 'block';
+ hiddenIframe.style.border = 0;
+ hiddenIframe.style.height = 0;
+ hiddenIframe.style.margin = 0;
+ hiddenIframe.style.position = 'absolute';
+ hiddenIframe.style.left = 0;
+ hiddenIframe.style.right = 0;
+ hiddenIframe.style.top = 0;
+ hiddenIframe.style.bottom = 0;
+
+ // Insert the iframe so that contentWindow is available
+ node.insertBefore(hiddenIframe, node.firstChild);
+
+ var timer = 0;
+ (hiddenIframe.contentWindow || hiddenIframe).onresize = function() {
+ if (callback) {
+ callback();
+ }
+ };
+ },
+ removeResizeListener = helpers.removeResizeListener = function(node) {
+ var hiddenIframe = node.querySelector('.chartjs-hidden-iframe');
+
+ // Remove the resize detect iframe
+ if (hiddenIframe) {
+ hiddenIframe.parentNode.removeChild(hiddenIframe);
+ }
+ },
+ isArray = helpers.isArray = function(obj) {
+ if (!Array.isArray) {
+ return Object.prototype.toString.call(arg) === '[object Array]';
+ }
+ return Array.isArray(obj);
+ },
+ isDatasetVisible = helpers.isDatasetVisible = function(dataset) {
+ return !dataset.hidden;
+ };
+
+ helpers.callCallback = function(fn, args, _tArg) {
+ if (fn && typeof fn.call === 'function') {
+ fn.apply(_tArg, args);
}
}
+}).call(this);
- var Radar = function (data,config,ctx) {
- var maxSize, scaleHop, calculatedScale, labelHeight, scaleHeight, valueBounds, labelTemplateString;
-
- //If no labels are defined set to an empty array, so referencing length for looping doesn't blow up.
- if (!data.labels) data.labels = [];
-
- calculateDrawingSizes();
+(function() {
- var valueBounds = getValueBounds();
+ "use strict";
- labelTemplateString = (config.scaleShowLabels)? config.scaleLabel : null;
+ //Declare root variable - window in the browser, global on the server
+ var root = this,
+ Chart = root.Chart,
+ helpers = Chart.helpers;
- //Check and set the scale
- if (!config.scaleOverride){
-
- calculatedScale = calculateScale(scaleHeight,valueBounds.maxSteps,valueBounds.minSteps,valueBounds.maxValue,valueBounds.minValue,labelTemplateString);
- }
- else {
- calculatedScale = {
- steps : config.scaleSteps,
- stepValue : config.scaleStepWidth,
- graphMin : config.scaleStartValue,
- labels : []
+ Chart.elements = {};
+
+ Chart.Element = function(configuration) {
+ helpers.extend(this, configuration);
+ this.initialize.apply(this, arguments);
+ };
+ helpers.extend(Chart.Element.prototype, {
+ initialize: function() {},
+ pivot: function() {
+ if (!this._view) {
+ this._view = helpers.clone(this._model);
}
- populateLabels(labelTemplateString, calculatedScale.labels,calculatedScale.steps,config.scaleStartValue,config.scaleStepWidth);
- }
-
- scaleHop = maxSize/(calculatedScale.steps);
-
- animationLoop(config,drawScale,drawAllDataPoints,ctx);
-
- //Radar specific functions.
- function drawAllDataPoints(animationDecimal){
- var rotationDegree = (2*Math.PI)/data.datasets[0].data.length;
-
- ctx.save();
- //translate to the centre of the canvas.
- ctx.translate(width/2,height/2);
-
- //We accept multiple data sets for radar charts, so show loop through each set
- for (var i=0; i Math.PI){
- ctx.textAlign = "right";
+ }
+
+ this.animations.push({
+ chartInstance: chartInstance,
+ animationObject: animationObject
+ });
+
+ // If there are no animations queued, manually kickstart a digest, for lack of a better word
+ if (this.animations.length == 1) {
+ helpers.requestAnimFrame.call(window, this.digestWrapper);
+ }
+ },
+ // Cancel the animation for a given chart instance
+ cancelAnimation: function(chartInstance) {
+ var index = helpers.findNextWhere(this.animations, function(animationWrapper) {
+ return animationWrapper.chartInstance === chartInstance;
+ });
+
+ if (index) {
+ this.animations.splice(index, 1);
+ chartInstance.animating = false;
+ }
+ },
+ // calls startDigest with the proper context
+ digestWrapper: function() {
+ Chart.animationService.startDigest.call(Chart.animationService);
+ },
+ startDigest: function() {
+
+ var startTime = Date.now();
+ var framesToDrop = 0;
+
+ if (this.dropFrames > 1) {
+ framesToDrop = Math.floor(this.dropFrames);
+ this.dropFrames = this.dropFrames % 1;
+ }
+
+ for (var i = 0; i < this.animations.length; i++) {
+ if (this.animations[i].animationObject.currentStep === null) {
+ this.animations[i].animationObject.currentStep = 0;
}
- else{
+
+ this.animations[i].animationObject.currentStep += 1 + framesToDrop;
+
+ if (this.animations[i].animationObject.currentStep > this.animations[i].animationObject.numSteps) {
+ this.animations[i].animationObject.currentStep = this.animations[i].animationObject.numSteps;
+ }
+
+ this.animations[i].animationObject.render(this.animations[i].chartInstance, this.animations[i].animationObject);
+ if (this.animations[i].animationObject.onAnimationProgress && this.animations[i].animationObject.onAnimationProgress.call) {
+ this.animations[i].animationObject.onAnimationProgress.call(this.animations[i].chartInstance, this.animations[i]);
+ }
+
+ if (this.animations[i].animationObject.currentStep == this.animations[i].animationObject.numSteps) {
+ if (this.animations[i].animationObject.onAnimationComplete && this.animations[i].animationObject.onAnimationComplete.call) {
+ this.animations[i].animationObject.onAnimationComplete.call(this.animations[i].chartInstance, this.animations[i]);
+ }
+
+ // executed the last frame. Remove the animation.
+ this.animations[i].chartInstance.animating = false;
+ this.animations.splice(i, 1);
+ // Keep the index in place to offset the splice
+ i--;
+ }
+ }
+
+ var endTime = Date.now();
+ var dropFrames = (endTime - startTime) / this.frameDuration;
+
+ this.dropFrames += dropFrames;
+
+ // Do we have more stuff to animate?
+ if (this.animations.length > 0) {
+ helpers.requestAnimFrame.call(window, this.digestWrapper);
+ }
+ }
+ };
+
+}).call(this);
+
+(function() {
+
+ "use strict";
+
+ //Declare root variable - window in the browser, global on the server
+ var root = this,
+ Chart = root.Chart,
+ helpers = Chart.helpers;
+
+
+ //Create a dictionary of chart types, to allow for extension of existing types
+ Chart.types = {};
+
+ //Store a reference to each instance - allowing us to globally resize chart instances on window resize.
+ //Destroy method on the chart will remove the instance of the chart from this reference.
+ Chart.instances = {};
+
+ // Controllers available for dataset visualization eg. bar, line, slice, etc.
+ Chart.controllers = {};
+
+ // The main controller of a chart
+ Chart.Controller = function(instance) {
+
+ this.chart = instance;
+ this.config = instance.config;
+ this.options = this.config.options = helpers.configMerge(Chart.defaults.global, Chart.defaults[this.config.type], this.config.options || {});
+ this.id = helpers.uid();
+
+ Object.defineProperty(this, 'data', {
+ get: function() {
+ return this.config.data;
+ },
+ });
+
+ //Add the chart instance to the global namespace
+ Chart.instances[this.id] = this;
+
+ if (this.options.responsive) {
+ // Silent resize before chart draws
+ this.resize(true);
+ }
+
+ this.initialize.call(this);
+
+ return this;
+ };
+
+ helpers.extend(Chart.Controller.prototype, {
+
+ initialize: function initialize() {
+
+ // TODO
+ // If BeforeInit(this) doesn't return false, proceed
+
+ this.bindEvents();
+
+ // Make sure controllers are built first so that each dataset is bound to an axis before the scales
+ // are built
+ this.ensureScalesHaveIDs();
+ this.buildOrUpdateControllers();
+ this.buildScales();
+ this.buildSurroundingItems();
+ this.updateLayout();
+ this.resetElements();
+ this.initToolTip();
+ this.update();
+
+ // TODO
+ // If AfterInit(this) doesn't return false, proceed
+
+ return this;
+ },
+
+ clear: function clear() {
+ helpers.clear(this.chart);
+ return this;
+ },
+
+ stop: function stop() {
+ // Stops any current animation loop occuring
+ Chart.animationService.cancelAnimation(this);
+ return this;
+ },
+
+ resize: function resize(silent) {
+ this.stop();
+ var canvas = this.chart.canvas;
+ var newWidth = helpers.getMaximumWidth(this.chart.canvas);
+ var newHeight = (this.options.maintainAspectRatio && isNaN(this.chart.aspectRatio) === false && isFinite(this.chart.aspectRatio) && this.chart.aspectRatio !== 0) ? newWidth / this.chart.aspectRatio : helpers.getMaximumHeight(this.chart.canvas);
+
+ canvas.width = this.chart.width = newWidth;
+ canvas.height = this.chart.height = newHeight;
+
+ helpers.retinaScale(this.chart);
+
+ if (!silent) {
+ this.update(this.options.responsiveAnimationDuration);
+ }
+
+ return this;
+ },
+ ensureScalesHaveIDs: function ensureScalesHaveIDs() {
+ var defaultXAxisID = 'x-axis-';
+ var defaultYAxisID = 'y-axis-';
+
+ if (this.options.scales) {
+ if (this.options.scales.xAxes && this.options.scales.xAxes.length) {
+ helpers.each(this.options.scales.xAxes, function(xAxisOptions, index) {
+ xAxisOptions.id = xAxisOptions.id || (defaultXAxisID + index);
+ }, this);
+ }
+
+ if (this.options.scales.yAxes && this.options.scales.yAxes.length) {
+ // Build the y axes
+ helpers.each(this.options.scales.yAxes, function(yAxisOptions, index) {
+ yAxisOptions.id = yAxisOptions.id || (defaultYAxisID + index);
+ }, this);
+ }
+ }
+ },
+ buildScales: function buildScales() {
+ // Map of scale ID to scale object so we can lookup later
+ this.scales = {};
+
+ // Build the x axes
+ if (this.options.scales) {
+ if (this.options.scales.xAxes && this.options.scales.xAxes.length) {
+ helpers.each(this.options.scales.xAxes, function(xAxisOptions, index) {
+ var ScaleClass = Chart.scaleService.getScaleConstructor(xAxisOptions.type);
+ var scale = new ScaleClass({
+ ctx: this.chart.ctx,
+ options: xAxisOptions,
+ chart: this,
+ id: xAxisOptions.id,
+ });
+
+ this.scales[scale.id] = scale;
+ }, this);
+ }
+
+ if (this.options.scales.yAxes && this.options.scales.yAxes.length) {
+ // Build the y axes
+ helpers.each(this.options.scales.yAxes, function(yAxisOptions, index) {
+ var ScaleClass = Chart.scaleService.getScaleConstructor(yAxisOptions.type);
+ var scale = new ScaleClass({
+ ctx: this.chart.ctx,
+ options: yAxisOptions,
+ chart: this,
+ id: yAxisOptions.id,
+ });
+
+ this.scales[scale.id] = scale;
+ }, this);
+ }
+ }
+ if (this.options.scale) {
+ // Build radial axes
+ var ScaleClass = Chart.scaleService.getScaleConstructor(this.options.scale.type);
+ var scale = new ScaleClass({
+ ctx: this.chart.ctx,
+ options: this.options.scale,
+ chart: this,
+ });
+
+ this.scale = scale;
+
+ this.scales.radialScale = scale;
+ }
+
+ Chart.scaleService.addScalesToLayout(this);
+ },
+
+ buildSurroundingItems: function() {
+ if (this.options.title) {
+ this.titleBlock = new Chart.Title({
+ ctx: this.chart.ctx,
+ options: this.options.title,
+ chart: this
+ });
+
+ Chart.layoutService.addBox(this, this.titleBlock);
+ }
+
+ if (this.options.legend) {
+ this.legend = new Chart.Legend({
+ ctx: this.chart.ctx,
+ options: this.options.legend,
+ chart: this,
+ });
+
+ Chart.layoutService.addBox(this, this.legend);
+ }
+ },
+
+ updateLayout: function() {
+ Chart.layoutService.update(this, this.chart.width, this.chart.height);
+ },
+
+ buildOrUpdateControllers: function buildOrUpdateControllers(resetNewControllers) {
+ var types = [];
+ helpers.each(this.data.datasets, function(dataset, datasetIndex) {
+ if (!dataset.type) {
+ dataset.type = this.config.type;
+ }
+
+ var type = dataset.type;
+ types.push(type);
+
+ if (dataset.controller) {
+ dataset.controller.updateIndex(datasetIndex);
+ } else {
+ dataset.controller = new Chart.controllers[type](this, datasetIndex);
+
+ if (resetNewControllers) {
+ dataset.controller.reset();
+ }
+ }
+ }, this);
+
+ if (types.length > 1) {
+ for (var i = 1; i < types.length; i++) {
+ if (types[i] != types[i - 1]) {
+ this.isCombo = true;
+ break;
+ }
+ }
+ }
+ },
+
+ resetElements: function resetElements() {
+ helpers.each(this.data.datasets, function(dataset, datasetIndex) {
+ dataset.controller.reset();
+ }, this);
+ },
+
+ update: function update(animationDuration, lazy) {
+ // In case the entire data object changed
+ this.tooltip._data = this.data;
+
+ // Make sure dataset controllers are updated and new controllers are reset
+ this.buildOrUpdateControllers(true);
+
+ Chart.layoutService.update(this, this.chart.width, this.chart.height);
+
+ // Make sure all dataset controllers have correct meta data counts
+ helpers.each(this.data.datasets, function(dataset, datasetIndex) {
+ dataset.controller.buildOrUpdateElements();
+ }, this);
+
+ // This will loop through any data and do the appropriate element update for the type
+ helpers.each(this.data.datasets, function(dataset, datasetIndex) {
+ dataset.controller.update();
+ }, this);
+ this.render(animationDuration, lazy);
+ },
+
+ render: function render(duration, lazy) {
+
+ if (this.options.animation && ((typeof duration !== 'undefined' && duration !== 0) || (typeof duration == 'undefined' && this.options.animation.duration !== 0))) {
+ var animation = new Chart.Animation();
+ animation.numSteps = (duration || this.options.animation.duration) / 16.66; //60 fps
+ animation.easing = this.options.animation.easing;
+
+ // render function
+ animation.render = function(chartInstance, animationObject) {
+ var easingFunction = helpers.easingEffects[animationObject.easing];
+ var stepDecimal = animationObject.currentStep / animationObject.numSteps;
+ var easeDecimal = easingFunction(stepDecimal);
+
+ chartInstance.draw(easeDecimal, stepDecimal, animationObject.currentStep);
+ };
+
+ // user events
+ animation.onAnimationProgress = this.options.animation.onProgress;
+ animation.onAnimationComplete = this.options.animation.onComplete;
+
+ Chart.animationService.addAnimation(this, animation, duration, lazy);
+ } else {
+ this.draw();
+ if (this.options.animation && this.options.animation.onComplete && this.options.animation.onComplete.call) {
+ this.options.animation.onComplete.call(this);
+ }
+ }
+ return this;
+ },
+
+ draw: function(ease) {
+ var easingDecimal = ease || 1;
+ this.clear();
+
+ // Draw all the scales
+ helpers.each(this.boxes, function(box) {
+ box.draw(this.chartArea);
+ }, this);
+ if (this.scale) {
+ this.scale.draw();
+ }
+
+ // Draw each dataset via its respective controller (reversed to support proper line stacking)
+ helpers.each(this.data.datasets, function(dataset, datasetIndex) {
+ if (helpers.isDatasetVisible(dataset)) {
+ dataset.controller.draw(ease);
+ }
+ }, this);
+
+ // Finally draw the tooltip
+ this.tooltip.transition(easingDecimal).draw();
+ },
+
+ // Get the single element that was clicked on
+ // @return : An object containing the dataset index and element index of the matching element. Also contains the rectangle that was draw
+ getElementAtEvent: function(e) {
+
+ var eventPosition = helpers.getRelativePosition(e, this.chart);
+ var elementsArray = [];
+
+ helpers.each(this.data.datasets, function(dataset, datasetIndex) {
+ if (helpers.isDatasetVisible(dataset)) {
+ helpers.each(dataset.metaData, function(element, index) {
+ if (element.inRange(eventPosition.x, eventPosition.y)) {
+ elementsArray.push(element);
+ return elementsArray;
+ }
+ }, this);
+ }
+ }, this);
+
+ return elementsArray;
+ },
+
+ getElementsAtEvent: function(e) {
+ var eventPosition = helpers.getRelativePosition(e, this.chart);
+ var elementsArray = [];
+
+ var found = (function(){
+ for (var i = 0; i < this.data.datasets.length; i++) {
+ if (helpers.isDatasetVisible(this.data.datasets[i])) {
+ for (var j = 0; j < this.data.datasets[i].metaData.length; j++) {
+ if (this.data.datasets[i].metaData[j].inRange(eventPosition.x, eventPosition.y)) {
+ return this.data.datasets[i].metaData[j];
+ }
+ }
+ }
+ }
+ }).call(this);
+
+ if(!found){
+ return elementsArray;
+ }
+
+ helpers.each(this.data.datasets, function(dataset, dsIndex){
+ if(helpers.isDatasetVisible(dataset)){
+ elementsArray.push(dataset.metaData[found._index]);
+ }
+ }, this);
+
+ return elementsArray;
+ },
+
+ getDatasetAtEvent: function(e) {
+ var elementsArray = this.getElementAtEvent(e);
+
+ if (elementsArray.length > 0) {
+ elementsArray = this.data.datasets[elementsArray[0]._datasetIndex].metaData;
+ }
+
+ return elementsArray;
+ },
+
+ generateLegend: function generateLegend() {
+ return this.options.legendCallback(this);
+ },
+
+ destroy: function destroy() {
+ this.clear();
+ helpers.unbindEvents(this, this.events);
+ helpers.removeResizeListener(this.chart.canvas.parentNode);
+
+ // Reset canvas height/width attributes
+ var canvas = this.chart.canvas;
+ canvas.width = this.chart.width;
+ canvas.height = this.chart.height;
+
+ // if we scaled the canvas in response to a devicePixelRatio !== 1, we need to undo that transform here
+ if (this.chart.originalDevicePixelRatio !== undefined) {
+ this.chart.ctx.scale(1 / this.chart.originalDevicePixelRatio, 1 / this.chart.originalDevicePixelRatio);
+ }
+
+ // Reset to the old style since it may have been changed by the device pixel ratio changes
+ canvas.style.width = this.chart.originalCanvasStyleWidth;
+ canvas.style.height = this.chart.originalCanvasStyleHeight;
+
+ delete Chart.instances[this.id];
+ },
+
+ toBase64Image: function toBase64Image() {
+ return this.chart.canvas.toDataURL.apply(this.chart.canvas, arguments);
+ },
+
+ initToolTip: function initToolTip() {
+ this.tooltip = new Chart.Tooltip({
+ _chart: this.chart,
+ _chartInstance: this,
+ _data: this.data,
+ _options: this.options,
+ }, this);
+ },
+
+ bindEvents: function bindEvents() {
+ helpers.bindEvents(this, this.options.events, function(evt) {
+ this.eventHandler(evt);
+ });
+ },
+ eventHandler: function eventHandler(e) {
+ this.lastActive = this.lastActive || [];
+ this.lastTooltipActive = this.lastTooltipActive || [];
+
+ // Find Active Elements for hover and tooltips
+ if (e.type == 'mouseout') {
+ this.active = [];
+ this.tooltipActive = [];
+ } else {
+
+ var _this = this;
+ var getItemsForMode = function(mode) {
+ switch (mode) {
+ case 'single':
+ return _this.getElementAtEvent(e);
+ case 'label':
+ return _this.getElementsAtEvent(e);
+ case 'dataset':
+ return _this.getDatasetAtEvent(e);
+ default:
+ return e;
+ }
+ };
+
+ this.active = getItemsForMode(this.options.hover.mode);
+ this.tooltipActive = getItemsForMode(this.options.tooltips.mode);
+ }
+
+ // On Hover hook
+ if (this.options.hover.onHover) {
+ this.options.hover.onHover.call(this, this.active);
+ }
+
+ if (e.type == 'mouseup' || e.type == 'click') {
+ if (this.options.onClick) {
+ this.options.onClick.call(this, e, this.active);
+ }
+
+ if (this.legend && this.legend.handleEvent) {
+ this.legend.handleEvent(e);
+ }
+ }
+
+ var dataset;
+ var index;
+
+ // Remove styling for last active (even if it may still be active)
+ if (this.lastActive.length) {
+ switch (this.options.hover.mode) {
+ case 'single':
+ this.data.datasets[this.lastActive[0]._datasetIndex].controller.removeHoverStyle(this.lastActive[0], this.lastActive[0]._datasetIndex, this.lastActive[0]._index);
+ break;
+ case 'label':
+ case 'dataset':
+ for (var i = 0; i < this.lastActive.length; i++) {
+ if (this.lastActive[i])
+ this.data.datasets[this.lastActive[i]._datasetIndex].controller.removeHoverStyle(this.lastActive[i], this.lastActive[i]._datasetIndex, this.lastActive[i]._index);
+ }
+ break;
+ default:
+ // Don't change anything
+ }
+ }
+
+ // Built in hover styling
+ if (this.active.length && this.options.hover.mode) {
+ switch (this.options.hover.mode) {
+ case 'single':
+ this.data.datasets[this.active[0]._datasetIndex].controller.setHoverStyle(this.active[0]);
+ break;
+ case 'label':
+ case 'dataset':
+ for (var j = 0; j < this.active.length; j++) {
+ if (this.active[j])
+ this.data.datasets[this.active[j]._datasetIndex].controller.setHoverStyle(this.active[j]);
+ }
+ break;
+ default:
+ // Don't change anything
+ }
+ }
+
+
+ // Built in Tooltips
+ if (this.options.tooltips.enabled || this.options.tooltips.custom) {
+
+ // The usual updates
+ this.tooltip.initialize();
+ this.tooltip._active = this.tooltipActive;
+ this.tooltip.update();
+ }
+
+ // Hover animations
+ this.tooltip.pivot();
+
+ if (!this.animating) {
+ var changed;
+
+ helpers.each(this.active, function(element, index) {
+ if (element !== this.lastActive[index]) {
+ changed = true;
+ }
+ }, this);
+
+ helpers.each(this.tooltipActive, function(element, index) {
+ if (element !== this.lastTooltipActive[index]) {
+ changed = true;
+ }
+ }, this);
+
+ // If entering, leaving, or changing elements, animate the change via pivot
+ if ((this.lastActive.length !== this.active.length) ||
+ (this.lastTooltipActive.length !== this.tooltipActive.length) ||
+ changed) {
+
+ this.stop();
+
+ if (this.options.tooltips.enabled || this.options.tooltips.custom) {
+ this.tooltip.update(true);
+ }
+
+ // We only need to render at this point. Updating will cause scales to be recomputed generating flicker & using more
+ // memory than necessary.
+ this.render(this.options.hover.animationDuration, true);
+ }
+ }
+
+ // Remember Last Actives
+ this.lastActive = this.active;
+ this.lastTooltipActive = this.tooltipActive;
+ return this;
+ },
+ });
+
+}).call(this);
+
+(function() {
+
+ "use strict";
+
+ //Declare root variable - window in the browser, global on the server
+ var root = this,
+ Chart = root.Chart,
+ helpers = Chart.helpers;
+
+
+ // Base class for all dataset controllers (line, bar, etc)
+ Chart.DatasetController = function(chart, datasetIndex) {
+ this.initialize.call(this, chart, datasetIndex);
+ };
+
+ helpers.extend(Chart.DatasetController.prototype, {
+ initialize: function(chart, datasetIndex) {
+ this.chart = chart;
+ this.index = datasetIndex;
+ this.linkScales();
+ this.addElements();
+ },
+ updateIndex: function(datasetIndex) {
+ this.index = datasetIndex;
+ },
+
+ linkScales: function() {
+ if (!this.getDataset().xAxisID) {
+ this.getDataset().xAxisID = this.chart.options.scales.xAxes[0].id;
+ }
+
+ if (!this.getDataset().yAxisID) {
+ this.getDataset().yAxisID = this.chart.options.scales.yAxes[0].id;
+ }
+ },
+
+ getDataset: function() {
+ return this.chart.data.datasets[this.index];
+ },
+
+ getScaleForId: function(scaleID) {
+ return this.chart.scales[scaleID];
+ },
+
+ reset: function() {
+ this.update(true);
+ },
+
+ buildOrUpdateElements: function buildOrUpdateElements() {
+ // Handle the number of data points changing
+ var numData = this.getDataset().data.length;
+ var numMetaData = this.getDataset().metaData.length;
+
+ // Make sure that we handle number of datapoints changing
+ if (numData < numMetaData) {
+ // Remove excess bars for data points that have been removed
+ this.getDataset().metaData.splice(numData, numMetaData - numData);
+ } else if (numData > numMetaData) {
+ // Add new elements
+ for (var index = numMetaData; index < numData; ++index) {
+ this.addElementAndReset(index);
+ }
+ }
+ },
+
+ // Controllers should implement the following
+ addElements: helpers.noop,
+ addElementAndReset: helpers.noop,
+ draw: helpers.noop,
+ removeHoverStyle: helpers.noop,
+ setHoverStyle: helpers.noop,
+ update: helpers.noop,
+ });
+
+ Chart.DatasetController.extend = helpers.inherits;
+
+}).call(this);
+
+(function() {
+ "use strict";
+
+ var root = this,
+ Chart = root.Chart,
+ helpers = Chart.helpers;
+
+ // The layout service is ver self explanatory. It's responsible for the layout within a chart.
+ // Scales, Legends and Plugins all rely on the layout service and can easily register to be placed anywhere they need
+ // It is this service's responsibility of carrying out that layout.
+ Chart.layoutService = {
+ defaults: {},
+
+ // Register a box to a chartInstance. A box is simply a reference to an object that requires layout. eg. Scales, Legend, Plugins.
+ addBox: function(chartInstance, box) {
+ if (!chartInstance.boxes) {
+ chartInstance.boxes = [];
+ }
+ chartInstance.boxes.push(box);
+ },
+
+ removeBox: function(chartInstance, box) {
+ if (!chartInstance.boxes) {
+ return;
+ }
+ chartInstance.boxes.splice(chartInstance.boxes.indexOf(box), 1);
+ },
+
+ // The most important function
+ update: function(chartInstance, width, height) {
+
+ if (!chartInstance) {
+ return;
+ }
+
+ var xPadding = width > 30 ? 5 : 2;
+ var yPadding = height > 30 ? 5 : 2;
+
+ var leftBoxes = helpers.where(chartInstance.boxes, function(box) {
+ return box.options.position == "left";
+ });
+ var rightBoxes = helpers.where(chartInstance.boxes, function(box) {
+ return box.options.position == "right";
+ });
+ var topBoxes = helpers.where(chartInstance.boxes, function(box) {
+ return box.options.position == "top";
+ });
+ var bottomBoxes = helpers.where(chartInstance.boxes, function(box) {
+ return box.options.position == "bottom";
+ });
+
+ // Boxes that overlay the chartarea such as the radialLinear scale
+ var chartAreaBoxes = helpers.where(chartInstance.boxes, function(box) {
+ return box.options.position == "chartArea";
+ });
+
+ function fullWidthSorter(a, b) {
+
+ }
+
+ // Ensure that full width boxes are at the very top / bottom
+ topBoxes.sort(function(a, b) {
+ return (b.options.fullWidth ? 1 : 0) - (a.options.fullWidth ? 1 : 0);
+ });
+ bottomBoxes.sort(function(a, b) {
+ return (a.options.fullWidth ? 1 : 0) - (b.options.fullWidth ? 1 : 0);
+ });
+
+ // Essentially we now have any number of boxes on each of the 4 sides.
+ // Our canvas looks like the following.
+ // The areas L1 and L2 are the left axes. R1 is the right axis, T1 is the top axis and
+ // B1 is the bottom axis
+ // There are also 4 quadrant-like locations (left to right instead of clockwise) reserved for chart overlays
+ // These locations are single-box locations only, when trying to register a chartArea location that is already taken,
+ // an error will be thrown.
+ //
+ // |----------------------------------------------------|
+ // | T1 (Full Width) |
+ // |----------------------------------------------------|
+ // | | | T2 | |
+ // | |----|-------------------------------------|----|
+ // | | | C1 | | C2 | |
+ // | | |----| |----| |
+ // | | | | |
+ // | L1 | L2 | ChartArea (C0) | R1 |
+ // | | | | |
+ // | | |----| |----| |
+ // | | | C3 | | C4 | |
+ // | |----|-------------------------------------|----|
+ // | | | B1 | |
+ // |----------------------------------------------------|
+ // | B2 (Full Width) |
+ // |----------------------------------------------------|
+ //
+ // What we do to find the best sizing, we do the following
+ // 1. Determine the minimum size of the chart area.
+ // 2. Split the remaining width equally between each vertical axis
+ // 3. Split the remaining height equally between each horizontal axis
+ // 4. Give each layout the maximum size it can be. The layout will return it's minimum size
+ // 5. Adjust the sizes of each axis based on it's minimum reported size.
+ // 6. Refit each axis
+ // 7. Position each axis in the final location
+ // 8. Tell the chart the final location of the chart area
+ // 9. Tell any axes that overlay the chart area the positions of the chart area
+
+ // Step 1
+ var chartWidth = width - (2 * xPadding);
+ var chartHeight = height - (2 * yPadding);
+ var chartAreaWidth = chartWidth / 2; // min 50%
+ var chartAreaHeight = chartHeight / 2; // min 50%
+
+ // Step 2
+ var verticalBoxWidth = (width - chartAreaWidth) / (leftBoxes.length + rightBoxes.length);
+
+ // Step 3
+ var horizontalBoxHeight = (height - chartAreaHeight) / (topBoxes.length + bottomBoxes.length);
+
+ // Step 4
+ var maxChartAreaWidth = chartWidth;
+ var maxChartAreaHeight = chartHeight;
+ var minBoxSizes = [];
+
+ helpers.each(leftBoxes.concat(rightBoxes, topBoxes, bottomBoxes), getMinimumBoxSize);
+
+ function getMinimumBoxSize(box) {
+ var minSize;
+ var isHorizontal = box.isHorizontal();
+
+ if (isHorizontal) {
+ minSize = box.update(box.options.fullWidth ? chartWidth : maxChartAreaWidth, horizontalBoxHeight);
+ maxChartAreaHeight -= minSize.height;
+ } else {
+ minSize = box.update(verticalBoxWidth, chartAreaHeight);
+ maxChartAreaWidth -= minSize.width;
+ }
+
+ minBoxSizes.push({
+ horizontal: isHorizontal,
+ minSize: minSize,
+ box: box,
+ });
+ }
+
+ // At this point, maxChartAreaHeight and maxChartAreaWidth are the size the chart area could
+ // be if the axes are drawn at their minimum sizes.
+
+ // Steps 5 & 6
+ var totalLeftBoxesWidth = xPadding;
+ var totalRightBoxesWidth = xPadding;
+ var totalTopBoxesHeight = yPadding;
+ var totalBottomBoxesHeight = yPadding;
+
+ // Update, and calculate the left and right margins for the horizontal boxes
+ helpers.each(leftBoxes.concat(rightBoxes), fitBox);
+
+ helpers.each(leftBoxes, function(box) {
+ totalLeftBoxesWidth += box.width;
+ });
+
+ helpers.each(rightBoxes, function(box) {
+ totalRightBoxesWidth += box.width;
+ });
+
+ // Set the Left and Right margins for the horizontal boxes
+ helpers.each(topBoxes.concat(bottomBoxes), fitBox);
+
+ // Function to fit a box
+ function fitBox(box) {
+ var minBoxSize = helpers.findNextWhere(minBoxSizes, function(minBoxSize) {
+ return minBoxSize.box === box;
+ });
+
+ if (minBoxSize) {
+ if (box.isHorizontal()) {
+ var scaleMargin = {
+ left: totalLeftBoxesWidth,
+ right: totalRightBoxesWidth,
+ top: 0,
+ bottom: 0,
+ };
+
+ box.update(box.options.fullWidth ? chartWidth : maxChartAreaWidth, minBoxSize.minSize.height, scaleMargin);
+ } else {
+ box.update(minBoxSize.minSize.width, maxChartAreaHeight);
+ }
+ }
+ }
+
+ // Figure out how much margin is on the top and bottom of the vertical boxes
+ helpers.each(topBoxes, function(box) {
+ totalTopBoxesHeight += box.height;
+ });
+
+ helpers.each(bottomBoxes, function(box) {
+ totalBottomBoxesHeight += box.height;
+ });
+
+ // Let the left layout know the final margin
+ helpers.each(leftBoxes.concat(rightBoxes), finalFitVerticalBox);
+
+ function finalFitVerticalBox(box) {
+ var minBoxSize = helpers.findNextWhere(minBoxSizes, function(minBoxSize) {
+ return minBoxSize.box === box;
+ });
+
+ var scaleMargin = {
+ left: 0,
+ right: 0,
+ top: totalTopBoxesHeight,
+ bottom: totalBottomBoxesHeight
+ };
+
+ if (minBoxSize) {
+ box.update(minBoxSize.minSize.width, maxChartAreaHeight, scaleMargin);
+ }
+ }
+
+ // Recalculate because the size of each layout might have changed slightly due to the margins (label rotation for instance)
+ totalLeftBoxesWidth = xPadding;
+ totalRightBoxesWidth = xPadding;
+ totalTopBoxesHeight = yPadding;
+ totalBottomBoxesHeight = yPadding;
+
+ helpers.each(leftBoxes, function(box) {
+ totalLeftBoxesWidth += box.width;
+ });
+
+ helpers.each(rightBoxes, function(box) {
+ totalRightBoxesWidth += box.width;
+ });
+
+ helpers.each(topBoxes, function(box) {
+ totalTopBoxesHeight += box.height;
+ });
+ helpers.each(bottomBoxes, function(box) {
+ totalBottomBoxesHeight += box.height;
+ });
+
+ // Figure out if our chart area changed. This would occur if the dataset layout label rotation
+ // changed due to the application of the margins in step 6. Since we can only get bigger, this is safe to do
+ // without calling `fit` again
+ var newMaxChartAreaHeight = height - totalTopBoxesHeight - totalBottomBoxesHeight;
+ var newMaxChartAreaWidth = width - totalLeftBoxesWidth - totalRightBoxesWidth;
+
+ if (newMaxChartAreaWidth !== maxChartAreaWidth || newMaxChartAreaHeight !== maxChartAreaHeight) {
+ helpers.each(leftBoxes, function(box) {
+ box.height = newMaxChartAreaHeight;
+ });
+
+ helpers.each(rightBoxes, function(box) {
+ box.height = newMaxChartAreaHeight;
+ });
+
+ helpers.each(topBoxes, function(box) {
+ box.width = newMaxChartAreaWidth;
+ });
+
+ helpers.each(bottomBoxes, function(box) {
+ box.width = newMaxChartAreaWidth;
+ });
+
+ maxChartAreaHeight = newMaxChartAreaHeight;
+ maxChartAreaWidth = newMaxChartAreaWidth;
+ }
+
+ // Step 7 - Position the boxes
+ var left = xPadding;
+ var top = yPadding;
+ var right = 0;
+ var bottom = 0;
+
+ helpers.each(leftBoxes.concat(topBoxes), placeBox);
+
+ // Account for chart width and height
+ left += maxChartAreaWidth;
+ top += maxChartAreaHeight;
+
+ helpers.each(rightBoxes, placeBox);
+ helpers.each(bottomBoxes, placeBox);
+
+ function placeBox(box) {
+ if (box.isHorizontal()) {
+ box.left = box.options.fullWidth ? xPadding : totalLeftBoxesWidth;
+ box.right = box.options.fullWidth ? width - xPadding : totalLeftBoxesWidth + maxChartAreaWidth;
+ box.top = top;
+ box.bottom = top + box.height;
+
+ // Move to next point
+ top = box.bottom;
+
+ } else {
+
+ box.left = left;
+ box.right = left + box.width;
+ box.top = totalTopBoxesHeight;
+ box.bottom = totalTopBoxesHeight + maxChartAreaHeight;
+
+ // Move to next point
+ left = box.right;
+ }
+ }
+
+ // Step 8
+ chartInstance.chartArea = {
+ left: totalLeftBoxesWidth,
+ top: totalTopBoxesHeight,
+ right: totalLeftBoxesWidth + maxChartAreaWidth,
+ bottom: totalTopBoxesHeight + maxChartAreaHeight,
+ };
+
+ // Step 9
+ helpers.each(chartAreaBoxes, function(box) {
+ box.left = chartInstance.chartArea.left;
+ box.top = chartInstance.chartArea.top;
+ box.right = chartInstance.chartArea.right;
+ box.bottom = chartInstance.chartArea.bottom;
+
+ box.update(maxChartAreaWidth, maxChartAreaHeight);
+ });
+ }
+ };
+
+
+}).call(this);
+
+(function() {
+ "use strict";
+
+ var root = this,
+ Chart = root.Chart,
+ helpers = Chart.helpers;
+
+ Chart.defaults.global.legend = {
+
+ display: true,
+ position: 'top',
+ fullWidth: true, // marks that this box should take the full width of the canvas (pushing down other boxes)
+
+ // a callback that will handle
+ onClick: function(e, legendItem) {
+ var dataset = this.chart.data.datasets[legendItem.datasetIndex];
+ dataset.hidden = !dataset.hidden;
+
+ // We hid a dataset ... rerender the chart
+ this.chart.update();
+ },
+
+ labels: {
+ boxWidth: 40,
+ fontSize: 12,
+ fontStyle: "normal",
+ fontColor: "#666",
+ fontFamily: "Helvetica Neue",
+ padding: 10,
+ // Generates labels shown in the legend
+ // Valid properties to return:
+ // text : text to display
+ // fillStyle : fill of coloured box
+ // strokeStyle: stroke of coloured box
+ // hidden : if this legend item refers to a hidden item
+ // lineCap : cap style for line
+ // lineDash
+ // lineDashOffset :
+ // lineJoin :
+ // lineWidth :
+ generateLabels: function(data) {
+ return data.datasets.map(function(dataset, i) {
+ return {
+ text: dataset.label,
+ fillStyle: dataset.backgroundColor,
+ hidden: dataset.hidden,
+ lineCap: dataset.borderCapStyle,
+ lineDash: dataset.borderDash,
+ lineDashOffset: dataset.borderDashOffset,
+ lineJoin: dataset.borderJoinStyle,
+ lineWidth: dataset.borderWidth,
+ strokeStyle: dataset.borderColor,
+
+ // Below is extra data used for toggling the datasets
+ datasetIndex: i
+ };
+ }, this);
+ }
+ },
+ };
+
+ Chart.Legend = Chart.Element.extend({
+
+ initialize: function(config) {
+ helpers.extend(this, config);
+
+ // Contains hit boxes for each dataset (in dataset order)
+ this.legendHitBoxes = [];
+
+ // Are we in doughnut mode which has a different data type
+ this.doughnutMode = false;
+ },
+
+ // These methods are ordered by lifecyle. Utilities then follow.
+ // Any function defined here is inherited by all legend types.
+ // Any function can be extended by the legend type
+
+ beforeUpdate: helpers.noop,
+ update: function(maxWidth, maxHeight, margins) {
+
+ // Update Lifecycle - Probably don't want to ever extend or overwrite this function ;)
+ this.beforeUpdate();
+
+ // Absorb the master measurements
+ this.maxWidth = maxWidth;
+ this.maxHeight = maxHeight;
+ this.margins = margins;
+
+ // Dimensions
+ this.beforeSetDimensions();
+ this.setDimensions();
+ this.afterSetDimensions();
+ // Labels
+ this.beforeBuildLabels();
+ this.buildLabels();
+ this.afterBuildLabels();
+
+ // Fit
+ this.beforeFit();
+ this.fit();
+ this.afterFit();
+ //
+ this.afterUpdate();
+
+ return this.minSize;
+
+ },
+ afterUpdate: helpers.noop,
+
+ //
+
+ beforeSetDimensions: helpers.noop,
+ setDimensions: function() {
+ // Set the unconstrained dimension before label rotation
+ if (this.isHorizontal()) {
+ // Reset position before calculating rotation
+ this.width = this.maxWidth;
+ this.left = 0;
+ this.right = this.width;
+ } else {
+ this.height = this.maxHeight;
+
+ // Reset position before calculating rotation
+ this.top = 0;
+ this.bottom = this.height;
+ }
+
+ // Reset padding
+ this.paddingLeft = 0;
+ this.paddingTop = 0;
+ this.paddingRight = 0;
+ this.paddingBottom = 0;
+
+ // Reset minSize
+ this.minSize = {
+ width: 0,
+ height: 0,
+ };
+ },
+ afterSetDimensions: helpers.noop,
+
+ //
+
+ beforeBuildLabels: helpers.noop,
+ buildLabels: function() {
+ this.legendItems = this.options.labels.generateLabels.call(this, this.chart.data);
+ },
+ afterBuildLabels: helpers.noop,
+
+ //
+
+ beforeFit: helpers.noop,
+ fit: function() {
+
+ var ctx = this.ctx;
+ var labelFont = helpers.fontString(this.options.labels.fontSize, this.options.labels.fontStyle, this.options.labels.fontFamily);
+
+ // Reset hit boxes
+ this.legendHitBoxes = [];
+
+ // Width
+ if (this.isHorizontal()) {
+ this.minSize.width = this.maxWidth; // fill all the width
+ } else {
+ this.minSize.width = this.options.display ? 10 : 0;
+ }
+
+ // height
+ if (this.isHorizontal()) {
+ this.minSize.height = this.options.display ? 10 : 0;
+ } else {
+ this.minSize.height = this.maxHeight; // fill all the height
+ }
+
+ // Increase sizes here
+ if (this.options.display) {
+ if (this.isHorizontal()) {
+ // Labels
+
+ // Width of each line of legend boxes. Labels wrap onto multiple lines when there are too many to fit on one
+ this.lineWidths = [0];
+ var totalHeight = this.legendItems.length ? this.options.labels.fontSize + (this.options.labels.padding) : 0;
+
ctx.textAlign = "left";
- }
-
- ctx.textBaseline = "middle";
-
- ctx.fillText(data.labels[k],opposite,-adjacent);
-
- }
- ctx.restore();
- };
- function calculateDrawingSizes(){
- maxSize = (Min([width,height])/2);
+ ctx.textBaseline = 'top';
+ ctx.font = labelFont;
- labelHeight = config.scaleFontSize*2;
-
- var labelLength = 0;
- for (var i=0; ilabelLength) labelLength = textMeasurement;
- }
-
- //Figure out whats the largest - the height of the text or the width of what's there, and minus it from the maximum usable size.
- maxSize -= Max([labelLength,((config.pointLabelFontSize/2)*1.5)]);
-
- maxSize -= config.pointLabelFontSize;
- maxSize = CapValue(maxSize, null, 0);
- scaleHeight = maxSize;
- //If the label height is less than 5, set it to 5 so we don't have lines on top of each other.
- labelHeight = Default(labelHeight,5);
- };
- function getValueBounds() {
- var upperValue = Number.MIN_VALUE;
- var lowerValue = Number.MAX_VALUE;
-
- for (var i=0; i upperValue){upperValue = data.datasets[i].data[j]}
- if (data.datasets[i].data[j] < lowerValue){lowerValue = data.datasets[i].data[j]}
+ helpers.each(this.legendItems, function(legendItem, i) {
+ var width = this.options.labels.boxWidth + (this.options.labels.fontSize / 2) + ctx.measureText(legendItem.text).width;
+ if (this.lineWidths[this.lineWidths.length - 1] + width >= this.width) {
+ totalHeight += this.options.labels.fontSize + (this.options.labels.padding);
+ this.lineWidths[this.lineWidths.length] = this.left;
+ }
+
+ // Store the hitbox width and height here. Final position will be updated in `draw`
+ this.legendHitBoxes[i] = {
+ left: 0,
+ top: 0,
+ width: width,
+ height: this.options.labels.fontSize,
+ };
+
+ this.lineWidths[this.lineWidths.length - 1] += width + this.options.labels.padding;
+ }, this);
+
+ this.minSize.height += totalHeight;
+
+ } else {
+ // TODO vertical
}
}
- var maxSteps = Math.floor((scaleHeight / (labelHeight*0.66)));
- var minSteps = Math.floor((scaleHeight / labelHeight*0.5));
-
- return {
- maxValue : upperValue,
- minValue : lowerValue,
- maxSteps : maxSteps,
- minSteps : minSteps
- };
-
+ this.width = this.minSize.width;
+ this.height = this.minSize.height;
- }
- }
+ },
+ afterFit: helpers.noop,
+
+ // Shared Methods
+ isHorizontal: function() {
+ return this.options.position == "top" || this.options.position == "bottom";
+ },
+
+ // Actualy draw the legend on the canvas
+ draw: function() {
+ if (this.options.display) {
+ var ctx = this.ctx;
+ var cursor = {
+ x: this.left + ((this.width - this.lineWidths[0]) / 2),
+ y: this.top + this.options.labels.padding,
+ line: 0,
+ };
+
+ var labelFont = helpers.fontString(this.options.labels.fontSize, this.options.labels.fontStyle, this.options.labels.fontFamily);
+
+ // Horizontal
+ if (this.isHorizontal()) {
+ // Labels
+ ctx.textAlign = "left";
+ ctx.textBaseline = 'top';
+ ctx.lineWidth = 0.5;
+ ctx.strokeStyle = this.options.labels.fontColor; // for strikethrough effect
+ ctx.fillStyle = this.options.labels.fontColor; // render in correct colour
+ ctx.font = labelFont;
+
+ helpers.each(this.legendItems, function(legendItem, i) {
+ var textWidth = ctx.measureText(legendItem.text).width;
+ var width = this.options.labels.boxWidth + (this.options.labels.fontSize / 2) + textWidth;
+
+ if (cursor.x + width >= this.width) {
+ cursor.y += this.options.labels.fontSize + (this.options.labels.padding);
+ cursor.line++;
+ cursor.x = this.left + ((this.width - this.lineWidths[cursor.line]) / 2);
+ }
+
+ // Set the ctx for the box
+ ctx.save();
+
+ var itemOrDefault = function(item, defaulVal) {
+ return item !== undefined ? item : defaulVal;
+ };
+
+ ctx.fillStyle = itemOrDefault(legendItem.fillStyle, Chart.defaults.global.defaultColor);
+ ctx.lineCap = itemOrDefault(legendItem.lineCap, Chart.defaults.global.elements.line.borderCapStyle);
+ ctx.lineDashOffset = itemOrDefault(legendItem.lineDashOffset, Chart.defaults.global.elements.line.borderDashOffset);
+ ctx.lineJoin = itemOrDefault(legendItem.lineJoin, Chart.defaults.global.elements.line.borderJoinStyle);
+ ctx.lineWidth = itemOrDefault(legendItem.lineWidth, Chart.defaults.global.elements.line.borderWidth);
+ ctx.strokeStyle = itemOrDefault(legendItem.strokeStyle, Chart.defaults.global.defaultColor);
+
+ if (ctx.setLineDash) {
+ // IE 9 and 10 do not support line dash
+ ctx.setLineDash(itemOrDefault(legendItem.lineDash, Chart.defaults.global.elements.line.borderDash));
+ }
+
+ // Draw the box
+ ctx.strokeRect(cursor.x, cursor.y, this.options.labels.boxWidth, this.options.labels.fontSize);
+ ctx.fillRect(cursor.x, cursor.y, this.options.labels.boxWidth, this.options.labels.fontSize);
+
+ ctx.restore();
+
+ this.legendHitBoxes[i].left = cursor.x;
+ this.legendHitBoxes[i].top = cursor.y;
+
+ // Fill the actual label
+ ctx.fillText(legendItem.text, this.options.labels.boxWidth + (this.options.labels.fontSize / 2) + cursor.x, cursor.y);
+
+ if (legendItem.hidden) {
+ // Strikethrough the text if hidden
+ ctx.beginPath();
+ ctx.lineWidth = 2;
+ ctx.moveTo(this.options.labels.boxWidth + (this.options.labels.fontSize / 2) + cursor.x, cursor.y + (this.options.labels.fontSize / 2));
+ ctx.lineTo(this.options.labels.boxWidth + (this.options.labels.fontSize / 2) + cursor.x + textWidth, cursor.y + (this.options.labels.fontSize / 2));
+ ctx.stroke();
+ }
+
+ cursor.x += width + (this.options.labels.padding);
+ }, this);
+ } else {
- var Pie = function(data,config,ctx){
- var segmentTotal = 0;
-
- //In case we have a canvas that is not a square. Minus 5 pixels as padding round the edge.
- var pieRadius = Min([height/2,width/2]) - 5;
-
- for (var i=0; i= this.left && position.x <= this.right && position.y >= this.top && position.y <= this.bottom) {
+ // See if we are touching one of the dataset boxes
+ for (var i = 0; i < this.legendHitBoxes.length; ++i) {
+ var hitBox = this.legendHitBoxes[i];
- for (var j=1; j= hitBox.left && position.x <= hitBox.left + hitBox.width && position.y >= hitBox.top && position.y <= hitBox.top + hitBox.height) {
+ // Touching an element
+ if (this.options.onClick) {
+ this.options.onClick.call(this, e, this.legendItems[i]);
+ }
+ break;
}
}
}
-
- function yPos(dataSet,iteration){
- return xAxisPosY - animPc*(calculateOffset(data.datasets[dataSet].data[iteration],calculatedScale,scaleHop));
- }
- function xPos(iteration){
- return yAxisPosX + (valueHop * iteration);
- }
}
- function drawScale(){
- //X axis line
- ctx.lineWidth = config.scaleLineWidth;
- ctx.strokeStyle = config.scaleLineColor;
- ctx.beginPath();
- ctx.moveTo(width-widestXLabel/2+5,xAxisPosY);
- ctx.lineTo(width-(widestXLabel/2)-xAxisLength-5,xAxisPosY);
- ctx.stroke();
-
-
- if (rotateLabels > 0){
- ctx.save();
- ctx.textAlign = "right";
- }
- else{
- ctx.textAlign = "center";
- }
- ctx.fillStyle = config.scaleFontColor;
- for (var i=0; i 0){
- ctx.translate(yAxisPosX + i*valueHop,xAxisPosY + config.scaleFontSize);
- ctx.rotate(-(rotateLabels * (Math.PI/180)));
- ctx.fillText(data.labels[i], 0,0);
- ctx.restore();
- }
-
- else{
- ctx.fillText(data.labels[i], yAxisPosX + i*valueHop,xAxisPosY + config.scaleFontSize+3);
- }
+ });
- ctx.beginPath();
- ctx.moveTo(yAxisPosX + i * valueHop, xAxisPosY+3);
-
- //Check i isnt 0, so we dont go over the Y axis twice.
- if(config.scaleShowGridLines && i>0){
- ctx.lineWidth = config.scaleGridLineWidth;
- ctx.strokeStyle = config.scaleGridLineColor;
- ctx.lineTo(yAxisPosX + i * valueHop, 5);
- }
- else{
- ctx.lineTo(yAxisPosX + i * valueHop, xAxisPosY+3);
- }
- ctx.stroke();
- }
-
- //Y axis
- ctx.lineWidth = config.scaleLineWidth;
- ctx.strokeStyle = config.scaleLineColor;
- ctx.beginPath();
- ctx.moveTo(yAxisPosX,xAxisPosY+5);
- ctx.lineTo(yAxisPosX,5);
- ctx.stroke();
-
- ctx.textAlign = "right";
- ctx.textBaseline = "middle";
- for (var j=0; j longestText)? measuredText : longestText;
- }
- //Add a little extra padding from the y axis
- longestText +=10;
- }
- xAxisLength = width - longestText - widestXLabel;
- valueHop = Math.floor(xAxisLength/(data.labels.length-1));
-
- yAxisPosX = width-widestXLabel/2-xAxisLength;
- xAxisPosY = scaleHeight + config.scaleFontSize/2;
- }
- function calculateDrawingSizes(){
- maxSize = height;
+}).call(this);
- //Need to check the X axis first - measure the length of each text metric, and figure out if we need to rotate by 45 degrees.
- ctx.font = config.scaleFontStyle + " " + config.scaleFontSize+"px " + config.scaleFontFamily;
- widestXLabel = 1;
- for (var i=0; i widestXLabel)? textLength : widestXLabel;
- }
- if (width/data.labels.length < widestXLabel){
- rotateLabels = 45;
- if (width/data.labels.length < Math.cos(rotateLabels) * widestXLabel){
- rotateLabels = 90;
- maxSize -= widestXLabel;
- }
- else{
- maxSize -= Math.sin(rotateLabels) * widestXLabel;
- }
- }
- else{
- maxSize -= config.scaleFontSize;
- }
-
- //Add a little padding between the x line and the text
- maxSize -= 5;
-
-
- labelHeight = config.scaleFontSize;
-
- maxSize -= labelHeight;
- //Set 5 pixels greater than the font size to allow for a little padding from the X axis.
-
- scaleHeight = maxSize;
-
- //Then get the area above we can safely draw on.
-
- }
- function getValueBounds() {
- var upperValue = Number.MIN_VALUE;
- var lowerValue = Number.MAX_VALUE;
- for (var i=0; i upperValue) { upperValue = data.datasets[i].data[j] };
- if ( data.datasets[i].data[j] < lowerValue) { lowerValue = data.datasets[i].data[j] };
- }
- };
-
- var maxSteps = Math.floor((scaleHeight / (labelHeight*0.66)));
- var minSteps = Math.floor((scaleHeight / labelHeight*0.5));
-
- return {
- maxValue : upperValue,
- minValue : lowerValue,
- maxSteps : maxSteps,
- minSteps : minSteps
- };
-
-
- }
+(function() {
+ "use strict";
-
- }
-
- var Bar = function(data,config,ctx){
- var maxSize, scaleHop, calculatedScale, labelHeight, scaleHeight, valueBounds, labelTemplateString, valueHop,widestXLabel, xAxisLength,yAxisPosX,xAxisPosY,barWidth, rotateLabels = 0;
-
- calculateDrawingSizes();
-
- valueBounds = getValueBounds();
- //Check and set the scale
- labelTemplateString = (config.scaleShowLabels)? config.scaleLabel : "";
- if (!config.scaleOverride){
-
- calculatedScale = calculateScale(scaleHeight,valueBounds.maxSteps,valueBounds.minSteps,valueBounds.maxValue,valueBounds.minValue,labelTemplateString);
- }
- else {
- calculatedScale = {
- steps : config.scaleSteps,
- stepValue : config.scaleStepWidth,
- graphMin : config.scaleStartValue,
- labels : []
- }
- populateLabels(labelTemplateString, calculatedScale.labels,calculatedScale.steps,config.scaleStartValue,config.scaleStepWidth);
- }
-
- scaleHop = Math.floor(scaleHeight/calculatedScale.steps);
- calculateXAxisSize();
- animationLoop(config,drawScale,drawBars,ctx);
-
- function drawBars(animPc){
- ctx.lineWidth = config.barStrokeWidth;
- for (var i=0; i 0){
- ctx.save();
- ctx.textAlign = "right";
- }
- else{
- ctx.textAlign = "center";
- }
- ctx.fillStyle = config.scaleFontColor;
- for (var i=0; i 0){
- ctx.translate(yAxisPosX + i*valueHop,xAxisPosY + config.scaleFontSize);
- ctx.rotate(-(rotateLabels * (Math.PI/180)));
- ctx.fillText(data.labels[i], 0,0);
- ctx.restore();
- }
-
- else{
- ctx.fillText(data.labels[i], yAxisPosX + i*valueHop + valueHop/2,xAxisPosY + config.scaleFontSize+3);
- }
+ var root = this,
+ Chart = root.Chart,
+ helpers = Chart.helpers;
- ctx.beginPath();
- ctx.moveTo(yAxisPosX + (i+1) * valueHop, xAxisPosY+3);
-
- //Check i isnt 0, so we dont go over the Y axis twice.
- ctx.lineWidth = config.scaleGridLineWidth;
- ctx.strokeStyle = config.scaleGridLineColor;
- ctx.lineTo(yAxisPosX + (i+1) * valueHop, 5);
- ctx.stroke();
- }
-
- //Y axis
- ctx.lineWidth = config.scaleLineWidth;
- ctx.strokeStyle = config.scaleLineColor;
- ctx.beginPath();
- ctx.moveTo(yAxisPosX,xAxisPosY+5);
- ctx.lineTo(yAxisPosX,5);
- ctx.stroke();
-
- ctx.textAlign = "right";
- ctx.textBaseline = "middle";
- for (var j=0; j longestText)? measuredText : longestText;
- }
- //Add a little extra padding from the y axis
- longestText +=10;
- }
- xAxisLength = width - longestText - widestXLabel;
- valueHop = Math.floor(xAxisLength/(data.labels.length));
-
- barWidth = (valueHop - config.scaleGridLineWidth*2 - (config.barValueSpacing*2) - (config.barDatasetSpacing*data.datasets.length-1) - ((config.barStrokeWidth/2)*data.datasets.length-1))/data.datasets.length;
-
- yAxisPosX = width-widestXLabel/2-xAxisLength;
- xAxisPosY = scaleHeight + config.scaleFontSize/2;
- }
- function calculateDrawingSizes(){
- maxSize = height;
+ Chart.defaults.scale = {
+ display: true,
- //Need to check the X axis first - measure the length of each text metric, and figure out if we need to rotate by 45 degrees.
- ctx.font = config.scaleFontStyle + " " + config.scaleFontSize+"px " + config.scaleFontFamily;
- widestXLabel = 1;
- for (var i=0; i widestXLabel)? textLength : widestXLabel;
- }
- if (width/data.labels.length < widestXLabel){
- rotateLabels = 45;
- if (width/data.labels.length < Math.cos(rotateLabels) * widestXLabel){
- rotateLabels = 90;
- maxSize -= widestXLabel;
- }
- else{
- maxSize -= Math.sin(rotateLabels) * widestXLabel;
- }
- }
- else{
- maxSize -= config.scaleFontSize;
- }
-
- //Add a little padding between the x line and the text
- maxSize -= 5;
-
-
- labelHeight = config.scaleFontSize;
-
- maxSize -= labelHeight;
- //Set 5 pixels greater than the font size to allow for a little padding from the X axis.
-
- scaleHeight = maxSize;
-
- //Then get the area above we can safely draw on.
-
- }
- function getValueBounds() {
- var upperValue = Number.MIN_VALUE;
- var lowerValue = Number.MAX_VALUE;
- for (var i=0; i upperValue) { upperValue = data.datasets[i].data[j] };
- if ( data.datasets[i].data[j] < lowerValue) { lowerValue = data.datasets[i].data[j] };
- }
- };
-
- var maxSteps = Math.floor((scaleHeight / (labelHeight*0.66)));
- var minSteps = Math.floor((scaleHeight / labelHeight*0.5));
-
- return {
- maxValue : upperValue,
- minValue : lowerValue,
- maxSteps : maxSteps,
- minSteps : minSteps
- };
-
-
- }
- }
-
- function calculateOffset(val,calculatedScale,scaleHop){
- var outerValue = calculatedScale.steps * calculatedScale.stepValue;
- var adjustedValue = val - calculatedScale.graphMin;
- var scalingFactor = CapValue(adjustedValue/outerValue,1,0);
- return (scaleHop*calculatedScale.steps) * scalingFactor;
- }
-
- function animationLoop(config,drawScale,drawData,ctx){
- var animFrameAmount = (config.animation)? 1/CapValue(config.animationSteps,Number.MAX_VALUE,1) : 1,
- easingFunction = animationOptions[config.animationEasing],
- percentAnimComplete =(config.animation)? 0 : 1;
-
-
-
- if (typeof drawScale !== "function") drawScale = function(){};
-
- requestAnimFrame(animLoop);
-
- function animateFrame(){
- var easeAdjustedAnimationPercent =(config.animation)? CapValue(easingFunction(percentAnimComplete),null,0) : 1;
- clear(ctx);
- if(config.scaleOverlay){
- drawData(easeAdjustedAnimationPercent);
- drawScale();
+ // grid line settings
+ gridLines: {
+ display: true,
+ color: "rgba(0, 0, 0, 0.1)",
+ lineWidth: 1,
+ drawOnChartArea: true,
+ drawTicks: true,
+ zeroLineWidth: 1,
+ zeroLineColor: "rgba(0,0,0,0.25)",
+ offsetGridLines: false,
+ },
+
+ // scale label
+ scaleLabel: {
+ fontColor: '#666',
+ fontFamily: 'Helvetica Neue',
+ fontSize: 12,
+ fontStyle: 'normal',
+
+ // actual label
+ labelString: '',
+
+ // display property
+ display: false,
+ },
+
+ // label settings
+ ticks: {
+ beginAtZero: false,
+ fontSize: 12,
+ fontStyle: "normal",
+ fontColor: "#666",
+ fontFamily: "Helvetica Neue",
+ maxRotation: 90,
+ mirror: false,
+ padding: 10,
+ reverse: false,
+ display: true,
+ autoSkip: true,
+ autoSkipPadding: 20,
+ callback: function(value) {
+ return '' + value;
+ },
+ },
+ };
+
+ Chart.Scale = Chart.Element.extend({
+
+ // These methods are ordered by lifecyle. Utilities then follow.
+ // Any function defined here is inherited by all scale types.
+ // Any function can be extended by the scale type
+
+ beforeUpdate: function() {
+ helpers.callCallback(this.options.beforeUpdate, [this]);
+ },
+ update: function(maxWidth, maxHeight, margins) {
+
+ // Update Lifecycle - Probably don't want to ever extend or overwrite this function ;)
+ this.beforeUpdate();
+
+ // Absorb the master measurements
+ this.maxWidth = maxWidth;
+ this.maxHeight = maxHeight;
+ this.margins = helpers.extend({
+ left: 0,
+ right: 0,
+ top: 0,
+ bottom: 0
+ }, margins);
+
+ // Dimensions
+ this.beforeSetDimensions();
+ this.setDimensions();
+ this.afterSetDimensions();
+
+ // Data min/max
+ this.beforeDataLimits();
+ this.determineDataLimits();
+ this.afterDataLimits();
+
+ // Ticks
+ this.beforeBuildTicks();
+ this.buildTicks();
+ this.afterBuildTicks();
+
+ this.beforeTickToLabelConversion();
+ this.convertTicksToLabels();
+ this.afterTickToLabelConversion();
+
+ // Tick Rotation
+ this.beforeCalculateTickRotation();
+ this.calculateTickRotation();
+ this.afterCalculateTickRotation();
+ // Fit
+ this.beforeFit();
+ this.fit();
+ this.afterFit();
+ //
+ this.afterUpdate();
+
+ return this.minSize;
+
+ },
+ afterUpdate: function() {
+ helpers.callCallback(this.options.afterUpdate, [this]);
+ },
+
+ //
+
+ beforeSetDimensions: function() {
+ helpers.callCallback(this.options.beforeSetDimensions, [this]);
+ },
+ setDimensions: function() {
+ // Set the unconstrained dimension before label rotation
+ if (this.isHorizontal()) {
+ // Reset position before calculating rotation
+ this.width = this.maxWidth;
+ this.left = 0;
+ this.right = this.width;
} else {
- drawScale();
- drawData(easeAdjustedAnimationPercent);
- }
- }
- function animLoop(){
- //We need to check if the animation is incomplete (less than 1), or complete (1).
- percentAnimComplete += animFrameAmount;
- animateFrame();
- //Stop the loop continuing forever
- if (percentAnimComplete <= 1){
- requestAnimFrame(animLoop);
- }
- else{
- if (typeof config.onAnimationComplete == "function") config.onAnimationComplete();
- }
-
- }
-
- }
+ this.height = this.maxHeight;
- //Declare global functions to be called within this namespace here.
-
-
- // shim layer with setTimeout fallback
- var requestAnimFrame = (function(){
- return window.requestAnimationFrame ||
- window.webkitRequestAnimationFrame ||
- window.mozRequestAnimationFrame ||
- window.oRequestAnimationFrame ||
- window.msRequestAnimationFrame ||
- function(callback) {
- window.setTimeout(callback, 1000 / 60);
+ // Reset position before calculating rotation
+ this.top = 0;
+ this.bottom = this.height;
+ }
+
+ // Reset padding
+ this.paddingLeft = 0;
+ this.paddingTop = 0;
+ this.paddingRight = 0;
+ this.paddingBottom = 0;
+ },
+ afterSetDimensions: function() {
+ helpers.callCallback(this.options.afterSetDimensions, [this]);
+ },
+
+ // Data limits
+ beforeDataLimits: function() {
+ helpers.callCallback(this.options.beforeDataLimits, [this]);
+ },
+ determineDataLimits: helpers.noop,
+ afterDataLimits: function() {
+ helpers.callCallback(this.options.afterDataLimits, [this]);
+ },
+
+ //
+ beforeBuildTicks: function() {
+ helpers.callCallback(this.options.beforeBuildTicks, [this]);
+ },
+ buildTicks: helpers.noop,
+ afterBuildTicks: function() {
+ helpers.callCallback(this.options.afterBuildTicks, [this]);
+ },
+
+ beforeTickToLabelConversion: function() {
+ helpers.callCallback(this.options.beforeTickToLabelConversion, [this]);
+ },
+ convertTicksToLabels: function() {
+ // Convert ticks to strings
+ this.ticks = this.ticks.map(function(numericalTick, index, ticks) {
+ if (this.options.ticks.userCallback) {
+ return this.options.ticks.userCallback(numericalTick, index, ticks);
+ }
+ return this.options.ticks.callback(numericalTick, index, ticks);
+ },
+ this);
+ },
+ afterTickToLabelConversion: function() {
+ helpers.callCallback(this.options.afterTickToLabelConversion, [this]);
+ },
+
+ //
+
+ beforeCalculateTickRotation: function() {
+ helpers.callCallback(this.options.beforeCalculateTickRotation, [this]);
+ },
+ calculateTickRotation: function() {
+ //Get the width of each grid by calculating the difference
+ //between x offsets between 0 and 1.
+ var labelFont = helpers.fontString(this.options.ticks.fontSize, this.options.ticks.fontStyle, this.options.ticks.fontFamily);
+ this.ctx.font = labelFont;
+
+ var firstWidth = this.ctx.measureText(this.ticks[0]).width;
+ var lastWidth = this.ctx.measureText(this.ticks[this.ticks.length - 1]).width;
+ var firstRotated;
+ var lastRotated;
+
+ this.paddingRight = lastWidth / 2 + 3;
+ this.paddingLeft = firstWidth / 2 + 3;
+
+ this.labelRotation = 0;
+
+ if (this.options.display && this.isHorizontal()) {
+ var originalLabelWidth = helpers.longestText(this.ctx, labelFont, this.ticks);
+ var cosRotation;
+ var sinRotation;
+
+ this.labelWidth = originalLabelWidth;
+
+ // Allow 3 pixels x2 padding either side for label readability
+ // only the index matters for a dataset scale, but we want a consistent interface between scales
+
+ var tickWidth = this.getPixelForTick(1) - this.getPixelForTick(0) - 6;
+
+ //Max label rotation can be set or default to 90 - also act as a loop counter
+ while (this.labelWidth > tickWidth && this.labelRotation < this.options.ticks.maxRotation) {
+ cosRotation = Math.cos(helpers.toRadians(this.labelRotation));
+ sinRotation = Math.sin(helpers.toRadians(this.labelRotation));
+
+ firstRotated = cosRotation * firstWidth;
+ lastRotated = cosRotation * lastWidth;
+
+ // We're right aligning the text now.
+ if (firstRotated + this.options.ticks.fontSize / 2 > this.yLabelWidth) {
+ this.paddingLeft = firstRotated + this.options.ticks.fontSize / 2;
+ }
+
+ this.paddingRight = this.options.ticks.fontSize / 2;
+
+ if (sinRotation * originalLabelWidth > this.maxHeight) {
+ // go back one step
+ this.labelRotation--;
+ break;
+ }
+
+ this.labelRotation++;
+ this.labelWidth = cosRotation * originalLabelWidth;
+
+ }
+ } else {
+ this.labelWidth = 0;
+ this.paddingRight = 0;
+ this.paddingLeft = 0;
+ }
+
+ if (this.margins) {
+ this.paddingLeft -= this.margins.left;
+ this.paddingRight -= this.margins.right;
+
+ this.paddingLeft = Math.max(this.paddingLeft, 0);
+ this.paddingRight = Math.max(this.paddingRight, 0);
+ }
+ },
+ afterCalculateTickRotation: function() {
+ helpers.callCallback(this.options.afterCalculateTickRotation, [this]);
+ },
+
+ //
+
+ beforeFit: function() {
+ helpers.callCallback(this.options.beforeFit, [this]);
+ },
+ fit: function() {
+
+ this.minSize = {
+ width: 0,
+ height: 0,
};
- })();
- function calculateScale(drawingHeight,maxSteps,minSteps,maxValue,minValue,labelTemplateString){
- var graphMin,graphMax,graphRange,stepValue,numberOfSteps,valueRange,rangeOrderOfMagnitude,decimalNum;
-
- valueRange = maxValue - minValue;
-
- rangeOrderOfMagnitude = calculateOrderOfMagnitude(valueRange);
+ // Width
+ if (this.isHorizontal()) {
+ // subtract the margins to line up with the chartArea if we are a full width scale
+ this.minSize.width = this.isFullWidth() ? this.maxWidth - this.margins.left - this.margins.right : this.maxWidth;
+ } else {
+ this.minSize.width = this.options.gridLines.display && this.options.display ? 10 : 0;
+ }
- graphMin = Math.floor(minValue / (1 * Math.pow(10, rangeOrderOfMagnitude))) * Math.pow(10, rangeOrderOfMagnitude);
-
- graphMax = Math.ceil(maxValue / (1 * Math.pow(10, rangeOrderOfMagnitude))) * Math.pow(10, rangeOrderOfMagnitude);
-
- graphRange = graphMax - graphMin;
-
- stepValue = Math.pow(10, rangeOrderOfMagnitude);
-
- numberOfSteps = Math.round(graphRange / stepValue);
-
- //Compare number of steps to the max and min for that size graph, and add in half steps if need be.
- while(numberOfSteps < minSteps || numberOfSteps > maxSteps) {
- if (numberOfSteps < minSteps){
- stepValue /= 2;
- numberOfSteps = Math.round(graphRange/stepValue);
- }
- else{
- stepValue *=2;
- numberOfSteps = Math.round(graphRange/stepValue);
- }
- };
+ // height
+ if (this.isHorizontal()) {
+ this.minSize.height = this.options.gridLines.display && this.options.display ? 10 : 0;
+ } else {
+ this.minSize.height = this.maxHeight; // fill all the height
+ }
- var labels = [];
- populateLabels(labelTemplateString, labels, numberOfSteps, graphMin, stepValue);
-
- return {
- steps : numberOfSteps,
- stepValue : stepValue,
- graphMin : graphMin,
- labels : labels
-
- }
-
- function calculateOrderOfMagnitude(val){
- return Math.floor(Math.log(val) / Math.LN10);
- }
+ // Are we showing a title for the scale?
+ if (this.options.scaleLabel.display) {
+ if (this.isHorizontal()) {
+ this.minSize.height += (this.options.scaleLabel.fontSize * 1.5);
+ } else {
+ this.minSize.width += (this.options.scaleLabel.fontSize * 1.5);
+ }
+ }
+
+ if (this.options.ticks.display && this.options.display) {
+ // Don't bother fitting the ticks if we are not showing them
+ var labelFont = helpers.fontString(this.options.ticks.fontSize,
+ this.options.ticks.fontStyle, this.options.ticks.fontFamily);
+
+ if (this.isHorizontal()) {
+ // A horizontal axis is more constrained by the height.
+ this.longestLabelWidth = helpers.longestText(this.ctx, labelFont, this.ticks);
+
+ // TODO - improve this calculation
+ var labelHeight = (Math.sin(helpers.toRadians(this.labelRotation)) * this.longestLabelWidth) + 1.5 * this.options.ticks.fontSize;
+
+ this.minSize.height = Math.min(this.maxHeight, this.minSize.height + labelHeight);
+
+ labelFont = helpers.fontString(this.options.ticks.fontSize, this.options.ticks.fontStyle, this.options.ticks.fontFamily);
+ this.ctx.font = labelFont;
+
+ var firstLabelWidth = this.ctx.measureText(this.ticks[0]).width;
+ var lastLabelWidth = this.ctx.measureText(this.ticks[this.ticks.length - 1]).width;
+
+ // Ensure that our ticks are always inside the canvas. When rotated, ticks are right aligned which means that the right padding is dominated
+ // by the font height
+ var cosRotation = Math.cos(helpers.toRadians(this.labelRotation));
+ var sinRotation = Math.sin(helpers.toRadians(this.labelRotation));
+ this.paddingLeft = this.labelRotation !== 0 ? (cosRotation * firstLabelWidth) + 3 : firstLabelWidth / 2 + 3; // add 3 px to move away from canvas edges
+ this.paddingRight = this.labelRotation !== 0 ? (sinRotation * (this.options.ticks.fontSize / 2)) + 3 : lastLabelWidth / 2 + 3; // when rotated
+ } else {
+ // A vertical axis is more constrained by the width. Labels are the dominant factor here, so get that length first
+ var maxLabelWidth = this.maxWidth - this.minSize.width;
+ var largestTextWidth = helpers.longestText(this.ctx, labelFont, this.ticks);
+
+ // Account for padding
+ if (!this.options.ticks.mirror) {
+ largestTextWidth += this.options.ticks.padding;
+ }
+
+ if (largestTextWidth < maxLabelWidth) {
+ // We don't need all the room
+ this.minSize.width += largestTextWidth;
+ } else {
+ // Expand to max size
+ this.minSize.width = this.maxWidth;
+ }
+
+ this.paddingTop = this.options.ticks.fontSize / 2;
+ this.paddingBottom = this.options.ticks.fontSize / 2;
+ }
+ }
+
+ if (this.margins) {
+ this.paddingLeft -= this.margins.left;
+ this.paddingTop -= this.margins.top;
+ this.paddingRight -= this.margins.right;
+ this.paddingBottom -= this.margins.bottom;
+
+ this.paddingLeft = Math.max(this.paddingLeft, 0);
+ this.paddingTop = Math.max(this.paddingTop, 0);
+ this.paddingRight = Math.max(this.paddingRight, 0);
+ this.paddingBottom = Math.max(this.paddingBottom, 0);
+ }
+
+ this.width = this.minSize.width;
+ this.height = this.minSize.height;
+
+ },
+ afterFit: function() {
+ helpers.callCallback(this.options.afterFit, [this]);
+ },
+
+ // Shared Methods
+ isHorizontal: function() {
+ return this.options.position === "top" || this.options.position === "bottom";
+ },
+ isFullWidth: function() {
+ return (this.options.fullWidth);
+ },
+
+ // Get the correct value. NaN bad inputs, If the value type is object get the x or y based on whether we are horizontal or not
+ getRightValue: function getRightValue(rawValue) {
+ // Null and undefined values first
+ if (rawValue === null || typeof(rawValue) === 'undefined') {
+ return NaN;
+ }
+ // isNaN(object) returns true, so make sure NaN is checking for a number
+ if (typeof(rawValue) === 'number' && isNaN(rawValue)) {
+ return NaN;
+ }
+ // If it is in fact an object, dive in one more level
+ if (typeof(rawValue) === "object") {
+ if (rawValue instanceof Date) {
+ return rawValue;
+ } else {
+ return getRightValue(this.isHorizontal() ? rawValue.x : rawValue.y);
+ }
+ }
+
+ // Value is good, return it
+ return rawValue;
+ },
+
+ // Used to get the value to display in the tooltip for the data at the given index
+ // function getLabelForIndex(index, datasetIndex)
+ getLabelForIndex: helpers.noop,
+
+ // Used to get data value locations. Value can either be an index or a numerical value
+ getPixelForValue: helpers.noop,
+
+ // Used for tick location, should
+ getPixelForTick: function(index, includeOffset) {
+ if (this.isHorizontal()) {
+ var innerWidth = this.width - (this.paddingLeft + this.paddingRight);
+ var tickWidth = innerWidth / Math.max((this.ticks.length - ((this.options.gridLines.offsetGridLines) ? 0 : 1)), 1);
+ var pixel = (tickWidth * index) + this.paddingLeft;
+
+ if (includeOffset) {
+ pixel += tickWidth / 2;
+ }
+
+ var finalVal = this.left + Math.round(pixel);
+ finalVal += this.isFullWidth() ? this.margins.left : 0;
+ return finalVal;
+ } else {
+ var innerHeight = this.height - (this.paddingTop + this.paddingBottom);
+ return this.top + (index * (innerHeight / (this.ticks.length - 1)));
+ }
+ },
+
+ // Utility for getting the pixel location of a percentage of scale
+ getPixelForDecimal: function(decimal/*, includeOffset*/) {
+ if (this.isHorizontal()) {
+ var innerWidth = this.width - (this.paddingLeft + this.paddingRight);
+ var valueOffset = (innerWidth * decimal) + this.paddingLeft;
+
+ var finalVal = this.left + Math.round(valueOffset);
+ finalVal += this.isFullWidth() ? this.margins.left : 0;
+ return finalVal;
+ } else {
+ return this.top + (decimal * this.height);
+ }
+ },
+
+ // Actualy draw the scale on the canvas
+ // @param {rectangle} chartArea : the area of the chart to draw full grid lines on
+ draw: function(chartArea) {
+ if (this.options.display) {
+
+ var setContextLineSettings;
+ var isRotated = this.labelRotation !== 0;
+ var skipRatio;
+ var scaleLabelX;
+ var scaleLabelY;
+ var useAutoskipper = this.options.ticks.autoSkip;
+
+ // Make sure we draw text in the correct color and font
+ this.ctx.fillStyle = this.options.ticks.fontColor;
+ var labelFont = helpers.fontString(this.options.ticks.fontSize, this.options.ticks.fontStyle, this.options.ticks.fontFamily);
+
+ var cosRotation = Math.cos(helpers.toRadians(this.labelRotation));
+ var sinRotation = Math.sin(helpers.toRadians(this.labelRotation));
+ var longestRotatedLabel = this.longestLabelWidth * cosRotation;
+ var rotatedLabelHeight = this.options.ticks.fontSize * sinRotation;
+
+ if (this.isHorizontal()) {
+ setContextLineSettings = true;
+ var yTickStart = this.options.position === "bottom" ? this.top : this.bottom - 10;
+ var yTickEnd = this.options.position === "bottom" ? this.top + 10 : this.bottom;
+ skipRatio = false;
+
+ if (((longestRotatedLabel / 2) + this.options.ticks.autoSkipPadding) * this.ticks.length > (this.width - (this.paddingLeft + this.paddingRight))) {
+ skipRatio = 1 + Math.floor((((longestRotatedLabel / 2) + this.options.ticks.autoSkipPadding) * this.ticks.length) / (this.width - (this.paddingLeft + this.paddingRight)));
+ }
+
+ if (!useAutoskipper) {
+ skipRatio = false;
+ }
+
+ helpers.each(this.ticks, function(label, index) {
+ // Blank ticks
+ if ((skipRatio > 1 && index % skipRatio > 0) || (label === undefined || label === null)) {
+ return;
+ }
+ var xLineValue = this.getPixelForTick(index); // xvalues for grid lines
+ var xLabelValue = this.getPixelForTick(index, this.options.gridLines.offsetGridLines); // x values for ticks (need to consider offsetLabel option)
+
+ if (this.options.gridLines.display) {
+ if (index === (typeof this.zeroLineIndex !== 'undefined' ? this.zeroLineIndex : 0)) {
+ // Draw the first index specially
+ this.ctx.lineWidth = this.options.gridLines.zeroLineWidth;
+ this.ctx.strokeStyle = this.options.gridLines.zeroLineColor;
+ setContextLineSettings = true; // reset next time
+ } else if (setContextLineSettings) {
+ this.ctx.lineWidth = this.options.gridLines.lineWidth;
+ this.ctx.strokeStyle = this.options.gridLines.color;
+ setContextLineSettings = false;
+ }
+
+ xLineValue += helpers.aliasPixel(this.ctx.lineWidth);
+
+ // Draw the label area
+ this.ctx.beginPath();
+
+ if (this.options.gridLines.drawTicks) {
+ this.ctx.moveTo(xLineValue, yTickStart);
+ this.ctx.lineTo(xLineValue, yTickEnd);
+ }
+
+ // Draw the chart area
+ if (this.options.gridLines.drawOnChartArea) {
+ this.ctx.moveTo(xLineValue, chartArea.top);
+ this.ctx.lineTo(xLineValue, chartArea.bottom);
+ }
+
+ // Need to stroke in the loop because we are potentially changing line widths & colours
+ this.ctx.stroke();
+ }
+
+ if (this.options.ticks.display) {
+ this.ctx.save();
+ this.ctx.translate(xLabelValue, (isRotated) ? this.top + 12 : this.options.position === "top" ? this.bottom - 10 : this.top + 10);
+ this.ctx.rotate(helpers.toRadians(this.labelRotation) * -1);
+ this.ctx.font = labelFont;
+ this.ctx.textAlign = (isRotated) ? "right" : "center";
+ this.ctx.textBaseline = (isRotated) ? "middle" : this.options.position === "top" ? "bottom" : "top";
+ this.ctx.fillText(label, 0, 0);
+ this.ctx.restore();
+ }
+ }, this);
+
+ if (this.options.scaleLabel.display) {
+ // Draw the scale label
+ this.ctx.textAlign = "center";
+ this.ctx.textBaseline = 'middle';
+ this.ctx.fillStyle = this.options.scaleLabel.fontColor; // render in correct colour
+ this.ctx.font = helpers.fontString(this.options.scaleLabel.fontSize, this.options.scaleLabel.fontStyle, this.options.scaleLabel.fontFamily);
+
+ scaleLabelX = this.left + ((this.right - this.left) / 2); // midpoint of the width
+ scaleLabelY = this.options.position === 'bottom' ? this.bottom - (this.options.scaleLabel.fontSize / 2) : this.top + (this.options.scaleLabel.fontSize / 2);
+
+ this.ctx.fillText(this.options.scaleLabel.labelString, scaleLabelX, scaleLabelY);
+ }
+
+ } else {
+ setContextLineSettings = true;
+ var xTickStart = this.options.position === "right" ? this.left : this.right - 5;
+ var xTickEnd = this.options.position === "right" ? this.left + 5 : this.right;
+
+ helpers.each(this.ticks, function(label, index) {
+ // If the callback returned a null or undefined value, do not draw this line
+ if (label === undefined || label === null) {
+ return;
+ }
+
+ var yLineValue = this.getPixelForTick(index); // xvalues for grid lines
+
+ if (this.options.gridLines.display) {
+ if (index === (typeof this.zeroLineIndex !== 'undefined' ? this.zeroLineIndex : 0)) {
+ // Draw the first index specially
+ this.ctx.lineWidth = this.options.gridLines.zeroLineWidth;
+ this.ctx.strokeStyle = this.options.gridLines.zeroLineColor;
+ setContextLineSettings = true; // reset next time
+ } else if (setContextLineSettings) {
+ this.ctx.lineWidth = this.options.gridLines.lineWidth;
+ this.ctx.strokeStyle = this.options.gridLines.color;
+ setContextLineSettings = false;
+ }
+
+ yLineValue += helpers.aliasPixel(this.ctx.lineWidth);
+
+ // Draw the label area
+ this.ctx.beginPath();
+
+ if (this.options.gridLines.drawTicks) {
+ this.ctx.moveTo(xTickStart, yLineValue);
+ this.ctx.lineTo(xTickEnd, yLineValue);
+ }
+
+ // Draw the chart area
+ if (this.options.gridLines.drawOnChartArea) {
+ this.ctx.moveTo(chartArea.left, yLineValue);
+ this.ctx.lineTo(chartArea.right, yLineValue);
+ }
+
+ // Need to stroke in the loop because we are potentially changing line widths & colours
+ this.ctx.stroke();
+ }
+
+ if (this.options.ticks.display) {
+ var xLabelValue;
+ var yLabelValue = this.getPixelForTick(index, this.options.gridLines.offsetGridLines); // x values for ticks (need to consider offsetLabel option)
+
+ this.ctx.save();
+
+ if (this.options.position === "left") {
+ if (this.options.ticks.mirror) {
+ xLabelValue = this.right + this.options.ticks.padding;
+ this.ctx.textAlign = "left";
+ } else {
+ xLabelValue = this.right - this.options.ticks.padding;
+ this.ctx.textAlign = "right";
+ }
+ } else {
+ // right side
+ if (this.options.ticks.mirror) {
+ xLabelValue = this.left - this.options.ticks.padding;
+ this.ctx.textAlign = "right";
+ } else {
+ xLabelValue = this.left + this.options.ticks.padding;
+ this.ctx.textAlign = "left";
+ }
+ }
+ this.ctx.translate(xLabelValue, yLabelValue);
+ this.ctx.rotate(helpers.toRadians(this.labelRotation) * -1);
+ this.ctx.font = labelFont;
+ this.ctx.textBaseline = "middle";
+ this.ctx.fillText(label, 0, 0);
+ this.ctx.restore();
+ }
+ }, this);
+
+ if (this.options.scaleLabel.display) {
+ // Draw the scale label
+ scaleLabelX = this.options.position === 'left' ? this.left + (this.options.scaleLabel.fontSize / 2) : this.right - (this.options.scaleLabel.fontSize / 2);
+ scaleLabelY = this.top + ((this.bottom - this.top) / 2);
+ var rotation = this.options.position === 'left' ? -0.5 * Math.PI : 0.5 * Math.PI;
+
+ this.ctx.save();
+ this.ctx.translate(scaleLabelX, scaleLabelY);
+ this.ctx.rotate(rotation);
+ this.ctx.textAlign = "center";
+ this.ctx.fillStyle = this.options.scaleLabel.fontColor; // render in correct colour
+ this.ctx.font = helpers.fontString(this.options.scaleLabel.fontSize, this.options.scaleLabel.fontStyle, this.options.scaleLabel.fontFamily);
+ this.ctx.textBaseline = 'middle';
+ this.ctx.fillText(this.options.scaleLabel.labelString, 0, 0);
+ this.ctx.restore();
+ }
+ }
+ }
+ }
+ });
+
+}).call(this);
+
+(function() {
+ "use strict";
+
+ var root = this,
+ Chart = root.Chart,
+ helpers = Chart.helpers;
+
+ Chart.scaleService = {
+ // Scale registration object. Extensions can register new scale types (such as log or DB scales) and then
+ // use the new chart options to grab the correct scale
+ constructors: {},
+ // Use a registration function so that we can move to an ES6 map when we no longer need to support
+ // old browsers
+
+ // Scale config defaults
+ defaults: {},
+ registerScaleType: function(type, scaleConstructor, defaults) {
+ this.constructors[type] = scaleConstructor;
+ this.defaults[type] = helpers.clone(defaults);
+ },
+ getScaleConstructor: function(type) {
+ return this.constructors.hasOwnProperty(type) ? this.constructors[type] : undefined;
+ },
+ getScaleDefaults: function(type) {
+ // Return the scale defaults merged with the global settings so that we always use the latest ones
+ return this.defaults.hasOwnProperty(type) ? helpers.scaleMerge(Chart.defaults.scale, this.defaults[type]) : {};
+ },
+ addScalesToLayout: function(chartInstance) {
+ // Adds each scale to the chart.boxes array to be sized accordingly
+ helpers.each(chartInstance.scales, function(scale) {
+ Chart.layoutService.addBox(chartInstance, scale);
+ });
+ },
+ };
+
+
+}).call(this);
+
+(function() {
+ "use strict";
+
+ var root = this,
+ Chart = root.Chart,
+ helpers = Chart.helpers;
+
+ Chart.defaults.global.title = {
+ display: false,
+ position: 'top',
+ fullWidth: true, // marks that this box should take the full width of the canvas (pushing down other boxes)
+
+ fontColor: '#666',
+ fontFamily: 'Helvetica Neue',
+ fontSize: 12,
+ fontStyle: 'bold',
+ padding: 10,
+
+ // actual title
+ text: '',
+ };
+
+ Chart.Title = Chart.Element.extend({
+
+ initialize: function(config) {
+ helpers.extend(this, config);
+ this.options = helpers.configMerge(Chart.defaults.global.title, config.options);
+
+ // Contains hit boxes for each dataset (in dataset order)
+ this.legendHitBoxes = [];
+ },
+
+ // These methods are ordered by lifecyle. Utilities then follow.
+
+ beforeUpdate: helpers.noop,
+ update: function(maxWidth, maxHeight, margins) {
+
+ // Update Lifecycle - Probably don't want to ever extend or overwrite this function ;)
+ this.beforeUpdate();
+
+ // Absorb the master measurements
+ this.maxWidth = maxWidth;
+ this.maxHeight = maxHeight;
+ this.margins = margins;
+
+ // Dimensions
+ this.beforeSetDimensions();
+ this.setDimensions();
+ this.afterSetDimensions();
+ // Labels
+ this.beforeBuildLabels();
+ this.buildLabels();
+ this.afterBuildLabels();
+
+ // Fit
+ this.beforeFit();
+ this.fit();
+ this.afterFit();
+ //
+ this.afterUpdate();
+
+ return this.minSize;
+
+ },
+ afterUpdate: helpers.noop,
+
+ //
+
+ beforeSetDimensions: helpers.noop,
+ setDimensions: function() {
+ // Set the unconstrained dimension before label rotation
+ if (this.isHorizontal()) {
+ // Reset position before calculating rotation
+ this.width = this.maxWidth;
+ this.left = 0;
+ this.right = this.width;
+ } else {
+ this.height = this.maxHeight;
+
+ // Reset position before calculating rotation
+ this.top = 0;
+ this.bottom = this.height;
+ }
+
+ // Reset padding
+ this.paddingLeft = 0;
+ this.paddingTop = 0;
+ this.paddingRight = 0;
+ this.paddingBottom = 0;
+
+ // Reset minSize
+ this.minSize = {
+ width: 0,
+ height: 0,
+ };
+ },
+ afterSetDimensions: helpers.noop,
+
+ //
+
+ beforeBuildLabels: helpers.noop,
+ buildLabels: helpers.noop,
+ afterBuildLabels: helpers.noop,
+
+ //
+
+ beforeFit: helpers.noop,
+ fit: function() {
+
+ var ctx = this.ctx;
+ var titleFont = helpers.fontString(this.options.fontSize, this.options.fontStyle, this.options.fontFamily);
+
+ // Width
+ if (this.isHorizontal()) {
+ this.minSize.width = this.maxWidth; // fill all the width
+ } else {
+ this.minSize.width = 0;
+ }
+
+ // height
+ if (this.isHorizontal()) {
+ this.minSize.height = 0;
+ } else {
+ this.minSize.height = this.maxHeight; // fill all the height
+ }
+
+ // Increase sizes here
+ if (this.isHorizontal()) {
+
+ // Title
+ if (this.options.display) {
+ this.minSize.height += this.options.fontSize + (this.options.padding * 2);
+ }
+ } else {
+ // TODO vertical
+ }
+
+ this.width = this.minSize.width;
+ this.height = this.minSize.height;
+
+ },
+ afterFit: helpers.noop,
+
+ // Shared Methods
+ isHorizontal: function() {
+ return this.options.position == "top" || this.options.position == "bottom";
+ },
+
+ // Actualy draw the title block on the canvas
+ draw: function() {
+ if (this.options.display) {
+ var ctx = this.ctx;
+ var titleX, titleY;
+
+ // Horizontal
+ if (this.isHorizontal()) {
+ // Title
+ if (this.options.display) {
+
+ ctx.textAlign = "center";
+ ctx.textBaseline = 'middle';
+ ctx.fillStyle = this.options.fontColor; // render in correct colour
+ ctx.font = helpers.fontString(this.options.fontSize, this.options.fontStyle, this.options.fontFamily);
+
+ titleX = this.left + ((this.right - this.left) / 2); // midpoint of the width
+ titleY = this.top + ((this.bottom - this.top) / 2); // midpoint of the height
+
+ ctx.fillText(this.options.text, titleX, titleY);
+ }
+ } else {
+
+ // Title
+ if (this.options.display) {
+ titleX = this.options.position == 'left' ? this.left + (this.options.fontSize / 2) : this.right - (this.options.fontSize / 2);
+ titleY = this.top + ((this.bottom - this.top) / 2);
+ var rotation = this.options.position == 'left' ? -0.5 * Math.PI : 0.5 * Math.PI;
+
+ ctx.save();
+ ctx.translate(titleX, titleY);
+ ctx.rotate(rotation);
+ ctx.textAlign = "center";
+ ctx.fillStyle = this.options.fontColor; // render in correct colour
+ ctx.font = helpers.fontString(this.options.fontSize, this.options.fontStyle, this.options.fontFamily);
+ ctx.textBaseline = 'middle';
+ ctx.fillText(this.options.text, 0, 0);
+ ctx.restore();
+
+ }
+
+ }
+ }
+ }
+ });
+
+}).call(this);
+
+(function() {
+
+ "use strict";
+
+ var root = this,
+ Chart = root.Chart,
+ helpers = Chart.helpers;
+
+ Chart.defaults.global.tooltips = {
+ enabled: true,
+ custom: null,
+ mode: 'single',
+ backgroundColor: "rgba(0,0,0,0.8)",
+ titleFontFamily: "'Helvetica Neue', 'Helvetica', 'Arial', sans-serif",
+ titleFontSize: 12,
+ titleFontStyle: "bold",
+ titleSpacing: 2,
+ titleMarginBottom: 6,
+ titleColor: "#fff",
+ titleAlign: "left",
+ bodyFontFamily: "'Helvetica Neue', 'Helvetica', 'Arial', sans-serif",
+ bodyFontSize: 12,
+ bodyFontStyle: "normal",
+ bodySpacing: 2,
+ bodyColor: "#fff",
+ bodyAlign: "left",
+ footerFontFamily: "'Helvetica Neue', 'Helvetica', 'Arial', sans-serif",
+ footerFontSize: 12,
+ footerFontStyle: "bold",
+ footerSpacing: 2,
+ footerMarginTop: 6,
+ footerColor: "#fff",
+ footerAlign: "left",
+ yPadding: 6,
+ xPadding: 6,
+ caretSize: 5,
+ cornerRadius: 6,
+ multiKeyBackground: '#fff',
+ callbacks: {
+ // Args are: (tooltipItems, data)
+ beforeTitle: helpers.noop,
+ title: function(tooltipItems, data) {
+ // Pick first xLabel for now
+ var title = '';
+
+ if (tooltipItems.length > 0) {
+ if (tooltipItems[0].xLabel) {
+ title = tooltipItems[0].xLabel;
+ } else if (data.labels.length > 0 && tooltipItems[0].index < data.labels.length) {
+ title = data.labels[tooltipItems[0].index];
+ }
+ }
+
+ return title;
+ },
+ afterTitle: helpers.noop,
+
+ // Args are: (tooltipItems, data)
+ beforeBody: helpers.noop,
+
+ // Args are: (tooltipItem, data)
+ beforeLabel: helpers.noop,
+ label: function(tooltipItem, data) {
+ var datasetLabel = data.datasets[tooltipItem.datasetIndex].label || '';
+ return datasetLabel + ': ' + tooltipItem.yLabel;
+ },
+ afterLabel: helpers.noop,
+
+ // Args are: (tooltipItems, data)
+ afterBody: helpers.noop,
+
+ // Args are: (tooltipItems, data)
+ beforeFooter: helpers.noop,
+ footer: helpers.noop,
+ afterFooter: helpers.noop,
+ },
+ };
+
+ // Helper to push or concat based on if the 2nd parameter is an array or not
+ function pushOrConcat(base, toPush) {
+ if (toPush) {
+ if (helpers.isArray(toPush)) {
+ base = base.concat(toPush);
+ } else {
+ base.push(toPush);
+ }
+ }
+
+ return base;
}
- //Populate an array of all the labels by interpolating the string.
- function populateLabels(labelTemplateString, labels, numberOfSteps, graphMin, stepValue) {
- if (labelTemplateString) {
- //Fix floating point errors by setting to fixed the on the same decimal as the stepValue.
- for (var i = 1; i < numberOfSteps + 1; i++) {
- labels.push(tmpl(labelTemplateString, {value: (graphMin + (stepValue * i)).toFixed(getDecimalPlaces(stepValue))}));
+ Chart.Tooltip = Chart.Element.extend({
+ initialize: function() {
+ var options = this._options;
+ helpers.extend(this, {
+ _model: {
+ // Positioning
+ xPadding: options.tooltips.xPadding,
+ yPadding: options.tooltips.yPadding,
+
+ // Body
+ bodyColor: options.tooltips.bodyColor,
+ _bodyFontFamily: options.tooltips.bodyFontFamily,
+ _bodyFontStyle: options.tooltips.bodyFontStyle,
+ _bodyAlign: options.tooltips.bodyAlign,
+ bodyFontSize: options.tooltips.bodyFontSize,
+ bodySpacing: options.tooltips.bodySpacing,
+
+ // Title
+ titleColor: options.tooltips.titleColor,
+ _titleFontFamily: options.tooltips.titleFontFamily,
+ _titleFontStyle: options.tooltips.titleFontStyle,
+ titleFontSize: options.tooltips.titleFontSize,
+ _titleAlign: options.tooltips.titleAlign,
+ titleSpacing: options.tooltips.titleSpacing,
+ titleMarginBottom: options.tooltips.titleMarginBottom,
+
+ // Footer
+ footerColor: options.tooltips.footerColor,
+ _footerFontFamily: options.tooltips.footerFontFamily,
+ _footerFontStyle: options.tooltips.footerFontStyle,
+ footerFontSize: options.tooltips.footerFontSize,
+ _footerAlign: options.tooltips.footerAlign,
+ footerSpacing: options.tooltips.footerSpacing,
+ footerMarginTop: options.tooltips.footerMarginTop,
+
+ // Appearance
+ caretSize: options.tooltips.caretSize,
+ cornerRadius: options.tooltips.cornerRadius,
+ backgroundColor: options.tooltips.backgroundColor,
+ opacity: 0,
+ legendColorBackground: options.tooltips.multiKeyBackground,
+ },
+ });
+ },
+
+ // Get the title
+ // Args are: (tooltipItem, data)
+ getTitle: function() {
+ var beforeTitle = this._options.tooltips.callbacks.beforeTitle.apply(this, arguments),
+ title = this._options.tooltips.callbacks.title.apply(this, arguments),
+ afterTitle = this._options.tooltips.callbacks.afterTitle.apply(this, arguments);
+
+ var lines = [];
+ lines = pushOrConcat(lines, beforeTitle);
+ lines = pushOrConcat(lines, title);
+ lines = pushOrConcat(lines, afterTitle);
+
+ return lines;
+ },
+
+ // Args are: (tooltipItem, data)
+ getBeforeBody: function() {
+ var lines = this._options.tooltips.callbacks.beforeBody.apply(this, arguments);
+ return helpers.isArray(lines) ? lines : lines !== undefined ? [lines] : [];
+ },
+
+ // Args are: (tooltipItem, data)
+ getBody: function(tooltipItems, data) {
+ var lines = [];
+
+ helpers.each(tooltipItems, function(bodyItem) {
+ var beforeLabel = this._options.tooltips.callbacks.beforeLabel.call(this, bodyItem, data) || '';
+ var bodyLabel = this._options.tooltips.callbacks.label.call(this, bodyItem, data) || '';
+ var afterLabel = this._options.tooltips.callbacks.afterLabel.call(this, bodyItem, data) || '';
+
+ lines.push(beforeLabel + bodyLabel + afterLabel);
+ }, this);
+
+ return lines;
+ },
+
+ // Args are: (tooltipItem, data)
+ getAfterBody: function() {
+ var lines = this._options.tooltips.callbacks.afterBody.apply(this, arguments);
+ return helpers.isArray(lines) ? lines : lines !== undefined ? [lines] : [];
+ },
+
+ // Get the footer and beforeFooter and afterFooter lines
+ // Args are: (tooltipItem, data)
+ getFooter: function() {
+ var beforeFooter = this._options.tooltips.callbacks.beforeFooter.apply(this, arguments);
+ var footer = this._options.tooltips.callbacks.footer.apply(this, arguments);
+ var afterFooter = this._options.tooltips.callbacks.afterFooter.apply(this, arguments);
+
+ var lines = [];
+ lines = pushOrConcat(lines, beforeFooter);
+ lines = pushOrConcat(lines, footer);
+ lines = pushOrConcat(lines, afterFooter);
+
+ return lines;
+ },
+
+ getAveragePosition: function(elements){
+
+ if(!elements.length){
+ return false;
+ }
+
+ var xPositions = [];
+ var yPositions = [];
+
+ helpers.each(elements, function(el){
+ if(el) {
+ var pos = el.tooltipPosition();
+ xPositions.push(pos.x);
+ yPositions.push(pos.y);
+ }
+ });
+
+ var x = 0, y = 0;
+ for (var i = 0; i < xPositions.length; i++) {
+ x += xPositions[i];
+ y += yPositions[i];
+ }
+
+ return {
+ x: Math.round(x / xPositions.length),
+ y: Math.round(y / xPositions.length)
+ };
+
+ },
+
+ update: function(changed) {
+ if (this._active.length){
+ this._model.opacity = 1;
+
+ var element = this._active[0],
+ labelColors = [],
+ tooltipPosition;
+
+ var tooltipItems = [];
+
+ if (this._options.tooltips.mode === 'single') {
+ var yScale = element._yScale || element._scale; // handle radar || polarArea charts
+ tooltipItems.push({
+ xLabel: element._xScale ? element._xScale.getLabelForIndex(element._index, element._datasetIndex) : '',
+ yLabel: yScale ? yScale.getLabelForIndex(element._index, element._datasetIndex) : '',
+ index: element._index,
+ datasetIndex: element._datasetIndex,
+ });
+ tooltipPosition = this.getAveragePosition(this._active);
+ } else {
+ helpers.each(this._data.datasets, function(dataset, datasetIndex) {
+ if (!helpers.isDatasetVisible(dataset)) {
+ return;
+ }
+ var currentElement = dataset.metaData[element._index];
+ if (currentElement) {
+ var yScale = element._yScale || element._scale; // handle radar || polarArea charts
+
+ tooltipItems.push({
+ xLabel: currentElement._xScale ? currentElement._xScale.getLabelForIndex(currentElement._index, currentElement._datasetIndex) : '',
+ yLabel: yScale ? yScale.getLabelForIndex(currentElement._index, currentElement._datasetIndex) : '',
+ index: element._index,
+ datasetIndex: datasetIndex,
+ });
+ }
+ });
+
+ helpers.each(this._active, function(active) {
+ if (active) {
+ labelColors.push({
+ borderColor: active._view.borderColor,
+ backgroundColor: active._view.backgroundColor
+ });
+ }
+ }, this);
+
+ tooltipPosition = this.getAveragePosition(this._active);
+ tooltipPosition.y = this._active[0]._yScale.getPixelForDecimal(0.5);
+ }
+
+ // Build the Text Lines
+ helpers.extend(this._model, {
+ title: this.getTitle(tooltipItems, this._data),
+ beforeBody: this.getBeforeBody(tooltipItems, this._data),
+ body: this.getBody(tooltipItems, this._data),
+ afterBody: this.getAfterBody(tooltipItems, this._data),
+ footer: this.getFooter(tooltipItems, this._data),
+ });
+
+ helpers.extend(this._model, {
+ x: Math.round(tooltipPosition.x),
+ y: Math.round(tooltipPosition.y),
+ caretPadding: helpers.getValueOrDefault(tooltipPosition.padding, 2),
+ labelColors: labelColors,
+ });
+
+ // We need to determine alignment of
+ var tooltipSize = this.getTooltipSize(this._model);
+ this.determineAlignment(tooltipSize); // Smart Tooltip placement to stay on the canvas
+
+ helpers.extend(this._model, this.getBackgroundPoint(this._model, tooltipSize));
+ }
+ else{
+ this._model.opacity = 0;
+ }
+
+ if (changed && this._options.tooltips.custom) {
+ this._options.tooltips.custom.call(this, this._model);
+ }
+
+ return this;
+ },
+ getTooltipSize: function getTooltipSize(vm) {
+ var ctx = this._chart.ctx;
+
+ var size = {
+ height: vm.yPadding * 2, // Tooltip Padding
+ width: 0
+ };
+ var combinedBodyLength = vm.body.length + vm.beforeBody.length + vm.afterBody.length;
+
+ size.height += vm.title.length * vm.titleFontSize; // Title Lines
+ size.height += (vm.title.length - 1) * vm.titleSpacing; // Title Line Spacing
+ size.height += vm.title.length ? vm.titleMarginBottom : 0; // Title's bottom Margin
+ size.height += combinedBodyLength * vm.bodyFontSize; // Body Lines
+ size.height += combinedBodyLength ? (combinedBodyLength - 1) * vm.bodySpacing : 0; // Body Line Spacing
+ size.height += vm.footer.length ? vm.footerMarginTop : 0; // Footer Margin
+ size.height += vm.footer.length * (vm.footerFontSize); // Footer Lines
+ size.height += vm.footer.length ? (vm.footer.length - 1) * vm.footerSpacing : 0; // Footer Line Spacing
+
+ // Width
+ ctx.font = helpers.fontString(vm.titleFontSize, vm._titleFontStyle, vm._titleFontFamily);
+ helpers.each(vm.title, function(line) {
+ size.width = Math.max(size.width, ctx.measureText(line).width);
+ });
+
+ ctx.font = helpers.fontString(vm.bodyFontSize, vm._bodyFontStyle, vm._bodyFontFamily);
+ helpers.each(vm.beforeBody.concat(vm.afterBody), function(line) {
+ size.width = Math.max(size.width, ctx.measureText(line).width);
+ }, this);
+ helpers.each(vm.body, function(line) {
+ size.width = Math.max(size.width, ctx.measureText(line).width + (this._options.tooltips.mode !== 'single' ? (vm.bodyFontSize + 2) : 0));
+ }, this);
+
+ ctx.font = helpers.fontString(vm.footerFontSize, vm._footerFontStyle, vm._footerFontFamily);
+ helpers.each(vm.footer, function(line) {
+ size.width = Math.max(size.width, ctx.measureText(line).width);
+ });
+ size.width += 2 * vm.xPadding;
+
+ return size;
+ },
+ determineAlignment: function determineAlignment(size) {
+ this._model.xAlign = this._model.yAlign = "center";
+
+ if (this._model.y < size.height) {
+ this._model.yAlign = 'top';
+ } else if (this._model.y > (this._chart.height - size.height)) {
+ this._model.yAlign = 'bottom';
+ }
+
+ var lf, rf;
+ var _this = this;
+ var midX = (this._chartInstance.chartArea.left + this._chartInstance.chartArea.right) / 2;
+
+ if (this._model.yAlign === 'center') {
+ lf = function(x) { return x <= midX; };
+ rf = function(x) { return x > midX; };
+ } else {
+ lf = function(x) { return x <= (size.width / 2); };
+ rf = function(x) { return x >= (_this._chart.width - (size.width / 2)); };
+ }
+
+ if (lf(this._model.x)) {
+ this._model.xAlign = 'left';
+ } else if (rf(this._model.x)) {
+ this._model.xAlign = 'right';
+ }
+ },
+ getBackgroundPoint: function getBackgroundPoint(vm, size) {
+ // Background Position
+ var pt = {
+ x: vm.x,
+ y: vm.y
+ };
+
+ if (vm.xAlign === 'right') {
+ pt.x -= size.width;
+ } else if (vm.xAlign === 'center') {
+ pt.x -= (size.width / 2);
+ }
+
+ if (vm.yAlign === 'top') {
+ pt.y += vm.caretPadding + vm.caretSize;
+ } else if (vm.yAlign === 'bottom') {
+ pt.y -= size.height + vm.caretPadding + vm.caretSize;
+ } else {
+ pt.y -= (size.height / 2);
+ }
+
+ if (vm.yAlign == 'center') {
+ if (vm.xAlign === 'left') {
+ pt.x += vm.caretPadding + vm.caretSize;
+ } else if (vm.xAlign === 'right') {
+ pt.x -= vm.caretPadding + vm.caretSize;
+ }
+ } else {
+ if (vm.xAlign === 'left') {
+ pt.x -= vm.cornerRadius + vm.caretPadding;
+ } else if (vm.xAlign === 'right') {
+ pt.x += vm.cornerRadius + vm.caretPadding;
+ }
+ }
+
+ return pt;
+ },
+ drawCaret: function drawCaret(tooltipPoint, size, opacity, caretPadding) {
+ var vm = this._view;
+ var ctx = this._chart.ctx;
+ var x1, x2, x3;
+ var y1, y2, y3;
+
+ if (vm.yAlign === 'center') {
+ // Left or right side
+ if (vm.xAlign === 'left') {
+ x1 = tooltipPoint.x;
+ x2 = x1 - vm.caretSize;
+ x3 = x1;
+ } else {
+ x1 = tooltipPoint.x + size.width;
+ x2 = x1 + vm.caretSize;
+ x3 = x1;
+ }
+
+ y2 = tooltipPoint.y + (size.height / 2);
+ y1 = y2 - vm.caretSize;
+ y3 = y2 + vm.caretSize;
+ } else {
+ if (vm.xAlign === 'left') {
+ x1 = tooltipPoint.x + vm.cornerRadius;
+ x2 = x1 + vm.caretSize;
+ x3 = x2 + vm.caretSize;
+ } else if (vm.xAlign === 'right') {
+ x1 = tooltipPoint.x + size.width - vm.cornerRadius;
+ x2 = x1 - vm.caretSize;
+ x3 = x2 - vm.caretSize;
+ } else {
+ x2 = tooltipPoint.x + (size.width / 2);
+ x1 = x2 - vm.caretSize;
+ x3 = x2 + vm.caretSize;
+ }
+
+ if (vm.yAlign === 'top') {
+ y1 = tooltipPoint.y;
+ y2 = y1 - vm.caretSize;
+ y3 = y1;
+ } else {
+ y1 = tooltipPoint.y + size.height;
+ y2 = y1 + vm.caretSize;
+ y3 = y1;
+ }
+ }
+
+ ctx.fillStyle = helpers.color(vm.backgroundColor).alpha(opacity).rgbString();
+ ctx.beginPath();
+ ctx.moveTo(x1, y1);
+ ctx.lineTo(x2, y2);
+ ctx.lineTo(x3, y3);
+ ctx.closePath();
+ ctx.fill();
+ },
+ drawTitle: function drawTitle(pt, vm, ctx, opacity) {
+ if (vm.title.length) {
+ ctx.textAlign = vm._titleAlign;
+ ctx.textBaseline = "top";
+ ctx.fillStyle = helpers.color(vm.titleColor).alpha(opacity).rgbString();
+ ctx.font = helpers.fontString(vm.titleFontSize, vm._titleFontStyle, vm._titleFontFamily);
+
+ helpers.each(vm.title, function(title, i) {
+ ctx.fillText(title, pt.x, pt.y);
+ pt.y += vm.titleFontSize + vm.titleSpacing; // Line Height and spacing
+
+ if (i + 1 === vm.title.length) {
+ pt.y += vm.titleMarginBottom - vm.titleSpacing; // If Last, add margin, remove spacing
+ }
+ }, this);
+ }
+ },
+ drawBody: function drawBody(pt, vm, ctx, opacity) {
+ ctx.textAlign = vm._bodyAlign;
+ ctx.textBaseline = "top";
+ ctx.fillStyle = helpers.color(vm.bodyColor).alpha(opacity).rgbString();
+ ctx.font = helpers.fontString(vm.bodyFontSize, vm._bodyFontStyle, vm._bodyFontFamily);
+
+ // Before Body
+ helpers.each(vm.beforeBody, function(beforeBody) {
+ ctx.fillText(beforeBody, pt.x, pt.y);
+ pt.y += vm.bodyFontSize + vm.bodySpacing;
+ });
+
+ helpers.each(vm.body, function(body, i) {
+ // Draw Legend-like boxes if needed
+ if (this._options.tooltips.mode !== 'single') {
+ // Fill a white rect so that colours merge nicely if the opacity is < 1
+ ctx.fillStyle = helpers.color(vm.legendColorBackground).alpha(opacity).rgbaString();
+ ctx.fillRect(pt.x, pt.y, vm.bodyFontSize, vm.bodyFontSize);
+
+ // Border
+ ctx.strokeStyle = helpers.color(vm.labelColors[i].borderColor).alpha(opacity).rgbaString();
+ ctx.strokeRect(pt.x, pt.y, vm.bodyFontSize, vm.bodyFontSize);
+
+ // Inner square
+ ctx.fillStyle = helpers.color(vm.labelColors[i].backgroundColor).alpha(opacity).rgbaString();
+ ctx.fillRect(pt.x + 1, pt.y + 1, vm.bodyFontSize - 2, vm.bodyFontSize - 2);
+
+ ctx.fillStyle = helpers.color(vm.bodyColor).alpha(opacity).rgbaString(); // Return fill style for text
+ }
+
+ // Body Line
+ ctx.fillText(body, pt.x + (this._options.tooltips.mode !== 'single' ? (vm.bodyFontSize + 2) : 0), pt.y);
+
+ pt.y += vm.bodyFontSize + vm.bodySpacing;
+ }, this);
+
+ // After Body
+ helpers.each(vm.afterBody, function(afterBody) {
+ ctx.fillText(afterBody, pt.x, pt.y);
+ pt.y += vm.bodyFontSize;
+ });
+
+ pt.y -= vm.bodySpacing; // Remove last body spacing
+ },
+ drawFooter: function drawFooter(pt, vm, ctx, opacity) {
+ if (vm.footer.length) {
+ pt.y += vm.footerMarginTop;
+
+ ctx.textAlign = vm._footerAlign;
+ ctx.textBaseline = "top";
+ ctx.fillStyle = helpers.color(vm.footerColor).alpha(opacity).rgbString();
+ ctx.font = helpers.fontString(vm.footerFontSize, vm._footerFontStyle, vm._footerFontFamily);
+
+ helpers.each(vm.footer, function(footer) {
+ ctx.fillText(footer, pt.x, pt.y);
+ pt.y += vm.footerFontSize + vm.footerSpacing;
+ }, this);
+ }
+ },
+ draw: function draw() {
+ var ctx = this._chart.ctx;
+ var vm = this._view;
+
+ if (vm.opacity === 0) {
+ return;
+ }
+
+ var caretPadding = vm.caretPadding;
+ var tooltipSize = this.getTooltipSize(vm);
+ var pt = {
+ x: vm.x,
+ y: vm.y
+ };
+
+ // IE11/Edge does not like very small opacities, so snap to 0
+ var opacity = Math.abs(vm.opacity < 1e-3) ? 0 : vm.opacity;
+
+ if (this._options.tooltips.enabled) {
+ // Draw Background
+ ctx.fillStyle = helpers.color(vm.backgroundColor).alpha(opacity).rgbString();
+ helpers.drawRoundedRectangle(ctx, pt.x, pt.y, tooltipSize.width, tooltipSize.height, vm.cornerRadius);
+ ctx.fill();
+
+ // Draw Caret
+ this.drawCaret(pt, tooltipSize, opacity, caretPadding);
+
+ // Draw Title, Body, and Footer
+ pt.x += vm.xPadding;
+ pt.y += vm.yPadding;
+
+ // Titles
+ this.drawTitle(pt, vm, ctx, opacity);
+
+ // Body
+ this.drawBody(pt, vm, ctx, opacity);
+
+ // Footer
+ this.drawFooter(pt, vm, ctx, opacity);
+ }
+ }
+ });
+
+}).call(this);
+
+(function() {
+
+ "use strict";
+
+ var root = this,
+ Chart = root.Chart,
+ helpers = Chart.helpers;
+
+ Chart.defaults.bar = {
+ hover: {
+ mode: "label"
+ },
+
+ scales: {
+ xAxes: [{
+ type: "category",
+
+ // Specific to Bar Controller
+ categoryPercentage: 0.8,
+ barPercentage: 0.9,
+
+ // grid line settings
+ gridLines: {
+ offsetGridLines: true,
+ },
+ }],
+ yAxes: [{
+ type: "linear",
+ }],
+ },
+ };
+
+ Chart.controllers.bar = Chart.DatasetController.extend({
+ initialize: function(chart, datasetIndex) {
+ Chart.DatasetController.prototype.initialize.call(this, chart, datasetIndex);
+
+ // Use this to indicate that this is a bar dataset.
+ this.getDataset().bar = true;
+ },
+ // Get the number of datasets that display bars. We use this to correctly calculate the bar width
+ getBarCount: function getBarCount() {
+ var barCount = 0;
+ helpers.each(this.chart.data.datasets, function(dataset) {
+ if (helpers.isDatasetVisible(dataset) && dataset.bar) {
+ ++barCount;
+ }
+ }, this);
+ return barCount;
+ },
+
+ addElements: function() {
+ this.getDataset().metaData = this.getDataset().metaData || [];
+ helpers.each(this.getDataset().data, function(value, index) {
+ this.getDataset().metaData[index] = this.getDataset().metaData[index] || new Chart.elements.Rectangle({
+ _chart: this.chart.chart,
+ _datasetIndex: this.index,
+ _index: index,
+ });
+ }, this);
+ },
+ addElementAndReset: function(index) {
+ this.getDataset().metaData = this.getDataset().metaData || [];
+ var rectangle = new Chart.elements.Rectangle({
+ _chart: this.chart.chart,
+ _datasetIndex: this.index,
+ _index: index,
+ });
+
+ var numBars = this.getBarCount();
+
+ this.updateElement(rectangle, index, true, numBars);
+ this.getDataset().metaData.splice(index, 0, rectangle);
+ },
+
+ update: function update(reset) {
+ var numBars = this.getBarCount();
+
+ helpers.each(this.getDataset().metaData, function(rectangle, index) {
+ this.updateElement(rectangle, index, reset, numBars);
+ }, this);
+ },
+
+ updateElement: function updateElement(rectangle, index, reset, numBars) {
+
+ var xScale = this.getScaleForId(this.getDataset().xAxisID);
+ var yScale = this.getScaleForId(this.getDataset().yAxisID);
+
+ var yScalePoint;
+
+ if (yScale.min < 0 && yScale.max < 0) {
+ // all less than 0. use the top
+ yScalePoint = yScale.getPixelForValue(yScale.max);
+ } else if (yScale.min > 0 && yScale.max > 0) {
+ yScalePoint = yScale.getPixelForValue(yScale.min);
+ } else {
+ yScalePoint = yScale.getPixelForValue(0);
+ }
+
+ helpers.extend(rectangle, {
+ // Utility
+ _chart: this.chart.chart,
+ _xScale: xScale,
+ _yScale: yScale,
+ _datasetIndex: this.index,
+ _index: index,
+
+
+ // Desired view properties
+ _model: {
+ x: this.calculateBarX(index, this.index),
+ y: reset ? yScalePoint : this.calculateBarY(index, this.index),
+
+ // Tooltip
+ label: this.chart.data.labels[index],
+ datasetLabel: this.getDataset().label,
+
+ // Appearance
+ base: this.calculateBarBase(this.index, index),
+ width: this.calculateBarWidth(numBars),
+ backgroundColor: rectangle.custom && rectangle.custom.backgroundColor ? rectangle.custom.backgroundColor : helpers.getValueAtIndexOrDefault(this.getDataset().backgroundColor, index, this.chart.options.elements.rectangle.backgroundColor),
+ borderColor: rectangle.custom && rectangle.custom.borderColor ? rectangle.custom.borderColor : helpers.getValueAtIndexOrDefault(this.getDataset().borderColor, index, this.chart.options.elements.rectangle.borderColor),
+ borderWidth: rectangle.custom && rectangle.custom.borderWidth ? rectangle.custom.borderWidth : helpers.getValueAtIndexOrDefault(this.getDataset().borderWidth, index, this.chart.options.elements.rectangle.borderWidth),
+ },
+ });
+ rectangle.pivot();
+ },
+
+ calculateBarBase: function(datasetIndex, index) {
+
+ var xScale = this.getScaleForId(this.getDataset().xAxisID);
+ var yScale = this.getScaleForId(this.getDataset().yAxisID);
+
+ var base = 0;
+
+ if (yScale.options.stacked) {
+
+ var value = this.chart.data.datasets[datasetIndex].data[index];
+
+ if (value < 0) {
+ for (var i = 0; i < datasetIndex; i++) {
+ var negDS = this.chart.data.datasets[i];
+ if (helpers.isDatasetVisible(negDS) && negDS.yAxisID === yScale.id) {
+ base += negDS.data[index] < 0 ? negDS.data[index] : 0;
+ }
+ }
+ } else {
+ for (var j = 0; j < datasetIndex; j++) {
+ var posDS = this.chart.data.datasets[j];
+ if (helpers.isDatasetVisible(posDS) && posDS.yAxisID === yScale.id) {
+ base += posDS.data[index] > 0 ? posDS.data[index] : 0;
+ }
+ }
+ }
+
+ return yScale.getPixelForValue(base);
+ }
+
+ base = yScale.getPixelForValue(yScale.min);
+
+ if (yScale.beginAtZero || ((yScale.min <= 0 && yScale.max >= 0) || (yScale.min >= 0 && yScale.max <= 0))) {
+ base = yScale.getPixelForValue(0, 0);
+ //base += yScale.options.gridLines.lineWidth;
+ } else if (yScale.min < 0 && yScale.max < 0) {
+ // All values are negative. Use the top as the base
+ base = yScale.getPixelForValue(yScale.max);
+ }
+
+ return base;
+
+ },
+
+ getRuler: function() {
+
+ var xScale = this.getScaleForId(this.getDataset().xAxisID);
+ var yScale = this.getScaleForId(this.getDataset().yAxisID);
+ var datasetCount = this.getBarCount();
+
+ var tickWidth = (function() {
+ var min = xScale.getPixelForTick(1) - xScale.getPixelForTick(0);
+ for (var i = 2; i < this.getDataset().data.length; i++) {
+ min = Math.min(xScale.getPixelForTick(i) - xScale.getPixelForTick(i - 1), min);
+ }
+ return min;
+ }).call(this);
+ var categoryWidth = tickWidth * xScale.options.categoryPercentage;
+ var categorySpacing = (tickWidth - (tickWidth * xScale.options.categoryPercentage)) / 2;
+ var fullBarWidth = categoryWidth / datasetCount;
+ var barWidth = fullBarWidth * xScale.options.barPercentage;
+ var barSpacing = fullBarWidth - (fullBarWidth * xScale.options.barPercentage);
+
+ return {
+ datasetCount: datasetCount,
+ tickWidth: tickWidth,
+ categoryWidth: categoryWidth,
+ categorySpacing: categorySpacing,
+ fullBarWidth: fullBarWidth,
+ barWidth: barWidth,
+ barSpacing: barSpacing,
+ };
+ },
+
+ calculateBarWidth: function() {
+
+ var xScale = this.getScaleForId(this.getDataset().xAxisID);
+ var ruler = this.getRuler();
+
+ if (xScale.options.stacked) {
+ return ruler.categoryWidth;
+ }
+
+ return ruler.barWidth;
+
+ },
+
+ // Get bar index from the given dataset index accounting for the fact that not all bars are visible
+ getBarIndex: function(datasetIndex) {
+ var barIndex = 0;
+
+ for (var j = 0; j < datasetIndex; ++j) {
+ if (helpers.isDatasetVisible(this.chart.data.datasets[j]) && this.chart.data.datasets[j].bar) {
+ ++barIndex;
+ }
+ }
+
+ return barIndex;
+ },
+
+ calculateBarX: function(index, datasetIndex) {
+
+ var yScale = this.getScaleForId(this.getDataset().yAxisID);
+ var xScale = this.getScaleForId(this.getDataset().xAxisID);
+ var barIndex = this.getBarIndex(datasetIndex);
+
+ var ruler = this.getRuler();
+ var leftTick = xScale.getPixelForValue(null, index, datasetIndex, this.chart.isCombo);
+ leftTick -= this.chart.isCombo ? (ruler.tickWidth / 2) : 0;
+
+ if (xScale.options.stacked) {
+ return leftTick + (ruler.categoryWidth / 2) + ruler.categorySpacing;
+ }
+
+ return leftTick +
+ (ruler.barWidth / 2) +
+ ruler.categorySpacing +
+ (ruler.barWidth * barIndex) +
+ (ruler.barSpacing / 2) +
+ (ruler.barSpacing * barIndex);
+ },
+
+ calculateBarY: function(index, datasetIndex) {
+
+ var xScale = this.getScaleForId(this.getDataset().xAxisID);
+ var yScale = this.getScaleForId(this.getDataset().yAxisID);
+
+ var value = this.getDataset().data[index];
+
+ if (yScale.options.stacked) {
+
+ var sumPos = 0,
+ sumNeg = 0;
+
+ for (var i = 0; i < datasetIndex; i++) {
+ var ds = this.chart.data.datasets[i];
+ if (helpers.isDatasetVisible(ds)) {
+ if (ds.data[index] < 0) {
+ sumNeg += ds.data[index] || 0;
+ } else {
+ sumPos += ds.data[index] || 0;
+ }
+ }
+ }
+
+ if (value < 0) {
+ return yScale.getPixelForValue(sumNeg + value);
+ } else {
+ return yScale.getPixelForValue(sumPos + value);
+ }
+
+ return yScale.getPixelForValue(value);
+ }
+
+ return yScale.getPixelForValue(value);
+ },
+
+ draw: function(ease) {
+ var easingDecimal = ease || 1;
+ helpers.each(this.getDataset().metaData, function(rectangle, index) {
+ rectangle.transition(easingDecimal).draw();
+ }, this);
+ },
+
+ setHoverStyle: function(rectangle) {
+ var dataset = this.chart.data.datasets[rectangle._datasetIndex];
+ var index = rectangle._index;
+
+ rectangle._model.backgroundColor = rectangle.custom && rectangle.custom.hoverBackgroundColor ? rectangle.custom.hoverBackgroundColor : helpers.getValueAtIndexOrDefault(dataset.hoverBackgroundColor, index, helpers.color(rectangle._model.backgroundColor).saturate(0.5).darken(0.1).rgbString());
+ rectangle._model.borderColor = rectangle.custom && rectangle.custom.hoverBorderColor ? rectangle.custom.hoverBorderColor : helpers.getValueAtIndexOrDefault(dataset.hoverBorderColor, index, helpers.color(rectangle._model.borderColor).saturate(0.5).darken(0.1).rgbString());
+ rectangle._model.borderWidth = rectangle.custom && rectangle.custom.hoverBorderWidth ? rectangle.custom.hoverBorderWidth : helpers.getValueAtIndexOrDefault(dataset.hoverBorderWidth, index, rectangle._model.borderWidth);
+ },
+
+ removeHoverStyle: function(rectangle) {
+ var dataset = this.chart.data.datasets[rectangle._datasetIndex];
+ var index = rectangle._index;
+
+ rectangle._model.backgroundColor = rectangle.custom && rectangle.custom.backgroundColor ? rectangle.custom.backgroundColor : helpers.getValueAtIndexOrDefault(this.getDataset().backgroundColor, index, this.chart.options.elements.rectangle.backgroundColor);
+ rectangle._model.borderColor = rectangle.custom && rectangle.custom.borderColor ? rectangle.custom.borderColor : helpers.getValueAtIndexOrDefault(this.getDataset().borderColor, index, this.chart.options.elements.rectangle.borderColor);
+ rectangle._model.borderWidth = rectangle.custom && rectangle.custom.borderWidth ? rectangle.custom.borderWidth : helpers.getValueAtIndexOrDefault(this.getDataset().borderWidth, index, this.chart.options.elements.rectangle.borderWidth);
+ }
+
+ });
+
+
+
+}).call(this);
+
+(function() {
+
+ "use strict";
+
+ var root = this,
+ Chart = root.Chart,
+ helpers = Chart.helpers;
+
+ Chart.defaults.bubble = {
+ hover: {
+ mode: "single"
+ },
+
+ scales: {
+ xAxes: [{
+ type: "linear", // bubble should probably use a linear scale by default
+ position: "bottom",
+ id: "x-axis-0", // need an ID so datasets can reference the scale
+ }],
+ yAxes: [{
+ type: "linear",
+ position: "left",
+ id: "y-axis-0",
+ }],
+ },
+
+ tooltips: {
+ template: "(<%= value.x %>, <%= value.y %>, <%= value.r %>)",
+ multiTemplate: "<%if (datasetLabel){%><%=datasetLabel%>: <%}%>(<%= value.x %>, <%= value.y %>, <%= value.r %>)",
+ },
+ };
+
+
+ Chart.controllers.bubble = Chart.DatasetController.extend({
+ addElements: function() {
+
+ this.getDataset().metaData = this.getDataset().metaData || [];
+
+ helpers.each(this.getDataset().data, function(value, index) {
+ this.getDataset().metaData[index] = this.getDataset().metaData[index] || new Chart.elements.Point({
+ _chart: this.chart.chart,
+ _datasetIndex: this.index,
+ _index: index,
+ });
+ }, this);
+ },
+ addElementAndReset: function(index) {
+ this.getDataset().metaData = this.getDataset().metaData || [];
+ var point = new Chart.elements.Point({
+ _chart: this.chart.chart,
+ _datasetIndex: this.index,
+ _index: index,
+ });
+
+ // Reset the point
+ this.updateElement(point, index, true);
+
+ // Add to the points array
+ this.getDataset().metaData.splice(index, 0, point);
+ },
+
+ update: function update(reset) {
+ var points = this.getDataset().metaData;
+
+ var yScale = this.getScaleForId(this.getDataset().yAxisID);
+ var xScale = this.getScaleForId(this.getDataset().xAxisID);
+ var scaleBase;
+
+ if (yScale.min < 0 && yScale.max < 0) {
+ scaleBase = yScale.getPixelForValue(yScale.max);
+ } else if (yScale.min > 0 && yScale.max > 0) {
+ scaleBase = yScale.getPixelForValue(yScale.min);
+ } else {
+ scaleBase = yScale.getPixelForValue(0);
+ }
+
+ // Update Points
+ helpers.each(points, function(point, index) {
+ this.updateElement(point, index, reset);
+ }, this);
+
+ },
+
+ updateElement: function(point, index, reset) {
+ var yScale = this.getScaleForId(this.getDataset().yAxisID);
+ var xScale = this.getScaleForId(this.getDataset().xAxisID);
+ var scaleBase;
+
+ if (yScale.min < 0 && yScale.max < 0) {
+ scaleBase = yScale.getPixelForValue(yScale.max);
+ } else if (yScale.min > 0 && yScale.max > 0) {
+ scaleBase = yScale.getPixelForValue(yScale.min);
+ } else {
+ scaleBase = yScale.getPixelForValue(0);
+ }
+
+ helpers.extend(point, {
+ // Utility
+ _chart: this.chart.chart,
+ _xScale: xScale,
+ _yScale: yScale,
+ _datasetIndex: this.index,
+ _index: index,
+
+ // Desired view properties
+ _model: {
+ x: reset ? xScale.getPixelForDecimal(0.5) : xScale.getPixelForValue(this.getDataset().data[index], index, this.index, this.chart.isCombo),
+ y: reset ? scaleBase : yScale.getPixelForValue(this.getDataset().data[index], index, this.index),
+ // Appearance
+ radius: reset ? 0 : point.custom && point.custom.radius ? point.custom.radius : this.getRadius(this.getDataset().data[index]),
+ backgroundColor: point.custom && point.custom.backgroundColor ? point.custom.backgroundColor : helpers.getValueAtIndexOrDefault(this.getDataset().backgroundColor, index, this.chart.options.elements.point.backgroundColor),
+ borderColor: point.custom && point.custom.borderColor ? point.custom.borderColor : helpers.getValueAtIndexOrDefault(this.getDataset().borderColor, index, this.chart.options.elements.point.borderColor),
+ borderWidth: point.custom && point.custom.borderWidth ? point.custom.borderWidth : helpers.getValueAtIndexOrDefault(this.getDataset().borderWidth, index, this.chart.options.elements.point.borderWidth),
+
+ // Tooltip
+ hitRadius: point.custom && point.custom.hitRadius ? point.custom.hitRadius : helpers.getValueAtIndexOrDefault(this.getDataset().hitRadius, index, this.chart.options.elements.point.hitRadius),
+ },
+ });
+
+ point._model.skip = point.custom && point.custom.skip ? point.custom.skip : (isNaN(point._model.x) || isNaN(point._model.y));
+
+ point.pivot();
+ },
+
+ getRadius: function(value) {
+ return value.r || this.chart.options.elements.point.radius;
+ },
+
+ draw: function(ease) {
+ var easingDecimal = ease || 1;
+
+ // Transition and Draw the Points
+ helpers.each(this.getDataset().metaData, function(point, index) {
+ point.transition(easingDecimal);
+ point.draw();
+ }, this);
+
+ },
+
+ setHoverStyle: function(point) {
+ // Point
+ var dataset = this.chart.data.datasets[point._datasetIndex];
+ var index = point._index;
+
+ point._model.radius = point.custom && point.custom.hoverRadius ? point.custom.hoverRadius : (helpers.getValueAtIndexOrDefault(dataset.hoverRadius, index, this.chart.options.elements.point.hoverRadius)) + this.getRadius(this.getDataset().data[point._index]);
+ point._model.backgroundColor = point.custom && point.custom.hoverBackgroundColor ? point.custom.hoverBackgroundColor : helpers.getValueAtIndexOrDefault(dataset.hoverBackgroundColor, index, helpers.color(point._model.backgroundColor).saturate(0.5).darken(0.1).rgbString());
+ point._model.borderColor = point.custom && point.custom.hoverBorderColor ? point.custom.hoverBorderColor : helpers.getValueAtIndexOrDefault(dataset.hoverBorderColor, index, helpers.color(point._model.borderColor).saturate(0.5).darken(0.1).rgbString());
+ point._model.borderWidth = point.custom && point.custom.hoverBorderWidth ? point.custom.hoverBorderWidth : helpers.getValueAtIndexOrDefault(dataset.hoverBorderWidth, index, point._model.borderWidth);
+ },
+
+ removeHoverStyle: function(point) {
+ var dataset = this.chart.data.datasets[point._datasetIndex];
+ var index = point._index;
+
+ point._model.radius = point.custom && point.custom.radius ? point.custom.radius : this.getRadius(this.getDataset().data[point._index]);
+ point._model.backgroundColor = point.custom && point.custom.backgroundColor ? point.custom.backgroundColor : helpers.getValueAtIndexOrDefault(this.getDataset().backgroundColor, index, this.chart.options.elements.point.backgroundColor);
+ point._model.borderColor = point.custom && point.custom.borderColor ? point.custom.borderColor : helpers.getValueAtIndexOrDefault(this.getDataset().borderColor, index, this.chart.options.elements.point.borderColor);
+ point._model.borderWidth = point.custom && point.custom.borderWidth ? point.custom.borderWidth : helpers.getValueAtIndexOrDefault(this.getDataset().borderWidth, index, this.chart.options.elements.point.borderWidth);
+ }
+ });
+}).call(this);
+
+(function() {
+ "use strict";
+
+ var root = this,
+ Chart = root.Chart,
+ //Cache a local reference to Chart.helpers
+ helpers = Chart.helpers;
+
+ Chart.defaults.doughnut = {
+ animation: {
+ //Boolean - Whether we animate the rotation of the Doughnut
+ animateRotate: true,
+ //Boolean - Whether we animate scaling the Doughnut from the centre
+ animateScale: false,
+ },
+ aspectRatio: 1,
+ hover: {
+ mode: 'single'
+ },
+ legendCallback: function(chart) {
+ var text = [];
+ text.push('');
+
+ if (chart.data.datasets.length) {
+ for (var i = 0; i < chart.data.datasets[0].data.length; ++i) {
+ text.push('');
+ if (chart.data.labels[i]) {
+ text.push(chart.data.labels[i]);
+ }
+ text.push(' ');
+ }
+ }
+
+ text.push(' ');
+ return text.join("");
+ },
+ legend: {
+ labels: {
+ generateLabels: function(data) {
+ return data.labels.map(function(label, i) {
+ return {
+ text: label,
+ fillStyle: data.datasets[0].backgroundColor[i],
+ hidden: isNaN(data.datasets[0].data[i]),
+
+ // Extra data used for toggling the correct item
+ index: i
+ };
+ });
+ }
+ },
+ onClick: function(e, legendItem) {
+ helpers.each(this.chart.data.datasets, function(dataset) {
+ dataset.metaHiddenData = dataset.metaHiddenData || [];
+ var idx = legendItem.index;
+
+ if (!isNaN(dataset.data[idx])) {
+ dataset.metaHiddenData[idx] = dataset.data[idx];
+ dataset.data[idx] = NaN;
+ } else if (!isNaN(dataset.metaHiddenData[idx])) {
+ dataset.data[idx] = dataset.metaHiddenData[idx];
+ }
+ });
+
+ this.chart.update();
+ }
+ },
+
+ //The percentage of the chart that we cut out of the middle.
+ cutoutPercentage: 50,
+
+ // Need to override these to give a nice default
+ tooltips: {
+ callbacks: {
+ title: function() { return '';},
+ label: function(tooltipItem, data) {
+ return data.labels[tooltipItem.index] + ': ' + data.datasets[tooltipItem.datasetIndex].data[tooltipItem.index];
+ }
+ }
+ }
+ };
+
+ Chart.defaults.pie = helpers.clone(Chart.defaults.doughnut);
+ helpers.extend(Chart.defaults.pie, {
+ cutoutPercentage: 0
+ });
+
+
+ Chart.controllers.doughnut = Chart.controllers.pie = Chart.DatasetController.extend({
+ linkScales: function() {
+ // no scales for doughnut
+ },
+
+ addElements: function() {
+ this.getDataset().metaData = this.getDataset().metaData || [];
+ helpers.each(this.getDataset().data, function(value, index) {
+ this.getDataset().metaData[index] = this.getDataset().metaData[index] || new Chart.elements.Arc({
+ _chart: this.chart.chart,
+ _datasetIndex: this.index,
+ _index: index,
+ });
+ }, this);
+ },
+ addElementAndReset: function(index, colorForNewElement) {
+ this.getDataset().metaData = this.getDataset().metaData || [];
+ var arc = new Chart.elements.Arc({
+ _chart: this.chart.chart,
+ _datasetIndex: this.index,
+ _index: index,
+ });
+
+ if (colorForNewElement && helpers.isArray(this.getDataset().backgroundColor)) {
+ this.getDataset().backgroundColor.splice(index, 0, colorForNewElement);
+ }
+
+ // Reset the point
+ this.updateElement(arc, index, true);
+
+ // Add to the points array
+ this.getDataset().metaData.splice(index, 0, arc);
+ },
+
+ getVisibleDatasetCount: function getVisibleDatasetCount() {
+ return helpers.where(this.chart.data.datasets, function(ds) { return helpers.isDatasetVisible(ds); }).length;
+ },
+
+ // Get index of the dataset in relation to the visible datasets. This allows determining the inner and outer radius correctly
+ getRingIndex: function getRingIndex(datasetIndex) {
+ var ringIndex = 0;
+
+ for (var j = 0; j < datasetIndex; ++j) {
+ if (helpers.isDatasetVisible(this.chart.data.datasets[j])) {
+ ++ringIndex;
+ }
+ }
+
+ return ringIndex;
+ },
+
+ update: function update(reset) {
+ var minSize = Math.min(this.chart.chartArea.right - this.chart.chartArea.left, this.chart.chartArea.bottom - this.chart.chartArea.top);
+
+ this.chart.outerRadius = Math.max((minSize / 2) - this.chart.options.elements.arc.borderWidth / 2, 0);
+ this.chart.innerRadius = Math.max(this.chart.options.cutoutPercentage ? (this.chart.outerRadius / 100) * (this.chart.options.cutoutPercentage) : 1, 0);
+ this.chart.radiusLength = (this.chart.outerRadius - this.chart.innerRadius) / this.getVisibleDatasetCount();
+
+ this.getDataset().total = 0;
+ helpers.each(this.getDataset().data, function(value) {
+ if (!isNaN(value)) {
+ this.getDataset().total += Math.abs(value);
+ }
+ }, this);
+
+ this.outerRadius = this.chart.outerRadius - (this.chart.radiusLength * this.getRingIndex(this.index));
+ this.innerRadius = this.outerRadius - this.chart.radiusLength;
+
+ helpers.each(this.getDataset().metaData, function(arc, index) {
+ this.updateElement(arc, index, reset);
+ }, this);
+ },
+ updateElement: function(arc, index, reset) {
+ var centerX = (this.chart.chartArea.left + this.chart.chartArea.right) / 2;
+ var centerY = (this.chart.chartArea.top + this.chart.chartArea.bottom) / 2;
+
+ var resetModel = {
+ x: centerX,
+ y: centerY,
+ startAngle: Math.PI * -0.5, // use - PI / 2 instead of 3PI / 2 to make animations better. It means that we never deal with overflow during the transition function
+ endAngle: Math.PI * -0.5,
+ circumference: (this.chart.options.animation.animateRotate) ? 0 : this.calculateCircumference(this.getDataset().data[index]),
+ outerRadius: (this.chart.options.animation.animateScale) ? 0 : this.outerRadius,
+ innerRadius: (this.chart.options.animation.animateScale) ? 0 : this.innerRadius
+ };
+
+ helpers.extend(arc, {
+ // Utility
+ _chart: this.chart.chart,
+ _datasetIndex: this.index,
+ _index: index,
+
+ // Desired view properties
+ _model: reset ? resetModel : {
+ x: centerX,
+ y: centerY,
+ circumference: this.calculateCircumference(this.getDataset().data[index]),
+ outerRadius: this.outerRadius,
+ innerRadius: this.innerRadius,
+
+ backgroundColor: arc.custom && arc.custom.backgroundColor ? arc.custom.backgroundColor : helpers.getValueAtIndexOrDefault(this.getDataset().backgroundColor, index, this.chart.options.elements.arc.backgroundColor),
+ hoverBackgroundColor: arc.custom && arc.custom.hoverBackgroundColor ? arc.custom.hoverBackgroundColor : helpers.getValueAtIndexOrDefault(this.getDataset().hoverBackgroundColor, index, this.chart.options.elements.arc.hoverBackgroundColor),
+ borderWidth: arc.custom && arc.custom.borderWidth ? arc.custom.borderWidth : helpers.getValueAtIndexOrDefault(this.getDataset().borderWidth, index, this.chart.options.elements.arc.borderWidth),
+ borderColor: arc.custom && arc.custom.borderColor ? arc.custom.borderColor : helpers.getValueAtIndexOrDefault(this.getDataset().borderColor, index, this.chart.options.elements.arc.borderColor),
+
+ label: helpers.getValueAtIndexOrDefault(this.getDataset().label, index, this.chart.data.labels[index])
+ },
+ });
+
+ if (!reset) {
+
+ if (index === 0) {
+ arc._model.startAngle = Math.PI * -0.5; // use - PI / 2 instead of 3PI / 2 to make animations better. It means that we never deal with overflow during the transition function
+ } else {
+ arc._model.startAngle = this.getDataset().metaData[index - 1]._model.endAngle;
+ }
+
+ arc._model.endAngle = arc._model.startAngle + arc._model.circumference;
+
+
+ //Check to see if it's the last arc, if not get the next and update its start angle
+ if (index < this.getDataset().data.length - 1) {
+ this.getDataset().metaData[index + 1]._model.startAngle = arc._model.endAngle;
+ }
+ }
+
+ arc.pivot();
+ },
+
+ draw: function(ease) {
+ var easingDecimal = ease || 1;
+ helpers.each(this.getDataset().metaData, function(arc, index) {
+ arc.transition(easingDecimal).draw();
+ }, this);
+ },
+
+ setHoverStyle: function(arc) {
+ var dataset = this.chart.data.datasets[arc._datasetIndex];
+ var index = arc._index;
+
+ arc._model.backgroundColor = arc.custom && arc.custom.hoverBackgroundColor ? arc.custom.hoverBackgroundColor : helpers.getValueAtIndexOrDefault(dataset.hoverBackgroundColor, index, helpers.color(arc._model.backgroundColor).saturate(0.5).darken(0.1).rgbString());
+ arc._model.borderColor = arc.custom && arc.custom.hoverBorderColor ? arc.custom.hoverBorderColor : helpers.getValueAtIndexOrDefault(dataset.hoverBorderColor, index, helpers.color(arc._model.borderColor).saturate(0.5).darken(0.1).rgbString());
+ arc._model.borderWidth = arc.custom && arc.custom.hoverBorderWidth ? arc.custom.hoverBorderWidth : helpers.getValueAtIndexOrDefault(dataset.hoverBorderWidth, index, arc._model.borderWidth);
+ },
+
+ removeHoverStyle: function(arc) {
+ var dataset = this.chart.data.datasets[arc._datasetIndex];
+ var index = arc._index;
+
+ arc._model.backgroundColor = arc.custom && arc.custom.backgroundColor ? arc.custom.backgroundColor : helpers.getValueAtIndexOrDefault(this.getDataset().backgroundColor, index, this.chart.options.elements.arc.backgroundColor);
+ arc._model.borderColor = arc.custom && arc.custom.borderColor ? arc.custom.borderColor : helpers.getValueAtIndexOrDefault(this.getDataset().borderColor, index, this.chart.options.elements.arc.borderColor);
+ arc._model.borderWidth = arc.custom && arc.custom.borderWidth ? arc.custom.borderWidth : helpers.getValueAtIndexOrDefault(this.getDataset().borderWidth, index, this.chart.options.elements.arc.borderWidth);
+ },
+
+ calculateCircumference: function(value) {
+ if (this.getDataset().total > 0 && !isNaN(value)) {
+ return (Math.PI * 1.999999) * (value / this.getDataset().total);
+ } else {
+ return 0;
+ }
+ },
+
+ });
+
+
+}).call(this);
+
+(function() {
+
+ "use strict";
+
+ var root = this,
+ Chart = root.Chart,
+ helpers = Chart.helpers;
+
+ Chart.defaults.line = {
+ hover: {
+ mode: "label"
+ },
+
+ scales: {
+ xAxes: [{
+ type: "category",
+ id: 'x-axis-0'
+ }],
+ yAxes: [{
+ type: "linear",
+ id: 'y-axis-0'
+ }],
+ },
+ };
+
+
+ Chart.controllers.line = Chart.DatasetController.extend({
+ addElements: function() {
+
+ this.getDataset().metaData = this.getDataset().metaData || [];
+
+ this.getDataset().metaDataset = this.getDataset().metaDataset || new Chart.elements.Line({
+ _chart: this.chart.chart,
+ _datasetIndex: this.index,
+ _points: this.getDataset().metaData,
+ });
+
+ helpers.each(this.getDataset().data, function(value, index) {
+ this.getDataset().metaData[index] = this.getDataset().metaData[index] || new Chart.elements.Point({
+ _chart: this.chart.chart,
+ _datasetIndex: this.index,
+ _index: index,
+ });
+ }, this);
+ },
+ addElementAndReset: function(index) {
+ this.getDataset().metaData = this.getDataset().metaData || [];
+ var point = new Chart.elements.Point({
+ _chart: this.chart.chart,
+ _datasetIndex: this.index,
+ _index: index,
+ });
+
+ // Reset the point
+ this.updateElement(point, index, true);
+
+ // Add to the points array
+ this.getDataset().metaData.splice(index, 0, point);
+
+ // Make sure bezier control points are updated
+ this.updateBezierControlPoints();
+ },
+
+ update: function update(reset) {
+ var line = this.getDataset().metaDataset;
+ var points = this.getDataset().metaData;
+
+ var yScale = this.getScaleForId(this.getDataset().yAxisID);
+ var xScale = this.getScaleForId(this.getDataset().xAxisID);
+ var scaleBase;
+
+ if (yScale.min < 0 && yScale.max < 0) {
+ scaleBase = yScale.getPixelForValue(yScale.max);
+ } else if (yScale.min > 0 && yScale.max > 0) {
+ scaleBase = yScale.getPixelForValue(yScale.min);
+ } else {
+ scaleBase = yScale.getPixelForValue(0);
+ }
+
+ // Update Line
+ helpers.extend(line, {
+ // Utility
+ _scale: yScale,
+ _datasetIndex: this.index,
+ // Data
+ _children: points,
+ // Model
+ _model: {
+ // Appearance
+ tension: line.custom && line.custom.tension ? line.custom.tension : helpers.getValueOrDefault(this.getDataset().tension, this.chart.options.elements.line.tension),
+ backgroundColor: line.custom && line.custom.backgroundColor ? line.custom.backgroundColor : (this.getDataset().backgroundColor || this.chart.options.elements.line.backgroundColor),
+ borderWidth: line.custom && line.custom.borderWidth ? line.custom.borderWidth : (this.getDataset().borderWidth || this.chart.options.elements.line.borderWidth),
+ borderColor: line.custom && line.custom.borderColor ? line.custom.borderColor : (this.getDataset().borderColor || this.chart.options.elements.line.borderColor),
+ borderCapStyle: line.custom && line.custom.borderCapStyle ? line.custom.borderCapStyle : (this.getDataset().borderCapStyle || this.chart.options.elements.line.borderCapStyle),
+ borderDash: line.custom && line.custom.borderDash ? line.custom.borderDash : (this.getDataset().borderDash || this.chart.options.elements.line.borderDash),
+ borderDashOffset: line.custom && line.custom.borderDashOffset ? line.custom.borderDashOffset : (this.getDataset().borderDashOffset || this.chart.options.elements.line.borderDashOffset),
+ borderJoinStyle: line.custom && line.custom.borderJoinStyle ? line.custom.borderJoinStyle : (this.getDataset().borderJoinStyle || this.chart.options.elements.line.borderJoinStyle),
+ fill: line.custom && line.custom.fill ? line.custom.fill : (this.getDataset().fill !== undefined ? this.getDataset().fill : this.chart.options.elements.line.fill),
+ // Scale
+ scaleTop: yScale.top,
+ scaleBottom: yScale.bottom,
+ scaleZero: scaleBase,
+ },
+ });
+ line.pivot();
+
+ // Update Points
+ helpers.each(points, function(point, index) {
+ this.updateElement(point, index, reset);
+ }, this);
+
+ this.updateBezierControlPoints();
+ },
+
+ getPointBackgroundColor: function(point, index) {
+ var backgroundColor = this.chart.options.elements.point.backgroundColor;
+ var dataset = this.getDataset();
+
+ if (point.custom && point.custom.backgroundColor) {
+ backgroundColor = point.custom.backgroundColor;
+ } else if (dataset.pointBackgroundColor) {
+ backgroundColor = helpers.getValueAtIndexOrDefault(dataset.pointBackgroundColor, index, backgroundColor);
+ } else if (dataset.backgroundColor) {
+ backgroundColor = dataset.backgroundColor;
+ }
+
+ return backgroundColor;
+ },
+ getPointBorderColor: function(point, index) {
+ var borderColor = this.chart.options.elements.point.borderColor;
+ var dataset = this.getDataset();
+
+ if (point.custom && point.custom.borderColor) {
+ borderColor = point.custom.borderColor;
+ } else if (dataset.pointBorderColor) {
+ borderColor = helpers.getValueAtIndexOrDefault(this.getDataset().pointBorderColor, index, borderColor);
+ } else if (dataset.borderColor) {
+ borderColor = dataset.borderColor;
+ }
+
+ return borderColor;
+ },
+ getPointBorderWidth: function(point, index) {
+ var borderWidth = this.chart.options.elements.point.borderWidth;
+ var dataset = this.getDataset();
+
+ if (point.custom && point.custom.borderWidth !== undefined) {
+ borderWidth = point.custom.borderWidth;
+ } else if (dataset.pointBorderWidth !== undefined) {
+ borderWidth = helpers.getValueAtIndexOrDefault(dataset.pointBorderWidth, index, borderWidth);
+ } else if (dataset.borderWidth !== undefined) {
+ borderWidth = dataset.borderWidth;
+ }
+
+ return borderWidth;
+ },
+
+ updateElement: function(point, index, reset) {
+ var yScale = this.getScaleForId(this.getDataset().yAxisID);
+ var xScale = this.getScaleForId(this.getDataset().xAxisID);
+ var scaleBase;
+
+ if (yScale.min < 0 && yScale.max < 0) {
+ scaleBase = yScale.getPixelForValue(yScale.max);
+ } else if (yScale.min > 0 && yScale.max > 0) {
+ scaleBase = yScale.getPixelForValue(yScale.min);
+ } else {
+ scaleBase = yScale.getPixelForValue(0);
+ }
+
+ helpers.extend(point, {
+ // Utility
+ _chart: this.chart.chart,
+ _xScale: xScale,
+ _yScale: yScale,
+ _datasetIndex: this.index,
+ _index: index,
+
+ // Desired view properties
+ _model: {
+ x: xScale.getPixelForValue(this.getDataset().data[index], index, this.index, this.chart.isCombo),
+ y: reset ? scaleBase : this.calculatePointY(this.getDataset().data[index], index, this.index, this.chart.isCombo),
+ // Appearance
+ tension: point.custom && point.custom.tension ? point.custom.tension : helpers.getValueOrDefault(this.getDataset().tension, this.chart.options.elements.line.tension),
+ radius: point.custom && point.custom.radius ? point.custom.radius : helpers.getValueAtIndexOrDefault(this.getDataset().radius, index, this.chart.options.elements.point.radius),
+ backgroundColor: this.getPointBackgroundColor(point, index),
+ borderColor: this.getPointBorderColor(point, index),
+ borderWidth: this.getPointBorderWidth(point, index),
+ // Tooltip
+ hitRadius: point.custom && point.custom.hitRadius ? point.custom.hitRadius : helpers.getValueAtIndexOrDefault(this.getDataset().hitRadius, index, this.chart.options.elements.point.hitRadius),
+ },
+ });
+
+ point._model.skip = point.custom && point.custom.skip ? point.custom.skip : (isNaN(point._model.x) || isNaN(point._model.y));
+ },
+
+ calculatePointY: function(value, index, datasetIndex, isCombo) {
+
+ var xScale = this.getScaleForId(this.getDataset().xAxisID);
+ var yScale = this.getScaleForId(this.getDataset().yAxisID);
+
+ if (yScale.options.stacked) {
+
+ var sumPos = 0,
+ sumNeg = 0;
+
+ for (var i = this.chart.data.datasets.length - 1; i > datasetIndex; i--) {
+ var ds = this.chart.data.datasets[i];
+ if (helpers.isDatasetVisible(ds)) {
+ if (ds.data[index] < 0) {
+ sumNeg += ds.data[index] || 0;
+ } else {
+ sumPos += ds.data[index] || 0;
+ }
+ }
+ }
+
+ if (value < 0) {
+ return yScale.getPixelForValue(sumNeg + value);
+ } else {
+ return yScale.getPixelForValue(sumPos + value);
+ }
+
+ return yScale.getPixelForValue(value);
+ }
+
+ return yScale.getPixelForValue(value);
+ },
+
+ updateBezierControlPoints: function() {
+ // Update bezier control points
+ helpers.each(this.getDataset().metaData, function(point, index) {
+ var controlPoints = helpers.splineCurve(
+ helpers.previousItem(this.getDataset().metaData, index)._model,
+ point._model,
+ helpers.nextItem(this.getDataset().metaData, index)._model,
+ point._model.tension
+ );
+
+ // Prevent the bezier going outside of the bounds of the graph
+ point._model.controlPointPreviousX = Math.max(Math.min(controlPoints.previous.x, this.chart.chartArea.right), this.chart.chartArea.left);
+ point._model.controlPointPreviousY = Math.max(Math.min(controlPoints.previous.y, this.chart.chartArea.bottom), this.chart.chartArea.top);
+
+ point._model.controlPointNextX = Math.max(Math.min(controlPoints.next.x, this.chart.chartArea.right), this.chart.chartArea.left);
+ point._model.controlPointNextY = Math.max(Math.min(controlPoints.next.y, this.chart.chartArea.bottom), this.chart.chartArea.top);
+
+ // Now pivot the point for animation
+ point.pivot();
+ }, this);
+ },
+
+ draw: function(ease) {
+ var easingDecimal = ease || 1;
+
+ // Transition Point Locations
+ helpers.each(this.getDataset().metaData, function(point, index) {
+ point.transition(easingDecimal);
+ }, this);
+
+ // Transition and Draw the line
+ this.getDataset().metaDataset.transition(easingDecimal).draw();
+
+ // Draw the points
+ helpers.each(this.getDataset().metaData, function(point) {
+ point.draw();
+ });
+ },
+
+ setHoverStyle: function(point) {
+ // Point
+ var dataset = this.chart.data.datasets[point._datasetIndex];
+ var index = point._index;
+
+ point._model.radius = point.custom && point.custom.hoverRadius ? point.custom.hoverRadius : helpers.getValueAtIndexOrDefault(dataset.pointHoverRadius, index, this.chart.options.elements.point.hoverRadius);
+ point._model.backgroundColor = point.custom && point.custom.hoverBackgroundColor ? point.custom.hoverBackgroundColor : helpers.getValueAtIndexOrDefault(dataset.pointHoverBackgroundColor, index, helpers.color(point._model.backgroundColor).saturate(0.5).darken(0.1).rgbString());
+ point._model.borderColor = point.custom && point.custom.hoverBorderColor ? point.custom.hoverBorderColor : helpers.getValueAtIndexOrDefault(dataset.pointHoverBorderColor, index, helpers.color(point._model.borderColor).saturate(0.5).darken(0.1).rgbString());
+ point._model.borderWidth = point.custom && point.custom.hoverBorderWidth ? point.custom.hoverBorderWidth : helpers.getValueAtIndexOrDefault(dataset.pointHoverBorderWidth, index, point._model.borderWidth);
+ },
+
+ removeHoverStyle: function(point) {
+ var dataset = this.chart.data.datasets[point._datasetIndex];
+ var index = point._index;
+
+ point._model.radius = point.custom && point.custom.radius ? point.custom.radius : helpers.getValueAtIndexOrDefault(this.getDataset().radius, index, this.chart.options.elements.point.radius);
+ point._model.backgroundColor = this.getPointBackgroundColor(point, index);
+ point._model.borderColor = this.getPointBorderColor(point, index);
+ point._model.borderWidth = this.getPointBorderWidth(point, index);
+ }
+ });
+}).call(this);
+
+(function() {
+ "use strict";
+
+ var root = this,
+ Chart = root.Chart,
+ //Cache a local reference to Chart.helpers
+ helpers = Chart.helpers;
+
+
+ Chart.defaults.polarArea = {
+
+ scale: {
+ type: "radialLinear",
+ lineArc: true, // so that lines are circular
+ },
+
+ //Boolean - Whether to animate the rotation of the chart
+ animateRotate: true,
+ animateScale: true,
+
+ aspectRatio: 1,
+ legendCallback: function(chart) {
+ var text = [];
+ text.push('');
+
+ if (chart.data.datasets.length) {
+ for (var i = 0; i < chart.data.datasets[0].data.length; ++i) {
+ text.push('');
+ if (chart.data.labels[i]) {
+ text.push(chart.data.labels[i]);
+ }
+ text.push(' ');
+ }
+ }
+
+ text.push(' ');
+ return text.join("");
+ },
+ legend: {
+ labels: {
+ generateLabels: function(data) {
+ return data.labels.map(function(label, i) {
+ return {
+ text: label,
+ fillStyle: data.datasets[0].backgroundColor[i],
+ hidden: isNaN(data.datasets[0].data[i]),
+
+ // Extra data used for toggling the correct item
+ index: i
+ };
+ });
+ }
+ },
+ onClick: function(e, legendItem) {
+ helpers.each(this.chart.data.datasets, function(dataset) {
+ dataset.metaHiddenData = dataset.metaHiddenData || [];
+ var idx = legendItem.index;
+
+ if (!isNaN(dataset.data[idx])) {
+ dataset.metaHiddenData[idx] = dataset.data[idx];
+ dataset.data[idx] = NaN;
+ } else if (!isNaN(dataset.metaHiddenData[idx])) {
+ dataset.data[idx] = dataset.metaHiddenData[idx];
+ }
+ });
+
+ this.chart.update();
+ }
+ },
+
+ // Need to override these to give a nice default
+ tooltips: {
+ callbacks: {
+ title: function() { return ''; },
+ label: function(tooltipItem, data) {
+ return data.labels[tooltipItem.index] + ': ' + tooltipItem.yLabel;
+ }
+ }
+ }
+ };
+
+ Chart.controllers.polarArea = Chart.DatasetController.extend({
+ linkScales: function() {
+ // no scales for doughnut
+ },
+ addElements: function() {
+ this.getDataset().metaData = this.getDataset().metaData || [];
+ helpers.each(this.getDataset().data, function(value, index) {
+ this.getDataset().metaData[index] = this.getDataset().metaData[index] || new Chart.elements.Arc({
+ _chart: this.chart.chart,
+ _datasetIndex: this.index,
+ _index: index,
+ });
+ }, this);
+ },
+ addElementAndReset: function(index) {
+ this.getDataset().metaData = this.getDataset().metaData || [];
+ var arc = new Chart.elements.Arc({
+ _chart: this.chart.chart,
+ _datasetIndex: this.index,
+ _index: index,
+ });
+
+ // Reset the point
+ this.updateElement(arc, index, true);
+
+ // Add to the points array
+ this.getDataset().metaData.splice(index, 0, arc);
+ },
+ getVisibleDatasetCount: function getVisibleDatasetCount() {
+ return helpers.where(this.chart.data.datasets, function(ds) { return helpers.isDatasetVisible(ds); }).length;
+ },
+
+ update: function update(reset) {
+ var minSize = Math.min(this.chart.chartArea.right - this.chart.chartArea.left, this.chart.chartArea.bottom - this.chart.chartArea.top);
+ this.chart.outerRadius = Math.max((minSize - this.chart.options.elements.arc.borderWidth / 2) / 2, 0);
+ this.chart.innerRadius = Math.max(this.chart.options.cutoutPercentage ? (this.chart.outerRadius / 100) * (this.chart.options.cutoutPercentage) : 1, 0);
+ this.chart.radiusLength = (this.chart.outerRadius - this.chart.innerRadius) / this.getVisibleDatasetCount();
+
+ this.getDataset().total = 0;
+ helpers.each(this.getDataset().data, function(value) {
+ this.getDataset().total += Math.abs(value);
+ }, this);
+
+ this.outerRadius = this.chart.outerRadius - (this.chart.radiusLength * this.index);
+ this.innerRadius = this.outerRadius - this.chart.radiusLength;
+
+ helpers.each(this.getDataset().metaData, function(arc, index) {
+ this.updateElement(arc, index, reset);
+ }, this);
+ },
+
+ updateElement: function(arc, index, reset) {
+ var circumference = this.calculateCircumference(this.getDataset().data[index]);
+ var centerX = (this.chart.chartArea.left + this.chart.chartArea.right) / 2;
+ var centerY = (this.chart.chartArea.top + this.chart.chartArea.bottom) / 2;
+
+ // If there is NaN data before us, we need to calculate the starting angle correctly.
+ // We could be way more efficient here, but its unlikely that the polar area chart will have a lot of data
+ var notNullIndex = 0;
+ for (var i = 0; i < index; ++i) {
+ if (!isNaN(this.getDataset().data[i])) {
+ ++notNullIndex;
+ }
+ }
+
+ var startAngle = (-0.5 * Math.PI) + (circumference * notNullIndex);
+ var endAngle = startAngle + circumference;
+
+ var resetModel = {
+ x: centerX,
+ y: centerY,
+ innerRadius: 0,
+ outerRadius: this.chart.options.animateScale ? 0 : this.chart.scale.getDistanceFromCenterForValue(this.getDataset().data[index]),
+ startAngle: this.chart.options.animateRotate ? Math.PI * -0.5 : startAngle,
+ endAngle: this.chart.options.animateRotate ? Math.PI * -0.5 : endAngle,
+
+ backgroundColor: arc.custom && arc.custom.backgroundColor ? arc.custom.backgroundColor : helpers.getValueAtIndexOrDefault(this.getDataset().backgroundColor, index, this.chart.options.elements.arc.backgroundColor),
+ hoverBackgroundColor: arc.custom && arc.custom.hoverBackgroundColor ? arc.custom.hoverBackgroundColor : helpers.getValueAtIndexOrDefault(this.getDataset().hoverBackgroundColor, index, this.chart.options.elements.arc.hoverBackgroundColor),
+ borderWidth: arc.custom && arc.custom.borderWidth ? arc.custom.borderWidth : helpers.getValueAtIndexOrDefault(this.getDataset().borderWidth, index, this.chart.options.elements.arc.borderWidth),
+ borderColor: arc.custom && arc.custom.borderColor ? arc.custom.borderColor : helpers.getValueAtIndexOrDefault(this.getDataset().borderColor, index, this.chart.options.elements.arc.borderColor),
+
+ label: helpers.getValueAtIndexOrDefault(this.chart.data.labels, index, this.chart.data.labels[index])
+ };
+
+ helpers.extend(arc, {
+ // Utility
+ _chart: this.chart.chart,
+ _datasetIndex: this.index,
+ _index: index,
+ _scale: this.chart.scale,
+
+ // Desired view properties
+ _model: reset ? resetModel : {
+ x: centerX,
+ y: centerY,
+ innerRadius: 0,
+ outerRadius: this.chart.scale.getDistanceFromCenterForValue(this.getDataset().data[index]),
+ startAngle: startAngle,
+ endAngle: endAngle,
+
+ backgroundColor: arc.custom && arc.custom.backgroundColor ? arc.custom.backgroundColor : helpers.getValueAtIndexOrDefault(this.getDataset().backgroundColor, index, this.chart.options.elements.arc.backgroundColor),
+ hoverBackgroundColor: arc.custom && arc.custom.hoverBackgroundColor ? arc.custom.hoverBackgroundColor : helpers.getValueAtIndexOrDefault(this.getDataset().hoverBackgroundColor, index, this.chart.options.elements.arc.hoverBackgroundColor),
+ borderWidth: arc.custom && arc.custom.borderWidth ? arc.custom.borderWidth : helpers.getValueAtIndexOrDefault(this.getDataset().borderWidth, index, this.chart.options.elements.arc.borderWidth),
+ borderColor: arc.custom && arc.custom.borderColor ? arc.custom.borderColor : helpers.getValueAtIndexOrDefault(this.getDataset().borderColor, index, this.chart.options.elements.arc.borderColor),
+
+ label: helpers.getValueAtIndexOrDefault(this.chart.data.labels, index, this.chart.data.labels[index])
+ },
+ });
+
+ arc.pivot();
+ },
+
+ draw: function(ease) {
+ var easingDecimal = ease || 1;
+ helpers.each(this.getDataset().metaData, function(arc, index) {
+ arc.transition(easingDecimal).draw();
+ }, this);
+ },
+
+ setHoverStyle: function(arc) {
+ var dataset = this.chart.data.datasets[arc._datasetIndex];
+ var index = arc._index;
+
+ arc._model.backgroundColor = arc.custom && arc.custom.hoverBackgroundColor ? arc.custom.hoverBackgroundColor : helpers.getValueAtIndexOrDefault(dataset.hoverBackgroundColor, index, helpers.color(arc._model.backgroundColor).saturate(0.5).darken(0.1).rgbString());
+ arc._model.borderColor = arc.custom && arc.custom.hoverBorderColor ? arc.custom.hoverBorderColor : helpers.getValueAtIndexOrDefault(dataset.hoverBorderColor, index, helpers.color(arc._model.borderColor).saturate(0.5).darken(0.1).rgbString());
+ arc._model.borderWidth = arc.custom && arc.custom.hoverBorderWidth ? arc.custom.hoverBorderWidth : helpers.getValueAtIndexOrDefault(dataset.borderWidth, index, arc._model.borderWidth);
+ },
+
+ removeHoverStyle: function(arc) {
+ var dataset = this.chart.data.datasets[arc._datasetIndex];
+ var index = arc._index;
+
+ arc._model.backgroundColor = arc.custom && arc.custom.backgroundColor ? arc.custom.backgroundColor : helpers.getValueAtIndexOrDefault(this.getDataset().backgroundColor, index, this.chart.options.elements.arc.backgroundColor);
+ arc._model.borderColor = arc.custom && arc.custom.borderColor ? arc.custom.borderColor : helpers.getValueAtIndexOrDefault(this.getDataset().borderColor, index, this.chart.options.elements.arc.borderColor);
+ arc._model.borderWidth = arc.custom && arc.custom.borderWidth ? arc.custom.borderWidth : helpers.getValueAtIndexOrDefault(this.getDataset().borderWidth, index, this.chart.options.elements.arc.borderWidth);
+ },
+
+ calculateCircumference: function(value) {
+ if (isNaN(value)) {
+ return 0;
+ } else {
+ // Count the number of NaN values
+ var numNaN = helpers.where(this.getDataset().data, function(data) {
+ return isNaN(data);
+ }).length;
+
+ return (2 * Math.PI) / (this.getDataset().data.length - numNaN);
+ }
+ }
+ });
+}).call(this);
+
+(function() {
+ "use strict";
+
+ var root = this,
+ Chart = root.Chart,
+ helpers = Chart.helpers;
+
+
+
+ Chart.defaults.radar = {
+ scale: {
+ type: "radialLinear",
+ },
+ elements: {
+ line: {
+ tension: 0, // no bezier in radar
+ }
+ },
+ };
+
+ Chart.controllers.radar = Chart.DatasetController.extend({
+ linkScales: function() {
+ // No need. Single scale only
+ },
+
+ addElements: function() {
+
+ this.getDataset().metaData = this.getDataset().metaData || [];
+
+ this.getDataset().metaDataset = this.getDataset().metaDataset || new Chart.elements.Line({
+ _chart: this.chart.chart,
+ _datasetIndex: this.index,
+ _points: this.getDataset().metaData,
+ _loop: true
+ });
+
+ helpers.each(this.getDataset().data, function(value, index) {
+ this.getDataset().metaData[index] = this.getDataset().metaData[index] || new Chart.elements.Point({
+ _chart: this.chart.chart,
+ _datasetIndex: this.index,
+ _index: index,
+ _model: {
+ x: 0, //xScale.getPixelForValue(null, index, true),
+ y: 0, //this.chartArea.bottom,
+ },
+ });
+ }, this);
+ },
+ addElementAndReset: function(index) {
+ this.getDataset().metaData = this.getDataset().metaData || [];
+ var point = new Chart.elements.Point({
+ _chart: this.chart.chart,
+ _datasetIndex: this.index,
+ _index: index,
+ });
+
+ // Reset the point
+ this.updateElement(point, index, true);
+
+ // Add to the points array
+ this.getDataset().metaData.splice(index, 0, point);
+
+ // Make sure bezier control points are updated
+ this.updateBezierControlPoints();
+ },
+
+ update: function update(reset) {
+
+ var line = this.getDataset().metaDataset;
+ var points = this.getDataset().metaData;
+
+ var scale = this.chart.scale;
+ var scaleBase;
+
+ if (scale.min < 0 && scale.max < 0) {
+ scaleBase = scale.getPointPositionForValue(0, scale.max);
+ } else if (scale.min > 0 && scale.max > 0) {
+ scaleBase = scale.getPointPositionForValue(0, scale.min);
+ } else {
+ scaleBase = scale.getPointPositionForValue(0, 0);
+ }
+
+ helpers.extend(this.getDataset().metaDataset, {
+ // Utility
+ _datasetIndex: this.index,
+ // Data
+ _children: this.getDataset().metaData,
+ // Model
+ _model: {
+ // Appearance
+ tension: helpers.getValueOrDefault(this.getDataset().tension, this.chart.options.elements.line.tension),
+ backgroundColor: this.getDataset().backgroundColor || this.chart.options.elements.line.backgroundColor,
+ borderWidth: this.getDataset().borderWidth || this.chart.options.elements.line.borderWidth,
+ borderColor: this.getDataset().borderColor || this.chart.options.elements.line.borderColor,
+ fill: this.getDataset().fill !== undefined ? this.getDataset().fill : this.chart.options.elements.line.fill, // use the value from the this.getDataset() if it was provided. else fall back to the default
+
+ // Scale
+ scaleTop: scale.top,
+ scaleBottom: scale.bottom,
+ scaleZero: scaleBase,
+ },
+ });
+
+ this.getDataset().metaDataset.pivot();
+
+ // Update Points
+ helpers.each(points, function(point, index) {
+ this.updateElement(point, index, reset);
+ }, this);
+
+
+ // Update bezier control points
+ this.updateBezierControlPoints();
+ },
+ updateElement: function(point, index, reset) {
+ var pointPosition = this.chart.scale.getPointPositionForValue(index, this.getDataset().data[index]);
+
+ helpers.extend(point, {
+ // Utility
+ _datasetIndex: this.index,
+ _index: index,
+ _scale: this.chart.scale,
+
+ // Desired view properties
+ _model: {
+ x: reset ? this.chart.scale.xCenter : pointPosition.x, // value not used in dataset scale, but we want a consistent API between scales
+ y: reset ? this.chart.scale.yCenter : pointPosition.y,
+
+ // Appearance
+ tension: point.custom && point.custom.tension ? point.custom.tension : helpers.getValueOrDefault(this.getDataset().tension, this.chart.options.elements.line.tension),
+ radius: point.custom && point.custom.radius ? point.custom.pointRadius : helpers.getValueAtIndexOrDefault(this.getDataset().pointRadius, index, this.chart.options.elements.point.radius),
+ backgroundColor: point.custom && point.custom.backgroundColor ? point.custom.backgroundColor : helpers.getValueAtIndexOrDefault(this.getDataset().pointBackgroundColor, index, this.chart.options.elements.point.backgroundColor),
+ borderColor: point.custom && point.custom.borderColor ? point.custom.borderColor : helpers.getValueAtIndexOrDefault(this.getDataset().pointBorderColor, index, this.chart.options.elements.point.borderColor),
+ borderWidth: point.custom && point.custom.borderWidth ? point.custom.borderWidth : helpers.getValueAtIndexOrDefault(this.getDataset().pointBorderWidth, index, this.chart.options.elements.point.borderWidth),
+
+ // Tooltip
+ hitRadius: point.custom && point.custom.hitRadius ? point.custom.hitRadius : helpers.getValueAtIndexOrDefault(this.getDataset().hitRadius, index, this.chart.options.elements.point.hitRadius),
+ },
+ });
+
+ point._model.skip = point.custom && point.custom.skip ? point.custom.skip : (isNaN(point._model.x) || isNaN(point._model.y));
+ },
+ updateBezierControlPoints: function() {
+ helpers.each(this.getDataset().metaData, function(point, index) {
+ var controlPoints = helpers.splineCurve(
+ helpers.previousItem(this.getDataset().metaData, index, true)._model,
+ point._model,
+ helpers.nextItem(this.getDataset().metaData, index, true)._model,
+ point._model.tension
+ );
+
+ // Prevent the bezier going outside of the bounds of the graph
+ point._model.controlPointPreviousX = Math.max(Math.min(controlPoints.previous.x, this.chart.chartArea.right), this.chart.chartArea.left);
+ point._model.controlPointPreviousY = Math.max(Math.min(controlPoints.previous.y, this.chart.chartArea.bottom), this.chart.chartArea.top);
+
+ point._model.controlPointNextX = Math.max(Math.min(controlPoints.next.x, this.chart.chartArea.right), this.chart.chartArea.left);
+ point._model.controlPointNextY = Math.max(Math.min(controlPoints.next.y, this.chart.chartArea.bottom), this.chart.chartArea.top);
+
+ // Now pivot the point for animation
+ point.pivot();
+ }, this);
+ },
+
+ draw: function(ease) {
+ var easingDecimal = ease || 1;
+
+ // Transition Point Locations
+ helpers.each(this.getDataset().metaData, function(point, index) {
+ point.transition(easingDecimal);
+ }, this);
+
+ // Transition and Draw the line
+ this.getDataset().metaDataset.transition(easingDecimal).draw();
+
+ // Draw the points
+ helpers.each(this.getDataset().metaData, function(point) {
+ point.draw();
+ });
+ },
+
+ setHoverStyle: function(point) {
+ // Point
+ var dataset = this.chart.data.datasets[point._datasetIndex];
+ var index = point._index;
+
+ point._model.radius = point.custom && point.custom.radius ? point.custom.radius : helpers.getValueAtIndexOrDefault(dataset.pointHoverRadius, index, this.chart.options.elements.point.hoverRadius);
+ point._model.backgroundColor = point.custom && point.custom.hoverBackgroundColor ? point.custom.hoverBackgroundColor : helpers.getValueAtIndexOrDefault(dataset.pointHoverBackgroundColor, index, helpers.color(point._model.backgroundColor).saturate(0.5).darken(0.1).rgbString());
+ point._model.borderColor = point.custom && point.custom.hoverBorderColor ? point.custom.hoverBorderColor : helpers.getValueAtIndexOrDefault(dataset.pointHoverBorderColor, index, helpers.color(point._model.borderColor).saturate(0.5).darken(0.1).rgbString());
+ point._model.borderWidth = point.custom && point.custom.hoverBorderWidth ? point.custom.hoverBorderWidth : helpers.getValueAtIndexOrDefault(dataset.pointBorderWidth, index, point._model.borderWidth);
+ },
+
+ removeHoverStyle: function(point) {
+ var dataset = this.chart.data.datasets[point._datasetIndex];
+ var index = point._index;
+
+ point._model.radius = point.custom && point.custom.radius ? point.custom.radius : helpers.getValueAtIndexOrDefault(this.getDataset().radius, index, this.chart.options.elements.point.radius);
+ point._model.backgroundColor = point.custom && point.custom.backgroundColor ? point.custom.backgroundColor : helpers.getValueAtIndexOrDefault(this.getDataset().pointBackgroundColor, index, this.chart.options.elements.point.backgroundColor);
+ point._model.borderColor = point.custom && point.custom.borderColor ? point.custom.borderColor : helpers.getValueAtIndexOrDefault(this.getDataset().pointBorderColor, index, this.chart.options.elements.point.borderColor);
+ point._model.borderWidth = point.custom && point.custom.borderWidth ? point.custom.borderWidth : helpers.getValueAtIndexOrDefault(this.getDataset().pointBorderWidth, index, this.chart.options.elements.point.borderWidth);
+ }
+ });
+}).call(this);
+
+(function() {
+ "use strict";
+
+ var root = this,
+ Chart = root.Chart,
+ helpers = Chart.helpers;
+
+ // Default config for a category scale
+ var defaultConfig = {
+ position: "bottom",
+ };
+
+ var DatasetScale = Chart.Scale.extend({
+ buildTicks: function(index) {
+ this.ticks = this.chart.data.labels;
+ },
+
+ getLabelForIndex: function(index, datasetIndex) {
+ return this.ticks[index];
+ },
+
+ // Used to get data value locations. Value can either be an index or a numerical value
+ getPixelForValue: function(value, index, datasetIndex, includeOffset) {
+ if (this.isHorizontal()) {
+ var innerWidth = this.width - (this.paddingLeft + this.paddingRight);
+ var valueWidth = innerWidth / Math.max((this.chart.data.labels.length - ((this.options.gridLines.offsetGridLines) ? 0 : 1)), 1);
+ var widthOffset = (valueWidth * index) + this.paddingLeft;
+
+ if (this.options.gridLines.offsetGridLines && includeOffset) {
+ widthOffset += (valueWidth / 2);
+ }
+
+ return this.left + Math.round(widthOffset);
+ } else {
+ var innerHeight = this.height - (this.paddingTop + this.paddingBottom);
+ var valueHeight = innerHeight / Math.max((this.chart.data.labels.length - ((this.options.gridLines.offsetGridLines) ? 0 : 1)), 1);
+ var heightOffset = (valueHeight * index) + this.paddingTop;
+
+ if (this.options.gridLines.offsetGridLines && includeOffset) {
+ heightOffset += (valueHeight / 2);
+ }
+
+ return this.top + Math.round(heightOffset);
}
- }
- }
-
- //Max value from array
- function Max( array ){
- return Math.max.apply( Math, array );
- };
- //Min value from array
- function Min( array ){
- return Math.min.apply( Math, array );
- };
- //Default if undefined
- function Default(userDeclared,valueIfFalse){
- if(!userDeclared){
- return valueIfFalse;
- } else {
- return userDeclared;
- }
- };
- //Is a number function
- function isNumber(n) {
- return !isNaN(parseFloat(n)) && isFinite(n);
- }
- //Apply cap a value at a high or low number
- function CapValue(valueToCap, maxValue, minValue){
- if(isNumber(maxValue)) {
- if( valueToCap > maxValue ) {
- return maxValue;
+ },
+ });
+
+ Chart.scaleService.registerScaleType("category", DatasetScale, defaultConfig);
+
+}).call(this);
+
+(function() {
+ "use strict";
+
+ var root = this,
+ Chart = root.Chart,
+ helpers = Chart.helpers;
+
+ var defaultConfig = {
+ position: "left",
+ ticks: {
+ callback: function(tickValue, index, ticks) {
+ var delta = ticks[1] - ticks[0];
+
+ // If we have a number like 2.5 as the delta, figure out how many decimal places we need
+ if (Math.abs(delta) > 1) {
+ if (tickValue !== Math.floor(tickValue)) {
+ // not an integer
+ delta = tickValue - Math.floor(tickValue);
+ }
+ }
+
+ var logDelta = helpers.log10(Math.abs(delta));
+ var tickString = '';
+
+ if (tickValue !== 0) {
+ var numDecimal = -1 * Math.floor(logDelta);
+ numDecimal = Math.max(Math.min(numDecimal, 20), 0); // toFixed has a max of 20 decimal places
+ tickString = tickValue.toFixed(numDecimal);
+ } else {
+ tickString = '0'; // never show decimal places for 0
+ }
+
+ return tickString;
}
}
- if(isNumber(minValue)){
- if ( valueToCap < minValue ){
- return minValue;
+ };
+
+ var LinearScale = Chart.Scale.extend({
+ determineDataLimits: function() {
+ // First Calculate the range
+ this.min = null;
+ this.max = null;
+
+ if (this.options.stacked) {
+ var valuesPerType = {};
+
+ helpers.each(this.chart.data.datasets, function(dataset) {
+ if (valuesPerType[dataset.type] === undefined) {
+ valuesPerType[dataset.type] = {
+ positiveValues: [],
+ negativeValues: [],
+ };
+ }
+
+ // Store these per type
+ var positiveValues = valuesPerType[dataset.type].positiveValues;
+ var negativeValues = valuesPerType[dataset.type].negativeValues;
+
+ if (helpers.isDatasetVisible(dataset) && (this.isHorizontal() ? dataset.xAxisID === this.id : dataset.yAxisID === this.id)) {
+ helpers.each(dataset.data, function(rawValue, index) {
+
+ var value = +this.getRightValue(rawValue);
+ if (isNaN(value)) {
+ return;
+ }
+
+ positiveValues[index] = positiveValues[index] || 0;
+ negativeValues[index] = negativeValues[index] || 0;
+
+ if (this.options.relativePoints) {
+ positiveValues[index] = 100;
+ } else {
+ if (value < 0) {
+ negativeValues[index] += value;
+ } else {
+ positiveValues[index] += value;
+ }
+ }
+ }, this);
+ }
+ }, this);
+
+ helpers.each(valuesPerType, function(valuesForType) {
+ var values = valuesForType.positiveValues.concat(valuesForType.negativeValues);
+ var minVal = helpers.min(values);
+ var maxVal = helpers.max(values);
+ this.min = this.min === null ? minVal : Math.min(this.min, minVal);
+ this.max = this.max === null ? maxVal : Math.max(this.max, maxVal);
+ }, this);
+
+ } else {
+ helpers.each(this.chart.data.datasets, function(dataset) {
+ if (helpers.isDatasetVisible(dataset) && (this.isHorizontal() ? dataset.xAxisID === this.id : dataset.yAxisID === this.id)) {
+ helpers.each(dataset.data, function(rawValue, index) {
+ var value = +this.getRightValue(rawValue);
+ if (isNaN(value)) {
+ return;
+ }
+
+ if (this.min === null) {
+ this.min = value;
+ } else if (value < this.min) {
+ this.min = value;
+ }
+
+ if (this.max === null) {
+ this.max = value;
+ } else if (value > this.max) {
+ this.max = value;
+ }
+ }, this);
+ }
+ }, this);
+ }
+
+ // If we are forcing it to begin at 0, but 0 will already be rendered on the chart,
+ // do nothing since that would make the chart weird. If the user really wants a weird chart
+ // axis, they can manually override it
+ if (this.options.ticks.beginAtZero) {
+ var minSign = helpers.sign(this.min);
+ var maxSign = helpers.sign(this.max);
+
+ if (minSign < 0 && maxSign < 0) {
+ // move the top up to 0
+ this.max = 0;
+ } else if (minSign > 0 && maxSign > 0) {
+ // move the botttom down to 0
+ this.min = 0;
+ }
+ }
+
+ if (this.options.ticks.min !== undefined) {
+ this.min = this.options.ticks.min;
+ } else if (this.options.ticks.suggestedMin !== undefined) {
+ this.min = Math.min(this.min, this.options.ticks.suggestedMin);
+ }
+
+ if (this.options.ticks.max !== undefined) {
+ this.max = this.options.ticks.max;
+ } else if (this.options.ticks.suggestedMax !== undefined) {
+ this.max = Math.max(this.max, this.options.ticks.suggestedMax);
+ }
+
+ if (this.min === this.max) {
+ this.min--;
+ this.max++;
+ }
+ },
+ buildTicks: function() {
+
+ // Then calulate the ticks
+ this.ticks = [];
+
+ // Figure out what the max number of ticks we can support it is based on the size of
+ // the axis area. For now, we say that the minimum tick spacing in pixels must be 50
+ // We also limit the maximum number of ticks to 11 which gives a nice 10 squares on
+ // the graph
+
+ var maxTicks;
+
+ if (this.isHorizontal()) {
+ maxTicks = Math.min(this.options.ticks.maxTicksLimit ? this.options.ticks.maxTicksLimit : 11,
+ Math.ceil(this.width / 50));
+ } else {
+ // The factor of 2 used to scale the font size has been experimentally determined.
+ maxTicks = Math.min(this.options.ticks.maxTicksLimit ? this.options.ticks.maxTicksLimit : 11,
+ Math.ceil(this.height / (2 * this.options.ticks.fontSize)));
+ }
+
+ // Make sure we always have at least 2 ticks
+ maxTicks = Math.max(2, maxTicks);
+
+ // To get a "nice" value for the tick spacing, we will use the appropriately named
+ // "nice number" algorithm. See http://stackoverflow.com/questions/8506881/nice-label-algorithm-for-charts-with-minimum-ticks
+ // for details.
+
+ var niceRange = helpers.niceNum(this.max - this.min, false);
+ var spacing = helpers.niceNum(niceRange / (maxTicks - 1), true);
+ var niceMin = Math.floor(this.min / spacing) * spacing;
+ var niceMax = Math.ceil(this.max / spacing) * spacing;
+
+ var numSpaces = Math.ceil((niceMax - niceMin) / spacing);
+
+ // Put the values into the ticks array
+ this.ticks.push(this.options.ticks.min !== undefined ? this.options.ticks.min : niceMin);
+ for (var j = 1; j < numSpaces; ++j) {
+ this.ticks.push(niceMin + (j * spacing));
+ }
+ this.ticks.push(this.options.ticks.max !== undefined ? this.options.ticks.max : niceMax);
+
+ if (this.options.position == "left" || this.options.position == "right") {
+ // We are in a vertical orientation. The top value is the highest. So reverse the array
+ this.ticks.reverse();
+ }
+
+ // At this point, we need to update our max and min given the tick values since we have expanded the
+ // range of the scale
+ this.max = helpers.max(this.ticks);
+ this.min = helpers.min(this.ticks);
+ this.ticksAsNumbers = this.ticks.slice();
+
+ if (this.options.ticks.reverse) {
+ this.ticks.reverse();
+
+ this.start = this.max;
+ this.end = this.min;
+ } else {
+ this.start = this.min;
+ this.end = this.max;
+ }
+
+ this.zeroLineIndex = this.ticks.indexOf(0);
+ },
+
+ getLabelForIndex: function(index, datasetIndex) {
+ return +this.getRightValue(this.chart.data.datasets[datasetIndex].data[index]);
+ },
+
+ // Utils
+ getPixelForValue: function(value, index, datasetIndex, includeOffset) {
+ // This must be called after fit has been run so that
+ // this.left, this.top, this.right, and this.bottom have been defined
+ var rightValue = +this.getRightValue(value);
+ var pixel;
+ var range = this.end - this.start;
+
+ if (this.isHorizontal()) {
+ var innerWidth = this.width - (this.paddingLeft + this.paddingRight);
+ pixel = this.left + (innerWidth / range * (rightValue - this.start));
+ return Math.round(pixel + this.paddingLeft);
+ } else {
+ var innerHeight = this.height - (this.paddingTop + this.paddingBottom);
+ pixel = (this.bottom - this.paddingBottom) - (innerHeight / range * (rightValue - this.start));
+ return Math.round(pixel);
+ }
+ },
+ getPixelForTick: function(index, includeOffset) {
+ return this.getPixelForValue(this.ticksAsNumbers[index], null, null, includeOffset);
+ },
+ });
+ Chart.scaleService.registerScaleType("linear", LinearScale, defaultConfig);
+
+}).call(this);
+
+(function() {
+ "use strict";
+
+ var root = this,
+ Chart = root.Chart,
+ helpers = Chart.helpers;
+
+ var defaultConfig = {
+ position: "left",
+
+ // label settings
+ ticks: {
+ callback: function(value, index, arr) {
+ var remain = value / (Math.pow(10, Math.floor(Chart.helpers.log10(value))));
+
+ if (remain === 1 || remain === 2 || remain === 5 || index === 0 || index === arr.length - 1) {
+ return value.toExponential();
+ } else {
+ return '';
+ }
}
}
- return valueToCap;
- }
- function getDecimalPlaces (num){
- var numberOfDecimalPlaces;
- if (num%1!=0){
- return num.toString().split(".")[1].length
- }
- else{
- return 0;
- }
-
- }
-
- function mergeChartConfig(defaults,userDefined){
- var returnObj = {};
- for (var attrname in defaults) { returnObj[attrname] = defaults[attrname]; }
- for (var attrname in userDefined) { returnObj[attrname] = userDefined[attrname]; }
- return returnObj;
- }
-
- //Javascript micro templating by John Resig - source at http://ejohn.org/blog/javascript-micro-templating/
- var cache = {};
-
- function tmpl(str, data){
- // Figure out if we're getting a template, or if we need to
- // load the template - and be sure to cache the result.
- var fn = !/\W/.test(str) ?
- cache[str] = cache[str] ||
- tmpl(document.getElementById(str).innerHTML) :
-
- // Generate a reusable function that will serve as a template
- // generator (and which will be cached).
- new Function("obj",
- "var p=[],print=function(){p.push.apply(p,arguments);};" +
-
- // Introduce the data as local variables using with(){}
- "with(obj){p.push('" +
-
- // Convert the template into pure JavaScript
- str
- .replace(/[\r\t\n]/g, " ")
- .split("<%").join("\t")
- .replace(/((^|%>)[^\t]*)'/g, "$1\r")
- .replace(/\t=(.*?)%>/g, "',$1,'")
- .split("\t").join("');")
- .split("%>").join("p.push('")
- .split("\r").join("\\'")
- + "');}return p.join('');");
-
- // Provide some basic currying to the user
- return data ? fn( data ) : fn;
- };
-}
+ };
+
+ var LogarithmicScale = Chart.Scale.extend({
+ determineDataLimits: function() {
+ // Calculate Range
+ this.min = null;
+ this.max = null;
+
+ if (this.options.stacked) {
+ var valuesPerType = {};
+
+ helpers.each(this.chart.data.datasets, function(dataset) {
+ if (helpers.isDatasetVisible(dataset) && (this.isHorizontal() ? dataset.xAxisID === this.id : dataset.yAxisID === this.id)) {
+ if (valuesPerType[dataset.type] === undefined) {
+ valuesPerType[dataset.type] = [];
+ }
+
+ helpers.each(dataset.data, function(rawValue, index) {
+ var values = valuesPerType[dataset.type];
+ var value = +this.getRightValue(rawValue);
+ if (isNaN(value)) {
+ return;
+ }
+
+ values[index] = values[index] || 0;
+
+ if (this.options.relativePoints) {
+ values[index] = 100;
+ } else {
+ // Don't need to split positive and negative since the log scale can't handle a 0 crossing
+ values[index] += value;
+ }
+ }, this);
+ }
+ }, this);
+
+ helpers.each(valuesPerType, function(valuesForType) {
+ var minVal = helpers.min(valuesForType);
+ var maxVal = helpers.max(valuesForType);
+ this.min = this.min === null ? minVal : Math.min(this.min, minVal);
+ this.max = this.max === null ? maxVal : Math.max(this.max, maxVal);
+ }, this);
+
+ } else {
+ helpers.each(this.chart.data.datasets, function(dataset) {
+ if (helpers.isDatasetVisible(dataset) && (this.isHorizontal() ? dataset.xAxisID === this.id : dataset.yAxisID === this.id)) {
+ helpers.each(dataset.data, function(rawValue, index) {
+ var value = +this.getRightValue(rawValue);
+ if (isNaN(value)) {
+ return;
+ }
+
+ if (this.min === null) {
+ this.min = value;
+ } else if (value < this.min) {
+ this.min = value;
+ }
+
+ if (this.max === null) {
+ this.max = value;
+ } else if (value > this.max) {
+ this.max = value;
+ }
+ }, this);
+ }
+ }, this);
+ }
+
+ this.min = this.options.ticks.min !== undefined ? this.options.ticks.min : this.min;
+ this.max = this.options.ticks.max !== undefined ? this.options.ticks.max : this.max;
+
+ if (this.min === this.max) {
+ if (this.min !== 0 && this.min !== null) {
+ this.min = Math.pow(10, Math.floor(helpers.log10(this.min)) - 1);
+ this.max = Math.pow(10, Math.floor(helpers.log10(this.max)) + 1);
+ } else {
+ this.min = 1;
+ this.max = 10;
+ }
+ }
+ },
+ buildTicks: function() {
+ // Reset the ticks array. Later on, we will draw a grid line at these positions
+ // The array simply contains the numerical value of the spots where ticks will be
+ this.tickValues = [];
+
+ // Figure out what the max number of ticks we can support it is based on the size of
+ // the axis area. For now, we say that the minimum tick spacing in pixels must be 50
+ // We also limit the maximum number of ticks to 11 which gives a nice 10 squares on
+ // the graph
+
+ var tickVal = this.options.ticks.min !== undefined ? this.options.ticks.min : Math.pow(10, Math.floor(helpers.log10(this.min)));
+
+ while (tickVal < this.max) {
+ this.tickValues.push(tickVal);
+
+ var exp = Math.floor(helpers.log10(tickVal));
+ var significand = Math.floor(tickVal / Math.pow(10, exp)) + 1;
+
+ if (significand === 10) {
+ significand = 1;
+ ++exp;
+ }
+
+ tickVal = significand * Math.pow(10, exp);
+ }
+
+ var lastTick = this.options.ticks.max !== undefined ? this.options.ticks.max : tickVal;
+ this.tickValues.push(lastTick);
+
+ if (this.options.position == "left" || this.options.position == "right") {
+ // We are in a vertical orientation. The top value is the highest. So reverse the array
+ this.tickValues.reverse();
+ }
+
+ // At this point, we need to update our max and min given the tick values since we have expanded the
+ // range of the scale
+ this.max = helpers.max(this.tickValues);
+ this.min = helpers.min(this.tickValues);
+
+ if (this.options.ticks.reverse) {
+ this.tickValues.reverse();
+
+ this.start = this.max;
+ this.end = this.min;
+ } else {
+ this.start = this.min;
+ this.end = this.max;
+ }
+
+ this.ticks = this.tickValues.slice();
+ },
+ // Get the correct tooltip label
+ getLabelForIndex: function(index, datasetIndex) {
+ return +this.getRightValue(this.chart.data.datasets[datasetIndex].data[index]);
+ },
+ getPixelForTick: function(index, includeOffset) {
+ return this.getPixelForValue(this.tickValues[index], null, null, includeOffset);
+ },
+ getPixelForValue: function(value, index, datasetIndex, includeOffset) {
+ var pixel;
+
+ var newVal = +this.getRightValue(value);
+ var range = helpers.log10(this.end) - helpers.log10(this.start);
+
+ if (this.isHorizontal()) {
+
+ if (newVal === 0) {
+ pixel = this.left + this.paddingLeft;
+ } else {
+ var innerWidth = this.width - (this.paddingLeft + this.paddingRight);
+ pixel = this.left + (innerWidth / range * (helpers.log10(newVal) - helpers.log10(this.start)));
+ return pixel + this.paddingLeft;
+ }
+ } else {
+ // Bottom - top since pixels increase downard on a screen
+ if (newVal === 0) {
+ pixel = this.top + this.paddingTop;
+ } else {
+ var innerHeight = this.height - (this.paddingTop + this.paddingBottom);
+ return (this.bottom - this.paddingBottom) - (innerHeight / range * (helpers.log10(newVal) - helpers.log10(this.start)));
+ }
+ }
+
+ },
+
+ });
+ Chart.scaleService.registerScaleType("logarithmic", LogarithmicScale, defaultConfig);
+
+}).call(this);
+
+(function() {
+ "use strict";
+
+ var root = this,
+ Chart = root.Chart,
+ helpers = Chart.helpers;
+
+ var defaultConfig = {
+ display: true,
+
+ //Boolean - Whether to animate scaling the chart from the centre
+ animate: true,
+ lineArc: false,
+ position: "chartArea",
+
+ angleLines: {
+ display: true,
+ color: "rgba(0, 0, 0, 0.1)",
+ lineWidth: 1
+ },
+
+ // label settings
+ ticks: {
+ //Boolean - Show a backdrop to the scale label
+ showLabelBackdrop: true,
+
+ //String - The colour of the label backdrop
+ backdropColor: "rgba(255,255,255,0.75)",
+
+ //Number - The backdrop padding above & below the label in pixels
+ backdropPaddingY: 2,
+
+ //Number - The backdrop padding to the side of the label in pixels
+ backdropPaddingX: 2,
+ },
+
+ pointLabels: {
+ //String - Point label font declaration
+ fontFamily: "'Arial'",
+
+ //String - Point label font weight
+ fontStyle: "normal",
+
+ //Number - Point label font size in pixels
+ fontSize: 10,
+
+ //String - Point label font colour
+ fontColor: "#666",
+ },
+ };
+
+ var LinearRadialScale = Chart.Scale.extend({
+ getValueCount: function() {
+ return this.chart.data.labels.length;
+ },
+ setDimensions: function() {
+ // Set the unconstrained dimension before label rotation
+ this.width = this.maxWidth;
+ this.height = this.maxHeight;
+ this.xCenter = Math.round(this.width / 2);
+ this.yCenter = Math.round(this.height / 2);
+
+ var minSize = helpers.min([this.height, this.width]);
+ this.drawingArea = (this.options.display) ? (minSize / 2) - (this.options.ticks.fontSize / 2 + this.options.ticks.backdropPaddingY) : (minSize / 2);
+ },
+ determineDataLimits: function() {
+ this.min = null;
+ this.max = null;
+
+ helpers.each(this.chart.data.datasets, function(dataset) {
+ if (helpers.isDatasetVisible(dataset)) {
+ helpers.each(dataset.data, function(rawValue, index) {
+ var value = +this.getRightValue(rawValue);
+ if (isNaN(value)) {
+ return;
+ }
+
+ if (this.min === null) {
+ this.min = value;
+ } else if (value < this.min) {
+ this.min = value;
+ }
+
+ if (this.max === null) {
+ this.max = value;
+ } else if (value > this.max) {
+ this.max = value;
+ }
+ }, this);
+ }
+ }, this);
+
+ if (this.min === this.max) {
+ this.min--;
+ this.max++;
+ }
+
+ // If we are forcing it to begin at 0, but 0 will already be rendered on the chart,
+ // do nothing since that would make the chart weird. If the user really wants a weird chart
+ // axis, they can manually override it
+ if (this.options.ticks.beginAtZero) {
+ var minSign = helpers.sign(this.min);
+ var maxSign = helpers.sign(this.max);
+
+ if (minSign < 0 && maxSign < 0) {
+ // move the top up to 0
+ this.max = 0;
+ } else if (minSign > 0 && maxSign > 0) {
+ // move the botttom down to 0
+ this.min = 0;
+ }
+ }
+ },
+ buildTicks: function() {
+
+
+ this.ticks = [];
+
+ // Figure out what the max number of ticks we can support it is based on the size of
+ // the axis area. For now, we say that the minimum tick spacing in pixels must be 50
+ // We also limit the maximum number of ticks to 11 which gives a nice 10 squares on
+ // the graph
+ var maxTicks = Math.min(this.options.ticks.maxTicksLimit ? this.options.ticks.maxTicksLimit : 11,
+ Math.ceil(this.drawingArea / (1.5 * this.options.ticks.fontSize)));
+ maxTicks = Math.max(2, maxTicks); // Make sure we always have at least 2 ticks
+
+ // To get a "nice" value for the tick spacing, we will use the appropriately named
+ // "nice number" algorithm. See http://stackoverflow.com/questions/8506881/nice-label-algorithm-for-charts-with-minimum-ticks
+ // for details.
+
+ var niceRange = helpers.niceNum(this.max - this.min, false);
+ var spacing = helpers.niceNum(niceRange / (maxTicks - 1), true);
+ var niceMin = Math.floor(this.min / spacing) * spacing;
+ var niceMax = Math.ceil(this.max / spacing) * spacing;
+
+ // Put the values into the ticks array
+ for (var j = niceMin; j <= niceMax; j += spacing) {
+ this.ticks.push(j);
+ }
+
+ // At this point, we need to update our max and min given the tick values since we have expanded the
+ // range of the scale
+ this.max = helpers.max(this.ticks);
+ this.min = helpers.min(this.ticks);
+
+ if (this.options.ticks.reverse) {
+ this.ticks.reverse();
+
+ this.start = this.max;
+ this.end = this.min;
+ } else {
+ this.start = this.min;
+ this.end = this.max;
+ }
+
+ this.zeroLineIndex = this.ticks.indexOf(0);
+ },
+ getLabelForIndex: function(index, datasetIndex) {
+ return +this.getRightValue(this.chart.data.datasets[datasetIndex].data[index]);
+ },
+ getCircumference: function() {
+ return ((Math.PI * 2) / this.getValueCount());
+ },
+ fit: function() {
+ /*
+ * Right, this is really confusing and there is a lot of maths going on here
+ * The gist of the problem is here: https://gist.github.com/nnnick/696cc9c55f4b0beb8fe9
+ *
+ * Reaction: https://dl.dropboxusercontent.com/u/34601363/toomuchscience.gif
+ *
+ * Solution:
+ *
+ * We assume the radius of the polygon is half the size of the canvas at first
+ * at each index we check if the text overlaps.
+ *
+ * Where it does, we store that angle and that index.
+ *
+ * After finding the largest index and angle we calculate how much we need to remove
+ * from the shape radius to move the point inwards by that x.
+ *
+ * We average the left and right distances to get the maximum shape radius that can fit in the box
+ * along with labels.
+ *
+ * Once we have that, we can find the centre point for the chart, by taking the x text protrusion
+ * on each side, removing that from the size, halving it and adding the left x protrusion width.
+ *
+ * This will mean we have a shape fitted to the canvas, as large as it can be with the labels
+ * and position it in the most space efficient manner
+ *
+ * https://dl.dropboxusercontent.com/u/34601363/yeahscience.gif
+ */
+ // Get maximum radius of the polygon. Either half the height (minus the text width) or half the width.
+ // Use this to calculate the offset + change. - Make sure L/R protrusion is at least 0 to stop issues with centre points
+ var largestPossibleRadius = helpers.min([(this.height / 2 - this.options.pointLabels.fontSize - 5), this.width / 2]),
+ pointPosition,
+ i,
+ textWidth,
+ halfTextWidth,
+ furthestRight = this.width,
+ furthestRightIndex,
+ furthestRightAngle,
+ furthestLeft = 0,
+ furthestLeftIndex,
+ furthestLeftAngle,
+ xProtrusionLeft,
+ xProtrusionRight,
+ radiusReductionRight,
+ radiusReductionLeft,
+ maxWidthRadius;
+ this.ctx.font = helpers.fontString(this.options.pointLabels.fontSize, this.options.pointLabels.fontStyle, this.options.pointLabels.fontFamily);
+ for (i = 0; i < this.getValueCount(); i++) {
+ // 5px to space the text slightly out - similar to what we do in the draw function.
+ pointPosition = this.getPointPosition(i, largestPossibleRadius);
+ textWidth = this.ctx.measureText(this.options.ticks.callback(this.chart.data.labels[i])).width + 5;
+ if (i === 0 || i === this.getValueCount() / 2) {
+ // If we're at index zero, or exactly the middle, we're at exactly the top/bottom
+ // of the radar chart, so text will be aligned centrally, so we'll half it and compare
+ // w/left and right text sizes
+ halfTextWidth = textWidth / 2;
+ if (pointPosition.x + halfTextWidth > furthestRight) {
+ furthestRight = pointPosition.x + halfTextWidth;
+ furthestRightIndex = i;
+ }
+ if (pointPosition.x - halfTextWidth < furthestLeft) {
+ furthestLeft = pointPosition.x - halfTextWidth;
+ furthestLeftIndex = i;
+ }
+ } else if (i < this.getValueCount() / 2) {
+ // Less than half the values means we'll left align the text
+ if (pointPosition.x + textWidth > furthestRight) {
+ furthestRight = pointPosition.x + textWidth;
+ furthestRightIndex = i;
+ }
+ } else if (i > this.getValueCount() / 2) {
+ // More than half the values means we'll right align the text
+ if (pointPosition.x - textWidth < furthestLeft) {
+ furthestLeft = pointPosition.x - textWidth;
+ furthestLeftIndex = i;
+ }
+ }
+ }
+
+ xProtrusionLeft = furthestLeft;
+ xProtrusionRight = Math.ceil(furthestRight - this.width);
+
+ furthestRightAngle = this.getIndexAngle(furthestRightIndex);
+ furthestLeftAngle = this.getIndexAngle(furthestLeftIndex);
+
+ radiusReductionRight = xProtrusionRight / Math.sin(furthestRightAngle + Math.PI / 2);
+ radiusReductionLeft = xProtrusionLeft / Math.sin(furthestLeftAngle + Math.PI / 2);
+
+ // Ensure we actually need to reduce the size of the chart
+ radiusReductionRight = (helpers.isNumber(radiusReductionRight)) ? radiusReductionRight : 0;
+ radiusReductionLeft = (helpers.isNumber(radiusReductionLeft)) ? radiusReductionLeft : 0;
+
+ this.drawingArea = Math.round(largestPossibleRadius - (radiusReductionLeft + radiusReductionRight) / 2);
+ this.setCenterPoint(radiusReductionLeft, radiusReductionRight);
+ },
+ setCenterPoint: function(leftMovement, rightMovement) {
+
+ var maxRight = this.width - rightMovement - this.drawingArea,
+ maxLeft = leftMovement + this.drawingArea;
+
+ this.xCenter = Math.round(((maxLeft + maxRight) / 2) + this.left);
+ // Always vertically in the centre as the text height doesn't change
+ this.yCenter = Math.round((this.height / 2) + this.top);
+ },
+
+ getIndexAngle: function(index) {
+ var angleMultiplier = (Math.PI * 2) / this.getValueCount();
+ // Start from the top instead of right, so remove a quarter of the circle
+
+ return index * angleMultiplier - (Math.PI / 2);
+ },
+ getDistanceFromCenterForValue: function(value) {
+ if (value === null) {
+ return 0; // null always in center
+ }
+
+ // Take into account half font size + the yPadding of the top value
+ var scalingFactor = this.drawingArea / (this.max - this.min);
+ if (this.options.reverse) {
+ return (this.max - value) * scalingFactor;
+ } else {
+ return (value - this.min) * scalingFactor;
+ }
+ },
+ getPointPosition: function(index, distanceFromCenter) {
+ var thisAngle = this.getIndexAngle(index);
+ return {
+ x: Math.round(Math.cos(thisAngle) * distanceFromCenter) + this.xCenter,
+ y: Math.round(Math.sin(thisAngle) * distanceFromCenter) + this.yCenter
+ };
+ },
+ getPointPositionForValue: function(index, value) {
+ return this.getPointPosition(index, this.getDistanceFromCenterForValue(value));
+ },
+ draw: function() {
+ if (this.options.display) {
+ var ctx = this.ctx;
+ helpers.each(this.ticks, function(label, index) {
+ // Don't draw a centre value (if it is minimum)
+ if (index > 0 || this.options.reverse) {
+ var yCenterOffset = this.getDistanceFromCenterForValue(this.ticks[index]);
+ var yHeight = this.yCenter - yCenterOffset;
+
+ // Draw circular lines around the scale
+ if (this.options.gridLines.display) {
+ ctx.strokeStyle = this.options.gridLines.color;
+ ctx.lineWidth = this.options.gridLines.lineWidth;
+
+ if (this.options.lineArc) {
+ // Draw circular arcs between the points
+ ctx.beginPath();
+ ctx.arc(this.xCenter, this.yCenter, yCenterOffset, 0, Math.PI * 2);
+ ctx.closePath();
+ ctx.stroke();
+ } else {
+ // Draw straight lines connecting each index
+ ctx.beginPath();
+ for (var i = 0; i < this.getValueCount(); i++) {
+ var pointPosition = this.getPointPosition(i, this.getDistanceFromCenterForValue(this.ticks[index]));
+ if (i === 0) {
+ ctx.moveTo(pointPosition.x, pointPosition.y);
+ } else {
+ ctx.lineTo(pointPosition.x, pointPosition.y);
+ }
+ }
+ ctx.closePath();
+ ctx.stroke();
+ }
+ }
+
+ if (this.options.ticks.display) {
+ ctx.font = helpers.fontString(this.options.ticks.fontSize, this.options.ticks.fontStyle, this.options.ticks.fontFamily);
+
+ if (this.options.ticks.showLabelBackdrop) {
+ var labelWidth = ctx.measureText(label).width;
+ ctx.fillStyle = this.options.ticks.backdropColor;
+ ctx.fillRect(
+ this.xCenter - labelWidth / 2 - this.options.ticks.backdropPaddingX,
+ yHeight - this.options.ticks.fontSize / 2 - this.options.ticks.backdropPaddingY,
+ labelWidth + this.options.ticks.backdropPaddingX * 2,
+ this.options.ticks.fontSize + this.options.ticks.backdropPaddingY * 2
+ );
+ }
+
+ ctx.textAlign = 'center';
+ ctx.textBaseline = "middle";
+ ctx.fillStyle = this.options.ticks.fontColor;
+ ctx.fillText(label, this.xCenter, yHeight);
+ }
+ }
+ }, this);
+
+ if (!this.options.lineArc) {
+ ctx.lineWidth = this.options.angleLines.lineWidth;
+ ctx.strokeStyle = this.options.angleLines.color;
+
+ for (var i = this.getValueCount() - 1; i >= 0; i--) {
+ if (this.options.angleLines.display) {
+ var outerPosition = this.getPointPosition(i, this.getDistanceFromCenterForValue(this.options.reverse ? this.min : this.max));
+ ctx.beginPath();
+ ctx.moveTo(this.xCenter, this.yCenter);
+ ctx.lineTo(outerPosition.x, outerPosition.y);
+ ctx.stroke();
+ ctx.closePath();
+ }
+ // Extra 3px out for some label spacing
+ var pointLabelPosition = this.getPointPosition(i, this.getDistanceFromCenterForValue(this.options.reverse ? this.min : this.max) + 5);
+ ctx.font = helpers.fontString(this.options.pointLabels.fontSize, this.options.pointLabels.fontStyle, this.options.pointLabels.fontFamily);
+ ctx.fillStyle = this.options.pointLabels.fontColor;
+
+ var labelsCount = this.chart.data.labels.length,
+ halfLabelsCount = this.chart.data.labels.length / 2,
+ quarterLabelsCount = halfLabelsCount / 2,
+ upperHalf = (i < quarterLabelsCount || i > labelsCount - quarterLabelsCount),
+ exactQuarter = (i === quarterLabelsCount || i === labelsCount - quarterLabelsCount);
+ if (i === 0) {
+ ctx.textAlign = 'center';
+ } else if (i === halfLabelsCount) {
+ ctx.textAlign = 'center';
+ } else if (i < halfLabelsCount) {
+ ctx.textAlign = 'left';
+ } else {
+ ctx.textAlign = 'right';
+ }
+
+ // Set the correct text baseline based on outer positioning
+ if (exactQuarter) {
+ ctx.textBaseline = 'middle';
+ } else if (upperHalf) {
+ ctx.textBaseline = 'bottom';
+ } else {
+ ctx.textBaseline = 'top';
+ }
+
+ ctx.fillText(this.chart.data.labels[i], pointLabelPosition.x, pointLabelPosition.y);
+ }
+ }
+ }
+ }
+ });
+ Chart.scaleService.registerScaleType("radialLinear", LinearRadialScale, defaultConfig);
+
+
+}).call(this);
+
+(function(moment) {
+ "use strict";
+
+ if (!moment) {
+ console.warn('Chart.js - Moment.js could not be found! You must include it before Chart.js to use the time scale. Download at http://momentjs.com/');
+ return;
+ }
+
+ var root = this,
+ Chart = root.Chart,
+ helpers = Chart.helpers;
+
+ var time = {
+ units: [
+ {
+ name: 'millisecond',
+ steps: [1, 2, 5, 10, 20, 50, 100, 250, 500]
+ }, {
+ name: 'second',
+ steps: [1, 2, 5, 10, 30]
+ }, {
+ name: 'minute',
+ steps: [1, 2, 5, 10, 30]
+ }, {
+ name: 'hour',
+ steps: [1, 2, 3, 6, 12]
+ }, {
+ name: 'day',
+ steps: [1, 2, 5]
+ }, {
+ name: 'week',
+ maxStep: 4
+ }, {
+ name: 'month',
+ maxStep: 3
+ }, {
+ name: 'quarter',
+ maxStep: 4,
+ }, {
+ name: 'year',
+ maxStep: false
+ },
+ ],
+ };
+
+ var defaultConfig = {
+ position: "bottom",
+
+ time: {
+ format: false, // false == date objects or use pattern string from http://momentjs.com/docs/#/parsing/string-format/
+ unit: false, // false == automatic or override with week, month, year, etc.
+ round: false, // none, or override with week, month, year, etc.
+ displayFormat: false, // DEPRECATED
+
+ // defaults to unit's corresponding unitFormat below or override using pattern string from http://momentjs.com/docs/#/displaying/format/
+ displayFormats: {
+ 'millisecond': 'SSS [ms]',
+ 'second': 'h:mm:ss a', // 11:20:01 AM
+ 'minute': 'h:mm:ss a', // 11:20:01 AM
+ 'hour': 'MMM D, hA', // Sept 4, 5PM
+ 'day': 'll', // Sep 4 2015
+ 'week': 'll', // Week 46, or maybe "[W]WW - YYYY" ?
+ 'month': 'MMM YYYY', // Sept 2015
+ 'quarter': '[Q]Q - YYYY', // Q3
+ 'year': 'YYYY', // 2015
+ },
+ },
+ };
+
+ var TimeScale = Chart.Scale.extend({
+ getLabelMoment: function(datasetIndex, index) {
+ return this.labelMoments[datasetIndex][index];
+ },
+ determineDataLimits: function() {
+ this.labelMoments = [];
+
+ // Only parse these once. If the dataset does not have data as x,y pairs, we will use
+ // these
+ var scaleLabelMoments = [];
+ if (this.chart.data.labels && this.chart.data.labels.length > 0) {
+ helpers.each(this.chart.data.labels, function(label, index) {
+ var labelMoment = this.parseTime(label);
+ if (this.options.time.round) {
+ labelMoment.startOf(this.options.time.round);
+ }
+ scaleLabelMoments.push(labelMoment);
+ }, this);
+
+ if (this.options.time.min) {
+ this.firstTick = this.parseTime(this.options.time.min);
+ } else {
+ this.firstTick = moment.min.call(this, scaleLabelMoments);
+ }
+
+ if (this.options.time.max) {
+ this.lastTick = this.parseTime(this.options.time.max);
+ } else {
+ this.lastTick = moment.max.call(this, scaleLabelMoments);
+ }
+ } else {
+ this.firstTick = null;
+ this.lastTick = null;
+ }
+
+ helpers.each(this.chart.data.datasets, function(dataset, datasetIndex) {
+ var momentsForDataset = [];
+
+ if (typeof dataset.data[0] === 'object') {
+ helpers.each(dataset.data, function(value, index) {
+ var labelMoment = this.parseTime(this.getRightValue(value));
+ if (this.options.time.round) {
+ labelMoment.startOf(this.options.time.round);
+ }
+ momentsForDataset.push(labelMoment);
+
+ // May have gone outside the scale ranges, make sure we keep the first and last ticks updated
+ this.firstTick = this.firstTick !== null ? moment.min(this.firstTick, labelMoment) : labelMoment;
+ this.lastTick = this.lastTick !== null ? moment.max(this.lastTick, labelMoment) : labelMoment;
+ }, this);
+ } else {
+ // We have no labels. Use the ones from the scale
+ momentsForDataset = scaleLabelMoments;
+ }
+
+ this.labelMoments.push(momentsForDataset);
+ }, this);
+
+ // We will modify these, so clone for later
+ this.firstTick = (this.firstTick || moment()).clone();
+ this.lastTick = (this.lastTick || moment()).clone();
+ },
+ buildTicks: function(index) {
+
+ this.ticks = [];
+ this.unitScale = 1; // How much we scale the unit by, ie 2 means 2x unit per step
+
+ // Set unit override if applicable
+ if (this.options.time.unit) {
+ this.tickUnit = this.options.time.unit || 'day';
+ this.displayFormat = this.options.time.displayFormats[this.tickUnit];
+ this.tickRange = Math.ceil(this.lastTick.diff(this.firstTick, this.tickUnit, true));
+ } else {
+ // Determine the smallest needed unit of the time
+ var innerWidth = this.width - (this.paddingLeft + this.paddingRight);
+ var labelCapacity = innerWidth / (this.options.ticks.fontSize + 10);
+ var buffer = this.options.time.round ? 0 : 2;
+
+ // Start as small as possible
+ this.tickUnit = 'millisecond';
+ this.tickRange = Math.ceil(this.lastTick.diff(this.firstTick, this.tickUnit, true) + buffer);
+ this.displayFormat = this.options.time.displayFormats[this.tickUnit];
+
+ var unitDefinitionIndex = 0;
+ var unitDefinition = time.units[unitDefinitionIndex];
+
+ // While we aren't ideal and we don't have units left
+ while (unitDefinitionIndex < time.units.length) {
+ // Can we scale this unit. If `false` we can scale infinitely
+ //var canScaleUnit = ;
+ this.unitScale = 1;
+
+ if (helpers.isArray(unitDefinition.steps) && Math.ceil(this.tickRange / labelCapacity) < helpers.max(unitDefinition.steps)) {
+ // Use one of the prefedined steps
+ for (var idx = 0; idx < unitDefinition.steps.length; ++idx) {
+ if (unitDefinition.steps[idx] > Math.ceil(this.tickRange / labelCapacity)) {
+ this.unitScale = unitDefinition.steps[idx];
+ break;
+ }
+ }
+
+ break;
+ } else if ((unitDefinition.maxStep === false) || (Math.ceil(this.tickRange / labelCapacity) < unitDefinition.maxStep)) {
+ // We have a max step. Scale this unit
+ this.unitScale = Math.ceil(this.tickRange / labelCapacity);
+ break;
+ } else {
+ // Move to the next unit up
+ ++unitDefinitionIndex;
+ unitDefinition = time.units[unitDefinitionIndex];
+
+ this.tickUnit = unitDefinition.name;
+ this.tickRange = Math.ceil(this.lastTick.diff(this.firstTick, this.tickUnit) + buffer);
+ this.displayFormat = this.options.time.displayFormats[unitDefinition.name];
+ }
+ }
+ }
+
+ this.firstTick.startOf(this.tickUnit);
+ this.lastTick.endOf(this.tickUnit);
+ this.smallestLabelSeparation = this.width;
+
+ helpers.each(this.chart.data.datasets, function(dataset, datasetIndex) {
+ for (var i = 1; i < this.labelMoments[datasetIndex].length; i++) {
+ this.smallestLabelSeparation = Math.min(this.smallestLabelSeparation, this.labelMoments[datasetIndex][i].diff(this.labelMoments[datasetIndex][i - 1], this.tickUnit, true));
+ }
+ }, this);
+
+ // Tick displayFormat override
+ if (this.options.time.displayFormat) {
+ this.displayFormat = this.options.time.displayFormat;
+ }
+
+ // For every unit in between the first and last moment, create a moment and add it to the ticks tick
+ for (var i = 0; i <= this.tickRange; ++i) {
+ if (i % this.unitScale === 0) {
+ this.ticks.push(this.firstTick.clone().add(i, this.tickUnit));
+ } else if (i === this.tickRange) {
+ // Expand out the last one if not an exact multiple
+ this.tickRange = Math.ceil(this.tickRange / this.unitScale) * this.unitScale;
+ this.ticks.push(this.firstTick.clone().add(this.tickRange, this.tickUnit));
+ this.lastTick = this.ticks[this.ticks.length - 1].clone();
+ break;
+ }
+ }
+ },
+ // Get tooltip label
+ getLabelForIndex: function(index, datasetIndex) {
+ var label = this.chart.data.labels && index < this.chart.data.labels.length ? this.chart.data.labels[index] : '';
+
+ if (typeof this.chart.data.datasets[datasetIndex].data[0] === 'object') {
+ label = this.getRightValue(this.chart.data.datasets[datasetIndex].data[index]);
+ }
+
+ // Format nicely
+ if (this.options.time.tooltipFormat) {
+ label = this.parseTime(label).format(this.options.time.tooltipFormat);
+ }
+
+ return label;
+ },
+ convertTicksToLabels: function() {
+ this.ticks = this.ticks.map(function(tick, index, ticks) {
+ var formattedTick = tick.format(this.displayFormat);
+
+ if (this.options.ticks.userCallback) {
+ return this.options.ticks.userCallback(formattedTick, index, ticks);
+ } else {
+ return formattedTick;
+ }
+ }, this);
+ },
+ getPixelForValue: function(value, index, datasetIndex, includeOffset) {
+ var labelMoment = this.getLabelMoment(datasetIndex, index);
+ var offset = labelMoment.diff(this.firstTick, this.tickUnit, true);
+
+ var decimal = offset / this.tickRange;
+
+ if (this.isHorizontal()) {
+ var innerWidth = this.width - (this.paddingLeft + this.paddingRight);
+ var valueWidth = innerWidth / Math.max(this.ticks.length - 1, 1);
+ var valueOffset = (innerWidth * decimal) + this.paddingLeft;
+
+ return this.left + Math.round(valueOffset);
+ } else {
+ var innerHeight = this.height - (this.paddingTop + this.paddingBottom);
+ var valueHeight = innerHeight / Math.max(this.ticks.length - 1, 1);
+ var heightOffset = (innerHeight * decimal) + this.paddingTop;
+
+ return this.top + Math.round(heightOffset);
+ }
+ },
+ parseTime: function(label) {
+ // Date objects
+ if (typeof label.getMonth === 'function' || typeof label == 'number') {
+ return moment(label);
+ }
+ // Moment support
+ if (label.isValid && label.isValid()) {
+ return label;
+ }
+ // Custom parsing (return an instance of moment)
+ if (typeof this.options.time.format !== 'string' && this.options.time.format.call) {
+ return this.options.time.format(label);
+ }
+ // Moment format parsing
+ return moment(label, this.options.time.format);
+ },
+ });
+ Chart.scaleService.registerScaleType("time", TimeScale, defaultConfig);
+
+}).call(this, moment);
+
+/*!
+ * Chart.js
+ * http://chartjs.org/
+ * Version: 2.0.0-beta2
+ *
+ * Copyright 2015 Nick Downie
+ * Released under the MIT license
+ * https://github.com/nnnick/Chart.js/blob/master/LICENSE.md
+ */
+
+
+(function() {
+
+ "use strict";
+
+ var root = this,
+ Chart = root.Chart,
+ helpers = Chart.helpers;
+
+ Chart.defaults.global.elements.arc = {
+ backgroundColor: Chart.defaults.global.defaultColor,
+ borderColor: "#fff",
+ borderWidth: 2
+ };
+
+ Chart.elements.Arc = Chart.Element.extend({
+ inLabelRange: function(mouseX) {
+ var vm = this._view;
+
+ if (vm) {
+ return (Math.pow(mouseX - vm.x, 2) < Math.pow(vm.radius + vm.hoverRadius, 2));
+ } else {
+ return false;
+ }
+ },
+ inRange: function(chartX, chartY) {
+
+ var vm = this._view;
+
+ if (vm) {
+ var pointRelativePosition = helpers.getAngleFromPoint(vm, {
+ x: chartX,
+ y: chartY
+ });
+
+ // Put into the range of (-PI/2, 3PI/2]
+ var startAngle = vm.startAngle < (-0.5 * Math.PI) ? vm.startAngle + (2.0 * Math.PI) : vm.startAngle > (1.5 * Math.PI) ? vm.startAngle - (2.0 * Math.PI) : vm.startAngle;
+ var endAngle = vm.endAngle < (-0.5 * Math.PI) ? vm.endAngle + (2.0 * Math.PI) : vm.endAngle > (1.5 * Math.PI) ? vm.endAngle - (2.0 * Math.PI) : vm.endAngle;
+
+ //Check if within the range of the open/close angle
+ var betweenAngles = (pointRelativePosition.angle >= startAngle && pointRelativePosition.angle <= endAngle),
+ withinRadius = (pointRelativePosition.distance >= vm.innerRadius && pointRelativePosition.distance <= vm.outerRadius);
+
+ return (betweenAngles && withinRadius);
+ } else {
+ return false;
+ }
+ },
+ tooltipPosition: function() {
+ var vm = this._view;
+
+ var centreAngle = vm.startAngle + ((vm.endAngle - vm.startAngle) / 2),
+ rangeFromCentre = (vm.outerRadius - vm.innerRadius) / 2 + vm.innerRadius;
+ return {
+ x: vm.x + (Math.cos(centreAngle) * rangeFromCentre),
+ y: vm.y + (Math.sin(centreAngle) * rangeFromCentre)
+ };
+ },
+ draw: function() {
+
+ var ctx = this._chart.ctx;
+ var vm = this._view;
+
+ ctx.beginPath();
+
+ ctx.arc(vm.x, vm.y, vm.outerRadius, vm.startAngle, vm.endAngle);
+
+ ctx.arc(vm.x, vm.y, vm.innerRadius, vm.endAngle, vm.startAngle, true);
+
+ ctx.closePath();
+ ctx.strokeStyle = vm.borderColor;
+ ctx.lineWidth = vm.borderWidth;
+
+ ctx.fillStyle = vm.backgroundColor;
+
+ ctx.fill();
+ ctx.lineJoin = 'bevel';
+
+ if (vm.borderWidth) {
+ ctx.stroke();
+ }
+ }
+ });
+
+
+}).call(this);
+
+/*!
+ * Chart.js
+ * http://chartjs.org/
+ * Version: 2.0.0-beta2
+ *
+ * Copyright 2015 Nick Downie
+ * Released under the MIT license
+ * https://github.com/nnnick/Chart.js/blob/master/LICENSE.md
+ */
+
+
+(function() {
+
+ "use strict";
+
+ var root = this,
+ Chart = root.Chart,
+ helpers = Chart.helpers;
+
+ Chart.defaults.global.elements.line = {
+ tension: 0.4,
+ backgroundColor: Chart.defaults.global.defaultColor,
+ borderWidth: 3,
+ borderColor: Chart.defaults.global.defaultColor,
+ borderCapStyle: 'butt',
+ borderDash: [],
+ borderDashOffset: 0.0,
+ borderJoinStyle: 'miter',
+ fill: true, // do we fill in the area between the line and its base axis
+ };
+
+ Chart.elements.Line = Chart.Element.extend({
+ lineToNextPoint: function(previousPoint, point, nextPoint, skipHandler, previousSkipHandler) {
+ var ctx = this._chart.ctx;
+
+ if (point._view.skip) {
+ skipHandler.call(this, previousPoint, point, nextPoint);
+ } else if (previousPoint._view.skip) {
+ previousSkipHandler.call(this, previousPoint, point, nextPoint);
+ } else if (point._view.tension === 0) {
+ ctx.lineTo(point._view.x, point._view.y);
+ } else {
+ // Line between points
+ ctx.bezierCurveTo(
+ previousPoint._view.controlPointNextX,
+ previousPoint._view.controlPointNextY,
+ point._view.controlPointPreviousX,
+ point._view.controlPointPreviousY,
+ point._view.x,
+ point._view.y
+ );
+ }
+ },
+
+ draw: function() {
+ var _this = this;
+
+ var vm = this._view;
+ var ctx = this._chart.ctx;
+ var first = this._children[0];
+ var last = this._children[this._children.length - 1];
+
+ function loopBackToStart(drawLineToCenter) {
+ if (!first._view.skip && !last._view.skip) {
+ // Draw a bezier line from last to first
+ ctx.bezierCurveTo(
+ last._view.controlPointNextX,
+ last._view.controlPointNextY,
+ first._view.controlPointPreviousX,
+ first._view.controlPointPreviousY,
+ first._view.x,
+ first._view.y
+ );
+ } else if (drawLineToCenter) {
+ // Go to center
+ ctx.lineTo(_this._view.scaleZero.x, _this._view.scaleZero.y);
+ }
+ }
+
+ ctx.save();
+
+ // If we had points and want to fill this line, do so.
+ if (this._children.length > 0 && vm.fill) {
+ // Draw the background first (so the border is always on top)
+ ctx.beginPath();
+
+ helpers.each(this._children, function(point, index) {
+ var previous = helpers.previousItem(this._children, index);
+ var next = helpers.nextItem(this._children, index);
+
+ // First point moves to it's starting position no matter what
+ if (index === 0) {
+ if (this._loop) {
+ ctx.moveTo(vm.scaleZero.x, vm.scaleZero.y);
+ } else {
+ ctx.moveTo(point._view.x, vm.scaleZero);
+ }
+
+ if (point._view.skip) {
+ if (!this._loop) {
+ ctx.moveTo(next._view.x, this._view.scaleZero);
+ }
+ } else {
+ ctx.lineTo(point._view.x, point._view.y);
+ }
+ } else {
+ this.lineToNextPoint(previous, point, next, function(previousPoint, point, nextPoint) {
+ if (this._loop) {
+ // Go to center
+ ctx.lineTo(this._view.scaleZero.x, this._view.scaleZero.y);
+ } else {
+ ctx.lineTo(previousPoint._view.x, this._view.scaleZero);
+ ctx.moveTo(nextPoint._view.x, this._view.scaleZero);
+ }
+ }, function(previousPoint, point) {
+ // If we skipped the last point, draw a line to ourselves so that the fill is nice
+ ctx.lineTo(point._view.x, point._view.y);
+ });
+ }
+ }, this);
+
+ // For radial scales, loop back around to the first point
+ if (this._loop) {
+ loopBackToStart(true);
+ } else {
+ //Round off the line by going to the base of the chart, back to the start, then fill.
+ ctx.lineTo(this._children[this._children.length - 1]._view.x, vm.scaleZero);
+ ctx.lineTo(this._children[0]._view.x, vm.scaleZero);
+ }
+
+ ctx.fillStyle = vm.backgroundColor || Chart.defaults.global.defaultColor;
+ ctx.closePath();
+ ctx.fill();
+ }
+
+ // Now draw the line between all the points with any borders
+ ctx.lineCap = vm.borderCapStyle || Chart.defaults.global.elements.line.borderCapStyle;
+
+ // IE 9 and 10 do not support line dash
+ if (ctx.setLineDash) {
+ ctx.setLineDash(vm.borderDash || Chart.defaults.global.elements.line.borderDash);
+ }
+
+ ctx.lineDashOffset = vm.borderDashOffset || Chart.defaults.global.elements.line.borderDashOffset;
+ ctx.lineJoin = vm.borderJoinStyle || Chart.defaults.global.elements.line.borderJoinStyle;
+ ctx.lineWidth = vm.borderWidth || Chart.defaults.global.elements.line.borderWidth;
+ ctx.strokeStyle = vm.borderColor || Chart.defaults.global.defaultColor;
+ ctx.beginPath();
+
+ helpers.each(this._children, function(point, index) {
+ var previous = helpers.previousItem(this._children, index);
+ var next = helpers.nextItem(this._children, index);
+
+ if (index === 0) {
+ ctx.moveTo(point._view.x, point._view.y);
+ } else {
+ this.lineToNextPoint(previous, point, next, function(previousPoint, point, nextPoint) {
+ ctx.moveTo(nextPoint._view.x, nextPoint._view.y);
+ }, function(previousPoint, point) {
+ // If we skipped the last point, move up to our point preventing a line from being drawn
+ ctx.moveTo(point._view.x, point._view.y);
+ });
+ }
+ }, this);
+
+ if (this._loop && this._children.length > 0) {
+ loopBackToStart();
+ }
+
+ ctx.stroke();
+ ctx.restore();
+ },
+ });
+
+}).call(this);
+
+/*!
+ * Chart.js
+ * http://chartjs.org/
+ * Version: 2.0.0-beta2
+ *
+ * Copyright 2015 Nick Downie
+ * Released under the MIT license
+ * https://github.com/nnnick/Chart.js/blob/master/LICENSE.md
+ */
+
+
+(function() {
+
+ "use strict";
+
+ var root = this,
+ Chart = root.Chart,
+ helpers = Chart.helpers;
+
+ Chart.defaults.global.elements.point = {
+ radius: 3,
+ backgroundColor: Chart.defaults.global.defaultColor,
+ borderWidth: 1,
+ borderColor: Chart.defaults.global.defaultColor,
+ // Hover
+ hitRadius: 1,
+ hoverRadius: 4,
+ hoverBorderWidth: 1,
+ };
+
+
+ Chart.elements.Point = Chart.Element.extend({
+ inRange: function(mouseX, mouseY) {
+ var vm = this._view;
+
+ if (vm) {
+ var hoverRange = vm.hitRadius + vm.radius;
+ return ((Math.pow(mouseX - vm.x, 2) + Math.pow(mouseY - vm.y, 2)) < Math.pow(hoverRange, 2));
+ } else {
+ return false;
+ }
+ },
+ inLabelRange: function(mouseX) {
+ var vm = this._view;
+
+ if (vm) {
+ return (Math.pow(mouseX - vm.x, 2) < Math.pow(vm.radius + vm.hitRadius, 2));
+ } else {
+ return false;
+ }
+ },
+ tooltipPosition: function() {
+ var vm = this._view;
+ return {
+ x: vm.x,
+ y: vm.y,
+ padding: vm.radius + vm.borderWidth
+ };
+ },
+ draw: function() {
+
+ var vm = this._view;
+ var ctx = this._chart.ctx;
+
+
+ if (vm.skip) {
+ return;
+ }
+
+ if (vm.radius > 0 || vm.borderWidth > 0) {
+
+ ctx.beginPath();
+
+ ctx.arc(vm.x, vm.y, vm.radius || Chart.defaults.global.elements.point.radius, 0, Math.PI * 2);
+ ctx.closePath();
+
+ ctx.strokeStyle = vm.borderColor || Chart.defaults.global.defaultColor;
+ ctx.lineWidth = vm.borderWidth || Chart.defaults.global.elements.point.borderWidth;
+
+ ctx.fillStyle = vm.backgroundColor || Chart.defaults.global.defaultColor;
+
+ ctx.fill();
+ ctx.stroke();
+ }
+ }
+ });
+
+
+}).call(this);
+
+(function() {
+
+ "use strict";
+
+ var root = this,
+ Chart = root.Chart,
+ helpers = Chart.helpers;
+
+ Chart.defaults.global.elements.rectangle = {
+ backgroundColor: Chart.defaults.global.defaultColor,
+ borderWidth: 0,
+ borderColor: Chart.defaults.global.defaultColor,
+ };
+
+ Chart.elements.Rectangle = Chart.Element.extend({
+ draw: function() {
+
+ var ctx = this._chart.ctx;
+ var vm = this._view;
+
+ var halfWidth = vm.width / 2,
+ leftX = vm.x - halfWidth,
+ rightX = vm.x + halfWidth,
+ top = vm.base - (vm.base - vm.y),
+ halfStroke = vm.borderWidth / 2;
+
+ // Canvas doesn't allow us to stroke inside the width so we can
+ // adjust the sizes to fit if we're setting a stroke on the line
+ if (vm.borderWidth) {
+ leftX += halfStroke;
+ rightX -= halfStroke;
+ top += halfStroke;
+ }
+
+ ctx.beginPath();
+
+ ctx.fillStyle = vm.backgroundColor;
+ ctx.strokeStyle = vm.borderColor;
+ ctx.lineWidth = vm.borderWidth;
+
+ // It'd be nice to keep this class totally generic to any rectangle
+ // and simply specify which border to miss out.
+ ctx.moveTo(leftX, vm.base);
+ ctx.lineTo(leftX, top);
+ ctx.lineTo(rightX, top);
+ ctx.lineTo(rightX, vm.base);
+ ctx.fill();
+ if (vm.borderWidth) {
+ ctx.stroke();
+ }
+ },
+ height: function() {
+ var vm = this._view;
+ return vm.base - vm.y;
+ },
+ inRange: function(mouseX, mouseY) {
+ var vm = this._view;
+ var inRange = false;
+
+ if (vm) {
+ if (vm.y < vm.base) {
+ inRange = (mouseX >= vm.x - vm.width / 2 && mouseX <= vm.x + vm.width / 2) && (mouseY >= vm.y && mouseY <= vm.base);
+ } else {
+ inRange = (mouseX >= vm.x - vm.width / 2 && mouseX <= vm.x + vm.width / 2) && (mouseY >= vm.base && mouseY <= vm.y);
+ }
+ }
+
+ return inRange;
+ },
+ inLabelRange: function(mouseX) {
+ var vm = this._view;
+
+ if (vm) {
+ return (mouseX >= vm.x - vm.width / 2 && mouseX <= vm.x + vm.width / 2);
+ } else {
+ return false;
+ }
+ },
+ tooltipPosition: function() {
+ var vm = this._view;
+ return {
+ x: vm.x,
+ y: vm.y
+ };
+ },
+ });
+
+
+
+}).call(this);
+
+(function() {
+ "use strict";
+
+ var root = this;
+ var Chart = root.Chart;
+ var helpers = Chart.helpers;
+
+ Chart.Bar = function(context, config) {
+ config.type = 'bar';
+
+ return new Chart(context, config);
+ };
+
+}).call(this);
+
+(function() {
+ "use strict";
+
+ var root = this;
+ var Chart = root.Chart;
+ var helpers = Chart.helpers;
+
+ var defaultConfig = {
+ hover: {
+ mode: 'single',
+ },
+
+ scales: {
+ xAxes: [{
+ type: "linear", // bubble should probably use a linear scale by default
+ position: "bottom",
+ id: "x-axis-0", // need an ID so datasets can reference the scale
+ }],
+ yAxes: [{
+ type: "linear",
+ position: "left",
+ id: "y-axis-0",
+ }],
+ },
+
+ tooltips: {
+ callbacks: {
+ title: function(tooltipItems, data) {
+ // Title doesn't make sense for scatter since we format the data as a point
+ return '';
+ },
+ label: function(tooltipItem, data) {
+ return '(' + tooltipItem.xLabel + ', ' + tooltipItem.yLabel + ')';
+ }
+ }
+ },
+
+ };
+
+ // Register the default config for this type
+ Chart.defaults.bubble = defaultConfig;
+
+ Chart.Bubble = function(context, config) {
+ config.type = 'bubble';
+ return new Chart(context, config);
+ };
+
+}).call(this);
+
+(function() {
+ "use strict";
+
+ var root = this;
+ var Chart = root.Chart;
+ var helpers = Chart.helpers;
+
+ Chart.Doughnut = function(context, config) {
+ config.type = 'doughnut';
+
+ return new Chart(context, config);
+ };
+
+}).call(this);
+
+(function() {
+ "use strict";
+
+ var root = this;
+ var Chart = root.Chart;
+ var helpers = Chart.helpers;
+
+ Chart.Line = function(context, config) {
+ config.type = 'line';
+
+ return new Chart(context, config);
+ };
+
+}).call(this);
+
+(function() {
+ "use strict";
+
+ var root = this;
+ var Chart = root.Chart;
+ var helpers = Chart.helpers;
+
+ Chart.PolarArea = function(context, config) {
+ config.type = 'polarArea';
+
+ return new Chart(context, config);
+ };
+
+}).call(this);
+
+(function() {
+ "use strict";
+
+ var root = this;
+ var Chart = root.Chart;
+ var helpers = Chart.helpers;
+
+ var defaultConfig = {
+ aspectRatio: 1,
+ };
+
+ Chart.Radar = function(context, config) {
+ config.options = helpers.configMerge(defaultConfig, config.options);
+ config.type = 'radar';
+
+ return new Chart(context, config);
+ };
+
+}).call(this);
+
+(function() {
+ "use strict";
+
+ var root = this;
+ var Chart = root.Chart;
+ var helpers = Chart.helpers;
+
+ var defaultConfig = {
+ hover: {
+ mode: 'single',
+ },
+
+ scales: {
+ xAxes: [{
+ type: "linear", // scatter should not use a category axis
+ position: "bottom",
+ id: "x-axis-1", // need an ID so datasets can reference the scale
+ }],
+ yAxes: [{
+ type: "linear",
+ position: "left",
+ id: "y-axis-1",
+ }],
+ },
+
+ tooltips: {
+ callbacks: {
+ title: function(tooltipItems, data) {
+ // Title doesn't make sense for scatter since we format the data as a point
+ return '';
+ },
+ label: function(tooltipItem, data) {
+ return '(' + tooltipItem.xLabel + ', ' + tooltipItem.yLabel + ')';
+ }
+ }
+ },
+ };
+
+ // Register the default config for this type
+ Chart.defaults.scatter = defaultConfig;
+
+ // Scatter charts use line controllers
+ Chart.controllers.scatter = Chart.controllers.line;
+
+ Chart.Scatter = function(context, config) {
+ config.type = 'scatter';
+ return new Chart(context, config);
+ };
+
+}).call(this);
+return Chart;
+}));
diff --git a/public/vendor/chartjs/Chart.min.js b/public/vendor/chartjs/Chart.min.js
index ab635881..7c7cdf74 100644
--- a/public/vendor/chartjs/Chart.min.js
+++ b/public/vendor/chartjs/Chart.min.js
@@ -1,39 +1,41 @@
-var Chart=function(s){function v(a,c,b){a=A((a-c.graphMin)/(c.steps*c.stepValue),1,0);return b*c.steps*a}function x(a,c,b,e){function h(){g+=f;var k=a.animation?A(d(g),null,0):1;e.clearRect(0,0,q,u);a.scaleOverlay?(b(k),c()):(c(),b(k));if(1>=g)D(h);else if("function"==typeof a.onAnimationComplete)a.onAnimationComplete()}var f=a.animation?1/A(a.animationSteps,Number.MAX_VALUE,1):1,d=B[a.animationEasing],g=a.animation?0:1;"function"!==typeof c&&(c=function(){});D(h)}function C(a,c,b,e,h,f){var d;a=
-Math.floor(Math.log(e-h)/Math.LN10);h=Math.floor(h/(1*Math.pow(10,a)))*Math.pow(10,a);e=Math.ceil(e/(1*Math.pow(10,a)))*Math.pow(10,a)-h;a=Math.pow(10,a);for(d=Math.round(e/a);dc;)a=dc?c:!isNaN(parseFloat(b))&&
-isFinite(b)&&a)[^\t]*)'/g,"$1\r").replace(/\t=(.*?)%>/g,"',$1,'").split("\t").join("');").split("%>").join("p.push('").split("\r").join("\\'")+"');}return p.join('');");return c?
-b(c):b}var r=this,B={linear:function(a){return a},easeInQuad:function(a){return a*a},easeOutQuad:function(a){return-1*a*(a-2)},easeInOutQuad:function(a){return 1>(a/=0.5)?0.5*a*a:-0.5*(--a*(a-2)-1)},easeInCubic:function(a){return a*a*a},easeOutCubic:function(a){return 1*((a=a/1-1)*a*a+1)},easeInOutCubic:function(a){return 1>(a/=0.5)?0.5*a*a*a:0.5*((a-=2)*a*a+2)},easeInQuart:function(a){return a*a*a*a},easeOutQuart:function(a){return-1*((a=a/1-1)*a*a*a-1)},easeInOutQuart:function(a){return 1>(a/=0.5)?
-0.5*a*a*a*a:-0.5*((a-=2)*a*a*a-2)},easeInQuint:function(a){return 1*(a/=1)*a*a*a*a},easeOutQuint:function(a){return 1*((a=a/1-1)*a*a*a*a+1)},easeInOutQuint:function(a){return 1>(a/=0.5)?0.5*a*a*a*a*a:0.5*((a-=2)*a*a*a*a+2)},easeInSine:function(a){return-1*Math.cos(a/1*(Math.PI/2))+1},easeOutSine:function(a){return 1*Math.sin(a/1*(Math.PI/2))},easeInOutSine:function(a){return-0.5*(Math.cos(Math.PI*a/1)-1)},easeInExpo:function(a){return 0==a?1:1*Math.pow(2,10*(a/1-1))},easeOutExpo:function(a){return 1==
-a?1:1*(-Math.pow(2,-10*a/1)+1)},easeInOutExpo:function(a){return 0==a?0:1==a?1:1>(a/=0.5)?0.5*Math.pow(2,10*(a-1)):0.5*(-Math.pow(2,-10*--a)+2)},easeInCirc:function(a){return 1<=a?a:-1*(Math.sqrt(1-(a/=1)*a)-1)},easeOutCirc:function(a){return 1*Math.sqrt(1-(a=a/1-1)*a)},easeInOutCirc:function(a){return 1>(a/=0.5)?-0.5*(Math.sqrt(1-a*a)-1):0.5*(Math.sqrt(1-(a-=2)*a)+1)},easeInElastic:function(a){var c=1.70158,b=0,e=1;if(0==a)return 0;if(1==(a/=1))return 1;b||(b=0.3);ea?-0.5*e*Math.pow(2,10*
-(a-=1))*Math.sin((1*a-c)*2*Math.PI/b):0.5*e*Math.pow(2,-10*(a-=1))*Math.sin((1*a-c)*2*Math.PI/b)+1},easeInBack:function(a){return 1*(a/=1)*a*(2.70158*a-1.70158)},easeOutBack:function(a){return 1*((a=a/1-1)*a*(2.70158*a+1.70158)+1)},easeInOutBack:function(a){var c=1.70158;return 1>(a/=0.5)?0.5*a*a*(((c*=1.525)+1)*a-c):0.5*((a-=2)*a*(((c*=1.525)+1)*a+c)+2)},easeInBounce:function(a){return 1-B.easeOutBounce(1-a)},easeOutBounce:function(a){return(a/=1)<1/2.75?1*7.5625*a*a:a<2/2.75?1*(7.5625*(a-=1.5/2.75)*
-a+0.75):a<2.5/2.75?1*(7.5625*(a-=2.25/2.75)*a+0.9375):1*(7.5625*(a-=2.625/2.75)*a+0.984375)},easeInOutBounce:function(a){return 0.5>a?0.5*B.easeInBounce(2*a):0.5*B.easeOutBounce(2*a-1)+0.5}},q=s.canvas.width,u=s.canvas.height;window.devicePixelRatio&&(s.canvas.style.width=q+"px",s.canvas.style.height=u+"px",s.canvas.height=u*window.devicePixelRatio,s.canvas.width=q*window.devicePixelRatio,s.scale(window.devicePixelRatio,window.devicePixelRatio));this.PolarArea=function(a,c){r.PolarArea.defaults={scaleOverlay:!0,
-scaleOverride:!1,scaleSteps:null,scaleStepWidth:null,scaleStartValue:null,scaleShowLine:!0,scaleLineColor:"rgba(0,0,0,.1)",scaleLineWidth:1,scaleShowLabels:!0,scaleLabel:"<%=value%>",scaleFontFamily:"'Arial'",scaleFontSize:12,scaleFontStyle:"normal",scaleFontColor:"#666",scaleShowLabelBackdrop:!0,scaleBackdropColor:"rgba(255,255,255,0.75)",scaleBackdropPaddingY:2,scaleBackdropPaddingX:2,segmentShowStroke:!0,segmentStrokeColor:"#fff",segmentStrokeWidth:2,animation:!0,animationSteps:100,animationEasing:"easeOutBounce",
-animateRotate:!0,animateScale:!1,onAnimationComplete:null};var b=c?y(r.PolarArea.defaults,c):r.PolarArea.defaults;return new G(a,b,s)};this.Radar=function(a,c){r.Radar.defaults={scaleOverlay:!1,scaleOverride:!1,scaleSteps:null,scaleStepWidth:null,scaleStartValue:null,scaleShowLine:!0,scaleLineColor:"rgba(0,0,0,.1)",scaleLineWidth:1,scaleShowLabels:!1,scaleLabel:"<%=value%>",scaleFontFamily:"'Arial'",scaleFontSize:12,scaleFontStyle:"normal",scaleFontColor:"#666",scaleShowLabelBackdrop:!0,scaleBackdropColor:"rgba(255,255,255,0.75)",
-scaleBackdropPaddingY:2,scaleBackdropPaddingX:2,angleShowLineOut:!0,angleLineColor:"rgba(0,0,0,.1)",angleLineWidth:1,pointLabelFontFamily:"'Arial'",pointLabelFontStyle:"normal",pointLabelFontSize:12,pointLabelFontColor:"#666",pointDot:!0,pointDotRadius:3,pointDotStrokeWidth:1,datasetStroke:!0,datasetStrokeWidth:2,datasetFill:!0,animation:!0,animationSteps:60,animationEasing:"easeOutQuart",onAnimationComplete:null};var b=c?y(r.Radar.defaults,c):r.Radar.defaults;return new H(a,b,s)};this.Pie=function(a,
-c){r.Pie.defaults={segmentShowStroke:!0,segmentStrokeColor:"#fff",segmentStrokeWidth:2,animation:!0,animationSteps:100,animationEasing:"easeOutBounce",animateRotate:!0,animateScale:!1,onAnimationComplete:null};var b=c?y(r.Pie.defaults,c):r.Pie.defaults;return new I(a,b,s)};this.Doughnut=function(a,c){r.Doughnut.defaults={segmentShowStroke:!0,segmentStrokeColor:"#fff",segmentStrokeWidth:2,percentageInnerCutout:50,animation:!0,animationSteps:100,animationEasing:"easeOutBounce",animateRotate:!0,animateScale:!1,
-onAnimationComplete:null};var b=c?y(r.Doughnut.defaults,c):r.Doughnut.defaults;return new J(a,b,s)};this.Line=function(a,c){r.Line.defaults={scaleOverlay:!1,scaleOverride:!1,scaleSteps:null,scaleStepWidth:null,scaleStartValue:null,scaleLineColor:"rgba(0,0,0,.1)",scaleLineWidth:1,scaleShowLabels:!0,scaleLabel:"<%=value%>",scaleFontFamily:"'Arial'",scaleFontSize:12,scaleFontStyle:"normal",scaleFontColor:"#666",scaleShowGridLines:!0,scaleGridLineColor:"rgba(0,0,0,.05)",scaleGridLineWidth:1,bezierCurve:!0,
-pointDot:!0,pointDotRadius:4,pointDotStrokeWidth:2,datasetStroke:!0,datasetStrokeWidth:2,datasetFill:!0,animation:!0,animationSteps:60,animationEasing:"easeOutQuart",onAnimationComplete:null};var b=c?y(r.Line.defaults,c):r.Line.defaults;return new K(a,b,s)};this.Bar=function(a,c){r.Bar.defaults={scaleOverlay:!1,scaleOverride:!1,scaleSteps:null,scaleStepWidth:null,scaleStartValue:null,scaleLineColor:"rgba(0,0,0,.1)",scaleLineWidth:1,scaleShowLabels:!0,scaleLabel:"<%=value%>",scaleFontFamily:"'Arial'",
-scaleFontSize:12,scaleFontStyle:"normal",scaleFontColor:"#666",scaleShowGridLines:!0,scaleGridLineColor:"rgba(0,0,0,.05)",scaleGridLineWidth:1,barShowStroke:!0,barStrokeWidth:2,barValueSpacing:5,barDatasetSpacing:1,animation:!0,animationSteps:60,animationEasing:"easeOutQuart",onAnimationComplete:null};var b=c?y(r.Bar.defaults,c):r.Bar.defaults;return new L(a,b,s)};var G=function(a,c,b){var e,h,f,d,g,k,j,l,m;g=Math.min.apply(Math,[q,u])/2;g-=Math.max.apply(Math,[0.5*c.scaleFontSize,0.5*c.scaleLineWidth]);
-d=2*c.scaleFontSize;c.scaleShowLabelBackdrop&&(d+=2*c.scaleBackdropPaddingY,g-=1.5*c.scaleBackdropPaddingY);l=g;d=d?d:5;e=Number.MIN_VALUE;h=Number.MAX_VALUE;for(f=0;fe&&(e=a[f].value),a[f].valuel&&(l=h);g-=Math.max.apply(Math,[l,1.5*(c.pointLabelFontSize/2)]);g-=c.pointLabelFontSize;l=g=A(g,null,0);d=d?d:5;e=Number.MIN_VALUE;
-h=Number.MAX_VALUE;for(f=0;fe&&(e=a.datasets[f].data[m]),a.datasets[f].data[m]Math.PI?"right":"left";b.textBaseline="middle";b.fillText(a.labels[d],f,-h)}b.restore()},function(d){var e=2*Math.PI/a.datasets[0].data.length;b.save();b.translate(q/2,u/2);for(var g=0;gt?e:t;q/a.labels.lengthe&&(e=a.datasets[f].data[l]),a.datasets[f].data[l]d?h:d;d+=10}r=q-d-t;m=Math.floor(r/(a.labels.length-1));n=q-t/2-r;p=g+c.scaleFontSize/2;x(c,function(){b.lineWidth=c.scaleLineWidth;b.strokeStyle=c.scaleLineColor;b.beginPath();b.moveTo(q-t/2+5,p);b.lineTo(q-t/2-r-5,p);b.stroke();0t?e:t;q/a.labels.lengthe&&(e=a.datasets[f].data[l]),a.datasets[f].data[l]<
-h&&(h=a.datasets[f].data[l]);f=Math.floor(g/(0.66*d));d=Math.floor(0.5*(g/d));l=c.scaleShowLabels?c.scaleLabel:"";c.scaleOverride?(j={steps:c.scaleSteps,stepValue:c.scaleStepWidth,graphMin:c.scaleStartValue,labels:[]},z(l,j.labels,j.steps,c.scaleStartValue,c.scaleStepWidth)):j=C(g,f,d,e,h,l);k=Math.floor(g/j.steps);d=1;if(c.scaleShowLabels){b.font=c.scaleFontStyle+" "+c.scaleFontSize+"px "+c.scaleFontFamily;for(e=0;ed?h:d;d+=10}r=q-d-t;m=
-Math.floor(r/a.labels.length);s=(m-2*c.scaleGridLineWidth-2*c.barValueSpacing-(c.barDatasetSpacing*a.datasets.length-1)-(c.barStrokeWidth/2*a.datasets.length-1))/a.datasets.length;n=q-t/2-r;p=g+c.scaleFontSize/2;x(c,function(){b.lineWidth=c.scaleLineWidth;b.strokeStyle=c.scaleLineColor;b.beginPath();b.moveTo(q-t/2+5,p);b.lineTo(q-t/2-r-5,p);b.stroke();0=a?a/12.92:Math.pow((a+.055)/1.055,2.4)}return.2126*e[0]+.7152*e[1]+.0722*e[2]},contrast:function(t){var e=this.luminosity(),i=t.luminosity();return e>i?(e+.05)/(i+.05):(i+.05)/(e+.05)},level:function(t){var e=this.contrast(t);return e>=7.1?"AAA":e>=4.5?"AA":""},dark:function(){var t=this.values.rgb,e=(299*t[0]+587*t[1]+114*t[2])/1e3;return 128>e},light:function(){return!this.dark()},negate:function(){for(var t=[],e=0;3>e;e++)t[e]=255-this.values.rgb[e];return this.setValues("rgb",t),this},lighten:function(t){return this.values.hsl[2]+=this.values.hsl[2]*t,this.setValues("hsl",this.values.hsl),this},darken:function(t){return this.values.hsl[2]-=this.values.hsl[2]*t,this.setValues("hsl",this.values.hsl),this},saturate:function(t){return this.values.hsl[1]+=this.values.hsl[1]*t,this.setValues("hsl",this.values.hsl),this},desaturate:function(t){return this.values.hsl[1]-=this.values.hsl[1]*t,this.setValues("hsl",this.values.hsl),this},whiten:function(t){return this.values.hwb[1]+=this.values.hwb[1]*t,this.setValues("hwb",this.values.hwb),this},blacken:function(t){return this.values.hwb[2]+=this.values.hwb[2]*t,this.setValues("hwb",this.values.hwb),this},greyscale:function(){var t=this.values.rgb,e=.3*t[0]+.59*t[1]+.11*t[2];return this.setValues("rgb",[e,e,e]),this},clearer:function(t){return this.setValues("alpha",this.values.alpha-this.values.alpha*t),this},opaquer:function(t){return this.setValues("alpha",this.values.alpha+this.values.alpha*t),this},rotate:function(t){var e=this.values.hsl[0];return e=(e+t)%360,e=0>e?360+e:e,this.values.hsl[0]=e,this.setValues("hsl",this.values.hsl),this},mix:function(t,e){e=1-(null==e?.5:e);for(var i=2*e-1,a=this.alpha()-t.alpha(),s=((i*a==-1?i:(i+a)/(1+i*a))+1)/2,o=1-s,n=this.rgbArray(),r=t.rgbArray(),h=0;he&&(e+=360),a=(r+h)/2,i=h==r?0:.5>=a?l/(h+r):l/(2-h-r),[e,100*i,100*a]}function s(t){var e,i,a,s=t[0],o=t[1],n=t[2],r=Math.min(s,o,n),h=Math.max(s,o,n),l=h-r;return i=0==h?0:l/h*1e3/10,h==r?e=0:s==h?e=(o-n)/l:o==h?e=2+(n-s)/l:n==h&&(e=4+(s-o)/l),e=Math.min(60*e,360),0>e&&(e+=360),a=h/255*1e3/10,[e,i,a]}function o(t){var e=t[0],i=t[1],s=t[2],o=a(t)[0],n=1/255*Math.min(e,Math.min(i,s)),s=1-1/255*Math.max(e,Math.max(i,s));return[o,100*n,100*s]}function n(t){var e,i,a,s,o=t[0]/255,n=t[1]/255,r=t[2]/255;return s=Math.min(1-o,1-n,1-r),e=(1-o-s)/(1-s)||0,i=(1-n-s)/(1-s)||0,a=(1-r-s)/(1-s)||0,[100*e,100*i,100*a,100*s]}function h(t){return G[JSON.stringify(t)]}function l(t){var e=t[0]/255,i=t[1]/255,a=t[2]/255;e=e>.04045?Math.pow((e+.055)/1.055,2.4):e/12.92,i=i>.04045?Math.pow((i+.055)/1.055,2.4):i/12.92,a=a>.04045?Math.pow((a+.055)/1.055,2.4):a/12.92;var s=.4124*e+.3576*i+.1805*a,o=.2126*e+.7152*i+.0722*a,n=.0193*e+.1192*i+.9505*a;return[100*s,100*o,100*n]}function c(t){var e,i,a,s=l(t),o=s[0],n=s[1],r=s[2];return o/=95.047,n/=100,r/=108.883,o=o>.008856?Math.pow(o,1/3):7.787*o+16/116,n=n>.008856?Math.pow(n,1/3):7.787*n+16/116,r=r>.008856?Math.pow(r,1/3):7.787*r+16/116,e=116*n-16,i=500*(o-n),a=200*(n-r),[e,i,a]}function d(t){return B(c(t))}function u(t){var e,i,a,s,o,n=t[0]/360,r=t[1]/100,h=t[2]/100;if(0==r)return o=255*h,[o,o,o];i=.5>h?h*(1+r):h+r-h*r,e=2*h-i,s=[0,0,0];for(var l=0;3>l;l++)a=n+1/3*-(l-1),0>a&&a++,a>1&&a--,o=1>6*a?e+6*(i-e)*a:1>2*a?i:2>3*a?e+(i-e)*(2/3-a)*6:e,s[l]=255*o;return s}function m(t){var e,i,a=t[0],s=t[1]/100,o=t[2]/100;return o*=2,s*=1>=o?o:2-o,i=(o+s)/2,e=2*s/(o+s),[a,100*e,100*i]}function f(t){return o(u(t))}function p(t){return n(u(t))}function x(t){return h(u(t))}function v(t){var e=t[0]/60,i=t[1]/100,a=t[2]/100,s=Math.floor(e)%6,o=e-Math.floor(e),n=255*a*(1-i),r=255*a*(1-i*o),h=255*a*(1-i*(1-o)),a=255*a;switch(s){case 0:return[a,h,n];case 1:return[r,a,n];case 2:return[n,a,h];case 3:return[n,r,a];case 4:return[h,n,a];case 5:return[a,n,r]}}function y(t){var e,i,a=t[0],s=t[1]/100,o=t[2]/100;return i=(2-s)*o,e=s*o,e/=1>=i?i:2-i,e=e||0,i/=2,[a,100*e,100*i]}function k(t){return o(v(t))}function C(t){return n(v(t))}function D(t){return h(v(t))}function S(t){var e,i,a,s,o=t[0]/360,n=t[1]/100,h=t[2]/100,l=n+h;switch(l>1&&(n/=l,h/=l),e=Math.floor(6*o),i=1-h,a=6*o-e,0!=(1&e)&&(a=1-a),s=n+a*(i-n),e){default:case 6:case 0:r=i,g=s,b=n;break;case 1:r=s,g=i,b=n;break;case 2:r=n,g=i,b=s;break;case 3:r=n,g=s,b=i;break;case 4:r=s,g=n,b=i;break;case 5:r=i,g=n,b=s}return[255*r,255*g,255*b]}function w(t){return a(S(t))}function _(t){return s(S(t))}function A(t){return n(S(t))}function M(t){return h(S(t))}function I(t){var e,i,a,s=t[0]/100,o=t[1]/100,n=t[2]/100,r=t[3]/100;return e=1-Math.min(1,s*(1-r)+r),i=1-Math.min(1,o*(1-r)+r),a=1-Math.min(1,n*(1-r)+r),[255*e,255*i,255*a]}function P(t){return a(I(t))}function F(t){return s(I(t))}function R(t){return o(I(t))}function T(t){return h(I(t))}function z(t){var e,i,a,s=t[0]/100,o=t[1]/100,n=t[2]/100;return e=3.2406*s+-1.5372*o+n*-.4986,i=s*-.9689+1.8758*o+.0415*n,a=.0557*s+o*-.204+1.057*n,e=e>.0031308?1.055*Math.pow(e,1/2.4)-.055:e=12.92*e,i=i>.0031308?1.055*Math.pow(i,1/2.4)-.055:i=12.92*i,a=a>.0031308?1.055*Math.pow(a,1/2.4)-.055:a=12.92*a,e=Math.min(Math.max(0,e),1),i=Math.min(Math.max(0,i),1),a=Math.min(Math.max(0,a),1),[255*e,255*i,255*a]}function W(t){var e,i,a,s=t[0],o=t[1],n=t[2];return s/=95.047,o/=100,n/=108.883,s=s>.008856?Math.pow(s,1/3):7.787*s+16/116,o=o>.008856?Math.pow(o,1/3):7.787*o+16/116,n=n>.008856?Math.pow(n,1/3):7.787*n+16/116,e=116*o-16,i=500*(s-o),a=200*(o-n),[e,i,a]}function L(t){return B(W(t))}function V(t){var e,i,a,s,o=t[0],n=t[1],r=t[2];return 8>=o?(i=100*o/903.3,s=7.787*(i/100)+16/116):(i=100*Math.pow((o+16)/116,3),s=Math.pow(i/100,1/3)),e=.008856>=e/95.047?e=95.047*(n/500+s-16/116)/7.787:95.047*Math.pow(n/500+s,3),a=.008859>=a/108.883?a=108.883*(s-r/200-16/116)/7.787:108.883*Math.pow(s-r/200,3),[e,i,a]}function B(t){var e,i,a,s=t[0],o=t[1],n=t[2];return e=Math.atan2(n,o),i=360*e/2/Math.PI,0>i&&(i+=360),a=Math.sqrt(o*o+n*n),[s,a,i]}function O(t){return z(V(t))}function N(t){var e,i,a,s=t[0],o=t[1],n=t[2];return a=n/360*2*Math.PI,e=o*Math.cos(a),i=o*Math.sin(a),[s,e,i]}function H(t){return V(N(t))}function E(t){return O(N(t))}function j(t){return Q[t]}function q(t){return a(j(t))}function U(t){return s(j(t))}function Y(t){return o(j(t))}function J(t){return n(j(t))}function Z(t){return c(j(t))}function X(t){return l(j(t))}e.exports={rgb2hsl:a,rgb2hsv:s,rgb2hwb:o,rgb2cmyk:n,rgb2keyword:h,rgb2xyz:l,rgb2lab:c,rgb2lch:d,hsl2rgb:u,hsl2hsv:m,hsl2hwb:f,hsl2cmyk:p,hsl2keyword:x,hsv2rgb:v,hsv2hsl:y,hsv2hwb:k,hsv2cmyk:C,hsv2keyword:D,hwb2rgb:S,hwb2hsl:w,hwb2hsv:_,hwb2cmyk:A,hwb2keyword:M,cmyk2rgb:I,cmyk2hsl:P,cmyk2hsv:F,cmyk2hwb:R,cmyk2keyword:T,keyword2rgb:j,keyword2hsl:q,keyword2hsv:U,keyword2hwb:Y,keyword2cmyk:J,keyword2lab:Z,keyword2xyz:X,xyz2rgb:z,xyz2lab:W,xyz2lch:L,lab2xyz:V,lab2rgb:O,lab2lch:B,lch2lab:N,lch2xyz:H,lch2rgb:E};var Q={aliceblue:[240,248,255],antiquewhite:[250,235,215],aqua:[0,255,255],aquamarine:[127,255,212],azure:[240,255,255],beige:[245,245,220],bisque:[255,228,196],black:[0,0,0],blanchedalmond:[255,235,205],blue:[0,0,255],blueviolet:[138,43,226],brown:[165,42,42],burlywood:[222,184,135],cadetblue:[95,158,160],chartreuse:[127,255,0],chocolate:[210,105,30],coral:[255,127,80],cornflowerblue:[100,149,237],cornsilk:[255,248,220],crimson:[220,20,60],cyan:[0,255,255],darkblue:[0,0,139],darkcyan:[0,139,139],darkgoldenrod:[184,134,11],darkgray:[169,169,169],darkgreen:[0,100,0],darkgrey:[169,169,169],darkkhaki:[189,183,107],darkmagenta:[139,0,139],darkolivegreen:[85,107,47],darkorange:[255,140,0],darkorchid:[153,50,204],darkred:[139,0,0],darksalmon:[233,150,122],darkseagreen:[143,188,143],darkslateblue:[72,61,139],darkslategray:[47,79,79],darkslategrey:[47,79,79],darkturquoise:[0,206,209],darkviolet:[148,0,211],deeppink:[255,20,147],deepskyblue:[0,191,255],dimgray:[105,105,105],dimgrey:[105,105,105],dodgerblue:[30,144,255],firebrick:[178,34,34],floralwhite:[255,250,240],forestgreen:[34,139,34],fuchsia:[255,0,255],gainsboro:[220,220,220],ghostwhite:[248,248,255],gold:[255,215,0],goldenrod:[218,165,32],gray:[128,128,128],green:[0,128,0],greenyellow:[173,255,47],grey:[128,128,128],honeydew:[240,255,240],hotpink:[255,105,180],indianred:[205,92,92],indigo:[75,0,130],ivory:[255,255,240],khaki:[240,230,140],lavender:[230,230,250],lavenderblush:[255,240,245],lawngreen:[124,252,0],lemonchiffon:[255,250,205],lightblue:[173,216,230],lightcoral:[240,128,128],lightcyan:[224,255,255],lightgoldenrodyellow:[250,250,210],lightgray:[211,211,211],lightgreen:[144,238,144],lightgrey:[211,211,211],lightpink:[255,182,193],lightsalmon:[255,160,122],lightseagreen:[32,178,170],lightskyblue:[135,206,250],lightslategray:[119,136,153],lightslategrey:[119,136,153],lightsteelblue:[176,196,222],lightyellow:[255,255,224],lime:[0,255,0],limegreen:[50,205,50],linen:[250,240,230],magenta:[255,0,255],maroon:[128,0,0],mediumaquamarine:[102,205,170],mediumblue:[0,0,205],mediumorchid:[186,85,211],mediumpurple:[147,112,219],mediumseagreen:[60,179,113],mediumslateblue:[123,104,238],mediumspringgreen:[0,250,154],mediumturquoise:[72,209,204],mediumvioletred:[199,21,133],midnightblue:[25,25,112],mintcream:[245,255,250],mistyrose:[255,228,225],moccasin:[255,228,181],navajowhite:[255,222,173],navy:[0,0,128],oldlace:[253,245,230],olive:[128,128,0],olivedrab:[107,142,35],orange:[255,165,0],orangered:[255,69,0],orchid:[218,112,214],palegoldenrod:[238,232,170],palegreen:[152,251,152],paleturquoise:[175,238,238],palevioletred:[219,112,147],papayawhip:[255,239,213],peachpuff:[255,218,185],peru:[205,133,63],pink:[255,192,203],plum:[221,160,221],powderblue:[176,224,230],purple:[128,0,128],rebeccapurple:[102,51,153],red:[255,0,0],rosybrown:[188,143,143],royalblue:[65,105,225],saddlebrown:[139,69,19],salmon:[250,128,114],sandybrown:[244,164,96],seagreen:[46,139,87],seashell:[255,245,238],sienna:[160,82,45],silver:[192,192,192],skyblue:[135,206,235],slateblue:[106,90,205],slategray:[112,128,144],slategrey:[112,128,144],snow:[255,250,250],springgreen:[0,255,127],steelblue:[70,130,180],tan:[210,180,140],teal:[0,128,128],thistle:[216,191,216],tomato:[255,99,71],turquoise:[64,224,208],violet:[238,130,238],wheat:[245,222,179],white:[255,255,255],whitesmoke:[245,245,245],yellow:[255,255,0],yellowgreen:[154,205,50]},G={};for(var $ in Q)G[JSON.stringify(Q[$])]=$},{}],3:[function(t,e,i){var a=t("./conversions"),s=function(){return new l};for(var o in a){s[o+"Raw"]=function(t){return function(e){return"number"==typeof e&&(e=Array.prototype.slice.call(arguments)),a[t](e)}}(o);var n=/(\w+)2(\w+)/.exec(o),r=n[1],h=n[2];s[r]=s[r]||{},s[r][h]=s[o]=function(t){return function(e){"number"==typeof e&&(e=Array.prototype.slice.call(arguments));var i=a[t](e);if("string"==typeof i||void 0===i)return i;for(var s=0;se||t[3]&&t[3]<1?d(t,e):"rgb("+t[0]+", "+t[1]+", "+t[2]+")"}function d(t,e){return void 0===e&&(e=void 0!==t[3]?t[3]:1),"rgba("+t[0]+", "+t[1]+", "+t[2]+", "+e+")"}function u(t,e){if(1>e||t[3]&&t[3]<1)return g(t,e);var i=Math.round(t[0]/255*100),a=Math.round(t[1]/255*100),s=Math.round(t[2]/255*100);return"rgb("+i+"%, "+a+"%, "+s+"%)"}function g(t,e){var i=Math.round(t[0]/255*100),a=Math.round(t[1]/255*100),s=Math.round(t[2]/255*100);return"rgba("+i+"%, "+a+"%, "+s+"%, "+(e||t[3]||1)+")"}function m(t,e){return 1>e||t[3]&&t[3]<1?f(t,e):"hsl("+t[0]+", "+t[1]+"%, "+t[2]+"%)"}function f(t,e){return void 0===e&&(e=void 0!==t[3]?t[3]:1),"hsla("+t[0]+", "+t[1]+"%, "+t[2]+"%, "+e+")"}function p(t,e){return void 0===e&&(e=void 0!==t[3]?t[3]:1),"hwb("+t[0]+", "+t[1]+"%, "+t[2]+"%"+(void 0!==e&&1!==e?", "+e:"")+")"}function b(t){return k[t.slice(0,3)]}function x(t,e,i){return Math.min(Math.max(e,t),i)}function v(t){var e=t.toString(16).toUpperCase();return e.length<2?"0"+e:e}var y=t("color-name");e.exports={getRgba:a,getHsla:s,getRgb:n,getHsl:r,getHwb:o,getAlpha:h,hexString:l,rgbString:c,rgbaString:d,percentString:u,percentaString:g,hslString:m,hslaString:f,hwbString:p,keyword:b};var k={};for(var C in y)k[y[C]]=C},{"color-name":5}],5:[function(t,e,i){e.exports={aliceblue:[240,248,255],antiquewhite:[250,235,215],aqua:[0,255,255],aquamarine:[127,255,212],azure:[240,255,255],beige:[245,245,220],bisque:[255,228,196],black:[0,0,0],blanchedalmond:[255,235,205],blue:[0,0,255],blueviolet:[138,43,226],brown:[165,42,42],burlywood:[222,184,135],cadetblue:[95,158,160],chartreuse:[127,255,0],chocolate:[210,105,30],coral:[255,127,80],cornflowerblue:[100,149,237],cornsilk:[255,248,220],crimson:[220,20,60],cyan:[0,255,255],darkblue:[0,0,139],darkcyan:[0,139,139],darkgoldenrod:[184,134,11],darkgray:[169,169,169],darkgreen:[0,100,0],darkgrey:[169,169,169],darkkhaki:[189,183,107],darkmagenta:[139,0,139],darkolivegreen:[85,107,47],darkorange:[255,140,0],darkorchid:[153,50,204],darkred:[139,0,0],darksalmon:[233,150,122],darkseagreen:[143,188,143],darkslateblue:[72,61,139],darkslategray:[47,79,79],darkslategrey:[47,79,79],darkturquoise:[0,206,209],darkviolet:[148,0,211],deeppink:[255,20,147],deepskyblue:[0,191,255],dimgray:[105,105,105],dimgrey:[105,105,105],dodgerblue:[30,144,255],firebrick:[178,34,34],floralwhite:[255,250,240],forestgreen:[34,139,34],fuchsia:[255,0,255],gainsboro:[220,220,220],ghostwhite:[248,248,255],gold:[255,215,0],goldenrod:[218,165,32],gray:[128,128,128],green:[0,128,0],greenyellow:[173,255,47],grey:[128,128,128],honeydew:[240,255,240],hotpink:[255,105,180],indianred:[205,92,92],indigo:[75,0,130],ivory:[255,255,240],khaki:[240,230,140],lavender:[230,230,250],lavenderblush:[255,240,245],lawngreen:[124,252,0],lemonchiffon:[255,250,205],lightblue:[173,216,230],lightcoral:[240,128,128],lightcyan:[224,255,255],lightgoldenrodyellow:[250,250,210],lightgray:[211,211,211],lightgreen:[144,238,144],lightgrey:[211,211,211],lightpink:[255,182,193],lightsalmon:[255,160,122],lightseagreen:[32,178,170],lightskyblue:[135,206,250],lightslategray:[119,136,153],lightslategrey:[119,136,153],lightsteelblue:[176,196,222],lightyellow:[255,255,224],lime:[0,255,0],limegreen:[50,205,50],linen:[250,240,230],magenta:[255,0,255],maroon:[128,0,0],mediumaquamarine:[102,205,170],mediumblue:[0,0,205],mediumorchid:[186,85,211],mediumpurple:[147,112,219],mediumseagreen:[60,179,113],mediumslateblue:[123,104,238],mediumspringgreen:[0,250,154],mediumturquoise:[72,209,204],mediumvioletred:[199,21,133],midnightblue:[25,25,112],mintcream:[245,255,250],mistyrose:[255,228,225],moccasin:[255,228,181],navajowhite:[255,222,173],navy:[0,0,128],oldlace:[253,245,230],olive:[128,128,0],olivedrab:[107,142,35],orange:[255,165,0],orangered:[255,69,0],orchid:[218,112,214],palegoldenrod:[238,232,170],palegreen:[152,251,152],paleturquoise:[175,238,238],palevioletred:[219,112,147],papayawhip:[255,239,213],peachpuff:[255,218,185],peru:[205,133,63],pink:[255,192,203],plum:[221,160,221],powderblue:[176,224,230],purple:[128,0,128],rebeccapurple:[102,51,153],red:[255,0,0],rosybrown:[188,143,143],royalblue:[65,105,225],saddlebrown:[139,69,19],salmon:[250,128,114],sandybrown:[244,164,96],seagreen:[46,139,87],seashell:[255,245,238],sienna:[160,82,45],silver:[192,192,192],skyblue:[135,206,235],slateblue:[106,90,205],slategray:[112,128,144],slategrey:[112,128,144],snow:[255,250,250],springgreen:[0,255,127],steelblue:[70,130,180],tan:[210,180,140],teal:[0,128,128],thistle:[216,191,216],tomato:[255,99,71],turquoise:[64,224,208],violet:[238,130,238],wheat:[245,222,179],white:[255,255,255],whitesmoke:[245,245,245],yellow:[255,255,0],yellowgreen:[154,205,50]}},{}]},{},[1]),function(){"use strict";var t=this,e=t.Chart,i=function(t,e){this.config=e,t.length&&t[0].getContext&&(t=t[0]),t.getContext&&(t=t.getContext("2d")),this.ctx=t,this.canvas=t.canvas,this.width=t.canvas.width||parseInt(i.helpers.getStyle(t.canvas,"width"))||i.helpers.getMaximumWidth(t.canvas),this.height=t.canvas.height||parseInt(i.helpers.getStyle(t.canvas,"height"))||i.helpers.getMaximumHeight(t.canvas),this.aspectRatio=this.width/this.height,(isNaN(this.aspectRatio)||isFinite(this.aspectRatio)===!1)&&(this.aspectRatio=void 0!==e.aspectRatio?e.aspectRatio:2),this.originalCanvasStyleWidth=t.canvas.style.width,this.originalCanvasStyleHeight=t.canvas.style.height,i.helpers.retinaScale(this),e&&(this.controller=new i.Controller(this));var a=this;return i.helpers.addResizeListener(t.canvas.parentNode,function(){a.controller&&a.controller.config.options.responsive&&a.controller.resize()}),this.controller?this.controller:this};i.defaults={global:{responsive:!0,responsiveAnimationDuration:0,maintainAspectRatio:!0,events:["mousemove","mouseout","click","touchstart","touchmove"],hover:{onHover:null,mode:"single",animationDuration:400},onClick:null,defaultColor:"rgba(0,0,0,0.1)",elements:{},legendCallback:function(t){var e=[];e.push('');for(var i=0;i'),t.data.datasets[i].label&&e.push(t.data.datasets[i].label),e.push(" ");return e.push(" "),e.join("")}}},t.Chart=i,i.noConflict=function(){return t.Chart=e,i}}.call(this),function(){"use strict";var t=this,e=t.Chart,i=e.helpers={},a=i.each=function(t,e,i,a){var s=Array.prototype.slice.call(arguments,3);if(t)if(t.length===+t.length){var o;if(a)for(o=t.length-1;o>=0;o--)e.apply(i,[t[o],o].concat(s));else for(o=0;o=o[s].length||!o[s][a].type?o[s].push(i.configMerge(t.type?e.scaleService.getScaleDefaults(t.type):{},t)):t.type!==o[s][a].type?o[s][a]=i.configMerge(o[s][a],t.type?e.scaleService.getScaleDefaults(t.type):{},t):o[s][a]=i.configMerge(o[s][a],t)}):(o[s]=[],i.each(t,function(t){o[s].push(i.configMerge(t.type?e.scaleService.getScaleDefaults(t.type):{},t))})):o.hasOwnProperty(s)&&"object"==typeof o[s]&&null!==o[s]&&"object"==typeof t?o[s]=i.configMerge(o[s],t):o[s]=t)}),o},i.getValueAtIndexOrDefault=function(t,e,a){return void 0===t||null===t?a:i.isArray(t)?e=0;a--){var s=t[a];if(e(s))return s}},i.inherits=function(t){var e=this,i=t&&t.hasOwnProperty("constructor")?t.constructor:function(){return e.apply(this,arguments)},a=function(){this.constructor=i};return a.prototype=e.prototype,i.prototype=new a,i.extend=n,t&&o(i.prototype,t),i.__super__=e.prototype,i}),r=i.noop=function(){},h=(i.uid=function(){var t=0;return function(){return"chart-"+t++}}(),i.warn=function(t){console&&"function"==typeof console.warn&&console.warn(t)},i.isNumber=function(t){return!isNaN(parseFloat(t))&&isFinite(t)}),l=(i.max=function(t){return Math.max.apply(Math,t)},i.min=function(t){return Math.min.apply(Math,t)},i.sign=function(t){return Math.sign?Math.sign(t):(t=+t,0===t||isNaN(t)?t:t>0?1:-1)},i.log10=function(t){return Math.log10?Math.log10(t):Math.log(t)/Math.LN10},i.getDecimalPlaces=function(t){if(t%1!==0&&h(t)){var e=t.toString();if(e.indexOf("e-")<0)return e.split(".")[1].length;if(e.indexOf(".")<0)return parseInt(e.split("e-")[1]);var i=e.split(".")[1].split("e-");return i[0].length+parseInt(i[1])}return 0},i.toRadians=function(t){return t*(Math.PI/180)},i.toDegrees=function(t){return t*(180/Math.PI)},i.getAngleFromPoint=function(t,e){var i=e.x-t.x,a=e.y-t.y,s=Math.sqrt(i*i+a*a),o=Math.atan2(a,i);return o<-.5*Math.PI&&(o+=2*Math.PI),{angle:o,distance:s}},i.aliasPixel=function(t){return t%2===0?0:.5},i.splineCurve=function(t,e,i,a){var s=t.skip?e:t,o=e,n=i.skip?e:i,r=Math.sqrt(Math.pow(o.x-s.x,2)+Math.pow(o.y-s.y,2)),h=Math.sqrt(Math.pow(n.x-o.x,2)+Math.pow(n.y-o.y,2)),l=r/(r+h),c=h/(r+h);l=isNaN(l)?0:l,c=isNaN(c)?0:c;var d=a*l,u=a*c;return{previous:{x:o.x-d*(n.x-s.x),y:o.y-d*(n.y-s.y)},next:{x:o.x+u*(n.x-s.x),y:o.y+u*(n.y-s.y)}}},i.nextItem=function(t,e,i){return i?e>=t.length-1?t[0]:t[e+1]:e>=t.length-1?t[t.length-1]:t[e+1]},i.previousItem=function(t,e,i){return i?0>=e?t[t.length-1]:t[e-1]:0>=e?t[0]:t[e-1]},i.niceNum=function(t,e){var a,s=Math.floor(i.log10(t)),o=t/Math.pow(10,s);return a=e?1.5>o?1:3>o?2:7>o?5:10:1>=o?1:2>=o?2:5>=o?5:10,a*Math.pow(10,s)},i.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 e=1.70158,i=0,a=1;return 0===t?0:1==(t/=1)?1:(i||(i=.3),at?-.5*(a*Math.pow(2,10*(t-=1))*Math.sin((1*t-e)*(2*Math.PI)/i)):a*Math.pow(2,-10*(t-=1))*Math.sin((1*t-e)*(2*Math.PI)/i)*.5+1)},easeInBack:function(t){var e=1.70158;return 1*(t/=1)*t*((e+1)*t-e)},easeOutBack:function(t){var e=1.70158;return 1*((t=t/1-1)*t*((e+1)*t+e)+1)},easeInOutBack:function(t){var e=1.70158;return(t/=.5)<1?.5*(t*t*(((e*=1.525)+1)*t-e)):.5*((t-=2)*t*(((e*=1.525)+1)*t+e)+2)},easeInBounce:function(t){return 1-l.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*l.easeInBounce(2*t):.5*l.easeOutBounce(2*t-1)+.5}}),c=(i.requestAnimFrame=function(){return window.requestAnimationFrame||window.webkitRequestAnimationFrame||window.mozRequestAnimationFrame||window.oRequestAnimationFrame||window.msRequestAnimationFrame||function(t){return window.setTimeout(t,1e3/60)}}(),i.cancelAnimFrame=function(){return window.cancelAnimationFrame||window.webkitCancelAnimationFrame||window.mozCancelAnimationFrame||window.oCancelAnimationFrame||window.msCancelAnimationFrame||function(t){return window.clearTimeout(t,1e3/60)}}(),i.getRelativePosition=function(t,e){var i,a,s=t.originalEvent||t,o=t.currentTarget||t.srcElement,n=o.getBoundingClientRect();return s.touches&&s.touches.length>0?(i=s.touches[0].clientX,a=s.touches[0].clientY):(i=s.clientX,a=s.clientY),i=Math.round((i-n.left)/(n.right-n.left)*o.width/e.currentDevicePixelRatio),a=Math.round((a-n.top)/(n.bottom-n.top)*o.height/e.currentDevicePixelRatio),{x:i,y:a}},i.addEvent=function(t,e,i){t.addEventListener?t.addEventListener(e,i):t.attachEvent?t.attachEvent("on"+e,i):t["on"+e]=i}),d=i.removeEvent=function(t,e,i){t.removeEventListener?t.removeEventListener(e,i,!1):t.detachEvent?t.detachEvent("on"+e,i):t["on"+e]=r},u=(i.bindEvents=function(t,e,i){t.events||(t.events={}),a(e,function(e){t.events[e]=function(){i.apply(t,arguments)},c(t.chart.canvas,e,t.events[e])})},i.unbindEvents=function(t,e){a(e,function(e,i){d(t.chart.canvas,i,e)})},i.getConstraintWidth=function(t){var e,i=document.defaultView.getComputedStyle(t)["max-width"],a=document.defaultView.getComputedStyle(t.parentNode)["max-width"],s=null!==i&&"none"!==i,o=null!==a&&"none"!==a;return(s||o)&&(e=Math.min(s?parseInt(i,10):Number.POSITIVE_INFINITY,o?parseInt(a,10):Number.POSITIVE_INFINITY)),e}),g=i.getConstraintHeight=function(t){var e,i=document.defaultView.getComputedStyle(t)["max-height"],a=document.defaultView.getComputedStyle(t.parentNode)["max-height"],s=null!==i&&"none"!==i,o=null!==a&&"none"!==a;return(i||a)&&(e=Math.min(s?parseInt(i,10):Number.POSITIVE_INFINITY,o?parseInt(a,10):Number.POSITIVE_INFINITY)),e},m=(i.getMaximumWidth=function(t){var e=t.parentNode,i=parseInt(m(e,"padding-left"))+parseInt(m(e,"padding-right")),a=e.clientWidth-i,s=u(t);return void 0!==s&&(a=Math.min(a,s)),a},i.getMaximumHeight=function(t){var e=t.parentNode,i=parseInt(m(e,"padding-top"))+parseInt(m(e,"padding-bottom")),a=e.clientHeight-i,s=g(t);return void 0!==s&&(a=Math.min(a,s)),a},i.getStyle=function(t,e){return t.currentStyle?t.currentStyle[e]:document.defaultView.getComputedStyle(t,null).getPropertyValue(e)});i.getMaximumSize=i.getMaximumWidth,i.retinaScale=function(t){var e=t.ctx,i=t.canvas.width,a=t.canvas.height,s=t.currentDevicePixelRatio=window.devicePixelRatio||1;1!==s&&(e.canvas.height=a*s,e.canvas.width=i*s,e.scale(s,s),e.canvas.style.width=i+"px",e.canvas.style.height=a+"px",t.originalDevicePixelRatio=t.originalDevicePixelRatio||s)},i.clear=function(t){t.ctx.clearRect(0,0,t.width,t.height)},i.fontString=function(t,e,i){return e+" "+t+"px "+i},i.longestText=function(t,e,i){t.font=e;var s=0;return a(i,function(e){var i=t.measureText(e).width;s=i>s?i:s}),s},i.drawRoundedRectangle=function(t,e,i,a,s,o){t.beginPath(),t.moveTo(e+o,i),t.lineTo(e+a-o,i),t.quadraticCurveTo(e+a,i,e+a,i+o),t.lineTo(e+a,i+s-o),t.quadraticCurveTo(e+a,i+s,e+a-o,i+s),t.lineTo(e+o,i+s),t.quadraticCurveTo(e,i+s,e,i+s-o),t.lineTo(e,i+o),t.quadraticCurveTo(e,i,e+o,i),t.closePath()},i.color=function(e){return t.Color?t.Color(e):(console.log("Color.js not found!"),e)},i.addResizeListener=function(t,e){var i=document.createElement("iframe"),a="chartjs-hidden-iframe";i.classlist?i.classlist.add(a):i.setAttribute("class",a),i.style.width="100%",i.style.display="block",i.style.border=0,i.style.height=0,i.style.margin=0,i.style.position="absolute",i.style.left=0,i.style.right=0,i.style.top=0,i.style.bottom=0,t.insertBefore(i,t.firstChild);(i.contentWindow||i).onresize=function(){e&&e()}},i.removeResizeListener=function(t){var e=t.querySelector(".chartjs-hidden-iframe");e&&e.parentNode.removeChild(e)},i.isArray=function(t){return Array.isArray?Array.isArray(t):"[object Array]"===Object.prototype.toString.call(arg)},i.isDatasetVisible=function(t){return!t.hidden};i.callCallback=function(t,e,i){t&&"function"==typeof t.call&&t.apply(i,e)}}.call(this),function(){"use strict";var t=this,e=t.Chart,i=e.helpers;e.elements={},e.Element=function(t){i.extend(this,t),this.initialize.apply(this,arguments)},i.extend(e.Element.prototype,{initialize:function(){},pivot:function(){return this._view||(this._view=i.clone(this._model)),this._start=i.clone(this._view),this},transition:function(t){return this._view||(this._view=i.clone(this._model)),this._start||this.pivot(),i.each(this._model,function(e,a){if("_"!==a[0]&&this._model.hasOwnProperty(a))if(this._view[a])if(this._model[a]===this._view[a]);else if("string"==typeof e)try{var s=i.color(this._start[a]).mix(i.color(this._model[a]),t);this._view[a]=s.rgbString()}catch(o){this._view[a]=e}else if("number"==typeof e){var n=void 0!==this._start[a]&&isNaN(this._start[a])===!1?this._start[a]:0;this._view[a]=(this._model[a]-n)*t+n}else this._view[a]=e;else"number"==typeof e&&isNaN(this._view[a])===!1?this._view[a]=e*t:this._view[a]=e||null;else;},this),1===t&&delete this._start,this},tooltipPosition:function(){return{x:this._model.x,y:this._model.y}},hasValue:function(){return i.isNumber(this._model.x)&&i.isNumber(this._model.y)}}),e.Element.extend=i.inherits}.call(this),function(){"use strict";var t=this,e=t.Chart,i=e.helpers;e.defaults.global.animation={duration:1e3,easing:"easeOutQuart",onProgress:i.noop,onComplete:i.noop},e.Animation=e.Element.extend({currentStep:null,numSteps:60,easing:"",render:null,onAnimationProgress:null,onAnimationComplete:null}),e.animationService={frameDuration:17,animations:[],dropFrames:0,addAnimation:function(t,e,a,s){s||(t.animating=!0);for(var o=0;o1&&(e=Math.floor(this.dropFrames),this.dropFrames=this.dropFrames%1);for(var a=0;athis.animations[a].animationObject.numSteps&&(this.animations[a].animationObject.currentStep=this.animations[a].animationObject.numSteps),this.animations[a].animationObject.render(this.animations[a].chartInstance,this.animations[a].animationObject),this.animations[a].animationObject.onAnimationProgress&&this.animations[a].animationObject.onAnimationProgress.call&&this.animations[a].animationObject.onAnimationProgress.call(this.animations[a].chartInstance,this.animations[a]),this.animations[a].animationObject.currentStep==this.animations[a].animationObject.numSteps&&(this.animations[a].animationObject.onAnimationComplete&&this.animations[a].animationObject.onAnimationComplete.call&&this.animations[a].animationObject.onAnimationComplete.call(this.animations[a].chartInstance,this.animations[a]),this.animations[a].chartInstance.animating=!1,this.animations.splice(a,1),a--);var s=Date.now(),o=(s-t)/this.frameDuration;this.dropFrames+=o,this.animations.length>0&&i.requestAnimFrame.call(window,this.digestWrapper)}}}.call(this),function(){"use strict";var t=this,e=t.Chart,i=e.helpers;e.types={},e.instances={},e.controllers={},e.Controller=function(t){return this.chart=t,this.config=t.config,this.options=this.config.options=i.configMerge(e.defaults.global,e.defaults[this.config.type],this.config.options||{}),this.id=i.uid(),Object.defineProperty(this,"data",{get:function(){return this.config.data}}),e.instances[this.id]=this,this.options.responsive&&this.resize(!0),this.initialize.call(this),this},i.extend(e.Controller.prototype,{initialize:function(){return this.bindEvents(),this.ensureScalesHaveIDs(),this.buildOrUpdateControllers(),this.buildScales(),this.buildSurroundingItems(),this.updateLayout(),this.resetElements(),this.initToolTip(),this.update(),this},clear:function(){return i.clear(this.chart),this},stop:function(){return e.animationService.cancelAnimation(this),this},resize:function(t){this.stop();var e=this.chart.canvas,a=i.getMaximumWidth(this.chart.canvas),s=this.options.maintainAspectRatio&&isNaN(this.chart.aspectRatio)===!1&&isFinite(this.chart.aspectRatio)&&0!==this.chart.aspectRatio?a/this.chart.aspectRatio:i.getMaximumHeight(this.chart.canvas);return e.width=this.chart.width=a,e.height=this.chart.height=s,i.retinaScale(this.chart),t||this.update(this.options.responsiveAnimationDuration),this},ensureScalesHaveIDs:function(){var t="x-axis-",e="y-axis-";this.options.scales&&(this.options.scales.xAxes&&this.options.scales.xAxes.length&&i.each(this.options.scales.xAxes,function(e,i){e.id=e.id||t+i},this),this.options.scales.yAxes&&this.options.scales.yAxes.length&&i.each(this.options.scales.yAxes,function(t,i){t.id=t.id||e+i},this))},buildScales:function(){if(this.scales={},this.options.scales&&(this.options.scales.xAxes&&this.options.scales.xAxes.length&&i.each(this.options.scales.xAxes,function(t,i){var a=e.scaleService.getScaleConstructor(t.type),s=new a({ctx:this.chart.ctx,options:t,chart:this,id:t.id});this.scales[s.id]=s},this),this.options.scales.yAxes&&this.options.scales.yAxes.length&&i.each(this.options.scales.yAxes,function(t,i){var a=e.scaleService.getScaleConstructor(t.type),s=new a({ctx:this.chart.ctx,options:t,chart:this,id:t.id});this.scales[s.id]=s},this)),this.options.scale){var t=e.scaleService.getScaleConstructor(this.options.scale.type),a=new t({ctx:this.chart.ctx,options:this.options.scale,chart:this});this.scale=a,this.scales.radialScale=a}e.scaleService.addScalesToLayout(this)},buildSurroundingItems:function(){this.options.title&&(this.titleBlock=new e.Title({ctx:this.chart.ctx,options:this.options.title,chart:this}),e.layoutService.addBox(this,this.titleBlock)),this.options.legend&&(this.legend=new e.Legend({ctx:this.chart.ctx,options:this.options.legend,chart:this}),e.layoutService.addBox(this,this.legend))},updateLayout:function(){e.layoutService.update(this,this.chart.width,this.chart.height)},buildOrUpdateControllers:function(t){var a=[];if(i.each(this.data.datasets,function(i,s){i.type||(i.type=this.config.type);var o=i.type;a.push(o),i.controller?i.controller.updateIndex(s):(i.controller=new e.controllers[o](this,s),t&&i.controller.reset())},this),a.length>1)for(var s=1;s0&&(e=this.data.datasets[e[0]._datasetIndex].metaData),e},generateLegend:function(){return this.options.legendCallback(this)},destroy:function(){this.clear(),i.unbindEvents(this,this.events),i.removeResizeListener(this.chart.canvas.parentNode);var t=this.chart.canvas;t.width=this.chart.width,t.height=this.chart.height,void 0!==this.chart.originalDevicePixelRatio&&this.chart.ctx.scale(1/this.chart.originalDevicePixelRatio,1/this.chart.originalDevicePixelRatio),t.style.width=this.chart.originalCanvasStyleWidth,t.style.height=this.chart.originalCanvasStyleHeight,delete e.instances[this.id]},toBase64Image:function(){return this.chart.canvas.toDataURL.apply(this.chart.canvas,arguments)},initToolTip:function(){this.tooltip=new e.Tooltip({_chart:this.chart,_chartInstance:this,_data:this.data,_options:this.options},this)},bindEvents:function(){i.bindEvents(this,this.options.events,function(t){this.eventHandler(t)})},eventHandler:function(t){if(this.lastActive=this.lastActive||[],this.lastTooltipActive=this.lastTooltipActive||[],"mouseout"==t.type)this.active=[],this.tooltipActive=[];else{var e=this,a=function(i){switch(i){case"single":return e.getElementAtEvent(t);case"label":return e.getElementsAtEvent(t);case"dataset":return e.getDatasetAtEvent(t);default:return t}};this.active=a(this.options.hover.mode),this.tooltipActive=a(this.options.tooltips.mode)}this.options.hover.onHover&&this.options.hover.onHover.call(this,this.active),("mouseup"==t.type||"click"==t.type)&&(this.options.onClick&&this.options.onClick.call(this,t,this.active),this.legend&&this.legend.handleEvent&&this.legend.handleEvent(t));if(this.lastActive.length)switch(this.options.hover.mode){case"single":this.data.datasets[this.lastActive[0]._datasetIndex].controller.removeHoverStyle(this.lastActive[0],this.lastActive[0]._datasetIndex,this.lastActive[0]._index);break;case"label":case"dataset":for(var s=0;st)this.getDataset().metaData.splice(t,e-t);else if(t>e)for(var i=e;t>i;++i)this.addElementAndReset(i)},addElements:i.noop,addElementAndReset:i.noop,draw:i.noop,removeHoverStyle:i.noop,setHoverStyle:i.noop,update:i.noop}),e.DatasetController.extend=i.inherits}.call(this),function(){"use strict";var t=this,e=t.Chart,i=e.helpers;e.layoutService={defaults:{},addBox:function(t,e){t.boxes||(t.boxes=[]),t.boxes.push(e)},removeBox:function(t,e){t.boxes&&t.boxes.splice(t.boxes.indexOf(e),1)},update:function(t,e,a){function s(t){var e,i=t.isHorizontal();i?(e=t.update(t.options.fullWidth?f:k,y),C-=e.height):(e=t.update(v,x),k-=e.width),D.push({horizontal:i,minSize:e,box:t})}function o(t){var e=i.findNextWhere(D,function(e){return e.box===t});if(e)if(t.isHorizontal()){var a={left:S,right:w,top:0,bottom:0};t.update(t.options.fullWidth?f:k,e.minSize.height,a)}else t.update(e.minSize.width,C)}function n(t){var e=i.findNextWhere(D,function(e){return e.box===t}),a={left:0,right:0,top:_,bottom:A};e&&t.update(e.minSize.width,C,a)}function r(t){t.isHorizontal()?(t.left=t.options.fullWidth?h:S,t.right=t.options.fullWidth?e-h:S+k,t.top=F,t.bottom=F+t.height,F=t.bottom):(t.left=P,t.right=P+t.width,t.top=_,t.bottom=_+C,P=t.right)}if(t){var h=e>30?5:2,l=a>30?5:2,c=i.where(t.boxes,function(t){return"left"==t.options.position}),d=i.where(t.boxes,function(t){return"right"==t.options.position}),u=i.where(t.boxes,function(t){return"top"==t.options.position}),g=i.where(t.boxes,function(t){return"bottom"==t.options.position}),m=i.where(t.boxes,function(t){return"chartArea"==t.options.position});u.sort(function(t,e){return(e.options.fullWidth?1:0)-(t.options.fullWidth?1:0)}),g.sort(function(t,e){return(t.options.fullWidth?1:0)-(e.options.fullWidth?1:0)});var f=e-2*h,p=a-2*l,b=f/2,x=p/2,v=(e-b)/(c.length+d.length),y=(a-x)/(u.length+g.length),k=f,C=p,D=[];i.each(c.concat(d,u,g),s);var S=h,w=h,_=l,A=l;i.each(c.concat(d),o),i.each(c,function(t){S+=t.width}),i.each(d,function(t){w+=t.width}),i.each(u.concat(g),o),i.each(u,function(t){_+=t.height}),i.each(g,function(t){A+=t.height}),i.each(c.concat(d),n),S=h,w=h,_=l,A=l,i.each(c,function(t){S+=t.width}),i.each(d,function(t){w+=t.width}),i.each(u,function(t){_+=t.height}),i.each(g,function(t){A+=t.height});var M=a-_-A,I=e-S-w;(I!==k||M!==C)&&(i.each(c,function(t){t.height=M}),i.each(d,function(t){t.height=M}),i.each(u,function(t){t.width=I}),i.each(g,function(t){t.width=I}),C=M,k=I);var P=h,F=l;i.each(c.concat(u),r),P+=k,F+=C,i.each(d,r),i.each(g,r),t.chartArea={left:S,top:_,right:S+k,bottom:_+C},i.each(m,function(e){e.left=t.chartArea.left,e.top=t.chartArea.top,e.right=t.chartArea.right,e.bottom=t.chartArea.bottom,e.update(k,C)})}}}}.call(this),function(){"use strict";var t=this,e=t.Chart,i=e.helpers;e.defaults.global.legend={display:!0,position:"top",fullWidth:!0,onClick:function(t,e){var i=this.chart.data.datasets[e.datasetIndex];i.hidden=!i.hidden,this.chart.update()},labels:{boxWidth:40,fontSize:12,fontStyle:"normal",fontColor:"#666",fontFamily:"Helvetica Neue",padding:10,generateLabels:function(t){return t.datasets.map(function(t,e){return{text:t.label,fillStyle:t.backgroundColor,hidden:t.hidden,lineCap:t.borderCapStyle,lineDash:t.borderDash,lineDashOffset:t.borderDashOffset,lineJoin:t.borderJoinStyle,lineWidth:t.borderWidth,strokeStyle:t.borderColor,datasetIndex:e}},this)}}},e.Legend=e.Element.extend({initialize:function(t){i.extend(this,t),this.legendHitBoxes=[],this.doughnutMode=!1},beforeUpdate:i.noop,update:function(t,e,i){return this.beforeUpdate(),this.maxWidth=t,this.maxHeight=e,this.margins=i,this.beforeSetDimensions(),this.setDimensions(),this.afterSetDimensions(),this.beforeBuildLabels(),this.buildLabels(),this.afterBuildLabels(),this.beforeFit(),this.fit(),this.afterFit(),this.afterUpdate(),this.minSize},afterUpdate:i.noop,beforeSetDimensions:i.noop,setDimensions:function(){this.isHorizontal()?(this.width=this.maxWidth,this.left=0,this.right=this.width):(this.height=this.maxHeight,this.top=0,this.bottom=this.height),this.paddingLeft=0,this.paddingTop=0,this.paddingRight=0,this.paddingBottom=0,this.minSize={width:0,height:0}},afterSetDimensions:i.noop,beforeBuildLabels:i.noop,buildLabels:function(){this.legendItems=this.options.labels.generateLabels.call(this,this.chart.data)},afterBuildLabels:i.noop,beforeFit:i.noop,fit:function(){var t=this.ctx,e=i.fontString(this.options.labels.fontSize,this.options.labels.fontStyle,this.options.labels.fontFamily);if(this.legendHitBoxes=[],this.isHorizontal()?this.minSize.width=this.maxWidth:this.minSize.width=this.options.display?10:0,this.isHorizontal()?this.minSize.height=this.options.display?10:0:this.minSize.height=this.maxHeight,this.options.display&&this.isHorizontal()){this.lineWidths=[0];var a=this.legendItems.length?this.options.labels.fontSize+this.options.labels.padding:0;t.textAlign="left",t.textBaseline="top",t.font=e,i.each(this.legendItems,function(e,i){var s=this.options.labels.boxWidth+this.options.labels.fontSize/2+t.measureText(e.text).width;this.lineWidths[this.lineWidths.length-1]+s>=this.width&&(a+=this.options.labels.fontSize+this.options.labels.padding,this.lineWidths[this.lineWidths.length]=this.left),this.legendHitBoxes[i]={left:0,top:0,width:s,height:this.options.labels.fontSize},this.lineWidths[this.lineWidths.length-1]+=s+this.options.labels.padding},this),this.minSize.height+=a}this.width=this.minSize.width,this.height=this.minSize.height},afterFit:i.noop,isHorizontal:function(){return"top"==this.options.position||"bottom"==this.options.position},draw:function(){if(this.options.display){var t=this.ctx,a={x:this.left+(this.width-this.lineWidths[0])/2,y:this.top+this.options.labels.padding,line:0},s=i.fontString(this.options.labels.fontSize,this.options.labels.fontStyle,this.options.labels.fontFamily);this.isHorizontal()&&(t.textAlign="left",t.textBaseline="top",t.lineWidth=.5,t.strokeStyle=this.options.labels.fontColor,t.fillStyle=this.options.labels.fontColor,t.font=s,i.each(this.legendItems,function(i,s){var o=t.measureText(i.text).width,n=this.options.labels.boxWidth+this.options.labels.fontSize/2+o;a.x+n>=this.width&&(a.y+=this.options.labels.fontSize+this.options.labels.padding,a.line++,a.x=this.left+(this.width-this.lineWidths[a.line])/2),t.save();var r=function(t,e){return void 0!==t?t:e};t.fillStyle=r(i.fillStyle,e.defaults.global.defaultColor),t.lineCap=r(i.lineCap,e.defaults.global.elements.line.borderCapStyle),t.lineDashOffset=r(i.lineDashOffset,e.defaults.global.elements.line.borderDashOffset),t.lineJoin=r(i.lineJoin,e.defaults.global.elements.line.borderJoinStyle),t.lineWidth=r(i.lineWidth,e.defaults.global.elements.line.borderWidth),t.strokeStyle=r(i.strokeStyle,e.defaults.global.defaultColor),t.setLineDash&&t.setLineDash(r(i.lineDash,e.defaults.global.elements.line.borderDash)),t.strokeRect(a.x,a.y,this.options.labels.boxWidth,this.options.labels.fontSize),t.fillRect(a.x,a.y,this.options.labels.boxWidth,this.options.labels.fontSize),t.restore(),this.legendHitBoxes[s].left=a.x,this.legendHitBoxes[s].top=a.y,t.fillText(i.text,this.options.labels.boxWidth+this.options.labels.fontSize/2+a.x,a.y),i.hidden&&(t.beginPath(),t.lineWidth=2,t.moveTo(this.options.labels.boxWidth+this.options.labels.fontSize/2+a.x,a.y+this.options.labels.fontSize/2),t.lineTo(this.options.labels.boxWidth+this.options.labels.fontSize/2+a.x+o,a.y+this.options.labels.fontSize/2),t.stroke()),a.x+=n+this.options.labels.padding},this))}},handleEvent:function(t){var e=i.getRelativePosition(t,this.chart.chart);if(e.x>=this.left&&e.x<=this.right&&e.y>=this.top&&e.y<=this.bottom)for(var a=0;a=s.left&&e.x<=s.left+s.width&&e.y>=s.top&&e.y<=s.top+s.height){this.options.onClick&&this.options.onClick.call(this,t,this.legendItems[a]);break}}}})}.call(this),function(){"use strict";var t=this,e=t.Chart,i=e.helpers;e.defaults.scale={display:!0,gridLines:{display:!0,color:"rgba(0, 0, 0, 0.1)",lineWidth:1,drawOnChartArea:!0,drawTicks:!0,zeroLineWidth:1,zeroLineColor:"rgba(0,0,0,0.25)",offsetGridLines:!1},scaleLabel:{fontColor:"#666",fontFamily:"Helvetica Neue",fontSize:12,fontStyle:"normal",labelString:"",display:!1},ticks:{beginAtZero:!1,fontSize:12,fontStyle:"normal",fontColor:"#666",fontFamily:"Helvetica Neue",maxRotation:90,mirror:!1,padding:10,reverse:!1,display:!0,autoSkip:!0,autoSkipPadding:20,callback:function(t){return""+t}}},e.Scale=e.Element.extend({beforeUpdate:function(){i.callCallback(this.options.beforeUpdate,[this])},update:function(t,e,a){return this.beforeUpdate(),this.maxWidth=t,this.maxHeight=e,this.margins=i.extend({left:0,right:0,top:0,bottom:0},a),this.beforeSetDimensions(),this.setDimensions(),this.afterSetDimensions(),this.beforeDataLimits(),this.determineDataLimits(),this.afterDataLimits(),this.beforeBuildTicks(),this.buildTicks(),this.afterBuildTicks(),this.beforeTickToLabelConversion(),this.convertTicksToLabels(),this.afterTickToLabelConversion(),this.beforeCalculateTickRotation(),this.calculateTickRotation(),this.afterCalculateTickRotation(),this.beforeFit(),this.fit(),this.afterFit(),this.afterUpdate(),this.minSize},afterUpdate:function(){i.callCallback(this.options.afterUpdate,[this])},beforeSetDimensions:function(){i.callCallback(this.options.beforeSetDimensions,[this])},setDimensions:function(){this.isHorizontal()?(this.width=this.maxWidth,this.left=0,this.right=this.width):(this.height=this.maxHeight,this.top=0,this.bottom=this.height),this.paddingLeft=0,this.paddingTop=0,this.paddingRight=0,this.paddingBottom=0},afterSetDimensions:function(){i.callCallback(this.options.afterSetDimensions,[this])},beforeDataLimits:function(){i.callCallback(this.options.beforeDataLimits,[this])},determineDataLimits:i.noop,afterDataLimits:function(){i.callCallback(this.options.afterDataLimits,[this])},beforeBuildTicks:function(){i.callCallback(this.options.beforeBuildTicks,[this])},buildTicks:i.noop,afterBuildTicks:function(){i.callCallback(this.options.afterBuildTicks,[this])},beforeTickToLabelConversion:function(){i.callCallback(this.options.beforeTickToLabelConversion,[this])},convertTicksToLabels:function(){this.ticks=this.ticks.map(function(t,e,i){return this.options.ticks.userCallback?this.options.ticks.userCallback(t,e,i):this.options.ticks.callback(t,e,i)},this)},afterTickToLabelConversion:function(){i.callCallback(this.options.afterTickToLabelConversion,[this])},beforeCalculateTickRotation:function(){i.callCallback(this.options.beforeCalculateTickRotation,[this])},calculateTickRotation:function(){var t=i.fontString(this.options.ticks.fontSize,this.options.ticks.fontStyle,this.options.ticks.fontFamily);this.ctx.font=t;var e,a,s=this.ctx.measureText(this.ticks[0]).width,o=this.ctx.measureText(this.ticks[this.ticks.length-1]).width;if(this.paddingRight=o/2+3,this.paddingLeft=s/2+3,this.labelRotation=0,this.options.display&&this.isHorizontal()){var n,r,h=i.longestText(this.ctx,t,this.ticks);this.labelWidth=h;for(var l=this.getPixelForTick(1)-this.getPixelForTick(0)-6;this.labelWidth>l&&this.labelRotationthis.yLabelWidth&&(this.paddingLeft=e+this.options.ticks.fontSize/2),this.paddingRight=this.options.ticks.fontSize/2,r*h>this.maxHeight){this.labelRotation--;break}this.labelRotation++,this.labelWidth=n*h}}else this.labelWidth=0,this.paddingRight=0,this.paddingLeft=0;this.margins&&(this.paddingLeft-=this.margins.left,this.paddingRight-=this.margins.right,this.paddingLeft=Math.max(this.paddingLeft,0),this.paddingRight=Math.max(this.paddingRight,0))},afterCalculateTickRotation:function(){i.callCallback(this.options.afterCalculateTickRotation,[this])},beforeFit:function(){i.callCallback(this.options.beforeFit,[this])},fit:function(){if(this.minSize={width:0,height:0},this.isHorizontal()?this.minSize.width=this.isFullWidth()?this.maxWidth-this.margins.left-this.margins.right:this.maxWidth:this.minSize.width=this.options.gridLines.display&&this.options.display?10:0,this.isHorizontal()?this.minSize.height=this.options.gridLines.display&&this.options.display?10:0:this.minSize.height=this.maxHeight,this.options.scaleLabel.display&&(this.isHorizontal()?this.minSize.height+=1.5*this.options.scaleLabel.fontSize:this.minSize.width+=1.5*this.options.scaleLabel.fontSize),this.options.ticks.display&&this.options.display){var t=i.fontString(this.options.ticks.fontSize,this.options.ticks.fontStyle,this.options.ticks.fontFamily);if(this.isHorizontal()){this.longestLabelWidth=i.longestText(this.ctx,t,this.ticks);var e=Math.sin(i.toRadians(this.labelRotation))*this.longestLabelWidth+1.5*this.options.ticks.fontSize;this.minSize.height=Math.min(this.maxHeight,this.minSize.height+e),t=i.fontString(this.options.ticks.fontSize,this.options.ticks.fontStyle,this.options.ticks.fontFamily),this.ctx.font=t;var a=this.ctx.measureText(this.ticks[0]).width,s=this.ctx.measureText(this.ticks[this.ticks.length-1]).width,o=Math.cos(i.toRadians(this.labelRotation)),n=Math.sin(i.toRadians(this.labelRotation));this.paddingLeft=0!==this.labelRotation?o*a+3:a/2+3,this.paddingRight=0!==this.labelRotation?n*(this.options.ticks.fontSize/2)+3:s/2+3}else{var r=this.maxWidth-this.minSize.width,h=i.longestText(this.ctx,t,this.ticks);this.options.ticks.mirror||(h+=this.options.ticks.padding),r>h?this.minSize.width+=h:this.minSize.width=this.maxWidth,this.paddingTop=this.options.ticks.fontSize/2,this.paddingBottom=this.options.ticks.fontSize/2}}this.margins&&(this.paddingLeft-=this.margins.left,this.paddingTop-=this.margins.top,this.paddingRight-=this.margins.right,this.paddingBottom-=this.margins.bottom,this.paddingLeft=Math.max(this.paddingLeft,0),this.paddingTop=Math.max(this.paddingTop,0),this.paddingRight=Math.max(this.paddingRight,0),this.paddingBottom=Math.max(this.paddingBottom,0)),this.width=this.minSize.width,this.height=this.minSize.height},afterFit:function(){i.callCallback(this.options.afterFit,[this])},isHorizontal:function(){return"top"===this.options.position||"bottom"===this.options.position},isFullWidth:function(){return this.options.fullWidth},getRightValue:function a(t){return null===t||"undefined"==typeof t?NaN:"number"==typeof t&&isNaN(t)?NaN:"object"==typeof t?t instanceof Date?t:a(this.isHorizontal()?t.x:t.y):t},getLabelForIndex:i.noop,getPixelForValue:i.noop,getPixelForTick:function(t,e){if(this.isHorizontal()){var i=this.width-(this.paddingLeft+this.paddingRight),a=i/Math.max(this.ticks.length-(this.options.gridLines.offsetGridLines?0:1),1),s=a*t+this.paddingLeft;e&&(s+=a/2);var o=this.left+Math.round(s);
+return o+=this.isFullWidth()?this.margins.left:0}var n=this.height-(this.paddingTop+this.paddingBottom);return this.top+t*(n/(this.ticks.length-1))},getPixelForDecimal:function(t){if(this.isHorizontal()){var e=this.width-(this.paddingLeft+this.paddingRight),i=e*t+this.paddingLeft,a=this.left+Math.round(i);return a+=this.isFullWidth()?this.margins.left:0}return this.top+t*this.height},draw:function(t){if(this.options.display){var e,a,s,o,n=0!==this.labelRotation,r=this.options.ticks.autoSkip;this.ctx.fillStyle=this.options.ticks.fontColor;var h=i.fontString(this.options.ticks.fontSize,this.options.ticks.fontStyle,this.options.ticks.fontFamily),l=Math.cos(i.toRadians(this.labelRotation)),c=Math.sin(i.toRadians(this.labelRotation)),d=this.longestLabelWidth*l;this.options.ticks.fontSize*c;if(this.isHorizontal()){e=!0;var u="bottom"===this.options.position?this.top:this.bottom-10,g="bottom"===this.options.position?this.top+10:this.bottom;a=!1,(d/2+this.options.ticks.autoSkipPadding)*this.ticks.length>this.width-(this.paddingLeft+this.paddingRight)&&(a=1+Math.floor((d/2+this.options.ticks.autoSkipPadding)*this.ticks.length/(this.width-(this.paddingLeft+this.paddingRight)))),r||(a=!1),i.each(this.ticks,function(s,o){if(!(a>1&&o%a>0||void 0===s||null===s)){var r=this.getPixelForTick(o),l=this.getPixelForTick(o,this.options.gridLines.offsetGridLines);this.options.gridLines.display&&(o===("undefined"!=typeof this.zeroLineIndex?this.zeroLineIndex:0)?(this.ctx.lineWidth=this.options.gridLines.zeroLineWidth,this.ctx.strokeStyle=this.options.gridLines.zeroLineColor,e=!0):e&&(this.ctx.lineWidth=this.options.gridLines.lineWidth,this.ctx.strokeStyle=this.options.gridLines.color,e=!1),r+=i.aliasPixel(this.ctx.lineWidth),this.ctx.beginPath(),this.options.gridLines.drawTicks&&(this.ctx.moveTo(r,u),this.ctx.lineTo(r,g)),this.options.gridLines.drawOnChartArea&&(this.ctx.moveTo(r,t.top),this.ctx.lineTo(r,t.bottom)),this.ctx.stroke()),this.options.ticks.display&&(this.ctx.save(),this.ctx.translate(l,n?this.top+12:"top"===this.options.position?this.bottom-10:this.top+10),this.ctx.rotate(-1*i.toRadians(this.labelRotation)),this.ctx.font=h,this.ctx.textAlign=n?"right":"center",this.ctx.textBaseline=n?"middle":"top"===this.options.position?"bottom":"top",this.ctx.fillText(s,0,0),this.ctx.restore())}},this),this.options.scaleLabel.display&&(this.ctx.textAlign="center",this.ctx.textBaseline="middle",this.ctx.fillStyle=this.options.scaleLabel.fontColor,this.ctx.font=i.fontString(this.options.scaleLabel.fontSize,this.options.scaleLabel.fontStyle,this.options.scaleLabel.fontFamily),s=this.left+(this.right-this.left)/2,o="bottom"===this.options.position?this.bottom-this.options.scaleLabel.fontSize/2:this.top+this.options.scaleLabel.fontSize/2,this.ctx.fillText(this.options.scaleLabel.labelString,s,o))}else{e=!0;var m="right"===this.options.position?this.left:this.right-5,f="right"===this.options.position?this.left+5:this.right;if(i.each(this.ticks,function(a,s){if(void 0!==a&&null!==a){var o=this.getPixelForTick(s);if(this.options.gridLines.display&&(s===("undefined"!=typeof this.zeroLineIndex?this.zeroLineIndex:0)?(this.ctx.lineWidth=this.options.gridLines.zeroLineWidth,this.ctx.strokeStyle=this.options.gridLines.zeroLineColor,e=!0):e&&(this.ctx.lineWidth=this.options.gridLines.lineWidth,this.ctx.strokeStyle=this.options.gridLines.color,e=!1),o+=i.aliasPixel(this.ctx.lineWidth),this.ctx.beginPath(),this.options.gridLines.drawTicks&&(this.ctx.moveTo(m,o),this.ctx.lineTo(f,o)),this.options.gridLines.drawOnChartArea&&(this.ctx.moveTo(t.left,o),this.ctx.lineTo(t.right,o)),this.ctx.stroke()),this.options.ticks.display){var n,r=this.getPixelForTick(s,this.options.gridLines.offsetGridLines);this.ctx.save(),"left"===this.options.position?this.options.ticks.mirror?(n=this.right+this.options.ticks.padding,this.ctx.textAlign="left"):(n=this.right-this.options.ticks.padding,this.ctx.textAlign="right"):this.options.ticks.mirror?(n=this.left-this.options.ticks.padding,this.ctx.textAlign="right"):(n=this.left+this.options.ticks.padding,this.ctx.textAlign="left"),this.ctx.translate(n,r),this.ctx.rotate(-1*i.toRadians(this.labelRotation)),this.ctx.font=h,this.ctx.textBaseline="middle",this.ctx.fillText(a,0,0),this.ctx.restore()}}},this),this.options.scaleLabel.display){s="left"===this.options.position?this.left+this.options.scaleLabel.fontSize/2:this.right-this.options.scaleLabel.fontSize/2,o=this.top+(this.bottom-this.top)/2;var p="left"===this.options.position?-.5*Math.PI:.5*Math.PI;this.ctx.save(),this.ctx.translate(s,o),this.ctx.rotate(p),this.ctx.textAlign="center",this.ctx.fillStyle=this.options.scaleLabel.fontColor,this.ctx.font=i.fontString(this.options.scaleLabel.fontSize,this.options.scaleLabel.fontStyle,this.options.scaleLabel.fontFamily),this.ctx.textBaseline="middle",this.ctx.fillText(this.options.scaleLabel.labelString,0,0),this.ctx.restore()}}}}})}.call(this),function(){"use strict";var t=this,e=t.Chart,i=e.helpers;e.scaleService={constructors:{},defaults:{},registerScaleType:function(t,e,a){this.constructors[t]=e,this.defaults[t]=i.clone(a)},getScaleConstructor:function(t){return this.constructors.hasOwnProperty(t)?this.constructors[t]:void 0},getScaleDefaults:function(t){return this.defaults.hasOwnProperty(t)?i.scaleMerge(e.defaults.scale,this.defaults[t]):{}},addScalesToLayout:function(t){i.each(t.scales,function(i){e.layoutService.addBox(t,i)})}}}.call(this),function(){"use strict";var t=this,e=t.Chart,i=e.helpers;e.defaults.global.title={display:!1,position:"top",fullWidth:!0,fontColor:"#666",fontFamily:"Helvetica Neue",fontSize:12,fontStyle:"bold",padding:10,text:""},e.Title=e.Element.extend({initialize:function(t){i.extend(this,t),this.options=i.configMerge(e.defaults.global.title,t.options),this.legendHitBoxes=[]},beforeUpdate:i.noop,update:function(t,e,i){return this.beforeUpdate(),this.maxWidth=t,this.maxHeight=e,this.margins=i,this.beforeSetDimensions(),this.setDimensions(),this.afterSetDimensions(),this.beforeBuildLabels(),this.buildLabels(),this.afterBuildLabels(),this.beforeFit(),this.fit(),this.afterFit(),this.afterUpdate(),this.minSize},afterUpdate:i.noop,beforeSetDimensions:i.noop,setDimensions:function(){this.isHorizontal()?(this.width=this.maxWidth,this.left=0,this.right=this.width):(this.height=this.maxHeight,this.top=0,this.bottom=this.height),this.paddingLeft=0,this.paddingTop=0,this.paddingRight=0,this.paddingBottom=0,this.minSize={width:0,height:0}},afterSetDimensions:i.noop,beforeBuildLabels:i.noop,buildLabels:i.noop,afterBuildLabels:i.noop,beforeFit:i.noop,fit:function(){this.ctx,i.fontString(this.options.fontSize,this.options.fontStyle,this.options.fontFamily);this.isHorizontal()?this.minSize.width=this.maxWidth:this.minSize.width=0,this.isHorizontal()?this.minSize.height=0:this.minSize.height=this.maxHeight,this.isHorizontal()&&this.options.display&&(this.minSize.height+=this.options.fontSize+2*this.options.padding),this.width=this.minSize.width,this.height=this.minSize.height},afterFit:i.noop,isHorizontal:function(){return"top"==this.options.position||"bottom"==this.options.position},draw:function(){if(this.options.display){var t,e,a=this.ctx;if(this.isHorizontal())this.options.display&&(a.textAlign="center",a.textBaseline="middle",a.fillStyle=this.options.fontColor,a.font=i.fontString(this.options.fontSize,this.options.fontStyle,this.options.fontFamily),t=this.left+(this.right-this.left)/2,e=this.top+(this.bottom-this.top)/2,a.fillText(this.options.text,t,e));else if(this.options.display){t="left"==this.options.position?this.left+this.options.fontSize/2:this.right-this.options.fontSize/2,e=this.top+(this.bottom-this.top)/2;var s="left"==this.options.position?-.5*Math.PI:.5*Math.PI;a.save(),a.translate(t,e),a.rotate(s),a.textAlign="center",a.fillStyle=this.options.fontColor,a.font=i.fontString(this.options.fontSize,this.options.fontStyle,this.options.fontFamily),a.textBaseline="middle",a.fillText(this.options.text,0,0),a.restore()}}}})}.call(this),function(){"use strict";function t(t,e){return e&&(a.isArray(e)?t=t.concat(e):t.push(e)),t}var e=this,i=e.Chart,a=i.helpers;i.defaults.global.tooltips={enabled:!0,custom:null,mode:"single",backgroundColor:"rgba(0,0,0,0.8)",titleFontFamily:"'Helvetica Neue', 'Helvetica', 'Arial', sans-serif",titleFontSize:12,titleFontStyle:"bold",titleSpacing:2,titleMarginBottom:6,titleColor:"#fff",titleAlign:"left",bodyFontFamily:"'Helvetica Neue', 'Helvetica', 'Arial', sans-serif",bodyFontSize:12,bodyFontStyle:"normal",bodySpacing:2,bodyColor:"#fff",bodyAlign:"left",footerFontFamily:"'Helvetica Neue', 'Helvetica', 'Arial', sans-serif",footerFontSize:12,footerFontStyle:"bold",footerSpacing:2,footerMarginTop:6,footerColor:"#fff",footerAlign:"left",yPadding:6,xPadding:6,caretSize:5,cornerRadius:6,multiKeyBackground:"#fff",callbacks:{beforeTitle:a.noop,title:function(t,e){var i="";return t.length>0&&(t[0].xLabel?i=t[0].xLabel:e.labels.length>0&&t[0].indexthis._chart.height-t.height&&(this._model.yAlign="bottom");var e,i,a=this,s=(this._chartInstance.chartArea.left+this._chartInstance.chartArea.right)/2;"center"===this._model.yAlign?(e=function(t){return s>=t},i=function(t){return t>s}):(e=function(e){return e<=t.width/2},i=function(e){return e>=a._chart.width-t.width/2}),e(this._model.x)?this._model.xAlign="left":i(this._model.x)&&(this._model.xAlign="right")},getBackgroundPoint:function(t,e){var i={x:t.x,y:t.y};return"right"===t.xAlign?i.x-=e.width:"center"===t.xAlign&&(i.x-=e.width/2),"top"===t.yAlign?i.y+=t.caretPadding+t.caretSize:"bottom"===t.yAlign?i.y-=e.height+t.caretPadding+t.caretSize:i.y-=e.height/2,"center"==t.yAlign?"left"===t.xAlign?i.x+=t.caretPadding+t.caretSize:"right"===t.xAlign&&(i.x-=t.caretPadding+t.caretSize):"left"===t.xAlign?i.x-=t.cornerRadius+t.caretPadding:"right"===t.xAlign&&(i.x+=t.cornerRadius+t.caretPadding),i},drawCaret:function(t,e,i,s){var o,n,r,h,l,c,d=this._view,u=this._chart.ctx;"center"===d.yAlign?("left"===d.xAlign?(o=t.x,n=o-d.caretSize,r=o):(o=t.x+e.width,n=o+d.caretSize,r=o),l=t.y+e.height/2,h=l-d.caretSize,c=l+d.caretSize):("left"===d.xAlign?(o=t.x+d.cornerRadius,n=o+d.caretSize,r=n+d.caretSize):"right"===d.xAlign?(o=t.x+e.width-d.cornerRadius,n=o-d.caretSize,r=n-d.caretSize):(n=t.x+e.width/2,o=n-d.caretSize,r=n+d.caretSize),"top"===d.yAlign?(h=t.y,l=h-d.caretSize,c=h):(h=t.y+e.height,l=h+d.caretSize,c=h)),u.fillStyle=a.color(d.backgroundColor).alpha(i).rgbString(),u.beginPath(),u.moveTo(o,h),u.lineTo(n,l),u.lineTo(r,c),u.closePath(),u.fill()},drawTitle:function(t,e,i,s){e.title.length&&(i.textAlign=e._titleAlign,i.textBaseline="top",i.fillStyle=a.color(e.titleColor).alpha(s).rgbString(),i.font=a.fontString(e.titleFontSize,e._titleFontStyle,e._titleFontFamily),a.each(e.title,function(a,s){i.fillText(a,t.x,t.y),t.y+=e.titleFontSize+e.titleSpacing,s+1===e.title.length&&(t.y+=e.titleMarginBottom-e.titleSpacing)},this))},drawBody:function(t,e,i,s){i.textAlign=e._bodyAlign,i.textBaseline="top",i.fillStyle=a.color(e.bodyColor).alpha(s).rgbString(),i.font=a.fontString(e.bodyFontSize,e._bodyFontStyle,e._bodyFontFamily),a.each(e.beforeBody,function(a){i.fillText(a,t.x,t.y),t.y+=e.bodyFontSize+e.bodySpacing}),a.each(e.body,function(o,n){"single"!==this._options.tooltips.mode&&(i.fillStyle=a.color(e.legendColorBackground).alpha(s).rgbaString(),i.fillRect(t.x,t.y,e.bodyFontSize,e.bodyFontSize),i.strokeStyle=a.color(e.labelColors[n].borderColor).alpha(s).rgbaString(),i.strokeRect(t.x,t.y,e.bodyFontSize,e.bodyFontSize),i.fillStyle=a.color(e.labelColors[n].backgroundColor).alpha(s).rgbaString(),i.fillRect(t.x+1,t.y+1,e.bodyFontSize-2,e.bodyFontSize-2),i.fillStyle=a.color(e.bodyColor).alpha(s).rgbaString()),i.fillText(o,t.x+("single"!==this._options.tooltips.mode?e.bodyFontSize+2:0),t.y),t.y+=e.bodyFontSize+e.bodySpacing},this),a.each(e.afterBody,function(a){i.fillText(a,t.x,t.y),t.y+=e.bodyFontSize}),t.y-=e.bodySpacing},drawFooter:function(t,e,i,s){e.footer.length&&(t.y+=e.footerMarginTop,i.textAlign=e._footerAlign,i.textBaseline="top",i.fillStyle=a.color(e.footerColor).alpha(s).rgbString(),i.font=a.fontString(e.footerFontSize,e._footerFontStyle,e._footerFontFamily),a.each(e.footer,function(a){i.fillText(a,t.x,t.y),t.y+=e.footerFontSize+e.footerSpacing},this))},draw:function(){var t=this._chart.ctx,e=this._view;if(0!==e.opacity){var i=e.caretPadding,s=this.getTooltipSize(e),o={x:e.x,y:e.y},n=Math.abs(e.opacity<.001)?0:e.opacity;this._options.tooltips.enabled&&(t.fillStyle=a.color(e.backgroundColor).alpha(n).rgbString(),a.drawRoundedRectangle(t,o.x,o.y,s.width,s.height,e.cornerRadius),t.fill(),this.drawCaret(o,s,n,i),o.x+=e.xPadding,o.y+=e.yPadding,this.drawTitle(o,e,t,n),this.drawBody(o,e,t,n),this.drawFooter(o,e,t,n))}}})}.call(this),function(){"use strict";var t=this,e=t.Chart,i=e.helpers;e.defaults.bar={hover:{mode:"label"},scales:{xAxes:[{type:"category",categoryPercentage:.8,barPercentage:.9,gridLines:{offsetGridLines:!0}}],yAxes:[{type:"linear"}]}},e.controllers.bar=e.DatasetController.extend({initialize:function(t,i){e.DatasetController.prototype.initialize.call(this,t,i),this.getDataset().bar=!0},getBarCount:function(){var t=0;return i.each(this.chart.data.datasets,function(e){i.isDatasetVisible(e)&&e.bar&&++t},this),t},addElements:function(){this.getDataset().metaData=this.getDataset().metaData||[],i.each(this.getDataset().data,function(t,i){this.getDataset().metaData[i]=this.getDataset().metaData[i]||new e.elements.Rectangle({_chart:this.chart.chart,_datasetIndex:this.index,_index:i})},this)},addElementAndReset:function(t){this.getDataset().metaData=this.getDataset().metaData||[];var i=new e.elements.Rectangle({_chart:this.chart.chart,_datasetIndex:this.index,_index:t}),a=this.getBarCount();this.updateElement(i,t,!0,a),this.getDataset().metaData.splice(t,0,i)},update:function(t){var e=this.getBarCount();i.each(this.getDataset().metaData,function(i,a){this.updateElement(i,a,t,e)},this)},updateElement:function(t,e,a,s){var o,n=this.getScaleForId(this.getDataset().xAxisID),r=this.getScaleForId(this.getDataset().yAxisID);o=r.min<0&&r.max<0?r.getPixelForValue(r.max):r.min>0&&r.max>0?r.getPixelForValue(r.min):r.getPixelForValue(0),i.extend(t,{_chart:this.chart.chart,_xScale:n,_yScale:r,_datasetIndex:this.index,_index:e,_model:{x:this.calculateBarX(e,this.index),y:a?o:this.calculateBarY(e,this.index),label:this.chart.data.labels[e],datasetLabel:this.getDataset().label,base:this.calculateBarBase(this.index,e),width:this.calculateBarWidth(s),backgroundColor:t.custom&&t.custom.backgroundColor?t.custom.backgroundColor:i.getValueAtIndexOrDefault(this.getDataset().backgroundColor,e,this.chart.options.elements.rectangle.backgroundColor),borderColor:t.custom&&t.custom.borderColor?t.custom.borderColor:i.getValueAtIndexOrDefault(this.getDataset().borderColor,e,this.chart.options.elements.rectangle.borderColor),borderWidth:t.custom&&t.custom.borderWidth?t.custom.borderWidth:i.getValueAtIndexOrDefault(this.getDataset().borderWidth,e,this.chart.options.elements.rectangle.borderWidth)}}),t.pivot()},calculateBarBase:function(t,e){var a=(this.getScaleForId(this.getDataset().xAxisID),this.getScaleForId(this.getDataset().yAxisID)),s=0;if(a.options.stacked){var o=this.chart.data.datasets[t].data[e];if(0>o)for(var n=0;t>n;n++){var r=this.chart.data.datasets[n];i.isDatasetVisible(r)&&r.yAxisID===a.id&&(s+=r.data[e]<0?r.data[e]:0)}else for(var h=0;t>h;h++){var l=this.chart.data.datasets[h];i.isDatasetVisible(l)&&l.yAxisID===a.id&&(s+=l.data[e]>0?l.data[e]:0)}return a.getPixelForValue(s)}return s=a.getPixelForValue(a.min),a.beginAtZero||a.min<=0&&a.max>=0||a.min>=0&&a.max<=0?s=a.getPixelForValue(0,0):a.min<0&&a.max<0&&(s=a.getPixelForValue(a.max)),s},getRuler:function(){var t=this.getScaleForId(this.getDataset().xAxisID),e=(this.getScaleForId(this.getDataset().yAxisID),this.getBarCount()),i=function(){for(var e=t.getPixelForTick(1)-t.getPixelForTick(0),i=2;ia;++a)i.isDatasetVisible(this.chart.data.datasets[a])&&this.chart.data.datasets[a].bar&&++e;return e},calculateBarX:function(t,e){var i=(this.getScaleForId(this.getDataset().yAxisID),this.getScaleForId(this.getDataset().xAxisID)),a=this.getBarIndex(e),s=this.getRuler(),o=i.getPixelForValue(null,t,e,this.chart.isCombo);return o-=this.chart.isCombo?s.tickWidth/2:0,i.options.stacked?o+s.categoryWidth/2+s.categorySpacing:o+s.barWidth/2+s.categorySpacing+s.barWidth*a+s.barSpacing/2+s.barSpacing*a},calculateBarY:function(t,e){var a=(this.getScaleForId(this.getDataset().xAxisID),this.getScaleForId(this.getDataset().yAxisID)),s=this.getDataset().data[t];if(a.options.stacked){for(var o=0,n=0,r=0;e>r;r++){var h=this.chart.data.datasets[r];i.isDatasetVisible(h)&&(h.data[t]<0?n+=h.data[t]||0:o+=h.data[t]||0)}return 0>s?a.getPixelForValue(n+s):a.getPixelForValue(o+s)}return a.getPixelForValue(s)},draw:function(t){var e=t||1;i.each(this.getDataset().metaData,function(t,i){t.transition(e).draw()},this)},setHoverStyle:function(t){var e=this.chart.data.datasets[t._datasetIndex],a=t._index;t._model.backgroundColor=t.custom&&t.custom.hoverBackgroundColor?t.custom.hoverBackgroundColor:i.getValueAtIndexOrDefault(e.hoverBackgroundColor,a,i.color(t._model.backgroundColor).saturate(.5).darken(.1).rgbString()),t._model.borderColor=t.custom&&t.custom.hoverBorderColor?t.custom.hoverBorderColor:i.getValueAtIndexOrDefault(e.hoverBorderColor,a,i.color(t._model.borderColor).saturate(.5).darken(.1).rgbString()),t._model.borderWidth=t.custom&&t.custom.hoverBorderWidth?t.custom.hoverBorderWidth:i.getValueAtIndexOrDefault(e.hoverBorderWidth,a,t._model.borderWidth)},removeHoverStyle:function(t){var e=(this.chart.data.datasets[t._datasetIndex],t._index);t._model.backgroundColor=t.custom&&t.custom.backgroundColor?t.custom.backgroundColor:i.getValueAtIndexOrDefault(this.getDataset().backgroundColor,e,this.chart.options.elements.rectangle.backgroundColor),t._model.borderColor=t.custom&&t.custom.borderColor?t.custom.borderColor:i.getValueAtIndexOrDefault(this.getDataset().borderColor,e,this.chart.options.elements.rectangle.borderColor),t._model.borderWidth=t.custom&&t.custom.borderWidth?t.custom.borderWidth:i.getValueAtIndexOrDefault(this.getDataset().borderWidth,e,this.chart.options.elements.rectangle.borderWidth)}})}.call(this),function(){"use strict";var t=this,e=t.Chart,i=e.helpers;e.defaults.bubble={hover:{mode:"single"},scales:{xAxes:[{type:"linear",position:"bottom",id:"x-axis-0"}],yAxes:[{type:"linear",position:"left",id:"y-axis-0"}]},tooltips:{template:"(<%= value.x %>, <%= value.y %>, <%= value.r %>)",multiTemplate:"<%if (datasetLabel){%><%=datasetLabel%>: <%}%>(<%= value.x %>, <%= value.y %>, <%= value.r %>)"}},e.controllers.bubble=e.DatasetController.extend({addElements:function(){this.getDataset().metaData=this.getDataset().metaData||[],i.each(this.getDataset().data,function(t,i){this.getDataset().metaData[i]=this.getDataset().metaData[i]||new e.elements.Point({_chart:this.chart.chart,_datasetIndex:this.index,_index:i})},this)},addElementAndReset:function(t){this.getDataset().metaData=this.getDataset().metaData||[];var i=new e.elements.Point({_chart:this.chart.chart,_datasetIndex:this.index,_index:t});this.updateElement(i,t,!0),this.getDataset().metaData.splice(t,0,i)},update:function(t){var e,a=this.getDataset().metaData,s=this.getScaleForId(this.getDataset().yAxisID);this.getScaleForId(this.getDataset().xAxisID);e=s.min<0&&s.max<0?s.getPixelForValue(s.max):s.min>0&&s.max>0?s.getPixelForValue(s.min):s.getPixelForValue(0),i.each(a,function(e,i){this.updateElement(e,i,t)},this)},updateElement:function(t,e,a){var s,o=this.getScaleForId(this.getDataset().yAxisID),n=this.getScaleForId(this.getDataset().xAxisID);s=o.min<0&&o.max<0?o.getPixelForValue(o.max):o.min>0&&o.max>0?o.getPixelForValue(o.min):o.getPixelForValue(0),i.extend(t,{_chart:this.chart.chart,_xScale:n,_yScale:o,_datasetIndex:this.index,_index:e,_model:{x:a?n.getPixelForDecimal(.5):n.getPixelForValue(this.getDataset().data[e],e,this.index,this.chart.isCombo),y:a?s:o.getPixelForValue(this.getDataset().data[e],e,this.index),radius:a?0:t.custom&&t.custom.radius?t.custom.radius:this.getRadius(this.getDataset().data[e]),backgroundColor:t.custom&&t.custom.backgroundColor?t.custom.backgroundColor:i.getValueAtIndexOrDefault(this.getDataset().backgroundColor,e,this.chart.options.elements.point.backgroundColor),borderColor:t.custom&&t.custom.borderColor?t.custom.borderColor:i.getValueAtIndexOrDefault(this.getDataset().borderColor,e,this.chart.options.elements.point.borderColor),borderWidth:t.custom&&t.custom.borderWidth?t.custom.borderWidth:i.getValueAtIndexOrDefault(this.getDataset().borderWidth,e,this.chart.options.elements.point.borderWidth),hitRadius:t.custom&&t.custom.hitRadius?t.custom.hitRadius:i.getValueAtIndexOrDefault(this.getDataset().hitRadius,e,this.chart.options.elements.point.hitRadius)}}),t._model.skip=t.custom&&t.custom.skip?t.custom.skip:isNaN(t._model.x)||isNaN(t._model.y),t.pivot()},getRadius:function(t){return t.r||this.chart.options.elements.point.radius},draw:function(t){var e=t||1;i.each(this.getDataset().metaData,function(t,i){t.transition(e),t.draw()},this)},setHoverStyle:function(t){var e=this.chart.data.datasets[t._datasetIndex],a=t._index;t._model.radius=t.custom&&t.custom.hoverRadius?t.custom.hoverRadius:i.getValueAtIndexOrDefault(e.hoverRadius,a,this.chart.options.elements.point.hoverRadius)+this.getRadius(this.getDataset().data[t._index]),t._model.backgroundColor=t.custom&&t.custom.hoverBackgroundColor?t.custom.hoverBackgroundColor:i.getValueAtIndexOrDefault(e.hoverBackgroundColor,a,i.color(t._model.backgroundColor).saturate(.5).darken(.1).rgbString()),t._model.borderColor=t.custom&&t.custom.hoverBorderColor?t.custom.hoverBorderColor:i.getValueAtIndexOrDefault(e.hoverBorderColor,a,i.color(t._model.borderColor).saturate(.5).darken(.1).rgbString()),t._model.borderWidth=t.custom&&t.custom.hoverBorderWidth?t.custom.hoverBorderWidth:i.getValueAtIndexOrDefault(e.hoverBorderWidth,a,t._model.borderWidth)},removeHoverStyle:function(t){var e=(this.chart.data.datasets[t._datasetIndex],t._index);t._model.radius=t.custom&&t.custom.radius?t.custom.radius:this.getRadius(this.getDataset().data[t._index]),t._model.backgroundColor=t.custom&&t.custom.backgroundColor?t.custom.backgroundColor:i.getValueAtIndexOrDefault(this.getDataset().backgroundColor,e,this.chart.options.elements.point.backgroundColor),t._model.borderColor=t.custom&&t.custom.borderColor?t.custom.borderColor:i.getValueAtIndexOrDefault(this.getDataset().borderColor,e,this.chart.options.elements.point.borderColor),t._model.borderWidth=t.custom&&t.custom.borderWidth?t.custom.borderWidth:i.getValueAtIndexOrDefault(this.getDataset().borderWidth,e,this.chart.options.elements.point.borderWidth)}})}.call(this),function(){"use strict";var t=this,e=t.Chart,i=e.helpers;e.defaults.doughnut={animation:{animateRotate:!0,animateScale:!1},aspectRatio:1,hover:{mode:"single"},legendCallback:function(t){var e=[];if(e.push(''),t.data.datasets.length)for(var i=0;i'),t.data.labels[i]&&e.push(t.data.labels[i]),e.push(" ");return e.push(" "),e.join("")},legend:{labels:{generateLabels:function(t){return t.labels.map(function(e,i){return{text:e,fillStyle:t.datasets[0].backgroundColor[i],hidden:isNaN(t.datasets[0].data[i]),index:i}})}},onClick:function(t,e){i.each(this.chart.data.datasets,function(t){t.metaHiddenData=t.metaHiddenData||[];var i=e.index;isNaN(t.data[i])?isNaN(t.metaHiddenData[i])||(t.data[i]=t.metaHiddenData[i]):(t.metaHiddenData[i]=t.data[i],t.data[i]=NaN)}),this.chart.update()}},cutoutPercentage:50,tooltips:{callbacks:{title:function(){return""},label:function(t,e){return e.labels[t.index]+": "+e.datasets[t.datasetIndex].data[t.index]}}}},e.defaults.pie=i.clone(e.defaults.doughnut),i.extend(e.defaults.pie,{cutoutPercentage:0}),e.controllers.doughnut=e.controllers.pie=e.DatasetController.extend({linkScales:function(){},addElements:function(){this.getDataset().metaData=this.getDataset().metaData||[],i.each(this.getDataset().data,function(t,i){this.getDataset().metaData[i]=this.getDataset().metaData[i]||new e.elements.Arc({_chart:this.chart.chart,_datasetIndex:this.index,_index:i})},this)},addElementAndReset:function(t,a){this.getDataset().metaData=this.getDataset().metaData||[];var s=new e.elements.Arc({_chart:this.chart.chart,_datasetIndex:this.index,_index:t});a&&i.isArray(this.getDataset().backgroundColor)&&this.getDataset().backgroundColor.splice(t,0,a),this.updateElement(s,t,!0),this.getDataset().metaData.splice(t,0,s)},getVisibleDatasetCount:function(){return i.where(this.chart.data.datasets,function(t){return i.isDatasetVisible(t)}).length},getRingIndex:function(t){for(var e=0,a=0;t>a;++a)i.isDatasetVisible(this.chart.data.datasets[a])&&++e;return e},update:function(t){var e=Math.min(this.chart.chartArea.right-this.chart.chartArea.left,this.chart.chartArea.bottom-this.chart.chartArea.top);this.chart.outerRadius=Math.max(e/2-this.chart.options.elements.arc.borderWidth/2,0),this.chart.innerRadius=Math.max(this.chart.options.cutoutPercentage?this.chart.outerRadius/100*this.chart.options.cutoutPercentage:1,0),this.chart.radiusLength=(this.chart.outerRadius-this.chart.innerRadius)/this.getVisibleDatasetCount(),this.getDataset().total=0,i.each(this.getDataset().data,function(t){isNaN(t)||(this.getDataset().total+=Math.abs(t))},this),this.outerRadius=this.chart.outerRadius-this.chart.radiusLength*this.getRingIndex(this.index),this.innerRadius=this.outerRadius-this.chart.radiusLength,i.each(this.getDataset().metaData,function(e,i){this.updateElement(e,i,t)},this)},updateElement:function(t,e,a){var s=(this.chart.chartArea.left+this.chart.chartArea.right)/2,o=(this.chart.chartArea.top+this.chart.chartArea.bottom)/2,n={x:s,y:o,startAngle:Math.PI*-.5,endAngle:Math.PI*-.5,circumference:this.chart.options.animation.animateRotate?0:this.calculateCircumference(this.getDataset().data[e]),
+outerRadius:this.chart.options.animation.animateScale?0:this.outerRadius,innerRadius:this.chart.options.animation.animateScale?0:this.innerRadius};i.extend(t,{_chart:this.chart.chart,_datasetIndex:this.index,_index:e,_model:a?n:{x:s,y:o,circumference:this.calculateCircumference(this.getDataset().data[e]),outerRadius:this.outerRadius,innerRadius:this.innerRadius,backgroundColor:t.custom&&t.custom.backgroundColor?t.custom.backgroundColor:i.getValueAtIndexOrDefault(this.getDataset().backgroundColor,e,this.chart.options.elements.arc.backgroundColor),hoverBackgroundColor:t.custom&&t.custom.hoverBackgroundColor?t.custom.hoverBackgroundColor:i.getValueAtIndexOrDefault(this.getDataset().hoverBackgroundColor,e,this.chart.options.elements.arc.hoverBackgroundColor),borderWidth:t.custom&&t.custom.borderWidth?t.custom.borderWidth:i.getValueAtIndexOrDefault(this.getDataset().borderWidth,e,this.chart.options.elements.arc.borderWidth),borderColor:t.custom&&t.custom.borderColor?t.custom.borderColor:i.getValueAtIndexOrDefault(this.getDataset().borderColor,e,this.chart.options.elements.arc.borderColor),label:i.getValueAtIndexOrDefault(this.getDataset().label,e,this.chart.data.labels[e])}}),a||(0===e?t._model.startAngle=Math.PI*-.5:t._model.startAngle=this.getDataset().metaData[e-1]._model.endAngle,t._model.endAngle=t._model.startAngle+t._model.circumference,e0&&!isNaN(t)?1.999999*Math.PI*(t/this.getDataset().total):0}})}.call(this),function(){"use strict";var t=this,e=t.Chart,i=e.helpers;e.defaults.line={hover:{mode:"label"},scales:{xAxes:[{type:"category",id:"x-axis-0"}],yAxes:[{type:"linear",id:"y-axis-0"}]}},e.controllers.line=e.DatasetController.extend({addElements:function(){this.getDataset().metaData=this.getDataset().metaData||[],this.getDataset().metaDataset=this.getDataset().metaDataset||new e.elements.Line({_chart:this.chart.chart,_datasetIndex:this.index,_points:this.getDataset().metaData}),i.each(this.getDataset().data,function(t,i){this.getDataset().metaData[i]=this.getDataset().metaData[i]||new e.elements.Point({_chart:this.chart.chart,_datasetIndex:this.index,_index:i})},this)},addElementAndReset:function(t){this.getDataset().metaData=this.getDataset().metaData||[];var i=new e.elements.Point({_chart:this.chart.chart,_datasetIndex:this.index,_index:t});this.updateElement(i,t,!0),this.getDataset().metaData.splice(t,0,i),this.updateBezierControlPoints()},update:function(t){var e,a=this.getDataset().metaDataset,s=this.getDataset().metaData,o=this.getScaleForId(this.getDataset().yAxisID);this.getScaleForId(this.getDataset().xAxisID);e=o.min<0&&o.max<0?o.getPixelForValue(o.max):o.min>0&&o.max>0?o.getPixelForValue(o.min):o.getPixelForValue(0),i.extend(a,{_scale:o,_datasetIndex:this.index,_children:s,_model:{tension:a.custom&&a.custom.tension?a.custom.tension:i.getValueOrDefault(this.getDataset().tension,this.chart.options.elements.line.tension),backgroundColor:a.custom&&a.custom.backgroundColor?a.custom.backgroundColor:this.getDataset().backgroundColor||this.chart.options.elements.line.backgroundColor,borderWidth:a.custom&&a.custom.borderWidth?a.custom.borderWidth:this.getDataset().borderWidth||this.chart.options.elements.line.borderWidth,borderColor:a.custom&&a.custom.borderColor?a.custom.borderColor:this.getDataset().borderColor||this.chart.options.elements.line.borderColor,borderCapStyle:a.custom&&a.custom.borderCapStyle?a.custom.borderCapStyle:this.getDataset().borderCapStyle||this.chart.options.elements.line.borderCapStyle,borderDash:a.custom&&a.custom.borderDash?a.custom.borderDash:this.getDataset().borderDash||this.chart.options.elements.line.borderDash,borderDashOffset:a.custom&&a.custom.borderDashOffset?a.custom.borderDashOffset:this.getDataset().borderDashOffset||this.chart.options.elements.line.borderDashOffset,borderJoinStyle:a.custom&&a.custom.borderJoinStyle?a.custom.borderJoinStyle:this.getDataset().borderJoinStyle||this.chart.options.elements.line.borderJoinStyle,fill:a.custom&&a.custom.fill?a.custom.fill:void 0!==this.getDataset().fill?this.getDataset().fill:this.chart.options.elements.line.fill,scaleTop:o.top,scaleBottom:o.bottom,scaleZero:e}}),a.pivot(),i.each(s,function(e,i){this.updateElement(e,i,t)},this),this.updateBezierControlPoints()},getPointBackgroundColor:function(t,e){var a=this.chart.options.elements.point.backgroundColor,s=this.getDataset();return t.custom&&t.custom.backgroundColor?a=t.custom.backgroundColor:s.pointBackgroundColor?a=i.getValueAtIndexOrDefault(s.pointBackgroundColor,e,a):s.backgroundColor&&(a=s.backgroundColor),a},getPointBorderColor:function(t,e){var a=this.chart.options.elements.point.borderColor,s=this.getDataset();return t.custom&&t.custom.borderColor?a=t.custom.borderColor:s.pointBorderColor?a=i.getValueAtIndexOrDefault(this.getDataset().pointBorderColor,e,a):s.borderColor&&(a=s.borderColor),a},getPointBorderWidth:function(t,e){var a=this.chart.options.elements.point.borderWidth,s=this.getDataset();return t.custom&&void 0!==t.custom.borderWidth?a=t.custom.borderWidth:void 0!==s.pointBorderWidth?a=i.getValueAtIndexOrDefault(s.pointBorderWidth,e,a):void 0!==s.borderWidth&&(a=s.borderWidth),a},updateElement:function(t,e,a){var s,o=this.getScaleForId(this.getDataset().yAxisID),n=this.getScaleForId(this.getDataset().xAxisID);s=o.min<0&&o.max<0?o.getPixelForValue(o.max):o.min>0&&o.max>0?o.getPixelForValue(o.min):o.getPixelForValue(0),i.extend(t,{_chart:this.chart.chart,_xScale:n,_yScale:o,_datasetIndex:this.index,_index:e,_model:{x:n.getPixelForValue(this.getDataset().data[e],e,this.index,this.chart.isCombo),y:a?s:this.calculatePointY(this.getDataset().data[e],e,this.index,this.chart.isCombo),tension:t.custom&&t.custom.tension?t.custom.tension:i.getValueOrDefault(this.getDataset().tension,this.chart.options.elements.line.tension),radius:t.custom&&t.custom.radius?t.custom.radius:i.getValueAtIndexOrDefault(this.getDataset().radius,e,this.chart.options.elements.point.radius),backgroundColor:this.getPointBackgroundColor(t,e),borderColor:this.getPointBorderColor(t,e),borderWidth:this.getPointBorderWidth(t,e),hitRadius:t.custom&&t.custom.hitRadius?t.custom.hitRadius:i.getValueAtIndexOrDefault(this.getDataset().hitRadius,e,this.chart.options.elements.point.hitRadius)}}),t._model.skip=t.custom&&t.custom.skip?t.custom.skip:isNaN(t._model.x)||isNaN(t._model.y)},calculatePointY:function(t,e,a,s){var o=(this.getScaleForId(this.getDataset().xAxisID),this.getScaleForId(this.getDataset().yAxisID));if(o.options.stacked){for(var n=0,r=0,h=this.chart.data.datasets.length-1;h>a;h--){var l=this.chart.data.datasets[h];i.isDatasetVisible(l)&&(l.data[e]<0?r+=l.data[e]||0:n+=l.data[e]||0)}return 0>t?o.getPixelForValue(r+t):o.getPixelForValue(n+t)}return o.getPixelForValue(t)},updateBezierControlPoints:function(){i.each(this.getDataset().metaData,function(t,e){var a=i.splineCurve(i.previousItem(this.getDataset().metaData,e)._model,t._model,i.nextItem(this.getDataset().metaData,e)._model,t._model.tension);t._model.controlPointPreviousX=Math.max(Math.min(a.previous.x,this.chart.chartArea.right),this.chart.chartArea.left),t._model.controlPointPreviousY=Math.max(Math.min(a.previous.y,this.chart.chartArea.bottom),this.chart.chartArea.top),t._model.controlPointNextX=Math.max(Math.min(a.next.x,this.chart.chartArea.right),this.chart.chartArea.left),t._model.controlPointNextY=Math.max(Math.min(a.next.y,this.chart.chartArea.bottom),this.chart.chartArea.top),t.pivot()},this)},draw:function(t){var e=t||1;i.each(this.getDataset().metaData,function(t,i){t.transition(e)},this),this.getDataset().metaDataset.transition(e).draw(),i.each(this.getDataset().metaData,function(t){t.draw()})},setHoverStyle:function(t){var e=this.chart.data.datasets[t._datasetIndex],a=t._index;t._model.radius=t.custom&&t.custom.hoverRadius?t.custom.hoverRadius:i.getValueAtIndexOrDefault(e.pointHoverRadius,a,this.chart.options.elements.point.hoverRadius),t._model.backgroundColor=t.custom&&t.custom.hoverBackgroundColor?t.custom.hoverBackgroundColor:i.getValueAtIndexOrDefault(e.pointHoverBackgroundColor,a,i.color(t._model.backgroundColor).saturate(.5).darken(.1).rgbString()),t._model.borderColor=t.custom&&t.custom.hoverBorderColor?t.custom.hoverBorderColor:i.getValueAtIndexOrDefault(e.pointHoverBorderColor,a,i.color(t._model.borderColor).saturate(.5).darken(.1).rgbString()),t._model.borderWidth=t.custom&&t.custom.hoverBorderWidth?t.custom.hoverBorderWidth:i.getValueAtIndexOrDefault(e.pointHoverBorderWidth,a,t._model.borderWidth)},removeHoverStyle:function(t){var e=(this.chart.data.datasets[t._datasetIndex],t._index);t._model.radius=t.custom&&t.custom.radius?t.custom.radius:i.getValueAtIndexOrDefault(this.getDataset().radius,e,this.chart.options.elements.point.radius),t._model.backgroundColor=this.getPointBackgroundColor(t,e),t._model.borderColor=this.getPointBorderColor(t,e),t._model.borderWidth=this.getPointBorderWidth(t,e)}})}.call(this),function(){"use strict";var t=this,e=t.Chart,i=e.helpers;e.defaults.polarArea={scale:{type:"radialLinear",lineArc:!0},animateRotate:!0,animateScale:!0,aspectRatio:1,legendCallback:function(t){var e=[];if(e.push(''),t.data.datasets.length)for(var i=0;i'),t.data.labels[i]&&e.push(t.data.labels[i]),e.push(" ");return e.push(" "),e.join("")},legend:{labels:{generateLabels:function(t){return t.labels.map(function(e,i){return{text:e,fillStyle:t.datasets[0].backgroundColor[i],hidden:isNaN(t.datasets[0].data[i]),index:i}})}},onClick:function(t,e){i.each(this.chart.data.datasets,function(t){t.metaHiddenData=t.metaHiddenData||[];var i=e.index;isNaN(t.data[i])?isNaN(t.metaHiddenData[i])||(t.data[i]=t.metaHiddenData[i]):(t.metaHiddenData[i]=t.data[i],t.data[i]=NaN)}),this.chart.update()}},tooltips:{callbacks:{title:function(){return""},label:function(t,e){return e.labels[t.index]+": "+t.yLabel}}}},e.controllers.polarArea=e.DatasetController.extend({linkScales:function(){},addElements:function(){this.getDataset().metaData=this.getDataset().metaData||[],i.each(this.getDataset().data,function(t,i){this.getDataset().metaData[i]=this.getDataset().metaData[i]||new e.elements.Arc({_chart:this.chart.chart,_datasetIndex:this.index,_index:i})},this)},addElementAndReset:function(t){this.getDataset().metaData=this.getDataset().metaData||[];var i=new e.elements.Arc({_chart:this.chart.chart,_datasetIndex:this.index,_index:t});this.updateElement(i,t,!0),this.getDataset().metaData.splice(t,0,i)},getVisibleDatasetCount:function(){return i.where(this.chart.data.datasets,function(t){return i.isDatasetVisible(t)}).length},update:function(t){var e=Math.min(this.chart.chartArea.right-this.chart.chartArea.left,this.chart.chartArea.bottom-this.chart.chartArea.top);this.chart.outerRadius=Math.max((e-this.chart.options.elements.arc.borderWidth/2)/2,0),this.chart.innerRadius=Math.max(this.chart.options.cutoutPercentage?this.chart.outerRadius/100*this.chart.options.cutoutPercentage:1,0),this.chart.radiusLength=(this.chart.outerRadius-this.chart.innerRadius)/this.getVisibleDatasetCount(),this.getDataset().total=0,i.each(this.getDataset().data,function(t){this.getDataset().total+=Math.abs(t)},this),this.outerRadius=this.chart.outerRadius-this.chart.radiusLength*this.index,this.innerRadius=this.outerRadius-this.chart.radiusLength,i.each(this.getDataset().metaData,function(e,i){this.updateElement(e,i,t)},this)},updateElement:function(t,e,a){for(var s=this.calculateCircumference(this.getDataset().data[e]),o=(this.chart.chartArea.left+this.chart.chartArea.right)/2,n=(this.chart.chartArea.top+this.chart.chartArea.bottom)/2,r=0,h=0;e>h;++h)isNaN(this.getDataset().data[h])||++r;var l=-.5*Math.PI+s*r,c=l+s,d={x:o,y:n,innerRadius:0,outerRadius:this.chart.options.animateScale?0:this.chart.scale.getDistanceFromCenterForValue(this.getDataset().data[e]),startAngle:this.chart.options.animateRotate?Math.PI*-.5:l,endAngle:this.chart.options.animateRotate?Math.PI*-.5:c,backgroundColor:t.custom&&t.custom.backgroundColor?t.custom.backgroundColor:i.getValueAtIndexOrDefault(this.getDataset().backgroundColor,e,this.chart.options.elements.arc.backgroundColor),hoverBackgroundColor:t.custom&&t.custom.hoverBackgroundColor?t.custom.hoverBackgroundColor:i.getValueAtIndexOrDefault(this.getDataset().hoverBackgroundColor,e,this.chart.options.elements.arc.hoverBackgroundColor),borderWidth:t.custom&&t.custom.borderWidth?t.custom.borderWidth:i.getValueAtIndexOrDefault(this.getDataset().borderWidth,e,this.chart.options.elements.arc.borderWidth),borderColor:t.custom&&t.custom.borderColor?t.custom.borderColor:i.getValueAtIndexOrDefault(this.getDataset().borderColor,e,this.chart.options.elements.arc.borderColor),label:i.getValueAtIndexOrDefault(this.chart.data.labels,e,this.chart.data.labels[e])};i.extend(t,{_chart:this.chart.chart,_datasetIndex:this.index,_index:e,_scale:this.chart.scale,_model:a?d:{x:o,y:n,innerRadius:0,outerRadius:this.chart.scale.getDistanceFromCenterForValue(this.getDataset().data[e]),startAngle:l,endAngle:c,backgroundColor:t.custom&&t.custom.backgroundColor?t.custom.backgroundColor:i.getValueAtIndexOrDefault(this.getDataset().backgroundColor,e,this.chart.options.elements.arc.backgroundColor),hoverBackgroundColor:t.custom&&t.custom.hoverBackgroundColor?t.custom.hoverBackgroundColor:i.getValueAtIndexOrDefault(this.getDataset().hoverBackgroundColor,e,this.chart.options.elements.arc.hoverBackgroundColor),borderWidth:t.custom&&t.custom.borderWidth?t.custom.borderWidth:i.getValueAtIndexOrDefault(this.getDataset().borderWidth,e,this.chart.options.elements.arc.borderWidth),borderColor:t.custom&&t.custom.borderColor?t.custom.borderColor:i.getValueAtIndexOrDefault(this.getDataset().borderColor,e,this.chart.options.elements.arc.borderColor),label:i.getValueAtIndexOrDefault(this.chart.data.labels,e,this.chart.data.labels[e])}}),t.pivot()},draw:function(t){var e=t||1;i.each(this.getDataset().metaData,function(t,i){t.transition(e).draw()},this)},setHoverStyle:function(t){var e=this.chart.data.datasets[t._datasetIndex],a=t._index;t._model.backgroundColor=t.custom&&t.custom.hoverBackgroundColor?t.custom.hoverBackgroundColor:i.getValueAtIndexOrDefault(e.hoverBackgroundColor,a,i.color(t._model.backgroundColor).saturate(.5).darken(.1).rgbString()),t._model.borderColor=t.custom&&t.custom.hoverBorderColor?t.custom.hoverBorderColor:i.getValueAtIndexOrDefault(e.hoverBorderColor,a,i.color(t._model.borderColor).saturate(.5).darken(.1).rgbString()),t._model.borderWidth=t.custom&&t.custom.hoverBorderWidth?t.custom.hoverBorderWidth:i.getValueAtIndexOrDefault(e.borderWidth,a,t._model.borderWidth)},removeHoverStyle:function(t){var e=(this.chart.data.datasets[t._datasetIndex],t._index);t._model.backgroundColor=t.custom&&t.custom.backgroundColor?t.custom.backgroundColor:i.getValueAtIndexOrDefault(this.getDataset().backgroundColor,e,this.chart.options.elements.arc.backgroundColor),t._model.borderColor=t.custom&&t.custom.borderColor?t.custom.borderColor:i.getValueAtIndexOrDefault(this.getDataset().borderColor,e,this.chart.options.elements.arc.borderColor),t._model.borderWidth=t.custom&&t.custom.borderWidth?t.custom.borderWidth:i.getValueAtIndexOrDefault(this.getDataset().borderWidth,e,this.chart.options.elements.arc.borderWidth)},calculateCircumference:function(t){if(isNaN(t))return 0;var e=i.where(this.getDataset().data,function(t){return isNaN(t)}).length;return 2*Math.PI/(this.getDataset().data.length-e)}})}.call(this),function(){"use strict";var t=this,e=t.Chart,i=e.helpers;e.defaults.radar={scale:{type:"radialLinear"},elements:{line:{tension:0}}},e.controllers.radar=e.DatasetController.extend({linkScales:function(){},addElements:function(){this.getDataset().metaData=this.getDataset().metaData||[],this.getDataset().metaDataset=this.getDataset().metaDataset||new e.elements.Line({_chart:this.chart.chart,_datasetIndex:this.index,_points:this.getDataset().metaData,_loop:!0}),i.each(this.getDataset().data,function(t,i){this.getDataset().metaData[i]=this.getDataset().metaData[i]||new e.elements.Point({_chart:this.chart.chart,_datasetIndex:this.index,_index:i,_model:{x:0,y:0}})},this)},addElementAndReset:function(t){this.getDataset().metaData=this.getDataset().metaData||[];var i=new e.elements.Point({_chart:this.chart.chart,_datasetIndex:this.index,_index:t});this.updateElement(i,t,!0),this.getDataset().metaData.splice(t,0,i),this.updateBezierControlPoints()},update:function(t){var e,a=(this.getDataset().metaDataset,this.getDataset().metaData),s=this.chart.scale;e=s.min<0&&s.max<0?s.getPointPositionForValue(0,s.max):s.min>0&&s.max>0?s.getPointPositionForValue(0,s.min):s.getPointPositionForValue(0,0),i.extend(this.getDataset().metaDataset,{_datasetIndex:this.index,_children:this.getDataset().metaData,_model:{tension:i.getValueOrDefault(this.getDataset().tension,this.chart.options.elements.line.tension),backgroundColor:this.getDataset().backgroundColor||this.chart.options.elements.line.backgroundColor,borderWidth:this.getDataset().borderWidth||this.chart.options.elements.line.borderWidth,borderColor:this.getDataset().borderColor||this.chart.options.elements.line.borderColor,fill:void 0!==this.getDataset().fill?this.getDataset().fill:this.chart.options.elements.line.fill,scaleTop:s.top,scaleBottom:s.bottom,scaleZero:e}}),this.getDataset().metaDataset.pivot(),i.each(a,function(e,i){this.updateElement(e,i,t)},this),this.updateBezierControlPoints()},updateElement:function(t,e,a){var s=this.chart.scale.getPointPositionForValue(e,this.getDataset().data[e]);i.extend(t,{_datasetIndex:this.index,_index:e,_scale:this.chart.scale,_model:{x:a?this.chart.scale.xCenter:s.x,y:a?this.chart.scale.yCenter:s.y,tension:t.custom&&t.custom.tension?t.custom.tension:i.getValueOrDefault(this.getDataset().tension,this.chart.options.elements.line.tension),radius:t.custom&&t.custom.radius?t.custom.pointRadius:i.getValueAtIndexOrDefault(this.getDataset().pointRadius,e,this.chart.options.elements.point.radius),backgroundColor:t.custom&&t.custom.backgroundColor?t.custom.backgroundColor:i.getValueAtIndexOrDefault(this.getDataset().pointBackgroundColor,e,this.chart.options.elements.point.backgroundColor),borderColor:t.custom&&t.custom.borderColor?t.custom.borderColor:i.getValueAtIndexOrDefault(this.getDataset().pointBorderColor,e,this.chart.options.elements.point.borderColor),borderWidth:t.custom&&t.custom.borderWidth?t.custom.borderWidth:i.getValueAtIndexOrDefault(this.getDataset().pointBorderWidth,e,this.chart.options.elements.point.borderWidth),hitRadius:t.custom&&t.custom.hitRadius?t.custom.hitRadius:i.getValueAtIndexOrDefault(this.getDataset().hitRadius,e,this.chart.options.elements.point.hitRadius)}}),t._model.skip=t.custom&&t.custom.skip?t.custom.skip:isNaN(t._model.x)||isNaN(t._model.y)},updateBezierControlPoints:function(){i.each(this.getDataset().metaData,function(t,e){var a=i.splineCurve(i.previousItem(this.getDataset().metaData,e,!0)._model,t._model,i.nextItem(this.getDataset().metaData,e,!0)._model,t._model.tension);t._model.controlPointPreviousX=Math.max(Math.min(a.previous.x,this.chart.chartArea.right),this.chart.chartArea.left),t._model.controlPointPreviousY=Math.max(Math.min(a.previous.y,this.chart.chartArea.bottom),this.chart.chartArea.top),t._model.controlPointNextX=Math.max(Math.min(a.next.x,this.chart.chartArea.right),this.chart.chartArea.left),t._model.controlPointNextY=Math.max(Math.min(a.next.y,this.chart.chartArea.bottom),this.chart.chartArea.top),t.pivot()},this)},draw:function(t){var e=t||1;i.each(this.getDataset().metaData,function(t,i){t.transition(e)},this),this.getDataset().metaDataset.transition(e).draw(),i.each(this.getDataset().metaData,function(t){t.draw()})},setHoverStyle:function(t){var e=this.chart.data.datasets[t._datasetIndex],a=t._index;t._model.radius=t.custom&&t.custom.radius?t.custom.radius:i.getValueAtIndexOrDefault(e.pointHoverRadius,a,this.chart.options.elements.point.hoverRadius),t._model.backgroundColor=t.custom&&t.custom.hoverBackgroundColor?t.custom.hoverBackgroundColor:i.getValueAtIndexOrDefault(e.pointHoverBackgroundColor,a,i.color(t._model.backgroundColor).saturate(.5).darken(.1).rgbString()),t._model.borderColor=t.custom&&t.custom.hoverBorderColor?t.custom.hoverBorderColor:i.getValueAtIndexOrDefault(e.pointHoverBorderColor,a,i.color(t._model.borderColor).saturate(.5).darken(.1).rgbString()),t._model.borderWidth=t.custom&&t.custom.hoverBorderWidth?t.custom.hoverBorderWidth:i.getValueAtIndexOrDefault(e.pointBorderWidth,a,t._model.borderWidth)},removeHoverStyle:function(t){var e=(this.chart.data.datasets[t._datasetIndex],t._index);t._model.radius=t.custom&&t.custom.radius?t.custom.radius:i.getValueAtIndexOrDefault(this.getDataset().radius,e,this.chart.options.elements.point.radius),t._model.backgroundColor=t.custom&&t.custom.backgroundColor?t.custom.backgroundColor:i.getValueAtIndexOrDefault(this.getDataset().pointBackgroundColor,e,this.chart.options.elements.point.backgroundColor),t._model.borderColor=t.custom&&t.custom.borderColor?t.custom.borderColor:i.getValueAtIndexOrDefault(this.getDataset().pointBorderColor,e,this.chart.options.elements.point.borderColor),t._model.borderWidth=t.custom&&t.custom.borderWidth?t.custom.borderWidth:i.getValueAtIndexOrDefault(this.getDataset().pointBorderWidth,e,this.chart.options.elements.point.borderWidth)}})}.call(this),function(){"use strict";var t=this,e=t.Chart,i=(e.helpers,{position:"bottom"}),a=e.Scale.extend({buildTicks:function(t){this.ticks=this.chart.data.labels},getLabelForIndex:function(t,e){return this.ticks[t]},getPixelForValue:function(t,e,i,a){if(this.isHorizontal()){var s=this.width-(this.paddingLeft+this.paddingRight),o=s/Math.max(this.chart.data.labels.length-(this.options.gridLines.offsetGridLines?0:1),1),n=o*e+this.paddingLeft;return this.options.gridLines.offsetGridLines&&a&&(n+=o/2),this.left+Math.round(n)}var r=this.height-(this.paddingTop+this.paddingBottom),h=r/Math.max(this.chart.data.labels.length-(this.options.gridLines.offsetGridLines?0:1),1),l=h*e+this.paddingTop;return this.options.gridLines.offsetGridLines&&a&&(l+=h/2),this.top+Math.round(l)}});e.scaleService.registerScaleType("category",a,i)}.call(this),function(){"use strict";var t=this,e=t.Chart,i=e.helpers,a={position:"left",ticks:{callback:function(t,e,a){var s=a[1]-a[0];Math.abs(s)>1&&t!==Math.floor(t)&&(s=t-Math.floor(t));var o=i.log10(Math.abs(s)),n="";if(0!==t){var r=-1*Math.floor(o);r=Math.max(Math.min(r,20),0),n=t.toFixed(r)}else n="0";return n}}},s=e.Scale.extend({determineDataLimits:function(){if(this.min=null,this.max=null,this.options.stacked){var t={};i.each(this.chart.data.datasets,function(e){void 0===t[e.type]&&(t[e.type]={positiveValues:[],negativeValues:[]});var a=t[e.type].positiveValues,s=t[e.type].negativeValues;i.isDatasetVisible(e)&&(this.isHorizontal()?e.xAxisID===this.id:e.yAxisID===this.id)&&i.each(e.data,function(t,e){var i=+this.getRightValue(t);isNaN(i)||(a[e]=a[e]||0,s[e]=s[e]||0,this.options.relativePoints?a[e]=100:0>i?s[e]+=i:a[e]+=i)},this)},this),i.each(t,function(t){var e=t.positiveValues.concat(t.negativeValues),a=i.min(e),s=i.max(e);this.min=null===this.min?a:Math.min(this.min,a),this.max=null===this.max?s:Math.max(this.max,s)},this)}else i.each(this.chart.data.datasets,function(t){i.isDatasetVisible(t)&&(this.isHorizontal()?t.xAxisID===this.id:t.yAxisID===this.id)&&i.each(t.data,function(t,e){var i=+this.getRightValue(t);isNaN(i)||(null===this.min?this.min=i:ithis.max&&(this.max=i))},this)},this);if(this.options.ticks.beginAtZero){var e=i.sign(this.min),a=i.sign(this.max);0>e&&0>a?this.max=0:e>0&&a>0&&(this.min=0)}void 0!==this.options.ticks.min?this.min=this.options.ticks.min:void 0!==this.options.ticks.suggestedMin&&(this.min=Math.min(this.min,this.options.ticks.suggestedMin)),void 0!==this.options.ticks.max?this.max=this.options.ticks.max:void 0!==this.options.ticks.suggestedMax&&(this.max=Math.max(this.max,this.options.ticks.suggestedMax)),this.min===this.max&&(this.min--,this.max++)},buildTicks:function(){this.ticks=[];var t;t=this.isHorizontal()?Math.min(this.options.ticks.maxTicksLimit?this.options.ticks.maxTicksLimit:11,Math.ceil(this.width/50)):Math.min(this.options.ticks.maxTicksLimit?this.options.ticks.maxTicksLimit:11,Math.ceil(this.height/(2*this.options.ticks.fontSize))),t=Math.max(2,t);var e=i.niceNum(this.max-this.min,!1),a=i.niceNum(e/(t-1),!0),s=Math.floor(this.min/a)*a,o=Math.ceil(this.max/a)*a,n=Math.ceil((o-s)/a);this.ticks.push(void 0!==this.options.ticks.min?this.options.ticks.min:s);for(var r=1;n>r;++r)this.ticks.push(s+r*a);this.ticks.push(void 0!==this.options.ticks.max?this.options.ticks.max:o),("left"==this.options.position||"right"==this.options.position)&&this.ticks.reverse(),this.max=i.max(this.ticks),this.min=i.min(this.ticks),this.ticksAsNumbers=this.ticks.slice(),this.options.ticks.reverse?(this.ticks.reverse(),this.start=this.max,this.end=this.min):(this.start=this.min,this.end=this.max),this.zeroLineIndex=this.ticks.indexOf(0)},getLabelForIndex:function(t,e){return+this.getRightValue(this.chart.data.datasets[e].data[t])},getPixelForValue:function(t,e,i,a){var s,o=+this.getRightValue(t),n=this.end-this.start;if(this.isHorizontal()){var r=this.width-(this.paddingLeft+this.paddingRight);return s=this.left+r/n*(o-this.start),Math.round(s+this.paddingLeft)}var h=this.height-(this.paddingTop+this.paddingBottom);return s=this.bottom-this.paddingBottom-h/n*(o-this.start),Math.round(s)},getPixelForTick:function(t,e){return this.getPixelForValue(this.ticksAsNumbers[t],null,null,e)}});e.scaleService.registerScaleType("linear",s,a)}.call(this),function(){"use strict";var t=this,e=t.Chart,i=e.helpers,a={position:"left",ticks:{callback:function(t,i,a){var s=t/Math.pow(10,Math.floor(e.helpers.log10(t)));return 1===s||2===s||5===s||0===i||i===a.length-1?t.toExponential():""}}},s=e.Scale.extend({determineDataLimits:function(){if(this.min=null,this.max=null,this.options.stacked){var t={};i.each(this.chart.data.datasets,function(e){i.isDatasetVisible(e)&&(this.isHorizontal()?e.xAxisID===this.id:e.yAxisID===this.id)&&(void 0===t[e.type]&&(t[e.type]=[]),i.each(e.data,function(i,a){var s=t[e.type],o=+this.getRightValue(i);isNaN(o)||(s[a]=s[a]||0,this.options.relativePoints?s[a]=100:s[a]+=o)},this))},this),i.each(t,function(t){var e=i.min(t),a=i.max(t);this.min=null===this.min?e:Math.min(this.min,e),this.max=null===this.max?a:Math.max(this.max,a)},this)}else i.each(this.chart.data.datasets,function(t){i.isDatasetVisible(t)&&(this.isHorizontal()?t.xAxisID===this.id:t.yAxisID===this.id)&&i.each(t.data,function(t,e){var i=+this.getRightValue(t);isNaN(i)||(null===this.min?this.min=i:ithis.max&&(this.max=i))},this)},this);this.min=void 0!==this.options.ticks.min?this.options.ticks.min:this.min,this.max=void 0!==this.options.ticks.max?this.options.ticks.max:this.max,this.min===this.max&&(0!==this.min&&null!==this.min?(this.min=Math.pow(10,Math.floor(i.log10(this.min))-1),this.max=Math.pow(10,Math.floor(i.log10(this.max))+1)):(this.min=1,this.max=10))},buildTicks:function(){this.tickValues=[];for(var t=void 0!==this.options.ticks.min?this.options.ticks.min:Math.pow(10,Math.floor(i.log10(this.min)));tthis.max&&(this.max=i))},this)},this),this.min===this.max&&(this.min--,this.max++),this.options.ticks.beginAtZero){var t=i.sign(this.min),e=i.sign(this.max);0>t&&0>e?this.max=0:t>0&&e>0&&(this.min=0)}},buildTicks:function(){this.ticks=[];var t=Math.min(this.options.ticks.maxTicksLimit?this.options.ticks.maxTicksLimit:11,Math.ceil(this.drawingArea/(1.5*this.options.ticks.fontSize)));t=Math.max(2,t);for(var e=i.niceNum(this.max-this.min,!1),a=i.niceNum(e/(t-1),!0),s=Math.floor(this.min/a)*a,o=Math.ceil(this.max/a)*a,n=s;o>=n;n+=a)this.ticks.push(n);this.max=i.max(this.ticks),this.min=i.min(this.ticks),this.options.ticks.reverse?(this.ticks.reverse(),this.start=this.max,this.end=this.min):(this.start=this.min,this.end=this.max),this.zeroLineIndex=this.ticks.indexOf(0)},getLabelForIndex:function(t,e){return+this.getRightValue(this.chart.data.datasets[e].data[t]);
+},getCircumference:function(){return 2*Math.PI/this.getValueCount()},fit:function(){var t,e,a,s,o,n,r,h,l,c,d,u,g=i.min([this.height/2-this.options.pointLabels.fontSize-5,this.width/2]),m=this.width,f=0;for(this.ctx.font=i.fontString(this.options.pointLabels.fontSize,this.options.pointLabels.fontStyle,this.options.pointLabels.fontFamily),e=0;em&&(m=t.x+s,o=e),t.x-sm&&(m=t.x+a,o=e):e>this.getValueCount()/2&&t.x-a0||this.options.reverse){var s=this.getDistanceFromCenterForValue(this.ticks[a]),o=this.yCenter-s;if(this.options.gridLines.display)if(t.strokeStyle=this.options.gridLines.color,t.lineWidth=this.options.gridLines.lineWidth,this.options.lineArc)t.beginPath(),t.arc(this.xCenter,this.yCenter,s,0,2*Math.PI),t.closePath(),t.stroke();else{t.beginPath();for(var n=0;n=0;e--){if(this.options.angleLines.display){var a=this.getPointPosition(e,this.getDistanceFromCenterForValue(this.options.reverse?this.min:this.max));t.beginPath(),t.moveTo(this.xCenter,this.yCenter),t.lineTo(a.x,a.y),t.stroke(),t.closePath()}var s=this.getPointPosition(e,this.getDistanceFromCenterForValue(this.options.reverse?this.min:this.max)+5);t.font=i.fontString(this.options.pointLabels.fontSize,this.options.pointLabels.fontStyle,this.options.pointLabels.fontFamily),t.fillStyle=this.options.pointLabels.fontColor;var o=this.chart.data.labels.length,n=this.chart.data.labels.length/2,r=n/2,h=r>e||e>o-r,l=e===r||e===o-r;0===e?t.textAlign="center":e===n?t.textAlign="center":n>e?t.textAlign="left":t.textAlign="right",l?t.textBaseline="middle":h?t.textBaseline="bottom":t.textBaseline="top",t.fillText(this.chart.data.labels[e],s.x,s.y)}}}}});e.scaleService.registerScaleType("radialLinear",s,a)}.call(this),function(t){"use strict";if(!t)return void console.warn("Chart.js - Moment.js could not be found! You must include it before Chart.js to use the time scale. Download at http://momentjs.com/");var e=this,i=e.Chart,a=i.helpers,s={units:[{name:"millisecond",steps:[1,2,5,10,20,50,100,250,500]},{name:"second",steps:[1,2,5,10,30]},{name:"minute",steps:[1,2,5,10,30]},{name:"hour",steps:[1,2,3,6,12]},{name:"day",steps:[1,2,5]},{name:"week",maxStep:4},{name:"month",maxStep:3},{name:"quarter",maxStep:4},{name:"year",maxStep:!1}]},o={position:"bottom",time:{format:!1,unit:!1,round:!1,displayFormat:!1,displayFormats:{millisecond:"SSS [ms]",second:"h:mm:ss a",minute:"h:mm:ss a",hour:"MMM D, hA",day:"ll",week:"ll",month:"MMM YYYY",quarter:"[Q]Q - YYYY",year:"YYYY"}}},n=i.Scale.extend({getLabelMoment:function(t,e){return this.labelMoments[t][e]},determineDataLimits:function(){this.labelMoments=[];var e=[];this.chart.data.labels&&this.chart.data.labels.length>0?(a.each(this.chart.data.labels,function(t,i){var a=this.parseTime(t);this.options.time.round&&a.startOf(this.options.time.round),e.push(a)},this),this.options.time.min?this.firstTick=this.parseTime(this.options.time.min):this.firstTick=t.min.call(this,e),this.options.time.max?this.lastTick=this.parseTime(this.options.time.max):this.lastTick=t.max.call(this,e)):(this.firstTick=null,this.lastTick=null),a.each(this.chart.data.datasets,function(i,s){var o=[];"object"==typeof i.data[0]?a.each(i.data,function(e,i){var a=this.parseTime(this.getRightValue(e));this.options.time.round&&a.startOf(this.options.time.round),o.push(a),this.firstTick=null!==this.firstTick?t.min(this.firstTick,a):a,this.lastTick=null!==this.lastTick?t.max(this.lastTick,a):a},this):o=e,this.labelMoments.push(o)},this),this.firstTick=(this.firstTick||t()).clone(),this.lastTick=(this.lastTick||t()).clone()},buildTicks:function(t){if(this.ticks=[],this.unitScale=1,this.options.time.unit)this.tickUnit=this.options.time.unit||"day",this.displayFormat=this.options.time.displayFormats[this.tickUnit],this.tickRange=Math.ceil(this.lastTick.diff(this.firstTick,this.tickUnit,!0));else{var e=this.width-(this.paddingLeft+this.paddingRight),i=e/(this.options.ticks.fontSize+10),o=this.options.time.round?0:2;this.tickUnit="millisecond",this.tickRange=Math.ceil(this.lastTick.diff(this.firstTick,this.tickUnit,!0)+o),this.displayFormat=this.options.time.displayFormats[this.tickUnit];for(var n=0,r=s.units[n];nMath.ceil(this.tickRange/i)){this.unitScale=r.steps[h];break}break}if(r.maxStep===!1||Math.ceil(this.tickRange/i)1.5*Math.PI?a.startAngle-2*Math.PI:a.startAngle,n=a.endAngle<-.5*Math.PI?a.endAngle+2*Math.PI:a.endAngle>1.5*Math.PI?a.endAngle-2*Math.PI:a.endAngle,r=s.angle>=o&&s.angle<=n,h=s.distance>=a.innerRadius&&s.distance<=a.outerRadius;return r&&h}return!1},tooltipPosition:function(){var t=this._view,e=t.startAngle+(t.endAngle-t.startAngle)/2,i=(t.outerRadius-t.innerRadius)/2+t.innerRadius;return{x:t.x+Math.cos(e)*i,y:t.y+Math.sin(e)*i}},draw:function(){var t=this._chart.ctx,e=this._view;t.beginPath(),t.arc(e.x,e.y,e.outerRadius,e.startAngle,e.endAngle),t.arc(e.x,e.y,e.innerRadius,e.endAngle,e.startAngle,!0),t.closePath(),t.strokeStyle=e.borderColor,t.lineWidth=e.borderWidth,t.fillStyle=e.backgroundColor,t.fill(),t.lineJoin="bevel",e.borderWidth&&t.stroke()}})}.call(this),function(){"use strict";var t=this,e=t.Chart,i=e.helpers;e.defaults.global.elements.line={tension:.4,backgroundColor:e.defaults.global.defaultColor,borderWidth:3,borderColor:e.defaults.global.defaultColor,borderCapStyle:"butt",borderDash:[],borderDashOffset:0,borderJoinStyle:"miter",fill:!0},e.elements.Line=e.Element.extend({lineToNextPoint:function(t,e,i,a,s){var o=this._chart.ctx;e._view.skip?a.call(this,t,e,i):t._view.skip?s.call(this,t,e,i):0===e._view.tension?o.lineTo(e._view.x,e._view.y):o.bezierCurveTo(t._view.controlPointNextX,t._view.controlPointNextY,e._view.controlPointPreviousX,e._view.controlPointPreviousY,e._view.x,e._view.y)},draw:function(){function t(t){n._view.skip||r._view.skip?t&&o.lineTo(a._view.scaleZero.x,a._view.scaleZero.y):o.bezierCurveTo(r._view.controlPointNextX,r._view.controlPointNextY,n._view.controlPointPreviousX,n._view.controlPointPreviousY,n._view.x,n._view.y)}var a=this,s=this._view,o=this._chart.ctx,n=this._children[0],r=this._children[this._children.length-1];o.save(),this._children.length>0&&s.fill&&(o.beginPath(),i.each(this._children,function(t,e){var a=i.previousItem(this._children,e),n=i.nextItem(this._children,e);0===e?(this._loop?o.moveTo(s.scaleZero.x,s.scaleZero.y):o.moveTo(t._view.x,s.scaleZero),t._view.skip?this._loop||o.moveTo(n._view.x,this._view.scaleZero):o.lineTo(t._view.x,t._view.y)):this.lineToNextPoint(a,t,n,function(t,e,i){this._loop?o.lineTo(this._view.scaleZero.x,this._view.scaleZero.y):(o.lineTo(t._view.x,this._view.scaleZero),o.moveTo(i._view.x,this._view.scaleZero))},function(t,e){o.lineTo(e._view.x,e._view.y)})},this),this._loop?t(!0):(o.lineTo(this._children[this._children.length-1]._view.x,s.scaleZero),o.lineTo(this._children[0]._view.x,s.scaleZero)),o.fillStyle=s.backgroundColor||e.defaults.global.defaultColor,o.closePath(),o.fill()),o.lineCap=s.borderCapStyle||e.defaults.global.elements.line.borderCapStyle,o.setLineDash&&o.setLineDash(s.borderDash||e.defaults.global.elements.line.borderDash),o.lineDashOffset=s.borderDashOffset||e.defaults.global.elements.line.borderDashOffset,o.lineJoin=s.borderJoinStyle||e.defaults.global.elements.line.borderJoinStyle,o.lineWidth=s.borderWidth||e.defaults.global.elements.line.borderWidth,o.strokeStyle=s.borderColor||e.defaults.global.defaultColor,o.beginPath(),i.each(this._children,function(t,e){var a=i.previousItem(this._children,e),s=i.nextItem(this._children,e);0===e?o.moveTo(t._view.x,t._view.y):this.lineToNextPoint(a,t,s,function(t,e,i){o.moveTo(i._view.x,i._view.y)},function(t,e){o.moveTo(e._view.x,e._view.y)})},this),this._loop&&this._children.length>0&&t(),o.stroke(),o.restore()}})}.call(this),function(){"use strict";var t=this,e=t.Chart;e.helpers;e.defaults.global.elements.point={radius:3,backgroundColor:e.defaults.global.defaultColor,borderWidth:1,borderColor:e.defaults.global.defaultColor,hitRadius:1,hoverRadius:4,hoverBorderWidth:1},e.elements.Point=e.Element.extend({inRange:function(t,e){var i=this._view;if(i){var a=i.hitRadius+i.radius;return Math.pow(t-i.x,2)+Math.pow(e-i.y,2)0||t.borderWidth>0)&&(i.beginPath(),i.arc(t.x,t.y,t.radius||e.defaults.global.elements.point.radius,0,2*Math.PI),i.closePath(),i.strokeStyle=t.borderColor||e.defaults.global.defaultColor,i.lineWidth=t.borderWidth||e.defaults.global.elements.point.borderWidth,i.fillStyle=t.backgroundColor||e.defaults.global.defaultColor,i.fill(),i.stroke())}})}.call(this),function(){"use strict";var t=this,e=t.Chart;e.helpers;e.defaults.global.elements.rectangle={backgroundColor:e.defaults.global.defaultColor,borderWidth:0,borderColor:e.defaults.global.defaultColor},e.elements.Rectangle=e.Element.extend({draw:function(){var t=this._chart.ctx,e=this._view,i=e.width/2,a=e.x-i,s=e.x+i,o=e.base-(e.base-e.y),n=e.borderWidth/2;e.borderWidth&&(a+=n,s-=n,o+=n),t.beginPath(),t.fillStyle=e.backgroundColor,t.strokeStyle=e.borderColor,t.lineWidth=e.borderWidth,t.moveTo(a,e.base),t.lineTo(a,o),t.lineTo(s,o),t.lineTo(s,e.base),t.fill(),e.borderWidth&&t.stroke()},height:function(){var t=this._view;return t.base-t.y},inRange:function(t,e){var i=this._view,a=!1;return i&&(a=i.y=i.x-i.width/2&&t<=i.x+i.width/2&&e>=i.y&&e<=i.base:t>=i.x-i.width/2&&t<=i.x+i.width/2&&e>=i.base&&e<=i.y),a},inLabelRange:function(t){var e=this._view;return e?t>=e.x-e.width/2&&t<=e.x+e.width/2:!1},tooltipPosition:function(){var t=this._view;return{x:t.x,y:t.y}}})}.call(this),function(){"use strict";var t=this,e=t.Chart;e.helpers;e.Bar=function(t,i){return i.type="bar",new e(t,i)}}.call(this),function(){"use strict";var t=this,e=t.Chart,i=(e.helpers,{hover:{mode:"single"},scales:{xAxes:[{type:"linear",position:"bottom",id:"x-axis-0"}],yAxes:[{type:"linear",position:"left",id:"y-axis-0"}]},tooltips:{callbacks:{title:function(t,e){return""},label:function(t,e){return"("+t.xLabel+", "+t.yLabel+")"}}}});e.defaults.bubble=i,e.Bubble=function(t,i){return i.type="bubble",new e(t,i)}}.call(this),function(){"use strict";var t=this,e=t.Chart;e.helpers;e.Doughnut=function(t,i){return i.type="doughnut",new e(t,i)}}.call(this),function(){"use strict";var t=this,e=t.Chart;e.helpers;e.Line=function(t,i){return i.type="line",new e(t,i)}}.call(this),function(){"use strict";var t=this,e=t.Chart;e.helpers;e.PolarArea=function(t,i){return i.type="polarArea",new e(t,i)}}.call(this),function(){"use strict";var t=this,e=t.Chart,i=e.helpers,a={aspectRatio:1};e.Radar=function(t,s){return s.options=i.configMerge(a,s.options),s.type="radar",new e(t,s)}}.call(this),function(){"use strict";var t=this,e=t.Chart,i=(e.helpers,{hover:{mode:"single"},scales:{xAxes:[{type:"linear",position:"bottom",id:"x-axis-1"}],yAxes:[{type:"linear",position:"left",id:"y-axis-1"}]},tooltips:{callbacks:{title:function(t,e){return""},label:function(t,e){return"("+t.xLabel+", "+t.yLabel+")"}}}});e.defaults.scatter=i,e.controllers.scatter=e.controllers.line,e.Scatter=function(t,i){return i.type="scatter",new e(t,i)}}.call(this),Chart});
\ No newline at end of file
diff --git a/public/vendor/chartjs/LICENSE.md b/public/vendor/chartjs/LICENSE.md
index 7d4dc492..e10bc0ff 100644
--- a/public/vendor/chartjs/LICENSE.md
+++ b/public/vendor/chartjs/LICENSE.md
@@ -1,4 +1,4 @@
-Copyright (c) 2013 Nick Downie
+Copyright (c) 2013-2015 Nick Downie
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
diff --git a/public/vendor/chartjs/component.json b/public/vendor/chartjs/component.json
deleted file mode 100644
index 11e11c79..00000000
--- a/public/vendor/chartjs/component.json
+++ /dev/null
@@ -1,11 +0,0 @@
-{
- "name": "Chart.js",
- "version": "0.2.0",
- "description": "Simple HTML5 Charts using the canvas element",
- "keywords": ["charts"],
- "homepage": "https://github.com/nnnick/Chart.js",
- "author": "nnnick",
- "main": ["Chart.min.js"],
- "dependencies": {
- }
-}
\ No newline at end of file
diff --git a/public/vendor/chartjs/docs/Chart.js b/public/vendor/chartjs/docs/Chart.js
deleted file mode 100644
index a25acef1..00000000
--- a/public/vendor/chartjs/docs/Chart.js
+++ /dev/null
@@ -1,1443 +0,0 @@
-/*!
- * Chart.js
- * http://chartjs.org/
- *
- * Copyright 2013 Nick Downie
- * Released under the MIT license
- * https://github.com/nnnick/Chart.js/blob/master/LICENSE.md
- */
-
-//Define the global Chart Variable as a class.
-var Chart = function(context){
-
- var chart = this;
-
-
- //Easing functions adapted from Robert Penner's easing equations
- //http://www.robertpenner.com/easing/
-
- var animationOptions = {
- linear : function (t){
- return t;
- },
- easeInQuad: function (t) {
- return t*t;
- },
- easeOutQuad: function (t) {
- return -1 *t*(t-2);
- },
- easeInOutQuad: function (t) {
- if ((t/=1/2) < 1) return 1/2*t*t;
- return -1/2 * ((--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) {
- if ((t/=1/2) < 1) return 1/2*t*t*t;
- return 1/2*((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) {
- if ((t/=1/2) < 1) return 1/2*t*t*t*t;
- return -1/2 * ((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) {
- if ((t/=1/2) < 1) return 1/2*t*t*t*t*t;
- return 1/2*((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 -1/2 * (Math.cos(Math.PI*t/1) - 1);
- },
- easeInExpo: function (t) {
- return (t==0) ? 1 : 1 * Math.pow(2, 10 * (t/1 - 1));
- },
- easeOutExpo: function (t) {
- return (t==1) ? 1 : 1 * (-Math.pow(2, -10 * t/1) + 1);
- },
- easeInOutExpo: function (t) {
- if (t==0) return 0;
- if (t==1) return 1;
- if ((t/=1/2) < 1) return 1/2 * Math.pow(2, 10 * (t - 1));
- return 1/2 * (-Math.pow(2, -10 * --t) + 2);
- },
- easeInCirc: function (t) {
- if (t>=1) return t;
- return -1 * (Math.sqrt(1 - (t/=1)*t) - 1);
- },
- easeOutCirc: function (t) {
- return 1 * Math.sqrt(1 - (t=t/1-1)*t);
- },
- easeInOutCirc: function (t) {
- if ((t/=1/2) < 1) return -1/2 * (Math.sqrt(1 - t*t) - 1);
- return 1/2 * (Math.sqrt(1 - (t-=2)*t) + 1);
- },
- easeInElastic: function (t) {
- var s=1.70158;var p=0;var a=1;
- if (t==0) return 0; if ((t/=1)==1) return 1; if (!p) p=1*.3;
- if (a < Math.abs(1)) { a=1; var s=p/4; }
- else var s = p/(2*Math.PI) * Math.asin (1/a);
- return -(a*Math.pow(2,10*(t-=1)) * Math.sin( (t*1-s)*(2*Math.PI)/p ));
- },
- easeOutElastic: function (t) {
- var s=1.70158;var p=0;var a=1;
- if (t==0) return 0; if ((t/=1)==1) return 1; if (!p) p=1*.3;
- if (a < Math.abs(1)) { a=1; var s=p/4; }
- else var s = p/(2*Math.PI) * Math.asin (1/a);
- return a*Math.pow(2,-10*t) * Math.sin( (t*1-s)*(2*Math.PI)/p ) + 1;
- },
- easeInOutElastic: function (t) {
- var s=1.70158;var p=0;var a=1;
- if (t==0) return 0; if ((t/=1/2)==2) return 1; if (!p) p=1*(.3*1.5);
- if (a < Math.abs(1)) { a=1; var s=p/4; }
- else var s = p/(2*Math.PI) * Math.asin (1/a);
- if (t < 1) return -.5*(a*Math.pow(2,10*(t-=1)) * Math.sin( (t*1-s)*(2*Math.PI)/p ));
- return a*Math.pow(2,-10*(t-=1)) * Math.sin( (t*1-s)*(2*Math.PI)/p )*.5 + 1;
- },
- easeInBack: function (t) {
- var s = 1.70158;
- return 1*(t/=1)*t*((s+1)*t - s);
- },
- easeOutBack: function (t) {
- var s = 1.70158;
- return 1*((t=t/1-1)*t*((s+1)*t + s) + 1);
- },
- easeInOutBack: function (t) {
- var s = 1.70158;
- if ((t/=1/2) < 1) return 1/2*(t*t*(((s*=(1.525))+1)*t - s));
- return 1/2*((t-=2)*t*(((s*=(1.525))+1)*t + s) + 2);
- },
- easeInBounce: function (t) {
- return 1 - animationOptions.easeOutBounce (1-t);
- },
- easeOutBounce: function (t) {
- if ((t/=1) < (1/2.75)) {
- return 1*(7.5625*t*t);
- } else if (t < (2/2.75)) {
- return 1*(7.5625*(t-=(1.5/2.75))*t + .75);
- } else if (t < (2.5/2.75)) {
- return 1*(7.5625*(t-=(2.25/2.75))*t + .9375);
- } else {
- return 1*(7.5625*(t-=(2.625/2.75))*t + .984375);
- }
- },
- easeInOutBounce: function (t) {
- if (t < 1/2) return animationOptions.easeInBounce (t*2) * .5;
- return animationOptions.easeOutBounce (t*2-1) * .5 + 1*.5;
- }
- };
-
- //Variables global to the chart
- var width = context.canvas.width;
- var height = context.canvas.height;
-
-
- //High pixel density displays - multiply the size of the canvas height/width by the device pixel ratio, then scale.
- if (window.devicePixelRatio) {
- context.canvas.style.width = width + "px";
- context.canvas.style.height = height + "px";
- context.canvas.height = height * window.devicePixelRatio;
- context.canvas.width = width * window.devicePixelRatio;
- context.scale(window.devicePixelRatio, window.devicePixelRatio);
- }
-
- this.PolarArea = function(data,options){
-
- chart.PolarArea.defaults = {
- scaleOverlay : true,
- scaleOverride : false,
- scaleSteps : null,
- scaleStepWidth : null,
- scaleStartValue : null,
- scaleShowLine : true,
- scaleLineColor : "rgba(0,0,0,.1)",
- scaleLineWidth : 1,
- scaleShowLabels : true,
- scaleLabel : "<%=value%>",
- scaleFontFamily : "'Arial'",
- scaleFontSize : 12,
- scaleFontStyle : "normal",
- scaleFontColor : "#666",
- scaleShowLabelBackdrop : true,
- scaleBackdropColor : "rgba(255,255,255,0.75)",
- scaleBackdropPaddingY : 2,
- scaleBackdropPaddingX : 2,
- segmentShowStroke : true,
- segmentStrokeColor : "#fff",
- segmentStrokeWidth : 2,
- animation : true,
- animationSteps : 100,
- animationEasing : "easeOutBounce",
- animateRotate : true,
- animateScale : false,
- onAnimationComplete : null
- };
-
- var config = (options)? mergeChartConfig(chart.PolarArea.defaults,options) : chart.PolarArea.defaults;
-
- return new PolarArea(data,config,context);
- };
-
- this.Radar = function(data,options){
-
- chart.Radar.defaults = {
- scaleOverlay : false,
- scaleOverride : false,
- scaleSteps : null,
- scaleStepWidth : null,
- scaleStartValue : null,
- scaleShowLine : true,
- scaleLineColor : "rgba(0,0,0,.1)",
- scaleLineWidth : 1,
- scaleShowLabels : false,
- scaleLabel : "<%=value%>",
- scaleFontFamily : "'Arial'",
- scaleFontSize : 12,
- scaleFontStyle : "normal",
- scaleFontColor : "#666",
- scaleShowLabelBackdrop : true,
- scaleBackdropColor : "rgba(255,255,255,0.75)",
- scaleBackdropPaddingY : 2,
- scaleBackdropPaddingX : 2,
- angleShowLineOut : true,
- angleLineColor : "rgba(0,0,0,.1)",
- angleLineWidth : 1,
- pointLabelFontFamily : "'Arial'",
- pointLabelFontStyle : "normal",
- pointLabelFontSize : 12,
- pointLabelFontColor : "#666",
- pointDot : true,
- pointDotRadius : 3,
- pointDotStrokeWidth : 1,
- datasetStroke : true,
- datasetStrokeWidth : 2,
- datasetFill : true,
- animation : true,
- animationSteps : 60,
- animationEasing : "easeOutQuart",
- onAnimationComplete : null
- };
-
- var config = (options)? mergeChartConfig(chart.Radar.defaults,options) : chart.Radar.defaults;
-
- return new Radar(data,config,context);
- };
-
- this.Pie = function(data,options){
- chart.Pie.defaults = {
- segmentShowStroke : true,
- segmentStrokeColor : "#fff",
- segmentStrokeWidth : 2,
- animation : true,
- animationSteps : 100,
- animationEasing : "easeOutBounce",
- animateRotate : true,
- animateScale : false,
- onAnimationComplete : null
- };
-
- var config = (options)? mergeChartConfig(chart.Pie.defaults,options) : chart.Pie.defaults;
-
- return new Pie(data,config,context);
- };
-
- this.Doughnut = function(data,options){
-
- chart.Doughnut.defaults = {
- segmentShowStroke : true,
- segmentStrokeColor : "#fff",
- segmentStrokeWidth : 2,
- percentageInnerCutout : 50,
- animation : true,
- animationSteps : 100,
- animationEasing : "easeOutBounce",
- animateRotate : true,
- animateScale : false,
- onAnimationComplete : null
- };
-
- var config = (options)? mergeChartConfig(chart.Doughnut.defaults,options) : chart.Doughnut.defaults;
-
- return new Doughnut(data,config,context);
-
- };
-
- this.Line = function(data,options){
-
- chart.Line.defaults = {
- scaleOverlay : false,
- scaleOverride : false,
- scaleSteps : null,
- scaleStepWidth : null,
- scaleStartValue : null,
- scaleLineColor : "rgba(0,0,0,.1)",
- scaleLineWidth : 1,
- scaleShowLabels : true,
- scaleLabel : "<%=value%>",
- scaleFontFamily : "'Arial'",
- scaleFontSize : 12,
- scaleFontStyle : "normal",
- scaleFontColor : "#666",
- scaleShowGridLines : true,
- scaleGridLineColor : "rgba(0,0,0,.05)",
- scaleGridLineWidth : 1,
- bezierCurve : true,
- pointDot : true,
- pointDotRadius : 4,
- pointDotStrokeWidth : 2,
- datasetStroke : true,
- datasetStrokeWidth : 2,
- datasetFill : true,
- animation : true,
- animationSteps : 60,
- animationEasing : "easeOutQuart",
- onAnimationComplete : null
- };
- var config = (options) ? mergeChartConfig(chart.Line.defaults,options) : chart.Line.defaults;
-
- return new Line(data,config,context);
- }
-
- this.Bar = function(data,options){
- chart.Bar.defaults = {
- scaleOverlay : false,
- scaleOverride : false,
- scaleSteps : null,
- scaleStepWidth : null,
- scaleStartValue : null,
- scaleLineColor : "rgba(0,0,0,.1)",
- scaleLineWidth : 1,
- scaleShowLabels : true,
- scaleLabel : "<%=value%>",
- scaleFontFamily : "'Arial'",
- scaleFontSize : 12,
- scaleFontStyle : "normal",
- scaleFontColor : "#666",
- scaleShowGridLines : true,
- scaleGridLineColor : "rgba(0,0,0,.05)",
- scaleGridLineWidth : 1,
- barShowStroke : true,
- barStrokeWidth : 2,
- barValueSpacing : 5,
- barDatasetSpacing : 1,
- animation : true,
- animationSteps : 60,
- animationEasing : "easeOutQuart",
- onAnimationComplete : null
- };
- var config = (options) ? mergeChartConfig(chart.Bar.defaults,options) : chart.Bar.defaults;
-
- return new Bar(data,config,context);
- }
-
- var clear = function(c){
- c.clearRect(0, 0, width, height);
- };
-
- var PolarArea = function(data,config,ctx){
- var maxSize, scaleHop, calculatedScale, labelHeight, scaleHeight, valueBounds, labelTemplateString;
-
-
- calculateDrawingSizes();
-
- valueBounds = getValueBounds();
-
- labelTemplateString = (config.scaleShowLabels)? config.scaleLabel : null;
-
- //Check and set the scale
- if (!config.scaleOverride){
-
- calculatedScale = calculateScale(scaleHeight,valueBounds.maxSteps,valueBounds.minSteps,valueBounds.maxValue,valueBounds.minValue,labelTemplateString);
- }
- else {
- calculatedScale = {
- steps : config.scaleSteps,
- stepValue : config.scaleStepWidth,
- graphMin : config.scaleStartValue,
- labels : []
- }
- for (var i=0; i upperValue) {upperValue = data[i].value;}
- if (data[i].value < lowerValue) {lowerValue = data[i].value;}
- };
-
- var maxSteps = Math.floor((scaleHeight / (labelHeight*0.66)));
- var minSteps = Math.floor((scaleHeight / labelHeight*0.5));
-
- return {
- maxValue : upperValue,
- minValue : lowerValue,
- maxSteps : maxSteps,
- minSteps : minSteps
- };
-
-
- }
- }
-
- var Radar = function (data,config,ctx) {
- var maxSize, scaleHop, calculatedScale, labelHeight, scaleHeight, valueBounds, labelTemplateString;
-
- //If no labels are defined set to an empty array, so referencing length for looping doesn't blow up.
- if (!data.labels) data.labels = [];
-
- calculateDrawingSizes();
-
- var valueBounds = getValueBounds();
-
- labelTemplateString = (config.scaleShowLabels)? config.scaleLabel : null;
-
- //Check and set the scale
- if (!config.scaleOverride){
-
- calculatedScale = calculateScale(scaleHeight,valueBounds.maxSteps,valueBounds.minSteps,valueBounds.maxValue,valueBounds.minValue,labelTemplateString);
- }
- else {
- calculatedScale = {
- steps : config.scaleSteps,
- stepValue : config.scaleStepWidth,
- graphMin : config.scaleStartValue,
- labels : []
- }
- for (var i=0; i Math.PI){
- ctx.textAlign = "right";
- }
- else{
- ctx.textAlign = "left";
- }
-
- ctx.textBaseline = "middle";
-
- ctx.fillText(data.labels[k],opposite,-adjacent);
-
- }
- ctx.restore();
- };
- function calculateDrawingSizes(){
- maxSize = (Min([width,height])/2);
-
- labelHeight = config.scaleFontSize*2;
-
- var labelLength = 0;
- for (var i=0; ilabelLength) labelLength = textMeasurement;
- }
-
- //Figure out whats the largest - the height of the text or the width of what's there, and minus it from the maximum usable size.
- maxSize -= Max([labelLength,((config.pointLabelFontSize/2)*1.5)]);
-
- maxSize -= config.pointLabelFontSize;
- maxSize = CapValue(maxSize, null, 0);
- scaleHeight = maxSize;
- //If the label height is less than 5, set it to 5 so we don't have lines on top of each other.
- labelHeight = Default(labelHeight,5);
- };
- function getValueBounds() {
- var upperValue = Number.MIN_VALUE;
- var lowerValue = Number.MAX_VALUE;
-
- for (var i=0; i upperValue){upperValue = data.datasets[i].data[j]}
- if (data.datasets[i].data[j] < lowerValue){lowerValue = data.datasets[i].data[j]}
- }
- }
-
- var maxSteps = Math.floor((scaleHeight / (labelHeight*0.66)));
- var minSteps = Math.floor((scaleHeight / labelHeight*0.5));
-
- return {
- maxValue : upperValue,
- minValue : lowerValue,
- maxSteps : maxSteps,
- minSteps : minSteps
- };
-
-
- }
- }
-
- var Pie = function(data,config,ctx){
- var segmentTotal = 0;
-
- //In case we have a canvas that is not a square. Minus 5 pixels as padding round the edge.
- var pieRadius = Min([height/2,width/2]) - 5;
-
- for (var i=0; i 0){
- ctx.save();
- ctx.textAlign = "right";
- }
- else{
- ctx.textAlign = "center";
- }
- ctx.fillStyle = config.scaleFontColor;
- for (var i=0; i 0){
- ctx.translate(yAxisPosX + i*valueHop,xAxisPosY + config.scaleFontSize);
- ctx.rotate(-(rotateLabels * (Math.PI/180)));
- ctx.fillText(data.labels[i], 0,0);
- ctx.restore();
- }
-
- else{
- ctx.fillText(data.labels[i], yAxisPosX + i*valueHop,xAxisPosY + config.scaleFontSize+3);
- }
-
- ctx.beginPath();
- ctx.moveTo(yAxisPosX + i * valueHop, xAxisPosY+3);
-
- //Check i isnt 0, so we dont go over the Y axis twice.
- if(config.scaleShowGridLines && i>0){
- ctx.lineWidth = config.scaleGridLineWidth;
- ctx.strokeStyle = config.scaleGridLineColor;
- ctx.lineTo(yAxisPosX + i * valueHop, 5);
- }
- else{
- ctx.lineTo(yAxisPosX + i * valueHop, xAxisPosY+3);
- }
- ctx.stroke();
- }
-
- //Y axis
- ctx.lineWidth = config.scaleLineWidth;
- ctx.strokeStyle = config.scaleLineColor;
- ctx.beginPath();
- ctx.moveTo(yAxisPosX,xAxisPosY+5);
- ctx.lineTo(yAxisPosX,5);
- ctx.stroke();
-
- ctx.textAlign = "right";
- ctx.textBaseline = "middle";
- for (var j=0; j longestText)? measuredText : longestText;
- }
- //Add a little extra padding from the y axis
- longestText +=10;
- }
- xAxisLength = width - longestText - widestXLabel;
- valueHop = Math.floor(xAxisLength/(data.labels.length-1));
-
- yAxisPosX = width-widestXLabel/2-xAxisLength;
- xAxisPosY = scaleHeight + config.scaleFontSize/2;
- }
- function calculateDrawingSizes(){
- maxSize = height;
-
- //Need to check the X axis first - measure the length of each text metric, and figure out if we need to rotate by 45 degrees.
- ctx.font = config.scaleFontStyle + " " + config.scaleFontSize+"px " + config.scaleFontFamily;
- widestXLabel = 1;
- for (var i=0; i widestXLabel)? textLength : widestXLabel;
- }
- if (width/data.labels.length < widestXLabel){
- rotateLabels = 45;
- if (width/data.labels.length < Math.cos(rotateLabels) * widestXLabel){
- rotateLabels = 90;
- maxSize -= widestXLabel;
- }
- else{
- maxSize -= Math.sin(rotateLabels) * widestXLabel;
- }
- }
- else{
- maxSize -= config.scaleFontSize;
- }
-
- //Add a little padding between the x line and the text
- maxSize -= 5;
-
-
- labelHeight = config.scaleFontSize;
-
- maxSize -= labelHeight;
- //Set 5 pixels greater than the font size to allow for a little padding from the X axis.
-
- scaleHeight = maxSize;
-
- //Then get the area above we can safely draw on.
-
- }
- function getValueBounds() {
- var upperValue = Number.MIN_VALUE;
- var lowerValue = Number.MAX_VALUE;
- for (var i=0; i upperValue) { upperValue = data.datasets[i].data[j] };
- if ( data.datasets[i].data[j] < lowerValue) { lowerValue = data.datasets[i].data[j] };
- }
- };
-
- var maxSteps = Math.floor((scaleHeight / (labelHeight*0.66)));
- var minSteps = Math.floor((scaleHeight / labelHeight*0.5));
-
- return {
- maxValue : upperValue,
- minValue : lowerValue,
- maxSteps : maxSteps,
- minSteps : minSteps
- };
-
-
- }
-
-
- }
-
- var Bar = function(data,config,ctx){
- var maxSize, scaleHop, calculatedScale, labelHeight, scaleHeight, valueBounds, labelTemplateString, valueHop,widestXLabel, xAxisLength,yAxisPosX,xAxisPosY,barWidth, rotateLabels = 0;
-
- calculateDrawingSizes();
-
- valueBounds = getValueBounds();
- //Check and set the scale
- labelTemplateString = (config.scaleShowLabels)? config.scaleLabel : "";
- if (!config.scaleOverride){
-
- calculatedScale = calculateScale(scaleHeight,valueBounds.maxSteps,valueBounds.minSteps,valueBounds.maxValue,valueBounds.minValue,labelTemplateString);
- }
- else {
- calculatedScale = {
- steps : config.scaleSteps,
- stepValue : config.scaleStepWidth,
- graphMin : config.scaleStartValue,
- labels : []
- }
- for (var i=0; i 0){
- ctx.save();
- ctx.textAlign = "right";
- }
- else{
- ctx.textAlign = "center";
- }
- ctx.fillStyle = config.scaleFontColor;
- for (var i=0; i 0){
- ctx.translate(yAxisPosX + i*valueHop,xAxisPosY + config.scaleFontSize);
- ctx.rotate(-(rotateLabels * (Math.PI/180)));
- ctx.fillText(data.labels[i], 0,0);
- ctx.restore();
- }
-
- else{
- ctx.fillText(data.labels[i], yAxisPosX + i*valueHop + valueHop/2,xAxisPosY + config.scaleFontSize+3);
- }
-
- ctx.beginPath();
- ctx.moveTo(yAxisPosX + (i+1) * valueHop, xAxisPosY+3);
-
- //Check i isnt 0, so we dont go over the Y axis twice.
- ctx.lineWidth = config.scaleGridLineWidth;
- ctx.strokeStyle = config.scaleGridLineColor;
- ctx.lineTo(yAxisPosX + (i+1) * valueHop, 5);
- ctx.stroke();
- }
-
- //Y axis
- ctx.lineWidth = config.scaleLineWidth;
- ctx.strokeStyle = config.scaleLineColor;
- ctx.beginPath();
- ctx.moveTo(yAxisPosX,xAxisPosY+5);
- ctx.lineTo(yAxisPosX,5);
- ctx.stroke();
-
- ctx.textAlign = "right";
- ctx.textBaseline = "middle";
- for (var j=0; j longestText)? measuredText : longestText;
- }
- //Add a little extra padding from the y axis
- longestText +=10;
- }
- xAxisLength = width - longestText - widestXLabel;
- valueHop = Math.floor(xAxisLength/(data.labels.length));
-
- barWidth = (valueHop - config.scaleGridLineWidth*2 - (config.barValueSpacing*2) - (config.barDatasetSpacing*data.datasets.length-1) - ((config.barStrokeWidth/2)*data.datasets.length-1))/data.datasets.length;
-
- yAxisPosX = width-widestXLabel/2-xAxisLength;
- xAxisPosY = scaleHeight + config.scaleFontSize/2;
- }
- function calculateDrawingSizes(){
- maxSize = height;
-
- //Need to check the X axis first - measure the length of each text metric, and figure out if we need to rotate by 45 degrees.
- ctx.font = config.scaleFontStyle + " " + config.scaleFontSize+"px " + config.scaleFontFamily;
- widestXLabel = 1;
- for (var i=0; i widestXLabel)? textLength : widestXLabel;
- }
- if (width/data.labels.length < widestXLabel){
- rotateLabels = 45;
- if (width/data.labels.length < Math.cos(rotateLabels) * widestXLabel){
- rotateLabels = 90;
- maxSize -= widestXLabel;
- }
- else{
- maxSize -= Math.sin(rotateLabels) * widestXLabel;
- }
- }
- else{
- maxSize -= config.scaleFontSize;
- }
-
- //Add a little padding between the x line and the text
- maxSize -= 5;
-
-
- labelHeight = config.scaleFontSize;
-
- maxSize -= labelHeight;
- //Set 5 pixels greater than the font size to allow for a little padding from the X axis.
-
- scaleHeight = maxSize;
-
- //Then get the area above we can safely draw on.
-
- }
- function getValueBounds() {
- var upperValue = Number.MIN_VALUE;
- var lowerValue = Number.MAX_VALUE;
- for (var i=0; i upperValue) { upperValue = data.datasets[i].data[j] };
- if ( data.datasets[i].data[j] < lowerValue) { lowerValue = data.datasets[i].data[j] };
- }
- };
-
- var maxSteps = Math.floor((scaleHeight / (labelHeight*0.66)));
- var minSteps = Math.floor((scaleHeight / labelHeight*0.5));
-
- return {
- maxValue : upperValue,
- minValue : lowerValue,
- maxSteps : maxSteps,
- minSteps : minSteps
- };
-
-
- }
- }
-
- function calculateOffset(val,calculatedScale,scaleHop){
- var outerValue = calculatedScale.steps * calculatedScale.stepValue;
- var adjustedValue = val - calculatedScale.graphMin;
- var scalingFactor = CapValue(adjustedValue/outerValue,1,0);
- return (scaleHop*calculatedScale.steps) * scalingFactor;
- }
-
- function animationLoop(config,drawScale,drawData,ctx){
- var animFrameAmount = (config.animation)? 1/CapValue(config.animationSteps,Number.MAX_VALUE,1) : 1,
- easingFunction = animationOptions[config.animationEasing],
- percentAnimComplete =(config.animation)? 0 : 1;
-
-
-
- if (typeof drawScale !== "function") drawScale = function(){};
-
- requestAnimFrame(animLoop);
-
- function animateFrame(){
- var easeAdjustedAnimationPercent =(config.animation)? CapValue(easingFunction(percentAnimComplete),null,0) : 1;
- clear(ctx);
- if(config.scaleOverlay){
- drawData(easeAdjustedAnimationPercent);
- drawScale();
- } else {
- drawScale();
- drawData(easeAdjustedAnimationPercent);
- }
- }
- function animLoop(){
- //We need to check if the animation is incomplete (less than 1), or complete (1).
- percentAnimComplete += animFrameAmount;
- animateFrame();
- //Stop the loop continuing forever
- if (percentAnimComplete <= 1){
- requestAnimFrame(animLoop);
- }
- else{
- if (typeof config.onAnimationComplete == "function") config.onAnimationComplete();
- }
-
- }
-
- }
-
- //Declare global functions to be called within this namespace here.
-
-
- // shim layer with setTimeout fallback
- var requestAnimFrame = (function(){
- return window.requestAnimationFrame ||
- window.webkitRequestAnimationFrame ||
- window.mozRequestAnimationFrame ||
- window.oRequestAnimationFrame ||
- window.msRequestAnimationFrame ||
- function(callback) {
- window.setTimeout(callback, 1000 / 60);
- };
- })();
-
- function calculateScale(drawingHeight,maxSteps,minSteps,maxValue,minValue,labelTemplateString){
- var graphMin,graphMax,graphRange,stepValue,numberOfSteps,valueRange,rangeOrderOfMagnitude,decimalNum;
-
- valueRange = maxValue - minValue;
-
- rangeOrderOfMagnitude = calculateOrderOfMagnitude(valueRange);
-
- graphMin = Math.floor(minValue / (1 * Math.pow(10, rangeOrderOfMagnitude))) * Math.pow(10, rangeOrderOfMagnitude);
-
- graphMax = Math.ceil(maxValue / (1 * Math.pow(10, rangeOrderOfMagnitude))) * Math.pow(10, rangeOrderOfMagnitude);
-
- graphRange = graphMax - graphMin;
-
- stepValue = Math.pow(10, rangeOrderOfMagnitude);
-
- numberOfSteps = Math.round(graphRange / stepValue);
-
- //Compare number of steps to the max and min for that size graph, and add in half steps if need be.
- while(numberOfSteps < minSteps || numberOfSteps > maxSteps) {
- if (numberOfSteps < minSteps){
- stepValue /= 2;
- numberOfSteps = Math.round(graphRange/stepValue);
- }
- else{
- stepValue *=2;
- numberOfSteps = Math.round(graphRange/stepValue);
- }
- };
-
-
-
- //Create an array of all the labels by interpolating the string.
-
- var labels = [];
-
- if(labelTemplateString){
- //Fix floating point errors by setting to fixed the on the same decimal as the stepValue.
- for (var i=1; i maxValue ) {
- return maxValue;
- }
- }
- if(isNumber(minValue)){
- if ( valueToCap < minValue ){
- return minValue;
- }
- }
- return valueToCap;
- }
- function getDecimalPlaces (num){
- var numberOfDecimalPlaces;
- if (num%1!=0){
- return num.toString().split(".")[1].length
- }
- else{
- return 0;
- }
-
- }
-
- function mergeChartConfig(defaults,userDefined){
- var returnObj = {};
- for (var attrname in defaults) { returnObj[attrname] = defaults[attrname]; }
- for (var attrname in userDefined) { returnObj[attrname] = userDefined[attrname]; }
- return returnObj;
- }
-
- //Javascript micro templating by John Resig - source at http://ejohn.org/blog/javascript-micro-templating/
- var cache = {};
-
- function tmpl(str, data){
- // Figure out if we're getting a template, or if we need to
- // load the template - and be sure to cache the result.
- var fn = !/\W/.test(str) ?
- cache[str] = cache[str] ||
- tmpl(document.getElementById(str).innerHTML) :
-
- // Generate a reusable function that will serve as a template
- // generator (and which will be cached).
- new Function("obj",
- "var p=[],print=function(){p.push.apply(p,arguments);};" +
-
- // Introduce the data as local variables using with(){}
- "with(obj){p.push('" +
-
- // Convert the template into pure JavaScript
- str
- .replace(/[\r\t\n]/g, " ")
- .split("<%").join("\t")
- .replace(/((^|%>)[^\t]*)'/g, "$1\r")
- .replace(/\t=(.*?)%>/g, "',$1,'")
- .split("\t").join("');")
- .split("%>").join("p.push('")
- .split("\r").join("\\'")
- + "');}return p.join('');");
-
- // Provide some basic currying to the user
- return data ? fn( data ) : fn;
- };
-}
-
-
-
diff --git a/public/vendor/chartjs/docs/index.html b/public/vendor/chartjs/docs/index.html
deleted file mode 100644
index ef6f522c..00000000
--- a/public/vendor/chartjs/docs/index.html
+++ /dev/null
@@ -1,766 +0,0 @@
-
-
-
- Chart.js Documentation
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
Chart.js Documentation
-
Everything you need to know to create great looking charts using Chart.js
-
- Getting started
- Include Chart.js
- First we need to include the Chart.js library on the page. The library occupies a global variable of Chart.
- <script src="Chart.js"></script>
- Creating a chart
- To create a chart, we need to instantiate the Chart class. To do this, we need to pass in the 2d context of where we want to draw the chart. Here's an example.
- <canvas id="myChart" width="400" height="400"></canvas>
- //Get the context of the canvas element we want to select
-var ctx = document.getElementById("myChart").getContext("2d");
-var myNewChart = new Chart(ctx).PolarArea(data);
- We can also get the context of our canvas with jQuery. To do this, we need to get the DOM node out of the jQuery collection, and call the getContext("2d") method on that.
- //Get context with jQuery - using jQuery's .get() method.
-var ctx = $("#myChart").get(0).getContext("2d");
-//This will get the first returned node in the jQuery collection.
-var myNewChart = new Chart(ctx);
- After we've instantiated the Chart class on the canvas we want to draw on, Chart.js will handle the scaling for retina displays.
- With the Chart class set up, we can go on to create one of the charts Chart.js has available. In the example below, we would be drawing a Polar area chart.
- new Chart(ctx).PolarArea(data,options);
- We call a method of the name of the chart we want to create. We pass in the data for that chart type, and the options for that chart as parameters. Chart.js will merge the options you pass in with the default options for that chart type.
-
-
-
- Line chart
- Introduction
- A line chart is a way of plotting data points on a line.
- Often, it is used to show trend data, and the comparison of two data sets.
- Example usage
-
- new Chart(ctx).Line(data,options);
- Data structure
- var data = {
- labels : ["January","February","March","April","May","June","July"],
- datasets : [
- {
- fillColor : "rgba(220,220,220,0.5)",
- strokeColor : "rgba(220,220,220,1)",
- pointColor : "rgba(220,220,220,1)",
- pointStrokeColor : "#fff",
- data : [65,59,90,81,56,55,40]
- },
- {
- fillColor : "rgba(151,187,205,0.5)",
- strokeColor : "rgba(151,187,205,1)",
- pointColor : "rgba(151,187,205,1)",
- pointStrokeColor : "#fff",
- data : [28,48,40,19,96,27,100]
- }
- ]
-}
- The line chart requires an array of labels for each of the data points. This is show on the X axis.
- The data for line charts is broken up into an array of datasets. Each dataset has a colour for the fill, a colour for the line and colours for the points and strokes of the points. These colours are strings just like CSS. You can use RGBA, RGB, HEX or HSL notation.
-
- Chart options
- Line.defaults = {
-
- //Boolean - If we show the scale above the chart data
- scaleOverlay : false,
-
- //Boolean - If we want to override with a hard coded scale
- scaleOverride : false,
-
- //** Required if scaleOverride is true **
- //Number - The number of steps in a hard coded scale
- scaleSteps : null,
- //Number - The value jump in the hard coded scale
- scaleStepWidth : null,
- //Number - The scale starting value
- scaleStartValue : null,
-
- //String - Colour of the scale line
- scaleLineColor : "rgba(0,0,0,.1)",
-
- //Number - Pixel width of the scale line
- scaleLineWidth : 1,
-
- //Boolean - Whether to show labels on the scale
- scaleShowLabels : true,
-
- //Interpolated JS string - can access value
- scaleLabel : "<%=value%>",
-
- //String - Scale label font declaration for the scale label
- scaleFontFamily : "'Arial'",
-
- //Number - Scale label font size in pixels
- scaleFontSize : 12,
-
- //String - Scale label font weight style
- scaleFontStyle : "normal",
-
- //String - Scale label font colour
- scaleFontColor : "#666",
-
- ///Boolean - Whether grid lines are shown across the chart
- scaleShowGridLines : true,
-
- //String - Colour of the grid lines
- scaleGridLineColor : "rgba(0,0,0,.05)",
-
- //Number - Width of the grid lines
- scaleGridLineWidth : 1,
-
- //Boolean - Whether the line is curved between points
- bezierCurve : true,
-
- //Boolean - Whether to show a dot for each point
- pointDot : true,
-
- //Number - Radius of each point dot in pixels
- pointDotRadius : 3,
-
- //Number - Pixel width of point dot stroke
- pointDotStrokeWidth : 1,
-
- //Boolean - Whether to show a stroke for datasets
- datasetStroke : true,
-
- //Number - Pixel width of dataset stroke
- datasetStrokeWidth : 2,
-
- //Boolean - Whether to fill the dataset with a colour
- datasetFill : true,
-
- //Boolean - Whether to animate the chart
- animation : true,
-
- //Number - Number of animation steps
- animationSteps : 60,
-
- //String - Animation easing effect
- animationEasing : "easeOutQuart",
-
- //Function - Fires when the animation is complete
- onAnimationComplete : null
-
-}
-
-
-
- Bar chart
- Introduction
- A bar chart is a way of showing data as bars.
- It is sometimes used to show trend data, and the comparison of multiple data sets side by side.
- Example usage
-
- new Chart(ctx).Bar(data,options);
- Data structure
- var data = {
- labels : ["January","February","March","April","May","June","July"],
- datasets : [
- {
- fillColor : "rgba(220,220,220,0.5)",
- strokeColor : "rgba(220,220,220,1)",
- data : [65,59,90,81,56,55,40]
- },
- {
- fillColor : "rgba(151,187,205,0.5)",
- strokeColor : "rgba(151,187,205,1)",
- data : [28,48,40,19,96,27,100]
- }
- ]
-}
- The bar chart has the a very similar data structure to the line chart, and has an array of datasets, each with colours and an array of data. Again, colours are in CSS format.
- We have an array of labels too for display. In the example, we are showing the same data as the previous line chart example.
-
- Chart options
- Bar.defaults = {
-
- //Boolean - If we show the scale above the chart data
- scaleOverlay : false,
-
- //Boolean - If we want to override with a hard coded scale
- scaleOverride : false,
-
- //** Required if scaleOverride is true **
- //Number - The number of steps in a hard coded scale
- scaleSteps : null,
- //Number - The value jump in the hard coded scale
- scaleStepWidth : null,
- //Number - The scale starting value
- scaleStartValue : null,
-
- //String - Colour of the scale line
- scaleLineColor : "rgba(0,0,0,.1)",
-
- //Number - Pixel width of the scale line
- scaleLineWidth : 1,
-
- //Boolean - Whether to show labels on the scale
- scaleShowLabels : true,
-
- //Interpolated JS string - can access value
- scaleLabel : "<%=value%>",
-
- //String - Scale label font declaration for the scale label
- scaleFontFamily : "'Arial'",
-
- //Number - Scale label font size in pixels
- scaleFontSize : 12,
-
- //String - Scale label font weight style
- scaleFontStyle : "normal",
-
- //String - Scale label font colour
- scaleFontColor : "#666",
-
- ///Boolean - Whether grid lines are shown across the chart
- scaleShowGridLines : true,
-
- //String - Colour of the grid lines
- scaleGridLineColor : "rgba(0,0,0,.05)",
-
- //Number - Width of the grid lines
- scaleGridLineWidth : 1,
-
- //Boolean - If there is a stroke on each bar
- barShowStroke : true,
-
- //Number - Pixel width of the bar stroke
- barStrokeWidth : 2,
-
- //Number - Spacing between each of the X value sets
- barValueSpacing : 5,
-
- //Number - Spacing between data sets within X values
- barDatasetSpacing : 1,
-
- //Boolean - Whether to animate the chart
- animation : true,
-
- //Number - Number of animation steps
- animationSteps : 60,
-
- //String - Animation easing effect
- animationEasing : "easeOutQuart",
-
- //Function - Fires when the animation is complete
- onAnimationComplete : null
-
-}
-
-
-
- Radar chart
- Introduction
- A radar chart is a way of showing multiple data points and the variation between them.
- They are often useful for comparing the points of two or more different data sets
- Example usage
-
- new Chart(ctx).Radar(data,options);
- Data structure
- var data = {
- labels : ["Eating","Drinking","Sleeping","Designing","Coding","Partying","Running"],
- datasets : [
- {
- fillColor : "rgba(220,220,220,0.5)",
- strokeColor : "rgba(220,220,220,1)",
- pointColor : "rgba(220,220,220,1)",
- pointStrokeColor : "#fff",
- data : [65,59,90,81,56,55,40]
- },
- {
- fillColor : "rgba(151,187,205,0.5)",
- strokeColor : "rgba(151,187,205,1)",
- pointColor : "rgba(151,187,205,1)",
- pointStrokeColor : "#fff",
- data : [28,48,40,19,96,27,100]
- }
- ]
-}
- For a radar chart, usually you will want to show a label on each point of the chart, so we include an array of strings that we show around each point in the chart. If you do not want this, you can either not include the array of labels, or choose to hide them in the chart options.
- For the radar chart data, we have an array of datasets. Each of these is an object, with a fill colour, a stroke colour, a colour for the fill of each point, and a colour for the stroke of each point. We also have an array of data values.
-
- Chart options
- Radar.defaults = {
-
- //Boolean - If we show the scale above the chart data
- scaleOverlay : false,
-
- //Boolean - If we want to override with a hard coded scale
- scaleOverride : false,
-
- //** Required if scaleOverride is true **
- //Number - The number of steps in a hard coded scale
- scaleSteps : null,
- //Number - The value jump in the hard coded scale
- scaleStepWidth : null,
- //Number - The centre starting value
- scaleStartValue : null,
-
- //Boolean - Whether to show lines for each scale point
- scaleShowLine : true,
-
- //String - Colour of the scale line
- scaleLineColor : "rgba(0,0,0,.1)",
-
- //Number - Pixel width of the scale line
- scaleLineWidth : 1,
-
- //Boolean - Whether to show labels on the scale
- scaleShowLabels : false,
-
- //Interpolated JS string - can access value
- scaleLabel : "<%=value%>",
-
- //String - Scale label font declaration for the scale label
- scaleFontFamily : "'Arial'",
-
- //Number - Scale label font size in pixels
- scaleFontSize : 12,
-
- //String - Scale label font weight style
- scaleFontStyle : "normal",
-
- //String - Scale label font colour
- scaleFontColor : "#666",
-
- //Boolean - Show a backdrop to the scale label
- scaleShowLabelBackdrop : true,
-
- //String - The colour of the label backdrop
- scaleBackdropColor : "rgba(255,255,255,0.75)",
-
- //Number - The backdrop padding above & below the label in pixels
- scaleBackdropPaddingY : 2,
-
- //Number - The backdrop padding to the side of the label in pixels
- scaleBackdropPaddingX : 2,
-
- //Boolean - Whether we show the angle lines out of the radar
- angleShowLineOut : true,
-
- //String - Colour of the angle line
- angleLineColor : "rgba(0,0,0,.1)",
-
- //Number - Pixel width of the angle line
- angleLineWidth : 1,
-
- //String - Point label font declaration
- pointLabelFontFamily : "'Arial'",
-
- //String - Point label font weight
- pointLabelFontStyle : "normal",
-
- //Number - Point label font size in pixels
- pointLabelFontSize : 12,
-
- //String - Point label font colour
- pointLabelFontColor : "#666",
-
- //Boolean - Whether to show a dot for each point
- pointDot : true,
-
- //Number - Radius of each point dot in pixels
- pointDotRadius : 3,
-
- //Number - Pixel width of point dot stroke
- pointDotStrokeWidth : 1,
-
- //Boolean - Whether to show a stroke for datasets
- datasetStroke : true,
-
- //Number - Pixel width of dataset stroke
- datasetStrokeWidth : 2,
-
- //Boolean - Whether to fill the dataset with a colour
- datasetFill : true,
-
- //Boolean - Whether to animate the chart
- animation : true,
-
- //Number - Number of animation steps
- animationSteps : 60,
-
- //String - Animation easing effect
- animationEasing : "easeOutQuart",
-
- //Function - Fires when the animation is complete
- onAnimationComplete : null
-
-}
-
-
-
- Polar area chart
- Introduction
- Polar area charts are similar to pie charts, but each segment has the same angle - the radius of the segment differs depending on the value.
- This type of chart is often useful when we want to show a comparison data similar to a pie chart, but also show a scale of values for context.
- Example usage
-
- new Chart(ctx).PolarArea(data,options);
- Data structure
- var data = [
- {
- value : 30,
- color: "#D97041"
- },
- {
- value : 90,
- color: "#C7604C"
- },
- {
- value : 24,
- color: "#21323D"
- },
- {
- value : 58,
- color: "#9D9B7F"
- },
- {
- value : 82,
- color: "#7D4F6D"
- },
- {
- value : 8,
- color: "#584A5E"
- }
-]
- As you can see, for the chart data you pass in an array of objects, with a value and a colour. The value attribute should be a number, while the color attribute should be a string. Similar to CSS, for this string you can use HEX notation, RGB, RGBA or HSL.
- Chart options
- These are the default chart options. By passing in an object with any of these attributes, Chart.js will merge these objects and the graph accordingly. Explanations of each option are commented in the code below.
- PolarArea.defaults = {
-
- //Boolean - Whether we show the scale above or below the chart segments
- scaleOverlay : true,
-
- //Boolean - If we want to override with a hard coded scale
- scaleOverride : false,
-
- //** Required if scaleOverride is true **
- //Number - The number of steps in a hard coded scale
- scaleSteps : null,
- //Number - The value jump in the hard coded scale
- scaleStepWidth : null,
- //Number - The centre starting value
- scaleStartValue : null,
-
- //Boolean - Show line for each value in the scale
- scaleShowLine : true,
-
- //String - The colour of the scale line
- scaleLineColor : "rgba(0,0,0,.1)",
-
- //Number - The width of the line - in pixels
- scaleLineWidth : 1,
-
- //Boolean - whether we should show text labels
- scaleShowLabels : true,
-
- //Interpolated JS string - can access value
- scaleLabel : "<%=value%>",
-
- //String - Scale label font declaration for the scale label
- scaleFontFamily : "'Arial'",
-
- //Number - Scale label font size in pixels
- scaleFontSize : 12,
-
- //String - Scale label font weight style
- scaleFontStyle : "normal",
-
- //String - Scale label font colour
- scaleFontColor : "#666",
-
- //Boolean - Show a backdrop to the scale label
- scaleShowLabelBackdrop : true,
-
- //String - The colour of the label backdrop
- scaleBackdropColor : "rgba(255,255,255,0.75)",
-
- //Number - The backdrop padding above & below the label in pixels
- scaleBackdropPaddingY : 2,
-
- //Number - The backdrop padding to the side of the label in pixels
- scaleBackdropPaddingX : 2,
-
- //Boolean - Stroke a line around each segment in the chart
- segmentShowStroke : true,
-
- //String - The colour of the stroke on each segement.
- segmentStrokeColor : "#fff",
-
- //Number - The width of the stroke value in pixels
- segmentStrokeWidth : 2,
-
- //Boolean - Whether to animate the chart or not
- animation : true,
-
- //Number - Amount of animation steps
- animationSteps : 100,
-
- //String - Animation easing effect.
- animationEasing : "easeOutBounce",
-
- //Boolean - Whether to animate the rotation of the chart
- animateRotate : true,
-
- //Boolean - Whether to animate scaling the chart from the centre
- animateScale : false,
-
- //Function - This will fire when the animation of the chart is complete.
- onAnimationComplete : null
-}
-
-
- Pie chart
- Introduction
- Pie charts are probably the most commonly used chart there are. They are divided into segments, the arc of each segment shows a the proportional value of each piece of data.
- They are excellent at showing the relational proportions between data.
- Example usage
-
- new Chart(ctx).Pie(data,options);
- Data structure
- var data = [
- {
- value: 30,
- color:"#F38630"
- },
- {
- value : 50,
- color : "#E0E4CC"
- },
- {
- value : 100,
- color : "#69D2E7"
- }
-]
- For a pie chart, you must pass in an array of objects with a value and a color property. The value attribute should be a number, Chart.js will total all of the numbers and calculate the relative proportion of each. The color attribute should be a string. Similar to CSS, for this string you can use HEX notation, RGB, RGBA or HSL.
- Chart options
- These are the default options for the Pie chart. Pass in an object with any of these attributes to override them.
-
Pie.defaults = {
- //Boolean - Whether we should show a stroke on each segment
- segmentShowStroke : true,
-
- //String - The colour of each segment stroke
- segmentStrokeColor : "#fff",
-
- //Number - The width of each segment stroke
- segmentStrokeWidth : 2,
-
- //Boolean - Whether we should animate the chart
- animation : true,
-
- //Number - Amount of animation steps
- animationSteps : 100,
-
- //String - Animation easing effect
- animationEasing : "easeOutBounce",
-
- //Boolean - Whether we animate the rotation of the Pie
- animateRotate : true,
-
- //Boolean - Whether we animate scaling the Pie from the centre
- animateScale : false,
-
- //Function - Will fire on animation completion.
- onAnimationComplete : null
-}
-
-
- Doughnut chart
- Introduction
- Doughnut charts are similar to pie charts, however they have the centre cut out, and are therefore shaped more like a doughnut than a pie!
- They are aso excellent at showing the relational proportions between data.
- Example usage
-
- new Chart(ctx).Doughnut(data,options);
- Data structure
- var data = [
- {
- value: 30,
- color:"#F7464A"
- },
- {
- value : 50,
- color : "#E2EAE9"
- },
- {
- value : 100,
- color : "#D4CCC5"
- },
- {
- value : 40,
- color : "#949FB1"
- },
- {
- value : 120,
- color : "#4D5360"
- }
-
-]
- For a doughnut chart, you must pass in an array of objects with a value and a color property. The value attribute should be a number, Chart.js will total all of the numbers and calculate the relative proportion of each. The color attribute should be a string. Similar to CSS, for this string you can use HEX notation, RGB, RGBA or HSL.
- Chart options
- These are the default options for the doughnut chart. Pass in an object with any of these attributes to override them.
-
Doughnut.defaults = {
- //Boolean - Whether we should show a stroke on each segment
- segmentShowStroke : true,
-
- //String - The colour of each segment stroke
- segmentStrokeColor : "#fff",
-
- //Number - The width of each segment stroke
- segmentStrokeWidth : 2,
-
- //The percentage of the chart that we cut out of the middle.
- percentageInnerCutout : 50,
-
- //Boolean - Whether we should animate the chart
- animation : true,
-
- //Number - Amount of animation steps
- animationSteps : 100,
-
- //String - Animation easing effect
- animationEasing : "easeOutBounce",
-
- //Boolean - Whether we animate the rotation of the Doughnut
- animateRotate : true,
-
- //Boolean - Whether we animate scaling the Doughnut from the centre
- animateScale : false,
-
- //Function - Will fire on animation completion.
- onAnimationComplete : null
-}
-
-
- General issues
- Chart interactivity
- If you are looking to add interaction as a layer to charts, Chart.js is not the library for you . A better option would be using SVG, as this will let you attach event listeners to any of the elements in the chart, as these are all DOM nodes.
- Chart.js uses the canvas element, which is a single DOM node, similar in characteristics to a static image. This does mean that it has a wider scope for compatibility, and less memory implications than SVG based charting solutions. The canvas element also allows for saving the contents as a base 64 string, allowing saving the chart as an image.
- In SVG, all of the lines, data points and everything you see is a DOM node. As a result of this, complex charts with a lot of intricacies, or many charts on the page will often see dips in performance when scrolling or generating the chart, especially when there are multiple on the page. SVG also has relatively poor mobile support, with Android not supporting SVG at all before version 3.0, and iOS before 5.0. (caniuse.com/svg-html5 ).
- Browser support
- Browser support for the canvas element is available in all modern & major mobile browsers (caniuse.com/canvas ).
- For IE8 & below, I would recommend using the polyfill ExplorerCanvas - available at https://code.google.com/p/explorercanvas/ . It falls back to Internet explorer's format VML when canvas support is not available. Example use:
- <head>
- <!--[if lte IE 8]>
- <script src="excanvas.js"></script>
- <![endif]-->
-</head>
- Usually I would recommend feature detection to choose whether or not to load a polyfill, rather than IE conditional comments, however in this case, VML is a Microsoft proprietary format, so it will only work in IE.
- Some important points to note in my experience using ExplorerCanvas as a fallback.
-
- Initialise charts on load rather than DOMContentReady when using the library, as sometimes a race condition will occur, and it will result in an error when trying to get the 2d context of a canvas.
- New VML DOM elements are being created for each animation frame and there is no hardware acceleration. As a result animation is usually slow and jerky, with flashing text. It is a good idea to dynamically turn off animation based on canvas support. I recommend using the excellent Modernizr to do this.
- When declaring fonts, the library explorercanvas requires the font name to be in single quotes inside the string. For example, instead of your scaleFontFamily property being simply "Arial", explorercanvas support, use "'Arial'" instead. Chart.js does this for default values.
-
-
- Bugs & issues
- Please report these on the Github page - at github.com/nnnick/Chart.js .
- New contributions to the library are welcome.
- License
- Chart.js is open source and available under the MIT license .
-
-
-
-
-
-
-
diff --git a/public/vendor/chartjs/docs/prettify.css b/public/vendor/chartjs/docs/prettify.css
deleted file mode 100644
index 22e0d02f..00000000
--- a/public/vendor/chartjs/docs/prettify.css
+++ /dev/null
@@ -1,38 +0,0 @@
-/* Pretty printing styles. Used with prettify.js. */
-/* Vim sunburst theme by David Leibovic */
-
-pre .str, code .str { color: #65B042; } /* string - green */
-pre .kwd, code .kwd { color: #E28964; } /* keyword - dark pink */
-pre .com, code .com { color: #AEAEAE; font-style: italic; } /* comment - gray */
-pre .typ, code .typ { color: #89bdff; } /* type - light blue */
-pre .lit, code .lit { color: #3387CC; } /* literal - blue */
-pre .pun, code .pun { color: #fff; } /* punctuation - white */
-pre .pln, code .pln { color: #fff; } /* plaintext - white */
-pre .tag, code .tag { color: #89bdff; } /* html/xml tag - light blue */
-pre .atn, code .atn { color: #bdb76b; } /* html/xml attribute name - khaki */
-pre .atv, code .atv { color: #65B042; } /* html/xml attribute value - green */
-pre .dec, code .dec { color: #3387CC; } /* decimal - blue */
-
-pre.prettyprint, code.prettyprint {
- background-color: #000;
- -moz-border-radius: 8px;
- -webkit-border-radius: 8px;
- -o-border-radius: 8px;
- -ms-border-radius: 8px;
- -khtml-border-radius: 8px;
- border-radius: 8px;
-}
-
-pre.prettyprint {
- width: 95%;
- margin: 1em auto;
- padding: 1em;
- white-space: pre-wrap;
-}
-
-
-/* Specify class=linenums on a pre to get line numbering */
-ol.linenums { margin-top: 0; margin-bottom: 0; color: #AEAEAE; } /* IE indents via margin-left */
-li.L0,li.L1,li.L2,li.L3,li.L5,li.L6,li.L7,li.L8 { list-style-type: none }
-/* Alternate shading for lines */
-li.L1,li.L3,li.L5,li.L7,li.L9 { }
diff --git a/public/vendor/chartjs/docs/prettify.js b/public/vendor/chartjs/docs/prettify.js
deleted file mode 100644
index 0f7ffa0c..00000000
--- a/public/vendor/chartjs/docs/prettify.js
+++ /dev/null
@@ -1,28 +0,0 @@
-var q=null;window.PR_SHOULD_USE_CONTINUATION=!0;
-(function(){function L(a){function m(a){var f=a.charCodeAt(0);if(f!==92)return f;var b=a.charAt(1);return(f=r[b])?f:"0"<=b&&b<="7"?parseInt(a.substring(1),8):b==="u"||b==="x"?parseInt(a.substring(2),16):a.charCodeAt(1)}function e(a){if(a<32)return(a<16?"\\x0":"\\x")+a.toString(16);a=String.fromCharCode(a);if(a==="\\"||a==="-"||a==="["||a==="]")a="\\"+a;return a}function h(a){for(var f=a.substring(1,a.length-1).match(/\\u[\dA-Fa-f]{4}|\\x[\dA-Fa-f]{2}|\\[0-3][0-7]{0,2}|\\[0-7]{1,2}|\\[\S\s]|[^\\]/g),a=
-[],b=[],o=f[0]==="^",c=o?1:0,i=f.length;c122||(d<65||j>90||b.push([Math.max(65,j)|32,Math.min(d,90)|32]),d<97||j>122||b.push([Math.max(97,j)&-33,Math.min(d,122)&-33]))}}b.sort(function(a,f){return a[0]-f[0]||f[1]-a[1]});f=[];j=[NaN,NaN];for(c=0;ci[0]&&(i[1]+1>i[0]&&b.push("-"),b.push(e(i[1])));b.push("]");return b.join("")}function y(a){for(var f=a.source.match(/\[(?:[^\\\]]|\\[\S\s])*]|\\u[\dA-Fa-f]{4}|\\x[\dA-Fa-f]{2}|\\\d+|\\[^\dux]|\(\?[!:=]|[()^]|[^()[\\^]+/g),b=f.length,d=[],c=0,i=0;c=2&&a==="["?f[c]=h(j):a!=="\\"&&(f[c]=j.replace(/[A-Za-z]/g,function(a){a=a.charCodeAt(0);return"["+String.fromCharCode(a&-33,a|32)+"]"}));return f.join("")}for(var t=0,s=!1,l=!1,p=0,d=a.length;p=5&&"lang-"===b.substring(0,5))&&!(o&&typeof o[1]==="string"))c=!1,b="src";c||(r[f]=b)}i=d;d+=f.length;if(c){c=o[1];var j=f.indexOf(c),k=j+c.length;o[2]&&(k=f.length-o[2].length,j=k-c.length);b=b.substring(5);B(l+i,f.substring(0,j),e,p);B(l+i+j,c,C(b,c),p);B(l+i+k,f.substring(k),e,p)}else p.push(l+i,b)}a.e=p}var h={},y;(function(){for(var e=a.concat(m),
-l=[],p={},d=0,g=e.length;d=0;)h[n.charAt(k)]=r;r=r[1];n=""+r;p.hasOwnProperty(n)||(l.push(r),p[n]=q)}l.push(/[\S\s]/);y=L(l)})();var t=m.length;return e}function u(a){var m=[],e=[];a.tripleQuotedStrings?m.push(["str",/^(?:'''(?:[^'\\]|\\[\S\s]|''?(?=[^']))*(?:'''|$)|"""(?:[^"\\]|\\[\S\s]|""?(?=[^"]))*(?:"""|$)|'(?:[^'\\]|\\[\S\s])*(?:'|$)|"(?:[^"\\]|\\[\S\s])*(?:"|$))/,q,"'\""]):a.multiLineStrings?m.push(["str",/^(?:'(?:[^'\\]|\\[\S\s])*(?:'|$)|"(?:[^"\\]|\\[\S\s])*(?:"|$)|`(?:[^\\`]|\\[\S\s])*(?:`|$))/,
-q,"'\"`"]):m.push(["str",/^(?:'(?:[^\n\r'\\]|\\.)*(?:'|$)|"(?:[^\n\r"\\]|\\.)*(?:"|$))/,q,"\"'"]);a.verbatimStrings&&e.push(["str",/^@"(?:[^"]|"")*(?:"|$)/,q]);var h=a.hashComments;h&&(a.cStyleComments?(h>1?m.push(["com",/^#(?:##(?:[^#]|#(?!##))*(?:###|$)|.*)/,q,"#"]):m.push(["com",/^#(?:(?:define|elif|else|endif|error|ifdef|include|ifndef|line|pragma|undef|warning)\b|[^\n\r]*)/,q,"#"]),e.push(["str",/^<(?:(?:(?:\.\.\/)*|\/?)(?:[\w-]+(?:\/[\w-]+)+)?[\w-]+\.h|[a-z]\w*)>/,q])):m.push(["com",/^#[^\n\r]*/,
-q,"#"]));a.cStyleComments&&(e.push(["com",/^\/\/[^\n\r]*/,q]),e.push(["com",/^\/\*[\S\s]*?(?:\*\/|$)/,q]));a.regexLiterals&&e.push(["lang-regex",/^(?:^^\.?|[!+-]|!=|!==|#|%|%=|&|&&|&&=|&=|\(|\*|\*=|\+=|,|-=|->|\/|\/=|:|::|;|<|<<|<<=|<=|=|==|===|>|>=|>>|>>=|>>>|>>>=|[?@[^]|\^=|\^\^|\^\^=|{|\||\|=|\|\||\|\|=|~|break|case|continue|delete|do|else|finally|instanceof|return|throw|try|typeof)\s*(\/(?=[^*/])(?:[^/[\\]|\\[\S\s]|\[(?:[^\\\]]|\\[\S\s])*(?:]|$))+\/)/]);(h=a.types)&&e.push(["typ",h]);a=(""+a.keywords).replace(/^ | $/g,
-"");a.length&&e.push(["kwd",RegExp("^(?:"+a.replace(/[\s,]+/g,"|")+")\\b"),q]);m.push(["pln",/^\s+/,q," \r\n\t\xa0"]);e.push(["lit",/^@[$_a-z][\w$@]*/i,q],["typ",/^(?:[@_]?[A-Z]+[a-z][\w$@]*|\w+_t\b)/,q],["pln",/^[$_a-z][\w$@]*/i,q],["lit",/^(?:0x[\da-f]+|(?:\d(?:_\d+)*\d*(?:\.\d*)?|\.\d\+)(?:e[+-]?\d+)?)[a-z]*/i,q,"0123456789"],["pln",/^\\[\S\s]?/,q],["pun",/^.[^\s\w"-$'./@\\`]*/,q]);return x(m,e)}function D(a,m){function e(a){switch(a.nodeType){case 1:if(k.test(a.className))break;if("BR"===a.nodeName)h(a),
-a.parentNode&&a.parentNode.removeChild(a);else for(a=a.firstChild;a;a=a.nextSibling)e(a);break;case 3:case 4:if(p){var b=a.nodeValue,d=b.match(t);if(d){var c=b.substring(0,d.index);a.nodeValue=c;(b=b.substring(d.index+d[0].length))&&a.parentNode.insertBefore(s.createTextNode(b),a.nextSibling);h(a);c||a.parentNode.removeChild(a)}}}}function h(a){function b(a,d){var e=d?a.cloneNode(!1):a,f=a.parentNode;if(f){var f=b(f,1),g=a.nextSibling;f.appendChild(e);for(var h=g;h;h=g)g=h.nextSibling,f.appendChild(h)}return e}
-for(;!a.nextSibling;)if(a=a.parentNode,!a)return;for(var a=b(a.nextSibling,0),e;(e=a.parentNode)&&e.nodeType===1;)a=e;d.push(a)}var k=/(?:^|\s)nocode(?:\s|$)/,t=/\r\n?|\n/,s=a.ownerDocument,l;a.currentStyle?l=a.currentStyle.whiteSpace:window.getComputedStyle&&(l=s.defaultView.getComputedStyle(a,q).getPropertyValue("white-space"));var p=l&&"pre"===l.substring(0,3);for(l=s.createElement("LI");a.firstChild;)l.appendChild(a.firstChild);for(var d=[l],g=0;g=0;){var h=m[e];A.hasOwnProperty(h)?window.console&&console.warn("cannot override language handler %s",h):A[h]=a}}function C(a,m){if(!a||!A.hasOwnProperty(a))a=/^\s*=o&&(h+=2);e>=c&&(a+=2)}}catch(w){"console"in window&&console.log(w&&w.stack?w.stack:w)}}var v=["break,continue,do,else,for,if,return,while"],w=[[v,"auto,case,char,const,default,double,enum,extern,float,goto,int,long,register,short,signed,sizeof,static,struct,switch,typedef,union,unsigned,void,volatile"],
-"catch,class,delete,false,import,new,operator,private,protected,public,this,throw,true,try,typeof"],F=[w,"alignof,align_union,asm,axiom,bool,concept,concept_map,const_cast,constexpr,decltype,dynamic_cast,explicit,export,friend,inline,late_check,mutable,namespace,nullptr,reinterpret_cast,static_assert,static_cast,template,typeid,typename,using,virtual,where"],G=[w,"abstract,boolean,byte,extends,final,finally,implements,import,instanceof,null,native,package,strictfp,super,synchronized,throws,transient"],
-H=[G,"as,base,by,checked,decimal,delegate,descending,dynamic,event,fixed,foreach,from,group,implicit,in,interface,internal,into,is,lock,object,out,override,orderby,params,partial,readonly,ref,sbyte,sealed,stackalloc,string,select,uint,ulong,unchecked,unsafe,ushort,var"],w=[w,"debugger,eval,export,function,get,null,set,undefined,var,with,Infinity,NaN"],I=[v,"and,as,assert,class,def,del,elif,except,exec,finally,from,global,import,in,is,lambda,nonlocal,not,or,pass,print,raise,try,with,yield,False,True,None"],
-J=[v,"alias,and,begin,case,class,def,defined,elsif,end,ensure,false,in,module,next,nil,not,or,redo,rescue,retry,self,super,then,true,undef,unless,until,when,yield,BEGIN,END"],v=[v,"case,done,elif,esac,eval,fi,function,in,local,set,then,until"],K=/^(DIR|FILE|vector|(de|priority_)?queue|list|stack|(const_)?iterator|(multi)?(set|map)|bitset|u?(int|float)\d*)/,N=/\S/,O=u({keywords:[F,H,w,"caller,delete,die,do,dump,elsif,eval,exit,foreach,for,goto,if,import,last,local,my,next,no,our,print,package,redo,require,sub,undef,unless,until,use,wantarray,while,BEGIN,END"+
-I,J,v],hashComments:!0,cStyleComments:!0,multiLineStrings:!0,regexLiterals:!0}),A={};k(O,["default-code"]);k(x([],[["pln",/^[^]+/],["dec",/^]*(?:>|$)/],["com",/^<\!--[\S\s]*?(?:--\>|$)/],["lang-",/^<\?([\S\s]+?)(?:\?>|$)/],["lang-",/^<%([\S\s]+?)(?:%>|$)/],["pun",/^(?:<[%?]|[%?]>)/],["lang-",/^]*>([\S\s]+?)<\/xmp\b[^>]*>/i],["lang-js",/^
-
-
-
-
-
+
+ Bar Chart
+
+
+
+
-
+
- var myLine = new Chart(document.getElementById("canvas").getContext("2d")).Bar(barChartData);
-
-
-
diff --git a/public/vendor/chartjs/samples/doughnut.html b/public/vendor/chartjs/samples/doughnut.html
index 83f4c9e7..42647557 100644
--- a/public/vendor/chartjs/samples/doughnut.html
+++ b/public/vendor/chartjs/samples/doughnut.html
@@ -1,46 +1,199 @@
-
- Doughnut Chart
-
-
-
-
-
-
+
+ Doughnut Chart
+
+
+
+
-
+
- var myDoughnut = new Chart(document.getElementById("canvas").getContext("2d")).Doughnut(doughnutData);
-
-
-
diff --git a/public/vendor/chartjs/samples/line.html b/public/vendor/chartjs/samples/line.html
index 4c673445..00c0f499 100644
--- a/public/vendor/chartjs/samples/line.html
+++ b/public/vendor/chartjs/samples/line.html
@@ -1,43 +1,229 @@
-
- Line Chart
-
-
-
-
-
-
+
+ Line Chart
+
+
+
+
-
+
- var myLine = new Chart(document.getElementById("canvas").getContext("2d")).Line(lineChartData);
-
-
-