diff --git a/production/form.html b/production/form.html index 6732892d..eb2fa457 100755 --- a/production/form.html +++ b/production/form.html @@ -1611,10 +1611,6 @@ rating: 4 }); - $('.starrr').on('click', function (e) { - e.preventDefault(); - }); - $('.stars').on('starrr:change', function (e, value) { $('.stars-count').html(value); }); diff --git a/vendors/Chart.js/.bower.json b/vendors/Chart.js/.bower.json index b5cc30f7..24fe5947 100644 --- a/vendors/Chart.js/.bower.json +++ b/vendors/Chart.js/.bower.json @@ -1,23 +1,23 @@ { "name": "Chart.js", - "version": "2.0.2", + "version": "2.1.0", "description": "Simple HTML5 Charts using the canvas element", "homepage": "https://github.com/nnnick/Chart.js", "author": "nnnick", + "license": "MIT", "main": [ "dist/Chart.js" ], "devDependencies": { "jquery": "~2.1.4" }, - "_release": "2.0.2", + "_release": "2.1.0", "_resolution": { "type": "version", - "tag": "2.0.2", - "commit": "67625063a3c1242ca13858aa629668007b5b8106" + "tag": "2.1.0", + "commit": "2ee37e12e379ca9b8ad3be7105715bf8c543ead0" }, "_source": "https://github.com/nnnick/Chart.js.git", "_target": "^2.0.2", - "_originalSource": "Chart.js", - "_direct": true + "_originalSource": "Chart.js" } \ No newline at end of file diff --git a/vendors/Chart.js/.codeclimate.yml b/vendors/Chart.js/.codeclimate.yml index 2d90af82..d865954a 100644 --- a/vendors/Chart.js/.codeclimate.yml +++ b/vendors/Chart.js/.codeclimate.yml @@ -1,4 +1,3 @@ ---- engines: duplication: enabled: true @@ -11,9 +10,9 @@ engines: enabled: true ratings: paths: - - "**.js" + - "src/**/*.js" exclude_paths: -- dist/ -- node_modules/ -- test/ -- coverage/ +- dist/**/* +- node_modules/**/* +- test/**/* +- coverage/**/* diff --git a/vendors/Chart.js/.travis.yml b/vendors/Chart.js/.travis.yml index cdb70857..2e66dc7b 100644 --- a/vendors/Chart.js/.travis.yml +++ b/vendors/Chart.js/.travis.yml @@ -1,7 +1,6 @@ language: node_js node_js: - - "5.6" - - "4.3" + - "5.10" before_install: - "export CHROME_BIN=/usr/bin/google-chrome" diff --git a/vendors/Chart.js/CONTRIBUTING.md b/vendors/Chart.js/CONTRIBUTING.md index beab22d0..0d026275 100644 --- a/vendors/Chart.js/CONTRIBUTING.md +++ b/vendors/Chart.js/CONTRIBUTING.md @@ -7,9 +7,9 @@ Contributions to Chart.js are welcome and encouraged, but please have a look thr Using issues ------------ -The [issue tracker](https://github.com/nnnick/Chart.js/issues) is the preferred channel for reporting bugs, requesting new features and submitting pull requests. +The [issue tracker](https://github.com/chartjs/Chart.js/issues) is the preferred channel for reporting bugs, requesting new features and submitting pull requests. -If you're suggesting a new chart type, please take a look at [writing new chart types](https://github.com/nnnick/Chart.js/blob/master/docs/06-Advanced.md#writing-new-chart-types) in the documentation, and some of the [community extensions](https://github.com/nnnick/Chart.js/blob/master/docs/06-Advanced.md#community-extensions) that have been created already. +If you're suggesting a new chart type, please take a look at [writing new chart types](https://github.com/chartjs/Chart.js/blob/master/docs/07-Advanced.md#writing-new-chart-types) in the documentation or consider [creating a plugin](https://github.com/chartjs/Chart.js/blob/master/docs/07-Advanced.md#creating-plugins). To keep the library lightweight for everyone, it's unlikely we'll add many more chart types to the core of Chart.js, but issues are a good medium to design and spec out how new chart types could work and look. @@ -41,21 +41,24 @@ Pull requests Clear, concise pull requests are excellent at continuing the project's community driven growth. But please review [these guidelines](https://github.com/blog/1943-how-to-write-the-perfect-pull-request) and the guidelines below before starting work on the project. -Guidlines: +Be advised that **Chart.js 1.0.2 is in feature-complete status**. Pull requests adding new features to the 1.x branch will be disregarded. + +Guidelines: - Please create an issue first: - For bugs, we can discuss the fixing approach - For enhancements, we can discuss if it is within the project scope and avoid duplicate effort - - Please make changes to the files in [`/src`](https://github.com/nnnick/Chart.js/tree/master/src), not `Chart.js` or `Chart.min.js` in the repo root directory, this avoids merge conflicts + - Please make changes to the files in [`/src`](https://github.com/chartjs/Chart.js/tree/master/src), not `Chart.js` or `Chart.min.js` in the repo root directory, this avoids merge conflicts - Tabs for indentation, not spaces please - - If adding new functionality, please also update the relevant `.md` file in [`/docs`](https://github.com/nnnick/Chart.js/tree/master/docs) + - If adding new functionality, please also update the relevant `.md` file in [`/docs`](https://github.com/chartjs/Chart.js/tree/master/docs) - Please make your commits in logical sections with clear commit messages -Joining the Project +Joining the project ------------- - - Active committers and contributors are invited to introduce yourself and request commit access to this project. Please send an email to hello@nickdownie.com or file an issue. + - Active committers and contributors are invited to introduce yourself and request commit access to this project. Please send an email to hello@nickdownie.com or file an issue. + - We have a very active Slack community that you can join at https://chartjs-slack-automation.herokuapp.com. If you think you can help, we'd love to have you! License ------- -By contributing your code, you agree to license your contribution under the [MIT license](https://github.com/nnnick/Chart.js/blob/master/LICENSE.md). +By contributing your code, you agree to license your contribution under the [MIT license](https://github.com/chartjs/Chart.js/blob/master/LICENSE.md). diff --git a/vendors/Chart.js/LICENSE.md b/vendors/Chart.js/LICENSE.md index e10bc0ff..dc93bcc3 100644 --- a/vendors/Chart.js/LICENSE.md +++ b/vendors/Chart.js/LICENSE.md @@ -1,4 +1,5 @@ -Copyright (c) 2013-2015 Nick Downie +The MIT License (MIT) +Copyright (c) 2013-2016 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/vendors/Chart.js/README.md b/vendors/Chart.js/README.md index f6341264..547a92f8 100644 --- a/vendors/Chart.js/README.md +++ b/vendors/Chart.js/README.md @@ -1,45 +1,36 @@ -# Chart.js - -[![Build Status](https://travis-ci.org/nnnick/Chart.js.svg?branch=v2.0-dev)](https://travis-ci.org/nnnick/Chart.js) [![Code Climate](https://codeclimate.com/github/nnnick/Chart.js/badges/gpa.svg)](https://codeclimate.com/github/nnnick/Chart.js)[![Coverage Status](https://coveralls.io/repos/nnnick/Chart.js/badge.svg?branch=v2.0-dev)](https://coveralls.io/r/nnnick/Chart.js?branch=v2.0-dev) +# Chart.js +[![Build Status](https://travis-ci.org/chartjs/Chart.js.svg?branch=master)](https://travis-ci.org/chartjs/Chart.js) [![Code Climate](https://codeclimate.com/github/nnnick/Chart.js/badges/gpa.svg)](https://codeclimate.com/github/nnnick/Chart.js) [![Coverage Status](https://coveralls.io/repos/github/chartjs/Chart.js/badge.svg?branch=master)](https://coveralls.io/github/chartjs/Chart.js?branch=master) +[![Chart.js on Slack](https://img.shields.io/badge/slack-Chart.js-blue.svg)](https://chartjs-slack-automation.herokuapp.com/) *Simple HTML5 Charts using the canvas element* [chartjs.org](http://www.chartjs.org) -## v2.0 Beta +## Installation -Current Release: [2.0.0-beta2](https://github.com/nnnick/Chart.js/releases/tag/2.0.0-beta2) +To download a zip, go to the Chart.js on Github -The next generation and release of Chart.js has been well under way this year and we are very close to releasing some amazing new features including, but not limited to: -- Rewritten, optimized, and unit-tested -- New and improved scales (log, time, linear, category, multiple scales) -- Improved responsiveness and resizing -- Powerful support for adding, removing, changing, and updating data on the fly -- Animations on all elements, colors and tooltips -- Powerful customization when you need it. Automatic and dynamic when you don't. -- Excellent support for modern frameworks and modular build systems. -- Even more extensible via new element controllers, combo chart support, and hook system -- Bug fixes not addressed in 1.x, and much, much more... +To install via npm / bower: -#####Contributing to 2.0 -Submit PR's to the v2.0-dev branch. - -#####Building and Testing -`gulp build`, `gulp test` - -## v1.x Status: Feature Complete -We are now treating v1.x as feature complete. PR's for bug fixes are welcome, but we urge any open PR's for v1.x features to be refactored and resubmitted for v2.x (if the feature has not already been implemented). +```bash +npm install chart.js --save +bower install Chart.js --save +``` +CDN: https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.0.0/Chart.js ## Documentation -You can find documentation at [chartjs.org/docs](http://www.chartjs.org/docs/). The markdown files that build the site are available under `/docs`. Please note - in some of the json examples of configuration you might notice some liquid tags - this is just for the generating the site html, please disregard. +You can find documentation at [www.chartjs.org/docs](http://www.chartjs.org/docs). The markdown files that build the site are available under `/docs`. Previous version documentation is available at [www.chartjs.org/docs/#notes-previous-versions](http://www.chartjs.org/docs/#notes-previous-versions). -## Bugs, issues and contributing +## Contributing -Before submitting an issue or a pull request to the project, please take a moment to look over the [contributing guidelines](https://github.com/nnnick/Chart.js/blob/master/CONTRIBUTING.md) first. +Before submitting an issue or a pull request to the project, please take a moment to look over the [contributing guidelines](https://github.com/chartjs/Chart.js/blob/master/CONTRIBUTING.md) first. For support using Chart.js, please post questions with the [`chartjs` tag on Stack Overflow](http://stackoverflow.com/questions/tagged/chartjs). +## Building and Testing +`gulp build`, `gulp test` + ## License Chart.js is available under the [MIT license](http://opensource.org/licenses/MIT). diff --git a/vendors/Chart.js/bower.json b/vendors/Chart.js/bower.json index 5e4c4da1..e1bb8c25 100644 --- a/vendors/Chart.js/bower.json +++ b/vendors/Chart.js/bower.json @@ -1,9 +1,10 @@ { "name": "Chart.js", - "version": "2.0.2", + "version": "2.1.0", "description": "Simple HTML5 Charts using the canvas element", "homepage": "https://github.com/nnnick/Chart.js", "author": "nnnick", + "license": "MIT", "main": [ "dist/Chart.js" ], diff --git a/vendors/Chart.js/dist/Chart.bundle.js b/vendors/Chart.js/dist/Chart.bundle.js index 20447e4f..68d4b054 100644 --- a/vendors/Chart.js/dist/Chart.bundle.js +++ b/vendors/Chart.js/dist/Chart.bundle.js @@ -1,3 +1,12 @@ +/*! + * Chart.js + * http://chartjs.org/ + * Version: 2.0.2 + * + * Copyright 2016 Nick Downie + * Released under the MIT license + * https://github.com/chartjs/Chart.js/blob/master/LICENSE.md + */ (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o 0 ? posDS.data[index] : 0; } } @@ -5133,9 +5136,9 @@ module.exports = function(Chart) { }, getRuler: function() { - - var xScale = this.getScaleForId(this.getDataset().xAxisID); - var yScale = this.getScaleForId(this.getDataset().yAxisID); + var meta = this.getMeta(); + var xScale = this.getScaleForId(meta.xAxisID); + var yScale = this.getScaleForId(meta.yAxisID); var datasetCount = this.getBarCount(); var tickWidth = (function() { @@ -5148,6 +5151,12 @@ module.exports = function(Chart) { var categoryWidth = tickWidth * xScale.options.categoryPercentage; var categorySpacing = (tickWidth - (tickWidth * xScale.options.categoryPercentage)) / 2; var fullBarWidth = categoryWidth / datasetCount; + + if (xScale.ticks.length !== this.chart.data.labels.length) { + var perc = xScale.ticks.length / this.chart.data.labels.length; + fullBarWidth = fullBarWidth * perc; + } + var barWidth = fullBarWidth * xScale.options.barPercentage; var barSpacing = fullBarWidth - (fullBarWidth * xScale.options.barPercentage); @@ -5163,7 +5172,7 @@ module.exports = function(Chart) { }, calculateBarWidth: function() { - var xScale = this.getScaleForId(this.getDataset().xAxisID); + var xScale = this.getScaleForId(this.getMeta().xAxisID); var ruler = this.getRuler(); return xScale.options.stacked ? ruler.categoryWidth : ruler.barWidth; }, @@ -5171,9 +5180,11 @@ module.exports = function(Chart) { // Get bar index from the given dataset index accounting for the fact that not all bars are visible getBarIndex: function(datasetIndex) { var barIndex = 0; + var meta, j; - for (var j = 0; j < datasetIndex; ++j) { - if (helpers.isDatasetVisible(this.chart.data.datasets[j]) && this.chart.data.datasets[j].bar) { + for (j = 0; j < datasetIndex; ++j) { + meta = this.chart.getDatasetMeta(j); + if (meta.bar && this.chart.isDatasetVisible(j)) { ++barIndex; } } @@ -5182,9 +5193,9 @@ module.exports = function(Chart) { }, calculateBarX: function(index, datasetIndex) { - - var yScale = this.getScaleForId(this.getDataset().yAxisID); - var xScale = this.getScaleForId(this.getDataset().xAxisID); + var meta = this.getMeta(); + var yScale = this.getScaleForId(meta.yAxisID); + var xScale = this.getScaleForId(meta.xAxisID); var barIndex = this.getBarIndex(datasetIndex); var ruler = this.getRuler(); @@ -5204,9 +5215,9 @@ module.exports = function(Chart) { }, calculateBarY: function(index, datasetIndex) { - - var xScale = this.getScaleForId(this.getDataset().xAxisID); - var yScale = this.getScaleForId(this.getDataset().yAxisID); + var meta = this.getMeta(); + var xScale = this.getScaleForId(meta.xAxisID); + var yScale = this.getScaleForId(meta.yAxisID); var value = this.getDataset().data[index]; @@ -5217,7 +5228,8 @@ module.exports = function(Chart) { for (var i = 0; i < datasetIndex; i++) { var ds = this.chart.data.datasets[i]; - if (helpers.isDatasetVisible(ds) && ds.bar && ds.yAxisID === yScale.id) { + var dsMeta = this.chart.getDatasetMeta(i); + if (dsMeta.bar && dsMeta.yAxisID === yScale.id && this.chart.isDatasetVisible(i)) { if (ds.data[index] < 0) { sumNeg += ds.data[index] || 0; } else { @@ -5231,8 +5243,6 @@ module.exports = function(Chart) { } else { return yScale.getPixelForValue(sumPos + value); } - - return yScale.getPixelForValue(value); } return yScale.getPixelForValue(value); @@ -5240,7 +5250,7 @@ module.exports = function(Chart) { draw: function(ease) { var easingDecimal = ease || 1; - helpers.each(this.getDataset().metaData, function(rectangle, index) { + helpers.each(this.getMeta().data, function(rectangle, index) { var d = this.getDataset().data[index]; if (d !== null && d !== undefined && !isNaN(d)) { rectangle.transition(easingDecimal).draw(); @@ -5267,6 +5277,296 @@ module.exports = function(Chart) { } }); + + + // including horizontalBar in the bar file, instead of a file of its own + // it extends bar (like pie extends doughnut) + Chart.defaults.horizontalBar = { + hover: { + mode: "label" + }, + + scales: { + xAxes: [{ + type: "linear", + position: "bottom" + }], + yAxes: [{ + position: "left", + type: "category", + + // Specific to Horizontal Bar Controller + categoryPercentage: 0.8, + barPercentage: 0.9, + + // grid line settings + gridLines: { + offsetGridLines: true + } + }] + }, + }; + + Chart.controllers.horizontalBar = Chart.controllers.bar.extend({ + updateElement: function updateElement(rectangle, index, reset, numBars) { + var meta = this.getMeta(); + var xScale = this.getScaleForId(meta.xAxisID); + var yScale = this.getScaleForId(meta.yAxisID); + + var xScalePoint; + + if (xScale.min < 0 && xScale.max < 0) { + // all less than 0. use the right + xScalePoint = xScale.getPixelForValue(xScale.max); + } else if (xScale.min > 0 && xScale.max > 0) { + xScalePoint = xScale.getPixelForValue(xScale.min); + } else { + xScalePoint = xScale.getPixelForValue(0); + } + + helpers.extend(rectangle, { + // Utility + _chart: this.chart.chart, + _xScale: xScale, + _yScale: yScale, + _datasetIndex: this.index, + _index: index, + + // Desired view properties + _model: { + x: reset ? xScalePoint : this.calculateBarX(index, this.index), + y: this.calculateBarY(index, this.index), + + // Tooltip + label: this.chart.data.labels[index], + datasetLabel: this.getDataset().label, + + // Appearance + base: reset ? xScalePoint : this.calculateBarBase(this.index, index), + height: this.calculateBarHeight(numBars), + backgroundColor: rectangle.custom && rectangle.custom.backgroundColor ? rectangle.custom.backgroundColor : helpers.getValueAtIndexOrDefault(this.getDataset().backgroundColor, index, this.chart.options.elements.rectangle.backgroundColor), + borderSkipped: rectangle.custom && rectangle.custom.borderSkipped ? rectangle.custom.borderSkipped : this.chart.options.elements.rectangle.borderSkipped, + 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) + }, + + draw: function () { + + var ctx = this._chart.ctx; + var vm = this._view; + + var halfHeight = vm.height / 2, + topY = vm.y - halfHeight, + bottomY = vm.y + halfHeight, + right = vm.base - (vm.base - vm.x), + 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) { + topY += halfStroke; + bottomY -= halfStroke; + right += halfStroke; + } + + ctx.beginPath(); + + ctx.fillStyle = vm.backgroundColor; + ctx.strokeStyle = vm.borderColor; + ctx.lineWidth = vm.borderWidth; + + // Corner points, from bottom-left to bottom-right clockwise + // | 1 2 | + // | 0 3 | + var corners = [ + [vm.base, bottomY], + [vm.base, topY], + [right, topY], + [right, bottomY] + ]; + + // Find first (starting) corner with fallback to 'bottom' + var borders = ['bottom', 'left', 'top', 'right']; + var startCorner = borders.indexOf(vm.borderSkipped, 0); + if (startCorner === -1) + startCorner = 0; + + function cornerAt(index) { + return corners[(startCorner + index) % 4]; + } + + // Draw rectangle from 'startCorner' + ctx.moveTo.apply(ctx, cornerAt(0)); + for (var i = 1; i < 4; i++) + ctx.lineTo.apply(ctx, cornerAt(i)); + + ctx.fill(); + if (vm.borderWidth) { + ctx.stroke(); + } + }, + + inRange: function (mouseX, mouseY) { + var vm = this._view; + var inRange = false; + + if (vm) { + if (vm.x < vm.base) { + inRange = (mouseY >= vm.y - vm.height / 2 && mouseY <= vm.y + vm.height / 2) && (mouseX >= vm.x && mouseX <= vm.base); + } else { + inRange = (mouseY >= vm.y - vm.height / 2 && mouseY <= vm.y + vm.height / 2) && (mouseX >= vm.base && mouseX <= vm.x); + } + } + + return inRange; + } + }); + + rectangle.pivot(); + }, + + calculateBarBase: function (datasetIndex, index) { + var meta = this.getMeta(); + var xScale = this.getScaleForId(meta.xAxisID); + var yScale = this.getScaleForId(meta.yAxisID); + + var base = 0; + + if (xScale.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]; + var negDSMeta = this.chart.getDatasetMeta(i); + if (negDSMeta.bar && negDSMeta.xAxisID === xScale.id && this.chart.isDatasetVisible(i)) { + base += negDS.data[index] < 0 ? negDS.data[index] : 0; + } + } + } else { + for (var j = 0; j < datasetIndex; j++) { + var posDS = this.chart.data.datasets[j]; + var posDSMeta = this.chart.getDatasetMeta(j); + if (posDSMeta.bar && posDSMeta.xAxisID === xScale.id && this.chart.isDatasetVisible(j)) { + base += posDS.data[index] > 0 ? posDS.data[index] : 0; + } + } + } + + return xScale.getPixelForValue(base); + } + + base = xScale.getPixelForValue(xScale.min); + + if (xScale.beginAtZero || ((xScale.min <= 0 && xScale.max >= 0) || (xScale.min >= 0 && xScale.max <= 0))) { + base = xScale.getPixelForValue(0, 0); + } else if (xScale.min < 0 && xScale.max < 0) { + // All values are negative. Use the right as the base + base = xScale.getPixelForValue(xScale.max); + } + + return base; + }, + + getRuler: function () { + var meta = this.getMeta(); + var xScale = this.getScaleForId(meta.xAxisID); + var yScale = this.getScaleForId(meta.yAxisID); + var datasetCount = this.getBarCount(); + + var tickHeight = (function () { + var min = yScale.getPixelForTick(1) - yScale.getPixelForTick(0); + for (var i = 2; i < this.getDataset().data.length; i++) { + min = Math.min(yScale.getPixelForTick(i) - yScale.getPixelForTick(i - 1), min); + } + return min; + }).call(this); + var categoryHeight = tickHeight * yScale.options.categoryPercentage; + var categorySpacing = (tickHeight - (tickHeight * yScale.options.categoryPercentage)) / 2; + var fullBarHeight = categoryHeight / datasetCount; + + if (yScale.ticks.length !== this.chart.data.labels.length) { + var perc = yScale.ticks.length / this.chart.data.labels.length; + fullBarHeight = fullBarHeight * perc; + } + + var barHeight = fullBarHeight * yScale.options.barPercentage; + var barSpacing = fullBarHeight - (fullBarHeight * yScale.options.barPercentage); + + return { + datasetCount: datasetCount, + tickHeight: tickHeight, + categoryHeight: categoryHeight, + categorySpacing: categorySpacing, + fullBarHeight: fullBarHeight, + barHeight: barHeight, + barSpacing: barSpacing, + }; + }, + + calculateBarHeight: function () { + var yScale = this.getScaleForId(this.getMeta().yAxisID); + var ruler = this.getRuler(); + return yScale.options.stacked ? ruler.categoryHeight : ruler.barHeight; + }, + + calculateBarX: function (index, datasetIndex) { + var meta = this.getMeta(); + var xScale = this.getScaleForId(meta.xAxisID); + var yScale = this.getScaleForId(meta.yAxisID); + + var value = this.getDataset().data[index]; + + if (xScale.options.stacked) { + + var sumPos = 0, + sumNeg = 0; + + for (var i = 0; i < datasetIndex; i++) { + var ds = this.chart.data.datasets[i]; + var dsMeta = this.chart.getDatasetMeta(i); + if (dsMeta.bar && dsMeta.xAxisID === xScale.id && this.chart.isDatasetVisible(i)) { + if (ds.data[index] < 0) { + sumNeg += ds.data[index] || 0; + } else { + sumPos += ds.data[index] || 0; + } + } + } + + if (value < 0) { + return xScale.getPixelForValue(sumNeg + value); + } else { + return xScale.getPixelForValue(sumPos + value); + } + } + + return xScale.getPixelForValue(value); + }, + + calculateBarY: function (index, datasetIndex) { + var meta = this.getMeta(); + var yScale = this.getScaleForId(meta.yAxisID); + var xScale = this.getScaleForId(meta.xAxisID); + var barIndex = this.getBarIndex(datasetIndex); + + var ruler = this.getRuler(); + var topTick = yScale.getPixelForValue(null, index, datasetIndex, this.chart.isCombo); + topTick -= this.chart.isCombo ? (ruler.tickHeight / 2) : 0; + + if (yScale.options.stacked) { + return topTick + (ruler.categoryHeight / 2) + ruler.categorySpacing; + } + + return topTick + + (ruler.barHeight / 2) + + ruler.categorySpacing + + (ruler.barHeight * barIndex) + + (ruler.barSpacing / 2) + + (ruler.barSpacing * barIndex); + } + }); }; },{}],16:[function(require,module,exports){ @@ -5312,11 +5612,9 @@ module.exports = function(Chart) { Chart.controllers.bubble = Chart.DatasetController.extend({ addElements: function() { - - this.getDataset().metaData = this.getDataset().metaData || []; - + var meta = this.getMeta(); helpers.each(this.getDataset().data, function(value, index) { - this.getDataset().metaData[index] = this.getDataset().metaData[index] || new Chart.elements.Point({ + meta.data[index] = meta.data[index] || new Chart.elements.Point({ _chart: this.chart.chart, _datasetIndex: this.index, _index: index @@ -5324,25 +5622,22 @@ module.exports = function(Chart) { }, 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 + // Add to the points array and reset it + this.getMeta().data.splice(index, 0, 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 meta = this.getMeta(); + var points = meta.data; + var yScale = this.getScaleForId(meta.yAxisID); + var xScale = this.getScaleForId(meta.xAxisID); var scaleBase; if (yScale.min < 0 && yScale.max < 0) { @@ -5361,8 +5656,9 @@ module.exports = function(Chart) { }, updateElement: function(point, index, reset) { - var yScale = this.getScaleForId(this.getDataset().yAxisID); - var xScale = this.getScaleForId(this.getDataset().xAxisID); + var meta = this.getMeta(); + var yScale = this.getScaleForId(meta.yAxisID); + var xScale = this.getScaleForId(meta.xAxisID); var scaleBase; if (yScale.min < 0 && yScale.max < 0) { @@ -5409,7 +5705,7 @@ module.exports = function(Chart) { var easingDecimal = ease || 1; // Transition and Draw the Points - helpers.each(this.getDataset().metaData, function(point, index) { + helpers.each(this.getMeta().data, function(point, index) { point.transition(easingDecimal); point.draw(); }); @@ -5462,11 +5758,11 @@ module.exports = function(Chart) { if (chart.data.datasets.length) { for (var i = 0; i < chart.data.datasets[0].data.length; ++i) { - text.push('
  • '); + text.push('
  • '); if (chart.data.labels[i]) { text.push(chart.data.labels[i]); } - text.push('
  • '); + text.push(''); } } @@ -5475,37 +5771,45 @@ module.exports = function(Chart) { }, legend: { labels: { - generateLabels: function(data) { + generateLabels: function(chart) { + var data = chart.data; if (data.labels.length && data.datasets.length) { return data.labels.map(function(label, i) { + var meta = chart.getDatasetMeta(0); + var ds = data.datasets[0]; + var arc = meta.data[i]; + var fill = arc.custom && arc.custom.backgroundColor ? arc.custom.backgroundColor : helpers.getValueAtIndexOrDefault(ds.backgroundColor, i, this.chart.options.elements.arc.backgroundColor); + var stroke = arc.custom && arc.custom.borderColor ? arc.custom.borderColor : helpers.getValueAtIndexOrDefault(ds.borderColor, i, this.chart.options.elements.arc.borderColor); + var bw = arc.custom && arc.custom.borderWidth ? arc.custom.borderWidth : helpers.getValueAtIndexOrDefault(ds.borderWidth, i, this.chart.options.elements.arc.borderWidth); + return { text: label, - fillStyle: data.datasets[0].backgroundColor[i], - hidden: isNaN(data.datasets[0].data[i]), + fillStyle: fill, + strokeStyle: stroke, + lineWidth: bw, + hidden: isNaN(ds.data[i]) || meta.data[i].hidden, // Extra data used for toggling the correct item index: i }; - }); + }, this); } else { return []; } } }, + onClick: function(e, legendItem) { - helpers.each(this.chart.data.datasets, function(dataset) { - dataset.metaHiddenData = dataset.metaHiddenData || []; - var idx = legendItem.index; + var index = legendItem.index; + var chart = this.chart; + var i, ilen, meta; - 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]; - } - }); + for (i = 0, ilen = (chart.data.datasets || []).length; i < ilen; ++i) { + meta = chart.getDatasetMeta(i); + meta.data[index].hidden = !meta.data[index].hidden; + } - this.chart.update(); + chart.update(); } }, @@ -5543,17 +5847,17 @@ module.exports = function(Chart) { }, addElements: function() { - this.getDataset().metaData = this.getDataset().metaData || []; + var meta = this.getMeta(); helpers.each(this.getDataset().data, function(value, index) { - this.getDataset().metaData[index] = this.getDataset().metaData[index] || new Chart.elements.Arc({ + meta.data[index] = meta.data[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, @@ -5564,17 +5868,9 @@ module.exports = function(Chart) { this.getDataset().backgroundColor.splice(index, 0, colorForNewElement); } - // Reset the point + // Add to the points array and reset it + this.getMeta().data.splice(index, 0, arc); 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 @@ -5582,7 +5878,7 @@ module.exports = function(Chart) { var ringIndex = 0; for (var j = 0; j < datasetIndex; ++j) { - if (helpers.isDatasetVisible(this.chart.data.datasets[j])) { + if (this.chart.isDatasetVisible(j)) { ++ringIndex; } } @@ -5597,7 +5893,7 @@ module.exports = function(Chart) { var offset = {x: 0, y: 0}; // If the chart's circumference isn't a full circle, calculate minSize as a ratio of the width/height of the arc - if (this.chart.options.circumference && this.chart.options.circumference < Math.PI * 2.0) { + if (this.chart.options.circumference < Math.PI * 2.0) { var startAngle = this.chart.options.rotation % (Math.PI * 2.0); startAngle += Math.PI * 2.0 * (startAngle >= Math.PI ? -1 : startAngle < -Math.PI ? 1 : 0); var endAngle = startAngle + this.chart.options.circumference; @@ -5617,30 +5913,26 @@ module.exports = function(Chart) { this.chart.outerRadius = Math.max(minSize / 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.chart.radiusLength = (this.chart.outerRadius - this.chart.innerRadius) / this.chart.getVisibleDatasetCount(); this.chart.offsetX = offset.x * this.chart.outerRadius; this.chart.offsetY = offset.y * this.chart.outerRadius; - this.getDataset().total = 0; - helpers.each(this.getDataset().data, function(value) { - if (!isNaN(value)) { - this.getDataset().total += Math.abs(value); - } - }, this); + this.getMeta().total = this.calculateTotal(); 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) { + helpers.each(this.getMeta().data, 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 startAngle = this.chart.options.rotation || (Math.PI * -0.5); // non reset case handled later - var endAngle = this.chart.options.rotation || (Math.PI * -0.5); // non reset case handled later - var circumference = reset && this.chart.options.animation.animateRotate ? 0 : this.calculateCircumference(this.getDataset().data[index]) * ((this.chart.options.circumference || (2.0 * Math.PI)) / (2.0 * Math.PI)); + var startAngle = this.chart.options.rotation; // non reset case handled later + var endAngle = this.chart.options.rotation; // non reset case handled later + var circumference = reset && this.chart.options.animation.animateRotate ? 0 : arc.hidden? 0 : this.calculateCircumference(this.getDataset().data[index]) * (this.chart.options.circumference / (2.0 * Math.PI)); var innerRadius = reset && this.chart.options.animation.animateScale ? 0 : this.innerRadius; var outerRadius = reset && this.chart.options.animation.animateScale ? 0 : this.outerRadius; @@ -5670,12 +5962,12 @@ module.exports = function(Chart) { }); // Set correct angles if not resetting - if (!reset) { + if (!reset || !this.chart.options.animation.animateRotate) { if (index === 0) { - arc._model.startAngle = this.chart.options.rotation || (Math.PI * -0.5); + arc._model.startAngle = this.chart.options.rotation; } else { - arc._model.startAngle = this.getDataset().metaData[index - 1]._model.endAngle; + arc._model.startAngle = this.getMeta().data[index - 1]._model.endAngle; } arc._model.endAngle = arc._model.startAngle + arc._model.circumference; @@ -5686,7 +5978,7 @@ module.exports = function(Chart) { draw: function(ease) { var easingDecimal = ease || 1; - helpers.each(this.getDataset().metaData, function(arc, index) { + helpers.each(this.getMeta().data, function(arc, index) { arc.transition(easingDecimal).draw(); }); }, @@ -5709,15 +6001,33 @@ module.exports = function(Chart) { arc._model.borderWidth = arc.custom && arc.custom.borderWidth ? arc.custom.borderWidth : helpers.getValueAtIndexOrDefault(this.getDataset().borderWidth, index, this.chart.options.elements.arc.borderWidth); }, + calculateTotal: function() { + var dataset = this.getDataset(); + var meta = this.getMeta(); + var total = 0; + var value; + + helpers.each(meta.data, function(element, index) { + value = dataset.data[index]; + if (!isNaN(value) && !element.hidden) { + total += Math.abs(value); + } + }); + + return total; + }, + calculateCircumference: function(value) { - if (this.getDataset().total > 0 && !isNaN(value)) { - return (Math.PI * 1.999999) * (value / this.getDataset().total); + var total = this.getMeta().total; + if (total > 0 && !isNaN(value)) { + return (Math.PI * 2.0) * (value / total); } else { return 0; } } }); }; + },{}],18:[function(require,module,exports){ "use strict"; @@ -5747,48 +6057,45 @@ module.exports = function(Chart) { Chart.controllers.line = Chart.DatasetController.extend({ addElements: function() { - - this.getDataset().metaData = this.getDataset().metaData || []; - - this.getDataset().metaDataset = this.getDataset().metaDataset || new Chart.elements.Line({ + var meta = this.getMeta(); + meta.dataset = meta.dataset || new Chart.elements.Line({ _chart: this.chart.chart, _datasetIndex: this.index, - _points: this.getDataset().metaData + _points: meta.data }); helpers.each(this.getDataset().data, function(value, index) { - this.getDataset().metaData[index] = this.getDataset().metaData[index] || new Chart.elements.Point({ + meta.data[index] = meta.data[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 + // Add to the points array and reset it + this.getMeta().data.splice(index, 0, 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 if (this.chart.options.showLines && this.chart.options.elements.line.tension !== 0) this.updateBezierControlPoints(); }, update: function update(reset) { - var line = this.getDataset().metaDataset; - var points = this.getDataset().metaData; + var meta = this.getMeta(); + var line = meta.dataset; + var points = meta.data; - var yScale = this.getScaleForId(this.getDataset().yAxisID); - var xScale = this.getScaleForId(this.getDataset().xAxisID); + var yScale = this.getScaleForId(meta.yAxisID); + var xScale = this.getScaleForId(meta.xAxisID); var scaleBase; if (yScale.min < 0 && yScale.max < 0) { @@ -5807,9 +6114,16 @@ module.exports = function(Chart) { // Data line._children = points; // Model + + // Compatibility: If the properties are defined with only the old name, use those values + if ((this.getDataset().tension !== undefined) && (this.getDataset().lineTension === undefined)) + { + this.getDataset().lineTension = this.getDataset().tension; + } + line._model = { // Appearance - tension: line.custom && line.custom.tension ? line.custom.tension : helpers.getValueOrDefault(this.getDataset().tension, this.chart.options.elements.line.tension), + tension: line.custom && line.custom.tension ? line.custom.tension : helpers.getValueOrDefault(this.getDataset().lineTension, 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), @@ -5879,8 +6193,9 @@ module.exports = function(Chart) { }, updateElement: function(point, index, reset) { - var yScale = this.getScaleForId(this.getDataset().yAxisID); - var xScale = this.getScaleForId(this.getDataset().xAxisID); + var meta = this.getMeta(); + var yScale = this.getScaleForId(meta.yAxisID); + var xScale = this.getScaleForId(meta.xAxisID); var scaleBase; if (yScale.min < 0 && yScale.max < 0) { @@ -5899,27 +6214,37 @@ module.exports = function(Chart) { point._index = index; // Desired view properties + + // Compatibility: If the properties are defined with only the old name, use those values + if ((this.getDataset().radius !== undefined) && (this.getDataset().pointRadius === undefined)) + { + this.getDataset().pointRadius = this.getDataset().radius; + } + if ((this.getDataset().hitRadius !== undefined) && (this.getDataset().pointHitRadius === undefined)) + { + this.getDataset().pointHitRadius = this.getDataset().hitRadius; + } + point._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), + radius: point.custom && point.custom.radius ? point.custom.radius : helpers.getValueAtIndexOrDefault(this.getDataset().pointRadius, index, this.chart.options.elements.point.radius), pointStyle: point.custom && point.custom.pointStyle ? point.custom.pointStyle : helpers.getValueAtIndexOrDefault(this.getDataset().pointStyle, index, this.chart.options.elements.point.pointStyle), 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) + hitRadius: point.custom && point.custom.hitRadius ? point.custom.hitRadius : helpers.getValueAtIndexOrDefault(this.getDataset().pointHitRadius, 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); + var meta = this.getMeta(); + var xScale = this.getScaleForId(meta.xAxisID); + var yScale = this.getScaleForId(meta.yAxisID); if (yScale.options.stacked) { @@ -5928,7 +6253,8 @@ module.exports = function(Chart) { for (var i = 0; i < datasetIndex; i++) { var ds = this.chart.data.datasets[i]; - if (ds.type === 'line' && helpers.isDatasetVisible(ds)) { + var dsMeta = this.chart.getDatasetMeta(i); + if (dsMeta.type === 'line' && this.chart.isDatasetVisible(i)) { if (ds.data[index] < 0) { sumNeg += ds.data[index] || 0; } else { @@ -5949,12 +6275,13 @@ module.exports = function(Chart) { updateBezierControlPoints: function() { // Update bezier control points - helpers.each(this.getDataset().metaData, function(point, index) { + var meta = this.getMeta(); + helpers.each(meta.data, function(point, index) { var controlPoints = helpers.splineCurve( - helpers.previousItem(this.getDataset().metaData, index)._model, + helpers.previousItem(meta.data, index)._model, point._model, - helpers.nextItem(this.getDataset().metaData, index)._model, - point._model.tension + helpers.nextItem(meta.data, index)._model, + meta.dataset._model.tension ); // Prevent the bezier going outside of the bounds of the graph @@ -5970,19 +6297,20 @@ module.exports = function(Chart) { }, draw: function(ease) { + var meta = this.getMeta(); var easingDecimal = ease || 1; // Transition Point Locations - helpers.each(this.getDataset().metaData, function(point) { + helpers.each(meta.data, function(point) { point.transition(easingDecimal); }); // Transition and Draw the line if (this.chart.options.showLines) - this.getDataset().metaDataset.transition(easingDecimal).draw(); + meta.dataset.transition(easingDecimal).draw(); // Draw the points - helpers.each(this.getDataset().metaData, function(point) { + helpers.each(meta.data, function(point) { point.draw(); }); }, @@ -6002,7 +6330,13 @@ module.exports = function(Chart) { 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); + // Compatibility: If the properties are defined with only the old name, use those values + if ((this.getDataset().radius !== undefined) && (this.getDataset().pointRadius === undefined)) + { + this.getDataset().pointRadius = this.getDataset().radius; + } + + point._model.radius = point.custom && point.custom.radius ? point.custom.radius : helpers.getValueAtIndexOrDefault(this.getDataset().pointRadius, 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); @@ -6025,8 +6359,10 @@ module.exports = function(Chart) { }, //Boolean - Whether to animate the rotation of the chart - animateRotate: true, - animateScale: true, + animation: { + animateRotate: true, + animateScale: true + }, aspectRatio: 1, legendCallback: function(chart) { @@ -6048,37 +6384,45 @@ module.exports = function(Chart) { }, legend: { labels: { - generateLabels: function(data) { + generateLabels: function(chart) { + var data = chart.data; if (data.labels.length && data.datasets.length) { return data.labels.map(function(label, i) { + var meta = chart.getDatasetMeta(0); + var ds = data.datasets[0]; + var arc = meta.data[i]; + var fill = arc.custom && arc.custom.backgroundColor ? arc.custom.backgroundColor : helpers.getValueAtIndexOrDefault(ds.backgroundColor, i, this.chart.options.elements.arc.backgroundColor); + var stroke = arc.custom && arc.custom.borderColor ? arc.custom.borderColor : helpers.getValueAtIndexOrDefault(ds.borderColor, i, this.chart.options.elements.arc.borderColor); + var bw = arc.custom && arc.custom.borderWidth ? arc.custom.borderWidth : helpers.getValueAtIndexOrDefault(ds.borderWidth, i, this.chart.options.elements.arc.borderWidth); + return { text: label, - fillStyle: data.datasets[0].backgroundColor[i], - hidden: isNaN(data.datasets[0].data[i]), + fillStyle: fill, + strokeStyle: stroke, + lineWidth: bw, + hidden: isNaN(ds.data[i]) || meta.data[i].hidden, // Extra data used for toggling the correct item index: i }; - }); + }, this); } else { return []; } } }, + onClick: function(e, legendItem) { - helpers.each(this.chart.data.datasets, function(dataset) { - dataset.metaHiddenData = dataset.metaHiddenData || []; - var idx = legendItem.index; + var index = legendItem.index; + var chart = this.chart; + var i, ilen, meta; - 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]; - } - }); + for (i = 0, ilen = (chart.data.datasets || []).length; i < ilen; ++i) { + meta = chart.getDatasetMeta(i); + meta.data[index].hidden = !meta.data[index].hidden; + } - this.chart.update(); + chart.update(); } }, @@ -6099,51 +6443,43 @@ module.exports = function(Chart) { linkScales: function() { // no scales for doughnut }, + addElements: function() { - this.getDataset().metaData = this.getDataset().metaData || []; + var meta = this.getMeta(); helpers.each(this.getDataset().data, function(value, index) { - this.getDataset().metaData[index] = this.getDataset().metaData[index] || new Chart.elements.Arc({ + meta.data[index] = meta.data[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 + // Add to the points array and reset it + this.getMeta().data.splice(index, 0, arc); 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 meta = this.getMeta(); 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.chart.radiusLength = (this.chart.outerRadius - this.chart.innerRadius) / this.chart.getVisibleDatasetCount(); 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) { + meta.count = this.countVisibleElements(); + + helpers.each(meta.data, function(arc, index) { this.updateElement(arc, index, reset); }, this); }, @@ -6155,23 +6491,25 @@ module.exports = function(Chart) { // 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; + var visibleCount = 0; + var meta = this.getMeta(); for (var i = 0; i < index; ++i) { - if (!isNaN(this.getDataset().data[i])) { - ++notNullIndex; + if (!isNaN(this.getDataset().data[i]) && !meta.data[i].hidden) { + ++visibleCount; } } - var startAngle = (-0.5 * Math.PI) + (circumference * notNullIndex); - var endAngle = startAngle + circumference; + var distance = arc.hidden? 0 : this.chart.scale.getDistanceFromCenterForValue(this.getDataset().data[index]); + var startAngle = (-0.5 * Math.PI) + (circumference * visibleCount); + var endAngle = startAngle + (arc.hidden? 0 : 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, + outerRadius: this.chart.options.animation.animateScale ? 0 : this.chart.scale.getDistanceFromCenterForValue(this.getDataset().data[index]), + startAngle: this.chart.options.animation.animateRotate ? Math.PI * -0.5 : startAngle, + endAngle: this.chart.options.animation.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), borderWidth: arc.custom && arc.custom.borderWidth ? arc.custom.borderWidth : helpers.getValueAtIndexOrDefault(this.getDataset().borderWidth, index, this.chart.options.elements.arc.borderWidth), @@ -6192,7 +6530,7 @@ module.exports = function(Chart) { x: centerX, y: centerY, innerRadius: 0, - outerRadius: this.chart.scale.getDistanceFromCenterForValue(this.getDataset().data[index]), + outerRadius: distance, startAngle: startAngle, endAngle: endAngle, @@ -6209,7 +6547,7 @@ module.exports = function(Chart) { draw: function(ease) { var easingDecimal = ease || 1; - helpers.each(this.getDataset().metaData, function(arc, index) { + helpers.each(this.getMeta().data, function(arc, index) { arc.transition(easingDecimal).draw(); }); }, @@ -6232,21 +6570,31 @@ module.exports = function(Chart) { 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; + countVisibleElements: function() { + var dataset = this.getDataset(); + var meta = this.getMeta(); + var count = 0; - return (2 * Math.PI) / (this.getDataset().data.length - numNaN); + helpers.each(meta.data, function(element, index) { + if (!isNaN(dataset.data[index]) && !element.hidden) { + count++; + } + }); + + return count; + }, + + calculateCircumference: function(value) { + var count = this.getMeta().count; + if (count > 0 && !isNaN(value)) { + return (2 * Math.PI) / count; + } else { + return 0; } } }); - }; + },{}],20:[function(require,module,exports){ "use strict"; @@ -6272,18 +6620,17 @@ module.exports = function(Chart) { }, addElements: function() { + var meta = this.getMeta(); - this.getDataset().metaData = this.getDataset().metaData || []; - - this.getDataset().metaDataset = this.getDataset().metaDataset || new Chart.elements.Line({ + meta.dataset = meta.dataset || new Chart.elements.Line({ _chart: this.chart.chart, _datasetIndex: this.index, - _points: this.getDataset().metaData, + _points: meta.data, _loop: true }); helpers.each(this.getDataset().data, function(value, index) { - this.getDataset().metaData[index] = this.getDataset().metaData[index] || new Chart.elements.Point({ + meta.data[index] = meta.data[index] || new Chart.elements.Point({ _chart: this.chart.chart, _datasetIndex: this.index, _index: index, @@ -6295,27 +6642,24 @@ module.exports = function(Chart) { }, 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 + // Add to the points array and reset it + this.getMeta().data.splice(index, 0, 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 meta = this.getMeta(); + var line = meta.dataset; + var points = meta.data; var scale = this.chart.scale; var scaleBase; @@ -6328,15 +6672,21 @@ module.exports = function(Chart) { scaleBase = scale.getPointPositionForValue(0, 0); } - helpers.extend(this.getDataset().metaDataset, { + // Compatibility: If the properties are defined with only the old name, use those values + if ((this.getDataset().tension !== undefined) && (this.getDataset().lineTension === undefined)) + { + this.getDataset().lineTension = this.getDataset().tension; + } + + helpers.extend(meta.dataset, { // Utility _datasetIndex: this.index, // Data - _children: this.getDataset().metaData, + _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), + tension: line.custom && line.custom.tension ? line.custom.tension : helpers.getValueOrDefault(this.getDataset().lineTension, 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), @@ -6353,7 +6703,7 @@ module.exports = function(Chart) { } }); - this.getDataset().metaDataset.pivot(); + meta.dataset.pivot(); // Update Points helpers.each(points, function(point, index) { @@ -6394,11 +6744,12 @@ module.exports = function(Chart) { 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 meta = this.getMeta(); + helpers.each(meta.data, function(point, index) { var controlPoints = helpers.splineCurve( - helpers.previousItem(this.getDataset().metaData, index, true)._model, + helpers.previousItem(meta.data, index, true)._model, point._model, - helpers.nextItem(this.getDataset().metaData, index, true)._model, + helpers.nextItem(meta.data, index, true)._model, point._model.tension ); @@ -6415,18 +6766,19 @@ module.exports = function(Chart) { }, draw: function(ease) { + var meta = this.getMeta(); var easingDecimal = ease || 1; // Transition Point Locations - helpers.each(this.getDataset().metaData, function(point, index) { + helpers.each(meta.data, function(point, index) { point.transition(easingDecimal); }); // Transition and Draw the line - this.getDataset().metaDataset.transition(easingDecimal).draw(); + meta.dataset.transition(easingDecimal).draw(); // Draw the points - helpers.each(this.getDataset().metaData, function(point) { + helpers.each(meta.data, function(point) { point.draw(); }); }, @@ -6629,9 +6981,8 @@ module.exports = function(Chart) { helpers.extend(Chart.Controller.prototype, { initialize: function initialize() { - - // TODO - // If BeforeInit(this) doesn't return false, proceed + // Before init plugin notification + Chart.pluginService.notifyPlugins('beforeInit', [this]); this.bindEvents(); @@ -6646,8 +6997,8 @@ module.exports = function(Chart) { this.initToolTip(); this.update(); - // TODO - // If AfterInit(this) doesn't return false, proceed + // After init plugin notification + Chart.pluginService.notifyPlugins('afterInit', [this]); return this; }, @@ -6795,18 +7146,18 @@ module.exports = function(Chart) { var newControllers = []; helpers.each(this.data.datasets, function(dataset, datasetIndex) { - if (!dataset.type) { - dataset.type = this.config.type; + var meta = this.getDatasetMeta(datasetIndex); + if (!meta.type) { + meta.type = dataset.type || this.config.type; } - var type = dataset.type; - types.push(type); + types.push(meta.type); - if (dataset.controller) { - dataset.controller.updateIndex(datasetIndex); + if (meta.controller) { + meta.controller.updateIndex(datasetIndex); } else { - dataset.controller = new Chart.controllers[type](this, datasetIndex); - newControllers.push(dataset.controller); + meta.controller = new Chart.controllers[meta.type](this, datasetIndex); + newControllers.push(meta.controller); } }, this); @@ -6824,17 +7175,24 @@ module.exports = function(Chart) { resetElements: function resetElements() { helpers.each(this.data.datasets, function(dataset, datasetIndex) { - dataset.controller.reset(); - }); + this.getDatasetMeta(datasetIndex).controller.reset(); + }, this); }, update: function update(animationDuration, lazy) { + Chart.pluginService.notifyPlugins('beforeUpdate', [this]); + // In case the entire data object changed this.tooltip._data = this.data; // Make sure dataset controllers are updated and new controllers are reset var newControllers = this.buildOrUpdateControllers(); + // Make sure all dataset controllers have correct meta data counts + helpers.each(this.data.datasets, function(dataset, datasetIndex) { + this.getDatasetMeta(datasetIndex).controller.buildOrUpdateElements(); + }, this); + Chart.layoutService.update(this, this.chart.width, this.chart.height); // Can only reset the new controllers after the scales have been updated @@ -6842,19 +7200,18 @@ module.exports = function(Chart) { controller.reset(); }); - // Make sure all dataset controllers have correct meta data counts - helpers.each(this.data.datasets, function(dataset, datasetIndex) { - dataset.controller.buildOrUpdateElements(); - }); - // 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.getDatasetMeta(datasetIndex).controller.update(); + }, this); + this.render(animationDuration, lazy); + + Chart.pluginService.notifyPlugins('afterUpdate', [this]); }, render: function render(duration, lazy) { + Chart.pluginService.notifyPlugins('beforeRender', [this]); if (this.options.animation && ((typeof duration !== 'undefined' && duration !== 0) || (typeof duration === 'undefined' && this.options.animation.duration !== 0))) { var animation = new Chart.Animation(); @@ -6888,6 +7245,8 @@ module.exports = function(Chart) { var easingDecimal = ease || 1; this.clear(); + Chart.pluginService.notifyPlugins('beforeDraw', [this, easingDecimal]); + // Draw all the scales helpers.each(this.boxes, function(box) { box.draw(this.chartArea); @@ -6904,35 +7263,37 @@ module.exports = function(Chart) { // 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); + if (this.isDatasetVisible(datasetIndex)) { + this.getDatasetMeta(datasetIndex).controller.draw(ease); } - }, null, true); + }, this, true); // Restore from the clipping operation this.chart.ctx.restore(); // Finally draw the tooltip this.tooltip.transition(easingDecimal).draw(); + + Chart.pluginService.notifyPlugins('afterDraw', [this, easingDecimal]); }, // 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 (this.isDatasetVisible(datasetIndex)) { + var meta = this.getDatasetMeta(datasetIndex); + helpers.each(meta.data, function(element, index) { if (element.inRange(eventPosition.x, eventPosition.y)) { elementsArray.push(element); return elementsArray; } }); } - }); + }, this); return elementsArray; }, @@ -6944,10 +7305,11 @@ module.exports = function(Chart) { var found = (function() { if (this.data.datasets) { 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]; + var meta = this.getDatasetMeta(i); + if (this.isDatasetVisible(i)) { + for (var j = 0; j < meta.data.length; j++) { + if (meta.data[j].inRange(eventPosition.x, eventPosition.y)) { + return meta.data[j]; } } } @@ -6959,11 +7321,12 @@ module.exports = function(Chart) { return elementsArray; } - helpers.each(this.data.datasets, function(dataset, dsIndex) { - if (helpers.isDatasetVisible(dataset)) { - elementsArray.push(dataset.metaData[found._index]); + helpers.each(this.data.datasets, function(dataset, datasetIndex) { + if (this.isDatasetVisible(datasetIndex)) { + var meta = this.getDatasetMeta(datasetIndex); + elementsArray.push(meta.data[found._index]); } - }); + }, this); return elementsArray; }, @@ -6972,12 +7335,52 @@ module.exports = function(Chart) { var elementsArray = this.getElementAtEvent(e); if (elementsArray.length > 0) { - elementsArray = this.data.datasets[elementsArray[0]._datasetIndex].metaData; + elementsArray = this.getDatasetMeta(elementsArray[0]._datasetIndex).data; } return elementsArray; }, + getDatasetMeta: function(datasetIndex) { + var dataset = this.data.datasets[datasetIndex]; + if (!dataset._meta) { + dataset._meta = {}; + } + + var meta = dataset._meta[this.id]; + if (!meta) { + meta = dataset._meta[this.id] = { + type: null, + data: [], + dataset: null, + controller: null, + hidden: null, // See isDatasetVisible() comment + xAxisID: null, + yAxisID: null + }; + } + + return meta; + }, + + getVisibleDatasetCount: function() { + var count = 0; + for (var i = 0, ilen = this.data.datasets.length; i